From 0d51688a87739e57d681727db807bab02766eb55 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 3 Sep 2021 11:18:15 -0400 Subject: Start from upstream main branch --- bot/exts/evergreen/color.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 bot/exts/evergreen/color.py diff --git a/bot/exts/evergreen/color.py b/bot/exts/evergreen/color.py new file mode 100644 index 00000000..5d86f002 --- /dev/null +++ b/bot/exts/evergreen/color.py @@ -0,0 +1 @@ +# initial creation -- cgit v1.2.3 From 15d545ec8f3c81fa5e06c3fefda7593b03521628 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 3 Sep 2021 14:35:26 -0400 Subject: Create draft body of file This is a large empty file with lots of comments. My general proposal is outlined in the code stumps. Details will need to be hashed out and decided on with CyberCitizen01. In particular: - How to use URLs that has list of color names? Read those into a dictionary? - How to handle the command call with options? `discord-flags`, parsing, function call like: .colour cmyk(49, 50, 0, 22) .colour hsl(241, 47, 58) .colour rgb 101 99 199 - How to implement fuzzy matching with rapidfuzz based on the color names from those URLs? - How to generate colors in other formats? Is this all possible in pillow? - How to generate photo to use in the embed? Do we temporarily create a file in a cache, send it in embed, then delete? This will be a fun project, and my first collab! Co-authored-by: Mohammad Rafivulla <77384412+CyberCitizen01@users.noreply.github.com> --- bot/exts/evergreen/color.py | 113 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/bot/exts/evergreen/color.py b/bot/exts/evergreen/color.py index 5d86f002..32a25b0d 100644 --- a/bot/exts/evergreen/color.py +++ b/bot/exts/evergreen/color.py @@ -1 +1,112 @@ -# initial creation +# imports +import logging + +import pillow +from discord import Embed +# ! need to install discord-flags and add to poetry.lock file +from discord.ext import commands, flags +from rapidfuzz import process + +from bot.bot import Bot +from bot.constants import Colours + +logger = logging.getLogger(__name__) + +# constants if needed +# TODO Will the color conversions be done only from pillow or will an API / URL be needed? +# Color URLs +COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" +COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" + + +COLOR_ERROR = Embed( + title="Input color is not possible", + description="The color code {user_color} is not a possible color combination." + "\nThe range of possible values are: " + "\nRGB & HSV: 0-255" + "\nCMYK: 0-100%" + "\nHSL: 0-360 degrees" + "\nHex: #000000-#FFFFFF" +) +COLOR_EMBED = Embed( + title="{color_name}", + description="RGB" + "\n{RGB}" + "\nHSV" + "\n{HSV}" + "\nCMYK" + "\n{CMYK}" + "\nHSL" + "\n{HSL}" + "\nHex" + "\n{Hex}" +) + + +# define color command +class Color(commands.cog): + """User initiated command to receive color information.""" + + def __init__(self, bot: Bot): + self.bot = bot + + # ? possible to use discord-flags to allow user to decide on color + # https://pypi.org/project/discord-flags/ + # @flags.add_flag("--rgb", type=str) + # @flags.add_flag("--hsv", type=str) + # @flags.add_flag("--cmyk", type=str) + # @flags.add_flag("--hsl", type=str) + # @flags.add_flag("--hex", type=str) + # @flags.add_flag("--name", type=str) + # @flags.command() + @commands.command(aliases=["color", "colour"]) + @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) + async def color(self, ctx: commands.Context, *, user_color: str) -> None: + """Send information on input color code or color name.""" + # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name + # should we assume the color is RGB if not defined? + # should discord tags be used? + # need to review discord.py V2.0 + + # TODO code to check if color code is possible + await ctx.send(embed=COLOR_ERROR.format(color=user_color)) + # await ctx.send(embed=COLOR_EMBED.format( + # RGB=color_dict["RGB"], + # HSV=color_dict["HSV"], + # HSL=color_dict["HSL"], + # CMYK=color_dict["CMYK"], + # HSL=color_dict["HSL"], + # Hex=color_dict["Hex"], + # color_name=color_dict["color_name"] + # ) + # ) + + # TODO pass for now + pass + + # if user_color in color_lists: + # # TODO fuzzy match for color + # pass + + async def color_converter(self, color: str, code_type: str) -> dict: + """Generate alternative color codes for use in the embed.""" + # TODO add code to take color and code type and return other types + # color_dict = { + # "RGB": color_RGB, + # "HSV": color_HSV, + # "HSL": color_HSL, + # "CMYK": color_CMYK, + # "HSL": color_HSL, + # "Hex": color_Hex, + # "color_name": color_name, + # } + pass + + async def photo_generator(self, color: str) -> None: + """Generate photo to use in embed.""" + # TODO need to find a way to store photo in cache to add to embed, then remove + + +def setup(bot: Bot) -> None: + """Load the Color Cog.""" + bot.add_cog(Color(bot)) -- cgit v1.2.3 From 969ab351b4906593505feaa43229d8bc3c95933c Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 3 Sep 2021 16:15:34 -0400 Subject: Add colorsys import, verbage for using JSON Co-authored-by: Mohammad Rafivulla <77384412+CyberCitizen01@users.noreply.github.com> --- bot/exts/evergreen/color.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bot/exts/evergreen/color.py b/bot/exts/evergreen/color.py index 32a25b0d..a00a956b 100644 --- a/bot/exts/evergreen/color.py +++ b/bot/exts/evergreen/color.py @@ -1,6 +1,7 @@ # imports import logging +import colorsys import pillow from discord import Embed # ! need to install discord-flags and add to poetry.lock file @@ -13,8 +14,8 @@ from bot.constants import Colours logger = logging.getLogger(__name__) # constants if needed -# TODO Will the color conversions be done only from pillow or will an API / URL be needed? -# Color URLs +# Color URLs - will be replaced by JSON file? +COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" @@ -78,7 +79,7 @@ class Color(commands.cog): # HSL=color_dict["HSL"], # Hex=color_dict["Hex"], # color_name=color_dict["color_name"] - # ) + # ).set_image() # url for image? # ) # TODO pass for now -- cgit v1.2.3 From b66e61394cd6168c7e74a91c134ceeb669e444f8 Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sat, 4 Sep 2021 01:47:58 +0530 Subject: Added ryanzec_colours.json constructed from ryanzec/name-that-color Original source: https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681 --- bot/resources/evergreen/ryanzec_colours.json | 1568 ++++++++++++++++++++++++++ 1 file changed, 1568 insertions(+) create mode 100644 bot/resources/evergreen/ryanzec_colours.json diff --git a/bot/resources/evergreen/ryanzec_colours.json b/bot/resources/evergreen/ryanzec_colours.json new file mode 100644 index 00000000..63d9be44 --- /dev/null +++ b/bot/resources/evergreen/ryanzec_colours.json @@ -0,0 +1,1568 @@ +{ + "Abbey": "4C4F56", + "Acadia": "1B1404", + "Acapulco": "7CB0A1", + "Aero Blue": "C9FFE5", + "Affair": "714693", + "Akaroa": "D4C4A8", + "Alabaster": "FAFAFA", + "Albescent White": "F5E9D3", + "Algae Green": "93DFB8", + "Alice Blue": "F0F8FF", + "Alizarin Crimson": "E32636", + "Allports": "0076A3", + "Almond": "EED9C4", + "Almond Frost": "907B71", + "Alpine": "AF8F2C", + "Alto": "DBDBDB", + "Aluminium": "A9ACB6", + "Amaranth": "E52B50", + "Amazon": "3B7A57", + "Amber": "FFBF00", + "Americano": "87756E", + "Amethyst": "9966CC", + "Amethyst Smoke": "A397B4", + "Amour": "F9EAF3", + "Amulet": "7B9F80", + "Anakiwa": "9DE5FF", + "Antique Brass": "C88A65", + "Antique Bronze": "704A07", + "Anzac": "E0B646", + "Apache": "DFBE6F", + "Apple": "4FA83D", + "Apple Blossom": "AF4D43", + "Apple Green": "E2F3EC", + "Apricot": "EB9373", + "Apricot Peach": "FBCEB1", + "Apricot White": "FFFEEC", + "Aqua Deep": "014B43", + "Aqua Forest": "5FA777", + "Aqua Haze": "EDF5F5", + "Aqua Island": "A1DAD7", + "Aqua Spring": "EAF9F5", + "Aqua Squeeze": "E8F5F2", + "Aquamarine": "7FFFD4", + "Aquamarine Blue": "71D9E2", + "Arapawa": "110C6C", + "Armadillo": "433E37", + "Arrowtown": "948771", + "Ash": "C6C3B5", + "Asparagus": "7BA05B", + "Asphalt": "130A06", + "Astra": "FAEAB9", + "Astral": "327DA0", + "Astronaut": "283A77", + "Astronaut Blue": "013E62", + "Athens Gray": "EEF0F3", + "Aths Special": "ECEBCE", + "Atlantis": "97CD2D", + "Atoll": "0A6F75", + "Atomic Tangerine": "FF9966", + "Au Chico": "97605D", + "Aubergine": "3B0910", + "Australian Mint": "F5FFBE", + "Avocado": "888D65", + "Axolotl": "4E6649", + "Azalea": "F7C8DA", + "Aztec": "0D1C19", + "Azure": "315BA1", + "Azure Radiance": "007FFF", + "Baby Blue": "E0FFFF", + "Bahama Blue": "026395", + "Bahia": "A5CB0C", + "Baja White": "FFF8D1", + "Bali Hai": "859FAF", + "Baltic Sea": "2A2630", + "Bamboo": "DA6304", + "Banana Mania": "FBE7B2", + "Bandicoot": "858470", + "Barberry": "DED717", + "Barley Corn": "A68B5B", + "Barley White": "FFF4CE", + "Barossa": "44012D", + "Bastille": "292130", + "Battleship Gray": "828F72", + "Bay Leaf": "7DA98D", + "Bay of Many": "273A81", + "Bazaar": "98777B", + "Bean ": "3D0C02", + "Beauty Bush": "EEC1BE", + "Beaver": "926F5B", + "Beeswax": "FEF2C7", + "Beige": "F5F5DC", + "Bermuda": "7DD8C6", + "Bermuda Gray": "6B8BA2", + "Beryl Green": "DEE5C0", + "Bianca": "FCFBF3", + "Big Stone": "162A40", + "Bilbao": "327C14", + "Biloba Flower": "B2A1EA", + "Birch": "373021", + "Bird Flower": "D4CD16", + "Biscay": "1B3162", + "Bismark": "497183", + "Bison Hide": "C1B7A4", + "Bistre": "3D2B1F", + "Bitter": "868974", + "Bitter Lemon": "CAE00D", + "Bittersweet": "FE6F5E", + "Bizarre": "EEDEDA", + "Black": "000000", + "Black Bean": "081910", + "Black Forest": "0B1304", + "Black Haze": "F6F7F7", + "Black Marlin": "3E2C1C", + "Black Olive": "242E16", + "Black Pearl": "041322", + "Black Rock": "0D0332", + "Black Rose": "67032D", + "Black Russian": "0A001C", + "Black Squeeze": "F2FAFA", + "Black White": "FFFEF6", + "Blackberry": "4D0135", + "Blackcurrant": "32293A", + "Blaze Orange": "FF6600", + "Bleach White": "FEF3D8", + "Bleached Cedar": "2C2133", + "Blizzard Blue": "A3E3ED", + "Blossom": "DCB4BC", + "Blue": "0000FF", + "Blue Bayoux": "496679", + "Blue Bell": "9999CC", + "Blue Chalk": "F1E9FF", + "Blue Charcoal": "010D1A", + "Blue Chill": "0C8990", + "Blue Diamond": "380474", + "Blue Dianne": "204852", + "Blue Gem": "2C0E8C", + "Blue Haze": "BFBED8", + "Blue Lagoon": "017987", + "Blue Marguerite": "7666C6", + "Blue Ribbon": "0066FF", + "Blue Romance": "D2F6DE", + "Blue Smoke": "748881", + "Blue Stone": "016162", + "Blue Violet": "6456B7", + "Blue Whale": "042E4C", + "Blue Zodiac": "13264D", + "Blumine": "18587A", + "Blush": "B44668", + "Blush Pink": "FF6FFF", + "Bombay": "AFB1B8", + "Bon Jour": "E5E0E1", + "Bondi Blue": "0095B6", + "Bone": "E4D1C0", + "Bordeaux": "5C0120", + "Bossanova": "4E2A5A", + "Boston Blue": "3B91B4", + "Botticelli": "C7DDE5", + "Bottle Green": "093624", + "Boulder": "7A7A7A", + "Bouquet": "AE809E", + "Bourbon": "BA6F1E", + "Bracken": "4A2A04", + "Brandy": "DEC196", + "Brandy Punch": "CD8429", + "Brandy Rose": "BB8983", + "Breaker Bay": "5DA19F", + "Brick Red": "C62D42", + "Bridal Heath": "FFFAF4", + "Bridesmaid": "FEF0EC", + "Bright Gray": "3C4151", + "Bright Green": "66FF00", + "Bright Red": "B10000", + "Bright Sun": "FED33C", + "Bright Turquoise": "08E8DE", + "Brilliant Rose": "F653A6", + "Brink Pink": "FB607F", + "Bronco": "ABA196", + "Bronze": "3F2109", + "Bronze Olive": "4E420C", + "Bronzetone": "4D400F", + "Broom": "FFEC13", + "Brown": "964B00", + "Brown Bramble": "592804", + "Brown Derby": "492615", + "Brown Pod": "401801", + "Brown Rust": "AF593E", + "Brown Tumbleweed": "37290E", + "Bubbles": "E7FEFF", + "Buccaneer": "622F30", + "Bud": "A8AE9C", + "Buddha Gold": "C1A004", + "Buff": "F0DC82", + "Bulgarian Rose": "480607", + "Bull Shot": "864D1E", + "Bunker": "0D1117", + "Bunting": "151F4C", + "Burgundy": "900020", + "Burnham": "002E20", + "Burning Orange": "FF7034", + "Burning Sand": "D99376", + "Burnt Maroon": "420303", + "Burnt Orange": "CC5500", + "Burnt Sienna": "E97451", + "Burnt Umber": "8A3324", + "Bush": "0D2E1C", + "Buttercup": "F3AD16", + "Buttered Rum": "A1750D", + "Butterfly Bush": "624E9A", + "Buttermilk": "FFF1B5", + "Buttery White": "FFFCEA", + "Cab Sav": "4D0A18", + "Cabaret": "D94972", + "Cabbage Pont": "3F4C3A", + "Cactus": "587156", + "Cadet Blue": "A9B2C3", + "Cadillac": "B04C6A", + "Cafe Royale": "6F440C", + "Calico": "E0C095", + "California": "FE9D04", + "Calypso": "31728D", + "Camarone": "00581A", + "Camelot": "893456", + "Cameo": "D9B99B", + "Camouflage": "3C3910", + "Camouflage Green": "78866B", + "Can Can": "D591A4", + "Canary": "F3FB62", + "Candlelight": "FCD917", + "Candy Corn": "FBEC5D", + "Cannon Black": "251706", + "Cannon Pink": "894367", + "Cape Cod": "3C4443", + "Cape Honey": "FEE5AC", + "Cape Palliser": "A26645", + "Caper": "DCEDB4", + "Caramel": "FFDDAF", + "Cararra": "EEEEE8", + "Cardin Green": "01361C", + "Cardinal": "C41E3A", + "Cardinal Pink": "8C055E", + "Careys Pink": "D29EAA", + "Caribbean Green": "00CC99", + "Carissma": "EA88A8", + "Carla": "F3FFD8", + "Carmine": "960018", + "Carnaby Tan": "5C2E01", + "Carnation": "F95A61", + "Carnation Pink": "FFA6C9", + "Carousel Pink": "F9E0ED", + "Carrot Orange": "ED9121", + "Casablanca": "F8B853", + "Casal": "2F6168", + "Cascade": "8BA9A5", + "Cashmere": "E6BEA5", + "Casper": "ADBED1", + "Castro": "52001F", + "Catalina Blue": "062A78", + "Catskill White": "EEF6F7", + "Cavern Pink": "E3BEBE", + "Cedar": "3E1C14", + "Cedar Wood Finish": "711A00", + "Celadon": "ACE1AF", + "Celery": "B8C25D", + "Celeste": "D1D2CA", + "Cello": "1E385B", + "Celtic": "163222", + "Cement": "8D7662", + "Ceramic": "FCFFF9", + "Cerise": "DA3287", + "Cerise Red": "DE3163", + "Cerulean": "02A4D3", + "Cerulean Blue": "2A52BE", + "Chablis": "FFF4F3", + "Chalet Green": "516E3D", + "Chalky": "EED794", + "Chambray": "354E8C", + "Chamois": "EDDCB1", + "Champagne": "FAECCC", + "Chantilly": "F8C3DF", + "Charade": "292937", + "Chardon": "FFF3F1", + "Chardonnay": "FFCD8C", + "Charlotte": "BAEEF9", + "Charm": "D47494", + "Chartreuse": "7FFF00", + "Chartreuse Yellow": "DFFF00", + "Chateau Green": "40A860", + "Chatelle": "BDB3C7", + "Chathams Blue": "175579", + "Chelsea Cucumber": "83AA5D", + "Chelsea Gem": "9E5302", + "Chenin": "DFCD6F", + "Cherokee": "FCDA98", + "Cherry Pie": "2A0359", + "Cherrywood": "651A14", + "Cherub": "F8D9E9", + "Chestnut": "B94E48", + "Chestnut Rose": "CD5C5C", + "Chetwode Blue": "8581D9", + "Chicago": "5D5C58", + "Chiffon": "F1FFC8", + "Chilean Fire": "F77703", + "Chilean Heath": "FFFDE6", + "China Ivory": "FCFFE7", + "Chino": "CEC7A7", + "Chinook": "A8E3BD", + "Chocolate": "370202", + "Christalle": "33036B", + "Christi": "67A712", + "Christine": "E7730A", + "Chrome White": "E8F1D4", + "Cinder": "0E0E18", + "Cinderella": "FDE1DC", + "Cinnabar": "E34234", + "Cinnamon": "7B3F00", + "Cioccolato": "55280C", + "Citrine White": "FAF7D6", + "Citron": "9EA91F", + "Citrus": "A1C50A", + "Clairvoyant": "480656", + "Clam Shell": "D4B6AF", + "Claret": "7F1734", + "Classic Rose": "FBCCE7", + "Clay Ash": "BDC8B3", + "Clay Creek": "8A8360", + "Clear Day": "E9FFFD", + "Clementine": "E96E00", + "Clinker": "371D09", + "Cloud": "C7C4BF", + "Cloud Burst": "202E54", + "Cloudy": "ACA59F", + "Clover": "384910", + "Cobalt": "0047AB", + "Cocoa Bean": "481C1C", + "Cocoa Brown": "301F1E", + "Coconut Cream": "F8F7DC", + "Cod Gray": "0B0B0B", + "Coffee": "706555", + "Coffee Bean": "2A140E", + "Cognac": "9F381D", + "Cola": "3F2500", + "Cold Purple": "ABA0D9", + "Cold Turkey": "CEBABA", + "Colonial White": "FFEDBC", + "Comet": "5C5D75", + "Como": "517C66", + "Conch": "C9D9D2", + "Concord": "7C7B7A", + "Concrete": "F2F2F2", + "Confetti": "E9D75A", + "Congo Brown": "593737", + "Congress Blue": "02478E", + "Conifer": "ACDD4D", + "Contessa": "C6726B", + "Copper": "B87333", + "Copper Canyon": "7E3A15", + "Copper Rose": "996666", + "Copper Rust": "944747", + "Copperfield": "DA8A67", + "Coral": "FF7F50", + "Coral Red": "FF4040", + "Coral Reef": "C7BCA2", + "Coral Tree": "A86B6B", + "Corduroy": "606E68", + "Coriander": "C4D0B0", + "Cork": "40291D", + "Corn": "E7BF05", + "Corn Field": "F8FACD", + "Corn Harvest": "8B6B0B", + "Cornflower": "93CCEA", + "Cornflower Blue": "6495ED", + "Cornflower Lilac": "FFB0AC", + "Corvette": "FAD3A2", + "Cosmic": "76395D", + "Cosmos": "FFD8D9", + "Costa Del Sol": "615D30", + "Cotton Candy": "FFB7D5", + "Cotton Seed": "C2BDB6", + "County Green": "01371A", + "Cowboy": "4D282D", + "Crail": "B95140", + "Cranberry": "DB5079", + "Crater Brown": "462425", + "Cream": "FFFDD0", + "Cream Brulee": "FFE5A0", + "Cream Can": "F5C85C", + "Creole": "1E0F04", + "Crete": "737829", + "Crimson": "DC143C", + "Crocodile": "736D58", + "Crown of Thorns": "771F1F", + "Crowshead": "1C1208", + "Cruise": "B5ECDF", + "Crusoe": "004816", + "Crusta": "FD7B33", + "Cumin": "924321", + "Cumulus": "FDFFD5", + "Cupid": "FBBEDA", + "Curious Blue": "2596D1", + "Cutty Sark": "507672", + "Cyan / Aqua": "00FFFF", + "Cyprus": "003E40", + "Daintree": "012731", + "Dairy Cream": "F9E4BC", + "Daisy Bush": "4F2398", + "Dallas": "6E4B26", + "Dandelion": "FED85D", + "Danube": "6093D1", + "Dark Blue": "0000C8", + "Dark Burgundy": "770F05", + "Dark Ebony": "3C2005", + "Dark Fern": "0A480D", + "Dark Tan": "661010", + "Dawn": "A6A29A", + "Dawn Pink": "F3E9E5", + "De York": "7AC488", + "Deco": "D2DA97", + "Deep Blue": "220878", + "Deep Blush": "E47698", + "Deep Bronze": "4A3004", + "Deep Cerulean": "007BA7", + "Deep Cove": "051040", + "Deep Fir": "002900", + "Deep Forest Green": "182D09", + "Deep Koamaru": "1B127B", + "Deep Oak": "412010", + "Deep Sapphire": "082567", + "Deep Sea": "01826B", + "Deep Sea Green": "095859", + "Deep Teal": "003532", + "Del Rio": "B09A95", + "Dell": "396413", + "Delta": "A4A49D", + "Deluge": "7563A8", + "Denim": "1560BD", + "Derby": "FFEED8", + "Desert": "AE6020", + "Desert Sand": "EDC9AF", + "Desert Storm": "F8F8F7", + "Dew": "EAFFFE", + "Di Serria": "DB995E", + "Diesel": "130000", + "Dingley": "5D7747", + "Disco": "871550", + "Dixie": "E29418", + "Dodger Blue": "1E90FF", + "Dolly": "F9FF8B", + "Dolphin": "646077", + "Domino": "8E775E", + "Don Juan": "5D4C51", + "Donkey Brown": "A69279", + "Dorado": "6B5755", + "Double Colonial White": "EEE3AD", + "Double Pearl Lusta": "FCF4D0", + "Double Spanish White": "E6D7B9", + "Dove Gray": "6D6C6C", + "Downriver": "092256", + "Downy": "6FD0C5", + "Driftwood": "AF8751", + "Drover": "FDF7AD", + "Dull Lavender": "A899E6", + "Dune": "383533", + "Dust Storm": "E5CCC9", + "Dusty Gray": "A8989B", + "Eagle": "B6BAA4", + "Earls Green": "C9B93B", + "Early Dawn": "FFF9E6", + "East Bay": "414C7D", + "East Side": "AC91CE", + "Eastern Blue": "1E9AB0", + "Ebb": "E9E3E3", + "Ebony": "0C0B1D", + "Ebony Clay": "26283B", + "Eclipse": "311C17", + "Ecru White": "F5F3E5", + "Ecstasy": "FA7814", + "Eden": "105852", + "Edgewater": "C8E3D7", + "Edward": "A2AEAB", + "Egg Sour": "FFF4DD", + "Egg White": "FFEFC1", + "Eggplant": "614051", + "El Paso": "1E1708", + "El Salva": "8F3E33", + "Electric Lime": "CCFF00", + "Electric Violet": "8B00FF", + "Elephant": "123447", + "Elf Green": "088370", + "Elm": "1C7C7D", + "Emerald": "50C878", + "Eminence": "6C3082", + "Emperor": "514649", + "Empress": "817377", + "Endeavour": "0056A7", + "Energy Yellow": "F8DD5C", + "English Holly": "022D15", + "English Walnut": "3E2B23", + "Envy": "8BA690", + "Equator": "E1BC64", + "Espresso": "612718", + "Eternity": "211A0E", + "Eucalyptus": "278A5B", + "Eunry": "CFA39D", + "Evening Sea": "024E46", + "Everglade": "1C402E", + "Faded Jade": "427977", + "Fair Pink": "FFEFEC", + "Falcon": "7F626D", + "Fall Green": "ECEBBD", + "Falu Red": "801818", + "Fantasy": "FAF3F0", + "Fedora": "796A78", + "Feijoa": "9FDD8C", + "Fern": "63B76C", + "Fern Frond": "657220", + "Fern Green": "4F7942", + "Ferra": "704F50", + "Festival": "FBE96C", + "Feta": "F0FCEA", + "Fiery Orange": "B35213", + "Finch": "626649", + "Finlandia": "556D56", + "Finn": "692D54", + "Fiord": "405169", + "Fire": "AA4203", + "Fire Bush": "E89928", + "Firefly": "0E2A30", + "Flame Pea": "DA5B38", + "Flamenco": "FF7D07", + "Flamingo": "F2552A", + "Flax": "EEDC82", + "Flax Smoke": "7B8265", + "Flesh": "FFCBA4", + "Flint": "6F6A61", + "Flirt": "A2006D", + "Flush Mahogany": "CA3435", + "Flush Orange": "FF7F00", + "Foam": "D8FCFA", + "Fog": "D7D0FF", + "Foggy Gray": "CBCAB6", + "Forest Green": "228B22", + "Forget Me Not": "FFF1EE", + "Fountain Blue": "56B4BE", + "Frangipani": "FFDEB3", + "French Gray": "BDBDC6", + "French Lilac": "ECC7EE", + "French Pass": "BDEDFD", + "French Rose": "F64A8A", + "Fresh Eggplant": "990066", + "Friar Gray": "807E79", + "Fringy Flower": "B1E2C1", + "Froly": "F57584", + "Frost": "EDF5DD", + "Frosted Mint": "DBFFF8", + "Frostee": "E4F6E7", + "Fruit Salad": "4F9D5D", + "Fuchsia Blue": "7A58C1", + "Fuchsia Pink": "C154C1", + "Fuego": "BEDE0D", + "Fuel Yellow": "ECA927", + "Fun Blue": "1959A8", + "Fun Green": "016D39", + "Fuscous Gray": "54534D", + "Fuzzy Wuzzy Brown": "C45655", + "Gable Green": "163531", + "Gallery": "EFEFEF", + "Galliano": "DCB20C", + "Gamboge": "E49B0F", + "Geebung": "D18F1B", + "Genoa": "15736B", + "Geraldine": "FB8989", + "Geyser": "D4DFE2", + "Ghost": "C7C9D5", + "Gigas": "523C94", + "Gimblet": "B8B56A", + "Gin": "E8F2EB", + "Gin Fizz": "FFF9E2", + "Givry": "F8E4BF", + "Glacier": "80B3C4", + "Glade Green": "61845F", + "Go Ben": "726D4E", + "Goblin": "3D7D52", + "Gold": "FFD700", + "Gold Drop": "F18200", + "Gold Sand": "E6BE8A", + "Gold Tips": "DEBA13", + "Golden Bell": "E28913", + "Golden Dream": "F0D52D", + "Golden Fizz": "F5FB3D", + "Golden Glow": "FDE295", + "Golden Grass": "DAA520", + "Golden Sand": "F0DB7D", + "Golden Tainoi": "FFCC5C", + "Goldenrod": "FCD667", + "Gondola": "261414", + "Gordons Green": "0B1107", + "Gorse": "FFF14F", + "Gossamer": "069B81", + "Gossip": "D2F8B0", + "Gothic": "6D92A1", + "Governor Bay": "2F3CB3", + "Grain Brown": "E4D5B7", + "Grandis": "FFD38C", + "Granite Green": "8D8974", + "Granny Apple": "D5F6E3", + "Granny Smith": "84A0A0", + "Granny Smith Apple": "9DE093", + "Grape": "381A51", + "Graphite": "251607", + "Gravel": "4A444B", + "Gray": "808080", + "Gray Asparagus": "465945", + "Gray Chateau": "A2AAB3", + "Gray Nickel": "C3C3BD", + "Gray Nurse": "E7ECE6", + "Gray Olive": "A9A491", + "Gray Suit": "C1BECD", + "Green": "00FF00", + "Green Haze": "01A368", + "Green House": "24500F", + "Green Kelp": "25311C", + "Green Leaf": "436A0D", + "Green Mist": "CBD3B0", + "Green Pea": "1D6142", + "Green Smoke": "A4AF6E", + "Green Spring": "B8C1B1", + "Green Vogue": "032B52", + "Green Waterloo": "101405", + "Green White": "E8EBE0", + "Green Yellow": "ADFF2F", + "Grenadier": "D54600", + "Guardsman Red": "BA0101", + "Gulf Blue": "051657", + "Gulf Stream": "80B3AE", + "Gull Gray": "9DACB7", + "Gum Leaf": "B6D3BF", + "Gumbo": "7CA1A6", + "Gun Powder": "414257", + "Gunsmoke": "828685", + "Gurkha": "9A9577", + "Hacienda": "98811B", + "Hairy Heath": "6B2A14", + "Haiti": "1B1035", + "Half Baked": "85C4CC", + "Half Colonial White": "FDF6D3", + "Half Dutch White": "FEF7DE", + "Half Spanish White": "FEF4DB", + "Half and Half": "FFFEE1", + "Hampton": "E5D8AF", + "Harlequin": "3FFF00", + "Harp": "E6F2EA", + "Harvest Gold": "E0B974", + "Havelock Blue": "5590D9", + "Hawaiian Tan": "9D5616", + "Hawkes Blue": "D4E2FC", + "Heath": "541012", + "Heather": "B7C3D0", + "Heathered Gray": "B6B095", + "Heavy Metal": "2B3228", + "Heliotrope": "DF73FF", + "Hemlock": "5E5D3B", + "Hemp": "907874", + "Hibiscus": "B6316C", + "Highland": "6F8E63", + "Hillary": "ACA586", + "Himalaya": "6A5D1B", + "Hint of Green": "E6FFE9", + "Hint of Red": "FBF9F9", + "Hint of Yellow": "FAFDE4", + "Hippie Blue": "589AAF", + "Hippie Green": "53824B", + "Hippie Pink": "AE4560", + "Hit Gray": "A1ADB5", + "Hit Pink": "FFAB81", + "Hokey Pokey": "C8A528", + "Hoki": "65869F", + "Holly": "011D13", + "Hollywood Cerise": "F400A1", + "Honey Flower": "4F1C70", + "Honeysuckle": "EDFC84", + "Hopbush": "D06DA1", + "Horizon": "5A87A0", + "Horses Neck": "604913", + "Hot Cinnamon": "D2691E", + "Hot Pink": "FF69B4", + "Hot Toddy": "B38007", + "Humming Bird": "CFF9F3", + "Hunter Green": "161D10", + "Hurricane": "877C7B", + "Husk": "B7A458", + "Ice Cold": "B1F4E7", + "Iceberg": "DAF4F0", + "Illusion": "F6A4C9", + "Inch Worm": "B0E313", + "Indian Khaki": "C3B091", + "Indian Tan": "4D1E01", + "Indigo": "4F69C6", + "Indochine": "C26B03", + "International Klein Blue": "002FA7", + "International Orange": "FF4F00", + "Irish Coffee": "5F3D26", + "Iroko": "433120", + "Iron": "D4D7D9", + "Ironside Gray": "676662", + "Ironstone": "86483C", + "Island Spice": "FFFCEE", + "Ivory": "FFFFF0", + "Jacaranda": "2E0329", + "Jacarta": "3A2A6A", + "Jacko Bean": "2E1905", + "Jacksons Purple": "20208D", + "Jade": "00A86B", + "Jaffa": "EF863F", + "Jagged Ice": "C2E8E5", + "Jagger": "350E57", + "Jaguar": "080110", + "Jambalaya": "5B3013", + "Janna": "F4EBD3", + "Japanese Laurel": "0A6906", + "Japanese Maple": "780109", + "Japonica": "D87C63", + "Java": "1FC2C2", + "Jazzberry Jam": "A50B5E", + "Jelly Bean": "297B9A", + "Jet Stream": "B5D2CE", + "Jewel": "126B40", + "Jon": "3B1F1F", + "Jonquil": "EEFF9A", + "Jordy Blue": "8AB9F1", + "Judge Gray": "544333", + "Jumbo": "7C7B82", + "Jungle Green": "29AB87", + "Jungle Mist": "B4CFD3", + "Juniper": "6D9292", + "Just Right": "ECCDB9", + "Kabul": "5E483E", + "Kaitoke Green": "004620", + "Kangaroo": "C6C8BD", + "Karaka": "1E1609", + "Karry": "FFEAD4", + "Kashmir Blue": "507096", + "Kelp": "454936", + "Kenyan Copper": "7C1C05", + "Keppel": "3AB09E", + "Key Lime Pie": "BFC921", + "Khaki": "F0E68C", + "Kidnapper": "E1EAD4", + "Kilamanjaro": "240C02", + "Killarney": "3A6A47", + "Kimberly": "736C9F", + "Kingfisher Daisy": "3E0480", + "Kobi": "E79FC4", + "Kokoda": "6E6D57", + "Korma": "8F4B0E", + "Koromiko": "FFBD5F", + "Kournikova": "FFE772", + "Kumera": "886221", + "La Palma": "368716", + "La Rioja": "B3C110", + "Las Palmas": "C6E610", + "Laser": "C8B568", + "Laser Lemon": "FFFF66", + "Laurel": "749378", + "Lavender": "B57EDC", + "Lavender Gray": "BDBBD7", + "Lavender Magenta": "EE82EE", + "Lavender Pink": "FBAED2", + "Lavender Purple": "967BB6", + "Lavender Rose": "FBA0E3", + "Lavender blush": "FFF0F5", + "Leather": "967059", + "Lemon": "FDE910", + "Lemon Chiffon": "FFFACD", + "Lemon Ginger": "AC9E22", + "Lemon Grass": "9B9E8F", + "Light Apricot": "FDD5B1", + "Light Orchid": "E29CD2", + "Light Wisteria": "C9A0DC", + "Lightning Yellow": "FCC01E", + "Lilac": "C8A2C8", + "Lilac Bush": "9874D3", + "Lily": "C8AABF", + "Lily White": "E7F8FF", + "Lima": "76BD17", + "Lime": "BFFF00", + "Limeade": "6F9D02", + "Limed Ash": "747D63", + "Limed Oak": "AC8A56", + "Limed Spruce": "394851", + "Linen": "FAF0E6", + "Link Water": "D9E4F5", + "Lipstick": "AB0563", + "Lisbon Brown": "423921", + "Livid Brown": "4D282E", + "Loafer": "EEF4DE", + "Loblolly": "BDC9CE", + "Lochinvar": "2C8C84", + "Lochmara": "007EC7", + "Locust": "A8AF8E", + "Log Cabin": "242A1D", + "Logan": "AAA9CD", + "Lola": "DFCFDB", + "London Hue": "BEA6C3", + "Lonestar": "6D0101", + "Lotus": "863C3C", + "Loulou": "460B41", + "Lucky": "AF9F1C", + "Lucky Point": "1A1A68", + "Lunar Green": "3C493A", + "Luxor Gold": "A7882C", + "Lynch": "697E9A", + "Mabel": "D9F7FF", + "Macaroni and Cheese": "FFB97B", + "Madang": "B7F0BE", + "Madison": "09255D", + "Madras": "3F3002", + "Magenta / Fuchsia": "FF00FF", + "Magic Mint": "AAF0D1", + "Magnolia": "F8F4FF", + "Mahogany": "4E0606", + "Mai Tai": "B06608", + "Maize": "F5D5A0", + "Makara": "897D6D", + "Mako": "444954", + "Malachite": "0BDA51", + "Malibu": "7DC8F7", + "Mallard": "233418", + "Malta": "BDB2A1", + "Mamba": "8E8190", + "Manatee": "8D90A1", + "Mandalay": "AD781B", + "Mandy": "E25465", + "Mandys Pink": "F2C3B2", + "Mango Tango": "E77200", + "Manhattan": "F5C999", + "Mantis": "74C365", + "Mantle": "8B9C90", + "Manz": "EEEF78", + "Mardi Gras": "350036", + "Marigold": "B98D28", + "Marigold Yellow": "FBE870", + "Mariner": "286ACD", + "Maroon": "800000", + "Maroon Flush": "C32148", + "Maroon Oak": "520C17", + "Marshland": "0B0F08", + "Martini": "AFA09E", + "Martinique": "363050", + "Marzipan": "F8DB9D", + "Masala": "403B38", + "Matisse": "1B659D", + "Matrix": "B05D54", + "Matterhorn": "4E3B41", + "Mauve": "E0B0FF", + "Mauvelous": "F091A9", + "Maverick": "D8C2D5", + "Medium Carmine": "AF4035", + "Medium Purple": "9370DB", + "Medium Red Violet": "BB3385", + "Melanie": "E4C2D5", + "Melanzane": "300529", + "Melon": "FEBAAD", + "Melrose": "C7C1FF", + "Mercury": "E5E5E5", + "Merino": "F6F0E6", + "Merlin": "413C37", + "Merlot": "831923", + "Metallic Bronze": "49371B", + "Metallic Copper": "71291D", + "Meteor": "D07D12", + "Meteorite": "3C1F76", + "Mexican Red": "A72525", + "Mid Gray": "5F5F6E", + "Midnight": "011635", + "Midnight Blue": "003366", + "Midnight Moss": "041004", + "Mikado": "2D2510", + "Milan": "FAFFA4", + "Milano Red": "B81104", + "Milk Punch": "FFF6D4", + "Millbrook": "594433", + "Mimosa": "F8FDD3", + "Mindaro": "E3F988", + "Mine Shaft": "323232", + "Mineral Green": "3F5D53", + "Ming": "36747D", + "Minsk": "3F307F", + "Mint Green": "98FF98", + "Mint Julep": "F1EEC1", + "Mint Tulip": "C4F4EB", + "Mirage": "161928", + "Mischka": "D1D2DD", + "Mist Gray": "C4C4BC", + "Mobster": "7F7589", + "Moccaccino": "6E1D14", + "Mocha": "782D19", + "Mojo": "C04737", + "Mona Lisa": "FFA194", + "Monarch": "8B0723", + "Mondo": "4A3C30", + "Mongoose": "B5A27F", + "Monsoon": "8A8389", + "Monte Carlo": "83D0C6", + "Monza": "C7031E", + "Moody Blue": "7F76D3", + "Moon Glow": "FCFEDA", + "Moon Mist": "DCDDCC", + "Moon Raker": "D6CEF6", + "Morning Glory": "9EDEE0", + "Morocco Brown": "441D00", + "Mortar": "504351", + "Mosque": "036A6E", + "Moss Green": "ADDFAD", + "Mountain Meadow": "1AB385", + "Mountain Mist": "959396", + "Mountbatten Pink": "997A8D", + "Muddy Waters": "B78E5C", + "Muesli": "AA8B5B", + "Mulberry": "C54B8C", + "Mulberry Wood": "5C0536", + "Mule Fawn": "8C472F", + "Mulled Wine": "4E4562", + "Mustard": "FFDB58", + "My Pink": "D69188", + "My Sin": "FFB31F", + "Mystic": "E2EBED", + "Nandor": "4B5D52", + "Napa": "ACA494", + "Narvik": "EDF9F1", + "Natural Gray": "8B8680", + "Navajo White": "FFDEAD", + "Navy Blue": "000080", + "Nebula": "CBDBD6", + "Negroni": "FFE2C5", + "Neon Carrot": "FF9933", + "Nepal": "8EABC1", + "Neptune": "7CB7BB", + "Nero": "140600", + "Nevada": "646E75", + "New Orleans": "F3D69D", + "New York Pink": "D7837F", + "Niagara": "06A189", + "Night Rider": "1F120F", + "Night Shadz": "AA375A", + "Nile Blue": "193751", + "Nobel": "B7B1B1", + "Nomad": "BAB1A2", + "Norway": "A8BD9F", + "Nugget": "C59922", + "Nutmeg": "81422C", + "Nutmeg Wood Finish": "683600", + "Oasis": "FEEFCE", + "Observatory": "02866F", + "Ocean Green": "41AA78", + "Ochre": "CC7722", + "Off Green": "E6F8F3", + "Off Yellow": "FEF9E3", + "Oil": "281E15", + "Old Brick": "901E1E", + "Old Copper": "724A2F", + "Old Gold": "CFB53B", + "Old Lace": "FDF5E6", + "Old Lavender": "796878", + "Old Rose": "C08081", + "Olive": "808000", + "Olive Drab": "6B8E23", + "Olive Green": "B5B35C", + "Olive Haze": "8B8470", + "Olivetone": "716E10", + "Olivine": "9AB973", + "Onahau": "CDF4FF", + "Onion": "2F270E", + "Opal": "A9C6C2", + "Opium": "8E6F70", + "Oracle": "377475", + "Orange": "FF681F", + "Orange Peel": "FFA000", + "Orange Roughy": "C45719", + "Orange White": "FEFCED", + "Orchid": "DA70D6", + "Orchid White": "FFFDF3", + "Oregon": "9B4703", + "Orient": "015E85", + "Oriental Pink": "C69191", + "Orinoco": "F3FBD4", + "Oslo Gray": "878D91", + "Ottoman": "E9F8ED", + "Outer Space": "2D383A", + "Outrageous Orange": "FF6037", + "Oxford Blue": "384555", + "Oxley": "779E86", + "Oyster Bay": "DAFAFF", + "Oyster Pink": "E9CECD", + "Paarl": "A65529", + "Pablo": "776F61", + "Pacific Blue": "009DC4", + "Pacifika": "778120", + "Paco": "411F10", + "Padua": "ADE6C4", + "Pale Canary": "FFFF99", + "Pale Leaf": "C0D3B9", + "Pale Oyster": "988D77", + "Pale Prim": "FDFEB8", + "Pale Rose": "FFE1F2", + "Pale Sky": "6E7783", + "Pale Slate": "C3BFC1", + "Palm Green": "09230F", + "Palm Leaf": "19330E", + "Pampas": "F4F2EE", + "Panache": "EAF6EE", + "Pancho": "EDCDAB", + "Papaya Whip": "FFEFD5", + "Paprika": "8D0226", + "Paradiso": "317D82", + "Parchment": "F1E9D2", + "Paris Daisy": "FFF46E", + "Paris M": "26056A", + "Paris White": "CADCD4", + "Parsley": "134F19", + "Pastel Green": "77DD77", + "Pastel Pink": "FFD1DC", + "Patina": "639A8F", + "Pattens Blue": "DEF5FF", + "Paua": "260368", + "Pavlova": "D7C498", + "Peach": "FFE5B4", + "Peach Cream": "FFF0DB", + "Peach Orange": "FFCC99", + "Peach Schnapps": "FFDCD6", + "Peach Yellow": "FADFAD", + "Peanut": "782F16", + "Pear": "D1E231", + "Pearl Bush": "E8E0D5", + "Pearl Lusta": "FCF4DC", + "Peat": "716B56", + "Pelorous": "3EABBF", + "Peppermint": "E3F5E1", + "Perano": "A9BEF2", + "Perfume": "D0BEF8", + "Periglacial Blue": "E1E6D6", + "Periwinkle": "CCCCFF", + "Periwinkle Gray": "C3CDE6", + "Persian Blue": "1C39BB", + "Persian Green": "00A693", + "Persian Indigo": "32127A", + "Persian Pink": "F77FBE", + "Persian Plum": "701C1C", + "Persian Red": "CC3333", + "Persian Rose": "FE28A2", + "Persimmon": "FF6B53", + "Peru Tan": "7F3A02", + "Pesto": "7C7631", + "Petite Orchid": "DB9690", + "Pewter": "96A8A1", + "Pharlap": "A3807B", + "Picasso": "FFF39D", + "Pickled Bean": "6E4826", + "Pickled Bluewood": "314459", + "Picton Blue": "45B1E8", + "Pig Pink": "FDD7E4", + "Pigeon Post": "AFBDD9", + "Pigment Indigo": "4B0082", + "Pine Cone": "6D5E54", + "Pine Glade": "C7CD90", + "Pine Green": "01796F", + "Pine Tree": "171F04", + "Pink": "FFC0CB", + "Pink Flamingo": "FF66FF", + "Pink Flare": "E1C0C8", + "Pink Lace": "FFDDF4", + "Pink Lady": "FFF1D8", + "Pink Salmon": "FF91A4", + "Pink Swan": "BEB5B7", + "Piper": "C96323", + "Pipi": "FEF4CC", + "Pippin": "FFE1DF", + "Pirate Gold": "BA7F03", + "Pistachio": "9DC209", + "Pixie Green": "C0D8B6", + "Pizazz": "FF9000", + "Pizza": "C99415", + "Plantation": "27504B", + "Plum": "843179", + "Pohutukawa": "8F021C", + "Polar": "E5F9F6", + "Polo Blue": "8DA8CC", + "Pomegranate": "F34723", + "Pompadour": "660045", + "Porcelain": "EFF2F3", + "Porsche": "EAAE69", + "Port Gore": "251F4F", + "Portafino": "FFFFB4", + "Portage": "8B9FEE", + "Portica": "F9E663", + "Pot Pourri": "F5E7E2", + "Potters Clay": "8C5738", + "Powder Ash": "BCC9C2", + "Powder Blue": "B0E0E6", + "Prairie Sand": "9A3820", + "Prelude": "D0C0E5", + "Prim": "F0E2EC", + "Primrose": "EDEA99", + "Provincial Pink": "FEF5F1", + "Prussian Blue": "003153", + "Puce": "CC8899", + "Pueblo": "7D2C14", + "Puerto Rico": "3FC1AA", + "Pumice": "C2CAC4", + "Pumpkin": "FF7518", + "Pumpkin Skin": "B1610B", + "Punch": "DC4333", + "Punga": "4D3D14", + "Purple": "660099", + "Purple Heart": "652DC1", + "Purple Mountain's Majesty": "9678B6", + "Purple Pizzazz": "FF00CC", + "Putty": "E7CD8C", + "Quarter Pearl Lusta": "FFFDF4", + "Quarter Spanish White": "F7F2E1", + "Quicksand": "BD978E", + "Quill Gray": "D6D6D1", + "Quincy": "623F2D", + "Racing Green": "0C1911", + "Radical Red": "FF355E", + "Raffia": "EADAB8", + "Rainee": "B9C8AC", + "Rajah": "F7B668", + "Rangitoto": "2E3222", + "Rangoon Green": "1C1E13", + "Raven": "727B89", + "Raw Sienna": "D27D46", + "Raw Umber": "734A12", + "Razzle Dazzle Rose": "FF33CC", + "Razzmatazz": "E30B5C", + "Rebel": "3C1206", + "Red": "FF0000", + "Red Beech": "7B3801", + "Red Berry": "8E0000", + "Red Damask": "DA6A41", + "Red Devil": "860111", + "Red Orange": "FF3F34", + "Red Oxide": "6E0902", + "Red Ribbon": "ED0A3F", + "Red Robin": "80341F", + "Red Stage": "D05F04", + "Red Violet": "C71585", + "Redwood": "5D1E0F", + "Reef": "C9FFA2", + "Reef Gold": "9F821C", + "Regal Blue": "013F6A", + "Regent Gray": "86949F", + "Regent St Blue": "AAD6E6", + "Remy": "FEEBF3", + "Reno Sand": "A86515", + "Resolution Blue": "002387", + "Revolver": "2C1632", + "Rhino": "2E3F62", + "Rice Cake": "FFFEF0", + "Rice Flower": "EEFFE2", + "Rich Gold": "A85307", + "Rio Grande": "BBD009", + "Ripe Lemon": "F4D81C", + "Ripe Plum": "410056", + "Riptide": "8BE6D8", + "River Bed": "434C59", + "Rob Roy": "EAC674", + "Robin's Egg Blue": "00CCCC", + "Rock": "4D3833", + "Rock Blue": "9EB1CD", + "Rock Spray": "BA450C", + "Rodeo Dust": "C9B29B", + "Rolling Stone": "747D83", + "Roman": "DE6360", + "Roman Coffee": "795D4C", + "Romance": "FFFEFD", + "Romantic": "FFD2B7", + "Ronchi": "ECC54E", + "Roof Terracotta": "A62F20", + "Rope": "8E4D1E", + "Rose": "FF007F", + "Rose Bud": "FBB2A3", + "Rose Bud Cherry": "800B47", + "Rose Fog": "E7BCB4", + "Rose White": "FFF6F5", + "Rose of Sharon": "BF5500", + "Rosewood": "65000B", + "Roti": "C6A84B", + "Rouge": "A23B6C", + "Royal Blue": "4169E1", + "Royal Heath": "AB3472", + "Royal Purple": "6B3FA0", + "Rum": "796989", + "Rum Swizzle": "F9F8E4", + "Russet": "80461B", + "Russett": "755A57", + "Rust": "B7410E", + "Rustic Red": "480404", + "Rusty Nail": "86560A", + "Saddle": "4C3024", + "Saddle Brown": "583401", + "Saffron": "F4C430", + "Saffron Mango": "F9BF58", + "Sage": "9EA587", + "Sahara": "B7A214", + "Sahara Sand": "F1E788", + "Sail": "B8E0F9", + "Salem": "097F4B", + "Salmon": "FF8C69", + "Salomie": "FEDB8D", + "Salt Box": "685E6E", + "Saltpan": "F1F7F2", + "Sambuca": "3A2010", + "San Felix": "0B6207", + "San Juan": "304B6A", + "San Marino": "456CAC", + "Sand Dune": "826F65", + "Sandal": "AA8D6F", + "Sandrift": "AB917A", + "Sandstone": "796D62", + "Sandwisp": "F5E7A2", + "Sandy Beach": "FFEAC8", + "Sandy brown": "F4A460", + "Sangria": "92000A", + "Sanguine Brown": "8D3D38", + "Santa Fe": "B16D52", + "Santas Gray": "9FA0B1", + "Sapling": "DED4A4", + "Sapphire": "2F519E", + "Saratoga": "555B10", + "Satin Linen": "E6E4D4", + "Sauvignon": "FFF5F3", + "Sazerac": "FFF4E0", + "Scampi": "675FA6", + "Scandal": "CFFAF4", + "Scarlet": "FF2400", + "Scarlet Gum": "431560", + "Scarlett": "950015", + "Scarpa Flow": "585562", + "Schist": "A9B497", + "School bus Yellow": "FFD800", + "Schooner": "8B847E", + "Science Blue": "0066CC", + "Scooter": "2EBFD4", + "Scorpion": "695F62", + "Scotch Mist": "FFFBDC", + "Screamin' Green": "66FF66", + "Sea Buckthorn": "FBA129", + "Sea Green": "2E8B57", + "Sea Mist": "C5DBCA", + "Sea Nymph": "78A39C", + "Sea Pink": "ED989E", + "Seagull": "80CCEA", + "Seance": "731E8F", + "Seashell": "F1F1F1", + "Seashell Peach": "FFF5EE", + "Seaweed": "1B2F11", + "Selago": "F0EEFD", + "Selective Yellow": "FFBA00", + "Sepia": "704214", + "Sepia Black": "2B0202", + "Sepia Skin": "9E5B40", + "Serenade": "FFF4E8", + "Shadow": "837050", + "Shadow Green": "9AC2B8", + "Shady Lady": "AAA5A9", + "Shakespeare": "4EABD1", + "Shalimar": "FBFFBA", + "Shamrock": "33CC99", + "Shark": "25272C", + "Sherpa Blue": "004950", + "Sherwood Green": "02402C", + "Shilo": "E8B9B3", + "Shingle Fawn": "6B4E31", + "Ship Cove": "788BBA", + "Ship Gray": "3E3A44", + "Shiraz": "B20931", + "Shocking": "E292C0", + "Shocking Pink": "FC0FC0", + "Shuttle Gray": "5F6672", + "Siam": "646A54", + "Sidecar": "F3E7BB", + "Silk": "BDB1A8", + "Silver": "C0C0C0", + "Silver Chalice": "ACACAC", + "Silver Rust": "C9C0BB", + "Silver Sand": "BFC1C2", + "Silver Tree": "66B58F", + "Sinbad": "9FD7D3", + "Siren": "7A013A", + "Sirocco": "718080", + "Sisal": "D3CBBA", + "Skeptic": "CAE6DA", + "Sky Blue": "76D7EA", + "Slate Gray": "708090", + "Smalt": "003399", + "Smalt Blue": "51808F", + "Smoky": "605B73", + "Snow Drift": "F7FAF7", + "Snow Flurry": "E4FFD1", + "Snowy Mint": "D6FFDB", + "Snuff": "E2D8ED", + "Soapstone": "FFFBF9", + "Soft Amber": "D1C6B4", + "Soft Peach": "F5EDEF", + "Solid Pink": "893843", + "Solitaire": "FEF8E2", + "Solitude": "EAF6FF", + "Sorbus": "FD7C07", + "Sorrell Brown": "CEB98F", + "Soya Bean": "6A6051", + "Spanish Green": "819885", + "Spectra": "2F5A57", + "Spice": "6A442E", + "Spicy Mix": "885342", + "Spicy Mustard": "74640D", + "Spicy Pink": "816E71", + "Spindle": "B6D1EA", + "Spray": "79DEEC", + "Spring Green": "00FF7F", + "Spring Leaves": "578363", + "Spring Rain": "ACCBB1", + "Spring Sun": "F6FFDC", + "Spring Wood": "F8F6F1", + "Sprout": "C1D7B0", + "Spun Pearl": "AAABB7", + "Squirrel": "8F8176", + "St Tropaz": "2D569B", + "Stack": "8A8F8A", + "Star Dust": "9F9F9C", + "Stark White": "E5D7BD", + "Starship": "ECF245", + "Steel Blue": "4682B4", + "Steel Gray": "262335", + "Stiletto": "9C3336", + "Stonewall": "928573", + "Storm Dust": "646463", + "Storm Gray": "717486", + "Stratos": "000741", + "Straw": "D4BF8D", + "Strikemaster": "956387", + "Stromboli": "325D52", + "Studio": "714AB2", + "Submarine": "BAC7C9", + "Sugar Cane": "F9FFF6", + "Sulu": "C1F07C", + "Summer Green": "96BBAB", + "Sun": "FBAC13", + "Sundance": "C9B35B", + "Sundown": "FFB1B3", + "Sunflower": "E4D422", + "Sunglo": "E16865", + "Sunglow": "FFCC33", + "Sunset Orange": "FE4C40", + "Sunshade": "FF9E2C", + "Supernova": "FFC901", + "Surf": "BBD7C1", + "Surf Crest": "CFE5D2", + "Surfie Green": "0C7A79", + "Sushi": "87AB39", + "Suva Gray": "888387", + "Swamp": "001B1C", + "Swamp Green": "ACB78E", + "Swans Down": "DCF0EA", + "Sweet Corn": "FBEA8C", + "Sweet Pink": "FD9FA2", + "Swirl": "D3CDC5", + "Swiss Coffee": "DDD6D5", + "Sycamore": "908D39", + "Tabasco": "A02712", + "Tacao": "EDB381", + "Tacha": "D6C562", + "Tahiti Gold": "E97C07", + "Tahuna Sands": "EEF0C8", + "Tall Poppy": "B32D29", + "Tallow": "A8A589", + "Tamarillo": "991613", + "Tamarind": "341515", + "Tan": "D2B48C", + "Tan Hide": "FA9D5A", + "Tana": "D9DCC1", + "Tangaroa": "03163C", + "Tangerine": "F28500", + "Tango": "ED7A1C", + "Tapa": "7B7874", + "Tapestry": "B05E81", + "Tara": "E1F6E8", + "Tarawera": "073A50", + "Tasman": "CFDCCF", + "Taupe": "483C32", + "Taupe Gray": "B3AF95", + "Tawny Port": "692545", + "Te Papa Green": "1E433C", + "Tea": "C1BAB0", + "Tea Green": "D0F0C0", + "Teak": "B19461", + "Teal": "008080", + "Teal Blue": "044259", + "Temptress": "3B000B", + "Tenn": "CD5700", + "Tequila": "FFE6C7", + "Terracotta": "E2725B", + "Texas": "F8F99C", + "Texas Rose": "FFB555", + "Thatch": "B69D98", + "Thatch Green": "403D19", + "Thistle": "D8BFD8", + "Thistle Green": "CCCAA8", + "Thunder": "33292F", + "Thunderbird": "C02B18", + "Tia Maria": "C1440E", + "Tiara": "C3D1D1", + "Tiber": "063537", + "Tickle Me Pink": "FC80A5", + "Tidal": "F1FFAD", + "Tide": "BFB8B0", + "Timber Green": "16322C", + "Timberwolf": "D9D6CF", + "Titan White": "F0EEFF", + "Toast": "9A6E61", + "Tobacco Brown": "715D47", + "Toledo": "3A0020", + "Tolopea": "1B0245", + "Tom Thumb": "3F583B", + "Tonys Pink": "E79F8C", + "Topaz": "7C778A", + "Torch Red": "FD0E35", + "Torea Bay": "0F2D9E", + "Tory Blue": "1450AA", + "Tosca": "8D3F3F", + "Totem Pole": "991B07", + "Tower Gray": "A9BDBF", + "Tradewind": "5FB3AC", + "Tranquil": "E6FFFF", + "Travertine": "FFFDE8", + "Tree Poppy": "FC9C1D", + "Treehouse": "3B2820", + "Trendy Green": "7C881A", + "Trendy Pink": "8C6495", + "Trinidad": "E64E03", + "Tropical Blue": "C3DDF9", + "Tropical Rain Forest": "00755E", + "Trout": "4A4E5A", + "True V": "8A73D6", + "Tuatara": "363534", + "Tuft Bush": "FFDDCD", + "Tulip Tree": "EAB33B", + "Tumbleweed": "DEA681", + "Tuna": "353542", + "Tundora": "4A4244", + "Turbo": "FAE600", + "Turkish Rose": "B57281", + "Turmeric": "CABB48", + "Turquoise": "30D5C8", + "Turquoise Blue": "6CDAE7", + "Turtle Green": "2A380B", + "Tuscany": "BD5E2E", + "Tusk": "EEF3C3", + "Tussock": "C5994B", + "Tutu": "FFF1F9", + "Twilight": "E4CFDE", + "Twilight Blue": "EEFDFF", + "Twine": "C2955D", + "Tyrian Purple": "66023C", + "Ultramarine": "120A8F", + "Valencia": "D84437", + "Valentino": "350E42", + "Valhalla": "2B194F", + "Van Cleef": "49170C", + "Vanilla": "D1BEA8", + "Vanilla Ice": "F3D9DF", + "Varden": "FFF6DF", + "Venetian Red": "72010F", + "Venice Blue": "055989", + "Venus": "928590", + "Verdigris": "5D5E37", + "Verdun Green": "495400", + "Vermilion": "FF4D00", + "Vesuvius": "B14A0B", + "Victoria": "534491", + "Vida Loca": "549019", + "Viking": "64CCDB", + "Vin Rouge": "983D61", + "Viola": "CB8FA9", + "Violent Violet": "290C5E", + "Violet": "240A40", + "Violet Eggplant": "991199", + "Violet Red": "F7468A", + "Viridian": "40826D", + "Viridian Green": "678975", + "Vis Vis": "FFEFA1", + "Vista Blue": "8FD6B4", + "Vista White": "FCF8F7", + "Vivid Tangerine": "FF9980", + "Vivid Violet": "803790", + "Voodoo": "533455", + "Vulcan": "10121D", + "Wafer": "DECBC6", + "Waikawa Gray": "5A6E9C", + "Waiouru": "363C0D", + "Walnut": "773F1A", + "Wasabi": "788A25", + "Water Leaf": "A1E9DE", + "Watercourse": "056F57", + "Waterloo ": "7B7C94", + "Wattle": "DCD747", + "Watusi": "FFDDCF", + "Wax Flower": "FFC0A8", + "We Peep": "F7DBE6", + "Web Orange": "FFA500", + "Wedgewood": "4E7F9E", + "Well Read": "B43332", + "West Coast": "625119", + "West Side": "FF910F", + "Westar": "DCD9D2", + "Wewak": "F19BAB", + "Wheat": "F5DEB3", + "Wheatfield": "F3EDCF", + "Whiskey": "D59A6F", + "Whisper": "F7F5FA", + "White": "FFFFFF", + "White Ice": "DDF9F1", + "White Lilac": "F8F7FC", + "White Linen": "F8F0E8", + "White Pointer": "FEF8FF", + "White Rock": "EAE8D4", + "Wild Blue Yonder": "7A89B8", + "Wild Rice": "ECE090", + "Wild Sand": "F4F4F4", + "Wild Strawberry": "FF3399", + "Wild Watermelon": "FD5B78", + "Wild Willow": "B9C46A", + "William": "3A686C", + "Willow Brook": "DFECDA", + "Willow Grove": "65745D", + "Windsor": "3C0878", + "Wine Berry": "591D35", + "Winter Hazel": "D5D195", + "Wisp Pink": "FEF4F8", + "Wisteria": "9771B5", + "Wistful": "A4A6D3", + "Witch Haze": "FFFC99", + "Wood Bark": "261105", + "Woodland": "4D5328", + "Woodrush": "302A0F", + "Woodsmoke": "0C0D0F", + "Woody Brown": "483131", + "Xanadu": "738678", + "Yellow": "FFFF00", + "Yellow Green": "C5E17A", + "Yellow Metal": "716338", + "Yellow Orange": "FFAE42", + "Yellow Sea": "FEA904", + "Your Pink": "FFC3C0", + "Yukon Gold": "7B6608", + "Yuma": "CEC291", + "Zambezi": "685558", + "Zanah": "DAECD6", + "Zest": "E5841B", + "Zeus": "292319", + "Ziggurat": "BFDBE2", + "Zinnwaldite": "EBC2AF", + "Zircon": "F4F8FF", + "Zombie": "E4D69B", + "Zorba": "A59B91", + "Zuccini": "044022", + "Zumthor": "EDF6FF" +} \ No newline at end of file -- cgit v1.2.3 From 663b52857913f9fc32d753ed2959afab15a97375 Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sat, 4 Sep 2021 17:40:02 +0530 Subject: Added ryanzec_colours.json constructed from ryanzec/name-that-color Original source: https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681 --- bot/resources/evergreen/ryanzec_colours.json | 1568 ++++++++++++++++++++++++++ 1 file changed, 1568 insertions(+) create mode 100644 bot/resources/evergreen/ryanzec_colours.json diff --git a/bot/resources/evergreen/ryanzec_colours.json b/bot/resources/evergreen/ryanzec_colours.json new file mode 100644 index 00000000..7b89f052 --- /dev/null +++ b/bot/resources/evergreen/ryanzec_colours.json @@ -0,0 +1,1568 @@ +{ + "Abbey": "4C4F56", + "Acadia": "1B1404", + "Acapulco": "7CB0A1", + "Aero Blue": "C9FFE5", + "Affair": "714693", + "Akaroa": "D4C4A8", + "Alabaster": "FAFAFA", + "Albescent White": "F5E9D3", + "Algae Green": "93DFB8", + "Alice Blue": "F0F8FF", + "Alizarin Crimson": "E32636", + "Allports": "0076A3", + "Almond": "EED9C4", + "Almond Frost": "907B71", + "Alpine": "AF8F2C", + "Alto": "DBDBDB", + "Aluminium": "A9ACB6", + "Amaranth": "E52B50", + "Amazon": "3B7A57", + "Amber": "FFBF00", + "Americano": "87756E", + "Amethyst": "9966CC", + "Amethyst Smoke": "A397B4", + "Amour": "F9EAF3", + "Amulet": "7B9F80", + "Anakiwa": "9DE5FF", + "Antique Brass": "C88A65", + "Antique Bronze": "704A07", + "Anzac": "E0B646", + "Apache": "DFBE6F", + "Apple": "4FA83D", + "Apple Blossom": "AF4D43", + "Apple Green": "E2F3EC", + "Apricot": "EB9373", + "Apricot Peach": "FBCEB1", + "Apricot White": "FFFEEC", + "Aqua Deep": "014B43", + "Aqua Forest": "5FA777", + "Aqua Haze": "EDF5F5", + "Aqua Island": "A1DAD7", + "Aqua Spring": "EAF9F5", + "Aqua Squeeze": "E8F5F2", + "Aquamarine": "7FFFD4", + "Aquamarine Blue": "71D9E2", + "Arapawa": "110C6C", + "Armadillo": "433E37", + "Arrowtown": "948771", + "Ash": "C6C3B5", + "Asparagus": "7BA05B", + "Asphalt": "130A06", + "Astra": "FAEAB9", + "Astral": "327DA0", + "Astronaut": "283A77", + "Astronaut Blue": "013E62", + "Athens Gray": "EEF0F3", + "Aths Special": "ECEBCE", + "Atlantis": "97CD2D", + "Atoll": "0A6F75", + "Atomic Tangerine": "FF9966", + "Au Chico": "97605D", + "Aubergine": "3B0910", + "Australian Mint": "F5FFBE", + "Avocado": "888D65", + "Axolotl": "4E6649", + "Azalea": "F7C8DA", + "Aztec": "0D1C19", + "Azure": "315BA1", + "Azure Radiance": "007FFF", + "Baby Blue": "E0FFFF", + "Bahama Blue": "026395", + "Bahia": "A5CB0C", + "Baja White": "FFF8D1", + "Bali Hai": "859FAF", + "Baltic Sea": "2A2630", + "Bamboo": "DA6304", + "Banana Mania": "FBE7B2", + "Bandicoot": "858470", + "Barberry": "DED717", + "Barley Corn": "A68B5B", + "Barley White": "FFF4CE", + "Barossa": "44012D", + "Bastille": "292130", + "Battleship Gray": "828F72", + "Bay Leaf": "7DA98D", + "Bay of Many": "273A81", + "Bazaar": "98777B", + "Bean ": "3D0C02", + "Beauty Bush": "EEC1BE", + "Beaver": "926F5B", + "Beeswax": "FEF2C7", + "Beige": "F5F5DC", + "Bermuda": "7DD8C6", + "Bermuda Gray": "6B8BA2", + "Beryl Green": "DEE5C0", + "Bianca": "FCFBF3", + "Big Stone": "162A40", + "Bilbao": "327C14", + "Biloba Flower": "B2A1EA", + "Birch": "373021", + "Bird Flower": "D4CD16", + "Biscay": "1B3162", + "Bismark": "497183", + "Bison Hide": "C1B7A4", + "Bistre": "3D2B1F", + "Bitter": "868974", + "Bitter Lemon": "CAE00D", + "Bittersweet": "FE6F5E", + "Bizarre": "EEDEDA", + "Black": "000000", + "Black Bean": "081910", + "Black Forest": "0B1304", + "Black Haze": "F6F7F7", + "Black Marlin": "3E2C1C", + "Black Olive": "242E16", + "Black Pearl": "041322", + "Black Rock": "0D0332", + "Black Rose": "67032D", + "Black Russian": "0A001C", + "Black Squeeze": "F2FAFA", + "Black White": "FFFEF6", + "Blackberry": "4D0135", + "Blackcurrant": "32293A", + "Blaze Orange": "FF6600", + "Bleach White": "FEF3D8", + "Bleached Cedar": "2C2133", + "Blizzard Blue": "A3E3ED", + "Blossom": "DCB4BC", + "Blue": "0000FF", + "Blue Bayoux": "496679", + "Blue Bell": "9999CC", + "Blue Chalk": "F1E9FF", + "Blue Charcoal": "010D1A", + "Blue Chill": "0C8990", + "Blue Diamond": "380474", + "Blue Dianne": "204852", + "Blue Gem": "2C0E8C", + "Blue Haze": "BFBED8", + "Blue Lagoon": "017987", + "Blue Marguerite": "7666C6", + "Blue Ribbon": "0066FF", + "Blue Romance": "D2F6DE", + "Blue Smoke": "748881", + "Blue Stone": "016162", + "Blue Violet": "6456B7", + "Blue Whale": "042E4C", + "Blue Zodiac": "13264D", + "Blumine": "18587A", + "Blush": "B44668", + "Blush Pink": "FF6FFF", + "Bombay": "AFB1B8", + "Bon Jour": "E5E0E1", + "Bondi Blue": "0095B6", + "Bone": "E4D1C0", + "Bordeaux": "5C0120", + "Bossanova": "4E2A5A", + "Boston Blue": "3B91B4", + "Botticelli": "C7DDE5", + "Bottle Green": "093624", + "Boulder": "7A7A7A", + "Bouquet": "AE809E", + "Bourbon": "BA6F1E", + "Bracken": "4A2A04", + "Brandy": "DEC196", + "Brandy Punch": "CD8429", + "Brandy Rose": "BB8983", + "Breaker Bay": "5DA19F", + "Brick Red": "C62D42", + "Bridal Heath": "FFFAF4", + "Bridesmaid": "FEF0EC", + "Bright Gray": "3C4151", + "Bright Green": "66FF00", + "Bright Red": "B10000", + "Bright Sun": "FED33C", + "Bright Turquoise": "08E8DE", + "Brilliant Rose": "F653A6", + "Brink Pink": "FB607F", + "Bronco": "ABA196", + "Bronze": "3F2109", + "Bronze Olive": "4E420C", + "Bronzetone": "4D400F", + "Broom": "FFEC13", + "Brown": "964B00", + "Brown Bramble": "592804", + "Brown Derby": "492615", + "Brown Pod": "401801", + "Brown Rust": "AF593E", + "Brown Tumbleweed": "37290E", + "Bubbles": "E7FEFF", + "Buccaneer": "622F30", + "Bud": "A8AE9C", + "Buddha Gold": "C1A004", + "Buff": "F0DC82", + "Bulgarian Rose": "480607", + "Bull Shot": "864D1E", + "Bunker": "0D1117", + "Bunting": "151F4C", + "Burgundy": "900020", + "Burnham": "002E20", + "Burning Orange": "FF7034", + "Burning Sand": "D99376", + "Burnt Maroon": "420303", + "Burnt Orange": "CC5500", + "Burnt Sienna": "E97451", + "Burnt Umber": "8A3324", + "Bush": "0D2E1C", + "Buttercup": "F3AD16", + "Buttered Rum": "A1750D", + "Butterfly Bush": "624E9A", + "Buttermilk": "FFF1B5", + "Buttery White": "FFFCEA", + "Cab Sav": "4D0A18", + "Cabaret": "D94972", + "Cabbage Pont": "3F4C3A", + "Cactus": "587156", + "Cadet Blue": "A9B2C3", + "Cadillac": "B04C6A", + "Cafe Royale": "6F440C", + "Calico": "E0C095", + "California": "FE9D04", + "Calypso": "31728D", + "Camarone": "00581A", + "Camelot": "893456", + "Cameo": "D9B99B", + "Camouflage": "3C3910", + "Camouflage Green": "78866B", + "Can Can": "D591A4", + "Canary": "F3FB62", + "Candlelight": "FCD917", + "Candy Corn": "FBEC5D", + "Cannon Black": "251706", + "Cannon Pink": "894367", + "Cape Cod": "3C4443", + "Cape Honey": "FEE5AC", + "Cape Palliser": "A26645", + "Caper": "DCEDB4", + "Caramel": "FFDDAF", + "Cararra": "EEEEE8", + "Cardin Green": "01361C", + "Cardinal": "C41E3A", + "Cardinal Pink": "8C055E", + "Careys Pink": "D29EAA", + "Caribbean Green": "00CC99", + "Carissma": "EA88A8", + "Carla": "F3FFD8", + "Carmine": "960018", + "Carnaby Tan": "5C2E01", + "Carnation": "F95A61", + "Carnation Pink": "FFA6C9", + "Carousel Pink": "F9E0ED", + "Carrot Orange": "ED9121", + "Casablanca": "F8B853", + "Casal": "2F6168", + "Cascade": "8BA9A5", + "Cashmere": "E6BEA5", + "Casper": "ADBED1", + "Castro": "52001F", + "Catalina Blue": "062A78", + "Catskill White": "EEF6F7", + "Cavern Pink": "E3BEBE", + "Cedar": "3E1C14", + "Cedar Wood Finish": "711A00", + "Celadon": "ACE1AF", + "Celery": "B8C25D", + "Celeste": "D1D2CA", + "Cello": "1E385B", + "Celtic": "163222", + "Cement": "8D7662", + "Ceramic": "FCFFF9", + "Cerise": "DA3287", + "Cerise Red": "DE3163", + "Cerulean": "02A4D3", + "Cerulean Blue": "2A52BE", + "Chablis": "FFF4F3", + "Chalet Green": "516E3D", + "Chalky": "EED794", + "Chambray": "354E8C", + "Chamois": "EDDCB1", + "Champagne": "FAECCC", + "Chantilly": "F8C3DF", + "Charade": "292937", + "Chardon": "FFF3F1", + "Chardonnay": "FFCD8C", + "Charlotte": "BAEEF9", + "Charm": "D47494", + "Chartreuse": "7FFF00", + "Chartreuse Yellow": "DFFF00", + "Chateau Green": "40A860", + "Chatelle": "BDB3C7", + "Chathams Blue": "175579", + "Chelsea Cucumber": "83AA5D", + "Chelsea Gem": "9E5302", + "Chenin": "DFCD6F", + "Cherokee": "FCDA98", + "Cherry Pie": "2A0359", + "Cherrywood": "651A14", + "Cherub": "F8D9E9", + "Chestnut": "B94E48", + "Chestnut Rose": "CD5C5C", + "Chetwode Blue": "8581D9", + "Chicago": "5D5C58", + "Chiffon": "F1FFC8", + "Chilean Fire": "F77703", + "Chilean Heath": "FFFDE6", + "China Ivory": "FCFFE7", + "Chino": "CEC7A7", + "Chinook": "A8E3BD", + "Chocolate": "370202", + "Christalle": "33036B", + "Christi": "67A712", + "Christine": "E7730A", + "Chrome White": "E8F1D4", + "Cinder": "0E0E18", + "Cinderella": "FDE1DC", + "Cinnabar": "E34234", + "Cinnamon": "7B3F00", + "Cioccolato": "55280C", + "Citrine White": "FAF7D6", + "Citron": "9EA91F", + "Citrus": "A1C50A", + "Clairvoyant": "480656", + "Clam Shell": "D4B6AF", + "Claret": "7F1734", + "Classic Rose": "FBCCE7", + "Clay Ash": "BDC8B3", + "Clay Creek": "8A8360", + "Clear Day": "E9FFFD", + "Clementine": "E96E00", + "Clinker": "371D09", + "Cloud": "C7C4BF", + "Cloud Burst": "202E54", + "Cloudy": "ACA59F", + "Clover": "384910", + "Cobalt": "0047AB", + "Cocoa Bean": "481C1C", + "Cocoa Brown": "301F1E", + "Coconut Cream": "F8F7DC", + "Cod Gray": "0B0B0B", + "Coffee": "706555", + "Coffee Bean": "2A140E", + "Cognac": "9F381D", + "Cola": "3F2500", + "Cold Purple": "ABA0D9", + "Cold Turkey": "CEBABA", + "Colonial White": "FFEDBC", + "Comet": "5C5D75", + "Como": "517C66", + "Conch": "C9D9D2", + "Concord": "7C7B7A", + "Concrete": "F2F2F2", + "Confetti": "E9D75A", + "Congo Brown": "593737", + "Congress Blue": "02478E", + "Conifer": "ACDD4D", + "Contessa": "C6726B", + "Copper": "B87333", + "Copper Canyon": "7E3A15", + "Copper Rose": "996666", + "Copper Rust": "944747", + "Copperfield": "DA8A67", + "Coral": "FF7F50", + "Coral Red": "FF4040", + "Coral Reef": "C7BCA2", + "Coral Tree": "A86B6B", + "Corduroy": "606E68", + "Coriander": "C4D0B0", + "Cork": "40291D", + "Corn": "E7BF05", + "Corn Field": "F8FACD", + "Corn Harvest": "8B6B0B", + "Cornflower": "93CCEA", + "Cornflower Blue": "6495ED", + "Cornflower Lilac": "FFB0AC", + "Corvette": "FAD3A2", + "Cosmic": "76395D", + "Cosmos": "FFD8D9", + "Costa Del Sol": "615D30", + "Cotton Candy": "FFB7D5", + "Cotton Seed": "C2BDB6", + "County Green": "01371A", + "Cowboy": "4D282D", + "Crail": "B95140", + "Cranberry": "DB5079", + "Crater Brown": "462425", + "Cream": "FFFDD0", + "Cream Brulee": "FFE5A0", + "Cream Can": "F5C85C", + "Creole": "1E0F04", + "Crete": "737829", + "Crimson": "DC143C", + "Crocodile": "736D58", + "Crown of Thorns": "771F1F", + "Crowshead": "1C1208", + "Cruise": "B5ECDF", + "Crusoe": "004816", + "Crusta": "FD7B33", + "Cumin": "924321", + "Cumulus": "FDFFD5", + "Cupid": "FBBEDA", + "Curious Blue": "2596D1", + "Cutty Sark": "507672", + "Cyan / Aqua": "00FFFF", + "Cyprus": "003E40", + "Daintree": "012731", + "Dairy Cream": "F9E4BC", + "Daisy Bush": "4F2398", + "Dallas": "6E4B26", + "Dandelion": "FED85D", + "Danube": "6093D1", + "Dark Blue": "0000C8", + "Dark Burgundy": "770F05", + "Dark Ebony": "3C2005", + "Dark Fern": "0A480D", + "Dark Tan": "661010", + "Dawn": "A6A29A", + "Dawn Pink": "F3E9E5", + "De York": "7AC488", + "Deco": "D2DA97", + "Deep Blue": "220878", + "Deep Blush": "E47698", + "Deep Bronze": "4A3004", + "Deep Cerulean": "007BA7", + "Deep Cove": "051040", + "Deep Fir": "002900", + "Deep Forest Green": "182D09", + "Deep Koamaru": "1B127B", + "Deep Oak": "412010", + "Deep Sapphire": "082567", + "Deep Sea": "01826B", + "Deep Sea Green": "095859", + "Deep Teal": "003532", + "Del Rio": "B09A95", + "Dell": "396413", + "Delta": "A4A49D", + "Deluge": "7563A8", + "Denim": "1560BD", + "Derby": "FFEED8", + "Desert": "AE6020", + "Desert Sand": "EDC9AF", + "Desert Storm": "F8F8F7", + "Dew": "EAFFFE", + "Di Serria": "DB995E", + "Diesel": "130000", + "Dingley": "5D7747", + "Disco": "871550", + "Dixie": "E29418", + "Dodger Blue": "1E90FF", + "Dolly": "F9FF8B", + "Dolphin": "646077", + "Domino": "8E775E", + "Don Juan": "5D4C51", + "Donkey Brown": "A69279", + "Dorado": "6B5755", + "Double Colonial White": "EEE3AD", + "Double Pearl Lusta": "FCF4D0", + "Double Spanish White": "E6D7B9", + "Dove Gray": "6D6C6C", + "Downriver": "092256", + "Downy": "6FD0C5", + "Driftwood": "AF8751", + "Drover": "FDF7AD", + "Dull Lavender": "A899E6", + "Dune": "383533", + "Dust Storm": "E5CCC9", + "Dusty Gray": "A8989B", + "Eagle": "B6BAA4", + "Earls Green": "C9B93B", + "Early Dawn": "FFF9E6", + "East Bay": "414C7D", + "East Side": "AC91CE", + "Eastern Blue": "1E9AB0", + "Ebb": "E9E3E3", + "Ebony": "0C0B1D", + "Ebony Clay": "26283B", + "Eclipse": "311C17", + "Ecru White": "F5F3E5", + "Ecstasy": "FA7814", + "Eden": "105852", + "Edgewater": "C8E3D7", + "Edward": "A2AEAB", + "Egg Sour": "FFF4DD", + "Egg White": "FFEFC1", + "Eggplant": "614051", + "El Paso": "1E1708", + "El Salva": "8F3E33", + "Electric Lime": "CCFF00", + "Electric Violet": "8B00FF", + "Elephant": "123447", + "Elf Green": "088370", + "Elm": "1C7C7D", + "Emerald": "50C878", + "Eminence": "6C3082", + "Emperor": "514649", + "Empress": "817377", + "Endeavour": "0056A7", + "Energy Yellow": "F8DD5C", + "English Holly": "022D15", + "English Walnut": "3E2B23", + "Envy": "8BA690", + "Equator": "E1BC64", + "Espresso": "612718", + "Eternity": "211A0E", + "Eucalyptus": "278A5B", + "Eunry": "CFA39D", + "Evening Sea": "024E46", + "Everglade": "1C402E", + "Faded Jade": "427977", + "Fair Pink": "FFEFEC", + "Falcon": "7F626D", + "Fall Green": "ECEBBD", + "Falu Red": "801818", + "Fantasy": "FAF3F0", + "Fedora": "796A78", + "Feijoa": "9FDD8C", + "Fern": "63B76C", + "Fern Frond": "657220", + "Fern Green": "4F7942", + "Ferra": "704F50", + "Festival": "FBE96C", + "Feta": "F0FCEA", + "Fiery Orange": "B35213", + "Finch": "626649", + "Finlandia": "556D56", + "Finn": "692D54", + "Fiord": "405169", + "Fire": "AA4203", + "Fire Bush": "E89928", + "Firefly": "0E2A30", + "Flame Pea": "DA5B38", + "Flamenco": "FF7D07", + "Flamingo": "F2552A", + "Flax": "EEDC82", + "Flax Smoke": "7B8265", + "Flesh": "FFCBA4", + "Flint": "6F6A61", + "Flirt": "A2006D", + "Flush Mahogany": "CA3435", + "Flush Orange": "FF7F00", + "Foam": "D8FCFA", + "Fog": "D7D0FF", + "Foggy Gray": "CBCAB6", + "Forest Green": "228B22", + "Forget Me Not": "FFF1EE", + "Fountain Blue": "56B4BE", + "Frangipani": "FFDEB3", + "French Gray": "BDBDC6", + "French Lilac": "ECC7EE", + "French Pass": "BDEDFD", + "French Rose": "F64A8A", + "Fresh Eggplant": "990066", + "Friar Gray": "807E79", + "Fringy Flower": "B1E2C1", + "Froly": "F57584", + "Frost": "EDF5DD", + "Frosted Mint": "DBFFF8", + "Frostee": "E4F6E7", + "Fruit Salad": "4F9D5D", + "Fuchsia Blue": "7A58C1", + "Fuchsia Pink": "C154C1", + "Fuego": "BEDE0D", + "Fuel Yellow": "ECA927", + "Fun Blue": "1959A8", + "Fun Green": "016D39", + "Fuscous Gray": "54534D", + "Fuzzy Wuzzy Brown": "C45655", + "Gable Green": "163531", + "Gallery": "EFEFEF", + "Galliano": "DCB20C", + "Gamboge": "E49B0F", + "Geebung": "D18F1B", + "Genoa": "15736B", + "Geraldine": "FB8989", + "Geyser": "D4DFE2", + "Ghost": "C7C9D5", + "Gigas": "523C94", + "Gimblet": "B8B56A", + "Gin": "E8F2EB", + "Gin Fizz": "FFF9E2", + "Givry": "F8E4BF", + "Glacier": "80B3C4", + "Glade Green": "61845F", + "Go Ben": "726D4E", + "Goblin": "3D7D52", + "Gold": "FFD700", + "Gold Drop": "F18200", + "Gold Sand": "E6BE8A", + "Gold Tips": "DEBA13", + "Golden Bell": "E28913", + "Golden Dream": "F0D52D", + "Golden Fizz": "F5FB3D", + "Golden Glow": "FDE295", + "Golden Grass": "DAA520", + "Golden Sand": "F0DB7D", + "Golden Tainoi": "FFCC5C", + "Goldenrod": "FCD667", + "Gondola": "261414", + "Gordons Green": "0B1107", + "Gorse": "FFF14F", + "Gossamer": "069B81", + "Gossip": "D2F8B0", + "Gothic": "6D92A1", + "Governor Bay": "2F3CB3", + "Grain Brown": "E4D5B7", + "Grandis": "FFD38C", + "Granite Green": "8D8974", + "Granny Apple": "D5F6E3", + "Granny Smith": "84A0A0", + "Granny Smith Apple": "9DE093", + "Grape": "381A51", + "Graphite": "251607", + "Gravel": "4A444B", + "Gray": "808080", + "Gray Asparagus": "465945", + "Gray Chateau": "A2AAB3", + "Gray Nickel": "C3C3BD", + "Gray Nurse": "E7ECE6", + "Gray Olive": "A9A491", + "Gray Suit": "C1BECD", + "Green": "00FF00", + "Green Haze": "01A368", + "Green House": "24500F", + "Green Kelp": "25311C", + "Green Leaf": "436A0D", + "Green Mist": "CBD3B0", + "Green Pea": "1D6142", + "Green Smoke": "A4AF6E", + "Green Spring": "B8C1B1", + "Green Vogue": "032B52", + "Green Waterloo": "101405", + "Green White": "E8EBE0", + "Green Yellow": "ADFF2F", + "Grenadier": "D54600", + "Guardsman Red": "BA0101", + "Gulf Blue": "051657", + "Gulf Stream": "80B3AE", + "Gull Gray": "9DACB7", + "Gum Leaf": "B6D3BF", + "Gumbo": "7CA1A6", + "Gun Powder": "414257", + "Gunsmoke": "828685", + "Gurkha": "9A9577", + "Hacienda": "98811B", + "Hairy Heath": "6B2A14", + "Haiti": "1B1035", + "Half Baked": "85C4CC", + "Half Colonial White": "FDF6D3", + "Half Dutch White": "FEF7DE", + "Half Spanish White": "FEF4DB", + "Half and Half": "FFFEE1", + "Hampton": "E5D8AF", + "Harlequin": "3FFF00", + "Harp": "E6F2EA", + "Harvest Gold": "E0B974", + "Havelock Blue": "5590D9", + "Hawaiian Tan": "9D5616", + "Hawkes Blue": "D4E2FC", + "Heath": "541012", + "Heather": "B7C3D0", + "Heathered Gray": "B6B095", + "Heavy Metal": "2B3228", + "Heliotrope": "DF73FF", + "Hemlock": "5E5D3B", + "Hemp": "907874", + "Hibiscus": "B6316C", + "Highland": "6F8E63", + "Hillary": "ACA586", + "Himalaya": "6A5D1B", + "Hint of Green": "E6FFE9", + "Hint of Red": "FBF9F9", + "Hint of Yellow": "FAFDE4", + "Hippie Blue": "589AAF", + "Hippie Green": "53824B", + "Hippie Pink": "AE4560", + "Hit Gray": "A1ADB5", + "Hit Pink": "FFAB81", + "Hokey Pokey": "C8A528", + "Hoki": "65869F", + "Holly": "011D13", + "Hollywood Cerise": "F400A1", + "Honey Flower": "4F1C70", + "Honeysuckle": "EDFC84", + "Hopbush": "D06DA1", + "Horizon": "5A87A0", + "Horses Neck": "604913", + "Hot Cinnamon": "D2691E", + "Hot Pink": "FF69B4", + "Hot Toddy": "B38007", + "Humming Bird": "CFF9F3", + "Hunter Green": "161D10", + "Hurricane": "877C7B", + "Husk": "B7A458", + "Ice Cold": "B1F4E7", + "Iceberg": "DAF4F0", + "Illusion": "F6A4C9", + "Inch Worm": "B0E313", + "Indian Khaki": "C3B091", + "Indian Tan": "4D1E01", + "Indigo": "4F69C6", + "Indochine": "C26B03", + "International Klein Blue": "002FA7", + "International Orange": "FF4F00", + "Irish Coffee": "5F3D26", + "Iroko": "433120", + "Iron": "D4D7D9", + "Ironside Gray": "676662", + "Ironstone": "86483C", + "Island Spice": "FFFCEE", + "Ivory": "FFFFF0", + "Jacaranda": "2E0329", + "Jacarta": "3A2A6A", + "Jacko Bean": "2E1905", + "Jacksons Purple": "20208D", + "Jade": "00A86B", + "Jaffa": "EF863F", + "Jagged Ice": "C2E8E5", + "Jagger": "350E57", + "Jaguar": "080110", + "Jambalaya": "5B3013", + "Janna": "F4EBD3", + "Japanese Laurel": "0A6906", + "Japanese Maple": "780109", + "Japonica": "D87C63", + "Java": "1FC2C2", + "Jazzberry Jam": "A50B5E", + "Jelly Bean": "297B9A", + "Jet Stream": "B5D2CE", + "Jewel": "126B40", + "Jon": "3B1F1F", + "Jonquil": "EEFF9A", + "Jordy Blue": "8AB9F1", + "Judge Gray": "544333", + "Jumbo": "7C7B82", + "Jungle Green": "29AB87", + "Jungle Mist": "B4CFD3", + "Juniper": "6D9292", + "Just Right": "ECCDB9", + "Kabul": "5E483E", + "Kaitoke Green": "004620", + "Kangaroo": "C6C8BD", + "Karaka": "1E1609", + "Karry": "FFEAD4", + "Kashmir Blue": "507096", + "Kelp": "454936", + "Kenyan Copper": "7C1C05", + "Keppel": "3AB09E", + "Key Lime Pie": "BFC921", + "Khaki": "F0E68C", + "Kidnapper": "E1EAD4", + "Kilamanjaro": "240C02", + "Killarney": "3A6A47", + "Kimberly": "736C9F", + "Kingfisher Daisy": "3E0480", + "Kobi": "E79FC4", + "Kokoda": "6E6D57", + "Korma": "8F4B0E", + "Koromiko": "FFBD5F", + "Kournikova": "FFE772", + "Kumera": "886221", + "La Palma": "368716", + "La Rioja": "B3C110", + "Las Palmas": "C6E610", + "Laser": "C8B568", + "Laser Lemon": "FFFF66", + "Laurel": "749378", + "Lavender": "B57EDC", + "Lavender Gray": "BDBBD7", + "Lavender Magenta": "EE82EE", + "Lavender Pink": "FBAED2", + "Lavender Purple": "967BB6", + "Lavender Rose": "FBA0E3", + "Lavender blush": "FFF0F5", + "Leather": "967059", + "Lemon": "FDE910", + "Lemon Chiffon": "FFFACD", + "Lemon Ginger": "AC9E22", + "Lemon Grass": "9B9E8F", + "Light Apricot": "FDD5B1", + "Light Orchid": "E29CD2", + "Light Wisteria": "C9A0DC", + "Lightning Yellow": "FCC01E", + "Lilac": "C8A2C8", + "Lilac Bush": "9874D3", + "Lily": "C8AABF", + "Lily White": "E7F8FF", + "Lima": "76BD17", + "Lime": "BFFF00", + "Limeade": "6F9D02", + "Limed Ash": "747D63", + "Limed Oak": "AC8A56", + "Limed Spruce": "394851", + "Linen": "FAF0E6", + "Link Water": "D9E4F5", + "Lipstick": "AB0563", + "Lisbon Brown": "423921", + "Livid Brown": "4D282E", + "Loafer": "EEF4DE", + "Loblolly": "BDC9CE", + "Lochinvar": "2C8C84", + "Lochmara": "007EC7", + "Locust": "A8AF8E", + "Log Cabin": "242A1D", + "Logan": "AAA9CD", + "Lola": "DFCFDB", + "London Hue": "BEA6C3", + "Lonestar": "6D0101", + "Lotus": "863C3C", + "Loulou": "460B41", + "Lucky": "AF9F1C", + "Lucky Point": "1A1A68", + "Lunar Green": "3C493A", + "Luxor Gold": "A7882C", + "Lynch": "697E9A", + "Mabel": "D9F7FF", + "Macaroni and Cheese": "FFB97B", + "Madang": "B7F0BE", + "Madison": "09255D", + "Madras": "3F3002", + "Magenta / Fuchsia": "FF00FF", + "Magic Mint": "AAF0D1", + "Magnolia": "F8F4FF", + "Mahogany": "4E0606", + "Mai Tai": "B06608", + "Maize": "F5D5A0", + "Makara": "897D6D", + "Mako": "444954", + "Malachite": "0BDA51", + "Malibu": "7DC8F7", + "Mallard": "233418", + "Malta": "BDB2A1", + "Mamba": "8E8190", + "Manatee": "8D90A1", + "Mandalay": "AD781B", + "Mandy": "E25465", + "Mandys Pink": "F2C3B2", + "Mango Tango": "E77200", + "Manhattan": "F5C999", + "Mantis": "74C365", + "Mantle": "8B9C90", + "Manz": "EEEF78", + "Mardi Gras": "350036", + "Marigold": "B98D28", + "Marigold Yellow": "FBE870", + "Mariner": "286ACD", + "Maroon": "800000", + "Maroon Flush": "C32148", + "Maroon Oak": "520C17", + "Marshland": "0B0F08", + "Martini": "AFA09E", + "Martinique": "363050", + "Marzipan": "F8DB9D", + "Masala": "403B38", + "Matisse": "1B659D", + "Matrix": "B05D54", + "Matterhorn": "4E3B41", + "Mauve": "E0B0FF", + "Mauvelous": "F091A9", + "Maverick": "D8C2D5", + "Medium Carmine": "AF4035", + "Medium Purple": "9370DB", + "Medium Red Violet": "BB3385", + "Melanie": "E4C2D5", + "Melanzane": "300529", + "Melon": "FEBAAD", + "Melrose": "C7C1FF", + "Mercury": "E5E5E5", + "Merino": "F6F0E6", + "Merlin": "413C37", + "Merlot": "831923", + "Metallic Bronze": "49371B", + "Metallic Copper": "71291D", + "Meteor": "D07D12", + "Meteorite": "3C1F76", + "Mexican Red": "A72525", + "Mid Gray": "5F5F6E", + "Midnight": "011635", + "Midnight Blue": "003366", + "Midnight Moss": "041004", + "Mikado": "2D2510", + "Milan": "FAFFA4", + "Milano Red": "B81104", + "Milk Punch": "FFF6D4", + "Millbrook": "594433", + "Mimosa": "F8FDD3", + "Mindaro": "E3F988", + "Mine Shaft": "323232", + "Mineral Green": "3F5D53", + "Ming": "36747D", + "Minsk": "3F307F", + "Mint Green": "98FF98", + "Mint Julep": "F1EEC1", + "Mint Tulip": "C4F4EB", + "Mirage": "161928", + "Mischka": "D1D2DD", + "Mist Gray": "C4C4BC", + "Mobster": "7F7589", + "Moccaccino": "6E1D14", + "Mocha": "782D19", + "Mojo": "C04737", + "Mona Lisa": "FFA194", + "Monarch": "8B0723", + "Mondo": "4A3C30", + "Mongoose": "B5A27F", + "Monsoon": "8A8389", + "Monte Carlo": "83D0C6", + "Monza": "C7031E", + "Moody Blue": "7F76D3", + "Moon Glow": "FCFEDA", + "Moon Mist": "DCDDCC", + "Moon Raker": "D6CEF6", + "Morning Glory": "9EDEE0", + "Morocco Brown": "441D00", + "Mortar": "504351", + "Mosque": "036A6E", + "Moss Green": "ADDFAD", + "Mountain Meadow": "1AB385", + "Mountain Mist": "959396", + "Mountbatten Pink": "997A8D", + "Muddy Waters": "B78E5C", + "Muesli": "AA8B5B", + "Mulberry": "C54B8C", + "Mulberry Wood": "5C0536", + "Mule Fawn": "8C472F", + "Mulled Wine": "4E4562", + "Mustard": "FFDB58", + "My Pink": "D69188", + "My Sin": "FFB31F", + "Mystic": "E2EBED", + "Nandor": "4B5D52", + "Napa": "ACA494", + "Narvik": "EDF9F1", + "Natural Gray": "8B8680", + "Navajo White": "FFDEAD", + "Navy Blue": "000080", + "Nebula": "CBDBD6", + "Negroni": "FFE2C5", + "Neon Carrot": "FF9933", + "Nepal": "8EABC1", + "Neptune": "7CB7BB", + "Nero": "140600", + "Nevada": "646E75", + "New Orleans": "F3D69D", + "New York Pink": "D7837F", + "Niagara": "06A189", + "Night Rider": "1F120F", + "Night Shadz": "AA375A", + "Nile Blue": "193751", + "Nobel": "B7B1B1", + "Nomad": "BAB1A2", + "Norway": "A8BD9F", + "Nugget": "C59922", + "Nutmeg": "81422C", + "Nutmeg Wood Finish": "683600", + "Oasis": "FEEFCE", + "Observatory": "02866F", + "Ocean Green": "41AA78", + "Ochre": "CC7722", + "Off Green": "E6F8F3", + "Off Yellow": "FEF9E3", + "Oil": "281E15", + "Old Brick": "901E1E", + "Old Copper": "724A2F", + "Old Gold": "CFB53B", + "Old Lace": "FDF5E6", + "Old Lavender": "796878", + "Old Rose": "C08081", + "Olive": "808000", + "Olive Drab": "6B8E23", + "Olive Green": "B5B35C", + "Olive Haze": "8B8470", + "Olivetone": "716E10", + "Olivine": "9AB973", + "Onahau": "CDF4FF", + "Onion": "2F270E", + "Opal": "A9C6C2", + "Opium": "8E6F70", + "Oracle": "377475", + "Orange": "FF681F", + "Orange Peel": "FFA000", + "Orange Roughy": "C45719", + "Orange White": "FEFCED", + "Orchid": "DA70D6", + "Orchid White": "FFFDF3", + "Oregon": "9B4703", + "Orient": "015E85", + "Oriental Pink": "C69191", + "Orinoco": "F3FBD4", + "Oslo Gray": "878D91", + "Ottoman": "E9F8ED", + "Outer Space": "2D383A", + "Outrageous Orange": "FF6037", + "Oxford Blue": "384555", + "Oxley": "779E86", + "Oyster Bay": "DAFAFF", + "Oyster Pink": "E9CECD", + "Paarl": "A65529", + "Pablo": "776F61", + "Pacific Blue": "009DC4", + "Pacifika": "778120", + "Paco": "411F10", + "Padua": "ADE6C4", + "Pale Canary": "FFFF99", + "Pale Leaf": "C0D3B9", + "Pale Oyster": "988D77", + "Pale Prim": "FDFEB8", + "Pale Rose": "FFE1F2", + "Pale Sky": "6E7783", + "Pale Slate": "C3BFC1", + "Palm Green": "09230F", + "Palm Leaf": "19330E", + "Pampas": "F4F2EE", + "Panache": "EAF6EE", + "Pancho": "EDCDAB", + "Papaya Whip": "FFEFD5", + "Paprika": "8D0226", + "Paradiso": "317D82", + "Parchment": "F1E9D2", + "Paris Daisy": "FFF46E", + "Paris M": "26056A", + "Paris White": "CADCD4", + "Parsley": "134F19", + "Pastel Green": "77DD77", + "Pastel Pink": "FFD1DC", + "Patina": "639A8F", + "Pattens Blue": "DEF5FF", + "Paua": "260368", + "Pavlova": "D7C498", + "Peach": "FFE5B4", + "Peach Cream": "FFF0DB", + "Peach Orange": "FFCC99", + "Peach Schnapps": "FFDCD6", + "Peach Yellow": "FADFAD", + "Peanut": "782F16", + "Pear": "D1E231", + "Pearl Bush": "E8E0D5", + "Pearl Lusta": "FCF4DC", + "Peat": "716B56", + "Pelorous": "3EABBF", + "Peppermint": "E3F5E1", + "Perano": "A9BEF2", + "Perfume": "D0BEF8", + "Periglacial Blue": "E1E6D6", + "Periwinkle": "CCCCFF", + "Periwinkle Gray": "C3CDE6", + "Persian Blue": "1C39BB", + "Persian Green": "00A693", + "Persian Indigo": "32127A", + "Persian Pink": "F77FBE", + "Persian Plum": "701C1C", + "Persian Red": "CC3333", + "Persian Rose": "FE28A2", + "Persimmon": "FF6B53", + "Peru Tan": "7F3A02", + "Pesto": "7C7631", + "Petite Orchid": "DB9690", + "Pewter": "96A8A1", + "Pharlap": "A3807B", + "Picasso": "FFF39D", + "Pickled Bean": "6E4826", + "Pickled Bluewood": "314459", + "Picton Blue": "45B1E8", + "Pig Pink": "FDD7E4", + "Pigeon Post": "AFBDD9", + "Pigment Indigo": "4B0082", + "Pine Cone": "6D5E54", + "Pine Glade": "C7CD90", + "Pine Green": "01796F", + "Pine Tree": "171F04", + "Pink": "FFC0CB", + "Pink Flamingo": "FF66FF", + "Pink Flare": "E1C0C8", + "Pink Lace": "FFDDF4", + "Pink Lady": "FFF1D8", + "Pink Salmon": "FF91A4", + "Pink Swan": "BEB5B7", + "Piper": "C96323", + "Pipi": "FEF4CC", + "Pippin": "FFE1DF", + "Pirate Gold": "BA7F03", + "Pistachio": "9DC209", + "Pixie Green": "C0D8B6", + "Pizazz": "FF9000", + "Pizza": "C99415", + "Plantation": "27504B", + "Plum": "843179", + "Pohutukawa": "8F021C", + "Polar": "E5F9F6", + "Polo Blue": "8DA8CC", + "Pomegranate": "F34723", + "Pompadour": "660045", + "Porcelain": "EFF2F3", + "Porsche": "EAAE69", + "Port Gore": "251F4F", + "Portafino": "FFFFB4", + "Portage": "8B9FEE", + "Portica": "F9E663", + "Pot Pourri": "F5E7E2", + "Potters Clay": "8C5738", + "Powder Ash": "BCC9C2", + "Powder Blue": "B0E0E6", + "Prairie Sand": "9A3820", + "Prelude": "D0C0E5", + "Prim": "F0E2EC", + "Primrose": "EDEA99", + "Provincial Pink": "FEF5F1", + "Prussian Blue": "003153", + "Puce": "CC8899", + "Pueblo": "7D2C14", + "Puerto Rico": "3FC1AA", + "Pumice": "C2CAC4", + "Pumpkin": "FF7518", + "Pumpkin Skin": "B1610B", + "Punch": "DC4333", + "Punga": "4D3D14", + "Purple": "660099", + "Purple Heart": "652DC1", + "Purple Mountain's Majesty": "9678B6", + "Purple Pizzazz": "FF00CC", + "Putty": "E7CD8C", + "Quarter Pearl Lusta": "FFFDF4", + "Quarter Spanish White": "F7F2E1", + "Quicksand": "BD978E", + "Quill Gray": "D6D6D1", + "Quincy": "623F2D", + "Racing Green": "0C1911", + "Radical Red": "FF355E", + "Raffia": "EADAB8", + "Rainee": "B9C8AC", + "Rajah": "F7B668", + "Rangitoto": "2E3222", + "Rangoon Green": "1C1E13", + "Raven": "727B89", + "Raw Sienna": "D27D46", + "Raw Umber": "734A12", + "Razzle Dazzle Rose": "FF33CC", + "Razzmatazz": "E30B5C", + "Rebel": "3C1206", + "Red": "FF0000", + "Red Beech": "7B3801", + "Red Berry": "8E0000", + "Red Damask": "DA6A41", + "Red Devil": "860111", + "Red Orange": "FF3F34", + "Red Oxide": "6E0902", + "Red Ribbon": "ED0A3F", + "Red Robin": "80341F", + "Red Stage": "D05F04", + "Red Violet": "C71585", + "Redwood": "5D1E0F", + "Reef": "C9FFA2", + "Reef Gold": "9F821C", + "Regal Blue": "013F6A", + "Regent Gray": "86949F", + "Regent St Blue": "AAD6E6", + "Remy": "FEEBF3", + "Reno Sand": "A86515", + "Resolution Blue": "002387", + "Revolver": "2C1632", + "Rhino": "2E3F62", + "Rice Cake": "FFFEF0", + "Rice Flower": "EEFFE2", + "Rich Gold": "A85307", + "Rio Grande": "BBD009", + "Ripe Lemon": "F4D81C", + "Ripe Plum": "410056", + "Riptide": "8BE6D8", + "River Bed": "434C59", + "Rob Roy": "EAC674", + "Robin's Egg Blue": "00CCCC", + "Rock": "4D3833", + "Rock Blue": "9EB1CD", + "Rock Spray": "BA450C", + "Rodeo Dust": "C9B29B", + "Rolling Stone": "747D83", + "Roman": "DE6360", + "Roman Coffee": "795D4C", + "Romance": "FFFEFD", + "Romantic": "FFD2B7", + "Ronchi": "ECC54E", + "Roof Terracotta": "A62F20", + "Rope": "8E4D1E", + "Rose": "FF007F", + "Rose Bud": "FBB2A3", + "Rose Bud Cherry": "800B47", + "Rose Fog": "E7BCB4", + "Rose White": "FFF6F5", + "Rose of Sharon": "BF5500", + "Rosewood": "65000B", + "Roti": "C6A84B", + "Rouge": "A23B6C", + "Royal Blue": "4169E1", + "Royal Heath": "AB3472", + "Royal Purple": "6B3FA0", + "Rum": "796989", + "Rum Swizzle": "F9F8E4", + "Russet": "80461B", + "Russett": "755A57", + "Rust": "B7410E", + "Rustic Red": "480404", + "Rusty Nail": "86560A", + "Saddle": "4C3024", + "Saddle Brown": "583401", + "Saffron": "F4C430", + "Saffron Mango": "F9BF58", + "Sage": "9EA587", + "Sahara": "B7A214", + "Sahara Sand": "F1E788", + "Sail": "B8E0F9", + "Salem": "097F4B", + "Salmon": "FF8C69", + "Salomie": "FEDB8D", + "Salt Box": "685E6E", + "Saltpan": "F1F7F2", + "Sambuca": "3A2010", + "San Felix": "0B6207", + "San Juan": "304B6A", + "San Marino": "456CAC", + "Sand Dune": "826F65", + "Sandal": "AA8D6F", + "Sandrift": "AB917A", + "Sandstone": "796D62", + "Sandwisp": "F5E7A2", + "Sandy Beach": "FFEAC8", + "Sandy brown": "F4A460", + "Sangria": "92000A", + "Sanguine Brown": "8D3D38", + "Santa Fe": "B16D52", + "Santas Gray": "9FA0B1", + "Sapling": "DED4A4", + "Sapphire": "2F519E", + "Saratoga": "555B10", + "Satin Linen": "E6E4D4", + "Sauvignon": "FFF5F3", + "Sazerac": "FFF4E0", + "Scampi": "675FA6", + "Scandal": "CFFAF4", + "Scarlet": "FF2400", + "Scarlet Gum": "431560", + "Scarlett": "950015", + "Scarpa Flow": "585562", + "Schist": "A9B497", + "School bus Yellow": "FFD800", + "Schooner": "8B847E", + "Science Blue": "0066CC", + "Scooter": "2EBFD4", + "Scorpion": "695F62", + "Scotch Mist": "FFFBDC", + "Screamin' Green": "66FF66", + "Sea Buckthorn": "FBA129", + "Sea Green": "2E8B57", + "Sea Mist": "C5DBCA", + "Sea Nymph": "78A39C", + "Sea Pink": "ED989E", + "Seagull": "80CCEA", + "Seance": "731E8F", + "Seashell": "F1F1F1", + "Seashell Peach": "FFF5EE", + "Seaweed": "1B2F11", + "Selago": "F0EEFD", + "Selective Yellow": "FFBA00", + "Sepia": "704214", + "Sepia Black": "2B0202", + "Sepia Skin": "9E5B40", + "Serenade": "FFF4E8", + "Shadow": "837050", + "Shadow Green": "9AC2B8", + "Shady Lady": "AAA5A9", + "Shakespeare": "4EABD1", + "Shalimar": "FBFFBA", + "Shamrock": "33CC99", + "Shark": "25272C", + "Sherpa Blue": "004950", + "Sherwood Green": "02402C", + "Shilo": "E8B9B3", + "Shingle Fawn": "6B4E31", + "Ship Cove": "788BBA", + "Ship Gray": "3E3A44", + "Shiraz": "B20931", + "Shocking": "E292C0", + "Shocking Pink": "FC0FC0", + "Shuttle Gray": "5F6672", + "Siam": "646A54", + "Sidecar": "F3E7BB", + "Silk": "BDB1A8", + "Silver": "C0C0C0", + "Silver Chalice": "ACACAC", + "Silver Rust": "C9C0BB", + "Silver Sand": "BFC1C2", + "Silver Tree": "66B58F", + "Sinbad": "9FD7D3", + "Siren": "7A013A", + "Sirocco": "718080", + "Sisal": "D3CBBA", + "Skeptic": "CAE6DA", + "Sky Blue": "76D7EA", + "Slate Gray": "708090", + "Smalt": "003399", + "Smalt Blue": "51808F", + "Smoky": "605B73", + "Snow Drift": "F7FAF7", + "Snow Flurry": "E4FFD1", + "Snowy Mint": "D6FFDB", + "Snuff": "E2D8ED", + "Soapstone": "FFFBF9", + "Soft Amber": "D1C6B4", + "Soft Peach": "F5EDEF", + "Solid Pink": "893843", + "Solitaire": "FEF8E2", + "Solitude": "EAF6FF", + "Sorbus": "FD7C07", + "Sorrell Brown": "CEB98F", + "Soya Bean": "6A6051", + "Spanish Green": "819885", + "Spectra": "2F5A57", + "Spice": "6A442E", + "Spicy Mix": "885342", + "Spicy Mustard": "74640D", + "Spicy Pink": "816E71", + "Spindle": "B6D1EA", + "Spray": "79DEEC", + "Spring Green": "00FF7F", + "Spring Leaves": "578363", + "Spring Rain": "ACCBB1", + "Spring Sun": "F6FFDC", + "Spring Wood": "F8F6F1", + "Sprout": "C1D7B0", + "Spun Pearl": "AAABB7", + "Squirrel": "8F8176", + "St Tropaz": "2D569B", + "Stack": "8A8F8A", + "Star Dust": "9F9F9C", + "Stark White": "E5D7BD", + "Starship": "ECF245", + "Steel Blue": "4682B4", + "Steel Gray": "262335", + "Stiletto": "9C3336", + "Stonewall": "928573", + "Storm Dust": "646463", + "Storm Gray": "717486", + "Stratos": "000741", + "Straw": "D4BF8D", + "Strikemaster": "956387", + "Stromboli": "325D52", + "Studio": "714AB2", + "Submarine": "BAC7C9", + "Sugar Cane": "F9FFF6", + "Sulu": "C1F07C", + "Summer Green": "96BBAB", + "Sun": "FBAC13", + "Sundance": "C9B35B", + "Sundown": "FFB1B3", + "Sunflower": "E4D422", + "Sunglo": "E16865", + "Sunglow": "FFCC33", + "Sunset Orange": "FE4C40", + "Sunshade": "FF9E2C", + "Supernova": "FFC901", + "Surf": "BBD7C1", + "Surf Crest": "CFE5D2", + "Surfie Green": "0C7A79", + "Sushi": "87AB39", + "Suva Gray": "888387", + "Swamp": "001B1C", + "Swamp Green": "ACB78E", + "Swans Down": "DCF0EA", + "Sweet Corn": "FBEA8C", + "Sweet Pink": "FD9FA2", + "Swirl": "D3CDC5", + "Swiss Coffee": "DDD6D5", + "Sycamore": "908D39", + "Tabasco": "A02712", + "Tacao": "EDB381", + "Tacha": "D6C562", + "Tahiti Gold": "E97C07", + "Tahuna Sands": "EEF0C8", + "Tall Poppy": "B32D29", + "Tallow": "A8A589", + "Tamarillo": "991613", + "Tamarind": "341515", + "Tan": "D2B48C", + "Tan Hide": "FA9D5A", + "Tana": "D9DCC1", + "Tangaroa": "03163C", + "Tangerine": "F28500", + "Tango": "ED7A1C", + "Tapa": "7B7874", + "Tapestry": "B05E81", + "Tara": "E1F6E8", + "Tarawera": "073A50", + "Tasman": "CFDCCF", + "Taupe": "483C32", + "Taupe Gray": "B3AF95", + "Tawny Port": "692545", + "Te Papa Green": "1E433C", + "Tea": "C1BAB0", + "Tea Green": "D0F0C0", + "Teak": "B19461", + "Teal": "008080", + "Teal Blue": "044259", + "Temptress": "3B000B", + "Tenn": "CD5700", + "Tequila": "FFE6C7", + "Terracotta": "E2725B", + "Texas": "F8F99C", + "Texas Rose": "FFB555", + "Thatch": "B69D98", + "Thatch Green": "403D19", + "Thistle": "D8BFD8", + "Thistle Green": "CCCAA8", + "Thunder": "33292F", + "Thunderbird": "C02B18", + "Tia Maria": "C1440E", + "Tiara": "C3D1D1", + "Tiber": "063537", + "Tickle Me Pink": "FC80A5", + "Tidal": "F1FFAD", + "Tide": "BFB8B0", + "Timber Green": "16322C", + "Timberwolf": "D9D6CF", + "Titan White": "F0EEFF", + "Toast": "9A6E61", + "Tobacco Brown": "715D47", + "Toledo": "3A0020", + "Tolopea": "1B0245", + "Tom Thumb": "3F583B", + "Tonys Pink": "E79F8C", + "Topaz": "7C778A", + "Torch Red": "FD0E35", + "Torea Bay": "0F2D9E", + "Tory Blue": "1450AA", + "Tosca": "8D3F3F", + "Totem Pole": "991B07", + "Tower Gray": "A9BDBF", + "Tradewind": "5FB3AC", + "Tranquil": "E6FFFF", + "Travertine": "FFFDE8", + "Tree Poppy": "FC9C1D", + "Treehouse": "3B2820", + "Trendy Green": "7C881A", + "Trendy Pink": "8C6495", + "Trinidad": "E64E03", + "Tropical Blue": "C3DDF9", + "Tropical Rain Forest": "00755E", + "Trout": "4A4E5A", + "True V": "8A73D6", + "Tuatara": "363534", + "Tuft Bush": "FFDDCD", + "Tulip Tree": "EAB33B", + "Tumbleweed": "DEA681", + "Tuna": "353542", + "Tundora": "4A4244", + "Turbo": "FAE600", + "Turkish Rose": "B57281", + "Turmeric": "CABB48", + "Turquoise": "30D5C8", + "Turquoise Blue": "6CDAE7", + "Turtle Green": "2A380B", + "Tuscany": "BD5E2E", + "Tusk": "EEF3C3", + "Tussock": "C5994B", + "Tutu": "FFF1F9", + "Twilight": "E4CFDE", + "Twilight Blue": "EEFDFF", + "Twine": "C2955D", + "Tyrian Purple": "66023C", + "Ultramarine": "120A8F", + "Valencia": "D84437", + "Valentino": "350E42", + "Valhalla": "2B194F", + "Van Cleef": "49170C", + "Vanilla": "D1BEA8", + "Vanilla Ice": "F3D9DF", + "Varden": "FFF6DF", + "Venetian Red": "72010F", + "Venice Blue": "055989", + "Venus": "928590", + "Verdigris": "5D5E37", + "Verdun Green": "495400", + "Vermilion": "FF4D00", + "Vesuvius": "B14A0B", + "Victoria": "534491", + "Vida Loca": "549019", + "Viking": "64CCDB", + "Vin Rouge": "983D61", + "Viola": "CB8FA9", + "Violent Violet": "290C5E", + "Violet": "240A40", + "Violet Eggplant": "991199", + "Violet Red": "F7468A", + "Viridian": "40826D", + "Viridian Green": "678975", + "Vis Vis": "FFEFA1", + "Vista Blue": "8FD6B4", + "Vista White": "FCF8F7", + "Vivid Tangerine": "FF9980", + "Vivid Violet": "803790", + "Voodoo": "533455", + "Vulcan": "10121D", + "Wafer": "DECBC6", + "Waikawa Gray": "5A6E9C", + "Waiouru": "363C0D", + "Walnut": "773F1A", + "Wasabi": "788A25", + "Water Leaf": "A1E9DE", + "Watercourse": "056F57", + "Waterloo ": "7B7C94", + "Wattle": "DCD747", + "Watusi": "FFDDCF", + "Wax Flower": "FFC0A8", + "We Peep": "F7DBE6", + "Web Orange": "FFA500", + "Wedgewood": "4E7F9E", + "Well Read": "B43332", + "West Coast": "625119", + "West Side": "FF910F", + "Westar": "DCD9D2", + "Wewak": "F19BAB", + "Wheat": "F5DEB3", + "Wheatfield": "F3EDCF", + "Whiskey": "D59A6F", + "Whisper": "F7F5FA", + "White": "FFFFFF", + "White Ice": "DDF9F1", + "White Lilac": "F8F7FC", + "White Linen": "F8F0E8", + "White Pointer": "FEF8FF", + "White Rock": "EAE8D4", + "Wild Blue Yonder": "7A89B8", + "Wild Rice": "ECE090", + "Wild Sand": "F4F4F4", + "Wild Strawberry": "FF3399", + "Wild Watermelon": "FD5B78", + "Wild Willow": "B9C46A", + "William": "3A686C", + "Willow Brook": "DFECDA", + "Willow Grove": "65745D", + "Windsor": "3C0878", + "Wine Berry": "591D35", + "Winter Hazel": "D5D195", + "Wisp Pink": "FEF4F8", + "Wisteria": "9771B5", + "Wistful": "A4A6D3", + "Witch Haze": "FFFC99", + "Wood Bark": "261105", + "Woodland": "4D5328", + "Woodrush": "302A0F", + "Woodsmoke": "0C0D0F", + "Woody Brown": "483131", + "Xanadu": "738678", + "Yellow": "FFFF00", + "Yellow Green": "C5E17A", + "Yellow Metal": "716338", + "Yellow Orange": "FFAE42", + "Yellow Sea": "FEA904", + "Your Pink": "FFC3C0", + "Yukon Gold": "7B6608", + "Yuma": "CEC291", + "Zambezi": "685558", + "Zanah": "DAECD6", + "Zest": "E5841B", + "Zeus": "292319", + "Ziggurat": "BFDBE2", + "Zinnwaldite": "EBC2AF", + "Zircon": "F4F8FF", + "Zombie": "E4D69B", + "Zorba": "A59B91", + "Zuccini": "044022", + "Zumthor": "EDF6FF" +} -- cgit v1.2.3 From 3fdbed208356f875464fc21e3f1d153a7daa0359 Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sun, 5 Sep 2021 20:31:53 +0530 Subject: Fix issues occured while deploying [no ci] - import PIL is the way to import pillow. - discord-flags isn't being used yet. - Fixed some of the linting issues. --- bot/exts/evergreen/color.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bot/exts/evergreen/color.py b/bot/exts/evergreen/color.py index a00a956b..dd922bf9 100644 --- a/bot/exts/evergreen/color.py +++ b/bot/exts/evergreen/color.py @@ -1,16 +1,18 @@ # imports +import colorsys import logging -import colorsys -import pillow +import PIL from discord import Embed -# ! need to install discord-flags and add to poetry.lock file -from discord.ext import commands, flags +from discord.ext import commands from rapidfuzz import process from bot.bot import Bot from bot.constants import Colours +# Planning to use discord-flags, hence require changes to poetry.lock file +# from discord.ext import flags + logger = logging.getLogger(__name__) # constants if needed -- cgit v1.2.3 From 8056ce1c266a7b91c2a905fc7935d9a00b46ffbe Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 5 Sep 2021 18:39:23 -0400 Subject: Move to bot/exts/fun folder to update restructure --- bot/exts/fun/color.py | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 bot/exts/fun/color.py diff --git a/bot/exts/fun/color.py b/bot/exts/fun/color.py new file mode 100644 index 00000000..dd922bf9 --- /dev/null +++ b/bot/exts/fun/color.py @@ -0,0 +1,115 @@ +# imports +import colorsys +import logging + +import PIL +from discord import Embed +from discord.ext import commands +from rapidfuzz import process + +from bot.bot import Bot +from bot.constants import Colours + +# Planning to use discord-flags, hence require changes to poetry.lock file +# from discord.ext import flags + +logger = logging.getLogger(__name__) + +# constants if needed +# Color URLs - will be replaced by JSON file? +COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" +COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" +COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" + + +COLOR_ERROR = Embed( + title="Input color is not possible", + description="The color code {user_color} is not a possible color combination." + "\nThe range of possible values are: " + "\nRGB & HSV: 0-255" + "\nCMYK: 0-100%" + "\nHSL: 0-360 degrees" + "\nHex: #000000-#FFFFFF" +) +COLOR_EMBED = Embed( + title="{color_name}", + description="RGB" + "\n{RGB}" + "\nHSV" + "\n{HSV}" + "\nCMYK" + "\n{CMYK}" + "\nHSL" + "\n{HSL}" + "\nHex" + "\n{Hex}" +) + + +# define color command +class Color(commands.cog): + """User initiated command to receive color information.""" + + def __init__(self, bot: Bot): + self.bot = bot + + # ? possible to use discord-flags to allow user to decide on color + # https://pypi.org/project/discord-flags/ + # @flags.add_flag("--rgb", type=str) + # @flags.add_flag("--hsv", type=str) + # @flags.add_flag("--cmyk", type=str) + # @flags.add_flag("--hsl", type=str) + # @flags.add_flag("--hex", type=str) + # @flags.add_flag("--name", type=str) + # @flags.command() + @commands.command(aliases=["color", "colour"]) + @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) + async def color(self, ctx: commands.Context, *, user_color: str) -> None: + """Send information on input color code or color name.""" + # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name + # should we assume the color is RGB if not defined? + # should discord tags be used? + # need to review discord.py V2.0 + + # TODO code to check if color code is possible + await ctx.send(embed=COLOR_ERROR.format(color=user_color)) + # await ctx.send(embed=COLOR_EMBED.format( + # RGB=color_dict["RGB"], + # HSV=color_dict["HSV"], + # HSL=color_dict["HSL"], + # CMYK=color_dict["CMYK"], + # HSL=color_dict["HSL"], + # Hex=color_dict["Hex"], + # color_name=color_dict["color_name"] + # ).set_image() # url for image? + # ) + + # TODO pass for now + pass + + # if user_color in color_lists: + # # TODO fuzzy match for color + # pass + + async def color_converter(self, color: str, code_type: str) -> dict: + """Generate alternative color codes for use in the embed.""" + # TODO add code to take color and code type and return other types + # color_dict = { + # "RGB": color_RGB, + # "HSV": color_HSV, + # "HSL": color_HSL, + # "CMYK": color_CMYK, + # "HSL": color_HSL, + # "Hex": color_Hex, + # "color_name": color_name, + # } + pass + + async def photo_generator(self, color: str) -> None: + """Generate photo to use in embed.""" + # TODO need to find a way to store photo in cache to add to embed, then remove + + +def setup(bot: Bot) -> None: + """Load the Color Cog.""" + bot.add_cog(Color(bot)) -- cgit v1.2.3 From 690040ba9cdde3c973a7a89db6eb752bc29ebeee Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 5 Sep 2021 18:41:23 -0400 Subject: Move to utilities folder as recommended by Xith --- bot/exts/utilities/color.py | 115 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 bot/exts/utilities/color.py diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py new file mode 100644 index 00000000..dd922bf9 --- /dev/null +++ b/bot/exts/utilities/color.py @@ -0,0 +1,115 @@ +# imports +import colorsys +import logging + +import PIL +from discord import Embed +from discord.ext import commands +from rapidfuzz import process + +from bot.bot import Bot +from bot.constants import Colours + +# Planning to use discord-flags, hence require changes to poetry.lock file +# from discord.ext import flags + +logger = logging.getLogger(__name__) + +# constants if needed +# Color URLs - will be replaced by JSON file? +COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" +COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" +COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" + + +COLOR_ERROR = Embed( + title="Input color is not possible", + description="The color code {user_color} is not a possible color combination." + "\nThe range of possible values are: " + "\nRGB & HSV: 0-255" + "\nCMYK: 0-100%" + "\nHSL: 0-360 degrees" + "\nHex: #000000-#FFFFFF" +) +COLOR_EMBED = Embed( + title="{color_name}", + description="RGB" + "\n{RGB}" + "\nHSV" + "\n{HSV}" + "\nCMYK" + "\n{CMYK}" + "\nHSL" + "\n{HSL}" + "\nHex" + "\n{Hex}" +) + + +# define color command +class Color(commands.cog): + """User initiated command to receive color information.""" + + def __init__(self, bot: Bot): + self.bot = bot + + # ? possible to use discord-flags to allow user to decide on color + # https://pypi.org/project/discord-flags/ + # @flags.add_flag("--rgb", type=str) + # @flags.add_flag("--hsv", type=str) + # @flags.add_flag("--cmyk", type=str) + # @flags.add_flag("--hsl", type=str) + # @flags.add_flag("--hex", type=str) + # @flags.add_flag("--name", type=str) + # @flags.command() + @commands.command(aliases=["color", "colour"]) + @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) + async def color(self, ctx: commands.Context, *, user_color: str) -> None: + """Send information on input color code or color name.""" + # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name + # should we assume the color is RGB if not defined? + # should discord tags be used? + # need to review discord.py V2.0 + + # TODO code to check if color code is possible + await ctx.send(embed=COLOR_ERROR.format(color=user_color)) + # await ctx.send(embed=COLOR_EMBED.format( + # RGB=color_dict["RGB"], + # HSV=color_dict["HSV"], + # HSL=color_dict["HSL"], + # CMYK=color_dict["CMYK"], + # HSL=color_dict["HSL"], + # Hex=color_dict["Hex"], + # color_name=color_dict["color_name"] + # ).set_image() # url for image? + # ) + + # TODO pass for now + pass + + # if user_color in color_lists: + # # TODO fuzzy match for color + # pass + + async def color_converter(self, color: str, code_type: str) -> dict: + """Generate alternative color codes for use in the embed.""" + # TODO add code to take color and code type and return other types + # color_dict = { + # "RGB": color_RGB, + # "HSV": color_HSV, + # "HSL": color_HSL, + # "CMYK": color_CMYK, + # "HSL": color_HSL, + # "Hex": color_Hex, + # "color_name": color_name, + # } + pass + + async def photo_generator(self, color: str) -> None: + """Generate photo to use in embed.""" + # TODO need to find a way to store photo in cache to add to embed, then remove + + +def setup(bot: Bot) -> None: + """Load the Color Cog.""" + bot.add_cog(Color(bot)) -- cgit v1.2.3 From cfa2a0c6b985050d11d98badf656a3f2e74efded Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 5 Sep 2021 23:07:27 -0400 Subject: Remove old files --- bot/exts/evergreen/color.py | 115 -------------------------------------------- bot/exts/fun/color.py | 115 -------------------------------------------- 2 files changed, 230 deletions(-) delete mode 100644 bot/exts/evergreen/color.py delete mode 100644 bot/exts/fun/color.py diff --git a/bot/exts/evergreen/color.py b/bot/exts/evergreen/color.py deleted file mode 100644 index dd922bf9..00000000 --- a/bot/exts/evergreen/color.py +++ /dev/null @@ -1,115 +0,0 @@ -# imports -import colorsys -import logging - -import PIL -from discord import Embed -from discord.ext import commands -from rapidfuzz import process - -from bot.bot import Bot -from bot.constants import Colours - -# Planning to use discord-flags, hence require changes to poetry.lock file -# from discord.ext import flags - -logger = logging.getLogger(__name__) - -# constants if needed -# Color URLs - will be replaced by JSON file? -COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" -COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" -COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" - - -COLOR_ERROR = Embed( - title="Input color is not possible", - description="The color code {user_color} is not a possible color combination." - "\nThe range of possible values are: " - "\nRGB & HSV: 0-255" - "\nCMYK: 0-100%" - "\nHSL: 0-360 degrees" - "\nHex: #000000-#FFFFFF" -) -COLOR_EMBED = Embed( - title="{color_name}", - description="RGB" - "\n{RGB}" - "\nHSV" - "\n{HSV}" - "\nCMYK" - "\n{CMYK}" - "\nHSL" - "\n{HSL}" - "\nHex" - "\n{Hex}" -) - - -# define color command -class Color(commands.cog): - """User initiated command to receive color information.""" - - def __init__(self, bot: Bot): - self.bot = bot - - # ? possible to use discord-flags to allow user to decide on color - # https://pypi.org/project/discord-flags/ - # @flags.add_flag("--rgb", type=str) - # @flags.add_flag("--hsv", type=str) - # @flags.add_flag("--cmyk", type=str) - # @flags.add_flag("--hsl", type=str) - # @flags.add_flag("--hex", type=str) - # @flags.add_flag("--name", type=str) - # @flags.command() - @commands.command(aliases=["color", "colour"]) - @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) - async def color(self, ctx: commands.Context, *, user_color: str) -> None: - """Send information on input color code or color name.""" - # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name - # should we assume the color is RGB if not defined? - # should discord tags be used? - # need to review discord.py V2.0 - - # TODO code to check if color code is possible - await ctx.send(embed=COLOR_ERROR.format(color=user_color)) - # await ctx.send(embed=COLOR_EMBED.format( - # RGB=color_dict["RGB"], - # HSV=color_dict["HSV"], - # HSL=color_dict["HSL"], - # CMYK=color_dict["CMYK"], - # HSL=color_dict["HSL"], - # Hex=color_dict["Hex"], - # color_name=color_dict["color_name"] - # ).set_image() # url for image? - # ) - - # TODO pass for now - pass - - # if user_color in color_lists: - # # TODO fuzzy match for color - # pass - - async def color_converter(self, color: str, code_type: str) -> dict: - """Generate alternative color codes for use in the embed.""" - # TODO add code to take color and code type and return other types - # color_dict = { - # "RGB": color_RGB, - # "HSV": color_HSV, - # "HSL": color_HSL, - # "CMYK": color_CMYK, - # "HSL": color_HSL, - # "Hex": color_Hex, - # "color_name": color_name, - # } - pass - - async def photo_generator(self, color: str) -> None: - """Generate photo to use in embed.""" - # TODO need to find a way to store photo in cache to add to embed, then remove - - -def setup(bot: Bot) -> None: - """Load the Color Cog.""" - bot.add_cog(Color(bot)) diff --git a/bot/exts/fun/color.py b/bot/exts/fun/color.py deleted file mode 100644 index dd922bf9..00000000 --- a/bot/exts/fun/color.py +++ /dev/null @@ -1,115 +0,0 @@ -# imports -import colorsys -import logging - -import PIL -from discord import Embed -from discord.ext import commands -from rapidfuzz import process - -from bot.bot import Bot -from bot.constants import Colours - -# Planning to use discord-flags, hence require changes to poetry.lock file -# from discord.ext import flags - -logger = logging.getLogger(__name__) - -# constants if needed -# Color URLs - will be replaced by JSON file? -COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" -COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" -COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" - - -COLOR_ERROR = Embed( - title="Input color is not possible", - description="The color code {user_color} is not a possible color combination." - "\nThe range of possible values are: " - "\nRGB & HSV: 0-255" - "\nCMYK: 0-100%" - "\nHSL: 0-360 degrees" - "\nHex: #000000-#FFFFFF" -) -COLOR_EMBED = Embed( - title="{color_name}", - description="RGB" - "\n{RGB}" - "\nHSV" - "\n{HSV}" - "\nCMYK" - "\n{CMYK}" - "\nHSL" - "\n{HSL}" - "\nHex" - "\n{Hex}" -) - - -# define color command -class Color(commands.cog): - """User initiated command to receive color information.""" - - def __init__(self, bot: Bot): - self.bot = bot - - # ? possible to use discord-flags to allow user to decide on color - # https://pypi.org/project/discord-flags/ - # @flags.add_flag("--rgb", type=str) - # @flags.add_flag("--hsv", type=str) - # @flags.add_flag("--cmyk", type=str) - # @flags.add_flag("--hsl", type=str) - # @flags.add_flag("--hex", type=str) - # @flags.add_flag("--name", type=str) - # @flags.command() - @commands.command(aliases=["color", "colour"]) - @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) - async def color(self, ctx: commands.Context, *, user_color: str) -> None: - """Send information on input color code or color name.""" - # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name - # should we assume the color is RGB if not defined? - # should discord tags be used? - # need to review discord.py V2.0 - - # TODO code to check if color code is possible - await ctx.send(embed=COLOR_ERROR.format(color=user_color)) - # await ctx.send(embed=COLOR_EMBED.format( - # RGB=color_dict["RGB"], - # HSV=color_dict["HSV"], - # HSL=color_dict["HSL"], - # CMYK=color_dict["CMYK"], - # HSL=color_dict["HSL"], - # Hex=color_dict["Hex"], - # color_name=color_dict["color_name"] - # ).set_image() # url for image? - # ) - - # TODO pass for now - pass - - # if user_color in color_lists: - # # TODO fuzzy match for color - # pass - - async def color_converter(self, color: str, code_type: str) -> dict: - """Generate alternative color codes for use in the embed.""" - # TODO add code to take color and code type and return other types - # color_dict = { - # "RGB": color_RGB, - # "HSV": color_HSV, - # "HSL": color_HSL, - # "CMYK": color_CMYK, - # "HSL": color_HSL, - # "Hex": color_Hex, - # "color_name": color_name, - # } - pass - - async def photo_generator(self, color: str) -> None: - """Generate photo to use in embed.""" - # TODO need to find a way to store photo in cache to add to embed, then remove - - -def setup(bot: Bot) -> None: - """Load the Color Cog.""" - bot.add_cog(Color(bot)) -- cgit v1.2.3 From 0d7bbafe9bf18ef9d1dda65bab5a5ae699d97d72 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Mon, 6 Sep 2021 23:48:34 +0200 Subject: Move logging to a separate module --- bot/__init__.py | 63 ++------------------------------------------------------- bot/log.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 61 deletions(-) create mode 100644 bot/log.py diff --git a/bot/__init__.py b/bot/__init__.py index c6a48105..b64f4732 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -6,80 +6,21 @@ except ModuleNotFoundError: pass import asyncio -import logging -import logging.handlers import os from functools import partial, partialmethod -from pathlib import Path import arrow from discord.ext import commands +from bot import log from bot.command import Command -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 +log.setup() # Set timestamp of when execution started (approximately) start_time = arrow.utcnow() -# Set up file logging -log_dir = Path("bot/log") -log_file = log_dir / "hackbot.log" -os.makedirs(log_dir, exist_ok=True) - -# File handler rotates logs every 5 MB -file_handler = logging.handlers.RotatingFileHandler( - log_file, maxBytes=5 * (2**20), backupCount=10, encoding="utf-8", -) -file_handler.setLevel(logging.TRACE if Client.debug else logging.DEBUG) - -# Console handler prints to terminal -console_handler = logging.StreamHandler() -level = logging.TRACE if Client.debug else logging.INFO -console_handler.setLevel(level) - -# Remove old loggers, if any -root = logging.getLogger() -if root.handlers: - for handler in root.handlers: - root.removeHandler(handler) - -# Silence irrelevant loggers -logging.getLogger("discord").setLevel(logging.ERROR) -logging.getLogger("websockets").setLevel(logging.ERROR) -logging.getLogger("PIL").setLevel(logging.ERROR) -logging.getLogger("matplotlib").setLevel(logging.ERROR) -logging.getLogger("async_rediscache").setLevel(logging.WARNING) - -# Setup new logging configuration -logging.basicConfig( - format="%(asctime)s - %(name)s %(levelname)s: %(message)s", - datefmt="%D %H:%M:%S", - level=logging.TRACE if Client.debug else logging.DEBUG, - handlers=[console_handler, file_handler], -) -logging.getLogger().info("Logging initialization complete") - - # On Windows, the selector event loop is required for aiodns. if os.name == "nt": asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) diff --git a/bot/log.py b/bot/log.py new file mode 100644 index 00000000..1f4b9159 --- /dev/null +++ b/bot/log.py @@ -0,0 +1,63 @@ +import logging +import logging.handlers +import os +from pathlib import Path + +from bot.constants import Client + + +def setup() -> None: + """Set up loggers.""" + # Configure the "TRACE" logging level (e.g. "log.trace(message)") + logging.TRACE = 5 + logging.addLevelName(logging.TRACE, "TRACE") + logging.Logger.trace = _monkeypatch_trace + + # Set up file logging + log_dir = Path("bot/log") + log_file = log_dir / "hackbot.log" + os.makedirs(log_dir, exist_ok=True) + + # File handler rotates logs every 5 MB + file_handler = logging.handlers.RotatingFileHandler( + log_file, maxBytes=5 * (2 ** 20), backupCount=10, encoding="utf-8", + ) + file_handler.setLevel(logging.TRACE if Client.debug else logging.DEBUG) + + # Console handler prints to terminal + console_handler = logging.StreamHandler() + level = logging.TRACE if Client.debug else logging.INFO + console_handler.setLevel(level) + + # Remove old loggers, if any + root = logging.getLogger() + if root.handlers: + for handler in root.handlers: + root.removeHandler(handler) + + # Silence irrelevant loggers + logging.getLogger("discord").setLevel(logging.ERROR) + logging.getLogger("websockets").setLevel(logging.ERROR) + logging.getLogger("PIL").setLevel(logging.ERROR) + logging.getLogger("matplotlib").setLevel(logging.ERROR) + logging.getLogger("async_rediscache").setLevel(logging.WARNING) + + # Setup new logging configuration + logging.basicConfig( + format="%(asctime)s - %(name)s %(levelname)s: %(message)s", + datefmt="%D %H:%M:%S", + level=logging.TRACE if Client.debug else logging.DEBUG, + handlers=[console_handler, file_handler], + ) + logging.getLogger().info("Logging initialization complete") + + +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) -- cgit v1.2.3 From c2c0aefae5d80f9daaecb4dcd2bcd776c14660cf Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Mon, 6 Sep 2021 23:52:22 +0200 Subject: Move logging to a top level logs directory and update file name --- bot/log.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bot/log.py b/bot/log.py index 1f4b9159..c8de957e 100644 --- a/bot/log.py +++ b/bot/log.py @@ -1,6 +1,5 @@ import logging import logging.handlers -import os from pathlib import Path from bot.constants import Client @@ -14,9 +13,8 @@ def setup() -> None: logging.Logger.trace = _monkeypatch_trace # Set up file logging - log_dir = Path("bot/log") - log_file = log_dir / "hackbot.log" - os.makedirs(log_dir, exist_ok=True) + log_file = Path("logs/sir-lancebot.log") + log_file.parent.mkdir(exist_ok=True) # File handler rotates logs every 5 MB file_handler = logging.handlers.RotatingFileHandler( -- cgit v1.2.3 From 9f2dcc30433d90739bd8a9bbc8f50fabbcd7d7fe Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Mon, 6 Sep 2021 23:53:49 +0200 Subject: Remove handler cleanup This doesn't seem to do anything as no handlers are set up beforehand --- bot/log.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bot/log.py b/bot/log.py index c8de957e..0e0c22f0 100644 --- a/bot/log.py +++ b/bot/log.py @@ -27,12 +27,6 @@ def setup() -> None: level = logging.TRACE if Client.debug else logging.INFO console_handler.setLevel(level) - # Remove old loggers, if any - root = logging.getLogger() - if root.handlers: - for handler in root.handlers: - root.removeHandler(handler) - # Silence irrelevant loggers logging.getLogger("discord").setLevel(logging.ERROR) logging.getLogger("websockets").setLevel(logging.ERROR) -- cgit v1.2.3 From e135189446e4a450376b9c694f1faadd57fef19a Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 7 Sep 2021 00:04:40 +0200 Subject: Control logging levels through root logger instead of handlers The difference in the logging levels without debug mode enabled was also removed --- bot/log.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bot/log.py b/bot/log.py index 0e0c22f0..9ae40984 100644 --- a/bot/log.py +++ b/bot/log.py @@ -20,12 +20,8 @@ def setup() -> None: file_handler = logging.handlers.RotatingFileHandler( log_file, maxBytes=5 * (2 ** 20), backupCount=10, encoding="utf-8", ) - file_handler.setLevel(logging.TRACE if Client.debug else logging.DEBUG) - # Console handler prints to terminal console_handler = logging.StreamHandler() - level = logging.TRACE if Client.debug else logging.INFO - console_handler.setLevel(level) # Silence irrelevant loggers logging.getLogger("discord").setLevel(logging.ERROR) @@ -38,7 +34,7 @@ def setup() -> None: logging.basicConfig( format="%(asctime)s - %(name)s %(levelname)s: %(message)s", datefmt="%D %H:%M:%S", - level=logging.TRACE if Client.debug else logging.DEBUG, + level=logging.TRACE if Client.debug else logging.INFO, handlers=[console_handler, file_handler], ) logging.getLogger().info("Logging initialization complete") -- cgit v1.2.3 From 37c4d55275ed1ceadc86ad2c437a6dd337614bea Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Mon, 6 Sep 2021 20:13:17 -0400 Subject: Continue work in progress Implemented the thumbnail creation from CyberCitizen0, worked on adding some features to the program. Notable Changes: -Check if user passes in hex color -Create thumbnail based on rgb_color To-Do: -Create hex color from rgb color -Create readable rgb color from user input Co-authored-by: Mohammad Rafivulla <77384412+CyberCitizen01@users.noreply.github.com> --- bot/exts/utilities/color.py | 140 +++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 79 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index dd922bf9..1a4f7031 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,113 +1,95 @@ # imports import colorsys import logging +import re +from io import BytesIO -import PIL -from discord import Embed +from PIL import Image, ImageColor +from discord import Embed, File from discord.ext import commands from rapidfuzz import process from bot.bot import Bot from bot.constants import Colours -# Planning to use discord-flags, hence require changes to poetry.lock file -# from discord.ext import flags logger = logging.getLogger(__name__) -# constants if needed -# Color URLs - will be replaced by JSON file? -COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" -COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" -COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" - - -COLOR_ERROR = Embed( - title="Input color is not possible", - description="The color code {user_color} is not a possible color combination." - "\nThe range of possible values are: " - "\nRGB & HSV: 0-255" - "\nCMYK: 0-100%" - "\nHSL: 0-360 degrees" - "\nHex: #000000-#FFFFFF" -) -COLOR_EMBED = Embed( - title="{color_name}", - description="RGB" - "\n{RGB}" - "\nHSV" - "\n{HSV}" - "\nCMYK" - "\n{CMYK}" - "\nHSL" - "\n{HSL}" - "\nHex" - "\n{Hex}" -) + +ERROR_MSG = """The color code {user_color} is not a possible color combination. +\nThe range of possible values are: +\nRGB & HSV: 0-255 +\nCMYK: 0-100% +\nHSL: 0-360 degrees +\nHex: #000000-#FFFFFF +""" # define color command -class Color(commands.cog): +class Color(commands.Cog): """User initiated command to receive color information.""" def __init__(self, bot: Bot): self.bot = bot - # ? possible to use discord-flags to allow user to decide on color - # https://pypi.org/project/discord-flags/ - # @flags.add_flag("--rgb", type=str) - # @flags.add_flag("--hsv", type=str) - # @flags.add_flag("--cmyk", type=str) - # @flags.add_flag("--hsl", type=str) - # @flags.add_flag("--hex", type=str) - # @flags.add_flag("--name", type=str) - # @flags.command() - @commands.command(aliases=["color", "colour"]) + @commands.command(aliases=["colour"]) @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) async def color(self, ctx: commands.Context, *, user_color: str) -> None: """Send information on input color code or color name.""" # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name # should we assume the color is RGB if not defined? - # should discord tags be used? - # need to review discord.py V2.0 - - # TODO code to check if color code is possible - await ctx.send(embed=COLOR_ERROR.format(color=user_color)) - # await ctx.send(embed=COLOR_EMBED.format( - # RGB=color_dict["RGB"], - # HSV=color_dict["HSV"], - # HSL=color_dict["HSL"], - # CMYK=color_dict["CMYK"], - # HSL=color_dict["HSL"], - # Hex=color_dict["Hex"], - # color_name=color_dict["color_name"] - # ).set_image() # url for image? - # ) - - # TODO pass for now - pass + + if "#" in user_color: + logger.info(f"{user_color = }") + hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) + if hex_match: + hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) + logger.info(f"{hex_color = }") + rgb_color = ImageColor.getcolor(user_color, "RGB") + else: + await ctx.send(embed=Embed( + title="An error has occured.", + description=ERROR_MSG.format(user_color=user_color) + ) + ) + + elif "RGB" or "rgb" in user_color: + rgb_parse = user_color.split() + rgb = rgb_parse[1:].replace(", ", "") + logger.info(f"{rgb = }") + logger.info(f"{rgb[0] = }") + logger.info(f"{rgb[1] = }") + logger.info(f"{rgb[2] = }") + rgb_color = tuple(rgb) + hex_color = f"0x{int(rgb[0]):02x}{int(rgb[1]):02x}{int(rgb[2]):02x}" + + main_embed = Embed( + title=user_color, + color=hex_color, + ) + async with ctx.typing(): + file = await self._create_thumbnail_attachment(rgb_color) + main_embed.set_thumbnail(url="attachment://color.png") + + await ctx.send(file=file, embed=main_embed) + + async def _create_thumbnail_attachment(self, color: str) -> File: + """Generate a thumbnail from `color`.""" + + thumbnail = Image.new("RGB", (100, 100), color=color) + bufferedio = BytesIO() + thumbnail.save(bufferedio, format="PNG") + bufferedio.seek(0) + + file = File(bufferedio, filename="color.png") + + return file + # if user_color in color_lists: # # TODO fuzzy match for color # pass - async def color_converter(self, color: str, code_type: str) -> dict: - """Generate alternative color codes for use in the embed.""" - # TODO add code to take color and code type and return other types - # color_dict = { - # "RGB": color_RGB, - # "HSV": color_HSV, - # "HSL": color_HSL, - # "CMYK": color_CMYK, - # "HSL": color_HSL, - # "Hex": color_Hex, - # "color_name": color_name, - # } - pass - - async def photo_generator(self, color: str) -> None: - """Generate photo to use in embed.""" - # TODO need to find a way to store photo in cache to add to embed, then remove def setup(bot: Bot) -> None: -- cgit v1.2.3 From a16ee6ecd1b1449e8203e650495809e85ea9ddc8 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 7 Sep 2021 07:39:21 -0400 Subject: Fixing flake8 errors, code style Still a work in progress but commenting out stub code and unused imports. List of To-Do's still applies. --- bot/exts/utilities/color.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 1a4f7031..b1a77b28 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,5 +1,5 @@ # imports -import colorsys +# import colorsys import logging import re from io import BytesIO @@ -7,10 +7,10 @@ from io import BytesIO from PIL import Image, ImageColor from discord import Embed, File from discord.ext import commands -from rapidfuzz import process +# from rapidfuzz import process from bot.bot import Bot -from bot.constants import Colours +# from bot.constants import Colours logger = logging.getLogger(__name__) @@ -46,12 +46,14 @@ class Color(commands.Cog): hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) logger.info(f"{hex_color = }") rgb_color = ImageColor.getcolor(user_color, "RGB") + logger.info(f"{rgb_color = }") else: - await ctx.send(embed=Embed( + await ctx.send( + embed=Embed( title="An error has occured.", - description=ERROR_MSG.format(user_color=user_color) - ) + description=ERROR_MSG.format(user_color=user_color), ) + ) elif "RGB" or "rgb" in user_color: rgb_parse = user_color.split() @@ -64,7 +66,7 @@ class Color(commands.Cog): hex_color = f"0x{int(rgb[0]):02x}{int(rgb[1]):02x}{int(rgb[2]):02x}" main_embed = Embed( - title=user_color, + title=user_color, # need to replace with fuzzymatch color name color=hex_color, ) async with ctx.typing(): @@ -75,7 +77,6 @@ class Color(commands.Cog): async def _create_thumbnail_attachment(self, color: str) -> File: """Generate a thumbnail from `color`.""" - thumbnail = Image.new("RGB", (100, 100), color=color) bufferedio = BytesIO() thumbnail.save(bufferedio, format="PNG") @@ -85,11 +86,8 @@ class Color(commands.Cog): return file - # if user_color in color_lists: - # # TODO fuzzy match for color - # pass - + # # fuzzy match for color def setup(bot: Bot) -> None: -- cgit v1.2.3 From 86cde23bcec5090e73abaf1289641d299f2e8677 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 7 Sep 2021 07:48:07 -0400 Subject: Add embed fields for Hex and RGB --- bot/exts/utilities/color.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index b1a77b28..b1b423e7 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -73,6 +73,16 @@ class Color(commands.Cog): file = await self._create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") + main_embed.add_field( + name="Hex", + value=f">>Hex #{hex_color}", + inline=False, + ) + main_embed.add_field( + name="RGB", + value=f">>RGB {rgb_color}", + inline=False, + ) await ctx.send(file=file, embed=main_embed) async def _create_thumbnail_attachment(self, color: str) -> File: -- cgit v1.2.3 From 6d7f46fabe530e4cafdffa25d7fced730965e481 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 7 Sep 2021 00:15:36 +0200 Subject: Add coloredlogs --- bot/log.py | 18 +++++++++++++++++- poetry.lock | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++------- pyproject.toml | 2 ++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/bot/log.py b/bot/log.py index 9ae40984..d44e6933 100644 --- a/bot/log.py +++ b/bot/log.py @@ -1,7 +1,11 @@ import logging import logging.handlers +import os +import sys from pathlib import Path +import coloredlogs + from bot.constants import Client @@ -23,6 +27,19 @@ def setup() -> None: # Console handler prints to terminal console_handler = logging.StreamHandler() + if "COLOREDLOGS_LEVEL_STYLES" not in os.environ: + coloredlogs.DEFAULT_LEVEL_STYLES = { + **coloredlogs.DEFAULT_LEVEL_STYLES, + "trace": {"color": 246}, + "critical": {"background": "red"}, + "debug": coloredlogs.DEFAULT_LEVEL_STYLES["info"], + } + + if "COLOREDLOGS_LOG_FORMAT" not in os.environ: + coloredlogs.DEFAULT_LOG_FORMAT = "%(asctime)s - %(name)s %(levelname)s: %(message)s" + + coloredlogs.install(stream=sys.stdout) + # Silence irrelevant loggers logging.getLogger("discord").setLevel(logging.ERROR) logging.getLogger("websockets").setLevel(logging.ERROR) @@ -32,7 +49,6 @@ def setup() -> None: # Setup new logging configuration logging.basicConfig( - format="%(asctime)s - %(name)s %(levelname)s: %(message)s", datefmt="%D %H:%M:%S", level=logging.TRACE if Client.debug else logging.INFO, handlers=[console_handler, file_handler], diff --git a/poetry.lock b/poetry.lock index 289f2039..328a474f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -139,10 +139,24 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." -category = "dev" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "coloredlogs" +version = "15.0.1" +description = "Colored terminal output for Python's logging module" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[package.dependencies] +humanfriendly = ">=9.1" + +[package.extras] +cron = ["capturer (>=2.4)"] + [[package]] name = "cycler" version = "0.10.0" @@ -328,6 +342,17 @@ category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "humanfriendly" +version = "9.2" +description = "Human friendly output for text interfaces using Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +pyreadline = {version = "*", markers = "sys_platform == \"win32\""} + [[package]] name = "identify" version = "2.2.13" @@ -552,6 +577,14 @@ category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "pyreadline" +version = "2.1" +description = "A python implmementation of GNU readline." +category = "main" +optional = false +python-versions = "*" + [[package]] name = "python-dateutil" version = "2.8.2" @@ -565,11 +598,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.0" +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)"] @@ -730,7 +763,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "9efbf6be5298ab8ace2588e218be309e105987bfdfa8317453d584a1faac4934" +content-hash = "f519d64a4c9286d08a77e33c6776a7da280494a008826a069daad8bea3d11995" [metadata.files] aiodns = [ @@ -863,6 +896,10 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +coloredlogs = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] cycler = [ {file = "cycler-0.10.0-py2.py3-none-any.whl", hash = "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d"}, {file = "cycler-0.10.0.tar.gz", hash = "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"}, @@ -962,6 +999,10 @@ hiredis = [ {file = "hiredis-2.0.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0"}, {file = "hiredis-2.0.0.tar.gz", hash = "sha256:81d6d8e39695f2c37954d1011c0480ef7cf444d4e3ae24bc5e89ee5de360139a"}, ] +humanfriendly = [ + {file = "humanfriendly-9.2-py2.py3-none-any.whl", hash = "sha256:332da98c24cc150efcc91b5508b19115209272bfdf4b0764a56795932f854271"}, + {file = "humanfriendly-9.2.tar.gz", hash = "sha256:f7dba53ac7935fd0b4a2fc9a29e316ddd9ea135fb3052d3d0279d10c18ff9c48"}, +] identify = [ {file = "identify-2.2.13-py2.py3-none-any.whl", hash = "sha256:7199679b5be13a6b40e6e19ea473e789b11b4e3b60986499b1f589ffb03c217c"}, {file = "identify-2.2.13.tar.gz", hash = "sha256:7bc6e829392bd017236531963d2d937d66fc27cadc643ac0aba2ce9f26157c79"}, @@ -1279,13 +1320,18 @@ pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] +pyreadline = [ + {file = "pyreadline-2.1.win-amd64.exe", hash = "sha256:9ce5fa65b8992dfa373bddc5b6e0864ead8f291c94fbfec05fbd5c836162e67b"}, + {file = "pyreadline-2.1.win32.exe", hash = "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e"}, + {file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"}, +] python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {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.0.tar.gz", hash = "sha256:f521bc2ac9a8e03c736f62911605c5d83970021e3fa95b37d769e2bbbe9b6172"}, + {file = "python_dotenv-0.19.0-py2.py3-none-any.whl", hash = "sha256:aae25dc1ebe97c420f50b81fb0e5c949659af713f31fdb63c749ca68748f34b1"}, ] pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, diff --git a/pyproject.toml b/pyproject.toml index 7848f593..31689468 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,8 @@ PyYAML = "~=5.4" async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"} emojis = "~=0.6.0" matplotlib = "~=3.4.1" +coloredlogs = "~=15.0" +colorama = { version = "~=0.4.3", markers = "sys_platform == 'win32'" } [tool.poetry.dev-dependencies] flake8 = "~=3.8" -- cgit v1.2.3 From ac63915dd38c920cbe1d2d194ecd1bc2168d7570 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 7 Sep 2021 00:20:30 +0200 Subject: Remove basicConfig configuration The basicConfig now only controlled the file handler which could've been confusing. The format string was also changed to use the same style as bot --- bot/log.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bot/log.py b/bot/log.py index d44e6933..c8437505 100644 --- a/bot/log.py +++ b/bot/log.py @@ -16,6 +16,9 @@ def setup() -> None: logging.addLevelName(logging.TRACE, "TRACE") logging.Logger.trace = _monkeypatch_trace + format_string = "%(asctime)s | %(name)s | %(levelname)s | %(message)s" + log_format = logging.Formatter(format_string) + # Set up file logging log_file = Path("logs/sir-lancebot.log") log_file.parent.mkdir(exist_ok=True) @@ -24,8 +27,11 @@ def setup() -> None: file_handler = logging.handlers.RotatingFileHandler( log_file, maxBytes=5 * (2 ** 20), backupCount=10, encoding="utf-8", ) - # Console handler prints to terminal - console_handler = logging.StreamHandler() + file_handler.setFormatter(log_format) + + root_logger = logging.getLogger() + root_logger.setLevel(logging.TRACE if Client.debug else logging.INFO) + root_logger.addHandler(file_handler) if "COLOREDLOGS_LEVEL_STYLES" not in os.environ: coloredlogs.DEFAULT_LEVEL_STYLES = { @@ -36,7 +42,7 @@ def setup() -> None: } if "COLOREDLOGS_LOG_FORMAT" not in os.environ: - coloredlogs.DEFAULT_LOG_FORMAT = "%(asctime)s - %(name)s %(levelname)s: %(message)s" + coloredlogs.DEFAULT_LOG_FORMAT = format_string coloredlogs.install(stream=sys.stdout) @@ -47,13 +53,7 @@ def setup() -> None: logging.getLogger("matplotlib").setLevel(logging.ERROR) logging.getLogger("async_rediscache").setLevel(logging.WARNING) - # Setup new logging configuration - logging.basicConfig( - datefmt="%D %H:%M:%S", - level=logging.TRACE if Client.debug else logging.INFO, - handlers=[console_handler, file_handler], - ) - logging.getLogger().info("Logging initialization complete") + root_logger.info("Logging initialization complete") def _monkeypatch_trace(self: logging.Logger, msg: str, *args, **kwargs) -> None: -- cgit v1.2.3 From ecfe6bc1b89632c1161f5aad83a08a8459f8f13a Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 7 Sep 2021 00:32:12 +0200 Subject: Add selective trace loggers Add selective enabling of trace loggers as described in python-discord/bot#1529 --- bot/constants.py | 1 + bot/log.py | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index 2313bfdb..ae6e02c1 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -138,6 +138,7 @@ class Client(NamedTuple): github_bot_repo = "https://github.com/python-discord/sir-lancebot" # Override seasonal locks: 1 (January) to 12 (December) month_override = int(environ["MONTH_OVERRIDE"]) if "MONTH_OVERRIDE" in environ else None + trace_loggers = environ.get("BOT_TRACE_LOGGERS") class Colours: diff --git a/bot/log.py b/bot/log.py index c8437505..5e0e909d 100644 --- a/bot/log.py +++ b/bot/log.py @@ -30,7 +30,6 @@ def setup() -> None: file_handler.setFormatter(log_format) root_logger = logging.getLogger() - root_logger.setLevel(logging.TRACE if Client.debug else logging.INFO) root_logger.addHandler(file_handler) if "COLOREDLOGS_LEVEL_STYLES" not in os.environ: @@ -44,8 +43,9 @@ def setup() -> None: if "COLOREDLOGS_LOG_FORMAT" not in os.environ: coloredlogs.DEFAULT_LOG_FORMAT = format_string - coloredlogs.install(stream=sys.stdout) + coloredlogs.install(level=logging.TRACE, stream=sys.stdout) + root_logger.setLevel(logging.DEBUG if Client.debug else logging.INFO) # Silence irrelevant loggers logging.getLogger("discord").setLevel(logging.ERROR) logging.getLogger("websockets").setLevel(logging.ERROR) @@ -53,6 +53,8 @@ def setup() -> None: logging.getLogger("matplotlib").setLevel(logging.ERROR) logging.getLogger("async_rediscache").setLevel(logging.WARNING) + _set_trace_loggers() + root_logger.info("Logging initialization complete") @@ -65,3 +67,30 @@ def _monkeypatch_trace(self: logging.Logger, msg: str, *args, **kwargs) -> None: """ if self.isEnabledFor(logging.TRACE): self._log(logging.TRACE, msg, args, **kwargs) + + +def _set_trace_loggers() -> None: + """ + Set loggers to the trace level according to the value from the BOT_TRACE_LOGGERS env var. + + When the env var is a list of logger names delimited by a comma, + each of the listed loggers will be set to the trace level. + + If this list is prefixed with a "!", all of the loggers except the listed ones will be set to the trace level. + + Otherwise if the env var begins with a "*", + the root logger is set to the trace level and other contents are ignored. + """ + level_filter = Client.trace_loggers + if level_filter: + if level_filter.startswith("*"): + logging.getLogger().setLevel(logging.TRACE) + + elif level_filter.startswith("!"): + logging.getLogger().setLevel(logging.TRACE) + for logger_name in level_filter.strip("!,").split(","): + logging.getLogger(logger_name).setLevel(logging.DEBUG) + + else: + for logger_name in level_filter.strip(",").split(","): + logging.getLogger(logger_name).setLevel(logging.TRACE) -- cgit v1.2.3 From 92b63e85501be8169aa3be71d8f58a5ca69d8572 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 7 Sep 2021 12:51:45 -0400 Subject: Update code to use 'mode' variable Updated the code to parse user_input depending on the color code 'mode' passed to the command. Added stub code for future color codes and embeds if mode is None or wrong code. --- bot/exts/utilities/color.py | 59 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index b1b423e7..1efacead 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -10,7 +10,7 @@ from discord.ext import commands # from rapidfuzz import process from bot.bot import Bot -# from bot.constants import Colours +from bot.constants import Colours logger = logging.getLogger(__name__) @@ -33,13 +33,12 @@ class Color(commands.Cog): self.bot = bot @commands.command(aliases=["colour"]) - @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) - async def color(self, ctx: commands.Context, *, user_color: str) -> None: + async def color(self, ctx: commands.Context, mode: str, user_color: str) -> None: """Send information on input color code or color name.""" # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name # should we assume the color is RGB if not defined? - if "#" in user_color: + if mode.lower() == "hex": logger.info(f"{user_color = }") hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) if hex_match: @@ -55,15 +54,32 @@ class Color(commands.Cog): ) ) - elif "RGB" or "rgb" in user_color: - rgb_parse = user_color.split() - rgb = rgb_parse[1:].replace(", ", "") - logger.info(f"{rgb = }") - logger.info(f"{rgb[0] = }") - logger.info(f"{rgb[1] = }") - logger.info(f"{rgb[2] = }") - rgb_color = tuple(rgb) - hex_color = f"0x{int(rgb[0]):02x}{int(rgb[1]):02x}{int(rgb[2]):02x}" + elif mode.lower() == "rgb": + logger.info(f"{user_color = }") + # rgb_color = user_color + + elif mode.lower() == "hsv": + pass + elif mode.lower() == "hsl": + pass + elif mode.lower() == "cmyk": + pass + else: + # mode is either None or an invalid code + if mode is None: + no_mode_embed = Embed( + title="No 'mode' was passed, please define a color code.", + color=Colours.soft_red, + ) + await ctx.send(embed=no_mode_embed) + return + wrong_mode_embed = Embed( + title=f"The color code {mode} is not a valid option", + description="Possible modes are: Hex, RGB, HSV, HSL and CMYK.", + color=Colours.soft_red, + ) + await ctx.send(embed=wrong_mode_embed) + return main_embed = Embed( title=user_color, # need to replace with fuzzymatch color name @@ -83,6 +99,23 @@ class Color(commands.Cog): value=f">>RGB {rgb_color}", inline=False, ) + """ + main_embed.add_field( + name="HSV", + value=f">>HSV {hsv_color}", + inline=False, + ) + main_embed.add_field( + name="HSL", + value=f">>HSL {hsl_color}", + inline=False, + ) + main_embed.add_field( + name="CMYK", + value=f">>CMYK {cmyk_color}", + inline=False, + ) + """ await ctx.send(file=file, embed=main_embed) async def _create_thumbnail_attachment(self, color: str) -> File: -- cgit v1.2.3 From 348de13c97baac9813ad6be16a49cffa5c536751 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 8 Sep 2021 10:06:47 -0400 Subject: Minor fixes --- bot/exts/utilities/color.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 1efacead..d7fff503 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,4 +1,3 @@ -# imports # import colorsys import logging import re @@ -35,16 +34,14 @@ class Color(commands.Cog): @commands.command(aliases=["colour"]) async def color(self, ctx: commands.Context, mode: str, user_color: str) -> None: """Send information on input color code or color name.""" - # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name - # should we assume the color is RGB if not defined? - + logger.info(f"{mode = }") + logger.info(f"{user_color = }") if mode.lower() == "hex": - logger.info(f"{user_color = }") hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) if hex_match: hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) - logger.info(f"{hex_color = }") rgb_color = ImageColor.getcolor(user_color, "RGB") + logger.info(f"{hex_color = }") logger.info(f"{rgb_color = }") else: await ctx.send( @@ -53,11 +50,8 @@ class Color(commands.Cog): description=ERROR_MSG.format(user_color=user_color), ) ) - elif mode.lower() == "rgb": - logger.info(f"{user_color = }") - # rgb_color = user_color - + pass elif mode.lower() == "hsv": pass elif mode.lower() == "hsl": @@ -66,6 +60,7 @@ class Color(commands.Cog): pass else: # mode is either None or an invalid code + # need to handle whether user passes color name if mode is None: no_mode_embed = Embed( title="No 'mode' was passed, please define a color code.", -- cgit v1.2.3 From 39d10a42d592da3eb8a4f35111c7a6e815ab7bd8 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 10 Sep 2021 07:47:12 -0400 Subject: Test to capture all user_input --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index d7fff503..c4df3e10 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -32,7 +32,7 @@ class Color(commands.Cog): self.bot = bot @commands.command(aliases=["colour"]) - async def color(self, ctx: commands.Context, mode: str, user_color: str) -> None: + async def color(self, ctx: commands.Context, mode: str, *, user_color: str) -> None: """Send information on input color code or color name.""" logger.info(f"{mode = }") logger.info(f"{user_color = }") -- cgit v1.2.3 From 854452c60c589fa414b8cac66edcc884caa03bd6 Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sat, 11 Sep 2021 04:17:18 +0530 Subject: Added "colour information" and "colour conversion" features Details: https://github.com/python-discord/sir-lancebot/issues/677 NOTE: get_color_fields (line 122) method explicity requires a valid tuple of RGB values. --- bot/exts/utilities/color.py | 134 +++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 34 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index c4df3e10..6abfc006 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,4 +1,4 @@ -# import colorsys +import colorsys import logging import re from io import BytesIO @@ -76,44 +76,28 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return - main_embed = Embed( - title=user_color, # need to replace with fuzzymatch color name - color=hex_color, - ) async with ctx.typing(): - file = await self._create_thumbnail_attachment(rgb_color) + main_embed = Embed( + title=user_color, # need to replace with fuzzymatch color name + description='(Approx..)', + color=hex_color, + ) + + file = await self.create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") - main_embed.add_field( - name="Hex", - value=f">>Hex #{hex_color}", - inline=False, - ) - main_embed.add_field( - name="RGB", - value=f">>RGB {rgb_color}", - inline=False, - ) - """ - main_embed.add_field( - name="HSV", - value=f">>HSV {hsv_color}", - inline=False, - ) - main_embed.add_field( - name="HSL", - value=f">>HSL {hsl_color}", - inline=False, - ) - main_embed.add_field( - name="CMYK", - value=f">>CMYK {cmyk_color}", - inline=False, - ) - """ + fields = self.get_color_fields(rgb_color) + for field in fields: + main_embed.add_field( + name=field['name'], + value=field['value'], + inline=False, + ) + await ctx.send(file=file, embed=main_embed) - async def _create_thumbnail_attachment(self, color: str) -> File: + @staticmethod + async def create_thumbnail_attachment(color: str) -> File: """Generate a thumbnail from `color`.""" thumbnail = Image.new("RGB", (100, 100), color=color) bufferedio = BytesIO() @@ -124,6 +108,88 @@ class Color(commands.Cog): return file + @staticmethod + def get_color_fields(rgb_color: tuple[int, int, int]) -> list[dict]: + """Converts from `RGB` to `CMYK`, `HSV`, `HSL` and returns a list of fields.""" + + def _rgb_to_hex(rgb_color: tuple[int, int, int]) -> str: + """To convert from `RGB` to `Hex` notation.""" + return '#' + ''.join(hex(color)[2:].zfill(2) for color in rgb_color).upper() + + def _rgb_to_cmyk(rgb_color: tuple[int, int, int]) -> tuple[int, int, int, int]: + """To convert from `RGB` to `CMYK` color space.""" + r, g, b = rgb_color + + # RGB_SCALE -> 255 + # CMYK_SCALE -> 100 + + if (r == g == b == 0): + return 0, 0, 0, 100 # Representing Black + + # rgb [0,RGB_SCALE] -> cmy [0,1] + c = 1 - r / 255 + m = 1 - g / 255 + y = 1 - b / 255 + + # extract out k [0, 1] + min_cmy = min(c, m, y) + c = (c - min_cmy) / (1 - min_cmy) + m = (m - min_cmy) / (1 - min_cmy) + y = (y - min_cmy) / (1 - min_cmy) + k = min_cmy + + # rescale to the range [0,CMYK_SCALE] and round off + c = round(c * 100) + m = round(m * 100) + y = round(y * 100) + k = round(k * 100) + + return c, m, y, k + + def _rgb_to_hsv(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: + """To convert from `RGB` to `HSV` color space.""" + r, g, b = rgb_color + h, v, s = colorsys.rgb_to_hsv(r/float(255), g/float(255), b/float(255)) + h = round(h*360) + s = round(s*100) + v = round(v*100) + return h, s, v + + def _rgb_to_hsl(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: + """To convert from `RGB` to `HSL` color space.""" + r, g, b = rgb_color + h, l, s = colorsys.rgb_to_hls(r/float(255), g/float(255), b/float(255)) + h = round(h*360) + s = round(s*100) + l = round(l*100) # noqa: E741 It's little `L`, Reason: To maintain consistency. + return h, s, l + + hex_color = _rgb_to_hex(rgb_color) + cmyk_color = _rgb_to_cmyk(rgb_color) + hsv_color = _rgb_to_hsv(rgb_color) + hsl_color = _rgb_to_hsl(rgb_color) + + all_fields = [ + { + "name": "RGB", + "value": f"» rgb {rgb_color}\n» hex {hex_color}" + }, + { + "name": "CMYK", + "value": f"» cmyk {cmyk_color}" + }, + { + "name": "HSV", + "value": f"» hsv {hsv_color}" + }, + { + "name": "HSL", + "value": f"» hsl {hsl_color}" + }, + ] + + return all_fields + # if user_color in color_lists: # # fuzzy match for color -- cgit v1.2.3 From 5714e496c331786f4614ce6e2e6e132524d7d72f Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 11 Sep 2021 09:11:28 -0400 Subject: Move .json file to correct folder --- bot/resources/evergreen/ryanzec_colours.json | 1568 -------------------------- bot/resources/utilities/ryanzec_colours.json | 1568 ++++++++++++++++++++++++++ 2 files changed, 1568 insertions(+), 1568 deletions(-) delete mode 100644 bot/resources/evergreen/ryanzec_colours.json create mode 100644 bot/resources/utilities/ryanzec_colours.json diff --git a/bot/resources/evergreen/ryanzec_colours.json b/bot/resources/evergreen/ryanzec_colours.json deleted file mode 100644 index 7b89f052..00000000 --- a/bot/resources/evergreen/ryanzec_colours.json +++ /dev/null @@ -1,1568 +0,0 @@ -{ - "Abbey": "4C4F56", - "Acadia": "1B1404", - "Acapulco": "7CB0A1", - "Aero Blue": "C9FFE5", - "Affair": "714693", - "Akaroa": "D4C4A8", - "Alabaster": "FAFAFA", - "Albescent White": "F5E9D3", - "Algae Green": "93DFB8", - "Alice Blue": "F0F8FF", - "Alizarin Crimson": "E32636", - "Allports": "0076A3", - "Almond": "EED9C4", - "Almond Frost": "907B71", - "Alpine": "AF8F2C", - "Alto": "DBDBDB", - "Aluminium": "A9ACB6", - "Amaranth": "E52B50", - "Amazon": "3B7A57", - "Amber": "FFBF00", - "Americano": "87756E", - "Amethyst": "9966CC", - "Amethyst Smoke": "A397B4", - "Amour": "F9EAF3", - "Amulet": "7B9F80", - "Anakiwa": "9DE5FF", - "Antique Brass": "C88A65", - "Antique Bronze": "704A07", - "Anzac": "E0B646", - "Apache": "DFBE6F", - "Apple": "4FA83D", - "Apple Blossom": "AF4D43", - "Apple Green": "E2F3EC", - "Apricot": "EB9373", - "Apricot Peach": "FBCEB1", - "Apricot White": "FFFEEC", - "Aqua Deep": "014B43", - "Aqua Forest": "5FA777", - "Aqua Haze": "EDF5F5", - "Aqua Island": "A1DAD7", - "Aqua Spring": "EAF9F5", - "Aqua Squeeze": "E8F5F2", - "Aquamarine": "7FFFD4", - "Aquamarine Blue": "71D9E2", - "Arapawa": "110C6C", - "Armadillo": "433E37", - "Arrowtown": "948771", - "Ash": "C6C3B5", - "Asparagus": "7BA05B", - "Asphalt": "130A06", - "Astra": "FAEAB9", - "Astral": "327DA0", - "Astronaut": "283A77", - "Astronaut Blue": "013E62", - "Athens Gray": "EEF0F3", - "Aths Special": "ECEBCE", - "Atlantis": "97CD2D", - "Atoll": "0A6F75", - "Atomic Tangerine": "FF9966", - "Au Chico": "97605D", - "Aubergine": "3B0910", - "Australian Mint": "F5FFBE", - "Avocado": "888D65", - "Axolotl": "4E6649", - "Azalea": "F7C8DA", - "Aztec": "0D1C19", - "Azure": "315BA1", - "Azure Radiance": "007FFF", - "Baby Blue": "E0FFFF", - "Bahama Blue": "026395", - "Bahia": "A5CB0C", - "Baja White": "FFF8D1", - "Bali Hai": "859FAF", - "Baltic Sea": "2A2630", - "Bamboo": "DA6304", - "Banana Mania": "FBE7B2", - "Bandicoot": "858470", - "Barberry": "DED717", - "Barley Corn": "A68B5B", - "Barley White": "FFF4CE", - "Barossa": "44012D", - "Bastille": "292130", - "Battleship Gray": "828F72", - "Bay Leaf": "7DA98D", - "Bay of Many": "273A81", - "Bazaar": "98777B", - "Bean ": "3D0C02", - "Beauty Bush": "EEC1BE", - "Beaver": "926F5B", - "Beeswax": "FEF2C7", - "Beige": "F5F5DC", - "Bermuda": "7DD8C6", - "Bermuda Gray": "6B8BA2", - "Beryl Green": "DEE5C0", - "Bianca": "FCFBF3", - "Big Stone": "162A40", - "Bilbao": "327C14", - "Biloba Flower": "B2A1EA", - "Birch": "373021", - "Bird Flower": "D4CD16", - "Biscay": "1B3162", - "Bismark": "497183", - "Bison Hide": "C1B7A4", - "Bistre": "3D2B1F", - "Bitter": "868974", - "Bitter Lemon": "CAE00D", - "Bittersweet": "FE6F5E", - "Bizarre": "EEDEDA", - "Black": "000000", - "Black Bean": "081910", - "Black Forest": "0B1304", - "Black Haze": "F6F7F7", - "Black Marlin": "3E2C1C", - "Black Olive": "242E16", - "Black Pearl": "041322", - "Black Rock": "0D0332", - "Black Rose": "67032D", - "Black Russian": "0A001C", - "Black Squeeze": "F2FAFA", - "Black White": "FFFEF6", - "Blackberry": "4D0135", - "Blackcurrant": "32293A", - "Blaze Orange": "FF6600", - "Bleach White": "FEF3D8", - "Bleached Cedar": "2C2133", - "Blizzard Blue": "A3E3ED", - "Blossom": "DCB4BC", - "Blue": "0000FF", - "Blue Bayoux": "496679", - "Blue Bell": "9999CC", - "Blue Chalk": "F1E9FF", - "Blue Charcoal": "010D1A", - "Blue Chill": "0C8990", - "Blue Diamond": "380474", - "Blue Dianne": "204852", - "Blue Gem": "2C0E8C", - "Blue Haze": "BFBED8", - "Blue Lagoon": "017987", - "Blue Marguerite": "7666C6", - "Blue Ribbon": "0066FF", - "Blue Romance": "D2F6DE", - "Blue Smoke": "748881", - "Blue Stone": "016162", - "Blue Violet": "6456B7", - "Blue Whale": "042E4C", - "Blue Zodiac": "13264D", - "Blumine": "18587A", - "Blush": "B44668", - "Blush Pink": "FF6FFF", - "Bombay": "AFB1B8", - "Bon Jour": "E5E0E1", - "Bondi Blue": "0095B6", - "Bone": "E4D1C0", - "Bordeaux": "5C0120", - "Bossanova": "4E2A5A", - "Boston Blue": "3B91B4", - "Botticelli": "C7DDE5", - "Bottle Green": "093624", - "Boulder": "7A7A7A", - "Bouquet": "AE809E", - "Bourbon": "BA6F1E", - "Bracken": "4A2A04", - "Brandy": "DEC196", - "Brandy Punch": "CD8429", - "Brandy Rose": "BB8983", - "Breaker Bay": "5DA19F", - "Brick Red": "C62D42", - "Bridal Heath": "FFFAF4", - "Bridesmaid": "FEF0EC", - "Bright Gray": "3C4151", - "Bright Green": "66FF00", - "Bright Red": "B10000", - "Bright Sun": "FED33C", - "Bright Turquoise": "08E8DE", - "Brilliant Rose": "F653A6", - "Brink Pink": "FB607F", - "Bronco": "ABA196", - "Bronze": "3F2109", - "Bronze Olive": "4E420C", - "Bronzetone": "4D400F", - "Broom": "FFEC13", - "Brown": "964B00", - "Brown Bramble": "592804", - "Brown Derby": "492615", - "Brown Pod": "401801", - "Brown Rust": "AF593E", - "Brown Tumbleweed": "37290E", - "Bubbles": "E7FEFF", - "Buccaneer": "622F30", - "Bud": "A8AE9C", - "Buddha Gold": "C1A004", - "Buff": "F0DC82", - "Bulgarian Rose": "480607", - "Bull Shot": "864D1E", - "Bunker": "0D1117", - "Bunting": "151F4C", - "Burgundy": "900020", - "Burnham": "002E20", - "Burning Orange": "FF7034", - "Burning Sand": "D99376", - "Burnt Maroon": "420303", - "Burnt Orange": "CC5500", - "Burnt Sienna": "E97451", - "Burnt Umber": "8A3324", - "Bush": "0D2E1C", - "Buttercup": "F3AD16", - "Buttered Rum": "A1750D", - "Butterfly Bush": "624E9A", - "Buttermilk": "FFF1B5", - "Buttery White": "FFFCEA", - "Cab Sav": "4D0A18", - "Cabaret": "D94972", - "Cabbage Pont": "3F4C3A", - "Cactus": "587156", - "Cadet Blue": "A9B2C3", - "Cadillac": "B04C6A", - "Cafe Royale": "6F440C", - "Calico": "E0C095", - "California": "FE9D04", - "Calypso": "31728D", - "Camarone": "00581A", - "Camelot": "893456", - "Cameo": "D9B99B", - "Camouflage": "3C3910", - "Camouflage Green": "78866B", - "Can Can": "D591A4", - "Canary": "F3FB62", - "Candlelight": "FCD917", - "Candy Corn": "FBEC5D", - "Cannon Black": "251706", - "Cannon Pink": "894367", - "Cape Cod": "3C4443", - "Cape Honey": "FEE5AC", - "Cape Palliser": "A26645", - "Caper": "DCEDB4", - "Caramel": "FFDDAF", - "Cararra": "EEEEE8", - "Cardin Green": "01361C", - "Cardinal": "C41E3A", - "Cardinal Pink": "8C055E", - "Careys Pink": "D29EAA", - "Caribbean Green": "00CC99", - "Carissma": "EA88A8", - "Carla": "F3FFD8", - "Carmine": "960018", - "Carnaby Tan": "5C2E01", - "Carnation": "F95A61", - "Carnation Pink": "FFA6C9", - "Carousel Pink": "F9E0ED", - "Carrot Orange": "ED9121", - "Casablanca": "F8B853", - "Casal": "2F6168", - "Cascade": "8BA9A5", - "Cashmere": "E6BEA5", - "Casper": "ADBED1", - "Castro": "52001F", - "Catalina Blue": "062A78", - "Catskill White": "EEF6F7", - "Cavern Pink": "E3BEBE", - "Cedar": "3E1C14", - "Cedar Wood Finish": "711A00", - "Celadon": "ACE1AF", - "Celery": "B8C25D", - "Celeste": "D1D2CA", - "Cello": "1E385B", - "Celtic": "163222", - "Cement": "8D7662", - "Ceramic": "FCFFF9", - "Cerise": "DA3287", - "Cerise Red": "DE3163", - "Cerulean": "02A4D3", - "Cerulean Blue": "2A52BE", - "Chablis": "FFF4F3", - "Chalet Green": "516E3D", - "Chalky": "EED794", - "Chambray": "354E8C", - "Chamois": "EDDCB1", - "Champagne": "FAECCC", - "Chantilly": "F8C3DF", - "Charade": "292937", - "Chardon": "FFF3F1", - "Chardonnay": "FFCD8C", - "Charlotte": "BAEEF9", - "Charm": "D47494", - "Chartreuse": "7FFF00", - "Chartreuse Yellow": "DFFF00", - "Chateau Green": "40A860", - "Chatelle": "BDB3C7", - "Chathams Blue": "175579", - "Chelsea Cucumber": "83AA5D", - "Chelsea Gem": "9E5302", - "Chenin": "DFCD6F", - "Cherokee": "FCDA98", - "Cherry Pie": "2A0359", - "Cherrywood": "651A14", - "Cherub": "F8D9E9", - "Chestnut": "B94E48", - "Chestnut Rose": "CD5C5C", - "Chetwode Blue": "8581D9", - "Chicago": "5D5C58", - "Chiffon": "F1FFC8", - "Chilean Fire": "F77703", - "Chilean Heath": "FFFDE6", - "China Ivory": "FCFFE7", - "Chino": "CEC7A7", - "Chinook": "A8E3BD", - "Chocolate": "370202", - "Christalle": "33036B", - "Christi": "67A712", - "Christine": "E7730A", - "Chrome White": "E8F1D4", - "Cinder": "0E0E18", - "Cinderella": "FDE1DC", - "Cinnabar": "E34234", - "Cinnamon": "7B3F00", - "Cioccolato": "55280C", - "Citrine White": "FAF7D6", - "Citron": "9EA91F", - "Citrus": "A1C50A", - "Clairvoyant": "480656", - "Clam Shell": "D4B6AF", - "Claret": "7F1734", - "Classic Rose": "FBCCE7", - "Clay Ash": "BDC8B3", - "Clay Creek": "8A8360", - "Clear Day": "E9FFFD", - "Clementine": "E96E00", - "Clinker": "371D09", - "Cloud": "C7C4BF", - "Cloud Burst": "202E54", - "Cloudy": "ACA59F", - "Clover": "384910", - "Cobalt": "0047AB", - "Cocoa Bean": "481C1C", - "Cocoa Brown": "301F1E", - "Coconut Cream": "F8F7DC", - "Cod Gray": "0B0B0B", - "Coffee": "706555", - "Coffee Bean": "2A140E", - "Cognac": "9F381D", - "Cola": "3F2500", - "Cold Purple": "ABA0D9", - "Cold Turkey": "CEBABA", - "Colonial White": "FFEDBC", - "Comet": "5C5D75", - "Como": "517C66", - "Conch": "C9D9D2", - "Concord": "7C7B7A", - "Concrete": "F2F2F2", - "Confetti": "E9D75A", - "Congo Brown": "593737", - "Congress Blue": "02478E", - "Conifer": "ACDD4D", - "Contessa": "C6726B", - "Copper": "B87333", - "Copper Canyon": "7E3A15", - "Copper Rose": "996666", - "Copper Rust": "944747", - "Copperfield": "DA8A67", - "Coral": "FF7F50", - "Coral Red": "FF4040", - "Coral Reef": "C7BCA2", - "Coral Tree": "A86B6B", - "Corduroy": "606E68", - "Coriander": "C4D0B0", - "Cork": "40291D", - "Corn": "E7BF05", - "Corn Field": "F8FACD", - "Corn Harvest": "8B6B0B", - "Cornflower": "93CCEA", - "Cornflower Blue": "6495ED", - "Cornflower Lilac": "FFB0AC", - "Corvette": "FAD3A2", - "Cosmic": "76395D", - "Cosmos": "FFD8D9", - "Costa Del Sol": "615D30", - "Cotton Candy": "FFB7D5", - "Cotton Seed": "C2BDB6", - "County Green": "01371A", - "Cowboy": "4D282D", - "Crail": "B95140", - "Cranberry": "DB5079", - "Crater Brown": "462425", - "Cream": "FFFDD0", - "Cream Brulee": "FFE5A0", - "Cream Can": "F5C85C", - "Creole": "1E0F04", - "Crete": "737829", - "Crimson": "DC143C", - "Crocodile": "736D58", - "Crown of Thorns": "771F1F", - "Crowshead": "1C1208", - "Cruise": "B5ECDF", - "Crusoe": "004816", - "Crusta": "FD7B33", - "Cumin": "924321", - "Cumulus": "FDFFD5", - "Cupid": "FBBEDA", - "Curious Blue": "2596D1", - "Cutty Sark": "507672", - "Cyan / Aqua": "00FFFF", - "Cyprus": "003E40", - "Daintree": "012731", - "Dairy Cream": "F9E4BC", - "Daisy Bush": "4F2398", - "Dallas": "6E4B26", - "Dandelion": "FED85D", - "Danube": "6093D1", - "Dark Blue": "0000C8", - "Dark Burgundy": "770F05", - "Dark Ebony": "3C2005", - "Dark Fern": "0A480D", - "Dark Tan": "661010", - "Dawn": "A6A29A", - "Dawn Pink": "F3E9E5", - "De York": "7AC488", - "Deco": "D2DA97", - "Deep Blue": "220878", - "Deep Blush": "E47698", - "Deep Bronze": "4A3004", - "Deep Cerulean": "007BA7", - "Deep Cove": "051040", - "Deep Fir": "002900", - "Deep Forest Green": "182D09", - "Deep Koamaru": "1B127B", - "Deep Oak": "412010", - "Deep Sapphire": "082567", - "Deep Sea": "01826B", - "Deep Sea Green": "095859", - "Deep Teal": "003532", - "Del Rio": "B09A95", - "Dell": "396413", - "Delta": "A4A49D", - "Deluge": "7563A8", - "Denim": "1560BD", - "Derby": "FFEED8", - "Desert": "AE6020", - "Desert Sand": "EDC9AF", - "Desert Storm": "F8F8F7", - "Dew": "EAFFFE", - "Di Serria": "DB995E", - "Diesel": "130000", - "Dingley": "5D7747", - "Disco": "871550", - "Dixie": "E29418", - "Dodger Blue": "1E90FF", - "Dolly": "F9FF8B", - "Dolphin": "646077", - "Domino": "8E775E", - "Don Juan": "5D4C51", - "Donkey Brown": "A69279", - "Dorado": "6B5755", - "Double Colonial White": "EEE3AD", - "Double Pearl Lusta": "FCF4D0", - "Double Spanish White": "E6D7B9", - "Dove Gray": "6D6C6C", - "Downriver": "092256", - "Downy": "6FD0C5", - "Driftwood": "AF8751", - "Drover": "FDF7AD", - "Dull Lavender": "A899E6", - "Dune": "383533", - "Dust Storm": "E5CCC9", - "Dusty Gray": "A8989B", - "Eagle": "B6BAA4", - "Earls Green": "C9B93B", - "Early Dawn": "FFF9E6", - "East Bay": "414C7D", - "East Side": "AC91CE", - "Eastern Blue": "1E9AB0", - "Ebb": "E9E3E3", - "Ebony": "0C0B1D", - "Ebony Clay": "26283B", - "Eclipse": "311C17", - "Ecru White": "F5F3E5", - "Ecstasy": "FA7814", - "Eden": "105852", - "Edgewater": "C8E3D7", - "Edward": "A2AEAB", - "Egg Sour": "FFF4DD", - "Egg White": "FFEFC1", - "Eggplant": "614051", - "El Paso": "1E1708", - "El Salva": "8F3E33", - "Electric Lime": "CCFF00", - "Electric Violet": "8B00FF", - "Elephant": "123447", - "Elf Green": "088370", - "Elm": "1C7C7D", - "Emerald": "50C878", - "Eminence": "6C3082", - "Emperor": "514649", - "Empress": "817377", - "Endeavour": "0056A7", - "Energy Yellow": "F8DD5C", - "English Holly": "022D15", - "English Walnut": "3E2B23", - "Envy": "8BA690", - "Equator": "E1BC64", - "Espresso": "612718", - "Eternity": "211A0E", - "Eucalyptus": "278A5B", - "Eunry": "CFA39D", - "Evening Sea": "024E46", - "Everglade": "1C402E", - "Faded Jade": "427977", - "Fair Pink": "FFEFEC", - "Falcon": "7F626D", - "Fall Green": "ECEBBD", - "Falu Red": "801818", - "Fantasy": "FAF3F0", - "Fedora": "796A78", - "Feijoa": "9FDD8C", - "Fern": "63B76C", - "Fern Frond": "657220", - "Fern Green": "4F7942", - "Ferra": "704F50", - "Festival": "FBE96C", - "Feta": "F0FCEA", - "Fiery Orange": "B35213", - "Finch": "626649", - "Finlandia": "556D56", - "Finn": "692D54", - "Fiord": "405169", - "Fire": "AA4203", - "Fire Bush": "E89928", - "Firefly": "0E2A30", - "Flame Pea": "DA5B38", - "Flamenco": "FF7D07", - "Flamingo": "F2552A", - "Flax": "EEDC82", - "Flax Smoke": "7B8265", - "Flesh": "FFCBA4", - "Flint": "6F6A61", - "Flirt": "A2006D", - "Flush Mahogany": "CA3435", - "Flush Orange": "FF7F00", - "Foam": "D8FCFA", - "Fog": "D7D0FF", - "Foggy Gray": "CBCAB6", - "Forest Green": "228B22", - "Forget Me Not": "FFF1EE", - "Fountain Blue": "56B4BE", - "Frangipani": "FFDEB3", - "French Gray": "BDBDC6", - "French Lilac": "ECC7EE", - "French Pass": "BDEDFD", - "French Rose": "F64A8A", - "Fresh Eggplant": "990066", - "Friar Gray": "807E79", - "Fringy Flower": "B1E2C1", - "Froly": "F57584", - "Frost": "EDF5DD", - "Frosted Mint": "DBFFF8", - "Frostee": "E4F6E7", - "Fruit Salad": "4F9D5D", - "Fuchsia Blue": "7A58C1", - "Fuchsia Pink": "C154C1", - "Fuego": "BEDE0D", - "Fuel Yellow": "ECA927", - "Fun Blue": "1959A8", - "Fun Green": "016D39", - "Fuscous Gray": "54534D", - "Fuzzy Wuzzy Brown": "C45655", - "Gable Green": "163531", - "Gallery": "EFEFEF", - "Galliano": "DCB20C", - "Gamboge": "E49B0F", - "Geebung": "D18F1B", - "Genoa": "15736B", - "Geraldine": "FB8989", - "Geyser": "D4DFE2", - "Ghost": "C7C9D5", - "Gigas": "523C94", - "Gimblet": "B8B56A", - "Gin": "E8F2EB", - "Gin Fizz": "FFF9E2", - "Givry": "F8E4BF", - "Glacier": "80B3C4", - "Glade Green": "61845F", - "Go Ben": "726D4E", - "Goblin": "3D7D52", - "Gold": "FFD700", - "Gold Drop": "F18200", - "Gold Sand": "E6BE8A", - "Gold Tips": "DEBA13", - "Golden Bell": "E28913", - "Golden Dream": "F0D52D", - "Golden Fizz": "F5FB3D", - "Golden Glow": "FDE295", - "Golden Grass": "DAA520", - "Golden Sand": "F0DB7D", - "Golden Tainoi": "FFCC5C", - "Goldenrod": "FCD667", - "Gondola": "261414", - "Gordons Green": "0B1107", - "Gorse": "FFF14F", - "Gossamer": "069B81", - "Gossip": "D2F8B0", - "Gothic": "6D92A1", - "Governor Bay": "2F3CB3", - "Grain Brown": "E4D5B7", - "Grandis": "FFD38C", - "Granite Green": "8D8974", - "Granny Apple": "D5F6E3", - "Granny Smith": "84A0A0", - "Granny Smith Apple": "9DE093", - "Grape": "381A51", - "Graphite": "251607", - "Gravel": "4A444B", - "Gray": "808080", - "Gray Asparagus": "465945", - "Gray Chateau": "A2AAB3", - "Gray Nickel": "C3C3BD", - "Gray Nurse": "E7ECE6", - "Gray Olive": "A9A491", - "Gray Suit": "C1BECD", - "Green": "00FF00", - "Green Haze": "01A368", - "Green House": "24500F", - "Green Kelp": "25311C", - "Green Leaf": "436A0D", - "Green Mist": "CBD3B0", - "Green Pea": "1D6142", - "Green Smoke": "A4AF6E", - "Green Spring": "B8C1B1", - "Green Vogue": "032B52", - "Green Waterloo": "101405", - "Green White": "E8EBE0", - "Green Yellow": "ADFF2F", - "Grenadier": "D54600", - "Guardsman Red": "BA0101", - "Gulf Blue": "051657", - "Gulf Stream": "80B3AE", - "Gull Gray": "9DACB7", - "Gum Leaf": "B6D3BF", - "Gumbo": "7CA1A6", - "Gun Powder": "414257", - "Gunsmoke": "828685", - "Gurkha": "9A9577", - "Hacienda": "98811B", - "Hairy Heath": "6B2A14", - "Haiti": "1B1035", - "Half Baked": "85C4CC", - "Half Colonial White": "FDF6D3", - "Half Dutch White": "FEF7DE", - "Half Spanish White": "FEF4DB", - "Half and Half": "FFFEE1", - "Hampton": "E5D8AF", - "Harlequin": "3FFF00", - "Harp": "E6F2EA", - "Harvest Gold": "E0B974", - "Havelock Blue": "5590D9", - "Hawaiian Tan": "9D5616", - "Hawkes Blue": "D4E2FC", - "Heath": "541012", - "Heather": "B7C3D0", - "Heathered Gray": "B6B095", - "Heavy Metal": "2B3228", - "Heliotrope": "DF73FF", - "Hemlock": "5E5D3B", - "Hemp": "907874", - "Hibiscus": "B6316C", - "Highland": "6F8E63", - "Hillary": "ACA586", - "Himalaya": "6A5D1B", - "Hint of Green": "E6FFE9", - "Hint of Red": "FBF9F9", - "Hint of Yellow": "FAFDE4", - "Hippie Blue": "589AAF", - "Hippie Green": "53824B", - "Hippie Pink": "AE4560", - "Hit Gray": "A1ADB5", - "Hit Pink": "FFAB81", - "Hokey Pokey": "C8A528", - "Hoki": "65869F", - "Holly": "011D13", - "Hollywood Cerise": "F400A1", - "Honey Flower": "4F1C70", - "Honeysuckle": "EDFC84", - "Hopbush": "D06DA1", - "Horizon": "5A87A0", - "Horses Neck": "604913", - "Hot Cinnamon": "D2691E", - "Hot Pink": "FF69B4", - "Hot Toddy": "B38007", - "Humming Bird": "CFF9F3", - "Hunter Green": "161D10", - "Hurricane": "877C7B", - "Husk": "B7A458", - "Ice Cold": "B1F4E7", - "Iceberg": "DAF4F0", - "Illusion": "F6A4C9", - "Inch Worm": "B0E313", - "Indian Khaki": "C3B091", - "Indian Tan": "4D1E01", - "Indigo": "4F69C6", - "Indochine": "C26B03", - "International Klein Blue": "002FA7", - "International Orange": "FF4F00", - "Irish Coffee": "5F3D26", - "Iroko": "433120", - "Iron": "D4D7D9", - "Ironside Gray": "676662", - "Ironstone": "86483C", - "Island Spice": "FFFCEE", - "Ivory": "FFFFF0", - "Jacaranda": "2E0329", - "Jacarta": "3A2A6A", - "Jacko Bean": "2E1905", - "Jacksons Purple": "20208D", - "Jade": "00A86B", - "Jaffa": "EF863F", - "Jagged Ice": "C2E8E5", - "Jagger": "350E57", - "Jaguar": "080110", - "Jambalaya": "5B3013", - "Janna": "F4EBD3", - "Japanese Laurel": "0A6906", - "Japanese Maple": "780109", - "Japonica": "D87C63", - "Java": "1FC2C2", - "Jazzberry Jam": "A50B5E", - "Jelly Bean": "297B9A", - "Jet Stream": "B5D2CE", - "Jewel": "126B40", - "Jon": "3B1F1F", - "Jonquil": "EEFF9A", - "Jordy Blue": "8AB9F1", - "Judge Gray": "544333", - "Jumbo": "7C7B82", - "Jungle Green": "29AB87", - "Jungle Mist": "B4CFD3", - "Juniper": "6D9292", - "Just Right": "ECCDB9", - "Kabul": "5E483E", - "Kaitoke Green": "004620", - "Kangaroo": "C6C8BD", - "Karaka": "1E1609", - "Karry": "FFEAD4", - "Kashmir Blue": "507096", - "Kelp": "454936", - "Kenyan Copper": "7C1C05", - "Keppel": "3AB09E", - "Key Lime Pie": "BFC921", - "Khaki": "F0E68C", - "Kidnapper": "E1EAD4", - "Kilamanjaro": "240C02", - "Killarney": "3A6A47", - "Kimberly": "736C9F", - "Kingfisher Daisy": "3E0480", - "Kobi": "E79FC4", - "Kokoda": "6E6D57", - "Korma": "8F4B0E", - "Koromiko": "FFBD5F", - "Kournikova": "FFE772", - "Kumera": "886221", - "La Palma": "368716", - "La Rioja": "B3C110", - "Las Palmas": "C6E610", - "Laser": "C8B568", - "Laser Lemon": "FFFF66", - "Laurel": "749378", - "Lavender": "B57EDC", - "Lavender Gray": "BDBBD7", - "Lavender Magenta": "EE82EE", - "Lavender Pink": "FBAED2", - "Lavender Purple": "967BB6", - "Lavender Rose": "FBA0E3", - "Lavender blush": "FFF0F5", - "Leather": "967059", - "Lemon": "FDE910", - "Lemon Chiffon": "FFFACD", - "Lemon Ginger": "AC9E22", - "Lemon Grass": "9B9E8F", - "Light Apricot": "FDD5B1", - "Light Orchid": "E29CD2", - "Light Wisteria": "C9A0DC", - "Lightning Yellow": "FCC01E", - "Lilac": "C8A2C8", - "Lilac Bush": "9874D3", - "Lily": "C8AABF", - "Lily White": "E7F8FF", - "Lima": "76BD17", - "Lime": "BFFF00", - "Limeade": "6F9D02", - "Limed Ash": "747D63", - "Limed Oak": "AC8A56", - "Limed Spruce": "394851", - "Linen": "FAF0E6", - "Link Water": "D9E4F5", - "Lipstick": "AB0563", - "Lisbon Brown": "423921", - "Livid Brown": "4D282E", - "Loafer": "EEF4DE", - "Loblolly": "BDC9CE", - "Lochinvar": "2C8C84", - "Lochmara": "007EC7", - "Locust": "A8AF8E", - "Log Cabin": "242A1D", - "Logan": "AAA9CD", - "Lola": "DFCFDB", - "London Hue": "BEA6C3", - "Lonestar": "6D0101", - "Lotus": "863C3C", - "Loulou": "460B41", - "Lucky": "AF9F1C", - "Lucky Point": "1A1A68", - "Lunar Green": "3C493A", - "Luxor Gold": "A7882C", - "Lynch": "697E9A", - "Mabel": "D9F7FF", - "Macaroni and Cheese": "FFB97B", - "Madang": "B7F0BE", - "Madison": "09255D", - "Madras": "3F3002", - "Magenta / Fuchsia": "FF00FF", - "Magic Mint": "AAF0D1", - "Magnolia": "F8F4FF", - "Mahogany": "4E0606", - "Mai Tai": "B06608", - "Maize": "F5D5A0", - "Makara": "897D6D", - "Mako": "444954", - "Malachite": "0BDA51", - "Malibu": "7DC8F7", - "Mallard": "233418", - "Malta": "BDB2A1", - "Mamba": "8E8190", - "Manatee": "8D90A1", - "Mandalay": "AD781B", - "Mandy": "E25465", - "Mandys Pink": "F2C3B2", - "Mango Tango": "E77200", - "Manhattan": "F5C999", - "Mantis": "74C365", - "Mantle": "8B9C90", - "Manz": "EEEF78", - "Mardi Gras": "350036", - "Marigold": "B98D28", - "Marigold Yellow": "FBE870", - "Mariner": "286ACD", - "Maroon": "800000", - "Maroon Flush": "C32148", - "Maroon Oak": "520C17", - "Marshland": "0B0F08", - "Martini": "AFA09E", - "Martinique": "363050", - "Marzipan": "F8DB9D", - "Masala": "403B38", - "Matisse": "1B659D", - "Matrix": "B05D54", - "Matterhorn": "4E3B41", - "Mauve": "E0B0FF", - "Mauvelous": "F091A9", - "Maverick": "D8C2D5", - "Medium Carmine": "AF4035", - "Medium Purple": "9370DB", - "Medium Red Violet": "BB3385", - "Melanie": "E4C2D5", - "Melanzane": "300529", - "Melon": "FEBAAD", - "Melrose": "C7C1FF", - "Mercury": "E5E5E5", - "Merino": "F6F0E6", - "Merlin": "413C37", - "Merlot": "831923", - "Metallic Bronze": "49371B", - "Metallic Copper": "71291D", - "Meteor": "D07D12", - "Meteorite": "3C1F76", - "Mexican Red": "A72525", - "Mid Gray": "5F5F6E", - "Midnight": "011635", - "Midnight Blue": "003366", - "Midnight Moss": "041004", - "Mikado": "2D2510", - "Milan": "FAFFA4", - "Milano Red": "B81104", - "Milk Punch": "FFF6D4", - "Millbrook": "594433", - "Mimosa": "F8FDD3", - "Mindaro": "E3F988", - "Mine Shaft": "323232", - "Mineral Green": "3F5D53", - "Ming": "36747D", - "Minsk": "3F307F", - "Mint Green": "98FF98", - "Mint Julep": "F1EEC1", - "Mint Tulip": "C4F4EB", - "Mirage": "161928", - "Mischka": "D1D2DD", - "Mist Gray": "C4C4BC", - "Mobster": "7F7589", - "Moccaccino": "6E1D14", - "Mocha": "782D19", - "Mojo": "C04737", - "Mona Lisa": "FFA194", - "Monarch": "8B0723", - "Mondo": "4A3C30", - "Mongoose": "B5A27F", - "Monsoon": "8A8389", - "Monte Carlo": "83D0C6", - "Monza": "C7031E", - "Moody Blue": "7F76D3", - "Moon Glow": "FCFEDA", - "Moon Mist": "DCDDCC", - "Moon Raker": "D6CEF6", - "Morning Glory": "9EDEE0", - "Morocco Brown": "441D00", - "Mortar": "504351", - "Mosque": "036A6E", - "Moss Green": "ADDFAD", - "Mountain Meadow": "1AB385", - "Mountain Mist": "959396", - "Mountbatten Pink": "997A8D", - "Muddy Waters": "B78E5C", - "Muesli": "AA8B5B", - "Mulberry": "C54B8C", - "Mulberry Wood": "5C0536", - "Mule Fawn": "8C472F", - "Mulled Wine": "4E4562", - "Mustard": "FFDB58", - "My Pink": "D69188", - "My Sin": "FFB31F", - "Mystic": "E2EBED", - "Nandor": "4B5D52", - "Napa": "ACA494", - "Narvik": "EDF9F1", - "Natural Gray": "8B8680", - "Navajo White": "FFDEAD", - "Navy Blue": "000080", - "Nebula": "CBDBD6", - "Negroni": "FFE2C5", - "Neon Carrot": "FF9933", - "Nepal": "8EABC1", - "Neptune": "7CB7BB", - "Nero": "140600", - "Nevada": "646E75", - "New Orleans": "F3D69D", - "New York Pink": "D7837F", - "Niagara": "06A189", - "Night Rider": "1F120F", - "Night Shadz": "AA375A", - "Nile Blue": "193751", - "Nobel": "B7B1B1", - "Nomad": "BAB1A2", - "Norway": "A8BD9F", - "Nugget": "C59922", - "Nutmeg": "81422C", - "Nutmeg Wood Finish": "683600", - "Oasis": "FEEFCE", - "Observatory": "02866F", - "Ocean Green": "41AA78", - "Ochre": "CC7722", - "Off Green": "E6F8F3", - "Off Yellow": "FEF9E3", - "Oil": "281E15", - "Old Brick": "901E1E", - "Old Copper": "724A2F", - "Old Gold": "CFB53B", - "Old Lace": "FDF5E6", - "Old Lavender": "796878", - "Old Rose": "C08081", - "Olive": "808000", - "Olive Drab": "6B8E23", - "Olive Green": "B5B35C", - "Olive Haze": "8B8470", - "Olivetone": "716E10", - "Olivine": "9AB973", - "Onahau": "CDF4FF", - "Onion": "2F270E", - "Opal": "A9C6C2", - "Opium": "8E6F70", - "Oracle": "377475", - "Orange": "FF681F", - "Orange Peel": "FFA000", - "Orange Roughy": "C45719", - "Orange White": "FEFCED", - "Orchid": "DA70D6", - "Orchid White": "FFFDF3", - "Oregon": "9B4703", - "Orient": "015E85", - "Oriental Pink": "C69191", - "Orinoco": "F3FBD4", - "Oslo Gray": "878D91", - "Ottoman": "E9F8ED", - "Outer Space": "2D383A", - "Outrageous Orange": "FF6037", - "Oxford Blue": "384555", - "Oxley": "779E86", - "Oyster Bay": "DAFAFF", - "Oyster Pink": "E9CECD", - "Paarl": "A65529", - "Pablo": "776F61", - "Pacific Blue": "009DC4", - "Pacifika": "778120", - "Paco": "411F10", - "Padua": "ADE6C4", - "Pale Canary": "FFFF99", - "Pale Leaf": "C0D3B9", - "Pale Oyster": "988D77", - "Pale Prim": "FDFEB8", - "Pale Rose": "FFE1F2", - "Pale Sky": "6E7783", - "Pale Slate": "C3BFC1", - "Palm Green": "09230F", - "Palm Leaf": "19330E", - "Pampas": "F4F2EE", - "Panache": "EAF6EE", - "Pancho": "EDCDAB", - "Papaya Whip": "FFEFD5", - "Paprika": "8D0226", - "Paradiso": "317D82", - "Parchment": "F1E9D2", - "Paris Daisy": "FFF46E", - "Paris M": "26056A", - "Paris White": "CADCD4", - "Parsley": "134F19", - "Pastel Green": "77DD77", - "Pastel Pink": "FFD1DC", - "Patina": "639A8F", - "Pattens Blue": "DEF5FF", - "Paua": "260368", - "Pavlova": "D7C498", - "Peach": "FFE5B4", - "Peach Cream": "FFF0DB", - "Peach Orange": "FFCC99", - "Peach Schnapps": "FFDCD6", - "Peach Yellow": "FADFAD", - "Peanut": "782F16", - "Pear": "D1E231", - "Pearl Bush": "E8E0D5", - "Pearl Lusta": "FCF4DC", - "Peat": "716B56", - "Pelorous": "3EABBF", - "Peppermint": "E3F5E1", - "Perano": "A9BEF2", - "Perfume": "D0BEF8", - "Periglacial Blue": "E1E6D6", - "Periwinkle": "CCCCFF", - "Periwinkle Gray": "C3CDE6", - "Persian Blue": "1C39BB", - "Persian Green": "00A693", - "Persian Indigo": "32127A", - "Persian Pink": "F77FBE", - "Persian Plum": "701C1C", - "Persian Red": "CC3333", - "Persian Rose": "FE28A2", - "Persimmon": "FF6B53", - "Peru Tan": "7F3A02", - "Pesto": "7C7631", - "Petite Orchid": "DB9690", - "Pewter": "96A8A1", - "Pharlap": "A3807B", - "Picasso": "FFF39D", - "Pickled Bean": "6E4826", - "Pickled Bluewood": "314459", - "Picton Blue": "45B1E8", - "Pig Pink": "FDD7E4", - "Pigeon Post": "AFBDD9", - "Pigment Indigo": "4B0082", - "Pine Cone": "6D5E54", - "Pine Glade": "C7CD90", - "Pine Green": "01796F", - "Pine Tree": "171F04", - "Pink": "FFC0CB", - "Pink Flamingo": "FF66FF", - "Pink Flare": "E1C0C8", - "Pink Lace": "FFDDF4", - "Pink Lady": "FFF1D8", - "Pink Salmon": "FF91A4", - "Pink Swan": "BEB5B7", - "Piper": "C96323", - "Pipi": "FEF4CC", - "Pippin": "FFE1DF", - "Pirate Gold": "BA7F03", - "Pistachio": "9DC209", - "Pixie Green": "C0D8B6", - "Pizazz": "FF9000", - "Pizza": "C99415", - "Plantation": "27504B", - "Plum": "843179", - "Pohutukawa": "8F021C", - "Polar": "E5F9F6", - "Polo Blue": "8DA8CC", - "Pomegranate": "F34723", - "Pompadour": "660045", - "Porcelain": "EFF2F3", - "Porsche": "EAAE69", - "Port Gore": "251F4F", - "Portafino": "FFFFB4", - "Portage": "8B9FEE", - "Portica": "F9E663", - "Pot Pourri": "F5E7E2", - "Potters Clay": "8C5738", - "Powder Ash": "BCC9C2", - "Powder Blue": "B0E0E6", - "Prairie Sand": "9A3820", - "Prelude": "D0C0E5", - "Prim": "F0E2EC", - "Primrose": "EDEA99", - "Provincial Pink": "FEF5F1", - "Prussian Blue": "003153", - "Puce": "CC8899", - "Pueblo": "7D2C14", - "Puerto Rico": "3FC1AA", - "Pumice": "C2CAC4", - "Pumpkin": "FF7518", - "Pumpkin Skin": "B1610B", - "Punch": "DC4333", - "Punga": "4D3D14", - "Purple": "660099", - "Purple Heart": "652DC1", - "Purple Mountain's Majesty": "9678B6", - "Purple Pizzazz": "FF00CC", - "Putty": "E7CD8C", - "Quarter Pearl Lusta": "FFFDF4", - "Quarter Spanish White": "F7F2E1", - "Quicksand": "BD978E", - "Quill Gray": "D6D6D1", - "Quincy": "623F2D", - "Racing Green": "0C1911", - "Radical Red": "FF355E", - "Raffia": "EADAB8", - "Rainee": "B9C8AC", - "Rajah": "F7B668", - "Rangitoto": "2E3222", - "Rangoon Green": "1C1E13", - "Raven": "727B89", - "Raw Sienna": "D27D46", - "Raw Umber": "734A12", - "Razzle Dazzle Rose": "FF33CC", - "Razzmatazz": "E30B5C", - "Rebel": "3C1206", - "Red": "FF0000", - "Red Beech": "7B3801", - "Red Berry": "8E0000", - "Red Damask": "DA6A41", - "Red Devil": "860111", - "Red Orange": "FF3F34", - "Red Oxide": "6E0902", - "Red Ribbon": "ED0A3F", - "Red Robin": "80341F", - "Red Stage": "D05F04", - "Red Violet": "C71585", - "Redwood": "5D1E0F", - "Reef": "C9FFA2", - "Reef Gold": "9F821C", - "Regal Blue": "013F6A", - "Regent Gray": "86949F", - "Regent St Blue": "AAD6E6", - "Remy": "FEEBF3", - "Reno Sand": "A86515", - "Resolution Blue": "002387", - "Revolver": "2C1632", - "Rhino": "2E3F62", - "Rice Cake": "FFFEF0", - "Rice Flower": "EEFFE2", - "Rich Gold": "A85307", - "Rio Grande": "BBD009", - "Ripe Lemon": "F4D81C", - "Ripe Plum": "410056", - "Riptide": "8BE6D8", - "River Bed": "434C59", - "Rob Roy": "EAC674", - "Robin's Egg Blue": "00CCCC", - "Rock": "4D3833", - "Rock Blue": "9EB1CD", - "Rock Spray": "BA450C", - "Rodeo Dust": "C9B29B", - "Rolling Stone": "747D83", - "Roman": "DE6360", - "Roman Coffee": "795D4C", - "Romance": "FFFEFD", - "Romantic": "FFD2B7", - "Ronchi": "ECC54E", - "Roof Terracotta": "A62F20", - "Rope": "8E4D1E", - "Rose": "FF007F", - "Rose Bud": "FBB2A3", - "Rose Bud Cherry": "800B47", - "Rose Fog": "E7BCB4", - "Rose White": "FFF6F5", - "Rose of Sharon": "BF5500", - "Rosewood": "65000B", - "Roti": "C6A84B", - "Rouge": "A23B6C", - "Royal Blue": "4169E1", - "Royal Heath": "AB3472", - "Royal Purple": "6B3FA0", - "Rum": "796989", - "Rum Swizzle": "F9F8E4", - "Russet": "80461B", - "Russett": "755A57", - "Rust": "B7410E", - "Rustic Red": "480404", - "Rusty Nail": "86560A", - "Saddle": "4C3024", - "Saddle Brown": "583401", - "Saffron": "F4C430", - "Saffron Mango": "F9BF58", - "Sage": "9EA587", - "Sahara": "B7A214", - "Sahara Sand": "F1E788", - "Sail": "B8E0F9", - "Salem": "097F4B", - "Salmon": "FF8C69", - "Salomie": "FEDB8D", - "Salt Box": "685E6E", - "Saltpan": "F1F7F2", - "Sambuca": "3A2010", - "San Felix": "0B6207", - "San Juan": "304B6A", - "San Marino": "456CAC", - "Sand Dune": "826F65", - "Sandal": "AA8D6F", - "Sandrift": "AB917A", - "Sandstone": "796D62", - "Sandwisp": "F5E7A2", - "Sandy Beach": "FFEAC8", - "Sandy brown": "F4A460", - "Sangria": "92000A", - "Sanguine Brown": "8D3D38", - "Santa Fe": "B16D52", - "Santas Gray": "9FA0B1", - "Sapling": "DED4A4", - "Sapphire": "2F519E", - "Saratoga": "555B10", - "Satin Linen": "E6E4D4", - "Sauvignon": "FFF5F3", - "Sazerac": "FFF4E0", - "Scampi": "675FA6", - "Scandal": "CFFAF4", - "Scarlet": "FF2400", - "Scarlet Gum": "431560", - "Scarlett": "950015", - "Scarpa Flow": "585562", - "Schist": "A9B497", - "School bus Yellow": "FFD800", - "Schooner": "8B847E", - "Science Blue": "0066CC", - "Scooter": "2EBFD4", - "Scorpion": "695F62", - "Scotch Mist": "FFFBDC", - "Screamin' Green": "66FF66", - "Sea Buckthorn": "FBA129", - "Sea Green": "2E8B57", - "Sea Mist": "C5DBCA", - "Sea Nymph": "78A39C", - "Sea Pink": "ED989E", - "Seagull": "80CCEA", - "Seance": "731E8F", - "Seashell": "F1F1F1", - "Seashell Peach": "FFF5EE", - "Seaweed": "1B2F11", - "Selago": "F0EEFD", - "Selective Yellow": "FFBA00", - "Sepia": "704214", - "Sepia Black": "2B0202", - "Sepia Skin": "9E5B40", - "Serenade": "FFF4E8", - "Shadow": "837050", - "Shadow Green": "9AC2B8", - "Shady Lady": "AAA5A9", - "Shakespeare": "4EABD1", - "Shalimar": "FBFFBA", - "Shamrock": "33CC99", - "Shark": "25272C", - "Sherpa Blue": "004950", - "Sherwood Green": "02402C", - "Shilo": "E8B9B3", - "Shingle Fawn": "6B4E31", - "Ship Cove": "788BBA", - "Ship Gray": "3E3A44", - "Shiraz": "B20931", - "Shocking": "E292C0", - "Shocking Pink": "FC0FC0", - "Shuttle Gray": "5F6672", - "Siam": "646A54", - "Sidecar": "F3E7BB", - "Silk": "BDB1A8", - "Silver": "C0C0C0", - "Silver Chalice": "ACACAC", - "Silver Rust": "C9C0BB", - "Silver Sand": "BFC1C2", - "Silver Tree": "66B58F", - "Sinbad": "9FD7D3", - "Siren": "7A013A", - "Sirocco": "718080", - "Sisal": "D3CBBA", - "Skeptic": "CAE6DA", - "Sky Blue": "76D7EA", - "Slate Gray": "708090", - "Smalt": "003399", - "Smalt Blue": "51808F", - "Smoky": "605B73", - "Snow Drift": "F7FAF7", - "Snow Flurry": "E4FFD1", - "Snowy Mint": "D6FFDB", - "Snuff": "E2D8ED", - "Soapstone": "FFFBF9", - "Soft Amber": "D1C6B4", - "Soft Peach": "F5EDEF", - "Solid Pink": "893843", - "Solitaire": "FEF8E2", - "Solitude": "EAF6FF", - "Sorbus": "FD7C07", - "Sorrell Brown": "CEB98F", - "Soya Bean": "6A6051", - "Spanish Green": "819885", - "Spectra": "2F5A57", - "Spice": "6A442E", - "Spicy Mix": "885342", - "Spicy Mustard": "74640D", - "Spicy Pink": "816E71", - "Spindle": "B6D1EA", - "Spray": "79DEEC", - "Spring Green": "00FF7F", - "Spring Leaves": "578363", - "Spring Rain": "ACCBB1", - "Spring Sun": "F6FFDC", - "Spring Wood": "F8F6F1", - "Sprout": "C1D7B0", - "Spun Pearl": "AAABB7", - "Squirrel": "8F8176", - "St Tropaz": "2D569B", - "Stack": "8A8F8A", - "Star Dust": "9F9F9C", - "Stark White": "E5D7BD", - "Starship": "ECF245", - "Steel Blue": "4682B4", - "Steel Gray": "262335", - "Stiletto": "9C3336", - "Stonewall": "928573", - "Storm Dust": "646463", - "Storm Gray": "717486", - "Stratos": "000741", - "Straw": "D4BF8D", - "Strikemaster": "956387", - "Stromboli": "325D52", - "Studio": "714AB2", - "Submarine": "BAC7C9", - "Sugar Cane": "F9FFF6", - "Sulu": "C1F07C", - "Summer Green": "96BBAB", - "Sun": "FBAC13", - "Sundance": "C9B35B", - "Sundown": "FFB1B3", - "Sunflower": "E4D422", - "Sunglo": "E16865", - "Sunglow": "FFCC33", - "Sunset Orange": "FE4C40", - "Sunshade": "FF9E2C", - "Supernova": "FFC901", - "Surf": "BBD7C1", - "Surf Crest": "CFE5D2", - "Surfie Green": "0C7A79", - "Sushi": "87AB39", - "Suva Gray": "888387", - "Swamp": "001B1C", - "Swamp Green": "ACB78E", - "Swans Down": "DCF0EA", - "Sweet Corn": "FBEA8C", - "Sweet Pink": "FD9FA2", - "Swirl": "D3CDC5", - "Swiss Coffee": "DDD6D5", - "Sycamore": "908D39", - "Tabasco": "A02712", - "Tacao": "EDB381", - "Tacha": "D6C562", - "Tahiti Gold": "E97C07", - "Tahuna Sands": "EEF0C8", - "Tall Poppy": "B32D29", - "Tallow": "A8A589", - "Tamarillo": "991613", - "Tamarind": "341515", - "Tan": "D2B48C", - "Tan Hide": "FA9D5A", - "Tana": "D9DCC1", - "Tangaroa": "03163C", - "Tangerine": "F28500", - "Tango": "ED7A1C", - "Tapa": "7B7874", - "Tapestry": "B05E81", - "Tara": "E1F6E8", - "Tarawera": "073A50", - "Tasman": "CFDCCF", - "Taupe": "483C32", - "Taupe Gray": "B3AF95", - "Tawny Port": "692545", - "Te Papa Green": "1E433C", - "Tea": "C1BAB0", - "Tea Green": "D0F0C0", - "Teak": "B19461", - "Teal": "008080", - "Teal Blue": "044259", - "Temptress": "3B000B", - "Tenn": "CD5700", - "Tequila": "FFE6C7", - "Terracotta": "E2725B", - "Texas": "F8F99C", - "Texas Rose": "FFB555", - "Thatch": "B69D98", - "Thatch Green": "403D19", - "Thistle": "D8BFD8", - "Thistle Green": "CCCAA8", - "Thunder": "33292F", - "Thunderbird": "C02B18", - "Tia Maria": "C1440E", - "Tiara": "C3D1D1", - "Tiber": "063537", - "Tickle Me Pink": "FC80A5", - "Tidal": "F1FFAD", - "Tide": "BFB8B0", - "Timber Green": "16322C", - "Timberwolf": "D9D6CF", - "Titan White": "F0EEFF", - "Toast": "9A6E61", - "Tobacco Brown": "715D47", - "Toledo": "3A0020", - "Tolopea": "1B0245", - "Tom Thumb": "3F583B", - "Tonys Pink": "E79F8C", - "Topaz": "7C778A", - "Torch Red": "FD0E35", - "Torea Bay": "0F2D9E", - "Tory Blue": "1450AA", - "Tosca": "8D3F3F", - "Totem Pole": "991B07", - "Tower Gray": "A9BDBF", - "Tradewind": "5FB3AC", - "Tranquil": "E6FFFF", - "Travertine": "FFFDE8", - "Tree Poppy": "FC9C1D", - "Treehouse": "3B2820", - "Trendy Green": "7C881A", - "Trendy Pink": "8C6495", - "Trinidad": "E64E03", - "Tropical Blue": "C3DDF9", - "Tropical Rain Forest": "00755E", - "Trout": "4A4E5A", - "True V": "8A73D6", - "Tuatara": "363534", - "Tuft Bush": "FFDDCD", - "Tulip Tree": "EAB33B", - "Tumbleweed": "DEA681", - "Tuna": "353542", - "Tundora": "4A4244", - "Turbo": "FAE600", - "Turkish Rose": "B57281", - "Turmeric": "CABB48", - "Turquoise": "30D5C8", - "Turquoise Blue": "6CDAE7", - "Turtle Green": "2A380B", - "Tuscany": "BD5E2E", - "Tusk": "EEF3C3", - "Tussock": "C5994B", - "Tutu": "FFF1F9", - "Twilight": "E4CFDE", - "Twilight Blue": "EEFDFF", - "Twine": "C2955D", - "Tyrian Purple": "66023C", - "Ultramarine": "120A8F", - "Valencia": "D84437", - "Valentino": "350E42", - "Valhalla": "2B194F", - "Van Cleef": "49170C", - "Vanilla": "D1BEA8", - "Vanilla Ice": "F3D9DF", - "Varden": "FFF6DF", - "Venetian Red": "72010F", - "Venice Blue": "055989", - "Venus": "928590", - "Verdigris": "5D5E37", - "Verdun Green": "495400", - "Vermilion": "FF4D00", - "Vesuvius": "B14A0B", - "Victoria": "534491", - "Vida Loca": "549019", - "Viking": "64CCDB", - "Vin Rouge": "983D61", - "Viola": "CB8FA9", - "Violent Violet": "290C5E", - "Violet": "240A40", - "Violet Eggplant": "991199", - "Violet Red": "F7468A", - "Viridian": "40826D", - "Viridian Green": "678975", - "Vis Vis": "FFEFA1", - "Vista Blue": "8FD6B4", - "Vista White": "FCF8F7", - "Vivid Tangerine": "FF9980", - "Vivid Violet": "803790", - "Voodoo": "533455", - "Vulcan": "10121D", - "Wafer": "DECBC6", - "Waikawa Gray": "5A6E9C", - "Waiouru": "363C0D", - "Walnut": "773F1A", - "Wasabi": "788A25", - "Water Leaf": "A1E9DE", - "Watercourse": "056F57", - "Waterloo ": "7B7C94", - "Wattle": "DCD747", - "Watusi": "FFDDCF", - "Wax Flower": "FFC0A8", - "We Peep": "F7DBE6", - "Web Orange": "FFA500", - "Wedgewood": "4E7F9E", - "Well Read": "B43332", - "West Coast": "625119", - "West Side": "FF910F", - "Westar": "DCD9D2", - "Wewak": "F19BAB", - "Wheat": "F5DEB3", - "Wheatfield": "F3EDCF", - "Whiskey": "D59A6F", - "Whisper": "F7F5FA", - "White": "FFFFFF", - "White Ice": "DDF9F1", - "White Lilac": "F8F7FC", - "White Linen": "F8F0E8", - "White Pointer": "FEF8FF", - "White Rock": "EAE8D4", - "Wild Blue Yonder": "7A89B8", - "Wild Rice": "ECE090", - "Wild Sand": "F4F4F4", - "Wild Strawberry": "FF3399", - "Wild Watermelon": "FD5B78", - "Wild Willow": "B9C46A", - "William": "3A686C", - "Willow Brook": "DFECDA", - "Willow Grove": "65745D", - "Windsor": "3C0878", - "Wine Berry": "591D35", - "Winter Hazel": "D5D195", - "Wisp Pink": "FEF4F8", - "Wisteria": "9771B5", - "Wistful": "A4A6D3", - "Witch Haze": "FFFC99", - "Wood Bark": "261105", - "Woodland": "4D5328", - "Woodrush": "302A0F", - "Woodsmoke": "0C0D0F", - "Woody Brown": "483131", - "Xanadu": "738678", - "Yellow": "FFFF00", - "Yellow Green": "C5E17A", - "Yellow Metal": "716338", - "Yellow Orange": "FFAE42", - "Yellow Sea": "FEA904", - "Your Pink": "FFC3C0", - "Yukon Gold": "7B6608", - "Yuma": "CEC291", - "Zambezi": "685558", - "Zanah": "DAECD6", - "Zest": "E5841B", - "Zeus": "292319", - "Ziggurat": "BFDBE2", - "Zinnwaldite": "EBC2AF", - "Zircon": "F4F8FF", - "Zombie": "E4D69B", - "Zorba": "A59B91", - "Zuccini": "044022", - "Zumthor": "EDF6FF" -} diff --git a/bot/resources/utilities/ryanzec_colours.json b/bot/resources/utilities/ryanzec_colours.json new file mode 100644 index 00000000..7b89f052 --- /dev/null +++ b/bot/resources/utilities/ryanzec_colours.json @@ -0,0 +1,1568 @@ +{ + "Abbey": "4C4F56", + "Acadia": "1B1404", + "Acapulco": "7CB0A1", + "Aero Blue": "C9FFE5", + "Affair": "714693", + "Akaroa": "D4C4A8", + "Alabaster": "FAFAFA", + "Albescent White": "F5E9D3", + "Algae Green": "93DFB8", + "Alice Blue": "F0F8FF", + "Alizarin Crimson": "E32636", + "Allports": "0076A3", + "Almond": "EED9C4", + "Almond Frost": "907B71", + "Alpine": "AF8F2C", + "Alto": "DBDBDB", + "Aluminium": "A9ACB6", + "Amaranth": "E52B50", + "Amazon": "3B7A57", + "Amber": "FFBF00", + "Americano": "87756E", + "Amethyst": "9966CC", + "Amethyst Smoke": "A397B4", + "Amour": "F9EAF3", + "Amulet": "7B9F80", + "Anakiwa": "9DE5FF", + "Antique Brass": "C88A65", + "Antique Bronze": "704A07", + "Anzac": "E0B646", + "Apache": "DFBE6F", + "Apple": "4FA83D", + "Apple Blossom": "AF4D43", + "Apple Green": "E2F3EC", + "Apricot": "EB9373", + "Apricot Peach": "FBCEB1", + "Apricot White": "FFFEEC", + "Aqua Deep": "014B43", + "Aqua Forest": "5FA777", + "Aqua Haze": "EDF5F5", + "Aqua Island": "A1DAD7", + "Aqua Spring": "EAF9F5", + "Aqua Squeeze": "E8F5F2", + "Aquamarine": "7FFFD4", + "Aquamarine Blue": "71D9E2", + "Arapawa": "110C6C", + "Armadillo": "433E37", + "Arrowtown": "948771", + "Ash": "C6C3B5", + "Asparagus": "7BA05B", + "Asphalt": "130A06", + "Astra": "FAEAB9", + "Astral": "327DA0", + "Astronaut": "283A77", + "Astronaut Blue": "013E62", + "Athens Gray": "EEF0F3", + "Aths Special": "ECEBCE", + "Atlantis": "97CD2D", + "Atoll": "0A6F75", + "Atomic Tangerine": "FF9966", + "Au Chico": "97605D", + "Aubergine": "3B0910", + "Australian Mint": "F5FFBE", + "Avocado": "888D65", + "Axolotl": "4E6649", + "Azalea": "F7C8DA", + "Aztec": "0D1C19", + "Azure": "315BA1", + "Azure Radiance": "007FFF", + "Baby Blue": "E0FFFF", + "Bahama Blue": "026395", + "Bahia": "A5CB0C", + "Baja White": "FFF8D1", + "Bali Hai": "859FAF", + "Baltic Sea": "2A2630", + "Bamboo": "DA6304", + "Banana Mania": "FBE7B2", + "Bandicoot": "858470", + "Barberry": "DED717", + "Barley Corn": "A68B5B", + "Barley White": "FFF4CE", + "Barossa": "44012D", + "Bastille": "292130", + "Battleship Gray": "828F72", + "Bay Leaf": "7DA98D", + "Bay of Many": "273A81", + "Bazaar": "98777B", + "Bean ": "3D0C02", + "Beauty Bush": "EEC1BE", + "Beaver": "926F5B", + "Beeswax": "FEF2C7", + "Beige": "F5F5DC", + "Bermuda": "7DD8C6", + "Bermuda Gray": "6B8BA2", + "Beryl Green": "DEE5C0", + "Bianca": "FCFBF3", + "Big Stone": "162A40", + "Bilbao": "327C14", + "Biloba Flower": "B2A1EA", + "Birch": "373021", + "Bird Flower": "D4CD16", + "Biscay": "1B3162", + "Bismark": "497183", + "Bison Hide": "C1B7A4", + "Bistre": "3D2B1F", + "Bitter": "868974", + "Bitter Lemon": "CAE00D", + "Bittersweet": "FE6F5E", + "Bizarre": "EEDEDA", + "Black": "000000", + "Black Bean": "081910", + "Black Forest": "0B1304", + "Black Haze": "F6F7F7", + "Black Marlin": "3E2C1C", + "Black Olive": "242E16", + "Black Pearl": "041322", + "Black Rock": "0D0332", + "Black Rose": "67032D", + "Black Russian": "0A001C", + "Black Squeeze": "F2FAFA", + "Black White": "FFFEF6", + "Blackberry": "4D0135", + "Blackcurrant": "32293A", + "Blaze Orange": "FF6600", + "Bleach White": "FEF3D8", + "Bleached Cedar": "2C2133", + "Blizzard Blue": "A3E3ED", + "Blossom": "DCB4BC", + "Blue": "0000FF", + "Blue Bayoux": "496679", + "Blue Bell": "9999CC", + "Blue Chalk": "F1E9FF", + "Blue Charcoal": "010D1A", + "Blue Chill": "0C8990", + "Blue Diamond": "380474", + "Blue Dianne": "204852", + "Blue Gem": "2C0E8C", + "Blue Haze": "BFBED8", + "Blue Lagoon": "017987", + "Blue Marguerite": "7666C6", + "Blue Ribbon": "0066FF", + "Blue Romance": "D2F6DE", + "Blue Smoke": "748881", + "Blue Stone": "016162", + "Blue Violet": "6456B7", + "Blue Whale": "042E4C", + "Blue Zodiac": "13264D", + "Blumine": "18587A", + "Blush": "B44668", + "Blush Pink": "FF6FFF", + "Bombay": "AFB1B8", + "Bon Jour": "E5E0E1", + "Bondi Blue": "0095B6", + "Bone": "E4D1C0", + "Bordeaux": "5C0120", + "Bossanova": "4E2A5A", + "Boston Blue": "3B91B4", + "Botticelli": "C7DDE5", + "Bottle Green": "093624", + "Boulder": "7A7A7A", + "Bouquet": "AE809E", + "Bourbon": "BA6F1E", + "Bracken": "4A2A04", + "Brandy": "DEC196", + "Brandy Punch": "CD8429", + "Brandy Rose": "BB8983", + "Breaker Bay": "5DA19F", + "Brick Red": "C62D42", + "Bridal Heath": "FFFAF4", + "Bridesmaid": "FEF0EC", + "Bright Gray": "3C4151", + "Bright Green": "66FF00", + "Bright Red": "B10000", + "Bright Sun": "FED33C", + "Bright Turquoise": "08E8DE", + "Brilliant Rose": "F653A6", + "Brink Pink": "FB607F", + "Bronco": "ABA196", + "Bronze": "3F2109", + "Bronze Olive": "4E420C", + "Bronzetone": "4D400F", + "Broom": "FFEC13", + "Brown": "964B00", + "Brown Bramble": "592804", + "Brown Derby": "492615", + "Brown Pod": "401801", + "Brown Rust": "AF593E", + "Brown Tumbleweed": "37290E", + "Bubbles": "E7FEFF", + "Buccaneer": "622F30", + "Bud": "A8AE9C", + "Buddha Gold": "C1A004", + "Buff": "F0DC82", + "Bulgarian Rose": "480607", + "Bull Shot": "864D1E", + "Bunker": "0D1117", + "Bunting": "151F4C", + "Burgundy": "900020", + "Burnham": "002E20", + "Burning Orange": "FF7034", + "Burning Sand": "D99376", + "Burnt Maroon": "420303", + "Burnt Orange": "CC5500", + "Burnt Sienna": "E97451", + "Burnt Umber": "8A3324", + "Bush": "0D2E1C", + "Buttercup": "F3AD16", + "Buttered Rum": "A1750D", + "Butterfly Bush": "624E9A", + "Buttermilk": "FFF1B5", + "Buttery White": "FFFCEA", + "Cab Sav": "4D0A18", + "Cabaret": "D94972", + "Cabbage Pont": "3F4C3A", + "Cactus": "587156", + "Cadet Blue": "A9B2C3", + "Cadillac": "B04C6A", + "Cafe Royale": "6F440C", + "Calico": "E0C095", + "California": "FE9D04", + "Calypso": "31728D", + "Camarone": "00581A", + "Camelot": "893456", + "Cameo": "D9B99B", + "Camouflage": "3C3910", + "Camouflage Green": "78866B", + "Can Can": "D591A4", + "Canary": "F3FB62", + "Candlelight": "FCD917", + "Candy Corn": "FBEC5D", + "Cannon Black": "251706", + "Cannon Pink": "894367", + "Cape Cod": "3C4443", + "Cape Honey": "FEE5AC", + "Cape Palliser": "A26645", + "Caper": "DCEDB4", + "Caramel": "FFDDAF", + "Cararra": "EEEEE8", + "Cardin Green": "01361C", + "Cardinal": "C41E3A", + "Cardinal Pink": "8C055E", + "Careys Pink": "D29EAA", + "Caribbean Green": "00CC99", + "Carissma": "EA88A8", + "Carla": "F3FFD8", + "Carmine": "960018", + "Carnaby Tan": "5C2E01", + "Carnation": "F95A61", + "Carnation Pink": "FFA6C9", + "Carousel Pink": "F9E0ED", + "Carrot Orange": "ED9121", + "Casablanca": "F8B853", + "Casal": "2F6168", + "Cascade": "8BA9A5", + "Cashmere": "E6BEA5", + "Casper": "ADBED1", + "Castro": "52001F", + "Catalina Blue": "062A78", + "Catskill White": "EEF6F7", + "Cavern Pink": "E3BEBE", + "Cedar": "3E1C14", + "Cedar Wood Finish": "711A00", + "Celadon": "ACE1AF", + "Celery": "B8C25D", + "Celeste": "D1D2CA", + "Cello": "1E385B", + "Celtic": "163222", + "Cement": "8D7662", + "Ceramic": "FCFFF9", + "Cerise": "DA3287", + "Cerise Red": "DE3163", + "Cerulean": "02A4D3", + "Cerulean Blue": "2A52BE", + "Chablis": "FFF4F3", + "Chalet Green": "516E3D", + "Chalky": "EED794", + "Chambray": "354E8C", + "Chamois": "EDDCB1", + "Champagne": "FAECCC", + "Chantilly": "F8C3DF", + "Charade": "292937", + "Chardon": "FFF3F1", + "Chardonnay": "FFCD8C", + "Charlotte": "BAEEF9", + "Charm": "D47494", + "Chartreuse": "7FFF00", + "Chartreuse Yellow": "DFFF00", + "Chateau Green": "40A860", + "Chatelle": "BDB3C7", + "Chathams Blue": "175579", + "Chelsea Cucumber": "83AA5D", + "Chelsea Gem": "9E5302", + "Chenin": "DFCD6F", + "Cherokee": "FCDA98", + "Cherry Pie": "2A0359", + "Cherrywood": "651A14", + "Cherub": "F8D9E9", + "Chestnut": "B94E48", + "Chestnut Rose": "CD5C5C", + "Chetwode Blue": "8581D9", + "Chicago": "5D5C58", + "Chiffon": "F1FFC8", + "Chilean Fire": "F77703", + "Chilean Heath": "FFFDE6", + "China Ivory": "FCFFE7", + "Chino": "CEC7A7", + "Chinook": "A8E3BD", + "Chocolate": "370202", + "Christalle": "33036B", + "Christi": "67A712", + "Christine": "E7730A", + "Chrome White": "E8F1D4", + "Cinder": "0E0E18", + "Cinderella": "FDE1DC", + "Cinnabar": "E34234", + "Cinnamon": "7B3F00", + "Cioccolato": "55280C", + "Citrine White": "FAF7D6", + "Citron": "9EA91F", + "Citrus": "A1C50A", + "Clairvoyant": "480656", + "Clam Shell": "D4B6AF", + "Claret": "7F1734", + "Classic Rose": "FBCCE7", + "Clay Ash": "BDC8B3", + "Clay Creek": "8A8360", + "Clear Day": "E9FFFD", + "Clementine": "E96E00", + "Clinker": "371D09", + "Cloud": "C7C4BF", + "Cloud Burst": "202E54", + "Cloudy": "ACA59F", + "Clover": "384910", + "Cobalt": "0047AB", + "Cocoa Bean": "481C1C", + "Cocoa Brown": "301F1E", + "Coconut Cream": "F8F7DC", + "Cod Gray": "0B0B0B", + "Coffee": "706555", + "Coffee Bean": "2A140E", + "Cognac": "9F381D", + "Cola": "3F2500", + "Cold Purple": "ABA0D9", + "Cold Turkey": "CEBABA", + "Colonial White": "FFEDBC", + "Comet": "5C5D75", + "Como": "517C66", + "Conch": "C9D9D2", + "Concord": "7C7B7A", + "Concrete": "F2F2F2", + "Confetti": "E9D75A", + "Congo Brown": "593737", + "Congress Blue": "02478E", + "Conifer": "ACDD4D", + "Contessa": "C6726B", + "Copper": "B87333", + "Copper Canyon": "7E3A15", + "Copper Rose": "996666", + "Copper Rust": "944747", + "Copperfield": "DA8A67", + "Coral": "FF7F50", + "Coral Red": "FF4040", + "Coral Reef": "C7BCA2", + "Coral Tree": "A86B6B", + "Corduroy": "606E68", + "Coriander": "C4D0B0", + "Cork": "40291D", + "Corn": "E7BF05", + "Corn Field": "F8FACD", + "Corn Harvest": "8B6B0B", + "Cornflower": "93CCEA", + "Cornflower Blue": "6495ED", + "Cornflower Lilac": "FFB0AC", + "Corvette": "FAD3A2", + "Cosmic": "76395D", + "Cosmos": "FFD8D9", + "Costa Del Sol": "615D30", + "Cotton Candy": "FFB7D5", + "Cotton Seed": "C2BDB6", + "County Green": "01371A", + "Cowboy": "4D282D", + "Crail": "B95140", + "Cranberry": "DB5079", + "Crater Brown": "462425", + "Cream": "FFFDD0", + "Cream Brulee": "FFE5A0", + "Cream Can": "F5C85C", + "Creole": "1E0F04", + "Crete": "737829", + "Crimson": "DC143C", + "Crocodile": "736D58", + "Crown of Thorns": "771F1F", + "Crowshead": "1C1208", + "Cruise": "B5ECDF", + "Crusoe": "004816", + "Crusta": "FD7B33", + "Cumin": "924321", + "Cumulus": "FDFFD5", + "Cupid": "FBBEDA", + "Curious Blue": "2596D1", + "Cutty Sark": "507672", + "Cyan / Aqua": "00FFFF", + "Cyprus": "003E40", + "Daintree": "012731", + "Dairy Cream": "F9E4BC", + "Daisy Bush": "4F2398", + "Dallas": "6E4B26", + "Dandelion": "FED85D", + "Danube": "6093D1", + "Dark Blue": "0000C8", + "Dark Burgundy": "770F05", + "Dark Ebony": "3C2005", + "Dark Fern": "0A480D", + "Dark Tan": "661010", + "Dawn": "A6A29A", + "Dawn Pink": "F3E9E5", + "De York": "7AC488", + "Deco": "D2DA97", + "Deep Blue": "220878", + "Deep Blush": "E47698", + "Deep Bronze": "4A3004", + "Deep Cerulean": "007BA7", + "Deep Cove": "051040", + "Deep Fir": "002900", + "Deep Forest Green": "182D09", + "Deep Koamaru": "1B127B", + "Deep Oak": "412010", + "Deep Sapphire": "082567", + "Deep Sea": "01826B", + "Deep Sea Green": "095859", + "Deep Teal": "003532", + "Del Rio": "B09A95", + "Dell": "396413", + "Delta": "A4A49D", + "Deluge": "7563A8", + "Denim": "1560BD", + "Derby": "FFEED8", + "Desert": "AE6020", + "Desert Sand": "EDC9AF", + "Desert Storm": "F8F8F7", + "Dew": "EAFFFE", + "Di Serria": "DB995E", + "Diesel": "130000", + "Dingley": "5D7747", + "Disco": "871550", + "Dixie": "E29418", + "Dodger Blue": "1E90FF", + "Dolly": "F9FF8B", + "Dolphin": "646077", + "Domino": "8E775E", + "Don Juan": "5D4C51", + "Donkey Brown": "A69279", + "Dorado": "6B5755", + "Double Colonial White": "EEE3AD", + "Double Pearl Lusta": "FCF4D0", + "Double Spanish White": "E6D7B9", + "Dove Gray": "6D6C6C", + "Downriver": "092256", + "Downy": "6FD0C5", + "Driftwood": "AF8751", + "Drover": "FDF7AD", + "Dull Lavender": "A899E6", + "Dune": "383533", + "Dust Storm": "E5CCC9", + "Dusty Gray": "A8989B", + "Eagle": "B6BAA4", + "Earls Green": "C9B93B", + "Early Dawn": "FFF9E6", + "East Bay": "414C7D", + "East Side": "AC91CE", + "Eastern Blue": "1E9AB0", + "Ebb": "E9E3E3", + "Ebony": "0C0B1D", + "Ebony Clay": "26283B", + "Eclipse": "311C17", + "Ecru White": "F5F3E5", + "Ecstasy": "FA7814", + "Eden": "105852", + "Edgewater": "C8E3D7", + "Edward": "A2AEAB", + "Egg Sour": "FFF4DD", + "Egg White": "FFEFC1", + "Eggplant": "614051", + "El Paso": "1E1708", + "El Salva": "8F3E33", + "Electric Lime": "CCFF00", + "Electric Violet": "8B00FF", + "Elephant": "123447", + "Elf Green": "088370", + "Elm": "1C7C7D", + "Emerald": "50C878", + "Eminence": "6C3082", + "Emperor": "514649", + "Empress": "817377", + "Endeavour": "0056A7", + "Energy Yellow": "F8DD5C", + "English Holly": "022D15", + "English Walnut": "3E2B23", + "Envy": "8BA690", + "Equator": "E1BC64", + "Espresso": "612718", + "Eternity": "211A0E", + "Eucalyptus": "278A5B", + "Eunry": "CFA39D", + "Evening Sea": "024E46", + "Everglade": "1C402E", + "Faded Jade": "427977", + "Fair Pink": "FFEFEC", + "Falcon": "7F626D", + "Fall Green": "ECEBBD", + "Falu Red": "801818", + "Fantasy": "FAF3F0", + "Fedora": "796A78", + "Feijoa": "9FDD8C", + "Fern": "63B76C", + "Fern Frond": "657220", + "Fern Green": "4F7942", + "Ferra": "704F50", + "Festival": "FBE96C", + "Feta": "F0FCEA", + "Fiery Orange": "B35213", + "Finch": "626649", + "Finlandia": "556D56", + "Finn": "692D54", + "Fiord": "405169", + "Fire": "AA4203", + "Fire Bush": "E89928", + "Firefly": "0E2A30", + "Flame Pea": "DA5B38", + "Flamenco": "FF7D07", + "Flamingo": "F2552A", + "Flax": "EEDC82", + "Flax Smoke": "7B8265", + "Flesh": "FFCBA4", + "Flint": "6F6A61", + "Flirt": "A2006D", + "Flush Mahogany": "CA3435", + "Flush Orange": "FF7F00", + "Foam": "D8FCFA", + "Fog": "D7D0FF", + "Foggy Gray": "CBCAB6", + "Forest Green": "228B22", + "Forget Me Not": "FFF1EE", + "Fountain Blue": "56B4BE", + "Frangipani": "FFDEB3", + "French Gray": "BDBDC6", + "French Lilac": "ECC7EE", + "French Pass": "BDEDFD", + "French Rose": "F64A8A", + "Fresh Eggplant": "990066", + "Friar Gray": "807E79", + "Fringy Flower": "B1E2C1", + "Froly": "F57584", + "Frost": "EDF5DD", + "Frosted Mint": "DBFFF8", + "Frostee": "E4F6E7", + "Fruit Salad": "4F9D5D", + "Fuchsia Blue": "7A58C1", + "Fuchsia Pink": "C154C1", + "Fuego": "BEDE0D", + "Fuel Yellow": "ECA927", + "Fun Blue": "1959A8", + "Fun Green": "016D39", + "Fuscous Gray": "54534D", + "Fuzzy Wuzzy Brown": "C45655", + "Gable Green": "163531", + "Gallery": "EFEFEF", + "Galliano": "DCB20C", + "Gamboge": "E49B0F", + "Geebung": "D18F1B", + "Genoa": "15736B", + "Geraldine": "FB8989", + "Geyser": "D4DFE2", + "Ghost": "C7C9D5", + "Gigas": "523C94", + "Gimblet": "B8B56A", + "Gin": "E8F2EB", + "Gin Fizz": "FFF9E2", + "Givry": "F8E4BF", + "Glacier": "80B3C4", + "Glade Green": "61845F", + "Go Ben": "726D4E", + "Goblin": "3D7D52", + "Gold": "FFD700", + "Gold Drop": "F18200", + "Gold Sand": "E6BE8A", + "Gold Tips": "DEBA13", + "Golden Bell": "E28913", + "Golden Dream": "F0D52D", + "Golden Fizz": "F5FB3D", + "Golden Glow": "FDE295", + "Golden Grass": "DAA520", + "Golden Sand": "F0DB7D", + "Golden Tainoi": "FFCC5C", + "Goldenrod": "FCD667", + "Gondola": "261414", + "Gordons Green": "0B1107", + "Gorse": "FFF14F", + "Gossamer": "069B81", + "Gossip": "D2F8B0", + "Gothic": "6D92A1", + "Governor Bay": "2F3CB3", + "Grain Brown": "E4D5B7", + "Grandis": "FFD38C", + "Granite Green": "8D8974", + "Granny Apple": "D5F6E3", + "Granny Smith": "84A0A0", + "Granny Smith Apple": "9DE093", + "Grape": "381A51", + "Graphite": "251607", + "Gravel": "4A444B", + "Gray": "808080", + "Gray Asparagus": "465945", + "Gray Chateau": "A2AAB3", + "Gray Nickel": "C3C3BD", + "Gray Nurse": "E7ECE6", + "Gray Olive": "A9A491", + "Gray Suit": "C1BECD", + "Green": "00FF00", + "Green Haze": "01A368", + "Green House": "24500F", + "Green Kelp": "25311C", + "Green Leaf": "436A0D", + "Green Mist": "CBD3B0", + "Green Pea": "1D6142", + "Green Smoke": "A4AF6E", + "Green Spring": "B8C1B1", + "Green Vogue": "032B52", + "Green Waterloo": "101405", + "Green White": "E8EBE0", + "Green Yellow": "ADFF2F", + "Grenadier": "D54600", + "Guardsman Red": "BA0101", + "Gulf Blue": "051657", + "Gulf Stream": "80B3AE", + "Gull Gray": "9DACB7", + "Gum Leaf": "B6D3BF", + "Gumbo": "7CA1A6", + "Gun Powder": "414257", + "Gunsmoke": "828685", + "Gurkha": "9A9577", + "Hacienda": "98811B", + "Hairy Heath": "6B2A14", + "Haiti": "1B1035", + "Half Baked": "85C4CC", + "Half Colonial White": "FDF6D3", + "Half Dutch White": "FEF7DE", + "Half Spanish White": "FEF4DB", + "Half and Half": "FFFEE1", + "Hampton": "E5D8AF", + "Harlequin": "3FFF00", + "Harp": "E6F2EA", + "Harvest Gold": "E0B974", + "Havelock Blue": "5590D9", + "Hawaiian Tan": "9D5616", + "Hawkes Blue": "D4E2FC", + "Heath": "541012", + "Heather": "B7C3D0", + "Heathered Gray": "B6B095", + "Heavy Metal": "2B3228", + "Heliotrope": "DF73FF", + "Hemlock": "5E5D3B", + "Hemp": "907874", + "Hibiscus": "B6316C", + "Highland": "6F8E63", + "Hillary": "ACA586", + "Himalaya": "6A5D1B", + "Hint of Green": "E6FFE9", + "Hint of Red": "FBF9F9", + "Hint of Yellow": "FAFDE4", + "Hippie Blue": "589AAF", + "Hippie Green": "53824B", + "Hippie Pink": "AE4560", + "Hit Gray": "A1ADB5", + "Hit Pink": "FFAB81", + "Hokey Pokey": "C8A528", + "Hoki": "65869F", + "Holly": "011D13", + "Hollywood Cerise": "F400A1", + "Honey Flower": "4F1C70", + "Honeysuckle": "EDFC84", + "Hopbush": "D06DA1", + "Horizon": "5A87A0", + "Horses Neck": "604913", + "Hot Cinnamon": "D2691E", + "Hot Pink": "FF69B4", + "Hot Toddy": "B38007", + "Humming Bird": "CFF9F3", + "Hunter Green": "161D10", + "Hurricane": "877C7B", + "Husk": "B7A458", + "Ice Cold": "B1F4E7", + "Iceberg": "DAF4F0", + "Illusion": "F6A4C9", + "Inch Worm": "B0E313", + "Indian Khaki": "C3B091", + "Indian Tan": "4D1E01", + "Indigo": "4F69C6", + "Indochine": "C26B03", + "International Klein Blue": "002FA7", + "International Orange": "FF4F00", + "Irish Coffee": "5F3D26", + "Iroko": "433120", + "Iron": "D4D7D9", + "Ironside Gray": "676662", + "Ironstone": "86483C", + "Island Spice": "FFFCEE", + "Ivory": "FFFFF0", + "Jacaranda": "2E0329", + "Jacarta": "3A2A6A", + "Jacko Bean": "2E1905", + "Jacksons Purple": "20208D", + "Jade": "00A86B", + "Jaffa": "EF863F", + "Jagged Ice": "C2E8E5", + "Jagger": "350E57", + "Jaguar": "080110", + "Jambalaya": "5B3013", + "Janna": "F4EBD3", + "Japanese Laurel": "0A6906", + "Japanese Maple": "780109", + "Japonica": "D87C63", + "Java": "1FC2C2", + "Jazzberry Jam": "A50B5E", + "Jelly Bean": "297B9A", + "Jet Stream": "B5D2CE", + "Jewel": "126B40", + "Jon": "3B1F1F", + "Jonquil": "EEFF9A", + "Jordy Blue": "8AB9F1", + "Judge Gray": "544333", + "Jumbo": "7C7B82", + "Jungle Green": "29AB87", + "Jungle Mist": "B4CFD3", + "Juniper": "6D9292", + "Just Right": "ECCDB9", + "Kabul": "5E483E", + "Kaitoke Green": "004620", + "Kangaroo": "C6C8BD", + "Karaka": "1E1609", + "Karry": "FFEAD4", + "Kashmir Blue": "507096", + "Kelp": "454936", + "Kenyan Copper": "7C1C05", + "Keppel": "3AB09E", + "Key Lime Pie": "BFC921", + "Khaki": "F0E68C", + "Kidnapper": "E1EAD4", + "Kilamanjaro": "240C02", + "Killarney": "3A6A47", + "Kimberly": "736C9F", + "Kingfisher Daisy": "3E0480", + "Kobi": "E79FC4", + "Kokoda": "6E6D57", + "Korma": "8F4B0E", + "Koromiko": "FFBD5F", + "Kournikova": "FFE772", + "Kumera": "886221", + "La Palma": "368716", + "La Rioja": "B3C110", + "Las Palmas": "C6E610", + "Laser": "C8B568", + "Laser Lemon": "FFFF66", + "Laurel": "749378", + "Lavender": "B57EDC", + "Lavender Gray": "BDBBD7", + "Lavender Magenta": "EE82EE", + "Lavender Pink": "FBAED2", + "Lavender Purple": "967BB6", + "Lavender Rose": "FBA0E3", + "Lavender blush": "FFF0F5", + "Leather": "967059", + "Lemon": "FDE910", + "Lemon Chiffon": "FFFACD", + "Lemon Ginger": "AC9E22", + "Lemon Grass": "9B9E8F", + "Light Apricot": "FDD5B1", + "Light Orchid": "E29CD2", + "Light Wisteria": "C9A0DC", + "Lightning Yellow": "FCC01E", + "Lilac": "C8A2C8", + "Lilac Bush": "9874D3", + "Lily": "C8AABF", + "Lily White": "E7F8FF", + "Lima": "76BD17", + "Lime": "BFFF00", + "Limeade": "6F9D02", + "Limed Ash": "747D63", + "Limed Oak": "AC8A56", + "Limed Spruce": "394851", + "Linen": "FAF0E6", + "Link Water": "D9E4F5", + "Lipstick": "AB0563", + "Lisbon Brown": "423921", + "Livid Brown": "4D282E", + "Loafer": "EEF4DE", + "Loblolly": "BDC9CE", + "Lochinvar": "2C8C84", + "Lochmara": "007EC7", + "Locust": "A8AF8E", + "Log Cabin": "242A1D", + "Logan": "AAA9CD", + "Lola": "DFCFDB", + "London Hue": "BEA6C3", + "Lonestar": "6D0101", + "Lotus": "863C3C", + "Loulou": "460B41", + "Lucky": "AF9F1C", + "Lucky Point": "1A1A68", + "Lunar Green": "3C493A", + "Luxor Gold": "A7882C", + "Lynch": "697E9A", + "Mabel": "D9F7FF", + "Macaroni and Cheese": "FFB97B", + "Madang": "B7F0BE", + "Madison": "09255D", + "Madras": "3F3002", + "Magenta / Fuchsia": "FF00FF", + "Magic Mint": "AAF0D1", + "Magnolia": "F8F4FF", + "Mahogany": "4E0606", + "Mai Tai": "B06608", + "Maize": "F5D5A0", + "Makara": "897D6D", + "Mako": "444954", + "Malachite": "0BDA51", + "Malibu": "7DC8F7", + "Mallard": "233418", + "Malta": "BDB2A1", + "Mamba": "8E8190", + "Manatee": "8D90A1", + "Mandalay": "AD781B", + "Mandy": "E25465", + "Mandys Pink": "F2C3B2", + "Mango Tango": "E77200", + "Manhattan": "F5C999", + "Mantis": "74C365", + "Mantle": "8B9C90", + "Manz": "EEEF78", + "Mardi Gras": "350036", + "Marigold": "B98D28", + "Marigold Yellow": "FBE870", + "Mariner": "286ACD", + "Maroon": "800000", + "Maroon Flush": "C32148", + "Maroon Oak": "520C17", + "Marshland": "0B0F08", + "Martini": "AFA09E", + "Martinique": "363050", + "Marzipan": "F8DB9D", + "Masala": "403B38", + "Matisse": "1B659D", + "Matrix": "B05D54", + "Matterhorn": "4E3B41", + "Mauve": "E0B0FF", + "Mauvelous": "F091A9", + "Maverick": "D8C2D5", + "Medium Carmine": "AF4035", + "Medium Purple": "9370DB", + "Medium Red Violet": "BB3385", + "Melanie": "E4C2D5", + "Melanzane": "300529", + "Melon": "FEBAAD", + "Melrose": "C7C1FF", + "Mercury": "E5E5E5", + "Merino": "F6F0E6", + "Merlin": "413C37", + "Merlot": "831923", + "Metallic Bronze": "49371B", + "Metallic Copper": "71291D", + "Meteor": "D07D12", + "Meteorite": "3C1F76", + "Mexican Red": "A72525", + "Mid Gray": "5F5F6E", + "Midnight": "011635", + "Midnight Blue": "003366", + "Midnight Moss": "041004", + "Mikado": "2D2510", + "Milan": "FAFFA4", + "Milano Red": "B81104", + "Milk Punch": "FFF6D4", + "Millbrook": "594433", + "Mimosa": "F8FDD3", + "Mindaro": "E3F988", + "Mine Shaft": "323232", + "Mineral Green": "3F5D53", + "Ming": "36747D", + "Minsk": "3F307F", + "Mint Green": "98FF98", + "Mint Julep": "F1EEC1", + "Mint Tulip": "C4F4EB", + "Mirage": "161928", + "Mischka": "D1D2DD", + "Mist Gray": "C4C4BC", + "Mobster": "7F7589", + "Moccaccino": "6E1D14", + "Mocha": "782D19", + "Mojo": "C04737", + "Mona Lisa": "FFA194", + "Monarch": "8B0723", + "Mondo": "4A3C30", + "Mongoose": "B5A27F", + "Monsoon": "8A8389", + "Monte Carlo": "83D0C6", + "Monza": "C7031E", + "Moody Blue": "7F76D3", + "Moon Glow": "FCFEDA", + "Moon Mist": "DCDDCC", + "Moon Raker": "D6CEF6", + "Morning Glory": "9EDEE0", + "Morocco Brown": "441D00", + "Mortar": "504351", + "Mosque": "036A6E", + "Moss Green": "ADDFAD", + "Mountain Meadow": "1AB385", + "Mountain Mist": "959396", + "Mountbatten Pink": "997A8D", + "Muddy Waters": "B78E5C", + "Muesli": "AA8B5B", + "Mulberry": "C54B8C", + "Mulberry Wood": "5C0536", + "Mule Fawn": "8C472F", + "Mulled Wine": "4E4562", + "Mustard": "FFDB58", + "My Pink": "D69188", + "My Sin": "FFB31F", + "Mystic": "E2EBED", + "Nandor": "4B5D52", + "Napa": "ACA494", + "Narvik": "EDF9F1", + "Natural Gray": "8B8680", + "Navajo White": "FFDEAD", + "Navy Blue": "000080", + "Nebula": "CBDBD6", + "Negroni": "FFE2C5", + "Neon Carrot": "FF9933", + "Nepal": "8EABC1", + "Neptune": "7CB7BB", + "Nero": "140600", + "Nevada": "646E75", + "New Orleans": "F3D69D", + "New York Pink": "D7837F", + "Niagara": "06A189", + "Night Rider": "1F120F", + "Night Shadz": "AA375A", + "Nile Blue": "193751", + "Nobel": "B7B1B1", + "Nomad": "BAB1A2", + "Norway": "A8BD9F", + "Nugget": "C59922", + "Nutmeg": "81422C", + "Nutmeg Wood Finish": "683600", + "Oasis": "FEEFCE", + "Observatory": "02866F", + "Ocean Green": "41AA78", + "Ochre": "CC7722", + "Off Green": "E6F8F3", + "Off Yellow": "FEF9E3", + "Oil": "281E15", + "Old Brick": "901E1E", + "Old Copper": "724A2F", + "Old Gold": "CFB53B", + "Old Lace": "FDF5E6", + "Old Lavender": "796878", + "Old Rose": "C08081", + "Olive": "808000", + "Olive Drab": "6B8E23", + "Olive Green": "B5B35C", + "Olive Haze": "8B8470", + "Olivetone": "716E10", + "Olivine": "9AB973", + "Onahau": "CDF4FF", + "Onion": "2F270E", + "Opal": "A9C6C2", + "Opium": "8E6F70", + "Oracle": "377475", + "Orange": "FF681F", + "Orange Peel": "FFA000", + "Orange Roughy": "C45719", + "Orange White": "FEFCED", + "Orchid": "DA70D6", + "Orchid White": "FFFDF3", + "Oregon": "9B4703", + "Orient": "015E85", + "Oriental Pink": "C69191", + "Orinoco": "F3FBD4", + "Oslo Gray": "878D91", + "Ottoman": "E9F8ED", + "Outer Space": "2D383A", + "Outrageous Orange": "FF6037", + "Oxford Blue": "384555", + "Oxley": "779E86", + "Oyster Bay": "DAFAFF", + "Oyster Pink": "E9CECD", + "Paarl": "A65529", + "Pablo": "776F61", + "Pacific Blue": "009DC4", + "Pacifika": "778120", + "Paco": "411F10", + "Padua": "ADE6C4", + "Pale Canary": "FFFF99", + "Pale Leaf": "C0D3B9", + "Pale Oyster": "988D77", + "Pale Prim": "FDFEB8", + "Pale Rose": "FFE1F2", + "Pale Sky": "6E7783", + "Pale Slate": "C3BFC1", + "Palm Green": "09230F", + "Palm Leaf": "19330E", + "Pampas": "F4F2EE", + "Panache": "EAF6EE", + "Pancho": "EDCDAB", + "Papaya Whip": "FFEFD5", + "Paprika": "8D0226", + "Paradiso": "317D82", + "Parchment": "F1E9D2", + "Paris Daisy": "FFF46E", + "Paris M": "26056A", + "Paris White": "CADCD4", + "Parsley": "134F19", + "Pastel Green": "77DD77", + "Pastel Pink": "FFD1DC", + "Patina": "639A8F", + "Pattens Blue": "DEF5FF", + "Paua": "260368", + "Pavlova": "D7C498", + "Peach": "FFE5B4", + "Peach Cream": "FFF0DB", + "Peach Orange": "FFCC99", + "Peach Schnapps": "FFDCD6", + "Peach Yellow": "FADFAD", + "Peanut": "782F16", + "Pear": "D1E231", + "Pearl Bush": "E8E0D5", + "Pearl Lusta": "FCF4DC", + "Peat": "716B56", + "Pelorous": "3EABBF", + "Peppermint": "E3F5E1", + "Perano": "A9BEF2", + "Perfume": "D0BEF8", + "Periglacial Blue": "E1E6D6", + "Periwinkle": "CCCCFF", + "Periwinkle Gray": "C3CDE6", + "Persian Blue": "1C39BB", + "Persian Green": "00A693", + "Persian Indigo": "32127A", + "Persian Pink": "F77FBE", + "Persian Plum": "701C1C", + "Persian Red": "CC3333", + "Persian Rose": "FE28A2", + "Persimmon": "FF6B53", + "Peru Tan": "7F3A02", + "Pesto": "7C7631", + "Petite Orchid": "DB9690", + "Pewter": "96A8A1", + "Pharlap": "A3807B", + "Picasso": "FFF39D", + "Pickled Bean": "6E4826", + "Pickled Bluewood": "314459", + "Picton Blue": "45B1E8", + "Pig Pink": "FDD7E4", + "Pigeon Post": "AFBDD9", + "Pigment Indigo": "4B0082", + "Pine Cone": "6D5E54", + "Pine Glade": "C7CD90", + "Pine Green": "01796F", + "Pine Tree": "171F04", + "Pink": "FFC0CB", + "Pink Flamingo": "FF66FF", + "Pink Flare": "E1C0C8", + "Pink Lace": "FFDDF4", + "Pink Lady": "FFF1D8", + "Pink Salmon": "FF91A4", + "Pink Swan": "BEB5B7", + "Piper": "C96323", + "Pipi": "FEF4CC", + "Pippin": "FFE1DF", + "Pirate Gold": "BA7F03", + "Pistachio": "9DC209", + "Pixie Green": "C0D8B6", + "Pizazz": "FF9000", + "Pizza": "C99415", + "Plantation": "27504B", + "Plum": "843179", + "Pohutukawa": "8F021C", + "Polar": "E5F9F6", + "Polo Blue": "8DA8CC", + "Pomegranate": "F34723", + "Pompadour": "660045", + "Porcelain": "EFF2F3", + "Porsche": "EAAE69", + "Port Gore": "251F4F", + "Portafino": "FFFFB4", + "Portage": "8B9FEE", + "Portica": "F9E663", + "Pot Pourri": "F5E7E2", + "Potters Clay": "8C5738", + "Powder Ash": "BCC9C2", + "Powder Blue": "B0E0E6", + "Prairie Sand": "9A3820", + "Prelude": "D0C0E5", + "Prim": "F0E2EC", + "Primrose": "EDEA99", + "Provincial Pink": "FEF5F1", + "Prussian Blue": "003153", + "Puce": "CC8899", + "Pueblo": "7D2C14", + "Puerto Rico": "3FC1AA", + "Pumice": "C2CAC4", + "Pumpkin": "FF7518", + "Pumpkin Skin": "B1610B", + "Punch": "DC4333", + "Punga": "4D3D14", + "Purple": "660099", + "Purple Heart": "652DC1", + "Purple Mountain's Majesty": "9678B6", + "Purple Pizzazz": "FF00CC", + "Putty": "E7CD8C", + "Quarter Pearl Lusta": "FFFDF4", + "Quarter Spanish White": "F7F2E1", + "Quicksand": "BD978E", + "Quill Gray": "D6D6D1", + "Quincy": "623F2D", + "Racing Green": "0C1911", + "Radical Red": "FF355E", + "Raffia": "EADAB8", + "Rainee": "B9C8AC", + "Rajah": "F7B668", + "Rangitoto": "2E3222", + "Rangoon Green": "1C1E13", + "Raven": "727B89", + "Raw Sienna": "D27D46", + "Raw Umber": "734A12", + "Razzle Dazzle Rose": "FF33CC", + "Razzmatazz": "E30B5C", + "Rebel": "3C1206", + "Red": "FF0000", + "Red Beech": "7B3801", + "Red Berry": "8E0000", + "Red Damask": "DA6A41", + "Red Devil": "860111", + "Red Orange": "FF3F34", + "Red Oxide": "6E0902", + "Red Ribbon": "ED0A3F", + "Red Robin": "80341F", + "Red Stage": "D05F04", + "Red Violet": "C71585", + "Redwood": "5D1E0F", + "Reef": "C9FFA2", + "Reef Gold": "9F821C", + "Regal Blue": "013F6A", + "Regent Gray": "86949F", + "Regent St Blue": "AAD6E6", + "Remy": "FEEBF3", + "Reno Sand": "A86515", + "Resolution Blue": "002387", + "Revolver": "2C1632", + "Rhino": "2E3F62", + "Rice Cake": "FFFEF0", + "Rice Flower": "EEFFE2", + "Rich Gold": "A85307", + "Rio Grande": "BBD009", + "Ripe Lemon": "F4D81C", + "Ripe Plum": "410056", + "Riptide": "8BE6D8", + "River Bed": "434C59", + "Rob Roy": "EAC674", + "Robin's Egg Blue": "00CCCC", + "Rock": "4D3833", + "Rock Blue": "9EB1CD", + "Rock Spray": "BA450C", + "Rodeo Dust": "C9B29B", + "Rolling Stone": "747D83", + "Roman": "DE6360", + "Roman Coffee": "795D4C", + "Romance": "FFFEFD", + "Romantic": "FFD2B7", + "Ronchi": "ECC54E", + "Roof Terracotta": "A62F20", + "Rope": "8E4D1E", + "Rose": "FF007F", + "Rose Bud": "FBB2A3", + "Rose Bud Cherry": "800B47", + "Rose Fog": "E7BCB4", + "Rose White": "FFF6F5", + "Rose of Sharon": "BF5500", + "Rosewood": "65000B", + "Roti": "C6A84B", + "Rouge": "A23B6C", + "Royal Blue": "4169E1", + "Royal Heath": "AB3472", + "Royal Purple": "6B3FA0", + "Rum": "796989", + "Rum Swizzle": "F9F8E4", + "Russet": "80461B", + "Russett": "755A57", + "Rust": "B7410E", + "Rustic Red": "480404", + "Rusty Nail": "86560A", + "Saddle": "4C3024", + "Saddle Brown": "583401", + "Saffron": "F4C430", + "Saffron Mango": "F9BF58", + "Sage": "9EA587", + "Sahara": "B7A214", + "Sahara Sand": "F1E788", + "Sail": "B8E0F9", + "Salem": "097F4B", + "Salmon": "FF8C69", + "Salomie": "FEDB8D", + "Salt Box": "685E6E", + "Saltpan": "F1F7F2", + "Sambuca": "3A2010", + "San Felix": "0B6207", + "San Juan": "304B6A", + "San Marino": "456CAC", + "Sand Dune": "826F65", + "Sandal": "AA8D6F", + "Sandrift": "AB917A", + "Sandstone": "796D62", + "Sandwisp": "F5E7A2", + "Sandy Beach": "FFEAC8", + "Sandy brown": "F4A460", + "Sangria": "92000A", + "Sanguine Brown": "8D3D38", + "Santa Fe": "B16D52", + "Santas Gray": "9FA0B1", + "Sapling": "DED4A4", + "Sapphire": "2F519E", + "Saratoga": "555B10", + "Satin Linen": "E6E4D4", + "Sauvignon": "FFF5F3", + "Sazerac": "FFF4E0", + "Scampi": "675FA6", + "Scandal": "CFFAF4", + "Scarlet": "FF2400", + "Scarlet Gum": "431560", + "Scarlett": "950015", + "Scarpa Flow": "585562", + "Schist": "A9B497", + "School bus Yellow": "FFD800", + "Schooner": "8B847E", + "Science Blue": "0066CC", + "Scooter": "2EBFD4", + "Scorpion": "695F62", + "Scotch Mist": "FFFBDC", + "Screamin' Green": "66FF66", + "Sea Buckthorn": "FBA129", + "Sea Green": "2E8B57", + "Sea Mist": "C5DBCA", + "Sea Nymph": "78A39C", + "Sea Pink": "ED989E", + "Seagull": "80CCEA", + "Seance": "731E8F", + "Seashell": "F1F1F1", + "Seashell Peach": "FFF5EE", + "Seaweed": "1B2F11", + "Selago": "F0EEFD", + "Selective Yellow": "FFBA00", + "Sepia": "704214", + "Sepia Black": "2B0202", + "Sepia Skin": "9E5B40", + "Serenade": "FFF4E8", + "Shadow": "837050", + "Shadow Green": "9AC2B8", + "Shady Lady": "AAA5A9", + "Shakespeare": "4EABD1", + "Shalimar": "FBFFBA", + "Shamrock": "33CC99", + "Shark": "25272C", + "Sherpa Blue": "004950", + "Sherwood Green": "02402C", + "Shilo": "E8B9B3", + "Shingle Fawn": "6B4E31", + "Ship Cove": "788BBA", + "Ship Gray": "3E3A44", + "Shiraz": "B20931", + "Shocking": "E292C0", + "Shocking Pink": "FC0FC0", + "Shuttle Gray": "5F6672", + "Siam": "646A54", + "Sidecar": "F3E7BB", + "Silk": "BDB1A8", + "Silver": "C0C0C0", + "Silver Chalice": "ACACAC", + "Silver Rust": "C9C0BB", + "Silver Sand": "BFC1C2", + "Silver Tree": "66B58F", + "Sinbad": "9FD7D3", + "Siren": "7A013A", + "Sirocco": "718080", + "Sisal": "D3CBBA", + "Skeptic": "CAE6DA", + "Sky Blue": "76D7EA", + "Slate Gray": "708090", + "Smalt": "003399", + "Smalt Blue": "51808F", + "Smoky": "605B73", + "Snow Drift": "F7FAF7", + "Snow Flurry": "E4FFD1", + "Snowy Mint": "D6FFDB", + "Snuff": "E2D8ED", + "Soapstone": "FFFBF9", + "Soft Amber": "D1C6B4", + "Soft Peach": "F5EDEF", + "Solid Pink": "893843", + "Solitaire": "FEF8E2", + "Solitude": "EAF6FF", + "Sorbus": "FD7C07", + "Sorrell Brown": "CEB98F", + "Soya Bean": "6A6051", + "Spanish Green": "819885", + "Spectra": "2F5A57", + "Spice": "6A442E", + "Spicy Mix": "885342", + "Spicy Mustard": "74640D", + "Spicy Pink": "816E71", + "Spindle": "B6D1EA", + "Spray": "79DEEC", + "Spring Green": "00FF7F", + "Spring Leaves": "578363", + "Spring Rain": "ACCBB1", + "Spring Sun": "F6FFDC", + "Spring Wood": "F8F6F1", + "Sprout": "C1D7B0", + "Spun Pearl": "AAABB7", + "Squirrel": "8F8176", + "St Tropaz": "2D569B", + "Stack": "8A8F8A", + "Star Dust": "9F9F9C", + "Stark White": "E5D7BD", + "Starship": "ECF245", + "Steel Blue": "4682B4", + "Steel Gray": "262335", + "Stiletto": "9C3336", + "Stonewall": "928573", + "Storm Dust": "646463", + "Storm Gray": "717486", + "Stratos": "000741", + "Straw": "D4BF8D", + "Strikemaster": "956387", + "Stromboli": "325D52", + "Studio": "714AB2", + "Submarine": "BAC7C9", + "Sugar Cane": "F9FFF6", + "Sulu": "C1F07C", + "Summer Green": "96BBAB", + "Sun": "FBAC13", + "Sundance": "C9B35B", + "Sundown": "FFB1B3", + "Sunflower": "E4D422", + "Sunglo": "E16865", + "Sunglow": "FFCC33", + "Sunset Orange": "FE4C40", + "Sunshade": "FF9E2C", + "Supernova": "FFC901", + "Surf": "BBD7C1", + "Surf Crest": "CFE5D2", + "Surfie Green": "0C7A79", + "Sushi": "87AB39", + "Suva Gray": "888387", + "Swamp": "001B1C", + "Swamp Green": "ACB78E", + "Swans Down": "DCF0EA", + "Sweet Corn": "FBEA8C", + "Sweet Pink": "FD9FA2", + "Swirl": "D3CDC5", + "Swiss Coffee": "DDD6D5", + "Sycamore": "908D39", + "Tabasco": "A02712", + "Tacao": "EDB381", + "Tacha": "D6C562", + "Tahiti Gold": "E97C07", + "Tahuna Sands": "EEF0C8", + "Tall Poppy": "B32D29", + "Tallow": "A8A589", + "Tamarillo": "991613", + "Tamarind": "341515", + "Tan": "D2B48C", + "Tan Hide": "FA9D5A", + "Tana": "D9DCC1", + "Tangaroa": "03163C", + "Tangerine": "F28500", + "Tango": "ED7A1C", + "Tapa": "7B7874", + "Tapestry": "B05E81", + "Tara": "E1F6E8", + "Tarawera": "073A50", + "Tasman": "CFDCCF", + "Taupe": "483C32", + "Taupe Gray": "B3AF95", + "Tawny Port": "692545", + "Te Papa Green": "1E433C", + "Tea": "C1BAB0", + "Tea Green": "D0F0C0", + "Teak": "B19461", + "Teal": "008080", + "Teal Blue": "044259", + "Temptress": "3B000B", + "Tenn": "CD5700", + "Tequila": "FFE6C7", + "Terracotta": "E2725B", + "Texas": "F8F99C", + "Texas Rose": "FFB555", + "Thatch": "B69D98", + "Thatch Green": "403D19", + "Thistle": "D8BFD8", + "Thistle Green": "CCCAA8", + "Thunder": "33292F", + "Thunderbird": "C02B18", + "Tia Maria": "C1440E", + "Tiara": "C3D1D1", + "Tiber": "063537", + "Tickle Me Pink": "FC80A5", + "Tidal": "F1FFAD", + "Tide": "BFB8B0", + "Timber Green": "16322C", + "Timberwolf": "D9D6CF", + "Titan White": "F0EEFF", + "Toast": "9A6E61", + "Tobacco Brown": "715D47", + "Toledo": "3A0020", + "Tolopea": "1B0245", + "Tom Thumb": "3F583B", + "Tonys Pink": "E79F8C", + "Topaz": "7C778A", + "Torch Red": "FD0E35", + "Torea Bay": "0F2D9E", + "Tory Blue": "1450AA", + "Tosca": "8D3F3F", + "Totem Pole": "991B07", + "Tower Gray": "A9BDBF", + "Tradewind": "5FB3AC", + "Tranquil": "E6FFFF", + "Travertine": "FFFDE8", + "Tree Poppy": "FC9C1D", + "Treehouse": "3B2820", + "Trendy Green": "7C881A", + "Trendy Pink": "8C6495", + "Trinidad": "E64E03", + "Tropical Blue": "C3DDF9", + "Tropical Rain Forest": "00755E", + "Trout": "4A4E5A", + "True V": "8A73D6", + "Tuatara": "363534", + "Tuft Bush": "FFDDCD", + "Tulip Tree": "EAB33B", + "Tumbleweed": "DEA681", + "Tuna": "353542", + "Tundora": "4A4244", + "Turbo": "FAE600", + "Turkish Rose": "B57281", + "Turmeric": "CABB48", + "Turquoise": "30D5C8", + "Turquoise Blue": "6CDAE7", + "Turtle Green": "2A380B", + "Tuscany": "BD5E2E", + "Tusk": "EEF3C3", + "Tussock": "C5994B", + "Tutu": "FFF1F9", + "Twilight": "E4CFDE", + "Twilight Blue": "EEFDFF", + "Twine": "C2955D", + "Tyrian Purple": "66023C", + "Ultramarine": "120A8F", + "Valencia": "D84437", + "Valentino": "350E42", + "Valhalla": "2B194F", + "Van Cleef": "49170C", + "Vanilla": "D1BEA8", + "Vanilla Ice": "F3D9DF", + "Varden": "FFF6DF", + "Venetian Red": "72010F", + "Venice Blue": "055989", + "Venus": "928590", + "Verdigris": "5D5E37", + "Verdun Green": "495400", + "Vermilion": "FF4D00", + "Vesuvius": "B14A0B", + "Victoria": "534491", + "Vida Loca": "549019", + "Viking": "64CCDB", + "Vin Rouge": "983D61", + "Viola": "CB8FA9", + "Violent Violet": "290C5E", + "Violet": "240A40", + "Violet Eggplant": "991199", + "Violet Red": "F7468A", + "Viridian": "40826D", + "Viridian Green": "678975", + "Vis Vis": "FFEFA1", + "Vista Blue": "8FD6B4", + "Vista White": "FCF8F7", + "Vivid Tangerine": "FF9980", + "Vivid Violet": "803790", + "Voodoo": "533455", + "Vulcan": "10121D", + "Wafer": "DECBC6", + "Waikawa Gray": "5A6E9C", + "Waiouru": "363C0D", + "Walnut": "773F1A", + "Wasabi": "788A25", + "Water Leaf": "A1E9DE", + "Watercourse": "056F57", + "Waterloo ": "7B7C94", + "Wattle": "DCD747", + "Watusi": "FFDDCF", + "Wax Flower": "FFC0A8", + "We Peep": "F7DBE6", + "Web Orange": "FFA500", + "Wedgewood": "4E7F9E", + "Well Read": "B43332", + "West Coast": "625119", + "West Side": "FF910F", + "Westar": "DCD9D2", + "Wewak": "F19BAB", + "Wheat": "F5DEB3", + "Wheatfield": "F3EDCF", + "Whiskey": "D59A6F", + "Whisper": "F7F5FA", + "White": "FFFFFF", + "White Ice": "DDF9F1", + "White Lilac": "F8F7FC", + "White Linen": "F8F0E8", + "White Pointer": "FEF8FF", + "White Rock": "EAE8D4", + "Wild Blue Yonder": "7A89B8", + "Wild Rice": "ECE090", + "Wild Sand": "F4F4F4", + "Wild Strawberry": "FF3399", + "Wild Watermelon": "FD5B78", + "Wild Willow": "B9C46A", + "William": "3A686C", + "Willow Brook": "DFECDA", + "Willow Grove": "65745D", + "Windsor": "3C0878", + "Wine Berry": "591D35", + "Winter Hazel": "D5D195", + "Wisp Pink": "FEF4F8", + "Wisteria": "9771B5", + "Wistful": "A4A6D3", + "Witch Haze": "FFFC99", + "Wood Bark": "261105", + "Woodland": "4D5328", + "Woodrush": "302A0F", + "Woodsmoke": "0C0D0F", + "Woody Brown": "483131", + "Xanadu": "738678", + "Yellow": "FFFF00", + "Yellow Green": "C5E17A", + "Yellow Metal": "716338", + "Yellow Orange": "FFAE42", + "Yellow Sea": "FEA904", + "Your Pink": "FFC3C0", + "Yukon Gold": "7B6608", + "Yuma": "CEC291", + "Zambezi": "685558", + "Zanah": "DAECD6", + "Zest": "E5841B", + "Zeus": "292319", + "Ziggurat": "BFDBE2", + "Zinnwaldite": "EBC2AF", + "Zircon": "F4F8FF", + "Zombie": "E4D69B", + "Zorba": "A59B91", + "Zuccini": "044022", + "Zumthor": "EDF6FF" +} -- cgit v1.2.3 From 172fd3389481cc690d2eedaf1f70c56efb018bcf Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 11 Sep 2021 09:57:13 -0400 Subject: Add fuzzy match function I made a few changes, the biggest being the fuzzy match function to return a hex color code based on an input color name. Open items that I can think of so far: -Since the json file has color names and hex values, in order to use fuzzy matching for a color name the color must first be converted to hex. Currently there is only a rgb to anything function which returns values in a dictionary. -The main embed creation references the rgb_color before it is defined, should the command function be moved to the bottom of the file or just the main embed creation and sending? -When using the rgb mode, should the user be forced to do (r, g, b) or should the command handle an input of "r, g, b"? If you are reading this, thank you. --- bot/exts/utilities/color.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6abfc006..9e199dd4 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,4 +1,5 @@ import colorsys +import json import logging import re from io import BytesIO @@ -6,7 +7,7 @@ from io import BytesIO from PIL import Image, ImageColor from discord import Embed, File from discord.ext import commands -# from rapidfuzz import process +from rapidfuzz import process from bot.bot import Bot from bot.constants import Colours @@ -23,6 +24,8 @@ ERROR_MSG = """The color code {user_color} is not a possible color combination. \nHex: #000000-#FFFFFF """ +COLOR_LIST = "bot/resources/utilities/ryanzec_colours.json" + # define color command class Color(commands.Cog): @@ -46,7 +49,7 @@ class Color(commands.Cog): else: await ctx.send( embed=Embed( - title="An error has occured.", + title="There was an issue converting the hex color code.", description=ERROR_MSG.format(user_color=user_color), ) ) @@ -58,9 +61,10 @@ class Color(commands.Cog): pass elif mode.lower() == "cmyk": pass + elif mode.lower() == "name": + color_name, hex_color = self.match_color(user_color) else: # mode is either None or an invalid code - # need to handle whether user passes color name if mode is None: no_mode_embed = Embed( title="No 'mode' was passed, please define a color code.", @@ -70,7 +74,7 @@ class Color(commands.Cog): return wrong_mode_embed = Embed( title=f"The color code {mode} is not a valid option", - description="Possible modes are: Hex, RGB, HSV, HSL and CMYK.", + description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", color=Colours.soft_red, ) await ctx.send(embed=wrong_mode_embed) @@ -78,15 +82,15 @@ class Color(commands.Cog): async with ctx.typing(): main_embed = Embed( - title=user_color, # need to replace with fuzzymatch color name + title=color_name, description='(Approx..)', - color=hex_color, + color=rgb_color, ) file = await self.create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") - fields = self.get_color_fields(rgb_color) + for field in fields: main_embed.add_field( name=field['name'], @@ -94,7 +98,7 @@ class Color(commands.Cog): inline=False, ) - await ctx.send(file=file, embed=main_embed) + await ctx.send(file=file, embed=main_embed) @staticmethod async def create_thumbnail_attachment(color: str) -> File: @@ -192,6 +196,17 @@ class Color(commands.Cog): # if user_color in color_lists: # # fuzzy match for color + @staticmethod + def match_color(user_color: str) -> str: + """Use fuzzy matching to return a hex color code based on the user's input.""" + with open(COLOR_LIST) as f: + color_list = json.load(f) + logger.debug(f"{type(color_list) = }") + match, certainty, _ = process.extractOne(query=user_color, choices=color_list.keys(), score_cutoff=50) + logger.debug(f"{match = }, {certainty = }") + hex_match = color_list[match] + logger.debug(f"{hex_match = }") + return match, hex_match def setup(bot: Bot) -> None: -- cgit v1.2.3 From e77a8319e7e681262c73bdbb1335a708de676e8a Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 11 Sep 2021 10:09:27 -0400 Subject: Remove placeholder comment --- bot/exts/utilities/color.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9e199dd4..6452d292 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -194,8 +194,6 @@ class Color(commands.Cog): return all_fields - # if user_color in color_lists: - # # fuzzy match for color @staticmethod def match_color(user_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" -- cgit v1.2.3 From 68c0de59f6f31fb1123c7ed3468c4faac202d9f6 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 12 Sep 2021 08:39:47 -0400 Subject: Load json file once --- bot/exts/utilities/color.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6452d292..dd470197 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -25,6 +25,8 @@ ERROR_MSG = """The color code {user_color} is not a possible color combination. """ COLOR_LIST = "bot/resources/utilities/ryanzec_colours.json" +with open(COLOR_LIST) as f: + COLOR_JSON = json.load(f) # define color command @@ -197,12 +199,9 @@ class Color(commands.Cog): @staticmethod def match_color(user_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" - with open(COLOR_LIST) as f: - color_list = json.load(f) - logger.debug(f"{type(color_list) = }") - match, certainty, _ = process.extractOne(query=user_color, choices=color_list.keys(), score_cutoff=50) + match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_JSON.keys(), score_cutoff=50) logger.debug(f"{match = }, {certainty = }") - hex_match = color_list[match] + hex_match = COLOR_JSON[match] logger.debug(f"{hex_match = }") return match, hex_match -- cgit v1.2.3 From 674221ead6d5376b22a1ea31bcec0cbadecd6104 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 15 Sep 2021 16:16:52 -0400 Subject: Fix Flake8 spacing errors --- bot/exts/utilities/color.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index dd470197..eb9d5f4d 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -155,19 +155,19 @@ class Color(commands.Cog): def _rgb_to_hsv(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: """To convert from `RGB` to `HSV` color space.""" r, g, b = rgb_color - h, v, s = colorsys.rgb_to_hsv(r/float(255), g/float(255), b/float(255)) - h = round(h*360) - s = round(s*100) - v = round(v*100) + h, v, s = colorsys.rgb_to_hsv(r / float(255), g / float(255), b / float(255)) + h = round(h * 360) + s = round(s * 100) + v = round(v * 100) return h, s, v def _rgb_to_hsl(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: """To convert from `RGB` to `HSL` color space.""" r, g, b = rgb_color - h, l, s = colorsys.rgb_to_hls(r/float(255), g/float(255), b/float(255)) - h = round(h*360) - s = round(s*100) - l = round(l*100) # noqa: E741 It's little `L`, Reason: To maintain consistency. + h, l, s = colorsys.rgb_to_hls(r / float(255), g / float(255), b / float(255)) + h = round(h * 360) + s = round(s * 100) + l = round(l * 100) # noqa: E741 It's little `L`, Reason: To maintain consistency. return h, s, l hex_color = _rgb_to_hex(rgb_color) -- cgit v1.2.3 From 029b8052b3d038be2808d5995d4f6422158b0084 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 19 Sep 2021 08:20:18 -0400 Subject: Reword json file variables and mapping --- bot/exts/utilities/color.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index eb9d5f4d..94c9d337 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -24,9 +24,9 @@ ERROR_MSG = """The color code {user_color} is not a possible color combination. \nHex: #000000-#FFFFFF """ -COLOR_LIST = "bot/resources/utilities/ryanzec_colours.json" -with open(COLOR_LIST) as f: - COLOR_JSON = json.load(f) +COLOR_JSON_PATH = "bot/resources/utilities/ryanzec_colours.json" +with open(COLOR_JSON_PATH) as f: + COLOR_MAPPING = json.load(f) # define color command @@ -199,9 +199,9 @@ class Color(commands.Cog): @staticmethod def match_color(user_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" - match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_JSON.keys(), score_cutoff=50) + match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_MAPPING.keys(), score_cutoff=50) logger.debug(f"{match = }, {certainty = }") - hex_match = COLOR_JSON[match] + hex_match = COLOR_MAPPING[match] logger.debug(f"{hex_match = }") return match, hex_match -- cgit v1.2.3 From 40e04bf4d304f8b2f231fedcb38db1f532550f0c Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 19 Sep 2021 10:20:58 -0400 Subject: Continue work on hex and rgb color commands --- bot/exts/utilities/color.py | 87 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 94c9d337..2bec6ba3 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -31,23 +31,45 @@ with open(COLOR_JSON_PATH) as f: # define color command class Color(commands.Cog): - """User initiated command to receive color information.""" + """User initiated commands to receive color information.""" def __init__(self, bot: Bot): self.bot = bot @commands.command(aliases=["colour"]) async def color(self, ctx: commands.Context, mode: str, *, user_color: str) -> None: - """Send information on input color code or color name.""" - logger.info(f"{mode = }") - logger.info(f"{user_color = }") + """ + Send information on input color code or color name. + + Possible modes are: "hex", "rgb", "hsv", "hsl", "cmyk" or "name". + """ + logger.debug(f"{mode = }") + logger.debug(f"{user_color = }") if mode.lower() == "hex": - hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) + hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", user_color) if hex_match: hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) - rgb_color = ImageColor.getcolor(user_color, "RGB") - logger.info(f"{hex_color = }") - logger.info(f"{rgb_color = }") + if "#" in user_color: + rgb_color = ImageColor.getcolor(user_color, "RGB") + elif "0x" in user_color: + hex_ = user_color.replace("0x", "#") + rgb_color = ImageColor.getcolor(hex_, "RGB") + else: + hex_ = "#" + user_color + rgb_color = ImageColor.getcolor(hex_, "RGB") + (r, g, b) = rgb_color + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") + hsv_color = all_colors[3]["value"].replace("» hsv ", "") + hsl_color = all_colors[4]["value"].replace("» hsl ", "") + logger.debug(f"{rgb_color = }") + logger.debug(f"{hex_color = }") + logger.debug(f"{hsv_color = }") + logger.debug(f"{hsl_color = }") + logger.debug(f"{cmyk_color = }") + color_name, _ = self.match_color(hex_color) else: await ctx.send( embed=Embed( @@ -56,7 +78,22 @@ class Color(commands.Cog): ) ) elif mode.lower() == "rgb": - pass + if "(" in user_color: + remove = "[() ]" + rgb_color = re.sub(remove, "", user_color) + rgb_color = tuple(map(int, rgb_color.split(","))) + elif "," in user_color: + rgb_color = tuple(map(int, user_color.split(","))) + else: + rgb_color = tuple(map(int, user_color.split(" "))) + (r, g, b) = rgb_color + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") + hsv_color = all_colors[3]["value"].replace("» hsv ", "") + hsl_color = all_colors[4]["value"].replace("» hsl ", "") + color_name, _ = self.match_color(hex_color) elif mode.lower() == "hsv": pass elif mode.lower() == "hsl": @@ -70,6 +107,7 @@ class Color(commands.Cog): if mode is None: no_mode_embed = Embed( title="No 'mode' was passed, please define a color code.", + description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", color=Colours.soft_red, ) await ctx.send(embed=no_mode_embed) @@ -86,7 +124,7 @@ class Color(commands.Cog): main_embed = Embed( title=color_name, description='(Approx..)', - color=rgb_color, + color=discord_rgb_int, ) file = await self.create_thumbnail_attachment(rgb_color) @@ -120,7 +158,7 @@ class Color(commands.Cog): def _rgb_to_hex(rgb_color: tuple[int, int, int]) -> str: """To convert from `RGB` to `Hex` notation.""" - return '#' + ''.join(hex(color)[2:].zfill(2) for color in rgb_color).upper() + return '#' + ''.join(hex(int(color))[2:].zfill(2) for color in rgb_color).upper() def _rgb_to_cmyk(rgb_color: tuple[int, int, int]) -> tuple[int, int, int, int]: """To convert from `RGB` to `CMYK` color space.""" @@ -178,7 +216,11 @@ class Color(commands.Cog): all_fields = [ { "name": "RGB", - "value": f"» rgb {rgb_color}\n» hex {hex_color}" + "value": f"» rgb {rgb_color}" + }, + { + "name": "HEX", + "value": f"» hex {hex_color}" }, { "name": "CMYK", @@ -197,13 +239,22 @@ class Color(commands.Cog): return all_fields @staticmethod - def match_color(user_color: str) -> str: + def match_color(input_hex_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" - match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_MAPPING.keys(), score_cutoff=50) - logger.debug(f"{match = }, {certainty = }") - hex_match = COLOR_MAPPING[match] - logger.debug(f"{hex_match = }") - return match, hex_match + try: + match, certainty, _ = process.extractOne( + query=input_hex_color, + choices=COLOR_MAPPING.keys(), + score_cutoff=50 + ) + logger.debug(f"{match = }, {certainty = }") + hex_match = COLOR_MAPPING[match] + logger.debug(f"{hex_match = }") + return match, hex_match + except TypeError: + match = "No color name match found." + hex_match = input_hex_color + return match, hex_match def setup(bot: Bot) -> None: -- cgit v1.2.3 From d55b59e5590e701094915bb1aff36d0cd38d061b Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 19 Sep 2021 17:49:32 -0400 Subject: Add all color modes and name matching --- bot/exts/utilities/color.py | 140 ++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 36 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 2bec6ba3..9b1f3776 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -45,6 +45,7 @@ class Color(commands.Cog): """ logger.debug(f"{mode = }") logger.debug(f"{user_color = }") + color_name = None if mode.lower() == "hex": hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", user_color) if hex_match: @@ -57,19 +58,6 @@ class Color(commands.Cog): else: hex_ = "#" + user_color rgb_color = ImageColor.getcolor(hex_, "RGB") - (r, g, b) = rgb_color - discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) - all_colors = self.get_color_fields(rgb_color) - hex_color = all_colors[1]["value"].replace("» hex ", "") - cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") - hsv_color = all_colors[3]["value"].replace("» hsv ", "") - hsl_color = all_colors[4]["value"].replace("» hsl ", "") - logger.debug(f"{rgb_color = }") - logger.debug(f"{hex_color = }") - logger.debug(f"{hsv_color = }") - logger.debug(f"{hsl_color = }") - logger.debug(f"{cmyk_color = }") - color_name, _ = self.match_color(hex_color) else: await ctx.send( embed=Embed( @@ -78,30 +66,22 @@ class Color(commands.Cog): ) ) elif mode.lower() == "rgb": - if "(" in user_color: - remove = "[() ]" - rgb_color = re.sub(remove, "", user_color) - rgb_color = tuple(map(int, rgb_color.split(","))) - elif "," in user_color: - rgb_color = tuple(map(int, user_color.split(","))) - else: - rgb_color = tuple(map(int, user_color.split(" "))) - (r, g, b) = rgb_color - discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) - all_colors = self.get_color_fields(rgb_color) - hex_color = all_colors[1]["value"].replace("» hex ", "") - cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") - hsv_color = all_colors[3]["value"].replace("» hsv ", "") - hsl_color = all_colors[4]["value"].replace("» hsl ", "") - color_name, _ = self.match_color(hex_color) + rgb_color = self.tuple_create(user_color) elif mode.lower() == "hsv": - pass + hsv_temp = self.tuple_create(user_color) + rgb_color = self.hsv_to_rgb(hsv_temp) elif mode.lower() == "hsl": - pass + hsl_temp = self.tuple_create(user_color) + rgb_color = self.hsl_to_rgb(hsl_temp) elif mode.lower() == "cmyk": - pass + cmyk_temp = self.tuple_create(user_color) + rgb_color = self.cmyk_to_rgb(cmyk_temp) elif mode.lower() == "name": - color_name, hex_color = self.match_color(user_color) + color_name, hex_color = self.match_color_name(user_color) + if "#" in hex_color: + rgb_color = ImageColor.getcolor(hex_color, "RGB") + else: + rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") else: # mode is either None or an invalid code if mode is None: @@ -120,6 +100,14 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return + (r, g, b) = rgb_color + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + if color_name is None: + logger.debug(f"Find color name from hex color: {hex_color}") + color_name = self.match_color_hex(hex_color) + async with ctx.typing(): main_embed = Embed( title=color_name, @@ -239,11 +227,11 @@ class Color(commands.Cog): return all_fields @staticmethod - def match_color(input_hex_color: str) -> str: + def match_color_name(input_color_name: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" try: match, certainty, _ = process.extractOne( - query=input_hex_color, + query=input_color_name, choices=COLOR_MAPPING.keys(), score_cutoff=50 ) @@ -253,9 +241,89 @@ class Color(commands.Cog): return match, hex_match except TypeError: match = "No color name match found." - hex_match = input_hex_color + hex_match = input_color_name return match, hex_match + @staticmethod + def match_color_hex(input_hex_color: str) -> str: + """Use fuzzy matching to return a hex color code based on the user's input.""" + try: + match, certainty, _ = process.extractOne( + query=input_hex_color, + choices=COLOR_MAPPING.values(), + score_cutoff=80 + ) + logger.debug(f"{match = }, {certainty = }") + color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] + logger.debug(f"{color_name = }") + return color_name + except TypeError: + color_name = "No color name match found." + return color_name + + @staticmethod + def tuple_create(input_color: str) -> tuple[int, int, int]: + """ + Create a tuple of integers based on user's input. + + Can handle inputs of the types: + (100, 100, 100) + 100, 100, 100 + 100 100 100 + """ + if "(" in input_color: + remove = "[() ]" + color_tuple = re.sub(remove, "", input_color) + color_tuple = tuple(map(int, color_tuple.split(","))) + elif "," in input_color: + color_tuple = tuple(map(int, input_color.split(","))) + else: + color_tuple = tuple(map(int, input_color.split(" "))) + return color_tuple + + @staticmethod + def hsv_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsv color to rgb color.""" + (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped + h = h / 360 + s = s / 100 + v = v / 100 + rgb_color = colorsys.hsv_to_rgb(h, s, v) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + rgb_color = (r, g, b) + return rgb_color + + @staticmethod + def hsl_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsl color to rgb color.""" + (h, s, l) = input_color + h = h / 360 + s = s / 100 + l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. + rgb_color = colorsys.hls_to_rgb(h, l, s) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + rgb_color = (r, g, b) + return rgb_color + + @staticmethod + def cmyk_to_rgb(input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + """Function to convert cmyk color to rgb color.""" + c = input_color[0] + m = input_color[1] + y = input_color[2] + k = input_color[3] + r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) + g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) + b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) + rgb_color = (r, g, b) + return rgb_color + def setup(bot: Bot) -> None: """Load the Color Cog.""" -- cgit v1.2.3 From 54880a121a0117639d935384905d2f1f0c6f606d Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 21 Sep 2021 06:51:55 -0400 Subject: fix: remove redundant rgb_color variable The conversion functions from hsv, hsl and cmyk now return r, g, b instead of a variable rgb_tuple. --- bot/exts/utilities/color.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9b1f3776..542a2e19 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -293,8 +293,7 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - rgb_color = (r, g, b) - return rgb_color + return r, g, b @staticmethod def hsl_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: @@ -308,8 +307,7 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - rgb_color = (r, g, b) - return rgb_color + return r, g, b @staticmethod def cmyk_to_rgb(input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: @@ -321,8 +319,7 @@ class Color(commands.Cog): r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - rgb_color = (r, g, b) - return rgb_color + return r, g, b def setup(bot: Bot) -> None: -- cgit v1.2.3 From 835e4469938ab2b490dcf752d2fcecf117bd0a62 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:24:23 -0400 Subject: fix: create subcommands and restructure script -Makes "main" function `color_embed` that takes an rgb tuple, calls `all_colors` to get all other color types, gets a name from the hex color, creates embed, calls `create_thumbnail` to get image, and then sends main embed. -Makes functions `xxx_to_rgb` functions to call `color_embed` -Creates new `hex_to_rgb` function -TODO: test all functions and continue restructure. --- bot/exts/utilities/color.py | 81 +++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 542a2e19..5d37cbee 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -47,35 +47,16 @@ class Color(commands.Cog): logger.debug(f"{user_color = }") color_name = None if mode.lower() == "hex": - hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", user_color) - if hex_match: - hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) - if "#" in user_color: - rgb_color = ImageColor.getcolor(user_color, "RGB") - elif "0x" in user_color: - hex_ = user_color.replace("0x", "#") - rgb_color = ImageColor.getcolor(hex_, "RGB") - else: - hex_ = "#" + user_color - rgb_color = ImageColor.getcolor(hex_, "RGB") - else: - await ctx.send( - embed=Embed( - title="There was an issue converting the hex color code.", - description=ERROR_MSG.format(user_color=user_color), - ) - ) + self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": rgb_color = self.tuple_create(user_color) + self.embed_color(rgb_color) elif mode.lower() == "hsv": - hsv_temp = self.tuple_create(user_color) - rgb_color = self.hsv_to_rgb(hsv_temp) + self.hsv_to_rgb(user_color) elif mode.lower() == "hsl": - hsl_temp = self.tuple_create(user_color) - rgb_color = self.hsl_to_rgb(hsl_temp) + self.hsl_to_rgb(user_color) elif mode.lower() == "cmyk": - cmyk_temp = self.tuple_create(user_color) - rgb_color = self.cmyk_to_rgb(cmyk_temp) + self.cmyk_to_rgb(user_color) elif mode.lower() == "name": color_name, hex_color = self.match_color_name(user_color) if "#" in hex_color: @@ -100,6 +81,13 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return + async def color_embed( + self, + ctx: commands.Context, + rgb_color: tuple[int, int, int], + color_name: str = None + ) -> None: + """Take a RGB color tuple, create embed, and send.""" (r, g, b) = rgb_color discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) all_colors = self.get_color_fields(rgb_color) @@ -281,9 +269,9 @@ class Color(commands.Cog): color_tuple = tuple(map(int, input_color.split(" "))) return color_tuple - @staticmethod - def hsv_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsv color to rgb color.""" + def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsv color to rgb color and send main embed..""" + input_color = self.tuple_create(input_color) (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped h = h / 360 s = s / 100 @@ -293,11 +281,11 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - return r, g, b + self.color_embed((r, g, b)) - @staticmethod - def hsl_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsl color to rgb color.""" + def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsl color to rgb color and send main embed..""" + input_color = self.tuple_create(input_color) (h, s, l) = input_color h = h / 360 s = s / 100 @@ -307,11 +295,11 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - return r, g, b + self.color_embed((r, g, b)) - @staticmethod - def cmyk_to_rgb(input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: - """Function to convert cmyk color to rgb color.""" + def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + """Function to convert cmyk color to rgb color and send main embed..""" + input_color = self.tuple_create(input_color) c = input_color[0] m = input_color[1] y = input_color[2] @@ -319,7 +307,28 @@ class Color(commands.Cog): r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - return r, g, b + self.color_embed((r, g, b)) + + async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: + """Create rgb color from hex string and send main embed.""" + hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) + if hex_match: + if "#" in hex_string: + rgb_color = ImageColor.getcolor(hex_string, "RGB") + elif "0x" in hex_string: + hex_ = hex_string.replace("0x", "#") + rgb_color = ImageColor.getcolor(hex_, "RGB") + else: + hex_ = "#" + hex_string + rgb_color = ImageColor.getcolor(hex_, "RGB") + self.color_embed(rgb_color) + else: + await ctx.send( + embed=Embed( + title="There was an issue converting the hex color code.", + description=ERROR_MSG.format(user_color=hex_string), + ) + ) def setup(bot: Bot) -> None: -- cgit v1.2.3 From 7694caccf42ac05c373b2f8fcc180205d43d7883 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:38:34 -0400 Subject: fix: restructure script --- bot/exts/utilities/color.py | 225 ++++++++++++++++++++++---------------------- 1 file changed, 115 insertions(+), 110 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 5d37cbee..67068809 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -50,19 +50,20 @@ class Color(commands.Cog): self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": rgb_color = self.tuple_create(user_color) - self.embed_color(rgb_color) + self.color_embed(ctx, rgb_color) elif mode.lower() == "hsv": - self.hsv_to_rgb(user_color) + self.hsv_to_rgb(ctx, user_color) elif mode.lower() == "hsl": - self.hsl_to_rgb(user_color) + self.hsl_to_rgb(ctx, user_color) elif mode.lower() == "cmyk": - self.cmyk_to_rgb(user_color) + self.cmyk_to_rgb(ctx, user_color) elif mode.lower() == "name": color_name, hex_color = self.match_color_name(user_color) if "#" in hex_color: rgb_color = ImageColor.getcolor(hex_color, "RGB") else: rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") + self.color_embed(ctx, rgb_color, color_name) else: # mode is either None or an invalid code if mode is None: @@ -81,44 +82,94 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return - async def color_embed( - self, - ctx: commands.Context, - rgb_color: tuple[int, int, int], - color_name: str = None - ) -> None: - """Take a RGB color tuple, create embed, and send.""" - (r, g, b) = rgb_color - discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) - all_colors = self.get_color_fields(rgb_color) - hex_color = all_colors[1]["value"].replace("» hex ", "") - if color_name is None: - logger.debug(f"Find color name from hex color: {hex_color}") - color_name = self.match_color_hex(hex_color) + @staticmethod + def tuple_create(input_color: str) -> tuple[int, int, int]: + """ + Create a tuple of integers based on user's input. - async with ctx.typing(): - main_embed = Embed( - title=color_name, - description='(Approx..)', - color=discord_rgb_int, + Can handle inputs of the types: + (100, 100, 100) + 100, 100, 100 + 100 100 100 + """ + if "(" in input_color: + remove = "[() ]" + color_tuple = re.sub(remove, "", input_color) + color_tuple = tuple(map(int, color_tuple.split(","))) + elif "," in input_color: + color_tuple = tuple(map(int, input_color.split(","))) + else: + color_tuple = tuple(map(int, input_color.split(" "))) + return color_tuple + + async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: + """Function to convert hex color to rgb color and send main embed.""" + hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) + if hex_match: + if "#" in hex_string: + rgb_color = ImageColor.getcolor(hex_string, "RGB") + elif "0x" in hex_string: + hex_ = hex_string.replace("0x", "#") + rgb_color = ImageColor.getcolor(hex_, "RGB") + else: + hex_ = "#" + hex_string + rgb_color = ImageColor.getcolor(hex_, "RGB") + self.color_embed(rgb_color) + else: + await ctx.send( + embed=Embed( + title="There was an issue converting the hex color code.", + description=ERROR_MSG.format(user_color=hex_string), + ) ) - file = await self.create_thumbnail_attachment(rgb_color) - main_embed.set_thumbnail(url="attachment://color.png") - fields = self.get_color_fields(rgb_color) + def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsv color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped + h = h / 360 + s = s / 100 + v = v / 100 + rgb_color = colorsys.hsv_to_rgb(h, s, v) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + self.color_embed((r, g, b)) - for field in fields: - main_embed.add_field( - name=field['name'], - value=field['value'], - inline=False, - ) + def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsl color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + (h, s, l) = input_color + h = h / 360 + s = s / 100 + l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. + rgb_color = colorsys.hls_to_rgb(h, l, s) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + self.color_embed((r, g, b)) - await ctx.send(file=file, embed=main_embed) + def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + """Function to convert cmyk color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + c = input_color[0] + m = input_color[1] + y = input_color[2] + k = input_color[3] + r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) + g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) + b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) + self.color_embed((r, g, b)) @staticmethod - async def create_thumbnail_attachment(color: str) -> File: - """Generate a thumbnail from `color`.""" + async def create_thumbnail_attachment(color: tuple[int, int, int]) -> File: + """ + Generate a thumbnail from `color`. + + Assumes that color is an rgb tuple. + """ thumbnail = Image.new("RGB", (100, 100), color=color) bufferedio = BytesIO() thumbnail.save(bufferedio, format="PNG") @@ -249,86 +300,40 @@ class Color(commands.Cog): color_name = "No color name match found." return color_name - @staticmethod - def tuple_create(input_color: str) -> tuple[int, int, int]: - """ - Create a tuple of integers based on user's input. - - Can handle inputs of the types: - (100, 100, 100) - 100, 100, 100 - 100 100 100 - """ - if "(" in input_color: - remove = "[() ]" - color_tuple = re.sub(remove, "", input_color) - color_tuple = tuple(map(int, color_tuple.split(","))) - elif "," in input_color: - color_tuple = tuple(map(int, input_color.split(","))) - else: - color_tuple = tuple(map(int, input_color.split(" "))) - return color_tuple - - def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsv color to rgb color and send main embed..""" - input_color = self.tuple_create(input_color) - (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped - h = h / 360 - s = s / 100 - v = v / 100 - rgb_color = colorsys.hsv_to_rgb(h, s, v) + async def color_embed( + self, + ctx: commands.Context, + rgb_color: tuple[int, int, int], + color_name: str = None + ) -> None: + """Take a RGB color tuple, create embed, and send.""" (r, g, b) = rgb_color - r = int(r * 255) - g = int(g * 255) - b = int(b * 255) - self.color_embed((r, g, b)) + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + if color_name is None: + logger.debug(f"Find color name from hex color: {hex_color}") + color_name = self.match_color_hex(hex_color) - def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsl color to rgb color and send main embed..""" - input_color = self.tuple_create(input_color) - (h, s, l) = input_color - h = h / 360 - s = s / 100 - l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. - rgb_color = colorsys.hls_to_rgb(h, l, s) - (r, g, b) = rgb_color - r = int(r * 255) - g = int(g * 255) - b = int(b * 255) - self.color_embed((r, g, b)) + async with ctx.typing(): + main_embed = Embed( + title=color_name, + description='(Approx..)', + color=discord_rgb_int, + ) - def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: - """Function to convert cmyk color to rgb color and send main embed..""" - input_color = self.tuple_create(input_color) - c = input_color[0] - m = input_color[1] - y = input_color[2] - k = input_color[3] - r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) - g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) - b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - self.color_embed((r, g, b)) + file = await self.create_thumbnail_attachment(rgb_color) + main_embed.set_thumbnail(url="attachment://color.png") + fields = self.get_color_fields(rgb_color) - async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: - """Create rgb color from hex string and send main embed.""" - hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) - if hex_match: - if "#" in hex_string: - rgb_color = ImageColor.getcolor(hex_string, "RGB") - elif "0x" in hex_string: - hex_ = hex_string.replace("0x", "#") - rgb_color = ImageColor.getcolor(hex_, "RGB") - else: - hex_ = "#" + hex_string - rgb_color = ImageColor.getcolor(hex_, "RGB") - self.color_embed(rgb_color) - else: - await ctx.send( - embed=Embed( - title="There was an issue converting the hex color code.", - description=ERROR_MSG.format(user_color=hex_string), + for field in fields: + main_embed.add_field( + name=field['name'], + value=field['value'], + inline=False, ) - ) + + await ctx.send(file=file, embed=main_embed) def setup(bot: Bot) -> None: -- cgit v1.2.3 From d9250cf76c6e45df0b2b5c6b2bcab90de7b70520 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:39:37 -0400 Subject: fix: remove `get_color_fields` call in color_embed --- bot/exts/utilities/color.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 67068809..5cdc5083 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -324,9 +324,8 @@ class Color(commands.Cog): file = await self.create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") - fields = self.get_color_fields(rgb_color) - for field in fields: + for field in all_colors: main_embed.add_field( name=field['name'], value=field['value'], -- cgit v1.2.3 From 4cf2da8233ed8b10f0bc198fda52c76306ede9ac Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:50:42 -0400 Subject: chore: small code fixes and cleanup --- bot/exts/utilities/color.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 5cdc5083..e0398e02 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -29,7 +29,6 @@ with open(COLOR_JSON_PATH) as f: COLOR_MAPPING = json.load(f) -# define color command class Color(commands.Cog): """User initiated commands to receive color information.""" @@ -45,7 +44,6 @@ class Color(commands.Cog): """ logger.debug(f"{mode = }") logger.debug(f"{user_color = }") - color_name = None if mode.lower() == "hex": self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": @@ -235,11 +233,6 @@ class Color(commands.Cog): l = round(l * 100) # noqa: E741 It's little `L`, Reason: To maintain consistency. return h, s, l - hex_color = _rgb_to_hex(rgb_color) - cmyk_color = _rgb_to_cmyk(rgb_color) - hsv_color = _rgb_to_hsv(rgb_color) - hsl_color = _rgb_to_hsl(rgb_color) - all_fields = [ { "name": "RGB", @@ -247,19 +240,19 @@ class Color(commands.Cog): }, { "name": "HEX", - "value": f"» hex {hex_color}" + "value": f"» hex {_rgb_to_hex(rgb_color)}" }, { "name": "CMYK", - "value": f"» cmyk {cmyk_color}" + "value": f"» cmyk {_rgb_to_cmyk(rgb_color)}" }, { "name": "HSV", - "value": f"» hsv {hsv_color}" + "value": f"» hsv {_rgb_to_hsv(rgb_color)}" }, { "name": "HSL", - "value": f"» hsl {hsl_color}" + "value": f"» hsl {_rgb_to_hsl(rgb_color)}" }, ] @@ -277,11 +270,11 @@ class Color(commands.Cog): logger.debug(f"{match = }, {certainty = }") hex_match = COLOR_MAPPING[match] logger.debug(f"{hex_match = }") - return match, hex_match except TypeError: match = "No color name match found." hex_match = input_color_name - return match, hex_match + + return match, hex_match @staticmethod def match_color_hex(input_hex_color: str) -> str: @@ -295,10 +288,10 @@ class Color(commands.Cog): logger.debug(f"{match = }, {certainty = }") color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] logger.debug(f"{color_name = }") - return color_name except TypeError: color_name = "No color name match found." - return color_name + + return color_name async def color_embed( self, -- cgit v1.2.3 From 4f52cad537e19b3313b726d099ac223a3fa31c5c Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 23 Sep 2021 00:22:10 -0400 Subject: chore: create subcommands for sending embed --- bot/exts/utilities/color.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index e0398e02..6cc03c9a 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -45,23 +45,23 @@ class Color(commands.Cog): logger.debug(f"{mode = }") logger.debug(f"{user_color = }") if mode.lower() == "hex": - self.hex_to_rgb(ctx, user_color) + await self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": rgb_color = self.tuple_create(user_color) - self.color_embed(ctx, rgb_color) + await self.color_embed(ctx, rgb_color) elif mode.lower() == "hsv": - self.hsv_to_rgb(ctx, user_color) + await self.hsv_to_rgb(ctx, user_color) elif mode.lower() == "hsl": - self.hsl_to_rgb(ctx, user_color) + await self.hsl_to_rgb(ctx, user_color) elif mode.lower() == "cmyk": - self.cmyk_to_rgb(ctx, user_color) + await self.cmyk_to_rgb(ctx, user_color) elif mode.lower() == "name": color_name, hex_color = self.match_color_name(user_color) if "#" in hex_color: rgb_color = ImageColor.getcolor(hex_color, "RGB") else: rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") - self.color_embed(ctx, rgb_color, color_name) + await self.color_embed(ctx, rgb_color, color_name) else: # mode is either None or an invalid code if mode is None: @@ -112,7 +112,7 @@ class Color(commands.Cog): else: hex_ = "#" + hex_string rgb_color = ImageColor.getcolor(hex_, "RGB") - self.color_embed(rgb_color) + await self.color_embed(ctx, rgb_color) else: await ctx.send( embed=Embed( @@ -121,7 +121,7 @@ class Color(commands.Cog): ) ) - def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + async def hsv_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: """Function to convert hsv color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped @@ -133,9 +133,9 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - self.color_embed((r, g, b)) + await self.color_embed(ctx, (r, g, b)) - def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + async def hsl_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: """Function to convert hsl color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) (h, s, l) = input_color @@ -147,9 +147,9 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - self.color_embed((r, g, b)) + await self.color_embed(ctx, (r, g, b)) - def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + async def cmyk_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: """Function to convert cmyk color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) c = input_color[0] @@ -159,7 +159,7 @@ class Color(commands.Cog): r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - self.color_embed((r, g, b)) + await self.color_embed(ctx, (r, g, b)) @staticmethod async def create_thumbnail_attachment(color: tuple[int, int, int]) -> File: -- cgit v1.2.3 From 78cdc0f3e29ecc2571d40a2acb53b98e1b0f0e78 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 23 Sep 2021 07:48:45 -0400 Subject: chore: make cmyk_to_rgb def multiline --- bot/exts/utilities/color.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6cc03c9a..9e2af325 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -149,7 +149,11 @@ class Color(commands.Cog): b = int(b * 255) await self.color_embed(ctx, (r, g, b)) - async def cmyk_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + async def cmyk_to_rgb( + self, + ctx: commands.Context, + input_color: tuple[int, int, int, int] + ) -> tuple[int, int, int]: """Function to convert cmyk color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) c = input_color[0] -- cgit v1.2.3 From bae934537185c50089d854a22f76596bd4403a39 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 23 Sep 2021 21:42:24 -0400 Subject: chore: set thumbnail image to 80x80 --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6cc03c9a..1652ee19 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -168,7 +168,7 @@ class Color(commands.Cog): Assumes that color is an rgb tuple. """ - thumbnail = Image.new("RGB", (100, 100), color=color) + thumbnail = Image.new("RGB", (80, 80), color=color) bufferedio = BytesIO() thumbnail.save(bufferedio, format="PNG") bufferedio.seek(0) -- cgit v1.2.3 From 443cd600e4060b4b0f58382e7da07ca245cfca00 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Mon, 27 Sep 2021 09:49:42 -0400 Subject: chore: remove doubled new line in ERROR_MSG --- bot/exts/utilities/color.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9e2af325..7c7f4bba 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -17,11 +17,11 @@ logger = logging.getLogger(__name__) ERROR_MSG = """The color code {user_color} is not a possible color combination. -\nThe range of possible values are: -\nRGB & HSV: 0-255 -\nCMYK: 0-100% -\nHSL: 0-360 degrees -\nHex: #000000-#FFFFFF +The range of possible values are: +RGB & HSV: 0-255 +CMYK: 0-100% +HSL: 0-360 degrees +Hex: #000000-#FFFFFF """ COLOR_JSON_PATH = "bot/resources/utilities/ryanzec_colours.json" -- cgit v1.2.3 From d209638ff2c4f78cdcda49972886d4a7da69165f Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Mon, 27 Sep 2021 09:56:33 -0400 Subject: chore: remove single-use constant for json path --- bot/exts/utilities/color.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 7c7f4bba..ac7b5fc6 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -24,8 +24,7 @@ HSL: 0-360 degrees Hex: #000000-#FFFFFF """ -COLOR_JSON_PATH = "bot/resources/utilities/ryanzec_colours.json" -with open(COLOR_JSON_PATH) as f: +with open("bot/resources/utilities/ryanzec_colours.json") as f: COLOR_MAPPING = json.load(f) -- cgit v1.2.3 From 57554db4fc14f5869168622e1896a80b851e7579 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Mon, 27 Sep 2021 10:46:08 -0400 Subject: chore: remove single-use constant for json path --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 57510488..6aa0c3cd 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -65,7 +65,7 @@ class Color(commands.Cog): # mode is either None or an invalid code if mode is None: no_mode_embed = Embed( - title="No 'mode' was passed, please define a color code.", + title="No mode was passed, please define a color code.", description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", color=Colours.soft_red, ) -- cgit v1.2.3 From c2650a9e9c2e1ed9fbfcf914c2fefec5fd9f7479 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 3 Sep 2021 11:18:15 -0400 Subject: Start from upstream main branch --- bot/exts/fun/color.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 bot/exts/fun/color.py diff --git a/bot/exts/fun/color.py b/bot/exts/fun/color.py new file mode 100644 index 00000000..5d86f002 --- /dev/null +++ b/bot/exts/fun/color.py @@ -0,0 +1 @@ +# initial creation -- cgit v1.2.3 From 32b06208a2212f8d596591f50fc8759049fc78e1 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 3 Sep 2021 14:35:26 -0400 Subject: Create draft body of file This is a large empty file with lots of comments. My general proposal is outlined in the code stumps. Details will need to be hashed out and decided on with CyberCitizen01. In particular: - How to use URLs that has list of color names? Read those into a dictionary? - How to handle the command call with options? `discord-flags`, parsing, function call like: .colour cmyk(49, 50, 0, 22) .colour hsl(241, 47, 58) .colour rgb 101 99 199 - How to implement fuzzy matching with rapidfuzz based on the color names from those URLs? - How to generate colors in other formats? Is this all possible in pillow? - How to generate photo to use in the embed? Do we temporarily create a file in a cache, send it in embed, then delete? This will be a fun project, and my first collab! Co-authored-by: Mohammad Rafivulla <77384412+CyberCitizen01@users.noreply.github.com> --- bot/exts/fun/color.py | 113 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/bot/exts/fun/color.py b/bot/exts/fun/color.py index 5d86f002..32a25b0d 100644 --- a/bot/exts/fun/color.py +++ b/bot/exts/fun/color.py @@ -1 +1,112 @@ -# initial creation +# imports +import logging + +import pillow +from discord import Embed +# ! need to install discord-flags and add to poetry.lock file +from discord.ext import commands, flags +from rapidfuzz import process + +from bot.bot import Bot +from bot.constants import Colours + +logger = logging.getLogger(__name__) + +# constants if needed +# TODO Will the color conversions be done only from pillow or will an API / URL be needed? +# Color URLs +COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" +COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" + + +COLOR_ERROR = Embed( + title="Input color is not possible", + description="The color code {user_color} is not a possible color combination." + "\nThe range of possible values are: " + "\nRGB & HSV: 0-255" + "\nCMYK: 0-100%" + "\nHSL: 0-360 degrees" + "\nHex: #000000-#FFFFFF" +) +COLOR_EMBED = Embed( + title="{color_name}", + description="RGB" + "\n{RGB}" + "\nHSV" + "\n{HSV}" + "\nCMYK" + "\n{CMYK}" + "\nHSL" + "\n{HSL}" + "\nHex" + "\n{Hex}" +) + + +# define color command +class Color(commands.cog): + """User initiated command to receive color information.""" + + def __init__(self, bot: Bot): + self.bot = bot + + # ? possible to use discord-flags to allow user to decide on color + # https://pypi.org/project/discord-flags/ + # @flags.add_flag("--rgb", type=str) + # @flags.add_flag("--hsv", type=str) + # @flags.add_flag("--cmyk", type=str) + # @flags.add_flag("--hsl", type=str) + # @flags.add_flag("--hex", type=str) + # @flags.add_flag("--name", type=str) + # @flags.command() + @commands.command(aliases=["color", "colour"]) + @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) + async def color(self, ctx: commands.Context, *, user_color: str) -> None: + """Send information on input color code or color name.""" + # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name + # should we assume the color is RGB if not defined? + # should discord tags be used? + # need to review discord.py V2.0 + + # TODO code to check if color code is possible + await ctx.send(embed=COLOR_ERROR.format(color=user_color)) + # await ctx.send(embed=COLOR_EMBED.format( + # RGB=color_dict["RGB"], + # HSV=color_dict["HSV"], + # HSL=color_dict["HSL"], + # CMYK=color_dict["CMYK"], + # HSL=color_dict["HSL"], + # Hex=color_dict["Hex"], + # color_name=color_dict["color_name"] + # ) + # ) + + # TODO pass for now + pass + + # if user_color in color_lists: + # # TODO fuzzy match for color + # pass + + async def color_converter(self, color: str, code_type: str) -> dict: + """Generate alternative color codes for use in the embed.""" + # TODO add code to take color and code type and return other types + # color_dict = { + # "RGB": color_RGB, + # "HSV": color_HSV, + # "HSL": color_HSL, + # "CMYK": color_CMYK, + # "HSL": color_HSL, + # "Hex": color_Hex, + # "color_name": color_name, + # } + pass + + async def photo_generator(self, color: str) -> None: + """Generate photo to use in embed.""" + # TODO need to find a way to store photo in cache to add to embed, then remove + + +def setup(bot: Bot) -> None: + """Load the Color Cog.""" + bot.add_cog(Color(bot)) -- cgit v1.2.3 From fbeb74bf9452840a9db8d3013d1f6dd2e350630f Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 3 Sep 2021 16:15:34 -0400 Subject: Add colorsys import, verbage for using JSON Co-authored-by: Mohammad Rafivulla <77384412+CyberCitizen01@users.noreply.github.com> --- bot/exts/fun/color.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bot/exts/fun/color.py b/bot/exts/fun/color.py index 32a25b0d..a00a956b 100644 --- a/bot/exts/fun/color.py +++ b/bot/exts/fun/color.py @@ -1,6 +1,7 @@ # imports import logging +import colorsys import pillow from discord import Embed # ! need to install discord-flags and add to poetry.lock file @@ -13,8 +14,8 @@ from bot.constants import Colours logger = logging.getLogger(__name__) # constants if needed -# TODO Will the color conversions be done only from pillow or will an API / URL be needed? -# Color URLs +# Color URLs - will be replaced by JSON file? +COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" @@ -78,7 +79,7 @@ class Color(commands.cog): # HSL=color_dict["HSL"], # Hex=color_dict["Hex"], # color_name=color_dict["color_name"] - # ) + # ).set_image() # url for image? # ) # TODO pass for now -- cgit v1.2.3 From 087d2f279e052871dcd4bb322953b01bf5b965cc Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sat, 4 Sep 2021 01:47:58 +0530 Subject: Added ryanzec_colours.json constructed from ryanzec/name-that-color Original source: https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681 --- bot/resources/fun/ryanzec_colours.json | 1568 ++++++++++++++++++++++++++++++++ 1 file changed, 1568 insertions(+) create mode 100644 bot/resources/fun/ryanzec_colours.json diff --git a/bot/resources/fun/ryanzec_colours.json b/bot/resources/fun/ryanzec_colours.json new file mode 100644 index 00000000..63d9be44 --- /dev/null +++ b/bot/resources/fun/ryanzec_colours.json @@ -0,0 +1,1568 @@ +{ + "Abbey": "4C4F56", + "Acadia": "1B1404", + "Acapulco": "7CB0A1", + "Aero Blue": "C9FFE5", + "Affair": "714693", + "Akaroa": "D4C4A8", + "Alabaster": "FAFAFA", + "Albescent White": "F5E9D3", + "Algae Green": "93DFB8", + "Alice Blue": "F0F8FF", + "Alizarin Crimson": "E32636", + "Allports": "0076A3", + "Almond": "EED9C4", + "Almond Frost": "907B71", + "Alpine": "AF8F2C", + "Alto": "DBDBDB", + "Aluminium": "A9ACB6", + "Amaranth": "E52B50", + "Amazon": "3B7A57", + "Amber": "FFBF00", + "Americano": "87756E", + "Amethyst": "9966CC", + "Amethyst Smoke": "A397B4", + "Amour": "F9EAF3", + "Amulet": "7B9F80", + "Anakiwa": "9DE5FF", + "Antique Brass": "C88A65", + "Antique Bronze": "704A07", + "Anzac": "E0B646", + "Apache": "DFBE6F", + "Apple": "4FA83D", + "Apple Blossom": "AF4D43", + "Apple Green": "E2F3EC", + "Apricot": "EB9373", + "Apricot Peach": "FBCEB1", + "Apricot White": "FFFEEC", + "Aqua Deep": "014B43", + "Aqua Forest": "5FA777", + "Aqua Haze": "EDF5F5", + "Aqua Island": "A1DAD7", + "Aqua Spring": "EAF9F5", + "Aqua Squeeze": "E8F5F2", + "Aquamarine": "7FFFD4", + "Aquamarine Blue": "71D9E2", + "Arapawa": "110C6C", + "Armadillo": "433E37", + "Arrowtown": "948771", + "Ash": "C6C3B5", + "Asparagus": "7BA05B", + "Asphalt": "130A06", + "Astra": "FAEAB9", + "Astral": "327DA0", + "Astronaut": "283A77", + "Astronaut Blue": "013E62", + "Athens Gray": "EEF0F3", + "Aths Special": "ECEBCE", + "Atlantis": "97CD2D", + "Atoll": "0A6F75", + "Atomic Tangerine": "FF9966", + "Au Chico": "97605D", + "Aubergine": "3B0910", + "Australian Mint": "F5FFBE", + "Avocado": "888D65", + "Axolotl": "4E6649", + "Azalea": "F7C8DA", + "Aztec": "0D1C19", + "Azure": "315BA1", + "Azure Radiance": "007FFF", + "Baby Blue": "E0FFFF", + "Bahama Blue": "026395", + "Bahia": "A5CB0C", + "Baja White": "FFF8D1", + "Bali Hai": "859FAF", + "Baltic Sea": "2A2630", + "Bamboo": "DA6304", + "Banana Mania": "FBE7B2", + "Bandicoot": "858470", + "Barberry": "DED717", + "Barley Corn": "A68B5B", + "Barley White": "FFF4CE", + "Barossa": "44012D", + "Bastille": "292130", + "Battleship Gray": "828F72", + "Bay Leaf": "7DA98D", + "Bay of Many": "273A81", + "Bazaar": "98777B", + "Bean ": "3D0C02", + "Beauty Bush": "EEC1BE", + "Beaver": "926F5B", + "Beeswax": "FEF2C7", + "Beige": "F5F5DC", + "Bermuda": "7DD8C6", + "Bermuda Gray": "6B8BA2", + "Beryl Green": "DEE5C0", + "Bianca": "FCFBF3", + "Big Stone": "162A40", + "Bilbao": "327C14", + "Biloba Flower": "B2A1EA", + "Birch": "373021", + "Bird Flower": "D4CD16", + "Biscay": "1B3162", + "Bismark": "497183", + "Bison Hide": "C1B7A4", + "Bistre": "3D2B1F", + "Bitter": "868974", + "Bitter Lemon": "CAE00D", + "Bittersweet": "FE6F5E", + "Bizarre": "EEDEDA", + "Black": "000000", + "Black Bean": "081910", + "Black Forest": "0B1304", + "Black Haze": "F6F7F7", + "Black Marlin": "3E2C1C", + "Black Olive": "242E16", + "Black Pearl": "041322", + "Black Rock": "0D0332", + "Black Rose": "67032D", + "Black Russian": "0A001C", + "Black Squeeze": "F2FAFA", + "Black White": "FFFEF6", + "Blackberry": "4D0135", + "Blackcurrant": "32293A", + "Blaze Orange": "FF6600", + "Bleach White": "FEF3D8", + "Bleached Cedar": "2C2133", + "Blizzard Blue": "A3E3ED", + "Blossom": "DCB4BC", + "Blue": "0000FF", + "Blue Bayoux": "496679", + "Blue Bell": "9999CC", + "Blue Chalk": "F1E9FF", + "Blue Charcoal": "010D1A", + "Blue Chill": "0C8990", + "Blue Diamond": "380474", + "Blue Dianne": "204852", + "Blue Gem": "2C0E8C", + "Blue Haze": "BFBED8", + "Blue Lagoon": "017987", + "Blue Marguerite": "7666C6", + "Blue Ribbon": "0066FF", + "Blue Romance": "D2F6DE", + "Blue Smoke": "748881", + "Blue Stone": "016162", + "Blue Violet": "6456B7", + "Blue Whale": "042E4C", + "Blue Zodiac": "13264D", + "Blumine": "18587A", + "Blush": "B44668", + "Blush Pink": "FF6FFF", + "Bombay": "AFB1B8", + "Bon Jour": "E5E0E1", + "Bondi Blue": "0095B6", + "Bone": "E4D1C0", + "Bordeaux": "5C0120", + "Bossanova": "4E2A5A", + "Boston Blue": "3B91B4", + "Botticelli": "C7DDE5", + "Bottle Green": "093624", + "Boulder": "7A7A7A", + "Bouquet": "AE809E", + "Bourbon": "BA6F1E", + "Bracken": "4A2A04", + "Brandy": "DEC196", + "Brandy Punch": "CD8429", + "Brandy Rose": "BB8983", + "Breaker Bay": "5DA19F", + "Brick Red": "C62D42", + "Bridal Heath": "FFFAF4", + "Bridesmaid": "FEF0EC", + "Bright Gray": "3C4151", + "Bright Green": "66FF00", + "Bright Red": "B10000", + "Bright Sun": "FED33C", + "Bright Turquoise": "08E8DE", + "Brilliant Rose": "F653A6", + "Brink Pink": "FB607F", + "Bronco": "ABA196", + "Bronze": "3F2109", + "Bronze Olive": "4E420C", + "Bronzetone": "4D400F", + "Broom": "FFEC13", + "Brown": "964B00", + "Brown Bramble": "592804", + "Brown Derby": "492615", + "Brown Pod": "401801", + "Brown Rust": "AF593E", + "Brown Tumbleweed": "37290E", + "Bubbles": "E7FEFF", + "Buccaneer": "622F30", + "Bud": "A8AE9C", + "Buddha Gold": "C1A004", + "Buff": "F0DC82", + "Bulgarian Rose": "480607", + "Bull Shot": "864D1E", + "Bunker": "0D1117", + "Bunting": "151F4C", + "Burgundy": "900020", + "Burnham": "002E20", + "Burning Orange": "FF7034", + "Burning Sand": "D99376", + "Burnt Maroon": "420303", + "Burnt Orange": "CC5500", + "Burnt Sienna": "E97451", + "Burnt Umber": "8A3324", + "Bush": "0D2E1C", + "Buttercup": "F3AD16", + "Buttered Rum": "A1750D", + "Butterfly Bush": "624E9A", + "Buttermilk": "FFF1B5", + "Buttery White": "FFFCEA", + "Cab Sav": "4D0A18", + "Cabaret": "D94972", + "Cabbage Pont": "3F4C3A", + "Cactus": "587156", + "Cadet Blue": "A9B2C3", + "Cadillac": "B04C6A", + "Cafe Royale": "6F440C", + "Calico": "E0C095", + "California": "FE9D04", + "Calypso": "31728D", + "Camarone": "00581A", + "Camelot": "893456", + "Cameo": "D9B99B", + "Camouflage": "3C3910", + "Camouflage Green": "78866B", + "Can Can": "D591A4", + "Canary": "F3FB62", + "Candlelight": "FCD917", + "Candy Corn": "FBEC5D", + "Cannon Black": "251706", + "Cannon Pink": "894367", + "Cape Cod": "3C4443", + "Cape Honey": "FEE5AC", + "Cape Palliser": "A26645", + "Caper": "DCEDB4", + "Caramel": "FFDDAF", + "Cararra": "EEEEE8", + "Cardin Green": "01361C", + "Cardinal": "C41E3A", + "Cardinal Pink": "8C055E", + "Careys Pink": "D29EAA", + "Caribbean Green": "00CC99", + "Carissma": "EA88A8", + "Carla": "F3FFD8", + "Carmine": "960018", + "Carnaby Tan": "5C2E01", + "Carnation": "F95A61", + "Carnation Pink": "FFA6C9", + "Carousel Pink": "F9E0ED", + "Carrot Orange": "ED9121", + "Casablanca": "F8B853", + "Casal": "2F6168", + "Cascade": "8BA9A5", + "Cashmere": "E6BEA5", + "Casper": "ADBED1", + "Castro": "52001F", + "Catalina Blue": "062A78", + "Catskill White": "EEF6F7", + "Cavern Pink": "E3BEBE", + "Cedar": "3E1C14", + "Cedar Wood Finish": "711A00", + "Celadon": "ACE1AF", + "Celery": "B8C25D", + "Celeste": "D1D2CA", + "Cello": "1E385B", + "Celtic": "163222", + "Cement": "8D7662", + "Ceramic": "FCFFF9", + "Cerise": "DA3287", + "Cerise Red": "DE3163", + "Cerulean": "02A4D3", + "Cerulean Blue": "2A52BE", + "Chablis": "FFF4F3", + "Chalet Green": "516E3D", + "Chalky": "EED794", + "Chambray": "354E8C", + "Chamois": "EDDCB1", + "Champagne": "FAECCC", + "Chantilly": "F8C3DF", + "Charade": "292937", + "Chardon": "FFF3F1", + "Chardonnay": "FFCD8C", + "Charlotte": "BAEEF9", + "Charm": "D47494", + "Chartreuse": "7FFF00", + "Chartreuse Yellow": "DFFF00", + "Chateau Green": "40A860", + "Chatelle": "BDB3C7", + "Chathams Blue": "175579", + "Chelsea Cucumber": "83AA5D", + "Chelsea Gem": "9E5302", + "Chenin": "DFCD6F", + "Cherokee": "FCDA98", + "Cherry Pie": "2A0359", + "Cherrywood": "651A14", + "Cherub": "F8D9E9", + "Chestnut": "B94E48", + "Chestnut Rose": "CD5C5C", + "Chetwode Blue": "8581D9", + "Chicago": "5D5C58", + "Chiffon": "F1FFC8", + "Chilean Fire": "F77703", + "Chilean Heath": "FFFDE6", + "China Ivory": "FCFFE7", + "Chino": "CEC7A7", + "Chinook": "A8E3BD", + "Chocolate": "370202", + "Christalle": "33036B", + "Christi": "67A712", + "Christine": "E7730A", + "Chrome White": "E8F1D4", + "Cinder": "0E0E18", + "Cinderella": "FDE1DC", + "Cinnabar": "E34234", + "Cinnamon": "7B3F00", + "Cioccolato": "55280C", + "Citrine White": "FAF7D6", + "Citron": "9EA91F", + "Citrus": "A1C50A", + "Clairvoyant": "480656", + "Clam Shell": "D4B6AF", + "Claret": "7F1734", + "Classic Rose": "FBCCE7", + "Clay Ash": "BDC8B3", + "Clay Creek": "8A8360", + "Clear Day": "E9FFFD", + "Clementine": "E96E00", + "Clinker": "371D09", + "Cloud": "C7C4BF", + "Cloud Burst": "202E54", + "Cloudy": "ACA59F", + "Clover": "384910", + "Cobalt": "0047AB", + "Cocoa Bean": "481C1C", + "Cocoa Brown": "301F1E", + "Coconut Cream": "F8F7DC", + "Cod Gray": "0B0B0B", + "Coffee": "706555", + "Coffee Bean": "2A140E", + "Cognac": "9F381D", + "Cola": "3F2500", + "Cold Purple": "ABA0D9", + "Cold Turkey": "CEBABA", + "Colonial White": "FFEDBC", + "Comet": "5C5D75", + "Como": "517C66", + "Conch": "C9D9D2", + "Concord": "7C7B7A", + "Concrete": "F2F2F2", + "Confetti": "E9D75A", + "Congo Brown": "593737", + "Congress Blue": "02478E", + "Conifer": "ACDD4D", + "Contessa": "C6726B", + "Copper": "B87333", + "Copper Canyon": "7E3A15", + "Copper Rose": "996666", + "Copper Rust": "944747", + "Copperfield": "DA8A67", + "Coral": "FF7F50", + "Coral Red": "FF4040", + "Coral Reef": "C7BCA2", + "Coral Tree": "A86B6B", + "Corduroy": "606E68", + "Coriander": "C4D0B0", + "Cork": "40291D", + "Corn": "E7BF05", + "Corn Field": "F8FACD", + "Corn Harvest": "8B6B0B", + "Cornflower": "93CCEA", + "Cornflower Blue": "6495ED", + "Cornflower Lilac": "FFB0AC", + "Corvette": "FAD3A2", + "Cosmic": "76395D", + "Cosmos": "FFD8D9", + "Costa Del Sol": "615D30", + "Cotton Candy": "FFB7D5", + "Cotton Seed": "C2BDB6", + "County Green": "01371A", + "Cowboy": "4D282D", + "Crail": "B95140", + "Cranberry": "DB5079", + "Crater Brown": "462425", + "Cream": "FFFDD0", + "Cream Brulee": "FFE5A0", + "Cream Can": "F5C85C", + "Creole": "1E0F04", + "Crete": "737829", + "Crimson": "DC143C", + "Crocodile": "736D58", + "Crown of Thorns": "771F1F", + "Crowshead": "1C1208", + "Cruise": "B5ECDF", + "Crusoe": "004816", + "Crusta": "FD7B33", + "Cumin": "924321", + "Cumulus": "FDFFD5", + "Cupid": "FBBEDA", + "Curious Blue": "2596D1", + "Cutty Sark": "507672", + "Cyan / Aqua": "00FFFF", + "Cyprus": "003E40", + "Daintree": "012731", + "Dairy Cream": "F9E4BC", + "Daisy Bush": "4F2398", + "Dallas": "6E4B26", + "Dandelion": "FED85D", + "Danube": "6093D1", + "Dark Blue": "0000C8", + "Dark Burgundy": "770F05", + "Dark Ebony": "3C2005", + "Dark Fern": "0A480D", + "Dark Tan": "661010", + "Dawn": "A6A29A", + "Dawn Pink": "F3E9E5", + "De York": "7AC488", + "Deco": "D2DA97", + "Deep Blue": "220878", + "Deep Blush": "E47698", + "Deep Bronze": "4A3004", + "Deep Cerulean": "007BA7", + "Deep Cove": "051040", + "Deep Fir": "002900", + "Deep Forest Green": "182D09", + "Deep Koamaru": "1B127B", + "Deep Oak": "412010", + "Deep Sapphire": "082567", + "Deep Sea": "01826B", + "Deep Sea Green": "095859", + "Deep Teal": "003532", + "Del Rio": "B09A95", + "Dell": "396413", + "Delta": "A4A49D", + "Deluge": "7563A8", + "Denim": "1560BD", + "Derby": "FFEED8", + "Desert": "AE6020", + "Desert Sand": "EDC9AF", + "Desert Storm": "F8F8F7", + "Dew": "EAFFFE", + "Di Serria": "DB995E", + "Diesel": "130000", + "Dingley": "5D7747", + "Disco": "871550", + "Dixie": "E29418", + "Dodger Blue": "1E90FF", + "Dolly": "F9FF8B", + "Dolphin": "646077", + "Domino": "8E775E", + "Don Juan": "5D4C51", + "Donkey Brown": "A69279", + "Dorado": "6B5755", + "Double Colonial White": "EEE3AD", + "Double Pearl Lusta": "FCF4D0", + "Double Spanish White": "E6D7B9", + "Dove Gray": "6D6C6C", + "Downriver": "092256", + "Downy": "6FD0C5", + "Driftwood": "AF8751", + "Drover": "FDF7AD", + "Dull Lavender": "A899E6", + "Dune": "383533", + "Dust Storm": "E5CCC9", + "Dusty Gray": "A8989B", + "Eagle": "B6BAA4", + "Earls Green": "C9B93B", + "Early Dawn": "FFF9E6", + "East Bay": "414C7D", + "East Side": "AC91CE", + "Eastern Blue": "1E9AB0", + "Ebb": "E9E3E3", + "Ebony": "0C0B1D", + "Ebony Clay": "26283B", + "Eclipse": "311C17", + "Ecru White": "F5F3E5", + "Ecstasy": "FA7814", + "Eden": "105852", + "Edgewater": "C8E3D7", + "Edward": "A2AEAB", + "Egg Sour": "FFF4DD", + "Egg White": "FFEFC1", + "Eggplant": "614051", + "El Paso": "1E1708", + "El Salva": "8F3E33", + "Electric Lime": "CCFF00", + "Electric Violet": "8B00FF", + "Elephant": "123447", + "Elf Green": "088370", + "Elm": "1C7C7D", + "Emerald": "50C878", + "Eminence": "6C3082", + "Emperor": "514649", + "Empress": "817377", + "Endeavour": "0056A7", + "Energy Yellow": "F8DD5C", + "English Holly": "022D15", + "English Walnut": "3E2B23", + "Envy": "8BA690", + "Equator": "E1BC64", + "Espresso": "612718", + "Eternity": "211A0E", + "Eucalyptus": "278A5B", + "Eunry": "CFA39D", + "Evening Sea": "024E46", + "Everglade": "1C402E", + "Faded Jade": "427977", + "Fair Pink": "FFEFEC", + "Falcon": "7F626D", + "Fall Green": "ECEBBD", + "Falu Red": "801818", + "Fantasy": "FAF3F0", + "Fedora": "796A78", + "Feijoa": "9FDD8C", + "Fern": "63B76C", + "Fern Frond": "657220", + "Fern Green": "4F7942", + "Ferra": "704F50", + "Festival": "FBE96C", + "Feta": "F0FCEA", + "Fiery Orange": "B35213", + "Finch": "626649", + "Finlandia": "556D56", + "Finn": "692D54", + "Fiord": "405169", + "Fire": "AA4203", + "Fire Bush": "E89928", + "Firefly": "0E2A30", + "Flame Pea": "DA5B38", + "Flamenco": "FF7D07", + "Flamingo": "F2552A", + "Flax": "EEDC82", + "Flax Smoke": "7B8265", + "Flesh": "FFCBA4", + "Flint": "6F6A61", + "Flirt": "A2006D", + "Flush Mahogany": "CA3435", + "Flush Orange": "FF7F00", + "Foam": "D8FCFA", + "Fog": "D7D0FF", + "Foggy Gray": "CBCAB6", + "Forest Green": "228B22", + "Forget Me Not": "FFF1EE", + "Fountain Blue": "56B4BE", + "Frangipani": "FFDEB3", + "French Gray": "BDBDC6", + "French Lilac": "ECC7EE", + "French Pass": "BDEDFD", + "French Rose": "F64A8A", + "Fresh Eggplant": "990066", + "Friar Gray": "807E79", + "Fringy Flower": "B1E2C1", + "Froly": "F57584", + "Frost": "EDF5DD", + "Frosted Mint": "DBFFF8", + "Frostee": "E4F6E7", + "Fruit Salad": "4F9D5D", + "Fuchsia Blue": "7A58C1", + "Fuchsia Pink": "C154C1", + "Fuego": "BEDE0D", + "Fuel Yellow": "ECA927", + "Fun Blue": "1959A8", + "Fun Green": "016D39", + "Fuscous Gray": "54534D", + "Fuzzy Wuzzy Brown": "C45655", + "Gable Green": "163531", + "Gallery": "EFEFEF", + "Galliano": "DCB20C", + "Gamboge": "E49B0F", + "Geebung": "D18F1B", + "Genoa": "15736B", + "Geraldine": "FB8989", + "Geyser": "D4DFE2", + "Ghost": "C7C9D5", + "Gigas": "523C94", + "Gimblet": "B8B56A", + "Gin": "E8F2EB", + "Gin Fizz": "FFF9E2", + "Givry": "F8E4BF", + "Glacier": "80B3C4", + "Glade Green": "61845F", + "Go Ben": "726D4E", + "Goblin": "3D7D52", + "Gold": "FFD700", + "Gold Drop": "F18200", + "Gold Sand": "E6BE8A", + "Gold Tips": "DEBA13", + "Golden Bell": "E28913", + "Golden Dream": "F0D52D", + "Golden Fizz": "F5FB3D", + "Golden Glow": "FDE295", + "Golden Grass": "DAA520", + "Golden Sand": "F0DB7D", + "Golden Tainoi": "FFCC5C", + "Goldenrod": "FCD667", + "Gondola": "261414", + "Gordons Green": "0B1107", + "Gorse": "FFF14F", + "Gossamer": "069B81", + "Gossip": "D2F8B0", + "Gothic": "6D92A1", + "Governor Bay": "2F3CB3", + "Grain Brown": "E4D5B7", + "Grandis": "FFD38C", + "Granite Green": "8D8974", + "Granny Apple": "D5F6E3", + "Granny Smith": "84A0A0", + "Granny Smith Apple": "9DE093", + "Grape": "381A51", + "Graphite": "251607", + "Gravel": "4A444B", + "Gray": "808080", + "Gray Asparagus": "465945", + "Gray Chateau": "A2AAB3", + "Gray Nickel": "C3C3BD", + "Gray Nurse": "E7ECE6", + "Gray Olive": "A9A491", + "Gray Suit": "C1BECD", + "Green": "00FF00", + "Green Haze": "01A368", + "Green House": "24500F", + "Green Kelp": "25311C", + "Green Leaf": "436A0D", + "Green Mist": "CBD3B0", + "Green Pea": "1D6142", + "Green Smoke": "A4AF6E", + "Green Spring": "B8C1B1", + "Green Vogue": "032B52", + "Green Waterloo": "101405", + "Green White": "E8EBE0", + "Green Yellow": "ADFF2F", + "Grenadier": "D54600", + "Guardsman Red": "BA0101", + "Gulf Blue": "051657", + "Gulf Stream": "80B3AE", + "Gull Gray": "9DACB7", + "Gum Leaf": "B6D3BF", + "Gumbo": "7CA1A6", + "Gun Powder": "414257", + "Gunsmoke": "828685", + "Gurkha": "9A9577", + "Hacienda": "98811B", + "Hairy Heath": "6B2A14", + "Haiti": "1B1035", + "Half Baked": "85C4CC", + "Half Colonial White": "FDF6D3", + "Half Dutch White": "FEF7DE", + "Half Spanish White": "FEF4DB", + "Half and Half": "FFFEE1", + "Hampton": "E5D8AF", + "Harlequin": "3FFF00", + "Harp": "E6F2EA", + "Harvest Gold": "E0B974", + "Havelock Blue": "5590D9", + "Hawaiian Tan": "9D5616", + "Hawkes Blue": "D4E2FC", + "Heath": "541012", + "Heather": "B7C3D0", + "Heathered Gray": "B6B095", + "Heavy Metal": "2B3228", + "Heliotrope": "DF73FF", + "Hemlock": "5E5D3B", + "Hemp": "907874", + "Hibiscus": "B6316C", + "Highland": "6F8E63", + "Hillary": "ACA586", + "Himalaya": "6A5D1B", + "Hint of Green": "E6FFE9", + "Hint of Red": "FBF9F9", + "Hint of Yellow": "FAFDE4", + "Hippie Blue": "589AAF", + "Hippie Green": "53824B", + "Hippie Pink": "AE4560", + "Hit Gray": "A1ADB5", + "Hit Pink": "FFAB81", + "Hokey Pokey": "C8A528", + "Hoki": "65869F", + "Holly": "011D13", + "Hollywood Cerise": "F400A1", + "Honey Flower": "4F1C70", + "Honeysuckle": "EDFC84", + "Hopbush": "D06DA1", + "Horizon": "5A87A0", + "Horses Neck": "604913", + "Hot Cinnamon": "D2691E", + "Hot Pink": "FF69B4", + "Hot Toddy": "B38007", + "Humming Bird": "CFF9F3", + "Hunter Green": "161D10", + "Hurricane": "877C7B", + "Husk": "B7A458", + "Ice Cold": "B1F4E7", + "Iceberg": "DAF4F0", + "Illusion": "F6A4C9", + "Inch Worm": "B0E313", + "Indian Khaki": "C3B091", + "Indian Tan": "4D1E01", + "Indigo": "4F69C6", + "Indochine": "C26B03", + "International Klein Blue": "002FA7", + "International Orange": "FF4F00", + "Irish Coffee": "5F3D26", + "Iroko": "433120", + "Iron": "D4D7D9", + "Ironside Gray": "676662", + "Ironstone": "86483C", + "Island Spice": "FFFCEE", + "Ivory": "FFFFF0", + "Jacaranda": "2E0329", + "Jacarta": "3A2A6A", + "Jacko Bean": "2E1905", + "Jacksons Purple": "20208D", + "Jade": "00A86B", + "Jaffa": "EF863F", + "Jagged Ice": "C2E8E5", + "Jagger": "350E57", + "Jaguar": "080110", + "Jambalaya": "5B3013", + "Janna": "F4EBD3", + "Japanese Laurel": "0A6906", + "Japanese Maple": "780109", + "Japonica": "D87C63", + "Java": "1FC2C2", + "Jazzberry Jam": "A50B5E", + "Jelly Bean": "297B9A", + "Jet Stream": "B5D2CE", + "Jewel": "126B40", + "Jon": "3B1F1F", + "Jonquil": "EEFF9A", + "Jordy Blue": "8AB9F1", + "Judge Gray": "544333", + "Jumbo": "7C7B82", + "Jungle Green": "29AB87", + "Jungle Mist": "B4CFD3", + "Juniper": "6D9292", + "Just Right": "ECCDB9", + "Kabul": "5E483E", + "Kaitoke Green": "004620", + "Kangaroo": "C6C8BD", + "Karaka": "1E1609", + "Karry": "FFEAD4", + "Kashmir Blue": "507096", + "Kelp": "454936", + "Kenyan Copper": "7C1C05", + "Keppel": "3AB09E", + "Key Lime Pie": "BFC921", + "Khaki": "F0E68C", + "Kidnapper": "E1EAD4", + "Kilamanjaro": "240C02", + "Killarney": "3A6A47", + "Kimberly": "736C9F", + "Kingfisher Daisy": "3E0480", + "Kobi": "E79FC4", + "Kokoda": "6E6D57", + "Korma": "8F4B0E", + "Koromiko": "FFBD5F", + "Kournikova": "FFE772", + "Kumera": "886221", + "La Palma": "368716", + "La Rioja": "B3C110", + "Las Palmas": "C6E610", + "Laser": "C8B568", + "Laser Lemon": "FFFF66", + "Laurel": "749378", + "Lavender": "B57EDC", + "Lavender Gray": "BDBBD7", + "Lavender Magenta": "EE82EE", + "Lavender Pink": "FBAED2", + "Lavender Purple": "967BB6", + "Lavender Rose": "FBA0E3", + "Lavender blush": "FFF0F5", + "Leather": "967059", + "Lemon": "FDE910", + "Lemon Chiffon": "FFFACD", + "Lemon Ginger": "AC9E22", + "Lemon Grass": "9B9E8F", + "Light Apricot": "FDD5B1", + "Light Orchid": "E29CD2", + "Light Wisteria": "C9A0DC", + "Lightning Yellow": "FCC01E", + "Lilac": "C8A2C8", + "Lilac Bush": "9874D3", + "Lily": "C8AABF", + "Lily White": "E7F8FF", + "Lima": "76BD17", + "Lime": "BFFF00", + "Limeade": "6F9D02", + "Limed Ash": "747D63", + "Limed Oak": "AC8A56", + "Limed Spruce": "394851", + "Linen": "FAF0E6", + "Link Water": "D9E4F5", + "Lipstick": "AB0563", + "Lisbon Brown": "423921", + "Livid Brown": "4D282E", + "Loafer": "EEF4DE", + "Loblolly": "BDC9CE", + "Lochinvar": "2C8C84", + "Lochmara": "007EC7", + "Locust": "A8AF8E", + "Log Cabin": "242A1D", + "Logan": "AAA9CD", + "Lola": "DFCFDB", + "London Hue": "BEA6C3", + "Lonestar": "6D0101", + "Lotus": "863C3C", + "Loulou": "460B41", + "Lucky": "AF9F1C", + "Lucky Point": "1A1A68", + "Lunar Green": "3C493A", + "Luxor Gold": "A7882C", + "Lynch": "697E9A", + "Mabel": "D9F7FF", + "Macaroni and Cheese": "FFB97B", + "Madang": "B7F0BE", + "Madison": "09255D", + "Madras": "3F3002", + "Magenta / Fuchsia": "FF00FF", + "Magic Mint": "AAF0D1", + "Magnolia": "F8F4FF", + "Mahogany": "4E0606", + "Mai Tai": "B06608", + "Maize": "F5D5A0", + "Makara": "897D6D", + "Mako": "444954", + "Malachite": "0BDA51", + "Malibu": "7DC8F7", + "Mallard": "233418", + "Malta": "BDB2A1", + "Mamba": "8E8190", + "Manatee": "8D90A1", + "Mandalay": "AD781B", + "Mandy": "E25465", + "Mandys Pink": "F2C3B2", + "Mango Tango": "E77200", + "Manhattan": "F5C999", + "Mantis": "74C365", + "Mantle": "8B9C90", + "Manz": "EEEF78", + "Mardi Gras": "350036", + "Marigold": "B98D28", + "Marigold Yellow": "FBE870", + "Mariner": "286ACD", + "Maroon": "800000", + "Maroon Flush": "C32148", + "Maroon Oak": "520C17", + "Marshland": "0B0F08", + "Martini": "AFA09E", + "Martinique": "363050", + "Marzipan": "F8DB9D", + "Masala": "403B38", + "Matisse": "1B659D", + "Matrix": "B05D54", + "Matterhorn": "4E3B41", + "Mauve": "E0B0FF", + "Mauvelous": "F091A9", + "Maverick": "D8C2D5", + "Medium Carmine": "AF4035", + "Medium Purple": "9370DB", + "Medium Red Violet": "BB3385", + "Melanie": "E4C2D5", + "Melanzane": "300529", + "Melon": "FEBAAD", + "Melrose": "C7C1FF", + "Mercury": "E5E5E5", + "Merino": "F6F0E6", + "Merlin": "413C37", + "Merlot": "831923", + "Metallic Bronze": "49371B", + "Metallic Copper": "71291D", + "Meteor": "D07D12", + "Meteorite": "3C1F76", + "Mexican Red": "A72525", + "Mid Gray": "5F5F6E", + "Midnight": "011635", + "Midnight Blue": "003366", + "Midnight Moss": "041004", + "Mikado": "2D2510", + "Milan": "FAFFA4", + "Milano Red": "B81104", + "Milk Punch": "FFF6D4", + "Millbrook": "594433", + "Mimosa": "F8FDD3", + "Mindaro": "E3F988", + "Mine Shaft": "323232", + "Mineral Green": "3F5D53", + "Ming": "36747D", + "Minsk": "3F307F", + "Mint Green": "98FF98", + "Mint Julep": "F1EEC1", + "Mint Tulip": "C4F4EB", + "Mirage": "161928", + "Mischka": "D1D2DD", + "Mist Gray": "C4C4BC", + "Mobster": "7F7589", + "Moccaccino": "6E1D14", + "Mocha": "782D19", + "Mojo": "C04737", + "Mona Lisa": "FFA194", + "Monarch": "8B0723", + "Mondo": "4A3C30", + "Mongoose": "B5A27F", + "Monsoon": "8A8389", + "Monte Carlo": "83D0C6", + "Monza": "C7031E", + "Moody Blue": "7F76D3", + "Moon Glow": "FCFEDA", + "Moon Mist": "DCDDCC", + "Moon Raker": "D6CEF6", + "Morning Glory": "9EDEE0", + "Morocco Brown": "441D00", + "Mortar": "504351", + "Mosque": "036A6E", + "Moss Green": "ADDFAD", + "Mountain Meadow": "1AB385", + "Mountain Mist": "959396", + "Mountbatten Pink": "997A8D", + "Muddy Waters": "B78E5C", + "Muesli": "AA8B5B", + "Mulberry": "C54B8C", + "Mulberry Wood": "5C0536", + "Mule Fawn": "8C472F", + "Mulled Wine": "4E4562", + "Mustard": "FFDB58", + "My Pink": "D69188", + "My Sin": "FFB31F", + "Mystic": "E2EBED", + "Nandor": "4B5D52", + "Napa": "ACA494", + "Narvik": "EDF9F1", + "Natural Gray": "8B8680", + "Navajo White": "FFDEAD", + "Navy Blue": "000080", + "Nebula": "CBDBD6", + "Negroni": "FFE2C5", + "Neon Carrot": "FF9933", + "Nepal": "8EABC1", + "Neptune": "7CB7BB", + "Nero": "140600", + "Nevada": "646E75", + "New Orleans": "F3D69D", + "New York Pink": "D7837F", + "Niagara": "06A189", + "Night Rider": "1F120F", + "Night Shadz": "AA375A", + "Nile Blue": "193751", + "Nobel": "B7B1B1", + "Nomad": "BAB1A2", + "Norway": "A8BD9F", + "Nugget": "C59922", + "Nutmeg": "81422C", + "Nutmeg Wood Finish": "683600", + "Oasis": "FEEFCE", + "Observatory": "02866F", + "Ocean Green": "41AA78", + "Ochre": "CC7722", + "Off Green": "E6F8F3", + "Off Yellow": "FEF9E3", + "Oil": "281E15", + "Old Brick": "901E1E", + "Old Copper": "724A2F", + "Old Gold": "CFB53B", + "Old Lace": "FDF5E6", + "Old Lavender": "796878", + "Old Rose": "C08081", + "Olive": "808000", + "Olive Drab": "6B8E23", + "Olive Green": "B5B35C", + "Olive Haze": "8B8470", + "Olivetone": "716E10", + "Olivine": "9AB973", + "Onahau": "CDF4FF", + "Onion": "2F270E", + "Opal": "A9C6C2", + "Opium": "8E6F70", + "Oracle": "377475", + "Orange": "FF681F", + "Orange Peel": "FFA000", + "Orange Roughy": "C45719", + "Orange White": "FEFCED", + "Orchid": "DA70D6", + "Orchid White": "FFFDF3", + "Oregon": "9B4703", + "Orient": "015E85", + "Oriental Pink": "C69191", + "Orinoco": "F3FBD4", + "Oslo Gray": "878D91", + "Ottoman": "E9F8ED", + "Outer Space": "2D383A", + "Outrageous Orange": "FF6037", + "Oxford Blue": "384555", + "Oxley": "779E86", + "Oyster Bay": "DAFAFF", + "Oyster Pink": "E9CECD", + "Paarl": "A65529", + "Pablo": "776F61", + "Pacific Blue": "009DC4", + "Pacifika": "778120", + "Paco": "411F10", + "Padua": "ADE6C4", + "Pale Canary": "FFFF99", + "Pale Leaf": "C0D3B9", + "Pale Oyster": "988D77", + "Pale Prim": "FDFEB8", + "Pale Rose": "FFE1F2", + "Pale Sky": "6E7783", + "Pale Slate": "C3BFC1", + "Palm Green": "09230F", + "Palm Leaf": "19330E", + "Pampas": "F4F2EE", + "Panache": "EAF6EE", + "Pancho": "EDCDAB", + "Papaya Whip": "FFEFD5", + "Paprika": "8D0226", + "Paradiso": "317D82", + "Parchment": "F1E9D2", + "Paris Daisy": "FFF46E", + "Paris M": "26056A", + "Paris White": "CADCD4", + "Parsley": "134F19", + "Pastel Green": "77DD77", + "Pastel Pink": "FFD1DC", + "Patina": "639A8F", + "Pattens Blue": "DEF5FF", + "Paua": "260368", + "Pavlova": "D7C498", + "Peach": "FFE5B4", + "Peach Cream": "FFF0DB", + "Peach Orange": "FFCC99", + "Peach Schnapps": "FFDCD6", + "Peach Yellow": "FADFAD", + "Peanut": "782F16", + "Pear": "D1E231", + "Pearl Bush": "E8E0D5", + "Pearl Lusta": "FCF4DC", + "Peat": "716B56", + "Pelorous": "3EABBF", + "Peppermint": "E3F5E1", + "Perano": "A9BEF2", + "Perfume": "D0BEF8", + "Periglacial Blue": "E1E6D6", + "Periwinkle": "CCCCFF", + "Periwinkle Gray": "C3CDE6", + "Persian Blue": "1C39BB", + "Persian Green": "00A693", + "Persian Indigo": "32127A", + "Persian Pink": "F77FBE", + "Persian Plum": "701C1C", + "Persian Red": "CC3333", + "Persian Rose": "FE28A2", + "Persimmon": "FF6B53", + "Peru Tan": "7F3A02", + "Pesto": "7C7631", + "Petite Orchid": "DB9690", + "Pewter": "96A8A1", + "Pharlap": "A3807B", + "Picasso": "FFF39D", + "Pickled Bean": "6E4826", + "Pickled Bluewood": "314459", + "Picton Blue": "45B1E8", + "Pig Pink": "FDD7E4", + "Pigeon Post": "AFBDD9", + "Pigment Indigo": "4B0082", + "Pine Cone": "6D5E54", + "Pine Glade": "C7CD90", + "Pine Green": "01796F", + "Pine Tree": "171F04", + "Pink": "FFC0CB", + "Pink Flamingo": "FF66FF", + "Pink Flare": "E1C0C8", + "Pink Lace": "FFDDF4", + "Pink Lady": "FFF1D8", + "Pink Salmon": "FF91A4", + "Pink Swan": "BEB5B7", + "Piper": "C96323", + "Pipi": "FEF4CC", + "Pippin": "FFE1DF", + "Pirate Gold": "BA7F03", + "Pistachio": "9DC209", + "Pixie Green": "C0D8B6", + "Pizazz": "FF9000", + "Pizza": "C99415", + "Plantation": "27504B", + "Plum": "843179", + "Pohutukawa": "8F021C", + "Polar": "E5F9F6", + "Polo Blue": "8DA8CC", + "Pomegranate": "F34723", + "Pompadour": "660045", + "Porcelain": "EFF2F3", + "Porsche": "EAAE69", + "Port Gore": "251F4F", + "Portafino": "FFFFB4", + "Portage": "8B9FEE", + "Portica": "F9E663", + "Pot Pourri": "F5E7E2", + "Potters Clay": "8C5738", + "Powder Ash": "BCC9C2", + "Powder Blue": "B0E0E6", + "Prairie Sand": "9A3820", + "Prelude": "D0C0E5", + "Prim": "F0E2EC", + "Primrose": "EDEA99", + "Provincial Pink": "FEF5F1", + "Prussian Blue": "003153", + "Puce": "CC8899", + "Pueblo": "7D2C14", + "Puerto Rico": "3FC1AA", + "Pumice": "C2CAC4", + "Pumpkin": "FF7518", + "Pumpkin Skin": "B1610B", + "Punch": "DC4333", + "Punga": "4D3D14", + "Purple": "660099", + "Purple Heart": "652DC1", + "Purple Mountain's Majesty": "9678B6", + "Purple Pizzazz": "FF00CC", + "Putty": "E7CD8C", + "Quarter Pearl Lusta": "FFFDF4", + "Quarter Spanish White": "F7F2E1", + "Quicksand": "BD978E", + "Quill Gray": "D6D6D1", + "Quincy": "623F2D", + "Racing Green": "0C1911", + "Radical Red": "FF355E", + "Raffia": "EADAB8", + "Rainee": "B9C8AC", + "Rajah": "F7B668", + "Rangitoto": "2E3222", + "Rangoon Green": "1C1E13", + "Raven": "727B89", + "Raw Sienna": "D27D46", + "Raw Umber": "734A12", + "Razzle Dazzle Rose": "FF33CC", + "Razzmatazz": "E30B5C", + "Rebel": "3C1206", + "Red": "FF0000", + "Red Beech": "7B3801", + "Red Berry": "8E0000", + "Red Damask": "DA6A41", + "Red Devil": "860111", + "Red Orange": "FF3F34", + "Red Oxide": "6E0902", + "Red Ribbon": "ED0A3F", + "Red Robin": "80341F", + "Red Stage": "D05F04", + "Red Violet": "C71585", + "Redwood": "5D1E0F", + "Reef": "C9FFA2", + "Reef Gold": "9F821C", + "Regal Blue": "013F6A", + "Regent Gray": "86949F", + "Regent St Blue": "AAD6E6", + "Remy": "FEEBF3", + "Reno Sand": "A86515", + "Resolution Blue": "002387", + "Revolver": "2C1632", + "Rhino": "2E3F62", + "Rice Cake": "FFFEF0", + "Rice Flower": "EEFFE2", + "Rich Gold": "A85307", + "Rio Grande": "BBD009", + "Ripe Lemon": "F4D81C", + "Ripe Plum": "410056", + "Riptide": "8BE6D8", + "River Bed": "434C59", + "Rob Roy": "EAC674", + "Robin's Egg Blue": "00CCCC", + "Rock": "4D3833", + "Rock Blue": "9EB1CD", + "Rock Spray": "BA450C", + "Rodeo Dust": "C9B29B", + "Rolling Stone": "747D83", + "Roman": "DE6360", + "Roman Coffee": "795D4C", + "Romance": "FFFEFD", + "Romantic": "FFD2B7", + "Ronchi": "ECC54E", + "Roof Terracotta": "A62F20", + "Rope": "8E4D1E", + "Rose": "FF007F", + "Rose Bud": "FBB2A3", + "Rose Bud Cherry": "800B47", + "Rose Fog": "E7BCB4", + "Rose White": "FFF6F5", + "Rose of Sharon": "BF5500", + "Rosewood": "65000B", + "Roti": "C6A84B", + "Rouge": "A23B6C", + "Royal Blue": "4169E1", + "Royal Heath": "AB3472", + "Royal Purple": "6B3FA0", + "Rum": "796989", + "Rum Swizzle": "F9F8E4", + "Russet": "80461B", + "Russett": "755A57", + "Rust": "B7410E", + "Rustic Red": "480404", + "Rusty Nail": "86560A", + "Saddle": "4C3024", + "Saddle Brown": "583401", + "Saffron": "F4C430", + "Saffron Mango": "F9BF58", + "Sage": "9EA587", + "Sahara": "B7A214", + "Sahara Sand": "F1E788", + "Sail": "B8E0F9", + "Salem": "097F4B", + "Salmon": "FF8C69", + "Salomie": "FEDB8D", + "Salt Box": "685E6E", + "Saltpan": "F1F7F2", + "Sambuca": "3A2010", + "San Felix": "0B6207", + "San Juan": "304B6A", + "San Marino": "456CAC", + "Sand Dune": "826F65", + "Sandal": "AA8D6F", + "Sandrift": "AB917A", + "Sandstone": "796D62", + "Sandwisp": "F5E7A2", + "Sandy Beach": "FFEAC8", + "Sandy brown": "F4A460", + "Sangria": "92000A", + "Sanguine Brown": "8D3D38", + "Santa Fe": "B16D52", + "Santas Gray": "9FA0B1", + "Sapling": "DED4A4", + "Sapphire": "2F519E", + "Saratoga": "555B10", + "Satin Linen": "E6E4D4", + "Sauvignon": "FFF5F3", + "Sazerac": "FFF4E0", + "Scampi": "675FA6", + "Scandal": "CFFAF4", + "Scarlet": "FF2400", + "Scarlet Gum": "431560", + "Scarlett": "950015", + "Scarpa Flow": "585562", + "Schist": "A9B497", + "School bus Yellow": "FFD800", + "Schooner": "8B847E", + "Science Blue": "0066CC", + "Scooter": "2EBFD4", + "Scorpion": "695F62", + "Scotch Mist": "FFFBDC", + "Screamin' Green": "66FF66", + "Sea Buckthorn": "FBA129", + "Sea Green": "2E8B57", + "Sea Mist": "C5DBCA", + "Sea Nymph": "78A39C", + "Sea Pink": "ED989E", + "Seagull": "80CCEA", + "Seance": "731E8F", + "Seashell": "F1F1F1", + "Seashell Peach": "FFF5EE", + "Seaweed": "1B2F11", + "Selago": "F0EEFD", + "Selective Yellow": "FFBA00", + "Sepia": "704214", + "Sepia Black": "2B0202", + "Sepia Skin": "9E5B40", + "Serenade": "FFF4E8", + "Shadow": "837050", + "Shadow Green": "9AC2B8", + "Shady Lady": "AAA5A9", + "Shakespeare": "4EABD1", + "Shalimar": "FBFFBA", + "Shamrock": "33CC99", + "Shark": "25272C", + "Sherpa Blue": "004950", + "Sherwood Green": "02402C", + "Shilo": "E8B9B3", + "Shingle Fawn": "6B4E31", + "Ship Cove": "788BBA", + "Ship Gray": "3E3A44", + "Shiraz": "B20931", + "Shocking": "E292C0", + "Shocking Pink": "FC0FC0", + "Shuttle Gray": "5F6672", + "Siam": "646A54", + "Sidecar": "F3E7BB", + "Silk": "BDB1A8", + "Silver": "C0C0C0", + "Silver Chalice": "ACACAC", + "Silver Rust": "C9C0BB", + "Silver Sand": "BFC1C2", + "Silver Tree": "66B58F", + "Sinbad": "9FD7D3", + "Siren": "7A013A", + "Sirocco": "718080", + "Sisal": "D3CBBA", + "Skeptic": "CAE6DA", + "Sky Blue": "76D7EA", + "Slate Gray": "708090", + "Smalt": "003399", + "Smalt Blue": "51808F", + "Smoky": "605B73", + "Snow Drift": "F7FAF7", + "Snow Flurry": "E4FFD1", + "Snowy Mint": "D6FFDB", + "Snuff": "E2D8ED", + "Soapstone": "FFFBF9", + "Soft Amber": "D1C6B4", + "Soft Peach": "F5EDEF", + "Solid Pink": "893843", + "Solitaire": "FEF8E2", + "Solitude": "EAF6FF", + "Sorbus": "FD7C07", + "Sorrell Brown": "CEB98F", + "Soya Bean": "6A6051", + "Spanish Green": "819885", + "Spectra": "2F5A57", + "Spice": "6A442E", + "Spicy Mix": "885342", + "Spicy Mustard": "74640D", + "Spicy Pink": "816E71", + "Spindle": "B6D1EA", + "Spray": "79DEEC", + "Spring Green": "00FF7F", + "Spring Leaves": "578363", + "Spring Rain": "ACCBB1", + "Spring Sun": "F6FFDC", + "Spring Wood": "F8F6F1", + "Sprout": "C1D7B0", + "Spun Pearl": "AAABB7", + "Squirrel": "8F8176", + "St Tropaz": "2D569B", + "Stack": "8A8F8A", + "Star Dust": "9F9F9C", + "Stark White": "E5D7BD", + "Starship": "ECF245", + "Steel Blue": "4682B4", + "Steel Gray": "262335", + "Stiletto": "9C3336", + "Stonewall": "928573", + "Storm Dust": "646463", + "Storm Gray": "717486", + "Stratos": "000741", + "Straw": "D4BF8D", + "Strikemaster": "956387", + "Stromboli": "325D52", + "Studio": "714AB2", + "Submarine": "BAC7C9", + "Sugar Cane": "F9FFF6", + "Sulu": "C1F07C", + "Summer Green": "96BBAB", + "Sun": "FBAC13", + "Sundance": "C9B35B", + "Sundown": "FFB1B3", + "Sunflower": "E4D422", + "Sunglo": "E16865", + "Sunglow": "FFCC33", + "Sunset Orange": "FE4C40", + "Sunshade": "FF9E2C", + "Supernova": "FFC901", + "Surf": "BBD7C1", + "Surf Crest": "CFE5D2", + "Surfie Green": "0C7A79", + "Sushi": "87AB39", + "Suva Gray": "888387", + "Swamp": "001B1C", + "Swamp Green": "ACB78E", + "Swans Down": "DCF0EA", + "Sweet Corn": "FBEA8C", + "Sweet Pink": "FD9FA2", + "Swirl": "D3CDC5", + "Swiss Coffee": "DDD6D5", + "Sycamore": "908D39", + "Tabasco": "A02712", + "Tacao": "EDB381", + "Tacha": "D6C562", + "Tahiti Gold": "E97C07", + "Tahuna Sands": "EEF0C8", + "Tall Poppy": "B32D29", + "Tallow": "A8A589", + "Tamarillo": "991613", + "Tamarind": "341515", + "Tan": "D2B48C", + "Tan Hide": "FA9D5A", + "Tana": "D9DCC1", + "Tangaroa": "03163C", + "Tangerine": "F28500", + "Tango": "ED7A1C", + "Tapa": "7B7874", + "Tapestry": "B05E81", + "Tara": "E1F6E8", + "Tarawera": "073A50", + "Tasman": "CFDCCF", + "Taupe": "483C32", + "Taupe Gray": "B3AF95", + "Tawny Port": "692545", + "Te Papa Green": "1E433C", + "Tea": "C1BAB0", + "Tea Green": "D0F0C0", + "Teak": "B19461", + "Teal": "008080", + "Teal Blue": "044259", + "Temptress": "3B000B", + "Tenn": "CD5700", + "Tequila": "FFE6C7", + "Terracotta": "E2725B", + "Texas": "F8F99C", + "Texas Rose": "FFB555", + "Thatch": "B69D98", + "Thatch Green": "403D19", + "Thistle": "D8BFD8", + "Thistle Green": "CCCAA8", + "Thunder": "33292F", + "Thunderbird": "C02B18", + "Tia Maria": "C1440E", + "Tiara": "C3D1D1", + "Tiber": "063537", + "Tickle Me Pink": "FC80A5", + "Tidal": "F1FFAD", + "Tide": "BFB8B0", + "Timber Green": "16322C", + "Timberwolf": "D9D6CF", + "Titan White": "F0EEFF", + "Toast": "9A6E61", + "Tobacco Brown": "715D47", + "Toledo": "3A0020", + "Tolopea": "1B0245", + "Tom Thumb": "3F583B", + "Tonys Pink": "E79F8C", + "Topaz": "7C778A", + "Torch Red": "FD0E35", + "Torea Bay": "0F2D9E", + "Tory Blue": "1450AA", + "Tosca": "8D3F3F", + "Totem Pole": "991B07", + "Tower Gray": "A9BDBF", + "Tradewind": "5FB3AC", + "Tranquil": "E6FFFF", + "Travertine": "FFFDE8", + "Tree Poppy": "FC9C1D", + "Treehouse": "3B2820", + "Trendy Green": "7C881A", + "Trendy Pink": "8C6495", + "Trinidad": "E64E03", + "Tropical Blue": "C3DDF9", + "Tropical Rain Forest": "00755E", + "Trout": "4A4E5A", + "True V": "8A73D6", + "Tuatara": "363534", + "Tuft Bush": "FFDDCD", + "Tulip Tree": "EAB33B", + "Tumbleweed": "DEA681", + "Tuna": "353542", + "Tundora": "4A4244", + "Turbo": "FAE600", + "Turkish Rose": "B57281", + "Turmeric": "CABB48", + "Turquoise": "30D5C8", + "Turquoise Blue": "6CDAE7", + "Turtle Green": "2A380B", + "Tuscany": "BD5E2E", + "Tusk": "EEF3C3", + "Tussock": "C5994B", + "Tutu": "FFF1F9", + "Twilight": "E4CFDE", + "Twilight Blue": "EEFDFF", + "Twine": "C2955D", + "Tyrian Purple": "66023C", + "Ultramarine": "120A8F", + "Valencia": "D84437", + "Valentino": "350E42", + "Valhalla": "2B194F", + "Van Cleef": "49170C", + "Vanilla": "D1BEA8", + "Vanilla Ice": "F3D9DF", + "Varden": "FFF6DF", + "Venetian Red": "72010F", + "Venice Blue": "055989", + "Venus": "928590", + "Verdigris": "5D5E37", + "Verdun Green": "495400", + "Vermilion": "FF4D00", + "Vesuvius": "B14A0B", + "Victoria": "534491", + "Vida Loca": "549019", + "Viking": "64CCDB", + "Vin Rouge": "983D61", + "Viola": "CB8FA9", + "Violent Violet": "290C5E", + "Violet": "240A40", + "Violet Eggplant": "991199", + "Violet Red": "F7468A", + "Viridian": "40826D", + "Viridian Green": "678975", + "Vis Vis": "FFEFA1", + "Vista Blue": "8FD6B4", + "Vista White": "FCF8F7", + "Vivid Tangerine": "FF9980", + "Vivid Violet": "803790", + "Voodoo": "533455", + "Vulcan": "10121D", + "Wafer": "DECBC6", + "Waikawa Gray": "5A6E9C", + "Waiouru": "363C0D", + "Walnut": "773F1A", + "Wasabi": "788A25", + "Water Leaf": "A1E9DE", + "Watercourse": "056F57", + "Waterloo ": "7B7C94", + "Wattle": "DCD747", + "Watusi": "FFDDCF", + "Wax Flower": "FFC0A8", + "We Peep": "F7DBE6", + "Web Orange": "FFA500", + "Wedgewood": "4E7F9E", + "Well Read": "B43332", + "West Coast": "625119", + "West Side": "FF910F", + "Westar": "DCD9D2", + "Wewak": "F19BAB", + "Wheat": "F5DEB3", + "Wheatfield": "F3EDCF", + "Whiskey": "D59A6F", + "Whisper": "F7F5FA", + "White": "FFFFFF", + "White Ice": "DDF9F1", + "White Lilac": "F8F7FC", + "White Linen": "F8F0E8", + "White Pointer": "FEF8FF", + "White Rock": "EAE8D4", + "Wild Blue Yonder": "7A89B8", + "Wild Rice": "ECE090", + "Wild Sand": "F4F4F4", + "Wild Strawberry": "FF3399", + "Wild Watermelon": "FD5B78", + "Wild Willow": "B9C46A", + "William": "3A686C", + "Willow Brook": "DFECDA", + "Willow Grove": "65745D", + "Windsor": "3C0878", + "Wine Berry": "591D35", + "Winter Hazel": "D5D195", + "Wisp Pink": "FEF4F8", + "Wisteria": "9771B5", + "Wistful": "A4A6D3", + "Witch Haze": "FFFC99", + "Wood Bark": "261105", + "Woodland": "4D5328", + "Woodrush": "302A0F", + "Woodsmoke": "0C0D0F", + "Woody Brown": "483131", + "Xanadu": "738678", + "Yellow": "FFFF00", + "Yellow Green": "C5E17A", + "Yellow Metal": "716338", + "Yellow Orange": "FFAE42", + "Yellow Sea": "FEA904", + "Your Pink": "FFC3C0", + "Yukon Gold": "7B6608", + "Yuma": "CEC291", + "Zambezi": "685558", + "Zanah": "DAECD6", + "Zest": "E5841B", + "Zeus": "292319", + "Ziggurat": "BFDBE2", + "Zinnwaldite": "EBC2AF", + "Zircon": "F4F8FF", + "Zombie": "E4D69B", + "Zorba": "A59B91", + "Zuccini": "044022", + "Zumthor": "EDF6FF" +} \ No newline at end of file -- cgit v1.2.3 From 29f6afac7b98e83962136964fbe129886613bef2 Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sat, 4 Sep 2021 17:40:02 +0530 Subject: Added ryanzec_colours.json constructed from ryanzec/name-that-color Original source: https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681 --- bot/resources/fun/ryanzec_colours.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/resources/fun/ryanzec_colours.json b/bot/resources/fun/ryanzec_colours.json index 63d9be44..7b89f052 100644 --- a/bot/resources/fun/ryanzec_colours.json +++ b/bot/resources/fun/ryanzec_colours.json @@ -1565,4 +1565,4 @@ "Zorba": "A59B91", "Zuccini": "044022", "Zumthor": "EDF6FF" -} \ No newline at end of file +} -- cgit v1.2.3 From e5ec6b7a62b1e8ba1679d0488e03c1d9c3af9d0b Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sun, 5 Sep 2021 20:31:53 +0530 Subject: Fix issues occured while deploying [no ci] - import PIL is the way to import pillow. - discord-flags isn't being used yet. - Fixed some of the linting issues. --- bot/exts/fun/color.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bot/exts/fun/color.py b/bot/exts/fun/color.py index a00a956b..dd922bf9 100644 --- a/bot/exts/fun/color.py +++ b/bot/exts/fun/color.py @@ -1,16 +1,18 @@ # imports +import colorsys import logging -import colorsys -import pillow +import PIL from discord import Embed -# ! need to install discord-flags and add to poetry.lock file -from discord.ext import commands, flags +from discord.ext import commands from rapidfuzz import process from bot.bot import Bot from bot.constants import Colours +# Planning to use discord-flags, hence require changes to poetry.lock file +# from discord.ext import flags + logger = logging.getLogger(__name__) # constants if needed -- cgit v1.2.3 From 6a692f03eface6e87dd5cdc1b1d415d52f9df148 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 5 Sep 2021 18:41:23 -0400 Subject: Move to utilities folder as recommended by Xith --- bot/exts/utilities/color.py | 115 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 bot/exts/utilities/color.py diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py new file mode 100644 index 00000000..dd922bf9 --- /dev/null +++ b/bot/exts/utilities/color.py @@ -0,0 +1,115 @@ +# imports +import colorsys +import logging + +import PIL +from discord import Embed +from discord.ext import commands +from rapidfuzz import process + +from bot.bot import Bot +from bot.constants import Colours + +# Planning to use discord-flags, hence require changes to poetry.lock file +# from discord.ext import flags + +logger = logging.getLogger(__name__) + +# constants if needed +# Color URLs - will be replaced by JSON file? +COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" +COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" +COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" + + +COLOR_ERROR = Embed( + title="Input color is not possible", + description="The color code {user_color} is not a possible color combination." + "\nThe range of possible values are: " + "\nRGB & HSV: 0-255" + "\nCMYK: 0-100%" + "\nHSL: 0-360 degrees" + "\nHex: #000000-#FFFFFF" +) +COLOR_EMBED = Embed( + title="{color_name}", + description="RGB" + "\n{RGB}" + "\nHSV" + "\n{HSV}" + "\nCMYK" + "\n{CMYK}" + "\nHSL" + "\n{HSL}" + "\nHex" + "\n{Hex}" +) + + +# define color command +class Color(commands.cog): + """User initiated command to receive color information.""" + + def __init__(self, bot: Bot): + self.bot = bot + + # ? possible to use discord-flags to allow user to decide on color + # https://pypi.org/project/discord-flags/ + # @flags.add_flag("--rgb", type=str) + # @flags.add_flag("--hsv", type=str) + # @flags.add_flag("--cmyk", type=str) + # @flags.add_flag("--hsl", type=str) + # @flags.add_flag("--hex", type=str) + # @flags.add_flag("--name", type=str) + # @flags.command() + @commands.command(aliases=["color", "colour"]) + @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) + async def color(self, ctx: commands.Context, *, user_color: str) -> None: + """Send information on input color code or color name.""" + # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name + # should we assume the color is RGB if not defined? + # should discord tags be used? + # need to review discord.py V2.0 + + # TODO code to check if color code is possible + await ctx.send(embed=COLOR_ERROR.format(color=user_color)) + # await ctx.send(embed=COLOR_EMBED.format( + # RGB=color_dict["RGB"], + # HSV=color_dict["HSV"], + # HSL=color_dict["HSL"], + # CMYK=color_dict["CMYK"], + # HSL=color_dict["HSL"], + # Hex=color_dict["Hex"], + # color_name=color_dict["color_name"] + # ).set_image() # url for image? + # ) + + # TODO pass for now + pass + + # if user_color in color_lists: + # # TODO fuzzy match for color + # pass + + async def color_converter(self, color: str, code_type: str) -> dict: + """Generate alternative color codes for use in the embed.""" + # TODO add code to take color and code type and return other types + # color_dict = { + # "RGB": color_RGB, + # "HSV": color_HSV, + # "HSL": color_HSL, + # "CMYK": color_CMYK, + # "HSL": color_HSL, + # "Hex": color_Hex, + # "color_name": color_name, + # } + pass + + async def photo_generator(self, color: str) -> None: + """Generate photo to use in embed.""" + # TODO need to find a way to store photo in cache to add to embed, then remove + + +def setup(bot: Bot) -> None: + """Load the Color Cog.""" + bot.add_cog(Color(bot)) -- cgit v1.2.3 From f9760f2680c607ede4bec14f8cb103a2ea0c302a Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 5 Sep 2021 23:07:27 -0400 Subject: Remove old files --- bot/exts/fun/color.py | 115 -------------------------------------------------- 1 file changed, 115 deletions(-) delete mode 100644 bot/exts/fun/color.py diff --git a/bot/exts/fun/color.py b/bot/exts/fun/color.py deleted file mode 100644 index dd922bf9..00000000 --- a/bot/exts/fun/color.py +++ /dev/null @@ -1,115 +0,0 @@ -# imports -import colorsys -import logging - -import PIL -from discord import Embed -from discord.ext import commands -from rapidfuzz import process - -from bot.bot import Bot -from bot.constants import Colours - -# Planning to use discord-flags, hence require changes to poetry.lock file -# from discord.ext import flags - -logger = logging.getLogger(__name__) - -# constants if needed -# Color URLs - will be replaced by JSON file? -COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" -COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" -COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" - - -COLOR_ERROR = Embed( - title="Input color is not possible", - description="The color code {user_color} is not a possible color combination." - "\nThe range of possible values are: " - "\nRGB & HSV: 0-255" - "\nCMYK: 0-100%" - "\nHSL: 0-360 degrees" - "\nHex: #000000-#FFFFFF" -) -COLOR_EMBED = Embed( - title="{color_name}", - description="RGB" - "\n{RGB}" - "\nHSV" - "\n{HSV}" - "\nCMYK" - "\n{CMYK}" - "\nHSL" - "\n{HSL}" - "\nHex" - "\n{Hex}" -) - - -# define color command -class Color(commands.cog): - """User initiated command to receive color information.""" - - def __init__(self, bot: Bot): - self.bot = bot - - # ? possible to use discord-flags to allow user to decide on color - # https://pypi.org/project/discord-flags/ - # @flags.add_flag("--rgb", type=str) - # @flags.add_flag("--hsv", type=str) - # @flags.add_flag("--cmyk", type=str) - # @flags.add_flag("--hsl", type=str) - # @flags.add_flag("--hex", type=str) - # @flags.add_flag("--name", type=str) - # @flags.command() - @commands.command(aliases=["color", "colour"]) - @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) - async def color(self, ctx: commands.Context, *, user_color: str) -> None: - """Send information on input color code or color name.""" - # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name - # should we assume the color is RGB if not defined? - # should discord tags be used? - # need to review discord.py V2.0 - - # TODO code to check if color code is possible - await ctx.send(embed=COLOR_ERROR.format(color=user_color)) - # await ctx.send(embed=COLOR_EMBED.format( - # RGB=color_dict["RGB"], - # HSV=color_dict["HSV"], - # HSL=color_dict["HSL"], - # CMYK=color_dict["CMYK"], - # HSL=color_dict["HSL"], - # Hex=color_dict["Hex"], - # color_name=color_dict["color_name"] - # ).set_image() # url for image? - # ) - - # TODO pass for now - pass - - # if user_color in color_lists: - # # TODO fuzzy match for color - # pass - - async def color_converter(self, color: str, code_type: str) -> dict: - """Generate alternative color codes for use in the embed.""" - # TODO add code to take color and code type and return other types - # color_dict = { - # "RGB": color_RGB, - # "HSV": color_HSV, - # "HSL": color_HSL, - # "CMYK": color_CMYK, - # "HSL": color_HSL, - # "Hex": color_Hex, - # "color_name": color_name, - # } - pass - - async def photo_generator(self, color: str) -> None: - """Generate photo to use in embed.""" - # TODO need to find a way to store photo in cache to add to embed, then remove - - -def setup(bot: Bot) -> None: - """Load the Color Cog.""" - bot.add_cog(Color(bot)) -- cgit v1.2.3 From f64fd14537633439e57381ddd884cb8c2aff997c Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Mon, 6 Sep 2021 20:13:17 -0400 Subject: Continue work in progress Implemented the thumbnail creation from CyberCitizen0, worked on adding some features to the program. Notable Changes: -Check if user passes in hex color -Create thumbnail based on rgb_color To-Do: -Create hex color from rgb color -Create readable rgb color from user input Co-authored-by: Mohammad Rafivulla <77384412+CyberCitizen01@users.noreply.github.com> --- bot/exts/utilities/color.py | 140 +++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 79 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index dd922bf9..1a4f7031 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,113 +1,95 @@ # imports import colorsys import logging +import re +from io import BytesIO -import PIL -from discord import Embed +from PIL import Image, ImageColor +from discord import Embed, File from discord.ext import commands from rapidfuzz import process from bot.bot import Bot from bot.constants import Colours -# Planning to use discord-flags, hence require changes to poetry.lock file -# from discord.ext import flags logger = logging.getLogger(__name__) -# constants if needed -# Color URLs - will be replaced by JSON file? -COLOR_JSON_PATH = ".bot//exts//resources//evergreen//" -COLOR_URL_XKCD = "https://xkcd.com/color/rgb/" -COLOR_URL_NAME_THAT_COLOR = "https://github.com/ryanzec/name-that-color/blob/master/lib/ntc.js#L116-L1681" - - -COLOR_ERROR = Embed( - title="Input color is not possible", - description="The color code {user_color} is not a possible color combination." - "\nThe range of possible values are: " - "\nRGB & HSV: 0-255" - "\nCMYK: 0-100%" - "\nHSL: 0-360 degrees" - "\nHex: #000000-#FFFFFF" -) -COLOR_EMBED = Embed( - title="{color_name}", - description="RGB" - "\n{RGB}" - "\nHSV" - "\n{HSV}" - "\nCMYK" - "\n{CMYK}" - "\nHSL" - "\n{HSL}" - "\nHex" - "\n{Hex}" -) + +ERROR_MSG = """The color code {user_color} is not a possible color combination. +\nThe range of possible values are: +\nRGB & HSV: 0-255 +\nCMYK: 0-100% +\nHSL: 0-360 degrees +\nHex: #000000-#FFFFFF +""" # define color command -class Color(commands.cog): +class Color(commands.Cog): """User initiated command to receive color information.""" def __init__(self, bot: Bot): self.bot = bot - # ? possible to use discord-flags to allow user to decide on color - # https://pypi.org/project/discord-flags/ - # @flags.add_flag("--rgb", type=str) - # @flags.add_flag("--hsv", type=str) - # @flags.add_flag("--cmyk", type=str) - # @flags.add_flag("--hsl", type=str) - # @flags.add_flag("--hex", type=str) - # @flags.add_flag("--name", type=str) - # @flags.command() - @commands.command(aliases=["color", "colour"]) + @commands.command(aliases=["colour"]) @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) async def color(self, ctx: commands.Context, *, user_color: str) -> None: """Send information on input color code or color name.""" # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name # should we assume the color is RGB if not defined? - # should discord tags be used? - # need to review discord.py V2.0 - - # TODO code to check if color code is possible - await ctx.send(embed=COLOR_ERROR.format(color=user_color)) - # await ctx.send(embed=COLOR_EMBED.format( - # RGB=color_dict["RGB"], - # HSV=color_dict["HSV"], - # HSL=color_dict["HSL"], - # CMYK=color_dict["CMYK"], - # HSL=color_dict["HSL"], - # Hex=color_dict["Hex"], - # color_name=color_dict["color_name"] - # ).set_image() # url for image? - # ) - - # TODO pass for now - pass + + if "#" in user_color: + logger.info(f"{user_color = }") + hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) + if hex_match: + hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) + logger.info(f"{hex_color = }") + rgb_color = ImageColor.getcolor(user_color, "RGB") + else: + await ctx.send(embed=Embed( + title="An error has occured.", + description=ERROR_MSG.format(user_color=user_color) + ) + ) + + elif "RGB" or "rgb" in user_color: + rgb_parse = user_color.split() + rgb = rgb_parse[1:].replace(", ", "") + logger.info(f"{rgb = }") + logger.info(f"{rgb[0] = }") + logger.info(f"{rgb[1] = }") + logger.info(f"{rgb[2] = }") + rgb_color = tuple(rgb) + hex_color = f"0x{int(rgb[0]):02x}{int(rgb[1]):02x}{int(rgb[2]):02x}" + + main_embed = Embed( + title=user_color, + color=hex_color, + ) + async with ctx.typing(): + file = await self._create_thumbnail_attachment(rgb_color) + main_embed.set_thumbnail(url="attachment://color.png") + + await ctx.send(file=file, embed=main_embed) + + async def _create_thumbnail_attachment(self, color: str) -> File: + """Generate a thumbnail from `color`.""" + + thumbnail = Image.new("RGB", (100, 100), color=color) + bufferedio = BytesIO() + thumbnail.save(bufferedio, format="PNG") + bufferedio.seek(0) + + file = File(bufferedio, filename="color.png") + + return file + # if user_color in color_lists: # # TODO fuzzy match for color # pass - async def color_converter(self, color: str, code_type: str) -> dict: - """Generate alternative color codes for use in the embed.""" - # TODO add code to take color and code type and return other types - # color_dict = { - # "RGB": color_RGB, - # "HSV": color_HSV, - # "HSL": color_HSL, - # "CMYK": color_CMYK, - # "HSL": color_HSL, - # "Hex": color_Hex, - # "color_name": color_name, - # } - pass - - async def photo_generator(self, color: str) -> None: - """Generate photo to use in embed.""" - # TODO need to find a way to store photo in cache to add to embed, then remove def setup(bot: Bot) -> None: -- cgit v1.2.3 From 1ee1fb10570b55561fc9b8bf42c01a5cc7e8171a Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 7 Sep 2021 07:39:21 -0400 Subject: Fixing flake8 errors, code style Still a work in progress but commenting out stub code and unused imports. List of To-Do's still applies. --- bot/exts/utilities/color.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 1a4f7031..b1a77b28 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,5 +1,5 @@ # imports -import colorsys +# import colorsys import logging import re from io import BytesIO @@ -7,10 +7,10 @@ from io import BytesIO from PIL import Image, ImageColor from discord import Embed, File from discord.ext import commands -from rapidfuzz import process +# from rapidfuzz import process from bot.bot import Bot -from bot.constants import Colours +# from bot.constants import Colours logger = logging.getLogger(__name__) @@ -46,12 +46,14 @@ class Color(commands.Cog): hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) logger.info(f"{hex_color = }") rgb_color = ImageColor.getcolor(user_color, "RGB") + logger.info(f"{rgb_color = }") else: - await ctx.send(embed=Embed( + await ctx.send( + embed=Embed( title="An error has occured.", - description=ERROR_MSG.format(user_color=user_color) - ) + description=ERROR_MSG.format(user_color=user_color), ) + ) elif "RGB" or "rgb" in user_color: rgb_parse = user_color.split() @@ -64,7 +66,7 @@ class Color(commands.Cog): hex_color = f"0x{int(rgb[0]):02x}{int(rgb[1]):02x}{int(rgb[2]):02x}" main_embed = Embed( - title=user_color, + title=user_color, # need to replace with fuzzymatch color name color=hex_color, ) async with ctx.typing(): @@ -75,7 +77,6 @@ class Color(commands.Cog): async def _create_thumbnail_attachment(self, color: str) -> File: """Generate a thumbnail from `color`.""" - thumbnail = Image.new("RGB", (100, 100), color=color) bufferedio = BytesIO() thumbnail.save(bufferedio, format="PNG") @@ -85,11 +86,8 @@ class Color(commands.Cog): return file - # if user_color in color_lists: - # # TODO fuzzy match for color - # pass - + # # fuzzy match for color def setup(bot: Bot) -> None: -- cgit v1.2.3 From 0862f56c56ebf2be46b2eb2ee66af52f5c12d70c Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 7 Sep 2021 07:48:07 -0400 Subject: Add embed fields for Hex and RGB --- bot/exts/utilities/color.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index b1a77b28..b1b423e7 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -73,6 +73,16 @@ class Color(commands.Cog): file = await self._create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") + main_embed.add_field( + name="Hex", + value=f">>Hex #{hex_color}", + inline=False, + ) + main_embed.add_field( + name="RGB", + value=f">>RGB {rgb_color}", + inline=False, + ) await ctx.send(file=file, embed=main_embed) async def _create_thumbnail_attachment(self, color: str) -> File: -- cgit v1.2.3 From a97803d05ecadf6621f943c068000f0997c4704a Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 7 Sep 2021 12:51:45 -0400 Subject: Update code to use 'mode' variable Updated the code to parse user_input depending on the color code 'mode' passed to the command. Added stub code for future color codes and embeds if mode is None or wrong code. --- bot/exts/utilities/color.py | 59 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index b1b423e7..1efacead 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -10,7 +10,7 @@ from discord.ext import commands # from rapidfuzz import process from bot.bot import Bot -# from bot.constants import Colours +from bot.constants import Colours logger = logging.getLogger(__name__) @@ -33,13 +33,12 @@ class Color(commands.Cog): self.bot = bot @commands.command(aliases=["colour"]) - @commands.cooldown(1, 10, commands.cooldowns.BucketType.user) - async def color(self, ctx: commands.Context, *, user_color: str) -> None: + async def color(self, ctx: commands.Context, mode: str, user_color: str) -> None: """Send information on input color code or color name.""" # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name # should we assume the color is RGB if not defined? - if "#" in user_color: + if mode.lower() == "hex": logger.info(f"{user_color = }") hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) if hex_match: @@ -55,15 +54,32 @@ class Color(commands.Cog): ) ) - elif "RGB" or "rgb" in user_color: - rgb_parse = user_color.split() - rgb = rgb_parse[1:].replace(", ", "") - logger.info(f"{rgb = }") - logger.info(f"{rgb[0] = }") - logger.info(f"{rgb[1] = }") - logger.info(f"{rgb[2] = }") - rgb_color = tuple(rgb) - hex_color = f"0x{int(rgb[0]):02x}{int(rgb[1]):02x}{int(rgb[2]):02x}" + elif mode.lower() == "rgb": + logger.info(f"{user_color = }") + # rgb_color = user_color + + elif mode.lower() == "hsv": + pass + elif mode.lower() == "hsl": + pass + elif mode.lower() == "cmyk": + pass + else: + # mode is either None or an invalid code + if mode is None: + no_mode_embed = Embed( + title="No 'mode' was passed, please define a color code.", + color=Colours.soft_red, + ) + await ctx.send(embed=no_mode_embed) + return + wrong_mode_embed = Embed( + title=f"The color code {mode} is not a valid option", + description="Possible modes are: Hex, RGB, HSV, HSL and CMYK.", + color=Colours.soft_red, + ) + await ctx.send(embed=wrong_mode_embed) + return main_embed = Embed( title=user_color, # need to replace with fuzzymatch color name @@ -83,6 +99,23 @@ class Color(commands.Cog): value=f">>RGB {rgb_color}", inline=False, ) + """ + main_embed.add_field( + name="HSV", + value=f">>HSV {hsv_color}", + inline=False, + ) + main_embed.add_field( + name="HSL", + value=f">>HSL {hsl_color}", + inline=False, + ) + main_embed.add_field( + name="CMYK", + value=f">>CMYK {cmyk_color}", + inline=False, + ) + """ await ctx.send(file=file, embed=main_embed) async def _create_thumbnail_attachment(self, color: str) -> File: -- cgit v1.2.3 From 815f3b56933d7a43dbc93ad357d81febf576a286 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 8 Sep 2021 10:06:47 -0400 Subject: Minor fixes --- bot/exts/utilities/color.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 1efacead..d7fff503 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,4 +1,3 @@ -# imports # import colorsys import logging import re @@ -35,16 +34,14 @@ class Color(commands.Cog): @commands.command(aliases=["colour"]) async def color(self, ctx: commands.Context, mode: str, user_color: str) -> None: """Send information on input color code or color name.""" - # need to check if user_color is RGB, HSV, CMYK, HSL, Hex or color name - # should we assume the color is RGB if not defined? - + logger.info(f"{mode = }") + logger.info(f"{user_color = }") if mode.lower() == "hex": - logger.info(f"{user_color = }") hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) if hex_match: hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) - logger.info(f"{hex_color = }") rgb_color = ImageColor.getcolor(user_color, "RGB") + logger.info(f"{hex_color = }") logger.info(f"{rgb_color = }") else: await ctx.send( @@ -53,11 +50,8 @@ class Color(commands.Cog): description=ERROR_MSG.format(user_color=user_color), ) ) - elif mode.lower() == "rgb": - logger.info(f"{user_color = }") - # rgb_color = user_color - + pass elif mode.lower() == "hsv": pass elif mode.lower() == "hsl": @@ -66,6 +60,7 @@ class Color(commands.Cog): pass else: # mode is either None or an invalid code + # need to handle whether user passes color name if mode is None: no_mode_embed = Embed( title="No 'mode' was passed, please define a color code.", -- cgit v1.2.3 From df4b672916563b8cde98e4d5e332bcb3757d3461 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 11 Sep 2021 09:11:28 -0400 Subject: Move .json file to correct folder --- bot/resources/fun/ryanzec_colours.json | 1568 -------------------------- bot/resources/utilities/ryanzec_colours.json | 1568 ++++++++++++++++++++++++++ 2 files changed, 1568 insertions(+), 1568 deletions(-) delete mode 100644 bot/resources/fun/ryanzec_colours.json create mode 100644 bot/resources/utilities/ryanzec_colours.json diff --git a/bot/resources/fun/ryanzec_colours.json b/bot/resources/fun/ryanzec_colours.json deleted file mode 100644 index 7b89f052..00000000 --- a/bot/resources/fun/ryanzec_colours.json +++ /dev/null @@ -1,1568 +0,0 @@ -{ - "Abbey": "4C4F56", - "Acadia": "1B1404", - "Acapulco": "7CB0A1", - "Aero Blue": "C9FFE5", - "Affair": "714693", - "Akaroa": "D4C4A8", - "Alabaster": "FAFAFA", - "Albescent White": "F5E9D3", - "Algae Green": "93DFB8", - "Alice Blue": "F0F8FF", - "Alizarin Crimson": "E32636", - "Allports": "0076A3", - "Almond": "EED9C4", - "Almond Frost": "907B71", - "Alpine": "AF8F2C", - "Alto": "DBDBDB", - "Aluminium": "A9ACB6", - "Amaranth": "E52B50", - "Amazon": "3B7A57", - "Amber": "FFBF00", - "Americano": "87756E", - "Amethyst": "9966CC", - "Amethyst Smoke": "A397B4", - "Amour": "F9EAF3", - "Amulet": "7B9F80", - "Anakiwa": "9DE5FF", - "Antique Brass": "C88A65", - "Antique Bronze": "704A07", - "Anzac": "E0B646", - "Apache": "DFBE6F", - "Apple": "4FA83D", - "Apple Blossom": "AF4D43", - "Apple Green": "E2F3EC", - "Apricot": "EB9373", - "Apricot Peach": "FBCEB1", - "Apricot White": "FFFEEC", - "Aqua Deep": "014B43", - "Aqua Forest": "5FA777", - "Aqua Haze": "EDF5F5", - "Aqua Island": "A1DAD7", - "Aqua Spring": "EAF9F5", - "Aqua Squeeze": "E8F5F2", - "Aquamarine": "7FFFD4", - "Aquamarine Blue": "71D9E2", - "Arapawa": "110C6C", - "Armadillo": "433E37", - "Arrowtown": "948771", - "Ash": "C6C3B5", - "Asparagus": "7BA05B", - "Asphalt": "130A06", - "Astra": "FAEAB9", - "Astral": "327DA0", - "Astronaut": "283A77", - "Astronaut Blue": "013E62", - "Athens Gray": "EEF0F3", - "Aths Special": "ECEBCE", - "Atlantis": "97CD2D", - "Atoll": "0A6F75", - "Atomic Tangerine": "FF9966", - "Au Chico": "97605D", - "Aubergine": "3B0910", - "Australian Mint": "F5FFBE", - "Avocado": "888D65", - "Axolotl": "4E6649", - "Azalea": "F7C8DA", - "Aztec": "0D1C19", - "Azure": "315BA1", - "Azure Radiance": "007FFF", - "Baby Blue": "E0FFFF", - "Bahama Blue": "026395", - "Bahia": "A5CB0C", - "Baja White": "FFF8D1", - "Bali Hai": "859FAF", - "Baltic Sea": "2A2630", - "Bamboo": "DA6304", - "Banana Mania": "FBE7B2", - "Bandicoot": "858470", - "Barberry": "DED717", - "Barley Corn": "A68B5B", - "Barley White": "FFF4CE", - "Barossa": "44012D", - "Bastille": "292130", - "Battleship Gray": "828F72", - "Bay Leaf": "7DA98D", - "Bay of Many": "273A81", - "Bazaar": "98777B", - "Bean ": "3D0C02", - "Beauty Bush": "EEC1BE", - "Beaver": "926F5B", - "Beeswax": "FEF2C7", - "Beige": "F5F5DC", - "Bermuda": "7DD8C6", - "Bermuda Gray": "6B8BA2", - "Beryl Green": "DEE5C0", - "Bianca": "FCFBF3", - "Big Stone": "162A40", - "Bilbao": "327C14", - "Biloba Flower": "B2A1EA", - "Birch": "373021", - "Bird Flower": "D4CD16", - "Biscay": "1B3162", - "Bismark": "497183", - "Bison Hide": "C1B7A4", - "Bistre": "3D2B1F", - "Bitter": "868974", - "Bitter Lemon": "CAE00D", - "Bittersweet": "FE6F5E", - "Bizarre": "EEDEDA", - "Black": "000000", - "Black Bean": "081910", - "Black Forest": "0B1304", - "Black Haze": "F6F7F7", - "Black Marlin": "3E2C1C", - "Black Olive": "242E16", - "Black Pearl": "041322", - "Black Rock": "0D0332", - "Black Rose": "67032D", - "Black Russian": "0A001C", - "Black Squeeze": "F2FAFA", - "Black White": "FFFEF6", - "Blackberry": "4D0135", - "Blackcurrant": "32293A", - "Blaze Orange": "FF6600", - "Bleach White": "FEF3D8", - "Bleached Cedar": "2C2133", - "Blizzard Blue": "A3E3ED", - "Blossom": "DCB4BC", - "Blue": "0000FF", - "Blue Bayoux": "496679", - "Blue Bell": "9999CC", - "Blue Chalk": "F1E9FF", - "Blue Charcoal": "010D1A", - "Blue Chill": "0C8990", - "Blue Diamond": "380474", - "Blue Dianne": "204852", - "Blue Gem": "2C0E8C", - "Blue Haze": "BFBED8", - "Blue Lagoon": "017987", - "Blue Marguerite": "7666C6", - "Blue Ribbon": "0066FF", - "Blue Romance": "D2F6DE", - "Blue Smoke": "748881", - "Blue Stone": "016162", - "Blue Violet": "6456B7", - "Blue Whale": "042E4C", - "Blue Zodiac": "13264D", - "Blumine": "18587A", - "Blush": "B44668", - "Blush Pink": "FF6FFF", - "Bombay": "AFB1B8", - "Bon Jour": "E5E0E1", - "Bondi Blue": "0095B6", - "Bone": "E4D1C0", - "Bordeaux": "5C0120", - "Bossanova": "4E2A5A", - "Boston Blue": "3B91B4", - "Botticelli": "C7DDE5", - "Bottle Green": "093624", - "Boulder": "7A7A7A", - "Bouquet": "AE809E", - "Bourbon": "BA6F1E", - "Bracken": "4A2A04", - "Brandy": "DEC196", - "Brandy Punch": "CD8429", - "Brandy Rose": "BB8983", - "Breaker Bay": "5DA19F", - "Brick Red": "C62D42", - "Bridal Heath": "FFFAF4", - "Bridesmaid": "FEF0EC", - "Bright Gray": "3C4151", - "Bright Green": "66FF00", - "Bright Red": "B10000", - "Bright Sun": "FED33C", - "Bright Turquoise": "08E8DE", - "Brilliant Rose": "F653A6", - "Brink Pink": "FB607F", - "Bronco": "ABA196", - "Bronze": "3F2109", - "Bronze Olive": "4E420C", - "Bronzetone": "4D400F", - "Broom": "FFEC13", - "Brown": "964B00", - "Brown Bramble": "592804", - "Brown Derby": "492615", - "Brown Pod": "401801", - "Brown Rust": "AF593E", - "Brown Tumbleweed": "37290E", - "Bubbles": "E7FEFF", - "Buccaneer": "622F30", - "Bud": "A8AE9C", - "Buddha Gold": "C1A004", - "Buff": "F0DC82", - "Bulgarian Rose": "480607", - "Bull Shot": "864D1E", - "Bunker": "0D1117", - "Bunting": "151F4C", - "Burgundy": "900020", - "Burnham": "002E20", - "Burning Orange": "FF7034", - "Burning Sand": "D99376", - "Burnt Maroon": "420303", - "Burnt Orange": "CC5500", - "Burnt Sienna": "E97451", - "Burnt Umber": "8A3324", - "Bush": "0D2E1C", - "Buttercup": "F3AD16", - "Buttered Rum": "A1750D", - "Butterfly Bush": "624E9A", - "Buttermilk": "FFF1B5", - "Buttery White": "FFFCEA", - "Cab Sav": "4D0A18", - "Cabaret": "D94972", - "Cabbage Pont": "3F4C3A", - "Cactus": "587156", - "Cadet Blue": "A9B2C3", - "Cadillac": "B04C6A", - "Cafe Royale": "6F440C", - "Calico": "E0C095", - "California": "FE9D04", - "Calypso": "31728D", - "Camarone": "00581A", - "Camelot": "893456", - "Cameo": "D9B99B", - "Camouflage": "3C3910", - "Camouflage Green": "78866B", - "Can Can": "D591A4", - "Canary": "F3FB62", - "Candlelight": "FCD917", - "Candy Corn": "FBEC5D", - "Cannon Black": "251706", - "Cannon Pink": "894367", - "Cape Cod": "3C4443", - "Cape Honey": "FEE5AC", - "Cape Palliser": "A26645", - "Caper": "DCEDB4", - "Caramel": "FFDDAF", - "Cararra": "EEEEE8", - "Cardin Green": "01361C", - "Cardinal": "C41E3A", - "Cardinal Pink": "8C055E", - "Careys Pink": "D29EAA", - "Caribbean Green": "00CC99", - "Carissma": "EA88A8", - "Carla": "F3FFD8", - "Carmine": "960018", - "Carnaby Tan": "5C2E01", - "Carnation": "F95A61", - "Carnation Pink": "FFA6C9", - "Carousel Pink": "F9E0ED", - "Carrot Orange": "ED9121", - "Casablanca": "F8B853", - "Casal": "2F6168", - "Cascade": "8BA9A5", - "Cashmere": "E6BEA5", - "Casper": "ADBED1", - "Castro": "52001F", - "Catalina Blue": "062A78", - "Catskill White": "EEF6F7", - "Cavern Pink": "E3BEBE", - "Cedar": "3E1C14", - "Cedar Wood Finish": "711A00", - "Celadon": "ACE1AF", - "Celery": "B8C25D", - "Celeste": "D1D2CA", - "Cello": "1E385B", - "Celtic": "163222", - "Cement": "8D7662", - "Ceramic": "FCFFF9", - "Cerise": "DA3287", - "Cerise Red": "DE3163", - "Cerulean": "02A4D3", - "Cerulean Blue": "2A52BE", - "Chablis": "FFF4F3", - "Chalet Green": "516E3D", - "Chalky": "EED794", - "Chambray": "354E8C", - "Chamois": "EDDCB1", - "Champagne": "FAECCC", - "Chantilly": "F8C3DF", - "Charade": "292937", - "Chardon": "FFF3F1", - "Chardonnay": "FFCD8C", - "Charlotte": "BAEEF9", - "Charm": "D47494", - "Chartreuse": "7FFF00", - "Chartreuse Yellow": "DFFF00", - "Chateau Green": "40A860", - "Chatelle": "BDB3C7", - "Chathams Blue": "175579", - "Chelsea Cucumber": "83AA5D", - "Chelsea Gem": "9E5302", - "Chenin": "DFCD6F", - "Cherokee": "FCDA98", - "Cherry Pie": "2A0359", - "Cherrywood": "651A14", - "Cherub": "F8D9E9", - "Chestnut": "B94E48", - "Chestnut Rose": "CD5C5C", - "Chetwode Blue": "8581D9", - "Chicago": "5D5C58", - "Chiffon": "F1FFC8", - "Chilean Fire": "F77703", - "Chilean Heath": "FFFDE6", - "China Ivory": "FCFFE7", - "Chino": "CEC7A7", - "Chinook": "A8E3BD", - "Chocolate": "370202", - "Christalle": "33036B", - "Christi": "67A712", - "Christine": "E7730A", - "Chrome White": "E8F1D4", - "Cinder": "0E0E18", - "Cinderella": "FDE1DC", - "Cinnabar": "E34234", - "Cinnamon": "7B3F00", - "Cioccolato": "55280C", - "Citrine White": "FAF7D6", - "Citron": "9EA91F", - "Citrus": "A1C50A", - "Clairvoyant": "480656", - "Clam Shell": "D4B6AF", - "Claret": "7F1734", - "Classic Rose": "FBCCE7", - "Clay Ash": "BDC8B3", - "Clay Creek": "8A8360", - "Clear Day": "E9FFFD", - "Clementine": "E96E00", - "Clinker": "371D09", - "Cloud": "C7C4BF", - "Cloud Burst": "202E54", - "Cloudy": "ACA59F", - "Clover": "384910", - "Cobalt": "0047AB", - "Cocoa Bean": "481C1C", - "Cocoa Brown": "301F1E", - "Coconut Cream": "F8F7DC", - "Cod Gray": "0B0B0B", - "Coffee": "706555", - "Coffee Bean": "2A140E", - "Cognac": "9F381D", - "Cola": "3F2500", - "Cold Purple": "ABA0D9", - "Cold Turkey": "CEBABA", - "Colonial White": "FFEDBC", - "Comet": "5C5D75", - "Como": "517C66", - "Conch": "C9D9D2", - "Concord": "7C7B7A", - "Concrete": "F2F2F2", - "Confetti": "E9D75A", - "Congo Brown": "593737", - "Congress Blue": "02478E", - "Conifer": "ACDD4D", - "Contessa": "C6726B", - "Copper": "B87333", - "Copper Canyon": "7E3A15", - "Copper Rose": "996666", - "Copper Rust": "944747", - "Copperfield": "DA8A67", - "Coral": "FF7F50", - "Coral Red": "FF4040", - "Coral Reef": "C7BCA2", - "Coral Tree": "A86B6B", - "Corduroy": "606E68", - "Coriander": "C4D0B0", - "Cork": "40291D", - "Corn": "E7BF05", - "Corn Field": "F8FACD", - "Corn Harvest": "8B6B0B", - "Cornflower": "93CCEA", - "Cornflower Blue": "6495ED", - "Cornflower Lilac": "FFB0AC", - "Corvette": "FAD3A2", - "Cosmic": "76395D", - "Cosmos": "FFD8D9", - "Costa Del Sol": "615D30", - "Cotton Candy": "FFB7D5", - "Cotton Seed": "C2BDB6", - "County Green": "01371A", - "Cowboy": "4D282D", - "Crail": "B95140", - "Cranberry": "DB5079", - "Crater Brown": "462425", - "Cream": "FFFDD0", - "Cream Brulee": "FFE5A0", - "Cream Can": "F5C85C", - "Creole": "1E0F04", - "Crete": "737829", - "Crimson": "DC143C", - "Crocodile": "736D58", - "Crown of Thorns": "771F1F", - "Crowshead": "1C1208", - "Cruise": "B5ECDF", - "Crusoe": "004816", - "Crusta": "FD7B33", - "Cumin": "924321", - "Cumulus": "FDFFD5", - "Cupid": "FBBEDA", - "Curious Blue": "2596D1", - "Cutty Sark": "507672", - "Cyan / Aqua": "00FFFF", - "Cyprus": "003E40", - "Daintree": "012731", - "Dairy Cream": "F9E4BC", - "Daisy Bush": "4F2398", - "Dallas": "6E4B26", - "Dandelion": "FED85D", - "Danube": "6093D1", - "Dark Blue": "0000C8", - "Dark Burgundy": "770F05", - "Dark Ebony": "3C2005", - "Dark Fern": "0A480D", - "Dark Tan": "661010", - "Dawn": "A6A29A", - "Dawn Pink": "F3E9E5", - "De York": "7AC488", - "Deco": "D2DA97", - "Deep Blue": "220878", - "Deep Blush": "E47698", - "Deep Bronze": "4A3004", - "Deep Cerulean": "007BA7", - "Deep Cove": "051040", - "Deep Fir": "002900", - "Deep Forest Green": "182D09", - "Deep Koamaru": "1B127B", - "Deep Oak": "412010", - "Deep Sapphire": "082567", - "Deep Sea": "01826B", - "Deep Sea Green": "095859", - "Deep Teal": "003532", - "Del Rio": "B09A95", - "Dell": "396413", - "Delta": "A4A49D", - "Deluge": "7563A8", - "Denim": "1560BD", - "Derby": "FFEED8", - "Desert": "AE6020", - "Desert Sand": "EDC9AF", - "Desert Storm": "F8F8F7", - "Dew": "EAFFFE", - "Di Serria": "DB995E", - "Diesel": "130000", - "Dingley": "5D7747", - "Disco": "871550", - "Dixie": "E29418", - "Dodger Blue": "1E90FF", - "Dolly": "F9FF8B", - "Dolphin": "646077", - "Domino": "8E775E", - "Don Juan": "5D4C51", - "Donkey Brown": "A69279", - "Dorado": "6B5755", - "Double Colonial White": "EEE3AD", - "Double Pearl Lusta": "FCF4D0", - "Double Spanish White": "E6D7B9", - "Dove Gray": "6D6C6C", - "Downriver": "092256", - "Downy": "6FD0C5", - "Driftwood": "AF8751", - "Drover": "FDF7AD", - "Dull Lavender": "A899E6", - "Dune": "383533", - "Dust Storm": "E5CCC9", - "Dusty Gray": "A8989B", - "Eagle": "B6BAA4", - "Earls Green": "C9B93B", - "Early Dawn": "FFF9E6", - "East Bay": "414C7D", - "East Side": "AC91CE", - "Eastern Blue": "1E9AB0", - "Ebb": "E9E3E3", - "Ebony": "0C0B1D", - "Ebony Clay": "26283B", - "Eclipse": "311C17", - "Ecru White": "F5F3E5", - "Ecstasy": "FA7814", - "Eden": "105852", - "Edgewater": "C8E3D7", - "Edward": "A2AEAB", - "Egg Sour": "FFF4DD", - "Egg White": "FFEFC1", - "Eggplant": "614051", - "El Paso": "1E1708", - "El Salva": "8F3E33", - "Electric Lime": "CCFF00", - "Electric Violet": "8B00FF", - "Elephant": "123447", - "Elf Green": "088370", - "Elm": "1C7C7D", - "Emerald": "50C878", - "Eminence": "6C3082", - "Emperor": "514649", - "Empress": "817377", - "Endeavour": "0056A7", - "Energy Yellow": "F8DD5C", - "English Holly": "022D15", - "English Walnut": "3E2B23", - "Envy": "8BA690", - "Equator": "E1BC64", - "Espresso": "612718", - "Eternity": "211A0E", - "Eucalyptus": "278A5B", - "Eunry": "CFA39D", - "Evening Sea": "024E46", - "Everglade": "1C402E", - "Faded Jade": "427977", - "Fair Pink": "FFEFEC", - "Falcon": "7F626D", - "Fall Green": "ECEBBD", - "Falu Red": "801818", - "Fantasy": "FAF3F0", - "Fedora": "796A78", - "Feijoa": "9FDD8C", - "Fern": "63B76C", - "Fern Frond": "657220", - "Fern Green": "4F7942", - "Ferra": "704F50", - "Festival": "FBE96C", - "Feta": "F0FCEA", - "Fiery Orange": "B35213", - "Finch": "626649", - "Finlandia": "556D56", - "Finn": "692D54", - "Fiord": "405169", - "Fire": "AA4203", - "Fire Bush": "E89928", - "Firefly": "0E2A30", - "Flame Pea": "DA5B38", - "Flamenco": "FF7D07", - "Flamingo": "F2552A", - "Flax": "EEDC82", - "Flax Smoke": "7B8265", - "Flesh": "FFCBA4", - "Flint": "6F6A61", - "Flirt": "A2006D", - "Flush Mahogany": "CA3435", - "Flush Orange": "FF7F00", - "Foam": "D8FCFA", - "Fog": "D7D0FF", - "Foggy Gray": "CBCAB6", - "Forest Green": "228B22", - "Forget Me Not": "FFF1EE", - "Fountain Blue": "56B4BE", - "Frangipani": "FFDEB3", - "French Gray": "BDBDC6", - "French Lilac": "ECC7EE", - "French Pass": "BDEDFD", - "French Rose": "F64A8A", - "Fresh Eggplant": "990066", - "Friar Gray": "807E79", - "Fringy Flower": "B1E2C1", - "Froly": "F57584", - "Frost": "EDF5DD", - "Frosted Mint": "DBFFF8", - "Frostee": "E4F6E7", - "Fruit Salad": "4F9D5D", - "Fuchsia Blue": "7A58C1", - "Fuchsia Pink": "C154C1", - "Fuego": "BEDE0D", - "Fuel Yellow": "ECA927", - "Fun Blue": "1959A8", - "Fun Green": "016D39", - "Fuscous Gray": "54534D", - "Fuzzy Wuzzy Brown": "C45655", - "Gable Green": "163531", - "Gallery": "EFEFEF", - "Galliano": "DCB20C", - "Gamboge": "E49B0F", - "Geebung": "D18F1B", - "Genoa": "15736B", - "Geraldine": "FB8989", - "Geyser": "D4DFE2", - "Ghost": "C7C9D5", - "Gigas": "523C94", - "Gimblet": "B8B56A", - "Gin": "E8F2EB", - "Gin Fizz": "FFF9E2", - "Givry": "F8E4BF", - "Glacier": "80B3C4", - "Glade Green": "61845F", - "Go Ben": "726D4E", - "Goblin": "3D7D52", - "Gold": "FFD700", - "Gold Drop": "F18200", - "Gold Sand": "E6BE8A", - "Gold Tips": "DEBA13", - "Golden Bell": "E28913", - "Golden Dream": "F0D52D", - "Golden Fizz": "F5FB3D", - "Golden Glow": "FDE295", - "Golden Grass": "DAA520", - "Golden Sand": "F0DB7D", - "Golden Tainoi": "FFCC5C", - "Goldenrod": "FCD667", - "Gondola": "261414", - "Gordons Green": "0B1107", - "Gorse": "FFF14F", - "Gossamer": "069B81", - "Gossip": "D2F8B0", - "Gothic": "6D92A1", - "Governor Bay": "2F3CB3", - "Grain Brown": "E4D5B7", - "Grandis": "FFD38C", - "Granite Green": "8D8974", - "Granny Apple": "D5F6E3", - "Granny Smith": "84A0A0", - "Granny Smith Apple": "9DE093", - "Grape": "381A51", - "Graphite": "251607", - "Gravel": "4A444B", - "Gray": "808080", - "Gray Asparagus": "465945", - "Gray Chateau": "A2AAB3", - "Gray Nickel": "C3C3BD", - "Gray Nurse": "E7ECE6", - "Gray Olive": "A9A491", - "Gray Suit": "C1BECD", - "Green": "00FF00", - "Green Haze": "01A368", - "Green House": "24500F", - "Green Kelp": "25311C", - "Green Leaf": "436A0D", - "Green Mist": "CBD3B0", - "Green Pea": "1D6142", - "Green Smoke": "A4AF6E", - "Green Spring": "B8C1B1", - "Green Vogue": "032B52", - "Green Waterloo": "101405", - "Green White": "E8EBE0", - "Green Yellow": "ADFF2F", - "Grenadier": "D54600", - "Guardsman Red": "BA0101", - "Gulf Blue": "051657", - "Gulf Stream": "80B3AE", - "Gull Gray": "9DACB7", - "Gum Leaf": "B6D3BF", - "Gumbo": "7CA1A6", - "Gun Powder": "414257", - "Gunsmoke": "828685", - "Gurkha": "9A9577", - "Hacienda": "98811B", - "Hairy Heath": "6B2A14", - "Haiti": "1B1035", - "Half Baked": "85C4CC", - "Half Colonial White": "FDF6D3", - "Half Dutch White": "FEF7DE", - "Half Spanish White": "FEF4DB", - "Half and Half": "FFFEE1", - "Hampton": "E5D8AF", - "Harlequin": "3FFF00", - "Harp": "E6F2EA", - "Harvest Gold": "E0B974", - "Havelock Blue": "5590D9", - "Hawaiian Tan": "9D5616", - "Hawkes Blue": "D4E2FC", - "Heath": "541012", - "Heather": "B7C3D0", - "Heathered Gray": "B6B095", - "Heavy Metal": "2B3228", - "Heliotrope": "DF73FF", - "Hemlock": "5E5D3B", - "Hemp": "907874", - "Hibiscus": "B6316C", - "Highland": "6F8E63", - "Hillary": "ACA586", - "Himalaya": "6A5D1B", - "Hint of Green": "E6FFE9", - "Hint of Red": "FBF9F9", - "Hint of Yellow": "FAFDE4", - "Hippie Blue": "589AAF", - "Hippie Green": "53824B", - "Hippie Pink": "AE4560", - "Hit Gray": "A1ADB5", - "Hit Pink": "FFAB81", - "Hokey Pokey": "C8A528", - "Hoki": "65869F", - "Holly": "011D13", - "Hollywood Cerise": "F400A1", - "Honey Flower": "4F1C70", - "Honeysuckle": "EDFC84", - "Hopbush": "D06DA1", - "Horizon": "5A87A0", - "Horses Neck": "604913", - "Hot Cinnamon": "D2691E", - "Hot Pink": "FF69B4", - "Hot Toddy": "B38007", - "Humming Bird": "CFF9F3", - "Hunter Green": "161D10", - "Hurricane": "877C7B", - "Husk": "B7A458", - "Ice Cold": "B1F4E7", - "Iceberg": "DAF4F0", - "Illusion": "F6A4C9", - "Inch Worm": "B0E313", - "Indian Khaki": "C3B091", - "Indian Tan": "4D1E01", - "Indigo": "4F69C6", - "Indochine": "C26B03", - "International Klein Blue": "002FA7", - "International Orange": "FF4F00", - "Irish Coffee": "5F3D26", - "Iroko": "433120", - "Iron": "D4D7D9", - "Ironside Gray": "676662", - "Ironstone": "86483C", - "Island Spice": "FFFCEE", - "Ivory": "FFFFF0", - "Jacaranda": "2E0329", - "Jacarta": "3A2A6A", - "Jacko Bean": "2E1905", - "Jacksons Purple": "20208D", - "Jade": "00A86B", - "Jaffa": "EF863F", - "Jagged Ice": "C2E8E5", - "Jagger": "350E57", - "Jaguar": "080110", - "Jambalaya": "5B3013", - "Janna": "F4EBD3", - "Japanese Laurel": "0A6906", - "Japanese Maple": "780109", - "Japonica": "D87C63", - "Java": "1FC2C2", - "Jazzberry Jam": "A50B5E", - "Jelly Bean": "297B9A", - "Jet Stream": "B5D2CE", - "Jewel": "126B40", - "Jon": "3B1F1F", - "Jonquil": "EEFF9A", - "Jordy Blue": "8AB9F1", - "Judge Gray": "544333", - "Jumbo": "7C7B82", - "Jungle Green": "29AB87", - "Jungle Mist": "B4CFD3", - "Juniper": "6D9292", - "Just Right": "ECCDB9", - "Kabul": "5E483E", - "Kaitoke Green": "004620", - "Kangaroo": "C6C8BD", - "Karaka": "1E1609", - "Karry": "FFEAD4", - "Kashmir Blue": "507096", - "Kelp": "454936", - "Kenyan Copper": "7C1C05", - "Keppel": "3AB09E", - "Key Lime Pie": "BFC921", - "Khaki": "F0E68C", - "Kidnapper": "E1EAD4", - "Kilamanjaro": "240C02", - "Killarney": "3A6A47", - "Kimberly": "736C9F", - "Kingfisher Daisy": "3E0480", - "Kobi": "E79FC4", - "Kokoda": "6E6D57", - "Korma": "8F4B0E", - "Koromiko": "FFBD5F", - "Kournikova": "FFE772", - "Kumera": "886221", - "La Palma": "368716", - "La Rioja": "B3C110", - "Las Palmas": "C6E610", - "Laser": "C8B568", - "Laser Lemon": "FFFF66", - "Laurel": "749378", - "Lavender": "B57EDC", - "Lavender Gray": "BDBBD7", - "Lavender Magenta": "EE82EE", - "Lavender Pink": "FBAED2", - "Lavender Purple": "967BB6", - "Lavender Rose": "FBA0E3", - "Lavender blush": "FFF0F5", - "Leather": "967059", - "Lemon": "FDE910", - "Lemon Chiffon": "FFFACD", - "Lemon Ginger": "AC9E22", - "Lemon Grass": "9B9E8F", - "Light Apricot": "FDD5B1", - "Light Orchid": "E29CD2", - "Light Wisteria": "C9A0DC", - "Lightning Yellow": "FCC01E", - "Lilac": "C8A2C8", - "Lilac Bush": "9874D3", - "Lily": "C8AABF", - "Lily White": "E7F8FF", - "Lima": "76BD17", - "Lime": "BFFF00", - "Limeade": "6F9D02", - "Limed Ash": "747D63", - "Limed Oak": "AC8A56", - "Limed Spruce": "394851", - "Linen": "FAF0E6", - "Link Water": "D9E4F5", - "Lipstick": "AB0563", - "Lisbon Brown": "423921", - "Livid Brown": "4D282E", - "Loafer": "EEF4DE", - "Loblolly": "BDC9CE", - "Lochinvar": "2C8C84", - "Lochmara": "007EC7", - "Locust": "A8AF8E", - "Log Cabin": "242A1D", - "Logan": "AAA9CD", - "Lola": "DFCFDB", - "London Hue": "BEA6C3", - "Lonestar": "6D0101", - "Lotus": "863C3C", - "Loulou": "460B41", - "Lucky": "AF9F1C", - "Lucky Point": "1A1A68", - "Lunar Green": "3C493A", - "Luxor Gold": "A7882C", - "Lynch": "697E9A", - "Mabel": "D9F7FF", - "Macaroni and Cheese": "FFB97B", - "Madang": "B7F0BE", - "Madison": "09255D", - "Madras": "3F3002", - "Magenta / Fuchsia": "FF00FF", - "Magic Mint": "AAF0D1", - "Magnolia": "F8F4FF", - "Mahogany": "4E0606", - "Mai Tai": "B06608", - "Maize": "F5D5A0", - "Makara": "897D6D", - "Mako": "444954", - "Malachite": "0BDA51", - "Malibu": "7DC8F7", - "Mallard": "233418", - "Malta": "BDB2A1", - "Mamba": "8E8190", - "Manatee": "8D90A1", - "Mandalay": "AD781B", - "Mandy": "E25465", - "Mandys Pink": "F2C3B2", - "Mango Tango": "E77200", - "Manhattan": "F5C999", - "Mantis": "74C365", - "Mantle": "8B9C90", - "Manz": "EEEF78", - "Mardi Gras": "350036", - "Marigold": "B98D28", - "Marigold Yellow": "FBE870", - "Mariner": "286ACD", - "Maroon": "800000", - "Maroon Flush": "C32148", - "Maroon Oak": "520C17", - "Marshland": "0B0F08", - "Martini": "AFA09E", - "Martinique": "363050", - "Marzipan": "F8DB9D", - "Masala": "403B38", - "Matisse": "1B659D", - "Matrix": "B05D54", - "Matterhorn": "4E3B41", - "Mauve": "E0B0FF", - "Mauvelous": "F091A9", - "Maverick": "D8C2D5", - "Medium Carmine": "AF4035", - "Medium Purple": "9370DB", - "Medium Red Violet": "BB3385", - "Melanie": "E4C2D5", - "Melanzane": "300529", - "Melon": "FEBAAD", - "Melrose": "C7C1FF", - "Mercury": "E5E5E5", - "Merino": "F6F0E6", - "Merlin": "413C37", - "Merlot": "831923", - "Metallic Bronze": "49371B", - "Metallic Copper": "71291D", - "Meteor": "D07D12", - "Meteorite": "3C1F76", - "Mexican Red": "A72525", - "Mid Gray": "5F5F6E", - "Midnight": "011635", - "Midnight Blue": "003366", - "Midnight Moss": "041004", - "Mikado": "2D2510", - "Milan": "FAFFA4", - "Milano Red": "B81104", - "Milk Punch": "FFF6D4", - "Millbrook": "594433", - "Mimosa": "F8FDD3", - "Mindaro": "E3F988", - "Mine Shaft": "323232", - "Mineral Green": "3F5D53", - "Ming": "36747D", - "Minsk": "3F307F", - "Mint Green": "98FF98", - "Mint Julep": "F1EEC1", - "Mint Tulip": "C4F4EB", - "Mirage": "161928", - "Mischka": "D1D2DD", - "Mist Gray": "C4C4BC", - "Mobster": "7F7589", - "Moccaccino": "6E1D14", - "Mocha": "782D19", - "Mojo": "C04737", - "Mona Lisa": "FFA194", - "Monarch": "8B0723", - "Mondo": "4A3C30", - "Mongoose": "B5A27F", - "Monsoon": "8A8389", - "Monte Carlo": "83D0C6", - "Monza": "C7031E", - "Moody Blue": "7F76D3", - "Moon Glow": "FCFEDA", - "Moon Mist": "DCDDCC", - "Moon Raker": "D6CEF6", - "Morning Glory": "9EDEE0", - "Morocco Brown": "441D00", - "Mortar": "504351", - "Mosque": "036A6E", - "Moss Green": "ADDFAD", - "Mountain Meadow": "1AB385", - "Mountain Mist": "959396", - "Mountbatten Pink": "997A8D", - "Muddy Waters": "B78E5C", - "Muesli": "AA8B5B", - "Mulberry": "C54B8C", - "Mulberry Wood": "5C0536", - "Mule Fawn": "8C472F", - "Mulled Wine": "4E4562", - "Mustard": "FFDB58", - "My Pink": "D69188", - "My Sin": "FFB31F", - "Mystic": "E2EBED", - "Nandor": "4B5D52", - "Napa": "ACA494", - "Narvik": "EDF9F1", - "Natural Gray": "8B8680", - "Navajo White": "FFDEAD", - "Navy Blue": "000080", - "Nebula": "CBDBD6", - "Negroni": "FFE2C5", - "Neon Carrot": "FF9933", - "Nepal": "8EABC1", - "Neptune": "7CB7BB", - "Nero": "140600", - "Nevada": "646E75", - "New Orleans": "F3D69D", - "New York Pink": "D7837F", - "Niagara": "06A189", - "Night Rider": "1F120F", - "Night Shadz": "AA375A", - "Nile Blue": "193751", - "Nobel": "B7B1B1", - "Nomad": "BAB1A2", - "Norway": "A8BD9F", - "Nugget": "C59922", - "Nutmeg": "81422C", - "Nutmeg Wood Finish": "683600", - "Oasis": "FEEFCE", - "Observatory": "02866F", - "Ocean Green": "41AA78", - "Ochre": "CC7722", - "Off Green": "E6F8F3", - "Off Yellow": "FEF9E3", - "Oil": "281E15", - "Old Brick": "901E1E", - "Old Copper": "724A2F", - "Old Gold": "CFB53B", - "Old Lace": "FDF5E6", - "Old Lavender": "796878", - "Old Rose": "C08081", - "Olive": "808000", - "Olive Drab": "6B8E23", - "Olive Green": "B5B35C", - "Olive Haze": "8B8470", - "Olivetone": "716E10", - "Olivine": "9AB973", - "Onahau": "CDF4FF", - "Onion": "2F270E", - "Opal": "A9C6C2", - "Opium": "8E6F70", - "Oracle": "377475", - "Orange": "FF681F", - "Orange Peel": "FFA000", - "Orange Roughy": "C45719", - "Orange White": "FEFCED", - "Orchid": "DA70D6", - "Orchid White": "FFFDF3", - "Oregon": "9B4703", - "Orient": "015E85", - "Oriental Pink": "C69191", - "Orinoco": "F3FBD4", - "Oslo Gray": "878D91", - "Ottoman": "E9F8ED", - "Outer Space": "2D383A", - "Outrageous Orange": "FF6037", - "Oxford Blue": "384555", - "Oxley": "779E86", - "Oyster Bay": "DAFAFF", - "Oyster Pink": "E9CECD", - "Paarl": "A65529", - "Pablo": "776F61", - "Pacific Blue": "009DC4", - "Pacifika": "778120", - "Paco": "411F10", - "Padua": "ADE6C4", - "Pale Canary": "FFFF99", - "Pale Leaf": "C0D3B9", - "Pale Oyster": "988D77", - "Pale Prim": "FDFEB8", - "Pale Rose": "FFE1F2", - "Pale Sky": "6E7783", - "Pale Slate": "C3BFC1", - "Palm Green": "09230F", - "Palm Leaf": "19330E", - "Pampas": "F4F2EE", - "Panache": "EAF6EE", - "Pancho": "EDCDAB", - "Papaya Whip": "FFEFD5", - "Paprika": "8D0226", - "Paradiso": "317D82", - "Parchment": "F1E9D2", - "Paris Daisy": "FFF46E", - "Paris M": "26056A", - "Paris White": "CADCD4", - "Parsley": "134F19", - "Pastel Green": "77DD77", - "Pastel Pink": "FFD1DC", - "Patina": "639A8F", - "Pattens Blue": "DEF5FF", - "Paua": "260368", - "Pavlova": "D7C498", - "Peach": "FFE5B4", - "Peach Cream": "FFF0DB", - "Peach Orange": "FFCC99", - "Peach Schnapps": "FFDCD6", - "Peach Yellow": "FADFAD", - "Peanut": "782F16", - "Pear": "D1E231", - "Pearl Bush": "E8E0D5", - "Pearl Lusta": "FCF4DC", - "Peat": "716B56", - "Pelorous": "3EABBF", - "Peppermint": "E3F5E1", - "Perano": "A9BEF2", - "Perfume": "D0BEF8", - "Periglacial Blue": "E1E6D6", - "Periwinkle": "CCCCFF", - "Periwinkle Gray": "C3CDE6", - "Persian Blue": "1C39BB", - "Persian Green": "00A693", - "Persian Indigo": "32127A", - "Persian Pink": "F77FBE", - "Persian Plum": "701C1C", - "Persian Red": "CC3333", - "Persian Rose": "FE28A2", - "Persimmon": "FF6B53", - "Peru Tan": "7F3A02", - "Pesto": "7C7631", - "Petite Orchid": "DB9690", - "Pewter": "96A8A1", - "Pharlap": "A3807B", - "Picasso": "FFF39D", - "Pickled Bean": "6E4826", - "Pickled Bluewood": "314459", - "Picton Blue": "45B1E8", - "Pig Pink": "FDD7E4", - "Pigeon Post": "AFBDD9", - "Pigment Indigo": "4B0082", - "Pine Cone": "6D5E54", - "Pine Glade": "C7CD90", - "Pine Green": "01796F", - "Pine Tree": "171F04", - "Pink": "FFC0CB", - "Pink Flamingo": "FF66FF", - "Pink Flare": "E1C0C8", - "Pink Lace": "FFDDF4", - "Pink Lady": "FFF1D8", - "Pink Salmon": "FF91A4", - "Pink Swan": "BEB5B7", - "Piper": "C96323", - "Pipi": "FEF4CC", - "Pippin": "FFE1DF", - "Pirate Gold": "BA7F03", - "Pistachio": "9DC209", - "Pixie Green": "C0D8B6", - "Pizazz": "FF9000", - "Pizza": "C99415", - "Plantation": "27504B", - "Plum": "843179", - "Pohutukawa": "8F021C", - "Polar": "E5F9F6", - "Polo Blue": "8DA8CC", - "Pomegranate": "F34723", - "Pompadour": "660045", - "Porcelain": "EFF2F3", - "Porsche": "EAAE69", - "Port Gore": "251F4F", - "Portafino": "FFFFB4", - "Portage": "8B9FEE", - "Portica": "F9E663", - "Pot Pourri": "F5E7E2", - "Potters Clay": "8C5738", - "Powder Ash": "BCC9C2", - "Powder Blue": "B0E0E6", - "Prairie Sand": "9A3820", - "Prelude": "D0C0E5", - "Prim": "F0E2EC", - "Primrose": "EDEA99", - "Provincial Pink": "FEF5F1", - "Prussian Blue": "003153", - "Puce": "CC8899", - "Pueblo": "7D2C14", - "Puerto Rico": "3FC1AA", - "Pumice": "C2CAC4", - "Pumpkin": "FF7518", - "Pumpkin Skin": "B1610B", - "Punch": "DC4333", - "Punga": "4D3D14", - "Purple": "660099", - "Purple Heart": "652DC1", - "Purple Mountain's Majesty": "9678B6", - "Purple Pizzazz": "FF00CC", - "Putty": "E7CD8C", - "Quarter Pearl Lusta": "FFFDF4", - "Quarter Spanish White": "F7F2E1", - "Quicksand": "BD978E", - "Quill Gray": "D6D6D1", - "Quincy": "623F2D", - "Racing Green": "0C1911", - "Radical Red": "FF355E", - "Raffia": "EADAB8", - "Rainee": "B9C8AC", - "Rajah": "F7B668", - "Rangitoto": "2E3222", - "Rangoon Green": "1C1E13", - "Raven": "727B89", - "Raw Sienna": "D27D46", - "Raw Umber": "734A12", - "Razzle Dazzle Rose": "FF33CC", - "Razzmatazz": "E30B5C", - "Rebel": "3C1206", - "Red": "FF0000", - "Red Beech": "7B3801", - "Red Berry": "8E0000", - "Red Damask": "DA6A41", - "Red Devil": "860111", - "Red Orange": "FF3F34", - "Red Oxide": "6E0902", - "Red Ribbon": "ED0A3F", - "Red Robin": "80341F", - "Red Stage": "D05F04", - "Red Violet": "C71585", - "Redwood": "5D1E0F", - "Reef": "C9FFA2", - "Reef Gold": "9F821C", - "Regal Blue": "013F6A", - "Regent Gray": "86949F", - "Regent St Blue": "AAD6E6", - "Remy": "FEEBF3", - "Reno Sand": "A86515", - "Resolution Blue": "002387", - "Revolver": "2C1632", - "Rhino": "2E3F62", - "Rice Cake": "FFFEF0", - "Rice Flower": "EEFFE2", - "Rich Gold": "A85307", - "Rio Grande": "BBD009", - "Ripe Lemon": "F4D81C", - "Ripe Plum": "410056", - "Riptide": "8BE6D8", - "River Bed": "434C59", - "Rob Roy": "EAC674", - "Robin's Egg Blue": "00CCCC", - "Rock": "4D3833", - "Rock Blue": "9EB1CD", - "Rock Spray": "BA450C", - "Rodeo Dust": "C9B29B", - "Rolling Stone": "747D83", - "Roman": "DE6360", - "Roman Coffee": "795D4C", - "Romance": "FFFEFD", - "Romantic": "FFD2B7", - "Ronchi": "ECC54E", - "Roof Terracotta": "A62F20", - "Rope": "8E4D1E", - "Rose": "FF007F", - "Rose Bud": "FBB2A3", - "Rose Bud Cherry": "800B47", - "Rose Fog": "E7BCB4", - "Rose White": "FFF6F5", - "Rose of Sharon": "BF5500", - "Rosewood": "65000B", - "Roti": "C6A84B", - "Rouge": "A23B6C", - "Royal Blue": "4169E1", - "Royal Heath": "AB3472", - "Royal Purple": "6B3FA0", - "Rum": "796989", - "Rum Swizzle": "F9F8E4", - "Russet": "80461B", - "Russett": "755A57", - "Rust": "B7410E", - "Rustic Red": "480404", - "Rusty Nail": "86560A", - "Saddle": "4C3024", - "Saddle Brown": "583401", - "Saffron": "F4C430", - "Saffron Mango": "F9BF58", - "Sage": "9EA587", - "Sahara": "B7A214", - "Sahara Sand": "F1E788", - "Sail": "B8E0F9", - "Salem": "097F4B", - "Salmon": "FF8C69", - "Salomie": "FEDB8D", - "Salt Box": "685E6E", - "Saltpan": "F1F7F2", - "Sambuca": "3A2010", - "San Felix": "0B6207", - "San Juan": "304B6A", - "San Marino": "456CAC", - "Sand Dune": "826F65", - "Sandal": "AA8D6F", - "Sandrift": "AB917A", - "Sandstone": "796D62", - "Sandwisp": "F5E7A2", - "Sandy Beach": "FFEAC8", - "Sandy brown": "F4A460", - "Sangria": "92000A", - "Sanguine Brown": "8D3D38", - "Santa Fe": "B16D52", - "Santas Gray": "9FA0B1", - "Sapling": "DED4A4", - "Sapphire": "2F519E", - "Saratoga": "555B10", - "Satin Linen": "E6E4D4", - "Sauvignon": "FFF5F3", - "Sazerac": "FFF4E0", - "Scampi": "675FA6", - "Scandal": "CFFAF4", - "Scarlet": "FF2400", - "Scarlet Gum": "431560", - "Scarlett": "950015", - "Scarpa Flow": "585562", - "Schist": "A9B497", - "School bus Yellow": "FFD800", - "Schooner": "8B847E", - "Science Blue": "0066CC", - "Scooter": "2EBFD4", - "Scorpion": "695F62", - "Scotch Mist": "FFFBDC", - "Screamin' Green": "66FF66", - "Sea Buckthorn": "FBA129", - "Sea Green": "2E8B57", - "Sea Mist": "C5DBCA", - "Sea Nymph": "78A39C", - "Sea Pink": "ED989E", - "Seagull": "80CCEA", - "Seance": "731E8F", - "Seashell": "F1F1F1", - "Seashell Peach": "FFF5EE", - "Seaweed": "1B2F11", - "Selago": "F0EEFD", - "Selective Yellow": "FFBA00", - "Sepia": "704214", - "Sepia Black": "2B0202", - "Sepia Skin": "9E5B40", - "Serenade": "FFF4E8", - "Shadow": "837050", - "Shadow Green": "9AC2B8", - "Shady Lady": "AAA5A9", - "Shakespeare": "4EABD1", - "Shalimar": "FBFFBA", - "Shamrock": "33CC99", - "Shark": "25272C", - "Sherpa Blue": "004950", - "Sherwood Green": "02402C", - "Shilo": "E8B9B3", - "Shingle Fawn": "6B4E31", - "Ship Cove": "788BBA", - "Ship Gray": "3E3A44", - "Shiraz": "B20931", - "Shocking": "E292C0", - "Shocking Pink": "FC0FC0", - "Shuttle Gray": "5F6672", - "Siam": "646A54", - "Sidecar": "F3E7BB", - "Silk": "BDB1A8", - "Silver": "C0C0C0", - "Silver Chalice": "ACACAC", - "Silver Rust": "C9C0BB", - "Silver Sand": "BFC1C2", - "Silver Tree": "66B58F", - "Sinbad": "9FD7D3", - "Siren": "7A013A", - "Sirocco": "718080", - "Sisal": "D3CBBA", - "Skeptic": "CAE6DA", - "Sky Blue": "76D7EA", - "Slate Gray": "708090", - "Smalt": "003399", - "Smalt Blue": "51808F", - "Smoky": "605B73", - "Snow Drift": "F7FAF7", - "Snow Flurry": "E4FFD1", - "Snowy Mint": "D6FFDB", - "Snuff": "E2D8ED", - "Soapstone": "FFFBF9", - "Soft Amber": "D1C6B4", - "Soft Peach": "F5EDEF", - "Solid Pink": "893843", - "Solitaire": "FEF8E2", - "Solitude": "EAF6FF", - "Sorbus": "FD7C07", - "Sorrell Brown": "CEB98F", - "Soya Bean": "6A6051", - "Spanish Green": "819885", - "Spectra": "2F5A57", - "Spice": "6A442E", - "Spicy Mix": "885342", - "Spicy Mustard": "74640D", - "Spicy Pink": "816E71", - "Spindle": "B6D1EA", - "Spray": "79DEEC", - "Spring Green": "00FF7F", - "Spring Leaves": "578363", - "Spring Rain": "ACCBB1", - "Spring Sun": "F6FFDC", - "Spring Wood": "F8F6F1", - "Sprout": "C1D7B0", - "Spun Pearl": "AAABB7", - "Squirrel": "8F8176", - "St Tropaz": "2D569B", - "Stack": "8A8F8A", - "Star Dust": "9F9F9C", - "Stark White": "E5D7BD", - "Starship": "ECF245", - "Steel Blue": "4682B4", - "Steel Gray": "262335", - "Stiletto": "9C3336", - "Stonewall": "928573", - "Storm Dust": "646463", - "Storm Gray": "717486", - "Stratos": "000741", - "Straw": "D4BF8D", - "Strikemaster": "956387", - "Stromboli": "325D52", - "Studio": "714AB2", - "Submarine": "BAC7C9", - "Sugar Cane": "F9FFF6", - "Sulu": "C1F07C", - "Summer Green": "96BBAB", - "Sun": "FBAC13", - "Sundance": "C9B35B", - "Sundown": "FFB1B3", - "Sunflower": "E4D422", - "Sunglo": "E16865", - "Sunglow": "FFCC33", - "Sunset Orange": "FE4C40", - "Sunshade": "FF9E2C", - "Supernova": "FFC901", - "Surf": "BBD7C1", - "Surf Crest": "CFE5D2", - "Surfie Green": "0C7A79", - "Sushi": "87AB39", - "Suva Gray": "888387", - "Swamp": "001B1C", - "Swamp Green": "ACB78E", - "Swans Down": "DCF0EA", - "Sweet Corn": "FBEA8C", - "Sweet Pink": "FD9FA2", - "Swirl": "D3CDC5", - "Swiss Coffee": "DDD6D5", - "Sycamore": "908D39", - "Tabasco": "A02712", - "Tacao": "EDB381", - "Tacha": "D6C562", - "Tahiti Gold": "E97C07", - "Tahuna Sands": "EEF0C8", - "Tall Poppy": "B32D29", - "Tallow": "A8A589", - "Tamarillo": "991613", - "Tamarind": "341515", - "Tan": "D2B48C", - "Tan Hide": "FA9D5A", - "Tana": "D9DCC1", - "Tangaroa": "03163C", - "Tangerine": "F28500", - "Tango": "ED7A1C", - "Tapa": "7B7874", - "Tapestry": "B05E81", - "Tara": "E1F6E8", - "Tarawera": "073A50", - "Tasman": "CFDCCF", - "Taupe": "483C32", - "Taupe Gray": "B3AF95", - "Tawny Port": "692545", - "Te Papa Green": "1E433C", - "Tea": "C1BAB0", - "Tea Green": "D0F0C0", - "Teak": "B19461", - "Teal": "008080", - "Teal Blue": "044259", - "Temptress": "3B000B", - "Tenn": "CD5700", - "Tequila": "FFE6C7", - "Terracotta": "E2725B", - "Texas": "F8F99C", - "Texas Rose": "FFB555", - "Thatch": "B69D98", - "Thatch Green": "403D19", - "Thistle": "D8BFD8", - "Thistle Green": "CCCAA8", - "Thunder": "33292F", - "Thunderbird": "C02B18", - "Tia Maria": "C1440E", - "Tiara": "C3D1D1", - "Tiber": "063537", - "Tickle Me Pink": "FC80A5", - "Tidal": "F1FFAD", - "Tide": "BFB8B0", - "Timber Green": "16322C", - "Timberwolf": "D9D6CF", - "Titan White": "F0EEFF", - "Toast": "9A6E61", - "Tobacco Brown": "715D47", - "Toledo": "3A0020", - "Tolopea": "1B0245", - "Tom Thumb": "3F583B", - "Tonys Pink": "E79F8C", - "Topaz": "7C778A", - "Torch Red": "FD0E35", - "Torea Bay": "0F2D9E", - "Tory Blue": "1450AA", - "Tosca": "8D3F3F", - "Totem Pole": "991B07", - "Tower Gray": "A9BDBF", - "Tradewind": "5FB3AC", - "Tranquil": "E6FFFF", - "Travertine": "FFFDE8", - "Tree Poppy": "FC9C1D", - "Treehouse": "3B2820", - "Trendy Green": "7C881A", - "Trendy Pink": "8C6495", - "Trinidad": "E64E03", - "Tropical Blue": "C3DDF9", - "Tropical Rain Forest": "00755E", - "Trout": "4A4E5A", - "True V": "8A73D6", - "Tuatara": "363534", - "Tuft Bush": "FFDDCD", - "Tulip Tree": "EAB33B", - "Tumbleweed": "DEA681", - "Tuna": "353542", - "Tundora": "4A4244", - "Turbo": "FAE600", - "Turkish Rose": "B57281", - "Turmeric": "CABB48", - "Turquoise": "30D5C8", - "Turquoise Blue": "6CDAE7", - "Turtle Green": "2A380B", - "Tuscany": "BD5E2E", - "Tusk": "EEF3C3", - "Tussock": "C5994B", - "Tutu": "FFF1F9", - "Twilight": "E4CFDE", - "Twilight Blue": "EEFDFF", - "Twine": "C2955D", - "Tyrian Purple": "66023C", - "Ultramarine": "120A8F", - "Valencia": "D84437", - "Valentino": "350E42", - "Valhalla": "2B194F", - "Van Cleef": "49170C", - "Vanilla": "D1BEA8", - "Vanilla Ice": "F3D9DF", - "Varden": "FFF6DF", - "Venetian Red": "72010F", - "Venice Blue": "055989", - "Venus": "928590", - "Verdigris": "5D5E37", - "Verdun Green": "495400", - "Vermilion": "FF4D00", - "Vesuvius": "B14A0B", - "Victoria": "534491", - "Vida Loca": "549019", - "Viking": "64CCDB", - "Vin Rouge": "983D61", - "Viola": "CB8FA9", - "Violent Violet": "290C5E", - "Violet": "240A40", - "Violet Eggplant": "991199", - "Violet Red": "F7468A", - "Viridian": "40826D", - "Viridian Green": "678975", - "Vis Vis": "FFEFA1", - "Vista Blue": "8FD6B4", - "Vista White": "FCF8F7", - "Vivid Tangerine": "FF9980", - "Vivid Violet": "803790", - "Voodoo": "533455", - "Vulcan": "10121D", - "Wafer": "DECBC6", - "Waikawa Gray": "5A6E9C", - "Waiouru": "363C0D", - "Walnut": "773F1A", - "Wasabi": "788A25", - "Water Leaf": "A1E9DE", - "Watercourse": "056F57", - "Waterloo ": "7B7C94", - "Wattle": "DCD747", - "Watusi": "FFDDCF", - "Wax Flower": "FFC0A8", - "We Peep": "F7DBE6", - "Web Orange": "FFA500", - "Wedgewood": "4E7F9E", - "Well Read": "B43332", - "West Coast": "625119", - "West Side": "FF910F", - "Westar": "DCD9D2", - "Wewak": "F19BAB", - "Wheat": "F5DEB3", - "Wheatfield": "F3EDCF", - "Whiskey": "D59A6F", - "Whisper": "F7F5FA", - "White": "FFFFFF", - "White Ice": "DDF9F1", - "White Lilac": "F8F7FC", - "White Linen": "F8F0E8", - "White Pointer": "FEF8FF", - "White Rock": "EAE8D4", - "Wild Blue Yonder": "7A89B8", - "Wild Rice": "ECE090", - "Wild Sand": "F4F4F4", - "Wild Strawberry": "FF3399", - "Wild Watermelon": "FD5B78", - "Wild Willow": "B9C46A", - "William": "3A686C", - "Willow Brook": "DFECDA", - "Willow Grove": "65745D", - "Windsor": "3C0878", - "Wine Berry": "591D35", - "Winter Hazel": "D5D195", - "Wisp Pink": "FEF4F8", - "Wisteria": "9771B5", - "Wistful": "A4A6D3", - "Witch Haze": "FFFC99", - "Wood Bark": "261105", - "Woodland": "4D5328", - "Woodrush": "302A0F", - "Woodsmoke": "0C0D0F", - "Woody Brown": "483131", - "Xanadu": "738678", - "Yellow": "FFFF00", - "Yellow Green": "C5E17A", - "Yellow Metal": "716338", - "Yellow Orange": "FFAE42", - "Yellow Sea": "FEA904", - "Your Pink": "FFC3C0", - "Yukon Gold": "7B6608", - "Yuma": "CEC291", - "Zambezi": "685558", - "Zanah": "DAECD6", - "Zest": "E5841B", - "Zeus": "292319", - "Ziggurat": "BFDBE2", - "Zinnwaldite": "EBC2AF", - "Zircon": "F4F8FF", - "Zombie": "E4D69B", - "Zorba": "A59B91", - "Zuccini": "044022", - "Zumthor": "EDF6FF" -} diff --git a/bot/resources/utilities/ryanzec_colours.json b/bot/resources/utilities/ryanzec_colours.json new file mode 100644 index 00000000..7b89f052 --- /dev/null +++ b/bot/resources/utilities/ryanzec_colours.json @@ -0,0 +1,1568 @@ +{ + "Abbey": "4C4F56", + "Acadia": "1B1404", + "Acapulco": "7CB0A1", + "Aero Blue": "C9FFE5", + "Affair": "714693", + "Akaroa": "D4C4A8", + "Alabaster": "FAFAFA", + "Albescent White": "F5E9D3", + "Algae Green": "93DFB8", + "Alice Blue": "F0F8FF", + "Alizarin Crimson": "E32636", + "Allports": "0076A3", + "Almond": "EED9C4", + "Almond Frost": "907B71", + "Alpine": "AF8F2C", + "Alto": "DBDBDB", + "Aluminium": "A9ACB6", + "Amaranth": "E52B50", + "Amazon": "3B7A57", + "Amber": "FFBF00", + "Americano": "87756E", + "Amethyst": "9966CC", + "Amethyst Smoke": "A397B4", + "Amour": "F9EAF3", + "Amulet": "7B9F80", + "Anakiwa": "9DE5FF", + "Antique Brass": "C88A65", + "Antique Bronze": "704A07", + "Anzac": "E0B646", + "Apache": "DFBE6F", + "Apple": "4FA83D", + "Apple Blossom": "AF4D43", + "Apple Green": "E2F3EC", + "Apricot": "EB9373", + "Apricot Peach": "FBCEB1", + "Apricot White": "FFFEEC", + "Aqua Deep": "014B43", + "Aqua Forest": "5FA777", + "Aqua Haze": "EDF5F5", + "Aqua Island": "A1DAD7", + "Aqua Spring": "EAF9F5", + "Aqua Squeeze": "E8F5F2", + "Aquamarine": "7FFFD4", + "Aquamarine Blue": "71D9E2", + "Arapawa": "110C6C", + "Armadillo": "433E37", + "Arrowtown": "948771", + "Ash": "C6C3B5", + "Asparagus": "7BA05B", + "Asphalt": "130A06", + "Astra": "FAEAB9", + "Astral": "327DA0", + "Astronaut": "283A77", + "Astronaut Blue": "013E62", + "Athens Gray": "EEF0F3", + "Aths Special": "ECEBCE", + "Atlantis": "97CD2D", + "Atoll": "0A6F75", + "Atomic Tangerine": "FF9966", + "Au Chico": "97605D", + "Aubergine": "3B0910", + "Australian Mint": "F5FFBE", + "Avocado": "888D65", + "Axolotl": "4E6649", + "Azalea": "F7C8DA", + "Aztec": "0D1C19", + "Azure": "315BA1", + "Azure Radiance": "007FFF", + "Baby Blue": "E0FFFF", + "Bahama Blue": "026395", + "Bahia": "A5CB0C", + "Baja White": "FFF8D1", + "Bali Hai": "859FAF", + "Baltic Sea": "2A2630", + "Bamboo": "DA6304", + "Banana Mania": "FBE7B2", + "Bandicoot": "858470", + "Barberry": "DED717", + "Barley Corn": "A68B5B", + "Barley White": "FFF4CE", + "Barossa": "44012D", + "Bastille": "292130", + "Battleship Gray": "828F72", + "Bay Leaf": "7DA98D", + "Bay of Many": "273A81", + "Bazaar": "98777B", + "Bean ": "3D0C02", + "Beauty Bush": "EEC1BE", + "Beaver": "926F5B", + "Beeswax": "FEF2C7", + "Beige": "F5F5DC", + "Bermuda": "7DD8C6", + "Bermuda Gray": "6B8BA2", + "Beryl Green": "DEE5C0", + "Bianca": "FCFBF3", + "Big Stone": "162A40", + "Bilbao": "327C14", + "Biloba Flower": "B2A1EA", + "Birch": "373021", + "Bird Flower": "D4CD16", + "Biscay": "1B3162", + "Bismark": "497183", + "Bison Hide": "C1B7A4", + "Bistre": "3D2B1F", + "Bitter": "868974", + "Bitter Lemon": "CAE00D", + "Bittersweet": "FE6F5E", + "Bizarre": "EEDEDA", + "Black": "000000", + "Black Bean": "081910", + "Black Forest": "0B1304", + "Black Haze": "F6F7F7", + "Black Marlin": "3E2C1C", + "Black Olive": "242E16", + "Black Pearl": "041322", + "Black Rock": "0D0332", + "Black Rose": "67032D", + "Black Russian": "0A001C", + "Black Squeeze": "F2FAFA", + "Black White": "FFFEF6", + "Blackberry": "4D0135", + "Blackcurrant": "32293A", + "Blaze Orange": "FF6600", + "Bleach White": "FEF3D8", + "Bleached Cedar": "2C2133", + "Blizzard Blue": "A3E3ED", + "Blossom": "DCB4BC", + "Blue": "0000FF", + "Blue Bayoux": "496679", + "Blue Bell": "9999CC", + "Blue Chalk": "F1E9FF", + "Blue Charcoal": "010D1A", + "Blue Chill": "0C8990", + "Blue Diamond": "380474", + "Blue Dianne": "204852", + "Blue Gem": "2C0E8C", + "Blue Haze": "BFBED8", + "Blue Lagoon": "017987", + "Blue Marguerite": "7666C6", + "Blue Ribbon": "0066FF", + "Blue Romance": "D2F6DE", + "Blue Smoke": "748881", + "Blue Stone": "016162", + "Blue Violet": "6456B7", + "Blue Whale": "042E4C", + "Blue Zodiac": "13264D", + "Blumine": "18587A", + "Blush": "B44668", + "Blush Pink": "FF6FFF", + "Bombay": "AFB1B8", + "Bon Jour": "E5E0E1", + "Bondi Blue": "0095B6", + "Bone": "E4D1C0", + "Bordeaux": "5C0120", + "Bossanova": "4E2A5A", + "Boston Blue": "3B91B4", + "Botticelli": "C7DDE5", + "Bottle Green": "093624", + "Boulder": "7A7A7A", + "Bouquet": "AE809E", + "Bourbon": "BA6F1E", + "Bracken": "4A2A04", + "Brandy": "DEC196", + "Brandy Punch": "CD8429", + "Brandy Rose": "BB8983", + "Breaker Bay": "5DA19F", + "Brick Red": "C62D42", + "Bridal Heath": "FFFAF4", + "Bridesmaid": "FEF0EC", + "Bright Gray": "3C4151", + "Bright Green": "66FF00", + "Bright Red": "B10000", + "Bright Sun": "FED33C", + "Bright Turquoise": "08E8DE", + "Brilliant Rose": "F653A6", + "Brink Pink": "FB607F", + "Bronco": "ABA196", + "Bronze": "3F2109", + "Bronze Olive": "4E420C", + "Bronzetone": "4D400F", + "Broom": "FFEC13", + "Brown": "964B00", + "Brown Bramble": "592804", + "Brown Derby": "492615", + "Brown Pod": "401801", + "Brown Rust": "AF593E", + "Brown Tumbleweed": "37290E", + "Bubbles": "E7FEFF", + "Buccaneer": "622F30", + "Bud": "A8AE9C", + "Buddha Gold": "C1A004", + "Buff": "F0DC82", + "Bulgarian Rose": "480607", + "Bull Shot": "864D1E", + "Bunker": "0D1117", + "Bunting": "151F4C", + "Burgundy": "900020", + "Burnham": "002E20", + "Burning Orange": "FF7034", + "Burning Sand": "D99376", + "Burnt Maroon": "420303", + "Burnt Orange": "CC5500", + "Burnt Sienna": "E97451", + "Burnt Umber": "8A3324", + "Bush": "0D2E1C", + "Buttercup": "F3AD16", + "Buttered Rum": "A1750D", + "Butterfly Bush": "624E9A", + "Buttermilk": "FFF1B5", + "Buttery White": "FFFCEA", + "Cab Sav": "4D0A18", + "Cabaret": "D94972", + "Cabbage Pont": "3F4C3A", + "Cactus": "587156", + "Cadet Blue": "A9B2C3", + "Cadillac": "B04C6A", + "Cafe Royale": "6F440C", + "Calico": "E0C095", + "California": "FE9D04", + "Calypso": "31728D", + "Camarone": "00581A", + "Camelot": "893456", + "Cameo": "D9B99B", + "Camouflage": "3C3910", + "Camouflage Green": "78866B", + "Can Can": "D591A4", + "Canary": "F3FB62", + "Candlelight": "FCD917", + "Candy Corn": "FBEC5D", + "Cannon Black": "251706", + "Cannon Pink": "894367", + "Cape Cod": "3C4443", + "Cape Honey": "FEE5AC", + "Cape Palliser": "A26645", + "Caper": "DCEDB4", + "Caramel": "FFDDAF", + "Cararra": "EEEEE8", + "Cardin Green": "01361C", + "Cardinal": "C41E3A", + "Cardinal Pink": "8C055E", + "Careys Pink": "D29EAA", + "Caribbean Green": "00CC99", + "Carissma": "EA88A8", + "Carla": "F3FFD8", + "Carmine": "960018", + "Carnaby Tan": "5C2E01", + "Carnation": "F95A61", + "Carnation Pink": "FFA6C9", + "Carousel Pink": "F9E0ED", + "Carrot Orange": "ED9121", + "Casablanca": "F8B853", + "Casal": "2F6168", + "Cascade": "8BA9A5", + "Cashmere": "E6BEA5", + "Casper": "ADBED1", + "Castro": "52001F", + "Catalina Blue": "062A78", + "Catskill White": "EEF6F7", + "Cavern Pink": "E3BEBE", + "Cedar": "3E1C14", + "Cedar Wood Finish": "711A00", + "Celadon": "ACE1AF", + "Celery": "B8C25D", + "Celeste": "D1D2CA", + "Cello": "1E385B", + "Celtic": "163222", + "Cement": "8D7662", + "Ceramic": "FCFFF9", + "Cerise": "DA3287", + "Cerise Red": "DE3163", + "Cerulean": "02A4D3", + "Cerulean Blue": "2A52BE", + "Chablis": "FFF4F3", + "Chalet Green": "516E3D", + "Chalky": "EED794", + "Chambray": "354E8C", + "Chamois": "EDDCB1", + "Champagne": "FAECCC", + "Chantilly": "F8C3DF", + "Charade": "292937", + "Chardon": "FFF3F1", + "Chardonnay": "FFCD8C", + "Charlotte": "BAEEF9", + "Charm": "D47494", + "Chartreuse": "7FFF00", + "Chartreuse Yellow": "DFFF00", + "Chateau Green": "40A860", + "Chatelle": "BDB3C7", + "Chathams Blue": "175579", + "Chelsea Cucumber": "83AA5D", + "Chelsea Gem": "9E5302", + "Chenin": "DFCD6F", + "Cherokee": "FCDA98", + "Cherry Pie": "2A0359", + "Cherrywood": "651A14", + "Cherub": "F8D9E9", + "Chestnut": "B94E48", + "Chestnut Rose": "CD5C5C", + "Chetwode Blue": "8581D9", + "Chicago": "5D5C58", + "Chiffon": "F1FFC8", + "Chilean Fire": "F77703", + "Chilean Heath": "FFFDE6", + "China Ivory": "FCFFE7", + "Chino": "CEC7A7", + "Chinook": "A8E3BD", + "Chocolate": "370202", + "Christalle": "33036B", + "Christi": "67A712", + "Christine": "E7730A", + "Chrome White": "E8F1D4", + "Cinder": "0E0E18", + "Cinderella": "FDE1DC", + "Cinnabar": "E34234", + "Cinnamon": "7B3F00", + "Cioccolato": "55280C", + "Citrine White": "FAF7D6", + "Citron": "9EA91F", + "Citrus": "A1C50A", + "Clairvoyant": "480656", + "Clam Shell": "D4B6AF", + "Claret": "7F1734", + "Classic Rose": "FBCCE7", + "Clay Ash": "BDC8B3", + "Clay Creek": "8A8360", + "Clear Day": "E9FFFD", + "Clementine": "E96E00", + "Clinker": "371D09", + "Cloud": "C7C4BF", + "Cloud Burst": "202E54", + "Cloudy": "ACA59F", + "Clover": "384910", + "Cobalt": "0047AB", + "Cocoa Bean": "481C1C", + "Cocoa Brown": "301F1E", + "Coconut Cream": "F8F7DC", + "Cod Gray": "0B0B0B", + "Coffee": "706555", + "Coffee Bean": "2A140E", + "Cognac": "9F381D", + "Cola": "3F2500", + "Cold Purple": "ABA0D9", + "Cold Turkey": "CEBABA", + "Colonial White": "FFEDBC", + "Comet": "5C5D75", + "Como": "517C66", + "Conch": "C9D9D2", + "Concord": "7C7B7A", + "Concrete": "F2F2F2", + "Confetti": "E9D75A", + "Congo Brown": "593737", + "Congress Blue": "02478E", + "Conifer": "ACDD4D", + "Contessa": "C6726B", + "Copper": "B87333", + "Copper Canyon": "7E3A15", + "Copper Rose": "996666", + "Copper Rust": "944747", + "Copperfield": "DA8A67", + "Coral": "FF7F50", + "Coral Red": "FF4040", + "Coral Reef": "C7BCA2", + "Coral Tree": "A86B6B", + "Corduroy": "606E68", + "Coriander": "C4D0B0", + "Cork": "40291D", + "Corn": "E7BF05", + "Corn Field": "F8FACD", + "Corn Harvest": "8B6B0B", + "Cornflower": "93CCEA", + "Cornflower Blue": "6495ED", + "Cornflower Lilac": "FFB0AC", + "Corvette": "FAD3A2", + "Cosmic": "76395D", + "Cosmos": "FFD8D9", + "Costa Del Sol": "615D30", + "Cotton Candy": "FFB7D5", + "Cotton Seed": "C2BDB6", + "County Green": "01371A", + "Cowboy": "4D282D", + "Crail": "B95140", + "Cranberry": "DB5079", + "Crater Brown": "462425", + "Cream": "FFFDD0", + "Cream Brulee": "FFE5A0", + "Cream Can": "F5C85C", + "Creole": "1E0F04", + "Crete": "737829", + "Crimson": "DC143C", + "Crocodile": "736D58", + "Crown of Thorns": "771F1F", + "Crowshead": "1C1208", + "Cruise": "B5ECDF", + "Crusoe": "004816", + "Crusta": "FD7B33", + "Cumin": "924321", + "Cumulus": "FDFFD5", + "Cupid": "FBBEDA", + "Curious Blue": "2596D1", + "Cutty Sark": "507672", + "Cyan / Aqua": "00FFFF", + "Cyprus": "003E40", + "Daintree": "012731", + "Dairy Cream": "F9E4BC", + "Daisy Bush": "4F2398", + "Dallas": "6E4B26", + "Dandelion": "FED85D", + "Danube": "6093D1", + "Dark Blue": "0000C8", + "Dark Burgundy": "770F05", + "Dark Ebony": "3C2005", + "Dark Fern": "0A480D", + "Dark Tan": "661010", + "Dawn": "A6A29A", + "Dawn Pink": "F3E9E5", + "De York": "7AC488", + "Deco": "D2DA97", + "Deep Blue": "220878", + "Deep Blush": "E47698", + "Deep Bronze": "4A3004", + "Deep Cerulean": "007BA7", + "Deep Cove": "051040", + "Deep Fir": "002900", + "Deep Forest Green": "182D09", + "Deep Koamaru": "1B127B", + "Deep Oak": "412010", + "Deep Sapphire": "082567", + "Deep Sea": "01826B", + "Deep Sea Green": "095859", + "Deep Teal": "003532", + "Del Rio": "B09A95", + "Dell": "396413", + "Delta": "A4A49D", + "Deluge": "7563A8", + "Denim": "1560BD", + "Derby": "FFEED8", + "Desert": "AE6020", + "Desert Sand": "EDC9AF", + "Desert Storm": "F8F8F7", + "Dew": "EAFFFE", + "Di Serria": "DB995E", + "Diesel": "130000", + "Dingley": "5D7747", + "Disco": "871550", + "Dixie": "E29418", + "Dodger Blue": "1E90FF", + "Dolly": "F9FF8B", + "Dolphin": "646077", + "Domino": "8E775E", + "Don Juan": "5D4C51", + "Donkey Brown": "A69279", + "Dorado": "6B5755", + "Double Colonial White": "EEE3AD", + "Double Pearl Lusta": "FCF4D0", + "Double Spanish White": "E6D7B9", + "Dove Gray": "6D6C6C", + "Downriver": "092256", + "Downy": "6FD0C5", + "Driftwood": "AF8751", + "Drover": "FDF7AD", + "Dull Lavender": "A899E6", + "Dune": "383533", + "Dust Storm": "E5CCC9", + "Dusty Gray": "A8989B", + "Eagle": "B6BAA4", + "Earls Green": "C9B93B", + "Early Dawn": "FFF9E6", + "East Bay": "414C7D", + "East Side": "AC91CE", + "Eastern Blue": "1E9AB0", + "Ebb": "E9E3E3", + "Ebony": "0C0B1D", + "Ebony Clay": "26283B", + "Eclipse": "311C17", + "Ecru White": "F5F3E5", + "Ecstasy": "FA7814", + "Eden": "105852", + "Edgewater": "C8E3D7", + "Edward": "A2AEAB", + "Egg Sour": "FFF4DD", + "Egg White": "FFEFC1", + "Eggplant": "614051", + "El Paso": "1E1708", + "El Salva": "8F3E33", + "Electric Lime": "CCFF00", + "Electric Violet": "8B00FF", + "Elephant": "123447", + "Elf Green": "088370", + "Elm": "1C7C7D", + "Emerald": "50C878", + "Eminence": "6C3082", + "Emperor": "514649", + "Empress": "817377", + "Endeavour": "0056A7", + "Energy Yellow": "F8DD5C", + "English Holly": "022D15", + "English Walnut": "3E2B23", + "Envy": "8BA690", + "Equator": "E1BC64", + "Espresso": "612718", + "Eternity": "211A0E", + "Eucalyptus": "278A5B", + "Eunry": "CFA39D", + "Evening Sea": "024E46", + "Everglade": "1C402E", + "Faded Jade": "427977", + "Fair Pink": "FFEFEC", + "Falcon": "7F626D", + "Fall Green": "ECEBBD", + "Falu Red": "801818", + "Fantasy": "FAF3F0", + "Fedora": "796A78", + "Feijoa": "9FDD8C", + "Fern": "63B76C", + "Fern Frond": "657220", + "Fern Green": "4F7942", + "Ferra": "704F50", + "Festival": "FBE96C", + "Feta": "F0FCEA", + "Fiery Orange": "B35213", + "Finch": "626649", + "Finlandia": "556D56", + "Finn": "692D54", + "Fiord": "405169", + "Fire": "AA4203", + "Fire Bush": "E89928", + "Firefly": "0E2A30", + "Flame Pea": "DA5B38", + "Flamenco": "FF7D07", + "Flamingo": "F2552A", + "Flax": "EEDC82", + "Flax Smoke": "7B8265", + "Flesh": "FFCBA4", + "Flint": "6F6A61", + "Flirt": "A2006D", + "Flush Mahogany": "CA3435", + "Flush Orange": "FF7F00", + "Foam": "D8FCFA", + "Fog": "D7D0FF", + "Foggy Gray": "CBCAB6", + "Forest Green": "228B22", + "Forget Me Not": "FFF1EE", + "Fountain Blue": "56B4BE", + "Frangipani": "FFDEB3", + "French Gray": "BDBDC6", + "French Lilac": "ECC7EE", + "French Pass": "BDEDFD", + "French Rose": "F64A8A", + "Fresh Eggplant": "990066", + "Friar Gray": "807E79", + "Fringy Flower": "B1E2C1", + "Froly": "F57584", + "Frost": "EDF5DD", + "Frosted Mint": "DBFFF8", + "Frostee": "E4F6E7", + "Fruit Salad": "4F9D5D", + "Fuchsia Blue": "7A58C1", + "Fuchsia Pink": "C154C1", + "Fuego": "BEDE0D", + "Fuel Yellow": "ECA927", + "Fun Blue": "1959A8", + "Fun Green": "016D39", + "Fuscous Gray": "54534D", + "Fuzzy Wuzzy Brown": "C45655", + "Gable Green": "163531", + "Gallery": "EFEFEF", + "Galliano": "DCB20C", + "Gamboge": "E49B0F", + "Geebung": "D18F1B", + "Genoa": "15736B", + "Geraldine": "FB8989", + "Geyser": "D4DFE2", + "Ghost": "C7C9D5", + "Gigas": "523C94", + "Gimblet": "B8B56A", + "Gin": "E8F2EB", + "Gin Fizz": "FFF9E2", + "Givry": "F8E4BF", + "Glacier": "80B3C4", + "Glade Green": "61845F", + "Go Ben": "726D4E", + "Goblin": "3D7D52", + "Gold": "FFD700", + "Gold Drop": "F18200", + "Gold Sand": "E6BE8A", + "Gold Tips": "DEBA13", + "Golden Bell": "E28913", + "Golden Dream": "F0D52D", + "Golden Fizz": "F5FB3D", + "Golden Glow": "FDE295", + "Golden Grass": "DAA520", + "Golden Sand": "F0DB7D", + "Golden Tainoi": "FFCC5C", + "Goldenrod": "FCD667", + "Gondola": "261414", + "Gordons Green": "0B1107", + "Gorse": "FFF14F", + "Gossamer": "069B81", + "Gossip": "D2F8B0", + "Gothic": "6D92A1", + "Governor Bay": "2F3CB3", + "Grain Brown": "E4D5B7", + "Grandis": "FFD38C", + "Granite Green": "8D8974", + "Granny Apple": "D5F6E3", + "Granny Smith": "84A0A0", + "Granny Smith Apple": "9DE093", + "Grape": "381A51", + "Graphite": "251607", + "Gravel": "4A444B", + "Gray": "808080", + "Gray Asparagus": "465945", + "Gray Chateau": "A2AAB3", + "Gray Nickel": "C3C3BD", + "Gray Nurse": "E7ECE6", + "Gray Olive": "A9A491", + "Gray Suit": "C1BECD", + "Green": "00FF00", + "Green Haze": "01A368", + "Green House": "24500F", + "Green Kelp": "25311C", + "Green Leaf": "436A0D", + "Green Mist": "CBD3B0", + "Green Pea": "1D6142", + "Green Smoke": "A4AF6E", + "Green Spring": "B8C1B1", + "Green Vogue": "032B52", + "Green Waterloo": "101405", + "Green White": "E8EBE0", + "Green Yellow": "ADFF2F", + "Grenadier": "D54600", + "Guardsman Red": "BA0101", + "Gulf Blue": "051657", + "Gulf Stream": "80B3AE", + "Gull Gray": "9DACB7", + "Gum Leaf": "B6D3BF", + "Gumbo": "7CA1A6", + "Gun Powder": "414257", + "Gunsmoke": "828685", + "Gurkha": "9A9577", + "Hacienda": "98811B", + "Hairy Heath": "6B2A14", + "Haiti": "1B1035", + "Half Baked": "85C4CC", + "Half Colonial White": "FDF6D3", + "Half Dutch White": "FEF7DE", + "Half Spanish White": "FEF4DB", + "Half and Half": "FFFEE1", + "Hampton": "E5D8AF", + "Harlequin": "3FFF00", + "Harp": "E6F2EA", + "Harvest Gold": "E0B974", + "Havelock Blue": "5590D9", + "Hawaiian Tan": "9D5616", + "Hawkes Blue": "D4E2FC", + "Heath": "541012", + "Heather": "B7C3D0", + "Heathered Gray": "B6B095", + "Heavy Metal": "2B3228", + "Heliotrope": "DF73FF", + "Hemlock": "5E5D3B", + "Hemp": "907874", + "Hibiscus": "B6316C", + "Highland": "6F8E63", + "Hillary": "ACA586", + "Himalaya": "6A5D1B", + "Hint of Green": "E6FFE9", + "Hint of Red": "FBF9F9", + "Hint of Yellow": "FAFDE4", + "Hippie Blue": "589AAF", + "Hippie Green": "53824B", + "Hippie Pink": "AE4560", + "Hit Gray": "A1ADB5", + "Hit Pink": "FFAB81", + "Hokey Pokey": "C8A528", + "Hoki": "65869F", + "Holly": "011D13", + "Hollywood Cerise": "F400A1", + "Honey Flower": "4F1C70", + "Honeysuckle": "EDFC84", + "Hopbush": "D06DA1", + "Horizon": "5A87A0", + "Horses Neck": "604913", + "Hot Cinnamon": "D2691E", + "Hot Pink": "FF69B4", + "Hot Toddy": "B38007", + "Humming Bird": "CFF9F3", + "Hunter Green": "161D10", + "Hurricane": "877C7B", + "Husk": "B7A458", + "Ice Cold": "B1F4E7", + "Iceberg": "DAF4F0", + "Illusion": "F6A4C9", + "Inch Worm": "B0E313", + "Indian Khaki": "C3B091", + "Indian Tan": "4D1E01", + "Indigo": "4F69C6", + "Indochine": "C26B03", + "International Klein Blue": "002FA7", + "International Orange": "FF4F00", + "Irish Coffee": "5F3D26", + "Iroko": "433120", + "Iron": "D4D7D9", + "Ironside Gray": "676662", + "Ironstone": "86483C", + "Island Spice": "FFFCEE", + "Ivory": "FFFFF0", + "Jacaranda": "2E0329", + "Jacarta": "3A2A6A", + "Jacko Bean": "2E1905", + "Jacksons Purple": "20208D", + "Jade": "00A86B", + "Jaffa": "EF863F", + "Jagged Ice": "C2E8E5", + "Jagger": "350E57", + "Jaguar": "080110", + "Jambalaya": "5B3013", + "Janna": "F4EBD3", + "Japanese Laurel": "0A6906", + "Japanese Maple": "780109", + "Japonica": "D87C63", + "Java": "1FC2C2", + "Jazzberry Jam": "A50B5E", + "Jelly Bean": "297B9A", + "Jet Stream": "B5D2CE", + "Jewel": "126B40", + "Jon": "3B1F1F", + "Jonquil": "EEFF9A", + "Jordy Blue": "8AB9F1", + "Judge Gray": "544333", + "Jumbo": "7C7B82", + "Jungle Green": "29AB87", + "Jungle Mist": "B4CFD3", + "Juniper": "6D9292", + "Just Right": "ECCDB9", + "Kabul": "5E483E", + "Kaitoke Green": "004620", + "Kangaroo": "C6C8BD", + "Karaka": "1E1609", + "Karry": "FFEAD4", + "Kashmir Blue": "507096", + "Kelp": "454936", + "Kenyan Copper": "7C1C05", + "Keppel": "3AB09E", + "Key Lime Pie": "BFC921", + "Khaki": "F0E68C", + "Kidnapper": "E1EAD4", + "Kilamanjaro": "240C02", + "Killarney": "3A6A47", + "Kimberly": "736C9F", + "Kingfisher Daisy": "3E0480", + "Kobi": "E79FC4", + "Kokoda": "6E6D57", + "Korma": "8F4B0E", + "Koromiko": "FFBD5F", + "Kournikova": "FFE772", + "Kumera": "886221", + "La Palma": "368716", + "La Rioja": "B3C110", + "Las Palmas": "C6E610", + "Laser": "C8B568", + "Laser Lemon": "FFFF66", + "Laurel": "749378", + "Lavender": "B57EDC", + "Lavender Gray": "BDBBD7", + "Lavender Magenta": "EE82EE", + "Lavender Pink": "FBAED2", + "Lavender Purple": "967BB6", + "Lavender Rose": "FBA0E3", + "Lavender blush": "FFF0F5", + "Leather": "967059", + "Lemon": "FDE910", + "Lemon Chiffon": "FFFACD", + "Lemon Ginger": "AC9E22", + "Lemon Grass": "9B9E8F", + "Light Apricot": "FDD5B1", + "Light Orchid": "E29CD2", + "Light Wisteria": "C9A0DC", + "Lightning Yellow": "FCC01E", + "Lilac": "C8A2C8", + "Lilac Bush": "9874D3", + "Lily": "C8AABF", + "Lily White": "E7F8FF", + "Lima": "76BD17", + "Lime": "BFFF00", + "Limeade": "6F9D02", + "Limed Ash": "747D63", + "Limed Oak": "AC8A56", + "Limed Spruce": "394851", + "Linen": "FAF0E6", + "Link Water": "D9E4F5", + "Lipstick": "AB0563", + "Lisbon Brown": "423921", + "Livid Brown": "4D282E", + "Loafer": "EEF4DE", + "Loblolly": "BDC9CE", + "Lochinvar": "2C8C84", + "Lochmara": "007EC7", + "Locust": "A8AF8E", + "Log Cabin": "242A1D", + "Logan": "AAA9CD", + "Lola": "DFCFDB", + "London Hue": "BEA6C3", + "Lonestar": "6D0101", + "Lotus": "863C3C", + "Loulou": "460B41", + "Lucky": "AF9F1C", + "Lucky Point": "1A1A68", + "Lunar Green": "3C493A", + "Luxor Gold": "A7882C", + "Lynch": "697E9A", + "Mabel": "D9F7FF", + "Macaroni and Cheese": "FFB97B", + "Madang": "B7F0BE", + "Madison": "09255D", + "Madras": "3F3002", + "Magenta / Fuchsia": "FF00FF", + "Magic Mint": "AAF0D1", + "Magnolia": "F8F4FF", + "Mahogany": "4E0606", + "Mai Tai": "B06608", + "Maize": "F5D5A0", + "Makara": "897D6D", + "Mako": "444954", + "Malachite": "0BDA51", + "Malibu": "7DC8F7", + "Mallard": "233418", + "Malta": "BDB2A1", + "Mamba": "8E8190", + "Manatee": "8D90A1", + "Mandalay": "AD781B", + "Mandy": "E25465", + "Mandys Pink": "F2C3B2", + "Mango Tango": "E77200", + "Manhattan": "F5C999", + "Mantis": "74C365", + "Mantle": "8B9C90", + "Manz": "EEEF78", + "Mardi Gras": "350036", + "Marigold": "B98D28", + "Marigold Yellow": "FBE870", + "Mariner": "286ACD", + "Maroon": "800000", + "Maroon Flush": "C32148", + "Maroon Oak": "520C17", + "Marshland": "0B0F08", + "Martini": "AFA09E", + "Martinique": "363050", + "Marzipan": "F8DB9D", + "Masala": "403B38", + "Matisse": "1B659D", + "Matrix": "B05D54", + "Matterhorn": "4E3B41", + "Mauve": "E0B0FF", + "Mauvelous": "F091A9", + "Maverick": "D8C2D5", + "Medium Carmine": "AF4035", + "Medium Purple": "9370DB", + "Medium Red Violet": "BB3385", + "Melanie": "E4C2D5", + "Melanzane": "300529", + "Melon": "FEBAAD", + "Melrose": "C7C1FF", + "Mercury": "E5E5E5", + "Merino": "F6F0E6", + "Merlin": "413C37", + "Merlot": "831923", + "Metallic Bronze": "49371B", + "Metallic Copper": "71291D", + "Meteor": "D07D12", + "Meteorite": "3C1F76", + "Mexican Red": "A72525", + "Mid Gray": "5F5F6E", + "Midnight": "011635", + "Midnight Blue": "003366", + "Midnight Moss": "041004", + "Mikado": "2D2510", + "Milan": "FAFFA4", + "Milano Red": "B81104", + "Milk Punch": "FFF6D4", + "Millbrook": "594433", + "Mimosa": "F8FDD3", + "Mindaro": "E3F988", + "Mine Shaft": "323232", + "Mineral Green": "3F5D53", + "Ming": "36747D", + "Minsk": "3F307F", + "Mint Green": "98FF98", + "Mint Julep": "F1EEC1", + "Mint Tulip": "C4F4EB", + "Mirage": "161928", + "Mischka": "D1D2DD", + "Mist Gray": "C4C4BC", + "Mobster": "7F7589", + "Moccaccino": "6E1D14", + "Mocha": "782D19", + "Mojo": "C04737", + "Mona Lisa": "FFA194", + "Monarch": "8B0723", + "Mondo": "4A3C30", + "Mongoose": "B5A27F", + "Monsoon": "8A8389", + "Monte Carlo": "83D0C6", + "Monza": "C7031E", + "Moody Blue": "7F76D3", + "Moon Glow": "FCFEDA", + "Moon Mist": "DCDDCC", + "Moon Raker": "D6CEF6", + "Morning Glory": "9EDEE0", + "Morocco Brown": "441D00", + "Mortar": "504351", + "Mosque": "036A6E", + "Moss Green": "ADDFAD", + "Mountain Meadow": "1AB385", + "Mountain Mist": "959396", + "Mountbatten Pink": "997A8D", + "Muddy Waters": "B78E5C", + "Muesli": "AA8B5B", + "Mulberry": "C54B8C", + "Mulberry Wood": "5C0536", + "Mule Fawn": "8C472F", + "Mulled Wine": "4E4562", + "Mustard": "FFDB58", + "My Pink": "D69188", + "My Sin": "FFB31F", + "Mystic": "E2EBED", + "Nandor": "4B5D52", + "Napa": "ACA494", + "Narvik": "EDF9F1", + "Natural Gray": "8B8680", + "Navajo White": "FFDEAD", + "Navy Blue": "000080", + "Nebula": "CBDBD6", + "Negroni": "FFE2C5", + "Neon Carrot": "FF9933", + "Nepal": "8EABC1", + "Neptune": "7CB7BB", + "Nero": "140600", + "Nevada": "646E75", + "New Orleans": "F3D69D", + "New York Pink": "D7837F", + "Niagara": "06A189", + "Night Rider": "1F120F", + "Night Shadz": "AA375A", + "Nile Blue": "193751", + "Nobel": "B7B1B1", + "Nomad": "BAB1A2", + "Norway": "A8BD9F", + "Nugget": "C59922", + "Nutmeg": "81422C", + "Nutmeg Wood Finish": "683600", + "Oasis": "FEEFCE", + "Observatory": "02866F", + "Ocean Green": "41AA78", + "Ochre": "CC7722", + "Off Green": "E6F8F3", + "Off Yellow": "FEF9E3", + "Oil": "281E15", + "Old Brick": "901E1E", + "Old Copper": "724A2F", + "Old Gold": "CFB53B", + "Old Lace": "FDF5E6", + "Old Lavender": "796878", + "Old Rose": "C08081", + "Olive": "808000", + "Olive Drab": "6B8E23", + "Olive Green": "B5B35C", + "Olive Haze": "8B8470", + "Olivetone": "716E10", + "Olivine": "9AB973", + "Onahau": "CDF4FF", + "Onion": "2F270E", + "Opal": "A9C6C2", + "Opium": "8E6F70", + "Oracle": "377475", + "Orange": "FF681F", + "Orange Peel": "FFA000", + "Orange Roughy": "C45719", + "Orange White": "FEFCED", + "Orchid": "DA70D6", + "Orchid White": "FFFDF3", + "Oregon": "9B4703", + "Orient": "015E85", + "Oriental Pink": "C69191", + "Orinoco": "F3FBD4", + "Oslo Gray": "878D91", + "Ottoman": "E9F8ED", + "Outer Space": "2D383A", + "Outrageous Orange": "FF6037", + "Oxford Blue": "384555", + "Oxley": "779E86", + "Oyster Bay": "DAFAFF", + "Oyster Pink": "E9CECD", + "Paarl": "A65529", + "Pablo": "776F61", + "Pacific Blue": "009DC4", + "Pacifika": "778120", + "Paco": "411F10", + "Padua": "ADE6C4", + "Pale Canary": "FFFF99", + "Pale Leaf": "C0D3B9", + "Pale Oyster": "988D77", + "Pale Prim": "FDFEB8", + "Pale Rose": "FFE1F2", + "Pale Sky": "6E7783", + "Pale Slate": "C3BFC1", + "Palm Green": "09230F", + "Palm Leaf": "19330E", + "Pampas": "F4F2EE", + "Panache": "EAF6EE", + "Pancho": "EDCDAB", + "Papaya Whip": "FFEFD5", + "Paprika": "8D0226", + "Paradiso": "317D82", + "Parchment": "F1E9D2", + "Paris Daisy": "FFF46E", + "Paris M": "26056A", + "Paris White": "CADCD4", + "Parsley": "134F19", + "Pastel Green": "77DD77", + "Pastel Pink": "FFD1DC", + "Patina": "639A8F", + "Pattens Blue": "DEF5FF", + "Paua": "260368", + "Pavlova": "D7C498", + "Peach": "FFE5B4", + "Peach Cream": "FFF0DB", + "Peach Orange": "FFCC99", + "Peach Schnapps": "FFDCD6", + "Peach Yellow": "FADFAD", + "Peanut": "782F16", + "Pear": "D1E231", + "Pearl Bush": "E8E0D5", + "Pearl Lusta": "FCF4DC", + "Peat": "716B56", + "Pelorous": "3EABBF", + "Peppermint": "E3F5E1", + "Perano": "A9BEF2", + "Perfume": "D0BEF8", + "Periglacial Blue": "E1E6D6", + "Periwinkle": "CCCCFF", + "Periwinkle Gray": "C3CDE6", + "Persian Blue": "1C39BB", + "Persian Green": "00A693", + "Persian Indigo": "32127A", + "Persian Pink": "F77FBE", + "Persian Plum": "701C1C", + "Persian Red": "CC3333", + "Persian Rose": "FE28A2", + "Persimmon": "FF6B53", + "Peru Tan": "7F3A02", + "Pesto": "7C7631", + "Petite Orchid": "DB9690", + "Pewter": "96A8A1", + "Pharlap": "A3807B", + "Picasso": "FFF39D", + "Pickled Bean": "6E4826", + "Pickled Bluewood": "314459", + "Picton Blue": "45B1E8", + "Pig Pink": "FDD7E4", + "Pigeon Post": "AFBDD9", + "Pigment Indigo": "4B0082", + "Pine Cone": "6D5E54", + "Pine Glade": "C7CD90", + "Pine Green": "01796F", + "Pine Tree": "171F04", + "Pink": "FFC0CB", + "Pink Flamingo": "FF66FF", + "Pink Flare": "E1C0C8", + "Pink Lace": "FFDDF4", + "Pink Lady": "FFF1D8", + "Pink Salmon": "FF91A4", + "Pink Swan": "BEB5B7", + "Piper": "C96323", + "Pipi": "FEF4CC", + "Pippin": "FFE1DF", + "Pirate Gold": "BA7F03", + "Pistachio": "9DC209", + "Pixie Green": "C0D8B6", + "Pizazz": "FF9000", + "Pizza": "C99415", + "Plantation": "27504B", + "Plum": "843179", + "Pohutukawa": "8F021C", + "Polar": "E5F9F6", + "Polo Blue": "8DA8CC", + "Pomegranate": "F34723", + "Pompadour": "660045", + "Porcelain": "EFF2F3", + "Porsche": "EAAE69", + "Port Gore": "251F4F", + "Portafino": "FFFFB4", + "Portage": "8B9FEE", + "Portica": "F9E663", + "Pot Pourri": "F5E7E2", + "Potters Clay": "8C5738", + "Powder Ash": "BCC9C2", + "Powder Blue": "B0E0E6", + "Prairie Sand": "9A3820", + "Prelude": "D0C0E5", + "Prim": "F0E2EC", + "Primrose": "EDEA99", + "Provincial Pink": "FEF5F1", + "Prussian Blue": "003153", + "Puce": "CC8899", + "Pueblo": "7D2C14", + "Puerto Rico": "3FC1AA", + "Pumice": "C2CAC4", + "Pumpkin": "FF7518", + "Pumpkin Skin": "B1610B", + "Punch": "DC4333", + "Punga": "4D3D14", + "Purple": "660099", + "Purple Heart": "652DC1", + "Purple Mountain's Majesty": "9678B6", + "Purple Pizzazz": "FF00CC", + "Putty": "E7CD8C", + "Quarter Pearl Lusta": "FFFDF4", + "Quarter Spanish White": "F7F2E1", + "Quicksand": "BD978E", + "Quill Gray": "D6D6D1", + "Quincy": "623F2D", + "Racing Green": "0C1911", + "Radical Red": "FF355E", + "Raffia": "EADAB8", + "Rainee": "B9C8AC", + "Rajah": "F7B668", + "Rangitoto": "2E3222", + "Rangoon Green": "1C1E13", + "Raven": "727B89", + "Raw Sienna": "D27D46", + "Raw Umber": "734A12", + "Razzle Dazzle Rose": "FF33CC", + "Razzmatazz": "E30B5C", + "Rebel": "3C1206", + "Red": "FF0000", + "Red Beech": "7B3801", + "Red Berry": "8E0000", + "Red Damask": "DA6A41", + "Red Devil": "860111", + "Red Orange": "FF3F34", + "Red Oxide": "6E0902", + "Red Ribbon": "ED0A3F", + "Red Robin": "80341F", + "Red Stage": "D05F04", + "Red Violet": "C71585", + "Redwood": "5D1E0F", + "Reef": "C9FFA2", + "Reef Gold": "9F821C", + "Regal Blue": "013F6A", + "Regent Gray": "86949F", + "Regent St Blue": "AAD6E6", + "Remy": "FEEBF3", + "Reno Sand": "A86515", + "Resolution Blue": "002387", + "Revolver": "2C1632", + "Rhino": "2E3F62", + "Rice Cake": "FFFEF0", + "Rice Flower": "EEFFE2", + "Rich Gold": "A85307", + "Rio Grande": "BBD009", + "Ripe Lemon": "F4D81C", + "Ripe Plum": "410056", + "Riptide": "8BE6D8", + "River Bed": "434C59", + "Rob Roy": "EAC674", + "Robin's Egg Blue": "00CCCC", + "Rock": "4D3833", + "Rock Blue": "9EB1CD", + "Rock Spray": "BA450C", + "Rodeo Dust": "C9B29B", + "Rolling Stone": "747D83", + "Roman": "DE6360", + "Roman Coffee": "795D4C", + "Romance": "FFFEFD", + "Romantic": "FFD2B7", + "Ronchi": "ECC54E", + "Roof Terracotta": "A62F20", + "Rope": "8E4D1E", + "Rose": "FF007F", + "Rose Bud": "FBB2A3", + "Rose Bud Cherry": "800B47", + "Rose Fog": "E7BCB4", + "Rose White": "FFF6F5", + "Rose of Sharon": "BF5500", + "Rosewood": "65000B", + "Roti": "C6A84B", + "Rouge": "A23B6C", + "Royal Blue": "4169E1", + "Royal Heath": "AB3472", + "Royal Purple": "6B3FA0", + "Rum": "796989", + "Rum Swizzle": "F9F8E4", + "Russet": "80461B", + "Russett": "755A57", + "Rust": "B7410E", + "Rustic Red": "480404", + "Rusty Nail": "86560A", + "Saddle": "4C3024", + "Saddle Brown": "583401", + "Saffron": "F4C430", + "Saffron Mango": "F9BF58", + "Sage": "9EA587", + "Sahara": "B7A214", + "Sahara Sand": "F1E788", + "Sail": "B8E0F9", + "Salem": "097F4B", + "Salmon": "FF8C69", + "Salomie": "FEDB8D", + "Salt Box": "685E6E", + "Saltpan": "F1F7F2", + "Sambuca": "3A2010", + "San Felix": "0B6207", + "San Juan": "304B6A", + "San Marino": "456CAC", + "Sand Dune": "826F65", + "Sandal": "AA8D6F", + "Sandrift": "AB917A", + "Sandstone": "796D62", + "Sandwisp": "F5E7A2", + "Sandy Beach": "FFEAC8", + "Sandy brown": "F4A460", + "Sangria": "92000A", + "Sanguine Brown": "8D3D38", + "Santa Fe": "B16D52", + "Santas Gray": "9FA0B1", + "Sapling": "DED4A4", + "Sapphire": "2F519E", + "Saratoga": "555B10", + "Satin Linen": "E6E4D4", + "Sauvignon": "FFF5F3", + "Sazerac": "FFF4E0", + "Scampi": "675FA6", + "Scandal": "CFFAF4", + "Scarlet": "FF2400", + "Scarlet Gum": "431560", + "Scarlett": "950015", + "Scarpa Flow": "585562", + "Schist": "A9B497", + "School bus Yellow": "FFD800", + "Schooner": "8B847E", + "Science Blue": "0066CC", + "Scooter": "2EBFD4", + "Scorpion": "695F62", + "Scotch Mist": "FFFBDC", + "Screamin' Green": "66FF66", + "Sea Buckthorn": "FBA129", + "Sea Green": "2E8B57", + "Sea Mist": "C5DBCA", + "Sea Nymph": "78A39C", + "Sea Pink": "ED989E", + "Seagull": "80CCEA", + "Seance": "731E8F", + "Seashell": "F1F1F1", + "Seashell Peach": "FFF5EE", + "Seaweed": "1B2F11", + "Selago": "F0EEFD", + "Selective Yellow": "FFBA00", + "Sepia": "704214", + "Sepia Black": "2B0202", + "Sepia Skin": "9E5B40", + "Serenade": "FFF4E8", + "Shadow": "837050", + "Shadow Green": "9AC2B8", + "Shady Lady": "AAA5A9", + "Shakespeare": "4EABD1", + "Shalimar": "FBFFBA", + "Shamrock": "33CC99", + "Shark": "25272C", + "Sherpa Blue": "004950", + "Sherwood Green": "02402C", + "Shilo": "E8B9B3", + "Shingle Fawn": "6B4E31", + "Ship Cove": "788BBA", + "Ship Gray": "3E3A44", + "Shiraz": "B20931", + "Shocking": "E292C0", + "Shocking Pink": "FC0FC0", + "Shuttle Gray": "5F6672", + "Siam": "646A54", + "Sidecar": "F3E7BB", + "Silk": "BDB1A8", + "Silver": "C0C0C0", + "Silver Chalice": "ACACAC", + "Silver Rust": "C9C0BB", + "Silver Sand": "BFC1C2", + "Silver Tree": "66B58F", + "Sinbad": "9FD7D3", + "Siren": "7A013A", + "Sirocco": "718080", + "Sisal": "D3CBBA", + "Skeptic": "CAE6DA", + "Sky Blue": "76D7EA", + "Slate Gray": "708090", + "Smalt": "003399", + "Smalt Blue": "51808F", + "Smoky": "605B73", + "Snow Drift": "F7FAF7", + "Snow Flurry": "E4FFD1", + "Snowy Mint": "D6FFDB", + "Snuff": "E2D8ED", + "Soapstone": "FFFBF9", + "Soft Amber": "D1C6B4", + "Soft Peach": "F5EDEF", + "Solid Pink": "893843", + "Solitaire": "FEF8E2", + "Solitude": "EAF6FF", + "Sorbus": "FD7C07", + "Sorrell Brown": "CEB98F", + "Soya Bean": "6A6051", + "Spanish Green": "819885", + "Spectra": "2F5A57", + "Spice": "6A442E", + "Spicy Mix": "885342", + "Spicy Mustard": "74640D", + "Spicy Pink": "816E71", + "Spindle": "B6D1EA", + "Spray": "79DEEC", + "Spring Green": "00FF7F", + "Spring Leaves": "578363", + "Spring Rain": "ACCBB1", + "Spring Sun": "F6FFDC", + "Spring Wood": "F8F6F1", + "Sprout": "C1D7B0", + "Spun Pearl": "AAABB7", + "Squirrel": "8F8176", + "St Tropaz": "2D569B", + "Stack": "8A8F8A", + "Star Dust": "9F9F9C", + "Stark White": "E5D7BD", + "Starship": "ECF245", + "Steel Blue": "4682B4", + "Steel Gray": "262335", + "Stiletto": "9C3336", + "Stonewall": "928573", + "Storm Dust": "646463", + "Storm Gray": "717486", + "Stratos": "000741", + "Straw": "D4BF8D", + "Strikemaster": "956387", + "Stromboli": "325D52", + "Studio": "714AB2", + "Submarine": "BAC7C9", + "Sugar Cane": "F9FFF6", + "Sulu": "C1F07C", + "Summer Green": "96BBAB", + "Sun": "FBAC13", + "Sundance": "C9B35B", + "Sundown": "FFB1B3", + "Sunflower": "E4D422", + "Sunglo": "E16865", + "Sunglow": "FFCC33", + "Sunset Orange": "FE4C40", + "Sunshade": "FF9E2C", + "Supernova": "FFC901", + "Surf": "BBD7C1", + "Surf Crest": "CFE5D2", + "Surfie Green": "0C7A79", + "Sushi": "87AB39", + "Suva Gray": "888387", + "Swamp": "001B1C", + "Swamp Green": "ACB78E", + "Swans Down": "DCF0EA", + "Sweet Corn": "FBEA8C", + "Sweet Pink": "FD9FA2", + "Swirl": "D3CDC5", + "Swiss Coffee": "DDD6D5", + "Sycamore": "908D39", + "Tabasco": "A02712", + "Tacao": "EDB381", + "Tacha": "D6C562", + "Tahiti Gold": "E97C07", + "Tahuna Sands": "EEF0C8", + "Tall Poppy": "B32D29", + "Tallow": "A8A589", + "Tamarillo": "991613", + "Tamarind": "341515", + "Tan": "D2B48C", + "Tan Hide": "FA9D5A", + "Tana": "D9DCC1", + "Tangaroa": "03163C", + "Tangerine": "F28500", + "Tango": "ED7A1C", + "Tapa": "7B7874", + "Tapestry": "B05E81", + "Tara": "E1F6E8", + "Tarawera": "073A50", + "Tasman": "CFDCCF", + "Taupe": "483C32", + "Taupe Gray": "B3AF95", + "Tawny Port": "692545", + "Te Papa Green": "1E433C", + "Tea": "C1BAB0", + "Tea Green": "D0F0C0", + "Teak": "B19461", + "Teal": "008080", + "Teal Blue": "044259", + "Temptress": "3B000B", + "Tenn": "CD5700", + "Tequila": "FFE6C7", + "Terracotta": "E2725B", + "Texas": "F8F99C", + "Texas Rose": "FFB555", + "Thatch": "B69D98", + "Thatch Green": "403D19", + "Thistle": "D8BFD8", + "Thistle Green": "CCCAA8", + "Thunder": "33292F", + "Thunderbird": "C02B18", + "Tia Maria": "C1440E", + "Tiara": "C3D1D1", + "Tiber": "063537", + "Tickle Me Pink": "FC80A5", + "Tidal": "F1FFAD", + "Tide": "BFB8B0", + "Timber Green": "16322C", + "Timberwolf": "D9D6CF", + "Titan White": "F0EEFF", + "Toast": "9A6E61", + "Tobacco Brown": "715D47", + "Toledo": "3A0020", + "Tolopea": "1B0245", + "Tom Thumb": "3F583B", + "Tonys Pink": "E79F8C", + "Topaz": "7C778A", + "Torch Red": "FD0E35", + "Torea Bay": "0F2D9E", + "Tory Blue": "1450AA", + "Tosca": "8D3F3F", + "Totem Pole": "991B07", + "Tower Gray": "A9BDBF", + "Tradewind": "5FB3AC", + "Tranquil": "E6FFFF", + "Travertine": "FFFDE8", + "Tree Poppy": "FC9C1D", + "Treehouse": "3B2820", + "Trendy Green": "7C881A", + "Trendy Pink": "8C6495", + "Trinidad": "E64E03", + "Tropical Blue": "C3DDF9", + "Tropical Rain Forest": "00755E", + "Trout": "4A4E5A", + "True V": "8A73D6", + "Tuatara": "363534", + "Tuft Bush": "FFDDCD", + "Tulip Tree": "EAB33B", + "Tumbleweed": "DEA681", + "Tuna": "353542", + "Tundora": "4A4244", + "Turbo": "FAE600", + "Turkish Rose": "B57281", + "Turmeric": "CABB48", + "Turquoise": "30D5C8", + "Turquoise Blue": "6CDAE7", + "Turtle Green": "2A380B", + "Tuscany": "BD5E2E", + "Tusk": "EEF3C3", + "Tussock": "C5994B", + "Tutu": "FFF1F9", + "Twilight": "E4CFDE", + "Twilight Blue": "EEFDFF", + "Twine": "C2955D", + "Tyrian Purple": "66023C", + "Ultramarine": "120A8F", + "Valencia": "D84437", + "Valentino": "350E42", + "Valhalla": "2B194F", + "Van Cleef": "49170C", + "Vanilla": "D1BEA8", + "Vanilla Ice": "F3D9DF", + "Varden": "FFF6DF", + "Venetian Red": "72010F", + "Venice Blue": "055989", + "Venus": "928590", + "Verdigris": "5D5E37", + "Verdun Green": "495400", + "Vermilion": "FF4D00", + "Vesuvius": "B14A0B", + "Victoria": "534491", + "Vida Loca": "549019", + "Viking": "64CCDB", + "Vin Rouge": "983D61", + "Viola": "CB8FA9", + "Violent Violet": "290C5E", + "Violet": "240A40", + "Violet Eggplant": "991199", + "Violet Red": "F7468A", + "Viridian": "40826D", + "Viridian Green": "678975", + "Vis Vis": "FFEFA1", + "Vista Blue": "8FD6B4", + "Vista White": "FCF8F7", + "Vivid Tangerine": "FF9980", + "Vivid Violet": "803790", + "Voodoo": "533455", + "Vulcan": "10121D", + "Wafer": "DECBC6", + "Waikawa Gray": "5A6E9C", + "Waiouru": "363C0D", + "Walnut": "773F1A", + "Wasabi": "788A25", + "Water Leaf": "A1E9DE", + "Watercourse": "056F57", + "Waterloo ": "7B7C94", + "Wattle": "DCD747", + "Watusi": "FFDDCF", + "Wax Flower": "FFC0A8", + "We Peep": "F7DBE6", + "Web Orange": "FFA500", + "Wedgewood": "4E7F9E", + "Well Read": "B43332", + "West Coast": "625119", + "West Side": "FF910F", + "Westar": "DCD9D2", + "Wewak": "F19BAB", + "Wheat": "F5DEB3", + "Wheatfield": "F3EDCF", + "Whiskey": "D59A6F", + "Whisper": "F7F5FA", + "White": "FFFFFF", + "White Ice": "DDF9F1", + "White Lilac": "F8F7FC", + "White Linen": "F8F0E8", + "White Pointer": "FEF8FF", + "White Rock": "EAE8D4", + "Wild Blue Yonder": "7A89B8", + "Wild Rice": "ECE090", + "Wild Sand": "F4F4F4", + "Wild Strawberry": "FF3399", + "Wild Watermelon": "FD5B78", + "Wild Willow": "B9C46A", + "William": "3A686C", + "Willow Brook": "DFECDA", + "Willow Grove": "65745D", + "Windsor": "3C0878", + "Wine Berry": "591D35", + "Winter Hazel": "D5D195", + "Wisp Pink": "FEF4F8", + "Wisteria": "9771B5", + "Wistful": "A4A6D3", + "Witch Haze": "FFFC99", + "Wood Bark": "261105", + "Woodland": "4D5328", + "Woodrush": "302A0F", + "Woodsmoke": "0C0D0F", + "Woody Brown": "483131", + "Xanadu": "738678", + "Yellow": "FFFF00", + "Yellow Green": "C5E17A", + "Yellow Metal": "716338", + "Yellow Orange": "FFAE42", + "Yellow Sea": "FEA904", + "Your Pink": "FFC3C0", + "Yukon Gold": "7B6608", + "Yuma": "CEC291", + "Zambezi": "685558", + "Zanah": "DAECD6", + "Zest": "E5841B", + "Zeus": "292319", + "Ziggurat": "BFDBE2", + "Zinnwaldite": "EBC2AF", + "Zircon": "F4F8FF", + "Zombie": "E4D69B", + "Zorba": "A59B91", + "Zuccini": "044022", + "Zumthor": "EDF6FF" +} -- cgit v1.2.3 From c87f4451206cfc1315fd32c33836f81a5e6ea300 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 10 Sep 2021 07:47:12 -0400 Subject: Test to capture all user_input --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index d7fff503..c4df3e10 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -32,7 +32,7 @@ class Color(commands.Cog): self.bot = bot @commands.command(aliases=["colour"]) - async def color(self, ctx: commands.Context, mode: str, user_color: str) -> None: + async def color(self, ctx: commands.Context, mode: str, *, user_color: str) -> None: """Send information on input color code or color name.""" logger.info(f"{mode = }") logger.info(f"{user_color = }") -- cgit v1.2.3 From fc5d7ea343336a3fc62617d4042a13a208763c6c Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Sat, 11 Sep 2021 04:17:18 +0530 Subject: Added "colour information" and "colour conversion" features Details: https://github.com/python-discord/sir-lancebot/issues/677 NOTE: get_color_fields (line 122) method explicity requires a valid tuple of RGB values. --- bot/exts/utilities/color.py | 134 +++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 34 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index c4df3e10..6abfc006 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,4 +1,4 @@ -# import colorsys +import colorsys import logging import re from io import BytesIO @@ -76,44 +76,28 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return - main_embed = Embed( - title=user_color, # need to replace with fuzzymatch color name - color=hex_color, - ) async with ctx.typing(): - file = await self._create_thumbnail_attachment(rgb_color) + main_embed = Embed( + title=user_color, # need to replace with fuzzymatch color name + description='(Approx..)', + color=hex_color, + ) + + file = await self.create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") - main_embed.add_field( - name="Hex", - value=f">>Hex #{hex_color}", - inline=False, - ) - main_embed.add_field( - name="RGB", - value=f">>RGB {rgb_color}", - inline=False, - ) - """ - main_embed.add_field( - name="HSV", - value=f">>HSV {hsv_color}", - inline=False, - ) - main_embed.add_field( - name="HSL", - value=f">>HSL {hsl_color}", - inline=False, - ) - main_embed.add_field( - name="CMYK", - value=f">>CMYK {cmyk_color}", - inline=False, - ) - """ + fields = self.get_color_fields(rgb_color) + for field in fields: + main_embed.add_field( + name=field['name'], + value=field['value'], + inline=False, + ) + await ctx.send(file=file, embed=main_embed) - async def _create_thumbnail_attachment(self, color: str) -> File: + @staticmethod + async def create_thumbnail_attachment(color: str) -> File: """Generate a thumbnail from `color`.""" thumbnail = Image.new("RGB", (100, 100), color=color) bufferedio = BytesIO() @@ -124,6 +108,88 @@ class Color(commands.Cog): return file + @staticmethod + def get_color_fields(rgb_color: tuple[int, int, int]) -> list[dict]: + """Converts from `RGB` to `CMYK`, `HSV`, `HSL` and returns a list of fields.""" + + def _rgb_to_hex(rgb_color: tuple[int, int, int]) -> str: + """To convert from `RGB` to `Hex` notation.""" + return '#' + ''.join(hex(color)[2:].zfill(2) for color in rgb_color).upper() + + def _rgb_to_cmyk(rgb_color: tuple[int, int, int]) -> tuple[int, int, int, int]: + """To convert from `RGB` to `CMYK` color space.""" + r, g, b = rgb_color + + # RGB_SCALE -> 255 + # CMYK_SCALE -> 100 + + if (r == g == b == 0): + return 0, 0, 0, 100 # Representing Black + + # rgb [0,RGB_SCALE] -> cmy [0,1] + c = 1 - r / 255 + m = 1 - g / 255 + y = 1 - b / 255 + + # extract out k [0, 1] + min_cmy = min(c, m, y) + c = (c - min_cmy) / (1 - min_cmy) + m = (m - min_cmy) / (1 - min_cmy) + y = (y - min_cmy) / (1 - min_cmy) + k = min_cmy + + # rescale to the range [0,CMYK_SCALE] and round off + c = round(c * 100) + m = round(m * 100) + y = round(y * 100) + k = round(k * 100) + + return c, m, y, k + + def _rgb_to_hsv(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: + """To convert from `RGB` to `HSV` color space.""" + r, g, b = rgb_color + h, v, s = colorsys.rgb_to_hsv(r/float(255), g/float(255), b/float(255)) + h = round(h*360) + s = round(s*100) + v = round(v*100) + return h, s, v + + def _rgb_to_hsl(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: + """To convert from `RGB` to `HSL` color space.""" + r, g, b = rgb_color + h, l, s = colorsys.rgb_to_hls(r/float(255), g/float(255), b/float(255)) + h = round(h*360) + s = round(s*100) + l = round(l*100) # noqa: E741 It's little `L`, Reason: To maintain consistency. + return h, s, l + + hex_color = _rgb_to_hex(rgb_color) + cmyk_color = _rgb_to_cmyk(rgb_color) + hsv_color = _rgb_to_hsv(rgb_color) + hsl_color = _rgb_to_hsl(rgb_color) + + all_fields = [ + { + "name": "RGB", + "value": f"» rgb {rgb_color}\n» hex {hex_color}" + }, + { + "name": "CMYK", + "value": f"» cmyk {cmyk_color}" + }, + { + "name": "HSV", + "value": f"» hsv {hsv_color}" + }, + { + "name": "HSL", + "value": f"» hsl {hsl_color}" + }, + ] + + return all_fields + # if user_color in color_lists: # # fuzzy match for color -- cgit v1.2.3 From 4e316e7991862db76b78e16019c02461c3c52fc2 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 11 Sep 2021 09:57:13 -0400 Subject: Add fuzzy match function I made a few changes, the biggest being the fuzzy match function to return a hex color code based on an input color name. Open items that I can think of so far: -Since the json file has color names and hex values, in order to use fuzzy matching for a color name the color must first be converted to hex. Currently there is only a rgb to anything function which returns values in a dictionary. -The main embed creation references the rgb_color before it is defined, should the command function be moved to the bottom of the file or just the main embed creation and sending? -When using the rgb mode, should the user be forced to do (r, g, b) or should the command handle an input of "r, g, b"? If you are reading this, thank you. --- bot/exts/utilities/color.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6abfc006..9e199dd4 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,4 +1,5 @@ import colorsys +import json import logging import re from io import BytesIO @@ -6,7 +7,7 @@ from io import BytesIO from PIL import Image, ImageColor from discord import Embed, File from discord.ext import commands -# from rapidfuzz import process +from rapidfuzz import process from bot.bot import Bot from bot.constants import Colours @@ -23,6 +24,8 @@ ERROR_MSG = """The color code {user_color} is not a possible color combination. \nHex: #000000-#FFFFFF """ +COLOR_LIST = "bot/resources/utilities/ryanzec_colours.json" + # define color command class Color(commands.Cog): @@ -46,7 +49,7 @@ class Color(commands.Cog): else: await ctx.send( embed=Embed( - title="An error has occured.", + title="There was an issue converting the hex color code.", description=ERROR_MSG.format(user_color=user_color), ) ) @@ -58,9 +61,10 @@ class Color(commands.Cog): pass elif mode.lower() == "cmyk": pass + elif mode.lower() == "name": + color_name, hex_color = self.match_color(user_color) else: # mode is either None or an invalid code - # need to handle whether user passes color name if mode is None: no_mode_embed = Embed( title="No 'mode' was passed, please define a color code.", @@ -70,7 +74,7 @@ class Color(commands.Cog): return wrong_mode_embed = Embed( title=f"The color code {mode} is not a valid option", - description="Possible modes are: Hex, RGB, HSV, HSL and CMYK.", + description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", color=Colours.soft_red, ) await ctx.send(embed=wrong_mode_embed) @@ -78,15 +82,15 @@ class Color(commands.Cog): async with ctx.typing(): main_embed = Embed( - title=user_color, # need to replace with fuzzymatch color name + title=color_name, description='(Approx..)', - color=hex_color, + color=rgb_color, ) file = await self.create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") - fields = self.get_color_fields(rgb_color) + for field in fields: main_embed.add_field( name=field['name'], @@ -94,7 +98,7 @@ class Color(commands.Cog): inline=False, ) - await ctx.send(file=file, embed=main_embed) + await ctx.send(file=file, embed=main_embed) @staticmethod async def create_thumbnail_attachment(color: str) -> File: @@ -192,6 +196,17 @@ class Color(commands.Cog): # if user_color in color_lists: # # fuzzy match for color + @staticmethod + def match_color(user_color: str) -> str: + """Use fuzzy matching to return a hex color code based on the user's input.""" + with open(COLOR_LIST) as f: + color_list = json.load(f) + logger.debug(f"{type(color_list) = }") + match, certainty, _ = process.extractOne(query=user_color, choices=color_list.keys(), score_cutoff=50) + logger.debug(f"{match = }, {certainty = }") + hex_match = color_list[match] + logger.debug(f"{hex_match = }") + return match, hex_match def setup(bot: Bot) -> None: -- cgit v1.2.3 From c6333ab48ddbc37af40cd958cd37494be7ff50e7 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 11 Sep 2021 10:09:27 -0400 Subject: Remove placeholder comment --- bot/exts/utilities/color.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9e199dd4..6452d292 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -194,8 +194,6 @@ class Color(commands.Cog): return all_fields - # if user_color in color_lists: - # # fuzzy match for color @staticmethod def match_color(user_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" -- cgit v1.2.3 From 2cc1ad0538d4edb69eddfe771bd3068d18ed54f3 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 12 Sep 2021 08:39:47 -0400 Subject: Load json file once --- bot/exts/utilities/color.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6452d292..dd470197 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -25,6 +25,8 @@ ERROR_MSG = """The color code {user_color} is not a possible color combination. """ COLOR_LIST = "bot/resources/utilities/ryanzec_colours.json" +with open(COLOR_LIST) as f: + COLOR_JSON = json.load(f) # define color command @@ -197,12 +199,9 @@ class Color(commands.Cog): @staticmethod def match_color(user_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" - with open(COLOR_LIST) as f: - color_list = json.load(f) - logger.debug(f"{type(color_list) = }") - match, certainty, _ = process.extractOne(query=user_color, choices=color_list.keys(), score_cutoff=50) + match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_JSON.keys(), score_cutoff=50) logger.debug(f"{match = }, {certainty = }") - hex_match = color_list[match] + hex_match = COLOR_JSON[match] logger.debug(f"{hex_match = }") return match, hex_match -- cgit v1.2.3 From 85de760ad006575bfb61472be0aa346406ac7d2c Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 15 Sep 2021 16:16:52 -0400 Subject: Fix Flake8 spacing errors --- bot/exts/utilities/color.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index dd470197..eb9d5f4d 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -155,19 +155,19 @@ class Color(commands.Cog): def _rgb_to_hsv(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: """To convert from `RGB` to `HSV` color space.""" r, g, b = rgb_color - h, v, s = colorsys.rgb_to_hsv(r/float(255), g/float(255), b/float(255)) - h = round(h*360) - s = round(s*100) - v = round(v*100) + h, v, s = colorsys.rgb_to_hsv(r / float(255), g / float(255), b / float(255)) + h = round(h * 360) + s = round(s * 100) + v = round(v * 100) return h, s, v def _rgb_to_hsl(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: """To convert from `RGB` to `HSL` color space.""" r, g, b = rgb_color - h, l, s = colorsys.rgb_to_hls(r/float(255), g/float(255), b/float(255)) - h = round(h*360) - s = round(s*100) - l = round(l*100) # noqa: E741 It's little `L`, Reason: To maintain consistency. + h, l, s = colorsys.rgb_to_hls(r / float(255), g / float(255), b / float(255)) + h = round(h * 360) + s = round(s * 100) + l = round(l * 100) # noqa: E741 It's little `L`, Reason: To maintain consistency. return h, s, l hex_color = _rgb_to_hex(rgb_color) -- cgit v1.2.3 From 0f777557d67bdf117eafcba3ab98192dd420cf96 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 19 Sep 2021 08:20:18 -0400 Subject: Reword json file variables and mapping --- bot/exts/utilities/color.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index eb9d5f4d..94c9d337 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -24,9 +24,9 @@ ERROR_MSG = """The color code {user_color} is not a possible color combination. \nHex: #000000-#FFFFFF """ -COLOR_LIST = "bot/resources/utilities/ryanzec_colours.json" -with open(COLOR_LIST) as f: - COLOR_JSON = json.load(f) +COLOR_JSON_PATH = "bot/resources/utilities/ryanzec_colours.json" +with open(COLOR_JSON_PATH) as f: + COLOR_MAPPING = json.load(f) # define color command @@ -199,9 +199,9 @@ class Color(commands.Cog): @staticmethod def match_color(user_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" - match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_JSON.keys(), score_cutoff=50) + match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_MAPPING.keys(), score_cutoff=50) logger.debug(f"{match = }, {certainty = }") - hex_match = COLOR_JSON[match] + hex_match = COLOR_MAPPING[match] logger.debug(f"{hex_match = }") return match, hex_match -- cgit v1.2.3 From 4a2b89dbde41057ba14c08f8994c6d02b3c114b8 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 19 Sep 2021 10:20:58 -0400 Subject: Continue work on hex and rgb color commands --- bot/exts/utilities/color.py | 87 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 94c9d337..2bec6ba3 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -31,23 +31,45 @@ with open(COLOR_JSON_PATH) as f: # define color command class Color(commands.Cog): - """User initiated command to receive color information.""" + """User initiated commands to receive color information.""" def __init__(self, bot: Bot): self.bot = bot @commands.command(aliases=["colour"]) async def color(self, ctx: commands.Context, mode: str, *, user_color: str) -> None: - """Send information on input color code or color name.""" - logger.info(f"{mode = }") - logger.info(f"{user_color = }") + """ + Send information on input color code or color name. + + Possible modes are: "hex", "rgb", "hsv", "hsl", "cmyk" or "name". + """ + logger.debug(f"{mode = }") + logger.debug(f"{user_color = }") if mode.lower() == "hex": - hex_match = re.search(r"^#(?:[0-9a-fA-F]{3}){1,2}$", user_color) + hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", user_color) if hex_match: hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) - rgb_color = ImageColor.getcolor(user_color, "RGB") - logger.info(f"{hex_color = }") - logger.info(f"{rgb_color = }") + if "#" in user_color: + rgb_color = ImageColor.getcolor(user_color, "RGB") + elif "0x" in user_color: + hex_ = user_color.replace("0x", "#") + rgb_color = ImageColor.getcolor(hex_, "RGB") + else: + hex_ = "#" + user_color + rgb_color = ImageColor.getcolor(hex_, "RGB") + (r, g, b) = rgb_color + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") + hsv_color = all_colors[3]["value"].replace("» hsv ", "") + hsl_color = all_colors[4]["value"].replace("» hsl ", "") + logger.debug(f"{rgb_color = }") + logger.debug(f"{hex_color = }") + logger.debug(f"{hsv_color = }") + logger.debug(f"{hsl_color = }") + logger.debug(f"{cmyk_color = }") + color_name, _ = self.match_color(hex_color) else: await ctx.send( embed=Embed( @@ -56,7 +78,22 @@ class Color(commands.Cog): ) ) elif mode.lower() == "rgb": - pass + if "(" in user_color: + remove = "[() ]" + rgb_color = re.sub(remove, "", user_color) + rgb_color = tuple(map(int, rgb_color.split(","))) + elif "," in user_color: + rgb_color = tuple(map(int, user_color.split(","))) + else: + rgb_color = tuple(map(int, user_color.split(" "))) + (r, g, b) = rgb_color + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") + hsv_color = all_colors[3]["value"].replace("» hsv ", "") + hsl_color = all_colors[4]["value"].replace("» hsl ", "") + color_name, _ = self.match_color(hex_color) elif mode.lower() == "hsv": pass elif mode.lower() == "hsl": @@ -70,6 +107,7 @@ class Color(commands.Cog): if mode is None: no_mode_embed = Embed( title="No 'mode' was passed, please define a color code.", + description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", color=Colours.soft_red, ) await ctx.send(embed=no_mode_embed) @@ -86,7 +124,7 @@ class Color(commands.Cog): main_embed = Embed( title=color_name, description='(Approx..)', - color=rgb_color, + color=discord_rgb_int, ) file = await self.create_thumbnail_attachment(rgb_color) @@ -120,7 +158,7 @@ class Color(commands.Cog): def _rgb_to_hex(rgb_color: tuple[int, int, int]) -> str: """To convert from `RGB` to `Hex` notation.""" - return '#' + ''.join(hex(color)[2:].zfill(2) for color in rgb_color).upper() + return '#' + ''.join(hex(int(color))[2:].zfill(2) for color in rgb_color).upper() def _rgb_to_cmyk(rgb_color: tuple[int, int, int]) -> tuple[int, int, int, int]: """To convert from `RGB` to `CMYK` color space.""" @@ -178,7 +216,11 @@ class Color(commands.Cog): all_fields = [ { "name": "RGB", - "value": f"» rgb {rgb_color}\n» hex {hex_color}" + "value": f"» rgb {rgb_color}" + }, + { + "name": "HEX", + "value": f"» hex {hex_color}" }, { "name": "CMYK", @@ -197,13 +239,22 @@ class Color(commands.Cog): return all_fields @staticmethod - def match_color(user_color: str) -> str: + def match_color(input_hex_color: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" - match, certainty, _ = process.extractOne(query=user_color, choices=COLOR_MAPPING.keys(), score_cutoff=50) - logger.debug(f"{match = }, {certainty = }") - hex_match = COLOR_MAPPING[match] - logger.debug(f"{hex_match = }") - return match, hex_match + try: + match, certainty, _ = process.extractOne( + query=input_hex_color, + choices=COLOR_MAPPING.keys(), + score_cutoff=50 + ) + logger.debug(f"{match = }, {certainty = }") + hex_match = COLOR_MAPPING[match] + logger.debug(f"{hex_match = }") + return match, hex_match + except TypeError: + match = "No color name match found." + hex_match = input_hex_color + return match, hex_match def setup(bot: Bot) -> None: -- cgit v1.2.3 From 620142ba3586fce88a61886288bafd5f078f95e7 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 19 Sep 2021 17:49:32 -0400 Subject: Add all color modes and name matching --- bot/exts/utilities/color.py | 140 ++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 36 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 2bec6ba3..9b1f3776 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -45,6 +45,7 @@ class Color(commands.Cog): """ logger.debug(f"{mode = }") logger.debug(f"{user_color = }") + color_name = None if mode.lower() == "hex": hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", user_color) if hex_match: @@ -57,19 +58,6 @@ class Color(commands.Cog): else: hex_ = "#" + user_color rgb_color = ImageColor.getcolor(hex_, "RGB") - (r, g, b) = rgb_color - discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) - all_colors = self.get_color_fields(rgb_color) - hex_color = all_colors[1]["value"].replace("» hex ", "") - cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") - hsv_color = all_colors[3]["value"].replace("» hsv ", "") - hsl_color = all_colors[4]["value"].replace("» hsl ", "") - logger.debug(f"{rgb_color = }") - logger.debug(f"{hex_color = }") - logger.debug(f"{hsv_color = }") - logger.debug(f"{hsl_color = }") - logger.debug(f"{cmyk_color = }") - color_name, _ = self.match_color(hex_color) else: await ctx.send( embed=Embed( @@ -78,30 +66,22 @@ class Color(commands.Cog): ) ) elif mode.lower() == "rgb": - if "(" in user_color: - remove = "[() ]" - rgb_color = re.sub(remove, "", user_color) - rgb_color = tuple(map(int, rgb_color.split(","))) - elif "," in user_color: - rgb_color = tuple(map(int, user_color.split(","))) - else: - rgb_color = tuple(map(int, user_color.split(" "))) - (r, g, b) = rgb_color - discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) - all_colors = self.get_color_fields(rgb_color) - hex_color = all_colors[1]["value"].replace("» hex ", "") - cmyk_color = all_colors[2]["value"].replace("» cmyk ", "") - hsv_color = all_colors[3]["value"].replace("» hsv ", "") - hsl_color = all_colors[4]["value"].replace("» hsl ", "") - color_name, _ = self.match_color(hex_color) + rgb_color = self.tuple_create(user_color) elif mode.lower() == "hsv": - pass + hsv_temp = self.tuple_create(user_color) + rgb_color = self.hsv_to_rgb(hsv_temp) elif mode.lower() == "hsl": - pass + hsl_temp = self.tuple_create(user_color) + rgb_color = self.hsl_to_rgb(hsl_temp) elif mode.lower() == "cmyk": - pass + cmyk_temp = self.tuple_create(user_color) + rgb_color = self.cmyk_to_rgb(cmyk_temp) elif mode.lower() == "name": - color_name, hex_color = self.match_color(user_color) + color_name, hex_color = self.match_color_name(user_color) + if "#" in hex_color: + rgb_color = ImageColor.getcolor(hex_color, "RGB") + else: + rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") else: # mode is either None or an invalid code if mode is None: @@ -120,6 +100,14 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return + (r, g, b) = rgb_color + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + if color_name is None: + logger.debug(f"Find color name from hex color: {hex_color}") + color_name = self.match_color_hex(hex_color) + async with ctx.typing(): main_embed = Embed( title=color_name, @@ -239,11 +227,11 @@ class Color(commands.Cog): return all_fields @staticmethod - def match_color(input_hex_color: str) -> str: + def match_color_name(input_color_name: str) -> str: """Use fuzzy matching to return a hex color code based on the user's input.""" try: match, certainty, _ = process.extractOne( - query=input_hex_color, + query=input_color_name, choices=COLOR_MAPPING.keys(), score_cutoff=50 ) @@ -253,9 +241,89 @@ class Color(commands.Cog): return match, hex_match except TypeError: match = "No color name match found." - hex_match = input_hex_color + hex_match = input_color_name return match, hex_match + @staticmethod + def match_color_hex(input_hex_color: str) -> str: + """Use fuzzy matching to return a hex color code based on the user's input.""" + try: + match, certainty, _ = process.extractOne( + query=input_hex_color, + choices=COLOR_MAPPING.values(), + score_cutoff=80 + ) + logger.debug(f"{match = }, {certainty = }") + color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] + logger.debug(f"{color_name = }") + return color_name + except TypeError: + color_name = "No color name match found." + return color_name + + @staticmethod + def tuple_create(input_color: str) -> tuple[int, int, int]: + """ + Create a tuple of integers based on user's input. + + Can handle inputs of the types: + (100, 100, 100) + 100, 100, 100 + 100 100 100 + """ + if "(" in input_color: + remove = "[() ]" + color_tuple = re.sub(remove, "", input_color) + color_tuple = tuple(map(int, color_tuple.split(","))) + elif "," in input_color: + color_tuple = tuple(map(int, input_color.split(","))) + else: + color_tuple = tuple(map(int, input_color.split(" "))) + return color_tuple + + @staticmethod + def hsv_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsv color to rgb color.""" + (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped + h = h / 360 + s = s / 100 + v = v / 100 + rgb_color = colorsys.hsv_to_rgb(h, s, v) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + rgb_color = (r, g, b) + return rgb_color + + @staticmethod + def hsl_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsl color to rgb color.""" + (h, s, l) = input_color + h = h / 360 + s = s / 100 + l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. + rgb_color = colorsys.hls_to_rgb(h, l, s) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + rgb_color = (r, g, b) + return rgb_color + + @staticmethod + def cmyk_to_rgb(input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + """Function to convert cmyk color to rgb color.""" + c = input_color[0] + m = input_color[1] + y = input_color[2] + k = input_color[3] + r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) + g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) + b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) + rgb_color = (r, g, b) + return rgb_color + def setup(bot: Bot) -> None: """Load the Color Cog.""" -- cgit v1.2.3 From fe2b7d442bec05ab02836e2c5d7613d738fd5151 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 21 Sep 2021 06:51:55 -0400 Subject: fix: remove redundant rgb_color variable The conversion functions from hsv, hsl and cmyk now return r, g, b instead of a variable rgb_tuple. --- bot/exts/utilities/color.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9b1f3776..542a2e19 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -293,8 +293,7 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - rgb_color = (r, g, b) - return rgb_color + return r, g, b @staticmethod def hsl_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: @@ -308,8 +307,7 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - rgb_color = (r, g, b) - return rgb_color + return r, g, b @staticmethod def cmyk_to_rgb(input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: @@ -321,8 +319,7 @@ class Color(commands.Cog): r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - rgb_color = (r, g, b) - return rgb_color + return r, g, b def setup(bot: Bot) -> None: -- cgit v1.2.3 From c32a3f622be9c5d95602fb455bb557c3cd8a10b8 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:24:23 -0400 Subject: fix: create subcommands and restructure script -Makes "main" function `color_embed` that takes an rgb tuple, calls `all_colors` to get all other color types, gets a name from the hex color, creates embed, calls `create_thumbnail` to get image, and then sends main embed. -Makes functions `xxx_to_rgb` functions to call `color_embed` -Creates new `hex_to_rgb` function -TODO: test all functions and continue restructure. --- bot/exts/utilities/color.py | 81 +++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 542a2e19..5d37cbee 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -47,35 +47,16 @@ class Color(commands.Cog): logger.debug(f"{user_color = }") color_name = None if mode.lower() == "hex": - hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", user_color) - if hex_match: - hex_color = int(hex(int(user_color.replace("#", ""), 16)), 0) - if "#" in user_color: - rgb_color = ImageColor.getcolor(user_color, "RGB") - elif "0x" in user_color: - hex_ = user_color.replace("0x", "#") - rgb_color = ImageColor.getcolor(hex_, "RGB") - else: - hex_ = "#" + user_color - rgb_color = ImageColor.getcolor(hex_, "RGB") - else: - await ctx.send( - embed=Embed( - title="There was an issue converting the hex color code.", - description=ERROR_MSG.format(user_color=user_color), - ) - ) + self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": rgb_color = self.tuple_create(user_color) + self.embed_color(rgb_color) elif mode.lower() == "hsv": - hsv_temp = self.tuple_create(user_color) - rgb_color = self.hsv_to_rgb(hsv_temp) + self.hsv_to_rgb(user_color) elif mode.lower() == "hsl": - hsl_temp = self.tuple_create(user_color) - rgb_color = self.hsl_to_rgb(hsl_temp) + self.hsl_to_rgb(user_color) elif mode.lower() == "cmyk": - cmyk_temp = self.tuple_create(user_color) - rgb_color = self.cmyk_to_rgb(cmyk_temp) + self.cmyk_to_rgb(user_color) elif mode.lower() == "name": color_name, hex_color = self.match_color_name(user_color) if "#" in hex_color: @@ -100,6 +81,13 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return + async def color_embed( + self, + ctx: commands.Context, + rgb_color: tuple[int, int, int], + color_name: str = None + ) -> None: + """Take a RGB color tuple, create embed, and send.""" (r, g, b) = rgb_color discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) all_colors = self.get_color_fields(rgb_color) @@ -281,9 +269,9 @@ class Color(commands.Cog): color_tuple = tuple(map(int, input_color.split(" "))) return color_tuple - @staticmethod - def hsv_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsv color to rgb color.""" + def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsv color to rgb color and send main embed..""" + input_color = self.tuple_create(input_color) (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped h = h / 360 s = s / 100 @@ -293,11 +281,11 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - return r, g, b + self.color_embed((r, g, b)) - @staticmethod - def hsl_to_rgb(input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsl color to rgb color.""" + def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsl color to rgb color and send main embed..""" + input_color = self.tuple_create(input_color) (h, s, l) = input_color h = h / 360 s = s / 100 @@ -307,11 +295,11 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - return r, g, b + self.color_embed((r, g, b)) - @staticmethod - def cmyk_to_rgb(input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: - """Function to convert cmyk color to rgb color.""" + def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + """Function to convert cmyk color to rgb color and send main embed..""" + input_color = self.tuple_create(input_color) c = input_color[0] m = input_color[1] y = input_color[2] @@ -319,7 +307,28 @@ class Color(commands.Cog): r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - return r, g, b + self.color_embed((r, g, b)) + + async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: + """Create rgb color from hex string and send main embed.""" + hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) + if hex_match: + if "#" in hex_string: + rgb_color = ImageColor.getcolor(hex_string, "RGB") + elif "0x" in hex_string: + hex_ = hex_string.replace("0x", "#") + rgb_color = ImageColor.getcolor(hex_, "RGB") + else: + hex_ = "#" + hex_string + rgb_color = ImageColor.getcolor(hex_, "RGB") + self.color_embed(rgb_color) + else: + await ctx.send( + embed=Embed( + title="There was an issue converting the hex color code.", + description=ERROR_MSG.format(user_color=hex_string), + ) + ) def setup(bot: Bot) -> None: -- cgit v1.2.3 From eeebd656d233541246a407d839a0436f893a4b43 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:38:34 -0400 Subject: fix: restructure script --- bot/exts/utilities/color.py | 225 ++++++++++++++++++++++---------------------- 1 file changed, 115 insertions(+), 110 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 5d37cbee..67068809 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -50,19 +50,20 @@ class Color(commands.Cog): self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": rgb_color = self.tuple_create(user_color) - self.embed_color(rgb_color) + self.color_embed(ctx, rgb_color) elif mode.lower() == "hsv": - self.hsv_to_rgb(user_color) + self.hsv_to_rgb(ctx, user_color) elif mode.lower() == "hsl": - self.hsl_to_rgb(user_color) + self.hsl_to_rgb(ctx, user_color) elif mode.lower() == "cmyk": - self.cmyk_to_rgb(user_color) + self.cmyk_to_rgb(ctx, user_color) elif mode.lower() == "name": color_name, hex_color = self.match_color_name(user_color) if "#" in hex_color: rgb_color = ImageColor.getcolor(hex_color, "RGB") else: rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") + self.color_embed(ctx, rgb_color, color_name) else: # mode is either None or an invalid code if mode is None: @@ -81,44 +82,94 @@ class Color(commands.Cog): await ctx.send(embed=wrong_mode_embed) return - async def color_embed( - self, - ctx: commands.Context, - rgb_color: tuple[int, int, int], - color_name: str = None - ) -> None: - """Take a RGB color tuple, create embed, and send.""" - (r, g, b) = rgb_color - discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) - all_colors = self.get_color_fields(rgb_color) - hex_color = all_colors[1]["value"].replace("» hex ", "") - if color_name is None: - logger.debug(f"Find color name from hex color: {hex_color}") - color_name = self.match_color_hex(hex_color) + @staticmethod + def tuple_create(input_color: str) -> tuple[int, int, int]: + """ + Create a tuple of integers based on user's input. - async with ctx.typing(): - main_embed = Embed( - title=color_name, - description='(Approx..)', - color=discord_rgb_int, + Can handle inputs of the types: + (100, 100, 100) + 100, 100, 100 + 100 100 100 + """ + if "(" in input_color: + remove = "[() ]" + color_tuple = re.sub(remove, "", input_color) + color_tuple = tuple(map(int, color_tuple.split(","))) + elif "," in input_color: + color_tuple = tuple(map(int, input_color.split(","))) + else: + color_tuple = tuple(map(int, input_color.split(" "))) + return color_tuple + + async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: + """Function to convert hex color to rgb color and send main embed.""" + hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) + if hex_match: + if "#" in hex_string: + rgb_color = ImageColor.getcolor(hex_string, "RGB") + elif "0x" in hex_string: + hex_ = hex_string.replace("0x", "#") + rgb_color = ImageColor.getcolor(hex_, "RGB") + else: + hex_ = "#" + hex_string + rgb_color = ImageColor.getcolor(hex_, "RGB") + self.color_embed(rgb_color) + else: + await ctx.send( + embed=Embed( + title="There was an issue converting the hex color code.", + description=ERROR_MSG.format(user_color=hex_string), + ) ) - file = await self.create_thumbnail_attachment(rgb_color) - main_embed.set_thumbnail(url="attachment://color.png") - fields = self.get_color_fields(rgb_color) + def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsv color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped + h = h / 360 + s = s / 100 + v = v / 100 + rgb_color = colorsys.hsv_to_rgb(h, s, v) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + self.color_embed((r, g, b)) - for field in fields: - main_embed.add_field( - name=field['name'], - value=field['value'], - inline=False, - ) + def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsl color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + (h, s, l) = input_color + h = h / 360 + s = s / 100 + l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. + rgb_color = colorsys.hls_to_rgb(h, l, s) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + self.color_embed((r, g, b)) - await ctx.send(file=file, embed=main_embed) + def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + """Function to convert cmyk color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + c = input_color[0] + m = input_color[1] + y = input_color[2] + k = input_color[3] + r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) + g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) + b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) + self.color_embed((r, g, b)) @staticmethod - async def create_thumbnail_attachment(color: str) -> File: - """Generate a thumbnail from `color`.""" + async def create_thumbnail_attachment(color: tuple[int, int, int]) -> File: + """ + Generate a thumbnail from `color`. + + Assumes that color is an rgb tuple. + """ thumbnail = Image.new("RGB", (100, 100), color=color) bufferedio = BytesIO() thumbnail.save(bufferedio, format="PNG") @@ -249,86 +300,40 @@ class Color(commands.Cog): color_name = "No color name match found." return color_name - @staticmethod - def tuple_create(input_color: str) -> tuple[int, int, int]: - """ - Create a tuple of integers based on user's input. - - Can handle inputs of the types: - (100, 100, 100) - 100, 100, 100 - 100 100 100 - """ - if "(" in input_color: - remove = "[() ]" - color_tuple = re.sub(remove, "", input_color) - color_tuple = tuple(map(int, color_tuple.split(","))) - elif "," in input_color: - color_tuple = tuple(map(int, input_color.split(","))) - else: - color_tuple = tuple(map(int, input_color.split(" "))) - return color_tuple - - def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsv color to rgb color and send main embed..""" - input_color = self.tuple_create(input_color) - (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped - h = h / 360 - s = s / 100 - v = v / 100 - rgb_color = colorsys.hsv_to_rgb(h, s, v) + async def color_embed( + self, + ctx: commands.Context, + rgb_color: tuple[int, int, int], + color_name: str = None + ) -> None: + """Take a RGB color tuple, create embed, and send.""" (r, g, b) = rgb_color - r = int(r * 255) - g = int(g * 255) - b = int(b * 255) - self.color_embed((r, g, b)) + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + if color_name is None: + logger.debug(f"Find color name from hex color: {hex_color}") + color_name = self.match_color_hex(hex_color) - def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsl color to rgb color and send main embed..""" - input_color = self.tuple_create(input_color) - (h, s, l) = input_color - h = h / 360 - s = s / 100 - l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. - rgb_color = colorsys.hls_to_rgb(h, l, s) - (r, g, b) = rgb_color - r = int(r * 255) - g = int(g * 255) - b = int(b * 255) - self.color_embed((r, g, b)) + async with ctx.typing(): + main_embed = Embed( + title=color_name, + description='(Approx..)', + color=discord_rgb_int, + ) - def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: - """Function to convert cmyk color to rgb color and send main embed..""" - input_color = self.tuple_create(input_color) - c = input_color[0] - m = input_color[1] - y = input_color[2] - k = input_color[3] - r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) - g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) - b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - self.color_embed((r, g, b)) + file = await self.create_thumbnail_attachment(rgb_color) + main_embed.set_thumbnail(url="attachment://color.png") + fields = self.get_color_fields(rgb_color) - async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: - """Create rgb color from hex string and send main embed.""" - hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) - if hex_match: - if "#" in hex_string: - rgb_color = ImageColor.getcolor(hex_string, "RGB") - elif "0x" in hex_string: - hex_ = hex_string.replace("0x", "#") - rgb_color = ImageColor.getcolor(hex_, "RGB") - else: - hex_ = "#" + hex_string - rgb_color = ImageColor.getcolor(hex_, "RGB") - self.color_embed(rgb_color) - else: - await ctx.send( - embed=Embed( - title="There was an issue converting the hex color code.", - description=ERROR_MSG.format(user_color=hex_string), + for field in fields: + main_embed.add_field( + name=field['name'], + value=field['value'], + inline=False, ) - ) + + await ctx.send(file=file, embed=main_embed) def setup(bot: Bot) -> None: -- cgit v1.2.3 From 8a9d71b77a6385bd2dbf8388a732e980fe66dac2 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:39:37 -0400 Subject: fix: remove `get_color_fields` call in color_embed --- bot/exts/utilities/color.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 67068809..5cdc5083 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -324,9 +324,8 @@ class Color(commands.Cog): file = await self.create_thumbnail_attachment(rgb_color) main_embed.set_thumbnail(url="attachment://color.png") - fields = self.get_color_fields(rgb_color) - for field in fields: + for field in all_colors: main_embed.add_field( name=field['name'], value=field['value'], -- cgit v1.2.3 From bacd5119f59c8d425ba9f129aff9191c98063a67 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:50:42 -0400 Subject: chore: small code fixes and cleanup --- bot/exts/utilities/color.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 5cdc5083..e0398e02 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -29,7 +29,6 @@ with open(COLOR_JSON_PATH) as f: COLOR_MAPPING = json.load(f) -# define color command class Color(commands.Cog): """User initiated commands to receive color information.""" @@ -45,7 +44,6 @@ class Color(commands.Cog): """ logger.debug(f"{mode = }") logger.debug(f"{user_color = }") - color_name = None if mode.lower() == "hex": self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": @@ -235,11 +233,6 @@ class Color(commands.Cog): l = round(l * 100) # noqa: E741 It's little `L`, Reason: To maintain consistency. return h, s, l - hex_color = _rgb_to_hex(rgb_color) - cmyk_color = _rgb_to_cmyk(rgb_color) - hsv_color = _rgb_to_hsv(rgb_color) - hsl_color = _rgb_to_hsl(rgb_color) - all_fields = [ { "name": "RGB", @@ -247,19 +240,19 @@ class Color(commands.Cog): }, { "name": "HEX", - "value": f"» hex {hex_color}" + "value": f"» hex {_rgb_to_hex(rgb_color)}" }, { "name": "CMYK", - "value": f"» cmyk {cmyk_color}" + "value": f"» cmyk {_rgb_to_cmyk(rgb_color)}" }, { "name": "HSV", - "value": f"» hsv {hsv_color}" + "value": f"» hsv {_rgb_to_hsv(rgb_color)}" }, { "name": "HSL", - "value": f"» hsl {hsl_color}" + "value": f"» hsl {_rgb_to_hsl(rgb_color)}" }, ] @@ -277,11 +270,11 @@ class Color(commands.Cog): logger.debug(f"{match = }, {certainty = }") hex_match = COLOR_MAPPING[match] logger.debug(f"{hex_match = }") - return match, hex_match except TypeError: match = "No color name match found." hex_match = input_color_name - return match, hex_match + + return match, hex_match @staticmethod def match_color_hex(input_hex_color: str) -> str: @@ -295,10 +288,10 @@ class Color(commands.Cog): logger.debug(f"{match = }, {certainty = }") color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] logger.debug(f"{color_name = }") - return color_name except TypeError: color_name = "No color name match found." - return color_name + + return color_name async def color_embed( self, -- cgit v1.2.3 From 23cf7cdd40dc162727e0697ccc6f802a84e9a7e0 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 23 Sep 2021 00:22:10 -0400 Subject: chore: create subcommands for sending embed --- bot/exts/utilities/color.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index e0398e02..6cc03c9a 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -45,23 +45,23 @@ class Color(commands.Cog): logger.debug(f"{mode = }") logger.debug(f"{user_color = }") if mode.lower() == "hex": - self.hex_to_rgb(ctx, user_color) + await self.hex_to_rgb(ctx, user_color) elif mode.lower() == "rgb": rgb_color = self.tuple_create(user_color) - self.color_embed(ctx, rgb_color) + await self.color_embed(ctx, rgb_color) elif mode.lower() == "hsv": - self.hsv_to_rgb(ctx, user_color) + await self.hsv_to_rgb(ctx, user_color) elif mode.lower() == "hsl": - self.hsl_to_rgb(ctx, user_color) + await self.hsl_to_rgb(ctx, user_color) elif mode.lower() == "cmyk": - self.cmyk_to_rgb(ctx, user_color) + await self.cmyk_to_rgb(ctx, user_color) elif mode.lower() == "name": color_name, hex_color = self.match_color_name(user_color) if "#" in hex_color: rgb_color = ImageColor.getcolor(hex_color, "RGB") else: rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") - self.color_embed(ctx, rgb_color, color_name) + await self.color_embed(ctx, rgb_color, color_name) else: # mode is either None or an invalid code if mode is None: @@ -112,7 +112,7 @@ class Color(commands.Cog): else: hex_ = "#" + hex_string rgb_color = ImageColor.getcolor(hex_, "RGB") - self.color_embed(rgb_color) + await self.color_embed(ctx, rgb_color) else: await ctx.send( embed=Embed( @@ -121,7 +121,7 @@ class Color(commands.Cog): ) ) - def hsv_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + async def hsv_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: """Function to convert hsv color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped @@ -133,9 +133,9 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - self.color_embed((r, g, b)) + await self.color_embed(ctx, (r, g, b)) - def hsl_to_rgb(self, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + async def hsl_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: """Function to convert hsl color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) (h, s, l) = input_color @@ -147,9 +147,9 @@ class Color(commands.Cog): r = int(r * 255) g = int(g * 255) b = int(b * 255) - self.color_embed((r, g, b)) + await self.color_embed(ctx, (r, g, b)) - def cmyk_to_rgb(self, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + async def cmyk_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: """Function to convert cmyk color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) c = input_color[0] @@ -159,7 +159,7 @@ class Color(commands.Cog): r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - self.color_embed((r, g, b)) + await self.color_embed(ctx, (r, g, b)) @staticmethod async def create_thumbnail_attachment(color: tuple[int, int, int]) -> File: -- cgit v1.2.3 From 8ff23478fb2bd9cfba34686be68513ab3ac7b905 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 23 Sep 2021 07:48:45 -0400 Subject: chore: make cmyk_to_rgb def multiline --- bot/exts/utilities/color.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6cc03c9a..9e2af325 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -149,7 +149,11 @@ class Color(commands.Cog): b = int(b * 255) await self.color_embed(ctx, (r, g, b)) - async def cmyk_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int, int]) -> tuple[int, int, int]: + async def cmyk_to_rgb( + self, + ctx: commands.Context, + input_color: tuple[int, int, int, int] + ) -> tuple[int, int, int]: """Function to convert cmyk color to rgb color and send main embed.""" input_color = self.tuple_create(input_color) c = input_color[0] -- cgit v1.2.3 From 5907900a80ce7bdeb6ddb97c80dbdd4defe0bb17 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Mon, 27 Sep 2021 09:49:42 -0400 Subject: chore: remove doubled new line in ERROR_MSG --- bot/exts/utilities/color.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9e2af325..7c7f4bba 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -17,11 +17,11 @@ logger = logging.getLogger(__name__) ERROR_MSG = """The color code {user_color} is not a possible color combination. -\nThe range of possible values are: -\nRGB & HSV: 0-255 -\nCMYK: 0-100% -\nHSL: 0-360 degrees -\nHex: #000000-#FFFFFF +The range of possible values are: +RGB & HSV: 0-255 +CMYK: 0-100% +HSL: 0-360 degrees +Hex: #000000-#FFFFFF """ COLOR_JSON_PATH = "bot/resources/utilities/ryanzec_colours.json" -- cgit v1.2.3 From a78731ad2cf457b25d311460578a778070900385 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Mon, 27 Sep 2021 09:56:33 -0400 Subject: chore: remove single-use constant for json path --- bot/exts/utilities/color.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 7c7f4bba..ac7b5fc6 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -24,8 +24,7 @@ HSL: 0-360 degrees Hex: #000000-#FFFFFF """ -COLOR_JSON_PATH = "bot/resources/utilities/ryanzec_colours.json" -with open(COLOR_JSON_PATH) as f: +with open("bot/resources/utilities/ryanzec_colours.json") as f: COLOR_MAPPING = json.load(f) -- cgit v1.2.3 From 9699e3a62d03d27acaac6e5376c2327cb8abf739 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 23 Sep 2021 21:42:24 -0400 Subject: chore: set thumbnail image to 80x80 --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index ac7b5fc6..57510488 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -171,7 +171,7 @@ class Color(commands.Cog): Assumes that color is an rgb tuple. """ - thumbnail = Image.new("RGB", (100, 100), color=color) + thumbnail = Image.new("RGB", (80, 80), color=color) bufferedio = BytesIO() thumbnail.save(bufferedio, format="PNG") bufferedio.seek(0) -- cgit v1.2.3 From 11c1c25a4767086c92b7a438aaee09fb65dcfdf1 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Mon, 27 Sep 2021 10:46:08 -0400 Subject: chore: remove single-use constant for json path --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 57510488..6aa0c3cd 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -65,7 +65,7 @@ class Color(commands.Cog): # mode is either None or an invalid code if mode is None: no_mode_embed = Embed( - title="No 'mode' was passed, please define a color code.", + title="No mode was passed, please define a color code.", description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", color=Colours.soft_red, ) -- cgit v1.2.3 From 11d00e7f846748fb87f02b5f0bfecc92feac198c Mon Sep 17 00:00:00 2001 From: Izan Date: Fri, 8 Oct 2021 14:45:02 +0100 Subject: Rename `Roles.moderator` to `Roles.moderation_team` --- bot/constants.py | 4 ++-- bot/exts/fun/snakes/_utils.py | 2 +- bot/exts/fun/trivia_quiz.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index 6e45632f..c5443393 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -332,8 +332,8 @@ class Reddit: # Default role combinations -MODERATION_ROLES = Roles.moderator, Roles.admin, Roles.owner -STAFF_ROLES = Roles.helpers, Roles.moderator, Roles.admin, Roles.owner +MODERATION_ROLES = Roles.moderation_team, Roles.admin, Roles.owner +STAFF_ROLES = Roles.helpers, Roles.moderation_team, Roles.admin, Roles.owner # Whitelisted channels WHITELISTED_CHANNELS = ( diff --git a/bot/exts/fun/snakes/_utils.py b/bot/exts/fun/snakes/_utils.py index de51339d..46834c2c 100644 --- a/bot/exts/fun/snakes/_utils.py +++ b/bot/exts/fun/snakes/_utils.py @@ -718,4 +718,4 @@ class SnakeAndLaddersGame: @staticmethod def _is_moderator(user: Member) -> bool: """Return True if the user is a Moderator.""" - return any(Roles.moderator == role.id for role in user.roles) + return any(Roles.moderation_team == role.id for role in user.roles) diff --git a/bot/exts/fun/trivia_quiz.py b/bot/exts/fun/trivia_quiz.py index 712c8a12..60afbb06 100644 --- a/bot/exts/fun/trivia_quiz.py +++ b/bot/exts/fun/trivia_quiz.py @@ -550,7 +550,7 @@ class TriviaQuiz(commands.Cog): if self.game_status[ctx.channel.id]: # Check if the author is the game starter or a moderator. if ctx.author == self.game_owners[ctx.channel.id] or any( - Roles.moderator == role.id for role in ctx.author.roles + Roles.moderation_team == role.id for role in ctx.author.roles ): self.game_status[ctx.channel.id] = False del self.game_owners[ctx.channel.id] -- cgit v1.2.3 From 71d800add94df3d678786ab482747ae904290129 Mon Sep 17 00:00:00 2001 From: Izan Date: Fri, 8 Oct 2021 15:04:35 +0100 Subject: Rename `Roles.admin` to `Roles.admins` --- bot/constants.py | 10 +++++----- bot/exts/core/internal_eval/_internal_eval.py | 6 +++--- bot/exts/events/advent_of_code/_cog.py | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index c5443393..92b40914 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -280,9 +280,9 @@ if Client.month_override is not None: class Roles(NamedTuple): - owner = 267627879762755584 - admin = int(environ.get("BOT_ADMIN_ROLE_ID", 267628507062992896)) - moderator = 267629731250176001 + owners = 267627879762755584 + admins = int(environ.get("BOT_ADMIN_ROLE_ID", 267628507062992896)) + moderation_team = 267629731250176001 helpers = int(environ.get("ROLE_HELPERS", 267630620367257601)) core_developers = 587606783669829632 everyone = int(environ.get("BOT_GUILD", 267624335836053506)) @@ -332,8 +332,8 @@ class Reddit: # Default role combinations -MODERATION_ROLES = Roles.moderation_team, Roles.admin, Roles.owner -STAFF_ROLES = Roles.helpers, Roles.moderation_team, Roles.admin, Roles.owner +MODERATION_ROLES = Roles.moderation_team, Roles.admins, Roles.owner +STAFF_ROLES = Roles.helpers, Roles.moderation_team, Roles.admins, Roles.owner # Whitelisted channels WHITELISTED_CHANNELS = ( diff --git a/bot/exts/core/internal_eval/_internal_eval.py b/bot/exts/core/internal_eval/_internal_eval.py index 4f6b4321..47e564a5 100644 --- a/bot/exts/core/internal_eval/_internal_eval.py +++ b/bot/exts/core/internal_eval/_internal_eval.py @@ -146,14 +146,14 @@ class InternalEval(commands.Cog): await self._send_output(ctx, eval_context.format_output()) @commands.group(name="internal", aliases=("int",)) - @with_role(Roles.admin) + @with_role(Roles.admins) async def internal_group(self, ctx: commands.Context) -> None: """Internal commands. Top secret!""" if not ctx.invoked_subcommand: await invoke_help_command(ctx) @internal_group.command(name="eval", aliases=("e",)) - @with_role(Roles.admin) + @with_role(Roles.admins) async def eval(self, ctx: commands.Context, *, code: str) -> None: """Run eval in a REPL-like format.""" if match := list(FORMATTED_CODE_REGEX.finditer(code)): @@ -172,7 +172,7 @@ class InternalEval(commands.Cog): await self._eval(ctx, code) @internal_group.command(name="reset", aliases=("clear", "exit", "r", "c")) - @with_role(Roles.admin) + @with_role(Roles.admins) async def reset(self, ctx: commands.Context) -> None: """Reset the context and locals of the eval session.""" self.locals = {} diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index ca60e517..4d811fa4 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -251,7 +251,7 @@ class AdventOfCode(commands.Cog): info_embed = _helpers.get_summary_embed(leaderboard) await ctx.send(f"```\n{table}\n```", embed=info_embed) - @with_role(Roles.admin) + @with_role(Roles.admins) @adventofcode_group.command( name="refresh", aliases=("fetch",), -- cgit v1.2.3 From dc5f73be8c18ef11c701822e8c600c8fca7b149c Mon Sep 17 00:00:00 2001 From: Izan Date: Fri, 8 Oct 2021 15:06:07 +0100 Subject: Rename `Roles.owner` to `Roles.owners` --- bot/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index 92b40914..b4191c5e 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -332,8 +332,8 @@ class Reddit: # Default role combinations -MODERATION_ROLES = Roles.moderation_team, Roles.admins, Roles.owner -STAFF_ROLES = Roles.helpers, Roles.moderation_team, Roles.admins, Roles.owner +MODERATION_ROLES = Roles.moderation_team, Roles.admins, Roles.owners +STAFF_ROLES = Roles.helpers, Roles.moderation_team, Roles.admins, Roles.owners # Whitelisted channels WHITELISTED_CHANNELS = ( -- cgit v1.2.3 From e2da188b554aba07b6c5a7a25b8af0baa74973cb Mon Sep 17 00:00:00 2001 From: Izan Date: Sat, 9 Oct 2021 21:20:46 +0100 Subject: Check role id in MODERATION_ROLES instead of comparing to moderation_team and safeguard `.roles` attribute --- bot/exts/fun/snakes/_utils.py | 25 +++++++++++++------------ bot/exts/fun/trivia_quiz.py | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/bot/exts/fun/snakes/_utils.py b/bot/exts/fun/snakes/_utils.py index 46834c2c..182fa9d9 100644 --- a/bot/exts/fun/snakes/_utils.py +++ b/bot/exts/fun/snakes/_utils.py @@ -6,13 +6,14 @@ import math import random from itertools import product from pathlib import Path +from typing import Union from PIL import Image from PIL.ImageDraw import ImageDraw -from discord import File, Member, Reaction +from discord import File, Member, Reaction, User from discord.ext.commands import Cog, Context -from bot.constants import Roles +from bot.constants import MODERATION_ROLES SNAKE_RESOURCES = Path("bot/resources/fun/snakes").absolute() @@ -395,7 +396,7 @@ class SnakeAndLaddersGame: Listen for reactions until players have joined, and the game has been started. """ - def startup_event_check(reaction_: Reaction, user_: Member) -> bool: + def startup_event_check(reaction_: Reaction, user_: Union[User, Member]) -> bool: """Make sure that this reaction is what we want to operate on.""" return ( all(( @@ -460,7 +461,7 @@ class SnakeAndLaddersGame: await self.cancel_game() return # We're done, no reactions for the last 5 minutes - async def _add_player(self, user: Member) -> None: + async def _add_player(self, user: Union[User, Member]) -> None: """Add player to game.""" self.players.append(user) self.player_tiles[user.id] = 1 @@ -469,7 +470,7 @@ class SnakeAndLaddersGame: im = Image.open(io.BytesIO(avatar_bytes)).resize((BOARD_PLAYER_SIZE, BOARD_PLAYER_SIZE)) self.avatar_images[user.id] = im - async def player_join(self, user: Member) -> None: + async def player_join(self, user: Union[User, Member]) -> None: """ Handle players joining the game. @@ -495,7 +496,7 @@ class SnakeAndLaddersGame: delete_after=10 ) - async def player_leave(self, user: Member) -> bool: + async def player_leave(self, user: Union[User, Member]) -> bool: """ Handle players leaving the game. @@ -530,7 +531,7 @@ class SnakeAndLaddersGame: await self.channel.send("**Snakes and Ladders**: Game has been canceled.") self._destruct() - async def start_game(self, user: Member) -> None: + async def start_game(self, user: Union[User, Member]) -> None: """ Allow the game author to begin the game. @@ -551,7 +552,7 @@ class SnakeAndLaddersGame: async def start_round(self) -> None: """Begin the round.""" - def game_event_check(reaction_: Reaction, user_: Member) -> bool: + def game_event_check(reaction_: Reaction, user_: Union[User, Member]) -> bool: """Make sure that this reaction is what we want to operate on.""" return ( all(( @@ -644,7 +645,7 @@ class SnakeAndLaddersGame: if not is_surrendered: await self._complete_round() - async def player_roll(self, user: Member) -> None: + async def player_roll(self, user: Union[User, Member]) -> None: """Handle the player's roll.""" if user.id not in self.player_tiles: await self.channel.send(user.mention + " You are not in the match.", delete_after=10) @@ -691,7 +692,7 @@ class SnakeAndLaddersGame: await self.channel.send("**Snakes and Ladders**: " + winner.mention + " has won the game! :tada:") self._destruct() - def _check_winner(self) -> Member: + def _check_winner(self) -> Union[User, Member]: """Return a winning member if we're in the post-round state and there's a winner.""" if self.state != "post_round": return None @@ -716,6 +717,6 @@ class SnakeAndLaddersGame: return x_level, y_level @staticmethod - def _is_moderator(user: Member) -> bool: + def _is_moderator(user: Union[User, Member]) -> bool: """Return True if the user is a Moderator.""" - return any(Roles.moderation_team == role.id for role in user.roles) + return any(role.id in MODERATION_ROLES for role in getattr(user, 'roles', [])) diff --git a/bot/exts/fun/trivia_quiz.py b/bot/exts/fun/trivia_quiz.py index 60afbb06..4a1cec5b 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 Client, Colours, NEGATIVE_REPLIES, Roles +from bot.constants import Client, Colours, MODERATION_ROLES, NEGATIVE_REPLIES logger = logging.getLogger(__name__) @@ -550,7 +550,7 @@ class TriviaQuiz(commands.Cog): if self.game_status[ctx.channel.id]: # Check if the author is the game starter or a moderator. if ctx.author == self.game_owners[ctx.channel.id] or any( - Roles.moderation_team == role.id for role in ctx.author.roles + role.id in MODERATION_ROLES for role in getattr(ctx.author, 'roles', []) ): self.game_status[ctx.channel.id] = False del self.game_owners[ctx.channel.id] -- cgit v1.2.3 From aa272dbe789e86013969bc6f4e506d70ddfc63be Mon Sep 17 00:00:00 2001 From: Izan Date: Mon, 11 Oct 2021 14:47:16 +0100 Subject: Check role id in STAFF_ROLES instead of comparing to helpers --- bot/exts/events/advent_of_code/_cog.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 4d811fa4..0a18c261 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -9,7 +9,7 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import ( - AdventOfCode as AocConfig, Channels, Colours, Emojis, Month, Roles, WHITELISTED_CHANNELS, + AdventOfCode as AocConfig, Channels, Colours, Emojis, Month, Roles, STAFF_ROLES, WHITELISTED_CHANNELS, ) from bot.exts.events.advent_of_code import _helpers from bot.utils.decorators import InChannelCheckFailure, in_month, whitelist_override, with_role @@ -145,7 +145,7 @@ class AdventOfCode(commands.Cog): author = ctx.author log.info(f"{author.name} ({author.id}) has requested a PyDis AoC leaderboard code") - if AocConfig.staff_leaderboard_id and any(r.id == Roles.helpers for r in author.roles): + if AocConfig.staff_leaderboard_id and any(r.id in STAFF_ROLES for r in author.roles): join_code = AocConfig.leaderboards[AocConfig.staff_leaderboard_id].join_code else: try: -- cgit v1.2.3 From a94ce986832694a572ce31b8fedd2b98c2c7747a Mon Sep 17 00:00:00 2001 From: Izan Date: Mon, 11 Oct 2021 14:59:31 +0100 Subject: Make certain AOC commands guild-only --- bot/exts/events/advent_of_code/_cog.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 0a18c261..3bd4873c 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -55,6 +55,7 @@ class AdventOfCode(commands.Cog): if not ctx.invoked_subcommand: await invoke_help_command(ctx) + @commands.guild_only() @adventofcode_group.command( name="subscribe", aliases=("sub", "notifications", "notify", "notifs"), @@ -84,6 +85,7 @@ class AdventOfCode(commands.Cog): ) @in_month(Month.DECEMBER) + @commands.guild_only() @adventofcode_group.command(name="unsubscribe", aliases=("unsub",), brief="Notifications for new days") @whitelist_override(channels=AOC_WHITELIST) async def aoc_unsubscribe(self, ctx: commands.Context) -> None: @@ -133,6 +135,7 @@ class AdventOfCode(commands.Cog): """Respond with an explanation of all things Advent of Code.""" await ctx.send(embed=self.cached_about_aoc) + @commands.guild_only() @adventofcode_group.command(name="join", aliases=("j",), brief="Learn how to join the leaderboard (via DM)") @whitelist_override(channels=AOC_WHITELIST) async def join_leaderboard(self, ctx: commands.Context) -> None: -- cgit v1.2.3 From bbef4f27a5ebade439e7073f66cac20977b18472 Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Wed, 13 Oct 2021 18:53:34 -0400 Subject: fixing errors --- bot/exts/utilities/challenges.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py index 234eb0be..ff9394ce 100644 --- a/bot/exts/utilities/challenges.py +++ b/bot/exts/utilities/challenges.py @@ -162,10 +162,16 @@ class Challenges(commands.Cog): kata_description = "\n".join(kata_description[:1000].split("\n")[:-1]) + "..." kata_description += f" [continue reading]({kata_url})" + if kata_information["rank"]["name"] is None: + embed_color = 8 + kata_information["rank"]["name"] = "Unable to retrieve difficulty for beta languages." + else: + embed_color = int(kata_information["rank"]["name"].replace(" kyu", "")) + kata_embed = Embed( title=kata_information["name"], description=kata_description, - color=MAPPING_OF_KYU[int(kata_information["rank"]["name"].replace(" kyu", ""))], + color=MAPPING_OF_KYU[embed_color], url=kata_url ) kata_embed.add_field(name="Difficulty", value=kata_information["rank"]["name"], inline=False) @@ -275,8 +281,7 @@ class Challenges(commands.Cog): params = {} if language and not query: - level = f"-{choice([1, 2, 3, 4, 5, 6, 7, 8])}" - params["r[]"] = level + pass elif "," in query: query_splitted = query.split("," if ", " not in query else ", ") -- cgit v1.2.3 From 196c451c867bc78beab2492b963b7d9a1f6a13f5 Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Thu, 14 Oct 2021 06:37:27 -0400 Subject: requested changes from TizzySaurus implemented --- bot/exts/utilities/challenges.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py index ff9394ce..d3ef82a0 100644 --- a/bot/exts/utilities/challenges.py +++ b/bot/exts/utilities/challenges.py @@ -164,9 +164,10 @@ class Challenges(commands.Cog): if kata_information["rank"]["name"] is None: embed_color = 8 - kata_information["rank"]["name"] = "Unable to retrieve difficulty for beta languages." + kata_difficulty = "Unable to retrieve difficulty for beta languages." else: embed_color = int(kata_information["rank"]["name"].replace(" kyu", "")) + kata_difficulty = kata_information["rank"]["name"] kata_embed = Embed( title=kata_information["name"], @@ -174,7 +175,7 @@ class Challenges(commands.Cog): color=MAPPING_OF_KYU[embed_color], url=kata_url ) - kata_embed.add_field(name="Difficulty", value=kata_information["rank"]["name"], inline=False) + kata_embed.add_field(name="Difficulty", value=kata_difficulty, inline=False) return kata_embed @staticmethod @@ -280,9 +281,7 @@ class Challenges(commands.Cog): get_kata_link = f"https://codewars.com/kata/search/{language}" params = {} - if language and not query: - pass - elif "," in query: + if query is not None and "," in query: query_splitted = query.split("," if ", " not in query else ", ") if len(query_splitted) > 2: @@ -293,9 +292,9 @@ class Challenges(commands.Cog): query, level = query_splitted params["q"] = query params["r[]"] = f"-{level}" - elif query.isnumeric(): + elif query is not None and query.isnumeric(): params["r[]"] = f"-{query}" - else: + elif query is not None: params["q"] = query params["beta"] = str(language in SUPPORTED_LANGUAGES["beta"]).lower() -- cgit v1.2.3 From 3ff315f34721bca59b0820207da6bdd748155293 Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Thu, 14 Oct 2021 06:51:23 -0400 Subject: removed repeating query is None --- bot/exts/utilities/challenges.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py index d3ef82a0..e4738455 100644 --- a/bot/exts/utilities/challenges.py +++ b/bot/exts/utilities/challenges.py @@ -281,21 +281,22 @@ class Challenges(commands.Cog): get_kata_link = f"https://codewars.com/kata/search/{language}" params = {} - if query is not None and "," 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 is not None and query.isnumeric(): - params["r[]"] = f"-{query}" - elif query is not None: - params["q"] = query + if query is not None: + if "," 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() -- 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 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 a054d50b9fdf18c5d1465016f7bd2d3b0abdc0fa Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 24 Oct 2021 18:12:11 -0400 Subject: temp: add restructured template as comments --- bot/exts/utilities/color.py | 137 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 6aa0c3cd..c1523281 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -4,14 +4,16 @@ import logging import re from io import BytesIO -from PIL import Image, ImageColor from discord import Embed, File from discord.ext import commands +from PIL import Image, ImageColor from rapidfuzz import process from bot.bot import Bot from bot.constants import Colours +# from bot.exts.core.extension import invoke_help_command + logger = logging.getLogger(__name__) @@ -28,6 +30,139 @@ with open("bot/resources/utilities/ryanzec_colours.json") as f: COLOR_MAPPING = json.load(f) +THUMBNAIL_SIZE = 80 + +""" +class Colour(commands.Cog): + + def __init__(self, bot: Bot) -> None: + self.bot = bot + + @commands.group(aliases=["color"]) + async def colour(self, ctx: commands.Context) -> None: + if ctx.invoked_subcommand is None: + await invoke_help_command(ctx) + + @colour.command() + async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: + rgb_tuple = ImageColor.getrgb(f"rgb({red}, {green}, {blue})") + await Colour.send_colour_response(ctx, list(rgb_tuple)) + + @colour.command() + async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: + hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") + await Colour.send_colour_response(ctx, list(hsv_tuple)) + + @colour.command() + async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: + hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") + await Colour.send_colour_response(ctx, list(hsl_tuple)) + + @colour.command() + async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: + ... + + @colour.command() + async def hex(self, ctx: commands.Context, hex_code: str) -> None: + hex_tuple = ImageColor.getrgb(hex_code) + await Colour.send_colour_response(ctx, list(hex_tuple)) + + @colour.command() + async def yiq( + self, + ctx: commands.Context, + perceived_luminesence: int, + in_phase: int, + quadrature: int + ) -> None: + yiq_list = list(colorsys.yiq_to_rgb(perceived_luminesence, in_phase, quadrature)) + yiq_tuple = [int(val * 255.0) for val in yiq_list] + await Colour.send_colour_response(ctx, list(yiq_tuple)) + + @staticmethod + async def send_colour_response(ctx: commands.Context, rgb: list[int]) -> Message: + r, g, b = rgb[0], rgb[1], rgb[2] + colour_embed = Embed( + title="Colour", + description="Here lies thy colour", + colour=int(f"{r:02x}{g:02x}{b:02x}", 16) + ) + colour_conversions = Colour.get_colour_conversions(rgb) + for colour_space, value in colour_conversions.items(): + colour_embed.add_field( + name=colour_space.upper(), + value=f"`{value}`", + inline=True + ) + + thumbnail = Image.new("RGB", (THUMBNAIL_SIZE, THUMBNAIL_SIZE), color=tuple(rgb)) + buffer = BytesIO() + thumbnail.save(buffer, "PNG") + buffer.seek(0) + thumbnail_file = File(buffer, filename="colour.png") + + colour_embed.set_thumbnail(url="attachment://colour.png") + + await ctx.send(file=thumbnail_file, embed=colour_embed) + + @staticmethod + def get_colour_conversions(rgb: list[int]) -> dict[str, str]: + return { + "rgb": tuple(rgb), + "hsv": Colour._rgb_to_hsv(rgb), + "hsl": Colour._rgb_to_hsl(rgb), + "cmyk": Colour._rgb_to_cmyk(rgb), + "hex": Colour._rgb_to_hex(rgb), + "yiq": Colour._rgb_to_yiq(rgb) + } + + @staticmethod + def _rgb_to_hsv(rgb: list[int]) -> tuple[int, int, int]: + rgb = [val / 255.0 for val in rgb] + h, v, s = colorsys.rgb_to_hsv(*rgb) + hsv = (round(h * 360), round(s * 100), round(v * 100)) + return hsv + + @staticmethod + def _rgb_to_hsl(rgb: list[int]) -> tuple[int, int, int]: + rgb = [val / 255.0 for val in rgb] + h, l, s = colorsys.rgb_to_hls(*rgb) + hsl = (round(h * 360), round(s * 100), round(l * 100)) + return hsl + + @staticmethod + def _rgb_to_cmyk(rgb: list[int]) -> tuple[int, int, int, int]: + rgb = [val / 255.0 for val in rgb] + + if all(val == 0 for val in rgb): + return 0, 0, 0, 100 + + cmy = [1 - val / 255 for val in rgb] + min_cmy = min(cmy) + + cmyk = [(val - min_cmy) / (1 - min_cmy) for val in cmy] + [min_cmy] + cmyk = [round(val * 100) for val in cmyk] + + return tuple(cmyk) + + @staticmethod + def _rgb_to_hex(rgb: list[int]) -> str: + hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) + hex_code = f"#{hex_}".upper() + return hex_code + + @staticmethod + def _rgb_to_yiq(rgb: list[int]) -> tuple[int, int, int, int]: + rgb = [val / 255.0 for val in rgb] + y, i, q = colorsys.rgb_to_yiq(*rgb) + yiq = (round(y), round(i), round(q)) + return yiq + +def setup(bot: commands.Bot) -> None: + bot.add_cog(Colour(bot)) +""" + + class Color(commands.Cog): """User initiated commands to receive color information.""" -- cgit v1.2.3 From 392616ea9f259ae1bb5f48f2cef366a273436c46 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sun, 24 Oct 2021 18:29:07 -0400 Subject: temp: add restructured layout in comments --- bot/exts/utilities/color.py | 471 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 471 insertions(+) create mode 100644 bot/exts/utilities/color.py diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py new file mode 100644 index 00000000..c1523281 --- /dev/null +++ b/bot/exts/utilities/color.py @@ -0,0 +1,471 @@ +import colorsys +import json +import logging +import re +from io import BytesIO + +from discord import Embed, File +from discord.ext import commands +from PIL import Image, ImageColor +from rapidfuzz import process + +from bot.bot import Bot +from bot.constants import Colours + +# from bot.exts.core.extension import invoke_help_command + + +logger = logging.getLogger(__name__) + + +ERROR_MSG = """The color code {user_color} is not a possible color combination. +The range of possible values are: +RGB & HSV: 0-255 +CMYK: 0-100% +HSL: 0-360 degrees +Hex: #000000-#FFFFFF +""" + +with open("bot/resources/utilities/ryanzec_colours.json") as f: + COLOR_MAPPING = json.load(f) + + +THUMBNAIL_SIZE = 80 + +""" +class Colour(commands.Cog): + + def __init__(self, bot: Bot) -> None: + self.bot = bot + + @commands.group(aliases=["color"]) + async def colour(self, ctx: commands.Context) -> None: + if ctx.invoked_subcommand is None: + await invoke_help_command(ctx) + + @colour.command() + async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: + rgb_tuple = ImageColor.getrgb(f"rgb({red}, {green}, {blue})") + await Colour.send_colour_response(ctx, list(rgb_tuple)) + + @colour.command() + async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: + hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") + await Colour.send_colour_response(ctx, list(hsv_tuple)) + + @colour.command() + async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: + hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") + await Colour.send_colour_response(ctx, list(hsl_tuple)) + + @colour.command() + async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: + ... + + @colour.command() + async def hex(self, ctx: commands.Context, hex_code: str) -> None: + hex_tuple = ImageColor.getrgb(hex_code) + await Colour.send_colour_response(ctx, list(hex_tuple)) + + @colour.command() + async def yiq( + self, + ctx: commands.Context, + perceived_luminesence: int, + in_phase: int, + quadrature: int + ) -> None: + yiq_list = list(colorsys.yiq_to_rgb(perceived_luminesence, in_phase, quadrature)) + yiq_tuple = [int(val * 255.0) for val in yiq_list] + await Colour.send_colour_response(ctx, list(yiq_tuple)) + + @staticmethod + async def send_colour_response(ctx: commands.Context, rgb: list[int]) -> Message: + r, g, b = rgb[0], rgb[1], rgb[2] + colour_embed = Embed( + title="Colour", + description="Here lies thy colour", + colour=int(f"{r:02x}{g:02x}{b:02x}", 16) + ) + colour_conversions = Colour.get_colour_conversions(rgb) + for colour_space, value in colour_conversions.items(): + colour_embed.add_field( + name=colour_space.upper(), + value=f"`{value}`", + inline=True + ) + + thumbnail = Image.new("RGB", (THUMBNAIL_SIZE, THUMBNAIL_SIZE), color=tuple(rgb)) + buffer = BytesIO() + thumbnail.save(buffer, "PNG") + buffer.seek(0) + thumbnail_file = File(buffer, filename="colour.png") + + colour_embed.set_thumbnail(url="attachment://colour.png") + + await ctx.send(file=thumbnail_file, embed=colour_embed) + + @staticmethod + def get_colour_conversions(rgb: list[int]) -> dict[str, str]: + return { + "rgb": tuple(rgb), + "hsv": Colour._rgb_to_hsv(rgb), + "hsl": Colour._rgb_to_hsl(rgb), + "cmyk": Colour._rgb_to_cmyk(rgb), + "hex": Colour._rgb_to_hex(rgb), + "yiq": Colour._rgb_to_yiq(rgb) + } + + @staticmethod + def _rgb_to_hsv(rgb: list[int]) -> tuple[int, int, int]: + rgb = [val / 255.0 for val in rgb] + h, v, s = colorsys.rgb_to_hsv(*rgb) + hsv = (round(h * 360), round(s * 100), round(v * 100)) + return hsv + + @staticmethod + def _rgb_to_hsl(rgb: list[int]) -> tuple[int, int, int]: + rgb = [val / 255.0 for val in rgb] + h, l, s = colorsys.rgb_to_hls(*rgb) + hsl = (round(h * 360), round(s * 100), round(l * 100)) + return hsl + + @staticmethod + def _rgb_to_cmyk(rgb: list[int]) -> tuple[int, int, int, int]: + rgb = [val / 255.0 for val in rgb] + + if all(val == 0 for val in rgb): + return 0, 0, 0, 100 + + cmy = [1 - val / 255 for val in rgb] + min_cmy = min(cmy) + + cmyk = [(val - min_cmy) / (1 - min_cmy) for val in cmy] + [min_cmy] + cmyk = [round(val * 100) for val in cmyk] + + return tuple(cmyk) + + @staticmethod + def _rgb_to_hex(rgb: list[int]) -> str: + hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) + hex_code = f"#{hex_}".upper() + return hex_code + + @staticmethod + def _rgb_to_yiq(rgb: list[int]) -> tuple[int, int, int, int]: + rgb = [val / 255.0 for val in rgb] + y, i, q = colorsys.rgb_to_yiq(*rgb) + yiq = (round(y), round(i), round(q)) + return yiq + +def setup(bot: commands.Bot) -> None: + bot.add_cog(Colour(bot)) +""" + + +class Color(commands.Cog): + """User initiated commands to receive color information.""" + + def __init__(self, bot: Bot): + self.bot = bot + + @commands.command(aliases=["colour"]) + async def color(self, ctx: commands.Context, mode: str, *, user_color: str) -> None: + """ + Send information on input color code or color name. + + Possible modes are: "hex", "rgb", "hsv", "hsl", "cmyk" or "name". + """ + logger.debug(f"{mode = }") + logger.debug(f"{user_color = }") + if mode.lower() == "hex": + await self.hex_to_rgb(ctx, user_color) + elif mode.lower() == "rgb": + rgb_color = self.tuple_create(user_color) + await self.color_embed(ctx, rgb_color) + elif mode.lower() == "hsv": + await self.hsv_to_rgb(ctx, user_color) + elif mode.lower() == "hsl": + await self.hsl_to_rgb(ctx, user_color) + elif mode.lower() == "cmyk": + await self.cmyk_to_rgb(ctx, user_color) + elif mode.lower() == "name": + color_name, hex_color = self.match_color_name(user_color) + if "#" in hex_color: + rgb_color = ImageColor.getcolor(hex_color, "RGB") + else: + rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") + await self.color_embed(ctx, rgb_color, color_name) + else: + # mode is either None or an invalid code + if mode is None: + no_mode_embed = Embed( + title="No mode was passed, please define a color code.", + description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", + color=Colours.soft_red, + ) + await ctx.send(embed=no_mode_embed) + return + wrong_mode_embed = Embed( + title=f"The color code {mode} is not a valid option", + description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", + color=Colours.soft_red, + ) + await ctx.send(embed=wrong_mode_embed) + return + + @staticmethod + def tuple_create(input_color: str) -> tuple[int, int, int]: + """ + Create a tuple of integers based on user's input. + + Can handle inputs of the types: + (100, 100, 100) + 100, 100, 100 + 100 100 100 + """ + if "(" in input_color: + remove = "[() ]" + color_tuple = re.sub(remove, "", input_color) + color_tuple = tuple(map(int, color_tuple.split(","))) + elif "," in input_color: + color_tuple = tuple(map(int, input_color.split(","))) + else: + color_tuple = tuple(map(int, input_color.split(" "))) + return color_tuple + + async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: + """Function to convert hex color to rgb color and send main embed.""" + hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) + if hex_match: + if "#" in hex_string: + rgb_color = ImageColor.getcolor(hex_string, "RGB") + elif "0x" in hex_string: + hex_ = hex_string.replace("0x", "#") + rgb_color = ImageColor.getcolor(hex_, "RGB") + else: + hex_ = "#" + hex_string + rgb_color = ImageColor.getcolor(hex_, "RGB") + await self.color_embed(ctx, rgb_color) + else: + await ctx.send( + embed=Embed( + title="There was an issue converting the hex color code.", + description=ERROR_MSG.format(user_color=hex_string), + ) + ) + + async def hsv_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsv color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped + h = h / 360 + s = s / 100 + v = v / 100 + rgb_color = colorsys.hsv_to_rgb(h, s, v) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + await self.color_embed(ctx, (r, g, b)) + + async def hsl_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: + """Function to convert hsl color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + (h, s, l) = input_color + h = h / 360 + s = s / 100 + l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. + rgb_color = colorsys.hls_to_rgb(h, l, s) + (r, g, b) = rgb_color + r = int(r * 255) + g = int(g * 255) + b = int(b * 255) + await self.color_embed(ctx, (r, g, b)) + + async def cmyk_to_rgb( + self, + ctx: commands.Context, + input_color: tuple[int, int, int, int] + ) -> tuple[int, int, int]: + """Function to convert cmyk color to rgb color and send main embed.""" + input_color = self.tuple_create(input_color) + c = input_color[0] + m = input_color[1] + y = input_color[2] + k = input_color[3] + r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) + g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) + b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) + await self.color_embed(ctx, (r, g, b)) + + @staticmethod + async def create_thumbnail_attachment(color: tuple[int, int, int]) -> File: + """ + Generate a thumbnail from `color`. + + Assumes that color is an rgb tuple. + """ + thumbnail = Image.new("RGB", (80, 80), color=color) + bufferedio = BytesIO() + thumbnail.save(bufferedio, format="PNG") + bufferedio.seek(0) + + file = File(bufferedio, filename="color.png") + + return file + + @staticmethod + def get_color_fields(rgb_color: tuple[int, int, int]) -> list[dict]: + """Converts from `RGB` to `CMYK`, `HSV`, `HSL` and returns a list of fields.""" + + def _rgb_to_hex(rgb_color: tuple[int, int, int]) -> str: + """To convert from `RGB` to `Hex` notation.""" + return '#' + ''.join(hex(int(color))[2:].zfill(2) for color in rgb_color).upper() + + def _rgb_to_cmyk(rgb_color: tuple[int, int, int]) -> tuple[int, int, int, int]: + """To convert from `RGB` to `CMYK` color space.""" + r, g, b = rgb_color + + # RGB_SCALE -> 255 + # CMYK_SCALE -> 100 + + if (r == g == b == 0): + return 0, 0, 0, 100 # Representing Black + + # rgb [0,RGB_SCALE] -> cmy [0,1] + c = 1 - r / 255 + m = 1 - g / 255 + y = 1 - b / 255 + + # extract out k [0, 1] + min_cmy = min(c, m, y) + c = (c - min_cmy) / (1 - min_cmy) + m = (m - min_cmy) / (1 - min_cmy) + y = (y - min_cmy) / (1 - min_cmy) + k = min_cmy + + # rescale to the range [0,CMYK_SCALE] and round off + c = round(c * 100) + m = round(m * 100) + y = round(y * 100) + k = round(k * 100) + + return c, m, y, k + + def _rgb_to_hsv(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: + """To convert from `RGB` to `HSV` color space.""" + r, g, b = rgb_color + h, v, s = colorsys.rgb_to_hsv(r / float(255), g / float(255), b / float(255)) + h = round(h * 360) + s = round(s * 100) + v = round(v * 100) + return h, s, v + + def _rgb_to_hsl(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: + """To convert from `RGB` to `HSL` color space.""" + r, g, b = rgb_color + h, l, s = colorsys.rgb_to_hls(r / float(255), g / float(255), b / float(255)) + h = round(h * 360) + s = round(s * 100) + l = round(l * 100) # noqa: E741 It's little `L`, Reason: To maintain consistency. + return h, s, l + + all_fields = [ + { + "name": "RGB", + "value": f"» rgb {rgb_color}" + }, + { + "name": "HEX", + "value": f"» hex {_rgb_to_hex(rgb_color)}" + }, + { + "name": "CMYK", + "value": f"» cmyk {_rgb_to_cmyk(rgb_color)}" + }, + { + "name": "HSV", + "value": f"» hsv {_rgb_to_hsv(rgb_color)}" + }, + { + "name": "HSL", + "value": f"» hsl {_rgb_to_hsl(rgb_color)}" + }, + ] + + return all_fields + + @staticmethod + def match_color_name(input_color_name: str) -> str: + """Use fuzzy matching to return a hex color code based on the user's input.""" + try: + match, certainty, _ = process.extractOne( + query=input_color_name, + choices=COLOR_MAPPING.keys(), + score_cutoff=50 + ) + logger.debug(f"{match = }, {certainty = }") + hex_match = COLOR_MAPPING[match] + logger.debug(f"{hex_match = }") + except TypeError: + match = "No color name match found." + hex_match = input_color_name + + return match, hex_match + + @staticmethod + def match_color_hex(input_hex_color: str) -> str: + """Use fuzzy matching to return a hex color code based on the user's input.""" + try: + match, certainty, _ = process.extractOne( + query=input_hex_color, + choices=COLOR_MAPPING.values(), + score_cutoff=80 + ) + logger.debug(f"{match = }, {certainty = }") + color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] + logger.debug(f"{color_name = }") + except TypeError: + color_name = "No color name match found." + + return color_name + + async def color_embed( + self, + ctx: commands.Context, + rgb_color: tuple[int, int, int], + color_name: str = None + ) -> None: + """Take a RGB color tuple, create embed, and send.""" + (r, g, b) = rgb_color + discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) + all_colors = self.get_color_fields(rgb_color) + hex_color = all_colors[1]["value"].replace("» hex ", "") + if color_name is None: + logger.debug(f"Find color name from hex color: {hex_color}") + color_name = self.match_color_hex(hex_color) + + async with ctx.typing(): + main_embed = Embed( + title=color_name, + description='(Approx..)', + color=discord_rgb_int, + ) + + file = await self.create_thumbnail_attachment(rgb_color) + main_embed.set_thumbnail(url="attachment://color.png") + + for field in all_colors: + main_embed.add_field( + name=field['name'], + value=field['value'], + inline=False, + ) + + await ctx.send(file=file, embed=main_embed) + + +def setup(bot: Bot) -> None: + """Load the Color Cog.""" + bot.add_cog(Color(bot)) -- cgit v1.2.3 From d28b932f4177f5d3056991a3c1872988f69dc952 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Mon, 25 Oct 2021 19:30:34 -0400 Subject: fix: finish restructure with all functionality Added commands for `name` and `random`. Added the ability to look up the color name based on the hex value. Co-authored-by: Mohammad Rafivulla <77384412+CyberCitizen01@users.noreply.github.com> Co-authored-by: Vivaan Verma <54081925+doublevcodes@users.noreply.github.com> --- bot/exts/utilities/color.py | 395 ++++++++------------------------------------ 1 file changed, 66 insertions(+), 329 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index c1523281..dc63cf84 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,7 +1,7 @@ import colorsys import json import logging -import re +import random from io import BytesIO from discord import Embed, File @@ -10,81 +10,97 @@ from PIL import Image, ImageColor from rapidfuzz import process from bot.bot import Bot -from bot.constants import Colours - -# from bot.exts.core.extension import invoke_help_command - +from bot.exts.core.extensions import invoke_help_command logger = logging.getLogger(__name__) -ERROR_MSG = """The color code {user_color} is not a possible color combination. -The range of possible values are: -RGB & HSV: 0-255 -CMYK: 0-100% -HSL: 0-360 degrees -Hex: #000000-#FFFFFF -""" - with open("bot/resources/utilities/ryanzec_colours.json") as f: COLOR_MAPPING = json.load(f) THUMBNAIL_SIZE = 80 -""" + class Colour(commands.Cog): + """Cog for the Colour command.""" def __init__(self, bot: Bot) -> None: self.bot = bot @commands.group(aliases=["color"]) async def colour(self, ctx: commands.Context) -> None: + """ + User initiated command to create an embed that displays color information. + + For the commands `hsl`, `hsv` and `rgb`: input is in the form `.color ` + For the command `cmyk`: input is in the form `.color cmyk ` + For the command `hex`: input is in the form `.color hex #` + For the command `name`: input is in the form `.color name ` + For the command `random`: input is in the form `.color random` + """ if ctx.invoked_subcommand is None: await invoke_help_command(ctx) @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: + """Function to create an embed from an RGB input.""" rgb_tuple = ImageColor.getrgb(f"rgb({red}, {green}, {blue})") await Colour.send_colour_response(ctx, list(rgb_tuple)) @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: + """Function to create an embed from an HSV input.""" hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") await Colour.send_colour_response(ctx, list(hsv_tuple)) @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: + """Function to create an embed from an HSL input.""" hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") await Colour.send_colour_response(ctx, list(hsl_tuple)) @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: - ... + """Function to create an embed from a CMYK input.""" + r = int(255 * (1.0 - cyan / float(100)) * (1.0 - key / float(100))) + g = int(255 * (1.0 - magenta / float(100)) * (1.0 - key / float(100))) + b = int(255 * (1.0 - yellow / float(100)) * (1.0 - key / float(100))) + await Colour.send_colour_response(ctx, list((r, g, b))) @colour.command() async def hex(self, ctx: commands.Context, hex_code: str) -> None: + """Function to create an embed from a HEX input. (Requires # as a prefix).""" hex_tuple = ImageColor.getrgb(hex_code) await Colour.send_colour_response(ctx, list(hex_tuple)) @colour.command() - async def yiq( - self, - ctx: commands.Context, - perceived_luminesence: int, - in_phase: int, - quadrature: int - ) -> None: - yiq_list = list(colorsys.yiq_to_rgb(perceived_luminesence, in_phase, quadrature)) - yiq_tuple = [int(val * 255.0) for val in yiq_list] - await Colour.send_colour_response(ctx, list(yiq_tuple)) + async def name(self, ctx: commands.Context, user_color: str) -> None: + """Function to create an embed from a name input.""" + _, hex_color = self.match_color_name(user_color) + hex_tuple = ImageColor.getrgb(hex_color) + await Colour.send_colour_response(ctx, list(hex_tuple)) + + @colour.command() + async def random(self, ctx: commands.Context) -> None: + """Function to create an embed from a randomly chosen color from the ryanzec.json file.""" + color_choices = list(COLOR_MAPPING.values()) + hex_color = random.choice(color_choices) + hex_tuple = ImageColor.getrgb(f"#{hex_color}") + await Colour.send_colour_response(ctx, list(hex_tuple)) @staticmethod - async def send_colour_response(ctx: commands.Context, rgb: list[int]) -> Message: + async def send_colour_response(ctx: commands.Context, rgb: list[int]) -> None: + """Function to create and send embed from color information.""" r, g, b = rgb[0], rgb[1], rgb[2] + name = Colour._rgb_to_name(rgb) + if name is None: + desc = "Color information for the input color." + else: + desc = f"Color information for {name}" colour_embed = Embed( title="Colour", - description="Here lies thy colour", + description=desc, colour=int(f"{r:02x}{g:02x}{b:02x}", 16) ) colour_conversions = Colour.get_colour_conversions(rgb) @@ -107,17 +123,19 @@ class Colour(commands.Cog): @staticmethod def get_colour_conversions(rgb: list[int]) -> dict[str, str]: + """Create a dictionary mapping of color types and their values.""" return { "rgb": tuple(rgb), "hsv": Colour._rgb_to_hsv(rgb), "hsl": Colour._rgb_to_hsl(rgb), "cmyk": Colour._rgb_to_cmyk(rgb), "hex": Colour._rgb_to_hex(rgb), - "yiq": Colour._rgb_to_yiq(rgb) + "name": Colour._rgb_to_name(rgb) } @staticmethod def _rgb_to_hsv(rgb: list[int]) -> tuple[int, int, int]: + """Function to convert an RGB list to a HSV list.""" rgb = [val / 255.0 for val in rgb] h, v, s = colorsys.rgb_to_hsv(*rgb) hsv = (round(h * 360), round(s * 100), round(v * 100)) @@ -125,6 +143,7 @@ class Colour(commands.Cog): @staticmethod def _rgb_to_hsl(rgb: list[int]) -> tuple[int, int, int]: + """Function to convert an RGB list to a HSL list.""" rgb = [val / 255.0 for val in rgb] h, l, s = colorsys.rgb_to_hls(*rgb) hsl = (round(h * 360), round(s * 100), round(l * 100)) @@ -132,269 +151,39 @@ class Colour(commands.Cog): @staticmethod def _rgb_to_cmyk(rgb: list[int]) -> tuple[int, int, int, int]: + """Function to convert an RGB list to a CMYK list.""" rgb = [val / 255.0 for val in rgb] - if all(val == 0 for val in rgb): return 0, 0, 0, 100 - cmy = [1 - val / 255 for val in rgb] min_cmy = min(cmy) - cmyk = [(val - min_cmy) / (1 - min_cmy) for val in cmy] + [min_cmy] cmyk = [round(val * 100) for val in cmyk] - return tuple(cmyk) @staticmethod def _rgb_to_hex(rgb: list[int]) -> str: + """Function to convert an RGB list to a HEX string.""" hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) hex_code = f"#{hex_}".upper() return hex_code @staticmethod - def _rgb_to_yiq(rgb: list[int]) -> tuple[int, int, int, int]: - rgb = [val / 255.0 for val in rgb] - y, i, q = colorsys.rgb_to_yiq(*rgb) - yiq = (round(y), round(i), round(q)) - return yiq - -def setup(bot: commands.Bot) -> None: - bot.add_cog(Colour(bot)) -""" - - -class Color(commands.Cog): - """User initiated commands to receive color information.""" - - def __init__(self, bot: Bot): - self.bot = bot - - @commands.command(aliases=["colour"]) - async def color(self, ctx: commands.Context, mode: str, *, user_color: str) -> None: - """ - Send information on input color code or color name. - - Possible modes are: "hex", "rgb", "hsv", "hsl", "cmyk" or "name". - """ - logger.debug(f"{mode = }") - logger.debug(f"{user_color = }") - if mode.lower() == "hex": - await self.hex_to_rgb(ctx, user_color) - elif mode.lower() == "rgb": - rgb_color = self.tuple_create(user_color) - await self.color_embed(ctx, rgb_color) - elif mode.lower() == "hsv": - await self.hsv_to_rgb(ctx, user_color) - elif mode.lower() == "hsl": - await self.hsl_to_rgb(ctx, user_color) - elif mode.lower() == "cmyk": - await self.cmyk_to_rgb(ctx, user_color) - elif mode.lower() == "name": - color_name, hex_color = self.match_color_name(user_color) - if "#" in hex_color: - rgb_color = ImageColor.getcolor(hex_color, "RGB") - else: - rgb_color = ImageColor.getcolor("#" + hex_color, "RGB") - await self.color_embed(ctx, rgb_color, color_name) - else: - # mode is either None or an invalid code - if mode is None: - no_mode_embed = Embed( - title="No mode was passed, please define a color code.", - description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", - color=Colours.soft_red, - ) - await ctx.send(embed=no_mode_embed) - return - wrong_mode_embed = Embed( - title=f"The color code {mode} is not a valid option", - description="Possible modes are: Name, Hex, RGB, HSV, HSL and CMYK.", - color=Colours.soft_red, - ) - await ctx.send(embed=wrong_mode_embed) - return - - @staticmethod - def tuple_create(input_color: str) -> tuple[int, int, int]: - """ - Create a tuple of integers based on user's input. - - Can handle inputs of the types: - (100, 100, 100) - 100, 100, 100 - 100 100 100 - """ - if "(" in input_color: - remove = "[() ]" - color_tuple = re.sub(remove, "", input_color) - color_tuple = tuple(map(int, color_tuple.split(","))) - elif "," in input_color: - color_tuple = tuple(map(int, input_color.split(","))) - else: - color_tuple = tuple(map(int, input_color.split(" "))) - return color_tuple - - async def hex_to_rgb(self, ctx: commands.Context, hex_string: str) -> None: - """Function to convert hex color to rgb color and send main embed.""" - hex_match = re.fullmatch(r"(#?[0x]?)((?:[0-9a-fA-F]{3}){1,2})", hex_string) - if hex_match: - if "#" in hex_string: - rgb_color = ImageColor.getcolor(hex_string, "RGB") - elif "0x" in hex_string: - hex_ = hex_string.replace("0x", "#") - rgb_color = ImageColor.getcolor(hex_, "RGB") - else: - hex_ = "#" + hex_string - rgb_color = ImageColor.getcolor(hex_, "RGB") - await self.color_embed(ctx, rgb_color) - else: - await ctx.send( - embed=Embed( - title="There was an issue converting the hex color code.", - description=ERROR_MSG.format(user_color=hex_string), - ) + def _rgb_to_name(rgb: list[int]) -> str: + """Function to convert from an RGB list to a fuzzy matched color name.""" + input_hex_color = Colour._rgb_to_hex(rgb) + try: + match, certainty, _ = process.extractOne( + query=input_hex_color, + choices=COLOR_MAPPING.values(), + score_cutoff=80 ) - - async def hsv_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsv color to rgb color and send main embed.""" - input_color = self.tuple_create(input_color) - (h, v, s) = input_color # the function hsv_to_rgb expects v and s to be swapped - h = h / 360 - s = s / 100 - v = v / 100 - rgb_color = colorsys.hsv_to_rgb(h, s, v) - (r, g, b) = rgb_color - r = int(r * 255) - g = int(g * 255) - b = int(b * 255) - await self.color_embed(ctx, (r, g, b)) - - async def hsl_to_rgb(self, ctx: commands.Context, input_color: tuple[int, int, int]) -> tuple[int, int, int]: - """Function to convert hsl color to rgb color and send main embed.""" - input_color = self.tuple_create(input_color) - (h, s, l) = input_color - h = h / 360 - s = s / 100 - l = l / 100 # noqa: E741 It's little `L`, Reason: To maintain consistency. - rgb_color = colorsys.hls_to_rgb(h, l, s) - (r, g, b) = rgb_color - r = int(r * 255) - g = int(g * 255) - b = int(b * 255) - await self.color_embed(ctx, (r, g, b)) - - async def cmyk_to_rgb( - self, - ctx: commands.Context, - input_color: tuple[int, int, int, int] - ) -> tuple[int, int, int]: - """Function to convert cmyk color to rgb color and send main embed.""" - input_color = self.tuple_create(input_color) - c = input_color[0] - m = input_color[1] - y = input_color[2] - k = input_color[3] - r = int(255 * (1.0 - c / float(100)) * (1.0 - k / float(100))) - g = int(255 * (1.0 - m / float(100)) * (1.0 - k / float(100))) - b = int(255 * (1.0 - y / float(100)) * (1.0 - k / float(100))) - await self.color_embed(ctx, (r, g, b)) - - @staticmethod - async def create_thumbnail_attachment(color: tuple[int, int, int]) -> File: - """ - Generate a thumbnail from `color`. - - Assumes that color is an rgb tuple. - """ - thumbnail = Image.new("RGB", (80, 80), color=color) - bufferedio = BytesIO() - thumbnail.save(bufferedio, format="PNG") - bufferedio.seek(0) - - file = File(bufferedio, filename="color.png") - - return file - - @staticmethod - def get_color_fields(rgb_color: tuple[int, int, int]) -> list[dict]: - """Converts from `RGB` to `CMYK`, `HSV`, `HSL` and returns a list of fields.""" - - def _rgb_to_hex(rgb_color: tuple[int, int, int]) -> str: - """To convert from `RGB` to `Hex` notation.""" - return '#' + ''.join(hex(int(color))[2:].zfill(2) for color in rgb_color).upper() - - def _rgb_to_cmyk(rgb_color: tuple[int, int, int]) -> tuple[int, int, int, int]: - """To convert from `RGB` to `CMYK` color space.""" - r, g, b = rgb_color - - # RGB_SCALE -> 255 - # CMYK_SCALE -> 100 - - if (r == g == b == 0): - return 0, 0, 0, 100 # Representing Black - - # rgb [0,RGB_SCALE] -> cmy [0,1] - c = 1 - r / 255 - m = 1 - g / 255 - y = 1 - b / 255 - - # extract out k [0, 1] - min_cmy = min(c, m, y) - c = (c - min_cmy) / (1 - min_cmy) - m = (m - min_cmy) / (1 - min_cmy) - y = (y - min_cmy) / (1 - min_cmy) - k = min_cmy - - # rescale to the range [0,CMYK_SCALE] and round off - c = round(c * 100) - m = round(m * 100) - y = round(y * 100) - k = round(k * 100) - - return c, m, y, k - - def _rgb_to_hsv(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: - """To convert from `RGB` to `HSV` color space.""" - r, g, b = rgb_color - h, v, s = colorsys.rgb_to_hsv(r / float(255), g / float(255), b / float(255)) - h = round(h * 360) - s = round(s * 100) - v = round(v * 100) - return h, s, v - - def _rgb_to_hsl(rgb_color: tuple[int, int, int]) -> tuple[int, int, int]: - """To convert from `RGB` to `HSL` color space.""" - r, g, b = rgb_color - h, l, s = colorsys.rgb_to_hls(r / float(255), g / float(255), b / float(255)) - h = round(h * 360) - s = round(s * 100) - l = round(l * 100) # noqa: E741 It's little `L`, Reason: To maintain consistency. - return h, s, l - - all_fields = [ - { - "name": "RGB", - "value": f"» rgb {rgb_color}" - }, - { - "name": "HEX", - "value": f"» hex {_rgb_to_hex(rgb_color)}" - }, - { - "name": "CMYK", - "value": f"» cmyk {_rgb_to_cmyk(rgb_color)}" - }, - { - "name": "HSV", - "value": f"» hsv {_rgb_to_hsv(rgb_color)}" - }, - { - "name": "HSL", - "value": f"» hsl {_rgb_to_hsl(rgb_color)}" - }, - ] - - return all_fields + logger.debug(f"{match = }, {certainty = }") + color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] + logger.debug(f"{color_name = }") + except TypeError: + color_name = None + return color_name @staticmethod def match_color_name(input_color_name: str) -> str: @@ -406,66 +195,14 @@ class Color(commands.Cog): score_cutoff=50 ) logger.debug(f"{match = }, {certainty = }") - hex_match = COLOR_MAPPING[match] + hex_match = f"#{COLOR_MAPPING[match]}" logger.debug(f"{hex_match = }") except TypeError: match = "No color name match found." hex_match = input_color_name - return match, hex_match - @staticmethod - def match_color_hex(input_hex_color: str) -> str: - """Use fuzzy matching to return a hex color code based on the user's input.""" - try: - match, certainty, _ = process.extractOne( - query=input_hex_color, - choices=COLOR_MAPPING.values(), - score_cutoff=80 - ) - logger.debug(f"{match = }, {certainty = }") - color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] - logger.debug(f"{color_name = }") - except TypeError: - color_name = "No color name match found." - - return color_name - - async def color_embed( - self, - ctx: commands.Context, - rgb_color: tuple[int, int, int], - color_name: str = None - ) -> None: - """Take a RGB color tuple, create embed, and send.""" - (r, g, b) = rgb_color - discord_rgb_int = int(f"{r:02x}{g:02x}{b:02x}", 16) - all_colors = self.get_color_fields(rgb_color) - hex_color = all_colors[1]["value"].replace("» hex ", "") - if color_name is None: - logger.debug(f"Find color name from hex color: {hex_color}") - color_name = self.match_color_hex(hex_color) - - async with ctx.typing(): - main_embed = Embed( - title=color_name, - description='(Approx..)', - color=discord_rgb_int, - ) - - file = await self.create_thumbnail_attachment(rgb_color) - main_embed.set_thumbnail(url="attachment://color.png") - - for field in all_colors: - main_embed.add_field( - name=field['name'], - value=field['value'], - inline=False, - ) - - await ctx.send(file=file, embed=main_embed) - def setup(bot: Bot) -> None: - """Load the Color Cog.""" - bot.add_cog(Color(bot)) + """Load the Colour cog.""" + bot.add_cog(Colour(bot)) -- cgit v1.2.3 From d6400337320124ed8ac48445aa2938ac74fb41c5 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Mon, 25 Oct 2021 19:40:55 -0400 Subject: chore: fix import order due to isort --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index dc63cf84..b5caf357 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -4,9 +4,9 @@ import logging import random from io import BytesIO +from PIL import Image, ImageColor from discord import Embed, File from discord.ext import commands -from PIL import Image, ImageColor from rapidfuzz import process from bot.bot import Bot -- cgit v1.2.3 From fed6c1315a04ae8970b1a9d1f23f1b8ed4615d86 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 26 Oct 2021 07:02:37 -0400 Subject: chore: code cleanup --- bot/exts/utilities/color.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index b5caf357..618970df 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -1,6 +1,6 @@ import colorsys import json -import logging +import pathlib import random from io import BytesIO @@ -12,23 +12,16 @@ from rapidfuzz import process from bot.bot import Bot from bot.exts.core.extensions import invoke_help_command -logger = logging.getLogger(__name__) - - -with open("bot/resources/utilities/ryanzec_colours.json") as f: +with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: COLOR_MAPPING = json.load(f) - THUMBNAIL_SIZE = 80 class Colour(commands.Cog): """Cog for the Colour command.""" - def __init__(self, bot: Bot) -> None: - self.bot = bot - - @commands.group(aliases=["color"]) + @commands.group(aliases=("color",)) async def colour(self, ctx: commands.Context) -> None: """ User initiated command to create an embed that displays color information. @@ -97,7 +90,7 @@ class Colour(commands.Cog): if name is None: desc = "Color information for the input color." else: - desc = f"Color information for {name}" + desc = f"Color information for {name}." colour_embed = Embed( title="Colour", description=desc, @@ -178,9 +171,7 @@ class Colour(commands.Cog): choices=COLOR_MAPPING.values(), score_cutoff=80 ) - logger.debug(f"{match = }, {certainty = }") color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] - logger.debug(f"{color_name = }") except TypeError: color_name = None return color_name @@ -194,9 +185,7 @@ class Colour(commands.Cog): choices=COLOR_MAPPING.keys(), score_cutoff=50 ) - logger.debug(f"{match = }, {certainty = }") hex_match = f"#{COLOR_MAPPING[match]}" - logger.debug(f"{hex_match = }") except TypeError: match = "No color name match found." hex_match = input_color_name -- cgit v1.2.3 From 626df00917a191eb3758a33ec112f4d87bcbb0af Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 26 Oct 2021 08:15:34 -0400 Subject: chore: code cleanup --- bot/exts/utilities/color.py | 152 +++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 66 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 618970df..606f5fd4 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -12,91 +12,112 @@ from rapidfuzz import process from bot.bot import Bot from bot.exts.core.extensions import invoke_help_command -with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: - COLOR_MAPPING = json.load(f) - -THUMBNAIL_SIZE = 80 +THUMBNAIL_SIZE = (80, 80) class Colour(commands.Cog): """Cog for the Colour command.""" + def __init__(self): + with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: + self.COLOUR_MAPPING = json.load(f) + @commands.group(aliases=("color",)) async def colour(self, ctx: commands.Context) -> None: - """ - User initiated command to create an embed that displays color information. - - For the commands `hsl`, `hsv` and `rgb`: input is in the form `.color ` - For the command `cmyk`: input is in the form `.color cmyk ` - For the command `hex`: input is in the form `.color hex #` - For the command `name`: input is in the form `.color name ` - For the command `random`: input is in the form `.color random` - """ + """User initiated command to create an embed that displays colour information.""" if ctx.invoked_subcommand is None: await invoke_help_command(ctx) @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: - """Function to create an embed from an RGB input.""" + """ + Command to create an embed from an RGB input. + + Input is in the form `.colour rgb ` + """ rgb_tuple = ImageColor.getrgb(f"rgb({red}, {green}, {blue})") - await Colour.send_colour_response(ctx, list(rgb_tuple)) + await self.send_colour_response(ctx, list(rgb_tuple)) @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: - """Function to create an embed from an HSV input.""" + """ + Command to create an embed from an HSV input. + + Input is in the form `.colour hsv ` + """ hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") - await Colour.send_colour_response(ctx, list(hsv_tuple)) + await self.send_colour_response(ctx, list(hsv_tuple)) @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: - """Function to create an embed from an HSL input.""" + """ + Command to create an embed from an HSL input. + + Input is in the form `.colour hsl ` + """ hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") - await Colour.send_colour_response(ctx, list(hsl_tuple)) + await self.send_colour_response(ctx, list(hsl_tuple)) @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: - """Function to create an embed from a CMYK input.""" + """ + Command to create an embed from a CMYK input. + + Input is in the form `.colour cmyk ` + """ r = int(255 * (1.0 - cyan / float(100)) * (1.0 - key / float(100))) g = int(255 * (1.0 - magenta / float(100)) * (1.0 - key / float(100))) b = int(255 * (1.0 - yellow / float(100)) * (1.0 - key / float(100))) - await Colour.send_colour_response(ctx, list((r, g, b))) + await self.send_colour_response(ctx, list((r, g, b))) @colour.command() async def hex(self, ctx: commands.Context, hex_code: str) -> None: - """Function to create an embed from a HEX input. (Requires # as a prefix).""" + """ + Command to create an embed from a HEX input. + + Input is in the form `.colour hex #` + """ hex_tuple = ImageColor.getrgb(hex_code) - await Colour.send_colour_response(ctx, list(hex_tuple)) + await self.send_colour_response(ctx, list(hex_tuple)) @colour.command() - async def name(self, ctx: commands.Context, user_color: str) -> None: - """Function to create an embed from a name input.""" - _, hex_color = self.match_color_name(user_color) - hex_tuple = ImageColor.getrgb(hex_color) - await Colour.send_colour_response(ctx, list(hex_tuple)) + async def name(self, ctx: commands.Context, user_colour: str) -> None: + """ + Command to create an embed from a name input. + + Input is in the form `.colour name ` + """ + _, hex_colour = self.match_colour_name(user_colour) + hex_tuple = ImageColor.getrgb(hex_colour) + await self.send_colour_response(ctx, list(hex_tuple)) @colour.command() async def random(self, ctx: commands.Context) -> None: - """Function to create an embed from a randomly chosen color from the ryanzec.json file.""" - color_choices = list(COLOR_MAPPING.values()) - hex_color = random.choice(color_choices) - hex_tuple = ImageColor.getrgb(f"#{hex_color}") - await Colour.send_colour_response(ctx, list(hex_tuple)) + """ + Command to create an embed from a randomly chosen colour from the reference file. - @staticmethod - async def send_colour_response(ctx: commands.Context, rgb: list[int]) -> None: - """Function to create and send embed from color information.""" + Input is in the form `.colour random` + """ + colour_choices = list(self.COLOUR_MAPPING.values()) + hex_colour = random.choice(colour_choices) + hex_tuple = ImageColor.getrgb(f"#{hex_colour}") + await self.send_colour_response(ctx, list(hex_tuple)) + + async def send_colour_response(self, ctx: commands.Context, rgb: list[int]) -> None: + """Function to create and send embed from colour information.""" r, g, b = rgb[0], rgb[1], rgb[2] - name = Colour._rgb_to_name(rgb) + name = self._rgb_to_name(rgb) + colour_mode = ctx.invoked_command if name is None: - desc = "Color information for the input color." + desc = f"{colour_mode.title()} information for the input colour." else: - desc = f"Color information for {name}." + desc = f"{colour_mode.title()} information for {name}." colour_embed = Embed( title="Colour", description=desc, colour=int(f"{r:02x}{g:02x}{b:02x}", 16) ) - colour_conversions = Colour.get_colour_conversions(rgb) + colour_conversions = self.get_colour_conversions(rgb) for colour_space, value in colour_conversions.items(): colour_embed.add_field( name=colour_space.upper(), @@ -104,7 +125,7 @@ class Colour(commands.Cog): inline=True ) - thumbnail = Image.new("RGB", (THUMBNAIL_SIZE, THUMBNAIL_SIZE), color=tuple(rgb)) + thumbnail = Image.new("RGB", THUMBNAIL_SIZE, color=tuple(rgb)) buffer = BytesIO() thumbnail.save(buffer, "PNG") buffer.seek(0) @@ -114,16 +135,15 @@ class Colour(commands.Cog): await ctx.send(file=thumbnail_file, embed=colour_embed) - @staticmethod - def get_colour_conversions(rgb: list[int]) -> dict[str, str]: - """Create a dictionary mapping of color types and their values.""" + def get_colour_conversions(self, rgb: list[int]) -> dict[str, str]: + """Create a dictionary mapping of colour types and their values.""" return { "rgb": tuple(rgb), - "hsv": Colour._rgb_to_hsv(rgb), - "hsl": Colour._rgb_to_hsl(rgb), - "cmyk": Colour._rgb_to_cmyk(rgb), - "hex": Colour._rgb_to_hex(rgb), - "name": Colour._rgb_to_name(rgb) + "hsv": self._rgb_to_hsv(rgb), + "hsl": self._rgb_to_hsl(rgb), + "cmyk": self._rgb_to_cmyk(rgb), + "hex": self._rgb_to_hex(rgb), + "name": self._rgb_to_name(rgb) } @staticmethod @@ -161,34 +181,34 @@ class Colour(commands.Cog): hex_code = f"#{hex_}".upper() return hex_code - @staticmethod - def _rgb_to_name(rgb: list[int]) -> str: - """Function to convert from an RGB list to a fuzzy matched color name.""" - input_hex_color = Colour._rgb_to_hex(rgb) + @classmethod + def _rgb_to_name(cls, rgb: list[int]) -> str: + """Function to convert from an RGB list to a fuzzy matched colour name.""" + input_hex_colour = cls._rgb_to_hex(rgb) try: match, certainty, _ = process.extractOne( - query=input_hex_color, - choices=COLOR_MAPPING.values(), + query=input_hex_colour, + choices=cls.COLOUR_MAPPING.values(), score_cutoff=80 ) - color_name = [name for name, _ in COLOR_MAPPING.items() if _ == match][0] + colour_name = [name for name, _ in cls.COLOUR_MAPPING.items() if _ == match][0] except TypeError: - color_name = None - return color_name + colour_name = None + return colour_name - @staticmethod - def match_color_name(input_color_name: str) -> str: - """Use fuzzy matching to return a hex color code based on the user's input.""" + @classmethod + def match_colour_name(cls, input_colour_name: str) -> str: + """Use fuzzy matching to return a hex colour code based on the user's input.""" try: match, certainty, _ = process.extractOne( - query=input_color_name, - choices=COLOR_MAPPING.keys(), + query=input_colour_name, + choices=cls.COLOUR_MAPPING.keys(), score_cutoff=50 ) - hex_match = f"#{COLOR_MAPPING[match]}" + hex_match = f"#{cls.COLOUR_MAPPING[match]}" except TypeError: - match = "No color name match found." - hex_match = input_color_name + match = "No colour name match found." + hex_match = input_colour_name return match, hex_match -- 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 05b56c0d58829b188f55490f9d6825ef95b9d9fb Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 27 Oct 2021 06:56:35 -0400 Subject: fix: testing fixes --- bot/exts/utilities/color.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 606f5fd4..495a1fd4 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -18,7 +18,8 @@ THUMBNAIL_SIZE = (80, 80) class Colour(commands.Cog): """Cog for the Colour command.""" - def __init__(self): + def __init__(self, bot: Bot): + self.bot = bot with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: self.COLOUR_MAPPING = json.load(f) @@ -107,7 +108,7 @@ class Colour(commands.Cog): """Function to create and send embed from colour information.""" r, g, b = rgb[0], rgb[1], rgb[2] name = self._rgb_to_name(rgb) - colour_mode = ctx.invoked_command + colour_mode = ctx.invoked_with if name is None: desc = f"{colour_mode.title()} information for the input colour." else: @@ -181,31 +182,29 @@ class Colour(commands.Cog): hex_code = f"#{hex_}".upper() return hex_code - @classmethod - def _rgb_to_name(cls, rgb: list[int]) -> str: + def _rgb_to_name(self, rgb: list[int]) -> str: """Function to convert from an RGB list to a fuzzy matched colour name.""" - input_hex_colour = cls._rgb_to_hex(rgb) + input_hex_colour = self._rgb_to_hex(rgb) try: match, certainty, _ = process.extractOne( query=input_hex_colour, - choices=cls.COLOUR_MAPPING.values(), + choices=self.COLOUR_MAPPING.values(), score_cutoff=80 ) - colour_name = [name for name, _ in cls.COLOUR_MAPPING.items() if _ == match][0] + colour_name = [name for name, _ in self.COLOUR_MAPPING.items() if _ == match][0] except TypeError: colour_name = None return colour_name - @classmethod - def match_colour_name(cls, input_colour_name: str) -> str: + def match_colour_name(self, input_colour_name: str) -> str: """Use fuzzy matching to return a hex colour code based on the user's input.""" try: match, certainty, _ = process.extractOne( query=input_colour_name, - choices=cls.COLOUR_MAPPING.keys(), + choices=self.COLOUR_MAPPING.keys(), score_cutoff=50 ) - hex_match = f"#{cls.COLOUR_MAPPING[match]}" + hex_match = f"#{self.COLOUR_MAPPING[match]}" except TypeError: match = "No colour name match found." hex_match = input_colour_name -- cgit v1.2.3 From 0fd2b8f960bcef646a16661f63e0fc21742fb8ab Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 27 Oct 2021 08:01:02 -0400 Subject: chore: embed format tweaking --- bot/exts/utilities/color.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 495a1fd4..a5b374d6 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -110,9 +110,9 @@ class Colour(commands.Cog): name = self._rgb_to_name(rgb) colour_mode = ctx.invoked_with if name is None: - desc = f"{colour_mode.title()} information for the input colour." + desc = f"{colour_mode.upper()} information for the input colour." else: - desc = f"{colour_mode.title()} information for {name}." + desc = f"{colour_mode.upper()} information for `{name}`." colour_embed = Embed( title="Colour", description=desc, -- cgit v1.2.3 From 20a3d55ef27a84e1911ea748e6edbe8b244d3317 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:49:42 -0400 Subject: chore: move send_colour_response to top of class --- bot/exts/utilities/color.py | 64 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index a5b374d6..ef2421e4 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -23,6 +23,38 @@ class Colour(commands.Cog): with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: self.COLOUR_MAPPING = json.load(f) + async def send_colour_response(self, ctx: commands.Context, rgb: list[int]) -> None: + """Function to create and send embed from colour information.""" + r, g, b = rgb[0], rgb[1], rgb[2] + name = self._rgb_to_name(rgb) + colour_mode = ctx.invoked_with + if name is None: + desc = f"{colour_mode.upper()} information for the input colour." + else: + desc = f"{colour_mode.upper()} information for `{name}`." + colour_embed = Embed( + title="Colour", + description=desc, + colour=int(f"{r:02x}{g:02x}{b:02x}", 16) + ) + colour_conversions = self.get_colour_conversions(rgb) + for colour_space, value in colour_conversions.items(): + colour_embed.add_field( + name=colour_space.upper(), + value=f"`{value}`", + inline=True + ) + + thumbnail = Image.new("RGB", THUMBNAIL_SIZE, color=tuple(rgb)) + buffer = BytesIO() + thumbnail.save(buffer, "PNG") + buffer.seek(0) + thumbnail_file = File(buffer, filename="colour.png") + + colour_embed.set_thumbnail(url="attachment://colour.png") + + await ctx.send(file=thumbnail_file, embed=colour_embed) + @commands.group(aliases=("color",)) async def colour(self, ctx: commands.Context) -> None: """User initiated command to create an embed that displays colour information.""" @@ -104,38 +136,6 @@ class Colour(commands.Cog): hex_tuple = ImageColor.getrgb(f"#{hex_colour}") await self.send_colour_response(ctx, list(hex_tuple)) - async def send_colour_response(self, ctx: commands.Context, rgb: list[int]) -> None: - """Function to create and send embed from colour information.""" - r, g, b = rgb[0], rgb[1], rgb[2] - name = self._rgb_to_name(rgb) - colour_mode = ctx.invoked_with - if name is None: - desc = f"{colour_mode.upper()} information for the input colour." - else: - desc = f"{colour_mode.upper()} information for `{name}`." - colour_embed = Embed( - title="Colour", - description=desc, - colour=int(f"{r:02x}{g:02x}{b:02x}", 16) - ) - colour_conversions = self.get_colour_conversions(rgb) - for colour_space, value in colour_conversions.items(): - colour_embed.add_field( - name=colour_space.upper(), - value=f"`{value}`", - inline=True - ) - - thumbnail = Image.new("RGB", THUMBNAIL_SIZE, color=tuple(rgb)) - buffer = BytesIO() - thumbnail.save(buffer, "PNG") - buffer.seek(0) - thumbnail_file = File(buffer, filename="colour.png") - - colour_embed.set_thumbnail(url="attachment://colour.png") - - await ctx.send(file=thumbnail_file, embed=colour_embed) - def get_colour_conversions(self, rgb: list[int]) -> dict[str, str]: """Create a dictionary mapping of colour types and their values.""" return { -- cgit v1.2.3 From 7d70bb40c164d176e3cb5653335c13196515f854 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 28 Oct 2021 07:09:01 -0400 Subject: chore: general code fixes and cleanup --- bot/exts/utilities/color.py | 91 +++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 62 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index ef2421e4..66dc78de 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -24,14 +24,11 @@ class Colour(commands.Cog): self.COLOUR_MAPPING = json.load(f) async def send_colour_response(self, ctx: commands.Context, rgb: list[int]) -> None: - """Function to create and send embed from colour information.""" + """Create and send embed from user given colour information.""" r, g, b = rgb[0], rgb[1], rgb[2] name = self._rgb_to_name(rgb) colour_mode = ctx.invoked_with - if name is None: - desc = f"{colour_mode.upper()} information for the input colour." - else: - desc = f"{colour_mode.upper()} information for `{name}`." + desc = f"{colour_mode.upper()} information for `{name or 'the input colour'}`." colour_embed = Embed( title="Colour", description=desc, @@ -40,7 +37,7 @@ class Colour(commands.Cog): colour_conversions = self.get_colour_conversions(rgb) for colour_space, value in colour_conversions.items(): colour_embed.add_field( - name=colour_space.upper(), + name=colour_space, value=f"`{value}`", inline=True ) @@ -63,41 +60,25 @@ class Colour(commands.Cog): @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: - """ - Command to create an embed from an RGB input. - - Input is in the form `.colour rgb ` - """ + """Command to create an embed from an RGB input.""" rgb_tuple = ImageColor.getrgb(f"rgb({red}, {green}, {blue})") await self.send_colour_response(ctx, list(rgb_tuple)) @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: - """ - Command to create an embed from an HSV input. - - Input is in the form `.colour hsv ` - """ + """Command to create an embed from an HSV input.""" hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") await self.send_colour_response(ctx, list(hsv_tuple)) @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: - """ - Command to create an embed from an HSL input. - - Input is in the form `.colour hsl ` - """ + """Command to create an embed from an HSL input.""" hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") await self.send_colour_response(ctx, list(hsl_tuple)) @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: - """ - Command to create an embed from a CMYK input. - - Input is in the form `.colour cmyk ` - """ + """Command to create an embed from a CMYK input.""" r = int(255 * (1.0 - cyan / float(100)) * (1.0 - key / float(100))) g = int(255 * (1.0 - magenta / float(100)) * (1.0 - key / float(100))) b = int(255 * (1.0 - yellow / float(100)) * (1.0 - key / float(100))) @@ -105,51 +86,38 @@ class Colour(commands.Cog): @colour.command() async def hex(self, ctx: commands.Context, hex_code: str) -> None: - """ - Command to create an embed from a HEX input. - - Input is in the form `.colour hex #` - """ + """Command to create an embed from a HEX input.""" hex_tuple = ImageColor.getrgb(hex_code) await self.send_colour_response(ctx, list(hex_tuple)) @colour.command() async def name(self, ctx: commands.Context, user_colour: str) -> None: - """ - Command to create an embed from a name input. - - Input is in the form `.colour name ` - """ - _, hex_colour = self.match_colour_name(user_colour) + """Command to create an embed from a name input.""" + hex_colour = self.match_colour_name(user_colour) hex_tuple = ImageColor.getrgb(hex_colour) await self.send_colour_response(ctx, list(hex_tuple)) @colour.command() async def random(self, ctx: commands.Context) -> None: - """ - Command to create an embed from a randomly chosen colour from the reference file. - - Input is in the form `.colour random` - """ - colour_choices = list(self.COLOUR_MAPPING.values()) - hex_colour = random.choice(colour_choices) + """Command to create an embed from a randomly chosen colour from the reference file.""" + hex_colour = random.choice(list(self.COLOUR_MAPPING.values())) hex_tuple = ImageColor.getrgb(f"#{hex_colour}") await self.send_colour_response(ctx, list(hex_tuple)) def get_colour_conversions(self, rgb: list[int]) -> dict[str, str]: """Create a dictionary mapping of colour types and their values.""" return { - "rgb": tuple(rgb), - "hsv": self._rgb_to_hsv(rgb), - "hsl": self._rgb_to_hsl(rgb), - "cmyk": self._rgb_to_cmyk(rgb), - "hex": self._rgb_to_hex(rgb), - "name": self._rgb_to_name(rgb) + "RGB": tuple(rgb), + "HSV": self._rgb_to_hsv(rgb), + "HSL": self._rgb_to_hsl(rgb), + "CMYK": self._rgb_to_cmyk(rgb), + "Hex": self._rgb_to_hex(rgb), + "Name": self._rgb_to_name(rgb) } @staticmethod def _rgb_to_hsv(rgb: list[int]) -> tuple[int, int, int]: - """Function to convert an RGB list to a HSV list.""" + """Convert RGB values to HSV values.""" rgb = [val / 255.0 for val in rgb] h, v, s = colorsys.rgb_to_hsv(*rgb) hsv = (round(h * 360), round(s * 100), round(v * 100)) @@ -157,7 +125,7 @@ class Colour(commands.Cog): @staticmethod def _rgb_to_hsl(rgb: list[int]) -> tuple[int, int, int]: - """Function to convert an RGB list to a HSL list.""" + """Convert RGB values to HSL values.""" rgb = [val / 255.0 for val in rgb] h, l, s = colorsys.rgb_to_hls(*rgb) hsl = (round(h * 360), round(s * 100), round(l * 100)) @@ -165,7 +133,7 @@ class Colour(commands.Cog): @staticmethod def _rgb_to_cmyk(rgb: list[int]) -> tuple[int, int, int, int]: - """Function to convert an RGB list to a CMYK list.""" + """Convert RGB values to CMYK values.""" rgb = [val / 255.0 for val in rgb] if all(val == 0 for val in rgb): return 0, 0, 0, 100 @@ -177,13 +145,13 @@ class Colour(commands.Cog): @staticmethod def _rgb_to_hex(rgb: list[int]) -> str: - """Function to convert an RGB list to a HEX string.""" + """Convert RGB values to HEX code.""" hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) hex_code = f"#{hex_}".upper() return hex_code def _rgb_to_name(self, rgb: list[int]) -> str: - """Function to convert from an RGB list to a fuzzy matched colour name.""" + """Convert RGB values to a fuzzy matched name.""" input_hex_colour = self._rgb_to_hex(rgb) try: match, certainty, _ = process.extractOne( @@ -191,24 +159,23 @@ class Colour(commands.Cog): choices=self.COLOUR_MAPPING.values(), score_cutoff=80 ) - colour_name = [name for name, _ in self.COLOUR_MAPPING.items() if _ == match][0] + colour_name = [name for name, hex_code in self.COLOUR_MAPPING.items() if hex_code == match][0] except TypeError: colour_name = None return colour_name def match_colour_name(self, input_colour_name: str) -> str: - """Use fuzzy matching to return a hex colour code based on the user's input.""" + """Convert a colour name to HEX code.""" try: match, certainty, _ = process.extractOne( query=input_colour_name, choices=self.COLOUR_MAPPING.keys(), - score_cutoff=50 + score_cutoff=90 ) hex_match = f"#{self.COLOUR_MAPPING[match]}" - except TypeError: - match = "No colour name match found." - hex_match = input_colour_name - return match, hex_match + except (ValueError, TypeError): + hex_match = None + return hex_match def setup(bot: Bot) -> None: -- cgit v1.2.3 From a742fe985eaee3757e565b6f8880c014eda15e10 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 28 Oct 2021 08:49:57 -0400 Subject: chore: change to tuples, various suggested changes --- bot/exts/utilities/color.py | 60 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 66dc78de..e9e8dcf6 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -23,9 +23,9 @@ class Colour(commands.Cog): with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: self.COLOUR_MAPPING = json.load(f) - async def send_colour_response(self, ctx: commands.Context, rgb: list[int]) -> None: + async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: """Create and send embed from user given colour information.""" - r, g, b = rgb[0], rgb[1], rgb[2] + r, g, b = rgb name = self._rgb_to_name(rgb) colour_mode = ctx.invoked_with desc = f"{colour_mode.upper()} information for `{name or 'the input colour'}`." @@ -42,7 +42,7 @@ class Colour(commands.Cog): inline=True ) - thumbnail = Image.new("RGB", THUMBNAIL_SIZE, color=tuple(rgb)) + thumbnail = Image.new("RGB", THUMBNAIL_SIZE, color=rgb) buffer = BytesIO() thumbnail.save(buffer, "PNG") buffer.seek(0) @@ -61,53 +61,53 @@ class Colour(commands.Cog): @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: """Command to create an embed from an RGB input.""" - rgb_tuple = ImageColor.getrgb(f"rgb({red}, {green}, {blue})") - await self.send_colour_response(ctx, list(rgb_tuple)) + rgb_tuple = (red, green, blue) + await self.send_colour_response(ctx, rgb_tuple) @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: """Command to create an embed from an HSV input.""" hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") - await self.send_colour_response(ctx, list(hsv_tuple)) + await self.send_colour_response(ctx, hsv_tuple) @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: """Command to create an embed from an HSL input.""" hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") - await self.send_colour_response(ctx, list(hsl_tuple)) + await self.send_colour_response(ctx, hsl_tuple) @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: """Command to create an embed from a CMYK input.""" - r = int(255 * (1.0 - cyan / float(100)) * (1.0 - key / float(100))) - g = int(255 * (1.0 - magenta / float(100)) * (1.0 - key / float(100))) - b = int(255 * (1.0 - yellow / float(100)) * (1.0 - key / float(100))) - await self.send_colour_response(ctx, list((r, g, b))) + r = int(255 * (1.0 - cyan / 100) * (1.0 - key / 100)) + g = int(255 * (1.0 - magenta / 100) * (1.0 - key / 100)) + b = int(255 * (1.0 - yellow / 100) * (1.0 - key / 100)) + await self.send_colour_response(ctx, (r, g, b)) @colour.command() async def hex(self, ctx: commands.Context, hex_code: str) -> None: """Command to create an embed from a HEX input.""" hex_tuple = ImageColor.getrgb(hex_code) - await self.send_colour_response(ctx, list(hex_tuple)) + await self.send_colour_response(ctx, hex_tuple) @colour.command() - async def name(self, ctx: commands.Context, user_colour: str) -> None: + async def name(self, ctx: commands.Context, user_colour_name: str) -> None: """Command to create an embed from a name input.""" - hex_colour = self.match_colour_name(user_colour) + hex_colour = self.match_colour_name(user_colour_name) hex_tuple = ImageColor.getrgb(hex_colour) - await self.send_colour_response(ctx, list(hex_tuple)) + await self.send_colour_response(ctx, hex_tuple) @colour.command() async def random(self, ctx: commands.Context) -> None: """Command to create an embed from a randomly chosen colour from the reference file.""" hex_colour = random.choice(list(self.COLOUR_MAPPING.values())) hex_tuple = ImageColor.getrgb(f"#{hex_colour}") - await self.send_colour_response(ctx, list(hex_tuple)) + await self.send_colour_response(ctx, hex_tuple) - def get_colour_conversions(self, rgb: list[int]) -> dict[str, str]: + def get_colour_conversions(self, rgb: tuple[int, int, int]) -> dict[str, str]: """Create a dictionary mapping of colour types and their values.""" return { - "RGB": tuple(rgb), + "RGB": rgb, "HSV": self._rgb_to_hsv(rgb), "HSL": self._rgb_to_hsl(rgb), "CMYK": self._rgb_to_cmyk(rgb), @@ -116,41 +116,41 @@ class Colour(commands.Cog): } @staticmethod - def _rgb_to_hsv(rgb: list[int]) -> tuple[int, int, int]: + def _rgb_to_hsv(rgb: tuple[int, int, int]) -> tuple[int, int, int]: """Convert RGB values to HSV values.""" - rgb = [val / 255.0 for val in rgb] - h, v, s = colorsys.rgb_to_hsv(*rgb) + rgb_list = [val / 255.0 for val in rgb] + h, v, s = colorsys.rgb_to_hsv(*rgb_list) hsv = (round(h * 360), round(s * 100), round(v * 100)) return hsv @staticmethod - def _rgb_to_hsl(rgb: list[int]) -> tuple[int, int, int]: + def _rgb_to_hsl(rgb: tuple[int, int, int]) -> tuple[int, int, int]: """Convert RGB values to HSL values.""" - rgb = [val / 255.0 for val in rgb] - h, l, s = colorsys.rgb_to_hls(*rgb) + rgb_list = [val / 255.0 for val in rgb] + h, l, s = colorsys.rgb_to_hls(*rgb_list) hsl = (round(h * 360), round(s * 100), round(l * 100)) return hsl @staticmethod - def _rgb_to_cmyk(rgb: list[int]) -> tuple[int, int, int, int]: + def _rgb_to_cmyk(rgb: tuple[int, int, int, int]) -> tuple[int, int, int, int]: """Convert RGB values to CMYK values.""" - rgb = [val / 255.0 for val in rgb] - if all(val == 0 for val in rgb): + rgb_list = [val / 255.0 for val in rgb] + if not any(rgb_list): return 0, 0, 0, 100 - cmy = [1 - val / 255 for val in rgb] + cmy = [1 - val / 255 for val in rgb_list] min_cmy = min(cmy) cmyk = [(val - min_cmy) / (1 - min_cmy) for val in cmy] + [min_cmy] cmyk = [round(val * 100) for val in cmyk] return tuple(cmyk) @staticmethod - def _rgb_to_hex(rgb: list[int]) -> str: + def _rgb_to_hex(rgb: tuple[int, int, int]) -> str: """Convert RGB values to HEX code.""" hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) hex_code = f"#{hex_}".upper() return hex_code - def _rgb_to_name(self, rgb: list[int]) -> str: + def _rgb_to_name(self, rgb: tuple[int, int, int]) -> str: """Convert RGB values to a fuzzy matched name.""" input_hex_colour = self._rgb_to_hex(rgb) try: -- cgit v1.2.3 From b2151ebc86a538b6e8eb492a2b10a7cd2c12f900 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 28 Oct 2021 09:01:57 -0400 Subject: chore: correct capitalization of command name in embed --- bot/exts/utilities/color.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index e9e8dcf6..573039fa 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -28,9 +28,14 @@ class Colour(commands.Cog): r, g, b = rgb name = self._rgb_to_name(rgb) colour_mode = ctx.invoked_with - desc = f"{colour_mode.upper()} information for `{name or 'the input colour'}`." + colour_or_color = ctx.command.name + if colour_mode not in ("name", "hex", "random"): + colour_mode = colour_mode.upper() + else: + colour_mode = colour_mode.title() + desc = f"{colour_mode} information for `{name or 'the input colour'}`." colour_embed = Embed( - title="Colour", + title=colour_or_color.title(), description=desc, colour=int(f"{r:02x}{g:02x}{b:02x}", 16) ) -- cgit v1.2.3 From 364a7083ab38c3055c6db514e5203d68d61eb597 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 28 Oct 2021 09:13:49 -0400 Subject: chore: change COLOUR_MAPPING to colour_mapping --- bot/exts/utilities/color.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 573039fa..9356577f 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -21,7 +21,7 @@ class Colour(commands.Cog): def __init__(self, bot: Bot): self.bot = bot with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: - self.COLOUR_MAPPING = json.load(f) + self.colour_mapping = json.load(f) async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: """Create and send embed from user given colour information.""" @@ -105,7 +105,7 @@ class Colour(commands.Cog): @colour.command() async def random(self, ctx: commands.Context) -> None: """Command to create an embed from a randomly chosen colour from the reference file.""" - hex_colour = random.choice(list(self.COLOUR_MAPPING.values())) + hex_colour = random.choice(list(self.colour_mapping.values())) hex_tuple = ImageColor.getrgb(f"#{hex_colour}") await self.send_colour_response(ctx, hex_tuple) @@ -161,10 +161,10 @@ class Colour(commands.Cog): try: match, certainty, _ = process.extractOne( query=input_hex_colour, - choices=self.COLOUR_MAPPING.values(), + choices=self.colour_mapping.values(), score_cutoff=80 ) - colour_name = [name for name, hex_code in self.COLOUR_MAPPING.items() if hex_code == match][0] + colour_name = [name for name, hex_code in self.colour_mapping.items() if hex_code == match][0] except TypeError: colour_name = None return colour_name @@ -174,10 +174,10 @@ class Colour(commands.Cog): try: match, certainty, _ = process.extractOne( query=input_colour_name, - choices=self.COLOUR_MAPPING.keys(), + choices=self.colour_mapping.keys(), score_cutoff=90 ) - hex_match = f"#{self.COLOUR_MAPPING[match]}" + hex_match = f"#{self.colour_mapping[match]}" except (ValueError, TypeError): hex_match = None return hex_match -- cgit v1.2.3 From 869f21a7cc376ef2382bc88980b660226b621cdd Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 28 Oct 2021 19:00:31 -0400 Subject: fix: added error handling and other cleanup chores --- bot/exts/utilities/color.py | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9356577f..fe57d388 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -7,6 +7,7 @@ from io import BytesIO from PIL import Image, ImageColor from discord import Embed, File from discord.ext import commands +from discord.ext.commands.errors import BadArgument from rapidfuzz import process from bot.bot import Bot @@ -28,12 +29,16 @@ class Colour(commands.Cog): r, g, b = rgb name = self._rgb_to_name(rgb) colour_mode = ctx.invoked_with - colour_or_color = ctx.command.name + try: + colour_or_color = ctx.invoked_parents[0] + except IndexError: + colour_or_color = "colour" + input_colour = ctx.args[2:] if colour_mode not in ("name", "hex", "random"): colour_mode = colour_mode.upper() else: colour_mode = colour_mode.title() - desc = f"{colour_mode} information for `{name or 'the input colour'}`." + desc = f"{colour_mode} information for `{name or input_colour}`." colour_embed = Embed( title=colour_or_color.title(), description=desc, @@ -66,32 +71,50 @@ class Colour(commands.Cog): @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: """Command to create an embed from an RGB input.""" + if (red or green or blue) > 250 or (red or green or blue) < 0: + raise BadArgument( + message=f"RGB values can only be from 0 to 250. User input was: `{red, green, blue}`" + ) rgb_tuple = (red, green, blue) await self.send_colour_response(ctx, rgb_tuple) @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: """Command to create an embed from an HSV input.""" + if (hue or saturation or value) > 250 or (hue or saturation or value) < 0: + raise BadArgument( + message=f"HSV values can only be from 0 to 250. User input was: `{hue, saturation, value}`" + ) hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") await self.send_colour_response(ctx, hsv_tuple) @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: """Command to create an embed from an HSL input.""" + if (hue or saturation or lightness) > 360 or (hue or saturation or lightness) < 0: + raise BadArgument( + message=f"HSL values can only be from 0 to 360. User input was: `{hue, saturation, lightness}`" + ) hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") await self.send_colour_response(ctx, hsl_tuple) @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: """Command to create an embed from a CMYK input.""" - r = int(255 * (1.0 - cyan / 100) * (1.0 - key / 100)) - g = int(255 * (1.0 - magenta / 100) * (1.0 - key / 100)) - b = int(255 * (1.0 - yellow / 100) * (1.0 - key / 100)) + if (cyan or magenta or yellow or key) > 100 or (cyan or magenta or yellow or key) < 0: + raise BadArgument( + message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`" + ) + r = int(255 * (1.0 - cyan / float(100)) * (1.0 - key / float(100))) + g = int(255 * (1.0 - magenta / float(100)) * (1.0 - key / float(100))) + b = int(255 * (1.0 - yellow / float(100)) * (1.0 - key / float(100))) await self.send_colour_response(ctx, (r, g, b)) @colour.command() async def hex(self, ctx: commands.Context, hex_code: str) -> None: """Command to create an embed from a HEX input.""" + if "#" not in hex_code: + hex_code = f"#{hex_code}" hex_tuple = ImageColor.getrgb(hex_code) await self.send_colour_response(ctx, hex_tuple) @@ -175,11 +198,12 @@ class Colour(commands.Cog): match, certainty, _ = process.extractOne( query=input_colour_name, choices=self.colour_mapping.keys(), - score_cutoff=90 + score_cutoff=80 ) hex_match = f"#{self.colour_mapping[match]}" except (ValueError, TypeError): hex_match = None + raise BadArgument(message=f"No color found for: `{input_colour_name}`") return hex_match -- cgit v1.2.3 From 5437712fe6fb5bc2149207f342afdfd37edece6e Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 28 Oct 2021 19:01:11 -0400 Subject: fix: add periods to error messages --- bot/exts/utilities/color.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index fe57d388..1ad6df27 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -73,7 +73,7 @@ class Colour(commands.Cog): """Command to create an embed from an RGB input.""" if (red or green or blue) > 250 or (red or green or blue) < 0: raise BadArgument( - message=f"RGB values can only be from 0 to 250. User input was: `{red, green, blue}`" + message=f"RGB values can only be from 0 to 250. User input was: `{red, green, blue}`." ) rgb_tuple = (red, green, blue) await self.send_colour_response(ctx, rgb_tuple) @@ -83,7 +83,7 @@ class Colour(commands.Cog): """Command to create an embed from an HSV input.""" if (hue or saturation or value) > 250 or (hue or saturation or value) < 0: raise BadArgument( - message=f"HSV values can only be from 0 to 250. User input was: `{hue, saturation, value}`" + message=f"HSV values can only be from 0 to 250. User input was: `{hue, saturation, value}`." ) hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") await self.send_colour_response(ctx, hsv_tuple) @@ -93,7 +93,7 @@ class Colour(commands.Cog): """Command to create an embed from an HSL input.""" if (hue or saturation or lightness) > 360 or (hue or saturation or lightness) < 0: raise BadArgument( - message=f"HSL values can only be from 0 to 360. User input was: `{hue, saturation, lightness}`" + message=f"HSL values can only be from 0 to 360. User input was: `{hue, saturation, lightness}`." ) hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") await self.send_colour_response(ctx, hsl_tuple) @@ -103,7 +103,7 @@ class Colour(commands.Cog): """Command to create an embed from a CMYK input.""" if (cyan or magenta or yellow or key) > 100 or (cyan or magenta or yellow or key) < 0: raise BadArgument( - message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`" + message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." ) r = int(255 * (1.0 - cyan / float(100)) * (1.0 - key / float(100))) g = int(255 * (1.0 - magenta / float(100)) * (1.0 - key / float(100))) -- cgit v1.2.3 From 1d1dff113de6c276d614a945789755d3c4f9c3ab Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 28 Oct 2021 19:40:09 -0400 Subject: fix: bug in cmyk and hsv --- bot/exts/utilities/color.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 1ad6df27..f594a0df 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -85,7 +85,8 @@ class Colour(commands.Cog): raise BadArgument( message=f"HSV values can only be from 0 to 250. User input was: `{hue, saturation, value}`." ) - hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") + # ImageColor HSV expects S and V to be swapped + hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {value}%, {saturation}%)") await self.send_colour_response(ctx, hsv_tuple) @colour.command() @@ -99,15 +100,15 @@ class Colour(commands.Cog): await self.send_colour_response(ctx, hsl_tuple) @colour.command() - async def cmyk(self, ctx: commands.Context, cyan: int, yellow: int, magenta: int, key: int) -> None: + async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: """Command to create an embed from a CMYK input.""" if (cyan or magenta or yellow or key) > 100 or (cyan or magenta or yellow or key) < 0: raise BadArgument( message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." ) - r = int(255 * (1.0 - cyan / float(100)) * (1.0 - key / float(100))) - g = int(255 * (1.0 - magenta / float(100)) * (1.0 - key / float(100))) - b = int(255 * (1.0 - yellow / float(100)) * (1.0 - key / float(100))) + r = round(255 * (1 - (cyan / 100)) * (1 - (key / 100))) + g = round(255 * (1 - (magenta / 100)) * (1 - (key / 100))) + b = round(255 * (1 - (yellow / 100)) * (1 - (key / 100))) await self.send_colour_response(ctx, (r, g, b)) @colour.command() @@ -165,11 +166,12 @@ class Colour(commands.Cog): rgb_list = [val / 255.0 for val in rgb] if not any(rgb_list): return 0, 0, 0, 100 - cmy = [1 - val / 255 for val in rgb_list] - min_cmy = min(cmy) - cmyk = [(val - min_cmy) / (1 - min_cmy) for val in cmy] + [min_cmy] - cmyk = [round(val * 100) for val in cmyk] - return tuple(cmyk) + k = 1 - max(val for val in rgb_list) + c = round((1 - rgb_list[0] - k) * 100 / (1 - k)) + m = round((1 - rgb_list[1] - k) * 100 / (1 - k)) + y = round((1 - rgb_list[2] - k) * 100 / (1 - k)) + cmyk = (c, m, y, round(k * 100)) + return cmyk @staticmethod def _rgb_to_hex(rgb: tuple[int, int, int]) -> str: -- 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 3ba2dfdfe51b543ac427b1dd50a5b3dcd73e8afc Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Fri, 29 Oct 2021 06:37:56 -0400 Subject: fix: correct ranges and logic for color error handling --- bot/exts/utilities/color.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index f594a0df..587d4e18 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -33,7 +33,7 @@ class Colour(commands.Cog): colour_or_color = ctx.invoked_parents[0] except IndexError: colour_or_color = "colour" - input_colour = ctx.args[2:] + input_colour = ctx.args[2:][0] if colour_mode not in ("name", "hex", "random"): colour_mode = colour_mode.upper() else: @@ -71,9 +71,9 @@ class Colour(commands.Cog): @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: """Command to create an embed from an RGB input.""" - if (red or green or blue) > 250 or (red or green or blue) < 0: + if any(c not in range(0, 256) for c in (red, green, blue)): raise BadArgument( - message=f"RGB values can only be from 0 to 250. User input was: `{red, green, blue}`." + message=f"RGB values can only be from 0 to 255. User input was: `{red, green, blue}`." ) rgb_tuple = (red, green, blue) await self.send_colour_response(ctx, rgb_tuple) @@ -81,9 +81,10 @@ class Colour(commands.Cog): @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: """Command to create an embed from an HSV input.""" - if (hue or saturation or value) > 250 or (hue or saturation or value) < 0: + if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, value)): raise BadArgument( - message=f"HSV values can only be from 0 to 250. User input was: `{hue, saturation, value}`." + message="Hue can only be from 0 to 360. Saturation and Value can only be from 0 to 100. " + f"User input was: `{hue, saturation, value}`." ) # ImageColor HSV expects S and V to be swapped hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {value}%, {saturation}%)") @@ -92,9 +93,10 @@ class Colour(commands.Cog): @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: """Command to create an embed from an HSL input.""" - if (hue or saturation or lightness) > 360 or (hue or saturation or lightness) < 0: + if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, lightness)): raise BadArgument( - message=f"HSL values can only be from 0 to 360. User input was: `{hue, saturation, lightness}`." + message="Hue can only be from 0 to 360. Saturation and Lightness can only be from 0 to 100. " + f"User input was: `{hue, saturation, lightness}`." ) hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") await self.send_colour_response(ctx, hsl_tuple) @@ -102,7 +104,7 @@ class Colour(commands.Cog): @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: """Command to create an embed from a CMYK input.""" - if (cyan or magenta or yellow or key) > 100 or (cyan or magenta or yellow or key) < 0: + if any(c not in range(0, 101) for c in (cyan or magenta or yellow or key)): raise BadArgument( message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." ) @@ -191,7 +193,7 @@ class Colour(commands.Cog): ) colour_name = [name for name, hex_code in self.colour_mapping.items() if hex_code == match][0] except TypeError: - colour_name = None + colour_name = "No match found" return colour_name def match_colour_name(self, input_colour_name: str) -> str: @@ -204,7 +206,6 @@ class Colour(commands.Cog): ) hex_match = f"#{self.colour_mapping[match]}" except (ValueError, TypeError): - hex_match = None raise BadArgument(message=f"No color found for: `{input_colour_name}`") return hex_match -- cgit v1.2.3 From 930c9649eaec79cebfa2969501b4614ccd26d069 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Fri, 29 Oct 2021 07:03:59 -0400 Subject: chore: add some conditions for the embed variables --- bot/exts/utilities/color.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 587d4e18..a21b74e4 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -28,16 +28,25 @@ class Colour(commands.Cog): """Create and send embed from user given colour information.""" r, g, b = rgb name = self._rgb_to_name(rgb) - colour_mode = ctx.invoked_with + if name == "No match found": + name = None + try: colour_or_color = ctx.invoked_parents[0] except IndexError: colour_or_color = "colour" - input_colour = ctx.args[2:][0] + + colour_mode = ctx.invoked_with + if colour_mode == "random": + input_colour = "random" + else: + input_colour = ctx.args[2:][0] + if colour_mode not in ("name", "hex", "random"): colour_mode = colour_mode.upper() else: colour_mode = colour_mode.title() + desc = f"{colour_mode} information for `{name or input_colour}`." colour_embed = Embed( title=colour_or_color.title(), -- cgit v1.2.3 From 409434dbf9c14fb47d20c1329f86a3863f19a2be Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 29 Oct 2021 15:49:57 -0400 Subject: fix: iterate through tuple Co-authored-by: Sn4u <35849006+Sn4u@users.noreply.github.com> --- bot/exts/utilities/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index a21b74e4..035f7d6a 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -113,7 +113,7 @@ class Colour(commands.Cog): @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: """Command to create an embed from a CMYK input.""" - if any(c not in range(0, 101) for c in (cyan or magenta or yellow or key)): + if any(c not in range(0, 101) for c in (cyan, magenta, yellow, key)): raise BadArgument( message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." ) -- cgit v1.2.3 From 88089140dab024b43428b31ef7c729219ff19b4a Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Fri, 29 Oct 2021 21:00:35 -0400 Subject: fix: invoke without command, hsv fix --- bot/exts/utilities/color.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 035f7d6a..5f5708b2 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -39,10 +39,12 @@ class Colour(commands.Cog): colour_mode = ctx.invoked_with if colour_mode == "random": input_colour = "random" + elif colour_mode in ("colour", "color"): + input_colour = rgb else: input_colour = ctx.args[2:][0] - if colour_mode not in ("name", "hex", "random"): + if colour_mode not in ("name", "hex", "random", "color", "colour"): colour_mode = colour_mode.upper() else: colour_mode = colour_mode.title() @@ -71,11 +73,15 @@ class Colour(commands.Cog): await ctx.send(file=thumbnail_file, embed=colour_embed) - @commands.group(aliases=("color",)) - async def colour(self, ctx: commands.Context) -> None: + @commands.group(aliases=("color",), invoke_without_command=True) + async def colour(self, ctx: commands.Context, *, extra: str) -> None: """User initiated command to create an embed that displays colour information.""" if ctx.invoked_subcommand is None: - await invoke_help_command(ctx) + try: + extra_colour = ImageColor.getrgb(extra) + await self.send_colour_response(ctx, extra_colour) + except ValueError: + await invoke_help_command(ctx) @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: @@ -95,8 +101,7 @@ class Colour(commands.Cog): message="Hue can only be from 0 to 360. Saturation and Value can only be from 0 to 100. " f"User input was: `{hue, saturation, value}`." ) - # ImageColor HSV expects S and V to be swapped - hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {value}%, {saturation}%)") + hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") await self.send_colour_response(ctx, hsv_tuple) @colour.command() @@ -158,8 +163,8 @@ class Colour(commands.Cog): @staticmethod def _rgb_to_hsv(rgb: tuple[int, int, int]) -> tuple[int, int, int]: """Convert RGB values to HSV values.""" - rgb_list = [val / 255.0 for val in rgb] - h, v, s = colorsys.rgb_to_hsv(*rgb_list) + rgb_list = [val / 255 for val in rgb] + h, s, v = colorsys.rgb_to_hsv(*rgb_list) hsv = (round(h * 360), round(s * 100), round(v * 100)) return hsv -- cgit v1.2.3 From eac9d3b4194004894d4f4e50862f184db695d402 Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Mon, 1 Nov 2021 20:17:15 +0530 Subject: Add source credit and Color.from_rgb method to get discord color https://github.com/python-discord/sir-lancebot/pull/842/files#r739619938 https://github.com/python-discord/sir-lancebot/pull/842/files#r739295253 --- bot/exts/utilities/color.py | 6 +++--- bot/resources/utilities/ryanzec_colours.json | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 5f5708b2..563376fe 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -5,7 +5,7 @@ import random from io import BytesIO from PIL import Image, ImageColor -from discord import Embed, File +from discord import Embed, File, Color from discord.ext import commands from discord.ext.commands.errors import BadArgument from rapidfuzz import process @@ -23,10 +23,10 @@ class Colour(commands.Cog): self.bot = bot with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: self.colour_mapping = json.load(f) + del self.colour_mapping['_'] # Delete source credit entry async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: """Create and send embed from user given colour information.""" - r, g, b = rgb name = self._rgb_to_name(rgb) if name == "No match found": name = None @@ -53,7 +53,7 @@ class Colour(commands.Cog): colour_embed = Embed( title=colour_or_color.title(), description=desc, - colour=int(f"{r:02x}{g:02x}{b:02x}", 16) + colour= Color.from_rgb(*rgb) ) colour_conversions = self.get_colour_conversions(rgb) for colour_space, value in colour_conversions.items(): diff --git a/bot/resources/utilities/ryanzec_colours.json b/bot/resources/utilities/ryanzec_colours.json index 7b89f052..ad8f05fd 100644 --- a/bot/resources/utilities/ryanzec_colours.json +++ b/bot/resources/utilities/ryanzec_colours.json @@ -1,4 +1,5 @@ { + "_": "Source: https://github.com/ryanzec/name-that-color/blob/0bb5ec7f37e4f6e7f2c164f39f7f08cca7c8e621/lib/ntc.js#L116-L1681", "Abbey": "4C4F56", "Acadia": "1B1404", "Acapulco": "7CB0A1", -- cgit v1.2.3 From 15a346bc726f6ca9075f6692b6deb2f486cc66aa Mon Sep 17 00:00:00 2001 From: CyberCitizen01 Date: Mon, 1 Nov 2021 20:23:09 +0530 Subject: Fix lint errors of eac9d3b4194004894d4f4e50862f184db695d402 --- bot/exts/utilities/color.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 563376fe..c79e7620 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -5,7 +5,7 @@ import random from io import BytesIO from PIL import Image, ImageColor -from discord import Embed, File, Color +from discord import Color, Embed, File from discord.ext import commands from discord.ext.commands.errors import BadArgument from rapidfuzz import process @@ -23,7 +23,7 @@ class Colour(commands.Cog): self.bot = bot with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: self.colour_mapping = json.load(f) - del self.colour_mapping['_'] # Delete source credit entry + del self.colour_mapping['_'] # Delete source credit entry async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: """Create and send embed from user given colour information.""" @@ -53,7 +53,7 @@ class Colour(commands.Cog): colour_embed = Embed( title=colour_or_color.title(), description=desc, - colour= Color.from_rgb(*rgb) + colour=Color.from_rgb(*rgb) ) colour_conversions = self.get_colour_conversions(rgb) for colour_space, value in colour_conversions.items(): -- 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 c869faf32ceeadc94a8a38b5370706a4b6da32ae Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 3 Nov 2021 20:40:15 -0400 Subject: fix: return None if no name match is found --- bot/exts/utilities/color.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index c79e7620..9c801413 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -28,8 +28,8 @@ class Colour(commands.Cog): async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: """Create and send embed from user given colour information.""" name = self._rgb_to_name(rgb) - if name == "No match found": - name = None + if name is None: + name = "No match found" try: colour_or_color = ctx.invoked_parents[0] @@ -207,7 +207,7 @@ class Colour(commands.Cog): ) colour_name = [name for name, hex_code in self.colour_mapping.items() if hex_code == match][0] except TypeError: - colour_name = "No match found" + colour_name = None return colour_name def match_colour_name(self, input_colour_name: str) -> str: -- cgit v1.2.3 From 6869fa330ea67bced27df68d3b730e5fdbdb7aa4 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 3 Nov 2021 21:01:36 -0400 Subject: fix: use and handle conversions with name value --- bot/exts/utilities/color.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 9c801413..56036cd0 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -151,13 +151,16 @@ class Colour(commands.Cog): def get_colour_conversions(self, rgb: tuple[int, int, int]) -> dict[str, str]: """Create a dictionary mapping of colour types and their values.""" + colour_name = self._rgb_to_name(rgb) + if colour_name is None: + colour_name = "No match found" return { "RGB": rgb, "HSV": self._rgb_to_hsv(rgb), "HSL": self._rgb_to_hsl(rgb), "CMYK": self._rgb_to_cmyk(rgb), "Hex": self._rgb_to_hex(rgb), - "Name": self._rgb_to_name(rgb) + "Name": colour_name } @staticmethod @@ -182,7 +185,7 @@ class Colour(commands.Cog): rgb_list = [val / 255.0 for val in rgb] if not any(rgb_list): return 0, 0, 0, 100 - k = 1 - max(val for val in rgb_list) + k = 1 - max(rgb_list) c = round((1 - rgb_list[0] - k) * 100 / (1 - k)) m = round((1 - rgb_list[1] - k) * 100 / (1 - k)) y = round((1 - rgb_list[2] - k) * 100 / (1 - k)) -- cgit v1.2.3 From 3280188ecb025c64597484b145aff9c19916a4e6 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 3 Nov 2021 21:02:20 -0400 Subject: fix: have description in-line --- bot/exts/utilities/color.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 56036cd0..2e18884c 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -49,10 +49,9 @@ class Colour(commands.Cog): else: colour_mode = colour_mode.title() - desc = f"{colour_mode} information for `{name or input_colour}`." colour_embed = Embed( title=colour_or_color.title(), - description=desc, + description=f"{colour_mode} information for `{name or input_colour}`.", colour=Color.from_rgb(*rgb) ) colour_conversions = self.get_colour_conversions(rgb) -- cgit v1.2.3 From a66cdd48784baf948e294b10f7f81746c0c4452d Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 3 Nov 2021 21:08:50 -0400 Subject: fix: reduce 'from' imports --- bot/exts/utilities/color.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py index 2e18884c..5ff1e2b8 100644 --- a/bot/exts/utilities/color.py +++ b/bot/exts/utilities/color.py @@ -4,11 +4,10 @@ import pathlib import random from io import BytesIO +import discord +import rapidfuzz from PIL import Image, ImageColor -from discord import Color, Embed, File from discord.ext import commands -from discord.ext.commands.errors import BadArgument -from rapidfuzz import process from bot.bot import Bot from bot.exts.core.extensions import invoke_help_command @@ -49,10 +48,10 @@ class Colour(commands.Cog): else: colour_mode = colour_mode.title() - colour_embed = Embed( + colour_embed = discord.Embed( title=colour_or_color.title(), description=f"{colour_mode} information for `{name or input_colour}`.", - colour=Color.from_rgb(*rgb) + colour=discord.Color.from_rgb(*rgb) ) colour_conversions = self.get_colour_conversions(rgb) for colour_space, value in colour_conversions.items(): @@ -66,7 +65,7 @@ class Colour(commands.Cog): buffer = BytesIO() thumbnail.save(buffer, "PNG") buffer.seek(0) - thumbnail_file = File(buffer, filename="colour.png") + thumbnail_file = discord.File(buffer, filename="colour.png") colour_embed.set_thumbnail(url="attachment://colour.png") @@ -86,7 +85,7 @@ class Colour(commands.Cog): async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: """Command to create an embed from an RGB input.""" if any(c not in range(0, 256) for c in (red, green, blue)): - raise BadArgument( + raise commands.BadArgument( message=f"RGB values can only be from 0 to 255. User input was: `{red, green, blue}`." ) rgb_tuple = (red, green, blue) @@ -96,7 +95,7 @@ class Colour(commands.Cog): async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: """Command to create an embed from an HSV input.""" if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, value)): - raise BadArgument( + raise commands.BadArgument( message="Hue can only be from 0 to 360. Saturation and Value can only be from 0 to 100. " f"User input was: `{hue, saturation, value}`." ) @@ -107,7 +106,7 @@ class Colour(commands.Cog): async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: """Command to create an embed from an HSL input.""" if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, lightness)): - raise BadArgument( + raise commands.BadArgument( message="Hue can only be from 0 to 360. Saturation and Lightness can only be from 0 to 100. " f"User input was: `{hue, saturation, lightness}`." ) @@ -118,7 +117,7 @@ class Colour(commands.Cog): async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: """Command to create an embed from a CMYK input.""" if any(c not in range(0, 101) for c in (cyan, magenta, yellow, key)): - raise BadArgument( + raise commands.BadArgument( message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." ) r = round(255 * (1 - (cyan / 100)) * (1 - (key / 100))) @@ -202,7 +201,7 @@ class Colour(commands.Cog): """Convert RGB values to a fuzzy matched name.""" input_hex_colour = self._rgb_to_hex(rgb) try: - match, certainty, _ = process.extractOne( + match, certainty, _ = rapidfuzz.process.extractOne( query=input_hex_colour, choices=self.colour_mapping.values(), score_cutoff=80 @@ -215,14 +214,14 @@ class Colour(commands.Cog): def match_colour_name(self, input_colour_name: str) -> str: """Convert a colour name to HEX code.""" try: - match, certainty, _ = process.extractOne( + match, certainty, _ = rapidfuzz.process.extractOne( query=input_colour_name, choices=self.colour_mapping.keys(), score_cutoff=80 ) hex_match = f"#{self.colour_mapping[match]}" except (ValueError, TypeError): - raise BadArgument(message=f"No color found for: `{input_colour_name}`") + raise commands.BadArgument(message=f"No color found for: `{input_colour_name}`") return hex_match -- cgit v1.2.3 From edeb48ab0489c0ac0fcbf0a3a45dde11236f613c Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 3 Nov 2021 21:13:24 -0400 Subject: rename to colour --- bot/exts/utilities/color.py | 230 ------------------------------------------- bot/exts/utilities/colour.py | 230 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 230 deletions(-) delete mode 100644 bot/exts/utilities/color.py create mode 100644 bot/exts/utilities/colour.py diff --git a/bot/exts/utilities/color.py b/bot/exts/utilities/color.py deleted file mode 100644 index 5ff1e2b8..00000000 --- a/bot/exts/utilities/color.py +++ /dev/null @@ -1,230 +0,0 @@ -import colorsys -import json -import pathlib -import random -from io import BytesIO - -import discord -import rapidfuzz -from PIL import Image, ImageColor -from discord.ext import commands - -from bot.bot import Bot -from bot.exts.core.extensions import invoke_help_command - -THUMBNAIL_SIZE = (80, 80) - - -class Colour(commands.Cog): - """Cog for the Colour command.""" - - def __init__(self, bot: Bot): - self.bot = bot - with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: - self.colour_mapping = json.load(f) - del self.colour_mapping['_'] # Delete source credit entry - - async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: - """Create and send embed from user given colour information.""" - name = self._rgb_to_name(rgb) - if name is None: - name = "No match found" - - try: - colour_or_color = ctx.invoked_parents[0] - except IndexError: - colour_or_color = "colour" - - colour_mode = ctx.invoked_with - if colour_mode == "random": - input_colour = "random" - elif colour_mode in ("colour", "color"): - input_colour = rgb - else: - input_colour = ctx.args[2:][0] - - if colour_mode not in ("name", "hex", "random", "color", "colour"): - colour_mode = colour_mode.upper() - else: - colour_mode = colour_mode.title() - - colour_embed = discord.Embed( - title=colour_or_color.title(), - description=f"{colour_mode} information for `{name or input_colour}`.", - colour=discord.Color.from_rgb(*rgb) - ) - colour_conversions = self.get_colour_conversions(rgb) - for colour_space, value in colour_conversions.items(): - colour_embed.add_field( - name=colour_space, - value=f"`{value}`", - inline=True - ) - - thumbnail = Image.new("RGB", THUMBNAIL_SIZE, color=rgb) - buffer = BytesIO() - thumbnail.save(buffer, "PNG") - buffer.seek(0) - thumbnail_file = discord.File(buffer, filename="colour.png") - - colour_embed.set_thumbnail(url="attachment://colour.png") - - await ctx.send(file=thumbnail_file, embed=colour_embed) - - @commands.group(aliases=("color",), invoke_without_command=True) - async def colour(self, ctx: commands.Context, *, extra: str) -> None: - """User initiated command to create an embed that displays colour information.""" - if ctx.invoked_subcommand is None: - try: - extra_colour = ImageColor.getrgb(extra) - await self.send_colour_response(ctx, extra_colour) - except ValueError: - await invoke_help_command(ctx) - - @colour.command() - async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: - """Command to create an embed from an RGB input.""" - if any(c not in range(0, 256) for c in (red, green, blue)): - raise commands.BadArgument( - message=f"RGB values can only be from 0 to 255. User input was: `{red, green, blue}`." - ) - rgb_tuple = (red, green, blue) - await self.send_colour_response(ctx, rgb_tuple) - - @colour.command() - async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: - """Command to create an embed from an HSV input.""" - if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, value)): - raise commands.BadArgument( - message="Hue can only be from 0 to 360. Saturation and Value can only be from 0 to 100. " - f"User input was: `{hue, saturation, value}`." - ) - hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") - await self.send_colour_response(ctx, hsv_tuple) - - @colour.command() - async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: - """Command to create an embed from an HSL input.""" - if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, lightness)): - raise commands.BadArgument( - message="Hue can only be from 0 to 360. Saturation and Lightness can only be from 0 to 100. " - f"User input was: `{hue, saturation, lightness}`." - ) - hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") - await self.send_colour_response(ctx, hsl_tuple) - - @colour.command() - async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: - """Command to create an embed from a CMYK input.""" - if any(c not in range(0, 101) for c in (cyan, magenta, yellow, key)): - raise commands.BadArgument( - message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." - ) - r = round(255 * (1 - (cyan / 100)) * (1 - (key / 100))) - g = round(255 * (1 - (magenta / 100)) * (1 - (key / 100))) - b = round(255 * (1 - (yellow / 100)) * (1 - (key / 100))) - await self.send_colour_response(ctx, (r, g, b)) - - @colour.command() - async def hex(self, ctx: commands.Context, hex_code: str) -> None: - """Command to create an embed from a HEX input.""" - if "#" not in hex_code: - hex_code = f"#{hex_code}" - hex_tuple = ImageColor.getrgb(hex_code) - await self.send_colour_response(ctx, hex_tuple) - - @colour.command() - async def name(self, ctx: commands.Context, user_colour_name: str) -> None: - """Command to create an embed from a name input.""" - hex_colour = self.match_colour_name(user_colour_name) - hex_tuple = ImageColor.getrgb(hex_colour) - await self.send_colour_response(ctx, hex_tuple) - - @colour.command() - async def random(self, ctx: commands.Context) -> None: - """Command to create an embed from a randomly chosen colour from the reference file.""" - hex_colour = random.choice(list(self.colour_mapping.values())) - hex_tuple = ImageColor.getrgb(f"#{hex_colour}") - await self.send_colour_response(ctx, hex_tuple) - - def get_colour_conversions(self, rgb: tuple[int, int, int]) -> dict[str, str]: - """Create a dictionary mapping of colour types and their values.""" - colour_name = self._rgb_to_name(rgb) - if colour_name is None: - colour_name = "No match found" - return { - "RGB": rgb, - "HSV": self._rgb_to_hsv(rgb), - "HSL": self._rgb_to_hsl(rgb), - "CMYK": self._rgb_to_cmyk(rgb), - "Hex": self._rgb_to_hex(rgb), - "Name": colour_name - } - - @staticmethod - def _rgb_to_hsv(rgb: tuple[int, int, int]) -> tuple[int, int, int]: - """Convert RGB values to HSV values.""" - rgb_list = [val / 255 for val in rgb] - h, s, v = colorsys.rgb_to_hsv(*rgb_list) - hsv = (round(h * 360), round(s * 100), round(v * 100)) - return hsv - - @staticmethod - def _rgb_to_hsl(rgb: tuple[int, int, int]) -> tuple[int, int, int]: - """Convert RGB values to HSL values.""" - rgb_list = [val / 255.0 for val in rgb] - h, l, s = colorsys.rgb_to_hls(*rgb_list) - hsl = (round(h * 360), round(s * 100), round(l * 100)) - return hsl - - @staticmethod - def _rgb_to_cmyk(rgb: tuple[int, int, int, int]) -> tuple[int, int, int, int]: - """Convert RGB values to CMYK values.""" - rgb_list = [val / 255.0 for val in rgb] - if not any(rgb_list): - return 0, 0, 0, 100 - k = 1 - max(rgb_list) - c = round((1 - rgb_list[0] - k) * 100 / (1 - k)) - m = round((1 - rgb_list[1] - k) * 100 / (1 - k)) - y = round((1 - rgb_list[2] - k) * 100 / (1 - k)) - cmyk = (c, m, y, round(k * 100)) - return cmyk - - @staticmethod - def _rgb_to_hex(rgb: tuple[int, int, int]) -> str: - """Convert RGB values to HEX code.""" - hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) - hex_code = f"#{hex_}".upper() - return hex_code - - def _rgb_to_name(self, rgb: tuple[int, int, int]) -> str: - """Convert RGB values to a fuzzy matched name.""" - input_hex_colour = self._rgb_to_hex(rgb) - try: - match, certainty, _ = rapidfuzz.process.extractOne( - query=input_hex_colour, - choices=self.colour_mapping.values(), - score_cutoff=80 - ) - colour_name = [name for name, hex_code in self.colour_mapping.items() if hex_code == match][0] - except TypeError: - colour_name = None - return colour_name - - def match_colour_name(self, input_colour_name: str) -> str: - """Convert a colour name to HEX code.""" - try: - match, certainty, _ = rapidfuzz.process.extractOne( - query=input_colour_name, - choices=self.colour_mapping.keys(), - score_cutoff=80 - ) - hex_match = f"#{self.colour_mapping[match]}" - except (ValueError, TypeError): - raise commands.BadArgument(message=f"No color found for: `{input_colour_name}`") - return hex_match - - -def setup(bot: Bot) -> None: - """Load the Colour cog.""" - bot.add_cog(Colour(bot)) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py new file mode 100644 index 00000000..5ff1e2b8 --- /dev/null +++ b/bot/exts/utilities/colour.py @@ -0,0 +1,230 @@ +import colorsys +import json +import pathlib +import random +from io import BytesIO + +import discord +import rapidfuzz +from PIL import Image, ImageColor +from discord.ext import commands + +from bot.bot import Bot +from bot.exts.core.extensions import invoke_help_command + +THUMBNAIL_SIZE = (80, 80) + + +class Colour(commands.Cog): + """Cog for the Colour command.""" + + def __init__(self, bot: Bot): + self.bot = bot + with open(pathlib.Path("bot/resources/utilities/ryanzec_colours.json")) as f: + self.colour_mapping = json.load(f) + del self.colour_mapping['_'] # Delete source credit entry + + async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: + """Create and send embed from user given colour information.""" + name = self._rgb_to_name(rgb) + if name is None: + name = "No match found" + + try: + colour_or_color = ctx.invoked_parents[0] + except IndexError: + colour_or_color = "colour" + + colour_mode = ctx.invoked_with + if colour_mode == "random": + input_colour = "random" + elif colour_mode in ("colour", "color"): + input_colour = rgb + else: + input_colour = ctx.args[2:][0] + + if colour_mode not in ("name", "hex", "random", "color", "colour"): + colour_mode = colour_mode.upper() + else: + colour_mode = colour_mode.title() + + colour_embed = discord.Embed( + title=colour_or_color.title(), + description=f"{colour_mode} information for `{name or input_colour}`.", + colour=discord.Color.from_rgb(*rgb) + ) + colour_conversions = self.get_colour_conversions(rgb) + for colour_space, value in colour_conversions.items(): + colour_embed.add_field( + name=colour_space, + value=f"`{value}`", + inline=True + ) + + thumbnail = Image.new("RGB", THUMBNAIL_SIZE, color=rgb) + buffer = BytesIO() + thumbnail.save(buffer, "PNG") + buffer.seek(0) + thumbnail_file = discord.File(buffer, filename="colour.png") + + colour_embed.set_thumbnail(url="attachment://colour.png") + + await ctx.send(file=thumbnail_file, embed=colour_embed) + + @commands.group(aliases=("color",), invoke_without_command=True) + async def colour(self, ctx: commands.Context, *, extra: str) -> None: + """User initiated command to create an embed that displays colour information.""" + if ctx.invoked_subcommand is None: + try: + extra_colour = ImageColor.getrgb(extra) + await self.send_colour_response(ctx, extra_colour) + except ValueError: + await invoke_help_command(ctx) + + @colour.command() + async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: + """Command to create an embed from an RGB input.""" + if any(c not in range(0, 256) for c in (red, green, blue)): + raise commands.BadArgument( + message=f"RGB values can only be from 0 to 255. User input was: `{red, green, blue}`." + ) + rgb_tuple = (red, green, blue) + await self.send_colour_response(ctx, rgb_tuple) + + @colour.command() + async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: + """Command to create an embed from an HSV input.""" + if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, value)): + raise commands.BadArgument( + message="Hue can only be from 0 to 360. Saturation and Value can only be from 0 to 100. " + f"User input was: `{hue, saturation, value}`." + ) + hsv_tuple = ImageColor.getrgb(f"hsv({hue}, {saturation}%, {value}%)") + await self.send_colour_response(ctx, hsv_tuple) + + @colour.command() + async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: + """Command to create an embed from an HSL input.""" + if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, lightness)): + raise commands.BadArgument( + message="Hue can only be from 0 to 360. Saturation and Lightness can only be from 0 to 100. " + f"User input was: `{hue, saturation, lightness}`." + ) + hsl_tuple = ImageColor.getrgb(f"hsl({hue}, {saturation}%, {lightness}%)") + await self.send_colour_response(ctx, hsl_tuple) + + @colour.command() + async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: + """Command to create an embed from a CMYK input.""" + if any(c not in range(0, 101) for c in (cyan, magenta, yellow, key)): + raise commands.BadArgument( + message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." + ) + r = round(255 * (1 - (cyan / 100)) * (1 - (key / 100))) + g = round(255 * (1 - (magenta / 100)) * (1 - (key / 100))) + b = round(255 * (1 - (yellow / 100)) * (1 - (key / 100))) + await self.send_colour_response(ctx, (r, g, b)) + + @colour.command() + async def hex(self, ctx: commands.Context, hex_code: str) -> None: + """Command to create an embed from a HEX input.""" + if "#" not in hex_code: + hex_code = f"#{hex_code}" + hex_tuple = ImageColor.getrgb(hex_code) + await self.send_colour_response(ctx, hex_tuple) + + @colour.command() + async def name(self, ctx: commands.Context, user_colour_name: str) -> None: + """Command to create an embed from a name input.""" + hex_colour = self.match_colour_name(user_colour_name) + hex_tuple = ImageColor.getrgb(hex_colour) + await self.send_colour_response(ctx, hex_tuple) + + @colour.command() + async def random(self, ctx: commands.Context) -> None: + """Command to create an embed from a randomly chosen colour from the reference file.""" + hex_colour = random.choice(list(self.colour_mapping.values())) + hex_tuple = ImageColor.getrgb(f"#{hex_colour}") + await self.send_colour_response(ctx, hex_tuple) + + def get_colour_conversions(self, rgb: tuple[int, int, int]) -> dict[str, str]: + """Create a dictionary mapping of colour types and their values.""" + colour_name = self._rgb_to_name(rgb) + if colour_name is None: + colour_name = "No match found" + return { + "RGB": rgb, + "HSV": self._rgb_to_hsv(rgb), + "HSL": self._rgb_to_hsl(rgb), + "CMYK": self._rgb_to_cmyk(rgb), + "Hex": self._rgb_to_hex(rgb), + "Name": colour_name + } + + @staticmethod + def _rgb_to_hsv(rgb: tuple[int, int, int]) -> tuple[int, int, int]: + """Convert RGB values to HSV values.""" + rgb_list = [val / 255 for val in rgb] + h, s, v = colorsys.rgb_to_hsv(*rgb_list) + hsv = (round(h * 360), round(s * 100), round(v * 100)) + return hsv + + @staticmethod + def _rgb_to_hsl(rgb: tuple[int, int, int]) -> tuple[int, int, int]: + """Convert RGB values to HSL values.""" + rgb_list = [val / 255.0 for val in rgb] + h, l, s = colorsys.rgb_to_hls(*rgb_list) + hsl = (round(h * 360), round(s * 100), round(l * 100)) + return hsl + + @staticmethod + def _rgb_to_cmyk(rgb: tuple[int, int, int, int]) -> tuple[int, int, int, int]: + """Convert RGB values to CMYK values.""" + rgb_list = [val / 255.0 for val in rgb] + if not any(rgb_list): + return 0, 0, 0, 100 + k = 1 - max(rgb_list) + c = round((1 - rgb_list[0] - k) * 100 / (1 - k)) + m = round((1 - rgb_list[1] - k) * 100 / (1 - k)) + y = round((1 - rgb_list[2] - k) * 100 / (1 - k)) + cmyk = (c, m, y, round(k * 100)) + return cmyk + + @staticmethod + def _rgb_to_hex(rgb: tuple[int, int, int]) -> str: + """Convert RGB values to HEX code.""" + hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) + hex_code = f"#{hex_}".upper() + return hex_code + + def _rgb_to_name(self, rgb: tuple[int, int, int]) -> str: + """Convert RGB values to a fuzzy matched name.""" + input_hex_colour = self._rgb_to_hex(rgb) + try: + match, certainty, _ = rapidfuzz.process.extractOne( + query=input_hex_colour, + choices=self.colour_mapping.values(), + score_cutoff=80 + ) + colour_name = [name for name, hex_code in self.colour_mapping.items() if hex_code == match][0] + except TypeError: + colour_name = None + return colour_name + + def match_colour_name(self, input_colour_name: str) -> str: + """Convert a colour name to HEX code.""" + try: + match, certainty, _ = rapidfuzz.process.extractOne( + query=input_colour_name, + choices=self.colour_mapping.keys(), + score_cutoff=80 + ) + hex_match = f"#{self.colour_mapping[match]}" + except (ValueError, TypeError): + raise commands.BadArgument(message=f"No color found for: `{input_colour_name}`") + return hex_match + + +def setup(bot: Bot) -> None: + """Load the Colour cog.""" + bot.add_cog(Colour(bot)) -- 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 a32fae52425fe6955be2be013f6149c90cc86e61 Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Sat, 6 Nov 2021 11:22:13 -0400 Subject: lowering challenges for compatibility with uppercase languages --- bot/exts/utilities/challenges.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py index e4738455..1f296390 100644 --- a/bot/exts/utilities/challenges.py +++ b/bot/exts/utilities/challenges.py @@ -278,7 +278,7 @@ class Challenges(commands.Cog): 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}" + get_kata_link = f"https://codewars.com/kata/search/{language.lower()}" params = {} if query is not None: -- cgit v1.2.3 From 7227fe279574ee0626ad6c7ead754c1212669af2 Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Sat, 6 Nov 2021 23:02:26 -0400 Subject: Change language to language.lower() --- bot/exts/utilities/challenges.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py index 1f296390..751ea2a3 100644 --- a/bot/exts/utilities/challenges.py +++ b/bot/exts/utilities/challenges.py @@ -275,10 +275,12 @@ class Challenges(commands.Cog): `.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"]: + + language = language.lower() + if language 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.lower()}" + get_kata_link = f"https://codewars.com/kata/search/{language}" params = {} if query is not None: -- 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 From 1503845b4c5349e1a49c9c9ecdc37425b659e73b Mon Sep 17 00:00:00 2001 From: Shom770 <82843611+Shom770@users.noreply.github.com> Date: Sun, 7 Nov 2021 11:19:05 -0500 Subject: Fix line after function docstring --- bot/exts/utilities/challenges.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py index 751ea2a3..ab7ae442 100644 --- a/bot/exts/utilities/challenges.py +++ b/bot/exts/utilities/challenges.py @@ -275,7 +275,6 @@ class Challenges(commands.Cog): `.challenge , ` - Pulls a random challenge with the query provided, under that difficulty within the language's scope. """ - language = language.lower() if language not in SUPPORTED_LANGUAGES["stable"] + SUPPORTED_LANGUAGES["beta"]: raise commands.BadArgument("This is not a recognized language on codewars.com!") -- cgit v1.2.3 From 4fed12e92a6bb7280e6b69af07267dd82b0d6d0d Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 9 Nov 2021 08:03:20 -0500 Subject: fix: type hinting _rgb_to_cmyk --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 5ff1e2b8..c2a5e7e7 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -178,7 +178,7 @@ class Colour(commands.Cog): return hsl @staticmethod - def _rgb_to_cmyk(rgb: tuple[int, int, int, int]) -> tuple[int, int, int, int]: + def _rgb_to_cmyk(rgb: tuple[int, int, int]) -> tuple[int, int, int, int]: """Convert RGB values to CMYK values.""" rgb_list = [val / 255.0 for val in rgb] if not any(rgb_list): -- cgit v1.2.3 From 9990492921dd3cd1321eee90a9016b239b38741c Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 9 Nov 2021 22:55:54 +0100 Subject: use pseudo-tty for sir-lancebot service This allows the coloredlogs module to automatically detect colour support when running in docker --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index cef49213..34408e82 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ services: dockerfile: Dockerfile container_name: sir-lancebot init: true + tty: true depends_on: - redis -- cgit v1.2.3 From 2df4ae0458e7d2765e76cff832a4b21a292ae176 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 9 Nov 2021 23:18:01 +0100 Subject: remove unnecessary volumes --- Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0b5876bd..44ef0574 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,3 @@ COPY . . # Start the bot CMD ["python", "-m", "bot"] - -# Define docker persistent volumes -VOLUME /bot/bot/log /bot/data -- cgit v1.2.3 From 2bb00fbf680d49c92bb40af71659489801cc0f99 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Tue, 9 Nov 2021 19:44:18 -0500 Subject: fix: handle alpha values in hex code Co-authored-by: Sn4u <35849006+Sn4u@users.noreply.github.com> --- bot/exts/utilities/colour.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index c2a5e7e7..7b128393 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -130,7 +130,13 @@ class Colour(commands.Cog): """Command to create an embed from a HEX input.""" if "#" not in hex_code: hex_code = f"#{hex_code}" + if len(hex_code) not in (4, 5, 7, 9) or any(_ not in string.hexdigits+"#" for _ in hex_code): + raise commands.BadArgument( + message=f"HEX values must be hexadecimal and take the form *#RRGGBB* or *#RGB*. User input was: `{hex_code}`.") + hex_tuple = ImageColor.getrgb(hex_code) + if len(hex_tuple) == 4: + hex_tuple = hex_tuple[:-1] # color must be RGB. If RGBA, we remove the alpha value await self.send_colour_response(ctx, hex_tuple) @colour.command() -- cgit v1.2.3 From 385cb3aacf60bdaea67fe59890e9c5d894f9d65a Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 9 Nov 2021 19:48:09 -0500 Subject: fix: add import, handle no name match in embed -Added `import string` to use the `string.hexdigits` method to check hex codes. -Handled bug where no name match found would be repeated in the embed in the first line as well as the value for the Name field. --- bot/exts/utilities/colour.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 7b128393..4528615b 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -2,6 +2,7 @@ import colorsys import json import pathlib import random +import string from io import BytesIO import discord @@ -27,8 +28,6 @@ class Colour(commands.Cog): async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: """Create and send embed from user given colour information.""" name = self._rgb_to_name(rgb) - if name is None: - name = "No match found" try: colour_or_color = ctx.invoked_parents[0] @@ -132,7 +131,9 @@ class Colour(commands.Cog): hex_code = f"#{hex_code}" if len(hex_code) not in (4, 5, 7, 9) or any(_ not in string.hexdigits+"#" for _ in hex_code): raise commands.BadArgument( - message=f"HEX values must be hexadecimal and take the form *#RRGGBB* or *#RGB*. User input was: `{hex_code}`.") + message="HEX values must be hexadecimal and take the form *#RRGGBB* or *#RGB*. " + f"User input was: `{hex_code}`." + ) hex_tuple = ImageColor.getrgb(hex_code) if len(hex_tuple) == 4: -- cgit v1.2.3 From 57c13ff35801281b5e592c9f6c195093a2fc5c7b Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 9 Nov 2021 20:20:19 -0500 Subject: bug: handle multi word name entries and full input --- bot/exts/utilities/colour.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 4528615b..cede3312 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -39,8 +39,10 @@ class Colour(commands.Cog): input_colour = "random" elif colour_mode in ("colour", "color"): input_colour = rgb + elif colour_mode == "name": + input_colour = ctx.kwargs["user_colour_name"] else: - input_colour = ctx.args[2:][0] + input_colour = tuple(ctx.args[2:]) if colour_mode not in ("name", "hex", "random", "color", "colour"): colour_mode = colour_mode.upper() @@ -141,7 +143,7 @@ class Colour(commands.Cog): await self.send_colour_response(ctx, hex_tuple) @colour.command() - async def name(self, ctx: commands.Context, user_colour_name: str) -> None: + async def name(self, ctx: commands.Context, *, user_colour_name: str) -> None: """Command to create an embed from a name input.""" hex_colour = self.match_colour_name(user_colour_name) hex_tuple = ImageColor.getrgb(hex_colour) -- cgit v1.2.3 From 1de5e9b905310eb4745b9b5c83561dea3a289ea9 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 9 Nov 2021 20:39:39 -0500 Subject: chore: pull hex match out of try/except block --- bot/exts/utilities/colour.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index cede3312..656dddba 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -228,10 +228,9 @@ class Colour(commands.Cog): choices=self.colour_mapping.keys(), score_cutoff=80 ) - hex_match = f"#{self.colour_mapping[match]}" except (ValueError, TypeError): raise commands.BadArgument(message=f"No color found for: `{input_colour_name}`") - return hex_match + return f"#{self.colour_mapping[match]}" def setup(bot: Bot) -> None: -- cgit v1.2.3 From 93e6e96c89e621db6e463f4d5716533fd85cd96f Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 9 Nov 2021 20:44:28 -0500 Subject: chore: re-arrange command invocation with try/except --- bot/exts/utilities/colour.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 656dddba..e69930f4 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -75,12 +75,14 @@ class Colour(commands.Cog): @commands.group(aliases=("color",), invoke_without_command=True) async def colour(self, ctx: commands.Context, *, extra: str) -> None: """User initiated command to create an embed that displays colour information.""" - if ctx.invoked_subcommand is None: - try: - extra_colour = ImageColor.getrgb(extra) - await self.send_colour_response(ctx, extra_colour) - except ValueError: - await invoke_help_command(ctx) + if ctx.invoked_subcommand: + return + + try: + extra_colour = ImageColor.getrgb(extra) + await self.send_colour_response(ctx, extra_colour) + except ValueError: + await invoke_help_command(ctx) @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: -- cgit v1.2.3 From c70a4e7670805ca774d1c0d634e86dc6759d8669 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 9 Nov 2021 21:22:49 -0500 Subject: chore: remove 0 from range and change to " --- bot/exts/utilities/colour.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index e69930f4..9cbf3394 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -87,7 +87,7 @@ class Colour(commands.Cog): @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: """Command to create an embed from an RGB input.""" - if any(c not in range(0, 256) for c in (red, green, blue)): + if any(c not in range(256) for c in (red, green, blue)): raise commands.BadArgument( message=f"RGB values can only be from 0 to 255. User input was: `{red, green, blue}`." ) @@ -97,7 +97,7 @@ class Colour(commands.Cog): @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: """Command to create an embed from an HSV input.""" - if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, value)): + if (hue not in range(361)) or any(c not in range(101) for c in (saturation, value)): raise commands.BadArgument( message="Hue can only be from 0 to 360. Saturation and Value can only be from 0 to 100. " f"User input was: `{hue, saturation, value}`." @@ -108,7 +108,7 @@ class Colour(commands.Cog): @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: """Command to create an embed from an HSL input.""" - if (hue not in range(0, 361)) or any(c not in range(0, 101) for c in (saturation, lightness)): + if (hue not in range(361)) or any(c not in range(101) for c in (saturation, lightness)): raise commands.BadArgument( message="Hue can only be from 0 to 360. Saturation and Lightness can only be from 0 to 100. " f"User input was: `{hue, saturation, lightness}`." @@ -119,7 +119,7 @@ class Colour(commands.Cog): @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: """Command to create an embed from a CMYK input.""" - if any(c not in range(0, 101) for c in (cyan, magenta, yellow, key)): + if any(c not in range(101) for c in (cyan, magenta, yellow, key)): raise commands.BadArgument( message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." ) @@ -204,7 +204,7 @@ class Colour(commands.Cog): @staticmethod def _rgb_to_hex(rgb: tuple[int, int, int]) -> str: """Convert RGB values to HEX code.""" - hex_ = ''.join([hex(val)[2:].zfill(2) for val in rgb]) + hex_ = "".join([hex(val)[2:].zfill(2) for val in rgb]) hex_code = f"#{hex_}".upper() return hex_code -- cgit v1.2.3 From 524d33a9909697386283d966dcda1dc712a16fb0 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Tue, 9 Nov 2021 21:55:49 -0500 Subject: fix: replace 'random' in embed with color mode --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 9cbf3394..7e5065cd 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -36,7 +36,7 @@ class Colour(commands.Cog): colour_mode = ctx.invoked_with if colour_mode == "random": - input_colour = "random" + colour_mode = colour_or_color elif colour_mode in ("colour", "color"): input_colour = rgb elif colour_mode == "name": -- cgit v1.2.3 From 6f9da835444e0d357edc06839d9b98eafe72af30 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 10 Nov 2021 06:46:55 -0500 Subject: fix: handle user hex in embed --- bot/exts/utilities/colour.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 7e5065cd..ec7545cd 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -41,6 +41,8 @@ class Colour(commands.Cog): input_colour = rgb elif colour_mode == "name": input_colour = ctx.kwargs["user_colour_name"] + elif colour_mode == "hex": + input_colour = ctx.args[2:][0] else: input_colour = tuple(ctx.args[2:]) -- cgit v1.2.3 From b9b1d8c10e999e16cbd067dc49710634e23e6bd7 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 10 Nov 2021 06:48:05 -0500 Subject: fix: change kwarg to color_input instead of extra --- bot/exts/utilities/colour.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index ec7545cd..1e64993c 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -75,13 +75,13 @@ class Colour(commands.Cog): await ctx.send(file=thumbnail_file, embed=colour_embed) @commands.group(aliases=("color",), invoke_without_command=True) - async def colour(self, ctx: commands.Context, *, extra: str) -> None: + async def colour(self, ctx: commands.Context, *, color_input: str) -> None: """User initiated command to create an embed that displays colour information.""" if ctx.invoked_subcommand: return try: - extra_colour = ImageColor.getrgb(extra) + extra_colour = ImageColor.getrgb(color_input) await self.send_colour_response(ctx, extra_colour) except ValueError: await invoke_help_command(ctx) -- cgit v1.2.3 From 6b21ffaef0e545d1710f2703c450c5492e100be7 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 10 Nov 2021 08:37:18 -0500 Subject: test: UI/UX updates, not tested yet --- bot/exts/utilities/colour.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 1e64993c..259e3394 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -4,6 +4,7 @@ import pathlib import random import string from io import BytesIO +from typing import Optional, Union import discord import rapidfuzz @@ -75,8 +76,11 @@ class Colour(commands.Cog): await ctx.send(file=thumbnail_file, embed=colour_embed) @commands.group(aliases=("color",), invoke_without_command=True) - async def colour(self, ctx: commands.Context, *, color_input: str) -> None: + async def colour(self, ctx: commands.Context, *, color_input: Optional[str] = None) -> None: """User initiated command to create an embed that displays colour information.""" + if color_input is None: + await self.random() + if ctx.invoked_subcommand: return @@ -133,13 +137,17 @@ class Colour(commands.Cog): @colour.command() async def hex(self, ctx: commands.Context, hex_code: str) -> None: """Command to create an embed from a HEX input.""" - if "#" not in hex_code: + if hex_code[0] != "#": hex_code = f"#{hex_code}" - if len(hex_code) not in (4, 5, 7, 9) or any(_ not in string.hexdigits+"#" for _ in hex_code): - raise commands.BadArgument( - message="HEX values must be hexadecimal and take the form *#RRGGBB* or *#RGB*. " - f"User input was: `{hex_code}`." + + if len(hex_code) not in (4, 5, 7, 9) or any(_ not in string.hexdigits for _ in hex_code[1:]): + hex_error_embed = discord.Embed( + title="The input hex code is not valid.", + message=f"Cannot convert `{hex_code}` to a recognizable Hex format. " + "Hex values must be hexadecimal and take the form *#RRGGBB* or *#RGB*.", + colour=discord.Colour.dark_red() ) + await ctx.send(hex_error_embed) hex_tuple = ImageColor.getrgb(hex_code) if len(hex_tuple) == 4: @@ -149,7 +157,7 @@ class Colour(commands.Cog): @colour.command() async def name(self, ctx: commands.Context, *, user_colour_name: str) -> None: """Command to create an embed from a name input.""" - hex_colour = self.match_colour_name(user_colour_name) + hex_colour = await self.match_colour_name(ctx, user_colour_name) hex_tuple = ImageColor.getrgb(hex_colour) await self.send_colour_response(ctx, hex_tuple) @@ -224,7 +232,7 @@ class Colour(commands.Cog): colour_name = None return colour_name - def match_colour_name(self, input_colour_name: str) -> str: + async def match_colour_name(self, ctx: commands.Context, input_colour_name: str) -> Union[str, None]: """Convert a colour name to HEX code.""" try: match, certainty, _ = rapidfuzz.process.extractOne( @@ -233,7 +241,12 @@ class Colour(commands.Cog): score_cutoff=80 ) except (ValueError, TypeError): - raise commands.BadArgument(message=f"No color found for: `{input_colour_name}`") + name_error_embed = discord.Embed( + title="No colour match found.", + description=f"No color found for: `{input_colour_name}`", + colour=discord.Color.dark_red() + ) + await ctx.send(name_error_embed) return f"#{self.colour_mapping[match]}" -- cgit v1.2.3 From f2735273ceb7a2eabf3beee93e1ed21635b4bfd0 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 10 Nov 2021 08:40:46 -0500 Subject: test: return after default random invocation --- bot/exts/utilities/colour.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 259e3394..e0607bf5 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -80,6 +80,7 @@ class Colour(commands.Cog): """User initiated command to create an embed that displays colour information.""" if color_input is None: await self.random() + return if ctx.invoked_subcommand: return -- cgit v1.2.3 From 87711b7b90110fc9d62d1ef880f69c1fbe6366b6 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:59:33 -0500 Subject: test: correct embed descriptions --- bot/exts/utilities/colour.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index e0607bf5..08a6973b 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -144,11 +144,11 @@ class Colour(commands.Cog): if len(hex_code) not in (4, 5, 7, 9) or any(_ not in string.hexdigits for _ in hex_code[1:]): hex_error_embed = discord.Embed( title="The input hex code is not valid.", - message=f"Cannot convert `{hex_code}` to a recognizable Hex format. " + description=f"Cannot convert `{hex_code}` to a recognizable Hex format. " "Hex values must be hexadecimal and take the form *#RRGGBB* or *#RGB*.", colour=discord.Colour.dark_red() ) - await ctx.send(hex_error_embed) + await ctx.send(embed=hex_error_embed) hex_tuple = ImageColor.getrgb(hex_code) if len(hex_tuple) == 4: @@ -247,7 +247,7 @@ class Colour(commands.Cog): description=f"No color found for: `{input_colour_name}`", colour=discord.Color.dark_red() ) - await ctx.send(name_error_embed) + await ctx.send(embed=name_error_embed) return f"#{self.colour_mapping[match]}" -- cgit v1.2.3 From aaad72a40b21b9d3b1d43d67a3206923722d8575 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 10 Nov 2021 19:08:58 -0500 Subject: cleanup: finalize reviews requested changes -Change _ to `digit` -Remove redundant "Command" from docstrings. Changed to "Create embed from ..." -Change hex command custom embed to `BadArgument` for consistency --- bot/exts/utilities/colour.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 08a6973b..9f7bedb5 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -79,7 +79,7 @@ class Colour(commands.Cog): async def colour(self, ctx: commands.Context, *, color_input: Optional[str] = None) -> None: """User initiated command to create an embed that displays colour information.""" if color_input is None: - await self.random() + await self.random(ctx) return if ctx.invoked_subcommand: @@ -93,7 +93,7 @@ class Colour(commands.Cog): @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: - """Command to create an embed from an RGB input.""" + """Create an embed from an RGB input.""" if any(c not in range(256) for c in (red, green, blue)): raise commands.BadArgument( message=f"RGB values can only be from 0 to 255. User input was: `{red, green, blue}`." @@ -103,7 +103,7 @@ class Colour(commands.Cog): @colour.command() async def hsv(self, ctx: commands.Context, hue: int, saturation: int, value: int) -> None: - """Command to create an embed from an HSV input.""" + """Create an embed from an HSV input.""" if (hue not in range(361)) or any(c not in range(101) for c in (saturation, value)): raise commands.BadArgument( message="Hue can only be from 0 to 360. Saturation and Value can only be from 0 to 100. " @@ -114,7 +114,7 @@ class Colour(commands.Cog): @colour.command() async def hsl(self, ctx: commands.Context, hue: int, saturation: int, lightness: int) -> None: - """Command to create an embed from an HSL input.""" + """Create an embed from an HSL input.""" if (hue not in range(361)) or any(c not in range(101) for c in (saturation, lightness)): raise commands.BadArgument( message="Hue can only be from 0 to 360. Saturation and Lightness can only be from 0 to 100. " @@ -125,7 +125,7 @@ class Colour(commands.Cog): @colour.command() async def cmyk(self, ctx: commands.Context, cyan: int, magenta: int, yellow: int, key: int) -> None: - """Command to create an embed from a CMYK input.""" + """Create an embed from a CMYK input.""" if any(c not in range(101) for c in (cyan, magenta, yellow, key)): raise commands.BadArgument( message=f"CMYK values can only be from 0 to 100. User input was: `{cyan, magenta, yellow, key}`." @@ -137,18 +137,15 @@ class Colour(commands.Cog): @colour.command() async def hex(self, ctx: commands.Context, hex_code: str) -> None: - """Command to create an embed from a HEX input.""" + """Create an embed from a HEX input.""" if hex_code[0] != "#": hex_code = f"#{hex_code}" - if len(hex_code) not in (4, 5, 7, 9) or any(_ not in string.hexdigits for _ in hex_code[1:]): - hex_error_embed = discord.Embed( - title="The input hex code is not valid.", - description=f"Cannot convert `{hex_code}` to a recognizable Hex format. " - "Hex values must be hexadecimal and take the form *#RRGGBB* or *#RGB*.", - colour=discord.Colour.dark_red() + if len(hex_code) not in (4, 5, 7, 9) or any(digit not in string.hexdigits for digit in hex_code[1:]): + raise commands.BadArgument( + message=f"Cannot convert `{hex_code}` to a recognizable Hex format. " + "Hex values must be hexadecimal and take the form *#RRGGBB* or *#RGB*." ) - await ctx.send(embed=hex_error_embed) hex_tuple = ImageColor.getrgb(hex_code) if len(hex_tuple) == 4: @@ -157,14 +154,14 @@ class Colour(commands.Cog): @colour.command() async def name(self, ctx: commands.Context, *, user_colour_name: str) -> None: - """Command to create an embed from a name input.""" + """Create an embed from a name input.""" hex_colour = await self.match_colour_name(ctx, user_colour_name) hex_tuple = ImageColor.getrgb(hex_colour) await self.send_colour_response(ctx, hex_tuple) @colour.command() async def random(self, ctx: commands.Context) -> None: - """Command to create an embed from a randomly chosen colour from the reference file.""" + """Create an embed from a randomly chosen colour from the reference file.""" hex_colour = random.choice(list(self.colour_mapping.values())) hex_tuple = ImageColor.getrgb(f"#{hex_colour}") await self.send_colour_response(ctx, hex_tuple) -- cgit v1.2.3 From 231ad0e58ee7b2eb58f48833abe469bf61582bdc Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Wed, 10 Nov 2021 19:20:56 -0500 Subject: cleanup: change main command docstring to be more clear --- bot/exts/utilities/colour.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 9f7bedb5..b233fc1e 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -77,7 +77,11 @@ class Colour(commands.Cog): @commands.group(aliases=("color",), invoke_without_command=True) async def colour(self, ctx: commands.Context, *, color_input: Optional[str] = None) -> None: - """User initiated command to create an embed that displays colour information.""" + """ + Create an embed that displays colour information. + + If no subcommand is called, a randomly selected colour will be selected and shown. + """ if color_input is None: await self.random(ctx) return -- cgit v1.2.3 From 3332bcf61e4586432225e2626a90a3430055a8a8 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 11 Nov 2021 16:45:27 -0500 Subject: fix: change color to colour in no match found result Co-authored-by: Hedy Li --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index b233fc1e..ee53c535 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -245,7 +245,7 @@ class Colour(commands.Cog): except (ValueError, TypeError): name_error_embed = discord.Embed( title="No colour match found.", - description=f"No color found for: `{input_colour_name}`", + description=f"No colour found for: `{input_colour_name}`", colour=discord.Color.dark_red() ) await ctx.send(embed=name_error_embed) -- cgit v1.2.3 From ed1fb463c4e04fa4628e46df33144a4b5c579b82 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 11 Nov 2021 16:54:10 -0500 Subject: fix: remove async call for match_colour_name --- bot/exts/utilities/colour.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index b233fc1e..ed69beaf 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -159,7 +159,15 @@ class Colour(commands.Cog): @colour.command() async def name(self, ctx: commands.Context, *, user_colour_name: str) -> None: """Create an embed from a name input.""" - hex_colour = await self.match_colour_name(ctx, user_colour_name) + hex_colour = self.match_colour_name(ctx, user_colour_name) + if hex_colour is None: + name_error_embed = discord.Embed( + title="No colour match found.", + description=f"No color found for: `{user_colour_name}`", + colour=discord.Color.dark_red() + ) + await ctx.send(embed=name_error_embed) + return hex_tuple = ImageColor.getrgb(hex_colour) await self.send_colour_response(ctx, hex_tuple) @@ -234,7 +242,7 @@ class Colour(commands.Cog): colour_name = None return colour_name - async def match_colour_name(self, ctx: commands.Context, input_colour_name: str) -> Union[str, None]: + def match_colour_name(self, ctx: commands.Context, input_colour_name: str) -> Union[str, None]: """Convert a colour name to HEX code.""" try: match, certainty, _ = rapidfuzz.process.extractOne( @@ -243,12 +251,7 @@ class Colour(commands.Cog): score_cutoff=80 ) except (ValueError, TypeError): - name_error_embed = discord.Embed( - title="No colour match found.", - description=f"No color found for: `{input_colour_name}`", - colour=discord.Color.dark_red() - ) - await ctx.send(embed=name_error_embed) + return None return f"#{self.colour_mapping[match]}" -- cgit v1.2.3 From a8aebd4fe051052f52b68c822d0762c56eba9591 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 11 Nov 2021 16:58:09 -0500 Subject: fix: change color to Colour in comment --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index ed69beaf..a35b393d 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -153,7 +153,7 @@ class Colour(commands.Cog): hex_tuple = ImageColor.getrgb(hex_code) if len(hex_tuple) == 4: - hex_tuple = hex_tuple[:-1] # color must be RGB. If RGBA, we remove the alpha value + hex_tuple = hex_tuple[:-1] # Colour must be RGB. If RGBA, we remove the alpha value await self.send_colour_response(ctx, hex_tuple) @colour.command() -- cgit v1.2.3 From 36a316f8ca27b35325ab31d575cc944a72f22c01 Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Thu, 11 Nov 2021 17:00:05 -0500 Subject: update: remove redundancy in docstring Co-authored-by: Hedy Li --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index ed69beaf..3b5c8681 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -80,7 +80,7 @@ class Colour(commands.Cog): """ Create an embed that displays colour information. - If no subcommand is called, a randomly selected colour will be selected and shown. + If no subcommand is called, a randomly selected colour will be shown. """ if color_input is None: await self.random(ctx) -- cgit v1.2.3 From 1914905bdc7bd591ff906562ee0496346d37a045 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 11 Nov 2021 17:02:45 -0500 Subject: fix: remove alpha values in embed for hex --- bot/exts/utilities/colour.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index c865859a..d438fa27 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -43,7 +43,7 @@ class Colour(commands.Cog): elif colour_mode == "name": input_colour = ctx.kwargs["user_colour_name"] elif colour_mode == "hex": - input_colour = ctx.args[2:][0] + input_colour = ctx.args[2:][0][0:-2] else: input_colour = tuple(ctx.args[2:]) @@ -80,7 +80,7 @@ class Colour(commands.Cog): """ Create an embed that displays colour information. - If no subcommand is called, a randomly selected colour will be shown. + If no subcommand is called, a randomly selected colour will be selected and shown. """ if color_input is None: await self.random(ctx) -- cgit v1.2.3 From 6b3ac76a7e5e63503bbba139538e52d23480b3fc Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Thu, 11 Nov 2021 17:07:15 -0500 Subject: update: remove redundancy in dosctring --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index d438fa27..6772fa1f 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -80,7 +80,7 @@ class Colour(commands.Cog): """ Create an embed that displays colour information. - If no subcommand is called, a randomly selected colour will be selected and shown. + If no subcommand is called, a randomly selected colour will be shown. """ if color_input is None: await self.random(ctx) -- cgit v1.2.3 From 6a9f1886c70658636f36272ea8b8f4c3f5f4a7a9 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Fri, 12 Nov 2021 06:09:32 +0400 Subject: Disable File Logs In Production The most recent changes to our log setup had the loggers writing to a read-only location in prod. This would cause an error during startup. To get around this while keeping the change, I moved it to only be used if debug is True. Signed-off-by: Hassan Abouelela --- bot/log.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/bot/log.py b/bot/log.py index 5e0e909d..97561be4 100644 --- a/bot/log.py +++ b/bot/log.py @@ -18,19 +18,22 @@ def setup() -> None: format_string = "%(asctime)s | %(name)s | %(levelname)s | %(message)s" log_format = logging.Formatter(format_string) + root_logger = logging.getLogger() - # Set up file logging - log_file = Path("logs/sir-lancebot.log") - log_file.parent.mkdir(exist_ok=True) + # Copied from constants file, which we can't import yet since loggers aren't instantiated + debug = os.environ.get("BOT_DEBUG", "true").lower() == "true" - # File handler rotates logs every 5 MB - file_handler = logging.handlers.RotatingFileHandler( - log_file, maxBytes=5 * (2 ** 20), backupCount=10, encoding="utf-8", - ) - file_handler.setFormatter(log_format) + if debug: + # Set up file logging + log_file = Path("logs/sir-lancebot.log") + log_file.parent.mkdir(exist_ok=True) - root_logger = logging.getLogger() - root_logger.addHandler(file_handler) + # File handler rotates logs every 5 MB + file_handler = logging.handlers.RotatingFileHandler( + log_file, maxBytes=5 * (2 ** 20), backupCount=10, encoding="utf-8", + ) + file_handler.setFormatter(log_format) + root_logger.addHandler(file_handler) if "COLOREDLOGS_LEVEL_STYLES" not in os.environ: coloredlogs.DEFAULT_LEVEL_STYLES = { -- cgit v1.2.3 From 40b58132d488bab962d8aeecfc932a1cb5842a85 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Fri, 12 Nov 2021 06:19:59 +0400 Subject: Move Sentry Into Init Moves the sentry setup to be one of the very first things run during startup, so we are able to catch more errors, such as ones that might occur while setting up logs. Signed-off-by: Hassan Abouelela --- bot/__init__.py | 18 ++++++++++++++++++ bot/__main__.py | 20 +------------------- bot/constants.py | 3 --- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/bot/__init__.py b/bot/__init__.py index b19bd76a..ae53a5a5 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -6,14 +6,32 @@ except ModuleNotFoundError: pass import asyncio +import logging import os from functools import partial, partialmethod import arrow +import sentry_sdk from discord.ext import commands +from sentry_sdk.integrations.logging import LoggingIntegration +from sentry_sdk.integrations.redis import RedisIntegration from bot import log, monkey_patches +sentry_logging = LoggingIntegration( + level=logging.DEBUG, + event_level=logging.WARNING +) + +sentry_sdk.init( + dsn=os.environ.get("BOT_SENTRY_DSN"), + integrations=[ + sentry_logging, + RedisIntegration() + ], + release=f"sir-lancebot@{os.environ.get('GIT_SHA', 'foobar')}" +) + log.setup() # Set timestamp of when execution started (approximately) diff --git a/bot/__main__.py b/bot/__main__.py index c6e5fa57..6889fe2b 100644 --- a/bot/__main__.py +++ b/bot/__main__.py @@ -1,28 +1,10 @@ import logging -import sentry_sdk -from sentry_sdk.integrations.logging import LoggingIntegration -from sentry_sdk.integrations.redis import RedisIntegration - from bot.bot import bot -from bot.constants import Client, GIT_SHA, STAFF_ROLES, WHITELISTED_CHANNELS +from bot.constants import Client, STAFF_ROLES, WHITELISTED_CHANNELS from bot.utils.decorators import whitelist_check from bot.utils.extensions import walk_extensions -sentry_logging = LoggingIntegration( - level=logging.DEBUG, - event_level=logging.WARNING -) - -sentry_sdk.init( - dsn=Client.sentry_dsn, - integrations=[ - sentry_logging, - RedisIntegration() - ], - release=f"sir-lancebot@{GIT_SHA}" -) - log = logging.getLogger(__name__) bot.add_check(whitelist_check(channels=WHITELISTED_CHANNELS, roles=STAFF_ROLES)) diff --git a/bot/constants.py b/bot/constants.py index 9d12000e..2b41b8a4 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -134,7 +134,6 @@ class Client(NamedTuple): guild = int(environ.get("BOT_GUILD", 267624335836053506)) prefix = environ.get("PREFIX", ".") token = environ.get("BOT_TOKEN") - sentry_dsn = environ.get("BOT_SENTRY_DSN") debug = environ.get("BOT_DEBUG", "true").lower() == "true" github_bot_repo = "https://github.com/python-discord/sir-lancebot" # Override seasonal locks: 1 (January) to 12 (December) @@ -348,8 +347,6 @@ WHITELISTED_CHANNELS = ( Channels.voice_chat_1, ) -GIT_SHA = environ.get("GIT_SHA", "foobar") - # Bot replies ERROR_REPLIES = [ "Please don't do that.", -- cgit v1.2.3 From 45ac010fd6d2f8f9774cc5f408aa31c40fac42e6 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Fri, 12 Nov 2021 10:05:15 -0500 Subject: fix: check length of hex before strip --- bot/exts/utilities/colour.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 6772fa1f..66df5e0b 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -43,7 +43,9 @@ class Colour(commands.Cog): elif colour_mode == "name": input_colour = ctx.kwargs["user_colour_name"] elif colour_mode == "hex": - input_colour = ctx.args[2:][0][0:-2] + input_colour = ctx.args[2:][0] + if len(input_colour) >= 7: + input_colour = input_colour[0:-2] else: input_colour = tuple(ctx.args[2:]) -- cgit v1.2.3 From 5b3a23fe7b81d07c842271dc1947aa60133a2f8d Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 12 Nov 2021 10:08:21 -0500 Subject: fix: replace Union with Optional type hint Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 66df5e0b..5cd01fb5 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -244,7 +244,7 @@ class Colour(commands.Cog): colour_name = None return colour_name - def match_colour_name(self, ctx: commands.Context, input_colour_name: str) -> Union[str, None]: + def match_colour_name(self, ctx: commands.Context, input_colour_name: str) -> Optional[str]: """Convert a colour name to HEX code.""" try: match, certainty, _ = rapidfuzz.process.extractOne( -- cgit v1.2.3 From 8bbef57ccda68c388cf3d4b4fbc90fedf0e8597e Mon Sep 17 00:00:00 2001 From: brad90four <42116429+brad90four@users.noreply.github.com> Date: Fri, 12 Nov 2021 10:08:42 -0500 Subject: fix: bare return instead of explicit None Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 5cd01fb5..c7edec0d 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -253,7 +253,7 @@ class Colour(commands.Cog): score_cutoff=80 ) except (ValueError, TypeError): - return None + return return f"#{self.colour_mapping[match]}" -- cgit v1.2.3 From 6d5505366313b2ddb9d1a8f11b758e043e466ece Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Fri, 12 Nov 2021 10:10:12 -0500 Subject: fix: remove equal sign from hex length check --- bot/exts/utilities/colour.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index c7edec0d..66dbfa30 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -4,7 +4,7 @@ import pathlib import random import string from io import BytesIO -from typing import Optional, Union +from typing import Optional import discord import rapidfuzz @@ -44,7 +44,7 @@ class Colour(commands.Cog): input_colour = ctx.kwargs["user_colour_name"] elif colour_mode == "hex": input_colour = ctx.args[2:][0] - if len(input_colour) >= 7: + if len(input_colour) > 7: input_colour = input_colour[0:-2] else: input_colour = tuple(ctx.args[2:]) -- cgit v1.2.3 From e7923ed258ed7bf51cafbeb030df265a0992b1f1 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 13 Nov 2021 09:44:03 -0500 Subject: fix: remove unnecessary return in main command --- bot/exts/utilities/colour.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 66dbfa30..0681e807 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -88,9 +88,6 @@ class Colour(commands.Cog): await self.random(ctx) return - if ctx.invoked_subcommand: - return - try: extra_colour = ImageColor.getrgb(color_input) await self.send_colour_response(ctx, extra_colour) -- cgit v1.2.3 From e87e037e772fa2319c786210f176fd5088f00131 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 13 Nov 2021 10:09:04 -0500 Subject: fix: update type hint, color to colour, embed wording --- bot/exts/utilities/colour.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 0681e807..e33f65c6 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -29,7 +29,6 @@ class Colour(commands.Cog): async def send_colour_response(self, ctx: commands.Context, rgb: tuple[int, int, int]) -> None: """Create and send embed from user given colour information.""" name = self._rgb_to_name(rgb) - try: colour_or_color = ctx.invoked_parents[0] except IndexError: @@ -38,8 +37,9 @@ class Colour(commands.Cog): colour_mode = ctx.invoked_with if colour_mode == "random": colour_mode = colour_or_color + input_colour = name elif colour_mode in ("colour", "color"): - input_colour = rgb + input_colour = name elif colour_mode == "name": input_colour = ctx.kwargs["user_colour_name"] elif colour_mode == "hex": @@ -55,8 +55,8 @@ class Colour(commands.Cog): colour_mode = colour_mode.title() colour_embed = discord.Embed( - title=colour_or_color.title(), - description=f"{colour_mode} information for `{name or input_colour}`.", + title=f"{name or input_colour}", + description=f"{colour_or_color.title()} information for {colour_mode} `{input_colour or name}`.", colour=discord.Color.from_rgb(*rgb) ) colour_conversions = self.get_colour_conversions(rgb) @@ -78,18 +78,18 @@ class Colour(commands.Cog): await ctx.send(file=thumbnail_file, embed=colour_embed) @commands.group(aliases=("color",), invoke_without_command=True) - async def colour(self, ctx: commands.Context, *, color_input: Optional[str] = None) -> None: + async def colour(self, ctx: commands.Context, *, colour_input: Optional[str] = None) -> None: """ Create an embed that displays colour information. If no subcommand is called, a randomly selected colour will be shown. """ - if color_input is None: + if colour_input is None: await self.random(ctx) return try: - extra_colour = ImageColor.getrgb(color_input) + extra_colour = ImageColor.getrgb(colour_input) await self.send_colour_response(ctx, extra_colour) except ValueError: await invoke_help_command(ctx) @@ -162,7 +162,7 @@ class Colour(commands.Cog): if hex_colour is None: name_error_embed = discord.Embed( title="No colour match found.", - description=f"No color found for: `{user_colour_name}`", + description=f"No colour found for: `{user_colour_name}`", colour=discord.Color.dark_red() ) await ctx.send(embed=name_error_embed) @@ -172,7 +172,7 @@ class Colour(commands.Cog): @colour.command() async def random(self, ctx: commands.Context) -> None: - """Create an embed from a randomly chosen colour from the reference file.""" + """Create an embed from a randomly chosen colour.""" hex_colour = random.choice(list(self.colour_mapping.values())) hex_tuple = ImageColor.getrgb(f"#{hex_colour}") await self.send_colour_response(ctx, hex_tuple) @@ -227,7 +227,7 @@ class Colour(commands.Cog): hex_code = f"#{hex_}".upper() return hex_code - def _rgb_to_name(self, rgb: tuple[int, int, int]) -> str: + def _rgb_to_name(self, rgb: tuple[int, int, int]) -> Optional[str]: """Convert RGB values to a fuzzy matched name.""" input_hex_colour = self._rgb_to_hex(rgb) try: -- cgit v1.2.3 From e9cda06c2ab147ace8e64a27503cf99e17948418 Mon Sep 17 00:00:00 2001 From: bradtimmis Date: Sat, 13 Nov 2021 10:17:00 -0500 Subject: fix: handle bare command embed title --- bot/exts/utilities/colour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index e33f65c6..7c83fc66 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -39,7 +39,7 @@ class Colour(commands.Cog): colour_mode = colour_or_color input_colour = name elif colour_mode in ("colour", "color"): - input_colour = name + input_colour = ctx.kwargs["colour_input"] elif colour_mode == "name": input_colour = ctx.kwargs["user_colour_name"] elif colour_mode == "hex": -- cgit v1.2.3 From eb60d8b69e3eb5a4d1fdbe85e906350f426479c1 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Sun, 14 Nov 2021 16:48:28 +0100 Subject: Resources: add copyright notice to ryanzec_colours.json --- bot/resources/utilities/ryanzec_colours.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/resources/utilities/ryanzec_colours.json b/bot/resources/utilities/ryanzec_colours.json index ad8f05fd..552d5a3f 100644 --- a/bot/resources/utilities/ryanzec_colours.json +++ b/bot/resources/utilities/ryanzec_colours.json @@ -1,5 +1,5 @@ { - "_": "Source: https://github.com/ryanzec/name-that-color/blob/0bb5ec7f37e4f6e7f2c164f39f7f08cca7c8e621/lib/ntc.js#L116-L1681", + "_": "Source: https://github.com/ryanzec/name-that-color/blob/0bb5ec7f37e4f6e7f2c164f39f7f08cca7c8e621/lib/ntc.js#L116-L1681\n\nCopyright (c) 2014 Ryan Zec\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", "Abbey": "4C4F56", "Acadia": "1B1404", "Acapulco": "7CB0A1", -- cgit v1.2.3 From c56c5a9ab01a45a50877c228843fa27625f03512 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Thu, 18 Nov 2021 21:02:15 +0100 Subject: Introduce command changes in the AoC Cog - The AoC day and star browser has been separated from the leaderboard command, from now on it's a separate command - The leaderboard command has a new `self_placement_name` option, that shows the personal stats for the specified profile name. --- bot/exts/events/advent_of_code/_cog.py | 72 +++++++++++++++++++----------- bot/exts/events/advent_of_code/_helpers.py | 25 +++++++++-- 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 2c1f4541..7f35c306 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -180,24 +180,18 @@ class AdventOfCode(commands.Cog): @in_month(Month.DECEMBER) @adventofcode_group.command( - name="leaderboard", - aliases=("board", "lb"), - brief="Get a snapshot of the PyDis private AoC leaderboard", + name="dayandstar", + aliases=("daynstar", "daystar"), + brief="Get a view that lets you filter the leaderboard by day and star", ) @whitelist_override(channels=AOC_WHITELIST_RESTRICTED) - async def aoc_leaderboard( + async def aoc_day_and_star_leaderboard( self, ctx: commands.Context, - day_and_star: Optional[bool] = False, - maximum_scorers: Optional[int] = 10 + maximum_scorers_day_and_star: 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: + """Have the bot send a View that will let you filter the leaderboard by day and star.""" + if maximum_scorers_day_and_star > AocConfig.max_day_and_star_results or maximum_scorers_day_and_star <= 0: raise commands.BadArgument( f"The maximum number of results you can query is {AocConfig.max_day_and_star_results}" ) @@ -207,25 +201,12 @@ class AdventOfCode(commands.Cog): except _helpers.FetchingLeaderboardFailedError: await ctx.send(":x: Unable to fetch leaderboard!") return - if not day_and_star: - - number_of_participants = leaderboard["number_of_participants"] - - top_count = min(AocConfig.leaderboard_displayed_members, number_of_participants) - header = f"Here's our current top {top_count}! {Emojis.christmas_tree * 3}" - - table = f"```\n{leaderboard['top_leaderboard']}\n```" - 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, + maximum_scorers=maximum_scorers_day_and_star, original_author=ctx.author ) message = await ctx.send( @@ -235,6 +216,43 @@ class AdventOfCode(commands.Cog): await view.wait() await message.edit(view=None) + @in_month(Month.DECEMBER) + @adventofcode_group.command( + name="leaderboard", + aliases=("board", "lb"), + brief="Get a snapshot of the PyDis private AoC leaderboard", + ) + @whitelist_override(channels=AOC_WHITELIST_RESTRICTED) + async def aoc_leaderboard( + self, + ctx: commands.Context, + self_placement_name: Optional[str] = None, + ) -> None: + """ + Get the current top scorers of the Python Discord Leaderboard. + + Additionaly you can specify a `self_placement_name` + that will append the specified profile's personal stats to the top of the leaderboard + """ + async with ctx.typing(): + try: + leaderboard = await _helpers.fetch_leaderboard(self_placement_name=self_placement_name) + except _helpers.FetchingLeaderboardFailedError: + await ctx.send(":x: Unable to fetch leaderboard!") + return + + number_of_participants = leaderboard["number_of_participants"] + + top_count = min(AocConfig.leaderboard_displayed_members, number_of_participants) + self_placement_header = "(and your personal stats compared to the top 10)" if self_placement_name else "" + header = f"Here's our current top {top_count}{self_placement_header}! {Emojis.christmas_tree * 3}" + + table = f"```\n{leaderboard['top_leaderboard']}\n```" + info_embed = _helpers.get_summary_embed(leaderboard) + + await ctx.send(content=f"{header}\n\n{table}", embed=info_embed) + return + @in_month(Month.DECEMBER) @adventofcode_group.command( name="global", diff --git a/bot/exts/events/advent_of_code/_helpers.py b/bot/exts/events/advent_of_code/_helpers.py index af64bc81..58fc3054 100644 --- a/bot/exts/events/advent_of_code/_helpers.py +++ b/bot/exts/events/advent_of_code/_helpers.py @@ -10,6 +10,7 @@ from typing import Any, Optional import aiohttp import arrow import discord +from discord.ext import commands from bot.bot import Bot from bot.constants import AdventOfCode, Channels, Colours @@ -160,10 +161,23 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict: return {"daily_stats": daily_stats, "leaderboard": sorted_leaderboard, 'per_day_and_star': per_day_star_stats} -def _format_leaderboard(leaderboard: dict[str, dict]) -> str: +def _format_leaderboard(leaderboard: dict[str, dict], self_placement_name: str = None) -> str: """Format the leaderboard using the AOC_TABLE_TEMPLATE.""" leaderboard_lines = [HEADER] + self_placement_exists = False for rank, data in enumerate(leaderboard.values(), start=1): + if self_placement_name and data["name"].lower() == self_placement_name.lower(): + leaderboard_lines.insert( + 1, + AOC_TABLE_TEMPLATE.format( + rank=rank, + name=f"(You) {data['name']}", + score=str(data["score"]), + stars=f"({data['star_1']}, {data['star_2']})" + ) + ) + self_placement_exists = True + continue leaderboard_lines.append( AOC_TABLE_TEMPLATE.format( rank=rank, @@ -172,7 +186,10 @@ def _format_leaderboard(leaderboard: dict[str, dict]) -> str: stars=f"({data['star_1']}, {data['star_2']})" ) ) - + if self_placement_name and not self_placement_exists: + raise commands.BadArgument( + "Sorry, your profile does not exist in this leaderboard." + ) return "\n".join(leaderboard_lines) @@ -260,7 +277,7 @@ def _get_top_leaderboard(full_leaderboard: str) -> str: @_caches.leaderboard_cache.atomic_transaction -async def fetch_leaderboard(invalidate_cache: bool = False) -> dict: +async def fetch_leaderboard(invalidate_cache: bool = False, self_placement_name: str = None) -> dict: """ Get the current Python Discord combined leaderboard. @@ -284,7 +301,7 @@ async def fetch_leaderboard(invalidate_cache: bool = False) -> dict: leaderboard = parsed_leaderboard_data["leaderboard"] number_of_participants = len(leaderboard) - formatted_leaderboard = _format_leaderboard(leaderboard) + formatted_leaderboard = _format_leaderboard(leaderboard, self_placement_name) full_leaderboard_url = await _upload_leaderboard(formatted_leaderboard) leaderboard_fetched_at = datetime.datetime.utcnow().isoformat() -- cgit v1.2.3 From ad66899453b027f3a5522cc103f5c128456144c4 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Fri, 19 Nov 2021 18:06:52 +0100 Subject: Update Caching logic in AoC helpers - This commit adds a new set of leaderboard data to the cache so that it calculates the correct information if issued with either a `self_placement_name` or not. - It also introduces code consistency upgrades Co-Authored-By: Johannes Christ --- bot/exts/events/advent_of_code/_cog.py | 7 +++--- bot/exts/events/advent_of_code/_helpers.py | 39 +++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 7f35c306..cd41e9ce 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -231,7 +231,7 @@ class AdventOfCode(commands.Cog): """ Get the current top scorers of the Python Discord Leaderboard. - Additionaly you can specify a `self_placement_name` + Additionally you can specify a `self_placement_name` that will append the specified profile's personal stats to the top of the leaderboard """ async with ctx.typing(): @@ -246,8 +246,9 @@ class AdventOfCode(commands.Cog): top_count = min(AocConfig.leaderboard_displayed_members, number_of_participants) self_placement_header = "(and your personal stats compared to the top 10)" if self_placement_name else "" header = f"Here's our current top {top_count}{self_placement_header}! {Emojis.christmas_tree * 3}" - - table = f"```\n{leaderboard['top_leaderboard']}\n```" + table = "```\n" \ + f"{leaderboard['placement_leaderboard'] if self_placement_name else leaderboard['top_leaderboard']}" \ + "\n```" info_embed = _helpers.get_summary_embed(leaderboard) await ctx.send(content=f"{header}\n\n{table}", embed=info_embed) diff --git a/bot/exts/events/advent_of_code/_helpers.py b/bot/exts/events/advent_of_code/_helpers.py index 58fc3054..35258544 100644 --- a/bot/exts/events/advent_of_code/_helpers.py +++ b/bot/exts/events/advent_of_code/_helpers.py @@ -71,6 +71,33 @@ class FetchingLeaderboardFailedError(Exception): """Raised when one or more leaderboards could not be fetched at all.""" +def _format_leaderboard_line(rank: int, data: dict[str, Any], *, is_author: bool) -> str: + """ + Build a string representing a line of the leaderboard. + + Parameters: + rank: + Rank in the leaderboard of this entry. + + data: + Mapping with entry information. + + Keyword arguments: + is_author: + Whether to address the name displayed in the returned line + personally. + + Returns: + A formatted line for the leaderboard. + """ + return AOC_TABLE_TEMPLATE.format( + rank=rank, + name=data['name'] if not is_author else f"(You) {data['name']}", + score=str(data['score']), + stars=f"({data['star_1']}, {data['star_2']})" + ) + + def leaderboard_sorting_function(entry: tuple[str, dict]) -> tuple[int, int]: """ Provide a sorting value for our leaderboard. @@ -287,7 +314,6 @@ async def fetch_leaderboard(invalidate_cache: bool = False, self_placement_name: miss, this function is locked to one call at a time using a decorator. """ cached_leaderboard = await _caches.leaderboard_cache.to_dict() - # Check if the cached leaderboard contains everything we expect it to. If it # does not, this probably means the cache has not been created yet or has # expired in Redis. This check also accounts for a malformed cache. @@ -301,11 +327,12 @@ async def fetch_leaderboard(invalidate_cache: bool = False, self_placement_name: leaderboard = parsed_leaderboard_data["leaderboard"] number_of_participants = len(leaderboard) - formatted_leaderboard = _format_leaderboard(leaderboard, self_placement_name) + formatted_leaderboard = _format_leaderboard(leaderboard) full_leaderboard_url = await _upload_leaderboard(formatted_leaderboard) leaderboard_fetched_at = datetime.datetime.utcnow().isoformat() cached_leaderboard = { + "placement_leaderboard": json.dumps(raw_leaderboard_data), "full_leaderboard": formatted_leaderboard, "top_leaderboard": _get_top_leaderboard(formatted_leaderboard), "full_leaderboard_url": full_leaderboard_url, @@ -324,7 +351,13 @@ async def fetch_leaderboard(invalidate_cache: bool = False, self_placement_name: _caches.leaderboard_cache.namespace, AdventOfCode.leaderboard_cache_expiry_seconds ) - + if self_placement_name: + formatted_placement_leaderboard = _parse_raw_leaderboard_data( + json.loads(cached_leaderboard["placement_leaderboard"]) + )["leaderboard"] + cached_leaderboard["placement_leaderboard"] = _get_top_leaderboard( + _format_leaderboard(formatted_placement_leaderboard, self_placement_name=self_placement_name) + ) return cached_leaderboard -- cgit v1.2.3 From 5059e61c354054b8cd463866cbd4ab4b1c0a8c09 Mon Sep 17 00:00:00 2001 From: aru Date: Sat, 20 Nov 2021 09:55:50 -0500 Subject: Remove unnecessary edits during pagination pick 3cd4c92b1e24c8cfdae8c5c68c19607c62cc01ed from python-discord/bot remove additional unnecessary edit --- bot/utils/pagination.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/bot/utils/pagination.py b/bot/utils/pagination.py index 013ef9e7..188b279f 100644 --- a/bot/utils/pagination.py +++ b/bot/utils/pagination.py @@ -211,8 +211,6 @@ class LinePaginator(Paginator): log.debug(f"Got first page reaction - changing to page 1/{len(paginator.pages)}") - embed.description = "" - await message.edit(embed=embed) embed.description = paginator.pages[current_page] if footer_text: embed.set_footer(text=f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})") @@ -226,8 +224,6 @@ class LinePaginator(Paginator): log.debug(f"Got last page reaction - changing to page {current_page + 1}/{len(paginator.pages)}") - embed.description = "" - await message.edit(embed=embed) embed.description = paginator.pages[current_page] if footer_text: embed.set_footer(text=f"{footer_text} (Page {current_page + 1}/{len(paginator.pages)})") @@ -245,8 +241,6 @@ class LinePaginator(Paginator): current_page -= 1 log.debug(f"Got previous page reaction - changing to page {current_page + 1}/{len(paginator.pages)}") - embed.description = "" - await message.edit(embed=embed) embed.description = paginator.pages[current_page] if footer_text: @@ -266,8 +260,6 @@ class LinePaginator(Paginator): current_page += 1 log.debug(f"Got next page reaction - changing to page {current_page + 1}/{len(paginator.pages)}") - embed.description = "" - await message.edit(embed=embed) embed.description = paginator.pages[current_page] if footer_text: @@ -428,8 +420,6 @@ class ImagePaginator(Paginator): reaction_type = "next" # Magic happens here, after page and reaction_type is set - embed.description = "" - await message.edit(embed=embed) embed.description = paginator.pages[current_page] image = paginator.images[current_page] or EmptyEmbed -- cgit v1.2.3 From b794b02c4aa81218500151fde53e95d8c10c9817 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sat, 20 Nov 2021 23:10:57 +0300 Subject: Disable File Logging By Default Place logging to file behind an environment variable. Signed-off-by: Hassan Abouelela --- bot/constants.py | 1 + bot/log.py | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index 2b41b8a4..33bc8b61 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -135,6 +135,7 @@ class Client(NamedTuple): prefix = environ.get("PREFIX", ".") token = environ.get("BOT_TOKEN") debug = environ.get("BOT_DEBUG", "true").lower() == "true" + file_logs = environ.get("FILE_LOGS", "false").lower() == "true" github_bot_repo = "https://github.com/python-discord/sir-lancebot" # Override seasonal locks: 1 (January) to 12 (December) month_override = int(environ["MONTH_OVERRIDE"]) if "MONTH_OVERRIDE" in environ else None diff --git a/bot/log.py b/bot/log.py index 97561be4..29e696e0 100644 --- a/bot/log.py +++ b/bot/log.py @@ -20,10 +20,7 @@ def setup() -> None: log_format = logging.Formatter(format_string) root_logger = logging.getLogger() - # Copied from constants file, which we can't import yet since loggers aren't instantiated - debug = os.environ.get("BOT_DEBUG", "true").lower() == "true" - - if debug: + if Client.file_logs: # Set up file logging log_file = Path("logs/sir-lancebot.log") log_file.parent.mkdir(exist_ok=True) -- cgit v1.2.3 From 19a21dc6b07a6c7947fbde1de9c6aee21ccc0ef8 Mon Sep 17 00:00:00 2001 From: D0rs4n <41237606+D0rs4n@users.noreply.github.com> Date: Sun, 21 Nov 2021 11:20:13 +0100 Subject: Add check to ensure the day-and-star data exists --- bot/exts/events/advent_of_code/views/dayandstarview.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bot/exts/events/advent_of_code/views/dayandstarview.py b/bot/exts/events/advent_of_code/views/dayandstarview.py index 243db32e..a0bfa316 100644 --- a/bot/exts/events/advent_of_code/views/dayandstarview.py +++ b/bot/exts/events/advent_of_code/views/dayandstarview.py @@ -17,14 +17,19 @@ class AoCDropdownView(discord.ui.View): 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.""" + """ + Generates a formatted codeblock with AoC statistics based on the currently selected day and star. + + Optionally, when the requested day and star data does not exist yet it returns an error message. + """ 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]): + if not (day_and_star_data := self.data.get(f"{self.day}-{self.star}")): + return ":x: The requested data for the specified day and star does not exist yet." + for rank, scorer in enumerate(day_and_star_data[:self.maximum_scorers]): time_data = datetime.fromtimestamp(scorer['completion_time']).strftime("%I:%M:%S %p") lines.append(AOC_DAY_AND_STAR_TEMPLATE.format( datastamp="", -- cgit v1.2.3 From 0a1ded20ee8111efc45805dcf4a668f575f1c798 Mon Sep 17 00:00:00 2001 From: DMFriends Date: Mon, 22 Nov 2021 16:15:23 -0500 Subject: Fix a grammatical mistake in the description of the `.spookify` command --- 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 fbee96dc..3ee70cfd 100644 --- a/bot/exts/avatar_modification/avatar_modify.py +++ b/bot/exts/avatar_modification/avatar_modify.py @@ -286,7 +286,7 @@ class AvatarModify(commands.Cog): @avatar_modify.command( aliases=("savatar", "spookify"), root_aliases=("spookyavatar", "spookify", "savatar"), - brief="Spookify an user's avatar." + brief="Spookify a user's avatar." ) async def spookyavatar(self, ctx: commands.Context) -> None: """This "spookifies" the user's avatar, with a random *spooky* effect.""" -- cgit v1.2.3 From be7da6f34e50b7a99ef6c3a7eb67a48b24b818ed Mon Sep 17 00:00:00 2001 From: Izan Date: Mon, 29 Nov 2021 09:11:17 +0000 Subject: Change `MODERATION_ROLES` and `STAFF_ROLES` constants to be a set --- bot/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index b4191c5e..bef7f3d1 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -332,8 +332,8 @@ class Reddit: # Default role combinations -MODERATION_ROLES = Roles.moderation_team, Roles.admins, Roles.owners -STAFF_ROLES = Roles.helpers, Roles.moderation_team, Roles.admins, Roles.owners +MODERATION_ROLES = {Roles.moderation_team, Roles.admins, Roles.owners} +STAFF_ROLES = {Roles.helpers, Roles.moderation_team, Roles.admins, Roles.owners} # Whitelisted channels WHITELISTED_CHANNELS = ( -- cgit v1.2.3 From a958d1c1f6a3308b5ffd03cb7f9ef846b0871265 Mon Sep 17 00:00:00 2001 From: Izan Date: Mon, 29 Nov 2021 09:34:31 +0000 Subject: Revert change to if statement checking if staff in `.aoc join` --- bot/exts/events/advent_of_code/_cog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index c3073fd5..34ade5b1 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -148,7 +148,7 @@ class AdventOfCode(commands.Cog): author = ctx.author log.info(f"{author.name} ({author.id}) has requested a PyDis AoC leaderboard code") - if AocConfig.staff_leaderboard_id and any(r.id in STAFF_ROLES for r in author.roles): + if AocConfig.staff_leaderboard_id and any(r.id == Roles.helpers for r in author.roles): join_code = AocConfig.leaderboards[AocConfig.staff_leaderboard_id].join_code else: try: -- cgit v1.2.3 From 338fc7a0b37483feba56a8810cd2e1a344ab8b22 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 29 Nov 2021 10:48:26 +0000 Subject: Swap conditional in aoc count This is so that there is less code within the if block, making it easier to parse the whole command by eye. --- bot/exts/events/advent_of_code/_cog.py | 41 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index cd41e9ce..c91a5019 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -100,32 +100,31 @@ class AdventOfCode(commands.Cog): @whitelist_override(channels=AOC_WHITELIST) async def aoc_countdown(self, ctx: commands.Context) -> None: """Return time left until next day.""" - if not _helpers.is_in_advent(): - datetime_now = arrow.now(_helpers.EST) - - # Calculate the delta to this & next year's December 1st to see which one is closest and not in the past - this_year = arrow.get(datetime(datetime_now.year, 12, 1), _helpers.EST) - next_year = arrow.get(datetime(datetime_now.year + 1, 12, 1), _helpers.EST) - deltas = (dec_first - datetime_now for dec_first in (this_year, next_year)) - delta = min(delta for delta in deltas if delta >= timedelta()) # timedelta() gives 0 duration delta - - # Add a finer timedelta if there's less than a day left - if delta.days == 0: - delta_str = f"approximately {delta.seconds // 3600} hours" - else: - delta_str = f"{delta.days} days" + if _helpers.is_in_advent(): + tomorrow, time_left = _helpers.time_left_to_est_midnight() + hours, minutes = time_left.seconds // 3600, time_left.seconds // 60 % 60 - await ctx.send( - "The Advent of Code event is not currently running. " - f"The next event will start in {delta_str}." - ) + await ctx.send(f"There are {hours} hours and {minutes} minutes left until day {tomorrow.day}.") return - tomorrow, time_left = _helpers.time_left_to_est_midnight() + datetime_now = arrow.now(_helpers.EST) - hours, minutes = time_left.seconds // 3600, time_left.seconds // 60 % 60 + # Calculate the delta to this & next year's December 1st to see which one is closest and not in the past + this_year = arrow.get(datetime(datetime_now.year, 12, 1), _helpers.EST) + next_year = arrow.get(datetime(datetime_now.year + 1, 12, 1), _helpers.EST) + deltas = (dec_first - datetime_now for dec_first in (this_year, next_year)) + delta = min(delta for delta in deltas if delta >= timedelta()) # timedelta() gives 0 duration delta - await ctx.send(f"There are {hours} hours and {minutes} minutes left until day {tomorrow.day}.") + # Add a finer timedelta if there's less than a day left + if delta.days == 0: + delta_str = f"approximately {delta.seconds // 3600} hours" + else: + delta_str = f"{delta.days} days" + + await ctx.send( + "The Advent of Code event is not currently running. " + f"The next event will start in {delta_str}." + ) @adventofcode_group.command(name="about", aliases=("ab", "info"), brief="Learn about Advent of Code") @whitelist_override(channels=AOC_WHITELIST) -- cgit v1.2.3 From 790bcdf2fedc8dd7aac8c5a2610dc8395852bce0 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 29 Nov 2021 10:49:28 +0000 Subject: Use a Discord timestamp to show countdown This gives the user the ability to hover the timestamp with their mouse to get an exact date and time. --- bot/exts/events/advent_of_code/_cog.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index c91a5019..94722005 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -115,15 +115,11 @@ class AdventOfCode(commands.Cog): deltas = (dec_first - datetime_now for dec_first in (this_year, next_year)) delta = min(delta for delta in deltas if delta >= timedelta()) # timedelta() gives 0 duration delta - # Add a finer timedelta if there's less than a day left - if delta.days == 0: - delta_str = f"approximately {delta.seconds // 3600} hours" - else: - delta_str = f"{delta.days} days" + next_aoc_timestamp = int((datetime_now + delta).timestamp()) await ctx.send( "The Advent of Code event is not currently running. " - f"The next event will start in {delta_str}." + f"The next event will start ." ) @adventofcode_group.command(name="about", aliases=("ab", "info"), brief="Learn about Advent of Code") -- cgit v1.2.3 From c81d30357db2c0950d5e781cdd5e9053907b228d Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 29 Nov 2021 15:10:29 +0000 Subject: Use Discord timestamps for aoc next day messages countdowns --- bot/exts/events/advent_of_code/_cog.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 94722005..af1cbcf5 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -101,14 +101,13 @@ class AdventOfCode(commands.Cog): async def aoc_countdown(self, ctx: commands.Context) -> None: """Return time left until next day.""" if _helpers.is_in_advent(): - tomorrow, time_left = _helpers.time_left_to_est_midnight() - hours, minutes = time_left.seconds // 3600, time_left.seconds // 60 % 60 + tomorrow, _ = _helpers.time_left_to_est_midnight() + next_day_timestamp = int(tomorrow.timestamp()) - await ctx.send(f"There are {hours} hours and {minutes} minutes left until day {tomorrow.day}.") + await ctx.send(f"Day {tomorrow.day} starts .") return datetime_now = arrow.now(_helpers.EST) - # Calculate the delta to this & next year's December 1st to see which one is closest and not in the past this_year = arrow.get(datetime(datetime_now.year, 12, 1), _helpers.EST) next_year = arrow.get(datetime(datetime_now.year + 1, 12, 1), _helpers.EST) -- cgit v1.2.3 From 65398ed2b9fb67dbe842996e01142722bd0667f3 Mon Sep 17 00:00:00 2001 From: aru Date: Wed, 1 Dec 2021 17:15:25 -0500 Subject: fix: hanukkah command respects month boundaries rewrote hanukkah to use datetime.strptime left a helper method and some variables in order to allow extending to use a cache in the future, rather than requesting the api every invoke that is out of scope of this commit and pull, since the command is currently broken. I've only kept the same functionality, without trying to rewrite the entire command. --- bot/exts/holidays/hanukkah/hanukkah_embed.py | 84 ++++++++++++---------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/bot/exts/holidays/hanukkah/hanukkah_embed.py b/bot/exts/holidays/hanukkah/hanukkah_embed.py index ac3eab7b..5767f91e 100644 --- a/bot/exts/holidays/hanukkah/hanukkah_embed.py +++ b/bot/exts/holidays/hanukkah/hanukkah_embed.py @@ -21,45 +21,41 @@ class HanukkahEmbed(commands.Cog): def __init__(self, bot: Bot): self.bot = bot - self.hanukkah_days = [] - self.hanukkah_months = [] - self.hanukkah_years = [] + self.hanukkah_dates: list[datetime.date] = [] - async def get_hanukkah_dates(self) -> list[str]: + def _parse_time_to_datetime(self, date: list[str]) -> datetime.datetime: + """Format the times provided by the api to datetime forms.""" + try: + return datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S%z") + except ValueError: + # there is a possibility of an event not having a time, just a day + # to catch this, we try again without time information + return datetime.datetime.strptime(date, "%Y-%m-%d") + + async def fetch_hanukkah_dates(self) -> list[datetime.date]: """Gets the dates for hanukkah festival.""" - hanukkah_dates = [] + # clear the datetime objects to prevent a memory link + self.hanukkah_dates = [] async with self.bot.http_session.get(HEBCAL_URL) as response: json_data = await response.json() festivals = json_data["items"] for festival in festivals: if festival["title"].startswith("Chanukah"): date = festival["date"] - hanukkah_dates.append(date) - return hanukkah_dates + self.hanukkah_dates.append(self._parse_time_to_datetime(date).date()) + return self.hanukkah_dates @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).""" - hanukkah_dates = await self.get_hanukkah_dates() - self.hanukkah_dates_split(hanukkah_dates) - hanukkah_start_day = int(self.hanukkah_days[0]) - hanukkah_start_month = int(self.hanukkah_months[0]) - hanukkah_start_year = int(self.hanukkah_years[0]) - hanukkah_end_day = int(self.hanukkah_days[8]) - hanukkah_end_month = int(self.hanukkah_months[8]) - hanukkah_end_year = int(self.hanukkah_years[8]) - - hanukkah_start = datetime.date(hanukkah_start_year, hanukkah_start_month, hanukkah_start_day) - hanukkah_end = datetime.date(hanukkah_end_year, hanukkah_end_month, hanukkah_end_day) + hanukkah_dates = await self.fetch_hanukkah_dates() + start_day = hanukkah_dates[0] + end_day = hanukkah_dates[-1] today = datetime.date.today() - # today = datetime.date(2019, 12, 24) (for testing) - day = str(today.day) - month = str(today.month) - year = str(today.year) embed = Embed(title="Hanukkah", colour=Colours.blue) - if day in self.hanukkah_days and month in self.hanukkah_months and year in self.hanukkah_years: - if int(day) == hanukkah_start_day: + if start_day <= today <= end_day: + if start_day == today: now = datetime.datetime.utcnow() hours = now.hour + 4 # using only hours hanukkah_start_hour = 18 @@ -77,35 +73,27 @@ class HanukkahEmbed(commands.Cog): ) await ctx.send(embed=embed) return - festival_day = self.hanukkah_days.index(day) + festival_day = hanukkah_dates.index(today) number_suffixes = ["st", "nd", "rd", "th"] suffix = number_suffixes[festival_day - 1 if festival_day <= 3 else 3] message = ":menorah:" * festival_day - embed.description = f"It is the {festival_day}{suffix} day of Hanukkah!\n{message}" - await ctx.send(embed=embed) + embed.description = ( + f"It is the {festival_day}{suffix} day of Hanukkah!\n{message}" + ) + elif today < start_day: + format_start = start_day.strftime("%d of %B") + embed.description = ( + "Hanukkah has not started yet. " + f"Hanukkah will start at sundown on {format_start}." + ) else: - if today < hanukkah_start: - festival_starting_month = hanukkah_start.strftime("%B") - embed.description = ( - f"Hanukkah has not started yet. " - f"Hanukkah will start at sundown on {hanukkah_start_day}th " - f"of {festival_starting_month}." - ) - else: - festival_end_month = hanukkah_end.strftime("%B") - embed.description = ( - f"Looks like you missed Hanukkah!" - f"Hanukkah ended on {hanukkah_end_day}th of {festival_end_month}." - ) - - await ctx.send(embed=embed) + format_end = end_day.strftime("%d of %B") + embed.description = ( + "Looks like you missed Hanukkah! " + f"Hanukkah ended on {format_end}." + ) - def hanukkah_dates_split(self, hanukkah_dates: list[str]) -> None: - """We are splitting the dates for hanukkah into days, months and years.""" - for date in hanukkah_dates: - self.hanukkah_days.append(date[8:10]) - self.hanukkah_months.append(date[5:7]) - self.hanukkah_years.append(date[0:4]) + await ctx.send(embed=embed) def setup(bot: Bot) -> None: -- cgit v1.2.3 From eba75f73964a258119e16ba2abfc181055281022 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Wed, 1 Dec 2021 22:41:07 -0500 Subject: Add `.aoc link` command This new command will allow people to associate their Discord ID with their Advent of Code name. This Redis Cache idea was taken from the hacktoberfest stats command, which allows people to associate their github username to then pull the correct stats. This does not check if the name exists on the leaderboard and that is intentional. Due to the cooldown on the leaderboard I don't want to rely on that before someone can link their account. Additionally, someone may change their display name on the Advent of Code side and I don't think validation of it existing on the leaderboard gets us anything. The usefulness of this function will not be apparent in this cog, but it is necessary for something fun I'd like to do. --- bot/exts/events/advent_of_code/_cog.py | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index af1cbcf5..1b1cd9f8 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -6,6 +6,7 @@ from typing import Optional import arrow import discord +from async_rediscache import RedisCache from discord.ext import commands from bot.bot import Bot @@ -29,6 +30,8 @@ AOC_WHITELIST = AOC_WHITELIST_RESTRICTED + (Channels.advent_of_code,) class AdventOfCode(commands.Cog): """Advent of Code festivities! Ho Ho Ho!""" + account_links = RedisCache() + def __init__(self, bot: Bot): self.bot = bot @@ -172,6 +175,72 @@ class AdventOfCode(commands.Cog): else: await ctx.message.add_reaction(Emojis.envelope) + @in_month(Month.NOVEMBER, Month.DECEMBER) + @adventofcode_group.command( + name="link", + aliases=("connect",), + brief="Tie your Discord account with your Advent of Code name." + ) + @whitelist_override(channels=AOC_WHITELIST) + async def aoc_link_account(self, ctx: commands.Context, aoc_name: str = None) -> None: + """ + Link your Discord Account to your Advent of Code name. + + Stored in a Redis Cache, Discord ID: Advent of Code Name + """ + cache_items = await self.account_links.items() + + # A short circuit in case the cache is empty + if len(cache_items) == 0 and aoc_name: + log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") + await self.account_links.set(ctx.author.id, aoc_name) + await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") + return + elif len(cache_items) == 0: + await ctx.reply( + "You have not linked an Advent of Code account." + "Please re-run the command with one specified." + ) + return + + cache_aoc_name = [value for _, value in cache_items] + + if aoc_name: + # Let's check the current values in the cache to make sure it isn't already tied to a different account + if aoc_name == await self.account_links.get(ctx.author.id): + await ctx.reply(f"{aoc_name} is already tied to your account.") + return + elif aoc_name in cache_aoc_name: + log.info( + f"{ctx.author} ({ctx.author.id}) tried to connect their account to {aoc_name}," + " but it's already connected to another user." + ) + await ctx.reply( + f"{aoc_name} is already tied to another account." + " Please contact an admin if you believe this is an error." + ) + return + + # Update an existing link + if old_aoc_name := await self.account_links.get(ctx.author.id): + log.info(f"{ctx.author} ({ctx.author.id}) has changed their link from {old_aoc_name} to {aoc_name}.") + await self.account_links.set(ctx.author.id, aoc_name) + await ctx.reply(f"Your linked account has been changed to {aoc_name}.") + else: + # Create a new link + log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") + await self.account_links.set(ctx.author.id, aoc_name) + await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") + else: + # User has not supplied a name, let's check if they're in the cache or not + if cache_name := await self.account_links.get(ctx.author.id): + await ctx.reply(f"You have already linked an Advent of Code account: {cache_name}.") + else: + await ctx.reply( + "You have not linked an Advent of Code account." + " Please re-run the command with one specified." + ) + @in_month(Month.DECEMBER) @adventofcode_group.command( name="dayandstar", -- cgit v1.2.3 From 1dba7a7a7132839230f776a8ecb73b9def93174f Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Wed, 1 Dec 2021 20:44:46 -0700 Subject: Make self_placement_name keyword-only in .aoc lb --- bot/exts/events/advent_of_code/_cog.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index af1cbcf5..900c3469 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -220,6 +220,7 @@ class AdventOfCode(commands.Cog): async def aoc_leaderboard( self, ctx: commands.Context, + *, self_placement_name: Optional[str] = None, ) -> None: """ -- cgit v1.2.3 From 4959f085537421814159734070b74dadd566501f Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Wed, 1 Dec 2021 21:16:49 -0700 Subject: Strip quotes from start/end of the username for .aoc lb --- bot/exts/events/advent_of_code/_cog.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 900c3469..c6225356 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -229,6 +229,10 @@ class AdventOfCode(commands.Cog): Additionally you can specify a `self_placement_name` that will append the specified profile's personal stats to the top of the leaderboard """ + # Strip quotes from the self placement name if needed (e.g. "My Name" -> My Name) + if self_placement_name and self_placement_name[0] == self_placement_name[-1] == '"': + self_placement_name = self_placement_name[1:-1] + async with ctx.typing(): try: leaderboard = await _helpers.fetch_leaderboard(self_placement_name=self_placement_name) -- cgit v1.2.3 From aea61a096bfbf60fab9711698c9353635b13ea0c Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Wed, 1 Dec 2021 21:43:17 -0700 Subject: Shorten parameter name for .aoc lb --- bot/exts/events/advent_of_code/_cog.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index c6225356..0f6739fc 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -217,25 +217,20 @@ 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, - *, - self_placement_name: Optional[str] = None, - ) -> None: + async def aoc_leaderboard(self, ctx: commands.Context, *, aoc_name: Optional[str] = None) -> None: """ Get the current top scorers of the Python Discord Leaderboard. - Additionally you can specify a `self_placement_name` - that will append the specified profile's personal stats to the top of the leaderboard + Additionally you can specify an `aoc_name` that will append the + specified profile's personal stats to the top of the leaderboard """ # Strip quotes from the self placement name if needed (e.g. "My Name" -> My Name) - if self_placement_name and self_placement_name[0] == self_placement_name[-1] == '"': - self_placement_name = self_placement_name[1:-1] + if aoc_name and aoc_name.startswith('"') and aoc_name.endswith('"'): + aoc_name = aoc_name[1:-1] async with ctx.typing(): try: - leaderboard = await _helpers.fetch_leaderboard(self_placement_name=self_placement_name) + leaderboard = await _helpers.fetch_leaderboard(self_placement_name=aoc_name) except _helpers.FetchingLeaderboardFailedError: await ctx.send(":x: Unable to fetch leaderboard!") return @@ -243,10 +238,10 @@ class AdventOfCode(commands.Cog): number_of_participants = leaderboard["number_of_participants"] top_count = min(AocConfig.leaderboard_displayed_members, number_of_participants) - self_placement_header = "(and your personal stats compared to the top 10)" if self_placement_name else "" + self_placement_header = "(and your personal stats compared to the top 10)" if aoc_name else "" header = f"Here's our current top {top_count}{self_placement_header}! {Emojis.christmas_tree * 3}" table = "```\n" \ - f"{leaderboard['placement_leaderboard'] if self_placement_name else leaderboard['top_leaderboard']}" \ + f"{leaderboard['placement_leaderboard'] if aoc_name else leaderboard['top_leaderboard']}" \ "\n```" info_embed = _helpers.get_summary_embed(leaderboard) -- cgit v1.2.3 From 4a06ec80cc9e78294475ab23c41649d47798cca4 Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Thu, 2 Dec 2021 15:33:29 -0700 Subject: Note that only one layer of quotes is stripped in .aoc lb --- bot/exts/events/advent_of_code/_cog.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 0f6739fc..9ae2d059 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -224,7 +224,9 @@ class AdventOfCode(commands.Cog): Additionally you can specify an `aoc_name` that will append the specified profile's personal stats to the top of the leaderboard """ - # Strip quotes from the self placement name if needed (e.g. "My Name" -> My Name) + # Strip quotes from the AoC username if needed (e.g. "My Name" -> My Name) + # Note: only strips one layer of quotes to allow names with quotes at the start and end + # e.g. ""My Name"" -> "My Name" if aoc_name and aoc_name.startswith('"') and aoc_name.endswith('"'): aoc_name = aoc_name[1:-1] -- cgit v1.2.3 From 914e4abe1f168167d8b1126adeb1bc27bff28e6d Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Thu, 2 Dec 2021 15:34:45 -0700 Subject: Note why .aoc lb strips quotes from names --- bot/exts/events/advent_of_code/_cog.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 9ae2d059..3f9f5787 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -225,6 +225,7 @@ class AdventOfCode(commands.Cog): specified profile's personal stats to the top of the leaderboard """ # Strip quotes from the AoC username if needed (e.g. "My Name" -> My Name) + # This is to keep compatibility with those already used to wrapping the AoC name in quotes # Note: only strips one layer of quotes to allow names with quotes at the start and end # e.g. ""My Name"" -> "My Name" if aoc_name and aoc_name.startswith('"') and aoc_name.endswith('"'): -- cgit v1.2.3 From 7cb5c5517043c0006b001c15373b664b86cc6b43 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Fri, 3 Dec 2021 17:28:15 -0500 Subject: feat: implement moving commands add exceptions and handler for commands that move locations --- bot/constants.py | 3 +++ bot/exts/core/error_handler.py | 10 +++++++++- bot/utils/exceptions.py | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/bot/constants.py b/bot/constants.py index f4b1cab0..854fbe55 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -23,6 +23,7 @@ __all__ = ( "Reddit", "RedisConfig", "RedirectOutput", + "PYTHON_PREFIX" "MODERATION_ROLES", "STAFF_ROLES", "WHITELISTED_CHANNELS", @@ -34,6 +35,8 @@ __all__ = ( log = logging.getLogger(__name__) +PYTHON_PREFIX = "!" + @dataclasses.dataclass class AdventOfCodeLeaderboard: id: str diff --git a/bot/exts/core/error_handler.py b/bot/exts/core/error_handler.py index fd2123e7..676a1e70 100644 --- a/bot/exts/core/error_handler.py +++ b/bot/exts/core/error_handler.py @@ -12,7 +12,7 @@ from sentry_sdk import push_scope from bot.bot import Bot from bot.constants import Channels, Colours, ERROR_REPLIES, NEGATIVE_REPLIES, RedirectOutput from bot.utils.decorators import InChannelCheckFailure, InMonthCheckFailure -from bot.utils.exceptions import APIError, UserNotPlayingError +from bot.utils.exceptions import APIError, MovedCommandError, UserNotPlayingError log = logging.getLogger(__name__) @@ -130,6 +130,14 @@ class CommandErrorHandler(commands.Cog): ) return + if isinstance(error, MovedCommandError): + description = ( + f"This command, `{ctx.prefix}{ctx.command.qualified_name}` has moved to `{error.new_command_name}`.\n" + f"Please use `{error.new_command_name}` instead." + ) + await ctx.send(embed=self.error_embed(description, NEGATIVE_REPLIES)) + return + with push_scope() as scope: scope.user = { "id": ctx.author.id, diff --git a/bot/utils/exceptions.py b/bot/utils/exceptions.py index bf0e5813..3cd96325 100644 --- a/bot/utils/exceptions.py +++ b/bot/utils/exceptions.py @@ -15,3 +15,10 @@ class APIError(Exception): self.api = api self.status_code = status_code self.error_msg = error_msg + + +class MovedCommandError(Exception): + """Raised when a command has moved locations.""" + + def __init__(self, new_command_name: str): + self.new_command_name = new_command_name -- cgit v1.2.3 From c7f62d3d63b4fe84c8f96bf38b66198838fdb538 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Fri, 3 Dec 2021 17:28:39 -0500 Subject: yank lovefest role management commands --- bot/exts/holidays/valentines/be_my_valentine.py | 31 +++++++++---------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/bot/exts/holidays/valentines/be_my_valentine.py b/bot/exts/holidays/valentines/be_my_valentine.py index 4d454c3a..a9a4731f 100644 --- a/bot/exts/holidays/valentines/be_my_valentine.py +++ b/bot/exts/holidays/valentines/be_my_valentine.py @@ -7,14 +7,17 @@ import discord from discord.ext import commands from bot.bot import Bot -from bot.constants import Channels, Colours, Lovefest, Month +from bot.constants import Channels, Colours, Lovefest, Month, PYTHON_PREFIX from bot.utils.decorators import in_month +from bot.utils.exceptions import MovedCommandError from bot.utils.extensions import invoke_help_command log = logging.getLogger(__name__) HEART_EMOJIS = [":heart:", ":gift_heart:", ":revolving_hearts:", ":sparkling_heart:", ":two_hearts:"] +MOVED_COMMAND = f"{PYTHON_PREFIX}subscribe" + class BeMyValentine(commands.Cog): """A cog that sends Valentines to other users!""" @@ -30,7 +33,7 @@ class BeMyValentine(commands.Cog): return loads(p.read_text("utf8")) @in_month(Month.FEBRUARY) - @commands.group(name="lovefest") + @commands.group(name="lovefest", help=f"This command has been moved to {MOVED_COMMAND}") async def lovefest_role(self, ctx: commands.Context) -> None: """ Subscribe or unsubscribe from the lovefest role. @@ -43,27 +46,15 @@ class BeMyValentine(commands.Cog): if not ctx.invoked_subcommand: await invoke_help_command(ctx) - @lovefest_role.command(name="sub") + @lovefest_role.command(name="sub", help=f"This command has been moved to {MOVED_COMMAND}") async def add_role(self, ctx: commands.Context) -> None: - """Adds the lovefest role.""" - user = ctx.author - role = ctx.guild.get_role(Lovefest.role_id) - if role not in ctx.author.roles: - await user.add_roles(role) - await ctx.send("The Lovefest role has been added !") - else: - await ctx.send("You already have the role !") + """NOTE: This command has been moved to bot.""" + raise MovedCommandError(MOVED_COMMAND) - @lovefest_role.command(name="unsub") + @lovefest_role.command(name="unsub", help=f"This command has been moved to {MOVED_COMMAND}") async def remove_role(self, ctx: commands.Context) -> None: - """Removes the lovefest role.""" - user = ctx.author - role = ctx.guild.get_role(Lovefest.role_id) - if role not in ctx.author.roles: - await ctx.send("You dont have the lovefest role.") - else: - await user.remove_roles(role) - await ctx.send("The lovefest role has been successfully removed!") + """NOTE: This command has been moved to bot.""" + raise MovedCommandError(MOVED_COMMAND) @commands.cooldown(1, 1800, commands.BucketType.user) @commands.group(name="bemyvalentine", invoke_without_command=True) -- cgit v1.2.3 From 2d0760821b629bcb3269534ed46c0a9af4026264 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Fri, 3 Dec 2021 17:19:57 -0500 Subject: chore: remove subcommands entirely --- bot/exts/holidays/valentines/be_my_valentine.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/bot/exts/holidays/valentines/be_my_valentine.py b/bot/exts/holidays/valentines/be_my_valentine.py index a9a4731f..1e13e424 100644 --- a/bot/exts/holidays/valentines/be_my_valentine.py +++ b/bot/exts/holidays/valentines/be_my_valentine.py @@ -10,7 +10,6 @@ from bot.bot import Bot from bot.constants import Channels, Colours, Lovefest, Month, PYTHON_PREFIX from bot.utils.decorators import in_month from bot.utils.exceptions import MovedCommandError -from bot.utils.extensions import invoke_help_command log = logging.getLogger(__name__) @@ -33,7 +32,7 @@ class BeMyValentine(commands.Cog): return loads(p.read_text("utf8")) @in_month(Month.FEBRUARY) - @commands.group(name="lovefest", help=f"This command has been moved to {MOVED_COMMAND}") + @commands.command(name="lovefest", help=f"NOTE: This command has been moved to {MOVED_COMMAND}") async def lovefest_role(self, ctx: commands.Context) -> None: """ Subscribe or unsubscribe from the lovefest role. @@ -43,17 +42,6 @@ class BeMyValentine(commands.Cog): 1) use the command \".lovefest sub\" to get the lovefest role. 2) use the command \".lovefest unsub\" to get rid of the lovefest role. """ - if not ctx.invoked_subcommand: - await invoke_help_command(ctx) - - @lovefest_role.command(name="sub", help=f"This command has been moved to {MOVED_COMMAND}") - async def add_role(self, ctx: commands.Context) -> None: - """NOTE: This command has been moved to bot.""" - raise MovedCommandError(MOVED_COMMAND) - - @lovefest_role.command(name="unsub", help=f"This command has been moved to {MOVED_COMMAND}") - async def remove_role(self, ctx: commands.Context) -> None: - """NOTE: This command has been moved to bot.""" raise MovedCommandError(MOVED_COMMAND) @commands.cooldown(1, 1800, commands.BucketType.user) -- cgit v1.2.3 From cfb2cc69287f0aefab0937d0e8e8f99811d50948 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Fri, 3 Dec 2021 18:26:33 -0500 Subject: chore: update lovefest docstring to reflect deprecation --- bot/exts/holidays/valentines/be_my_valentine.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bot/exts/holidays/valentines/be_my_valentine.py b/bot/exts/holidays/valentines/be_my_valentine.py index 1e13e424..1572d474 100644 --- a/bot/exts/holidays/valentines/be_my_valentine.py +++ b/bot/exts/holidays/valentines/be_my_valentine.py @@ -35,12 +35,9 @@ class BeMyValentine(commands.Cog): @commands.command(name="lovefest", help=f"NOTE: This command has been moved to {MOVED_COMMAND}") async def lovefest_role(self, ctx: commands.Context) -> None: """ - Subscribe or unsubscribe from the lovefest role. + Deprecated lovefest role command. - The lovefest role makes you eligible to receive anonymous valentines from other users. - - 1) use the command \".lovefest sub\" to get the lovefest role. - 2) use the command \".lovefest unsub\" to get rid of the lovefest role. + This command has been moved to bot, and will be removed in the future. """ raise MovedCommandError(MOVED_COMMAND) -- cgit v1.2.3 From 846c34fd8988eaede08186fa9fb342213dc85585 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 18:46:39 -0500 Subject: Remove unneeded check and add comments Removes the unneeded check for if the cache is empty. Also adds a seconds comment about the format of the contents of the Redis cache. --- bot/exts/events/advent_of_code/_cog.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 1b1cd9f8..8d87b5bc 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -30,6 +30,7 @@ AOC_WHITELIST = AOC_WHITELIST_RESTRICTED + (Channels.advent_of_code,) class AdventOfCode(commands.Cog): """Advent of Code festivities! Ho Ho Ho!""" + # Redis Cache for linking Discord IDs to Advent of Code usernames account_links = RedisCache() def __init__(self, bot: Bot): @@ -186,23 +187,9 @@ class AdventOfCode(commands.Cog): """ Link your Discord Account to your Advent of Code name. - Stored in a Redis Cache, Discord ID: Advent of Code Name + Stored in a Redis Cache with the format of `Discord ID: Advent of Code Name` """ cache_items = await self.account_links.items() - - # A short circuit in case the cache is empty - if len(cache_items) == 0 and aoc_name: - log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") - await self.account_links.set(ctx.author.id, aoc_name) - await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") - return - elif len(cache_items) == 0: - await ctx.reply( - "You have not linked an Advent of Code account." - "Please re-run the command with one specified." - ) - return - cache_aoc_name = [value for _, value in cache_items] if aoc_name: -- cgit v1.2.3 From 1ac965f67fea8e5dd0e0f026aca27e3368f4e44e Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 20:50:17 -0500 Subject: Add unlink AoC command Adds the ability for the user to unlink their advent of code name. It will delete the entry in the cache if it exists. --- bot/exts/events/advent_of_code/_cog.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 8d87b5bc..7f904f6b 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -228,6 +228,27 @@ class AdventOfCode(commands.Cog): " Please re-run the command with one specified." ) + @in_month(Month.NOVEMBER, Month.DECEMBER) + @adventofcode_group.command( + name="unlink", + aliases=("disconnect",), + brief="Tie your Discord account with your Advent of Code name." + ) + @whitelist_override(channels=AOC_WHITELIST) + async def aoc_unlink_account(self, ctx: commands.Context) -> None: + """ + Unlink your Discord ID with your Advent of Code leaderboard name. + + Deletes the entry that was Stored in the Redis cache. + """ + if aoc_cache_name := await self.account_links.get(ctx.author.id): + log.info(f"Unlinking {ctx.author} ({ctx.author.id}) from Advent of Code account {aoc_cache_name}") + await self.account_links.delete(ctx.author.id) + await ctx.reply(f"We have removed the link between your Discord ID and {aoc_cache_name}.") + else: + log.info(f"Attempted to unlink {ctx.author} ({ctx.author.id}), but not link was found.") + await ctx.reply("You don't have an Advent of Code account linked.") + @in_month(Month.DECEMBER) @adventofcode_group.command( name="dayandstar", -- cgit v1.2.3 From 00e3fe5bede6f8310405e143179530df0ad3ca95 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 20:53:59 -0500 Subject: Adjust wording on log statements to present tense --- bot/exts/events/advent_of_code/_cog.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 7f904f6b..b7d26cb9 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -210,12 +210,12 @@ class AdventOfCode(commands.Cog): # Update an existing link if old_aoc_name := await self.account_links.get(ctx.author.id): - log.info(f"{ctx.author} ({ctx.author.id}) has changed their link from {old_aoc_name} to {aoc_name}.") + log.info(f"Changing link for{ctx.author} ({ctx.author.id}) from {old_aoc_name} to {aoc_name}.") await self.account_links.set(ctx.author.id, aoc_name) await ctx.reply(f"Your linked account has been changed to {aoc_name}.") else: # Create a new link - log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") + log.info(f"Linking {ctx.author} ({ctx.author.id}) to account {aoc_name}.") await self.account_links.set(ctx.author.id, aoc_name) await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") else: @@ -246,7 +246,7 @@ class AdventOfCode(commands.Cog): await self.account_links.delete(ctx.author.id) await ctx.reply(f"We have removed the link between your Discord ID and {aoc_cache_name}.") else: - log.info(f"Attempted to unlink {ctx.author} ({ctx.author.id}), but not link was found.") + log.info(f"Attempted to unlink {ctx.author} ({ctx.author.id}), but no link was found.") await ctx.reply("You don't have an Advent of Code account linked.") @in_month(Month.DECEMBER) -- cgit v1.2.3 From b3a7c79ffb1f4220bad8ca3814d594a9b1b00826 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 21:02:28 -0500 Subject: Make aoc_name a keyword arguemnt to accept spaces Makes `aoc_name` in the link command a keyword only argument. This allows users to link accounts with spaces in the name without having to use quotes. --- bot/exts/events/advent_of_code/_cog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index b7d26cb9..55fd0ac6 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -183,7 +183,7 @@ class AdventOfCode(commands.Cog): brief="Tie your Discord account with your Advent of Code name." ) @whitelist_override(channels=AOC_WHITELIST) - async def aoc_link_account(self, ctx: commands.Context, aoc_name: str = None) -> None: + async def aoc_link_account(self, ctx: commands.Context, *, aoc_name: str = None) -> None: """ Link your Discord Account to your Advent of Code name. -- cgit v1.2.3 From b134010e1682a40d2aa9e3ce893c274388896680 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 21:29:01 -0500 Subject: Adjust `.aoc lb` to use linked account in cache If the user has not supplied a name to use for the leaderboard, then code will check if they have an account linked. If they do, it will use the linked account in the leaderboard to show placement. --- bot/exts/events/advent_of_code/_cog.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 16176c69..49b604ab 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -311,6 +311,10 @@ class AdventOfCode(commands.Cog): if aoc_name and aoc_name.startswith('"') and aoc_name.endswith('"'): aoc_name = aoc_name[1:-1] + # Check if an advent of code account is linked in the Redis Cache if aoc_name is not given + if (aoc_cache_name := await self.account_links.get(ctx.author.id)) and aoc_name is None: + aoc_name = aoc_cache_name + async with ctx.typing(): try: leaderboard = await _helpers.fetch_leaderboard(self_placement_name=aoc_name) @@ -321,7 +325,7 @@ class AdventOfCode(commands.Cog): number_of_participants = leaderboard["number_of_participants"] top_count = min(AocConfig.leaderboard_displayed_members, number_of_participants) - self_placement_header = "(and your personal stats compared to the top 10)" if aoc_name else "" + self_placement_header = " (and your personal stats compared to the top 10)" if aoc_name else "" header = f"Here's our current top {top_count}{self_placement_header}! {Emojis.christmas_tree * 3}" table = "```\n" \ f"{leaderboard['placement_leaderboard'] if aoc_name else leaderboard['top_leaderboard']}" \ -- cgit v1.2.3 From f4324a0f447a7791743ce9a5c4f0957f32738b78 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Sat, 4 Dec 2021 10:55:49 -0500 Subject: Adjust variable name for clarity and add space --- bot/exts/events/advent_of_code/_cog.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 49b604ab..52254ea1 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -193,14 +193,14 @@ class AdventOfCode(commands.Cog): Stored in a Redis Cache with the format of `Discord ID: Advent of Code Name` """ cache_items = await self.account_links.items() - cache_aoc_name = [value for _, value in cache_items] + cache_aoc_names = [value for _, value in cache_items] if aoc_name: # Let's check the current values in the cache to make sure it isn't already tied to a different account if aoc_name == await self.account_links.get(ctx.author.id): await ctx.reply(f"{aoc_name} is already tied to your account.") return - elif aoc_name in cache_aoc_name: + elif aoc_name in cache_aoc_names: log.info( f"{ctx.author} ({ctx.author.id}) tried to connect their account to {aoc_name}," " but it's already connected to another user." @@ -213,7 +213,7 @@ class AdventOfCode(commands.Cog): # Update an existing link if old_aoc_name := await self.account_links.get(ctx.author.id): - log.info(f"Changing link for{ctx.author} ({ctx.author.id}) from {old_aoc_name} to {aoc_name}.") + log.info(f"Changing link for {ctx.author} ({ctx.author.id}) from {old_aoc_name} to {aoc_name}.") await self.account_links.set(ctx.author.id, aoc_name) await ctx.reply(f"Your linked account has been changed to {aoc_name}.") else: -- cgit v1.2.3 From 03b5464e6e37f625ba7a590d45120f4b46b1d0aa Mon Sep 17 00:00:00 2001 From: Janine vN Date: Sat, 4 Dec 2021 11:00:48 -0500 Subject: Add more information to `.aoc lb` error embed Advent of Code Leaderboard BadArgument error embed now mentions to join the leaderboard and to wait up to 30 minutes if you've joined recently. --- bot/exts/events/advent_of_code/_helpers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bot/exts/events/advent_of_code/_helpers.py b/bot/exts/events/advent_of_code/_helpers.py index 35258544..807cc275 100644 --- a/bot/exts/events/advent_of_code/_helpers.py +++ b/bot/exts/events/advent_of_code/_helpers.py @@ -216,6 +216,9 @@ def _format_leaderboard(leaderboard: dict[str, dict], self_placement_name: str = if self_placement_name and not self_placement_exists: raise commands.BadArgument( "Sorry, your profile does not exist in this leaderboard." + "\n\n" + "To join our leaderboard, run the command `.aoc join`." + " If you've joined recently, please wait up to 30 minutes for our leaderboard to refresh." ) return "\n".join(leaderboard_lines) -- cgit v1.2.3 From 163a6e14c22b7992f44dca699de9e71c11362613 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sun, 5 Dec 2021 13:11:03 +0000 Subject: Patch d.py's message converters to infer channelID from the given context Discord.py's message converter is supposed to infer channelID based on ctx.channel if only a messageID is given. A refactor (linked below) a few weeks before d.py's archival broke this, so that if only a messageID is given to the converter, it will only find that message if it's in the bot's cache. --- bot/__init__.py | 5 +++++ bot/monkey_patches.py | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/bot/__init__.py b/bot/__init__.py index ae53a5a5..3136c863 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -43,6 +43,11 @@ if os.name == "nt": monkey_patches.patch_typing() +# This patches any convertors that use PartialMessage, but not the PartialMessageConverter itself +# as library objects are made by this mapping. +# https://github.com/Rapptz/discord.py/blob/1a4e73d59932cdbe7bf2c281f25e32529fc7ae1f/discord/ext/commands/converter.py#L984-L1004 +commands.converter.PartialMessageConverter = monkey_patches.FixedPartialMessageConverter + # 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=monkey_patches.Command) diff --git a/bot/monkey_patches.py b/bot/monkey_patches.py index fa6627d1..19965c19 100644 --- a/bot/monkey_patches.py +++ b/bot/monkey_patches.py @@ -1,10 +1,12 @@ import logging +import re from datetime import datetime, timedelta from discord import Forbidden, http from discord.ext import commands log = logging.getLogger(__name__) +MESSAGE_ID_RE = re.compile(r'(?P[0-9]{15,20})$') class Command(commands.Command): @@ -65,3 +67,25 @@ def patch_typing() -> None: pass http.HTTPClient.send_typing = honeybadger_type + + +class FixedPartialMessageConverter(commands.PartialMessageConverter): + """ + Make the Message converter infer channelID from the given context if only a messageID is given. + + Discord.py's Message converter is supposed to infer channelID based + on ctx.channel if only a messageID is given. A refactor commit, linked below, + a few weeks before d.py's archival broke this defined behaviour of the converter. + Currently, if only a messageID is given to the converter, it will only find that message + if it's in the bot's cache. + + https://github.com/Rapptz/discord.py/commit/1a4e73d59932cdbe7bf2c281f25e32529fc7ae1f + """ + + @staticmethod + def _get_id_matches(ctx: commands.Context, argument: str) -> tuple[int, int, int]: + """Inserts ctx.channel.id before calling super method if argument is just a messageID.""" + match = MESSAGE_ID_RE.match(argument) + if match: + argument = f"{ctx.channel.id}-{match.group('message_id')}" + return commands.PartialMessageConverter._get_id_matches(ctx, argument) -- cgit v1.2.3 From 598cf151cfaaa8e6777cd602714c10666ad45b4a Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sun, 5 Dec 2021 13:12:41 +0000 Subject: Reflect new message converter behaviour in bm help message Since w epatched the message converter to work as intended, the help message given to a user when failing to resolve a message reference to a message object has been updated. --- bot/exts/utilities/bookmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py index a11c366b..b50205a0 100644 --- a/bot/exts/utilities/bookmark.py +++ b/bot/exts/utilities/bookmark.py @@ -102,7 +102,7 @@ class Bookmark(commands.Cog): "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)" + "\n2. Lookup by message ID (the message **must** be in the context channel)" "\n3. Lookup by message URL" ) target_message = ctx.message.reference.resolved -- cgit v1.2.3 From 61e264bb39be551b4c5d083206df0bc2b09d1c10 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Fri, 10 Dec 2021 13:47:17 +0100 Subject: Remove myself from the codeowners --- .github/CODEOWNERS | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cffe15d5..d164ad04 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,10 +4,6 @@ bot/exts/events/hacktoberfest/** @ks129 bot/exts/holidays/halloween/** @ks129 # CI & Docker -.github/workflows/** @Akarys42 @SebastiaanZ @Den4200 -Dockerfile @Akarys42 @Den4200 -docker-compose.yml @Akarys42 @Den4200 - -# Tools -poetry.lock @Akarys42 -pyproject.toml @Akarys42 +.github/workflows/** @SebastiaanZ @Den4200 +Dockerfile @Den4200 +docker-compose.yml @Den4200 -- cgit v1.2.3 From 70b9ec7dbdc346e7ddcac7624968424cf0e66ef6 Mon Sep 17 00:00:00 2001 From: evgriff Date: Fri, 10 Dec 2021 19:09:31 +0000 Subject: Added the user's score to Candy Command according to #947 --- bot/exts/holidays/halloween/candy_collection.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py index bb9c93be..6edce1a0 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -173,6 +173,7 @@ class CandyCollection(commands.Cog): async def candy(self, ctx: commands.Context) -> None: """Get the candy leaderboard and save to JSON.""" records = await self.candy_records.items() + user = await self.bot.fetch_user(ctx.author.id) def generate_leaderboard() -> str: top_sorted = sorted( @@ -187,12 +188,23 @@ class CandyCollection(commands.Cog): for index, record in enumerate(top_five) ) if top_five else "No Candies" + def get_user_candy_score() -> str: + for user_id, score in records: + if user_id == user.id: + return f'<@{user.id}>: {score}' + return f'<@{user.id}>: 0' + e = discord.Embed(colour=discord.Colour.og_blurple()) e.add_field( name="Top Candy Records", value=generate_leaderboard(), inline=False ) + e.add_field( + name=f'{user.name}' + "'s Candy Score", + value=get_user_candy_score(), + inline=False + ) e.add_field( name="\u200b", value="Candies will randomly appear on messages sent. " -- cgit v1.2.3 From bcd47e1a0642dcc7c538d86d29c8311aed828bf5 Mon Sep 17 00:00:00 2001 From: evgriff Date: Fri, 10 Dec 2021 20:15:45 +0000 Subject: added key check --- bot/exts/utilities/issues.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/utilities/issues.py b/bot/exts/utilities/issues.py index b6d5a43e..b3f8340c 100644 --- a/bot/exts/utilities/issues.py +++ b/bot/exts/utilities/issues.py @@ -139,7 +139,7 @@ class Issues(commands.Cog): log.trace(f"PR provided, querying GH pulls API for additional information: {pulls_url}") async with self.bot.http_session.get(pulls_url) as p: pull_data = await p.json() - if pull_data["draft"]: + if "draft" in pull_data and pull_data["draft"]: emoji = Emojis.pull_request_draft elif pull_data["state"] == "open": emoji = Emojis.pull_request_open -- cgit v1.2.3 From f32b52791926249ea9ae5d3f2dbffce26569e827 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Dec 2021 20:58:47 +0000 Subject: chore(deps): bump lxml from 4.6.4 to 4.6.5 Bumps [lxml](https://github.com/lxml/lxml) from 4.6.4 to 4.6.5. - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](https://github.com/lxml/lxml/compare/lxml-4.6.4...lxml-4.6.5) --- updated-dependencies: - dependency-name: lxml dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- poetry.lock | 125 +++++++++++++++++++++++++++++---------------------------- pyproject.toml | 2 +- 2 files changed, 64 insertions(+), 63 deletions(-) diff --git a/poetry.lock b/poetry.lock index e02c2baa..5e950343 100644 --- a/poetry.lock +++ b/poetry.lock @@ -199,6 +199,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.3" @@ -418,7 +419,7 @@ python-versions = ">=3.7" [[package]] name = "lxml" -version = "4.6.4" +version = "4.6.5" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." category = "main" optional = false @@ -851,7 +852,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "c370c87b0425b330845ef1aad9cead2c3c3f9db7be95895895ac96fc3a2d28a6" +content-hash = "b091f392619f058d265309c9474d9d2b86f53f634017210cca11713cdb11ae14" [metadata.files] aiodns = [ @@ -1159,66 +1160,66 @@ kiwisolver = [ {file = "kiwisolver-1.3.2.tar.gz", hash = "sha256:fc4453705b81d03568d5b808ad8f09c77c47534f6ac2e72e733f9ca4714aa75c"}, ] lxml = [ - {file = "lxml-4.6.4-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bbf2dc330bd44bfc0254ab37677ec60f7c7ecea55ad8ba1b8b2ea7bf20c265f5"}, - {file = "lxml-4.6.4-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b667c51682fe9b9788c69465956baa8b6999531876ccedcafc895c74ad716cd8"}, - {file = "lxml-4.6.4-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:72e730d33fe2e302fd07285f14624fca5e5e2fb2bb4fb2c3941e318c41c443d1"}, - {file = "lxml-4.6.4-cp27-cp27m-win32.whl", hash = "sha256:433df8c7dde0f9e41cbf4f36b0829d50a378116ef5e962ba3881f2f5f025c7be"}, - {file = "lxml-4.6.4-cp27-cp27m-win_amd64.whl", hash = "sha256:35752ee40f7bbf6adc9ff4e1f4b84794a3593736dcce80db32e3c2aa85e294ac"}, - {file = "lxml-4.6.4-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ff5bb2a198ea67403bb6818705e9a4f90e0313f2215428ec51001ce56d939fb"}, - {file = "lxml-4.6.4-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9b87727561c1150c0cc91c5d9d389448b37a7d15f0ba939ed3d1acb2f11bf6c5"}, - {file = "lxml-4.6.4-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:45fdb2899c755138722797161547a40b3e2a06feda620cc41195ee7e97806d81"}, - {file = "lxml-4.6.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:38b9de0de3aa689fe9fb9877ae1be1e83b8cf9621f7e62049d0436b9ecf4ad64"}, - {file = "lxml-4.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:662523cd2a0246740225c7e32531f2e766544122e58bee70e700a024cfc0cf81"}, - {file = "lxml-4.6.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:4aa349c5567651f34d4eaae7de6ed5b523f6d70a288f9c6fbac22d13a0784e04"}, - {file = "lxml-4.6.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:08eb9200d88b376a8ed5e50f1dc1d1a45b49305169674002a3b5929943390591"}, - {file = "lxml-4.6.4-cp310-cp310-win32.whl", hash = "sha256:bdc224f216ead849e902151112efef6e96c41ee1322e15d4e5f7c8a826929aee"}, - {file = "lxml-4.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:ab6db93a2b6b66cbf62b4e4a7135f476e708e8c5c990d186584142c77d7f975a"}, - {file = "lxml-4.6.4-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50790313df028aa05cf22be9a8da033b86c42fa32523e4fd944827b482b17bf0"}, - {file = "lxml-4.6.4-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6764998345552b1dfc9326a932d2bad6367c6b37a176bb73ada6b9486bf602f7"}, - {file = "lxml-4.6.4-cp35-cp35m-win32.whl", hash = "sha256:543b239b191bb3b6d9bef5f09f1fb2be5b7eb09ab4d386aa655e4d53fbe9ff47"}, - {file = "lxml-4.6.4-cp35-cp35m-win_amd64.whl", hash = "sha256:a75c1ad05eedb1a3ff2a34a52a4f0836cfaa892e12796ba39a7732c82701eff4"}, - {file = "lxml-4.6.4-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:47e955112ce64241fdb357acf0216081f9f3255b3ac9c502ca4b3323ec1ca558"}, - {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:20d7c8d90d449c6a353b15ee0459abae8395dbe59ad01e406ccbf30cd81c6f98"}, - {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:240db6f3228d26e3c6f4fad914b9ddaaf8707254e8b3efd564dc680c8ec3c264"}, - {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:351482da8dd028834028537f08724b1de22d40dcf3bb723b469446564f409074"}, - {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e678a643177c0e5ec947b645fa7bc84260dfb9b6bf8fb1fdd83008dfc2ca5928"}, - {file = "lxml-4.6.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:15d0381feb56f08f78c5cc4fc385ddfe0bde1456e37f54a9322833371aec4060"}, - {file = "lxml-4.6.4-cp36-cp36m-win32.whl", hash = "sha256:4ba74afe5ee5cb5e28d83b513a6e8f0875fda1dc1a9aea42cc0065f029160d2a"}, - {file = "lxml-4.6.4-cp36-cp36m-win_amd64.whl", hash = "sha256:9c91a73971a922c13070fd8fa5a114c858251791ba2122a941e6aa781c713e44"}, - {file = "lxml-4.6.4-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:6020c70ff695106bf80651953a23e37718ef1fee9abd060dcad8e32ab2dc13f3"}, - {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f5dd358536b8a964bf6bd48de038754c1609e72e5f17f5d21efe2dda17594dbf"}, - {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7ae7089d81fc502df4b217ad77f03c54039fe90dac0acbe70448d7e53bfbc57e"}, - {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:80d10d53d3184837445ff8562021bdd37f57c4cadacbf9d8726cc16220a00d54"}, - {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e95da348d57eb448d226a44b868ff2ca5786fbcbe417ac99ff62d0a7d724b9c7"}, - {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ffd65cfa33fed01735c82aca640fde4cc63f0414775cba11e06f84fae2085a6e"}, - {file = "lxml-4.6.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:877666418598f6cb289546c77ff87590cfd212f903b522b0afa0b9fb73b3ccfb"}, - {file = "lxml-4.6.4-cp37-cp37m-win32.whl", hash = "sha256:e91d24623e747eeb2d8121f4a94c6a7ad27dc48e747e2dc95bfe88632bd028a2"}, - {file = "lxml-4.6.4-cp37-cp37m-win_amd64.whl", hash = "sha256:4ec9a80dd5704ecfde54319b6964368daf02848c8954d3bacb9b64d1c7659159"}, - {file = "lxml-4.6.4-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:2901625f4a878a055d275beedc20ba9cb359cefc4386a967222fee29eb236038"}, - {file = "lxml-4.6.4-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b567178a74a2261345890eac66fbf394692a6e002709d329f28a673ca6042473"}, - {file = "lxml-4.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4717123f7c11c81e0da69989e5a64079c3f402b0efeb4c6241db6c369d657bd8"}, - {file = "lxml-4.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:cf201bf5594d1aab139fe53e3fca457e4f8204a5bbd65d48ab3b82a16f517868"}, - {file = "lxml-4.6.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a77a3470ba37e11872c75ca95baf9b3312133a3d5a5dc720803b23098c653976"}, - {file = "lxml-4.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:619c6d2b552bba00491e96c0518aad94002651c108a0f7364ff2d7798812c00e"}, - {file = "lxml-4.6.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:601f0ab75538b280aaf1e720eb9d68d4fa104ac274e1e9e6971df488f4dcdb0f"}, - {file = "lxml-4.6.4-cp38-cp38-win32.whl", hash = "sha256:75d3c5bbc0ddbad03bb68b9be638599f67e4b98ed3dcd0fec9f6f39e41ee96cb"}, - {file = "lxml-4.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:4341d135f5660db10184963d9c3418c3e28d7f868aaf8b11a323ebf85813f7f4"}, - {file = "lxml-4.6.4-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:9db24803fa71e3305fe4a7812782b708da21a0b774b130dd1860cf40a6d7a3ee"}, - {file = "lxml-4.6.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:afd60230ad9d8bcba005945ec3a343722f09e0b7f8ae804246e5d2cfc6bd71a6"}, - {file = "lxml-4.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:0c15e1cd55055956e77b0732270f1c6005850696bc3ef3e03d01e78af84eaa42"}, - {file = "lxml-4.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d422b3c729737d8a39279a25fa156c983a56458f8b2f97661ee6fb22b80b1d6"}, - {file = "lxml-4.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2eb90f6ec3c236ef2f1bb38aee7c0d23e77d423d395af6326e7cca637519a4cb"}, - {file = "lxml-4.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:51a0e5d243687596f46e24e464121d4b232ad772e2d1785b2a2c0eb413c285d4"}, - {file = "lxml-4.6.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d43bd68714049c84e297c005456a15ecdec818f7b5aa5868c8b0a865cfb78a44"}, - {file = "lxml-4.6.4-cp39-cp39-win32.whl", hash = "sha256:ee9e4b07b0eba4b6a521509e9e1877476729c1243246b6959de697ebea739643"}, - {file = "lxml-4.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:48eaac2991b3036175b42ee8d3c23f4cca13f2be8426bf29401a690ab58c88f4"}, - {file = "lxml-4.6.4-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:2b06a91cf7b8acea7793006e4ae50646cef0fe35ce5acd4f5cb1c77eb228e4a1"}, - {file = "lxml-4.6.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:523f195948a1ba4f9f5b7294d83c6cd876547dc741820750a7e5e893a24bbe38"}, - {file = "lxml-4.6.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b0ca0ada9d3bc18bd6f611bd001a28abdd49ab9698bd6d717f7f5394c8e94628"}, - {file = "lxml-4.6.4-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:197b7cb7a753cf553a45115739afd8458464a28913da00f5c525063f94cd3f48"}, - {file = "lxml-4.6.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:6298f5b42a26581206ef63fffa97c754245d329414108707c525512a5197f2ba"}, - {file = "lxml-4.6.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0b12c95542f04d10cba46b3ff28ea52ea56995b78cf918f0b11b05e75812bb79"}, - {file = "lxml-4.6.4.tar.gz", hash = "sha256:daf9bd1fee31f1c7a5928b3e1059e09a8d683ea58fb3ffc773b6c88cb8d1399c"}, + {file = "lxml-4.6.5-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:abcf7daa5ebcc89328326254f6dd6d566adb483d4d00178892afd386ab389de2"}, + {file = "lxml-4.6.5-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3884476a90d415be79adfa4e0e393048630d0d5bcd5757c4c07d8b4b00a1096b"}, + {file = "lxml-4.6.5-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:add017c5bd6b9ec3a5f09248396b6ee2ce61c5621f087eb2269c813cd8813808"}, + {file = "lxml-4.6.5-cp27-cp27m-win32.whl", hash = "sha256:a702005e447d712375433ed0499cb6e1503fadd6c96a47f51d707b4d37b76d3c"}, + {file = "lxml-4.6.5-cp27-cp27m-win_amd64.whl", hash = "sha256:da07c7e7fc9a3f40446b78c54dbba8bfd5c9100dfecb21b65bfe3f57844f5e71"}, + {file = "lxml-4.6.5-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a708c291900c40a7ecf23f1d2384ed0bc0604e24094dd13417c7e7f8f7a50d93"}, + {file = "lxml-4.6.5-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f33d8efb42e4fc2b31b3b4527940b25cdebb3026fb56a80c1c1c11a4271d2352"}, + {file = "lxml-4.6.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:f6befb83bca720b71d6bd6326a3b26e9496ae6649e26585de024890fe50f49b8"}, + {file = "lxml-4.6.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:59d77bfa3bea13caee95bc0d3f1c518b15049b97dd61ea8b3d71ce677a67f808"}, + {file = "lxml-4.6.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:68a851176c931e2b3de6214347b767451243eeed3bea34c172127bbb5bf6c210"}, + {file = "lxml-4.6.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7790a273225b0c46e5f859c1327f0f659896cc72eaa537d23aa3ad9ff2a1cc1"}, + {file = "lxml-4.6.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6548fc551de15f310dd0564751d9dc3d405278d45ea9b2b369ed1eccf142e1f5"}, + {file = "lxml-4.6.5-cp310-cp310-win32.whl", hash = "sha256:dc8a0dbb2a10ae8bb609584f5c504789f0f3d0d81840da4849102ec84289f952"}, + {file = "lxml-4.6.5-cp310-cp310-win_amd64.whl", hash = "sha256:1ccbfe5d17835db906f2bab6f15b34194db1a5b07929cba3cf45a96dbfbfefc0"}, + {file = "lxml-4.6.5-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca9a40497f7e97a2a961c04fa8a6f23d790b0521350a8b455759d786b0bcb203"}, + {file = "lxml-4.6.5-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e5b4b0d9440046ead3bd425eb2b852499241ee0cef1ae151038e4f87ede888c4"}, + {file = "lxml-4.6.5-cp35-cp35m-win32.whl", hash = "sha256:87f8f7df70b90fbe7b49969f07b347e3f978f8bd1046bb8ecae659921869202b"}, + {file = "lxml-4.6.5-cp35-cp35m-win_amd64.whl", hash = "sha256:ce52aad32ec6e46d1a91ff8b8014a91538800dd533914bfc4a82f5018d971408"}, + {file = "lxml-4.6.5-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:8021eeff7fabde21b9858ed058a8250ad230cede91764d598c2466b0ba70db8b"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:cab343b265e38d4e00649cbbad9278b734c5715f9bcbb72c85a1f99b1a58e19a"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3534d7c468c044f6aef3c0aff541db2826986a29ea73f2ca831f5d5284d9b570"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdb98f4c9e8a1735efddfaa995b0c96559792da15d56b76428bdfc29f77c4cdb"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5ea121cb66d7e5cb396b4c3ca90471252b94e01809805cfe3e4e44be2db3a99c"}, + {file = "lxml-4.6.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:121fc6f71c692b49af6c963b84ab7084402624ffbe605287da362f8af0668ea3"}, + {file = "lxml-4.6.5-cp36-cp36m-win32.whl", hash = "sha256:1a2a7659b8eb93c6daee350a0d844994d49245a0f6c05c747f619386fb90ba04"}, + {file = "lxml-4.6.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2f77556266a8fe5428b8759fbfc4bd70be1d1d9c9b25d2a414f6a0c0b0f09120"}, + {file = "lxml-4.6.5-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:558485218ee06458643b929765ac1eb04519ca3d1e2dcc288517de864c747c33"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ba0006799f21d83c3717fe20e2707a10bbc296475155aadf4f5850f6659b96b9"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:916d457ad84e05b7db52700bad0a15c56e0c3000dcaf1263b2fb7a56fe148996"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c580c2a61d8297a6e47f4d01f066517dbb019be98032880d19ece7f337a9401d"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a21b78af7e2e13bec6bea12fc33bc05730197674f3e5402ce214d07026ccfebd"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:46515773570a33eae13e451c8fcf440222ef24bd3b26f40774dd0bd8b6db15b2"}, + {file = "lxml-4.6.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:124f09614f999551ac65e5b9875981ce4b66ac4b8e2ba9284572f741935df3d9"}, + {file = "lxml-4.6.5-cp37-cp37m-win32.whl", hash = "sha256:b4015baed99d046c760f09a4c59d234d8f398a454380c3cf0b859aba97136090"}, + {file = "lxml-4.6.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12ae2339d32a2b15010972e1e2467345b7bf962e155671239fba74c229564b7f"}, + {file = "lxml-4.6.5-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:76b6c296e4f7a1a8a128aec42d128646897f9ae9a700ef6839cdc9b3900db9b5"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:534032a5ceb34bba1da193b7d386ac575127cc39338379f39a164b10d97ade89"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:60aeb14ff9022d2687ef98ce55f6342944c40d00916452bb90899a191802137a"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9801bcd52ac9c795a7d81ea67471a42cffe532e46cfb750cd5713befc5c019c0"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3b95fb7e6f9c2f53db88f4642231fc2b8907d854e614710996a96f1f32018d5c"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:642eb4cabd997c9b949a994f9643cd8ae00cf4ca8c5cd9c273962296fadf1c44"}, + {file = "lxml-4.6.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:af4139172ff0263d269abdcc641e944c9de4b5d660894a3ec7e9f9db63b56ac9"}, + {file = "lxml-4.6.5-cp38-cp38-win32.whl", hash = "sha256:57cf05466917e08f90e323f025b96f493f92c0344694f5702579ab4b7e2eb10d"}, + {file = "lxml-4.6.5-cp38-cp38-win_amd64.whl", hash = "sha256:4f415624cf8b065796649a5e4621773dc5c9ea574a944c76a7f8a6d3d2906b41"}, + {file = "lxml-4.6.5-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7679bb6e4d9a3978a46ab19a3560e8d2b7265ef3c88152e7fdc130d649789887"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c34234a1bc9e466c104372af74d11a9f98338a3f72fae22b80485171a64e0144"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4b9390bf973e3907d967b75be199cf1978ca8443183cf1e78ad80ad8be9cf242"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fcc849b28f584ed1dbf277291ded5c32bb3476a37032df4a1d523b55faa5f944"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:46f21f2600d001af10e847df9eb3b832e8a439f696c04891bcb8a8cedd859af9"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:99cf827f5a783038eb313beee6533dddb8bdb086d7269c5c144c1c952d142ace"}, + {file = "lxml-4.6.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:925174cafb0f1179a7fd38da90302555d7445e34c9ece68019e53c946be7f542"}, + {file = "lxml-4.6.5-cp39-cp39-win32.whl", hash = "sha256:12d8d6fe3ddef629ac1349fa89a638b296a34b6529573f5055d1cb4e5245f73b"}, + {file = "lxml-4.6.5-cp39-cp39-win_amd64.whl", hash = "sha256:a52e8f317336a44836475e9c802f51c2dc38d612eaa76532cb1d17690338b63b"}, + {file = "lxml-4.6.5-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:11ae552a78612620afd15625be9f1b82e3cc2e634f90d6b11709b10a100cba59"}, + {file = "lxml-4.6.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:473701599665d874919d05bb33b56180447b3a9da8d52d6d9799f381ce23f95c"}, + {file = "lxml-4.6.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7f00cc64b49d2ef19ddae898a3def9dd8fda9c3d27c8a174c2889ee757918e71"}, + {file = "lxml-4.6.5-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:73e8614258404b2689a26cb5d002512b8bc4dfa18aca86382f68f959aee9b0c8"}, + {file = "lxml-4.6.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ff44de36772b05c2eb74f2b4b6d1ae29b8f41ed5506310ce1258d44826ee38c1"}, + {file = "lxml-4.6.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5d5254c815c186744c8f922e2ce861a2bdeabc06520b4b30b2f7d9767791ce6e"}, + {file = "lxml-4.6.5.tar.gz", hash = "sha256:6e84edecc3a82f90d44ddee2ee2a2630d4994b8471816e226d2b771cda7ac4ca"}, ] matplotlib = [ {file = "matplotlib-3.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c988bb43414c7c2b0a31bd5187b4d27fd625c080371b463a6d422047df78913"}, diff --git a/pyproject.toml b/pyproject.toml index 71c79b13..d758385e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ emojis = "~=0.6.0" matplotlib = "~=3.4.1" coloredlogs = "~=15.0" colorama = { version = "~=0.4.3", markers = "sys_platform == 'win32'" } -lxml = "~=4.4" +lxml = "~=4.6" [tool.poetry.dev-dependencies] flake8 = "~=3.8" -- cgit v1.2.3 From 770292ea5a064ab57accabda93022fdfa64addd1 Mon Sep 17 00:00:00 2001 From: evgriff <44847470+evgriff@users.noreply.github.com> Date: Wed, 15 Dec 2021 12:43:11 -0500 Subject: Update bot/exts/holidays/halloween/candy_collection.py From @Shivansh-007 Co-authored-by: Shivansh-007 --- 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 6edce1a0..6e5ae84b 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -201,7 +201,7 @@ class CandyCollection(commands.Cog): inline=False ) e.add_field( - name=f'{user.name}' + "'s Candy Score", + name="Your Candy Score", value=get_user_candy_score(), inline=False ) -- cgit v1.2.3 From 43f1a14765133229053c06bd36517f2f5081f20d Mon Sep 17 00:00:00 2001 From: evgriff Date: Wed, 15 Dec 2021 17:52:49 +0000 Subject: Adding suggestions, removing erroneous commit --- bot/exts/holidays/halloween/candy_collection.py | 9 ++++----- bot/exts/utilities/issues.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py index 6edce1a0..9b16d543 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -173,7 +173,6 @@ class CandyCollection(commands.Cog): async def candy(self, ctx: commands.Context) -> None: """Get the candy leaderboard and save to JSON.""" records = await self.candy_records.items() - user = await self.bot.fetch_user(ctx.author.id) def generate_leaderboard() -> str: top_sorted = sorted( @@ -190,9 +189,9 @@ class CandyCollection(commands.Cog): def get_user_candy_score() -> str: for user_id, score in records: - if user_id == user.id: - return f'<@{user.id}>: {score}' - return f'<@{user.id}>: 0' + if user_id == ctx.author.id: + return f'<@{ctx.author.id}>: {score}' + return f'<@{ctx.author.id}>: 0' e = discord.Embed(colour=discord.Colour.og_blurple()) e.add_field( @@ -201,7 +200,7 @@ class CandyCollection(commands.Cog): inline=False ) e.add_field( - name=f'{user.name}' + "'s Candy Score", + name="Your Candy Score", value=get_user_candy_score(), inline=False ) diff --git a/bot/exts/utilities/issues.py b/bot/exts/utilities/issues.py index b3f8340c..b6d5a43e 100644 --- a/bot/exts/utilities/issues.py +++ b/bot/exts/utilities/issues.py @@ -139,7 +139,7 @@ class Issues(commands.Cog): log.trace(f"PR provided, querying GH pulls API for additional information: {pulls_url}") async with self.bot.http_session.get(pulls_url) as p: pull_data = await p.json() - if "draft" in pull_data and pull_data["draft"]: + if pull_data["draft"]: emoji = Emojis.pull_request_draft elif pull_data["state"] == "open": emoji = Emojis.pull_request_open -- cgit v1.2.3 From 55f008ee03c15b24551bdc5509459337df9acd8e Mon Sep 17 00:00:00 2001 From: aru Date: Wed, 15 Dec 2021 18:15:16 -0500 Subject: minor: allow color command in dev-media (#944) Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/utilities/colour.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index 7c83fc66..ee6bad93 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -11,8 +11,10 @@ import rapidfuzz from PIL import Image, ImageColor from discord.ext import commands +from bot import constants from bot.bot import Bot from bot.exts.core.extensions import invoke_help_command +from bot.utils.decorators import whitelist_override THUMBNAIL_SIZE = (80, 80) @@ -78,6 +80,11 @@ class Colour(commands.Cog): await ctx.send(file=thumbnail_file, embed=colour_embed) @commands.group(aliases=("color",), invoke_without_command=True) + @whitelist_override( + channels=constants.WHITELISTED_CHANNELS, + roles=constants.STAFF_ROLES, + categories=[constants.Categories.development, constants.Categories.media] + ) async def colour(self, ctx: commands.Context, *, colour_input: Optional[str] = None) -> None: """ Create an embed that displays colour information. -- cgit v1.2.3 From 85242f87d8c946b645d0ca50ed266a78dd51393d Mon Sep 17 00:00:00 2001 From: evgriff Date: Thu, 16 Dec 2021 20:06:44 +0000 Subject: user.mention --- bot/exts/holidays/halloween/candy_collection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py index 9b16d543..61dc8f97 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -190,8 +190,8 @@ class CandyCollection(commands.Cog): def get_user_candy_score() -> str: for user_id, score in records: if user_id == ctx.author.id: - return f'<@{ctx.author.id}>: {score}' - return f'<@{ctx.author.id}>: 0' + return f'{ctx.author.mention}: {score}' + return f'{ctx.author.mention}: 0' e = discord.Embed(colour=discord.Colour.og_blurple()) e.add_field( -- cgit v1.2.3 From e48fda5a7ae3509dd0ef7e591fedbf3dab125ba1 Mon Sep 17 00:00:00 2001 From: evgriff Date: Thu, 16 Dec 2021 20:09:12 +0000 Subject: Double quotes --- bot/exts/holidays/halloween/candy_collection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py index 61dc8f97..729bbc97 100644 --- a/bot/exts/holidays/halloween/candy_collection.py +++ b/bot/exts/holidays/halloween/candy_collection.py @@ -190,8 +190,8 @@ class CandyCollection(commands.Cog): def get_user_candy_score() -> str: for user_id, score in records: if user_id == ctx.author.id: - return f'{ctx.author.mention}: {score}' - return f'{ctx.author.mention}: 0' + return f"{ctx.author.mention}: {score}" + return f"{ctx.author.mention}: 0" e = discord.Embed(colour=discord.Colour.og_blurple()) e.add_field( -- cgit v1.2.3 From 4d47cae15594babfb6e4c4a77b0fc13176e8f7bc Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Tue, 28 Dec 2021 20:10:17 +0000 Subject: Remove latex cog and matplotlib matplotlib, and its sub dependencies, caused a fresh install of an environment to take multiple minutes. As the latex cog is the only one that used it, and that is currently disabled, we have decided to remove it entirely. Git gives us the benefit of being able to see deleted files. So whoever decides to implement latex again can use that for reference. --- bot/exts/utilities/latex.py | 101 -------- poetry.lock | 579 +++++++++++++++++++------------------------- pyproject.toml | 1 - 3 files changed, 250 insertions(+), 431 deletions(-) delete mode 100644 bot/exts/utilities/latex.py diff --git a/bot/exts/utilities/latex.py b/bot/exts/utilities/latex.py deleted file mode 100644 index 36c7e0ab..00000000 --- a/bot/exts/utilities/latex.py +++ /dev/null @@ -1,101 +0,0 @@ -import asyncio -import hashlib -import pathlib -import re -from concurrent.futures import ThreadPoolExecutor -from io import BytesIO - -import discord -import matplotlib.pyplot as plt -from discord.ext import commands - -from bot.bot import Bot - -# configure fonts and colors for matplotlib -plt.rcParams.update( - { - "font.size": 16, - "mathtext.fontset": "cm", # Computer Modern font set - "mathtext.rm": "serif", - "figure.facecolor": "36393F", # matches Discord's dark mode background color - "text.color": "white", - } -) - -FORMATTED_CODE_REGEX = re.compile( - r"(?P(?P```)|``?)" # code delimiter: 1-3 backticks; (?P=block) only matches if it's a block - r"(?(block)(?:(?P[a-z]+)\n)?)" # if we're in a block, match optional language (only letters plus newline) - r"(?:[ \t]*\n)*" # any blank (empty or tabs/spaces only) lines before the code - r"(?P.*?)" # extract all code inside the markup - r"\s*" # any more whitespace before the end of the code markup - r"(?P=delim)", # match the exact same delimiter from the start again - re.DOTALL | re.IGNORECASE, # "." also matches newlines, case insensitive -) - -CACHE_DIRECTORY = pathlib.Path("_latex_cache") -CACHE_DIRECTORY.mkdir(exist_ok=True) - - -class Latex(commands.Cog): - """Renders latex.""" - - @staticmethod - def _render(text: str, filepath: pathlib.Path) -> BytesIO: - """ - Return the rendered image if latex compiles without errors, otherwise raise a BadArgument Exception. - - Saves rendered image to cache. - """ - fig = plt.figure() - rendered_image = BytesIO() - fig.text(0, 1, text, horizontalalignment="left", verticalalignment="top") - - try: - plt.savefig(rendered_image, bbox_inches="tight", dpi=600) - except ValueError as e: - raise commands.BadArgument(str(e)) - - rendered_image.seek(0) - - with open(filepath, "wb") as f: - f.write(rendered_image.getbuffer()) - - return rendered_image - - @staticmethod - def _prepare_input(text: str) -> str: - text = text.replace(r"\\", "$\n$") # matplotlib uses \n for newlines, not \\ - - if match := FORMATTED_CODE_REGEX.match(text): - return match.group("code") - else: - return text - - @commands.command() - @commands.max_concurrency(1, commands.BucketType.guild, wait=True) - async def latex(self, ctx: commands.Context, *, text: str) -> None: - """Renders the text in latex and sends the image.""" - text = self._prepare_input(text) - query_hash = hashlib.md5(text.encode()).hexdigest() - image_path = CACHE_DIRECTORY.joinpath(f"{query_hash}.png") - async with ctx.typing(): - if image_path.exists(): - await ctx.send(file=discord.File(image_path)) - return - - with ThreadPoolExecutor() as pool: - image = await asyncio.get_running_loop().run_in_executor( - pool, self._render, text, image_path - ) - - await ctx.send(file=discord.File(image, "latex.png")) - - -def setup(bot: Bot) -> None: - """Load the Latex Cog.""" - # As we have resource issues on this cog, - # we have it currently disabled while we fix it. - import logging - logging.info("Latex cog is currently disabled. It won't be loaded.") - return - bot.add_cog(Latex()) diff --git a/poetry.lock b/poetry.lock index 5e950343..6a83efed 100644 --- a/poetry.lock +++ b/poetry.lock @@ -76,29 +76,17 @@ python-versions = ">=3.5.3" [[package]] name = "attrs" -version = "21.2.0" +version = "21.3.0" description = "Classes Without Boilerplate" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] - -[[package]] -name = "backports.entry-points-selectable" -version = "1.1.1" -description = "Compatibility shim providing selectable entry points for older implementations" -category = "dev" -optional = false -python-versions = ">=2.7" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] name = "beautifulsoup4" @@ -173,12 +161,18 @@ humanfriendly = ">=9.1" cron = ["capturer (>=2.4)"] [[package]] -name = "cycler" -version = "0.11.0" -description = "Composable style cycles" +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] [[package]] name = "discord.py" @@ -199,10 +193,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.3" +version = "0.3.4" description = "Distribution utilities" category = "dev" optional = false @@ -218,7 +211,7 @@ python-versions = "*" [[package]] name = "fakeredis" -version = "1.6.1" +version = "1.7.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false @@ -226,7 +219,7 @@ python-versions = ">=3.5" [package.dependencies] packaging = "*" -redis = "<3.6.0" +redis = "<4.1.0" six = ">=1.12" sortedcontainers = "*" @@ -236,11 +229,11 @@ lua = ["lupa"] [[package]] name = "filelock" -version = "3.3.2" +version = "3.4.2" description = "A platform independent file lock." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] @@ -378,14 +371,14 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve [[package]] name = "identify" -version = "2.3.5" +version = "2.4.1" description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.6.1" [package.extras] -license = ["editdistance-s"] +license = ["ukkonen"] [[package]] name = "idna" @@ -409,17 +402,9 @@ requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] plugins = ["setuptools"] -[[package]] -name = "kiwisolver" -version = "1.3.2" -description = "A fast implementation of the Cassowary constraint solver" -category = "main" -optional = false -python-versions = ">=3.7" - [[package]] name = "lxml" -version = "4.6.5" +version = "4.7.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." category = "main" optional = false @@ -431,22 +416,6 @@ html5 = ["html5lib"] htmlsoup = ["beautifulsoup4"] source = ["Cython (>=0.29.7)"] -[[package]] -name = "matplotlib" -version = "3.4.3" -description = "Python plotting package" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -cycler = ">=0.10" -kiwisolver = ">=1.0.1" -numpy = ">=1.16" -pillow = ">=6.2.0" -pyparsing = ">=2.2.1" -python-dateutil = ">=2.7" - [[package]] name = "mccabe" version = "0.6.1" @@ -479,24 +448,16 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "numpy" -version = "1.21.1" -description = "NumPy is the fundamental package for array computing with Python." -category = "main" -optional = false -python-versions = ">=3.7" - [[package]] name = "packaging" -version = "21.0" +version = "21.3" description = "Core utilities for Python packages" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pep8-naming" @@ -534,11 +495,11 @@ test = ["docutils", "pytest-cov", "pytest-pycodestyle", "pytest-runner"] [[package]] name = "platformdirs" -version = "2.4.0" +version = "2.4.1" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] @@ -546,7 +507,7 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock [[package]] name = "pre-commit" -version = "2.15.0" +version = "2.16.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false @@ -633,7 +594,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pyparsing" -version = "3.0.5" +version = "3.0.6" description = "Python parsing module" category = "main" optional = false @@ -663,7 +624,7 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "0.19.1" +version = "0.19.2" description = "Read key-value pairs from a .env file and set them as environment variables" category = "dev" optional = false @@ -682,7 +643,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] name = "rapidfuzz" -version = "1.8.2" +version = "1.9.1" description = "rapid fuzzy string matching" category = "main" optional = false @@ -693,14 +654,17 @@ full = ["numpy"] [[package]] name = "redis" -version = "3.5.3" -description = "Python client for Redis key-value store" +version = "4.0.2" +description = "Python client for Redis database and key-value store" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" + +[package.dependencies] +deprecated = "*" [package.extras] -hiredis = ["hiredis (>=0.1.3)"] +hiredis = ["hiredis (>=1.0.0)"] [[package]] name = "sentry-sdk" @@ -740,7 +704,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "snowballstemmer" -version = "2.1.0" +version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." category = "dev" optional = false @@ -756,7 +720,7 @@ python-versions = "*" [[package]] name = "soupsieve" -version = "2.3" +version = "2.3.1" description = "A modern CSS selector implementation for Beautiful Soup." category = "main" optional = false @@ -799,11 +763,11 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "typing-extensions" -version = "3.10.0.2" -description = "Backported and Experimental Type Hints for Python 3.5+" +version = "4.0.1" +description = "Backported and Experimental Type Hints for Python 3.6+" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "urllib3" @@ -820,14 +784,13 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.10.0" +version = "20.11.0" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] -"backports.entry-points-selectable" = ">=1.0.4" distlib = ">=0.3.1,<1" filelock = ">=3.2,<4" platformdirs = ">=2,<3" @@ -837,6 +800,14 @@ six = ">=1.9.0,<2" docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] +[[package]] +name = "wrapt" +version = "1.13.3" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + [[package]] name = "yarl" version = "1.7.2" @@ -852,7 +823,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "b091f392619f058d265309c9474d9d2b86f53f634017210cca11713cdb11ae14" +content-hash = "e3682fd5b518ada5066b36015210f00d223c5485c24e4e7c377e371fe6ef0a0d" [metadata.files] aiodns = [ @@ -915,12 +886,8 @@ async-timeout = [ {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, ] attrs = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, -] -"backports.entry-points-selectable" = [ - {file = "backports.entry_points_selectable-1.1.1-py2.py3-none-any.whl", hash = "sha256:7fceed9532a7aa2bd888654a7314f864a3c16a4e710b34a58cfc0f08114c663b"}, - {file = "backports.entry_points_selectable-1.1.1.tar.gz", hash = "sha256:914b21a479fde881635f7af5adc7f6e38d6b274be32269070c53b698c60d5386"}, + {file = "attrs-21.3.0-py2.py3-none-any.whl", hash = "sha256:8f7335278dedd26b58c38e006338242cc0977f06d51579b2b8b87b9b33bff66c"}, + {file = "attrs-21.3.0.tar.gz", hash = "sha256:50f3c9b216dc9021042f71b392859a773b904ce1a029077f58f6598272432045"}, ] beautifulsoup4 = [ {file = "beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf"}, @@ -998,26 +965,26 @@ coloredlogs = [ {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, ] -cycler = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +deprecated = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, ] "discord.py" = [] distlib = [ - {file = "distlib-0.3.3-py2.py3-none-any.whl", hash = "sha256:c8b54e8454e5bf6237cc84c20e8264c3e991e824ef27e8f1e81049867d861e31"}, - {file = "distlib-0.3.3.zip", hash = "sha256:d982d0751ff6eaaab5e2ec8e691d949ee80eddf01a62eaa96ddb11531fe16b05"}, + {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, + {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, ] 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.1-py3-none-any.whl", hash = "sha256:5eb1516f1fe1813e9da8f6c482178fc067af09f53de587ae03887ef5d9d13024"}, - {file = "fakeredis-1.6.1.tar.gz", hash = "sha256:0d06a9384fb79da9f2164ce96e34eb9d4e2ea46215070805ea6fd3c174590b47"}, + {file = "fakeredis-1.7.0-py3-none-any.whl", hash = "sha256:6f1e04f64557ad3b6835bdc6e5a8d022cbace4bdc24a47ad58f6a72e0fbff760"}, + {file = "fakeredis-1.7.0.tar.gz", hash = "sha256:c9bd12e430336cbd3e189fae0e91eb99997b93e76dbfdd6ed67fa352dc684c71"}, ] filelock = [ - {file = "filelock-3.3.2-py3-none-any.whl", hash = "sha256:bb2a1c717df74c48a2d00ed625e5a66f8572a3a30baacb7657add1d7bac4097b"}, - {file = "filelock-3.3.2.tar.gz", hash = "sha256:7afc856f74fa7006a289fd10fa840e1eebd8bbff6bffb69c26c54a0512ea8cf8"}, + {file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"}, + {file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"}, ] flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, @@ -1102,8 +1069,8 @@ humanfriendly = [ {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, ] identify = [ - {file = "identify-2.3.5-py2.py3-none-any.whl", hash = "sha256:ba945bddb4322394afcf3f703fa68eda08a6acc0f99d9573eb2be940aa7b9bba"}, - {file = "identify-2.3.5.tar.gz", hash = "sha256:6f0368ba0f21c199645a331beb7425d5374376e71bc149e9cb55e45cb45f832d"}, + {file = "identify-2.4.1-py2.py3-none-any.whl", hash = "sha256:0192893ff68b03d37fed553e261d4a22f94ea974093aefb33b29df2ff35fed3c"}, + {file = "identify-2.4.1.tar.gz", hash = "sha256:64d4885e539f505dd8ffb5e93c142a1db45480452b1594cacd3e91dca9a984e9"}, ] idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, @@ -1113,136 +1080,67 @@ isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -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"}, - {file = "kiwisolver-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4550a359c5157aaf8507e6820d98682872b9100ce7607f8aa070b4b8af6c298"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2210f28778c7d2ee13f3c2a20a3a22db889e75f4ec13a21072eabb5693801e84"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:82f49c5a79d3839bc8f38cb5f4bfc87e15f04cbafa5fbd12fb32c941cb529cfb"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9661a04ca3c950a8ac8c47f53cbc0b530bce1b52f516a1e87b7736fec24bfff0"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ddb500a2808c100e72c075cbb00bf32e62763c82b6a882d403f01a119e3f402"}, - {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72be6ebb4e92520b9726d7146bc9c9b277513a57a38efcf66db0620aec0097e0"}, - {file = "kiwisolver-1.3.2-cp310-cp310-win32.whl", hash = "sha256:83d2c9db5dfc537d0171e32de160461230eb14663299b7e6d18ca6dca21e4977"}, - {file = "kiwisolver-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:cba430db673c29376135e695c6e2501c44c256a81495da849e85d1793ee975ad"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4116ba9a58109ed5e4cb315bdcbff9838f3159d099ba5259c7c7fb77f8537492"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19554bd8d54cf41139f376753af1a644b63c9ca93f8f72009d50a2080f870f77"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a4cf5bbdc861987a7745aed7a536c6405256853c94abc9f3287c3fa401b174"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0007840186bacfaa0aba4466d5890334ea5938e0bb7e28078a0eb0e63b5b59d5"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec2eba188c1906b05b9b49ae55aae4efd8150c61ba450e6721f64620c50b59eb"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3dbb3cea20b4af4f49f84cffaf45dd5f88e8594d18568e0225e6ad9dec0e7967"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:5326ddfacbe51abf9469fe668944bc2e399181a2158cb5d45e1d40856b2a0589"}, - {file = "kiwisolver-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c6572c2dab23c86a14e82c245473d45b4c515314f1f859e92608dcafbd2f19b8"}, - {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b5074fb09429f2b7bc82b6fb4be8645dcbac14e592128beeff5461dcde0af09f"}, - {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22521219ca739654a296eea6d4367703558fba16f98688bd8ce65abff36eaa84"}, - {file = "kiwisolver-1.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c358721aebd40c243894298f685a19eb0491a5c3e0b923b9f887ef1193ddf829"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ba5a1041480c6e0a8b11a9544d53562abc2d19220bfa14133e0cdd9967e97af"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44e6adf67577dbdfa2d9f06db9fbc5639afefdb5bf2b4dfec25c3a7fbc619536"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d45d1c74f88b9f41062716c727f78f2a59a5476ecbe74956fafb423c5c87a76"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70adc3658138bc77a36ce769f5f183169bc0a2906a4f61f09673f7181255ac9b"}, - {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6a5431940f28b6de123de42f0eb47b84a073ee3c3345dc109ad550a3307dd28"}, - {file = "kiwisolver-1.3.2-cp38-cp38-win32.whl", hash = "sha256:ee040a7de8d295dbd261ef2d6d3192f13e2b08ec4a954de34a6fb8ff6422e24c"}, - {file = "kiwisolver-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:8dc3d842fa41a33fe83d9f5c66c0cc1f28756530cd89944b63b072281e852031"}, - {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a498bcd005e8a3fedd0022bb30ee0ad92728154a8798b703f394484452550507"}, - {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80efd202108c3a4150e042b269f7c78643420cc232a0a771743bb96b742f838f"}, - {file = "kiwisolver-1.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f8eb7b6716f5b50e9c06207a14172cf2de201e41912ebe732846c02c830455b9"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f441422bb313ab25de7b3dbfd388e790eceb76ce01a18199ec4944b369017009"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:30fa008c172355c7768159983a7270cb23838c4d7db73d6c0f6b60dde0d432c6"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f8f6c8f4f1cff93ca5058d6ec5f0efda922ecb3f4c5fb76181f327decff98b8"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba677bcaff9429fd1bf01648ad0901cea56c0d068df383d5f5856d88221fe75b"}, - {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7843b1624d6ccca403a610d1277f7c28ad184c5aa88a1750c1a999754e65b439"}, - {file = "kiwisolver-1.3.2-cp39-cp39-win32.whl", hash = "sha256:e6f5eb2f53fac7d408a45fbcdeda7224b1cfff64919d0f95473420a931347ae9"}, - {file = "kiwisolver-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:eedd3b59190885d1ebdf6c5e0ca56828beb1949b4dfe6e5d0256a461429ac386"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dedc71c8eb9c5096037766390172c34fb86ef048b8e8958b4e484b9e505d66bc"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bf7eb45d14fc036514c09554bf983f2a72323254912ed0c3c8e697b62c4c158f"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b65bd35f3e06a47b5c30ea99e0c2b88f72c6476eedaf8cfbc8e66adb5479dcf"}, - {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25405f88a37c5f5bcba01c6e350086d65e7465fd1caaf986333d2a045045a223"}, - {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.5-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:abcf7daa5ebcc89328326254f6dd6d566adb483d4d00178892afd386ab389de2"}, - {file = "lxml-4.6.5-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3884476a90d415be79adfa4e0e393048630d0d5bcd5757c4c07d8b4b00a1096b"}, - {file = "lxml-4.6.5-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:add017c5bd6b9ec3a5f09248396b6ee2ce61c5621f087eb2269c813cd8813808"}, - {file = "lxml-4.6.5-cp27-cp27m-win32.whl", hash = "sha256:a702005e447d712375433ed0499cb6e1503fadd6c96a47f51d707b4d37b76d3c"}, - {file = "lxml-4.6.5-cp27-cp27m-win_amd64.whl", hash = "sha256:da07c7e7fc9a3f40446b78c54dbba8bfd5c9100dfecb21b65bfe3f57844f5e71"}, - {file = "lxml-4.6.5-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a708c291900c40a7ecf23f1d2384ed0bc0604e24094dd13417c7e7f8f7a50d93"}, - {file = "lxml-4.6.5-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f33d8efb42e4fc2b31b3b4527940b25cdebb3026fb56a80c1c1c11a4271d2352"}, - {file = "lxml-4.6.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:f6befb83bca720b71d6bd6326a3b26e9496ae6649e26585de024890fe50f49b8"}, - {file = "lxml-4.6.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:59d77bfa3bea13caee95bc0d3f1c518b15049b97dd61ea8b3d71ce677a67f808"}, - {file = "lxml-4.6.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:68a851176c931e2b3de6214347b767451243eeed3bea34c172127bbb5bf6c210"}, - {file = "lxml-4.6.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7790a273225b0c46e5f859c1327f0f659896cc72eaa537d23aa3ad9ff2a1cc1"}, - {file = "lxml-4.6.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6548fc551de15f310dd0564751d9dc3d405278d45ea9b2b369ed1eccf142e1f5"}, - {file = "lxml-4.6.5-cp310-cp310-win32.whl", hash = "sha256:dc8a0dbb2a10ae8bb609584f5c504789f0f3d0d81840da4849102ec84289f952"}, - {file = "lxml-4.6.5-cp310-cp310-win_amd64.whl", hash = "sha256:1ccbfe5d17835db906f2bab6f15b34194db1a5b07929cba3cf45a96dbfbfefc0"}, - {file = "lxml-4.6.5-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca9a40497f7e97a2a961c04fa8a6f23d790b0521350a8b455759d786b0bcb203"}, - {file = "lxml-4.6.5-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e5b4b0d9440046ead3bd425eb2b852499241ee0cef1ae151038e4f87ede888c4"}, - {file = "lxml-4.6.5-cp35-cp35m-win32.whl", hash = "sha256:87f8f7df70b90fbe7b49969f07b347e3f978f8bd1046bb8ecae659921869202b"}, - {file = "lxml-4.6.5-cp35-cp35m-win_amd64.whl", hash = "sha256:ce52aad32ec6e46d1a91ff8b8014a91538800dd533914bfc4a82f5018d971408"}, - {file = "lxml-4.6.5-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:8021eeff7fabde21b9858ed058a8250ad230cede91764d598c2466b0ba70db8b"}, - {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:cab343b265e38d4e00649cbbad9278b734c5715f9bcbb72c85a1f99b1a58e19a"}, - {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3534d7c468c044f6aef3c0aff541db2826986a29ea73f2ca831f5d5284d9b570"}, - {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdb98f4c9e8a1735efddfaa995b0c96559792da15d56b76428bdfc29f77c4cdb"}, - {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5ea121cb66d7e5cb396b4c3ca90471252b94e01809805cfe3e4e44be2db3a99c"}, - {file = "lxml-4.6.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:121fc6f71c692b49af6c963b84ab7084402624ffbe605287da362f8af0668ea3"}, - {file = "lxml-4.6.5-cp36-cp36m-win32.whl", hash = "sha256:1a2a7659b8eb93c6daee350a0d844994d49245a0f6c05c747f619386fb90ba04"}, - {file = "lxml-4.6.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2f77556266a8fe5428b8759fbfc4bd70be1d1d9c9b25d2a414f6a0c0b0f09120"}, - {file = "lxml-4.6.5-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:558485218ee06458643b929765ac1eb04519ca3d1e2dcc288517de864c747c33"}, - {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ba0006799f21d83c3717fe20e2707a10bbc296475155aadf4f5850f6659b96b9"}, - {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:916d457ad84e05b7db52700bad0a15c56e0c3000dcaf1263b2fb7a56fe148996"}, - {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c580c2a61d8297a6e47f4d01f066517dbb019be98032880d19ece7f337a9401d"}, - {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a21b78af7e2e13bec6bea12fc33bc05730197674f3e5402ce214d07026ccfebd"}, - {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:46515773570a33eae13e451c8fcf440222ef24bd3b26f40774dd0bd8b6db15b2"}, - {file = "lxml-4.6.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:124f09614f999551ac65e5b9875981ce4b66ac4b8e2ba9284572f741935df3d9"}, - {file = "lxml-4.6.5-cp37-cp37m-win32.whl", hash = "sha256:b4015baed99d046c760f09a4c59d234d8f398a454380c3cf0b859aba97136090"}, - {file = "lxml-4.6.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12ae2339d32a2b15010972e1e2467345b7bf962e155671239fba74c229564b7f"}, - {file = "lxml-4.6.5-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:76b6c296e4f7a1a8a128aec42d128646897f9ae9a700ef6839cdc9b3900db9b5"}, - {file = "lxml-4.6.5-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:534032a5ceb34bba1da193b7d386ac575127cc39338379f39a164b10d97ade89"}, - {file = "lxml-4.6.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:60aeb14ff9022d2687ef98ce55f6342944c40d00916452bb90899a191802137a"}, - {file = "lxml-4.6.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9801bcd52ac9c795a7d81ea67471a42cffe532e46cfb750cd5713befc5c019c0"}, - {file = "lxml-4.6.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3b95fb7e6f9c2f53db88f4642231fc2b8907d854e614710996a96f1f32018d5c"}, - {file = "lxml-4.6.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:642eb4cabd997c9b949a994f9643cd8ae00cf4ca8c5cd9c273962296fadf1c44"}, - {file = "lxml-4.6.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:af4139172ff0263d269abdcc641e944c9de4b5d660894a3ec7e9f9db63b56ac9"}, - {file = "lxml-4.6.5-cp38-cp38-win32.whl", hash = "sha256:57cf05466917e08f90e323f025b96f493f92c0344694f5702579ab4b7e2eb10d"}, - {file = "lxml-4.6.5-cp38-cp38-win_amd64.whl", hash = "sha256:4f415624cf8b065796649a5e4621773dc5c9ea574a944c76a7f8a6d3d2906b41"}, - {file = "lxml-4.6.5-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7679bb6e4d9a3978a46ab19a3560e8d2b7265ef3c88152e7fdc130d649789887"}, - {file = "lxml-4.6.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c34234a1bc9e466c104372af74d11a9f98338a3f72fae22b80485171a64e0144"}, - {file = "lxml-4.6.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4b9390bf973e3907d967b75be199cf1978ca8443183cf1e78ad80ad8be9cf242"}, - {file = "lxml-4.6.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fcc849b28f584ed1dbf277291ded5c32bb3476a37032df4a1d523b55faa5f944"}, - {file = "lxml-4.6.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:46f21f2600d001af10e847df9eb3b832e8a439f696c04891bcb8a8cedd859af9"}, - {file = "lxml-4.6.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:99cf827f5a783038eb313beee6533dddb8bdb086d7269c5c144c1c952d142ace"}, - {file = "lxml-4.6.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:925174cafb0f1179a7fd38da90302555d7445e34c9ece68019e53c946be7f542"}, - {file = "lxml-4.6.5-cp39-cp39-win32.whl", hash = "sha256:12d8d6fe3ddef629ac1349fa89a638b296a34b6529573f5055d1cb4e5245f73b"}, - {file = "lxml-4.6.5-cp39-cp39-win_amd64.whl", hash = "sha256:a52e8f317336a44836475e9c802f51c2dc38d612eaa76532cb1d17690338b63b"}, - {file = "lxml-4.6.5-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:11ae552a78612620afd15625be9f1b82e3cc2e634f90d6b11709b10a100cba59"}, - {file = "lxml-4.6.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:473701599665d874919d05bb33b56180447b3a9da8d52d6d9799f381ce23f95c"}, - {file = "lxml-4.6.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7f00cc64b49d2ef19ddae898a3def9dd8fda9c3d27c8a174c2889ee757918e71"}, - {file = "lxml-4.6.5-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:73e8614258404b2689a26cb5d002512b8bc4dfa18aca86382f68f959aee9b0c8"}, - {file = "lxml-4.6.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ff44de36772b05c2eb74f2b4b6d1ae29b8f41ed5506310ce1258d44826ee38c1"}, - {file = "lxml-4.6.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5d5254c815c186744c8f922e2ce861a2bdeabc06520b4b30b2f7d9767791ce6e"}, - {file = "lxml-4.6.5.tar.gz", hash = "sha256:6e84edecc3a82f90d44ddee2ee2a2630d4994b8471816e226d2b771cda7ac4ca"}, -] -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"}, - {file = "matplotlib-3.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:eeb1859efe7754b1460e1d4991bbd4a60a56f366bc422ef3a9c5ae05f0bc70b5"}, - {file = "matplotlib-3.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:844a7b0233e4ff7fba57e90b8799edaa40b9e31e300b8d5efc350937fa8b1bea"}, - {file = "matplotlib-3.4.3-cp37-cp37m-win32.whl", hash = "sha256:85f0c9cf724715e75243a7b3087cf4a3de056b55e05d4d76cc58d610d62894f3"}, - {file = "matplotlib-3.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c70b6311dda3e27672f1bf48851a0de816d1ca6aaf3d49365fbdd8e959b33d2b"}, - {file = "matplotlib-3.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b884715a59fec9ad3b6048ecf3860f3b2ce965e676ef52593d6fa29abcf7d330"}, - {file = "matplotlib-3.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a78a3b51f29448c7f4d4575e561f6b0dbb8d01c13c2046ab6c5220eb25c06506"}, - {file = "matplotlib-3.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6a724e3a48a54b8b6e7c4ae38cd3d07084508fa47c410c8757e9db9791421838"}, - {file = "matplotlib-3.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:48e1e0859b54d5f2e29bb78ca179fd59b971c6ceb29977fb52735bfd280eb0f5"}, - {file = "matplotlib-3.4.3-cp38-cp38-win32.whl", hash = "sha256:01c9de93a2ca0d128c9064f23709362e7fefb34910c7c9e0b8ab0de8258d5eda"}, - {file = "matplotlib-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:ebfb01a65c3f5d53a8c2a8133fec2b5221281c053d944ae81ff5822a68266617"}, - {file = "matplotlib-3.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b53f336a4688cfce615887505d7e41fd79b3594bf21dd300531a4f5b4f746a"}, - {file = "matplotlib-3.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:fcd6f1954943c0c192bfbebbac263f839d7055409f1173f80d8b11a224d236da"}, - {file = "matplotlib-3.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6be8df61b1626e1a142c57e065405e869e9429b4a6dab4a324757d0dc4d42235"}, - {file = "matplotlib-3.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:41b6e307458988891fcdea2d8ecf84a8c92d53f84190aa32da65f9505546e684"}, - {file = "matplotlib-3.4.3-cp39-cp39-win32.whl", hash = "sha256:f72657f1596199dc1e4e7a10f52a4784ead8a711f4e5b59bea95bdb97cf0e4fd"}, - {file = "matplotlib-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:f15edcb0629a0801738925fe27070480f446fcaa15de65946ff946ad99a59a40"}, - {file = "matplotlib-3.4.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:556965514b259204637c360d213de28d43a1f4aed1eca15596ce83f768c5a56f"}, - {file = "matplotlib-3.4.3-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:54a026055d5f8614f184e588f6e29064019a0aa8448450214c0b60926d62d919"}, - {file = "matplotlib-3.4.3.tar.gz", hash = "sha256:fc4f526dfdb31c9bd6b8ca06bf9fab663ca12f3ec9cdf4496fb44bc680140318"}, + {file = "lxml-4.7.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:d546431636edb1d6a608b348dd58cc9841b81f4116745857b6cb9f8dadb2725f"}, + {file = "lxml-4.7.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6308062534323f0d3edb4e702a0e26a76ca9e0e23ff99be5d82750772df32a9e"}, + {file = "lxml-4.7.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f76dbe44e31abf516114f6347a46fa4e7c2e8bceaa4b6f7ee3a0a03c8eba3c17"}, + {file = "lxml-4.7.1-cp27-cp27m-win32.whl", hash = "sha256:d5618d49de6ba63fe4510bdada62d06a8acfca0b4b5c904956c777d28382b419"}, + {file = "lxml-4.7.1-cp27-cp27m-win_amd64.whl", hash = "sha256:9393a05b126a7e187f3e38758255e0edf948a65b22c377414002d488221fdaa2"}, + {file = "lxml-4.7.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50d3dba341f1e583265c1a808e897b4159208d814ab07530202b6036a4d86da5"}, + {file = "lxml-4.7.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:44f552e0da3c8ee3c28e2eb82b0b784200631687fc6a71277ea8ab0828780e7d"}, + {file = "lxml-4.7.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:e662c6266e3a275bdcb6bb049edc7cd77d0b0f7e119a53101d367c841afc66dc"}, + {file = "lxml-4.7.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4c093c571bc3da9ebcd484e001ba18b8452903cd428c0bc926d9b0141bcb710e"}, + {file = "lxml-4.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3e26ad9bc48d610bf6cc76c506b9e5ad9360ed7a945d9be3b5b2c8535a0145e3"}, + {file = "lxml-4.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a5f623aeaa24f71fce3177d7fee875371345eb9102b355b882243e33e04b7175"}, + {file = "lxml-4.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7b5e2acefd33c259c4a2e157119c4373c8773cf6793e225006a1649672ab47a6"}, + {file = "lxml-4.7.1-cp310-cp310-win32.whl", hash = "sha256:67fa5f028e8a01e1d7944a9fb616d1d0510d5d38b0c41708310bd1bc45ae89f6"}, + {file = "lxml-4.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:b1d381f58fcc3e63fcc0ea4f0a38335163883267f77e4c6e22d7a30877218a0e"}, + {file = "lxml-4.7.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:38d9759733aa04fb1697d717bfabbedb21398046bd07734be7cccc3d19ea8675"}, + {file = "lxml-4.7.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dfd0d464f3d86a1460683cd742306d1138b4e99b79094f4e07e1ca85ee267fe7"}, + {file = "lxml-4.7.1-cp35-cp35m-win32.whl", hash = "sha256:534e946bce61fd162af02bad7bfd2daec1521b71d27238869c23a672146c34a5"}, + {file = "lxml-4.7.1-cp35-cp35m-win_amd64.whl", hash = "sha256:6ec829058785d028f467be70cd195cd0aaf1a763e4d09822584ede8c9eaa4b03"}, + {file = "lxml-4.7.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:ade74f5e3a0fd17df5782896ddca7ddb998845a5f7cd4b0be771e1ffc3b9aa5b"}, + {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41358bfd24425c1673f184d7c26c6ae91943fe51dfecc3603b5e08187b4bcc55"}, + {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6e56521538f19c4a6690f439fefed551f0b296bd785adc67c1777c348beb943d"}, + {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b0f782f0e03555c55e37d93d7a57454efe7495dab33ba0ccd2dbe25fc50f05d"}, + {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:490712b91c65988012e866c411a40cc65b595929ececf75eeb4c79fcc3bc80a6"}, + {file = "lxml-4.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:34c22eb8c819d59cec4444d9eebe2e38b95d3dcdafe08965853f8799fd71161d"}, + {file = "lxml-4.7.1-cp36-cp36m-win32.whl", hash = "sha256:2a906c3890da6a63224d551c2967413b8790a6357a80bf6b257c9a7978c2c42d"}, + {file = "lxml-4.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:36b16fecb10246e599f178dd74f313cbdc9f41c56e77d52100d1361eed24f51a"}, + {file = "lxml-4.7.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a5edc58d631170de90e50adc2cc0248083541affef82f8cd93bea458e4d96db8"}, + {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:87c1b0496e8c87ec9db5383e30042357b4839b46c2d556abd49ec770ce2ad868"}, + {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:0a5f0e4747f31cff87d1eb32a6000bde1e603107f632ef4666be0dc065889c7a"}, + {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:bf6005708fc2e2c89a083f258b97709559a95f9a7a03e59f805dd23c93bc3986"}, + {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc15874816b9320581133ddc2096b644582ab870cf6a6ed63684433e7af4b0d3"}, + {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b5e96e25e70917b28a5391c2ed3ffc6156513d3db0e1476c5253fcd50f7a944"}, + {file = "lxml-4.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ec9027d0beb785a35aa9951d14e06d48cfbf876d8ff67519403a2522b181943b"}, + {file = "lxml-4.7.1-cp37-cp37m-win32.whl", hash = "sha256:9fbc0dee7ff5f15c4428775e6fa3ed20003140560ffa22b88326669d53b3c0f4"}, + {file = "lxml-4.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1104a8d47967a414a436007c52f533e933e5d52574cab407b1e49a4e9b5ddbd1"}, + {file = "lxml-4.7.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:fc9fb11b65e7bc49f7f75aaba1b700f7181d95d4e151cf2f24d51bfd14410b77"}, + {file = "lxml-4.7.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:317bd63870b4d875af3c1be1b19202de34c32623609ec803b81c99193a788c1e"}, + {file = "lxml-4.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:610807cea990fd545b1559466971649e69302c8a9472cefe1d6d48a1dee97440"}, + {file = "lxml-4.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:09b738360af8cb2da275998a8bf79517a71225b0de41ab47339c2beebfff025f"}, + {file = "lxml-4.7.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a2ab9d089324d77bb81745b01f4aeffe4094306d939e92ba5e71e9a6b99b71e"}, + {file = "lxml-4.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eed394099a7792834f0cb4a8f615319152b9d801444c1c9e1b1a2c36d2239f9e"}, + {file = "lxml-4.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:735e3b4ce9c0616e85f302f109bdc6e425ba1670a73f962c9f6b98a6d51b77c9"}, + {file = "lxml-4.7.1-cp38-cp38-win32.whl", hash = "sha256:772057fba283c095db8c8ecde4634717a35c47061d24f889468dc67190327bcd"}, + {file = "lxml-4.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:13dbb5c7e8f3b6a2cf6e10b0948cacb2f4c9eb05029fe31c60592d08ac63180d"}, + {file = "lxml-4.7.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:718d7208b9c2d86aaf0294d9381a6acb0158b5ff0f3515902751404e318e02c9"}, + {file = "lxml-4.7.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:5bee1b0cbfdb87686a7fb0e46f1d8bd34d52d6932c0723a86de1cc532b1aa489"}, + {file = "lxml-4.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e410cf3a2272d0a85526d700782a2fa92c1e304fdcc519ba74ac80b8297adf36"}, + {file = "lxml-4.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:585ea241ee4961dc18a95e2f5581dbc26285fcf330e007459688096f76be8c42"}, + {file = "lxml-4.7.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a555e06566c6dc167fbcd0ad507ff05fd9328502aefc963cb0a0547cfe7f00db"}, + {file = "lxml-4.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:adaab25be351fff0d8a691c4f09153647804d09a87a4e4ea2c3f9fe9e8651851"}, + {file = "lxml-4.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:82d16a64236970cb93c8d63ad18c5b9f138a704331e4b916b2737ddfad14e0c4"}, + {file = "lxml-4.7.1-cp39-cp39-win32.whl", hash = "sha256:59e7da839a1238807226f7143c68a479dee09244d1b3cf8c134f2fce777d12d0"}, + {file = "lxml-4.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:a1bbc4efa99ed1310b5009ce7f3a1784698082ed2c1ef3895332f5df9b3b92c2"}, + {file = "lxml-4.7.1-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:0607ff0988ad7e173e5ddf7bf55ee65534bd18a5461183c33e8e41a59e89edf4"}, + {file = "lxml-4.7.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:6c198bfc169419c09b85ab10cb0f572744e686f40d1e7f4ed09061284fc1303f"}, + {file = "lxml-4.7.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a58d78653ae422df6837dd4ca0036610b8cb4962b5cfdbd337b7b24de9e5f98a"}, + {file = "lxml-4.7.1-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:e18281a7d80d76b66a9f9e68a98cf7e1d153182772400d9a9ce855264d7d0ce7"}, + {file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8e54945dd2eeb50925500957c7c579df3cd07c29db7810b83cf30495d79af267"}, + {file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60"}, + {file = "lxml-4.7.1.tar.gz", hash = "sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, @@ -1330,39 +1228,9 @@ nodeenv = [ {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, ] -numpy = [ - {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, - {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, - {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, - {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, - {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, - {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, - {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, - {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"}, + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] pep8-naming = [ {file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"}, @@ -1416,12 +1284,12 @@ pip-licenses = [ {file = "pip_licenses-3.5.3-py3-none-any.whl", hash = "sha256:59c148d6a03784bf945d232c0dc0e9de4272a3675acaa0361ad7712398ca86ba"}, ] platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, + {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"}, + {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"}, ] pre-commit = [ - {file = "pre_commit-2.15.0-py2.py3-none-any.whl", hash = "sha256:a4ed01000afcb484d9eb8d504272e642c4c4099bbad3a6b27e519bd6a3e928a6"}, - {file = "pre_commit-2.15.0.tar.gz", hash = "sha256:3c25add78dbdfb6a28a651780d5c311ac40dd17f160eb3954a0c59da40a505a7"}, + {file = "pre_commit-2.16.0-py2.py3-none-any.whl", hash = "sha256:758d1dc9b62c2ed8881585c254976d66eae0889919ab9b859064fc2fe3c7743e"}, + {file = "pre_commit-2.16.0.tar.gz", hash = "sha256:fe9897cac830aa7164dbd02a4e7b90cae49630451ce88464bca73db486ba9f65"}, ] psutil = [ {file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"}, @@ -1506,8 +1374,8 @@ pyflakes = [ {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pyparsing = [ - {file = "pyparsing-3.0.5-py3-none-any.whl", hash = "sha256:4881e3d2979f27b41a3a2421b10be9cbfa7ce2baa6c7117952222f8bbea6650c"}, - {file = "pyparsing-3.0.5.tar.gz", hash = "sha256:9329d1c1b51f0f76371c4ded42c5ec4cc0be18456b22193e0570c2da98ed288b"}, + {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"}, + {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"}, ] pyreadline3 = [ {file = "pyreadline3-3.3-py3-none-any.whl", hash = "sha256:0003fd0079d152ecbd8111202c5a7dfa6a5569ffd65b235e45f3c2ecbee337b4"}, @@ -1518,8 +1386,8 @@ python-dateutil = [ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] python-dotenv = [ - {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"}, + {file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"}, + {file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"}, ] pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, @@ -1553,61 +1421,62 @@ pyyaml = [ {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] rapidfuzz = [ - {file = "rapidfuzz-1.8.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:d218a4aac1488cc7d63f1a597a33863aa304f6ac590d70057e708ec6865a4118"}, - {file = "rapidfuzz-1.8.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:8e47b2f9f49edbfd582f6703cde54d22ffa98d83c8393ccd07073852b33832ea"}, - {file = "rapidfuzz-1.8.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:17e456d2ba6bee54b5c83bb403c33e02c3873958e153c0413021a2a042b0940d"}, - {file = "rapidfuzz-1.8.2-cp27-cp27m-win32.whl", hash = "sha256:ab067c4f04f037686d6cad1a7fce4c3998548f38778f0edb351280b902b8b3e1"}, - {file = "rapidfuzz-1.8.2-cp27-cp27m-win_amd64.whl", hash = "sha256:6c3e298aa955b164c85e7e0e2372805da1d6bae7399dad256211caafdab46e7f"}, - {file = "rapidfuzz-1.8.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f62471a08d2c46c79a8e0129b74c2997e62692c36bef47a7392b542d6dafc6bf"}, - {file = "rapidfuzz-1.8.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:271ce29c63eb87d76bcd384753cdfbfb8f2a0aeb3c7d0891787b1f19b007a0e8"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22f49eb345759602cc002200217a62564d947f65a568723f99b80c74027ce77b"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4ec6015b74cdbd4ac8bbbf280522e913f11c4656e334559a8454713def4f3b33"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d53a474e3b7592a2ff3d4c1e545324314845d3ccbbc80f6dd89d044bceaf8a59"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:242ebe941991a086b9e455dadcdaf624bb895457e3ce254b0b51a7b9adc68fed"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dab9822666819350aa32008fe35a7c7da422289d6961a01a2e00e99c2581e7fe"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8107e175577f200a2426c4896b8e17a97b86f513122cba4155c7462f0fcc18ac"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-win32.whl", hash = "sha256:526d92f1ff354303cba0a4cbf184d11b94395841d00eaecf8963c6dc89deec21"}, - {file = "rapidfuzz-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:55168678ae7df1ad8099ec2f0ce54024c924b375b18a6f5d3237c930083fcfca"}, - {file = "rapidfuzz-1.8.2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:23c0632047bf8fac891ef73dfd397e951514d11fb5f168b630e3569ffcd51d61"}, - {file = "rapidfuzz-1.8.2-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:90d0e10c7075f761b17e590cf9254b32e7084de7e2b4cd11201031c61386714e"}, - {file = "rapidfuzz-1.8.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:c9537e7f2a489654671c4e3bdc3e01d1116052b3889217da7fe2f0b0f0b27e10"}, - {file = "rapidfuzz-1.8.2-cp35-cp35m-win32.whl", hash = "sha256:8ded55e5395af1705bbc89ab94bea3c73218e1f71ae2b72cd905a827ab131fa1"}, - {file = "rapidfuzz-1.8.2-cp35-cp35m-win_amd64.whl", hash = "sha256:2d4240fce22e74c6f3d381201288cea6cc5af8d310ec271b573b26558c2eaec8"}, - {file = "rapidfuzz-1.8.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:90901b7be174b1f14455c5601eff46b03b174cf1d61cec0fd6d37c74dd727c88"}, - {file = "rapidfuzz-1.8.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7dbd1524e0f2d4290cd60fe1474068a8d8a27a41e1dfa14b1e4d53735529a11c"}, - {file = "rapidfuzz-1.8.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b8eee29e35ce51adf1cbfcc5b64d1a89d71401a5101b8fe9b87abbe6bf4f893"}, - {file = "rapidfuzz-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:648fd2e561b6beb208e6cf46eb9f20ba952add69c2f90fb4e46898a821bca4c9"}, - {file = "rapidfuzz-1.8.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:40dacd641d93708818ff2c9921eb6e5b9463e9b3b7f410dde3c96e0e0f80c414"}, - {file = "rapidfuzz-1.8.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:28528d34fb73f991e2822fdf1aa28eff7832c2189c8d2d0b598f15dd1b1b7d88"}, - {file = "rapidfuzz-1.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f46137937dfa2ec04fbb9f0225ff3160b9f1ed993dc5abf126ccdeae38726c5"}, - {file = "rapidfuzz-1.8.2-cp37-cp37m-win32.whl", hash = "sha256:709ea3151a7448bb15adc3212cbdd4766eca557f1ae73cdff8ae656b6899e71a"}, - {file = "rapidfuzz-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c426eb833d16ddeec95c966efa78492803d741c85cf6553febf78979fc267692"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:91e20676b562c972de8af6a153df6eaaea27da96ade8321e51da7bab32285242"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea3c3c1a5401affeb7d279c2b7cf418d5e7d7e170eb010fcb1b45bb28de5e4d1"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ab21f86812a7da111a17c118fc8e827b4c289d02f39536f7a6acc6baf479dcc0"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0eef79b223e239af5cc9c0b89ae8096a38bc8a9109474ff610151ea0115b931c"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:20dfda3bd9c14e6d7951360af66792a15e81051fa017db00c71bad4b1e25688d"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec24328d855b88e8a472379c61af9972f0d7992edfe2ebaca03afed2c5282f94"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-win32.whl", hash = "sha256:69ab203a4b59c7e9ddec96044bd684d6165eab3362f84677822936fea2e8c4f1"}, - {file = "rapidfuzz-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:bd039be9798a3deba25301827b86b3ff084d69e2b4b16ae8da6a34638235680c"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7219ca078df644aa0694af9174b7abb09a75302021f1e062f39fcf183cb9f087"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d240b7cd8dc7890c103adf4666a43fb3b3d1e5b1231e59aa3986e18dba1d086f"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06f639a65f1269a52679942437228c804a354618dda79b68a70612c5c0a36f4e"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:750ea6977e68a17f16308ac044017f8ce35c8a553698696f5a4fbb77e3110c8c"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:517f26474012dbce37358a447165ca3b100b9b1b83ee8b3d6877accfdb209d46"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b2bf70a24e129af11e217d94cb34f96a1487606bf4a9d8c8f16bc49c9465b56"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-win32.whl", hash = "sha256:02ec1154e62493c0cb66c8b058d7196de48acbee7e884b757cff7bf075252232"}, - {file = "rapidfuzz-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:be564aea09ec8da0478b67f35be73f8c129054d45da7f4b02cd7e035d1aea96d"}, - {file = "rapidfuzz-1.8.2-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:54406d07788ca85aff12134425a2b931e842ee2c3b1ae915523cdd3d104c1136"}, - {file = "rapidfuzz-1.8.2-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:5648fcf1cbeacb05ea4b441ddf99c7f5e15dd53b7d3192e7449581b638e8b3f7"}, - {file = "rapidfuzz-1.8.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7d1d6ab126f960aa0df10454a06d17e303680df6370cc3c44c1f0697c4587c5c"}, - {file = "rapidfuzz-1.8.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1412ec4d43f0d1854ed3dd220dacbb68b977519553e80a2c4a250d3569793f92"}, - {file = "rapidfuzz-1.8.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9dd34ad050ccb680d9dbf9871a53e1f01b084488d5310349c3e9cedcb4561eb2"}, - {file = "rapidfuzz-1.8.2.tar.gz", hash = "sha256:d6efbb2b6b18b3a67d7bdfbcd9bb72732f55736852bbef823bdf210f9e0c6c90"}, + {file = "rapidfuzz-1.9.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:68227a8b25291d6a2140aef049271ea30a77be5ef672a58e582a55a5cc1fce93"}, + {file = "rapidfuzz-1.9.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c33541995b96ff40025c1456b8c74b7dd2ab9cbf91943fc35a7bb621f48940e2"}, + {file = "rapidfuzz-1.9.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c2fafbbf97a4632822248f4201601b691e2eac5fdb30e5d7a96d07a6d058a7d4"}, + {file = "rapidfuzz-1.9.1-cp27-cp27m-win32.whl", hash = "sha256:364795f617a99e1dbb55ac3947ab8366588b72531cb2d6152666287d20610706"}, + {file = "rapidfuzz-1.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:f171d9e66144b0647f9b998ef10bdd919a640e4b1357250c8ef6259deb5ffe0d"}, + {file = "rapidfuzz-1.9.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c83801a7c5209663aa120b815a4f2c39e95fe8e0b774ec58a1e0affd6a2fcfc6"}, + {file = "rapidfuzz-1.9.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:67e61c2baa6bb1848c4a33752f1781124dcc90bf3f31b18b44db1ae4e4e26634"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8ab7eb003a18991347174910f11d38ff40399081185d9e3199ec277535f7828b"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5ad450badf06ddf98a246140b5059ba895ee8445e8102a5a289908327f551f81"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:402b2174bded62a793c5f7d9aec16bc32c661402360a934819ae72b54cfbce1e"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92066ccb054efc2e17afb4049c98b550969653cd58f71dd756cfcc8e6864630a"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8dc0bf1814accee08a9c9bace6672ef06eae6b0446fce88e3e97e23dfaf3ea10"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdbd387efb8478605951344f327dd03bf053c138d757369a43404305b99e55db"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-win32.whl", hash = "sha256:b1c54807e556dbcc6caf4ce0f24446c01b195f3cc46e2a6e74b82d3a21eaa45d"}, + {file = "rapidfuzz-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:ac3273364cd1619cab3bf0ba731efea5405833f9eba362da7dcd70bd42073d8e"}, + {file = "rapidfuzz-1.9.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:d9faf62606c08a0a6992dd480c72b6a068733ae02688dc35f2e36ba0d44673f4"}, + {file = "rapidfuzz-1.9.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:f6a56a48be047637b1b0b2459a11cf7cd5aa7bbe16a439bd4f73b4af39e620e4"}, + {file = "rapidfuzz-1.9.1-cp35-cp35m-win32.whl", hash = "sha256:aa91609979e9d2700f0ff100df99b36e7d700b70169ee385d43d5de9e471ae97"}, + {file = "rapidfuzz-1.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b4cfdd0915ab4cec86c2ff6bab9f01b03454f3de0963c37f9f219df2ddf42b95"}, + {file = "rapidfuzz-1.9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c6bfa4ad0158a093cd304f795ceefdc3861ae6942a61432b2a50858be6de88ca"}, + {file = "rapidfuzz-1.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:eb0ea02295d9278bd2dcd2df4760b0f2887b6c3f2f374005ec5af320d8d3a37e"}, + {file = "rapidfuzz-1.9.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d5187cd5cd6273e9fee07de493a42a2153134a4914df74cb1abb0744551c548a"}, + {file = "rapidfuzz-1.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6e5b8af63f9c05b64454460759ed84a715d581d598ec4484f4ec512f398e8b1"}, + {file = "rapidfuzz-1.9.1-cp36-cp36m-win32.whl", hash = "sha256:36137f88f2b28115af506118e64e11c816611eab2434293af7fdacd1290ffb9d"}, + {file = "rapidfuzz-1.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:fcc420cad46be7c9887110edf04cdee545f26dbf22650a443d89790fc35f7b88"}, + {file = "rapidfuzz-1.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b06de314f426aebff8a44319016bbe2b22f7848c84e44224f80b0690b7b08b18"}, + {file = "rapidfuzz-1.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e5de44e719faea79e45322b037f0d4a141d750b80d2204fa68f43a42a24f0fbc"}, + {file = "rapidfuzz-1.9.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f9439df09a782afd01b67005a3b110c70bbf9e1cf06d2ac9b293ce2d02d3c549"}, + {file = "rapidfuzz-1.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e903d4702647465721e2d0431c95f04fd56a06577f06f41e2960c83fd63c1bad"}, + {file = "rapidfuzz-1.9.1-cp37-cp37m-win32.whl", hash = "sha256:a5298f4ac1975edcbb15583eab659a44b33aebaf3bccf172e185cfea68771c08"}, + {file = "rapidfuzz-1.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:103193a01921b54fcdad6b01cfda3a68e00aeafca236b7ecd5b1b2c2e7e96337"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1d98a3187040dca855e02179a35c137f72ef83ce243783d44ea59efa86b94b3a"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cb92bf7fc911b787055a88d9295ca3b4fe8576e3b59271f070f1b1b181eb087d"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3f014a0f5f8159a94c6ee884fedd1c30e07fb866a5d76ff2c18091bc6363b76f"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:31474074a99f72289ac325fbd77983e7d355d48860bfe7a4f6f6396fdb24410a"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec67d79af5a2d7b0cf67b570a5579710e461cadda4120478e813b63491f394dd"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ebc0d3d15ed32f98f0052cf6e3e9c9b8010fb93c04fb74d2022e3c51ec540e2"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-win32.whl", hash = "sha256:477ab1a3044bab89db45caabc562b158f68765ecaa638b73ba17e92f09dfa5ff"}, + {file = "rapidfuzz-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:8e872763dc0367d7544aa585d2e8b27af233323b8a7cd2f9b78cafa05bae5018"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8401c41e219ae36ca7a88762776a6270511650d4cc70d024ae61561e96d67e47"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ea10bd8e0436801c3264f7084a5ea194f12ba9fe1ba898aa4a2107d276501292"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:433737914b46c1ffa0c678eceae1c260dc6b7fb5b6cad4c725d3e3607c764b32"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8c3b08e90e45acbc469d1f456681643256e952bf84ec7714f58979baba0c8a1c"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bbcd265b3c86176e5db4cbba7b4364d7333c214ee80e2d259c7085929934ca9d"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d69fabcd635783cd842e7d5ee4b77164314c5124b82df5a0c436ab3d698f8a9"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-win32.whl", hash = "sha256:01f16b6f3fa5d1a26c12f5da5de0032f1e12c919d876005b57492a8ec9a5c043"}, + {file = "rapidfuzz-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:0bcc5bbfdbe6068cc2cf0029ab6cde08dceac498d232fa3a61dd34fbfa0b3f36"}, + {file = "rapidfuzz-1.9.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:de869c8f4e8edb9b2f7b8232a04896645501defcbd9d85bc0202ff3ec6285f6b"}, + {file = "rapidfuzz-1.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:db5978e970fb0955974d51021da4b929e2e4890fef17792989ee32658e2b159c"}, + {file = "rapidfuzz-1.9.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:33479f75f36ac3a1d8421365d4fa906e013490790730a89caba31d06e6f71738"}, + {file = "rapidfuzz-1.9.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:af991cb333ec526d894923163050931b3a870b7694bf7687aaa6154d341a98f5"}, + {file = "rapidfuzz-1.9.1.tar.gz", hash = "sha256:bd7a4fe33ba49db3417f0f57a8af02462554f1296dedcf35b026cd3525efef74"}, ] redis = [ - {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, - {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, + {file = "redis-4.0.2-py3-none-any.whl", hash = "sha256:c8481cf414474e3497ec7971a1ba9b998c8efad0f0d289a009a5bbef040894f9"}, + {file = "redis-4.0.2.tar.gz", hash = "sha256:ccf692811f2c1fc7a92b466aa2599e4a6d2d73d5f736a2c70be600657c0da34a"}, ] sentry-sdk = [ {file = "sentry-sdk-0.20.3.tar.gz", hash = "sha256:4ae8d1ced6c67f1c8ea51d82a16721c166c489b76876c9f2c202b8a50334b237"}, @@ -1618,16 +1487,16 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] snowballstemmer = [ - {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"}, - {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] 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.3-py3-none-any.whl", hash = "sha256:617ffc4d0dfd39c66f4d1413a6e165663a34eca86be9b54f97b91756300ff6df"}, - {file = "soupsieve-2.3.tar.gz", hash = "sha256:e4860f889dfa88774c07da0b276b70c073b6470fa1a4a8350800bb7bce3dcc76"}, + {file = "soupsieve-2.3.1-py3-none-any.whl", hash = "sha256:1a3cca2617c6b38c0343ed661b1fa5de5637f257d4fe22bd9f1338010a1efefb"}, + {file = "soupsieve-2.3.1.tar.gz", hash = "sha256:b8d49b1cd4f037c7082a9683dfa1801aa2597fb11c3a1155b7a5b94829b4f1f9"}, ] taskipy = [ {file = "taskipy-1.9.0-py3-none-any.whl", hash = "sha256:02bd2c51c7356ed3f7f8853210ada1cd2ab273e68359ee865021c3057eec6615"}, @@ -1642,17 +1511,69 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, + {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, + {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, ] urllib3 = [ {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.10.0-py2.py3-none-any.whl", hash = "sha256:4b02e52a624336eece99c96e3ab7111f469c24ba226a53ec474e8e787b365814"}, - {file = "virtualenv-20.10.0.tar.gz", hash = "sha256:576d05b46eace16a9c348085f7d0dc8ef28713a2cabaa1cf0aea41e8f12c9218"}, + {file = "virtualenv-20.11.0-py2.py3-none-any.whl", hash = "sha256:eb0cb34160f32c6596405308ee6a8a4abbf3247b2b9794ae655a156d43abf48e"}, + {file = "virtualenv-20.11.0.tar.gz", hash = "sha256:2f15b9226cb74b59c21e8236dd791c395bee08cdd33b99cddd18e1f866cdb098"}, +] +wrapt = [ + {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"}, + {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"}, + {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"}, + {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"}, + {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"}, + {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"}, + {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"}, + {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"}, + {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"}, + {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"}, + {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"}, + {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"}, + {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"}, + {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"}, + {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"}, + {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"}, + {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"}, + {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"}, + {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"}, + {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"}, + {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"}, + {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"}, + {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"}, + {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"}, + {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"}, + {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"}, + {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"}, + {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"}, + {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"}, + {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"}, + {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"}, + {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"}, + {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"}, + {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"}, + {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"}, + {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"}, + {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"}, + {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"}, + {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"}, ] yarl = [ {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"}, diff --git a/pyproject.toml b/pyproject.toml index d758385e..2a216209 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,6 @@ sentry-sdk = "~=0.19" PyYAML = "~=5.4" async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"} emojis = "~=0.6.0" -matplotlib = "~=3.4.1" coloredlogs = "~=15.0" colorama = { version = "~=0.4.3", markers = "sys_platform == 'win32'" } lxml = "~=4.6" -- cgit v1.2.3 From 06a704aae87ecd0d4a9e65263be25185eee66b69 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 25 Dec 2021 22:11:49 +0000 Subject: Add member util functions This adds some useful utils, get_or_fetch and handle role change. These utils handle errors themselves, so can simplify implementations within the commands. --- bot/utils/members.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 bot/utils/members.py diff --git a/bot/utils/members.py b/bot/utils/members.py new file mode 100644 index 00000000..9c8c8dd8 --- /dev/null +++ b/bot/utils/members.py @@ -0,0 +1,47 @@ +import logging +import typing as t + +import discord + +log = logging.getLogger(__name__) + + +async def get_or_fetch_member(guild: discord.Guild, member_id: int) -> t.Optional[discord.Member]: + """ + Attempt to get a member from cache; on failure fetch from the API. + + Return `None` to indicate the member could not be found. + """ + if member := guild.get_member(member_id): + log.trace("%s retrieved from cache.", member) + else: + try: + member = await guild.fetch_member(member_id) + except discord.errors.NotFound: + log.trace("Failed to fetch %d from API.", member_id) + return None + log.trace("%s fetched from API.", member) + return member + + +async def handle_role_change( + member: discord.Member, + coro: t.Callable[..., t.Coroutine], + role: discord.Role +) -> None: + """ + Change `member`'s cooldown role via awaiting `coro` and handle errors. + + `coro` is intended to be `discord.Member.add_roles` or `discord.Member.remove_roles`. + """ + try: + await coro(role) + except discord.NotFound: + log.debug(f"Failed to change role for {member} ({member.id}): member not found") + except discord.Forbidden: + log.debug( + f"Forbidden to change role for {member} ({member.id}); " + f"possibly due to role hierarchy" + ) + except discord.HTTPException as e: + log.error(f"Failed to change role for {member} ({member.id}): {e.status} {e.code}") -- cgit v1.2.3 From 21518aed7b3cfb9c2ec4fa1722689a6c4df56372 Mon Sep 17 00:00:00 2001 From: ChrisLovering Date: Sat, 25 Dec 2021 22:23:12 +0000 Subject: Add hourly task to assign AoC completer role This task uses the cached leaderboard to see who has all 50 stars and assigns them a role to highlight them as completers. --- bot/constants.py | 1 + bot/exts/events/advent_of_code/_cog.py | 60 ++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index 854fbe55..01f825a0 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -291,6 +291,7 @@ class Roles(NamedTuple): helpers = int(environ.get("ROLE_HELPERS", 267630620367257601)) core_developers = 587606783669829632 everyone = int(environ.get("BOT_GUILD", 267624335836053506)) + aoc_completionist = int(environ.get("AOC_COMPLETIONIST_ROLE_ID", 916691790181056532)) class Tokens(NamedTuple): diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 52254ea1..6974d89c 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -7,12 +7,15 @@ from typing import Optional import arrow import discord from async_rediscache import RedisCache -from discord.ext import commands +from discord.ext import commands, tasks 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, Client, 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 import members from bot.utils.decorators import InChannelCheckFailure, in_month, whitelist_override, with_role from bot.utils.extensions import invoke_help_command @@ -31,6 +34,7 @@ class AdventOfCode(commands.Cog): """Advent of Code festivities! Ho Ho Ho!""" # Redis Cache for linking Discord IDs to Advent of Code usernames + # RedisCache[member_id: aoc_username_string] account_links = RedisCache() def __init__(self, bot: Bot): @@ -52,6 +56,57 @@ class AdventOfCode(commands.Cog): self.status_task.set_name("AoC Status Countdown") self.status_task.add_done_callback(_helpers.background_task_callback) + self.completionist_task.start() + + @tasks.loop(minutes=10.0) + async def completionist_task(self) -> None: + """ + Give members who have completed all 50 AoC stars the completionist role. + + Runs on a schedule, as defined in the task.loop decorator. + """ + await self.bot.wait_until_guild_available() + guild = self.bot.get_guild(Client.guild) + completionist_role = guild.get_role(Roles.aoc_completionist) + if completionist_role is None: + log.warning("Could not find the AoC completionist role; cancelling completionist task.") + self.completer_task.cancel() + return + + aoc_name_to_member_id = { + aoc_name: member_id + for member_id, aoc_name in await self.account_links.items() + } + + try: + leaderboard = await _helpers.fetch_leaderboard() + except _helpers.FetchingLeaderboardFailedError: + await self.bot.send_log("Unable to fetch AoC leaderboard during role sync.") + return + + placement_leaderboard = json.loads(leaderboard["placement_leaderboard"]) + + for member_aoc_info in placement_leaderboard.values(): + if not member_aoc_info["stars"] == 50: + # Only give the role to people who have completed all 50 stars + continue + + member_id = aoc_name_to_member_id[member_aoc_info["name"]] + if not member_id: + continue + + member = members.get_or_fetch_member(guild, member_id) + if member is None: + continue + + if completionist_role in member.roles: + continue + + if await self.completionist_block_list.contains(member_id): + continue + + await members.handle_role_change(member, member.add_roles, completionist_role) + @commands.group(name="adventofcode", aliases=("aoc",)) @whitelist_override(channels=AOC_WHITELIST) async def adventofcode_group(self, ctx: commands.Context) -> None: @@ -408,6 +463,7 @@ class AdventOfCode(commands.Cog): log.debug("Unloading the cog and canceling the background task.") self.notification_task.cancel() self.status_task.cancel() + self.completionist_task.cancel() def _build_about_embed(self) -> discord.Embed: """Build and return the informational "About AoC" embed from the resources file.""" -- cgit v1.2.3 From e44460d56364ff45ab19352af9719da5def4161f Mon Sep 17 00:00:00 2001 From: ChrisLovering Date: Sat, 25 Dec 2021 22:28:10 +0000 Subject: Ability to block users from AoC completer role --- bot/exts/events/advent_of_code/_cog.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 6974d89c..67d43556 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -37,6 +37,10 @@ class AdventOfCode(commands.Cog): # RedisCache[member_id: aoc_username_string] account_links = RedisCache() + # A dict with keys of member_ids to block from getting the role + # RedisCache[member_id: None] + completionist_block_list = RedisCache() + def __init__(self, bot: Bot): self.bot = bot @@ -91,11 +95,11 @@ class AdventOfCode(commands.Cog): # Only give the role to people who have completed all 50 stars continue - member_id = aoc_name_to_member_id[member_aoc_info["name"]] + member_id = aoc_name_to_member_id.get(member_aoc_info["name"], None) if not member_id: continue - member = members.get_or_fetch_member(guild, member_id) + member = await members.get_or_fetch_member(guild, member_id) if member is None: continue @@ -114,6 +118,19 @@ class AdventOfCode(commands.Cog): if not ctx.invoked_subcommand: await invoke_help_command(ctx) + @with_role(Roles.admins) + @adventofcode_group.command( + name="block", + brief="Block a user from getting the completionist role.", + ) + async def block_from_role(self, ctx: commands.Context, member: discord.Member) -> None: + """Block the given member from receiving the AoC completionist role, removing it from them if needed.""" + completionist_role = ctx.guild.get_role(Roles.aoc_completionist) + if completionist_role in member.roles: + await member.remove_roles(completionist_role) + + await self.completionist_block_list.set(member.id, "sentinel") + @commands.guild_only() @adventofcode_group.command( name="subscribe", -- cgit v1.2.3 From d55cbc8e4ed371f0ca11b97b1dd6e41cf8f6719c Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Tue, 28 Dec 2021 22:20:01 +0000 Subject: Condense conditional logic in AoC completionist role task --- bot/exts/events/advent_of_code/_cog.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 67d43556..9d412adf 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -100,16 +100,11 @@ class AdventOfCode(commands.Cog): continue member = await members.get_or_fetch_member(guild, member_id) - if member is None: + if member is None or completionist_role in member.roles: continue - if completionist_role in member.roles: - continue - - if await self.completionist_block_list.contains(member_id): - continue - - await members.handle_role_change(member, member.add_roles, completionist_role) + if not await self.completionist_block_list.contains(member_id): + await members.handle_role_change(member, member.add_roles, completionist_role) @commands.group(name="adventofcode", aliases=("aoc",)) @whitelist_override(channels=AOC_WHITELIST) -- cgit v1.2.3 From dc2e3a72cf7958d9410d3b1f1e9d13d1eadcef89 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Tue, 28 Dec 2021 22:41:20 +0000 Subject: Inform invoker after successfully blocking a user from AoC comp. role --- bot/exts/events/advent_of_code/_cog.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 9d412adf..30bcaae6 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -125,6 +125,7 @@ class AdventOfCode(commands.Cog): await member.remove_roles(completionist_role) await self.completionist_block_list.set(member.id, "sentinel") + await ctx.send(f":+1: Blocked {member.mention} from getting the AoC completionist role.") @commands.guild_only() @adventofcode_group.command( -- cgit v1.2.3 From 4ecec867d9f1d06f23d7fd7216dd0902de82cfa0 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 29 Dec 2021 13:34:24 +0000 Subject: Add logging to AoC role task to help debugging issues --- bot/exts/events/advent_of_code/_cog.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 30bcaae6..c597fd0e 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -74,7 +74,7 @@ class AdventOfCode(commands.Cog): completionist_role = guild.get_role(Roles.aoc_completionist) if completionist_role is None: log.warning("Could not find the AoC completionist role; cancelling completionist task.") - self.completer_task.cancel() + self.completionist_task.cancel() return aoc_name_to_member_id = { @@ -97,13 +97,20 @@ class AdventOfCode(commands.Cog): member_id = aoc_name_to_member_id.get(member_aoc_info["name"], None) if not member_id: + log.debug(f"Could not find member_id for {member_aoc_info['name']}, not giving role.") continue member = await members.get_or_fetch_member(guild, member_id) - if member is None or completionist_role in member.roles: + if member is None: + log.debug(f"Could not find {member_id}, not giving role.") + continue + + if completionist_role in member.roles: + log.debug(f"{member.name} ({member.mention}) already has the completionist role.") continue if not await self.completionist_block_list.contains(member_id): + log.debug(f"Giving completionist role to {member.name} ({member.mention}).") await members.handle_role_change(member, member.add_roles, completionist_role) @commands.group(name="adventofcode", aliases=("aoc",)) -- cgit v1.2.3 From 0c043c825482578e4a940ce2a8f0d4b5a952fe29 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 29 Dec 2021 13:35:10 +0000 Subject: Raise error when bot can't modify the given role in member helper util --- bot/utils/members.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/utils/members.py b/bot/utils/members.py index 9c8c8dd8..de5850ca 100644 --- a/bot/utils/members.py +++ b/bot/utils/members.py @@ -39,7 +39,7 @@ async def handle_role_change( except discord.NotFound: log.debug(f"Failed to change role for {member} ({member.id}): member not found") except discord.Forbidden: - log.debug( + log.error( f"Forbidden to change role for {member} ({member.id}); " f"possibly due to role hierarchy" ) -- cgit v1.2.3