From edb80b90186b7ebfcce8b3dae55fedb62a77b912 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 7 Sep 2021 16:41:27 +0530 Subject: Wikiguess Game (#618) * (trivia-quiz): Add Wikipedia Guess Game This commit also moves all the 'dynamic' question generator to a separate class. Closes: #446 * (trivia quiz): Use tuples for command aliases * (trivia quiz): Edit congratulations message * (trivia quiz): Use default dict for storing player scores * (trivia quiz): 'done_question' to 'done_questions' * Add space after 'Congratulations' word * Use classmethods for dynamically generating questions * Don't add wiki category if max error fetches hit If the task hit max error fetches, which is 3 currently, it would remove wikipedia from listed categories and not add it to loaded questions. If it doesn't hit max fetches, then it adds them. * Don't hardcode the number of questions in RULES * Add information field only if it exists * Add "cs" and "python" categories to the `.quiz` command * add 30 questions each under the categories "cs" and "python" add the two categories into the code and modify the starting phase Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> Co-authored-by: ToxicKidz <78174417+ToxicKidz@users.noreply.github.com> * refactor: Use yesterday's most read to make trivia questions Since random wikipedia article guess questions weren't really "knowledgeable", no one could really guess it or gain any "good" knowledge from them, so after asking wookie (this commits mentions his review comments above also), I decided to use these. * refactor: Logic to remove pronounciations from question Co-authored-by: wookie184 * fix: Set to correct question limit If the number of questions are less then the default limit which can happen in the case of wikipedia guess game as it is dependent on the most read articiles on wikipedia, it would create a infinite loop sending us into infinite amount of errors, so let's prevent that, thanks wookie * chore: Add comment for d5f8205 change * refactor: Remove double mention of dataclass in quizentry * chore: Use r"" over noqa We can use r"", a raw string, here to make it clear that \* and \s aren't supposed to be handled as escape sequences and just use the "raw string". * fix: Correct off by one bug Originally, before this commit, we checked the number of questions left by comparing `len(done_questions) > self.question_limit`, so question limit had to be 1 since if it wasn't we would compare 7 > 7, which would be false and then it would send another question. To correct this bug, we now use == comparision on the two, so if the number of done questions is same as the question limit it means that the round is over. I have changed the relevant parts of the code to reflect this change i.e. where-ever we did +-1 due to the off by one bug. * refactor: Noramlize the title to remove all punctuations Since the title can sometimes contain punctuations making it very difficult to get the matching answer to the question, we originally removed all such questions. This took the question count down :( and wasn't an effective way. Therefore now we keep them but as normalized, yay! I have also updated the code documentation to make the process much clearer to anyone reading the "normalizing" code section of the wiki questions generator. * refactor: Keep answers as a list & not ",".join() Wasn't fitting in character limit so shorterned it ^^ lol. Okay, getting to the point, this mentions fix error's comment of making quiz entry except the answers as a list and not as a string which could a comma joined list. The same structure was in the json resource, where multiple answers where joined with commas. This didn't allow you to use commas in answers. So I went ahead and did a bit more than requested to change the json structure and make `answers` a list. Also now all questions are in the form of the quiz entry to keep it same through out the code and var tolerance has become a valid param in QuizEntry, this is done because it was differing between questions, if not needed this would make the process to add `var_tol` as a argument to the json easier. And that's it! Co-authored-by: Objectivitix <79152594+Objectivitix@users.noreply.github.com> Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> Co-authored-by: ToxicKidz <78174417+ToxicKidz@users.noreply.github.com> Co-authored-by: wookie184 --- bot/exts/fun/trivia_quiz.py | 422 ++++++++++++++++++++++--------------- bot/resources/fun/trivia_quiz.json | 94 ++++----- 2 files changed, 299 insertions(+), 217 deletions(-) diff --git a/bot/exts/fun/trivia_quiz.py b/bot/exts/fun/trivia_quiz.py index cf9e6cd3..236586b0 100644 --- a/bot/exts/fun/trivia_quiz.py +++ b/bot/exts/fun/trivia_quiz.py @@ -3,12 +3,16 @@ import json import logging import operator import random +import re +import string +from collections import defaultdict from dataclasses import dataclass +from datetime import datetime, timedelta from pathlib import Path from typing import Callable, Optional import discord -from discord.ext import commands +from discord.ext import commands, tasks from rapidfuzz import fuzz from bot.bot import Bot @@ -16,177 +20,194 @@ from bot.constants import Colours, NEGATIVE_REPLIES, Roles logger = logging.getLogger(__name__) -DEFAULT_QUESTION_LIMIT = 6 +DEFAULT_QUESTION_LIMIT = 7 STANDARD_VARIATION_TOLERANCE = 88 DYNAMICALLY_GEN_VARIATION_TOLERANCE = 97 +MAX_ERROR_FETCH_TRIES = 3 + WRONG_ANS_RESPONSE = [ "No one answered correctly!", "Better luck next time...", ] -N_PREFIX_STARTS_AT = 5 -N_PREFIXES = [ - "penta", "hexa", "hepta", "octa", "nona", - "deca", "hendeca", "dodeca", "trideca", "tetradeca", -] +RULES = ( + "No cheating and have fun!", + "Points for each question reduces by 25 after 10s or after a hint. Total time is 30s per question" +) -PLANETS = [ - ("1st", "Mercury"), - ("2nd", "Venus"), - ("3rd", "Earth"), - ("4th", "Mars"), - ("5th", "Jupiter"), - ("6th", "Saturn"), - ("7th", "Uranus"), - ("8th", "Neptune"), -] - -TAXONOMIC_HIERARCHY = [ - "species", "genus", "family", "order", - "class", "phylum", "kingdom", "domain", -] - -UNITS_TO_BASE_UNITS = { - "hertz": ("(unit of frequency)", "s^-1"), - "newton": ("(unit of force)", "m*kg*s^-2"), - "pascal": ("(unit of pressure & stress)", "m^-1*kg*s^-2"), - "joule": ("(unit of energy & quantity of heat)", "m^2*kg*s^-2"), - "watt": ("(unit of power)", "m^2*kg*s^-3"), - "coulomb": ("(unit of electric charge & quantity of electricity)", "s*A"), - "volt": ("(unit of voltage & electromotive force)", "m^2*kg*s^-3*A^-1"), - "farad": ("(unit of capacitance)", "m^-2*kg^-1*s^4*A^2"), - "ohm": ("(unit of electric resistance)", "m^2*kg*s^-3*A^-2"), - "weber": ("(unit of magnetic flux)", "m^2*kg*s^-2*A^-1"), - "tesla": ("(unit of magnetic flux density)", "kg*s^-2*A^-1"), -} +WIKI_FEED_API_URL = "https://en.wikipedia.org/api/rest_v1/feed/featured/{date}" +TRIVIA_QUIZ_ICON = ( + "https://raw.githubusercontent.com/python-discord/branding/main/icons/trivia_quiz/trivia-quiz-dist.png" +) @dataclass(frozen=True) class QuizEntry: - """Dataclass for a quiz entry (a question and a string containing answers separated by commas).""" + """Stores quiz entry (a question and a list of answers).""" question: str - answer: str - - -def linear_system(q_format: str, a_format: str) -> QuizEntry: - """Generate a system of linear equations with two unknowns.""" - x, y = random.randint(2, 5), random.randint(2, 5) - answer = a_format.format(x, y) - - coeffs = random.sample(range(1, 6), 4) - - question = q_format.format( - coeffs[0], - coeffs[1], - coeffs[0] * x + coeffs[1] * y, - coeffs[2], - coeffs[3], - coeffs[2] * x + coeffs[3] * y, - ) - - return QuizEntry(question, answer) - - -def mod_arith(q_format: str, a_format: str) -> QuizEntry: - """Generate a basic modular arithmetic question.""" - quotient, m, b = random.randint(30, 40), random.randint(10, 20), random.randint(200, 350) - ans = random.randint(0, 9) # max remainder is 9, since the minimum modulus is 10 - a = quotient * m + ans - b - - question = q_format.format(a, b, m) - answer = a_format.format(ans) + answers: list[str] + var_tol: int + + +class DynamicQuestionGen: + """Class that contains functions to generate math/science questions for TriviaQuiz Cog.""" + + N_PREFIX_STARTS_AT = 5 + N_PREFIXES = [ + "penta", "hexa", "hepta", "octa", "nona", + "deca", "hendeca", "dodeca", "trideca", "tetradeca", + ] + + PLANETS = [ + ("1st", "Mercury"), + ("2nd", "Venus"), + ("3rd", "Earth"), + ("4th", "Mars"), + ("5th", "Jupiter"), + ("6th", "Saturn"), + ("7th", "Uranus"), + ("8th", "Neptune"), + ] + + TAXONOMIC_HIERARCHY = [ + "species", "genus", "family", "order", + "class", "phylum", "kingdom", "domain", + ] + + UNITS_TO_BASE_UNITS = { + "hertz": ("(unit of frequency)", "s^-1"), + "newton": ("(unit of force)", "m*kg*s^-2"), + "pascal": ("(unit of pressure & stress)", "m^-1*kg*s^-2"), + "joule": ("(unit of energy & quantity of heat)", "m^2*kg*s^-2"), + "watt": ("(unit of power)", "m^2*kg*s^-3"), + "coulomb": ("(unit of electric charge & quantity of electricity)", "s*A"), + "volt": ("(unit of voltage & electromotive force)", "m^2*kg*s^-3*A^-1"), + "farad": ("(unit of capacitance)", "m^-2*kg^-1*s^4*A^2"), + "ohm": ("(unit of electric resistance)", "m^2*kg*s^-3*A^-2"), + "weber": ("(unit of magnetic flux)", "m^2*kg*s^-2*A^-1"), + "tesla": ("(unit of magnetic flux density)", "kg*s^-2*A^-1"), + } + + @classmethod + def linear_system(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a system of linear equations with two unknowns.""" + x, y = random.randint(2, 5), random.randint(2, 5) + answer = a_format.format(x, y) + + coeffs = random.sample(range(1, 6), 4) + + question = q_format.format( + coeffs[0], + coeffs[1], + coeffs[0] * x + coeffs[1] * y, + coeffs[2], + coeffs[3], + coeffs[2] * x + coeffs[3] * y, + ) - return QuizEntry(question, answer) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) + @classmethod + def mod_arith(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a basic modular arithmetic question.""" + quotient, m, b = random.randint(30, 40), random.randint(10, 20), random.randint(200, 350) + ans = random.randint(0, 9) # max remainder is 9, since the minimum modulus is 10 + a = quotient * m + ans - b -def ngonal_prism(q_format: str, a_format: str) -> QuizEntry: - """Generate a question regarding vertices on n-gonal prisms.""" - n = random.randint(0, len(N_PREFIXES) - 1) + question = q_format.format(a, b, m) + answer = a_format.format(ans) - question = q_format.format(N_PREFIXES[n]) - answer = a_format.format((n + N_PREFIX_STARTS_AT) * 2) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) - return QuizEntry(question, answer) + @classmethod + def ngonal_prism(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a question regarding vertices on n-gonal prisms.""" + n = random.randint(0, len(cls.N_PREFIXES) - 1) + question = q_format.format(cls.N_PREFIXES[n]) + answer = a_format.format((n + cls.N_PREFIX_STARTS_AT) * 2) -def imag_sqrt(q_format: str, a_format: str) -> QuizEntry: - """Generate a negative square root question.""" - ans_coeff = random.randint(3, 10) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) - question = q_format.format(ans_coeff ** 2) - answer = a_format.format(ans_coeff) + @classmethod + def imag_sqrt(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a negative square root question.""" + ans_coeff = random.randint(3, 10) - return QuizEntry(question, answer) + question = q_format.format(ans_coeff ** 2) + answer = a_format.format(ans_coeff) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) -def binary_calc(q_format: str, a_format: str) -> QuizEntry: - """Generate a binary calculation question.""" - a = random.randint(15, 20) - b = random.randint(10, a) - oper = random.choice( - ( - ("+", operator.add), - ("-", operator.sub), - ("*", operator.mul), + @classmethod + def binary_calc(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a binary calculation question.""" + a = random.randint(15, 20) + b = random.randint(10, a) + oper = random.choice( + ( + ("+", operator.add), + ("-", operator.sub), + ("*", operator.mul), + ) ) - ) - # if the operator is multiplication, lower the values of the two operands to make it easier - if oper[0] == "*": - a -= 5 - b -= 5 + # if the operator is multiplication, lower the values of the two operands to make it easier + if oper[0] == "*": + a -= 5 + b -= 5 - question = q_format.format(a, oper[0], b) - answer = a_format.format(oper[1](a, b)) + question = q_format.format(a, oper[0], b) + answer = a_format.format(oper[1](a, b)) - return QuizEntry(question, answer) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) + @classmethod + def solar_system(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a question on the planets of the Solar System.""" + planet = random.choice(cls.PLANETS) -def solar_system(q_format: str, a_format: str) -> QuizEntry: - """Generate a question on the planets of the Solar System.""" - planet = random.choice(PLANETS) + question = q_format.format(planet[0]) + answer = a_format.format(planet[1]) - question = q_format.format(planet[0]) - answer = a_format.format(planet[1]) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) - return QuizEntry(question, answer) + @classmethod + def taxonomic_rank(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a question on taxonomic classification.""" + level = random.randint(0, len(cls.TAXONOMIC_HIERARCHY) - 2) + question = q_format.format(cls.TAXONOMIC_HIERARCHY[level]) + answer = a_format.format(cls.TAXONOMIC_HIERARCHY[level + 1]) -def taxonomic_rank(q_format: str, a_format: str) -> QuizEntry: - """Generate a question on taxonomic classification.""" - level = random.randint(0, len(TAXONOMIC_HIERARCHY) - 2) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) - question = q_format.format(TAXONOMIC_HIERARCHY[level]) - answer = a_format.format(TAXONOMIC_HIERARCHY[level + 1]) + @classmethod + def base_units_convert(cls, q_format: str, a_format: str) -> QuizEntry: + """Generate a SI base units conversion question.""" + unit = random.choice(list(cls.UNITS_TO_BASE_UNITS)) - return QuizEntry(question, answer) - - -def base_units_convert(q_format: str, a_format: str) -> QuizEntry: - """Generate a SI base units conversion question.""" - unit = random.choice(list(UNITS_TO_BASE_UNITS)) - - question = q_format.format( - unit + " " + UNITS_TO_BASE_UNITS[unit][0] - ) - answer = a_format.format( - UNITS_TO_BASE_UNITS[unit][1] - ) + question = q_format.format( + unit + " " + cls.UNITS_TO_BASE_UNITS[unit][0] + ) + answer = a_format.format( + cls.UNITS_TO_BASE_UNITS[unit][1] + ) - return QuizEntry(question, answer) + return QuizEntry(question, [answer], DYNAMICALLY_GEN_VARIATION_TOLERANCE) DYNAMIC_QUESTIONS_FORMAT_FUNCS = { - 201: linear_system, - 202: mod_arith, - 203: ngonal_prism, - 204: imag_sqrt, - 205: binary_calc, - 301: solar_system, - 302: taxonomic_rank, - 303: base_units_convert, + 201: DynamicQuestionGen.linear_system, + 202: DynamicQuestionGen.mod_arith, + 203: DynamicQuestionGen.ngonal_prism, + 204: DynamicQuestionGen.imag_sqrt, + 205: DynamicQuestionGen.binary_calc, + 301: DynamicQuestionGen.solar_system, + 302: DynamicQuestionGen.taxonomic_rank, + 303: DynamicQuestionGen.base_units_convert, } @@ -202,7 +223,7 @@ class TriviaQuiz(commands.Cog): self.questions = self.load_questions() self.question_limit = 0 - self.player_scores = {} # A variable to store all player's scores for a bot session. + self.player_scores = defaultdict(int) # A variable to store all player's scores for a bot session. self.game_player_scores = {} # A variable to store temporary game player's scores. self.categories = { @@ -212,8 +233,72 @@ class TriviaQuiz(commands.Cog): "science": "Put your understanding of science to the test!", "cs": "A large variety of computer science questions.", "python": "Trivia on our amazing language, Python!", + "wikipedia": "Guess the title of random wikipedia passages.", } + self.get_wiki_questions.start() + + def cog_unload(self) -> None: + """Cancel `get_wiki_questions` task when Cog will unload.""" + self.get_wiki_questions.cancel() + + @tasks.loop(hours=24.0) + async def get_wiki_questions(self) -> None: + """Get yesterday's most read articles from wikipedia and format them like trivia questions.""" + error_fetches = 0 + wiki_questions = [] + # trivia_quiz.json follows a pattern, every new category starts with the next century. + start_id = 501 + yesterday = datetime.strftime(datetime.now() - timedelta(1), '%Y/%m/%d') + + while error_fetches < MAX_ERROR_FETCH_TRIES: + async with self.bot.http_session.get(url=WIKI_FEED_API_URL.format(date=yesterday)) as r: + if r.status != 200: + error_fetches += 1 + continue + raw_json = await r.json() + articles_raw = raw_json["mostread"]["articles"] + + for article in articles_raw: + question = article.get("extract") + if not question: + continue + + # Normalize the wikipedia article title to remove all punctuations from it + for word in re.split(r"[\s-]", title := article["normalizedtitle"]): + cleaned_title = re.sub( + rf'\b{word.strip(string.punctuation)}\b', word, title, flags=re.IGNORECASE + ) + + # Since the extract contains the article name sometimes this would replace all the matching words + # in that article with *** of that length. + # NOTE: This removes the "answer" for 99% of the cases, but sometimes the wikipedia article is + # very different from the words in the extract, for example the title would be the nickname of a + # person (Bob Ross) whereas in the extract it would the full name (Robert Norman Ross) so it comes + # out as (Robert Norman ****) and (Robert Norman Ross) won't be a right answer :( + for word in re.split(r"[\s-]", cleaned_title): + word = word.strip(string.punctuation) + secret_word = r"\*" * len(word) + question = re.sub(rf'\b{word}\b', f"**{secret_word}**", question, flags=re.IGNORECASE) + + formatted_article_question = { + "id": start_id, + "question": f"Guess the title of the Wikipedia article.\n\n{question}", + "answer": cleaned_title, + "info": article["extract"] + } + start_id += 1 + wiki_questions.append(formatted_article_question) + + # If everything has gone smoothly until now, we can break out of the while loop + break + + if error_fetches < MAX_ERROR_FETCH_TRIES: + self.questions["wikipedia"] = wiki_questions.copy() + else: + del self.categories["wikipedia"] + logger.warning(f"Not loading wikipedia guess questions, hit max error fetches: {MAX_ERROR_FETCH_TRIES}.") + @staticmethod def load_questions() -> dict: """Load the questions from the JSON file.""" @@ -221,7 +306,7 @@ class TriviaQuiz(commands.Cog): return json.loads(p.read_text(encoding="utf-8")) - @commands.group(name="quiz", aliases=["trivia"], invoke_without_command=True) + @commands.group(name="quiz", aliases=("trivia", "triviaquiz"), invoke_without_command=True) async def quiz_game(self, ctx: commands.Context, category: Optional[str], questions: Optional[int]) -> None: """ Start a quiz! @@ -233,6 +318,7 @@ class TriviaQuiz(commands.Cog): - science: Put your understanding of science to the test! - cs: A large variety of computer science questions. - python: Trivia on our amazing language, Python! + - wikipedia: Guess the title of random wikipedia passages. (More to come!) """ @@ -264,7 +350,7 @@ class TriviaQuiz(commands.Cog): topic_length = len(topic) if questions is None: - self.question_limit = DEFAULT_QUESTION_LIMIT + self.question_limit = min(DEFAULT_QUESTION_LIMIT, topic_length) else: if questions > topic_length: await ctx.send( @@ -279,13 +365,13 @@ class TriviaQuiz(commands.Cog): await ctx.send( embed=self.make_error_embed( "You must choose to complete at least one question. " - f"(or enter nothing for the default value of {DEFAULT_QUESTION_LIMIT + 1} questions)" + f"(or enter nothing for the default value of {DEFAULT_QUESTION_LIMIT} questions)" ) ) return else: - self.question_limit = questions - 1 + self.question_limit = questions # Start game if not running. if not self.game_status[ctx.channel.id]: @@ -296,13 +382,13 @@ class TriviaQuiz(commands.Cog): await ctx.send(embed=start_embed) # send an embed with the rules await asyncio.sleep(5) - done_question = [] + done_questions = [] hint_no = 0 - answers = None + quiz_entry = None while self.game_status[ctx.channel.id]: # Exit quiz if number of questions for a round are already sent. - if len(done_question) > self.question_limit and hint_no == 0: + if len(done_questions) == self.question_limit and hint_no == 0: await ctx.send("The round has ended.") await self.declare_winner(ctx.channel, self.game_player_scores[ctx.channel.id]) @@ -317,32 +403,27 @@ class TriviaQuiz(commands.Cog): # Select a random question which has not been used yet. while True: question_dict = random.choice(topic) - if question_dict["id"] not in done_question: - done_question.append(question_dict["id"]) + if question_dict["id"] not in done_questions: + done_questions.append(question_dict["id"]) break if "dynamic_id" not in question_dict: - question = question_dict["question"] - answers = question_dict["answer"].split(", ") - - var_tol = STANDARD_VARIATION_TOLERANCE + quiz_entry = QuizEntry( + question_dict["question"], + quiz_answers if isinstance(quiz_answers := question_dict["answer"], list) else [quiz_answers], + STANDARD_VARIATION_TOLERANCE + ) else: format_func = DYNAMIC_QUESTIONS_FORMAT_FUNCS[question_dict["dynamic_id"]] - quiz_entry = format_func( question_dict["question"], question_dict["answer"], ) - question, answers = quiz_entry.question, quiz_entry.answer - answers = [answers] - - var_tol = DYNAMICALLY_GEN_VARIATION_TOLERANCE - embed = discord.Embed( colour=Colours.gold, - title=f"Question #{len(done_question)}", - description=question, + title=f"Question #{len(done_questions)}", + description=quiz_entry.question, ) if img_url := question_dict.get("img_url"): @@ -354,13 +435,13 @@ class TriviaQuiz(commands.Cog): def contains_correct_answer(m: discord.Message) -> bool: return m.channel == ctx.channel and any( fuzz.ratio(answer.lower(), m.content.lower()) > variation_tolerance - for answer in answers + for answer in quiz_entry.answers ) return contains_correct_answer try: - msg = await self.bot.wait_for("message", check=check_func(var_tol), timeout=10) + msg = await self.bot.wait_for("message", check=check_func(quiz_entry.var_tol), timeout=10) except asyncio.TimeoutError: # In case of TimeoutError and the game has been stopped, then do nothing. if not self.game_status[ctx.channel.id]: @@ -388,10 +469,10 @@ class TriviaQuiz(commands.Cog): await self.send_answer( ctx.channel, - answers, + quiz_entry.answers, False, question_dict, - self.question_limit - len(done_question) + 1, + self.question_limit - len(done_questions), ) await asyncio.sleep(1) @@ -421,10 +502,10 @@ class TriviaQuiz(commands.Cog): await self.send_answer( ctx.channel, - answers, + quiz_entry.answers, True, question_dict, - self.question_limit - len(done_question) + 1, + self.question_limit - len(done_questions), ) await self.send_score(ctx.channel, self.game_player_scores[ctx.channel.id]) @@ -432,19 +513,18 @@ class TriviaQuiz(commands.Cog): def make_start_embed(self, category: str) -> discord.Embed: """Generate a starting/introduction embed for the quiz.""" + rules = "\n".join([f"{index}: {rule}" for index, rule in enumerate(RULES, start=1)]) + start_embed = discord.Embed( - colour=Colours.blue, - title="A quiz game is starting!", + title="Quiz game Starting!!", description=( - f"This game consists of {self.question_limit + 1} questions.\n\n" - "**Rules: **\n" - "1. Only enclose your answer in backticks when the question tells you to.\n" - "2. If the question specifies an answer format, follow it or else it won't be accepted.\n" - "3. You have 30s per question. Points for each question reduces by 25 after 10s or after a hint.\n" - "4. No cheating and have fun!\n\n" - f"**Category**: {category}" + f"Each game consists of {self.question_limit} questions.\n" + f"**Rules :**\n{rules}" + f"\n **Category** : {category}" ), + colour=Colours.blue ) + start_embed.set_thumbnail(url=TRIVIA_QUIZ_ICON) return start_embed @@ -503,6 +583,7 @@ class TriviaQuiz(commands.Cog): title="Score Board", description="", ) + embed.set_thumbnail(url=TRIVIA_QUIZ_ICON) sorted_dict = sorted(player_data.items(), key=operator.itemgetter(1), reverse=True) for item in sorted_dict: @@ -534,8 +615,8 @@ class TriviaQuiz(commands.Cog): winners_mention = winner.mention await channel.send( - f"Congratulations {winners_mention} :tada: " - f"You have won this quiz game with a grand total of {highest_points} points!" + f"{winners_mention} Congratulations " + f"on winning this quiz game with a grand total of {highest_points} points :tada:" ) def category_embed(self) -> discord.Embed: @@ -578,7 +659,8 @@ class TriviaQuiz(commands.Cog): description="", ) - if info is not None: + # Don't check for info is not None, as we want to filter out empty strings. + if info: embed.description += f"**Information**\n{info}\n\n" embed.description += ( diff --git a/bot/resources/fun/trivia_quiz.json b/bot/resources/fun/trivia_quiz.json index 8008838c..0b3e6802 100644 --- a/bot/resources/fun/trivia_quiz.json +++ b/bot/resources/fun/trivia_quiz.json @@ -52,7 +52,7 @@ "They generally have handdrawn nature images on them." ], "question": "What did Nintendo make before video games and toys?", - "answer": "Hanafuda, Hanafuda cards" + "answer": ["Hanafuda", "Hanafuda cards"] }, { "id": 7, @@ -292,22 +292,22 @@ { "id": 201, "question": "What is the highest power of a biquadratic polynomial?", - "answer": "4, four" + "answer": ["4", "four"] }, { "id": 202, "question": "What is the formula for surface area of a sphere?", - "answer": "4pir^2, 4πr^2" + "answer": ["4pir^2", "4πr^2"] }, { "id": 203, "question": "Which theorem states that hypotenuse^2 = base^2 + height^2?", - "answer": "Pythagorean's, Pythagorean's theorem" + "answer": ["Pythagorean's", "Pythagorean's theorem"] }, { "id": 204, "question": "Which trigonometric function is defined as hypotenuse/opposite?", - "answer": "cosecant, cosec, csc" + "answer": ["cosecant", "cosec", "csc"] }, { "id": 205, @@ -317,7 +317,7 @@ { "id": 206, "question": "How many quadrants are there in a cartesian plane?", - "answer": "4, four" + "answer": ["4", "four"] }, { "id": 207, @@ -328,7 +328,7 @@ "id": 208, "question": "What's the following formula that finds the area of a triangle called?", "img_url": "https://wikimedia.org/api/rest_v1/media/math/render/png/d22b8566e8187542966e8d166e72e93746a1a6fc", - "answer": "Heron's formula, Heron" + "answer": ["Heron's formula", "Heron"] }, { "id": 209, @@ -372,12 +372,12 @@ { "id": 216, "question": "In set builder notation, what does {p/q | q ≠ 0, p & q ∈ Z} represent?", - "answer": "Rationals, Rational Numbers" + "answer": ["Rationals", "Rational Numbers"] }, { "id": 217, "question": "What is the natural log of -1 (use i for imaginary number)?", - "answer": "pi*i, pii, πi" + "answer": ["pi*i", "pii", "πi"] }, { "id": 218, @@ -397,7 +397,7 @@ { "id": 221, "question": "Prime numbers only have __ factors.", - "answer": "2, two" + "answer": ["2", "two"] }, { "id": 222, @@ -408,7 +408,7 @@ "id": 223, "question": "In statistics, what does this formula represent?", "img_url": "https://www.statisticshowto.com/wp-content/uploads/2013/11/sample-standard-deviation.jpg", - "answer": "sample standard deviation, standard deviation of a sample" + "answer": ["sample standard deviation", "standard deviation of a sample"] }, { "id": 224, @@ -418,7 +418,7 @@ { "id": 225, "question": "A matrix multiplied by its inverse matrix equals...", - "answer": "the identity matrix, identity matrix" + "answer": ["the identity matrix", "identity matrix"] }, { "id": 226, @@ -429,19 +429,19 @@ { "id": 227, "question": "What is the only number in the entire number system which can be spelled with the same number of letters as itself?", - "answer": "4, four" + "answer": ["4", "four"] }, { "id": 228, "question": "1/100th of a second is also termed as what?", - "answer": "a jiffy, jiffy, centisecond" + "answer": ["a jiffy", "jiffy", "centisecond"] }, { "id": 229, "question": "What is this triangle called?", "img_url": "https://cdn.askpython.com/wp-content/uploads/2020/07/Pascals-triangle.png", - "answer": "Pascal's triangle, Pascal" + "answer": ["Pascal's triangle", "Pascal"] }, { "id": 230, @@ -468,17 +468,17 @@ { "id": 304, "question": "What do you call an organism composed of only one cell?", - "answer": "unicellular, single-celled" + "answer": ["unicellular", "single-celled"] }, { "id": 305, "question": "The Heisenberg's Uncertainty Principle states that the position and \\_\\_\\_\\_\\_\\_\\_\\_ of a quantum object can't be both exactly measured at the same time.", - "answer": "velocity, momentum" + "answer": ["velocity", "momentum"] }, { "id": 306, "question": "A \\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_ reaction is the one wherein an atom or a set of atoms is/are replaced by another atom or a set of atoms", - "answer": "displacement, exchange" + "answer": ["displacement", "exchange"] }, { "id": 307, @@ -512,7 +512,7 @@ { "id": 312, "question": "What is the intermolecular force caused by temporary and induced dipoles?", - "answer": "LDF, London dispersion, London dispersion force" + "answer": ["LDF", "London dispersion", "London dispersion force"] }, { "id": 313, @@ -522,7 +522,7 @@ { "id": 314, "question": "About how many neurons are in the human brain?\n(A. 1 billion, B. 10 billion, C. 100 billion, D. 300 billion)", - "answer": "C, 100 billion, 100 bil" + "answer": ["C", "100 billion", "100 bil"] }, { "id": 315, @@ -537,12 +537,12 @@ { "id": 317, "question": "Which vascular tissue transports water and minerals from the roots to the rest of a plant?", - "answer": "the xylem, xylem" + "answer": ["the xylem", "xylem"] }, { "id": 318, "question": "Who discovered the theories of relativity?", - "answer": "Albert Einstein, Einstein" + "answer": ["Albert Einstein", "Einstein"] }, { "id": 319, @@ -557,7 +557,7 @@ { "id": 321, "question": "What range of frequency are the average human ears capable of hearing?\n(A. 10Hz-10kHz, B. 20Hz-20kHz, C. 20Hz-2000Hz, D. 10kHz-20kHz)", - "answer": "B, 20Hz-20kHz" + "answer": ["B", "20Hz-20kHz"] }, { "id": 322, @@ -572,7 +572,7 @@ { "id": 324, "question": "The type of rock that is formed by the accumulation or deposition of mineral or organic particles at the Earth's surface, followed by cementation, is called...", - "answer": "sedimentary, sedimentary rock" + "answer": ["sedimentary", "sedimentary rock"] }, { "id": 325, @@ -582,7 +582,7 @@ { "id": 326, "question": "What type of image is formed by a convex mirror?", - "answer": "virtual image, virtual" + "answer": ["virtual image", "virtual"] }, { "id": 327, @@ -592,17 +592,17 @@ { "id": 328, "question": "Which law states that the global entropy in a closed system can only increase?", - "answer": "second law, second law of thermodynamics" + "answer": ["second law", "second law of thermodynamics"] }, { "id": 329, "question": "Which particle is emitted during the beta decay of a radioactive element?", - "answer": "an electron, the electron, electron" + "answer": ["an electron", "the electron", "electron"] }, { "id": 330, "question": "When DNA is unzipped, two strands are formed. What are they called (separate both answers by the word \"and\")?", - "answer": "leading and lagging, leading strand and lagging strand" + "answer": ["leading and lagging", "leading strand and lagging strand"] } ], "cs": [ @@ -619,7 +619,7 @@ { "id": 403, "question": "What does SASS stand for?", - "answer": "Syntactically Awesome Stylesheets, Syntactically Awesome Style Sheets" + "answer": ["Syntactically Awesome Stylesheets", "Syntactically Awesome Style Sheets"] }, { "id": 404, @@ -629,7 +629,7 @@ { "id": 405, "question": "What is computing capable of performing exaFLOPS called?", - "answer": "exascale computing, exascale" + "answer": ["exascale computing", "exascale"] }, { "id": 406, @@ -654,7 +654,7 @@ { "id": 410, "question": "A hypothetical point in time at which technological growth becomes uncontrollable and irreversible, resulting in unforeseeable changes to human civilization is termed as...?", - "answer": "technological singularity, singularity" + "answer": ["technological singularity", "singularity"] }, { "id": 411, @@ -664,12 +664,12 @@ { "id": 412, "question": "How many bits are in a TCP checksum header?", - "answer": "16, sixteen" + "answer": ["16", "sixteen"] }, { "id": 413, "question": "What is the most popular protocol (as of 2021) that handles communication between email servers?", - "answer": "SMTP, Simple Mail Transfer Protocol" + "answer": ["SMTP", "Simple Mail Transfer Protocol"] }, { "id": 414, @@ -679,12 +679,12 @@ { "id": 415, "question": "Which DNS record contains mail servers of a given domain?", - "answer": "MX, mail exchange" + "answer": ["MX", "mail exchange"] }, { "id": 416, "question": "Which newline sequence does HTTP use?", - "answer": "carriage return line feed, CRLF, \\r\\n" + "answer": ["carriage return line feed", "CRLF", "\\r\\n"] }, { "id": 417, @@ -694,7 +694,7 @@ { "id": 418, "question": "Name a universal logic gate.", - "answer": "NAND, NOR" + "answer": ["NAND", "NOR"] }, { "id": 419, @@ -729,7 +729,7 @@ { "id": 425, "question": "What does the \"a\" represent in a HSLA color value?", - "answer": "transparency, translucency, alpha value, alpha channel, alpha" + "answer": ["transparency", "translucency", "alpha value", "alpha channel", "alpha"] }, { "id": 426, @@ -749,7 +749,7 @@ { "id": 429, "question": "Which of these sorting algorithms is not stable?\n(Counting sort, quick sort, insertion sort, tim sort, bubble sort)", - "answer": "quick, quick sort" + "answer": ["quick", "quick sort"] }, { "id": 430, @@ -761,7 +761,7 @@ { "id": 501, "question": "Is everything an instance of the `object` class (y/n)?", - "answer": "y, yes" + "answer": ["y", "yes"] }, { "id": 502, @@ -781,7 +781,7 @@ { "id": 505, "question": "Can you pickle a running `list_iterator` (y/n)?", - "answer": "y, yes" + "answer": ["y", "yes"] }, { "id": 506, @@ -821,12 +821,12 @@ { "id": 513, "question": "Where does the name Python come from?", - "answer": "Monty Python, Monty Python's Flying Circus" + "answer": ["Monty Python", "Monty Python's Flying Circus"] }, { "id": 514, "question": "How is infinity represented in Python?", - "answer": "float(\"infinity\"), float('infinity'), float(\"inf\"), float('inf')" + "answer": ["float(\"infinity\")", "float('infinity')", "float(\"inf\")", "float('inf')"] }, { "id": 515, @@ -846,12 +846,12 @@ { "id": 518, "question": "What decorator is used to allow a protocol to be checked at runtime?", - "answer": "runtime_checkable, typing.runtime_checkable" + "answer": ["runtime_checkable", "typing.runtime_checkable"] }, { "id": 519, "question": "Does `numbers.Rational` include the builtin object float (y/n)", - "answer": "n, no" + "answer": ["n", "no"] }, { "id": 520, @@ -866,7 +866,7 @@ { "id": 522, "question": "What is the garbage collection strategy used by cpython to collect everything but reference cycles?", - "answer": "reference counting, refcounting" + "answer": ["reference counting", "refcounting"] }, { "id": 523, @@ -891,12 +891,12 @@ { "id": 527, "question": "Is the `__aiter__` method async (y/n)?", - "answer": "n, no" + "answer": ["n", "no"] }, { "id": 528, "question": "How does one call a class who defines the behavior of their instance classes?", - "answer": "a metaclass, metaclass" + "answer": ["a metaclass", "metaclass"] }, { "id": 529, -- cgit v1.2.3 From 52e82e69b18ea0f305f970f776afb75b284c7453 Mon Sep 17 00:00:00 2001 From: NIRDERIi <78727420+NIRDERIi@users.noreply.github.com> Date: Wed, 8 Sep 2021 17:47:20 +0300 Subject: Added Hanukka command in November month. This is a solution for the #862 issue, which says the Hanukka holiday can also be in November and not only in December. --- bot/exts/holidays/hanukkah/hanukkah_embed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/holidays/hanukkah/hanukkah_embed.py b/bot/exts/holidays/hanukkah/hanukkah_embed.py index 00125be3..ac3eab7b 100644 --- a/bot/exts/holidays/hanukkah/hanukkah_embed.py +++ b/bot/exts/holidays/hanukkah/hanukkah_embed.py @@ -37,7 +37,7 @@ class HanukkahEmbed(commands.Cog): hanukkah_dates.append(date) return hanukkah_dates - @in_month(Month.DECEMBER) + @in_month(Month.NOVEMBER, Month.DECEMBER) @commands.command(name="hanukkah", aliases=("chanukah",)) async def hanukkah_festival(self, ctx: commands.Context) -> None: """Tells you about the Hanukkah Festivaltime of festival, festival day, etc).""" -- cgit v1.2.3 From 3f105042ae516b74fcaeca80c79d8f3894e43fb8 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Mon, 13 Sep 2021 18:22:26 -0500 Subject: added .gitpod.yml --- .gitpod.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..6ae59c4e --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,7 @@ +tasks: + - name: Initialize Poetry Environment + before: pyenv install 3.9.6 && pyenv global 3.9.6 + env: + PIP_USER: false + init: pip install poetry + command: poetry install && poetry run pre-commit install -- cgit v1.2.3 From e0d04101c772d54d302392e5d8a641be8d1c1199 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 14 Sep 2021 13:17:30 -0500 Subject: Update .gitpod.yml Co-authored-by: Bluenix --- .gitpod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index 6ae59c4e..3925d8f3 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,5 +1,5 @@ tasks: - - name: Initialize Poetry Environment + - name: Python Environment before: pyenv install 3.9.6 && pyenv global 3.9.6 env: PIP_USER: false -- cgit v1.2.3 From 57daa223af5503f30d86052cce35cb14bb0264be Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 14 Sep 2021 17:18:55 -0500 Subject: chore: added vscode extensions to .gitpod.yml --- .gitpod.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitpod.yml b/.gitpod.yml index 3925d8f3..138bb8bd 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -5,3 +5,8 @@ tasks: PIP_USER: false init: pip install poetry command: poetry install && poetry run pre-commit install + +vscode: + extensions: + - ms-python.vscode-pylance + - ms-python.python -- cgit v1.2.3 From eca8bcebf7c47de7fa661009df583fe79b95334e Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 14 Sep 2021 17:24:29 -0500 Subject: test --- .gitpod.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index 138bb8bd..3925d8f3 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -5,8 +5,3 @@ tasks: PIP_USER: false init: pip install poetry command: poetry install && poetry run pre-commit install - -vscode: - extensions: - - ms-python.vscode-pylance - - ms-python.python -- cgit v1.2.3 From 7b54e96edf3b74e407371a4f4df64c5038106633 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 15 Sep 2021 08:03:28 -0500 Subject: added double quotes to fix strings --- .gitpod.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index 3925d8f3..fcc425c5 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,7 +1,7 @@ tasks: - - name: Python Environment - before: pyenv install 3.9.6 && pyenv global 3.9.6 + - name: "Python Environment" + before: "pyenv install 3.9.6 && pyenv global 3.9.6" env: - PIP_USER: false - init: pip install poetry - command: poetry install && poetry run pre-commit install + PIP_USER: "false" + init: "pip install poetry" + command: "poetry install && poetry run pre-commit install" -- cgit v1.2.3 From 285993bc1cb5e4a1461e1c704b130d2a4e01a474 Mon Sep 17 00:00:00 2001 From: Kronifer Date: Wed, 15 Sep 2021 13:15:20 +0000 Subject: added vscode extensions --- .gitpod.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index fcc425c5..0c07be67 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,7 +1,9 @@ tasks: - name: "Python Environment" before: "pyenv install 3.9.6 && pyenv global 3.9.6" - env: - PIP_USER: "false" - init: "pip install poetry" + init: "pip install poetry && export PIP_USER=false" command: "poetry install && poetry run pre-commit install" + +vscode: + extensions: + - "ms-python.python" \ No newline at end of file -- cgit v1.2.3 From 7c08af2655c07d0d13b247905eb23acbbd42e976 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 15 Sep 2021 19:52:40 -0500 Subject: chore: small quotation change --- .gitpod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index 0c07be67..ca1b5456 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -6,4 +6,4 @@ tasks: vscode: extensions: - - "ms-python.python" \ No newline at end of file + - ms-python.python -- cgit v1.2.3 From 3d67a305dd5f7a572aa71648c0c1b8b710304bbd Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 15 Sep 2021 19:54:44 -0500 Subject: removed vscode.extensions due to errors --- .gitpod.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index ca1b5456..a10e6e26 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -3,7 +3,3 @@ tasks: before: "pyenv install 3.9.6 && pyenv global 3.9.6" init: "pip install poetry && export PIP_USER=false" command: "poetry install && poetry run pre-commit install" - -vscode: - extensions: - - ms-python.python -- cgit v1.2.3 From 874326c4bb05ad36224e388d134691c55cd2141a Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:45:36 -0400 Subject: Hangman (#843) * beginning commit creating the base of the hangman, code needs to be linted in the future * updated words list * adding images to show the hangman person * added images, though it is a bit laggy * replacing images with discord attachment urls * adding error if filters aren't found * fixing typo in ``filter_not_found_embed`` * final lints + removing `mode` parameter as it renders useless * linting flake8 errors * adding newline at the end of `top_1000_used_words.txt` * minor change to filter message * improving hangman docstring * removing `bot/resources/evergreen/hangman` directory as file attachments are used * replacing single quotes with double quotes, to adhere to the style guide. * fixing style inconsistencies and other problems with how the code looks - as per requested by Objectivix * fixing `IMAGES` style inconsistency * adding trailing commas and switching to `Colours` for consistency * adding trailing commas and switching to `Colours` for consistency * fixing the remnants of non-trailing commas and allowing specification for single player vs mulitplayer * removing all 2 letter words from the hangman word choosing and removing words that @Objectivix found that shouldn't be in the list of words * removing some inappropriate words from the txt file * Adding space for grammatical errors Co-authored-by: ChrisJL * changing two periods to a full stop & wrapping try and except block to only the part that can raise it * using negative replies instead along with fixing grammatical errors in the sentence * removing words that could be considered inappropirate * removing `TOP_WORDS_FILE_PATH` and making `ALL_WORDS` a global variable. * more specific docstring * more specific docstring * Removing more words The words removed shouldn't really belong here * replacing mapping_of_images with IMAGES and other fixes * Dedenting Co-authored-by: Bluenix * Improving tries logic Co-authored-by: Bluenix * Updating `positions` list to set Co-authored-by: Bluenix * fixing too many blank lines * Hardcode dictionary Co-authored-by: Bluenix * remove 3 letter words * add the word python * remove all 3 letter words - forgot to remove some * case insensitivity * changes to improve gameplay * setting check outside of every iteration * checking if a letter has already been guessed * changing to transparent images without the shadows * consistency with timeout * capitalization / edits to the hangman_words.txt * changing `singleplayer` to a boolean * sending then deleting, along with encouraging to try again * Grammar Co-authored-by: Bluenix * Grammatical error Co-authored-by: Bluenix * Simplification Co-authored-by: ChrisJL * changing from pathlib to open * python-related words * two more python-related words * making error embeds more clear * Update hangman_words.txt deleted a possibly inappropriate word and added 3 new python related words * Update hangman.py Added some more comments and made some line spacing changes before and after the docstring * adding a new word * Adding newline * updating comments * when the game has won, it will display the word * add helper function to abstract some code, and edit the message at the end when won with the original word * editing message for win screen for consistency * prettifying the user guess * sending win and losing embed separately * Clarify 'tries remaining' Co-authored-by: ChrisJL * changing to `delete_after` * not editing `message.content` variable * fixing error; changing to len(normalized_content) * Update hangman.py Reworded the comment about the timeout a little * last nitpicks for grammatical errors in comments * adding suggestions from ToxicKidz * Improving comments/removing unnecessary ones Co-authored-by: Bluenix * Renaming parameter from `singleplayer` to `mode` Co-authored-by: Bluenix Co-authored-by: ChrisJL Co-authored-by: Bluenix Co-authored-by: DMFriends --- bot/exts/fun/hangman.py | 194 ++++++++ bot/resources/fun/hangman_words.txt | 877 ++++++++++++++++++++++++++++++++++++ 2 files changed, 1071 insertions(+) create mode 100644 bot/exts/fun/hangman.py create mode 100644 bot/resources/fun/hangman_words.txt diff --git a/bot/exts/fun/hangman.py b/bot/exts/fun/hangman.py new file mode 100644 index 00000000..08883103 --- /dev/null +++ b/bot/exts/fun/hangman.py @@ -0,0 +1,194 @@ +from asyncio import TimeoutError +from pathlib import Path +from random import choice +from typing import Literal + +from discord import Embed, Message +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours, NEGATIVE_REPLIES + +# Defining all words in the list of words as a global variable +ALL_WORDS = Path("bot/resources/fun/hangman_words.txt").read_text().splitlines() + +# Defining a dictionary of images that will be used for the game to represent the hangman person +IMAGES = { + 6: "https://cdn.discordapp.com/attachments/859123972884922418/888133201497837598/hangman0.png", + 5: "https://cdn.discordapp.com/attachments/859123972884922418/888133595259084800/hangman1.png", + 4: "https://cdn.discordapp.com/attachments/859123972884922418/888134194474139688/hangman2.png", + 3: "https://cdn.discordapp.com/attachments/859123972884922418/888133758069395466/hangman3.png", + 2: "https://cdn.discordapp.com/attachments/859123972884922418/888133786724859924/hangman4.png", + 1: "https://cdn.discordapp.com/attachments/859123972884922418/888133828831477791/hangman5.png", + 0: "https://cdn.discordapp.com/attachments/859123972884922418/888133845449338910/hangman6.png", +} + + +class Hangman(commands.Cog): + """ + Cog for the Hangman game. + + Hangman is a classic game where the user tries to guess a word, with a limited amount of tries. + """ + + def __init__(self, bot: Bot): + self.bot = bot + + @staticmethod + def create_embed(tries: int, user_guess: str) -> Embed: + """ + Helper method that creates the embed where the game information is shown. + + This includes how many letters the user has guessed so far, and the hangman photo itself. + """ + hangman_embed = Embed( + title="Hangman", + color=Colours.python_blue, + ) + hangman_embed.set_image(url=IMAGES[tries]) + hangman_embed.add_field( + name=f"You've guessed `{user_guess}` so far.", + value="Guess the word by sending a message with a letter!" + ) + hangman_embed.set_footer(text=f"Tries remaining: {tries}") + return hangman_embed + + @commands.command() + async def hangman( + self, + ctx: commands.Context, + min_length: int = 0, + max_length: int = 25, + min_unique_letters: int = 0, + max_unique_letters: int = 25, + mode: Literal["s", "m", "S", "M"] = "s", + ) -> None: + """ + Play hangman against the bot, where you have to guess the word it has provided! + + The arguments for this command mean: + - min_length: the minimum length you want the word to be (i.e. 2) + - max_length: the maximum length you want the word to be (i.e. 5) + - min_unique_letters: the minimum unique letters you want the word to have (i.e. 4) + - max_unique_letters: the maximum unique letters you want the word to have (i.e. 7) + - mode: writing 's' means you want to play by yourself, and only you can suggest letters, + - writing 'm' means you want multiple players to join in and guess the word. + """ + # Changing singleplayer to a boolean + singleplayer = mode.lower() == 's' + + # Filtering the list of all words depending on the configuration + filtered_words = [ + word for word in ALL_WORDS + if min_length < len(word) < max_length + and min_unique_letters < len(set(word)) < max_unique_letters + ] + + if not filtered_words: + filter_not_found_embed = Embed( + title=choice(NEGATIVE_REPLIES), + description="No words could be found that fit all filters specified.", + color=Colours.soft_red, + ) + await ctx.send(embed=filter_not_found_embed) + return + + word = choice(filtered_words) + # `pretty_word` is used for comparing the indices where the guess of the user is similar to the word + # The `user_guess` variable is prettified by adding spaces between every dash, and so is the `pretty_word` + pretty_word = ''.join([f"{letter} " for letter in word])[:-1] + user_guess = ("_ " * len(word))[:-1] + tries = 6 + guessed_letters = set() + + # Checking if the game is singleplayer + def check(msg: Message) -> bool: + if singleplayer: + return msg.author == ctx.author + else: + # Multiplayer mode + return not msg.author.bot + + original_message = await ctx.send(embed=Embed( + title="Hangman", + description="Loading game...", + color=Colours.soft_green + )) + + # Game loop + while user_guess.replace(' ', '') != word: + # Edit the message to the current state of the game + await original_message.edit(embed=self.create_embed(tries, user_guess)) + + try: + message = await self.bot.wait_for( + event="message", + timeout=60.0, + check=check + ) + except TimeoutError: + timeout_embed = Embed( + title=choice(NEGATIVE_REPLIES), + description="Looks like the bot timed out! You must send a letter within 60 seconds.", + color=Colours.soft_red, + ) + await original_message.edit(embed=timeout_embed) + return + + # If the user enters a capital letter as their guess, it is automatically converted to a lowercase letter + normalized_content = message.content.lower() + # The user should only guess one letter per message + if len(normalized_content) > 1: + letter_embed = Embed( + title=choice(NEGATIVE_REPLIES), + description="You can only send one letter at a time, try again!", + color=Colours.dark_green, + ) + await ctx.send(embed=letter_embed, delete_after=4) + continue + + # Checks for repeated guesses + elif normalized_content in guessed_letters: + already_guessed_embed = Embed( + title=choice(NEGATIVE_REPLIES), + description=f"You have already guessed `{normalized_content}`, try again!", + color=Colours.dark_green, + ) + await ctx.send(embed=already_guessed_embed, delete_after=4) + continue + + # Checks for correct guesses from the user + elif normalized_content in word: + positions = {idx for idx, letter in enumerate(pretty_word) if letter == normalized_content} + user_guess = "".join( + [normalized_content if index in positions else dash for index, dash in enumerate(user_guess)] + ) + + else: + tries -= 1 + + if tries <= 0: + losing_embed = Embed( + title="You lost.", + description=f"The word was `{word}`.", + color=Colours.soft_red, + ) + await original_message.edit(embed=self.create_embed(tries, user_guess)) + await ctx.send(embed=losing_embed) + return + + guessed_letters.add(normalized_content) + + # The loop exited meaning that the user has guessed the word + await original_message.edit(embed=self.create_embed(tries, user_guess)) + win_embed = Embed( + title="You won!", + description=f"The word was `{word}`.", + color=Colours.grass_green + ) + await ctx.send(embed=win_embed) + + +def setup(bot: Bot) -> None: + """Load the Hangman cog.""" + bot.add_cog(Hangman(bot)) diff --git a/bot/resources/fun/hangman_words.txt b/bot/resources/fun/hangman_words.txt new file mode 100644 index 00000000..5e20bfde --- /dev/null +++ b/bot/resources/fun/hangman_words.txt @@ -0,0 +1,877 @@ +abandon +ability +able +about +above +accept +according +account +across +action +activity +actually +address +administration +admit +adult +affect +after +again +against +agency +agent +agree +agreement +ahead +allow +almost +alone +along +already +also +although +always +among +amount +analysis +animal +another +answer +anyone +anything +appear +apply +approach +area +argue +around +arrive +article +artist +assume +attack +attention +attorney +audience +author +authority +available +avoid +away +baby +back +ball +bank +base +beat +beautiful +because +become +before +begin +behavior +behind +believe +benefit +best +better +between +beyond +bill +billion +black +blood +blue +board +body +book +born +both +break +bring +brother +budget +build +building +business +bytecode +call +camera +campaign +cancer +candidate +capital +card +care +career +carry +case +catch +cause +cell +center +central +century +certain +certainly +chair +challenge +chance +change +character +charge +check +child +choice +choose +church +citizen +city +civil +claim +class +clear +clearly +close +coach +cold +collection +college +color +come +commercial +common +community +company +compare +computer +concern +condition +conference +consider +consumer +contain +continue +control +cost +could +country +couple +course +court +cover +create +crime +cultural +culture +current +customer +dark +data +daughter +dead +deal +death +debate +decade +decide +decision +deep +defense +degree +describe +design +despite +detail +determine +develop +development +dictionary +difference +different +difficult +dinner +direction +director +discover +discuss +discussion +disease +doctor +door +down +draw +dream +drive +drop +during +each +early +east +easy +economic +economy +edge +education +effect +effort +eight +either +election +else +employee +energy +enjoy +enough +enter +entire +environment +environmental +especially +establish +even +evening +event +ever +every +everybody +everyone +everything +evidence +exactly +example +executive +exist +expect +experience +expert +explain +face +fact +factor +fall +false +family +fast +father +fear +federal +feel +feeling +field +fight +figure +fill +film +final +finally +financial +find +fine +finger +finish +fire +firm +first +fish +five +floor +focus +follow +food +foot +force +foreign +forget +form +former +forward +four +free +friend +from +front +full +function +fund +future +game +garden +general +generation +girl +give +glass +goal +good +government +great +green +ground +group +grow +growth +guess +guido +hair +half +hand +hang +happen +happy +hard +have +head +health +hear +heart +heat +heavy +help +here +herself +high +himself +history +hold +home +hope +hospital +hotel +hour +house +however +huge +human +hundred +husband +idea +identify +image +imagine +impact +import +important +improve +include +including +increase +indeed +indicate +individual +industry +information +inside +instead +institution +interest +interesting +international +interpreter +interview +into +investment +involve +issue +item +itself +join +just +keep +kill +kind +kitchen +know +knowledge +land +lambda +language +large +last +late +later +laugh +lawyer +lead +leader +learn +least +leave +left +legal +less +letter +level +life +light +like +likely +line +list +listen +little +live +local +long +look +loop +lose +loss +love +machine +magazine +main +maintain +major +majority +make +manage +management +manager +many +market +marriage +material +matter +maybe +mean +measure +media +medical +meet +meeting +member +memory +mention +message +method +middle +might +military +million +mind +minute +miss +mission +model +modern +moment +money +month +more +morning +most +mother +mouth +move +movement +movie +much +music +must +myself +name +nation +national +natural +nature +near +nearly +necessary +need +network +never +news +newspaper +next +nice +nightnone +north +note +nothing +notice +number +object +occur +offer +office +officer +official +often +once +only +onto +open +operation +opportunity +option +order +organization +other +others +outside +over +owner +page +pain +painting +paper +parameters +parent +part +participant +particular +particularly +partner +party +pass +past +patient +pattern +peace +people +perform +performance +perhaps +period +person +personal +phone +physical +pick +picture +piece +place +plan +plant +play +player +point +police +policy +political +politics +poor +popular +population +position +positive +possible +power +practice +prepare +present +president +pressure +pretty +prevent +price +print +private +probably +problem +process +produce +product +production +professional +professor +program +project +property +protect +prove +provide +public +pull +purpose +push +pydis +pygame +python +quality +question +quickly +quite +race +radio +raise +range +rate +rather +reach +read +ready +real +reality +realize +really +reason +receive +recent +recently +recognize +record +reduce +reflect +region +relate +relationship +remain +remember +remove +report +represent +require +research +resource +respond +response +responsibility +rest +result +return +reveal +rich +right +rise +risk +road +rock +role +room +rule +safe +same +save +scene +school +science +scientist +score +season +seat +second +section +security +seek +seem +sell +send +senior +sense +series +serious +serve +service +seven +several +shake +share +shoot +short +shot +should +shoulder +show +side +sign +significant +similar +simple +simply +since +sing +single +sister +site +situation +size +skill +skin +small +smile +social +society +soldier +some +somebody +someone +something +sometimes +song +soon +sort +sound +source +south +southern +space +speak +special +specific +speech +spend +sport +spring +staff +stage +stand +standard +star +start +state +statement +station +stay +step +still +stock +stop +store +story +strategy +street +strong +structure +student +study +stuff +style +subject +success +successful +such +suddenly +suffer +suggest +summer +support +sure +surface +system +table +take +talk +task +teach +teacher +team +technology +television +tell +tend +term +test +than +thank +that +their +them +themselves +then +theory +there +these +they +thing +think +third +this +those +though +thought +thousand +threat +three +through +throughout +throw +thus +time +today +together +tonight +total +tough +toward +town +trade +traditional +training +travel +treat +treatment +tree +trial +trip +trouble +true +truth +turn +type +under +understand +unit +until +upon +usually +value +variable +various +very +victim +view +visit +voice +vote +wait +walk +wall +want +watch +water +wear +week +weight +well +west +western +what +whatever +when +where +whether +which +while +white +whole +whom +whose +wide +wife +will +wind +window +wish +with +within +without +woman +wonder +word +work +worker +world +worry +would +write +writer +wrong +yard +yield +yeah +year +young +your +yourself -- cgit v1.2.3 From 1f5970134d710358f716c35d8d7e33b6f76f48d3 Mon Sep 17 00:00:00 2001 From: Bluenix Date: Sun, 19 Sep 2021 15:27:48 +0200 Subject: Remove multiplayer mode and correctly check current channel Closes #871 With multiplayer and a missing check for the right channel the bot would respond to each message as one directed to the game. Multiplayer mode is planned to be reintroduced later on using threads. --- bot/exts/fun/hangman.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/bot/exts/fun/hangman.py b/bot/exts/fun/hangman.py index 08883103..db95ba5c 100644 --- a/bot/exts/fun/hangman.py +++ b/bot/exts/fun/hangman.py @@ -1,7 +1,6 @@ from asyncio import TimeoutError from pathlib import Path from random import choice -from typing import Literal from discord import Embed, Message from discord.ext import commands @@ -61,7 +60,6 @@ class Hangman(commands.Cog): max_length: int = 25, min_unique_letters: int = 0, max_unique_letters: int = 25, - mode: Literal["s", "m", "S", "M"] = "s", ) -> None: """ Play hangman against the bot, where you have to guess the word it has provided! @@ -71,12 +69,7 @@ class Hangman(commands.Cog): - max_length: the maximum length you want the word to be (i.e. 5) - min_unique_letters: the minimum unique letters you want the word to have (i.e. 4) - max_unique_letters: the maximum unique letters you want the word to have (i.e. 7) - - mode: writing 's' means you want to play by yourself, and only you can suggest letters, - - writing 'm' means you want multiple players to join in and guess the word. """ - # Changing singleplayer to a boolean - singleplayer = mode.lower() == 's' - # Filtering the list of all words depending on the configuration filtered_words = [ word for word in ALL_WORDS @@ -103,11 +96,7 @@ class Hangman(commands.Cog): # Checking if the game is singleplayer def check(msg: Message) -> bool: - if singleplayer: - return msg.author == ctx.author - else: - # Multiplayer mode - return not msg.author.bot + return msg.author == ctx.author and msg.channel == ctx.channel original_message = await ctx.send(embed=Embed( title="Hangman", -- cgit v1.2.3 From 1a981e127a5ad87382c846851c0930226405fcda Mon Sep 17 00:00:00 2001 From: Bluenix Date: Sun, 19 Sep 2021 18:46:51 +0200 Subject: Remove false comment --- bot/exts/fun/hangman.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/exts/fun/hangman.py b/bot/exts/fun/hangman.py index db95ba5c..a2c8c735 100644 --- a/bot/exts/fun/hangman.py +++ b/bot/exts/fun/hangman.py @@ -94,7 +94,6 @@ class Hangman(commands.Cog): tries = 6 guessed_letters = set() - # Checking if the game is singleplayer def check(msg: Message) -> bool: return msg.author == ctx.author and msg.channel == ctx.channel -- cgit v1.2.3 From 0b59a5e8d110e1aa7e5d76addcf6a92ee5f89ace Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Mon, 20 Sep 2021 17:20:27 +0200 Subject: Emoji: make the datetimes offset-naive You know the drill, due to discord.py 2.0a0 datetimes are now offset-aware, breaking some code. Closes python-discord/sir-lancebot#875 --- bot/exts/utilities/emoji.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/emoji.py b/bot/exts/utilities/emoji.py index 55d6b8e9..83df39cc 100644 --- a/bot/exts/utilities/emoji.py +++ b/bot/exts/utilities/emoji.py @@ -107,8 +107,8 @@ class Emojis(commands.Cog): title=f"Emoji Information: {emoji.name}", description=textwrap.dedent(f""" **Name:** {emoji.name} - **Created:** {time_since(emoji.created_at, precision="hours")} - **Date:** {datetime.strftime(emoji.created_at, "%d/%m/%Y")} + **Created:** {time_since(emoji.created_at.replace(tzinfo=None), precision="hours")} + **Date:** {datetime.strftime(emoji.created_at.replace(tzinfo=None), "%d/%m/%Y")} **ID:** {emoji.id} """), color=Color.blurple(), -- cgit v1.2.3 From 24e099e8247e51f91d96294f147c6e024bd1db69 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Tue, 21 Sep 2021 09:21:33 +0200 Subject: Hacktoberfest: make datetimes offset-naive --- bot/exts/events/hacktoberfest/hacktober-issue-finder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py index e3053851..0cbb6df4 100644 --- a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py +++ b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py @@ -52,10 +52,10 @@ class HacktoberIssues(commands.Cog): async def get_issues(self, ctx: commands.Context, option: str) -> Optional[dict]: """Get a list of the python issues with the label 'hacktoberfest' from the Github api.""" if option == "beginner": - if (ctx.message.created_at - self.cache_timer_beginner).seconds <= 60: + if (ctx.message.created_at.replace(tzinfo=None) - self.cache_timer_beginner).seconds <= 60: log.debug("using cache") return self.cache_beginner - elif (ctx.message.created_at - self.cache_timer_normal).seconds <= 60: + elif (ctx.message.created_at.replace(tzinfo=None) - self.cache_timer_normal).seconds <= 60: log.debug("using cache") return self.cache_normal -- cgit v1.2.3 From 6e7e65d12392bfa44a13d82fa90631482d9eb653 Mon Sep 17 00:00:00 2001 From: aru Date: Tue, 21 Sep 2021 16:51:27 -0400 Subject: properly blacklist the extensions cog since the restructure of lancebot, this code was incorrect, and is no longer blacklisting itself. --- bot/exts/core/extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/core/extensions.py b/bot/exts/core/extensions.py index 424bacac..dbb9e069 100644 --- a/bot/exts/core/extensions.py +++ b/bot/exts/core/extensions.py @@ -18,7 +18,7 @@ from bot.utils.pagination import LinePaginator log = logging.getLogger(__name__) -UNLOAD_BLACKLIST = {f"{exts.__name__}.utils.extensions"} +UNLOAD_BLACKLIST = {f"{exts.__name__}.core.extensions"} BASE_PATH_LEN = len(exts.__name__.split(".")) -- cgit v1.2.3 From c893e86b61e5309d4bd6a03259f6e87fa76d4f39 Mon Sep 17 00:00:00 2001 From: PythonTryHard <31789326+PythonTryHard@users.noreply.github.com> Date: Fri, 24 Sep 2021 20:40:45 +0700 Subject: Bisect only on love percent thresholds --- bot/exts/holidays/valentines/lovecalculator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bot/exts/holidays/valentines/lovecalculator.py b/bot/exts/holidays/valentines/lovecalculator.py index 3999db2b..3ef9c3e1 100644 --- a/bot/exts/holidays/valentines/lovecalculator.py +++ b/bot/exts/holidays/valentines/lovecalculator.py @@ -74,7 +74,8 @@ class LoveCalculator(Cog): # We need the -1 due to how bisect returns the point # see the documentation for further detail # https://docs.python.org/3/library/bisect.html#bisect.bisect - index = bisect.bisect(LOVE_DATA, (love_percent,)) - 1 + love_threshold = [threshold for threshold, _ in LOVE_DATA] + index = bisect.bisect(love_threshold, love_percent) - 1 # We already have the nearest "fit" love level # We only need the dict, so we can ditch the first element _, data = LOVE_DATA[index] -- cgit v1.2.3 From 4590c42f8398787902881ef51396142c32366088 Mon Sep 17 00:00:00 2001 From: PythonTryHard <31789326+PythonTryHard@users.noreply.github.com> Date: Fri, 24 Sep 2021 20:47:46 +0700 Subject: Remove trailing whitespace --- bot/exts/holidays/valentines/lovecalculator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/holidays/valentines/lovecalculator.py b/bot/exts/holidays/valentines/lovecalculator.py index 3ef9c3e1..a53014e5 100644 --- a/bot/exts/holidays/valentines/lovecalculator.py +++ b/bot/exts/holidays/valentines/lovecalculator.py @@ -74,7 +74,7 @@ class LoveCalculator(Cog): # We need the -1 due to how bisect returns the point # see the documentation for further detail # https://docs.python.org/3/library/bisect.html#bisect.bisect - love_threshold = [threshold for threshold, _ in LOVE_DATA] + love_threshold = [threshold for threshold, _ in LOVE_DATA] index = bisect.bisect(love_threshold, love_percent) - 1 # We already have the nearest "fit" love level # We only need the dict, so we can ditch the first element -- cgit v1.2.3 From e5111789e553b4c9c1763fc791c875fce57c6fef Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Fri, 24 Sep 2021 13:37:57 -0500 Subject: chore: added an open in gitpod badge to the README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dd8301dc..dcdaf1c4 100755 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Lint Badge][1]][2] [![Build Badge][3]][4] [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE) +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#/python-discord/sir-lancebot) ![Header](sir-lancebot-logo.png) -- cgit v1.2.3 From 84841f3108c9eb8d731dff5fb17705f1064a5464 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Fri, 24 Sep 2021 13:39:58 -0500 Subject: chore: changed gitpod button --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcdaf1c4..ed1ff235 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Lint Badge][1]][2] [![Build Badge][3]][4] [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE) -[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#/python-discord/sir-lancebot) +[![Open in Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-908a85?logo=gitpod)](https://gitpod.io/#/python-discord/sir-lancebot) ![Header](sir-lancebot-logo.png) -- cgit v1.2.3 From 4d9ec6c3f8f0212cb45bfa1e7d8b6667dcbf5f4f Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Fri, 24 Sep 2021 13:52:06 -0500 Subject: chore: fixed the link in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed1ff235..2e2b7aec 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Lint Badge][1]][2] [![Build Badge][3]][4] [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE) -[![Open in Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-908a85?logo=gitpod)](https://gitpod.io/#/python-discord/sir-lancebot) +[![Open in Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-908a85?logo=gitpod)](https://gitpod.io/#/github.com/python-discord/sir-lancebot) ![Header](sir-lancebot-logo.png) -- cgit v1.2.3 -- cgit v1.2.3 From 420968c38922f7ebbd763e20fbe916deb3bf5cb6 Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Sun, 5 Sep 2021 00:53:05 -0400 Subject: Split initial embed in two Board and claimed answers discord.py doesn't let you cleanly edit an embed with an image in it --- bot/exts/fun/duck_game.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index 1ef7513f..eb509e55 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -130,6 +130,9 @@ class DuckGame: while len(self.solutions) < minimum_solutions: self.board = random.sample(DECK, size) + self.board_msg = None + self.found_msg = None + @property def board(self) -> list[tuple[int]]: """Accesses board property.""" @@ -191,8 +194,8 @@ class DuckGamesDirector(commands.Cog): game.running = True self.current_games[ctx.channel.id] = game - game.msg_content = "" - game.embed_msg = await self.send_board_embed(ctx, game) + game.board_msg = await self.send_board_embed(ctx, game) + game.found_msg = await self.send_found_embed(ctx) await asyncio.sleep(GAME_DURATION) # Checking for the channel ID in the currently running games is not sufficient. @@ -251,7 +254,7 @@ class DuckGamesDirector(commands.Cog): game.scores[msg.author] += INCORRECT_SOLN async def send_board_embed(self, ctx: commands.Context, game: DuckGame) -> discord.Message: - """Create and send the initial game embed. This will be edited as the game goes on.""" + """Create and send an embed to display the board.""" image = assemble_board_image(game.board, game.rows, game.columns) with BytesIO() as image_stream: image.save(image_stream, format="png") @@ -264,14 +267,21 @@ class DuckGamesDirector(commands.Cog): embed.set_image(url="attachment://board.png") return await ctx.send(embed=embed, file=file) + async def send_found_embed(self, ctx: commands.Context) -> discord.Message: + """Create and send an embed to display claimed answers. This will be edited as the game goes on.""" + # Can't be part of the board embed because of discord.py limitations with editing an embed with an image. + embed = discord.Embed( + title="Flights Found", + color=discord.Color.dark_purple(), + ) + return await ctx.send(embed=embed) + async def display_claimed_answer(self, game: DuckGame, author: discord.Member, answer: tuple[int]) -> None: """Add a claimed answer to the game embed.""" async with game.editing_embed: - # We specifically edit the message contents instead of the embed - # Because we load in the image from the file, editing any portion of the embed - # Does weird things to the image and this works around that weirdness - game.msg_content = f"{game.msg_content}\n{str(answer):12s} - {author.display_name}" - await game.embed_msg.edit(content=game.msg_content) + found_embed, = game.found_msg.embeds + found_embed.description = f"{found_embed.description}\n{str(answer):12s} - {author.display_name}" + await game.found_msg.edit(embed=found_embed) async def end_game(self, channel: discord.TextChannel, game: DuckGame, end_message: str) -> None: """Edit the game embed to reflect the end of the game and mark the game as not running.""" -- cgit v1.2.3 From e7bbd14f95f59593581a8c18da8bc4ef9a0f6208 Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Sun, 5 Sep 2021 00:56:58 -0400 Subject: Add function for appending to claimed answers embed --- bot/exts/fun/duck_game.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index eb509e55..1fdc05be 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -248,7 +248,7 @@ class DuckGamesDirector(commands.Cog): if answer in game.solutions: game.claimed_answers[answer] = msg.author game.scores[msg.author] += CORRECT_SOLN - await self.display_claimed_answer(game, msg.author, answer) + await self.append_to_found_embed(game, f"{str(answer):12s} - {msg.author.display_name}") else: await msg.add_reaction(EMOJI_WRONG) game.scores[msg.author] += INCORRECT_SOLN @@ -276,6 +276,16 @@ class DuckGamesDirector(commands.Cog): ) return await ctx.send(embed=embed) + async def append_to_found_embed(self, game: DuckGame, text: str) -> None: + """Append text to the claimed answers embed.""" + async with game.editing_embed: + found_embed, = game.found_msg.embeds + old_desc = found_embed.description + if old_desc == discord.Embed.Empty: + old_desc = "" + found_embed.description = f"{old_desc.rstrip()}\n{text}" + await game.found_msg.edit(embed=found_embed) + async def display_claimed_answer(self, game: DuckGame, author: discord.Member, answer: tuple[int]) -> None: """Add a claimed answer to the game embed.""" async with game.editing_embed: -- cgit v1.2.3 From 65aec408bc3d50934d543b9124de67720d617bb8 Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Sun, 5 Sep 2021 01:12:10 -0400 Subject: Bring end_game up to date --- bot/exts/fun/duck_game.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index 1fdc05be..46ea36fe 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -311,13 +311,19 @@ class DuckGamesDirector(commands.Cog): scoreboard_embed.description = scoreboard await channel.send(embed=scoreboard_embed) + board_embed, = game.board_msg.embeds + embed_as_dict = board_embed.to_dict() # Cannot set embed color after initialization + embed_as_dict["color"] = discord.Color.red().value + board_embed = discord.Embed.from_dict(embed_as_dict) + await self.edit_embed_with_image(game.board_msg, board_embed) + + found_embed, = game.found_msg.embeds missed = [ans for ans in game.solutions if ans not in game.claimed_answers] if missed: missed_text = "Flights everyone missed:\n" + "\n".join(f"{ans}" for ans in missed) else: missed_text = "All the flights were found!" - - await game.embed_msg.edit(content=f"{missed_text}") + await self.append_to_found_embed(game, f"\n{missed_text}") @start_game.command(name="help") async def show_rules(self, ctx: commands.Context) -> None: -- cgit v1.2.3 From f96ecffb3927acd254158210655524e24db37d3b Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Sun, 5 Sep 2021 01:13:49 -0400 Subject: Change board embed color Can't update color when the game is over anymore --- bot/exts/fun/duck_game.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index 46ea36fe..a456c86b 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -11,7 +11,7 @@ from PIL import Image, ImageDraw, ImageFont from discord.ext import commands from bot.bot import Bot -from bot.constants import Colours, MODERATION_ROLES +from bot.constants import MODERATION_ROLES from bot.utils.decorators import with_role DECK = list(product(*[(0, 1, 2)]*4)) @@ -262,7 +262,7 @@ class DuckGamesDirector(commands.Cog): file = discord.File(fp=image_stream, filename="board.png") embed = discord.Embed( title="Duck Duck Duck Goose!", - color=Colours.bright_green, + color=discord.Color.dark_purple(), ) embed.set_image(url="attachment://board.png") return await ctx.send(embed=embed, file=file) -- cgit v1.2.3 -- cgit v1.2.3 From 00c323222be2aeef010b15607f801b3066b5b1ed Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Fri, 24 Sep 2021 22:59:24 -0400 Subject: Remove display_claimed_answer Replaced with append_to_found_embed which is more general --- bot/exts/fun/duck_game.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index a456c86b..8b5338f4 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -286,13 +286,6 @@ class DuckGamesDirector(commands.Cog): found_embed.description = f"{old_desc.rstrip()}\n{text}" await game.found_msg.edit(embed=found_embed) - async def display_claimed_answer(self, game: DuckGame, author: discord.Member, answer: tuple[int]) -> None: - """Add a claimed answer to the game embed.""" - async with game.editing_embed: - found_embed, = game.found_msg.embeds - found_embed.description = f"{found_embed.description}\n{str(answer):12s} - {author.display_name}" - await game.found_msg.edit(embed=found_embed) - async def end_game(self, channel: discord.TextChannel, game: DuckGame, end_message: str) -> None: """Edit the game embed to reflect the end of the game and mark the game as not running.""" game.running = False -- cgit v1.2.3 From baa4d252b72de1e25bceb15721b475ee9724d47b Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Fri, 24 Sep 2021 23:00:40 -0400 Subject: Don't change board embed color Can't edit that embed --- bot/exts/fun/duck_game.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index 8b5338f4..f97c712d 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -304,13 +304,6 @@ class DuckGamesDirector(commands.Cog): scoreboard_embed.description = scoreboard await channel.send(embed=scoreboard_embed) - board_embed, = game.board_msg.embeds - embed_as_dict = board_embed.to_dict() # Cannot set embed color after initialization - embed_as_dict["color"] = discord.Color.red().value - board_embed = discord.Embed.from_dict(embed_as_dict) - await self.edit_embed_with_image(game.board_msg, board_embed) - - found_embed, = game.found_msg.embeds missed = [ans for ans in game.solutions if ans not in game.claimed_answers] if missed: missed_text = "Flights everyone missed:\n" + "\n".join(f"{ans}" for ans in missed) -- cgit v1.2.3 From debe4a185f1429f5dd139929c7506c04abd9fa34 Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Fri, 24 Sep 2021 23:00:58 -0400 Subject: Change docstring to be more help with the help command --- bot/exts/fun/duck_game.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index f97c712d..95e12ced 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -184,7 +184,7 @@ class DuckGamesDirector(commands.Cog): ) @commands.cooldown(rate=1, per=2, type=commands.BucketType.channel) async def start_game(self, ctx: commands.Context) -> None: - """Generate a board, send the game embed, and end the game after a time limit.""" + """Start a new Duck Duck Duck Goose game.""" if ctx.channel.id in self.current_games: await ctx.send("There's already a game running!") return -- cgit v1.2.3 From b0e9ffb94f05e6ef7619b7440e00363e10928932 Mon Sep 17 00:00:00 2001 From: Objectivitix <79152594+Objectivitix@users.noreply.github.com> Date: Sun, 26 Sep 2021 18:24:30 -0300 Subject: Allow everyone to use the `.bm` command everywhere (#885) * Allow everyone to use the bm command * Add everyone role in Roles constants * Use envvars and re-order Roles section to be more organized * Fix trailing whitespace We might need to squash merge, four commits for a single small fix is too much --- bot/constants.py | 3 ++- bot/exts/utilities/bookmark.py | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index 2313bfdb..6e45632f 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -280,11 +280,12 @@ if Client.month_override is not None: class Roles(NamedTuple): + owner = 267627879762755584 admin = int(environ.get("BOT_ADMIN_ROLE_ID", 267628507062992896)) moderator = 267629731250176001 - owner = 267627879762755584 helpers = int(environ.get("ROLE_HELPERS", 267630620367257601)) core_developers = 587606783669829632 + everyone = int(environ.get("BOT_GUILD", 267624335836053506)) class Tokens(NamedTuple): diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index a91ef1c0..39d65168 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -7,7 +7,7 @@ import discord from discord.ext import commands from bot.bot import Bot -from bot.constants import Categories, Colours, ERROR_REPLIES, Icons, WHITELISTED_CHANNELS +from bot.constants import Colours, ERROR_REPLIES, Icons, Roles from bot.utils.converters import WrappedMessageConverter from bot.utils.decorators import whitelist_override @@ -16,7 +16,6 @@ log = logging.getLogger(__name__) # Number of seconds to wait for other users to bookmark the same message TIMEOUT = 120 BOOKMARK_EMOJI = "📌" -WHITELISTED_CATEGORIES = (Categories.help_in_use,) class Bookmark(commands.Cog): @@ -87,8 +86,8 @@ class Bookmark(commands.Cog): await message.add_reaction(BOOKMARK_EMOJI) return message - @whitelist_override(channels=WHITELISTED_CHANNELS, categories=WHITELISTED_CATEGORIES) @commands.command(name="bookmark", aliases=("bm", "pin")) + @whitelist_override(roles=(Roles.everyone,)) async def bookmark( self, ctx: commands.Context, -- cgit v1.2.3 From beb42c28911d8bbc4de5b0926a77619b4454f402 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Fri, 1 Oct 2021 04:32:58 -0500 Subject: `.quack` (#849) * feat: Added quack command * added log.error call for request fails * spacing change Co-authored-by: Bluenix * another spacing change Co-authored-by: Bluenix * Moved description to footer Co-authored-by: Bluenix * whitespace fix * chore: Removed the link from the footer and set it as the url param * chore: moved footer to description Co-authored-by: Bluenix Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/fun/quack.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 bot/exts/fun/quack.py diff --git a/bot/exts/fun/quack.py b/bot/exts/fun/quack.py new file mode 100644 index 00000000..0c228aed --- /dev/null +++ b/bot/exts/fun/quack.py @@ -0,0 +1,75 @@ +import logging +import random +from typing import Literal, Optional + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours, NEGATIVE_REPLIES + +API_URL = 'https://quackstack.pythondiscord.com' + +log = logging.getLogger(__name__) + + +class Quackstack(commands.Cog): + """Cog used for wrapping Quackstack.""" + + def __init__(self, bot: Bot): + self.bot = bot + + @commands.command() + async def quack( + self, + ctx: commands.Context, + ducktype: Literal["duck", "manduck"] = "duck", + *, + seed: Optional[str] = None + ) -> None: + """ + Use the Quackstack API to generate a random duck. + + If a seed is provided, a duck is generated based on the given seed. + Either "duck" or "manduck" can be provided to change the duck type generated. + """ + ducktype = ducktype.lower() + quackstack_url = f"{API_URL}/{ducktype}" + params = {} + if seed is not None: + try: + seed = int(seed) + except ValueError: + # We just need to turn the string into an integer any way possible + seed = int.from_bytes(seed.encode(), "big") + params["seed"] = seed + + async with self.bot.http_session.get(quackstack_url, params=params) as response: + error_embed = discord.Embed( + title=random.choice(NEGATIVE_REPLIES), + description="The request failed. Please try again later.", + color=Colours.soft_red, + ) + if response.status != 200: + log.error(f"Response to Quackstack returned code {response.status}") + await ctx.send(embed=error_embed) + return + + data = await response.json() + file = data["file"] + + embed = discord.Embed( + title=f"Quack! Here's a {ducktype} for you.", + description=f"A {ducktype} from Quackstack.", + color=Colours.grass_green, + url=f"{API_URL}/docs" + ) + + embed.set_image(url=API_URL + file) + + await ctx.send(embed=embed) + + +def setup(bot: Bot) -> None: + """Loads the Quack cog.""" + bot.add_cog(Quackstack(bot)) -- cgit v1.2.3 From 0246a66a668a5928ec57a40629c1ef740c8fd651 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Fri, 1 Oct 2021 19:17:14 +0200 Subject: Hackto issue finder: make d.py timestamp naive --- bot/exts/events/hacktoberfest/hacktober-issue-finder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py index 0cbb6df4..088e7e43 100644 --- a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py +++ b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py @@ -88,10 +88,10 @@ class HacktoberIssues(commands.Cog): if option == "beginner": self.cache_beginner = data - self.cache_timer_beginner = ctx.message.created_at + self.cache_timer_beginner = ctx.message.created_at.replace(tzinfo=None) else: self.cache_normal = data - self.cache_timer_normal = ctx.message.created_at + self.cache_timer_normal = ctx.message.created_at.replace(tzinfo=None) return data -- cgit v1.2.3 From 97ccd35d27946abb39b86befdeb36364fea8b5ce Mon Sep 17 00:00:00 2001 From: camcaswell <38672443+camcaswell@users.noreply.github.com> Date: Sat, 2 Oct 2021 00:15:44 -0400 Subject: Make setting the old embed description cleaner --- bot/exts/fun/duck_game.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py index 95e12ced..10b03a49 100644 --- a/bot/exts/fun/duck_game.py +++ b/bot/exts/fun/duck_game.py @@ -280,9 +280,7 @@ class DuckGamesDirector(commands.Cog): """Append text to the claimed answers embed.""" async with game.editing_embed: found_embed, = game.found_msg.embeds - old_desc = found_embed.description - if old_desc == discord.Embed.Empty: - old_desc = "" + old_desc = found_embed.description or "" found_embed.description = f"{old_desc.rstrip()}\n{text}" await game.found_msg.edit(embed=found_embed) -- cgit v1.2.3 From 26943e5b10fedf9d90d774c921ea8e4c4ceb0b66 Mon Sep 17 00:00:00 2001 From: TizzySaurus <47674925+TizzySaurus@users.noreply.github.com> Date: Sat, 2 Oct 2021 12:15:13 +0100 Subject: Change pascal's triangle image --- bot/resources/fun/trivia_quiz.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/resources/fun/trivia_quiz.json b/bot/resources/fun/trivia_quiz.json index 0b3e6802..99aa5f42 100644 --- a/bot/resources/fun/trivia_quiz.json +++ b/bot/resources/fun/trivia_quiz.json @@ -440,7 +440,7 @@ { "id": 229, "question": "What is this triangle called?", - "img_url": "https://cdn.askpython.com/wp-content/uploads/2020/07/Pascals-triangle.png", + "img_url": "https://wikimedia.org/api/rest_v1/media/math/render/png/23050fcb53d6083d9e42043bebf2863fa9746043", "answer": ["Pascal's triangle", "Pascal"] }, { -- cgit v1.2.3 From 9f07c20f8f2e78051ab9c0d31d45755921007156 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sun, 3 Oct 2021 14:07:25 +0100 Subject: Give the bookmark command a better error message --- bot/exts/utilities/bookmark.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index 39d65168..a11c366b 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -98,7 +98,13 @@ class Bookmark(commands.Cog): """Send the author a link to `target_message` via DMs.""" if not target_message: if not ctx.message.reference: - raise commands.UserInputError("You must either provide a valid message to bookmark, or reply to one.") + raise commands.UserInputError( + "You must either provide a valid message to bookmark, or reply to one." + "\n\nThe lookup strategy for a message is as follows (in order):" + "\n1. Lookup by '{channel ID}-{message ID}' (retrieved by shift-clicking on 'Copy ID')" + "\n2. Lookup by message ID (the message **must** have been sent after the bot last started)" + "\n3. Lookup by message URL" + ) target_message = ctx.message.reference.resolved # Prevent users from bookmarking a message in a channel they don't have access to -- cgit v1.2.3 From 42d3e10317a327157ea8a5c04418bd6e26438793 Mon Sep 17 00:00:00 2001 From: Gustav Odinger <65498475+gustavwilliam@users.noreply.github.com> Date: Sun, 3 Oct 2021 15:30:07 +0200 Subject: Ignore bot messages for spooky react Previously only ignored its own messages, but now ignores messages from all bots. --- bot/exts/holidays/halloween/spookyreact.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bot/exts/holidays/halloween/spookyreact.py b/bot/exts/holidays/halloween/spookyreact.py index 25e783f4..e228b91d 100644 --- a/bot/exts/holidays/halloween/spookyreact.py +++ b/bot/exts/holidays/halloween/spookyreact.py @@ -47,12 +47,12 @@ class SpookyReact(Cog): Short-circuit helper check. Return True if: - * author is the bot + * author is a bot * prefix is not None """ - # Check for self reaction - if message.author == self.bot.user: - log.debug(f"Ignoring reactions on self message. Message ID: {message.id}") + # Check if message author is a bot + if message.author.bot: + log.debug(f"Ignoring reactions on bot message. Message ID: {message.id}") return True # Check for command invocation -- cgit v1.2.3 From 6fbd7883fee19e62898eacea08b4d7b7f7fc74db Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 4 Oct 2021 20:26:59 +0100 Subject: Monkey patch http.send_typing to catch 403s Sometimes discord turns off typing events by throwing 403's, so we should catch those --- bot/__init__.py | 26 +++++------------ bot/command.py | 18 ------------ bot/group.py | 18 ------------ bot/monkey_patches.py | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 55 deletions(-) delete mode 100644 bot/command.py delete mode 100644 bot/group.py create mode 100644 bot/monkey_patches.py diff --git a/bot/__init__.py b/bot/__init__.py index c6a48105..db576cb2 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -15,28 +15,15 @@ from pathlib import Path import arrow from discord.ext import commands -from bot.command import Command +from bot import monkey_patches from bot.constants import Client -from bot.group import Group # Configure the "TRACE" logging level (e.g. "log.trace(message)") logging.TRACE = 5 logging.addLevelName(logging.TRACE, "TRACE") - -def monkeypatch_trace(self: logging.Logger, msg: str, *args, **kwargs) -> None: - """ - Log 'msg % args' with severity 'TRACE'. - - To pass exception information, use the keyword argument exc_info with a true value, e.g. - logger.trace("Houston, we have an %s", "interesting problem", exc_info=1) - """ - if self.isEnabledFor(logging.TRACE): - self._log(logging.TRACE, msg, args, **kwargs) - - -logging.Logger.trace = monkeypatch_trace +logging.Logger.trace = monkey_patches.trace_log # Set timestamp of when execution started (approximately) start_time = arrow.utcnow() @@ -84,11 +71,12 @@ logging.getLogger().info("Logging initialization complete") if os.name == "nt": asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) +monkey_patches.patch_typing() # Monkey-patch discord.py decorators to use the both the Command and Group subclasses which supports root aliases. # Must be patched before any cogs are added. -commands.command = partial(commands.command, cls=Command) -commands.GroupMixin.command = partialmethod(commands.GroupMixin.command, cls=Command) +commands.command = partial(commands.command, cls=monkey_patches.Command) +commands.GroupMixin.command = partialmethod(commands.GroupMixin.command, cls=monkey_patches.Command) -commands.group = partial(commands.group, cls=Group) -commands.GroupMixin.group = partialmethod(commands.GroupMixin.group, cls=Group) +commands.group = partial(commands.group, cls=monkey_patches.Group) +commands.GroupMixin.group = partialmethod(commands.GroupMixin.group, cls=monkey_patches.Group) diff --git a/bot/command.py b/bot/command.py deleted file mode 100644 index 0fb900f7..00000000 --- a/bot/command.py +++ /dev/null @@ -1,18 +0,0 @@ -from discord.ext import commands - - -class Command(commands.Command): - """ - A `discord.ext.commands.Command` subclass which supports root aliases. - - A `root_aliases` keyword argument is added, which is a sequence of alias names that will act as - top-level commands rather than being aliases of the command's group. It's stored as an attribute - also named `root_aliases`. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.root_aliases = kwargs.get("root_aliases", []) - - if not isinstance(self.root_aliases, (list, tuple)): - raise TypeError("Root aliases of a command must be a list or a tuple of strings.") diff --git a/bot/group.py b/bot/group.py deleted file mode 100644 index a7bc59b7..00000000 --- a/bot/group.py +++ /dev/null @@ -1,18 +0,0 @@ -from discord.ext import commands - - -class Group(commands.Group): - """ - A `discord.ext.commands.Group` subclass which supports root aliases. - - A `root_aliases` keyword argument is added, which is a sequence of alias names that will act as - top-level groups rather than being aliases of the command's group. It's stored as an attribute - also named `root_aliases`. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.root_aliases = kwargs.get("root_aliases", []) - - if not isinstance(self.root_aliases, (list, tuple)): - raise TypeError("Root aliases of a group must be a list or a tuple of strings.") diff --git a/bot/monkey_patches.py b/bot/monkey_patches.py new file mode 100644 index 00000000..fe81f2e3 --- /dev/null +++ b/bot/monkey_patches.py @@ -0,0 +1,78 @@ +import logging +from datetime import datetime, timedelta + +from discord import Forbidden, http +from discord.ext import commands + +log = logging.getLogger(__name__) + + +def trace_log(self: logging.Logger, msg: str, *args, **kwargs) -> None: + """ + Log 'msg % args' with severity 'TRACE'. + + To pass exception information, use the keyword argument exc_info with a true value, e.g. + logger.trace("Houston, we have an %s", "interesting problem", exc_info=1) + """ + if self.isEnabledFor(logging.TRACE): + self._log(logging.TRACE, msg, args, **kwargs) + + +class Command(commands.Command): + """ + A `discord.ext.commands.Command` subclass which supports root aliases. + + A `root_aliases` keyword argument is added, which is a sequence of alias names that will act as + top-level commands rather than being aliases of the command's group. It's stored as an attribute + also named `root_aliases`. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.root_aliases = kwargs.get("root_aliases", []) + + if not isinstance(self.root_aliases, (list, tuple)): + raise TypeError("Root aliases of a command must be a list or a tuple of strings.") + + +class Group(commands.Group): + """ + A `discord.ext.commands.Group` subclass which supports root aliases. + + A `root_aliases` keyword argument is added, which is a sequence of alias names that will act as + top-level groups rather than being aliases of the command's group. It's stored as an attribute + also named `root_aliases`. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.root_aliases = kwargs.get("root_aliases", []) + + if not isinstance(self.root_aliases, (list, tuple)): + raise TypeError("Root aliases of a group must be a list or a tuple of strings.") + + +def patch_typing() -> None: + """ + Sometimes discord turns off typing events by throwing 403's. + + Handle those issues by patching the trigger_typing method so it ignores 403's in general. + """ + log.debug("Patching send_typing, which should fix things breaking when discord disables typing events. Stay safe!") + + original = http.HTTPClient.send_typing + last_403 = None + + async def honeybadger_type(self, channel_id: int) -> None: # noqa: ANN001 + nonlocal last_403 + if last_403 and (datetime.utcnow() - last_403) < timedelta(minutes=5): + log.warning("Not sending typing event, we got a 403 less than 5 minutes ago.") + return + try: + await original(self, channel_id) + except Forbidden: + last_403 = datetime.utcnow() + log.warning("Got a 403 from typing event!") + pass + + http.HTTPClient.send_typing = honeybadger_type -- cgit v1.2.3 From dccd30e27a594dad808a20bacef213c461ea2c48 Mon Sep 17 00:00:00 2001 From: Mayur Odedara Date: Fri, 8 Oct 2021 00:57:57 +0530 Subject: Added Anagrams command (#874) * Added Anagrams command Added 2 files anagram.py - Has the code for anagram command anagram.json - Contains all the words for anagram command * Update bot/exts/fun/anagram.py Using "with" for resource file instead of getting data directly Co-authored-by: brad90four <42116429+brad90four@users.noreply.github.com> * Update bot/exts/fun/anagram.py Updated title text for answer embed Co-authored-by: Bluenix * Update bot/exts/fun/anagram.py Comma separated text for winners list Co-authored-by: Bluenix * Updated anagram.py as per review comments -Removed redundant variables -Updated embed text to avoid 'all' -Updated stale comments * Some minor formatting fixes -Added trailing commas to embed -Updated all embeds to have consistent format * Polish anagram command for multiple channels * Updated docstrings * Allowed command to be used in multiple channels * Create a class for anagram game instances * Lay groundwork for threads Co-Authored-By: Bluenix * Updated resource file for anagram command * Anagrams are now cross referenced with list of common words which should be easy for users to guess * It should not have any slur words * Update bot/exts/fun/anagram.py Co-authored-by: brad90four <42116429+brad90four@users.noreply.github.com> * Update bot/exts/fun/anagram.py Co-authored-by: brad90four <42116429+brad90four@users.noreply.github.com> * Update bot/exts/fun/anagram.py Co-authored-by: brad90four <42116429+brad90four@users.noreply.github.com> * Update bot/exts/fun/anagram.py Co-authored-by: brad90four <42116429+brad90four@users.noreply.github.com> * Linting error fix Linting error fix * Error fix Removed the "seconds" causing issue for anagram command * Revert "Error fix" This reverts commit 8c00d70f9faf62c536eac1fa61877dfab328a83f. * Error fix for seconds Fixed the error by removing "seconds" Co-authored-by: brad90four <42116429+brad90four@users.noreply.github.com> Co-authored-by: Bluenix Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/fun/anagram.py | 110 + bot/resources/fun/anagram.json | 17668 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 17778 insertions(+) create mode 100644 bot/exts/fun/anagram.py create mode 100644 bot/resources/fun/anagram.json diff --git a/bot/exts/fun/anagram.py b/bot/exts/fun/anagram.py new file mode 100644 index 00000000..9aee5f18 --- /dev/null +++ b/bot/exts/fun/anagram.py @@ -0,0 +1,110 @@ +import asyncio +import json +import logging +import random +from pathlib import Path + +import discord +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours + +log = logging.getLogger(__name__) + +TIME_LIMIT = 60 + +# anagram.json file contains all the anagrams +with open(Path("bot/resources/fun/anagram.json"), "r") as f: + ANAGRAMS_ALL = json.load(f) + + +class AnagramGame: + """ + Used for creating instances of anagram games. + + Once multiple games can be run at the same time, this class' instances + can be used for keeping track of each anagram game. + """ + + def __init__(self, scrambled: str, correct: list[str]) -> None: + self.scrambled = scrambled + self.correct = set(correct) + + self.winners = set() + + async def message_creation(self, message: discord.Message) -> None: + """Check if the message is a correct answer and remove it from the list of answers.""" + if message.content.lower() in self.correct: + self.winners.add(message.author.mention) + self.correct.remove(message.content.lower()) + + +class Anagram(commands.Cog): + """Cog for the Anagram game command.""" + + def __init__(self, bot: Bot): + self.bot = bot + + self.games: dict[int, AnagramGame] = {} + + @commands.command(name="anagram", aliases=("anag", "gram", "ag")) + @commands.guild_only() + async def anagram_command(self, ctx: commands.Context) -> None: + """ + Given shuffled letters, rearrange them into anagrams. + + Show an embed with scrambled letters which if rearranged can form words. + After a specific amount of time, list the correct answers and whether someone provided a + correct answer. + """ + if self.games.get(ctx.channel.id): + await ctx.send("An anagram is already being solved in this channel!") + return + + scrambled_letters, correct = random.choice(list(ANAGRAMS_ALL.items())) + + game = AnagramGame(scrambled_letters, correct) + self.games[ctx.channel.id] = game + + anagram_embed = discord.Embed( + title=f"Find anagrams from these letters: '{scrambled_letters.upper()}'", + description=f"You have {TIME_LIMIT} seconds to find correct words.", + colour=Colours.purple, + ) + + await ctx.send(embed=anagram_embed) + await asyncio.sleep(TIME_LIMIT) + + if game.winners: + win_list = ", ".join(game.winners) + content = f"Well done {win_list} for getting it right!" + else: + content = "Nobody got it right." + + answer_embed = discord.Embed( + title=f"The words were: `{'`, `'.join(ANAGRAMS_ALL[game.scrambled])}`!", + colour=Colours.pink, + ) + + await ctx.send(content, embed=answer_embed) + + # Game is finished, let's remove it from the dict + self.games.pop(ctx.channel.id) + + @commands.Cog.listener() + async def on_message(self, message: discord.Message) -> None: + """Check a message for an anagram attempt and pass to an ongoing game.""" + if message.author.bot or not message.guild: + return + + game = self.games.get(message.channel.id) + if not game: + return + + await game.message_creation(message) + + +def setup(bot: Bot) -> None: + """Load the Anagram cog.""" + bot.add_cog(Anagram(bot)) diff --git a/bot/resources/fun/anagram.json b/bot/resources/fun/anagram.json new file mode 100644 index 00000000..ea5a5794 --- /dev/null +++ b/bot/resources/fun/anagram.json @@ -0,0 +1,17668 @@ +{ + "eht": [ + "eth", + "het", + "the" + ], + "adn": [ + "and", + "dan", + "nad" + ], + "for": [ + "for", + "fro", + "orf" + ], + "ahtt": [ + "hatt", + "tath", + "that" + ], + "hist": [ + "hist", + "hits", + "isth", + "shit", + "sith", + "this", + "tshi" + ], + "hitw": [ + "whit", + "with" + ], + "not": [ + "not", + "ont", + "ton" + ], + "aer": [ + "aer", + "are", + "ear", + "era", + "rea" + ], + "fmor": [ + "form", + "from" + ], + "enw": [ + "new", + "wen" + ], + "emor": [ + "mero", + "more", + "omer", + "rome" + ], + "asw": [ + "saw", + "swa", + "was" + ], + "acn": [ + "anc", + "can" + ], + "aegp": [ + "gape", + "page", + "peag", + "pega" + ], + "ahs": [ + "ahs", + "ash", + "has", + "sah", + "sha" + ], + "acehrs": [ + "arches", + "ascher", + "casher", + "chares", + "chaser", + "eschar", + "raches", + "recash", + "search" + ], + "eefr": [ + "feer", + "fere", + "free", + "reef" + ], + "btu": [ + "btu", + "but", + "tub" + ], + "oru": [ + "our", + "uro" + ], + "eno": [ + "eon", + "neo", + "one" + ], + "ehort": [ + "other", + "theor", + "thore", + "throe", + "toher" + ], + "eimt": [ + "emit", + "item", + "mite", + "time" + ], + "ehty": [ + "hyte", + "yeth", + "they" + ], + "eist": [ + "seit", + "site", + "ties" + ], + "amy": [ + "amy", + "yam", + "may", + "mya" + ], + "ahtw": [ + "thaw", + "wath", + "what" + ], + "ehirt": [ + "ither", + "rithe", + "their" + ], + "ensw": [ + "news", + "sewn", + "snew", + "wens" + ], + "otu": [ + "out", + "tou" + ], + "esu": [ + "esu", + "sue", + "use" + ], + "any": [ + "any", + "yan", + "nay" + ], + "eehrt": [ + "ether", + "rethe", + "theer", + "there", + "three" + ], + "ees": [ + "ese", + "see" + ], + "lnoy": [ + "lyon", + "loyn", + "only" + ], + "his": [ + "his", + "hsi", + "ihs", + "ish", + "shi" + ], + "ehnw": [ + "hewn", + "when" + ], + "eehr": [ + "heer", + "here" + ], + "how": [ + "how", + "who" + ], + "alos": [ + "also", + "laos", + "sola" + ], + "now": [ + "now", + "own", + "won" + ], + "egt": [ + "get", + "gte", + "teg" + ], + "eivw": [ + "view", + "wive" + ], + "eilnno": [ + "lionne", + "online" + ], + "first": [ + "first", + "frist", + "frits", + "rifts" + ], + "been": [ + "been", + "bene", + "eben" + ], + "eerw": [ + "ewer", + "weer", + "were" + ], + "ceeirssv": [ + "scrieves", + "services" + ], + "emos": [ + "meso", + "mose", + "some" + ], + "eehst": [ + "sheet", + "these" + ], + "ist": [ + "ist", + "its", + "sit", + "tis", + "tsi" + ], + "eikl": [ + "kiel", + "like" + ], + "ceeirsv": [ + "cerevis", + "cresive", + "scrieve", + "service" + ], + "ahnt": [ + "hant", + "tanh", + "than" + ], + "ceipr": [ + "price", + "recip", + "repic" + ], + "adet": [ + "adet", + "ated", + "date", + "tade", + "tead", + "teda" + ], + "opt": [ + "opt", + "pot", + "top" + ], + "adh": [ + "dah", + "dha", + "had" + ], + "ilst": [ + "list", + "lits", + "silt", + "slit", + "tils" + ], + "aemn": [ + "amen", + "enam", + "mane", + "mean", + "name", + "nema" + ], + "jstu": [ + "just", + "juts" + ], + "eorv": [ + "over", + "rove" + ], + "aestt": [ + "state", + "taste", + "tates", + "teats", + "testa" + ], + "aery": [ + "aery", + "ayre", + "eyra", + "yare", + "year" + ], + "ady": [ + "ady", + "day", + "yad" + ], + "inot": [ + "into", + "nito", + "oint", + "tino" + ], + "aeilm": [ + "email", + "maile", + "malie", + "melia" + ], + "otw": [ + "owt", + "tow", + "two", + "wot" + ], + "desu": [ + "deus", + "dues", + "sude", + "sued", + "used" + ], + "alst": [ + "alts", + "last", + "lats", + "salt", + "slat" + ], + "most": [ + "most", + "mots", + "toms" + ], + "cimsu": [ + "musci", + "music" + ], + "aadt": [ + "adat", + "data" + ], + "aekm": [ + "kame", + "make", + "meak" + ], + "ehmt": [ + "meth", + "them" + ], + "emssty": [ + "mystes", + "system" + ], + "opst": [ + "opts", + "post", + "pots", + "spot", + "stop", + "tops" + ], + "ehr": [ + "her", + "reh", + "rhe" + ], + "add": [ + "add", + "dad" + ], + "chsu": [ + "cush", + "such" + ], + "aeelps": [ + "asleep", + "elapse", + "please", + "sapele" + ], + "aeegmss": [ + "megasse", + "message" + ], + "aefrt": [ + "afret", + "after", + "frate", + "trefa" + ], + "best": [ + "best", + "bets" + ], + "aeforstw": [ + "forwaste", + "software" + ], + "ehnt": [ + "hent", + "neth", + "then" + ], + "ellw": [ + "llew", + "well" + ], + "eehrw": [ + "hewer", + "wheer", + "where" + ], + "fino": [ + "fino", + "foin", + "info" + ], + "ghirst": [ + "girths", + "griths", + "rights" + ], + "bkoos": [ + "bokos", + "books" + ], + "chloos": [ + "cholos", + "school" + ], + "aceh": [ + "ache", + "each", + "haec" + ], + "iklns": [ + "kilns", + "links", + "slink" + ], + "ehs": [ + "hes", + "she" + ], + "eeirvw": [ + "review", + "viewer" + ], + "aersy": [ + "eyras", + "years", + "reasy", + "resay", + "sayer", + "seary" + ], + "bkoo": [ + "boko", + "book" + ], + "eimst": [ + "emits", + "items", + "metis", + "mites", + "smite", + "stime", + "times" + ], + "acmnopy": [ + "company", + "copyman" + ], + "ader": [ + "ared", + "daer", + "dare", + "dear", + "read" + ], + "deen": [ + "dene", + "eden", + "ende", + "ened", + "need" + ], + "amny": [ + "many", + "myna" + ], + "ersu": [ + "rues", + "ruse", + "suer", + "sure", + "user" + ], + "adis": [ + "aids", + "dais", + "dasi", + "dias", + "disa", + "sadi", + "said", + "sida" + ], + "deos": [ + "does", + "dose", + "odes" + ], + "est": [ + "est", + "set" + ], + "denru": [ + "nuder", + "rendu", + "runed", + "under", + "unred" + ], + "aeeglnr": [ + "enlarge", + "general", + "gleaner" + ], + "aceehrrs": [ + "reachers", + "rechaser", + "research", + "searcher" + ], + "ailm": [ + "amil", + "amli", + "lima", + "mail", + "mali", + "mila" + ], + "amp": [ + "amp", + "map", + "pam" + ], + "eeirsvw": [ + "reviews", + "viewers" + ], + "efil": [ + "feil", + "fiel", + "file", + "leif", + "lief", + "life" + ], + "know": [ + "know", + "wonk" + ], + "aegms": [ + "games", + "mages" + ], + "awy": [ + "yaw", + "way" + ], + "adsy": [ + "days", + "dyas" + ], + "aprt": [ + "part", + "prat", + "rapt", + "tarp", + "trap" + ], + "cdlou": [ + "cloud", + "could" + ], + "aegrt": [ + "gater", + "grate", + "great", + "greta", + "retag", + "targe", + "terga" + ], + "deintu": [ + "dunite", + "united", + "untied" + ], + "ehlot": [ + "helot", + "hotel", + "theol", + "thole" + ], + "aelr": [ + "arle", + "earl", + "eral", + "lare", + "lear", + "rale", + "real" + ], + "ceenrt": [ + "center", + "centre", + "entrec", + "recent", + "tenrec" + ], + "abey": [ + "abey", + "abye" + ], + "mstu": [ + "must", + "muts", + "smut", + "stum" + ], + "eorst": [ + "roset", + "rotes", + "rotse", + "soter", + "stero", + "store", + "tores", + "torse" + ], + "aelrtv": [ + "travel", + "varlet" + ], + "adem": [ + "dame", + "edam", + "emda", + "made", + "maed", + "mead" + ], + "eoprrt": [ + "porret", + "porter", + "pretor", + "report", + "troper" + ], + "adeilst": [ + "details", + "dilates", + "distale", + "salited" + ], + "eiln": [ + "lien", + "line", + "neil", + "nile" + ], + "emrst": [ + "mster", + "terms" + ], + "ehlost": [ + "helots", + "hostel", + "hostle", + "hotels", + "tholes" + ], + "dens": [ + "dens", + "ends", + "send", + "sned" + ], + "ghirt": [ + "girth", + "grith", + "right" + ], + "abceesu": [ + "because", + "besauce" + ], + "acllo": [ + "callo", + "colla", + "local" + ], + "ehost": [ + "ethos", + "shote", + "theos", + "those" + ], + "ginsu": [ + "suing", + "using" + ], + "elrsstu": [ + "lusters", + "lustres", + "results", + "rustles", + "sutlers", + "tussler", + "ulsters" + ], + "ceffio": [ + "coiffe", + "office" + ], + "acdeinotu": [ + "auctioned", + "cautioned", + "coadunite", + "education", + "noctuidae" + ], + "aailnnot": [ + "latonian", + "nataloin", + "national" + ], + "acr": [ + "arc", + "car" + ], + "degins": [ + "deigns", + "design", + "sdeign", + "signed", + "singed" + ], + "aekt": [ + "kate", + "keat", + "keta", + "take", + "teak" + ], + "deopst": [ + "depots", + "despot", + "posted", + "stoped" + ], + "eeinnrtt": [ + "internet", + "renitent", + "trentine" + ], + "hiintw": [ + "inwith", + "whitin", + "within" + ], + "aesstt": [ + "estats", + "states", + "tasset", + "tastes" + ], + "antw": [ + "nawt", + "tawn", + "want" + ], + "ehnop": [ + "pheon", + "phone" + ], + "deeerrsv": [ + "deserver", + "reserved", + "reversed" + ], + "abdes": [ + "based", + "beads", + "sabed" + ], + "cdeo": [ + "code", + "coed", + "deco", + "ecod" + ], + "hosw": [ + "hows", + "show" + ], + "eenv": [ + "even", + "neve", + "veen" + ], + "aceilps": [ + "plaices", + "special" + ], + "ceiprs": [ + "crepis", + "cripes", + "persic", + "precis", + "prices", + "spicer" + ], + "deinx": [ + "index", + "nixed" + ], + "begin": [ + "begin", + "being", + "binge" + ], + "emnow": [ + "menow", + "women" + ], + "chmu": [ + "chum", + "much" + ], + "gins": [ + "gins", + "sign", + "sing", + "snig" + ], + "ikln": [ + "kiln", + "link" + ], + "enop": [ + "nope", + "open", + "peon", + "pone" + ], + "adoty": [ + "doaty", + "toady", + "today" + ], + "hostu": [ + "shout", + "south", + "thous" + ], + "aces": [ + "aces", + "aesc", + "case", + "esca" + ], + "aems": [ + "asem", + "maes", + "meas", + "mesa", + "same", + "seam" + ], + "aegps": [ + "gapes", + "pages", + "peags" + ], + "einorsv": [ + "renvois", + "version" + ], + "ceinost": [ + "contise", + "noetics", + "notices", + "section" + ], + "dfnou": [ + "fondu", + "found" + ], + "oprsst": [ + "sports", + "strops" + ], + "adeelrt": [ + "alerted", + "altered", + "delater", + "latrede", + "redealt", + "related", + "treadle" + ], + "bhot": [ + "both", + "thob" + ], + "aaceimnr": [ + "amacrine", + "american", + "camarine", + "camerina", + "cinerama" + ], + "aegm": [ + "egma", + "game", + "mage" + ], + "acer": [ + "acer", + "acre", + "care", + "cera", + "crea", + "race" + ], + "alott": [ + "lotta", + "total" + ], + "acelp": [ + "capel", + "clape", + "place" + ], + "den": [ + "den", + "end", + "ned" + ], + "addlnoow": [ + "download", + "woodland" + ], + "hiottuw": [ + "outwith", + "without" + ], + "epr": [ + "per", + "pre", + "rep" + ], + "hnort": [ + "north", + "thorn" + ], + "ceeorrssu": [ + "recourses", + "resources" + ], + "opsst": [ + "posts", + "spots", + "stops" + ], + "bgi": [ + "big", + "gib" + ], + "adeim": [ + "aimed", + "amide", + "damie", + "media" + ], + "alw": [ + "alw", + "awl", + "law" + ], + "aertw": [ + "tawer", + "water", + "wreat" + ], + "hiorsty": [ + "history", + "toryish" + ], + "ceiprstu": [ + "crepitus", + "cuprites", + "pictures", + "piecrust" + ], + "art": [ + "art", + "rat", + "tar", + "tra" + ], + "ceins": [ + "cines", + "senci", + "since" + ], + "degiu": [ + "digue", + "guide" + ], + "hops": [ + "hops", + "hosp", + "phos", + "posh", + "shop", + "soph" + ], + "abdor": [ + "abord", + "bardo", + "board", + "broad", + "dobra", + "dorab" + ], + "acilnoot": [ + "colation", + "coontail", + "location" + ], + "ehitw": [ + "white", + "withe" + ], + "allms": [ + "malls", + "small" + ], + "aginrt": [ + "gratin", + "rating", + "taring", + "tringa" + ], + "aert": [ + "aret", + "arte", + "erat", + "rate", + "tare", + "tear", + "tera" + ], + "dginru": [ + "during", + "ungird", + "ungrid" + ], + "asu": [ + "aus", + "sau", + "usa" + ], + "enrrtu": [ + "return", + "turner" + ], + "eisst": [ + "sesti", + "siest", + "sites", + "sties" + ], + "eioprsuv": [ + "pervious", + "previous", + "viperous" + ], + "eenstv": [ + "events", + "steven" + ], + "elov": [ + "levo", + "love", + "velo", + "vole" + ], + "dlo": [ + "dol", + "lod", + "old" + ], + "aimn": [ + "amin", + "anim", + "iman", + "main", + "mani", + "mian", + "mina", + "naim" + ], + "cdeiinoprst": [ + "description", + "discerption", + "predictions" + ], + "aceinnrsu": [ + "insurance", + "nuisancer" + ], + "aehnort": [ + "another", + "athenor", + "rheotan" + ], + "hwy": [ + "hwy", + "why" + ], + "ahlls": [ + "halls", + "shall" + ], + "illst": [ + "lilts", + "still", + "tills" + ], + "emnoy": [ + "emony", + "moyen", + "money" + ], + "eervy": [ + "every", + "veery", + "verey" + ], + "giilnst": [ + "listing", + "silting", + "sliting", + "tilings" + ], + "eilltt": [ + "little", + "tillet" + ], + "iistv": [ + "visit", + "vitis" + ], + "aesv": [ + "aves", + "save", + "vase" + ], + "loost": [ + "loots", + "lotos", + "sloot", + "sotol", + "stool", + "tools" + ], + "low": [ + "low", + "lwo", + "owl" + ], + "elpry": [ + "lepry", + "plyer", + "reply" + ], + "cemorstu": [ + "costumer", + "customer" + ], + "acemopr": [ + "compare", + "compear" + ], + "cdeilnu": [ + "include", + "nuclide" + ], + "aeluv": [ + "uveal", + "value" + ], + "aceilrt": [ + "article", + "recital" + ], + "kory": [ + "york", + "kory", + "roky" + ], + "amn": [ + "man", + "mna", + "nam" + ], + "deioprv": [ + "dropvie", + "prevoid", + "provide" + ], + "ceorsu": [ + "cerous", + "course", + "crouse", + "source" + ], + "aelnr": [ + "learn", + "neral", + "renal" + ], + "aels": [ + "ales", + "elsa", + "lase", + "leas", + "sale", + "seal", + "slae" + ], + "adnoru": [ + "around", + "arundo" + ], + "bjo": [ + "job", + "obj" + ], + "ceoprss": [ + "corpses", + "process" + ], + "eent": [ + "eten", + "neet", + "nete", + "teen" + ], + "moor": [ + "moor", + "moro", + "room" + ], + "oot": [ + "oot", + "oto", + "too" + ], + "cdeirt": [ + "credit", + "direct", + "triced" + ], + "inopt": [ + "pinot", + "pinto", + "piton", + "point" + ], + "ijno": [ + "join", + "joni" + ], + "aceegiorst": [ + "categories", + "categorise" + ], + "estw": [ + "stew", + "tews", + "west", + "wets" + ], + "aelss": [ + "lases", + "sales", + "salse", + "seals" + ], + "kloo": [ + "kolo", + "look" + ], + "eghilns": [ + "english", + "shingle" + ], + "eflt": [ + "felt", + "flet", + "left" + ], + "aemt": [ + "mate", + "meat", + "meta", + "tame", + "team", + "tema" + ], + "aeestt": [ + "estate", + "testae" + ], + "ceelst": [ + "elects", + "select" + ], + "hoopst": [ + "photos", + "pothos" + ], + "agy": [ + "agy", + "gay" + ], + "adehrt": [ + "dearth", + "hatred", + "rathed", + "thread" + ], + "acegorty": [ + "category", + "greycoat" + ], + "enot": [ + "eton", + "note", + "tone" + ], + "eilv": [ + "evil", + "levi", + "live", + "veil", + "vile", + "vlei" + ], + "aeglr": [ + "argel", + "argle", + "ergal", + "garle", + "glare", + "lager", + "large", + "regal" + ], + "aegllry": [ + "allergy", + "gallery", + "largely", + "regally" + ], + "abelt": [ + "ablet", + "batel", + "belat", + "blate", + "bleat", + "tabel", + "table" + ], + "eehorvw": [ + "everwho", + "however", + "whoever" + ], + "aellry": [ + "rallye", + "really" + ], + "acinot": [ + "action", + "atonic", + "cation" + ], + "arstt": [ + "start", + "tarts" + ], + "eeirss": [ + "seiser", + "series", + "sirees" + ], + "air": [ + "air", + "ira", + "ria" + ], + "ahmnu": [ + "human", + "nahum" + ], + "esy": [ + "yes", + "sey", + "sye" + ], + "cdenos": [ + "codens", + "second" + ], + "hot": [ + "hot", + "tho" + ], + "cost": [ + "cost", + "cots", + "scot" + ], + "achmr": [ + "charm", + "march" + ], + "asy": [ + "ays", + "yas", + "say" + ], + "acdeilm": [ + "camelid", + "claimed", + "decimal", + "declaim", + "medical" + ], + "estt": [ + "sett", + "stet", + "test" + ], + "definr": [ + "finder", + "friend", + "redfin", + "refind" + ], + "eerrsv": [ + "revers", + "server", + "verser" + ], + "dstuy": [ + "dusty", + "study" + ], + "acrt": [ + "cart", + "trac" + ], + "aceilrst": [ + "altrices", + "articles", + "recitals", + "selictar", + "sterical" + ], + "ans": [ + "ans", + "san" + ], + "aagin": [ + "again", + "angia" + ], + "alpy": [ + "paly", + "pyal", + "pyla", + "play" + ], + "eisssu": [ + "issues", + "suisse" + ], + "ailpr": [ + "april", + "parli", + "pilar", + "ripal" + ], + "eenrv": [ + "nerve", + "never" + ], + "erssu": [ + "ruses", + "russe", + "suers", + "sures", + "users" + ], + "eerstt": [ + "retest", + "setter", + "street", + "tester" + ], + "ciopt": [ + "optic", + "picot", + "topic" + ], + "ghinst": [ + "nights", + "snight", + "things" + ], + "giknorw": [ + "kingrow", + "working" + ], + "aaginst": [ + "against", + "antisag" + ], + "atx": [ + "tax", + "xat" + ], + "enoprs": [ + "person", + "speron" + ], + "below": [ + "below", + "bowel", + "bowle", + "elbow" + ], + "beilmo": [ + "bemoil", + "emboil", + "emboli", + "mobile" + ], + "elss": [ + "less", + "sels" + ], + "got": [ + "got", + "tog" + ], + "aprty": [ + "party", + "trypa" + ], + "gilno": [ + "lingo", + "login" + ], + "densttu": [ + "student", + "stunted" + ], + "elt": [ + "elt", + "let", + "tel" + ], + "effors": [ + "offers", + "reffos" + ], + "aegll": [ + "egall", + "legal" + ], + "eorsst": [ + "retoss", + "rosets", + "sorest", + "sortes", + "stores", + "torses", + "tosser" + ], + "deis": [ + "deis", + "desi", + "dies", + "ides", + "ised", + "seid", + "side" + ], + "act": [ + "act", + "cat" + ], + "der": [ + "der", + "erd", + "red" + ], + "acilos": [ + "colias", + "scolia", + "social" + ], + "eoqtu": [ + "quote", + "toque" + ], + "aaegglnu": [ + "ganguela", + "langauge", + "language" + ], + "orsty": [ + "ryots", + "sorty", + "story", + "stroy", + "tyros", + "troys" + ], + "ells": [ + "ells", + "sell" + ], + "inoopst": [ + "options", + "potions" + ], + "aerst": [ + "arest", + "aster", + "astre", + "rates", + "reast", + "resat", + "serta", + "stare", + "strae", + "tares", + "tarse", + "tears", + "teras", + "treas" + ], + "aceert": [ + "cerate", + "cetera", + "create", + "ecarte" + ], + "eky": [ + "key", + "kye" + ], + "bdoy": [ + "body", + "boyd", + "doby" + ], + "defil": [ + "felid", + "fidel", + "field", + "filed", + "flied" + ], + "efw": [ + "few", + "wef" + ], + "aest": [ + "ates", + "east", + "eats", + "etas", + "sate", + "seat", + "seta", + "teas" + ], + "aeppr": [ + "paper", + "rappe" + ], + "egilns": [ + "glinse", + "ingles", + "lignes", + "seling", + "single", + "slinge" + ], + "aeg": [ + "age", + "gae" + ], + "aeelmpx": [ + "example", + "exempla" + ], + "aelstt": [ + "latest", + "sattle", + "taslet" + ], + "ador": [ + "ador", + "dora", + "orad", + "road" + ], + "ghint": [ + "night", + "thing" + ], + "aestx": [ + "taxes", + "texas" + ], + "cot": [ + "cot", + "cto", + "oct", + "otc" + ], + "apy": [ + "yap", + "pay", + "pya" + ], + "ekopr": [ + "poker", + "proke" + ], + "assttu": [ + "status", + "suttas" + ], + "beorsw": [ + "bowers", + "bowser", + "browse" + ], + "eissu": [ + "issue", + "susie" + ], + "aegnr": [ + "anger", + "areng", + "grane", + "range", + "regna", + "renga" + ], + "eellrs": [ + "resell", + "seller" + ], + "cortu": [ + "court", + "crout", + "turco" + ], + "elrstu": [ + "luster", + "lustre", + "result", + "rustle", + "sutler", + "ulster" + ], + "eirtw": [ + "twier", + "twire", + "write" + ], + "arw": [ + "raw", + "war" + ], + "nov": [ + "nov", + "von" + ], + "effor": [ + "offer", + "reffo" + ], + "belu": [ + "bleu", + "blue", + "lube" + ], + "aesy": [ + "ayes", + "easy", + "eyas", + "yeas" + ], + "efils": [ + "felis", + "files", + "flies" + ], + "eeqrstu": [ + "quester", + "request" + ], + "achin": [ + "chain", + "chian", + "china" + ], + "ceiprtu": [ + "cuprite", + "picture" + ], + "deens": [ + "denes", + "dense", + "needs" + ], + "ety": [ + "ety", + "yet", + "tye" + ], + "ajmor": [ + "jarmo", + "joram", + "major" + ], + "arst": [ + "arts", + "astr", + "rats", + "sart", + "star", + "stra", + "tars", + "tsar" + ], + "aaers": [ + "arase", + "areas" + ], + "aceps": [ + "capes", + "paces", + "scape", + "space" + ], + "adhn": [ + "dhan", + "hand" + ], + "nsu": [ + "nus", + "sun", + "uns" + ], + "aghinnostw": [ + "nowanights", + "washington" + ], + "eegimnt": [ + "meeting", + "teeming", + "tegmine" + ], + "eeinrstt": [ + "insetter", + "interest", + "interset", + "sternite", + "trientes" + ], + "eekp": [ + "keep", + "peek", + "peke" + ], + "eenrt": [ + "enter", + "entre", + "neter", + "renet", + "rente", + "terne", + "treen" + ], + "aehrs": [ + "asher", + "earsh", + "hares", + "hears", + "rheas", + "share", + "shear" + ], + "adegnr": [ + "danger", + "gander", + "garden", + "grande", + "ranged" + ], + "aceimnops": [ + "campesino", + "companies" + ], + "deilst": [ + "delist", + "desilt", + "idlest", + "listed", + "silted", + "tildes" + ], + "abby": [ + "abby", + "baby" + ], + "eegnry": [ + "energy", + "gyrene", + "greeny", + "ygerne" + ], + "nru": [ + "run", + "urn" + ], + "ent": [ + "net", + "ten" + ], + "eiorsst": [ + "isoster", + "rosiest", + "rossite", + "sorites", + "sorties", + "stories", + "trioses" + ], + "ptu": [ + "put", + "tup" + ], + "eoprrst": [ + "porters", + "pretors", + "reports", + "sporter", + "strepor" + ], + "rty": [ + "tyr", + "try" + ], + "aegims": [ + "ageism", + "images" + ], + "deeinprst": [ + "president", + "serpentid" + ], + "ceinot": [ + "conite", + "eciton", + "noetic", + "notice", + "octine" + ], + "adeh": [ + "hade", + "haed", + "head" + ], + "adior": [ + "aroid", + "doria", + "radio" + ], + "ilntu": [ + "unlit", + "until" + ], + "cloor": [ + "color", + "corol", + "crool" + ], + "efls": [ + "fels", + "self" + ], + "cdeilnsu": [ + "includes", + "nuclides", + "unsliced" + ], + "ceno": [ + "cone", + "econ", + "once" + ], + "ehorst": [ + "horste", + "hoster", + "others", + "reshot", + "throes", + "tosher" + ], + "aelst": [ + "astel", + "least", + "salet", + "setal", + "slate", + "stale", + "steal", + "stela", + "taels", + "tales", + "teals", + "tesla" + ], + "glo": [ + "gol", + "log" + ], + "definrs": [ + "finders", + "friends", + "redfins", + "refinds" + ], + "afq": [ + "faq", + "qaf" + ], + "adert": [ + "adret", + "dater", + "derat", + "detar", + "drate", + "rated", + "tarde", + "tared", + "trade", + "tread" + ], + "deiinot": [ + "edition", + "odinite", + "otidine", + "tineoid" + ], + "acrs": [ + "arcs", + "cars", + "scar", + "srac" + ], + "aeegmsss": [ + "megasses", + "messages" + ], + "abel": [ + "abel", + "able", + "albe", + "bael", + "bale", + "beal", + "bela", + "blae", + "blea" + ], + "deioprsv": [ + "disprove", + "provides" + ], + "aadelry": [ + "aleyard", + "already" + ], + "eegnr": [ + "genre", + "green", + "grene", + "neger", + "reneg" + ], + "deisstu": [ + "studies", + "tissued" + ], + "celos": [ + "cloes", + "close", + "coles", + "socle" + ], + "deirv": [ + "deriv", + "diver", + "drive", + "rived", + "verdi" + ], + "aeelrsv": [ + "laveers", + "leavers", + "reveals", + "several", + "vealers" + ], + "dglo": [ + "glod", + "gold" + ], + "eps": [ + "esp", + "pes", + "sep" + ], + "horst": [ + "horst", + "short" + ], + "lot": [ + "lot", + "tlo", + "tol" + ], + "aks": [ + "ask", + "kas", + "sak" + ], + "deiilmt": [ + "delimit", + "limited" + ], + "aemns": [ + "amens", + "manes", + "manse", + "means", + "mensa", + "names", + "nemas", + "samen", + "senam" + ], + "cdeiorrt": [ + "creditor", + "director" + ], + "adily": [ + "daily", + "lydia" + ], + "abceh": [ + "bache", + "beach" + ], + "apst": [ + "apts", + "past", + "pats", + "spat", + "stap", + "taps" + ], + "nopu": [ + "noup", + "puno", + "upon" + ], + "deiopr": [ + "dopier", + "period" + ], + "aeehrtw": [ + "weather", + "whereat", + "wreathe" + ], + "amr": [ + "arm", + "mar", + "ram" + ], + "deno": [ + "done", + "node" + ], + "accehilnt": [ + "catchline", + "technical" + ], + "opr": [ + "por", + "pro" + ], + "eginor": [ + "eringo", + "ignore", + "region" + ], + "cdeorr": [ + "corder", + "record" + ], + "cdeorrs": [ + "corders", + "records" + ], + "aacdelnr": [ + "calander", + "calandre", + "calendar", + "landrace" + ], + "cosst": [ + "costs", + "scots" + ], + "aeemnsttt": [ + "statement", + "testament" + ], + "aprst": [ + "parts", + "prats", + "spart", + "sprat", + "strap", + "tarps", + "traps" + ], + "agu": [ + "aug", + "gau" + ], + "eerv": [ + "ever", + "reve", + "veer" + ], + "addlnoosw": [ + "downloads", + "woodlands" + ], + "aelry": [ + "early", + "layer", + "leary", + "relay" + ], + "eilms": [ + "limes", + "melis", + "miles", + "slime", + "smile" + ], + "dnosu": [ + "nodus", + "ounds", + "sound" + ], + "ceeorrsu": [ + "recourse", + "resource" + ], + "eenprst": [ + "penster", + "present", + "repents", + "serpent", + "strepen" + ], + "ago": [ + "ago", + "goa" + ], + "dorw": [ + "drow", + "word" + ], + "apr": [ + "apr", + "par", + "rap" + ], + "einrttw": [ + "twinter", + "written" + ], + "ghinost": [ + "hosting", + "onsight" + ], + "elrsu": [ + "lures", + "luser", + "rules", + "sluer" + ], + "afiln": [ + "alfin", + "final", + "flain" + ], + "adltu": [ + "adult", + "dault", + "dulat" + ], + "ceikstt": [ + "sticket", + "tickets" + ], + "aiv": [ + "iva", + "vai", + "via" + ], + "acehp": [ + "chape", + "cheap", + "peach" + ], + "diks": [ + "disk", + "kids", + "skid" + ], + "eimnstu": [ + "minuets", + "minutes", + "mistune", + "mutines" + ], + "eels": [ + "eels", + "else", + "lees", + "lese", + "seel", + "sele", + "slee" + ], + "ckor": [ + "cork", + "rock" + ], + "adeginr": [ + "degrain", + "deraign", + "deringa", + "gradine", + "grained", + "reading" + ], + "ciopst": [ + "copist", + "coptis", + "optics", + "picots", + "postic", + "topics" + ], + "abd": [ + "abd", + "bad", + "dab" + ], + "ipst": [ + "pist", + "pits", + "spit", + "tips" + ], + "lpsu": [ + "plus", + "puls", + "slup" + ], + "ceorv": [ + "corve", + "cover" + ], + "deit": [ + "deti", + "diet", + "dite", + "edit", + "tide", + "tied" + ], + "ceenprt": [ + "percent", + "precent" + ], + "afst": [ + "fast", + "fats", + "saft" + ], + "ceht": [ + "chet", + "echt", + "etch", + "tche", + "tech" + ], + "eemt": [ + "meet", + "mete", + "teem" + ], + "afr": [ + "arf", + "far", + "fra" + ], + "aelpry": [ + "parley", + "pearly", + "player", + "rapely", + "replay" + ], + "aegmnry": [ + "germany", + "mangery" + ], + "amnotu": [ + "amount", + "moutan", + "outman" + ], + "eefl": [ + "feel", + "fele", + "flee", + "leef" + ], + "abkn": [ + "bank", + "knab", + "nabk" + ], + "ikrs": [ + "irks", + "kris", + "risk" + ], + "adels": [ + "dales", + "deals", + "lades", + "lased", + "leads", + "slade" + ], + "aiorsuv": [ + "saviour", + "various" + ], + "dorsw": [ + "sword", + "words" + ], + "notw": [ + "nowt", + "town", + "wont" + ], + "aehrt": [ + "earth", + "hater", + "heart", + "herat", + "rathe" + ], + "cdeeeirv": [ + "deceiver", + "received" + ], + "inopst": [ + "instop", + "pintos", + "piston", + "pitons", + "points", + "postin" + ], + "aacemr": [ + "acream", + "camera", + "mareca" + ], + "osty": [ + "toys", + "tosy" + ], + "deeegirrst": [ + "deregister", + "registered" + ], + "acelr": [ + "carle", + "ceral", + "clare", + "clear", + "lacer" + ], + "fglo": [ + "flog", + "golf" + ], + "adimno": [ + "amidon", + "daimon", + "domain", + "domina" + ], + "acehprt": [ + "chapter", + "patcher", + "repatch" + ], + "aekms": [ + "kames", + "makes", + "samek" + ], + "deiw": [ + "wide", + "wied" + ], + "aaegmnr": [ + "gearman", + "manager" + ], + "iinoopst": [ + "position", + "sopition" + ], + "orst": [ + "orts", + "rots", + "sort", + "stor", + "tors" + ], + "delmos": [ + "models", + "seldom", + "somdel" + ], + "acehilm": [ + "michael", + "micheal" + ], + "acess": [ + "cases", + "casse", + "scase" + ], + "epst": [ + "pest", + "pets", + "sept", + "spet", + "step" + ], + "eilmps": [ + "impels", + "mespil", + "simple" + ], + "enno": [ + "neon", + "none" + ], + "eeilrssw": [ + "weirless", + "wireless" + ], + "ceeilns": [ + "license", + "selenic", + "silence" + ], + "alpu": [ + "paul", + "upla" + ], + "aekl": [ + "kale", + "lake", + "leak" + ], + "ehlow": [ + "howel", + "whole" + ], + "aelrt": [ + "alert", + "alter", + "artel", + "later", + "ratel", + "retal", + "taler", + "telar" + ], + "abcis": [ + "bacis", + "basic" + ], + "hossw": [ + "shows", + "swosh" + ], + "dehmot": [ + "method", + "mothed" + ], + "cemorsstu": [ + "costumers", + "customers" + ], + "eenoprss": [ + "pessoner", + "response" + ], + "acceiprt": [ + "accipter", + "practice" + ], + "efir": [ + "fire", + "reif", + "rife" + ], + "adhiloy": [ + "hyaloid", + "hyoidal", + "holiday" + ], + "acht": [ + "cath", + "chat", + "tach" + ], + "aglno": [ + "along", + "anglo", + "gonal", + "lango", + "logan", + "longa", + "nogal" + ], + "agmno": [ + "among", + "mango", + "ngoma" + ], + "adeht": [ + "death", + "hated" + ], + "deeps": [ + "deeps", + "pedes", + "speed" + ], + "ceinorstu": [ + "countries", + "cretinous", + "neurotics" + ], + "loss": [ + "loss", + "sols" + ], + "acef": [ + "cafe", + "face" + ], + "cdinostu": [ + "conduits", + "discount", + "noctuids" + ], + "acdeert": [ + "catered", + "cedrate", + "cerated", + "created", + "reacted" + ], + "bit": [ + "bit", + "tib" + ], + "aceeinrs": [ + "cerasein", + "increase", + "resiance" + ], + "adeeirstv": [ + "advertise", + "derivates" + ], + "abes": [ + "base", + "besa", + "sabe", + "seba" + ], + "aenr": [ + "anre", + "aren", + "arne", + "earn", + "nare", + "near", + "rane" + ], + "ffstu": [ + "stuff", + "tuffs" + ], + "aegorst": [ + "garotes", + "orgeats", + "storage", + "tagsore" + ], + "dgino": [ + "dingo", + "doing", + "gondi", + "gonid" + ], + "alnos": [ + "loans", + "salon", + "sloan", + "solan" + ], + "ehoss": [ + "hoses", + "shoes" + ], + "aenrtu": [ + "aunter", + "auntre", + "nature" + ], + "deorrs": [ + "dorser", + "orders" + ], + "nrtu": [ + "runt", + "trun", + "turn" + ], + "enost": [ + "notes", + "onset", + "seton", + "steno", + "stone", + "tenso", + "tones" + ], + "gikn": [ + "gink", + "king" + ], + "admnoy": [ + "amydon", + "dynamo", + "monday" + ], + "cips": [ + "pics", + "spic" + ], + "aellorv": [ + "allover", + "overall" + ], + "aby": [ + "aby", + "bay" + ], + "eens": [ + "ense", + "esne", + "nese", + "seen", + "snee" + ], + "aelprsy": [ + "asperly", + "parleys", + "parsley", + "pyrales", + "players", + "replays", + "sparely", + "splayer" + ], + "eeginn": [ + "engine", + "ingene" + ], + "oprt": [ + "port", + "trop" + ], + "aegilnor": [ + "geraniol", + "regional" + ], + "aderstt": [ + "started", + "tetrads" + ], + "abr": [ + "abr", + "arb", + "bar", + "bra", + "rab" + ], + "eisvw": [ + "swive", + "views", + "wives" + ], + "bdelou": [ + "dobule", + "double" + ], + "dgo": [ + "dog", + "god" + ], + "ceenrs": [ + "censer", + "scerne", + "screen", + "secern" + ], + "noos": [ + "oons", + "soon" + ], + "eilns": [ + "elsin", + "lenis", + "liens", + "lines", + "niels", + "silen", + "sline" + ], + "ceinnotu": [ + "contineu", + "continue" + ], + "acorss": [ + "across", + "oscars" + ], + "einprrt": [ + "printer", + "reprint" + ], + "eru": [ + "rue", + "ure" + ], + "dimn": [ + "midn", + "mind" + ], + "ceeilnost": [ + "elections", + "selection" + ], + "acinos": [ + "casino", + "sonica" + ], + "lost": [ + "lost", + "lots", + "slot" + ], + "ortu": [ + "outr", + "rout", + "toru", + "tour" + ], + "emnu": [ + "menu", + "neum" + ], + "ehop": [ + "hope", + "peho" + ], + "eilrsv": [ + "ervils", + "livers", + "livres", + "silver", + "sliver" + ], + "deiins": [ + "deisin", + "indies", + "inside" + ], + "aemrtu": [ + "mature", + "tamure" + ], + "elor": [ + "lore", + "orle", + "role" + ], + "acem": [ + "acme", + "came", + "mace" + ], + "aceinrt": [ + "centiar", + "ceratin", + "certain", + "citrean", + "creatin", + "crinate", + "nacrite", + "nectria" + ], + "rsu": [ + "rus", + "sur", + "urs" + ], + "elorw": [ + "lower", + "owler", + "rowel" + ], + "mno": [ + "mon", + "nom" + ], + "cmo": [ + "com", + "moc" + ], + "efin": [ + "enif", + "fine", + "neif", + "nife" + ], + "ags": [ + "asg", + "gas", + "sag" + ], + "isx": [ + "six", + "xis" + ], + "bhsu": [ + "bush", + "hubs" + ], + "acdeiv": [ + "advice", + "vedaic" + ], + "aceerr": [ + "career", + "carree" + ], + "aiilmrty": [ + "limitary", + "military" + ], + "aelnrt": [ + "altern", + "antler", + "learnt", + "rental", + "ternal" + ], + "eenst": [ + "steen", + "teens", + "tense" + ], + "ast": [ + "ast", + "sat", + "sta", + "tas" + ], + "bdi": [ + "bid", + "dib" + ], + "dikn": [ + "dink", + "kind" + ], + "eellrss": [ + "resells", + "sellers" + ], + "abcel": [ + "cable", + "caleb" + ], + "aelsuv": [ + "alveus", + "avulse", + "values" + ], + "cgimno": [ + "coming", + "gnomic" + ], + "abeilns": [ + "albines", + "bensail", + "lesbian" + ], + "acehimn": [ + "chimane", + "machine" + ], + "gloo": [ + "golo", + "gool", + "logo" + ], + "cein": [ + "cine", + "nice" + ], + "ceors": [ + "ceros", + "cores", + "corse", + "crose", + "score" + ], + "ceilnt": [ + "client", + "lentic" + ], + "enrrstu": [ + "returns", + "turners" + ], + "aacilpt": [ + "capital", + "palatic" + ], + "aelmps": [ + "maples", + "sample" + ], + "enst": [ + "nest", + "nets", + "sent", + "sten", + "tens" + ], + "adel": [ + "dale", + "deal", + "lade", + "lead", + "leda" + ], + "ccehio": [ + "choice", + "echoic" + ], + "entw": [ + "newt", + "went" + ], + "ceorssu": [ + "courses", + "rescous", + "secours", + "sources", + "sucrose" + ], + "cemnorsu": [ + "consumer", + "cornmuse", + "mucrones" + ], + "aioprrt": [ + "airport", + "paritor" + ], + "airstt": [ + "artist", + "strait", + "strati", + "traist", + "traits" + ], + "deiostu": [ + "outside", + "tedious" + ], + "demo": [ + "demo", + "dome", + "mode", + "moed" + ], + "adeis": [ + "aides", + "aside", + "ideas", + "sadie" + ], + "emmrsu": [ + "rummes", + "summer" + ], + "dew": [ + "dew", + "wed" + ], + "eprsu": [ + "purse", + "resup", + "sprue", + "super" + ], + "aelm": [ + "alem", + "alme", + "amel", + "lame", + "leam", + "male", + "meal", + "mela" + ], + "aemrtt": [ + "matter", + "mettar" + ], + "cmostu": [ + "custom", + "muscot" + ], + "almost": [ + "almost", + "smalto", + "stomal" + ], + "koot": [ + "koto", + "toko", + "took" + ], + "aains": [ + "asian", + "naias", + "sanai" + ], + "deiort": [ + "dotier", + "editor", + "rioted", + "triode" + ], + "acesu": [ + "cause", + "sauce" + ], + "aeilnoptt": [ + "peltation", + "potential" + ], + "gnos": [ + "nogs", + "snog", + "song" + ], + "aelt": [ + "atle", + "laet", + "late", + "leat", + "tael", + "tale", + "teal", + "tela" + ], + "adei": [ + "aide", + "deia", + "eadi", + "idea" + ], + "moors": [ + "moors", + "rooms" + ], + "accenr": [ + "cancer", + "crance" + ], + "aenors": [ + "arseno", + "reason", + "senora" + ], + "loot": [ + "loot", + "loto", + "tool" + ], + "aenrsw": [ + "answer", + "resawn" + ], + "eopprsu": [ + "peropus", + "purpose" + ], + "bde": [ + "bde", + "bed", + "deb" + ], + "aeginoprt": [ + "operating", + "pignorate" + ], + "amps": [ + "amps", + "maps", + "pams", + "samp" + ], + "aginrst": [ + "gastrin", + "gratins", + "ratings", + "staring" + ], + "aglss": [ + "glass", + "slags" + ], + "etu": [ + "tue", + "ute" + ], + "himst": [ + "isthm", + "smith" + ], + "ahknt": [ + "hankt", + "thank" + ], + "eeehlnopt": [ + "phenetole", + "telephone" + ], + "oprst": [ + "ports", + "prost", + "sport", + "sprot", + "strop" + ], + "adery": [ + "deary", + "deray", + "yeard", + "rayed", + "ready" + ], + "aailmn": [ + "almain", + "animal", + "lamina", + "manila" + ], + "ceersu": [ + "cereus", + "ceruse", + "cesure", + "recuse", + "rescue", + "secure" + ], + "aeinooprst": [ + "anisotrope", + "operations" + ], + "ilmpsy": [ + "limpsy", + "simply" + ], + "achiinrst": [ + "christian", + "christina", + "trichinas" + ], + "addennrstu": [ + "understand", + "unstranded" + ], + "inoopt": [ + "option", + "potion" + ], + "aemrst": [ + "armets", + "martes", + "master", + "maters", + "matres", + "ramets", + "remast", + "stream", + "tamers" + ], + "aelnrst": [ + "antlers", + "rentals", + "saltern", + "slanter", + "starnel", + "sternal" + ], + "aes": [ + "aes", + "ase", + "sae", + "sea" + ], + "bdloo": [ + "blood", + "boldo" + ], + "behilprsu": [ + "publisher", + "republish" + ], + "aint": [ + "aint", + "anti", + "inta", + "tain", + "tina" + ], + "aenprst": [ + "arpents", + "enrapts", + "entraps", + "parents", + "pastern", + "trepans" + ], + "aikno": [ + "ikona", + "konia" + ], + "acimpt": [ + "campit", + "impact" + ], + "cehiknt": [ + "kitchen", + "thicken" + ], + "aacilnor": [ + "carolina", + "colnaria", + "conarial" + ], + "eeiopprrst": [ + "peripteros", + "properties" + ], + "hips": [ + "hips", + "phis", + "pish", + "ship" + ], + "enorsw": [ + "owners", + "resown", + "rowens", + "worsen" + ], + "adeeiss": [ + "disease", + "seaside" + ], + "ailty": [ + "ality", + "italy", + "laity", + "taily" + ], + "ceefprt": [ + "perfect", + "prefect" + ], + "ahir": [ + "ahir", + "hair" + ], + "abiss": [ + "absis", + "basis", + "bassi", + "isbas" + ], + "ceiist": [ + "cities", + "iciest" + ], + "acdeinst": [ + "disenact", + "distance" + ], + "eert": [ + "reet", + "rete", + "teer", + "tree" + ], + "eeprt": [ + "erept", + "peert", + "peter", + "petre" + ], + "eenrsu": [ + "ensuer", + "ensure", + "enures", + "unsere" + ], + "hstu": [ + "hust", + "huts", + "shut", + "thus", + "tush" + ], + "aertx": [ + "extra", + "retax", + "taxer" + ], + "degisu": [ + "guides", + "guised" + ], + "eiqtu": [ + "quiet", + "quite" + ], + "cdeeelst": [ + "deselect", + "selected" + ], + "boy": [ + "boy", + "yob" + ], + "ehors": [ + "heros", + "hoers", + "horse", + "shoer", + "shore" + ], + "eotv": [ + "veto", + "voet", + "vote" + ], + "adforrw": [ + "forward", + "froward" + ], + "eflorsw": [ + "flowers", + "fowlers", + "reflows", + "wolfers" + ], + "arsst": [ + "stars", + "trass", + "tsars" + ], + "ilsst": [ + "lists", + "silts", + "slits" + ], + "enorw": [ + "owner", + "reown", + "rewon", + "rowen" + ], + "aeilrt": [ + "aliter", + "lirate", + "retail", + "retial", + "tailer" + ], + "aailmns": [ + "animals", + "laminas", + "manilas" + ], + "cdeilrty": [ + "directly", + "tridecyl" + ], + "aswy": [ + "yaws", + "sway", + "ways" + ], + "nos": [ + "nos", + "ons", + "son" + ], + "elru": [ + "lure", + "rule" + ], + "acm": [ + "cam", + "mac" + ], + "ghinosu": [ + "housing", + "hugonis" + ], + "aekst": [ + "keats", + "skate", + "skeat", + "stake", + "steak", + "takes", + "teaks" + ], + "gmt": [ + "mgt", + "mtg" + ], + "ginrty": [ + "tyring", + "trigyn", + "trying" + ], + "ehmort": [ + "mother", + "thermo" + ], + "cddeeinors": [ + "considered", + "deconsider" + ], + "dlot": [ + "dolt", + "told" + ], + "inptu": [ + "input", + "punti" + ], + "eeft": [ + "feet", + "fete" + ], + "aegnt": [ + "agent", + "etang" + ], + "bin": [ + "bin", + "nib" + ], + "demnor": [ + "modern", + "morned", + "normed", + "rodmen" + ], + "einors": [ + "irones", + "noires", + "nosier", + "rosine", + "senior", + "soneri" + ], + "adeilnr": [ + "ireland", + "lindera" + ], + "aceghint": [ + "cheating", + "teaching" + ], + "door": [ + "door", + "odor", + "oord", + "ordo", + "rood" + ], + "adgnr": [ + "drang", + "grand" + ], + "eginstt": [ + "setting", + "testing" + ], + "ailrt": [ + "litra", + "trail", + "trial" + ], + "aceghr": [ + "charge", + "creagh" + ], + "instu": [ + "inust", + "sintu", + "suint", + "tunis", + "unist", + "units" + ], + "adeinst": [ + "destain", + "detains", + "instead", + "sainted", + "satined", + "stained" + ], + "cloo": [ + "cool", + "loco" + ], + "eortw": [ + "rowet", + "rowte", + "tower", + "wrote" + ], + "eeinrt": [ + "entier", + "entire", + "nerite", + "triene" + ], + "adegiln": [ + "adeling", + "aligned", + "dealing", + "leading" + ], + "aelmt": [ + "amlet", + "metal" + ], + "efinsst": [ + "fitness", + "infests" + ], + "aais": [ + "aias", + "asia" + ], + "essu": [ + "sues", + "uses" + ], + "opttuu": [ + "output", + "putout" + ], + "aeegrrt": [ + "greater", + "regrate", + "terrage" + ], + "airsstt": [ + "artists", + "straits", + "tsarist" + ], + "eilnoorstu": [ + "resolution", + "solutioner" + ], + "eemss": [ + "messe", + "seems", + "semes" + ], + "apss": [ + "asps", + "pass", + "saps", + "spas" + ], + "aeilnorst": [ + "lairstone", + "orientals", + "orleanist", + "relations", + "serotinal", + "tensorial" + ], + "rsttu": [ + "strut", + "sturt", + "trust" + ], + "anv": [ + "avn", + "nav", + "van" + ], + "acinnost": [ + "actinons", + "canonist", + "contains", + "sanction", + "santonic", + "sonantic" + ], + "einosss": [ + "essoins", + "osseins", + "session", + "sissone" + ], + "ilmtu": [ + "multi", + "tumli" + ], + "aacinotv": [ + "octavian", + "octavina", + "vacation" + ], + "ikns": [ + "inks", + "kins", + "sink", + "skin" + ], + "eprv": [ + "perv", + "prev" + ], + "ads": [ + "ads", + "das", + "sad" + ], + "amry": [ + "army", + "yarm", + "mary", + "myra" + ], + "cdeeeptx": [ + "excepted", + "expected" + ], + "ginr": [ + "girn", + "grin", + "ring" + ], + "adegr": [ + "edgar", + "gader", + "garde", + "grade", + "raged" + ], + "opp": [ + "opp", + "pop" + ], + "efilrt": [ + "fertil", + "filter", + "filtre", + "lifter", + "relift", + "trifle" + ], + "eglnor": [ + "longer", + "relong" + ], + "int": [ + "int", + "nit", + "tin" + ], + "aelnp": [ + "alpen", + "nepal", + "panel", + "penal", + "plane", + "plena" + ], + "aegmnr": [ + "engram", + "german", + "manger", + "ragmen" + ], + "adefltu": [ + "default", + "faulted" + ], + "eeiqrru": [ + "querier", + "require" + ], + "bosy": [ + "boys", + "yobs", + "sybo" + ], + "deep": [ + "deep", + "depe", + "peed" + ], + "allosw": [ + "allows", + "sallow", + "swallo" + ], + "erst": [ + "erst", + "rest", + "rets", + "sert", + "ster", + "stre", + "tres" + ], + "einoprt": [ + "pointer", + "protein", + "pterion", + "repoint", + "tropein", + "tropine" + ], + "deeoprrt": [ + "deporter", + "reported" + ], + "loop": [ + "loop", + "polo", + "pool" + ], + "ciilopst": [ + "colpitis", + "politics", + "psilotic" + ], + "abdors": [ + "adsorb", + "boards", + "broads", + "dobras" + ], + "aeiprst": [ + "parties", + "pastier", + "piaster", + "piastre", + "pirates", + "raspite", + "spirate", + "tapiser", + "traipse" + ], + "eey": [ + "eye", + "yee" + ], + "adeeelrs": [ + "released", + "resealed" + ], + "aegst": [ + "gates", + "geast", + "getas", + "stage" + ], + "aegrtt": [ + "gatter", + "target" + ], + "ceeptx": [ + "except", + "expect" + ], + "bsu": [ + "bus", + "sub" + ], + "abemy": [ + "beamy", + "embay", + "maybe" + ], + "acelps": [ + "places", + "scapel" + ], + "ainps": [ + "nipas", + "pains", + "pians", + "pinas", + "pisan", + "sapin", + "spain", + "spina" + ], + "cet": [ + "cte", + "etc", + "tec" + ], + "einrtw": [ + "twiner", + "winter" + ], + "eeprrssu": [ + "perusers", + "pressure" + ], + "ceor": [ + "cero", + "core" + ], + "abekr": [ + "baker", + "brake", + "break", + "kebar" + ], + "eopprssu": [ + "purposes", + "supposer" + ], + "ghhoorttuu": [ + "outthrough", + "throughout" + ], + "esst": [ + "sets", + "tess" + ], + "acden": [ + "acned", + "caned", + "dance", + "decan" + ], + "efilst": [ + "filets", + "fistle", + "fliest", + "flites", + "itself", + "stifle" + ], + "aepprs": [ + "papers", + "sapper" + ], + "agilnpy": [ + "playing", + "plygain" + ], + "adeerr": [ + "dearer", + "reader", + "reared", + "redare", + "redear", + "reread" + ], + "ailrtuv": [ + "virtual", + "vitular" + ], + "aenrssw": [ + "answers", + "rawness" + ], + "enrt": [ + "entr", + "rent", + "tern" + ], + "als": [ + "als", + "las", + "sal", + "sla" + ], + "eemort": [ + "emoter", + "meteor", + "remote" + ], + "aelpp": [ + "appel", + "apple", + "pepla" + ], + "adegginrr": [ + "regarding", + "regrading" + ], + "imn": [ + "min", + "nim" + ], + "eemorv": [ + "evermo", + "remove" + ], + "adi": [ + "aid", + "dia", + "ida" + ], + "host": [ + "host", + "hots", + "shot", + "soth", + "thos", + "tosh" + ], + "aceehrst": [ + "cheaters", + "hectares", + "recheats", + "teachers" + ], + "bins": [ + "bins", + "nibs", + "snib" + ], + "aalmnu": [ + "alumna", + "manual" + ], + "aegnst": [ + "agents", + "estang", + "stagne" + ], + "acdeeinrs": [ + "ardencies", + "ecardines", + "increased" + ], + "aeiprr": [ + "pairer", + "rapier", + "repair" + ], + "afir": [ + "fair", + "fiar", + "raif" + ], + "eelst": [ + "leets", + "leste", + "sleet", + "slete", + "steel", + "stele", + "teles" + ], + "defix": [ + "defix", + "fixed" + ], + "gnorw": [ + "grown", + "wrong" + ], + "aiprs": [ + "pairs", + "paris", + "parsi", + "sarip", + "spair", + "spira" + ], + "egst": [ + "gest", + "gets", + "steg", + "stge", + "tegs" + ], + "ceorst": [ + "corset", + "cortes", + "coster", + "croset", + "escort", + "recost", + "rectos", + "scoter", + "sector" + ], + "eeiqrrsu": [ + "queriers", + "requires" + ], + "aft": [ + "aft", + "fat" + ], + "aefhrt": [ + "father", + "freath", + "hafter", + "trefah" + ], + "cceeilrt": [ + "electric", + "lectrice" + ], + "eoqstu": [ + "quotes", + "toques" + ], + "adde": [ + "dade", + "dead", + "deda", + "edda" + ], + "ceeprst": [ + "recepts", + "respect", + "scepter", + "sceptre", + "specter", + "spectre" + ], + "eikm": [ + "miek", + "mike" + ], + "pst": [ + "pst", + "pts", + "spt", + "tps", + "tsp" + ], + "hortw": [ + "rowth", + "throw", + "whort", + "worth", + "wroth" + ], + "cdeeoprrsu": [ + "procedures", + "reproduces" + ], + "oopr": [ + "poor", + "proo", + "roop" + ], + "aceehrt": [ + "cheater", + "hectare", + "rechate", + "recheat", + "reteach", + "teacher" + ], + "eesy": [ + "eyes", + "yees", + "yese" + ], + "ekorrsw": [ + "reworks", + "workers" + ], + "afmr": [ + "farm", + "fram" + ], + "mot": [ + "mot", + "tom" + ], + "aceeirtv": [ + "creative", + "reactive" + ], + "acost": [ + "acost", + "actos", + "ascot", + "catso", + "coast", + "coats", + "costa", + "tacos", + "tacso", + "tasco", + "tosca" + ], + "aeegr": [ + "aeger", + "agree", + "eager", + "eagre", + "ragee" + ], + "aehr": [ + "hare", + "hear", + "hera", + "rhea" + ], + "aceerrs": [ + "careers", + "creaser", + "searcer" + ], + "egos": [ + "egos", + "goes", + "sego" + ], + "del": [ + "del", + "eld", + "led" + ], + "afn": [ + "fan", + "naf" + ], + "efmorr": [ + "former", + "reform" + ], + "aeegillrs": [ + "allergies", + "galleries" + ], + "dei": [ + "dei", + "die", + "ide" + ], + "deeenprst": [ + "presented", + "pretensed", + "repetends" + ], + "aflt": [ + "flat", + "laft" + ], + "flow": [ + "flow", + "fowl", + "wolf" + ], + "aceegins": [ + "agencies", + "agenesic", + "genesiac" + ], + "aenprt": [ + "arpent", + "enrapt", + "entrap", + "panter", + "parent", + "parten", + "pretan", + "pterna", + "trepan" + ], + "acghiimn": [ + "michigan", + "minhagic" + ], + "acels": [ + "alces", + "alecs", + "casel", + "claes", + "laces", + "scale" + ], + "adnst": [ + "dasnt", + "stand" + ], + "cemnooy": [ + "economy", + "monoecy" + ], + "eghhist": [ + "eighths", + "heights", + "highest" + ], + "aefmr": [ + "frame", + "fream" + ], + "aeeglns": [ + "angeles", + "senegal" + ], + "ahpt": [ + "path", + "phat" + ], + "aaailnrstu": [ + "australian", + "saturnalia" + ], + "cefhi": [ + "chief", + "fiche" + ], + "adeilt": [ + "detail", + "dietal", + "dilate", + "edital", + "tailed" + ], + "alsw": [ + "awls", + "laws", + "slaw" + ], + "acdeghn": [ + "changed", + "ganched" + ], + "ept": [ + "pet", + "pte" + ], + "adehr": [ + "derah", + "hared", + "heard", + "rheda" + ], + "aceln": [ + "ancle", + "canel", + "clean", + "lance", + "lenca" + ], + "aacfinr": [ + "african", + "francia" + ], + "guy": [ + "guy", + "yug" + ], + "eilstt": [ + "stilet", + "titles" + ], + "aeelnrtv": [ + "levanter", + "relevant", + "revelant" + ], + "ccennot": [ + "concent", + "connect" + ], + "bbeil": [ + "bible", + "blibe" + ], + "cpu": [ + "cpu", + "cup" + ], + "abekst": [ + "basket", + "betask" + ], + "addemn": [ + "damned", + "ddname", + "demand", + "madden" + ], + "eistu": [ + "etuis", + "suite" + ], + "aeinnottt": [ + "attention", + "tentation" + ], + "ikps": [ + "kips", + "pisk", + "skip", + "spik" + ], + "acinotu": [ + "auction", + "caution" + ], + "aegr": [ + "ager", + "agre", + "areg", + "gare", + "gear", + "rage" + ], + "eel": [ + "eel", + "lee" + ], + "acehlrs": [ + "charles", + "clasher", + "larches" + ], + "ainnot": [ + "anoint", + "nation" + ], + "fimr": [ + "firm", + "frim" + ], + "eensv": [ + "evens", + "neves", + "seven" + ], + "delor": [ + "lored", + "older" + ], + "iiillnos": [ + "illinois", + "illision" + ], + "eeelmnst": [ + "elements", + "steelmen" + ], + "eorrst": [ + "resort", + "retros", + "roster", + "sorter", + "storer" + ], + "admnor": [ + "random", + "rodman" + ], + "eiimnrst": [ + "interims", + "minister", + "misinter" + ], + "kloos": [ + "kolos", + "looks" + ], + "cdeiinorst": [ + "directions", + "discretion", + "soricident" + ], + "adginrt": [ + "darting", + "trading" + ], + "eforst": [ + "fetors", + "forest", + "forset", + "fortes", + "foster", + "fstore", + "softer" + ], + "aclls": [ + "calls", + "scall" + ], + "ehosw": [ + "howes", + "whose" + ], + "celopu": [ + "couple", + "culpeo" + ], + "deginn": [ + "ending", + "ginned" + ], + "ceilnst": [ + "clients", + "lentisc", + "scintle", + "stencil" + ], + "acinost": [ + "actions", + "atonics", + "cations" + ], + "eilnst": [ + "enlist", + "inlets", + "listen", + "silent", + "slinte", + "tinsel" + ], + "adekn": [ + "danke", + "kande", + "knead", + "naked" + ], + "aglo": [ + "gaol", + "goal", + "gola", + "olga" + ], + "dlos": [ + "dols", + "olds", + "slod", + "sold" + ], + "aekmrst": [ + "estmark", + "markets" + ], + "elostw": [ + "lowest", + "owlets", + "towels" + ], + "eilsv": [ + "elvis", + "evils", + "levis", + "lives", + "slive", + "veils" + ], + "aeehlrt": [ + "haltere", + "leather", + "tarheel" + ], + "deeeimnrt": [ + "determine", + "intermede" + ], + "almp": [ + "lamp", + "palm" + ], + "bbo": [ + "bob", + "obb" + ], + "aehpprs": [ + "perhaps", + "prehaps" + ], + "aeeillstt": [ + "satellite", + "telestial" + ], + "esstt": [ + "stets", + "tests" + ], + "emt": [ + "met", + "tem" + ], + "ainp": [ + "nipa", + "pain", + "pani", + "pian", + "pina" + ], + "eginsstt": [ + "settings", + "testings" + ], + "beruy": [ + "buyer", + "rebuy" + ], + "aeilsy": [ + "easily", + "elysia", + "sailye" + ], + "alor": [ + "lora", + "oral" + ], + "dfor": [ + "drof", + "ford" + ], + "eoprst": [ + "poster", + "presto", + "repost", + "respot", + "stoper", + "topers", + "tropes" + ], + "deeg": [ + "edge", + "geed" + ], + "oort": [ + "root", + "roto", + "toro" + ], + "adhilosy": [ + "hyaloids", + "holidays" + ], + "cei": [ + "cie", + "ice" + ], + "eeilprs": [ + "replies", + "spieler" + ], + "abell": [ + "bella", + "label" + ], + "ces": [ + "esc", + "sec" + ], + "cdeemmnor": [ + "commender", + "recommend" + ], + "acnno": [ + "ancon", + "canon" + ], + "aestw": [ + "awest", + "etwas", + "sweat", + "tawse", + "twaes", + "waste" + ], + "eimntu": [ + "minuet", + "minute", + "munite", + "mutine", + "untime" + ], + "deioprrv": [ + "overdrip", + "provider" + ], + "ailnoopt": [ + "antipolo", + "antipool", + "optional" + ], + "acdiinorty": [ + "dictionary", + "indicatory" + ], + "cdlo": [ + "clod", + "cold" + ], + "achir": [ + "chair", + "chria" + ], + "aehps": [ + "ephas", + "heaps", + "pesah", + "phase", + "shape" + ], + "defils": [ + "felids", + "fields" + ], + "abg": [ + "bag", + "gab" + ], + "eelrstt": [ + "letters", + "settler", + "sterlet", + "trestle" + ], + "hirst": [ + "hirst", + "shirt" + ], + "cdeinnotu": [ + "continued", + "unnoticed" + ], + "ceimr": [ + "crime", + "merci" + ], + "aberst": [ + "barest", + "baster", + "bestar", + "breast", + "restab", + "tabers", + "trabes" + ], + "bim": [ + "bim", + "ibm", + "mib" + ], + "egiilnor": [ + "ligroine", + "religion", + "reoiling" + ], + "acilm": [ + "claim", + "clima", + "malic" + ], + "eiimnoprss": [ + "impression", + "permission" + ], + "achpt": [ + "chapt", + "pacht", + "patch" + ], + "aeht": [ + "ahet", + "eath", + "haet", + "hate", + "heat", + "thae", + "thea" + ], + "aeemrssu": [ + "measures", + "reassume" + ], + "aeeginnort": [ + "generation", + "renegation" + ], + "imss": [ + "isms", + "miss", + "sims" + ], + "accehilm": [ + "alchemic", + "chemical" + ], + "akst": [ + "kats", + "skat", + "task" + ], + "efhilms": [ + "flemish", + "himself" + ], + "nor": [ + "nor", + "ron" + ], + "abeeln": [ + "baleen", + "enable" + ], + "aanst": [ + "antas", + "nasat", + "santa", + "satan" + ], + "dim": [ + "dim", + "mid" + ], + "adeelr": [ + "dealer", + "leader", + "redeal", + "relade", + "relead" + ], + "aeilrs": [ + "ariels", + "israel", + "laiser", + "relais", + "resail", + "sailer", + "serail", + "serial" + ], + "fost": [ + "soft", + "stof" + ], + "eerrssv": [ + "servers", + "versers" + ], + "aelno": [ + "alone", + "anole", + "olena" + ], + "eegimnst": [ + "gisement", + "meetings" + ], + "aainorz": [ + "arizona", + "azorian", + "zonaria" + ], + "eeinrsstt": [ + "insetters", + "interests", + "resistent", + "sternites", + "triteness" + ], + "eflu": [ + "flue", + "fuel" + ], + "aklw": [ + "lawk", + "walk" + ], + "aaiilnt": [ + "antilia", + "italian" + ], + "ainst": [ + "antis", + "saint", + "sanit", + "satin", + "stain", + "tains" + ], + "eors": [ + "eros", + "ores", + "roes", + "rose", + "seor", + "sero", + "sore" + ], + "aegmnrtu": [ + "argentum", + "argument" + ], + "aceginrt": [ + "antergic", + "argentic", + "catering", + "citrange", + "creating", + "reacting" + ], + "deioprrsv": [ + "disprover", + "providers" + ], + "adegpru": [ + "guepard", + "upgrade" + ], + "acfort": [ + "factor", + "forcat" + ], + "aeenrst": [ + "earnest", + "eastern", + "nearest" + ], + "acinostu": [ + "acontius", + "anticous", + "auctions", + "cautions" + ], + "eeinrst": [ + "entires", + "entries", + "trienes" + ], + "adest": [ + "dates", + "sated", + "sedat", + "stade", + "stead", + "tsade" + ], + "adeeegnrt": [ + "generated", + "greatened", + "renegated" + ], + "eimpr": [ + "imper", + "prime" + ], + "iilmt": [ + "limit", + "milit" + ], + "abegn": [ + "bagne", + "bange", + "began" + ], + "epsst": [ + "pests", + "septs", + "steps" + ], + "hopss": [ + "phoss", + "shops", + "sophs", + "sposh" + ], + "defimnor": [ + "foremind", + "informed" + ], + "abnru": [ + "buran", + "unbar", + "urban" + ], + "deorst": [ + "doters", + "sorted", + "stored", + "strode" + ], + "orstu": [ + "roust", + "routs", + "rusot", + "stour", + "sutor", + "torus", + "tours" + ], + "adlo": [ + "alod", + "dola", + "load", + "odal" + ], + "ablor": [ + "balor", + "bolar", + "boral", + "labor", + "lobar" + ], + "adimn": [ + "admin", + "dimna", + "mandi", + "manid" + ], + "agst": [ + "agst", + "gast", + "gats", + "stag", + "tags" + ], + "dopr": [ + "dorp", + "drop", + "prod" + ], + "dilos": [ + "dilos", + "diols", + "idols", + "lidos", + "sloid", + "soldi", + "solid" + ], + "aeeinnoprstt": [ + "penetrations", + "presentation" + ], + "aaegglnsu": [ + "languages", + "slanguage" + ], + "abceem": [ + "became", + "embace" + ], + "aegnor": [ + "onager", + "orange" + ], + "eehmt": [ + "meeth", + "theme" + ], + "aacgimnp": [ + "campaign", + "pangamic" + ], + "aeimnr": [ + "airmen", + "armine", + "ermani", + "marine", + "remain" + ], + "iiprst": [ + "pitris", + "spirit" + ], + "acilms": [ + "claims", + "miscal" + ], + "eems": [ + "emes", + "mese", + "seem", + "seme", + "smee" + ], + "aaffirs": [ + "affairs", + "raffias" + ], + "chotu": [ + "chout", + "couth", + "thuoc", + "touch" + ], + "ddeeinnt": [ + "indented", + "intended" + ], + "aglos": [ + "gaols", + "goals" + ], + "ehir": [ + "heir", + "hire" + ], + "ceeilnot": [ + "coteline", + "election" + ], + "eersv": [ + "serve", + "sever", + "veers", + "verse" + ], + "aenorss": [ + "reasons", + "senoras" + ], + "acgim": [ + "gamic", + "magic" + ], + "mnotu": [ + "montu", + "mount", + "notum" + ], + "amrst": [ + "marts", + "smart", + "stram", + "trams" + ], + "aegv": [ + "gave", + "vage", + "vega" + ], + "enos": [ + "enos", + "eons", + "noes", + "nose", + "ones", + "sone" + ], + "ailnt": [ + "altin", + "latin" + ], + "cdeefiirt": [ + "certified", + "rectified" + ], + "aaegmn": [ + "agname", + "manage" + ], + "aknr": [ + "karn", + "knar", + "kran", + "krna", + "nark", + "rank" + ], + "egnoor": [ + "oregon", + "orgone", + "orogen" + ], + "eeelmnt": [ + "element", + "leetmen", + "telemen" + ], + "bhirt": [ + "birth", + "brith" + ], + "abesu": [ + "abuse", + "beaus" + ], + "eeqrsstu": [ + "questers", + "requests" + ], + "aaeeprst": [ + "asperate", + "separate" + ], + "cdeeoprru": [ + "procedure", + "reproduce" + ], + "adeehilprs": [ + "dealership", + "leadership" + ], + "abelst": [ + "ablest", + "belast", + "bleats", + "stable", + "tables" + ], + "deefin": [ + "define", + "infeed" + ], + "acginr": [ + "arcing", + "caring", + "racing" + ], + "gkno": [ + "gonk", + "kong" + ], + "deeeloprv": [ + "developer", + "redevelop" + ], + "cdeimost": [ + "comedist", + "demotics", + "docetism", + "domestic" + ], + "aeimpst": [ + "impaste", + "pastime" + ], + "hnoostu": [ + "hontous", + "houston", + "nothous" + ], + "acehr": [ + "acher", + "arche", + "chare", + "chera", + "echar", + "rache", + "reach" + ], + "aelmnt": [ + "lament", + "manlet", + "mantel", + "mantle", + "mental" + ], + "emmnot": [ + "moment", + "montem" + ], + "chin": [ + "chin", + "inch" + ], + "ceenrst": [ + "centers", + "centres", + "scenter", + "tenrecs" + ], + "aadegm": [ + "dagame", + "damage" + ], + "abl": [ + "abl", + "alb", + "bal", + "lab" + ], + "eeerrsv": [ + "reserve", + "resever", + "reveres", + "reverse", + "severer" + ], + "ceeiprs": [ + "piecers", + "pierces", + "precise", + "recipes", + "respice", + "scripee" + ], + "aagmm": [ + "gamma", + "magma" + ], + "nosw": [ + "nows", + "owns", + "snow", + "sown", + "wons" + ], + "hrttu": [ + "thurt", + "truth" + ], + "cenortu": [ + "conteur", + "cornute", + "counter", + "recount", + "trounce" + ], + "ainoort": [ + "ontario", + "oration" + ], + "des": [ + "des", + "eds", + "esd", + "sed" + ], + "aeimnnost": [ + "antimeson", + "mannitose", + "minnesota", + "nominates" + ], + "bdegir": [ + "begird", + "bridge" + ], + "aeintv": [ + "native", + "navite" + ], + "denow": [ + "endow", + "nowed", + "owned", + "woden" + ], + "achrt": [ + "archt", + "chart", + "ratch" + ], + "adeerrs": [ + "readers", + "redears", + "redsear", + "rereads" + ], + "aelqu": [ + "equal", + "quale", + "queal" + ], + "adeenrtuv": [ + "adventure", + "unaverted" + ], + "fioprt": [ + "forpit", + "profit" + ], + "adeelrs": [ + "dealers", + "leaders" + ], + "eoprsst": [ + "posters", + "prestos", + "stopers" + ], + "aainssstt": [ + "assistant", + "satanists" + ], + "aev": [ + "ave", + "eva" + ], + "acdemopr": [ + "compadre", + "compared" + ], + "hkooprsw": [ + "shopwork", + "workshop" + ], + "egno": [ + "geon", + "goen", + "gone" + ], + "cdeos": [ + "codes", + "coeds", + "cosed" + ], + "dikns": [ + "dinks", + "kinds" + ], + "aeelstt": [ + "atelets", + "seattle", + "tsatlee" + ], + "aeemnssttt": [ + "statements", + "testaments" + ], + "deglno": [ + "engold", + "golden", + "longed" + ], + "aemst": [ + "mates", + "meats", + "metas", + "satem", + "steam", + "stema", + "tames", + "teams" + ], + "fort": [ + "fort", + "frot" + ], + "aeenst": [ + "enates", + "ensate", + "enseat", + "santee", + "sateen", + "senate" + ], + "cefors": [ + "forces", + "fresco" + ], + "denrtu": [ + "deturn", + "dunter", + "retund", + "runted", + "tunder", + "turned" + ], + "deirt": [ + "diter", + "tired", + "tried" + ], + "deenrrtu": [ + "returned", + "unterred" + ], + "aenprtt": [ + "pattern", + "reptant" + ], + "abot": [ + "boat", + "bota", + "toba" + ], + "ademn": [ + "admen", + "amend", + "mande", + "maned", + "menad", + "named" + ], + "aeehrtt": [ + "teather", + "theater", + "theatre", + "thereat" + ], + "aelrs": [ + "arles", + "arsle", + "earls", + "lares", + "laser", + "lears", + "rales", + "reals", + "seral", + "slare" + ], + "aeeilrr": [ + "earlier", + "learier" + ], + "cino": [ + "cion", + "coin", + "coni", + "icon" + ], + "aadiinn": [ + "anidian", + "indiana" + ], + "cdeiinort": [ + "cretinoid", + "direction" + ], + "deeelt": [ + "delete", + "teedle" + ], + "acelnru": [ + "crenula", + "lucarne", + "nuclear", + "unclear" + ], + "emosu": [ + "moues", + "mouse" + ], + "agilns": [ + "algins", + "aligns", + "glanis", + "lasing", + "liangs", + "ligans", + "lingas", + "sangil", + "signal" + ], + "deissu": [ + "dissue", + "disuse", + "issued" + ], + "abinr": [ + "abrin", + "bairn", + "brain", + "brian", + "rabin" + ], + "eflopruw": [ + "powerful", + "upflower" + ], + "ademr": [ + "armed", + "derma", + "drame", + "dream", + "madre", + "ramed" + ], + "aefls": [ + "alefs", + "false", + "fleas", + "leafs" + ], + "acst": [ + "acts", + "cast", + "cats", + "scat" + ], + "eflorw": [ + "flower", + "fowler", + "reflow", + "wolfer" + ], + "adepss": [ + "depass", + "passed", + "spades" + ], + "cip": [ + "cpi", + "pci", + "pic" + ], + "emooprt": [ + "promote", + "protome" + ], + "adestt": [ + "stated", + "tasted" + ], + "aaepprs": [ + "appears", + "sappare" + ], + "ceorsv": [ + "corves", + "covers" + ], + "aaiimnnt": [ + "amanitin", + "maintain" + ], + "imorstu": [ + "sumitro", + "tourism" + ], + "amot": [ + "atmo", + "atom", + "moat", + "mota", + "toma" + ], + "adeeimstt": [ + "estimated", + "meditates" + ], + "befir": [ + "bifer", + "brief", + "fiber", + "fibre" + ], + "inor": [ + "inro", + "iron", + "noir", + "nori", + "roin" + ], + "deersv": [ + "served", + "versed" + ], + "anstw": [ + "stawn", + "wants", + "wasnt" + ], + "adeepprr": [ + "dapperer", + "prepared" + ], + "diov": [ + "ovid", + "void" + ], + "dgiinn": [ + "dining", + "indign", + "niding" + ], + "aegiinnortt": [ + "integration", + "orientating" + ], + "agt": [ + "agt", + "gat", + "tag" + ], + "adeillnst": [ + "installed", + "landsleit" + ], + "cdeirst": [ + "credits", + "directs" + ], + "adehln": [ + "handel", + "handle" + ], + "eestw": [ + "ewest", + "sweet", + "weest", + "weets", + "weste" + ], + "deks": [ + "desk", + "sked" + ], + "aceiirrt": [ + "criteria", + "triceria" + ], + "adev": [ + "dave", + "deva", + "vade", + "veda" + ], + "degio": [ + "diego", + "dogie", + "geoid" + ], + "ceiv": [ + "cive", + "vice" + ], + "ary": [ + "ary", + "yar", + "ray", + "rya" + ], + "eeenruv": [ + "revenue", + "unreeve" + ], + "aeemrsu": [ + "measure", + "reamuse" + ], + "acgghinn": [ + "changing", + "ganching" + ], + "eostv": [ + "ovest", + "stove", + "votes" + ], + "aber": [ + "bare", + "bear", + "brae" + ], + "agin": [ + "agin", + "gain", + "inga", + "naig", + "ngai" + ], + "aceno": [ + "acone", + "canoe", + "ocean" + ], + "ginss": [ + "signs", + "sings", + "snigs", + "ssing" + ], + "ackl": [ + "calk", + "kcal", + "lack" + ], + "degglo": [ + "doggle", + "dogleg", + "logged" + ], + "aloppt": [ + "applot", + "laptop" + ], + "aegintv": [ + "vagient", + "vintage" + ], + "ainrt": [ + "intra", + "riant", + "tairn", + "tarin", + "train", + "trina" + ], + "aps": [ + "asp", + "pas", + "sap", + "spa" + ], + "aelnry": [ + "anerly", + "layner", + "nearly" + ], + "aeilrty": [ + "irately", + "reality", + "tearily" + ], + "giinor": [ + "nigori", + "origin" + ], + "aggimn": [ + "gaming", + "gigman" + ], + "aefrst": [ + "afters", + "farset", + "faster", + "strafe" + ], + "cno": [ + "con", + "nco" + ], + "psu": [ + "pus", + "sup", + "ups" + ], + "ainnost": [ + "anoints", + "nations", + "onanist" + ], + "eortu": [ + "outer", + "outre", + "route", + "troue", + "utero" + ], + "mooz": [ + "mozo", + "zoom" + ], + "blow": [ + "blow", + "bowl" + ], + "abeltt": [ + "batlet", + "battel", + "battle", + "tablet" + ], + "aeimn": [ + "amine", + "anime", + "enami", + "maine", + "manei", + "manie", + "minae" + ], + "aekps": [ + "peaks", + "sapek", + "spake", + "speak" + ], + "deiinrsstu": [ + "disuniters", + "industries" + ], + "adeiilort": [ + "editorial", + "radiolite" + ], + "ceehps": [ + "cheeps", + "speech" + ], + "eirw": [ + "weir", + "weri", + "wire" + ], + "alrru": [ + "rural", + "urlar" + ], + "adehrs": [ + "dasher", + "rhedas", + "shader", + "shared", + "sheard" + ], + "aept": [ + "pate", + "peat", + "tape", + "teap", + "tepa" + ], + "cceimnoos": [ + "economics", + "neocosmic" + ], + "acdi": [ + "acid", + "cadi", + "caid" + ], + "besty": [ + "betsy", + "bytes" + ], + "eghhit": [ + "eighth", + "height" + ], + "aeekprs": [ + "respeak", + "speaker" + ], + "abinot": [ + "batino", + "bonita", + "oatbin", + "obtain" + ], + "ceffios": [ + "coiffes", + "offices" + ], + "deeginrs": [ + "designer", + "energids", + "redesign", + "reedings", + "resigned" + ], + "aadegmn": [ + "agnamed", + "managed" + ], + "adefil": [ + "afield", + "defail", + "defial", + "failed" + ], + "ceerst": [ + "certes", + "erects", + "resect", + "screet", + "secret", + "terces" + ], + "abht": [ + "baht", + "bath", + "bhat" + ], + "aeegintv": [ + "agentive", + "negative" + ], + "adenrw": [ + "andrew", + "redawn", + "wander", + "warden", + "warned" + ], + "efmoprr": [ + "perform", + "preform" + ], + "aeeimsstt": [ + "estimates", + "semistate", + "steamiest" + ], + "aessst": [ + "assets", + "stases", + "tasses" + ], + "iimnrsty": [ + "ministry", + "myristin" + ], + "aelrwy": [ + "yawler", + "lawyer", + "warely" + ], + "adeimrr": [ + "admirer", + "madrier", + "married" + ], + "aghinrs": [ + "garnish", + "rashing", + "sharing" + ], + "aloprt": [ + "patrol", + "portal", + "tropal" + ], + "abet": [ + "abet", + "bate", + "beat", + "beta" + ], + "afil": [ + "alif", + "fail", + "fila" + ], + "agirst": [ + "gratis", + "striga" + ], + "aissst": [ + "assist", + "stasis" + ], + "eginrsv": [ + "serving", + "versing" + ], + "abgs": [ + "bags", + "gabs" + ], + "ccimos": [ + "comics", + "cosmic" + ], + "aemrstt": [ + "matster", + "matters", + "smatter" + ], + "ehossu": [ + "houses", + "shouse" + ], + "cdo": [ + "cod", + "doc" + ], + "aerw": [ + "arew", + "waer", + "ware", + "wear" + ], + "abegiknr": [ + "beraking", + "breaking", + "rebaking" + ], + "aeilmttu": [ + "mutilate", + "ultimate" + ], + "aelsw": [ + "swale", + "sweal", + "wales", + "wasel", + "weals" + ], + "imnor": [ + "minor", + "morin" + ], + "deeinrsst": [ + "dissenter", + "residents", + "tiredness", + "triedness" + ], + "denot": [ + "donet", + "noted", + "tendo", + "toned" + ], + "cddeeru": [ + "deducer", + "reduced" + ], + "aerr": [ + "rare", + "rear" + ], + "deefmoprr": [ + "performed", + "preformed" + ], + "adisv": [ + "davis", + "divas", + "vadis" + ], + "adeiln": [ + "aldine", + "alined", + "daniel", + "delian", + "denial", + "enalid", + "leadin", + "nailed" + ], + "abrs": [ + "arbs", + "bars", + "bras" + ], + "orw": [ + "row", + "wro" + ], + "aceforst": [ + "cofaster", + "forecast" + ], + "ehlps": [ + "helps", + "shlep" + ], + "egilnss": [ + "essling", + "singles" + ], + "amnostu": [ + "amounts", + "outmans", + "saumont" + ], + "acinnot": [ + "actinon", + "cantino", + "cantion", + "contain" + ], + "adlu": [ + "auld", + "dual", + "laud", + "udal" + ], + "eirs": [ + "eris", + "ires", + "reis", + "ries", + "rise", + "seri", + "sier", + "sire" + ], + "dsu": [ + "sud", + "uds" + ], + "eelps": [ + "peels", + "peles", + "sleep", + "speel" + ], + "bdir": [ + "bird", + "brid", + "drib" + ], + "aceinort": [ + "actioner", + "anerotic", + "anoretic", + "canotier", + "ceration", + "cortinae", + "creation", + "reaction" + ], + "acistt": [ + "attics", + "static", + "sticta" + ], + "ceens": [ + "cense", + "scene", + "sence" + ], + "adly": [ + "yald", + "lady" + ], + "aet": [ + "aet", + "ate", + "eat", + "eta", + "tae", + "tea" + ], + "acegilnn": [ + "cleaning", + "enlacing" + ], + "eilnt": [ + "inlet", + "intel", + "linet" + ], + "aegilnortu": [ + "regulation", + "urogenital" + ], + "cdeinortu": [ + "introduce", + "reduction" + ], + "aim": [ + "aim", + "ami", + "ima", + "mia" + ], + "bdis": [ + "bids", + "dibs" + ], + "deeefrrr": [ + "deferrer", + "referred" + ], + "eginors": [ + "eringos", + "ignores", + "regions", + "signore" + ], + "els": [ + "els", + "les", + "sel" + ], + "acep": [ + "cape", + "cepa", + "pace" + ], + "ann": [ + "ann", + "nan" + ], + "ginrs": [ + "girns", + "grins", + "rings" + ], + "ipt": [ + "pit", + "tip", + "tpi" + ], + "deflnoruw": [ + "underflow", + "wonderful" + ], + "eimn": [ + "mein", + "mien", + "mine" + ], + "adeils": [ + "aisled", + "deasil", + "ideals", + "ladies", + "sailed" + ], + "adeegr": [ + "agreed", + "dragee", + "geared" + ], + "eeinnoprtv": [ + "prevention", + "provenient" + ], + "iks": [ + "ksi", + "ski" + ], + "cceors": [ + "scorce", + "soccer" + ], + "imoprt": [ + "import", + "promit" + ], + "ginopst": [ + "posting", + "stoping" + ], + "aadeiimnnt": [ + "diamantine", + "inanimated", + "maintained" + ], + "ccdeennot": [ + "condecent", + "connected" + ], + "chirst": [ + "christ", + "strich" + ], + "dgos": [ + "dogs", + "gods" + ], + "cdeiorrst": [ + "creditors", + "directors", + "recordist" + ], + "aadeh": [ + "aahed", + "ahead" + ], + "mnoo": [ + "mono", + "moon" + ], + "ceehms": [ + "scheme", + "smeech" + ], + "deelv": [ + "delve", + "devel" + ], + "eeeinprrsst": [ + "enterprises", + "intersperse" + ], + "adelt": [ + "adlet", + "dealt", + "delta", + "lated", + "taled" + ], + "aefr": [ + "afer", + "fare", + "fear", + "frae", + "rafe" + ], + "eegikns": [ + "seeking", + "skeeing" + ], + "cehins": [ + "chines", + "chinse", + "inches", + "niches" + ], + "aehrss": [ + "rashes", + "shares", + "shears" + ], + "arsw": [ + "raws", + "wars" + ], + "ekpt": [ + "kept", + "tpke" + ], + "aaelpp": [ + "appale", + "appeal" + ], + "ceirsu": [ + "cruise", + "crusie", + "curies" + ], + "bnosu": [ + "bonus", + "bosun" + ], + "accefiiinortt": [ + "certification", + "cretification", + "rectification" + ], + "eiloprsuvy": [ + "perviously", + "previously", + "viperously" + ], + "ehy": [ + "hey", + "hye", + "yeh" + ], + "aceilpss": [ + "slipcase", + "specials" + ], + "deinsy": [ + "disney", + "sidney" + ], + "abdeo": [ + "abode", + "adobe" + ], + "deirsv": [ + "divers", + "drives" + ], + "amrs": [ + "arms", + "mars", + "rams" + ], + "eerst": [ + "ester", + "estre", + "reest", + "reset", + "steer", + "stere", + "stree", + "teres", + "terse", + "trees", + "tsere" + ], + "agv": [ + "avg", + "vag" + ], + "ahtu": [ + "auth", + "haut", + "utah" + ], + "abenry": [ + "barney", + "nearby" + ], + "mor": [ + "mor", + "rom" + ], + "acdeirr": [ + "acrider", + "carried" + ], + "dehi": [ + "hide", + "hied" + ], + "aeginrstu": [ + "gauntries", + "signature" + ], + "eefrr": [ + "freer", + "frere", + "refer", + "rfree" + ], + "eillmr": [ + "miller", + "remill" + ], + "acdesu": [ + "caused", + "sauced" + ], + "abbes": [ + "abbes", + "babes" + ], + "ddeein": [ + "denied", + "indeed" + ], + "oty": [ + "yot", + "toy" + ], + "deinprt": [ + "deprint", + "printed" + ], + "losw": [ + "lows", + "owls", + "slow", + "sowl" + ], + "aelmorv": [ + "removal", + "valorem" + ], + "aeeirs": [ + "aeries", + "easier" + ], + "crs": [ + "crs", + "scr" + ], + "abiiillty": [ + "alibility", + "liability" + ], + "hip": [ + "hip", + "ihp", + "iph", + "phi" + ], + "einprrst": [ + "printers", + "reprints", + "sprinter" + ], + "einn": [ + "inne", + "nein", + "nine" + ], + "addgin": [ + "adding", + "dading" + ], + "ceir": [ + "cire", + "eric", + "rice" + ], + "inprst": [ + "prints", + "sprint" + ], + "denps": [ + "pends", + "psend", + "spend" + ], + "deeirsv": [ + "derives", + "deviser", + "diverse", + "revised" + ], + "acilopt": [ + "capitol", + "coalpit", + "optical", + "topical" + ], + "aeeilrtv": [ + "levirate", + "relative" + ], + "dot": [ + "dot", + "tod" + ], + "eisstu": [ + "suites", + "tissue" + ], + "eefgiln": [ + "feeling", + "fleeing" + ], + "eefilr": [ + "ferlie", + "liefer", + "refile", + "relief" + ], + "eiinorsv": [ + "revision", + "visioner" + ], + "aiort": [ + "ariot", + "ratio" + ], + "adp": [ + "adp", + "dap", + "pad" + ], + "ainr": [ + "airn", + "arni", + "iran", + "nair", + "rain", + "rani" + ], + "noot": [ + "onto", + "oont", + "toon" + ], + "aelnpt": [ + "pantle", + "planet", + "platen" + ], + "ceeipr": [ + "piecer", + "pierce", + "recipe" + ], + "eimprt": [ + "permit", + "premit" + ], + "eegins": [ + "genies", + "seeing", + "signee" + ], + "einnst": [ + "innest", + "intens", + "sennit", + "sinnet", + "tennis" + ], + "abss": [ + "bass", + "sabs" + ], + "bdemoor": [ + "bedroom", + "boerdom", + "boredom", + "broomed" + ], + "aceinnst": [ + "ancients", + "canniest", + "insectan", + "instance" + ], + "deir": [ + "dier", + "dire", + "drie", + "ired", + "reid", + "ride" + ], + "cdeeilns": [ + "declines", + "licensed", + "silenced" + ], + "adlnoor": [ + "lardoon", + "orlando", + "rolando" + ], + "imt": [ + "mit", + "tim" + ], + "eeenprrst": [ + "presenter", + "repenters", + "represent" + ], + "aceinnoorstv": [ + "conservation", + "conversation" + ], + "aipr": [ + "pair", + "pari", + "pria", + "ripa" + ], + "adeil": [ + "adiel", + "ailed", + "delia", + "ideal" + ], + "dno": [ + "don", + "nod" + ], + "ceeips": [ + "pieces", + "specie" + ], + "defhiins": [ + "definish", + "fiendish", + "finished" + ], + "akprs": [ + "parks", + "spark" + ], + "deinnr": [ + "dinner", + "endrin" + ], + "acemr": [ + "cream", + "macer" + ], + "nrsu": [ + "runs", + "snur", + "urns" + ], + "aehy": [ + "ahey", + "eyah", + "haye", + "yeah" + ], + "cdeiorsv": [ + "discover", + "divorces" + ], + "aenprstt": [ + "patterns", + "prestant", + "transept", + "trapnest" + ], + "hills": [ + "hills", + "shill" + ], + "ilnosw": [ + "lowsin", + "wilson" + ], + "hiirs": [ + "irish", + "rishi", + "sirih" + ], + "aeimnrs": [ + "marines", + "remains", + "seminar" + ], + "aeegrstt": [ + "greatest", + "stratege" + ], + "eoru": [ + "euro", + "roue" + ], + "ceeginr": [ + "energic", + "generic" + ], + "aegsu": [ + "agues", + "usage" + ], + "acp": [ + "cap", + "pac" + ], + "ikn": [ + "ink", + "kin" + ], + "achrst": [ + "charts", + "scarth", + "scrath", + "starch" + ], + "cgiinnnotu": [ + "continuing", + "unnoticing" + ], + "aekp": [ + "keap", + "peak" + ], + "eistx": [ + "exist", + "exits", + "sixte" + ], + "eehlw": [ + "hewel", + "wheel" + ], + "ainrstt": [ + "straint", + "transit", + "tristan" + ], + "accmopt": [ + "accompt", + "compact" + ], + "ghilst": [ + "lights", + "slight" + ], + "aegln": [ + "agnel", + "angel", + "angle", + "galen", + "genal", + "glean", + "lagen", + "nagel" + ], + "eegiknp": [ + "keeping", + "peeking" + ], + "aaeinopprrt": [ + "paraprotein", + "preparation" + ], + "einos": [ + "eosin", + "noise" + ], + "eeginns": [ + "engines", + "senegin" + ], + "aaccertu": [ + "accurate", + "carucate" + ], + "inp": [ + "nip", + "pin" + ], + "eirsst": [ + "resist", + "restis", + "sister", + "tresis" + ], + "gnu": [ + "gnu", + "gun", + "ung" + ], + "ahprs": [ + "harps", + "sharp", + "shrap" + ], + "abeilnss": [ + "albiness", + "lesbians" + ], + "ben": [ + "ben", + "neb" + ], + "aeln": [ + "alen", + "elan", + "laen", + "lane", + "lean", + "lena", + "nael", + "nale", + "neal" + ], + "alo": [ + "alo", + "lao", + "loa", + "ola" + ], + "eoprtx": [ + "export", + "torpex" + ], + "eelmopry": [ + "employer", + "polymere", + "reemploy" + ], + "knosw": [ + "knows", + "snowk", + "swonk" + ], + "bcdeeirs": [ + "describe", + "escribed" + ], + "ceiinstz": [ + "citizens", + "zincites" + ], + "aelnoprss": [ + "apronless", + "personals", + "responsal" + ], + "belortu": [ + "boulter", + "trouble" + ], + "adeprs": [ + "drapes", + "padres", + "parsed", + "rasped", + "spader", + "spared", + "spread" + ], + "accho": [ + "chaco", + "choca", + "coach" + ], + "eiknv": [ + "kevin", + "knive" + ], + "adjnor": [ + "jardon", + "jordan" + ], + "aegs": [ + "ages", + "gaes", + "sage" + ], + "glpu": [ + "gulp", + "plug" + ], + "aceiilpsst": [ + "plasticise", + "specialist" + ], + "giinrv": [ + "irving", + "riving", + "virgin" + ], + "aegiiinnosttv": [ + "investigation", + "tenovaginitis" + ], + "adeirs": [ + "aiders", + "arised", + "deairs", + "irades", + "raised", + "redias", + "resaid" + ], + "aht": [ + "aht", + "hat", + "tha" + ], + "cddeeirt": [ + "credited", + "directed" + ], + "elpr": [ + "lerp", + "repl" + ], + "beik": [ + "bike", + "kibe" + ], + "aelpt": [ + "leapt", + "lepta", + "palet", + "patel", + "pelta", + "petal", + "plate", + "pleat", + "tepal" + ], + "acdeiint": [ + "actinide", + "ctenidia", + "diacetin", + "diactine", + "indicate" + ], + "bdelno": [ + "blonde", + "bolden", + "nobled" + ], + "elos": [ + "leos", + "lose", + "oles", + "sloe", + "sole" + ], + "eeks": [ + "ekes", + "kees", + "seek", + "skee" + ], + "ablmsu": [ + "albums", + "sambul", + "sumbal" + ], + "acehst": [ + "chaste", + "cheats", + "sachet", + "scathe", + "scheat", + "taches" + ], + "egsstu": [ + "guests", + "gusset" + ], + "adeeisss": [ + "diseases", + "seasides" + ], + "deeeloprsv": [ + "developers", + "redevelops" + ], + "noty": [ + "yont", + "tony" + ], + "aadenv": [ + "advena", + "nevada", + "vedana", + "venada" + ], + "ikst": [ + "kist", + "kits", + "skit" + ], + "aadegn": [ + "agenda", + "gadean" + ], + "ceinnostu": [ + "continues", + "neustonic" + ], + "ackrst": [ + "strack", + "tracks" + ], + "aeelmptt": [ + "palmette", + "template" + ], + "ceinpr": [ + "pincer", + "prince" + ], + "cceilr": [ + "circle", + "cleric" + ], + "ilos": [ + "lois", + "oils", + "silo", + "siol", + "soil", + "soli" + ], + "agnrst": [ + "grants", + "strang" + ], + "aacilntt": [ + "atlantic", + "tantalic" + ], + "etw": [ + "tew", + "wet" + ], + "adderw": [ + "edward", + "wadder", + "warded" + ], + "aegilnv": [ + "leaving", + "vangeli", + "vealing" + ], + "denoprs": [ + "ponders", + "respond" + ], + "eissz": [ + "sizes", + "zeiss" + ], + "ailnp": [ + "lapin", + "lipan", + "pinal", + "plain" + ], + "eksy": [ + "keys", + "syke", + "skey", + "skye" + ], + "achlnu": [ + "chulan", + "launch", + "nuchal" + ], + "ehms": [ + "hems", + "mesh", + "shem" + ], + "blmosy": [ + "blosmy", + "symbol" + ], + "aden": [ + "aden", + "ande", + "dane", + "dean", + "edna" + ], + "epstu": [ + "setup", + "spute", + "stupe", + "upset" + ], + "acfils": [ + "califs", + "fiscal" + ], + "elssty": [ + "slyest", + "styles" + ], + "deenrv": [ + "denver", + "nerved", + "revend", + "vender" + ], + "finoty": [ + "notify", + "tonify" + ], + "belsu": [ + "blues", + "bulse", + "lubes" + ], + "ceops": [ + "copes", + "copse", + "pecos", + "scope" + ], + "eilpprsu": [ + "periplus", + "supplier" + ], + "adelnt": [ + "dental", + "tandle" + ], + "bdeorr": [ + "border", + "roberd" + ], + "acessu": [ + "causes", + "causse", + "sauces" + ], + "adeelnr": [ + "laender", + "leander", + "learned", + "reladen" + ], + "chiiorst": [ + "historic", + "orchitis" + ], + "deenop": [ + "depone", + "opened" + ], + "ceorss": [ + "cessor", + "corses", + "crosse", + "scores", + "scorse" + ], + "aeilnr": [ + "aliner", + "arline", + "enrail", + "lainer", + "lanier", + "larine", + "linear", + "nailer", + "renail" + ], + "abers": [ + "bares", + "barse", + "baser", + "bears", + "besra", + "braes", + "saber", + "sabre", + "serab" + ], + "aejn": [ + "jane", + "jean" + ], + "hop": [ + "hop", + "pho", + "poh" + ], + "ddeeit": [ + "dieted", + "edited" + ], + "aisv": [ + "avis", + "siva", + "vias", + "visa" + ], + "eemrt": [ + "meter", + "metre", + "remet", + "retem" + ], + "deikln": [ + "kilned", + "kindle", + "linked" + ], + "ccenopst": [ + "concepts", + "conspect" + ], + "epru": [ + "peru", + "prue", + "pure" + ], + "deeilrv": [ + "deliver", + "deviler", + "livered", + "relived", + "reviled", + "riveled" + ], + "denorw": [ + "downer", + "nowder", + "wonder", + "worden" + ], + "elnosss": [ + "lessons", + "sonless" + ], + "begins": [ + "begins", + "beings", + "besing", + "binges" + ], + "aelrst": [ + "alerts", + "alters", + "artels", + "estral", + "laster", + "lastre", + "rastle", + "ratels", + "relast", + "resalt", + "salter", + "slater", + "staler", + "stelar", + "talers" + ], + "adrw": [ + "draw", + "ward" + ], + "aegilnrt": [ + "alerting", + "altering", + "integral", + "relating", + "tanglier", + "teraglin", + "triangle" + ], + "aemssu": [ + "amuses", + "assume", + "seamus" + ], + "aaceilln": [ + "alliance", + "ancillae", + "canaille" + ], + "eehinrt": [ + "enherit", + "etherin", + "neither", + "therein" + ], + "eilsw": [ + "lewis", + "swile", + "wiles" + ], + "aeelsv": [ + "leaves", + "sleave" + ], + "aceelpr": [ + "percale", + "replace" + ], + "ceenorrtv": [ + "converter", + "reconvert" + ], + "abbe": [ + "abbe", + "babe" + ], + "agrsu": [ + "argus", + "gaurs", + "guars", + "sugar" + ], + "egls": [ + "gels", + "legs" + ], + "ams": [ + "mas", + "sam", + "sma" + ], + "cikst": [ + "stick", + "ticks" + ], + "aelln": [ + "allen", + "ellan" + ], + "dpt": [ + "dpt", + "tpd" + ], + "aeilnort": [ + "oriental", + "relation", + "tirolean" + ], + "abdeeln": [ + "enabled", + "endable" + ], + "deils": [ + "deils", + "delis", + "idles", + "isled", + "sidle", + "slide" + ], + "deestt": [ + "detest", + "tested" + ], + "aadeprt": [ + "adapter", + "predata", + "readapt" + ], + "cklo": [ + "colk", + "lock" + ], + "cehkoy": [ + "chokey", + "hockey" + ], + "morst": [ + "morts", + "storm", + "strom" + ], + "cimor": [ + "micro", + "moric", + "romic" + ], + "eilm": [ + "emil", + "lime", + "mile" + ], + "deiorst": [ + "editors", + "oestrid", + "sortied", + "steroid", + "storied", + "triodes" + ], + "adehrst": [ + "dearths", + "hardest", + "hardset", + "hatreds", + "threads", + "trashed" + ], + "eemprsu": [ + "presume", + "supreme" + ], + "eenprsst": [ + "pensters", + "pertness", + "presents", + "serpents" + ], + "efr": [ + "erf", + "fer", + "ref" + ], + "aknt": [ + "kant", + "tank" + ], + "aeeimstt": [ + "estimate", + "etatisme", + "meatiest", + "teatimes" + ], + "ceiinnopst": [ + "cispontine", + "inceptions", + "inspection" + ], + "iilmst": [ + "limits", + "mislit" + ], + "aceehmnrst": [ + "manchester", + "searchment" + ], + "ainpt": [ + "inapt", + "paint", + "patin", + "pinta" + ], + "adely": [ + "delay", + "layed", + "leady" + ], + "ilopt": [ + "pilot", + "polit" + ], + "elottu": [ + "outlet", + "tutelo" + ], + "egilnrstu": [ + "lustering", + "resulting", + "ulstering" + ], + "anp": [ + "nap", + "pan" + ], + "alrtu": [ + "lutra", + "ultra" + ], + "aaeiimnnotx": [ + "examination", + "exanimation" + ], + "eoprtt": [ + "porett", + "potter" + ], + "alpsy": [ + "palsy", + "plays", + "splay" + ], + "beillntu": [ + "bulletin", + "unbillet" + ], + "acdeiinst": [ + "actinides", + "andesitic", + "dianetics", + "indicates" + ], + "dfimoy": [ + "domify", + "modify" + ], + "aadm": [ + "adam", + "dama", + "maad" + ], + "lrtuy": [ + "rutyl", + "truly" + ], + "agiinnpt": [ + "painting", + "patining" + ], + "aenptt": [ + "patent", + "patten", + "tapnet" + ], + "pps": [ + "pps", + "spp" + ], + "aegint": [ + "eating", + "ingate", + "tangie", + "teaing", + "tinage" + ], + "ceeeipprstv": [ + "perspective", + "prespective" + ], + "deglo": [ + "lodge", + "ogled" + ], + "egilnrst": [ + "lingster", + "ringlets", + "sterling", + "tinglers" + ], + "bersuy": [ + "buyers", + "rebusy" + ], + "agry": [ + "gary", + "gray" + ], + "aaceglotu": [ + "catalogue", + "coagulate" + ], + "aaintw": [ + "atwain", + "taiwan" + ], + "cehnos": [ + "cheson", + "chosen", + "cohens", + "schone" + ], + "aahrs": [ + "asarh", + "haars", + "haras", + "raash", + "sarah" + ], + "aeilmnrt": [ + "terminal", + "tramline" + ], + "aelnors": [ + "loaners", + "orleans", + "reloans" + ], + "eeimpr": [ + "empire", + "epimer", + "premie" + ], + "aeirs": [ + "aesir", + "aries", + "arise", + "raise", + "serai" + ], + "aeepprr": [ + "paperer", + "perpera", + "prepare", + "repaper" + ], + "aabr": [ + "arab", + "arba", + "baar", + "bara" + ], + "eeimprr": [ + "premier", + "reprime" + ], + "mooorrtw": [ + "moorwort", + "rootworm", + "tomorrow", + "wormroot" + ], + "cddeei": [ + "decide", + "deiced" + ], + "aadmr": [ + "damar", + "drama" + ], + "efgimnoprr": [ + "performing", + "preforming" + ], + "abeilstu": [ + "sabulite", + "suitable" + ], + "abcehmr": [ + "becharm", + "brecham", + "chamber", + "chambre" + ], + "aeginu": [ + "enigua", + "guinea", + "naigue" + ], + "celmsu": [ + "clumse", + "muscle" + ], + "aefginrtu": [ + "featuring", + "figurante" + ], + "ios": [ + "ios", + "iso", + "osi" + ], + "orsuy": [ + "yours", + "soury" + ], + "msu": [ + "mus", + "sum" + ], + "adentt": [ + "attend", + "detant" + ], + "ehorsw": [ + "reshow", + "shower", + "whores" + ], + "aaln": [ + "alan", + "anal", + "lana" + ], + "deginns": [ + "endings", + "sending" + ], + "ajnos": [ + "janos", + "jason", + "jonas", + "sonja" + ], + "ghinott": [ + "hotting", + "tonight" + ], + "ehlls": [ + "hells", + "shell" + ], + "ako": [ + "ako", + "koa", + "oak", + "oka" + ], + "atv": [ + "tav", + "vat" + ], + "beer": [ + "beer", + "bere", + "bree" + ], + "deeems": [ + "seemed", + "semeed" + ], + "alors": [ + "orals", + "rosal", + "solar", + "soral" + ], + "ejos": [ + "joes", + "jose" + ], + "irs": [ + "irs", + "sir", + "sri" + ], + "abelnu": [ + "nebula", + "unable", + "unbale" + ], + "aksst": [ + "skats", + "tasks" + ], + "aceeinrsst": [ + "ancestries", + "resistance", + "senatrices" + ], + "doors": [ + "doors", + "odors", + "ordos", + "roods", + "soord", + "sordo" + ], + "eorrsst": [ + "resorts", + "ressort", + "rosters", + "sorters" + ], + "iiorstv": [ + "ivorist", + "visitor" + ], + "intw": [ + "twin", + "wint" + ], + "fhort": [ + "forth", + "froth" + ], + "einrst": [ + "estrin", + "inerts", + "insert", + "inters", + "niters", + "nitres", + "sinter", + "sterin", + "triens", + "trines" + ], + "abeilmort": [ + "artmobile", + "baltimore" + ], + "aaegtwy": [ + "gateway", + "getaway", + "waygate" + ], + "ailmnu": [ + "alumin", + "alumni", + "lumina", + "unmail" + ], + "adginrw": [ + "drawing", + "ginward", + "warding" + ], + "acemnor": [ + "cremona", + "romance" + ], + "eimnnrsttu": [ + "instrument", + "nutriments" + ], + "bceru": [ + "bruce", + "cebur", + "cuber" + ], + "ilpst": [ + "slipt", + "spilt", + "split" + ], + "eehmst": [ + "smeeth", + "smethe", + "themes" + ], + "bist": [ + "bist", + "bits", + "stib" + ], + "cdefosu": [ + "defocus", + "focused" + ], + "agikns": [ + "asking", + "gaskin", + "kiangs", + "kisang" + ], + "abdeeist": [ + "beadiest", + "diabetes" + ], + "istu": [ + "situ", + "suit", + "tuis" + ], + "chip": [ + "chip", + "pich" + ], + "ers": [ + "ers", + "res", + "ser" + ], + "bdeios": [ + "bodies", + "dobies", + "obside" + ], + "imnos": [ + "minos", + "osmin", + "simon" + ], + "eirrstw": [ + "wrister", + "writers" + ], + "delov": [ + "loved", + "voled" + ], + "bdirs": [ + "birds", + "dribs" + ], + "eeenprrsst": [ + "presenters", + "represents" + ], + "achr": [ + "arch", + "char", + "rach" + ], + "adesv": [ + "devas", + "saved" + ], + "acnoort": [ + "cartoon", + "coranto" + ], + "hosst": [ + "hosts", + "shots", + "soths", + "stosh" + ], + "emoor": [ + "moore", + "romeo" + ], + "adegnrt": [ + "dragnet", + "granted" + ], + "ccehios": [ + "choices", + "secchio" + ], + "abcnor": [ + "bracon", + "carbon", + "corban" + ], + "egiilnnst": [ + "enlisting", + "listening", + "tinseling" + ], + "kloootu": [ + "lookout", + "outlook" + ], + "aeimssv": [ + "massive", + "mavises" + ], + "aertt": [ + "atter", + "tarte", + "tater", + "teart", + "tetra", + "treat" + ], + "adeehr": [ + "adhere", + "header", + "hedera", + "rehead", + "rhedae" + ], + "defmor": [ + "deform", + "formed" + ], + "dgir": [ + "gird", + "grid" + ], + "eehsst": [ + "sheets", + "theses" + ], + "acikprt": [ + "patrick", + "tripack" + ], + "eoprtu": [ + "pouter", + "puerto", + "roupet", + "troupe", + "uptore" + ], + "aalmps": [ + "lampas", + "plasma" + ], + "aeginnrs": [ + "aginners", + "earnings", + "engrains", + "grannies" + ], + "ikrss": [ + "kriss", + "risks" + ], + "acehrrt": [ + "charter", + "ratcher", + "rechart" + ], + "fgi": [ + "fig", + "gif" + ], + "aaabbrr": [ + "barabra", + "barbara" + ], + "ademrs": [ + "dermas", + "dreams", + "madres" + ], + "begglor": [ + "boggler", + "broggle" + ], + "cegiilnns": [ + "licensing", + "silencing" + ], + "aceht": [ + "cheat", + "tache", + "teach", + "theca" + ], + "adipr": [ + "adrip", + "padri", + "pardi", + "rapid" + ], + "deiopst": [ + "deposit", + "dopiest", + "podites", + "posited", + "sopited", + "topside" + ], + "aailnt": [ + "antlia", + "latian", + "nalita" + ], + "aans": [ + "anas", + "ansa", + "nasa", + "saan" + ], + "eehlsw": [ + "shewel", + "wheels" + ], + "aeelmpstt": [ + "palmettes", + "templates" + ], + "afmorst": [ + "farmost", + "formats" + ], + "abt": [ + "abt", + "bat", + "tab" + ], + "ddeenps": [ + "depends", + "despend" + ], + "boost": [ + "boost", + "boots" + ], + "eorrtu": [ + "retour", + "roture", + "router", + "tourer" + ], + "degiint": [ + "dieting", + "editing", + "ignited" + ], + "deflor": [ + "folder", + "refold" + ], + "elpsu": [ + "lepus", + "pules", + "pulse" + ], + "corstu": [ + "courts", + "scrout", + "scruto" + ], + "deiortt": [ + "detroit", + "dottier" + ], + "emort": [ + "metro", + "moter" + ], + "iprst": [ + "spirt", + "sprit", + "stirp", + "strip", + "trips" + ], + "aelpr": [ + "lepra", + "paler", + "parel", + "parle", + "pearl", + "perla", + "prela", + "relap" + ], + "deeinrst": [ + "disenter", + "indesert", + "inserted", + "resident", + "sentried", + "sintered" + ], + "lopt": [ + "plot", + "polt" + ], + "adegrr": [ + "darger", + "garred", + "gerard", + "grader", + "redrag", + "regard" + ], + "eisstx": [ + "exists", + "sexist", + "sixtes" + ], + "eikrst": [ + "kiters", + "skiter", + "strike" + ], + "aehrtt": [ + "hatter", + "threat" + ], + "ehinoprsw": [ + "ownership", + "shipowner" + ], + "aeilrrt": [ + "retiral", + "retrial", + "trailer" + ], + "aenn": [ + "anne", + "nane" + ], + "acelst": [ + "castle", + "cleats", + "eclats", + "scalet", + "sclate" + ], + "adegnrs": [ + "dangers", + "ganders", + "gardens" + ], + "deimss": [ + "deisms", + "demiss", + "dismes", + "missed" + ], + "aeinqtu": [ + "antique", + "quinate" + ], + "bio": [ + "bio", + "ibo", + "obi" + ], + "acgint": [ + "acting", + "cating" + ], + "adehs": [ + "ashed", + "deash", + "hades", + "heads", + "sadhe", + "shade" + ], + "aemx": [ + "amex", + "exam", + "xema" + ], + "gloos": [ + "gools", + "logos" + ], + "aeinqstu": [ + "antiques", + "quanties" + ], + "deinsty": [ + "density", + "destiny" + ], + "anry": [ + "yarn", + "nary" + ], + "aegnrst": [ + "angster", + "argents", + "garnets", + "nagster", + "strange" + ], + "bdes": [ + "beds", + "debs" + ], + "cps": [ + "cps", + "csp" + ], + "eelmoprsy": [ + "employers", + "reemploys" + ], + "egry": [ + "gery", + "gyre", + "grey" + ], + "addeemn": [ + "amended", + "deadmen" + ], + "bdlo": [ + "bold", + "dobl" + ], + "elnoss": [ + "lesson", + "nossel", + "onless" + ], + "aceimn": [ + "anemic", + "cinema", + "iceman" + ], + "aesst": [ + "asset", + "easts", + "sates", + "seats", + "tasse" + ], + "acns": [ + "cans", + "scan" + ], + "eeersv": [ + "everse", + "reeves", + "severe" + ], + "aeeegnrt": [ + "generate", + "renegate", + "teenager" + ], + "aeilnssst": [ + "saintless", + "saltiness", + "slatiness", + "stainless" + ], + "ahilopsst": [ + "hospitals", + "thalposis" + ], + "hmoru": [ + "humor", + "mohur" + ], + "adeg": [ + "aged", + "egad", + "gade", + "gaed" + ], + "ceeinoptx": [ + "exception", + "expection" + ], + "deilv": [ + "devil", + "divel", + "lived" + ], + "adinortu": [ + "duration", + "unadroit" + ], + "cis": [ + "cis", + "csi", + "sci", + "sic" + ], + "det": [ + "det", + "ted" + ], + "adimnos": [ + "daimons", + "domains", + "madison" + ], + "fgilny": [ + "flying", + "flingy" + ], + "ins": [ + "ins", + "isn", + "nis", + "sin" + ], + "adeginorz": [ + "dragonize", + "organized" + ], + "aapr": [ + "apar", + "paar", + "para" + ], + "eeimnss": [ + "nemesis", + "siemens" + ], + "aemnt": [ + "ament", + "manet", + "meant", + "menat", + "menta", + "teman" + ], + "aceprtu": [ + "capture", + "cuprate", + "uptrace" + ], + "dnopsu": [ + "pondus", + "pounds" + ], + "dees": [ + "dees", + "seed" + ], + "deeirs": [ + "desire", + "eiders", + "reside" + ], + "eemst": [ + "meets", + "metes", + "steem", + "teems", + "temse" + ], + "eepr": [ + "peer", + "pere", + "pree" + ], + "adekmr": [ + "demark", + "marked" + ], + "deinrv": [ + "driven", + "nervid", + "verdin" + ], + "adeemrsu": [ + "madurese", + "measured" + ], + "adhnostu": [ + "handouts", + "thousand" + ], + "acegr": [ + "cager", + "garce", + "grace" + ], + "anssu": [ + "nasus", + "susan" + ], + "gin": [ + "gin", + "ign", + "ing", + "nig" + ], + "aadms": [ + "adams", + "damas" + ], + "hnopty": [ + "phyton", + "python", + "typhon" + ], + "emnorst": [ + "mentors", + "monster" + ], + "aelx": [ + "alex", + "axel", + "axle", + "exla" + ], + "beno": [ + "beno", + "bone", + "ebon" + ], + "bgsu": [ + "bugs", + "subg" + ], + "einnr": [ + "inner", + "renin" + ], + "ailorttu": [ + "outtrail", + "tutorial" + ], + "dem": [ + "dem", + "med" + ], + "eeeginnrs": [ + "engineers", + "geneserin" + ], + "eintty": [ + "entity", + "tinety" + ], + "ceirssu": [ + "ciruses", + "cruises" + ], + "aegt": [ + "aget", + "gaet", + "gate", + "geat", + "geta", + "tega" + ], + "amnor": [ + "manor", + "moran", + "norma", + "ramon", + "roman" + ], + "deistu": [ + "duties", + "eudist", + "setuid", + "suited" + ], + "cehist": [ + "ethics", + "itches", + "sethic" + ], + "adgnor": [ + "dragon", + "gardon", + "grando" + ], + "bsuy": [ + "buys", + "busy" + ], + "aacinpt": [ + "capitan", + "captain", + "panctia" + ], + "aeghint": [ + "gahnite", + "heating" + ], + "egl": [ + "gel", + "leg" + ], + "abc": [ + "abc", + "bac", + "cab" + ], + "ailr": [ + "aril", + "lair", + "lari", + "liar", + "lira", + "rail", + "rial" + ], + "abeillr": [ + "braille", + "liberal" + ], + "betu": [ + "bute", + "tebu", + "tube" + ], + "nrstu": [ + "runts", + "snurt", + "turns" + ], + "acceh": [ + "cache", + "chace" + ], + "belt": [ + "belt", + "blet" + ], + "aaiimnnot": [ + "amination", + "animation" + ], + "acelor": [ + "carole", + "coaler", + "coelar", + "colera", + "oracle", + "recoal" + ], + "aeels": [ + "easel", + "lease" + ], + "adeirsst": [ + "diasters", + "disaster", + "disrates" + ], + "celnoos": [ + "colones", + "console" + ], + "agint": [ + "ating", + "giant", + "tangi", + "tiang" + ], + "aalmr": [ + "alarm", + "malar", + "maral", + "marla", + "ramal" + ], + "alsuu": [ + "luaus", + "usual" + ], + "adgilno": [ + "angloid", + "digonal", + "loading" + ], + "bor": [ + "bor", + "bro", + "orb", + "rob" + ], + "deeginrss": [ + "designers", + "redesigns" + ], + "orstw": [ + "strow", + "trows", + "worst", + "worts" + ], + "aaeginnrt": [ + "argentina", + "tanagrine" + ], + "ceiimmnoorss": [ + "commissioner", + "recommission" + ], + "agmnor": [ + "gorman", + "morgan" + ], + "aeelprsu": [ + "pleasure", + "serpulae" + ], + "deeinort": [ + "enteroid", + "orendite", + "oriented" + ], + "aeegl": [ + "aegle", + "aglee", + "eagle", + "galee" + ], + "enrsu": [ + "nurse", + "resun", + "runes" + ], + "aeprry": [ + "prayer", + "repray" + ], + "acehinrru": [ + "hurricane", + "raunchier" + ], + "aegopst": [ + "gestapo", + "postage", + "potages" + ], + "cdeoprru": [ + "procured", + "producer" + ], + "adil": [ + "dail", + "dali", + "dial", + "laid", + "lida" + ], + "aekmr": [ + "maker", + "marek", + "merak" + ], + "cikps": [ + "picks", + "spick" + ], + "efhist": [ + "fetish", + "fishet" + ], + "acinoss": [ + "caisson", + "casinos", + "cassino", + "cassoni" + ], + "ekmos": [ + "mokes", + "smoke" + ], + "aacehp": [ + "achape", + "apache" + ], + "efilrst": [ + "filters", + "frislet", + "lifters", + "slifter", + "stifler", + "trifles" + ], + "acdeinooprrt": [ + "adrenotropic", + "incorporated" + ], + "acfrt": [ + "craft", + "fract" + ], + "aaprt": [ + "apart", + "trapa" + ], + "eglnou": [ + "longue", + "lounge" + ], + "adm": [ + "adm", + "dam", + "mad" + ], + "aghilmort": [ + "algorithm", + "logarithm" + ], + "eims": [ + "mise", + "semi", + "sime" + ], + "cinos": [ + "cions", + "coins", + "cosin", + "icons", + "oscin", + "scion", + "sonic" + ], + "glnorsty": [ + "strongyl", + "strongly" + ], + "aeeilnntv": [ + "levantine", + "valentine" + ], + "ekn": [ + "ken", + "nek" + ], + "einoprst": [ + "pointers", + "proteins", + "ripstone", + "tropines" + ], + "aabcelp": [ + "capable", + "pacable" + ], + "illt": [ + "itll", + "lilt", + "till" + ], + "enp": [ + "nep", + "pen" + ], + "enops": [ + "opens", + "peons", + "pones" + ], + "ehos": [ + "hoes", + "hose", + "shoe" + ], + "adns": [ + "ands", + "sand" + ], + "deiinost": [ + "desition", + "editions", + "sedition" + ], + "ailmny": [ + "amylin", + "mainly" + ], + "anr": [ + "arn", + "nar", + "ran" + ], + "aaeilmnprt": [ + "palermitan", + "parliament" + ], + "acort": [ + "actor", + "carot", + "coart", + "corta", + "croat", + "rocta", + "taroc", + "troca" + ], + "aacdellot": [ + "acetaldol", + "allocated" + ], + "ceiintz": [ + "citizen", + "zincite" + ], + "ccorsu": [ + "crocus", + "occurs", + "succor" + ], + "aeimnty": [ + "amenity", + "anytime" + ], + "eils": [ + "isle", + "leis", + "lies", + "lise", + "sile" + ], + "alotuy": [ + "layout", + "lutayo", + "outlay" + ], + "bls": [ + "bls", + "lbs" + ], + "aly": [ + "aly", + "lay" + ], + "ehorss": [ + "horses", + "shoers", + "shores" + ], + "aenwy": [ + "wayne", + "waney" + ], + "adenot": [ + "atoned", + "donate" + ], + "ekorrw": [ + "rework", + "worker" + ], + "aeilv": [ + "alive", + "avile" + ], + "eelmpt": [ + "pelmet", + "temple" + ], + "ginsw": [ + "swing", + "wings" + ], + "abekrs": [ + "bakers", + "basker", + "brakes", + "breaks", + "kebars" + ], + "aerstw": [ + "rawest", + "tawers", + "waster", + "waters" + ], + "eimoprs": [ + "imposer", + "promise", + "semipro" + ], + "hint": [ + "hint", + "thin" + ], + "degir": [ + "dirge", + "egrid", + "gride", + "redig", + "ridge" + ], + "ahirrs": [ + "arrish", + "harris", + "rarish", + "shirra", + "sirrah" + ], + "aciloprt": [ + "plicator", + "tropical" + ], + "eersstt": [ + "retests", + "setters", + "streets", + "tersest", + "testers" + ], + "ceortv": [ + "corvet", + "covert", + "vector" + ], + "beffru": [ + "buffer", + "rebuff" + ], + "elppru": [ + "pulper", + "purple" + ], + "def": [ + "def", + "fed" + ], + "adeiinnosstt": [ + "destinations", + "dissentation" + ], + "elst": [ + "lest", + "lets", + "selt" + ], + "almtuu": [ + "mutual", + "umlaut" + ], + "inoprs": [ + "orpins", + "prinos", + "prison", + "spinor" + ], + "iklls": [ + "kills", + "skill" + ], + "achirs": [ + "chairs", + "ischar", + "rachis" + ], + "denrt": [ + "drent", + "trend" + ], + "aeirrs": [ + "airers", + "ariser", + "raiser", + "serrai", + "sierra" + ], + "deerst": [ + "desert", + "deters", + "rested" + ], + "delost": [ + "oldest", + "sloted", + "stoled" + ], + "abn": [ + "abn", + "ban", + "nab" + ], + "abdhknoo": [ + "bandhook", + "handbook" + ], + "aaegintv": [ + "navigate", + "vaginate" + ], + "eorsw": [ + "owser", + "resow", + "serow", + "sower", + "swore", + "worse" + ], + "immstu": [ + "mutism", + "summit" + ], + "aep": [ + "ape", + "epa", + "pea" + ], + "acepss": [ + "scapes", + "spaces" + ], + "aceeps": [ + "escape", + "espace", + "peaces" + ], + "cnoopsu": [ + "coupons", + "soupcon" + ], + "aciils": [ + "sialic", + "silica" + ], + "abost": [ + "basto", + "boast", + "boats", + "botas", + "sabot" + ], + "acegln": [ + "cangle", + "glance" + ], + "ellst": [ + "stell", + "tells" + ], + "bdemoors": [ + "bedrooms", + "boredoms" + ], + "aklst": [ + "stalk", + "talks" + ], + "ailrst": [ + "latris", + "strail", + "strial", + "trails", + "trials" + ], + "aemrsst": [ + "masters", + "streams" + ], + "aabelrt": [ + "alberta", + "latebra", + "ratable" + ], + "gor": [ + "gor", + "gro", + "org", + "rog" + ], + "cmmnoos": [ + "commons", + "consomm" + ], + "adfru": [ + "faurd", + "fraud" + ], + "cemprstu": [ + "crumpets", + "spectrum" + ], + "akoy": [ + "kayo", + "oaky", + "okay" + ], + "aehimpss": [ + "emphasis", + "misshape" + ], + "egorr": [ + "gorer", + "roger" + ], + "acepst": [ + "aspect", + "epacts" + ], + "aeemosw": [ + "awesome", + "waesome" + ], + "cnostu": [ + "counts", + "tucson", + "uncost" + ], + "cdeipr": [ + "percid", + "priced" + ], + "achrs": [ + "chars", + "crash" + ], + "filt": [ + "filt", + "flit", + "lift" + ], + "ddeeirs": [ + "derides", + "desired", + "resided" + ], + "einrt": [ + "inert", + "inter", + "niter", + "nitre", + "retin", + "trine" + ], + "celors": [ + "ceorls", + "closer", + "cresol", + "escrol" + ], + "ails": [ + "ails", + "lasi", + "lias", + "lisa", + "sail", + "sial" + ], + "ceinprss": [ + "crispens", + "princess" + ], + "aprsy": [ + "prays", + "raspy", + "spary", + "spray" + ], + "deentx": [ + "dentex", + "extend" + ], + "adors": [ + "dorsa", + "roads", + "sarod", + "sorda" + ], + "apt": [ + "apt", + "pat", + "pta", + "tap" + ], + "adry": [ + "adry", + "dray", + "yard" + ], + "eeimmors": [ + "memories", + "memorise" + ], + "aceerst": [ + "cerates", + "creates", + "ecartes", + "secreta" + ], + "acefs": [ + "cafes", + "faces" + ], + "amory": [ + "mayor", + "moray" + ], + "aens": [ + "anes", + "sane", + "sean", + "sena" + ], + "aenorst": [ + "atoners", + "noreast", + "orantes", + "rosetan", + "seatron", + "senator", + "treason" + ], + "adegrs": [ + "degras", + "egards", + "grades" + ], + "acnoorst": [ + "cartoons", + "corantos", + "ostracon", + "socotran" + ], + "opru": [ + "pour", + "roup" + ], + "egr": [ + "erg", + "ger", + "gre", + "reg" + ], + "dggilno": [ + "godling", + "golding", + "lodging" + ], + "dstu": [ + "dust", + "stud" + ], + "eeilnrty": [ + "entirely", + "lientery" + ], + "acdeelpr": [ + "parceled", + "replaced" + ], + "elosss": [ + "losses", + "sossle" + ], + "abcmot": [ + "combat", + "tombac" + ], + "aekls": [ + "alkes", + "kales", + "lakes", + "leaks", + "sakel", + "slake" + ], + "adinnoost": [ + "anisodont", + "donations", + "sondation" + ], + "adiry": [ + "dairy", + "diary", + "yaird" + ], + "gikns": [ + "ginks", + "kings" + ], + "ghinoost": [ + "shooting", + "soothing" + ], + "eknt": [ + "kent", + "knet" + ], + "adds": [ + "adds", + "dads" + ], + "aceeinorstvv": [ + "conservative", + "conversative" + ], + "chkos": [ + "hocks", + "shock" + ], + "aabdor": [ + "aboard", + "aborad", + "abroad" + ], + "benoy": [ + "boney", + "ebony" + ], + "ain": [ + "ain", + "ani", + "ian" + ], + "aeehmoprst": [ + "atmosphere", + "shapometer" + ], + "ikss": [ + "kiss", + "skis" + ], + "abest": [ + "abets", + "baste", + "bates", + "beast", + "beats", + "betas", + "estab", + "sebat", + "tabes" + ], + "aegrstt": [ + "tagster", + "targets" + ], + "celnosu": [ + "counsel", + "unclose" + ], + "adrsy": [ + "drays", + "dryas", + "yards" + ], + "dgnoor": [ + "drongo", + "gordon" + ], + "dmo": [ + "dom", + "mod" + ], + "aefmrrs": [ + "farmers", + "framers" + ], + "eeiqrsu": [ + "esquire", + "queries", + "risquee" + ], + "hrsu": [ + "rhus", + "rush" + ], + "celrstu": [ + "cluster", + "custrel", + "cutlers", + "relucts" + ], + "eerssv": [ + "serves", + "severs", + "sevres", + "verses" + ], + "eiprrssu": [ + "spurries", + "surprise", + "uprisers" + ], + "aailprt": [ + "partial", + "patrial" + ], + "celopsu": [ + "closeup", + "couples", + "culpose", + "opuscle", + "ploceus", + "upclose" + ], + "agiknnr": [ + "narking", + "ranking" + ], + "cst": [ + "cst", + "cts", + "sct" + ], + "ceo": [ + "coe", + "eco" + ], + "aacelp": [ + "aplace", + "palace" + ], + "beglo": [ + "bogle", + "globe" + ], + "ackr": [ + "cark", + "rack" + ], + "acdeiimnot": [ + "decimation", + "medication" + ], + "aeehorsuw": [ + "housewear", + "warehouse" + ], + "ceeiprt": [ + "ereptic", + "precite", + "receipt" + ], + "ghost": [ + "ghost", + "goths" + ], + "boss": [ + "boss", + "sobs" + ], + "deipr": [ + "pride", + "pried", + "redip", + "riped" + ], + "ehikt": [ + "keith", + "kithe" + ], + "adiln": [ + "danli", + "ladin", + "linda", + "nidal" + ], + "cehil": [ + "chiel", + "chile" + ], + "aann": [ + "anan", + "anna", + "nana" + ], + "elnpty": [ + "pentyl", + "plenty" + ], + "loos": [ + "loos", + "oslo", + "sloo", + "solo", + "sool" + ], + "ahortt": [ + "athort", + "throat" + ], + "eirstw": [ + "twiers", + "wister", + "wriest", + "writes" + ], + "adps": [ + "daps", + "pads", + "spad" + ], + "eqstu": [ + "quest", + "squet" + ], + "ceeginnrs": [ + "screening", + "secerning" + ], + "anrst": [ + "rants", + "starn", + "tarns", + "trans" + ], + "eeinopr": [ + "pereion", + "peronei", + "pioneer" + ], + "aabcort": [ + "abactor", + "acrobat" + ], + "aelpst": [ + "palest", + "palets", + "pastel", + "petals", + "plates", + "pleats", + "septal", + "staple", + "tepals" + ], + "acers": [ + "acres", + "arces", + "cares", + "carse", + "caser", + "ceras", + "cesar", + "escar", + "races", + "sacre", + "scare", + "scrae", + "serac" + ], + "acehiltt": [ + "athletic", + "thetical" + ], + "egillnt": [ + "gillnet", + "telling" + ], + "aaclost": [ + "catalos", + "coastal", + "salacot" + ], + "demos": [ + "demos", + "domes", + "modes" + ], + "aekw": [ + "wake", + "weak", + "weka" + ], + "aghnruy": [ + "ahungry", + "hungary" + ], + "aeelrrtv": [ + "retravel", + "revertal", + "traveler" + ], + "aln": [ + "aln", + "lan" + ], + "eemny": [ + "enemy", + "yemen" + ], + "giinrs": [ + "rising", + "siring" + ], + "ellsw": [ + "swell", + "wells" + ], + "ghiinst": [ + "histing", + "insight" + ], + "cdeeirrstt": [ + "derestrict", + "restricted" + ], + "ceersst": [ + "cresset", + "resects", + "secrets" + ], + "aelrtt": [ + "artlet", + "latter", + "rattel", + "rattle", + "talter", + "tartle", + "tatler" + ], + "acehmnrst": [ + "merchants", + "starchmen" + ], + "aeilrrst": [ + "retrials", + "trailers" + ], + "aeeprt": [ + "petrea", + "repeat", + "retape" + ], + "aelnpty": [ + "aplenty", + "penalty" + ], + "aeglsss": [ + "gasless", + "glasses", + "sagless" + ], + "abeelns": [ + "baleens", + "enables" + ], + "cen": [ + "cen", + "enc" + ], + "bdeilru": [ + "builder", + "rebuild" + ], + "errty": [ + "retry", + "terry" + ], + "aegmnrstu": [ + "argentums", + "arguments", + "mustanger" + ], + "aaenr": [ + "anear", + "arean", + "arena" + ], + "ilppsu": [ + "pupils", + "slipup", + "upslip" + ], + "aersttw": [ + "stewart", + "swatter" + ], + "abst": [ + "bast", + "bats", + "stab", + "tabs" + ], + "aaclsu": [ + "ascula", + "calusa", + "casual", + "casula", + "causal" + ], + "hilops": [ + "philos", + "polish" + ], + "ellovy": [ + "lovely", + "volley" + ], + "aerstx": [ + "extras", + "sextar", + "taxers" + ], + "acelsu": [ + "caelus", + "casule", + "caules", + "clause" + ], + "einp": [ + "pein", + "pien", + "pine" + ], + "cgilnoo": [ + "cooling", + "locoing" + ], + "dent": [ + "dent", + "detn", + "tend" + ], + "ckrstu": [ + "struck", + "trucks" + ], + "cdeiorv": [ + "cervoid", + "divorce" + ], + "aalru": [ + "aural", + "laura" + ], + "ehopprs": [ + "hoppers", + "shopper" + ], + "kooty": [ + "kyoto", + "tokyo" + ], + "alprty": [ + "paltry", + "partly", + "raptly" + ], + "acdny": [ + "candy", + "dancy" + ], + "illps": [ + "pills", + "spill" + ], + "egirt": [ + "greit", + "tiger", + "tigre" + ], + "enorss": [ + "senors", + "sensor", + "snores" + ], + "aeglns": [ + "angels", + "angles", + "gansel", + "gleans" + ], + "acdiinorst": [ + "ancistroid", + "indicators" + ], + "adeels": [ + "leased", + "sealed" + ], + "ahit": [ + "aith", + "hait", + "hati", + "thai" + ], + "defr": [ + "derf", + "ferd", + "fred" + ], + "acilmnopt": [ + "complaint", + "compliant" + ], + "ceenss": [ + "censes", + "scenes" + ], + "almor": [ + "molar", + "moral", + "romal" + ], + "adu": [ + "aud", + "dau" + ], + "efginr": [ + "finger", + "fringe" + ], + "eekps": [ + "keeps", + "peeks", + "pekes" + ], + "acelot": [ + "acetol", + "colate", + "locate" + ], + "adeinrt": [ + "andrite", + "antired", + "detrain", + "diantre", + "radient", + "randite", + "trained" + ], + "eorss": [ + "roses", + "sores" + ], + "abls": [ + "albs", + "bals", + "blas", + "labs", + "slab" + ], + "abder": [ + "ardeb", + "barde", + "bared", + "beard", + "bread", + "debar" + ], + "denoow": [ + "enwood", + "wooden" + ], + "ghotu": [ + "ought", + "tough" + ], + "eil": [ + "eli", + "ile", + "lei", + "lie" + ], + "cehst": [ + "chest", + "stech" + ], + "einnops": [ + "pension", + "pinones" + ], + "eeenrsuv": [ + "revenues", + "unreeves", + "unsevere" + ], + "acgir": [ + "agric", + "cigar", + "craig" + ], + "eefhlrs": [ + "flesher", + "herself" + ], + "ceiinoprs": [ + "coinspire", + "precision" + ], + "eeerrssv": [ + "reserves", + "reverses", + "severers" + ], + "elosv": [ + "loves", + "solve", + "voles" + ], + "horsst": [ + "horsts", + "shorts" + ], + "cdeinooprrtu": [ + "proreduction", + "reproduction" + ], + "deegiinnrst": [ + "ingredients", + "tenderising" + ], + "cdeeorrr": [ + "recorder", + "rerecord" + ], + "acnny": [ + "canny", + "nancy" + ], + "acly": [ + "acyl", + "clay", + "lacy" + ], + "acehpst": [ + "hepcats", + "patches" + ], + "defnru": [ + "funder", + "refund" + ], + "nostw": [ + "nowts", + "towns", + "wonts" + ], + "ceeinoprt": [ + "prenotice", + "reception" + ], + "aeilms": [ + "amiles", + "asmile", + "mailes", + "mesail", + "mesial", + "samiel" + ], + "cprsuy": [ + "cyprus", + "sprucy" + ], + "ddos": [ + "dods", + "odds" + ], + "deiinrs": [ + "insider", + "siderin" + ], + "aeimnrss": [ + "arsenism", + "seminars" + ], + "aekmrs": [ + "makers", + "masker", + "remask" + ], + "aehrst": [ + "earths", + "haster", + "haters", + "hearst", + "hearts" + ], + "eev": [ + "eve", + "vee" + ], + "acerrt": [ + "arrect", + "carter", + "crater", + "recart", + "tracer" + ], + "acmr": [ + "cram", + "marc" + ], + "adeelps": [ + "delapse", + "elapsed", + "pleased", + "sepaled" + ], + "deilwy": [ + "dewily", + "widely", + "wieldy" + ], + "aehprs": [ + "phaser", + "phrase", + "raphes", + "seraph", + "shaper", + "sherpa", + "shrape" + ], + "eeginnu": [ + "genuine", + "ingenue" + ], + "agiinrs": [ + "airings", + "arising", + "raising" + ], + "aadeiprs": [ + "paradise", + "sparidae" + ], + "aders": [ + "dares", + "dears", + "rased", + "reads" + ], + "elors": [ + "lores", + "loser", + "orles", + "orsel", + "roles", + "rosel", + "soler", + "sorel" + ], + "aefl": [ + "alef", + "feal", + "flea", + "leaf" + ], + "deeils": [ + "delies", + "diesel", + "ediles", + "elides", + "sedile", + "seidel" + ], + "erssuv": [ + "servus", + "versus" + ], + "dor": [ + "dor", + "ord", + "rod" + ], + "adisu": [ + "saudi", + "udasi" + ], + "hrs": [ + "hrs", + "shr" + ], + "ikls": [ + "ilks", + "lisk", + "silk", + "skil", + "slik" + ], + "aeknr": [ + "anker", + "karen", + "kearn", + "naker", + "nerka" + ], + "cdeilmop": [ + "compiled", + "complied" + ], + "acimnort": [ + "macrotin", + "romantic" + ], + "adeeelrv": [ + "laveered", + "revealed" + ], + "abelrt": [ + "albert", + "balter", + "batler", + "labret", + "tabler", + "tarble" + ], + "bilorst": [ + "bristol", + "strobil" + ], + "acl": [ + "alc", + "cal", + "lac", + "lca" + ], + "inooprst": [ + "notropis", + "portions", + "positron", + "sorption" + ], + "ceorsst": [ + "corsets", + "costers", + "escorts", + "scoters", + "sectors" + ], + "aelmsu": [ + "amelus", + "samuel", + "ulemas" + ], + "fist": [ + "fist", + "fits", + "sift" + ], + "adegrrs": [ + "graders", + "regards" + ], + "hrtu": [ + "hurt", + "ruth", + "thru" + ], + "acehimnry": [ + "hemicrany", + "machinery" + ], + "gim": [ + "gim", + "mig" + ], + "aenrrw": [ + "rewarn", + "warner", + "warren" + ], + "ilps": [ + "lips", + "lisp", + "slip" + ], + "ddeistu": [ + "studdie", + "studied" + ], + "aeimr": [ + "aimer", + "amire", + "maire", + "marie", + "ramie" + ], + "cstu": [ + "cust", + "cuts", + "scut" + ], + "aeflnru": [ + "earnful", + "flaneur", + "frenula", + "funeral", + "furlane" + ], + "aeginrrs": [ + "earrings", + "grainers" + ], + "acehprst": [ + "chapters", + "patchers" + ], + "deinns": [ + "dennis", + "sinned" + ], + "aagmn": [ + "amang", + "ganam", + "magna", + "manga" + ], + "cdeinot": [ + "condite", + "ctenoid", + "deontic", + "noticed" + ], + "aeilrrty": [ + "literary", + "trailery" + ], + "agilnss": [ + "glassin", + "signals" + ], + "acps": [ + "caps", + "pacs", + "scap" + ], + "alt": [ + "alt", + "lat", + "tal" + ], + "aaglno": [ + "agonal", + "analog", + "angola" + ], + "aacfil": [ + "cafila", + "facial" + ], + "aelntt": [ + "latent", + "latten", + "nattle", + "talent", + "tantle" + ], + "eeekrs": [ + "kreese", + "reseek", + "seeker", + "sekere" + ], + "hoost": [ + "hoots", + "shoot", + "sooth", + "sotho", + "toosh" + ], + "effost": [ + "offset", + "setoff" + ], + "eeilt": [ + "elite", + "telei" + ], + "inps": [ + "insp", + "nips", + "pins", + "snip", + "spin" + ], + "dehissw": [ + "swedish", + "swished" + ], + "emops": [ + "epsom", + "mopes", + "poems", + "pomes" + ], + "boort": [ + "boort", + "robot" + ], + "einsstw": [ + "wisents", + "witness" + ], + "aegsst": [ + "sagest", + "stages" + ], + "deoprw": [ + "powder", + "prowed" + ], + "aessss": [ + "assess", + "sasses" + ], + "ahsw": [ + "haws", + "shaw", + "shwa", + "wash" + ], + "enosst": [ + "onsets", + "seston", + "setons", + "stenos", + "stones" + ], + "aceennrt": [ + "centenar", + "entrance" + ], + "egmno": [ + "emong", + "genom", + "gnome" + ], + "oorst": [ + "roost", + "roots", + "rotos", + "toros", + "torso" + ], + "aacdeilnort": [ + "declaration", + "redactional" + ], + "gilnos": [ + "logins", + "losing", + "soling" + ], + "adeggst": [ + "gadgets", + "stagged" + ], + "belno": [ + "nobel", + "noble" + ], + "erv": [ + "rev", + "ver" + ], + "eglops": [ + "gospel", + "spogel" + ], + "eloos": [ + "loose", + "oleos" + ], + "aims": [ + "aims", + "amis", + "mias", + "saim", + "siam", + "sima" + ], + "ceeiinprt": [ + "princeite", + "recipient" + ], + "giiklnn": [ + "inkling", + "kilning", + "linking" + ], + "adeenr": [ + "deaner", + "earned", + "endear", + "neared" + ], + "aciilms": [ + "islamic", + "laicism", + "silicam" + ], + "acehilstt": [ + "athletics", + "statelich" + ], + "aekprr": [ + "parker", + "repark" + ], + "copr": [ + "copr", + "corp", + "crop", + "porc", + "proc" + ], + "aops": [ + "asop", + "paso", + "sapo", + "soap" + ], + "eilprt": [ + "pretil", + "tripel", + "triple" + ], + "cdeersu": [ + "descure", + "recused", + "reduces", + "rescued", + "secured", + "seducer" + ], + "einortu": [ + "routine", + "tueiron" + ], + "aabcillsy": [ + "asyllabic", + "basically" + ], + "ckors": [ + "corks", + "rocks" + ], + "ainstt": [ + "astint", + "taints", + "tanist", + "titans" + ], + "ghostu": [ + "oughts", + "sought", + "toughs" + ], + "demnotu": [ + "demount", + "mounted" + ], + "aabhitt": [ + "habitat", + "tabitha" + ], + "adeimn": [ + "aidmen", + "daimen", + "damine", + "demain", + "dimane", + "maiden", + "median", + "medina" + ], + "gnsu": [ + "gnus", + "guns", + "snug", + "sung" + ], + "acennrs": [ + "canners", + "scanner" + ], + "eehinr": [ + "herein", + "inhere" + ], + "aadeimnt": [ + "aminated", + "animated", + "diamante", + "mandaite", + "mantidae" + ], + "ior": [ + "rio", + "roi" + ], + "ehor": [ + "hero", + "hoer", + "hore", + "rheo" + ], + "eeginrt": [ + "giterne", + "integer", + "retinge", + "treeing" + ], + "abcehlor": [ + "bachelor", + "crabhole", + "lochaber" + ], + "afgilln": [ + "falling", + "fingall" + ], + "aceprt": [ + "carpet", + "peract", + "preact" + ], + "eelnss": [ + "lenses", + "lessen" + ], + "abinry": [ + "binary", + "brainy" + ], + "addeentt": [ + "attended", + "dentated" + ], + "aciilnoot": [ + "coalition", + "coitional", + "lociation" + ], + "aelrtw": [ + "lawter", + "walter" + ], + "aegw": [ + "waeg", + "wage", + "wega" + ], + "aalst": [ + "atlas", + "salat", + "salta", + "talas" + ], + "adnw": [ + "dawn", + "wand" + ], + "eefls": [ + "feels", + "flees" + ], + "eorrttu": [ + "torture", + "trouter", + "tutorer" + ], + "aclr": [ + "carl", + "clar" + ], + "acot": [ + "coat", + "taco" + ], + "mrs": [ + "mrs", + "rms" + ], + "aceinnort": [ + "connarite", + "container", + "cotarnine", + "crenation", + "narcotine" + ], + "app": [ + "app", + "pap", + "ppa" + ], + "eioprrssuv": [ + "proviruses", + "supervisor" + ], + "coprs": [ + "corps", + "crops" + ], + "acorst": [ + "actors", + "arctos", + "castor", + "castro", + "costar", + "ostrca", + "scrota", + "tarocs" + ], + "eilrv": [ + "ervil", + "levir", + "liver", + "livre", + "rivel", + "viler" + ], + "abeill": [ + "alible", + "belial", + "labile", + "liable" + ], + "acellr": [ + "caller", + "cellar", + "recall" + ], + "ademssu": [ + "assumed", + "medusas" + ], + "adeeprrtu": [ + "apertured", + "departure" + ], + "beefil": [ + "befile", + "belief" + ], + "dehlorsu": [ + "shoulder", + "shoulerd" + ], + "cdeor": [ + "coder", + "cored", + "credo", + "decor" + ], + "kloopu": [ + "lookup", + "uplook" + ], + "ory": [ + "yor", + "ory", + "roy" + ], + "ino": [ + "ino", + "ion", + "oni" + ], + "adeeimrt": [ + "diameter", + "diatreme" + ], + "eefinr": [ + "enfire", + "ferine", + "fineer", + "infree", + "refine" + ], + "bddeir": [ + "bedrid", + "bidder", + "birded" + ], + "eginrs": [ + "reigns", + "renigs", + "resign", + "resing", + "sering", + "signer", + "singer" + ], + "aensv": [ + "avens", + "evans", + "naves", + "vanes" + ], + "adehlr": [ + "hareld", + "harled", + "herald" + ], + "afils": [ + "alifs", + "fails" + ], + "eikn": [ + "enki", + "kine", + "nike" + ], + "eeiinnnorttv": [ + "intervention", + "introvenient" + ], + "gilnpu": [ + "gulpin", + "puling" + ], + "aacinorttt": [ + "attraction", + "tractation" + ], + "acdfiiimnoot": [ + "domification", + "modification" + ], + "aceil": [ + "alice", + "celia", + "elaic", + "ileac" + ], + "aailnst": [ + "lanista", + "saliant", + "santali" + ], + "deer": [ + "deer", + "dere", + "dree", + "rede", + "reed" + ], + "ceim": [ + "emic", + "mice" + ], + "adilpry": [ + "pyralid", + "rapidly" + ], + "empt": [ + "empt", + "temp" + ], + "inort": [ + "intro", + "iortn", + "nitro", + "norit" + ], + "aacenrssu": [ + "anacruses", + "assurance" + ], + "astv": [ + "tavs", + "vast", + "vats" + ], + "eilnotu": [ + "elution", + "outline" + ], + "aejns": [ + "janes", + "jeans" + ], + "acefiiinortv": [ + "revification", + "verification" + ], + "ddo": [ + "dod", + "odd" + ], + "aprw": [ + "warp", + "wrap" + ], + "eefrrs": [ + "freers", + "freres", + "refers" + ], + "dmoo": [ + "doom", + "modo", + "mood" + ], + "agims": [ + "agism", + "sigma" + ], + "addemns": [ + "demands", + "maddens" + ], + "eegilnps": [ + "peelings", + "sleeping", + "speeling" + ], + "etx": [ + "ext", + "tex" + ], + "abem": [ + "ambe", + "beam", + "bema" + ], + "adegginnr": [ + "dangering", + "deranging", + "gandering", + "gardening" + ], + "aeirrv": [ + "arrive", + "varier" + ], + "acehorrst": [ + "carthorse", + "horsecart", + "orchestra" + ], + "ensstu": [ + "sunset", + "unsets" + ], + "eemoorrv": [ + "moreover", + "overmore" + ], + "adefmr": [ + "farmed", + "framed" + ], + "aacillnoot": [ + "allocation", + "locational" + ], + "aessy": [ + "eyass", + "essay" + ], + "acmps": [ + "camps", + "scamp" + ], + "acert": [ + "caret", + "carte", + "cater", + "cerat", + "crate", + "creat", + "creta", + "ecart", + "react", + "recta", + "trace" + ], + "ackps": [ + "packs", + "spack" + ], + "aaimnor": [ + "amanori", + "moarian" + ], + "hotu": [ + "hout", + "thou" + ], + "aeglrty": [ + "greatly", + "regalty" + ], + "akms": [ + "kasm", + "mask" + ], + "aeghhoopprrt": [ + "photographer", + "rephotograph" + ], + "fimnor": [ + "formin", + "inform" + ], + "aclo": [ + "alco", + "coal", + "cola", + "loca" + ], + "aeggimnss": [ + "gigmaness", + "messaging" + ], + "einntt": [ + "intent", + "nitent", + "tinnet" + ], + "aaelnpst": [ + "platanes", + "pleasant" + ], + "ekops": [ + "pokes", + "spoke" + ], + "agilmnps": [ + "psalming", + "sampling" + ], + "deirw": [ + "weird", + "wider", + "wierd", + "wired", + "wride", + "wried" + ], + "ilno": [ + "lino", + "lion", + "loin", + "noil" + ], + "ehlos": [ + "holes", + "hosel", + "sheol", + "shole" + ], + "abdel": [ + "baled", + "blade" + ], + "aelms": [ + "almes", + "amsel", + "lames", + "males", + "meals", + "melas", + "mesal", + "salem", + "samel" + ], + "acnnoy": [ + "ancony", + "canyon" + ], + "goot": [ + "goto", + "togo" + ], + "eemrst": [ + "merest", + "mester", + "meters", + "metres", + "restem", + "retems", + "temser", + "termes" + ], + "eelmry": [ + "yelmer", + "merely" + ], + "eimprst": [ + "imprest", + "permits" + ], + "ilmmsu": [ + "mulism", + "muslim" + ], + "eeelsv": [ + "levees", + "sleeve" + ], + "aceelnr": [ + "cleaner", + "enclear", + "reclean", + "relance" + ], + "beef": [ + "beef", + "feeb" + ], + "deefgin": [ + "feeding", + "feigned" + ], + "ekorst": [ + "stoker", + "stroke", + "trokes" + ], + "aegimnrsu": [ + "geraniums", + "measuring" + ], + "acd": [ + "adc", + "cad", + "dca" + ], + "ahst": [ + "hast", + "hats", + "shat", + "tash" + ], + "binor": [ + "biron", + "inorb", + "robin" + ], + "ahnors": [ + "rhason", + "sharon", + "shoran" + ], + "cpt": [ + "cpt", + "pct" + ], + "frsu": [ + "furs", + "surf" + ], + "adeeimnr": [ + "adermine", + "remained" + ], + "dir": [ + "dir", + "rid" + ], + "aeiilrs": [ + "alisier", + "israeli", + "resilia" + ], + "cdor": [ + "cord", + "dcor" + ], + "alv": [ + "lav", + "val" + ], + "efhls": [ + "flesh", + "shelf" + ], + "giimnt": [ + "miting", + "timing" + ], + "aeginnprt": [ + "enrapting", + "parenting" + ], + "foost": [ + "foots", + "sfoot", + "stoof" + ], + "adehst": [ + "deaths", + "hasted", + "sdeath" + ], + "aaiknrt": [ + "katrina", + "tarkani" + ], + "ailms": [ + "islam", + "ismal", + "limas", + "mails", + "salmi", + "simal" + ], + "denos": [ + "doesn", + "nodes", + "nosed", + "sonde" + ], + "deess": [ + "deess", + "essed", + "seeds" + ], + "cdeit": [ + "cetid", + "cited", + "edict" + ], + "eilt": [ + "itel", + "lite", + "teil", + "teli", + "tile" + ], + "defnoru": [ + "founder", + "refound", + "underfo" + ], + "adeersv": [ + "adverse", + "evaders" + ], + "egn": [ + "eng", + "gen", + "neg" + ], + "acdeghirs": [ + "discharge", + "scraighed" + ], + "nost": [ + "nots", + "snot", + "tons" + ], + "aclor": [ + "alcor", + "calor", + "carlo", + "carol", + "claro", + "coral" + ], + "ehnost": [ + "ethnos", + "honest" + ], + "ackst": [ + "stack", + "tacks" + ], + "aeehorssuw": [ + "housewares", + "warehouses" + ], + "aeinrsstt": [ + "resistant", + "straitens" + ], + "aghn": [ + "ghan", + "hang" + ], + "aceorrt": [ + "acroter", + "creator", + "reactor" + ], + "abemr": [ + "amber", + "bearm", + "bemar", + "brame", + "bream", + "embar" + ], + "acekrrt": [ + "retrack", + "tracker" + ], + "eeiprr": [ + "perrie", + "pierre" + ], + "adeehst": [ + "headset", + "sethead" + ], + "acelm": [ + "camel", + "clame", + "cleam", + "macle" + ], + "almps": [ + "lamps", + "palms", + "plasm", + "psalm", + "slamp" + ], + "degilnnruy": [ + "enduringly", + "underlying" + ], + "chi": [ + "chi", + "hic", + "ich" + ], + "acehs": [ + "aches", + "chase" + ], + "ceorstuy": [ + "cosurety", + "courtesy" + ], + "aehnst": [ + "athens", + "hasten", + "snathe", + "sneath", + "thanes" + ], + "eos": [ + "eos", + "oes", + "ose", + "soe" + ], + "deeirrt": [ + "retired", + "retried", + "tireder" + ], + "ips": [ + "ips", + "pis", + "psi", + "sip" + ], + "aekmrrs": [ + "markers", + "remarks" + ], + "aceesstt": [ + "casettes", + "cassette" + ], + "acginsu": [ + "causing", + "saucing" + ], + "aeilmnr": [ + "lairmen", + "manlier", + "marline", + "mineral", + "railmen", + "ramline" + ], + "bruy": [ + "bury", + "ruby" + ], + "eeginrst": [ + "energist", + "gentries", + "ingester", + "integers", + "reesting", + "steering" + ], + "ahiprs": [ + "parish", + "raphis", + "rhapis" + ], + "ceenrss": [ + "censers", + "screens", + "secerns" + ], + "flosw": [ + "flows", + "fowls", + "wolfs" + ], + "adimstu": [ + "dumaist", + "stadium" + ], + "imns": [ + "mins", + "nims" + ], + "cnoopu": [ + "coupon", + "uncoop" + ], + "emst": [ + "mest", + "mets", + "stem" + ], + "addersw": [ + "edwards", + "swadder", + "swarded", + "wadders" + ], + "aaelnrstt": [ + "alterants", + "tarletans", + "translate" + ], + "adeggt": [ + "gadget", + "tagged" + ], + "deotv": [ + "devot", + "voted" + ], + "eikllr": [ + "killer", + "rekill" + ], + "beiks": [ + "bikes", + "kibes" + ], + "entu": [ + "neut", + "tune" + ], + "adehps": [ + "hasped", + "pashed", + "phased", + "shaped" + ], + "aefmrr": [ + "farmer", + "framer" + ], + "cenorstu": [ + "construe", + "counters", + "recounts", + "trounces" + ], + "pstu": [ + "puts", + "sput", + "supt", + "tups" + ], + "ceeflprty": [ + "perfectly", + "prefectly" + ], + "aelsv": [ + "laves", + "salve", + "selva", + "slave", + "vales", + "valse", + "veals" + ], + "emo": [ + "eom", + "meo", + "moe" + ], + "eehors": [ + "heroes", + "reshoe" + ], + "adeinpt": [ + "depaint", + "inadept", + "painted", + "patined" + ], + "ahilnoortz": [ + "horizontal", + "notorhizal" + ], + "deelrstu": [ + "deluster", + "lustered", + "resulted", + "ulstered" + ], + "acehilt": [ + "alethic", + "ethical", + "thecial" + ], + "aceirrrs": [ + "carriers", + "scarrier" + ], + "bdeilrsu": [ + "builders", + "rebuilds" + ], + "egglrstu": [ + "gurglets", + "struggle" + ], + "aelnrtu": [ + "laurent", + "naturel", + "neutral", + "unalert" + ], + "efhirs": [ + "fisher", + "sherif" + ], + "aeprss": [ + "aspers", + "parses", + "passer", + "prases", + "repass", + "spares", + "sparse", + "spears" + ], + "abeginr": [ + "bearing", + "begrain", + "brainge", + "gribane", + "rigbane" + ], + "abdr": [ + "bard", + "brad", + "darb", + "drab" + ], + "bcmoo": [ + "combo", + "coomb" + ], + "einorss": [ + "seniors", + "sonsier" + ], + "aaciinottv": [ + "activation", + "cavitation" + ], + "dos": [ + "dos", + "ods", + "sod" + ], + "ailt": [ + "alit", + "atli", + "ital", + "lait", + "lati", + "tail", + "tali" + ], + "eilnotv": [ + "violent", + "volenti" + ], + "abins": [ + "basin", + "nabis", + "sabin" + ], + "opsu": [ + "opus", + "soup" + ], + "cginorss": [ + "crossing", + "scorings" + ], + "ceimrs": [ + "crimes", + "scrime" + ], + "enort": [ + "noter", + "notre", + "tenor", + "toner", + "trone" + ], + "aeltx": [ + "exalt", + "latex" + ], + "abcehnrs": [ + "branches", + "brechans" + ], + "aemnory": [ + "anymore", + "romneya" + ], + "dehil": [ + "delhi", + "heild", + "hidel", + "hield" + ], + "aeiln": [ + "alien", + "aline", + "anile", + "elain", + "elian", + "laine", + "liane", + "linea" + ], + "acloort": [ + "carotol", + "crotalo", + "locator" + ], + "ajnu": [ + "jaun", + "juan" + ], + "aeilmss": [ + "aimless", + "melissa", + "samiels", + "seismal" + ], + "ehisst": [ + "heists", + "shiest", + "sithes", + "thesis" + ], + "lnnoy": [ + "nylon", + "nonyl", + "nonly" + ], + "ckory": [ + "corky", + "rocky" + ], + "aabginrs": [ + "abrasing", + "bargains" + ], + "aegiinr": [ + "igraine", + "nigeria" + ], + "enps": [ + "pens", + "sepn" + ], + "deilnttu": [ + "dilutent", + "untilted", + "untitled" + ], + "ggiinns": [ + "signing", + "singing" + ], + "ailmopt": [ + "optimal", + "palmito" + ], + "cloooprst": [ + "procotols", + "protocols" + ], + "glnu": [ + "gunl", + "lung" + ], + "censt": [ + "cents", + "csnet", + "scent" + ], + "eerrstu": [ + "retruse", + "ureters" + ], + "aadeeltuv": [ + "devaluate", + "evaluated" + ], + "adesty": [ + "stayed", + "steady" + ], + "eess": [ + "eses", + "esse", + "sees" + ], + "aersv": [ + "avers", + "raves", + "saver", + "versa" + ], + "deeemr": [ + "deemer", + "meered", + "redeem", + "remede" + ], + "egorrs": [ + "groser", + "rogers" + ], + "aginr": [ + "agrin", + "argin", + "garni", + "grain" + ], + "eegimr": [ + "emigre", + "regime" + ], + "ehissw": [ + "wishes", + "wisshe" + ], + "ddeenp": [ + "depend", + "pended" + ], + "deffir": [ + "differ", + "riffed" + ], + "achimnost": [ + "macintosh", + "monachist" + ], + "acimno": [ + "anomic", + "camino", + "camion", + "conima", + "manioc", + "monica" + ], + "aeiprrs": [ + "aspirer", + "parries", + "praiser", + "rapiers", + "raspier", + "repairs", + "serpari" + ], + "abehrt": [ + "bather", + "bertha", + "breath" + ], + "celo": [ + "cole", + "ecol" + ], + "amrt": [ + "mart", + "tram" + ], + "acdeln": [ + "calden", + "candle", + "lanced" + ], + "cdeloor": [ + "colored", + "croodle", + "decolor" + ], + "eekss": [ + "kesse", + "seeks", + "skees" + ], + "gilnov": [ + "loving", + "voling" + ], + "ginortu": [ + "outgrin", + "outring", + "routing", + "touring" + ], + "cdos": [ + "cods", + "docs" + ], + "aeeilrrt": [ + "irrelate", + "retailer" + ], + "aiimnstv": [ + "nativism", + "vitamins" + ], + "aeeglnt": [ + "angelet", + "elegant" + ], + "agins": [ + "gains", + "signa" + ], + "eirssst": [ + "resists", + "sisters" + ], + "aghilmorst": [ + "algorithms", + "logarithms" + ], + "addimr": [ + "madrid", + "riddam" + ], + "agimnr": [ + "arming", + "ingram", + "margin" + ], + "aefk": [ + "fake", + "feak" + ], + "adf": [ + "afd", + "fad" + ], + "eorstv": [ + "stover", + "strove", + "troves", + "voters" + ], + "ceru": [ + "cure", + "ecru", + "eruc" + ], + "acdemmnor": [ + "commander", + "recommand" + ], + "deilors": [ + "soldier", + "solider" + ], + "ains": [ + "ains", + "anis", + "ansi", + "nais", + "nasi", + "nias", + "sain", + "sina" + ], + "ijnstu": [ + "injust", + "justin" + ], + "ghilopstt": [ + "spotlight", + "stoplight" + ], + "cikrst": [ + "strick", + "tricks" + ], + "bhrsu": [ + "brush", + "buhrs", + "shrub" + ], + "aelnps": [ + "naples", + "panels", + "planes" + ], + "aeprs": [ + "apers", + "apres", + "asper", + "pares", + "parse", + "pears", + "prase", + "presa", + "rapes", + "reaps", + "repas", + "spaer", + "spare", + "spear" + ], + "cgiilosst": [ + "glossitic", + "logistics" + ], + "bgilnow": [ + "blowing", + "bowling" + ], + "irt": [ + "rit", + "rti", + "tri" + ], + "adhins": [ + "danish", + "sandhi" + ], + "alp": [ + "alp", + "apl", + "lap", + "pal" + ], + "ikrst": [ + "skirt", + "stirk" + ], + "adginrsw": [ + "drawings", + "swarding" + ], + "elorsv": [ + "lovers", + "solver" + ], + "acimot": [ + "atomic", + "matico" + ], + "aabcir": [ + "arabic", + "cairba" + ], + "amt": [ + "amt", + "atm", + "mat", + "tam" + ], + "acehlr": [ + "rachel", + "rechal" + ], + "enov": [ + "nevo", + "oven" + ], + "achins": [ + "chains", + "chinas" + ], + "cghiinstw": [ + "switching", + "witchings" + ], + "aadeprst": [ + "adapters", + "readapts" + ], + "imoprst": [ + "imports", + "primost", + "tropism" + ], + "benorz": [ + "bonzer", + "bronze" + ], + "adnsy": [ + "dansy", + "sandy" + ], + "aaeinoprst": [ + "anisoptera", + "asperation", + "separation" + ], + "cepsstu": [ + "suscept", + "suspect" + ], + "acmor": [ + "carom", + "coram", + "macro", + "marco" + ], + "deenrs": [ + "denser", + "enders", + "resend", + "sender" + ], + "aadmnorty": [ + "damnatory", + "mandatory" + ], + "gmy": [ + "gym", + "myg" + ], + "iinottu": [ + "intuito", + "tuition" + ], + "eopssu": [ + "esopus", + "opuses", + "pousse", + "spouse" + ], + "ceiotx": [ + "coxite", + "exotic" + ], + "ginpsu": [ + "pignus", + "spuing" + ], + "aehrstt": [ + "hatters", + "rathest", + "shatter", + "threats" + ], + "acms": [ + "cams", + "macs", + "masc", + "scam" + ], + "ejlo": [ + "joel", + "jole" + ], + "deorsty": [ + "destroy", + "stroyed" + ], + "aostu": [ + "aotus", + "autos", + "outas" + ], + "eeimprss": [ + "emprises", + "impreses", + "mesprise", + "premises", + "spiremes" + ], + "eprry": [ + "perry", + "pryer", + "repry" + ], + "denoz": [ + "dozen", + "zendo", + "zoned" + ], + "eehtt": [ + "teeth", + "theet", + "thete" + ], + "ampst": [ + "stamp", + "tamps" + ], + "lostu": [ + "lotus", + "louts", + "tolus" + ], + "aadeeprst": [ + "asperated", + "estrapade", + "paederast", + "separated" + ], + "ant": [ + "ant", + "nat", + "tan" + ], + "cdeeiirtv": [ + "creditive", + "directive" + ], + "aerrstt": [ + "ratters", + "restart", + "starter" + ], + "bdenru": [ + "bunder", + "burden", + "burned", + "unbred" + ], + "aepst": [ + "paste", + "pates", + "peats", + "septa", + "spate", + "tapes", + "tepas" + ], + "ilms": [ + "mils", + "slim" + ], + "aelmp": [ + "ample", + "elamp", + "maple" + ], + "eklu": [ + "leuk", + "luke" + ], + "aeeilrrst": [ + "retailers", + "serratile" + ], + "deopt": [ + "depot", + "opted", + "toped" + ], + "eip": [ + "epi", + "pie" + ], + "eiimnoss": [ + "emission", + "misiones", + "simonies" + ], + "eept": [ + "pete", + "tepe" + ], + "ceps": [ + "ceps", + "psec", + "spec" + ], + "efinst": [ + "feints", + "festin", + "finest", + "infest" + ], + "aelrty": [ + "elytra", + "lyrate", + "raylet", + "realty", + "telary" + ], + "bow": [ + "bow", + "wob" + ], + "aaenpprt": [ + "apparent", + "trappean" + ], + "aciilnnorsttu": [ + "instructional", + "nonaltruistic" + ], + "beopr": [ + "probe", + "rebop" + ], + "diim": [ + "imid", + "midi" + ], + "eiimnoprsss": [ + "impressions", + "permissions" + ], + "eilott": [ + "lottie", + "toilet", + "tolite" + ], + "adeknr": [ + "danker", + "darken", + "endark", + "kanred", + "narked", + "ranked" + ], + "eorstu": [ + "ouster", + "outers", + "routes", + "souter", + "stoure", + "touser", + "trouse" + ], + "ceeorrv": [ + "coverer", + "recover" + ], + "aceehinrt": [ + "catherine", + "heritance" + ], + "bdegu": [ + "budge", + "debug" + ], + "cddeeoprru": [ + "procedured", + "reproduced" + ], + "hno": [ + "hon", + "noh" + ], + "aillsv": [ + "vallis", + "villas" + ], + "eeginp": [ + "epigne", + "genepi", + "peeing" + ], + "bgino": [ + "bingo", + "boing" + ], + "notu": [ + "tuno", + "unto" + ], + "acceimr": [ + "ceramic", + "racemic" + ], + "apsy": [ + "aspy", + "yaps", + "pays", + "pyas", + "spay" + ], + "efginrs": [ + "fingers", + "fringes" + ], + "deeilrsv": [ + "delivers", + "desilver", + "silvered", + "slivered" + ], + "deels": [ + "deles", + "leeds", + "lesed" + ], + "acder": [ + "acred", + "arced", + "cader", + "cadre", + "cared", + "cedar", + "cread", + "creda", + "raced" + ], + "aeehrstt": [ + "earthset", + "streahte", + "theaters", + "theatres" + ], + "dflo": [ + "dolf", + "fold" + ], + "abilr": [ + "blair", + "brail", + "libra" + ], + "ehops": [ + "hopes", + "phose", + "shope" + ], + "amnos": [ + "manos", + "manso", + "mason", + "moans", + "monas", + "mosan", + "nomas" + ], + "civ": [ + "civ", + "vic" + ], + "aimor": [ + "maori", + "mario", + "moira" + ], + "ops": [ + "ops", + "pos", + "sop" + ], + "aachtt": [ + "attach", + "chatta" + ], + "ceeilnss": [ + "licenses", + "silences" + ], + "ilstu": [ + "litus", + "sluit", + "tulsi" + ], + "deiprs": [ + "prides", + "prised", + "redips", + "spider", + "spired", + "spried" + ], + "hpsy": [ + "hyps", + "phys", + "syph" + ], + "aegnrs": [ + "angers", + "ganser", + "granes", + "ranges", + "sanger", + "serang" + ], + "dhnosu": [ + "hounds", + "hudson", + "unshod" + ], + "adeilost": [ + "diastole", + "isolated", + "sodalite", + "solidate" + ], + "eiimnrt": [ + "interim", + "mintier", + "termini" + ], + "adeissst": [ + "assisted", + "disseats" + ], + "aegimnrst": [ + "emigrants", + "germanist", + "mastering", + "streaming" + ], + "cehos": [ + "choes", + "chose", + "echos" + ], + "acdeinsty": [ + "asyndetic", + "cystidean", + "syndicate" + ], + "abinoort": [ + "abortion", + "orbation", + "robotian" + ], + "adgilo": [ + "algoid", + "dialog", + "goliad" + ], + "ablst": [ + "blast", + "blats" + ], + "elop": [ + "lope", + "olpe", + "pole" + ], + "cddeinostu": [ + "deductions", + "discounted" + ], + "aehrstv": [ + "harvest", + "thraves" + ], + "ehmorst": [ + "mothers", + "smother", + "thermos" + ], + "acdeiln": [ + "candiel", + "cladine", + "decalin", + "iceland", + "inlaced" + ], + "acdelns": [ + "calends", + "candles" + ], + "aadginortu": [ + "argonautid", + "graduation" + ], + "agiilns": [ + "aisling", + "liasing", + "nilgais", + "sailing" + ], + "acders": [ + "cadres", + "cedars", + "sacred", + "scared" + ], + "cehmor": [ + "chomer", + "chrome" + ], + "eilorv": [ + "lovier", + "oliver", + "violer", + "virole" + ], + "cgnoo": [ + "cogon", + "congo" + ], + "egln": [ + "engl", + "genl", + "glen", + "leng" + ], + "adelsy": [ + "delays", + "slayed" + ], + "eilov": [ + "olive", + "ovile", + "voile" + ], + "bcery": [ + "becry", + "bryce" + ], + "cdeors": [ + "coders", + "credos", + "decors", + "escrod", + "scored" + ], + "celno": [ + "clone", + "colen" + ], + "aioss": [ + "oasis", + "ossia", + "sosia" + ], + "abeeilns": [ + "balinese", + "baseline" + ], + "agnry": [ + "angry", + "rangy" + ], + "acdeiilnt": [ + "ctenidial", + "identical" + ], + "abeelst": [ + "beatles", + "besteal", + "estable" + ], + "eeinnortt": [ + "intertone", + "retention" + ], + "aalmt": [ + "malta", + "talma", + "tamal" + ], + "efrry": [ + "ferry", + "freyr", + "fryer", + "refry" + ], + "aeginst": [ + "easting", + "eatings", + "gainset", + "genista", + "ingates", + "ingesta", + "seating", + "signate", + "teasing" + ], + "aahmo": [ + "haoma", + "omaha" + ], + "eirt": [ + "iter", + "reit", + "rite", + "teri", + "tier", + "tire" + ], + "elmot": [ + "metol", + "molet", + "motel" + ], + "innosu": [ + "nonius", + "unions", + "unison" + ], + "ainrst": [ + "instar", + "santir", + "strain", + "trains" + ], + "adgr": [ + "darg", + "drag", + "gard", + "grad" + ], + "ehmoosw": [ + "somehow", + "whosome" + ], + "adeerrst": [ + "arrested", + "retreads", + "serrated", + "treaders" + ], + "eipr": [ + "irpe", + "peri", + "pier", + "prie", + "ripe" + ], + "elry": [ + "lyre", + "rely" + ], + "acdeiimnost": [ + "daemonistic", + "medications" + ], + "ceehorrst": [ + "orchester", + "orchestre", + "rochester", + "torcheres" + ], + "dginy": [ + "dying", + "dingy" + ], + "ckstu": [ + "stuck", + "tucks" + ], + "acgilnp": [ + "capling", + "placing" + ], + "cefossu": [ + "focuses", + "fucoses" + ], + "eiostv": [ + "soviet", + "sovite" + ], + "aertty": [ + "attery", + "yatter", + "treaty" + ], + "aeinrrt": [ + "arterin", + "retrain", + "terrain", + "trainer" + ], + "agnor": [ + "agron", + "angor", + "argon", + "garon", + "goran", + "grano", + "groan", + "nagor", + "orang", + "organ", + "rogan", + "ronga" + ], + "aacdensv": [ + "advances", + "canvased" + ], + "elmno": [ + "lemon", + "melon", + "monel" + ], + "pty": [ + "pty", + "typ" + ], + "nstu": [ + "nuts", + "stun", + "sunt", + "tsun", + "tuns" + ], + "ailn": [ + "alin", + "anil", + "lain", + "lina", + "nail" + ], + "aeinnv": [ + "avenin", + "vienna" + ], + "anps": [ + "naps", + "pans", + "snap", + "span" + ], + "adfnorst": [ + "forstand", + "stanford" + ], + "aestttu": [ + "statute", + "tautest" + ], + "acehlp": [ + "chapel", + "lepcha", + "pleach" + ], + "aelrsy": [ + "layers", + "relays", + "reslay", + "slayer" + ], + "abceeelrt": [ + "celebrate", + "erectable" + ], + "cdeemoprss": [ + "compressed", + "decompress" + ], + "deirr": [ + "derri", + "direr", + "drier", + "irred", + "rider" + ], + "adirsu": [ + "darius", + "radius" + ], + "achiinrsst": [ + "christians", + "sinarchist" + ], + "eeiimprssv": [ + "impressive", + "permissive" + ], + "ceelrstu": [ + "cruelest", + "lectures" + ], + "einsw": [ + "sewin", + "sinew", + "swine", + "wines", + "wisen" + ], + "cpsu": [ + "cpus", + "cups", + "cusp", + "scup" + ], + "accdeinst": [ + "accidents", + "desiccant" + ], + "aceilnoort": [ + "corelation", + "iconolater", + "relocation" + ], + "arsttu": [ + "astrut", + "rattus", + "stuart" + ], + "ail": [ + "ail", + "ila", + "lai" + ], + "emnoor": [ + "monroe", + "mooner", + "morone" + ], + "deenrt": [ + "denter", + "rented", + "tender", + "tendre", + "terned" + ], + "eeeprrsv": [ + "perverse", + "preserve" + ], + "emop": [ + "mope", + "poem", + "pome" + ], + "deginnsu": [ + "undesign", + "unsigned", + "unsinged" + ], + "aginsty": [ + "staying", + "stygian" + ], + "aeerst": [ + "aretes", + "asteer", + "easter", + "eastre", + "eaters", + "reseat", + "saeter", + "seater", + "staree", + "teaser", + "teresa" + ], + "eehiorst": [ + "isothere", + "theories", + "theorise" + ], + "aeiprs": [ + "aspire", + "paries", + "persia", + "praise", + "sirpea", + "spirae", + "spirea" + ], + "ceeinv": [ + "cevine", + "evince", + "venice" + ], + "aeinost": [ + "aeonist", + "asiento", + "atonies", + "estonia", + "satieno" + ], + "aeenrtv": [ + "aventre", + "nervate", + "veteran" + ], + "adgilnn": [ + "danglin", + "landing" + ], + "aeikt": [ + "katie", + "keita" + ], + "aceiilrst": [ + "clarities", + "eristical", + "realistic" + ], + "aelrx": [ + "laxer", + "relax" + ], + "aeegginnrt": [ + "generating", + "greatening", + "renegating" + ], + "aben": [ + "bane", + "bean", + "bena" + ], + "abenst": [ + "absent", + "basnet", + "basten", + "besant" + ], + "acdeoru": [ + "acuerdo", + "cordeau", + "ecuador" + ], + "iiprsst": [ + "pristis", + "spirits", + "tripsis" + ], + "aflot": [ + "aloft", + "float", + "flota" + ], + "cilno": [ + "colin", + "conli", + "nicol" + ], + "abis": [ + "absi", + "bais", + "bias", + "isba" + ], + "ahpst": [ + "paths", + "spath", + "staph" + ], + "beinrtu": [ + "tribune", + "tuberin", + "turbine" + ], + "eelssv": [ + "selves", + "vessel" + ], + "acdis": [ + "acids", + "asdic", + "cadis", + "caids", + "sadic" + ], + "eirssuv": [ + "servius", + "survise", + "viruses" + ], + "aceehpr": [ + "cheaper", + "peacher" + ], + "adimt": [ + "admit", + "atmid" + ], + "emm": [ + "emm", + "mem" + ], + "aamos": [ + "omasa", + "samoa" + ], + "aceinorst": [ + "atroscine", + "certosina", + "creations", + "narcotise", + "ostracine", + "reactions", + "secration", + "tinoceras", + "tricosane" + ], + "aegilns": [ + "inglesa", + "leasing", + "linages", + "sealing" + ], + "aelnru": [ + "alrune", + "lunare", + "neural", + "ulnare", + "unreal" + ], + "adqsu": [ + "quads", + "squad" + ], + "aeelrt": [ + "earlet", + "elater", + "relate" + ], + "aegsw": [ + "swage", + "wages" + ], + "effrsu": [ + "ruffes", + "suffer" + ], + "eforsst": [ + "forests", + "fosters" + ], + "anno": [ + "anno", + "anon", + "nona", + "onan" + ], + "aailmrt": [ + "marital", + "martial" + ], + "aeinrt": [ + "anteri", + "entria", + "nerita", + "ratine", + "retain", + "retina", + "tanier" + ], + "elnntu": [ + "nunlet", + "tunnel", + "unlent" + ], + "eegnrs": [ + "genres", + "greens" + ], + "aenpstt": [ + "patents", + "pattens" + ], + "achos": [ + "chaos", + "oshac" + ], + "aehtw": [ + "awhet", + "wheat" + ], + "adeginrs": [ + "deraigns", + "disrange", + "gradines", + "readings" + ], + "ceilmopr": [ + "compiler", + "complier" + ], + "abess": [ + "bases", + "sabes" + ], + "accdesu": [ + "accused", + "succade" + ], + "dlou": [ + "loud", + "ludo" + ], + "bdeir": [ + "bider", + "birde", + "bredi", + "bride", + "rebid" + ], + "aceinnsst": [ + "anticness", + "cantiness", + "incessant", + "instances" + ], + "achnor": [ + "anchor", + "archon", + "charon", + "rancho" + ], + "astt": [ + "stat", + "tats" + ], + "eessx": [ + "essex", + "sexes" + ], + "abceehs": [ + "beaches", + "bechase" + ], + "deflors": [ + "folders", + "refolds" + ], + "eorrstu": [ + "rouster", + "routers", + "tourers", + "trouser" + ], + "bios": [ + "bios", + "bois", + "obis" + ], + "cmp": [ + "cpm", + "pcm" + ], + "eeht": [ + "hete", + "thee" + ], + "eopp": [ + "epop", + "pepo", + "pope" + ], + "adlnor": [ + "androl", + "arnold", + "ladron", + "lardon", + "lordan", + "roland", + "ronald" + ], + "cchiks": [ + "chicks", + "schick" + ], + "aceltt": [ + "cattle", + "tectal" + ], + "abm": [ + "amb", + "bam", + "mab" + ], + "aacdilr": [ + "cardial", + "radical" + ], + "aeerrstu": [ + "austerer", + "treasure" + ], + "adelor": [ + "loader", + "ordeal", + "reload" + ], + "aeflm": [ + "flame", + "fleam" + ], + "aknst": [ + "stank", + "tanks" + ], + "aemnorty": [ + "myronate", + "monetary", + "naometry" + ], + "aceilprst": [ + "palestric", + "particles" + ], + "acdeinoort": [ + "aerodontic", + "carotenoid", + "coordinate", + "coronadite", + "decoration" + ], + "aiktuw": [ + "kuwait", + "waukit" + ], + "eilmy": [ + "elymi", + "emily", + "limey" + ], + "aiiilmnott": [ + "limitation", + "militation" + ], + "ceilmop": [ + "compile", + "polemic" + ], + "beerstw": [ + "bestrew", + "webster" + ], + "abdilr": [ + "bildar", + "bridal", + "labrid", + "libard", + "ribald" + ], + "agm": [ + "gam", + "mag" + ], + "efghirt": [ + "fighter", + "freight", + "refight" + ], + "abeert": [ + "beater", + "berate", + "betear", + "rebate", + "rebeat" + ], + "adnsu": [ + "sudan", + "unsad" + ], + "cer": [ + "cre", + "rec" + ], + "aceforsst": [ + "factoress", + "forecasts" + ], + "eekn": [ + "keen", + "knee" + ], + "eppr": [ + "perp", + "prep", + "repp" + ], + "cehm": [ + "chem", + "mech" + ], + "aefsstt": [ + "fastest", + "setfast" + ], + "belrtu": [ + "bulter", + "burlet", + "butler", + "turble" + ], + "acdeginort": [ + "centigrado", + "decorating" + ], + "allopry": [ + "payroll", + "polarly" + ], + "hinst": [ + "hints", + "thins", + "thisn" + ], + "acellops": [ + "collapse", + "escallop" + ], + "aaceimrs": [ + "americas", + "cramasie", + "mesaraic" + ], + "oprs": [ + "pros", + "spor" + ], + "aailtv": [ + "avital", + "latvia" + ], + "aelrry": [ + "rarely", + "rearly" + ], + "aahmrt": [ + "amarth", + "martha", + "matrah" + ], + "eeginss": [ + "genesis", + "seeings" + ], + "aegru": [ + "argue", + "auger", + "gaure", + "rugae" + ], + "aelmst": [ + "lamest", + "metals", + "samlet" + ], + "egilntt": [ + "ettling", + "letting" + ], + "cir": [ + "cir", + "ric" + ], + "aeijm": [ + "jaime", + "jamie" + ], + "aceilprt": [ + "particle", + "plicater", + "prelatic" + ], + "ceeinopprt": [ + "perception", + "preception" + ], + "aeilmnrs": [ + "marlines", + "minerals", + "mislearn" + ], + "adeisv": [ + "advise", + "davies", + "visaed" + ], + "belostt": [ + "bottles", + "setbolt" + ], + "aaceeinnrss": [ + "necessarian", + "renaissance" + ], + "aars": [ + "rasa", + "sara" + ], + "acdeinnor": [ + "cerdonian", + "encardion", + "ordinance" + ], + "eghhsu": [ + "heughs", + "hughes", + "sheugh" + ], + "eeffjry": [ + "jeffery", + "jeffrey" + ], + "aeeoprst": [ + "asterope", + "operates", + "protease" + ], + "acors": [ + "arcos", + "crosa", + "orcas", + "oscar", + "sacro" + ], + "emnsu": [ + "menus", + "neums", + "sumen" + ], + "aeelrv": [ + "laveer", + "leaver", + "reveal", + "vealer" + ], + "aimno": [ + "amino", + "animo", + "inoma", + "naomi", + "omani", + "omina" + ], + "cciilns": [ + "cinclis", + "clinics" + ], + "lms": [ + "msl", + "sml" + ], + "cow": [ + "cow", + "cwo" + ], + "gilny": [ + "lying", + "lingy" + ], + "deiv": [ + "devi", + "dive", + "vide", + "vied" + ], + "abnry": [ + "barny", + "bryan" + ], + "eoprstt": [ + "potters", + "protest", + "spotter" + ], + "eirst": [ + "iters", + "reist", + "resit", + "rites", + "steri", + "stire", + "tiers", + "tires", + "tries" + ], + "aghinsw": [ + "hawsing", + "shawing", + "washing" + ], + "celorsu": [ + "closure", + "colures" + ], + "adir": [ + "arid", + "dari", + "raid" + ], + "beimrt": [ + "betrim", + "timber", + "timbre" + ], + "eeinnst": [ + "ensient", + "intense", + "sennite", + "sentine" + ], + "ehorssw": [ + "reshows", + "showers" + ], + "gilnru": [ + "luring", + "ruling", + "urling" + ], + "dirt": [ + "dirt", + "trid" + ], + "doprs": [ + "dorps", + "drops", + "prods", + "sprod" + ], + "gilnpsu": [ + "pulings", + "pulsing" + ], + "deellnor": [ + "enrolled", + "rondelle" + ], + "cersw": [ + "crews", + "screw" + ], + "eiimnrsst": [ + "ministers", + "misinters" + ], + "abelm": [ + "amble", + "belam", + "blame", + "mabel", + "melba" + ], + "aeegnv": [ + "avenge", + "geneva", + "vangee" + ], + "dist": [ + "dist", + "dits", + "stid" + ], + "addehn": [ + "hadden", + "handed" + ], + "aeiknt": [ + "intake", + "kentia", + "tankie" + ], + "afilmnor": [ + "formalin", + "formnail", + "informal", + "laniform" + ], + "accehimns": [ + "mechanics", + "mischance" + ], + "ffity": [ + "fifty", + "tiffy" + ], + "adeehrs": [ + "adheres", + "headers", + "hearsed", + "sheared" + ], + "aceilmnru": [ + "ceruminal", + "melanuric", + "numerical" + ], + "aerssu": [ + "assure", + "urases" + ], + "dimosu": [ + "modius", + "odiums", + "sodium" + ], + "ehmnoor": [ + "hormone", + "moorhen" + ], + "gipr": [ + "grip", + "prig" + ], + "aalnv": [ + "alvan", + "naval" + ], + "aceilnopr": [ + "oliprance", + "porcelain" + ], + "bdegirs": [ + "begirds", + "bridges" + ], + "attw": [ + "twat", + "watt" + ], + "cdeent": [ + "cedent", + "decent", + "decnet" + ], + "acginst": [ + "actings", + "casting" + ], + "adnoty": [ + "adyton", + "dayton" + ], + "aclors": [ + "carlos", + "carols", + "claros", + "corals" + ], + "enor": [ + "nore", + "oner", + "reno", + "rone" + ], + "adnno": [ + "donna", + "nonda" + ], + "abcin": [ + "bacin", + "cabin" + ], + "acginnns": [ + "cannings", + "scanning" + ], + "ailmuv": [ + "maulvi", + "valium" + ], + "cdelorss": [ + "cordless", + "scolders" + ], + "defir": [ + "fired", + "fried" + ], + "airsy": [ + "sairy", + "syria" + ], + "eikln": [ + "inkle", + "liken" + ], + "glos": [ + "glos", + "logs", + "slog" + ], + "eorrt": [ + "retro", + "roter" + ], + "elo": [ + "leo", + "loe", + "ole" + ], + "accilrru": [ + "circular", + "curricla" + ], + "isstu": [ + "situs", + "suist", + "suits", + "tissu" + ], + "agr": [ + "agr", + "arg", + "gar", + "gra", + "rag" + ], + "abeirrz": [ + "bizarre", + "brazier" + ], + "ego": [ + "ego", + "geo" + ], + "bbinor": [ + "ribbon", + "robbin" + ], + "deo": [ + "doe", + "edo", + "ode" + ], + "aprsttu": [ + "startup", + "upstart" + ], + "ait": [ + "ait", + "ati", + "ita", + "tai" + ], + "giiknss": [ + "kissing", + "skiings" + ], + "adhny": [ + "anhyd", + "haydn", + "handy" + ], + "apsw": [ + "paws", + "swap", + "waps", + "wasp" + ], + "eegmorty": [ + "geoemtry", + "geometry" + ], + "abs": [ + "abs", + "asb", + "bas", + "sab" + ], + "ims": [ + "ism", + "mis", + "sim" + ], + "dehiss": [ + "dishes", + "hissed" + ], + "aceilpr": [ + "caliper", + "earclip", + "picarel", + "replica" + ], + "beirt": [ + "biter", + "brite", + "tiber", + "tribe" + ], + "aderst": [ + "daters", + "derats", + "stader", + "stared", + "sterad", + "strade", + "trades", + "treads" + ], + "eknu": [ + "neuk", + "nuke" + ], + "aclm": [ + "calm", + "clam" + ], + "cdeiop": [ + "copied", + "epodic" + ], + "aciost": [ + "coatis", + "isotac", + "scotia" + ], + "afgimnr": [ + "farming", + "fingram", + "framing" + ], + "bginos": [ + "bingos", + "gibson", + "obsign" + ], + "orty": [ + "ryot", + "royt", + "tyro", + "tory", + "troy" + ], + "ellorr": [ + "reroll", + "roller" + ], + "aeginorz": [ + "agonizer", + "orangize", + "organize" + ], + "aacdeeipprt": [ + "appreciated", + "appredicate" + ], + "ceilno": [ + "cineol", + "clione", + "cloine", + "coelin", + "encoil", + "enolic" + ], + "ailnot": [ + "italon", + "latino", + "lation", + "talion" + ], + "aaghn": [ + "aghan", + "ghana" + ], + "deegs": [ + "edges", + "sedge" + ], + "adehlns": [ + "handles", + "handsel" + ], + "deiklls": [ + "deskill", + "dillesk", + "skilled" + ], + "aahmst": [ + "amsath", + "asthma" + ], + "ipr": [ + "ipr", + "pir", + "rip" + ], + "aderrw": [ + "drawer", + "redraw", + "reward", + "warder", + "warred" + ], + "arty": [ + "arty", + "atry", + "tray" + ], + "inpstu": [ + "inputs", + "ptinus", + "unspit" + ], + "aaeinrrstw": [ + "warranties", + "warrantise" + ], + "adelm": [ + "demal", + "lamed", + "medal" + ], + "aklsw": [ + "lawks", + "walks" + ], + "bhoot": [ + "bhoot", + "booth" + ], + "cdeeeflrt": [ + "redeflect", + "reflected" + ], + "benos": [ + "bones", + "ebons" + ], + "bdeer": [ + "brede", + "breed", + "rebed" + ], + "cdeeortt": [ + "cottered", + "detector" + ], + "deginor": [ + "eroding", + "gironde", + "groined", + "ignored", + "negroid", + "redoing" + ], + "alopr": [ + "parol", + "polar", + "poral", + "proal" + ], + "aaegilntuv": [ + "evaluating", + "vaginulate" + ], + "ilp": [ + "ipl", + "lip", + "pil", + "pli" + ], + "aeghrt": [ + "gareth", + "gather" + ], + "adeflr": [ + "alfred", + "fardel", + "flared" + ], + "acery": [ + "carey", + "craye" + ], + "elmost": [ + "molest", + "motels" + ], + "cdeeoprs": [ + "procedes", + "proceeds" + ], + "cdeiinrt": [ + "indicter", + "indirect", + "reindict" + ], + "aerrst": [ + "arrest", + "astrer", + "rarest", + "raster", + "raters", + "starer", + "tarres", + "terras", + "treasr" + ], + "deelpy": [ + "deeply", + "yelped" + ], + "cit": [ + "cit", + "tic" + ], + "aaimnr": [ + "airman", + "amarin", + "marian", + "marina", + "mirana" + ], + "abinos": [ + "basion", + "bonsai", + "sabino" + ], + "aiopt": [ + "patio", + "taipo", + "topia" + ], + "aceelnort": [ + "antrocele", + "coeternal", + "tolerance" + ], + "aceiirttvy": [ + "creativity", + "reactivity" + ], + "dlloy": [ + "dolly", + "lloyd" + ], + "deey": [ + "eyed", + "yede" + ], + "abgr": [ + "brag", + "garb", + "grab" + ], + "ceinoprst": [ + "inceptors", + "inspector" + ], + "abens": [ + "banes", + "beans", + "besan" + ], + "eills": [ + "liles", + "lisle", + "selli" + ], + "aekns": [ + "kanes", + "skean", + "snake", + "sneak" + ], + "adelnor": [ + "endoral", + "ladrone", + "leonard" + ], + "ailnps": [ + "lapins", + "plains", + "spinal" + ], + "admnory": [ + "doryman", + "raymond" + ], + "adeiiintt": [ + "dietitian", + "initiated" + ], + "floo": [ + "fool", + "loof", + "olof" + ], + "aacelnrst": [ + "ancestral", + "lancaster" + ], + "beeorsv": [ + "observe", + "obverse", + "verbose" + ], + "aceinnorst": [ + "containers", + "resanction", + "sanctioner" + ], + "aklr": [ + "karl", + "kral", + "lark" + ], + "aacilr": [ + "alaric", + "racial" + ], + "aeeginrtt": [ + "argentite", + "grenatite", + "integrate" + ], + "abdemru": [ + "bermuda", + "rumbaed" + ], + "aaadmn": [ + "amadan", + "amanda", + "manada" + ], + "beilmos": [ + "mobiles", + "obelism" + ], + "aceerrt": [ + "caterer", + "recrate", + "retrace", + "terrace" + ], + "deeilpr": [ + "periled", + "replied" + ], + "elnosv": [ + "novels", + "sloven", + "volens" + ], + "aijl": [ + "jail", + "lija" + ], + "aeflsy": [ + "fayles", + "safely" + ], + "deikny": [ + "dinkey", + "kidney" + ], + "denss": [ + "sends", + "sneds" + ], + "abdelru": [ + "delubra", + "durable" + ], + "horstw": [ + "rowths", + "throws", + "whorts", + "worths" + ], + "eimorstu": [ + "moisture", + "semitour" + ], + "eimrt": [ + "ermit", + "merit", + "miter", + "mitre", + "mtier", + "remit", + "timer" + ], + "abelstt": [ + "battels", + "battles", + "tablets" + ], + "acdeorstu": [ + "aeroducts", + "ceratodus", + "croustade", + "educators" + ], + "aegilmnnt": [ + "alignment", + "lamenting" + ], + "aey": [ + "aye", + "yea" + ], + "eorstw": [ + "restow", + "stower", + "towers", + "towser", + "worset" + ], + "ackrs": [ + "carks", + "racks" + ], + "acel": [ + "acle", + "alce", + "alec", + "lace" + ], + "ansty": [ + "antsy", + "nasty", + "santy", + "styan", + "tansy" + ], + "adeilttu": [ + "altitude", + "latitude" + ], + "gluy": [ + "guly", + "ugly" + ], + "deiopsst": [ + "deposits", + "topsides" + ], + "asttw": [ + "twats", + "watts" + ], + "ahrt": [ + "hart", + "rath", + "tahr", + "thar", + "trah" + ], + "abdenrr": [ + "bernard", + "brander", + "rebrand" + ], + "bestu": [ + "stube", + "subet", + "tubes" + ], + "clo": [ + "clo", + "col", + "loc" + ], + "eiprst": [ + "esprit", + "priest", + "pteris", + "ripest", + "sitrep", + "sprite", + "stripe", + "tripes" + ], + "dfloy": [ + "floyd", + "foldy" + ], + "acenrt": [ + "canter", + "carnet", + "centra", + "cranet", + "creant", + "cretan", + "nectar", + "recant", + "tanrec", + "trance" + ], + "achilnos": [ + "lichanos", + "nicholas" + ], + "bilo": [ + "bilo", + "biol", + "boil", + "lobi", + "obli" + ], + "bdelnu": [ + "bundle", + "unbled" + ], + "iknss": [ + "sinks", + "skins" + ], + "adeilm": [ + "aldime", + "mailed", + "medial" + ], + "aderrsw": [ + "drawers", + "redraws", + "resward", + "rewards", + "warders" + ], + "ddeefn": [ + "defend", + "fended" + ], + "acddeiim": [ + "mediacid", + "medicaid" + ], + "eort": [ + "rote", + "tore" + ], + "ehlsw": [ + "welsh", + "whsle" + ], + "elnost": [ + "lentos", + "solent", + "stolen", + "telson" + ], + "aci": [ + "cai", + "cia" + ], + "deeeimnrst": [ + "densimeter", + "determines", + "misentered" + ], + "lopy": [ + "ploy", + "poly" + ], + "aers": [ + "ares", + "arse", + "ears", + "eras", + "rase", + "sare", + "sear", + "sera" + ], + "aalnrstu": [ + "naturals", + "saturnal" + ], + "deelnrs": [ + "lenders", + "relends", + "slender" + ], + "eemr": [ + "emer", + "erme", + "meer", + "mere", + "reem" + ], + "aeegrs": [ + "agrees", + "eagers", + "eagres", + "grease", + "ragees", + "sageer" + ], + "ceehrs": [ + "cheers", + "creesh" + ], + "dgi": [ + "dig", + "gid" + ], + "ehimnnpstu": [ + "punishment", + "unshipment" + ], + "aceinooprrt": [ + "incorporate", + "procreation" + ], + "aeerrrstu": [ + "serrature", + "treasurer" + ], + "ceeenss": [ + "essence", + "necesse", + "senesce" + ], + "ehlmos": [ + "holmes", + "mohels" + ], + "gis": [ + "gis", + "sig" + ], + "ceehrst": [ + "chester", + "etchers", + "retches", + "tresche" + ], + "isttw": [ + "twist", + "twits" + ], + "einstu": [ + "intuse", + "tenuis", + "unites", + "unties" + ], + "bdeiru": [ + "burdie", + "buried", + "rubied" + ], + "adinrw": [ + "darwin", + "inward" + ], + "aknrs": [ + "karns", + "knars", + "krans", + "narks", + "ranks", + "snark" + ], + "bdetu": [ + "debut", + "tubed" + ], + "abdelry": [ + "bradley", + "dryable" + ], + "deny": [ + "deny", + "dyne" + ], + "abil": [ + "albi", + "bail", + "bali" + ], + "iort": [ + "riot", + "roit", + "roti", + "tiro", + "tori", + "trio" + ], + "aekmrr": [ + "marker", + "remark" + ], + "grsu": [ + "grus", + "rugs", + "surg" + ], + "aadnrs": [ + "nasard", + "sandra" + ], + "acmnoo": [ + "mocoan", + "monaco" + ], + "aeeimrst": [ + "emirates", + "steamier" + ], + "aeft": [ + "atef", + "fate", + "feat", + "feta" + ], + "borstu": [ + "robust", + "turbos" + ], + "agrs": [ + "gars", + "gras", + "rags" + ], + "ddeenoprs": [ + "desponder", + "responded" + ], + "imr": [ + "mir", + "rim" + ], + "aeilnp": [ + "alpine", + "nepali", + "penial", + "pineal" + ], + "dis": [ + "dis", + "ids", + "sid" + ], + "eimrx": [ + "mirex", + "mixer", + "remix" + ], + "eenrw": [ + "newer", + "renew", + "weren" + ], + "aky": [ + "yak", + "kay" + ], + "ceips": [ + "epics", + "sepic", + "spice" + ], + "amos": [ + "amos", + "moas", + "soam", + "soma" + ], + "celoor": [ + "cooler", + "recool" + ], + "aciis": [ + "ascii", + "isiac" + ], + "bdeeginr": [ + "beringed", + "breeding" + ], + "aciinostt": [ + "actionist", + "citations" + ], + "dnoor": [ + "donor", + "rondo" + ], + "einnost": [ + "intones", + "stenion", + "tension" + ], + "ahrst": [ + "harst", + "harts", + "tahrs", + "trash" + ], + "aehpss": [ + "pashes", + "phases", + "shapes" + ], + "eeelnopv": [ + "envelope", + "ovenpeel" + ], + "adein": [ + "diane", + "endia", + "idean" + ], + "bdeers": [ + "bredes", + "breeds" + ], + "adiprs": [ + "dispar", + "rapids", + "sparid" + ], + "cdios": [ + "disco", + "sodic" + ], + "defin": [ + "fiend", + "fined", + "indef" + ], + "eimnoost": [ + "emotions", + "mooniest" + ], + "aceelnrs": [ + "cleaners", + "cleanser", + "recleans" + ], + "aabgilnru": [ + "biangular", + "bulgarian" + ], + "aeelnrt": [ + "alterne", + "enteral", + "eternal", + "teleran", + "teneral" + ], + "acehirss": [ + "cashiers", + "rachises" + ], + "agmu": [ + "gaum", + "guam", + "muga" + ], + "ceit": [ + "ceti", + "cite", + "tice" + ], + "gip": [ + "gip", + "pig" + ], + "imnsu": [ + "minus", + "numis", + "unism" + ], + "aeeilnpst": [ + "palestine", + "penalties", + "tapelines" + ], + "aaeimnr": [ + "amarine", + "armenia" + ], + "celosst": [ + "closest", + "closets" + ], + "aacdeittv": [ + "activated", + "cavitated" + ], + "acersst": [ + "actress", + "casters", + "recasts" + ], + "ilt": [ + "lit", + "til" + ], + "deilss": [ + "dessil", + "sidles", + "slides" + ], + "ailmn": [ + "lamin", + "liman", + "milan" + ], + "deelnr": [ + "eldern", + "lender", + "relend" + ], + "chorsu": [ + "chorus", + "urochs" + ], + "cehiinrst": [ + "christine", + "snitchier" + ], + "adegru": [ + "argued", + "dargue" + ], + "hmnopsyy": [ + "physnomy", + "symphony" + ], + "aceklr": [ + "calker", + "clarke", + "lacker", + "rackle", + "recalk", + "reckla" + ], + "ilnos": [ + "insol", + "isoln", + "linos", + "lions", + "loins", + "noils" + ], + "loops": [ + "loops", + "polos", + "pools", + "sloop", + "spool" + ], + "cilry": [ + "cyril", + "lyric" + ], + "aceilr": [ + "acerli", + "carlie", + "claire", + "eclair", + "erical", + "lacier" + ], + "eopr": [ + "pore", + "rope" + ], + "aailnort": [ + "notarial", + "rational", + "rotalian" + ], + "efghirst": [ + "fighters", + "freights", + "refights" + ], + "abcehmrs": [ + "becharms", + "brechams", + "chambers" + ], + "ceeilmnopt": [ + "emplection", + "incomplete" + ], + "benrru": [ + "burner", + "reburn" + ], + "rsy": [ + "yrs", + "syr" + ], + "foo": [ + "foo", + "ofo", + "oof" + ], + "eeglnt": [ + "gentle", + "telegn" + ], + "deeepr": [ + "deeper", + "peered" + ], + "hortwy": [ + "worthy", + "wrothy" + ], + "ainsst": [ + "saints", + "satins", + "stains" + ], + "aceirrs": [ + "carries", + "scarier" + ], + "dou": [ + "duo", + "oud", + "udo" + ], + "denov": [ + "devon", + "doven" + ], + "aeehln": [ + "anhele", + "helena" + ], + "aessv": [ + "saves", + "vases" + ], + "addeegrr": [ + "degrader", + "regarded", + "regraded" + ], + "cdeeenptux": [ + "unexcepted", + "unexpected" + ], + "aimnor": [ + "mainor", + "manoir", + "marion", + "minora", + "morian", + "romain" + ], + "deilnotu": [ + "outlined", + "untoiled" + ], + "aeginrtt": [ + "gnattier", + "treating" + ], + "rst": [ + "str", + "trs" + ], + "aaeinrrtv": [ + "narrative", + "veratrina" + ], + "emnoorsu": [ + "enormous", + "unmorose" + ], + "aakmr": [ + "karma", + "krama", + "makar", + "marka" + ], + "cinosst": [ + "consist", + "tocsins" + ], + "aclsu": [ + "cauls", + "claus", + "scaul" + ], + "beirst": [ + "bestir", + "bister", + "bistre", + "biters", + "bitser", + "tribes" + ], + "adimr": [ + "mardi", + "marid" + ], + "abceinst": [ + "bascinet", + "cabinets" + ], + "aehks": [ + "hakes", + "shake" + ], + "aabeglr": [ + "algebar", + "algebra" + ], + "illsy": [ + "yills", + "silyl", + "silly", + "slily" + ], + "einrssu": [ + "insures", + "rusines", + "russine", + "serinus", + "sunrise" + ], + "fru": [ + "fur", + "urf" + ], + "eeiilmnt": [ + "ilmenite", + "melinite", + "menilite" + ], + "adeilry": [ + "arylide", + "readily" + ], + "cos": [ + "cos", + "osc", + "soc" + ], + "dinstu": [ + "dustin", + "nudist" + ], + "aadin": [ + "andia", + "danai", + "diana", + "naiad" + ], + "eenrssu": [ + "ensures", + "russene" + ], + "aeeilrstv": [ + "levirates", + "relatives", + "versatile" + ], + "adilnsy": [ + "islandy", + "lindsay" + ], + "aehms": [ + "ahems", + "haems", + "hames", + "sahme", + "shame", + "shema" + ], + "eehlnopty": [ + "polythene", + "telephony" + ], + "aaflt": [ + "aflat", + "fatal" + ], + "aelorrst": [ + "realtors", + "relators", + "restoral" + ], + "abeghinrt": [ + "breathing", + "rebathing" + ], + "aacghilpr": [ + "algraphic", + "graphical" + ], + "aeerrtt": [ + "ettarre", + "retreat", + "treater" + ], + "abelry": [ + "barely", + "barley", + "bleary", + "yerbal" + ], + "gru": [ + "gur", + "rug" + ], + "aaiimnnst": [ + "amanitins", + "maintains" + ], + "adeeinrt": [ + "detainer", + "retained" + ], + "aaelmp": [ + "palame", + "palmae", + "pamela" + ], + "adenrsw": [ + "wanders", + "wardens" + ], + "abelmr": [ + "ambler", + "blamer", + "lamber", + "marble", + "ramble" + ], + "cehimnoopr": [ + "microphone", + "neomorphic" + ], + "aginst": [ + "gainst", + "giants", + "gisant", + "sating" + ], + "dehs": [ + "edhs", + "shed" + ], + "emmo": [ + "memo", + "mome" + ], + "ahm": [ + "ham", + "mah" + ], + "celnooss": [ + "consoles", + "coolness" + ], + "bfi": [ + "fbi", + "fib" + ], + "eelr": [ + "leer", + "lere", + "reel" + ], + "eehrs": [ + "heres", + "herse", + "sereh", + "sheer", + "shree" + ], + "ginops": [ + "gipons", + "pingos", + "posing" + ], + "bdin": [ + "bind", + "inbd" + ], + "adnr": [ + "darn", + "nard", + "rand" + ], + "egnrtu": [ + "gunter", + "gurnet", + "urgent" + ], + "chitw": [ + "tchwi", + "wicht", + "witch" + ], + "cehno": [ + "cohen", + "enoch" + ], + "eis": [ + "ise", + "sei", + "sie" + ], + "eeiprsx": [ + "expires", + "prexies" + ], + "ellms": [ + "mells", + "smell" + ], + "acdeinoorst": [ + "coordinates", + "decorations" + ], + "ceikrst": [ + "rickets", + "sticker", + "tickers" + ], + "eimoprss": [ + "imposers", + "promises", + "semipros" + ], + "bno": [ + "bon", + "nob" + ], + "deeersv": [ + "deserve", + "severed" + ], + "ailmot": [ + "lomita", + "tomial" + ], + "achn": [ + "chan", + "nach" + ], + "deiorrw": [ + "rowdier", + "wordier", + "worried" + ], + "enstu": [ + "suent", + "tunes", + "unset", + "usent" + ], + "cegimnopt": [ + "coempting", + "competing" + ], + "beht": [ + "beth", + "theb" + ], + "eln": [ + "enl", + "len" + ], + "aehprss": [ + "phasers", + "phrases", + "seraphs", + "shapers", + "sherpas" + ], + "aik": [ + "aik", + "kai" + ], + "aceehls": [ + "clashee", + "leaches" + ], + "bginor": [ + "boring", + "orbing", + "robing" + ], + "aceehrs": [ + "archsee", + "reaches", + "rechase" + ], + "acehms": [ + "sachem", + "samech", + "schema" + ], + "afos": [ + "oafs", + "sofa" + ], + "efiprx": [ + "perfix", + "prefix" + ], + "acilu": [ + "aulic", + "cauli", + "lucia" + ], + "aelnpst": [ + "planets", + "platens" + ], + "bdeloru": [ + "boulder", + "doubler" + ], + "adhlor": [ + "harold", + "holard" + ], + "ajr": [ + "jar", + "raj" + ], + "entt": [ + "nett", + "tent" + ], + "deefiiinst": [ + "definitise", + "identifies" + ], + "cklos": [ + "locks", + "slock" + ], + "aelmny": [ + "laymen", + "meanly", + "namely" + ], + "eorsu": [ + "euros", + "roues", + "rouse" + ], + "aaeilr": [ + "aerial", + "aralie", + "realia" + ], + "beelr": [ + "blere", + "rebel" + ], + "giinors": [ + "origins", + "signior", + "signori" + ], + "dehir": [ + "dheri", + "hider", + "hired", + "rehid" + ], + "ablm": [ + "balm", + "blam", + "lamb" + ], + "aahnnt": [ + "nathan", + "thanan" + ], + "ceeinrstu": [ + "ceintures", + "centuries" + ], + "dhinu": [ + "hindu", + "hundi", + "unhid" + ], + "aaeehkqrtu": [ + "earthquake", + "heartquake" + ], + "aeginssss": [ + "assessing", + "gassiness" + ], + "agilnst": [ + "anglist", + "lasting", + "salting", + "slating", + "staling" + ], + "cdeinorstu": [ + "discounter", + "introduces", + "rediscount", + "reductions" + ], + "cluy": [ + "cyul", + "lucy" + ], + "ahns": [ + "hans", + "hasn", + "nash", + "shan" + ], + "elops": [ + "elops", + "lopes", + "olpes", + "poles", + "slope", + "spole" + ], + "aeeggr": [ + "agrege", + "raggee", + "reggae" + ], + "eopt": [ + "peto", + "poet", + "pote", + "tope" + ], + "accinoprsy": [ + "conspiracy", + "snipocracy" + ], + "aemnrsu": [ + "manures", + "surname" + ], + "eghlooty": [ + "ethology", + "theology" + ], + "ailns": [ + "anils", + "nails", + "sinal", + "slain", + "snail" + ], + "ahstw": [ + "swath", + "thaws", + "whats" + ], + "deirs": [ + "dries", + "resid", + "rides", + "sider", + "sired" + ], + "ceip": [ + "epic", + "pice" + ], + "anrstu": [ + "saturn", + "unstar" + ], + "ntu": [ + "nut", + "tun" + ], + "aeks": [ + "kaes", + "keas", + "sake", + "seak" + ], + "dikss": [ + "disks", + "skids" + ], + "cdnoo": [ + "codon", + "condo" + ], + "abeimn": [ + "benami", + "bimane", + "embain" + ], + "anss": [ + "assn", + "sans" + ], + "bdilsu": [ + "builds", + "sublid" + ], + "afhst": [ + "hafts", + "shaft" + ], + "bey": [ + "bey", + "bye" + ], + "cdeeorrrs": [ + "recorders", + "rerecords" + ], + "eeills": [ + "eisell", + "leslie", + "sellie" + ], + "aan": [ + "ana", + "naa" + ], + "ginopsst": [ + "postings", + "postsign", + "signpost" + ], + "adinr": [ + "darin", + "dinar", + "drain", + "indra", + "nadir", + "ranid" + ], + "emnot": [ + "entom", + "monte" + ], + "efirs": [ + "fires", + "fries", + "frise", + "reifs", + "serif" + ], + "aaegilr": [ + "algeria", + "argaile", + "lairage", + "railage", + "regalia" + ], + "bdeelss": [ + "bedless", + "blessed" + ], + "aooptt": [ + "pattoo", + "potato", + "topato" + ], + "efmorrs": [ + "formers", + "reforms" + ], + "alot": [ + "alto", + "lota", + "tola" + ], + "cceilrs": [ + "circles", + "clerics" + ], + "aciilt": [ + "clitia", + "italic" + ], + "ilm": [ + "lim", + "mil" + ], + "abcsu": [ + "cubas", + "scuba" + ], + "egor": [ + "ergo", + "goer", + "gore", + "ogre", + "rego" + ], + "adhs": [ + "dahs", + "dash", + "sadh", + "shad" + ], + "aeipssv": [ + "passive", + "pavises", + "pavisse", + "spavies" + ], + "adeluv": [ + "devaul", + "valued" + ], + "deerv": [ + "derve", + "verde" + ], + "aceinorss": [ + "sarcosine", + "scenarios" + ], + "aabmnt": [ + "bantam", + "batman" + ], + "aeghinrs": [ + "hearings", + "hearsing", + "shearing" + ], + "acelmno": [ + "aclemon", + "cloamen" + ], + "aelv": [ + "eval", + "lave", + "leva", + "vale", + "veal", + "vela" + ], + "aaehimn": [ + "anaheim", + "anhimae" + ], + "ddeir": [ + "dried", + "redid" + ], + "aeegiinnnrtt": [ + "entertaining", + "intenerating" + ], + "ehlrtu": [ + "hurtle", + "luther", + "thurle" + ], + "ginoppst": [ + "stopping", + "toppings" + ], + "aelmpr": [ + "ampler", + "emparl", + "lamper", + "palmer", + "relamp" + ], + "acinopt": [ + "caption", + "paction", + "pontiac" + ], + "cdeinort": [ + "centroid", + "doctrine" + ], + "aeinrrst": [ + "restrain", + "retrains", + "strainer", + "terrains", + "trainers", + "transire" + ], + "eginsw": [ + "sewing", + "swinge" + ], + "amno": [ + "mano", + "moan", + "mona", + "noam", + "noma", + "oman" + ], + "cgm": [ + "cgm", + "mcg" + ], + "eoopprs": [ + "opposer", + "propose" + ], + "eghilrt": [ + "lighter", + "relight", + "rightle" + ], + "adls": [ + "lads", + "slad" + ], + "accistt": [ + "tactics", + "tictacs" + ], + "rssttu": [ + "struts", + "sturts", + "trusts" + ], + "aeinn": [ + "annie", + "ennia", + "inane" + ], + "ehorrst": [ + "rhetors", + "shorter" + ], + "adeginprs": [ + "respading", + "spreading" + ], + "acelpr": [ + "carpel", + "parcel", + "placer" + ], + "deefinr": [ + "definer", + "refined" + ], + "aefrs": [ + "fares", + "farse", + "fears", + "frase", + "safer" + ], + "enrtu": [ + "enrut", + "tuner", + "urent" + ], + "arsy": [ + "rays", + "ryas" + ], + "aeikl": [ + "alike", + "kelia", + "lakie" + ], + "altw": [ + "twal", + "walt" + ], + "acen": [ + "acne", + "cane", + "nace" + ], + "bcdeklo": [ + "blocked", + "deblock" + ], + "aailmw": [ + "awalim", + "malawi", + "mawali" + ], + "aadn": [ + "anda", + "dana", + "nada" + ], + "ahlo": [ + "halo", + "hola" + ], + "cirstu": [ + "citrus", + "curtis", + "rictus", + "rustic" + ], + "aaelnprt": [ + "parental", + "parlante", + "paternal", + "prenatal" + ], + "agsy": [ + "gays", + "sagy" + ], + "eginprss": [ + "pressing", + "springes" + ], + "aaaginr": [ + "agrania", + "angaria", + "niagara" + ], + "fin": [ + "fin", + "inf" + ], + "achmrs": [ + "charms", + "ramsch" + ], + "aderrt": [ + "darter", + "dartre", + "dertra", + "redart", + "retard", + "retrad", + "tarred", + "trader" + ], + "aeirss": [ + "arises", + "raises", + "serais" + ], + "egm": [ + "gem", + "meg" + ], + "ceelort": [ + "elector", + "electro" + ], + "ceiinorrt": [ + "cirterion", + "criterion", + "tricerion" + ], + "abdeg": [ + "badge", + "begad", + "debag" + ], + "irstw": [ + "wrist", + "writs" + ], + "aehht": [ + "heath", + "theah" + ], + "deeeimrs": [ + "redemise", + "remedies" + ], + "eersttu": [ + "surette", + "trustee" + ], + "efmoprrs": [ + "performs", + "preforms" + ], + "aelmr": [ + "lamer", + "realm" + ], + "aaeilrss": [ + "assailer", + "reassail", + "salaries" + ], + "aimnstu": [ + "manitus", + "tsunami" + ], + "achlors": [ + "chorals", + "scholar" + ], + "ceikln": [ + "nickel", + "nickle" + ], + "acginot": [ + "coating", + "cognati", + "cotinga" + ], + "aelltw": [ + "wallet", + "wellat" + ], + "acdeelr": [ + "cedrela", + "cleared", + "creedal", + "declare", + "relaced" + ], + "eiilmss": [ + "mislies", + "missile", + "similes" + ], + "aadeginr": [ + "drainage", + "gardenia" + ], + "aahikrs": [ + "kashira", + "shikara", + "sikhara" + ], + "cenorrs": [ + "corners", + "scorner" + ], + "abdeorr": [ + "arbored", + "boarder", + "broader", + "reboard" + ], + "aaeeginrtv": [ + "renavigate", + "vegetarian" + ], + "egoru": [ + "erugo", + "orgue", + "rogue", + "rouge" + ], + "aesty": [ + "yeast", + "teasy" + ], + "acegilnr": [ + "clearing", + "relacing" + ], + "acdeot": [ + "coated", + "decoat" + ], + "deinnt": [ + "dentin", + "indent", + "intend", + "tinned" + ], + "aeehinpst": [ + "ephestian", + "stephanie" + ], + "eilosu": [ + "louies", + "louise" + ], + "enow": [ + "enow", + "owen", + "wone" + ], + "einorstu": [ + "routines", + "rutinose", + "snoutier", + "tursenoi" + ], + "ghiintt": [ + "hitting", + "tithing" + ], + "aceeilnr": [ + "cerealin", + "cinereal", + "raceline", + "reliance" + ], + "abhist": [ + "habits", + "tasbih" + ], + "giiknrst": [ + "skirting", + "striking" + ], + "ghins": [ + "nighs", + "singh" + ], + "opsttuu": [ + "outputs", + "putouts" + ], + "iilnnsu": [ + "insulin", + "inulins" + ], + "deew": [ + "wede", + "weed" + ], + "eiiltuz": [ + "tuilzie", + "utilize" + ], + "aaegln": [ + "alange", + "alnage", + "angela", + "anlage", + "galena", + "lagena" + ], + "aeelrst": [ + "elaters", + "laertes", + "realest", + "relates", + "reslate", + "resteal", + "seletar", + "stealer", + "teasler" + ], + "cdei": [ + "cedi", + "dice", + "iced" + ], + "dmos": [ + "doms", + "mods" + ], + "adeginors": [ + "grandiose", + "organdies", + "organised", + "sargonide" + ], + "orsst": [ + "sorts", + "ssort", + "sstor" + ], + "eiinorssv": [ + "ivoriness", + "revisions" + ], + "deeorrst": [ + "resorted", + "restored" + ], + "amorr": [ + "armor", + "maror", + "morra" + ], + "deirrs": [ + "derris", + "driers", + "riders" + ], + "denosz": [ + "dozens", + "zendos" + ], + "aeirsv": [ + "aivers", + "sairve", + "varies" + ], + "adgrsu": [ + "gradus", + "guards" + ], + "acegilnpr": [ + "parceling", + "replacing" + ], + "adeehrstw": [ + "drawsheet", + "watershed" + ], + "ccilnosu": [ + "councils", + "succinol" + ], + "ailrv": [ + "rival", + "viral" + ], + "eipps": [ + "pepsi", + "pipes" + ], + "adeln": [ + "alden", + "eland", + "laden", + "lande", + "lenad", + "naled" + ], + "aelorrt": [ + "realtor", + "relator" + ], + "aeiimnostt": [ + "estimation", + "testimonia" + ], + "abnr": [ + "barn", + "bran" + ], + "ghinpsu": [ + "gunship", + "pushing" + ], + "acdeiiprt": [ + "dipicrate", + "patricide", + "pediatric" + ], + "bco": [ + "boc", + "cob" + ], + "emprs": [ + "perms", + "sperm" + ], + "abdl": [ + "bald", + "blad" + ], + "acprs": [ + "carps", + "craps", + "scarp", + "scrap" + ], + "forst": [ + "forst", + "forts", + "frost" + ], + "elno": [ + "elon", + "enol", + "leno", + "leon", + "lone", + "noel" + ], + "achty": [ + "cathy", + "cyath", + "yacht" + ], + "acrty": [ + "carty", + "tracy" + ], + "mpt": [ + "pmt", + "tpm" + ], + "abcehr": [ + "barche", + "brache", + "breach", + "chaber" + ], + "aehlw": [ + "halwe", + "whale", + "wheal" + ], + "deil": [ + "deil", + "deli", + "diel", + "eild", + "idle", + "lide", + "lied" + ], + "agmnstu": [ + "mustang", + "stagnum" + ], + "aoprst": [ + "asport", + "pastor", + "portas", + "sproat" + ], + "dmu": [ + "dum", + "mud" + ], + "ahkrs": [ + "harks", + "shark" + ], + "abdeeilrs": [ + "desirable", + "redisable" + ], + "abellt": [ + "ballet", + "batell" + ], + "egiilnors": [ + "ligroines", + "religions" + ], + "ehins": [ + "eshin", + "hsien", + "shine" + ], + "befirs": [ + "briefs", + "febris", + "fibers", + "fibres" + ], + "ceov": [ + "cove", + "voce" + ], + "aceinnoorsstv": [ + "conservations", + "conversations" + ], + "adiors": [ + "aroids", + "radios" + ], + "adiinv": [ + "avidin", + "vidian" + ], + "aapst": [ + "apast", + "pasta", + "patas", + "tapas" + ], + "emrsu": [ + "mures", + "muser", + "remus", + "serum" + ], + "eimnrtu": [ + "minuter", + "runtime", + "unmiter", + "unmitre" + ], + "acflo": [ + "falco", + "focal" + ], + "adinstt": [ + "dantist", + "distant" + ], + "ciln": [ + "clin", + "incl" + ], + "aal": [ + "aal", + "ala" + ], + "aabms": [ + "ambas", + "samba" + ], + "elmopy": [ + "employ", + "pomely" + ], + "aacgilm": [ + "camalig", + "magical" + ], + "aceilmr": [ + "calmier", + "claimer", + "milacre", + "miracle", + "reclaim" + ], + "cdeeenrt": [ + "centered", + "decenter", + "decentre", + "recedent" + ], + "aelryy": [ + "yarely", + "yearly", + "layery" + ], + "aors": [ + "asor", + "oars", + "oras", + "osar", + "rosa", + "soar", + "sora" + ], + "ahhs": [ + "hahs", + "hash", + "sahh", + "shah" + ], + "gmp": [ + "gpm", + "mpg" + ], + "aefhrst": [ + "fathers", + "hafters", + "shafter" + ], + "deiln": [ + "eldin", + "lined" + ], + "dow": [ + "dow", + "owd", + "wod" + ], + "diu": [ + "dui", + "iud", + "udi" + ], + "eny": [ + "eyn", + "yen", + "nye" + ], + "iprsst": [ + "spirts", + "sprits", + "stirps", + "strips" + ], + "aegnrrs": [ + "garners", + "rangers" + ], + "morw": [ + "morw", + "worm" + ], + "cdeeirst": [ + "creedist", + "desertic", + "discreet", + "discrete" + ], + "dil": [ + "dil", + "lid" + ], + "eeloprsty": [ + "polyester", + "proselyte" + ], + "adef": [ + "deaf", + "fade" + ], + "aehipprs": [ + "papisher", + "sapphire" + ], + "aeikns": [ + "kinase", + "sekani", + "skenai" + ], + "ikrsst": [ + "skirts", + "stirks" + ], + "amst": [ + "mast", + "mats", + "stam", + "tams" + ], + "abdeell": [ + "beladle", + "labeled" + ], + "abeirs": [ + "braies", + "braise", + "rabies", + "rebias", + "serbia" + ], + "ffgiinr": [ + "griffin", + "riffing" + ], + "aagnuy": [ + "guanay", + "guyana" + ], + "eipss": [ + "sipes", + "spies", + "spise" + ], + "eimm": [ + "emim", + "mime" + ], + "acceennortt": [ + "concentrate", + "concertante" + ], + "eglnost": [ + "longest", + "songlet" + ], + "inost": [ + "nitos", + "sinto", + "stion" + ], + "ceeennsst": [ + "senescent", + "sentences" + ], + "eflry": [ + "ferly", + "flyer", + "refly" + ], + "aeps": [ + "apes", + "apse", + "pase", + "peas", + "pesa", + "spae" + ], + "adegos": [ + "dagoes", + "dosage", + "seadog" + ], + "ceeeirrsv": [ + "receivers", + "reservice" + ], + "acemnoor": [ + "cameroon", + "coenamor" + ], + "deeeln": [ + "lendee", + "needle" + ], + "abhst": [ + "bahts", + "baths" + ], + "aainnrv": [ + "navarin", + "nirvana" + ], + "ademnss": [ + "desmans", + "dsnames", + "madness" + ], + "acems": [ + "acmes", + "cames", + "maces" + ], + "ahy": [ + "hay", + "yah" + ], + "aaccdir": [ + "arcadic", + "cardiac" + ], + "aailnostv": [ + "lavations", + "salvation" + ], + "deorv": [ + "dover", + "drove", + "roved", + "vedro", + "voder" + ], + "aadinr": [ + "adrian", + "andira", + "andria", + "radian", + "randia" + ], + "aeelnrrs": [ + "learners", + "relearns" + ], + "ceeeilstv": [ + "cleveites", + "electives", + "selective" + ], + "adeiilorst": [ + "editorials", + "idolatries", + "idolatrise", + "radiolites" + ], + "eeekrss": [ + "reseeks", + "seekers" + ], + "ais": [ + "ais", + "sai", + "sia" + ], + "abeelmorv": [ + "overblame", + "removable" + ], + "ceimnru": [ + "micerun", + "numeric", + "uncrime" + ], + "agiknst": [ + "gitksan", + "skating", + "staking", + "takings", + "tasking" + ], + "belst": [ + "belts", + "blest", + "blets" + ], + "abeerst": [ + "beaters", + "berates", + "bestare", + "rebates" + ], + "eeoprrrst": [ + "preresort", + "reporters" + ], + "bekru": [ + "bruke", + "burke" + ], + "ceeinssty": [ + "cysteines", + "necessity" + ], + "ekly": [ + "yelk", + "kyle" + ], + "cersuv": [ + "cervus", + "curves" + ], + "aaclr": [ + "clara", + "craal" + ], + "aelrstv": [ + "travels", + "varlets", + "vestral" + ], + "aeirvw": [ + "waiver", + "wavier" + ], + "aelp": [ + "leap", + "lepa", + "pale", + "peal", + "plea" + ], + "deghilt": [ + "delight", + "lighted" + ], + "ceeimnoos": [ + "economies", + "economise", + "monoecies" + ], + "aabceilrt": [ + "bacterial", + "calibrate" + ], + "agps": [ + "gaps", + "gasp", + "spag" + ], + "dnoors": [ + "donors", + "rondos" + ], + "aat": [ + "ata", + "taa" + ], + "aceehst": [ + "escheat", + "teaches" + ], + "iln": [ + "lin", + "nil" + ], + "aegnrrst": [ + "granters", + "regrants", + "stranger" + ], + "adegrty": [ + "gyrated", + "tragedy" + ], + "derry": [ + "derry", + "dryer", + "redry", + "ryder" + ], + "abilnrtu": [ + "tribunal", + "turbinal", + "untribal" + ], + "delru": [ + "duler", + "lured", + "ruled", + "urled" + ], + "anot": [ + "nato", + "nota", + "tano" + ], + "einnopss": [ + "pensions", + "snipnose" + ], + "aeprrsy": [ + "prayers", + "respray", + "sprayer" + ], + "eehnorw": [ + "nowhere", + "whereon" + ], + "cop": [ + "cop", + "cpo" + ], + "aegl": [ + "egal", + "gael", + "gale", + "geal" + ], + "aellty": [ + "lately", + "lealty" + ], + "acrsy": [ + "ascry", + "sacry", + "scary", + "scray" + ], + "aemrsstt": [ + "mattress", + "smartest", + "smatters" + ], + "beinru": [ + "burnie", + "eburin", + "rubine" + ], + "eeiiklsw": [ + "likewise", + "wiselike" + ], + "anst": [ + "ants", + "nast", + "sant", + "stan", + "tans" + ], + "dilo": [ + "dilo", + "diol", + "doli", + "idol", + "lido", + "olid" + ], + "deimnr": [ + "minder", + "remind" + ], + "acghimnr": [ + "charming", + "marching" + ], + "cdeeeprst": [ + "respected", + "sceptered", + "spectered" + ], + "assty": [ + "sayst", + "stays" + ], + "aaffir": [ + "affair", + "raffia" + ], + "aehrsw": [ + "hawser", + "rewash", + "washer" + ], + "ceirrstt": [ + "critters", + "restrict", + "stricter" + ], + "eginprrs": [ + "respring", + "springer" + ], + "eimns": [ + "miens", + "mines" + ], + "bdenoru": [ + "beround", + "bounder", + "rebound", + "unbored", + "unorbed", + "unrobed" + ], + "emnort": [ + "mentor", + "merton", + "metron", + "montre", + "termon", + "tormen" + ], + "eefmoprrr": [ + "performer", + "prereform", + "reperform" + ], + "deiltt": [ + "tilted", + "titled" + ], + "eehprs": [ + "herpes", + "hesper", + "sphere" + ], + "aiorst": [ + "aorist", + "aristo", + "ratios", + "satori" + ], + "addelr": [ + "ladder", + "larded", + "raddle" + ], + "aenorsst": [ + "assentor", + "essorant", + "senators", + "starnose", + "treasons" + ], + "koortuw": [ + "outwork", + "workout" + ], + "aelns": [ + "ansel", + "elans", + "lanes", + "leans", + "senal", + "slane" + ], + "aginstt": [ + "stating", + "tasting" + ], + "aceilnor": [ + "acrolein", + "arecolin", + "caroline", + "colinear", + "cornelia", + "creolian", + "lonicera" + ], + "elu": [ + "leu", + "lue", + "ule" + ], + "agiln": [ + "algin", + "align", + "langi", + "liang", + "ligan", + "linga" + ], + "adeimnnot": [ + "dentinoma", + "nominated" + ], + "aceellort": [ + "electoral", + "recollate" + ], + "eehl": [ + "heel", + "hele" + ], + "alloy": [ + "alloy", + "loyal" + ], + "cdnoos": [ + "codons", + "condos" + ], + "lopst": [ + "plots", + "topsl" + ], + "dehilops": [ + "depolish", + "polished" + ], + "alstu": [ + "altus", + "latus", + "sault", + "talus", + "tulsa" + ], + "adrsw": [ + "draws", + "sward", + "wards" + ], + "lou": [ + "lou", + "luo" + ], + "cdeeeorrv": [ + "overcreed", + "recovered" + ], + "aefrrs": [ + "farers", + "fraser" + ], + "egrsu": [ + "grues", + "guser", + "surge", + "urges" + ], + "aamrtu": [ + "taruma", + "trauma" + ], + "addegimnn": [ + "demanding", + "maddening" + ], + "lossu": [ + "solus", + "souls" + ], + "aknps": [ + "knaps", + "spank" + ], + "egoorv": [ + "groove", + "overgo" + ], + "aeeilnortv": [ + "relevation", + "revelation" + ], + "adeegilnot": [ + "degelation", + "delegation" + ], + "eirsw": [ + "swire", + "weirs", + "wires", + "wiser", + "wries" + ], + "eelpss": [ + "sleeps", + "speels" + ], + "abekl": [ + "blake", + "bleak", + "kabel" + ], + "eginr": [ + "grein", + "inger", + "nigre", + "regin", + "reign", + "renig", + "ringe" + ], + "abcno": [ + "bacon", + "banco" + ], + "aeehrt": [ + "aether", + "heater", + "hereat", + "reheat" + ], + "ccirsu": [ + "circus", + "crucis" + ], + "demooprt": [ + "promoted", + "toperdom" + ], + "aem": [ + "ame", + "eam", + "mae", + "mea" + ], + "elm": [ + "elm", + "mel" + ], + "einps": [ + "insep", + "peins", + "penis", + "pines", + "snipe", + "spine" + ], + "orttu": [ + "tourt", + "trout", + "tutor" + ], + "aeilmoprrty": [ + "polarimetry", + "premorality", + "temporarily" + ], + "ehillrrt": [ + "rethrill", + "thriller" + ], + "aimnrstt": [ + "tantrism", + "transmit" + ], + "adeglr": [ + "argled", + "gerald", + "glared", + "regald" + ], + "deeprss": [ + "depress", + "pressed" + ], + "eghnru": [ + "hunger", + "rehung" + ], + "pssu": [ + "puss", + "sups" + ], + "aeinnrtt": [ + "antirent", + "internat", + "intranet" + ], + "celoss": [ + "closes", + "socles" + ], + "eqs": [ + "esq", + "seq" + ], + "eeinprsstt": [ + "persistent", + "pinsetters", + "presentist", + "prettiness" + ], + "aeimmrssu": [ + "summaries", + "summarise" + ], + "glow": [ + "glow", + "gowl" + ], + "amw": [ + "awm", + "maw", + "mwa" + ], + "deiox": [ + "doxie", + "oxide" + ], + "akos": [ + "asok", + "koas", + "oaks", + "okas", + "soak", + "soka" + ], + "eikr": [ + "erik", + "keir", + "kier", + "reki" + ], + "ceelnorsu": [ + "enclosure", + "recounsel" + ], + "aeknrw": [ + "newark", + "wanker" + ], + "mnor": [ + "morn", + "norm" + ], + "elrttu": [ + "ruttle", + "turtle", + "tutler" + ], + "abinooprst": [ + "absorption", + "probations", + "saprobiont" + ], + "abdly": [ + "badly", + "baldy", + "blady" + ], + "alloop": [ + "apollo", + "palolo" + ], + "anw": [ + "awn", + "naw", + "wan" + ], + "aeinprs": [ + "paniers", + "persian", + "prasine", + "rapines", + "saprine", + "spirane" + ], + "eeegnr": [ + "neeger", + "reenge", + "renege" + ], + "boorst": [ + "brosot", + "robots" + ], + "adej": [ + "deja", + "jade" + ], + "coops": [ + "coops", + "scoop" + ], + "aeginnr": [ + "aginner", + "earning", + "engrain", + "geranin", + "grannie", + "nearing" + ], + "deenst": [ + "dentes", + "nested", + "sedent", + "tensed" + ], + "emorsv": [ + "movers", + "vomers" + ], + "abelrv": [ + "barvel", + "blaver", + "verbal" + ], + "eelnprsty": [ + "presently", + "serpently" + ], + "aess": [ + "asse", + "seas" + ], + "eilst": [ + "islet", + "istle", + "liest", + "lites", + "slite", + "stile", + "tiles" + ], + "eops": [ + "epos", + "opes", + "peso", + "pose", + "sope" + ], + "ikloott": [ + "kittool", + "toolkit" + ], + "agot": [ + "goat", + "toag", + "toga" + ], + "deenrr": [ + "derner", + "render" + ], + "ens": [ + "ens", + "sen" + ], + "efgor": [ + "forge", + "gofer" + ], + "ceiimmnoorsss": [ + "commissioners", + "recommissions" + ], + "aberv": [ + "brave", + "breva" + ], + "afluw": [ + "awful", + "fulwa" + ], + "aaeilnpr": [ + "airplane", + "perianal" + ], + "eenrst": [ + "enters", + "ernest", + "nester", + "rentes", + "resent", + "streen", + "tenser", + "ternes" + ], + "dop": [ + "dop", + "pod" + ], + "aaegsv": [ + "agaves", + "savage" + ], + "blot": [ + "blot", + "bolt" + ], + "ghinortw": [ + "ingrowth", + "throwing", + "worthing" + ], + "agnow": [ + "gowan", + "wagon", + "wonga" + ], + "adt": [ + "dat", + "tad" + ], + "egru": [ + "grue", + "urge" + ], + "aeeegnrst": [ + "generates", + "teenagers" + ], + "krtu": [ + "kurt", + "turk" + ], + "eeprs": [ + "peers", + "peres", + "perse", + "prees", + "prese", + "speer", + "spere", + "spree" + ], + "orsu": [ + "ours", + "rous", + "sour" + ], + "eefhrrs": [ + "fresher", + "refresh" + ], + "belstu": [ + "bluest", + "bluets", + "bustle", + "butles", + "sublet", + "subtle" + ], + "eiprsst": [ + "esprits", + "persist", + "priests", + "spriest", + "sprites", + "stirpes", + "stripes" + ], + "ceop": [ + "cope", + "opec" + ], + "acdelr": [ + "cardel", + "cradle", + "credal", + "reclad" + ], + "ikkr": [ + "kirk", + "rikk" + ], + "floru": [ + "flour", + "fluor" + ], + "adeeglnry": [ + "enragedly", + "legendary" + ], + "bloo": [ + "bolo", + "bool", + "lobo", + "loob", + "obol" + ], + "ahmpstyy": [ + "sympathy", + "symphyta" + ], + "chior": [ + "chiro", + "choir", + "ichor" + ], + "ceepstx": [ + "excepts", + "expects" + ], + "cho": [ + "cho", + "hoc", + "och" + ], + "itw": [ + "twi", + "wit" + ], + "brstu": [ + "burst", + "strub" + ], + "din": [ + "din", + "ind", + "nid" + ], + "coprsu": [ + "corpus", + "croups" + ], + "adehss": [ + "dashes", + "sadhes", + "sashed", + "shades" + ], + "ejst": [ + "jest", + "jets" + ], + "cdeiins": [ + "incised", + "indices" + ], + "ilnt": [ + "intl", + "lint" + ], + "adisy": [ + "daisy", + "sayid" + ], + "corrsu": [ + "cruors", + "cursor" + ], + "aeeilrst": [ + "ateliers", + "earliest", + "leariest", + "realties", + "tresaiel" + ], + "addenot": [ + "donated", + "nodated" + ], + "deffstu": [ + "destuff", + "stuffed" + ], + "ceinsst": [ + "incests", + "insects", + "scenist" + ], + "aeilmnrst": [ + "mislearnt", + "terminals", + "trailsmen", + "tramlines" + ], + "cderu": [ + "crude", + "cured" + ], + "elmrty": [ + "myrtle", + "termly" + ], + "bdeor": [ + "boder", + "bored", + "orbed", + "robed" + ], + "acelnpu": [ + "cleanup", + "unplace" + ], + "iknt": [ + "knit", + "tink" + ], + "gmu": [ + "gum", + "mug" + ], + "behort": [ + "bother", + "brothe" + ], + "abhntu": [ + "bhutan", + "thuban" + ], + "agimnt": [ + "mating", + "taming" + ], + "addeehr": [ + "adhered", + "redhead" + ], + "aeirrsv": [ + "arrives", + "riserva", + "variers" + ], + "aahll": [ + "allah", + "halal" + ], + "anpruw": [ + "unwarp", + "unwrap" + ], + "dehop": [ + "depoh", + "ephod", + "hoped" + ], + "eikp": [ + "kepi", + "kipe", + "pike" + ], + "ghou": [ + "hugo", + "ough" + ], + "aegnrw": [ + "gnawer", + "wagner", + "wanger" + ], + "aegnrr": [ + "garner", + "ranger" + ], + "ahmrs": [ + "harms", + "marsh", + "shram" + ], + "aehtt": [ + "hatte", + "theat", + "theta" + ] +} -- cgit v1.2.3 From 60b146f9b55af5688b96534884ab350f63da1e28 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Fri, 24 Sep 2021 12:13:26 +0100 Subject: Add a 2 minute cooldown to the topic command Using the command while it's on cooldown will hit the error handler, which sends an error message showing how long is left on the cooldown, which is deleted after 7.5 seconds. --- bot/exts/utilities/conversationstarters.py | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/bot/exts/utilities/conversationstarters.py b/bot/exts/utilities/conversationstarters.py index dd537022..07d71f15 100644 --- a/bot/exts/utilities/conversationstarters.py +++ b/bot/exts/utilities/conversationstarters.py @@ -36,32 +36,16 @@ class ConvoStarters(commands.Cog): """General conversation topics.""" @commands.command() + @commands.cooldown(1, 60*2, commands.BucketType.channel) @whitelist_override(channels=ALL_ALLOWED_CHANNELS) async def topic(self, ctx: commands.Context) -> None: """ Responds with a random topic to start a conversation. - If in a Python channel, a python-related topic will be given. - - Otherwise, a random conversation topic will be received by the user. + Allows the refresh of a topic by pressing an emoji. """ - # No matter what, the form will be shown. - embed = Embed(description=f"Suggest more topics [here]({SUGGESTION_FORM})!", color=Color.blurple()) - - try: - # Fetching topics. - channel_topics = TOPICS[ctx.channel.id] - - # If the channel isn't Python-related. - except KeyError: - embed.title = f"**{next(TOPICS['default'])}**" - - # If the channel ID doesn't have any topics. - else: - embed.title = f"**{next(channel_topics)}**" - - finally: - await ctx.send(embed=embed) + message = await ctx.send(embed=self._build_topic_embed(ctx.channel.id)) + self.bot.loop.create_task(self._listen_for_refresh(message)) def setup(bot: Bot) -> None: -- cgit v1.2.3 From 515c6390563f33a02af2e46fe6f3d13b15353a0a Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Fri, 24 Sep 2021 13:10:53 +0100 Subject: Allow topics to be refreshed This is done via an emoji as buttons are too big Co-authored-by: Bluenix --- bot/exts/utilities/conversationstarters.py | 65 ++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/conversationstarters.py b/bot/exts/utilities/conversationstarters.py index 07d71f15..5d62fa83 100644 --- a/bot/exts/utilities/conversationstarters.py +++ b/bot/exts/utilities/conversationstarters.py @@ -1,11 +1,14 @@ +import asyncio +from contextlib import suppress +from functools import partial from pathlib import Path +import discord import yaml -from discord import Color, Embed from discord.ext import commands from bot.bot import Bot -from bot.constants import WHITELISTED_CHANNELS +from bot.constants import MODERATION_ROLES, WHITELISTED_CHANNELS from bot.utils.decorators import whitelist_override from bot.utils.randomization import RandomCycle @@ -35,6 +38,62 @@ TOPICS = { class ConvoStarters(commands.Cog): """General conversation topics.""" + def __init__(self, bot: Bot): + self.bot = bot + + @staticmethod + def _build_topic_embed(channel_id: int) -> discord.Embed: + """ + Build an embed containing a conversation topic. + + If in a Python channel, a python-related topic will be given. + Otherwise, a random conversation topic will be received by the user. + """ + # No matter what, the form will be shown. + embed = discord.Embed( + description=f"Suggest more topics [here]({SUGGESTION_FORM})!", + color=discord.Color.blurple() + ) + + try: + channel_topics = TOPICS[channel_id] + except KeyError: + # Channel doesn't have any topics. + embed.title = f"**{next(TOPICS['default'])}**" + else: + embed.title = f"**{next(channel_topics)}**" + return embed + + def _predicate(self, message: discord.Message, reaction: discord.Reaction, user: discord.User) -> bool: + right_reaction = ( + user != self.bot.user + and reaction.message.id == message.id + and str(reaction.emoji) == "🔄" + ) + if not right_reaction: + return False + + is_moderator = any(role.id in MODERATION_ROLES for role in getattr(user, "roles", [])) + if is_moderator or user.id == message.author.id: + return True + + return False + + async def _listen_for_refresh(self, message: discord.Message) -> None: + await message.add_reaction("🔄") + while True: + try: + reaction, user = await self.bot.wait_for( + "reaction_add", + check=partial(self._predicate, message), + timeout=60.0 + ) + except asyncio.TimeoutError: + with suppress(discord.NotFound): + await message.clear_reaction("🔄") + else: + await message.edit(embed=self._build_topic_embed(message.channel.id)) + @commands.command() @commands.cooldown(1, 60*2, commands.BucketType.channel) @whitelist_override(channels=ALL_ALLOWED_CHANNELS) @@ -50,4 +109,4 @@ class ConvoStarters(commands.Cog): def setup(bot: Bot) -> None: """Load the ConvoStarters cog.""" - bot.add_cog(ConvoStarters()) + bot.add_cog(ConvoStarters(bot)) -- cgit v1.2.3 From 0cc435c1e56260271bb6ff27fddd8d6971837feb Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Fri, 8 Oct 2021 07:58:23 +0200 Subject: Candy collection: fix positional arg being passed as kword This caused a `TypeError` to be raised, as the `id` argument could only be used as a positional argument and not by keyword. --- bot/exts/holidays/halloween/candy_collection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py index 4afd5913..09bd0e59 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -134,7 +134,7 @@ class CandyCollection(commands.Cog): @property def hacktober_channel(self) -> discord.TextChannel: """Get #hacktoberbot channel from its ID.""" - return self.bot.get_channel(id=Channels.community_bot_commands) + return self.bot.get_channel(Channels.community_bot_commands) @staticmethod async def send_spook_msg( -- cgit v1.2.3 From 999604b335840fe820deddd0cebea7b6b601c218 Mon Sep 17 00:00:00 2001 From: Izan Date: Fri, 8 Oct 2021 11:39:20 +0100 Subject: `.topic` command improvements. - Fix bug where command author couldn't re-roll - Now removes user's reaction up re-roll - Added a missing `break` statement --- bot/exts/utilities/conversationstarters.py | 45 ++++++++++++++++++------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/bot/exts/utilities/conversationstarters.py b/bot/exts/utilities/conversationstarters.py index 5d62fa83..2316c50d 100644 --- a/bot/exts/utilities/conversationstarters.py +++ b/bot/exts/utilities/conversationstarters.py @@ -2,6 +2,7 @@ import asyncio from contextlib import suppress from functools import partial from pathlib import Path +from typing import Union import discord import yaml @@ -64,35 +65,43 @@ class ConvoStarters(commands.Cog): embed.title = f"**{next(channel_topics)}**" return embed - def _predicate(self, message: discord.Message, reaction: discord.Reaction, user: discord.User) -> bool: - right_reaction = ( - user != self.bot.user - and reaction.message.id == message.id - and str(reaction.emoji) == "🔄" - ) - if not right_reaction: - return False - - is_moderator = any(role.id in MODERATION_ROLES for role in getattr(user, "roles", [])) - if is_moderator or user.id == message.author.id: - return True - - return False - - async def _listen_for_refresh(self, message: discord.Message) -> None: + @staticmethod + def _predicate( + command_invoker: Union[discord.User, discord.Member], + message: discord.Message, + reaction: discord.Reaction, + user: discord.User + ) -> bool: + user_is_moderator = any(role.id in MODERATION_ROLES for role in getattr(user, "roles", [])) + user_is_invoker = user.id == command_invoker.id + + is_right_reaction = all(( + reaction.message.id == message.id, + str(reaction.emoji) == "🔄", + user_is_moderator or user_is_invoker + )) + return is_right_reaction + + async def _listen_for_refresh( + self, + command_invoker: Union[discord.User, discord.Member], + message: discord.Message + ) -> None: await message.add_reaction("🔄") while True: try: reaction, user = await self.bot.wait_for( "reaction_add", - check=partial(self._predicate, message), + check=partial(self._predicate, command_invoker, message), timeout=60.0 ) except asyncio.TimeoutError: with suppress(discord.NotFound): await message.clear_reaction("🔄") + break else: await message.edit(embed=self._build_topic_embed(message.channel.id)) + await message.remove_reaction(reaction, user) @commands.command() @commands.cooldown(1, 60*2, commands.BucketType.channel) @@ -104,7 +113,7 @@ class ConvoStarters(commands.Cog): Allows the refresh of a topic by pressing an emoji. """ message = await ctx.send(embed=self._build_topic_embed(ctx.channel.id)) - self.bot.loop.create_task(self._listen_for_refresh(message)) + self.bot.loop.create_task(self._listen_for_refresh(ctx.author, message)) def setup(bot: Bot) -> None: -- cgit v1.2.3 From 3c26b4d2fc4746da13695c31ef4dc7435f35525f Mon Sep 17 00:00:00 2001 From: Izan Date: Fri, 8 Oct 2021 14:24:14 +0100 Subject: Add handling for `discord.NotFound` when re-rolling / removing reaction --- bot/exts/utilities/conversationstarters.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/conversationstarters.py b/bot/exts/utilities/conversationstarters.py index 2316c50d..fcb5f977 100644 --- a/bot/exts/utilities/conversationstarters.py +++ b/bot/exts/utilities/conversationstarters.py @@ -100,8 +100,13 @@ class ConvoStarters(commands.Cog): await message.clear_reaction("🔄") break else: - await message.edit(embed=self._build_topic_embed(message.channel.id)) - await message.remove_reaction(reaction, user) + try: + await message.edit(embed=self._build_topic_embed(message.channel.id)) + except discord.NotFound: + break + + with suppress(discord.NotFound): + await message.remove_reaction(reaction, user) @commands.command() @commands.cooldown(1, 60*2, commands.BucketType.channel) -- cgit v1.2.3 From e01503a61015d483cd70e1e408c647b4054a927f Mon Sep 17 00:00:00 2001 From: Izan Date: Fri, 8 Oct 2021 14:27:15 +0100 Subject: Remove unnecessary `else` --- bot/exts/utilities/conversationstarters.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bot/exts/utilities/conversationstarters.py b/bot/exts/utilities/conversationstarters.py index fcb5f977..dcbfe4d5 100644 --- a/bot/exts/utilities/conversationstarters.py +++ b/bot/exts/utilities/conversationstarters.py @@ -99,14 +99,14 @@ class ConvoStarters(commands.Cog): with suppress(discord.NotFound): await message.clear_reaction("🔄") break - else: - try: - await message.edit(embed=self._build_topic_embed(message.channel.id)) - except discord.NotFound: - break - with suppress(discord.NotFound): - await message.remove_reaction(reaction, user) + try: + await message.edit(embed=self._build_topic_embed(message.channel.id)) + except discord.NotFound: + break + + with suppress(discord.NotFound): + await message.remove_reaction(reaction, user) @commands.command() @commands.cooldown(1, 60*2, commands.BucketType.channel) -- cgit v1.2.3 From febe5b9218f44a2c6abfa6355f063471c0593bc9 Mon Sep 17 00:00:00 2001 From: wookie184 Date: Sat, 9 Oct 2021 16:24:42 +0100 Subject: Replace usage of bot.command_prefix with constants.Client.prefix --- bot/exts/fun/trivia_quiz.py | 4 ++-- bot/exts/holidays/halloween/spookynamerate.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/exts/fun/trivia_quiz.py b/bot/exts/fun/trivia_quiz.py index 236586b0..712c8a12 100644 --- a/bot/exts/fun/trivia_quiz.py +++ b/bot/exts/fun/trivia_quiz.py @@ -16,7 +16,7 @@ from discord.ext import commands, tasks from rapidfuzz import fuzz from bot.bot import Bot -from bot.constants import Colours, NEGATIVE_REPLIES, Roles +from bot.constants import Client, Colours, NEGATIVE_REPLIES, Roles logger = logging.getLogger(__name__) @@ -332,7 +332,7 @@ class TriviaQuiz(commands.Cog): if self.game_status[ctx.channel.id]: await ctx.send( "Game is already running... " - f"do `{self.bot.command_prefix}quiz stop`" + f"do `{Client.prefix}quiz stop`" ) return diff --git a/bot/exts/holidays/halloween/spookynamerate.py b/bot/exts/holidays/halloween/spookynamerate.py index 2e59d4a8..a3aa4f13 100644 --- a/bot/exts/holidays/halloween/spookynamerate.py +++ b/bot/exts/holidays/halloween/spookynamerate.py @@ -143,7 +143,7 @@ class SpookyNameRate(Cog): if data["author"] == ctx.author.id: await ctx.send( "But you have already added an entry! Type " - f"`{self.bot.command_prefix}spookynamerate " + f"`{Client.prefix}spookynamerate " "delete` to delete it, and then you can add it again" ) return @@ -185,7 +185,7 @@ class SpookyNameRate(Cog): return await ctx.send( - f"But you don't have an entry... :eyes: Type `{self.bot.command_prefix}spookynamerate add your entry`" + f"But you don't have an entry... :eyes: Type `{Client.prefix}spookynamerate add your entry`" ) @Cog.listener() @@ -225,7 +225,7 @@ class SpookyNameRate(Cog): "Okkey... Welcome to the **Spooky Name Rate Game**! It's a relatively simple game.\n" f"Everyday, a random name will be sent in <#{Channels.community_bot_commands}> " "and you need to try and spookify it!\nRegister your name using " - f"`{self.bot.command_prefix}spookynamerate add spookified name`" + f"`{Client.prefix}spookynamerate add spookified name`" ) await self.data.set("first_time", False) -- cgit v1.2.3 From 0c814ceb2da9d1e8ffe49b902c4fbed377038a39 Mon Sep 17 00:00:00 2001 From: Izan Date: Mon, 11 Oct 2021 13:53:29 +0100 Subject: Set `AI.user` to @Sir Lancebot --- bot/exts/fun/tic_tac_toe.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bot/exts/fun/tic_tac_toe.py b/bot/exts/fun/tic_tac_toe.py index 5c4f8051..49620d02 100644 --- a/bot/exts/fun/tic_tac_toe.py +++ b/bot/exts/fun/tic_tac_toe.py @@ -72,7 +72,8 @@ class Player: class AI: """Tic Tac Toe AI class for against computer gaming.""" - def __init__(self, symbol: str): + def __init__(self, ctx: Context, symbol: str): + self.user = ctx.me self.symbol = symbol async def get_move(self, board: dict[int, str], _: discord.Message) -> tuple[bool, int]: @@ -97,8 +98,8 @@ class AI: return False, random.choice(open_edges) def __str__(self) -> str: - """Return `AI` as user name.""" - return "AI" + """Return mention of @Sir Lancebot.""" + return self.user.mention class Game: @@ -265,7 +266,7 @@ class TicTacToe(Cog): return if opponent is None: game = Game( - [Player(ctx.author, ctx, Emojis.x_square), AI(Emojis.o_square)], + [Player(ctx.author, ctx, Emojis.x_square), AI(ctx, Emojis.o_square)], ctx ) else: -- cgit v1.2.3 From 462b83c8150bbc9121d87cf8ee0e61d850776fc6 Mon Sep 17 00:00:00 2001 From: Izan Date: Mon, 11 Oct 2021 14:17:38 +0100 Subject: Add missing `Game.channel` attribute --- bot/exts/fun/tic_tac_toe.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/exts/fun/tic_tac_toe.py b/bot/exts/fun/tic_tac_toe.py index 49620d02..1ebf8d11 100644 --- a/bot/exts/fun/tic_tac_toe.py +++ b/bot/exts/fun/tic_tac_toe.py @@ -108,6 +108,7 @@ class Game: def __init__(self, players: list[Union[Player, AI]], ctx: Context): self.players = players self.ctx = ctx + self.channel = ctx.channel self.board = { 1: Emojis.number_emojis[1], 2: Emojis.number_emojis[2], -- cgit v1.2.3 From b0be25bed15bbfc88d61e2e842b9f894c9cac15c Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 13 Oct 2021 20:44:07 +0100 Subject: update advent of code channel IDs We deleted and re-made the channels so new IDs are needed. --- bot/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index 6e45632f..567daadd 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -101,8 +101,8 @@ class Cats: class Channels(NamedTuple): - advent_of_code = int(environ.get("AOC_CHANNEL_ID", 782715290437943306)) - advent_of_code_commands = int(environ.get("AOC_COMMANDS_CHANNEL_ID", 607247579608121354)) + advent_of_code = int(environ.get("AOC_CHANNEL_ID", 897932085766004786)) + advent_of_code_commands = int(environ.get("AOC_COMMANDS_CHANNEL_ID", 897932607545823342)) bot = 267659945086812160 organisation = 551789653284356126 devlog = int(environ.get("CHANNEL_DEVLOG", 622895325144940554)) -- cgit v1.2.3 From a0c86e72c0a418f1265a1aa035b45048d8e921ec Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Wed, 13 Oct 2021 17:23:30 -0400 Subject: Challenges (#860) * beginning commit creating the base of the hangman, code needs to be linted in the future * updated words list * adding images to show the hangman person * added images, though it is a bit laggy * replacing images with discord attachment urls * adding error if filters aren't found * fixing typo in ``filter_not_found_embed`` * final lints + removing `mode` parameter as it renders useless * linting flake8 errors * adding newline at the end of `top_1000_used_words.txt` * minor change to filter message * beginning commit -- trying to add bs4 to pyproject.toml, though it is currently failing * kata information section done, ready for issue * fixing bugs with the query not being fully picked up, also allowing query only with no kyu * fixing bug where user cannot leave all arguments blank * typo - forgot unary before the level within the `language and not query` if statement * changing to random kata chosen * ensuring that if the user provides a query that won't work, that it won't error out * limiting choice to smaller numbers if a query was provided, so the user gets what they want * improving hangman docstring * removing `bot/resources/evergreen/hangman` directory as file attachments are used * replacing single quotes with double quotes, to adhere to the style guide. * fixing style inconsistencies and other problems with how the code looks - as per requested by Objectivix * fixing `IMAGES` style inconsistency * adding trailing commas and switching to `Colours` for consistency * adding trailing commas and switching to `Colours` for consistency * fixing the remnants of non-trailing commas and allowing specification for single player vs mulitplayer * removing all 2 letter words from the hangman word choosing and removing words that @Objectivix found that shouldn't be in the list of words * removing some inappropriate words from the txt file * Adding space for grammatical errors Co-authored-by: ChrisJL * changing two periods to a full stop & wrapping try and except block to only the part that can raise it * using negative replies instead along with fixing grammatical errors in the sentence * removing words that could be considered inappropirate * removing `TOP_WORDS_FILE_PATH` and making `ALL_WORDS` a global variable. * error handling * fixing the overcomplication of the bs4 portion * adding button and dropdowns to the challenges command * more specific docstring * more specific docstring * finishing dropdowns/buttons * putting the dropdown on top of the link button * replacing ' with a double quote for some strings * Removing more words The words removed shouldn't really belong here * Update bot/exts/utilities/challenges.py Co-authored-by: Bluenix * replacing mapping_of_images with IMAGES and other fixes * Dedenting Co-authored-by: Bluenix * Improving tries logic Co-authored-by: Bluenix * Updating `positions` list to set Co-authored-by: Bluenix * Updating setup docstring Co-authored-by: Bluenix * Updating comment in callback function of the dropdown Co-authored-by: Bluenix * fixing too many blank lines * Hardcode dictionary Co-authored-by: Bluenix * restructuring * fixing errors * Remove unnecessary comments Co-authored-by: Bluenix * Remove unnecessary comments Co-authored-by: Bluenix * Improve comment explanation Co-authored-by: Bluenix * Remove redundant extra membership test Co-authored-by: Bluenix * Removing verbose variable definition Co-authored-by: Bluenix * Redundant list Co-authored-by: Bluenix * Shorten 'social distancing' (too many separations) between related lines Co-authored-by: Bluenix * improving docstring in `kata_id` * sending embed if error occurs with api or bs4, also hardcoding params dictionary * Better comments Co-authored-by: Bluenix * better docstring Co-authored-by: Bluenix * Removing f-string inception and replacing it with more readable code Co-authored-by: Bluenix * More specific docstring Co-authored-by: Bluenix * Removing redundant comments Co-authored-by: Bluenix * Fixing linting errors * mapping of kyu -> constant * adding trailing comma * specific comment regarding where colors are from for `MAPPING_OF_KYU` * changing name to link too along with link button * adding ellipsis to make it more clear for `Read more` * removing redundant sentences from all docstrings of embed creator functions * fixing unboundlocalerror due to kata_url only being defined under a certain condition * only allowing supported languages on codewars.com * fixing url glitch with embed * Delete hangman.py * Delete top_1000_used_words.txt * hangman dependencies leaked into this PR, removing them * add bs4 and lxml back to lock file * Capitalize comments Co-authored-by: Bluenix * Improving comments (capitalization) Co-authored-by: Bluenix * polishing * explaining that self.original_message will be set later in the callback function of the dropdown * fixing nitpicks * cast to integer from hex * removing unnecessary trailing commas * Simplifying L274-L276 Co-authored-by: Bluenix * Add ellipsis to end of description if it's too long Co-authored-by: Bluenix * Changing to hex Co-authored-by: Bluenix * Running blocking function (BeautifulSoup.find_all) to thread Co-authored-by: Bluenix * logger.error errors * Fixing error with to_thread * Fixing errors with MAPPING_OF_KYU Co-authored-by: Bluenix * changing `query` to `-query` if the query is a kata level * changing embed names to add the kata name * Mimicking mailing list's behavior Co-authored-by: Bluenix * url attribute for all embeds & title for all embeds * remove view after a certain amount of tikme * disabling view after waiting instead of just editing it out * styling * remove view to avoid spamming errors * changing `logger` to `log` Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> * Change `logger` to `log` for logging errors Co-authored-by: ChrisJL Co-authored-by: Bluenix Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/utilities/challenges.py | 335 +++++++++++++++++++++++++++++++++++++++ poetry.lock | 98 +++++++++++- pyproject.toml | 2 + 3 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 bot/exts/utilities/challenges.py diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py new file mode 100644 index 00000000..234eb0be --- /dev/null +++ b/bot/exts/utilities/challenges.py @@ -0,0 +1,335 @@ +import logging +from asyncio import to_thread +from random import choice +from typing import Union + +from bs4 import BeautifulSoup +from discord import Embed, Interaction, SelectOption, ui +from discord.ext import commands + +from bot.bot import Bot +from bot.constants import Colours, Emojis, NEGATIVE_REPLIES + +log = logging.getLogger(__name__) +API_ROOT = "https://www.codewars.com/api/v1/code-challenges/{kata_id}" + +# Map difficulty for the kata to color we want to display in the embed. +# These colors are representative of the colors that each kyu's level represents on codewars.com +MAPPING_OF_KYU = { + 8: 0xdddbda, 7: 0xdddbda, 6: 0xecb613, 5: 0xecb613, + 4: 0x3c7ebb, 3: 0x3c7ebb, 2: 0x866cc7, 1: 0x866cc7 +} + +# Supported languages for a kata on codewars.com +SUPPORTED_LANGUAGES = { + "stable": [ + "c", "c#", "c++", "clojure", "coffeescript", "coq", "crystal", "dart", "elixir", + "f#", "go", "groovy", "haskell", "java", "javascript", "kotlin", "lean", "lua", "nasm", + "php", "python", "racket", "ruby", "rust", "scala", "shell", "sql", "swift", "typescript" + ], + "beta": [ + "agda", "bf", "cfml", "cobol", "commonlisp", "elm", "erlang", "factor", + "forth", "fortran", "haxe", "idris", "julia", "nim", "objective-c", "ocaml", + "pascal", "perl", "powershell", "prolog", "purescript", "r", "raku", "reason", "solidity", "vb.net" + ] +} + + +class InformationDropdown(ui.Select): + """A dropdown inheriting from ui.Select that allows finding out other information about the kata.""" + + def __init__(self, language_embed: Embed, tags_embed: Embed, other_info_embed: Embed, main_embed: Embed): + options = [ + SelectOption( + label="Main Information", + description="See the kata's difficulty, description, etc.", + emoji="🌎" + ), + SelectOption( + label="Languages", + description="See what languages this kata supports!", + emoji=Emojis.reddit_post_text + ), + SelectOption( + label="Tags", + description="See what categories this kata falls under!", + emoji=Emojis.stackoverflow_tag + ), + SelectOption( + label="Other Information", + description="See how other people performed on this kata and more!", + emoji="ℹ" + ) + ] + + # We map the option label to the embed instance so that it can be easily looked up later in O(1) + self.mapping_of_embeds = { + "Main Information": main_embed, + "Languages": language_embed, + "Tags": tags_embed, + "Other Information": other_info_embed, + } + + super().__init__( + placeholder="See more information regarding this kata", + min_values=1, + max_values=1, + options=options + ) + + async def callback(self, interaction: Interaction) -> None: + """Callback for when someone clicks on a dropdown.""" + # Edit the message to the embed selected in the option + # The `original_message` attribute is set just after the message is sent with the view. + # The attribute is not set during initialization. + result_embed = self.mapping_of_embeds[self.values[0]] + await self.original_message.edit(embed=result_embed) + + +class Challenges(commands.Cog): + """ + Cog for the challenge command. + + The challenge command pulls a random kata from codewars.com. + A kata is the name for a challenge, specific to codewars.com. + + The challenge command also has filters to customize the kata that is given. + You can specify the language the kata should be from, difficulty and topic of the kata. + """ + + def __init__(self, bot: Bot): + self.bot = bot + + async def kata_id(self, search_link: str, params: dict) -> Union[str, Embed]: + """ + Uses bs4 to get the HTML code for the page of katas, where the page is the link of the formatted `search_link`. + + This will webscrape the search page with `search_link` and then get the ID of a kata for the + codewars.com API to use. + """ + async with self.bot.http_session.get(search_link, params=params) as response: + if response.status != 200: + error_embed = Embed( + title=choice(NEGATIVE_REPLIES), + description="We ran into an error when getting the kata from codewars.com, try again later.", + color=Colours.soft_red + ) + log.error(f"Unexpected response from codewars.com, status code: {response.status}") + return error_embed + + soup = BeautifulSoup(await response.text(), features="lxml") + first_kata_div = await to_thread(soup.find_all, "div", class_="item-title px-0") + + if not first_kata_div: + raise commands.BadArgument("No katas could be found with the filters provided.") + elif len(first_kata_div) >= 3: + first_kata_div = choice(first_kata_div[:3]) + elif "q=" not in search_link: + first_kata_div = choice(first_kata_div) + else: + first_kata_div = first_kata_div[0] + + # There are numerous divs before arriving at the id of the kata, which can be used for the link. + first_kata_id = first_kata_div.a["href"].split("/")[-1] + return first_kata_id + + async def kata_information(self, kata_id: str) -> Union[dict, Embed]: + """ + Returns the information about the Kata. + + Uses the codewars.com API to get information about the kata using `kata_id`. + """ + async with self.bot.http_session.get(API_ROOT.format(kata_id=kata_id)) as response: + if response.status != 200: + error_embed = Embed( + title=choice(NEGATIVE_REPLIES), + description="We ran into an error when getting the kata information, try again later.", + color=Colours.soft_red + ) + log.error(f"Unexpected response from codewars.com/api/v1, status code: {response.status}") + return error_embed + + return await response.json() + + @staticmethod + def main_embed(kata_information: dict) -> Embed: + """Creates the main embed which displays the name, difficulty and description of the kata.""" + kata_description = kata_information["description"] + kata_url = f"https://codewars.com/kata/{kata_information['id']}" + + # Ensuring it isn't over the length 1024 + if len(kata_description) > 1024: + kata_description = "\n".join(kata_description[:1000].split("\n")[:-1]) + "..." + kata_description += f" [continue reading]({kata_url})" + + kata_embed = Embed( + title=kata_information["name"], + description=kata_description, + color=MAPPING_OF_KYU[int(kata_information["rank"]["name"].replace(" kyu", ""))], + url=kata_url + ) + kata_embed.add_field(name="Difficulty", value=kata_information["rank"]["name"], inline=False) + return kata_embed + + @staticmethod + def language_embed(kata_information: dict) -> Embed: + """Creates the 'language embed' which displays all languages the kata supports.""" + kata_url = f"https://codewars.com/kata/{kata_information['id']}" + + languages = "\n".join(map(str.title, kata_information["languages"])) + language_embed = Embed( + title=kata_information["name"], + description=f"```yaml\nSupported Languages:\n{languages}\n```", + color=Colours.python_blue, + url=kata_url + ) + return language_embed + + @staticmethod + def tags_embed(kata_information: dict) -> Embed: + """ + Creates the 'tags embed' which displays all the tags of the Kata. + + Tags explain what the kata is about, this is what codewars.com calls categories. + """ + kata_url = f"https://codewars.com/kata/{kata_information['id']}" + + tags = "\n".join(kata_information["tags"]) + tags_embed = Embed( + title=kata_information["name"], + description=f"```yaml\nTags:\n{tags}\n```", + color=Colours.grass_green, + url=kata_url + ) + return tags_embed + + @staticmethod + def miscellaneous_embed(kata_information: dict) -> Embed: + """ + Creates the 'other information embed' which displays miscellaneous information about the kata. + + This embed shows statistics such as the total number of people who completed the kata, + the total number of stars of the kata, etc. + """ + kata_url = f"https://codewars.com/kata/{kata_information['id']}" + + embed = Embed( + title=kata_information["name"], + description="```nim\nOther Information\n```", + color=Colours.grass_green, + url=kata_url + ) + embed.add_field( + name="`Total Score`", + value=f"```css\n{kata_information['voteScore']}\n```", + inline=False + ) + embed.add_field( + name="`Total Stars`", + value=f"```css\n{kata_information['totalStars']}\n```", + inline=False + ) + embed.add_field( + name="`Total Completed`", + value=f"```css\n{kata_information['totalCompleted']}\n```", + inline=False + ) + embed.add_field( + name="`Total Attempts`", + value=f"```css\n{kata_information['totalAttempts']}\n```", + inline=False + ) + return embed + + @staticmethod + def create_view(dropdown: InformationDropdown, link: str) -> ui.View: + """ + Creates the discord.py View for the Discord message components (dropdowns and buttons). + + The discord UI is implemented onto the embed, where the user can choose what information about the kata they + want, along with a link button to the kata itself. + """ + view = ui.View() + view.add_item(dropdown) + view.add_item(ui.Button(label="View the Kata", url=link)) + return view + + @commands.command(aliases=["kata"]) + @commands.cooldown(1, 5, commands.BucketType.user) + async def challenge(self, ctx: commands.Context, language: str = "python", *, query: str = None) -> None: + """ + The challenge command pulls a random kata (challenge) from codewars.com. + + The different ways to use this command are: + `.challenge ` - Pulls a random challenge within that language's scope. + `.challenge ` - The difficulty can be from 1-8, + 1 being the hardest, 8 being the easiest. This pulls a random challenge within that difficulty & language. + `.challenge ` - Pulls a random challenge with the query provided under the language + `.challenge , ` - Pulls a random challenge with the query provided, + under that difficulty within the language's scope. + """ + if language.lower() not in SUPPORTED_LANGUAGES["stable"] + SUPPORTED_LANGUAGES["beta"]: + raise commands.BadArgument("This is not a recognized language on codewars.com!") + + get_kata_link = f"https://codewars.com/kata/search/{language}" + params = {} + + if language and not query: + level = f"-{choice([1, 2, 3, 4, 5, 6, 7, 8])}" + params["r[]"] = level + elif "," in query: + query_splitted = query.split("," if ", " not in query else ", ") + + if len(query_splitted) > 2: + raise commands.BadArgument( + "There can only be one comma within the query, separating the difficulty and the query itself." + ) + + query, level = query_splitted + params["q"] = query + params["r[]"] = f"-{level}" + elif query.isnumeric(): + params["r[]"] = f"-{query}" + else: + params["q"] = query + + params["beta"] = str(language in SUPPORTED_LANGUAGES["beta"]).lower() + + first_kata_id = await self.kata_id(get_kata_link, params) + if isinstance(first_kata_id, Embed): + # We ran into an error when retrieving the website link + await ctx.send(embed=first_kata_id) + return + + kata_information = await self.kata_information(first_kata_id) + if isinstance(kata_information, Embed): + # Something went wrong when trying to fetch the kata information + await ctx.d(embed=kata_information) + return + + kata_embed = self.main_embed(kata_information) + language_embed = self.language_embed(kata_information) + tags_embed = self.tags_embed(kata_information) + miscellaneous_embed = self.miscellaneous_embed(kata_information) + + dropdown = InformationDropdown( + main_embed=kata_embed, + language_embed=language_embed, + tags_embed=tags_embed, + other_info_embed=miscellaneous_embed + ) + kata_view = self.create_view(dropdown, f"https://codewars.com/kata/{first_kata_id}") + original_message = await ctx.send( + embed=kata_embed, + view=kata_view + ) + dropdown.original_message = original_message + + wait_for_kata = await kata_view.wait() + if wait_for_kata: + await original_message.edit(embed=kata_embed, view=None) + + +def setup(bot: Bot) -> None: + """Load the Challenges cog.""" + bot.add_cog(Challenges(bot)) diff --git a/poetry.lock b/poetry.lock index 289f2039..21373a92 100644 --- a/poetry.lock +++ b/poetry.lock @@ -100,6 +100,21 @@ python-versions = ">=2.7" docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"] +[[package]] +name = "beautifulsoup4" +version = "4.10.0" +description = "Screen-scraping library" +category = "main" +optional = false +python-versions = ">3.0.0" + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + [[package]] name = "certifi" version = "2021.5.30" @@ -173,6 +188,7 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "url" url = "https://github.com/Rapptz/discord.py/archive/45d498c1b76deaf3b394d17ccf56112fa691d160.zip" + [[package]] name = "distlib" version = "0.3.2" @@ -355,6 +371,20 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "lxml" +version = "4.6.3" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["beautifulsoup4"] +source = ["Cython (>=0.29.7)"] + [[package]] name = "matplotlib" version = "3.4.3" @@ -653,6 +683,14 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "soupsieve" +version = "2.2.1" +description = "A modern CSS selector implementation for Beautiful Soup." +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "taskipy" version = "1.8.1" @@ -730,7 +768,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "9efbf6be5298ab8ace2588e218be309e105987bfdfa8317453d584a1faac4934" +content-hash = "6cced4e3fff83ad6ead9a18b3f585b83426fab34f6e2bcf2466c2ebbbf66dac4" [metadata.files] aiodns = [ @@ -800,6 +838,10 @@ attrs = [ {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"}, {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"}, ] +beautifulsoup4 = [ + {file = "beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf"}, + {file = "beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"}, +] certifi = [ {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, @@ -1016,6 +1058,56 @@ kiwisolver = [ {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bcadb05c3d4794eb9eee1dddf1c24215c92fb7b55a80beae7a60530a91060560"}, {file = "kiwisolver-1.3.2.tar.gz", hash = "sha256:fc4453705b81d03568d5b808ad8f09c77c47534f6ac2e72e733f9ca4714aa75c"}, ] +lxml = [ + {file = "lxml-4.6.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2"}, + {file = "lxml-4.6.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1b7584d421d254ab86d4f0b13ec662a9014397678a7c4265a02a6d7c2b18a75f"}, + {file = "lxml-4.6.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d"}, + {file = "lxml-4.6.3-cp27-cp27m-win32.whl", hash = "sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106"}, + {file = "lxml-4.6.3-cp27-cp27m-win_amd64.whl", hash = "sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee"}, + {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f"}, + {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4"}, + {file = "lxml-4.6.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:64812391546a18896adaa86c77c59a4998f33c24788cadc35789e55b727a37f4"}, + {file = "lxml-4.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c1a40c06fd5ba37ad39caa0b3144eb3772e813b5fb5b084198a985431c2f1e8d"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16"}, + {file = "lxml-4.6.3-cp35-cp35m-win32.whl", hash = "sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2"}, + {file = "lxml-4.6.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4"}, + {file = "lxml-4.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d916d31fd85b2f78c76400d625076d9124de3e4bda8b016d25a050cc7d603f24"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617"}, + {file = "lxml-4.6.3-cp36-cp36m-win32.whl", hash = "sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04"}, + {file = "lxml-4.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a"}, + {file = "lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:36108c73739985979bf302006527cf8a20515ce444ba916281d1c43938b8bb96"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92"}, + {file = "lxml-4.6.3-cp37-cp37m-win32.whl", hash = "sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade"}, + {file = "lxml-4.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b"}, + {file = "lxml-4.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:e1cbd3f19a61e27e011e02f9600837b921ac661f0c40560eefb366e4e4fb275e"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1b38116b6e628118dea5b2186ee6820ab138dbb1e24a13e478490c7db2f326ae"}, + {file = "lxml-4.6.3-cp38-cp38-win32.whl", hash = "sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28"}, + {file = "lxml-4.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7"}, + {file = "lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3082c518be8e97324390614dacd041bb1358c882d77108ca1957ba47738d9d59"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a"}, + {file = "lxml-4.6.3-cp39-cp39-win32.whl", hash = "sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f"}, + {file = "lxml-4.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83"}, + {file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"}, +] matplotlib = [ {file = "matplotlib-3.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c988bb43414c7c2b0a31bd5187b4d27fd625c080371b463a6d422047df78913"}, {file = "matplotlib-3.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f1c5efc278d996af8a251b2ce0b07bbeccb821f25c8c9846bdcb00ffc7f158aa"}, @@ -1401,6 +1493,10 @@ sortedcontainers = [ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] +soupsieve = [ + {file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"}, + {file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"}, +] taskipy = [ {file = "taskipy-1.8.1-py3-none-any.whl", hash = "sha256:2b98f499966e40175d1f1306a64587f49dfa41b90d0d86c8f28b067cc58d0a56"}, {file = "taskipy-1.8.1.tar.gz", hash = "sha256:7a2404125817e45d80e13fa663cae35da6e8ba590230094e815633653e25f98f"}, diff --git a/pyproject.toml b/pyproject.toml index 7848f593..08287b23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,12 +12,14 @@ aiodns = "~=2.0" aioredis = "~1.3" rapidfuzz = "~=1.4" arrow = "~=1.1.0" +beautifulsoup4 = "~=4.9" pillow = "~=8.1" sentry-sdk = "~=0.19" PyYAML = "~=5.4" async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"} emojis = "~=0.6.0" matplotlib = "~=3.4.1" +lxml = "~=4.4" [tool.poetry.dev-dependencies] flake8 = "~=3.8" -- cgit v1.2.3 From 6eecd5c251da804b38e5521ebd562aa25e6bc61d Mon Sep 17 00:00:00 2001 From: aru Date: Wed, 13 Oct 2021 20:24:20 -0400 Subject: Fix GH-907 Issues can have empty bodies, in this case GitHub doesn't include the key in the API response --- bot/exts/events/hacktoberfest/hacktober-issue-finder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py index 088e7e43..1774564b 100644 --- a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py +++ b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py @@ -100,7 +100,8 @@ class HacktoberIssues(commands.Cog): """Format the issue data into a embed.""" title = issue["title"] issue_url = issue["url"].replace("api.", "").replace("/repos/", "/") - body = issue["body"] + # issues can have empty bodies, which in that case GitHub doesn't include the key in the API response + body = issue.get("body", "") labels = [label["name"] for label in issue["labels"]] embed = discord.Embed(title=title) -- cgit v1.2.3 From f18e9c3dda721b9bbbba884e31b34e4ae2831ffc Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Thu, 14 Oct 2021 21:55:41 +0200 Subject: Add support to query AoC results in respect of days and stars (#857) * Add support to query AoC results in respect of days and stars From now on the AoC leaderboard command accepts a total of 2 optional arguments a day and star string (eg.: 1-2, for the second star of the first day) and a number of results they would like to see, with a total maximum of 15. This commit also introduces a few minor fixes in the AoC helper. * Improve overall code consitency in the AoC event Cog and helpers * Improve indenting and code consistency in the AoC cog * Improve code transparency in the AoC helpers * Patch various inconsistencies in the AoC cog and helpers * Migrate AoC Day and Star statistics filtering to Dropdowns From now on when the AoC leadearboard command is used with the DayAndStar argument(bool) the bot will send a View with two dropdowns and a button to Fetch the data based on the value of the Dropdowns. * Improve code and comment consistency in the AoC views and helpers * Patch logic errors, improve consistency in the AoC cog and view. * Add support to delete view from the message after timeout in the AoC cog * Move the day_and_star logic out of the typing context manager in the AoC cog * Revert season-locker in the AoC cog * Improve overall code transparency and indenting in the AoC cog and views * Remove unnecessary returns in the AoC cog and view --- bot/constants.py | 1 + bot/exts/events/advent_of_code/_cog.py | 45 ++++++++++++-- bot/exts/events/advent_of_code/_helpers.py | 9 ++- .../events/advent_of_code/views/dayandstarview.py | 71 ++++++++++++++++++++++ 4 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 bot/exts/events/advent_of_code/views/dayandstarview.py diff --git a/bot/constants.py b/bot/constants.py index 567daadd..0720dd20 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -88,6 +88,7 @@ class AdventOfCode: ignored_days = environ.get("AOC_IGNORED_DAYS", "").split(",") leaderboard_displayed_members = 10 leaderboard_cache_expiry_seconds = 1800 + max_day_and_star_results = 15 year = int(environ.get("AOC_YEAR", datetime.utcnow().year)) role_id = int(environ.get("AOC_ROLE_ID", 518565788744024082)) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index ca60e517..7dd967ec 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -2,6 +2,7 @@ import json import logging from datetime import datetime, timedelta from pathlib import Path +from typing import Optional import arrow import discord @@ -12,6 +13,7 @@ from bot.constants import ( AdventOfCode as AocConfig, Channels, Colours, Emojis, Month, Roles, WHITELISTED_CHANNELS, ) from bot.exts.events.advent_of_code import _helpers +from bot.exts.events.advent_of_code.views.dayandstarview import AoCDropdownView from bot.utils.decorators import InChannelCheckFailure, in_month, whitelist_override, with_role from bot.utils.extensions import invoke_help_command @@ -150,7 +152,7 @@ class AdventOfCode(commands.Cog): else: try: join_code = await _helpers.get_public_join_code(author) - except _helpers.FetchingLeaderboardFailed: + except _helpers.FetchingLeaderboardFailedError: await ctx.send(":x: Failed to get join code! Notified maintainers.") return @@ -185,14 +187,29 @@ class AdventOfCode(commands.Cog): brief="Get a snapshot of the PyDis private AoC leaderboard", ) @whitelist_override(channels=AOC_WHITELIST_RESTRICTED) - async def aoc_leaderboard(self, ctx: commands.Context) -> None: - """Get the current top scorers of the Python Discord Leaderboard.""" + async def aoc_leaderboard( + self, + ctx: commands.Context, + day_and_star: Optional[bool] = False, + maximum_scorers: Optional[int] = 10 + ) -> None: + """ + Get the current top scorers of the Python Discord Leaderboard. + + Additionally, you can provide an argument `day_and_star` (Boolean) to have the bot send a View + that will let you filter by day and star. + """ + if maximum_scorers > AocConfig.max_day_and_star_results or maximum_scorers <= 0: + raise commands.BadArgument( + f"The maximum number of results you can query is {AocConfig.max_day_and_star_results}" + ) async with ctx.typing(): try: leaderboard = await _helpers.fetch_leaderboard() - except _helpers.FetchingLeaderboardFailed: + except _helpers.FetchingLeaderboardFailedError: await ctx.send(":x: Unable to fetch leaderboard!") return + if not day_and_star: number_of_participants = leaderboard["number_of_participants"] @@ -203,6 +220,22 @@ class AdventOfCode(commands.Cog): info_embed = _helpers.get_summary_embed(leaderboard) await ctx.send(content=f"{header}\n\n{table}", embed=info_embed) + return + + # This is a dictionary that contains solvers in respect of day, and star. + # e.g. 1-1 means the solvers of the first star of the first day and their completion time + per_day_and_star = json.loads(leaderboard['leaderboard_per_day_and_star']) + view = AoCDropdownView( + day_and_star_data=per_day_and_star, + maximum_scorers=maximum_scorers, + original_author=ctx.author + ) + message = await ctx.send( + content="Please select a day and a star to filter by!", + view=view + ) + await view.wait() + await message.edit(view=None) @in_month(Month.DECEMBER) @adventofcode_group.command( @@ -231,7 +264,7 @@ class AdventOfCode(commands.Cog): """Send an embed with daily completion statistics for the Python Discord leaderboard.""" try: leaderboard = await _helpers.fetch_leaderboard() - except _helpers.FetchingLeaderboardFailed: + except _helpers.FetchingLeaderboardFailedError: await ctx.send(":x: Can't fetch leaderboard for stats right now!") return @@ -267,7 +300,7 @@ class AdventOfCode(commands.Cog): async with ctx.typing(): try: await _helpers.fetch_leaderboard(invalidate_cache=True) - except _helpers.FetchingLeaderboardFailed: + except _helpers.FetchingLeaderboardFailedError: await ctx.send(":x: Something went wrong while trying to refresh the cache!") else: await ctx.send("\N{OK Hand Sign} Refreshed leaderboard cache!") diff --git a/bot/exts/events/advent_of_code/_helpers.py b/bot/exts/events/advent_of_code/_helpers.py index 5fedb60f..af64bc81 100644 --- a/bot/exts/events/advent_of_code/_helpers.py +++ b/bot/exts/events/advent_of_code/_helpers.py @@ -105,6 +105,7 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict: # The data we get from the AoC website is structured by member, not by day/star, # which means we need to iterate over the members to transpose the data to a per # star view. We need that per star view to compute rank scores per star. + per_day_star_stats = collections.defaultdict(list) for member in raw_leaderboard_data.values(): name = member["name"] if member["name"] else f"Anonymous #{member['id']}" member_id = member["id"] @@ -122,6 +123,11 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict: star_results[(day, star)].append( StarResult(member_id=member_id, completion_time=completion_time) ) + per_day_star_stats[f"{day}-{star}"].append( + {'completion_time': int(data["get_star_ts"]), 'member_name': name} + ) + for key in per_day_star_stats: + per_day_star_stats[key] = sorted(per_day_star_stats[key], key=operator.itemgetter('completion_time')) # Now that we have a transposed dataset that holds the completion time of all # participants per star, we can compute the rank-based scores each participant @@ -151,7 +157,7 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict: # this data to JSON in order to cache it in Redis. daily_stats[day] = {"star_one": star_one, "star_two": star_two} - return {"daily_stats": daily_stats, "leaderboard": sorted_leaderboard} + return {"daily_stats": daily_stats, "leaderboard": sorted_leaderboard, 'per_day_and_star': per_day_star_stats} def _format_leaderboard(leaderboard: dict[str, dict]) -> str: @@ -289,6 +295,7 @@ async def fetch_leaderboard(invalidate_cache: bool = False) -> dict: "leaderboard_fetched_at": leaderboard_fetched_at, "number_of_participants": number_of_participants, "daily_stats": json.dumps(parsed_leaderboard_data["daily_stats"]), + "leaderboard_per_day_and_star": json.dumps(parsed_leaderboard_data["per_day_and_star"]) } # Store the new values in Redis diff --git a/bot/exts/events/advent_of_code/views/dayandstarview.py b/bot/exts/events/advent_of_code/views/dayandstarview.py new file mode 100644 index 00000000..243db32e --- /dev/null +++ b/bot/exts/events/advent_of_code/views/dayandstarview.py @@ -0,0 +1,71 @@ +from datetime import datetime + +import discord + +AOC_DAY_AND_STAR_TEMPLATE = "{rank: >4} | {name:25.25} | {completion_time: >10}" + + +class AoCDropdownView(discord.ui.View): + """Interactive view to filter AoC stats by Day and Star.""" + + def __init__(self, original_author: discord.Member, day_and_star_data: dict[str: dict], maximum_scorers: int): + super().__init__() + self.day = 0 + self.star = 0 + self.data = day_and_star_data + self.maximum_scorers = maximum_scorers + self.original_author = original_author + + def generate_output(self) -> str: + """Generates a formatted codeblock with AoC statistics based on the currently selected day and star.""" + header = AOC_DAY_AND_STAR_TEMPLATE.format( + rank="Rank", + name="Name", completion_time="Completion time (UTC)" + ) + lines = [f"{header}\n{'-' * (len(header) + 2)}"] + + for rank, scorer in enumerate(self.data[f"{self.day}-{self.star}"][:self.maximum_scorers]): + time_data = datetime.fromtimestamp(scorer['completion_time']).strftime("%I:%M:%S %p") + lines.append(AOC_DAY_AND_STAR_TEMPLATE.format( + datastamp="", + rank=rank + 1, + name=scorer['member_name'], + completion_time=time_data) + ) + joined_lines = "\n".join(lines) + return f"Statistics for Day: {self.day}, Star: {self.star}.\n ```\n{joined_lines}\n```" + + async def interaction_check(self, interaction: discord.Interaction) -> bool: + """Global check to ensure that the interacting user is the user who invoked the command originally.""" + return interaction.user == self.original_author + + @discord.ui.select( + placeholder="Day", + options=[discord.SelectOption(label=str(i)) for i in range(1, 26)], + custom_id="day_select" + ) + async def day_select(self, select: discord.ui.Select, interaction: discord.Interaction) -> None: + """Dropdown to choose a Day of the AoC.""" + self.day = select.values[0] + + @discord.ui.select( + placeholder="Star", + options=[discord.SelectOption(label=str(i)) for i in range(1, 3)], + custom_id="star_select" + ) + async def star_select(self, select: discord.ui.Select, interaction: discord.Interaction) -> None: + """Dropdown to choose either the first or the second star.""" + self.star = select.values[0] + + @discord.ui.button(label="Fetch", style=discord.ButtonStyle.blurple) + async def fetch(self, button: discord.ui.Button, interaction: discord.Interaction) -> None: + """Button that fetches the statistics based on the dropdown values.""" + if self.day == 0 or self.star == 0: + await interaction.response.send_message( + "You have to select a value from both of the dropdowns!", + ephemeral=True + ) + else: + await interaction.response.edit_message(content=self.generate_output()) + self.day = 0 + self.star = 0 -- cgit v1.2.3 From a7bb17c3e475594ac2e52a4958f382fe9d26b036 Mon Sep 17 00:00:00 2001 From: TizzySaurus <47674925+TizzySaurus@users.noreply.github.com> Date: Sun, 17 Oct 2021 12:21:09 +0100 Subject: Fix bugs in `.issue` command & add aliases - Now requires at least one issue/PR - No longer continues to send issues/PRs when there's too many listed in the invocation - Added plural aliases (`.issues` and `.prs`) --- bot/exts/utilities/issues.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/issues.py b/bot/exts/utilities/issues.py index 8a7ebed0..36655e1b 100644 --- a/bot/exts/utilities/issues.py +++ b/bot/exts/utilities/issues.py @@ -185,7 +185,7 @@ class Issues(commands.Cog): return resp @whitelist_override(channels=WHITELISTED_CHANNELS, categories=WHITELISTED_CATEGORIES) - @commands.command(aliases=("pr",)) + @commands.command(aliases=("issues", "pr", "prs")) async def issue( self, ctx: commands.Context, @@ -197,14 +197,23 @@ class Issues(commands.Cog): # Remove duplicates numbers = set(numbers) - if len(numbers) > MAXIMUM_ISSUES: - embed = discord.Embed( + err_message = None + if not numbers: + err_message = "You must have at least one issue/PR!" + + elif len(numbers) > MAXIMUM_ISSUES: + err_message = f"Too many issues/PRs! (maximum of {MAXIMUM_ISSUES})" + + # If there's an error with command invocation then send an error embed + if err_message is not None: + err_embed = discord.Embed( title=random.choice(ERROR_REPLIES), color=Colours.soft_red, - description=f"Too many issues/PRs! (maximum of {MAXIMUM_ISSUES})" + description=err_message ) - await ctx.send(embed=embed) + await ctx.send(embed=err_embed) await invoke_help_command(ctx) + return results = [await self.fetch_issues(number, repository, user) for number in numbers] await ctx.send(embed=self.format_embed(results, user, repository)) -- cgit v1.2.3 From 860c137f868ff9c91df0669a33dd9d551cbcc4a5 Mon Sep 17 00:00:00 2001 From: Izan Date: Sun, 17 Oct 2021 13:09:54 +0100 Subject: Address review & make `AI.get_move` a staticmethod --- bot/exts/fun/tic_tac_toe.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bot/exts/fun/tic_tac_toe.py b/bot/exts/fun/tic_tac_toe.py index 1ebf8d11..946b6f7b 100644 --- a/bot/exts/fun/tic_tac_toe.py +++ b/bot/exts/fun/tic_tac_toe.py @@ -72,11 +72,12 @@ class Player: class AI: """Tic Tac Toe AI class for against computer gaming.""" - def __init__(self, ctx: Context, symbol: str): - self.user = ctx.me + def __init__(self, bot_user: discord.Member, symbol: str): + self.user = bot_user self.symbol = symbol - async def get_move(self, board: dict[int, str], _: discord.Message) -> tuple[bool, int]: + @staticmethod + async def get_move(board: dict[int, str], _: discord.Message) -> tuple[bool, int]: """Get move from AI. AI use Minimax strategy.""" possible_moves = [i for i, emoji in board.items() if emoji in list(Emojis.number_emojis.values())] @@ -175,7 +176,8 @@ class Game: self.canceled = True return False, "User declined" - async def add_reactions(self, msg: discord.Message) -> None: + @staticmethod + async def add_reactions(msg: discord.Message) -> None: """Add number emojis to message.""" for nr in Emojis.number_emojis.values(): await msg.add_reaction(nr) @@ -267,7 +269,7 @@ class TicTacToe(Cog): return if opponent is None: game = Game( - [Player(ctx.author, ctx, Emojis.x_square), AI(ctx, Emojis.o_square)], + [Player(ctx.author, ctx, Emojis.x_square), AI(ctx.me, Emojis.o_square)], ctx ) else: -- cgit v1.2.3 From cbe05b4d3ce86acfd5c472295df870f9ee996f07 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sun, 17 Oct 2021 16:33:47 +0100 Subject: Add a border around the scary bat When users with dark avatars would use the spookify command, they wouldn't be able to see the bat that was added. By adding a white border around the bat, it is now more visable. --- bot/resources/holidays/halloween/bat-clipart.png | Bin 12313 -> 19006 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bot/resources/holidays/halloween/bat-clipart.png b/bot/resources/holidays/halloween/bat-clipart.png index 7df26ba9..fc2f77b0 100644 Binary files a/bot/resources/holidays/halloween/bat-clipart.png and b/bot/resources/holidays/halloween/bat-clipart.png differ -- cgit v1.2.3 From 6a52e8080ce8f4d22726dfefec3b57e3e51c62ec Mon Sep 17 00:00:00 2001 From: Karlis Suvi <45097959+ks129@users.noreply.github.com> Date: Wed, 20 Oct 2021 19:55:03 +0300 Subject: Use display_avatar instead of avatar in send_pride_image Discord.py 2.0 returns None for avatar if a user has default avatar. `display_avatar` returns always `Asset`. --- bot/exts/avatar_modification/avatar_modify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/avatar_modification/avatar_modify.py b/bot/exts/avatar_modification/avatar_modify.py index 87eb05e6..fbee96dc 100644 --- a/bot/exts/avatar_modification/avatar_modify.py +++ b/bot/exts/avatar_modification/avatar_modify.py @@ -239,7 +239,7 @@ class AvatarModify(commands.Cog): description=f"Here is your lovely avatar, surrounded by\n a beautiful {option} flag. Enjoy :D" ) embed.set_image(url=f"attachment://{file_name}") - embed.set_footer(text=f"Made by {ctx.author.display_name}.", icon_url=ctx.author.avatar.url) + embed.set_footer(text=f"Made by {ctx.author.display_name}.", icon_url=ctx.author.display_avatar.url) await ctx.send(file=file, embed=embed) @avatar_modify.group( -- cgit v1.2.3 From dde7535fc342ddf025e2049bddd9b52b80788898 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Thu, 21 Oct 2021 21:36:56 +0100 Subject: Bump pip licenses pip licenses used to use an internal method of pip, which got removed and caused errors in any runs. The newer version, which this commit bumps it too, now uses another method. --- poetry.lock | 728 ++++++++++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 405 insertions(+), 325 deletions(-) diff --git a/poetry.lock b/poetry.lock index 21373a92..cbfc90fb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -117,7 +117,7 @@ lxml = ["lxml"] [[package]] name = "certifi" -version = "2021.5.30" +version = "2021.10.8" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -125,7 +125,7 @@ python-versions = "*" [[package]] name = "cffi" -version = "1.14.6" +version = "1.15.0" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -188,10 +188,9 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] [package.source] type = "url" url = "https://github.com/Rapptz/discord.py/archive/45d498c1b76deaf3b394d17ccf56112fa691d160.zip" - [[package]] name = "distlib" -version = "0.3.2" +version = "0.3.3" description = "Distribution utilities" category = "dev" optional = false @@ -207,13 +206,14 @@ python-versions = "*" [[package]] name = "fakeredis" -version = "1.6.0" +version = "1.6.1" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false python-versions = ">=3.5" [package.dependencies] +packaging = "*" redis = "<3.6.0" six = ">=1.12" sortedcontainers = "*" @@ -224,11 +224,15 @@ lua = ["lupa"] [[package]] name = "filelock" -version = "3.0.12" +version = "3.3.1" description = "A platform independent file lock." category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" + +[package.extras] +docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] +testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] [[package]] name = "flake8" @@ -245,14 +249,14 @@ pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "flake8-annotations" -version = "2.6.2" +version = "2.7.0" description = "Flake8 Type Annotation Checks" category = "dev" optional = false -python-versions = ">=3.6.1,<4.0.0" +python-versions = ">=3.6.2,<4.0.0" [package.dependencies] -flake8 = ">=3.7,<4.0" +flake8 = ">=3.7,<5.0" [[package]] name = "flake8-bugbear" @@ -316,14 +320,14 @@ flake8 = "*" [[package]] name = "flake8-tidy-imports" -version = "4.4.1" +version = "4.5.0" description = "A flake8 plugin that helps you write tidier imports." category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -flake8 = ">=3.8.0,<4" +flake8 = ">=3.8.0,<5" [[package]] name = "flake8-todo" @@ -346,7 +350,7 @@ python-versions = ">=3.6" [[package]] name = "identify" -version = "2.2.13" +version = "2.3.0" description = "File identification library for Python" category = "dev" optional = false @@ -357,7 +361,7 @@ license = ["editdistance-s"] [[package]] name = "idna" -version = "3.2" +version = "3.3" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -419,7 +423,7 @@ python-versions = ">=3.5" [[package]] name = "multidict" -version = "5.1.0" +version = "5.2.0" description = "multidict implementation" category = "main" optional = false @@ -441,6 +445,17 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + [[package]] name = "pep8-naming" version = "0.12.1" @@ -455,7 +470,7 @@ flake8-polyfill = ">=1.0.2,<2" [[package]] name = "pillow" -version = "8.3.2" +version = "8.4.0" description = "Python Imaging Library (Fork)" category = "main" optional = false @@ -463,7 +478,7 @@ python-versions = ">=3.6" [[package]] name = "pip-licenses" -version = "3.5.2" +version = "3.5.3" description = "Dump the software license list of Python packages installed with pip." category = "dev" optional = false @@ -477,7 +492,7 @@ test = ["docutils", "pytest-cov", "pytest-pycodestyle", "pytest-runner"] [[package]] name = "platformdirs" -version = "2.3.0" +version = "2.4.0" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false @@ -524,7 +539,7 @@ python-versions = "*" [[package]] name = "pycares" -version = "4.0.0" +version = "4.1.2" description = "Python interface for c-ares" category = "main" optional = false @@ -595,11 +610,11 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "0.15.0" -description = "Add .env support to your django/flask apps in development and deployments" +version = "0.19.1" +description = "Read key-value pairs from a .env file and set them as environment variables" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.5" [package.extras] cli = ["click (>=5.0)"] @@ -614,11 +629,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] name = "rapidfuzz" -version = "1.5.1" +version = "1.8.0" description = "rapid fuzzy string matching" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=2.7" + +[package.extras] +full = ["numpy"] [[package]] name = "redis" @@ -693,7 +711,7 @@ python-versions = ">=3.6" [[package]] name = "taskipy" -version = "1.8.1" +version = "1.9.0" description = "tasks runner for python projects" category = "dev" optional = false @@ -701,7 +719,7 @@ python-versions = ">=3.6,<4.0" [package.dependencies] colorama = ">=0.4.4,<0.5.0" -mslex = ">=0.3.0,<0.4.0" +mslex = {version = ">=0.3.0,<0.4.0", markers = "sys_platform == \"win32\""} psutil = ">=5.7.2,<6.0.0" toml = ">=0.10.0,<0.11.0" @@ -723,7 +741,7 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.6" +version = "1.26.7" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -736,7 +754,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.7.2" +version = "20.8.1" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -755,7 +773,7 @@ testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", [[package]] name = "yarl" -version = "1.6.3" +version = "1.7.0" description = "Yet another URL library" category = "main" optional = false @@ -768,7 +786,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "6cced4e3fff83ad6ead9a18b3f585b83426fab34f6e2bcf2466c2ebbbf66dac4" +content-hash = "3a470d4a9b63f106bfead96094c73a865dfa3d01e8c187e43d415ea6cd83f5bf" [metadata.files] aiodns = [ @@ -843,55 +861,60 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"}, ] certifi = [ - {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, - {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] cffi = [ - {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, - {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, - {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, - {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"}, - {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"}, - {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"}, - {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"}, - {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"}, - {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, - {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, - {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, - {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, - {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, - {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, - {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, - {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, - {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, - {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, - {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, - {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, - {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, + {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, + {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, + {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, + {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, + {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, + {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, + {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, + {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, + {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, + {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, + {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, + {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, + {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, + {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, + {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, + {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, + {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, ] cfgv = [ {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, @@ -911,28 +934,28 @@ cycler = [ ] "discord.py" = [] distlib = [ - {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"}, - {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"}, + {file = "distlib-0.3.3-py2.py3-none-any.whl", hash = "sha256:c8b54e8454e5bf6237cc84c20e8264c3e991e824ef27e8f1e81049867d861e31"}, + {file = "distlib-0.3.3.zip", hash = "sha256:d982d0751ff6eaaab5e2ec8e691d949ee80eddf01a62eaa96ddb11531fe16b05"}, ] emojis = [ {file = "emojis-0.6.0-py3-none-any.whl", hash = "sha256:7da34c8a78ae262fd68cef9e2c78a3c1feb59784489eeea0f54ba1d4b7111c7c"}, {file = "emojis-0.6.0.tar.gz", hash = "sha256:bf605d1f1a27a81cd37fe82eb65781c904467f569295a541c33710b97e4225ec"}, ] fakeredis = [ - {file = "fakeredis-1.6.0-py3-none-any.whl", hash = "sha256:3449b306f3a85102b28f8180c24722ef966fcb1e3c744758b6f635ec80321a5c"}, - {file = "fakeredis-1.6.0.tar.gz", hash = "sha256:11ccfc9769d718d37e45b382e64a6ba02586b622afa0371a6bd85766d72255f3"}, + {file = "fakeredis-1.6.1-py3-none-any.whl", hash = "sha256:5eb1516f1fe1813e9da8f6c482178fc067af09f53de587ae03887ef5d9d13024"}, + {file = "fakeredis-1.6.1.tar.gz", hash = "sha256:0d06a9384fb79da9f2164ce96e34eb9d4e2ea46215070805ea6fd3c174590b47"}, ] filelock = [ - {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, - {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, + {file = "filelock-3.3.1-py3-none-any.whl", hash = "sha256:2b5eb3589e7fdda14599e7eb1a50e09b4cc14f34ed98b8ba56d33bfaafcbef2f"}, + {file = "filelock-3.3.1.tar.gz", hash = "sha256:34a9f35f95c441e7b38209775d6e0337f9a3759f3565f6c5798f19618527c76f"}, ] flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] flake8-annotations = [ - {file = "flake8-annotations-2.6.2.tar.gz", hash = "sha256:0d6cd2e770b5095f09689c9d84cc054c51b929c41a68969ea1beb4b825cac515"}, - {file = "flake8_annotations-2.6.2-py3-none-any.whl", hash = "sha256:d10c4638231f8a50c0a597c4efce42bd7b7d85df4f620a0ddaca526138936a4f"}, + {file = "flake8-annotations-2.7.0.tar.gz", hash = "sha256:52e53c05b0c06cac1c2dec192ea2c36e85081238add3bd99421d56f574b9479b"}, + {file = "flake8_annotations-2.7.0-py3-none-any.whl", hash = "sha256:3edfbbfb58e404868834fe6ec3eaf49c139f64f0701259f707d043185545151e"}, ] flake8-bugbear = [ {file = "flake8-bugbear-20.11.1.tar.gz", hash = "sha256:528020129fea2dea33a466b9d64ab650aa3e5f9ffc788b70ea4bc6cf18283538"}, @@ -955,8 +978,8 @@ flake8-string-format = [ {file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"}, ] flake8-tidy-imports = [ - {file = "flake8-tidy-imports-4.4.1.tar.gz", hash = "sha256:c18b3351b998787db071e766e318da1f0bd9d5cecc69c4022a69e7aa2efb2c51"}, - {file = "flake8_tidy_imports-4.4.1-py3-none-any.whl", hash = "sha256:631a1ba9daaedbe8bb53f6086c5a92b390e98371205259e0e311a378df8c3dc8"}, + {file = "flake8-tidy-imports-4.5.0.tar.gz", hash = "sha256:ac637961d0f319012d099e49619f8c928e3221f74e00fe6eb89513bc64c40adb"}, + {file = "flake8_tidy_imports-4.5.0-py3-none-any.whl", hash = "sha256:87eed94ae6a2fda6a5918d109746feadf1311e0eb8274ab7a7920f6db00a41c9"}, ] flake8-todo = [ {file = "flake8-todo-0.7.tar.gz", hash = "sha256:6e4c5491ff838c06fe5a771b0e95ee15fc005ca57196011011280fc834a85915"}, @@ -1005,12 +1028,12 @@ hiredis = [ {file = "hiredis-2.0.0.tar.gz", hash = "sha256:81d6d8e39695f2c37954d1011c0480ef7cf444d4e3ae24bc5e89ee5de360139a"}, ] identify = [ - {file = "identify-2.2.13-py2.py3-none-any.whl", hash = "sha256:7199679b5be13a6b40e6e19ea473e789b11b4e3b60986499b1f589ffb03c217c"}, - {file = "identify-2.2.13.tar.gz", hash = "sha256:7bc6e829392bd017236531963d2d937d66fc27cadc643ac0aba2ce9f26157c79"}, + {file = "identify-2.3.0-py2.py3-none-any.whl", hash = "sha256:d1e82c83d063571bb88087676f81261a4eae913c492dafde184067c584bc7c05"}, + {file = "identify-2.3.0.tar.gz", hash = "sha256:fd08c97f23ceee72784081f1ce5125c8f53a02d3f2716dde79a6ab8f1039fea5"}, ] idna = [ - {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, - {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] kiwisolver = [ {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1d819553730d3c2724582124aee8a03c846ec4362ded1034c16fb3ef309264e6"}, @@ -1140,43 +1163,78 @@ mslex = [ {file = "mslex-0.3.0.tar.gz", hash = "sha256:4a1ac3f25025cad78ad2fe499dd16d42759f7a3801645399cce5c404415daa97"}, ] multidict = [ - {file = "multidict-5.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224"}, - {file = "multidict-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26"}, - {file = "multidict-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6"}, - {file = "multidict-5.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37"}, - {file = "multidict-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5"}, - {file = "multidict-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632"}, - {file = "multidict-5.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea"}, - {file = "multidict-5.1.0-cp38-cp38-win32.whl", hash = "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656"}, - {file = "multidict-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3"}, - {file = "multidict-5.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda"}, - {file = "multidict-5.1.0-cp39-cp39-win32.whl", hash = "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"}, - {file = "multidict-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359"}, - {file = "multidict-5.1.0.tar.gz", hash = "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5"}, + {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3822c5894c72e3b35aae9909bef66ec83e44522faf767c0ad39e0e2de11d3b55"}, + {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:28e6d883acd8674887d7edc896b91751dc2d8e87fbdca8359591a13872799e4e"}, + {file = "multidict-5.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b61f85101ef08cbbc37846ac0e43f027f7844f3fade9b7f6dd087178caedeee7"}, + {file = "multidict-5.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9b668c065968c5979fe6b6fa6760bb6ab9aeb94b75b73c0a9c1acf6393ac3bf"}, + {file = "multidict-5.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517d75522b7b18a3385726b54a081afd425d4f41144a5399e5abd97ccafdf36b"}, + {file = "multidict-5.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1b4ac3ba7a97b35a5ccf34f41b5a8642a01d1e55454b699e5e8e7a99b5a3acf5"}, + {file = "multidict-5.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:df23c83398715b26ab09574217ca21e14694917a0c857e356fd39e1c64f8283f"}, + {file = "multidict-5.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e58a9b5cc96e014ddf93c2227cbdeca94b56a7eb77300205d6e4001805391747"}, + {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f76440e480c3b2ca7f843ff8a48dc82446b86ed4930552d736c0bac507498a52"}, + {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cfde464ca4af42a629648c0b0d79b8f295cf5b695412451716531d6916461628"}, + {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0fed465af2e0eb6357ba95795d003ac0bdb546305cc2366b1fc8f0ad67cc3fda"}, + {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:b70913cbf2e14275013be98a06ef4b412329fe7b4f83d64eb70dce8269ed1e1a"}, + {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a5635bcf1b75f0f6ef3c8a1ad07b500104a971e38d3683167b9454cb6465ac86"}, + {file = "multidict-5.2.0-cp310-cp310-win32.whl", hash = "sha256:77f0fb7200cc7dedda7a60912f2059086e29ff67cefbc58d2506638c1a9132d7"}, + {file = "multidict-5.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:9416cf11bcd73c861267e88aea71e9fcc35302b3943e45e1dbb4317f91a4b34f"}, + {file = "multidict-5.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fd77c8f3cba815aa69cb97ee2b2ef385c7c12ada9c734b0f3b32e26bb88bbf1d"}, + {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ec9aea6223adf46999f22e2c0ab6cf33f5914be604a404f658386a8f1fba37"}, + {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5283c0a00f48e8cafcecadebfa0ed1dac8b39e295c7248c44c665c16dc1138b"}, + {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5f79c19c6420962eb17c7e48878a03053b7ccd7b69f389d5831c0a4a7f1ac0a1"}, + {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e4a67f1080123de76e4e97a18d10350df6a7182e243312426d508712e99988d4"}, + {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:94b117e27efd8e08b4046c57461d5a114d26b40824995a2eb58372b94f9fca02"}, + {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2e77282fd1d677c313ffcaddfec236bf23f273c4fba7cdf198108f5940ae10f5"}, + {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:116347c63ba049c1ea56e157fa8aa6edaf5e92925c9b64f3da7769bdfa012858"}, + {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:dc3a866cf6c13d59a01878cd806f219340f3e82eed514485e094321f24900677"}, + {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ac42181292099d91217a82e3fa3ce0e0ddf3a74fd891b7c2b347a7f5aa0edded"}, + {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:f0bb0973f42ffcb5e3537548e0767079420aefd94ba990b61cf7bb8d47f4916d"}, + {file = "multidict-5.2.0-cp36-cp36m-win32.whl", hash = "sha256:ea21d4d5104b4f840b91d9dc8cbc832aba9612121eaba503e54eaab1ad140eb9"}, + {file = "multidict-5.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:e6453f3cbeb78440747096f239d282cc57a2997a16b5197c9bc839099e1633d0"}, + {file = "multidict-5.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3def943bfd5f1c47d51fd324df1e806d8da1f8e105cc7f1c76a1daf0f7e17b0"}, + {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35591729668a303a02b06e8dba0eb8140c4a1bfd4c4b3209a436a02a5ac1de11"}, + {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8cacda0b679ebc25624d5de66c705bc53dcc7c6f02a7fb0f3ca5e227d80422"}, + {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:baf1856fab8212bf35230c019cde7c641887e3fc08cadd39d32a421a30151ea3"}, + {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a43616aec0f0d53c411582c451f5d3e1123a68cc7b3475d6f7d97a626f8ff90d"}, + {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25cbd39a9029b409167aa0a20d8a17f502d43f2efebfe9e3ac019fe6796c59ac"}, + {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a2cbcfbea6dc776782a444db819c8b78afe4db597211298dd8b2222f73e9cd0"}, + {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3d2d7d1fff8e09d99354c04c3fd5b560fb04639fd45926b34e27cfdec678a704"}, + {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a37e9a68349f6abe24130846e2f1d2e38f7ddab30b81b754e5a1fde32f782b23"}, + {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:637c1896497ff19e1ee27c1c2c2ddaa9f2d134bbb5e0c52254361ea20486418d"}, + {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9815765f9dcda04921ba467957be543423e5ec6a1136135d84f2ae092c50d87b"}, + {file = "multidict-5.2.0-cp37-cp37m-win32.whl", hash = "sha256:8b911d74acdc1fe2941e59b4f1a278a330e9c34c6c8ca1ee21264c51ec9b67ef"}, + {file = "multidict-5.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:380b868f55f63d048a25931a1632818f90e4be71d2081c2338fcf656d299949a"}, + {file = "multidict-5.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e7d81ce5744757d2f05fc41896e3b2ae0458464b14b5a2c1e87a6a9d69aefaa8"}, + {file = "multidict-5.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d1d55cdf706ddc62822d394d1df53573d32a7a07d4f099470d3cb9323b721b6"}, + {file = "multidict-5.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4771d0d0ac9d9fe9e24e33bed482a13dfc1256d008d101485fe460359476065"}, + {file = "multidict-5.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da7d57ea65744d249427793c042094c4016789eb2562576fb831870f9c878d9e"}, + {file = "multidict-5.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdd68778f96216596218b4e8882944d24a634d984ee1a5a049b300377878fa7c"}, + {file = "multidict-5.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ecc99bce8ee42dcad15848c7885197d26841cb24fa2ee6e89d23b8993c871c64"}, + {file = "multidict-5.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:067150fad08e6f2dd91a650c7a49ba65085303fcc3decbd64a57dc13a2733031"}, + {file = "multidict-5.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:78c106b2b506b4d895ddc801ff509f941119394b89c9115580014127414e6c2d"}, + {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e6c4fa1ec16e01e292315ba76eb1d012c025b99d22896bd14a66628b245e3e01"}, + {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b227345e4186809d31f22087d0265655114af7cda442ecaf72246275865bebe4"}, + {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:06560fbdcf22c9387100979e65b26fba0816c162b888cb65b845d3def7a54c9b"}, + {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7878b61c867fb2df7a95e44b316f88d5a3742390c99dfba6c557a21b30180cac"}, + {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:246145bff76cc4b19310f0ad28bd0769b940c2a49fc601b86bfd150cbd72bb22"}, + {file = "multidict-5.2.0-cp38-cp38-win32.whl", hash = "sha256:c30ac9f562106cd9e8071c23949a067b10211917fdcb75b4718cf5775356a940"}, + {file = "multidict-5.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:f19001e790013ed580abfde2a4465388950728861b52f0da73e8e8a9418533c0"}, + {file = "multidict-5.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c1ff762e2ee126e6f1258650ac641e2b8e1f3d927a925aafcfde943b77a36d24"}, + {file = "multidict-5.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bd6c9c50bf2ad3f0448edaa1a3b55b2e6866ef8feca5d8dbec10ec7c94371d21"}, + {file = "multidict-5.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc66d4016f6e50ed36fb39cd287a3878ffcebfa90008535c62e0e90a7ab713ae"}, + {file = "multidict-5.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9acb76d5f3dd9421874923da2ed1e76041cb51b9337fd7f507edde1d86535d6"}, + {file = "multidict-5.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dfc924a7e946dd3c6360e50e8f750d51e3ef5395c95dc054bc9eab0f70df4f9c"}, + {file = "multidict-5.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32fdba7333eb2351fee2596b756d730d62b5827d5e1ab2f84e6cbb287cc67fe0"}, + {file = "multidict-5.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b9aad49466b8d828b96b9e3630006234879c8d3e2b0a9d99219b3121bc5cdb17"}, + {file = "multidict-5.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:93de39267c4c676c9ebb2057e98a8138bade0d806aad4d864322eee0803140a0"}, + {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f9bef5cff994ca3026fcc90680e326d1a19df9841c5e3d224076407cc21471a1"}, + {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5f841c4f14331fd1e36cbf3336ed7be2cb2a8f110ce40ea253e5573387db7621"}, + {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:38ba256ee9b310da6a1a0f013ef4e422fca30a685bcbec86a969bd520504e341"}, + {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3bc3b1621b979621cee9f7b09f024ec76ec03cc365e638126a056317470bde1b"}, + {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ee908c070020d682e9b42c8f621e8bb10c767d04416e2ebe44e37d0f44d9ad5"}, + {file = "multidict-5.2.0-cp39-cp39-win32.whl", hash = "sha256:1c7976cd1c157fa7ba5456ae5d31ccdf1479680dc9b8d8aa28afabc370df42b8"}, + {file = "multidict-5.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:c9631c642e08b9fff1c6255487e62971d8b8e821808ddd013d8ac058087591ac"}, + {file = "multidict-5.2.0.tar.gz", hash = "sha256:0dd1c93edb444b33ba2274b66f63def8a327d607c6c790772f448a53b6ea59ce"}, ] nodeenv = [ {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, @@ -1212,72 +1270,64 @@ numpy = [ {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, ] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] pep8-naming = [ {file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"}, {file = "pep8_naming-0.12.1-py2.py3-none-any.whl", hash = "sha256:4a8daeaeb33cfcde779309fc0c9c0a68a3bbe2ad8a8308b763c5068f86eb9f37"}, ] pillow = [ - {file = "Pillow-8.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, - {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, - {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, - {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, - {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550"}, - {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, - {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, - {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da"}, - {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, - {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, - {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, - {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b"}, - {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, - {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, - {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, - {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441"}, - {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, - {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, - {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, + {file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"}, + {file = "Pillow-8.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f"}, + {file = "Pillow-8.4.0-cp310-cp310-win32.whl", hash = "sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a"}, + {file = "Pillow-8.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39"}, + {file = "Pillow-8.4.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645"}, + {file = "Pillow-8.4.0-cp36-cp36m-win32.whl", hash = "sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9"}, + {file = "Pillow-8.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff"}, + {file = "Pillow-8.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488"}, + {file = "Pillow-8.4.0-cp37-cp37m-win32.whl", hash = "sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b"}, + {file = "Pillow-8.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b"}, + {file = "Pillow-8.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49"}, + {file = "Pillow-8.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df"}, + {file = "Pillow-8.4.0-cp38-cp38-win32.whl", hash = "sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09"}, + {file = "Pillow-8.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76"}, + {file = "Pillow-8.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a"}, + {file = "Pillow-8.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed"}, + {file = "Pillow-8.4.0-cp39-cp39-win32.whl", hash = "sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02"}, + {file = "Pillow-8.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc"}, + {file = "Pillow-8.4.0.tar.gz", hash = "sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed"}, ] pip-licenses = [ - {file = "pip-licenses-3.5.2.tar.gz", hash = "sha256:c5e984f461b34ad04dafa151d0048eb9d049e3d6439966c6440bb6b53ad077b6"}, - {file = "pip_licenses-3.5.2-py3-none-any.whl", hash = "sha256:62deafc82d5dccea1a4cab55172706e02f228abcd67f4d53e382fcb1497e9b62"}, + {file = "pip-licenses-3.5.3.tar.gz", hash = "sha256:f44860e00957b791c6c6005a3328f2d5eaeee96ddb8e7d87d4b0aa25b02252e4"}, + {file = "pip_licenses-3.5.3-py3-none-any.whl", hash = "sha256:59c148d6a03784bf945d232c0dc0e9de4272a3675acaa0361ad7712398ca86ba"}, ] platformdirs = [ - {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, - {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, + {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, + {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, ] pre-commit = [ {file = "pre_commit-2.15.0-py2.py3-none-any.whl", hash = "sha256:a4ed01000afcb484d9eb8d504272e642c4c4099bbad3a6b27e519bd6a3e928a6"}, @@ -1317,39 +1367,37 @@ ptable = [ {file = "PTable-0.9.2.tar.gz", hash = "sha256:aa7fc151cb40f2dabcd2275ba6f7fd0ff8577a86be3365cd3fb297cbe09cc292"}, ] pycares = [ - {file = "pycares-4.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:db5a533111a3cfd481e7e4fb2bf8bef69f4fa100339803e0504dd5aecafb96a5"}, - {file = "pycares-4.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fdff88393c25016f417770d82678423fc7a56995abb2df3d2a1e55725db6977d"}, - {file = "pycares-4.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0aa97f900a7ffb259be77d640006585e2a907b0cd4edeee0e85cf16605995d5a"}, - {file = "pycares-4.0.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:a34b0e3e693dceb60b8a1169668d606c75cb100ceba0a2df53c234a0eb067fbc"}, - {file = "pycares-4.0.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7661d6bbd51a337e7373cb356efa8be9b4655fda484e068f9455e939aec8d54e"}, - {file = "pycares-4.0.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:57315b8eb8fdbc56b3ad4932bc4b17132bb7c7fd2bd590f7fb84b6b522098aa9"}, - {file = "pycares-4.0.0-cp36-cp36m-win32.whl", hash = "sha256:dca9dc58845a9d083f302732a3130c68ded845ad5d463865d464e53c75a3dd45"}, - {file = "pycares-4.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c95c964d5dd307e104b44b193095c67bb6b10c9eda1ffe7d44ab7a9e84c476d9"}, - {file = "pycares-4.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26e67e4f81c80a5955dcf6193f3d9bee3c491fc0056299b383b84d792252fba4"}, - {file = "pycares-4.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cd3011ffd5e1ad55880f7256791dbab9c43ebeda260474a968f19cd0319e1aef"}, - {file = "pycares-4.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1b959dd5921d207d759d421eece1b60416df33a7f862465739d5f2c363c2f523"}, - {file = "pycares-4.0.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6f258c1b74c048a9501a25f732f11b401564005e5e3c18f1ca6cad0c3dc0fb19"}, - {file = "pycares-4.0.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:b17ef48729786e62b574c6431f675f4cb02b27691b49e7428a605a50cd59c072"}, - {file = "pycares-4.0.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:82b3259cb590ddd107a6d2dc52da2a2e9a986bf242e893d58c786af2f8191047"}, - {file = "pycares-4.0.0-cp37-cp37m-win32.whl", hash = "sha256:4876fc790ae32832ae270c4a010a1a77e12ddf8d8e6ad70ad0b0a9d506c985f7"}, - {file = "pycares-4.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f60c04c5561b1ddf85ca4e626943cc09d7fb684e1adb22abb632095415a40fd7"}, - {file = "pycares-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:615406013cdcd1b445e5d1a551d276c6200b3abe77e534f8a7f7e1551208d14f"}, - {file = "pycares-4.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6580aef5d1b29a88c3d72fe73c691eacfd454f86e74d3fdd18f4bad8e8def98b"}, - {file = "pycares-4.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8ebb3ba0485f66cae8eed7ce3e9ed6f2c0bfd5e7319d5d0fbbb511064f17e1d4"}, - {file = "pycares-4.0.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c5362b7690ca481440f6b98395ac6df06aa50518ccb183c560464d1e5e2ab5d4"}, - {file = "pycares-4.0.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:eb60be66accc9a9ea1018b591a1f5800cba83491d07e9acc8c56bc6e6607ab54"}, - {file = "pycares-4.0.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:44896d6e191a6b5a914dbe3aa7c748481bf6ad19a9df33c1e76f8f2dc33fc8f0"}, - {file = "pycares-4.0.0-cp38-cp38-win32.whl", hash = "sha256:09b28fc7bc2cc05f7f69bf1636ddf46086e0a1837b62961e2092fcb40477320d"}, - {file = "pycares-4.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4a5081e232c1d181883dcac4675807f3a6cf33911c4173fbea00c0523687ed4"}, - {file = "pycares-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:103353577a6266a53e71bfee4cf83825f1401fefa60f0fb8bdec35f13be6a5f2"}, - {file = "pycares-4.0.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ad6caf580ee69806fc6534be93ddbb6e99bf94296d79ab351c37b2992b17abfd"}, - {file = "pycares-4.0.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3d5e50c95849f6905d2a9dbf02ed03f82580173e3c5604a39e2ad054185631f1"}, - {file = "pycares-4.0.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:53bc4f181b19576499b02cea4b45391e8dcbe30abd4cd01492f66bfc15615a13"}, - {file = "pycares-4.0.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:d52f9c725d2a826d5ffa37681eb07ffb996bfe21788590ef257664a3898fc0b5"}, - {file = "pycares-4.0.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3c7fb8d34ee11971c39acfaf98d0fac66725385ccef3bfe1b174c92b210e1aa4"}, - {file = "pycares-4.0.0-cp39-cp39-win32.whl", hash = "sha256:e9773e07684a55f54657df05237267611a77b294ec3bacb5f851c4ffca38a465"}, - {file = "pycares-4.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:38e54037f36c149146ff15f17a4a963fbdd0f9871d4a21cd94ff9f368140f57e"}, - {file = "pycares-4.0.0.tar.gz", hash = "sha256:d0154fc5753b088758fbec9bc137e1b24bb84fc0c6a09725c8bac25a342311cd"}, + {file = "pycares-4.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:71b99b9e041ae3356b859822c511f286f84c8889ec9ed1fbf6ac30fb4da13e4c"}, + {file = "pycares-4.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c000942f5fc64e6e046aa61aa53b629b576ba11607d108909727c3c8f211a157"}, + {file = "pycares-4.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b0e50ddc78252f2e2b6b5f2c73e5b2449dfb6bea7a5a0e21dfd1e2bcc9e17382"}, + {file = "pycares-4.1.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6831e963a910b0a8cbdd2750ffcdf5f2bb0edb3f53ca69ff18484de2cc3807c4"}, + {file = "pycares-4.1.2-cp310-cp310-win32.whl", hash = "sha256:ad7b28e1b6bc68edd3d678373fa3af84e39d287090434f25055d21b4716b2fc6"}, + {file = "pycares-4.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:27a6f09dbfb69bb79609724c0f90dfaa7c215876a7cd9f12d585574d1f922112"}, + {file = "pycares-4.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e5a060f5fa90ae245aa99a4a8ad13ec39c2340400de037c7e8d27b081e1a3c64"}, + {file = "pycares-4.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:056330275dea42b7199494047a745e1d9785d39fb8c4cd469dca043532240b80"}, + {file = "pycares-4.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0aa897543a786daba74ec5e19638bd38b2b432d179a0e248eac1e62de5756207"}, + {file = "pycares-4.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cbceaa9b2c416aa931627466d3240aecfc905c292c842252e3d77b8630072505"}, + {file = "pycares-4.1.2-cp36-cp36m-win32.whl", hash = "sha256:112e1385c451069112d6b5ea1f9c378544f3c6b89882ff964e9a64be3336d7e4"}, + {file = "pycares-4.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:c6680f7fdc0f1163e8f6c2a11d11b9a0b524a61000d2a71f9ccd410f154fb171"}, + {file = "pycares-4.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58a41a2baabcd95266db776c510d349d417919407f03510fc87ac7488730d913"}, + {file = "pycares-4.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a810d01c9a426ee8b0f36969c2aef5fb966712be9d7e466920beb328cd9cefa3"}, + {file = "pycares-4.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b266cec81dcea2c3efbbd3dda00af8d7eb0693ae9e47e8706518334b21f27d4a"}, + {file = "pycares-4.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8319afe4838e09df267c421ca93da408f770b945ec6217dda72f1f6a493e37e4"}, + {file = "pycares-4.1.2-cp37-cp37m-win32.whl", hash = "sha256:4d5da840aa0d9b15fa51107f09270c563a348cb77b14ae9653d0bbdbe326fcc2"}, + {file = "pycares-4.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5632f21d92cc0225ba5ff906e4e5dec415ef0b3df322c461d138190681cd5d89"}, + {file = "pycares-4.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8fd1ff17a26bb004f0f6bb902ba7dddd810059096ae0cc3b45e4f5be46315d19"}, + {file = "pycares-4.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:439799be4b7576e907139a7f9b3c8a01b90d3e38af4af9cd1fc6c1ee9a42b9e6"}, + {file = "pycares-4.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:40079ed58efa91747c50aac4edf8ecc7e570132ab57dc0a4030eb0d016a6cab8"}, + {file = "pycares-4.1.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e190471a015f8225fa38069617192e06122771cce2b169ac7a60bfdbd3d4ab2"}, + {file = "pycares-4.1.2-cp38-cp38-win32.whl", hash = "sha256:2b837315ed08c7df009b67725fe1f50489e99de9089f58ec1b243dc612f172aa"}, + {file = "pycares-4.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:c7eba3c8354b730a54d23237d0b6445a2f68570fa68d0848887da23a3f3b71f3"}, + {file = "pycares-4.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2f5f84fe9f83eab9cd68544b165b74ba6e3412d029cc9ab20098d9c332869fc5"}, + {file = "pycares-4.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569eef8597b5e02b1bc4644b9f272160304d8c9985357d7ecfcd054da97c0771"}, + {file = "pycares-4.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e1489aa25d14dbf7176110ead937c01176ed5a0ebefd3b092bbd6b202241814c"}, + {file = "pycares-4.1.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dc942692fca0e27081b7bb414bb971d34609c80df5e953f6d0c62ecc8019acd9"}, + {file = "pycares-4.1.2-cp39-cp39-win32.whl", hash = "sha256:ed71dc4290d9c3353945965604ef1f6a4de631733e9819a7ebc747220b27e641"}, + {file = "pycares-4.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:ec00f3594ee775665167b1a1630edceefb1b1283af9ac57480dba2fb6fd6c360"}, + {file = "pycares-4.1.2.tar.gz", hash = "sha256:03490be0e7b51a0c8073f877bec347eff31003f64f57d9518d419d9369452837"}, ] pycodestyle = [ {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, @@ -1376,8 +1424,8 @@ python-dateutil = [ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] python-dotenv = [ - {file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"}, - {file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"}, + {file = "python-dotenv-0.19.1.tar.gz", hash = "sha256:14f8185cc8d494662683e6914addcb7e95374771e707601dfc70166946b4c4b8"}, + {file = "python_dotenv-0.19.1-py2.py3-none-any.whl", hash = "sha256:bbd3da593fc49c249397cbfbcc449cf36cb02e75afc8157fcc6a81df6fb7750a"}, ] pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, @@ -1411,67 +1459,64 @@ pyyaml = [ {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] rapidfuzz = [ - {file = "rapidfuzz-1.5.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:6a951ad31ef121bacf40bbe6fbd387740d5038400ec2bfb41d037e9fd2754ef5"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:b64acce4f6e745417218fc0bb6ff31b26fac0d723506b82ee4b9cad448b85ebb"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a834061e6d4dfb9672e89e28583486f60821796cf0d7cc559643a0d597ce33a9"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:50548b919bc7608f7b9b4780415ddad135cfc3a54135bdb4bd0bb7ff2cdf9fdf"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:c39c7f200eef49f4f9d6b808950709334e6f1c22262d570f1f77d6d3d373ad81"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:347973ddf12d66d4d06daf1aca3a096a1bffe12306bcf13b832bdfc8db6d9f4a"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:e6cd6717d87d02dde2088c080b0851bdba970b77085b68e213a7b786dee4be88"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:ba956add4c34da019fb5e8f5e1768604b05569dd68055382795ad9062b9ca55e"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-win32.whl", hash = "sha256:95164076d8e0433f9f93e218270f19e3020a3a9b8db28a3d74143810d4243600"}, - {file = "rapidfuzz-1.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:274878c59440d6ad3efca833da61594836306af7dcdd914cc1b6ceb2d4cea23b"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3b3df0c1a307a64273f6fd64c0f28218e002768eda1d94b9fffdab9371e38a6a"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:55472932a8bcf008855b2cc8e5bc47d60066b504ef02dbf8d8fd43ddd8f20a6e"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:170e71f2ec36a086ce5d2667331721cc9b779370d0ef7248ef6979819cd8fb09"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:00734857b412afc35b29f0ea2f1d9ee26ff93d4cd3fa5f47bb90f6aef385f2a1"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ef0cf038c910a3ed626a3224effde8eb49dd7dcda87af59fcd37bc63b78a9bd1"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9f454f79bc463e3de08c5d5c0f438fce1b1736cd4da1a1f47f72dc37da156552"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:05e8dede642af1b38ebcf8fb5e9bbfdcdf8debba660ae1aafb5c1b0e6ca3e4de"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:f08773adb7f21e1f530bad2c6ababaf472f80283650bc265a7e8f614480cd49c"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-win32.whl", hash = "sha256:4e1a7fb18d4a6c3d471a3ad8f820f179216de61bef74663342340cf9c685a31e"}, - {file = "rapidfuzz-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:09e992579c4aae59310e44db99ed848a8437ed1e8810a513d3bbab7ac7a8f215"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e2cd05869bd50f25b6d384e0cc73f8cfd6ebb8f1e7bdf1315384e21611f091"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b173f8d4c9360b8b32b5ab7a669623f239cb85013e1749bdca03e1b3c297faa7"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6ab75111e2216a48c7e01d47d8903fc2d0c1df398e7262a6df544d86812e40c7"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:eb560622d9970eb0c615d5dff26af8a8647ba541a89a927fca1eb0862898f997"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:59246615b819e4aff685aa57359f5bbaf02441cccc83e8899608037542a3fe36"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:7a960dfedcf1acdb8435b5b00aebfc2ee8fd53b7b4f7acf613915b4c24fc0ef7"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:3d727a7e09f1a01b61452c86d687d0564bad923d5d209224549ae790408d6449"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:eb5e43dbef900367b91fb73a4c447efde034656b25b397844c8cf622dae84ac3"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-win32.whl", hash = "sha256:03ea226734cca3f86bc402fc04b8a38b795795e99dbf02dd834845b80bcf7588"}, - {file = "rapidfuzz-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5e9beeb6643d663c410ad8ccf88eafbe59ba7aa9b34eea5b51c6312976789803"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0d3cdb6ced024ed1567ba0be4b0909b17f691bd6e9e9f29626e4953ecf7cba9e"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c06f98bb94fbad9b773c38a3e2cf28a315466b41f862917ba4d228052bcc0966"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7bf51eb2ff342c4a0d77ab22b3d7de461ef9d2c480fd863c57fb139e7578fa7b"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:6b0c74f60c03eed4b5d19f866df79c1d1bffc4c61f9bf31b114402c47680997f"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:bbba42e244a0ebc1639c62ab44e4a172767d3721d2af48f2764ca00de7721479"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0b9f76f47b6df8c6aaa02a27fdff52e6aaf64d39296683ed06d0ec9acf2515d2"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:c52ce4b4bfe8e0c2cf102f7b71cca00fc3228113e71712597940c9c340ae31b1"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:0d3ae040c91f500814df6557276462c0c869b16168ef51d01c8a7da150f54513"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-win32.whl", hash = "sha256:112ecc4825c5d362298d1e3c512d3f942c1a74f26ca69dc4b19a4f2cd95cb764"}, - {file = "rapidfuzz-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:b1feec7407df54045bc9d4dce3431ce20855c1ff4dd170480fbace62164f8f9c"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8b352fe56b92bd2aa4ceae550543a923996c16efecf8f981c955dd5f522d2002"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9454f46bc4007be9148f18143bb1b615a740a99737a38cf7b9baf3c495d5d17c"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c1a75c87a2f4c9709c6e3ecdbb2317f0964ac96f845f6a331d8a437a2944d24"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:02f8b282a940cb749b1c51196baab7abb5590fcc8c065ce540c5d8414366036d"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2def32a4228a717c5e6a699f0742546aee4091eb1e59e79781ceacabfc54452c"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2e9d494ff51b942ed1504f84c13476319c89fc9bcc6379cc0816b776a7994199"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:e94a6af7f0cc8ff49ab22842af255d8d927ca3b168b1a7e8e0784f1a2f49bc38"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c4ee8b9baaf46447dcaed925ad1d3606d3a375dfc5c67d1f3e33c46a3008cb5a"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:10e236b3ce5851f584bbf178e7fb04ae5d0fbb008f3bc580ef6185bbbb346cd1"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:068404913619182739fa3fde3079c17e3402744a1117df7f60055db331095a01"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-win32.whl", hash = "sha256:e933e3ce2d88b7584248493abcba2cd27240f42bf73ca040babfd1ce8036750e"}, - {file = "rapidfuzz-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:46f5931f7441e13574d0fe33e897212d00ff63f69c0db1d449afbc5e87bafd7f"}, - {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7fb25ee0340cc26dad0bb4a97019bf61b4cefaec67a1be64ac9dac2f98c697cd"}, - {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:e738ec4e680bebe4442befda5cdd18020c3721d4cd75f9bfe2fb94e78ef55618"}, - {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:cb083609923bc4ac602e6f1d61be61a25b35cccfb5ee208d2aa89eb0be357c69"}, - {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:08ecef2995b6ed1187b375d8f28ba4557522f098a1515b6afb0e3b452997a3a4"}, - {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b6ff10d856fce55e2b1c681e4e7cd7da9b9eb6854571df60d6ed8904c777e64b"}, - {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-manylinux1_x86_64.whl", hash = "sha256:b41c346f16cd1ee71b259106d3cfad3347bd8fff4ff20f334a12738df6736c01"}, - {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:f7148a53a0fd3466b82b81d94ad91aee7ce7947f37f16f9fb54319ea7df7f4af"}, - {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-win32.whl", hash = "sha256:31d83af9ac39f47f47ce4830ee118e6fa53964cccd8161e9a478a326f2a994cf"}, - {file = "rapidfuzz-1.5.1.tar.gz", hash = "sha256:4ebbd071425ee812548c301c60661a4f8faa5e5bcc97a6f0bef5b562585a8025"}, + {file = "rapidfuzz-1.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:91f094562c683802e6c972bce27a692dad70d6cd1114e626b29d990c3704c653"}, + {file = "rapidfuzz-1.8.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:4a20682121e245cf5ad2dbdd771360763ea11b77520632a1034c4bb9ad1e854c"}, + {file = "rapidfuzz-1.8.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8810e75d8f9c4453bbd6209c372bf97514359b0b5efff555caf85b15f8a9d862"}, + {file = "rapidfuzz-1.8.0-cp27-cp27m-win32.whl", hash = "sha256:00cf713d843735b5958d87294f08b05c653a593ced7c4120be34f5d26d7a320a"}, + {file = "rapidfuzz-1.8.0-cp27-cp27m-win_amd64.whl", hash = "sha256:2baca64e23a623e077f57e5470de21af2765af15aa1088676eb2d475e664eed0"}, + {file = "rapidfuzz-1.8.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:9bf7a6c61bacedd84023be356e057e1d209dd6997cfaa3c1cee77aa21d642f88"}, + {file = "rapidfuzz-1.8.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:61b6434e3341ca5158ecb371b1ceb4c1f6110563a72d28bdce4eb2a084493e47"}, + {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e425e690383f6cf308e8c2e8d630fa9596f67d233344efd8fae11e70a9f5635f"}, + {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:93db5e693b76d616b09df27ca5c79e0dda169af7f1b8f5ab3262826d981e37e2"}, + {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a8c4f76ed1c8a65892d98dc2913027c9acdb219d18f3a441cfa427a32861af9"}, + {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71e217fd30901214cc96c0c15057278bafb7072aa9b2be4c97459c1fedf3e731"}, + {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d579dd447b8e851462e79054b68f94b66b09df8b3abb2aa5ca07fe00912ef5e8"}, + {file = "rapidfuzz-1.8.0-cp310-cp310-win32.whl", hash = "sha256:5808064555273496dcd594d659bd28ee8d399149dd31575321034424455dc955"}, + {file = "rapidfuzz-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:798fef1671ca66c78b47802228e9583f7ab32b99bdfe3984ebb1f96e93e38b5f"}, + {file = "rapidfuzz-1.8.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:c9e0ed210831f5c73533bf11099ea7897db491e76c3443bef281d9c1c67d7f3a"}, + {file = "rapidfuzz-1.8.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:c819bb19eb615a31ddc9cb8248a285bf04f58158b53ce096451178631f99b652"}, + {file = "rapidfuzz-1.8.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:942ee45564f28ef70320d1229f02dc998bd93e3519c1f3a80f33ce144b51039c"}, + {file = "rapidfuzz-1.8.0-cp35-cp35m-win32.whl", hash = "sha256:7e6ae2e5a3bc9acc51e118f25d32b8efcd431c5d8deb408336dd2ed0f21d087c"}, + {file = "rapidfuzz-1.8.0-cp35-cp35m-win_amd64.whl", hash = "sha256:98901fba67c89ad2506f3946642cf6eb8f489592fb7eb307ebdf8bdb0c4e97f9"}, + {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e1686f406a0c77ef323cdb7369b7cf9e68f2abfcb83ff5f1e0a5b21f5a534"}, + {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da0c5fe5fdbbd74206c1778af6b8c5ff8dfbe2dd04ae12bbe96642b358acefce"}, + {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:535253bc9224215131ae450aad6c9f7ef1b24f15c685045eab2b52511268bd06"}, + {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acdad83f07d886705fce164b0d1f4e3b56788a205602ed3a7fc8b10ceaf05fbf"}, + {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35097f649831f8375d6c65a237deccac3aceb573aa7fae1e5d3fa942e89de1c8"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6f4db142e5b4b44314166a90e11603220db659bd2f9c23dd5db402c13eac8eb7"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19a3f55f27411d68360540484874beda0b428b062596d5f0f141663ef0738bfd"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22b4c1a7f6fe29bd8dae49f7d5ab085dc42c3964f1a78b6dca22fdf83b5c9bfa"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8bfb2fbc147904b78d5c510ee75dc8704b606e956df23f33a9e89abc03f45c3"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6dc5111ebfed2c4f2e4d120a9b280ea13ea4fbb60b6915dd239817b4fc092ed"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db5ee2457d97cb967ffe08446a8c595c03fe747fdc2e145266713f9c516d1c4a"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-win32.whl", hash = "sha256:12c1b78cc15fc26f555a4bf66088d5afb6354b5a5aa149a123f01a15af6c411b"}, + {file = "rapidfuzz-1.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:693e9579048d8db4ff020715dd6f25aa315fd6445bc94e7400d7a94a227dad27"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b4fe19df3edcf7de359448b872aec08e6592b4ca2d3df4d8ee57b5812d68bebf"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3670b9df0e1f479637cad1577afca7766a02775dc08c14837cf495c82861d7c"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:61d118f36eb942649b0db344f7b7a19ad7e9b5749d831788187eb03b57ce1bfa"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fce3a2c8a1d10da12aff4a0d367624e8ae9e15c1b84a5144843681d39be0c355"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1577ef26e3647ccc4cc9754c34ffaa731639779f4d7779e91a761c72adac093e"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fec9b7e60fde51990c3b48fc1aa9dba9ac3acaf78f623dbb645a6fe21a9654e"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b954469d93858bc8b48129bc63fd644382a4df5f3fb1b4b290f48eac1d00a2da"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:190ba709069a7e5a6b39b7c8bc413a08cfa7f1f4defec5d974c4128b510e0234"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-win32.whl", hash = "sha256:97b2d13d6323649b43d1b113681e4013ba230bd6e9827cc832dcebee447d7250"}, + {file = "rapidfuzz-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:81c3091209b75f6611efe2af18834180946d4ce28f41ca8d44fce816187840d2"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d610afa33e92aa0481a514ffda3ec51ca5df3c684c1c1c795307589c62025931"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d976f33ca6b5fabbb095c0a662f5b86baf706184fc24c7f125d4ddb54b8bf036"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0f5ca7bca2af598d4ddcf5b93b64b50654a9ff684e6f18d865f6e13fee442b3e"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2aac5ea6b0306dcd28a6d1a89d35ed2c6ac426f2673ee1b92cf3f1d0fd5cd"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f145c9831c0454a696a3136a6380ea4e01434e9cc2f2bc10d032864c16d1d0e5"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4ce53291575b56c9d45add73ea013f43bafcea55eee9d5139aa759918d7685f"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de5773a39c00a0f23cfc5da9e0e5fd0fb512b0ebe23dc7289a38e1f9a4b5cefc"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87a802e55792bfbe192e2d557f38867dbe3671b49b3d5ecd873859c7460746ba"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-win32.whl", hash = "sha256:9391abf1121df831316222f28cea37397a0f72bd7978f3be6e7da29a7821e4e5"}, + {file = "rapidfuzz-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:9eeca1b436042b5523dcf314f5822b1131597898c1d967f140d1917541a8a3d1"}, + {file = "rapidfuzz-1.8.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:a01f2495aca479b49d3b3a8863d6ba9bea2043447a1ced74ae5ec5270059cbc1"}, + {file = "rapidfuzz-1.8.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:b7d4b1a5d16817f8cdb34365c7b58ae22d5cf1b3207720bb2fa0b55968bdb034"}, + {file = "rapidfuzz-1.8.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c738d0d7f1744646d48d19b4c775926082bcefebd2460f45ca383a0e882f5672"}, + {file = "rapidfuzz-1.8.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fb9c6078c17c12b52e66b7d0a2a1674f6bbbdc6a76e454c8479b95147018123"}, + {file = "rapidfuzz-1.8.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1482b385d83670eb069577c9667f72b41eec4f005aee32f1a4ff4e71e88afde2"}, + {file = "rapidfuzz-1.8.0.tar.gz", hash = "sha256:83fff37acf0367314879231264169dcbc5e7de969a94f4b82055d06a7fddab9a"}, ] redis = [ {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, @@ -1498,8 +1543,8 @@ soupsieve = [ {file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"}, ] taskipy = [ - {file = "taskipy-1.8.1-py3-none-any.whl", hash = "sha256:2b98f499966e40175d1f1306a64587f49dfa41b90d0d86c8f28b067cc58d0a56"}, - {file = "taskipy-1.8.1.tar.gz", hash = "sha256:7a2404125817e45d80e13fa663cae35da6e8ba590230094e815633653e25f98f"}, + {file = "taskipy-1.9.0-py3-none-any.whl", hash = "sha256:02bd2c51c7356ed3f7f8853210ada1cd2ab273e68359ee865021c3057eec6615"}, + {file = "taskipy-1.9.0.tar.gz", hash = "sha256:449c160b557cdb1d9c17097a5ea4aa0cd5223723ddbaaa5d5032dd16274fb8f0"}, ] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, @@ -1511,49 +1556,84 @@ typing-extensions = [ {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] urllib3 = [ - {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, - {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, ] virtualenv = [ - {file = "virtualenv-20.7.2-py2.py3-none-any.whl", hash = "sha256:e4670891b3a03eb071748c569a87cceaefbf643c5bac46d996c5a45c34aa0f06"}, - {file = "virtualenv-20.7.2.tar.gz", hash = "sha256:9ef4e8ee4710826e98ff3075c9a4739e2cb1040de6a2a8d35db0055840dc96a0"}, + {file = "virtualenv-20.8.1-py2.py3-none-any.whl", hash = "sha256:10062e34c204b5e4ec5f62e6ef2473f8ba76513a9a617e873f1f8fb4a519d300"}, + {file = "virtualenv-20.8.1.tar.gz", hash = "sha256:bcc17f0b3a29670dd777d6f0755a4c04f28815395bca279cdcb213b97199a6b8"}, ] yarl = [ - {file = "yarl-1.6.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366"}, - {file = "yarl-1.6.3-cp36-cp36m-win32.whl", hash = "sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721"}, - {file = "yarl-1.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643"}, - {file = "yarl-1.6.3-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970"}, - {file = "yarl-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e"}, - {file = "yarl-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50"}, - {file = "yarl-1.6.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2"}, - {file = "yarl-1.6.3-cp38-cp38-win32.whl", hash = "sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896"}, - {file = "yarl-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a"}, - {file = "yarl-1.6.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4"}, - {file = "yarl-1.6.3-cp39-cp39-win32.whl", hash = "sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424"}, - {file = "yarl-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6"}, - {file = "yarl-1.6.3.tar.gz", hash = "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10"}, + {file = "yarl-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e35d8230e4b08d86ea65c32450533b906a8267a87b873f2954adeaecede85169"}, + {file = "yarl-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eb4b3f277880c314e47720b4b6bb2c85114ab3c04c5442c9bc7006b3787904d8"}, + {file = "yarl-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7015dcedb91d90a138eebdc7e432aec8966e0147ab2a55f2df27b1904fa7291"}, + {file = "yarl-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb3e478175e15e00d659fb0354a6a8db71a7811a2a5052aed98048bc972e5d2b"}, + {file = "yarl-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8c409aa3a7966647e7c1c524846b362a6bcbbe120bf8a176431f940d2b9a2e"}, + {file = "yarl-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b22ea41c7e98170474a01e3eded1377d46b2dfaef45888a0005c683eaaa49285"}, + {file = "yarl-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a7dfc46add4cfe5578013dbc4127893edc69fe19132d2836ff2f6e49edc5ecd6"}, + {file = "yarl-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:82ff6f85f67500a4f74885d81659cd270eb24dfe692fe44e622b8a2fd57e7279"}, + {file = "yarl-1.7.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f3cd2158b2ed0fb25c6811adfdcc47224efe075f2d68a750071dacc03a7a66e4"}, + {file = "yarl-1.7.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:59c0f13f9592820c51280d1cf811294d753e4a18baf90f0139d1dc93d4b6fc5f"}, + {file = "yarl-1.7.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7f7655ad83d1a8afa48435a449bf2f3009293da1604f5dd95b5ddcf5f673bd69"}, + {file = "yarl-1.7.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aa9f0d9b62d15182341b3e9816582f46182cab91c1a57b2d308b9a3c4e2c4f78"}, + {file = "yarl-1.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fdd1b90c225a653b1bd1c0cae8edf1957892b9a09c8bf7ee6321eeb8208eac0f"}, + {file = "yarl-1.7.0-cp310-cp310-win32.whl", hash = "sha256:7c8d0bb76eabc5299db203e952ec55f8f4c53f08e0df4285aac8c92bd9e12675"}, + {file = "yarl-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:622a36fa779efb4ff9eff5fe52730ff17521431379851a31e040958fc251670c"}, + {file = "yarl-1.7.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d461b7a8e139b9e4b41f62eb417ffa0b98d1c46d4caf14c845e6a3b349c0bb1"}, + {file = "yarl-1.7.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81cfacdd1e40bc931b5519499342efa388d24d262c30a3d31187bfa04f4a7001"}, + {file = "yarl-1.7.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:821b978f2152be7695d4331ef0621d207aedf9bbd591ba23a63412a3efc29a01"}, + {file = "yarl-1.7.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b64bd24c8c9a487f4a12260dc26732bf41028816dbf0c458f17864fbebdb3131"}, + {file = "yarl-1.7.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:98c9ddb92b60a83c21be42c776d3d9d5ec632a762a094c41bda37b7dfbd2cd83"}, + {file = "yarl-1.7.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a532d75ca74431c053a88a802e161fb3d651b8bf5821a3440bc3616e38754583"}, + {file = "yarl-1.7.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:053e09817eafb892e94e172d05406c1b3a22a93bc68f6eff5198363a3d764459"}, + {file = "yarl-1.7.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:98c51f02d542945d306c8e934aa2c1e66ba5e9c1c86b5bf37f3a51c8a747067e"}, + {file = "yarl-1.7.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:15ec41a5a5fdb7bace6d7b16701f9440007a82734f69127c0fbf6d87e10f4a1e"}, + {file = "yarl-1.7.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:a7f08819dba1e1255d6991ed37448a1bf4b1352c004bcd899b9da0c47958513d"}, + {file = "yarl-1.7.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8e3ffab21db0542ffd1887f3b9575ddd58961f2cf61429cb6458afc00c4581e0"}, + {file = "yarl-1.7.0-cp36-cp36m-win32.whl", hash = "sha256:50127634f519b2956005891507e3aa4ac345f66a7ea7bbc2d7dcba7401f41898"}, + {file = "yarl-1.7.0-cp36-cp36m-win_amd64.whl", hash = "sha256:36ec44f15193f6d5288d42ebb8e751b967ebdfb72d6830983838d45ab18edb4f"}, + {file = "yarl-1.7.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ec1b5a25a25c880c976d0bb3d107def085bb08dbb3db7f4442e0a2b980359d24"}, + {file = "yarl-1.7.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b36f5a63c891f813c6f04ef19675b382efc190fd5ce7e10ab19386d2548bca06"}, + {file = "yarl-1.7.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38173b8c3a29945e7ecade9a3f6ff39581eee8201338ee6a2c8882db5df3e806"}, + {file = "yarl-1.7.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ba402f32184f0b405fb281b93bd0d8ab7e3257735b57b62a6ed2e94cdf4fe50"}, + {file = "yarl-1.7.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:be52bc5208d767cdd8308a9e93059b3b36d1e048fecbea0e0346d0d24a76adc0"}, + {file = "yarl-1.7.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:08c2044a956f4ef30405f2f433ce77f1f57c2c773bf81ae43201917831044d5a"}, + {file = "yarl-1.7.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:484d61c047c45670ef5967653a1d0783e232c54bf9dd786a7737036828fa8d54"}, + {file = "yarl-1.7.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b7de92a4af85cfcaf4081f8aa6165b1d63ee5de150af3ee85f954145f93105a7"}, + {file = "yarl-1.7.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:376e41775aab79c5575534924a386c8e0f1a5d91db69fc6133fd27a489bcaf10"}, + {file = "yarl-1.7.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:8a8b10d0e7bac154f959b709fcea593cda527b234119311eb950096653816a86"}, + {file = "yarl-1.7.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f46cd4c43e6175030e2a56def8f1d83b64e6706eeb2bb9ab0ef4756f65eab23f"}, + {file = "yarl-1.7.0-cp37-cp37m-win32.whl", hash = "sha256:b28cfb46140efe1a6092b8c5c4994a1fe70dc83c38fbcea4992401e0c6fb9cce"}, + {file = "yarl-1.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9624154ec9c02a776802da1086eed7f5034bd1971977f5146233869c2ac80297"}, + {file = "yarl-1.7.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:69945d13e1bbf81784a9bc48824feb9cd66491e6a503d4e83f6cd7c7cc861361"}, + {file = "yarl-1.7.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:46a742ed9e363bd01be64160ce7520e92e11989bd4cb224403cfd31c101cc83d"}, + {file = "yarl-1.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb4ff1ac7cb4500f43581b3f4cbd627d702143aa6be1fdc1fa3ebffaf4dc1be5"}, + {file = "yarl-1.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ad51e17cd65ea3debb0e10f0120cf8dd987c741fe423ed2285087368090b33d"}, + {file = "yarl-1.7.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e37786ea89a5d3ffbbf318ea9790926f8dfda83858544f128553c347ad143c6"}, + {file = "yarl-1.7.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c63c1e208f800daad71715786bfeb1cecdc595d87e2e9b1cd234fd6e597fd71d"}, + {file = "yarl-1.7.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91cbe24300c11835ef186436363352b3257db7af165e0a767f4f17aa25761388"}, + {file = "yarl-1.7.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e510dbec7c59d32eaa61ffa48173d5e3d7170a67f4a03e8f5e2e9e3971aca622"}, + {file = "yarl-1.7.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3def6e681cc02397e5d8141ee97b41d02932b2bcf0fb34532ad62855eab7c60e"}, + {file = "yarl-1.7.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:263c81b94e6431942b27f6f671fa62f430a0a5c14bb255f2ab69eeb9b2b66ff7"}, + {file = "yarl-1.7.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e78c91faefe88d601ddd16e3882918dbde20577a2438e2320f8239c8b7507b8f"}, + {file = "yarl-1.7.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:22b2430c49713bfb2f0a0dd4a8d7aab218b28476ba86fd1c78ad8899462cbcf2"}, + {file = "yarl-1.7.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2e7ad9db939082f5d0b9269cfd92c025cb8f2fbbb1f1b9dc5a393c639db5bd92"}, + {file = "yarl-1.7.0-cp38-cp38-win32.whl", hash = "sha256:3a31e4a8dcb1beaf167b7e7af61b88cb961b220db8d3ba1c839723630e57eef7"}, + {file = "yarl-1.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:d579957439933d752358c6a300c93110f84aae67b63dd0c19dde6ecbf4056f6b"}, + {file = "yarl-1.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:87721b549505a546eb003252185103b5ec8147de6d3ad3714d148a5a67b6fe53"}, + {file = "yarl-1.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1fa866fa24d9f4108f9e58ea8a2135655419885cdb443e36b39a346e1181532"}, + {file = "yarl-1.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d3b8449dfedfe94eaff2b77954258b09b24949f6818dfa444b05dbb05ae1b7e"}, + {file = "yarl-1.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db2372e350794ce8b9f810feb094c606b7e0e4aa6807141ac4fadfe5ddd75bb0"}, + {file = "yarl-1.7.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a06d9d0b9a97fa99b84fee71d9dd11e69e21ac8a27229089f07b5e5e50e8d63c"}, + {file = "yarl-1.7.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3455c2456d6307bcfa80bc1157b8603f7d93573291f5bdc7144489ca0df4628"}, + {file = "yarl-1.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d30d67e3486aea61bb2cbf7cf81385364c2e4f7ce7469a76ed72af76a5cdfe6b"}, + {file = "yarl-1.7.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c18a4b286e8d780c3a40c31d7b79836aa93b720f71d5743f20c08b7e049ca073"}, + {file = "yarl-1.7.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d54c925396e7891666cabc0199366ca55b27d003393465acef63fd29b8b7aa92"}, + {file = "yarl-1.7.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:64773840952de17851a1c7346ad7f71688c77e74248d1f0bc230e96680f84028"}, + {file = "yarl-1.7.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:acbf1756d9dc7cd0ae943d883be72e84e04396f6c2ff93a6ddeca929d562039f"}, + {file = "yarl-1.7.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:2e48f27936aa838939c798f466c851ba4ae79e347e8dfce43b009c64b930df12"}, + {file = "yarl-1.7.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1beef4734ca1ad40a9d8c6b20a76ab46e3a2ed09f38561f01e4aa2ea82cafcef"}, + {file = "yarl-1.7.0-cp39-cp39-win32.whl", hash = "sha256:8ee78c9a5f3c642219d4607680a4693b59239c27a3aa608b64ef79ddc9698039"}, + {file = "yarl-1.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:d750503682605088a14d29a4701548c15c510da4f13c8b17409c4097d5b04c52"}, + {file = "yarl-1.7.0.tar.gz", hash = "sha256:8e7ebaf62e19c2feb097ffb7c94deb0f0c9fab52590784c8cd679d30ab009162"}, ] diff --git a/pyproject.toml b/pyproject.toml index 08287b23..88a974ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ flake8-string-format = "~=0.3" flake8-tidy-imports = "~=4.1" flake8-todo = "~=0.7" pep8-naming = "~=0.11" -pip-licenses = "~=3.5.2" +pip-licenses = "~=3.5" pre-commit = "~=2.1" python-dotenv = "~=0.15" taskipy = "~=1.6" -- cgit v1.2.3 From 93f8385fcaa543b7deb69e7c7740cd148be6297c Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 21 Oct 2021 22:29:54 -0400 Subject: Add WTF Python Command (#859) * Add WTF Python Command * Fix grammar in docstrings, remove redundant variable, remove the use of a wrapper * Fix indentation issues and make use of triple quotes * Update docstrings and remove redundant list() * Change minimum certainty to 75. * Make 'make_embed' function a non async function * Try to unload WTFPython Extension if max fetch requests hit i.e. 3 else try to load the extension. * Correct log messages. * Make flake8 happy :D * Remove redundant class attributes and async functions. * Apply requested grammar and style changes. * Fix unload and load extension logic. * Fix typo in `WTF_PYTHON_RAW_URL` * Changed fuzzy_wuzzy to rapidfuzz Since rapidfuzz also has an extractOne method, this should be a straight replacement with the import statement. * Move wtf_python.py to bot/exts/utilities, flake8 Moved the file to the correct location after merge with main, made changes from the last open suggestions from the previous PR, had to make WTF lowercase to pass flake8 on lines 54 and 118. * Fix trailing commas and long lines * # This is a combination of 3 commits. # This is the 1st commit message: Squashing small commits Small changes and fixes -Added "the" to setup docstring -Fixed typo for mis-matched WTF and wtf in get_wtf_python_readme -Fixed ext location -Added more information to fuzzy_match_header docstring regarding the MINIMUM_CERTAINTY and what the score / value represents. Add wildcard to capture unused return Updated MINIMUM_CERTAINTY to 75 Change MINIMUM_CERTAINTY to 50 Squash commits from Bluenix suggestions Fix docstring for fuzzy_match_header Swap if / else for match Fix functools import Rename get_wtf_python_readme to fetch_readme Collapse self.headers into one line Fix docstring for fuzzy_match_header Swap if / else for match # This is the commit message #2: Fix functools import # This is the commit message #3: Rename get_wtf_python_readme to fetch_readme * Squashing commits Squashing small commits Small changes and fixes -Added "the" to setup docstring -Fixed typo for mis-matched WTF and wtf in get_wtf_python_readme -Fixed ext location -Added more information to fuzzy_match_header docstring regarding the MINIMUM_CERTAINTY and what the score / value represents. Add wildcard to capture unused return Updated MINIMUM_CERTAINTY to 75 Change MINIMUM_CERTAINTY to 50 Squash commits from Bluenix suggestions Fix docstring for fuzzy_match_header Swap if / else for match Fix functools import Rename get_wtf_python_readme to fetch_readme Collapse self.headers into one line Fix docstring for fuzzy_match_header Swap if / else for match Fix functools import Rename get_wtf_python_readme to fetch_readme Collapse self.headers into one line Fix type hints with dict Add match comment for clarity * Add debug logs, and send embed * Add markdown file creation Big change here is to create a .md file based on the matched header. I save the raw text as a class attribute, then slice it based on the index returned by the .find() method for the header, and the separator "/n---/n". * Move the list(map(str.strip , ...) to for loop * Remove line * Use StringIO for file creation * Update file creation with StringIO * Remove embed file preview * chore: update wtf_python docstring * chore: change regex to search, remove file preview * feat: update caching as recommended Minor fixes to import statements as well. Co-authored-by: Bluenix2 * chore: remove logging statements * feat: scheduled task for fetch_readme * chore: fix hyperlink, remove dead code * fix: capitalization clean up * chore: remove unused code * chore: remove more unused code * feat: add light grey logo image in embed * feat: add light grey image * chore: remove debug log message * feat: add found search result header * feat: limit user query to 50 characters * cleanup: remove debug logging * fix: restructure if not match statement Co-authored-by: Bluenix Co-authored-by: Shivansh-007 Co-authored-by: Shivansh-007 Co-authored-by: Bluenix2 Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/utilities/wtf_python.py | 126 ++++++++++++++++++++++++++++ bot/resources/utilities/wtf_python_logo.jpg | Bin 0 -> 19481 bytes 2 files changed, 126 insertions(+) create mode 100644 bot/exts/utilities/wtf_python.py create mode 100644 bot/resources/utilities/wtf_python_logo.jpg diff --git a/bot/exts/utilities/wtf_python.py b/bot/exts/utilities/wtf_python.py new file mode 100644 index 00000000..66a022d7 --- /dev/null +++ b/bot/exts/utilities/wtf_python.py @@ -0,0 +1,126 @@ +import logging +import random +import re +from typing import Optional + +import rapidfuzz +from discord import Embed, File +from discord.ext import commands, tasks + +from bot import constants +from bot.bot import Bot + +log = logging.getLogger(__name__) + +WTF_PYTHON_RAW_URL = "http://raw.githubusercontent.com/satwikkansal/wtfpython/master/" +BASE_URL = "https://github.com/satwikkansal/wtfpython" +LOGO_PATH = "./bot/resources/utilities/wtf_python_logo.jpg" + +ERROR_MESSAGE = f""" +Unknown WTF Python Query. Please try to reformulate your query. + +**Examples**: +```md +{constants.Client.prefix}wtf wild imports +{constants.Client.prefix}wtf subclass +{constants.Client.prefix}wtf del +``` +If the problem persists send a message in <#{constants.Channels.dev_contrib}> +""" + +MINIMUM_CERTAINTY = 55 + + +class WTFPython(commands.Cog): + """Cog that allows getting WTF Python entries from the WTF Python repository.""" + + def __init__(self, bot: Bot): + self.bot = bot + self.headers: dict[str, str] = {} + self.fetch_readme.start() + + @tasks.loop(minutes=60) + async def fetch_readme(self) -> None: + """Gets the content of README.md from the WTF Python Repository.""" + async with self.bot.http_session.get(f"{WTF_PYTHON_RAW_URL}README.md") as resp: + log.trace("Fetching the latest WTF Python README.md") + if resp.status == 200: + raw = await resp.text() + self.parse_readme(raw) + + def parse_readme(self, data: str) -> None: + """ + Parses the README.md into a dict. + + It parses the readme into the `self.headers` dict, + where the key is the heading and the value is the + link to the heading. + """ + # Match the start of examples, until the end of the table of contents (toc) + table_of_contents = re.search( + r"\[👀 Examples\]\(#-examples\)\n([\w\W]*)", data + )[0].split("\n") + + for header in list(map(str.strip, table_of_contents)): + match = re.search(r"\[▶ (.*)\]\((.*)\)", header) + if match: + hyper_link = match[0].split("(")[1].replace(")", "") + self.headers[match[0]] = f"{BASE_URL}/{hyper_link}" + + def fuzzy_match_header(self, query: str) -> Optional[str]: + """ + Returns the fuzzy match of a query if its ratio is above "MINIMUM_CERTAINTY" else returns None. + + "MINIMUM_CERTAINTY" is the lowest score at which the fuzzy match will return a result. + The certainty returned by rapidfuzz.process.extractOne is a score between 0 and 100, + with 100 being a perfect match. + """ + match, certainty, _ = rapidfuzz.process.extractOne(query, self.headers.keys()) + return match if certainty > MINIMUM_CERTAINTY else None + + @commands.command(aliases=("wtf", "WTF")) + async def wtf_python(self, ctx: commands.Context, *, query: str) -> None: + """ + Search WTF Python repository. + + Gets the link of the fuzzy matched query from https://github.com/satwikkansal/wtfpython. + Usage: + --> .wtf wild imports + """ + if len(query) > 50: + embed = Embed( + title=random.choice(constants.ERROR_REPLIES), + description=ERROR_MESSAGE, + colour=constants.Colours.soft_red, + ) + match = None + else: + match = self.fuzzy_match_header(query) + + if not match: + embed = Embed( + title=random.choice(constants.ERROR_REPLIES), + description=ERROR_MESSAGE, + colour=constants.Colours.soft_red, + ) + await ctx.send(embed=embed) + return + + embed = Embed( + title="WTF Python?!", + colour=constants.Colours.dark_green, + description=f"""Search result for '{query}': {match.split("]")[0].replace("[", "")} + [Go to Repository Section]({self.headers[match]})""", + ) + logo = File(LOGO_PATH, filename="wtf_logo.jpg") + embed.set_thumbnail(url="attachment://wtf_logo.jpg") + await ctx.send(embed=embed, file=logo) + + def cog_unload(self) -> None: + """Unload the cog and cancel the task.""" + self.fetch_readme.cancel() + + +def setup(bot: Bot) -> None: + """Load the WTFPython Cog.""" + bot.add_cog(WTFPython(bot)) diff --git a/bot/resources/utilities/wtf_python_logo.jpg b/bot/resources/utilities/wtf_python_logo.jpg new file mode 100644 index 00000000..851d7f9a Binary files /dev/null and b/bot/resources/utilities/wtf_python_logo.jpg differ -- cgit v1.2.3 From 817c5769a16081f9ddb2d88b9ed36ea18661b289 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Fri, 22 Oct 2021 07:23:34 +0000 Subject: Add ISort to our toolchain --- poetry.lock | 174 +++++++++++++++++++++++++++++++++++---------------------- pyproject.toml | 12 +++- 2 files changed, 118 insertions(+), 68 deletions(-) diff --git a/poetry.lock b/poetry.lock index cbfc90fb..8a4091f1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -286,15 +286,20 @@ flake8 = ">=3" pydocstyle = ">=2.1" [[package]] -name = "flake8-import-order" -version = "0.18.1" -description = "Flake8 and pylama plugin that checks the ordering of import statements." +name = "flake8-isort" +version = "4.1.1" +description = "flake8 plugin that integrates isort ." category = "dev" optional = false python-versions = "*" [package.dependencies] -pycodestyle = "*" +flake8 = ">=3.2.1,<5" +isort = ">=4.3.5,<6" +testfixtures = ">=6.8.0,<7" + +[package.extras] +test = ["pytest-cov"] [[package]] name = "flake8-polyfill" @@ -367,6 +372,20 @@ category = "main" optional = false python-versions = ">=3.5" +[[package]] +name = "isort" +version = "5.9.3" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.6.1,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] + [[package]] name = "kiwisolver" version = "1.3.2" @@ -629,7 +648,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] name = "rapidfuzz" -version = "1.8.0" +version = "1.8.1" description = "rapid fuzzy string matching" category = "main" optional = false @@ -723,6 +742,19 @@ mslex = {version = ">=0.3.0,<0.4.0", markers = "sys_platform == \"win32\""} psutil = ">=5.7.2,<6.0.0" toml = ">=0.10.0,<0.11.0" +[[package]] +name = "testfixtures" +version = "6.18.3" +description = "A collection of helpers and mock objects for unit tests and doc tests." +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +build = ["setuptools-git", "wheel", "twine"] +docs = ["sphinx", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"] +test = ["pytest (>=3.6)", "pytest-cov", "pytest-django", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"] + [[package]] name = "toml" version = "0.10.2" @@ -786,7 +818,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "3a470d4a9b63f106bfead96094c73a865dfa3d01e8c187e43d415ea6cd83f5bf" +content-hash = "ff67b082d7226e0098fb00a7cefb457da9067d0a5d9ade708e26c8c8362bd5bf" [metadata.files] aiodns = [ @@ -965,9 +997,9 @@ flake8-docstrings = [ {file = "flake8-docstrings-1.6.0.tar.gz", hash = "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"}, {file = "flake8_docstrings-1.6.0-py2.py3-none-any.whl", hash = "sha256:99cac583d6c7e32dd28bbfbef120a7c0d1b6dde4adb5a9fd441c4227a6534bde"}, ] -flake8-import-order = [ - {file = "flake8-import-order-0.18.1.tar.gz", hash = "sha256:a28dc39545ea4606c1ac3c24e9d05c849c6e5444a50fb7e9cdd430fc94de6e92"}, - {file = "flake8_import_order-0.18.1-py2.py3-none-any.whl", hash = "sha256:90a80e46886259b9c396b578d75c749801a41ee969a235e163cfe1be7afd2543"}, +flake8-isort = [ + {file = "flake8-isort-4.1.1.tar.gz", hash = "sha256:d814304ab70e6e58859bc5c3e221e2e6e71c958e7005239202fee19c24f82717"}, + {file = "flake8_isort-4.1.1-py3-none-any.whl", hash = "sha256:c4e8b6dcb7be9b71a02e6e5d4196cefcef0f3447be51e82730fb336fff164949"}, ] flake8-polyfill = [ {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, @@ -1035,6 +1067,10 @@ idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] +isort = [ + {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, + {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, +] kiwisolver = [ {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1d819553730d3c2724582124aee8a03c846ec4362ded1034c16fb3ef309264e6"}, {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d93a1095f83e908fc253f2fb569c2711414c0bfd451cab580466465b235b470"}, @@ -1459,64 +1495,64 @@ pyyaml = [ {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] rapidfuzz = [ - {file = "rapidfuzz-1.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:91f094562c683802e6c972bce27a692dad70d6cd1114e626b29d990c3704c653"}, - {file = "rapidfuzz-1.8.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:4a20682121e245cf5ad2dbdd771360763ea11b77520632a1034c4bb9ad1e854c"}, - {file = "rapidfuzz-1.8.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8810e75d8f9c4453bbd6209c372bf97514359b0b5efff555caf85b15f8a9d862"}, - {file = "rapidfuzz-1.8.0-cp27-cp27m-win32.whl", hash = "sha256:00cf713d843735b5958d87294f08b05c653a593ced7c4120be34f5d26d7a320a"}, - {file = "rapidfuzz-1.8.0-cp27-cp27m-win_amd64.whl", hash = "sha256:2baca64e23a623e077f57e5470de21af2765af15aa1088676eb2d475e664eed0"}, - {file = "rapidfuzz-1.8.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:9bf7a6c61bacedd84023be356e057e1d209dd6997cfaa3c1cee77aa21d642f88"}, - {file = "rapidfuzz-1.8.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:61b6434e3341ca5158ecb371b1ceb4c1f6110563a72d28bdce4eb2a084493e47"}, - {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e425e690383f6cf308e8c2e8d630fa9596f67d233344efd8fae11e70a9f5635f"}, - {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:93db5e693b76d616b09df27ca5c79e0dda169af7f1b8f5ab3262826d981e37e2"}, - {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a8c4f76ed1c8a65892d98dc2913027c9acdb219d18f3a441cfa427a32861af9"}, - {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71e217fd30901214cc96c0c15057278bafb7072aa9b2be4c97459c1fedf3e731"}, - {file = "rapidfuzz-1.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d579dd447b8e851462e79054b68f94b66b09df8b3abb2aa5ca07fe00912ef5e8"}, - {file = "rapidfuzz-1.8.0-cp310-cp310-win32.whl", hash = "sha256:5808064555273496dcd594d659bd28ee8d399149dd31575321034424455dc955"}, - {file = "rapidfuzz-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:798fef1671ca66c78b47802228e9583f7ab32b99bdfe3984ebb1f96e93e38b5f"}, - {file = "rapidfuzz-1.8.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:c9e0ed210831f5c73533bf11099ea7897db491e76c3443bef281d9c1c67d7f3a"}, - {file = "rapidfuzz-1.8.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:c819bb19eb615a31ddc9cb8248a285bf04f58158b53ce096451178631f99b652"}, - {file = "rapidfuzz-1.8.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:942ee45564f28ef70320d1229f02dc998bd93e3519c1f3a80f33ce144b51039c"}, - {file = "rapidfuzz-1.8.0-cp35-cp35m-win32.whl", hash = "sha256:7e6ae2e5a3bc9acc51e118f25d32b8efcd431c5d8deb408336dd2ed0f21d087c"}, - {file = "rapidfuzz-1.8.0-cp35-cp35m-win_amd64.whl", hash = "sha256:98901fba67c89ad2506f3946642cf6eb8f489592fb7eb307ebdf8bdb0c4e97f9"}, - {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e1686f406a0c77ef323cdb7369b7cf9e68f2abfcb83ff5f1e0a5b21f5a534"}, - {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da0c5fe5fdbbd74206c1778af6b8c5ff8dfbe2dd04ae12bbe96642b358acefce"}, - {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:535253bc9224215131ae450aad6c9f7ef1b24f15c685045eab2b52511268bd06"}, - {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acdad83f07d886705fce164b0d1f4e3b56788a205602ed3a7fc8b10ceaf05fbf"}, - {file = "rapidfuzz-1.8.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35097f649831f8375d6c65a237deccac3aceb573aa7fae1e5d3fa942e89de1c8"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6f4db142e5b4b44314166a90e11603220db659bd2f9c23dd5db402c13eac8eb7"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19a3f55f27411d68360540484874beda0b428b062596d5f0f141663ef0738bfd"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22b4c1a7f6fe29bd8dae49f7d5ab085dc42c3964f1a78b6dca22fdf83b5c9bfa"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8bfb2fbc147904b78d5c510ee75dc8704b606e956df23f33a9e89abc03f45c3"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6dc5111ebfed2c4f2e4d120a9b280ea13ea4fbb60b6915dd239817b4fc092ed"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db5ee2457d97cb967ffe08446a8c595c03fe747fdc2e145266713f9c516d1c4a"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-win32.whl", hash = "sha256:12c1b78cc15fc26f555a4bf66088d5afb6354b5a5aa149a123f01a15af6c411b"}, - {file = "rapidfuzz-1.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:693e9579048d8db4ff020715dd6f25aa315fd6445bc94e7400d7a94a227dad27"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b4fe19df3edcf7de359448b872aec08e6592b4ca2d3df4d8ee57b5812d68bebf"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3670b9df0e1f479637cad1577afca7766a02775dc08c14837cf495c82861d7c"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:61d118f36eb942649b0db344f7b7a19ad7e9b5749d831788187eb03b57ce1bfa"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fce3a2c8a1d10da12aff4a0d367624e8ae9e15c1b84a5144843681d39be0c355"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1577ef26e3647ccc4cc9754c34ffaa731639779f4d7779e91a761c72adac093e"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fec9b7e60fde51990c3b48fc1aa9dba9ac3acaf78f623dbb645a6fe21a9654e"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b954469d93858bc8b48129bc63fd644382a4df5f3fb1b4b290f48eac1d00a2da"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:190ba709069a7e5a6b39b7c8bc413a08cfa7f1f4defec5d974c4128b510e0234"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-win32.whl", hash = "sha256:97b2d13d6323649b43d1b113681e4013ba230bd6e9827cc832dcebee447d7250"}, - {file = "rapidfuzz-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:81c3091209b75f6611efe2af18834180946d4ce28f41ca8d44fce816187840d2"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d610afa33e92aa0481a514ffda3ec51ca5df3c684c1c1c795307589c62025931"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d976f33ca6b5fabbb095c0a662f5b86baf706184fc24c7f125d4ddb54b8bf036"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0f5ca7bca2af598d4ddcf5b93b64b50654a9ff684e6f18d865f6e13fee442b3e"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2aac5ea6b0306dcd28a6d1a89d35ed2c6ac426f2673ee1b92cf3f1d0fd5cd"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f145c9831c0454a696a3136a6380ea4e01434e9cc2f2bc10d032864c16d1d0e5"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4ce53291575b56c9d45add73ea013f43bafcea55eee9d5139aa759918d7685f"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de5773a39c00a0f23cfc5da9e0e5fd0fb512b0ebe23dc7289a38e1f9a4b5cefc"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87a802e55792bfbe192e2d557f38867dbe3671b49b3d5ecd873859c7460746ba"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-win32.whl", hash = "sha256:9391abf1121df831316222f28cea37397a0f72bd7978f3be6e7da29a7821e4e5"}, - {file = "rapidfuzz-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:9eeca1b436042b5523dcf314f5822b1131597898c1d967f140d1917541a8a3d1"}, - {file = "rapidfuzz-1.8.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:a01f2495aca479b49d3b3a8863d6ba9bea2043447a1ced74ae5ec5270059cbc1"}, - {file = "rapidfuzz-1.8.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:b7d4b1a5d16817f8cdb34365c7b58ae22d5cf1b3207720bb2fa0b55968bdb034"}, - {file = "rapidfuzz-1.8.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c738d0d7f1744646d48d19b4c775926082bcefebd2460f45ca383a0e882f5672"}, - {file = "rapidfuzz-1.8.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fb9c6078c17c12b52e66b7d0a2a1674f6bbbdc6a76e454c8479b95147018123"}, - {file = "rapidfuzz-1.8.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1482b385d83670eb069577c9667f72b41eec4f005aee32f1a4ff4e71e88afde2"}, - {file = "rapidfuzz-1.8.0.tar.gz", hash = "sha256:83fff37acf0367314879231264169dcbc5e7de969a94f4b82055d06a7fddab9a"}, + {file = "rapidfuzz-1.8.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:7a6c6b161221eb535b2a8fbd74a2c9ef779384d644a2c7a9390957704b80119c"}, + {file = "rapidfuzz-1.8.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:52e936b7fe14808c3d080e0aa91ba6694d2ebb4e723d612e4952f380a13abb2b"}, + {file = "rapidfuzz-1.8.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:edb70e94edbac04d98cbf5524c3ffb0da40fb8d2a32d4cecb24f1bd73341f79f"}, + {file = "rapidfuzz-1.8.1-cp27-cp27m-win32.whl", hash = "sha256:f48c459d549ff0242da832d5f94c8d518532d96e4d9ce8093447c7ad6bc63cf4"}, + {file = "rapidfuzz-1.8.1-cp27-cp27m-win_amd64.whl", hash = "sha256:b1b728846f23b91e5de36bfe851df81006041ca40c70a24feced730e59e67f6d"}, + {file = "rapidfuzz-1.8.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:983c04e8ed2a34d5ad8a9b70ea0bbbfdefe5b5ca27feb616ee0457e52b7b2f1d"}, + {file = "rapidfuzz-1.8.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:04f41f1a55d3d9ff93c0b02b9213b43e04c80863b3be85402e6239be68518656"}, + {file = "rapidfuzz-1.8.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d07ef42555c595d1e8581b6e981ad82d6e9e2a1b09c20ae00f17f70b87e38c50"}, + {file = "rapidfuzz-1.8.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c6420645e40307cd770f8fe9ed9008f5537da887ba808433ec8cb460641513ad"}, + {file = "rapidfuzz-1.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dc7569eeca5cea5dad14bf1878985a892b27c499746f6d0f9cb259ab8084525"}, + {file = "rapidfuzz-1.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e90e243aece81636e6f24b3e7762148c15bcafe5f320bc860fa6e122dc449a7b"}, + {file = "rapidfuzz-1.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f4d5abde7b9ef9aaa84005d9a0d8337d46c17c5938223de9c5bcb5a20ac3bad"}, + {file = "rapidfuzz-1.8.1-cp310-cp310-win32.whl", hash = "sha256:b6ce46f65574acef77882c47ff9810376b3dc431fed95f28439b4b1d4bb7f9d3"}, + {file = "rapidfuzz-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:684fafdd5229e95f6bc26517566ddea971fcb3f0b8bceb94d35b3d4d7adc508a"}, + {file = "rapidfuzz-1.8.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:c092d998e57286a347ffd548368152aece2336fdd7620d433bf3b32fa516ed67"}, + {file = "rapidfuzz-1.8.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e82bf3ce820a9fb883157bd2fc291be564422def2845d7b09e9347ed43b91a1f"}, + {file = "rapidfuzz-1.8.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4a6831adbf463dfb6a2395bf4e2c606aa6653caaf6a9f5cfde782971f3296605"}, + {file = "rapidfuzz-1.8.1-cp35-cp35m-win32.whl", hash = "sha256:11a0523742feb9af88d7cb252432e55abbfcdd8548bcef0e9012d6cab71a615b"}, + {file = "rapidfuzz-1.8.1-cp35-cp35m-win_amd64.whl", hash = "sha256:2aab8a168e10134ba7f6851aa4a207a3ac8f3a00e4ccadb87548527fda18bd16"}, + {file = "rapidfuzz-1.8.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a47ec7cd79e2b31c36d724693e836f6d2a75beae2218cf0c5f6c330e64e41295"}, + {file = "rapidfuzz-1.8.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c01c71d88e60355f22b1a199f7622204aff149313bfc5985d1d197bdbf1cc19d"}, + {file = "rapidfuzz-1.8.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4920daef40beb9ad372b76179a023562b660cd760172aa175866972d860629"}, + {file = "rapidfuzz-1.8.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cc17dad5227b85312b8ac58544597df914c030d22a76f113877f2ca0715b401"}, + {file = "rapidfuzz-1.8.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e80ba975f1d2cf9c85341c09e29c95f164502eac828398563f8f0269157103b"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d2bac1d343a707e2090c9737e6d5d49e780a43d3541132d96338e42a83524b6d"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4df8b3b1e322eac4af0894b100591078a707c4dd9bf6d0cb6360fd74f012bcfd"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f31db70318ff494171f6a95f9a8f2b1542c1ae4b11aee7e7cff9bd5c7f076706"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bd95454a2a13c18b39a61ac8b8475f24aaf474c48448115bd81c67f7e421c18"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ac47023c4e9aa61984557602f0beea53a623fe32edd2d799294812596f74798"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef91bd5a865f237b9ec28d1db06e41bc81ef7dd468569653b34c93717dabbbde"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-win32.whl", hash = "sha256:19560fc6b025a1ccb9d22e2cac597201fc6979eaffeb39cea9ef171c4e9ae48a"}, + {file = "rapidfuzz-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08572f743e89d3bb5ad56839a046bc7b23ae225356fdf9a1b4798d8ed7e15d69"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:02a309a1fb103e8db6bf212884777ec22bf9fbcba1413854aa88ecd91bc61a99"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:30ba1aca03c300b8c05e0e259fda540ced6bffa22202a8c6d1128f7120df5ee0"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:31dbe267927ad82694d117bd66b56f73ed1e3c34cf50b10429446f331e57086c"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:25e96435b1099dc9d14c5d73ea2b8341090d4315148d204d8b276c24deca46a4"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:59910b0a00ccbf33252563b67e7c71fdff707d4f1b7533e392131e8cf287f341"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257fbb5b5e237c2d43a4c7e6a12b2828b690fe54e98d38d48e33e3acbc5a959a"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55af7a8c39f3da0f3a77c2ad1674851d63aeb24df379bf3acc745fd764c3bb08"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f9b5650ceb3f5b4ef6a43d5de4e47e121c29537a3eda4e35edaa2347567670c"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-win32.whl", hash = "sha256:508c028d7ab70ea202122b9a41b5393ec4b492877c6cac42a7b23e7bd06abeff"}, + {file = "rapidfuzz-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e824de20f05dc6392e5d6171bca046db27f1b6d6882b7c7aa4a692a088c97cf7"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5a275a625168db7c728f46ab3be3cf7faa5d822567552caec491acb7b577c9d0"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3389f0543c23647511afc87c935933ffc41c9f9c373425946d0b1ab10d9f7ad"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d18277c390b548aa282bea5cccf82cce6de621d3b477c46e6bb26678b9745697"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d78ad5f8bd6b0d514e50a0f92e3db52ce5d3852fdb167c434589a291b26cabb"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef601cc99b8ae7fd242f212fae3e411f6407bef8a8d47376963c0069ee1408c5"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2275b8ad68c55a4e897710cde26693b4ab502f678ccf78056e1b3c1a4f6bdf60"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:316ddc3ee3b6e6a02281c66b1553dabe75de05febed613ad3341fd513bf4710e"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc3609ab10d451fd4d8599b06096b75e1a98ac5be90e94d716f1a22f4479e2b8"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-win32.whl", hash = "sha256:696abe5b4386ab2be0ab14283554d65693765114de0cf39a9c4ac9d4aa8ed49c"}, + {file = "rapidfuzz-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:5e1a13268ed05f14fc034feaff2bd7ef25b62dec10f382851df83948b9c2955a"}, + {file = "rapidfuzz-1.8.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:30fc0264f59ea3a964a6d973f0f513708c4f128c60c07abfdba1cabf88810491"}, + {file = "rapidfuzz-1.8.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:ce6188048bd3d837510dda622199bf4707e6f459a274b259e2228df8f34d393f"}, + {file = "rapidfuzz-1.8.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:993772c6d322695c61ae79566e13182b9a99229307db4e1f34b3f261876f6f34"}, + {file = "rapidfuzz-1.8.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf2f41be966bd3f1ec9f3aea828fad29c99f2a32cf92a7246f094d09a0b779ae"}, + {file = "rapidfuzz-1.8.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:2f5bfd4852876dd438a7c704d0b3f8efc225f1b5e73bcd35bee52345f1e9b49a"}, + {file = "rapidfuzz-1.8.1.tar.gz", hash = "sha256:73aed694e0f36764b61418a9d5d75e9e428fbd954e154e71ad1e34912f2e85ab"}, ] redis = [ {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, @@ -1546,6 +1582,10 @@ taskipy = [ {file = "taskipy-1.9.0-py3-none-any.whl", hash = "sha256:02bd2c51c7356ed3f7f8853210ada1cd2ab273e68359ee865021c3057eec6615"}, {file = "taskipy-1.9.0.tar.gz", hash = "sha256:449c160b557cdb1d9c17097a5ea4aa0cd5223723ddbaaa5d5032dd16274fb8f0"}, ] +testfixtures = [ + {file = "testfixtures-6.18.3-py2.py3-none-any.whl", hash = "sha256:6ddb7f56a123e1a9339f130a200359092bd0a6455e31838d6c477e8729bb7763"}, + {file = "testfixtures-6.18.3.tar.gz", hash = "sha256:2600100ae96ffd082334b378e355550fef8b4a529a6fa4c34f47130905c7426d"}, +] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, diff --git a/pyproject.toml b/pyproject.toml index 88a974ab..91dd65fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,10 +26,10 @@ flake8 = "~=3.8" flake8-annotations = "~=2.3" flake8-bugbear = "~=20.1" flake8-docstrings = "~=1.5" -flake8-import-order = "~=0.18" flake8-string-format = "~=0.3" flake8-tidy-imports = "~=4.1" flake8-todo = "~=0.7" +flake8-isort = "~=4.0" pep8-naming = "~=0.11" pip-licenses = "~=3.5" pre-commit = "~=2.1" @@ -40,7 +40,17 @@ taskipy = "~=1.6" start = "python -m bot" lint = "pre-commit run --all-files" precommit = "pre-commit install" +isort = "isort ." [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + +[tool.isort] +multi_line_output = 6 +order_by_type = false +case_sensitive = true +combine_as_imports = true +line_length = 120 +atomic = true +known_first_party = ["bot"] -- cgit v1.2.3 From cdaa77830f9bce1529d93990f00415dbde33a0cd Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Fri, 22 Oct 2021 07:25:39 +0000 Subject: Isort: give the codebase a sort --- bot/__init__.py | 1 - bot/exts/core/help.py | 5 +---- bot/exts/core/internal_eval/_internal_eval.py | 1 + bot/exts/events/advent_of_code/_cog.py | 4 +--- bot/exts/holidays/easter/earth_photos.py | 3 +-- bot/exts/holidays/halloween/scarymovie.py | 1 + bot/exts/utilities/issues.py | 9 +-------- bot/utils/checks.py | 9 +-------- bot/utils/halloween/spookifications.py | 3 +-- 9 files changed, 8 insertions(+), 28 deletions(-) diff --git a/bot/__init__.py b/bot/__init__.py index db576cb2..cfaee9f8 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -18,7 +18,6 @@ from discord.ext import commands from bot import monkey_patches from bot.constants import Client - # Configure the "TRACE" logging level (e.g. "log.trace(message)") logging.TRACE = 5 logging.addLevelName(logging.TRACE, "TRACE") diff --git a/bot/exts/core/help.py b/bot/exts/core/help.py index 4b766b50..db3c2aa6 100644 --- a/bot/exts/core/help.py +++ b/bot/exts/core/help.py @@ -13,10 +13,7 @@ from rapidfuzz import process from bot import constants from bot.bot import Bot from bot.constants import Emojis -from bot.utils.pagination import ( - FIRST_EMOJI, LAST_EMOJI, - LEFT_EMOJI, LinePaginator, RIGHT_EMOJI, -) +from bot.utils.pagination import FIRST_EMOJI, LAST_EMOJI, LEFT_EMOJI, LinePaginator, RIGHT_EMOJI DELETE_EMOJI = Emojis.trashcan diff --git a/bot/exts/core/internal_eval/_internal_eval.py b/bot/exts/core/internal_eval/_internal_eval.py index 4f6b4321..12a860fa 100644 --- a/bot/exts/core/internal_eval/_internal_eval.py +++ b/bot/exts/core/internal_eval/_internal_eval.py @@ -10,6 +10,7 @@ from bot.bot import Bot from bot.constants import Client, Roles from bot.utils.decorators import with_role from bot.utils.extensions import invoke_help_command + from ._helpers import EvalContext __all__ = ["InternalEval"] diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 7dd967ec..2c1f4541 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -9,9 +9,7 @@ import discord from discord.ext import commands from bot.bot import Bot -from bot.constants import ( - AdventOfCode as AocConfig, Channels, Colours, Emojis, Month, Roles, WHITELISTED_CHANNELS, -) +from bot.constants import AdventOfCode as AocConfig, Channels, Colours, Emojis, Month, Roles, WHITELISTED_CHANNELS from bot.exts.events.advent_of_code import _helpers from bot.exts.events.advent_of_code.views.dayandstarview import AoCDropdownView from bot.utils.decorators import InChannelCheckFailure, in_month, whitelist_override, with_role diff --git a/bot/exts/holidays/easter/earth_photos.py b/bot/exts/holidays/easter/earth_photos.py index f65790af..27442f1c 100644 --- a/bot/exts/holidays/easter/earth_photos.py +++ b/bot/exts/holidays/easter/earth_photos.py @@ -4,8 +4,7 @@ import discord from discord.ext import commands from bot.bot import Bot -from bot.constants import Colours -from bot.constants import Tokens +from bot.constants import Colours, Tokens log = logging.getLogger(__name__) diff --git a/bot/exts/holidays/halloween/scarymovie.py b/bot/exts/holidays/halloween/scarymovie.py index 33659fd8..89310b97 100644 --- a/bot/exts/holidays/halloween/scarymovie.py +++ b/bot/exts/holidays/halloween/scarymovie.py @@ -6,6 +6,7 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import Tokens + log = logging.getLogger(__name__) diff --git a/bot/exts/utilities/issues.py b/bot/exts/utilities/issues.py index 36655e1b..b6d5a43e 100644 --- a/bot/exts/utilities/issues.py +++ b/bot/exts/utilities/issues.py @@ -9,14 +9,7 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import ( - Categories, - Channels, - Colours, - ERROR_REPLIES, - Emojis, - NEGATIVE_REPLIES, - Tokens, - WHITELISTED_CHANNELS + Categories, Channels, Colours, ERROR_REPLIES, Emojis, NEGATIVE_REPLIES, Tokens, WHITELISTED_CHANNELS ) from bot.utils.decorators import whitelist_override from bot.utils.extensions import invoke_help_command diff --git a/bot/utils/checks.py b/bot/utils/checks.py index 612d1ed6..8c426ed7 100644 --- a/bot/utils/checks.py +++ b/bot/utils/checks.py @@ -4,14 +4,7 @@ from collections.abc import Container, Iterable from typing import Callable, Optional from discord.ext.commands import ( - BucketType, - CheckFailure, - Cog, - Command, - CommandOnCooldown, - Context, - Cooldown, - CooldownMapping, + BucketType, CheckFailure, Cog, Command, CommandOnCooldown, Context, Cooldown, CooldownMapping ) from bot import constants diff --git a/bot/utils/halloween/spookifications.py b/bot/utils/halloween/spookifications.py index 93c5ddb9..c45ef8dc 100644 --- a/bot/utils/halloween/spookifications.py +++ b/bot/utils/halloween/spookifications.py @@ -1,8 +1,7 @@ import logging from random import choice, randint -from PIL import Image -from PIL import ImageOps +from PIL import Image, ImageOps log = logging.getLogger() -- cgit v1.2.3 From 3983d28349fd9be55627f6284b3d2e4b96fe37ce Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Fri, 22 Oct 2021 07:25:58 +0000 Subject: Precommit: add an isort hook --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7244cb4e..a2e9a398 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,11 @@ repos: rev: v1.5.1 hooks: - id: python-check-blanket-noqa + - repo: https://github.com/pycqa/isort + rev: 5.8.0 + hooks: + - id: isort + name: isort (python) - repo: local hooks: - id: flake8 -- cgit v1.2.3 From 74e8bd470356885a5f419999d88960124e6e0584 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Fri, 22 Oct 2021 07:27:49 +0000 Subject: CI: only check licenses of dev deps --- .github/workflows/lint.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 81706e1e..756b3c16 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -74,12 +74,14 @@ jobs: pip install poetry poetry install --no-interaction --no-ansi - # Check all the dependencies are compatible with the MIT license. + # Check all of our dev dependencies are compatible with the MIT license. # If you added a new dependencies that is being rejected, # please make sure it is compatible with the license for this project, # and add it to the ALLOWED_LICENSE variable - name: Check Dependencies License - run: pip-licenses --allow-only="$ALLOWED_LICENSES" + run: | + pip-licenses --allow-only="$ALLOWED_LICENSE" \ + --package $(poetry export -f requirements.txt --without-hashes | sed "s/==.*//g" | tr "\n" " ") # This step caches our pre-commit environment. To make sure we # do create a new environment when our pre-commit setup changes, -- cgit v1.2.3 From d6d8992e68a18819706bcb2a6e40a7ee1e581ca9 Mon Sep 17 00:00:00 2001 From: TizzySaurus <47674925+TizzySaurus@users.noreply.github.com> Date: Wed, 27 Oct 2021 00:13:25 +0100 Subject: Migrate to `og_blurple` (#924) --- bot/exts/core/extensions.py | 2 +- bot/exts/holidays/halloween/candy_collection.py | 2 +- bot/exts/utilities/conversationstarters.py | 2 +- bot/exts/utilities/emoji.py | 2 +- bot/exts/utilities/githubinfo.py | 4 ++-- bot/exts/utilities/reddit.py | 10 +++++----- bot/exts/utilities/wikipedia.py | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bot/exts/core/extensions.py b/bot/exts/core/extensions.py index dbb9e069..d809d2b9 100644 --- a/bot/exts/core/extensions.py +++ b/bot/exts/core/extensions.py @@ -152,7 +152,7 @@ class Extensions(commands.Cog): Grey indicates that the extension is unloaded. Green indicates that the extension is currently loaded. """ - embed = Embed(colour=Colour.blurple()) + embed = Embed(colour=Colour.og_blurple()) embed.set_author( name="Extensions List", url=Client.github_bot_repo, diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py index 09bd0e59..079d900d 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -182,7 +182,7 @@ class CandyCollection(commands.Cog): for index, record in enumerate(top_five) ) if top_five else "No Candies" - e = discord.Embed(colour=discord.Colour.blurple()) + e = discord.Embed(colour=discord.Colour.og_blurple()) e.add_field( name="Top Candy Records", value=generate_leaderboard(), diff --git a/bot/exts/utilities/conversationstarters.py b/bot/exts/utilities/conversationstarters.py index dcbfe4d5..8bf2abfd 100644 --- a/bot/exts/utilities/conversationstarters.py +++ b/bot/exts/utilities/conversationstarters.py @@ -53,7 +53,7 @@ class ConvoStarters(commands.Cog): # No matter what, the form will be shown. embed = discord.Embed( description=f"Suggest more topics [here]({SUGGESTION_FORM})!", - color=discord.Color.blurple() + color=discord.Colour.og_blurple() ) try: diff --git a/bot/exts/utilities/emoji.py b/bot/exts/utilities/emoji.py index 83df39cc..fa438d7f 100644 --- a/bot/exts/utilities/emoji.py +++ b/bot/exts/utilities/emoji.py @@ -111,7 +111,7 @@ class Emojis(commands.Cog): **Date:** {datetime.strftime(emoji.created_at.replace(tzinfo=None), "%d/%m/%Y")} **ID:** {emoji.id} """), - color=Color.blurple(), + color=Color.og_blurple(), url=str(emoji.url), ).set_thumbnail(url=emoji.url) diff --git a/bot/exts/utilities/githubinfo.py b/bot/exts/utilities/githubinfo.py index d00b408d..539e388b 100644 --- a/bot/exts/utilities/githubinfo.py +++ b/bot/exts/utilities/githubinfo.py @@ -67,7 +67,7 @@ class GithubInfo(commands.Cog): embed = discord.Embed( title=f"`{user_data['login']}`'s GitHub profile info", description=f"```\n{user_data['bio']}\n```\n" if user_data["bio"] else "", - colour=discord.Colour.blurple(), + colour=discord.Colour.og_blurple(), url=user_data["html_url"], timestamp=datetime.strptime(user_data["created_at"], "%Y-%m-%dT%H:%M:%SZ") ) @@ -139,7 +139,7 @@ class GithubInfo(commands.Cog): embed = discord.Embed( title=repo_data["name"], description=repo_data["description"], - colour=discord.Colour.blurple(), + colour=discord.Colour.og_blurple(), url=repo_data["html_url"] ) diff --git a/bot/exts/utilities/reddit.py b/bot/exts/utilities/reddit.py index e6cb5337..782583d2 100644 --- a/bot/exts/utilities/reddit.py +++ b/bot/exts/utilities/reddit.py @@ -244,7 +244,7 @@ class Reddit(Cog): # Use only starting summary page for #reddit channel posts. embed.description = self.build_pagination_pages(posts, paginate=False) - embed.colour = Colour.blurple() + embed.colour = Colour.og_blurple() return embed @loop() @@ -312,7 +312,7 @@ class Reddit(Cog): await ctx.send(f"Here are the top {subreddit} posts of all time!") embed = Embed( - color=Colour.blurple() + color=Colour.og_blurple() ) await ImagePaginator.paginate(pages, ctx, embed) @@ -325,7 +325,7 @@ class Reddit(Cog): await ctx.send(f"Here are today's top {subreddit} posts!") embed = Embed( - color=Colour.blurple() + color=Colour.og_blurple() ) await ImagePaginator.paginate(pages, ctx, embed) @@ -338,7 +338,7 @@ class Reddit(Cog): await ctx.send(f"Here are this week's top {subreddit} posts!") embed = Embed( - color=Colour.blurple() + color=Colour.og_blurple() ) await ImagePaginator.paginate(pages, ctx, embed) @@ -349,7 +349,7 @@ class Reddit(Cog): """Send a paginated embed of all the subreddits we're relaying.""" embed = Embed() embed.title = "Relayed subreddits." - embed.colour = Colour.blurple() + embed.colour = Colour.og_blurple() await LinePaginator.paginate( RedditConfig.subreddits, diff --git a/bot/exts/utilities/wikipedia.py b/bot/exts/utilities/wikipedia.py index eccc1f8c..c5283de0 100644 --- a/bot/exts/utilities/wikipedia.py +++ b/bot/exts/utilities/wikipedia.py @@ -82,7 +82,7 @@ class WikipediaSearch(commands.Cog): if contents: embed = Embed( title="Wikipedia Search Results", - colour=Color.blurple() + colour=Color.og_blurple() ) embed.set_thumbnail(url=WIKI_THUMBNAIL) embed.timestamp = datetime.utcnow() -- cgit v1.2.3 From 36d8f996575d99e08256b0336ae75e9e491c381a Mon Sep 17 00:00:00 2001 From: Hedy Li Date: Fri, 29 Oct 2021 02:45:48 +0000 Subject: Candy Game: Ignore reactions to bot messages when adding candies Check whether a reaction is for a bot message when adding candies upon reactions. Previously you could use bot's reaction buttons which would trigger `on_reaction_add` and have a high chance of getting candies (or skulls). It can easily be abused to spam reactions, which apparently doesn't trigger an auto-mute like spamming messages do, AFAIK. In any case, I don't really feel good about reactions triggering candies. Despite this fix, the game *can* still be abused (but I won't tell you how). Though this occuring by accident is less likely than before. Either figure it out yourself or don't try to cheat :P This patch can be tested using the `.snake antidote` game when you react to the recipe buttons. Using `.help` works too but it produces a lot of noise in the logs. Tic tac toe may be helpful as well. Anyway, you could just react to bot messages yourself. --- bot/exts/holidays/halloween/candy_collection.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py index 079d900d..bb9c93be 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -83,6 +83,11 @@ class CandyCollection(commands.Cog): # if its not a candy or skull, and it is one of 10 most recent messages, # proceed to add a skull/candy with higher chance if str(reaction.emoji) not in (EMOJIS["SKULL"], EMOJIS["CANDY"]): + # Ensure the reaction is not for a bot's message so users can't spam + # reaction buttons like in .help to get candies. + if message.author.bot: + return + recent_message_ids = map( lambda m: m.id, await self.hacktober_channel.history(limit=10).flatten() -- cgit v1.2.3 From fedd30b0aa9afdddb33b20630096b67370b3ac89 Mon Sep 17 00:00:00 2001 From: SavagePastaMan <69145546+SavagePastaMan@users.noreply.github.com> Date: Mon, 1 Nov 2021 20:38:42 -0400 Subject: Remove the "what's your skill level topic" --- bot/resources/utilities/py_topics.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/resources/utilities/py_topics.yaml b/bot/resources/utilities/py_topics.yaml index a3fb2ccc..1cd2c325 100644 --- a/bot/resources/utilities/py_topics.yaml +++ b/bot/resources/utilities/py_topics.yaml @@ -33,7 +33,6 @@ - How often do you program in Python? - How would you learn a new library if needed to do so? - Have you ever worked with a microcontroller or anything physical with Python before? - - How good would you say you are at Python so far? Beginner, intermediate, or advanced? - Have you ever tried making your own programming language? - Has a recently discovered Python module changed your general use of Python? -- cgit v1.2.3 From 2cd5aa83a722f4137e32514dfe9c45688be365ac Mon Sep 17 00:00:00 2001 From: NipaDev <60810623+Nipa-Code@users.noreply.github.com> Date: Fri, 5 Nov 2021 03:18:11 +0200 Subject: Add option to get specific amount of realpython articles Add a feature to choice in between 1-5 (inclusive) articles. If value not specified, the default, 5 will be used. Co-authored-by: ChrisJL --- bot/exts/utilities/realpython.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/realpython.py b/bot/exts/utilities/realpython.py index ef8b2638..bf8f1341 100644 --- a/bot/exts/utilities/realpython.py +++ b/bot/exts/utilities/realpython.py @@ -1,5 +1,6 @@ import logging from html import unescape +from typing import Optional from urllib.parse import quote_plus from discord import Embed @@ -31,9 +32,18 @@ class RealPython(commands.Cog): @commands.command(aliases=["rp"]) @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) - async def realpython(self, ctx: commands.Context, *, user_search: str) -> None: - """Send 5 articles that match the user's search terms.""" - params = {"q": user_search, "limit": 5, "kind": "article"} + async def realpython(self, ctx: commands.Context, amount: Optional[int] = 5, *, user_search: str) -> None: + """ + Send some articles from RealPython that match the search terms. + + By default the top 5 matches are sent, this can be overwritten to + a number between 1 and 5 by specifying an amount before the search query. + """ + if not 1 <= amount <= 5: + await ctx.send("`amount` must be between 1 and 5 (inclusive).") + return + + params = {"q": user_search, "limit": amount, "kind": "article"} async with self.bot.http_session.get(url=API_ROOT, params=params) as response: if response.status != 200: logger.error( -- cgit v1.2.3 From 726109fc47eec6259e6d8f8291b330e3353809e4 Mon Sep 17 00:00:00 2001 From: NipaDev <60810623+Nipa-Code@users.noreply.github.com> Date: Fri, 5 Nov 2021 12:49:20 +0200 Subject: Limit user reactions on embed pagination * Limit user reactions on embed pagination Limit user reactions to prevent non-author from removing message by adding user restriction to paginator. * Fixed the format of code to single line. Co-authored-by: ChrisJL --- bot/exts/utilities/wikipedia.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bot/exts/utilities/wikipedia.py b/bot/exts/utilities/wikipedia.py index c5283de0..e5e8e289 100644 --- a/bot/exts/utilities/wikipedia.py +++ b/bot/exts/utilities/wikipedia.py @@ -86,9 +86,7 @@ class WikipediaSearch(commands.Cog): ) embed.set_thumbnail(url=WIKI_THUMBNAIL) embed.timestamp = datetime.utcnow() - await LinePaginator.paginate( - contents, ctx, embed - ) + await LinePaginator.paginate(contents, ctx, embed, restrict_to_user=ctx.author) else: await ctx.send( "Sorry, we could not find a wikipedia article using that search term." -- cgit v1.2.3 From 65cfed425e19fa508c7d4e8736deb55c564cecbb Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Sat, 6 Nov 2021 23:07:31 -0400 Subject: Handle `.wtf` command without query (#939) Co-authored-by: Hedy Li Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/utilities/wtf_python.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bot/exts/utilities/wtf_python.py b/bot/exts/utilities/wtf_python.py index 66a022d7..980b3dba 100644 --- a/bot/exts/utilities/wtf_python.py +++ b/bot/exts/utilities/wtf_python.py @@ -79,7 +79,7 @@ class WTFPython(commands.Cog): return match if certainty > MINIMUM_CERTAINTY else None @commands.command(aliases=("wtf", "WTF")) - async def wtf_python(self, ctx: commands.Context, *, query: str) -> None: + async def wtf_python(self, ctx: commands.Context, *, query: Optional[str] = None) -> None: """ Search WTF Python repository. @@ -87,6 +87,18 @@ class WTFPython(commands.Cog): Usage: --> .wtf wild imports """ + if query is None: + no_query_embed = Embed( + title="WTF Python?!", + colour=constants.Colours.dark_green, + description="A repository filled with suprising snippets that can make you say WTF?!\n\n" + f"[Go to the Repository]({BASE_URL})" + ) + logo = File(LOGO_PATH, filename="wtf_logo.jpg") + no_query_embed.set_thumbnail(url="attachment://wtf_logo.jpg") + await ctx.send(embed=no_query_embed, file=logo) + return + if len(query) > 50: embed = Embed( title=random.choice(constants.ERROR_REPLIES), -- cgit v1.2.3