├── .gitignore ├── .env ├── README.md ├── Pipfile ├── zappa_settings.json ├── metaicon.py └── Pipfile.lock /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | FLASK_APP=metaicon.py -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Quickly grab a 32x32 icon for a domain. 2 | 3 | e.g.: https://i6mk4l2o3i.execute-api.ap-southeast-2.amazonaws.com/dev/api/news.ycombinator.com/32.png 4 | 5 | Built with Flask, Zappa, BeautifulSoup and Pillow. -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | 3 | url = "https://pypi.python.org/simple" 4 | verify_ssl = true 5 | name = "pypi" 6 | 7 | 8 | [packages] 9 | 10 | pillow = "*" 11 | flask = "*" 12 | zappa = "*" 13 | requests = "*" 14 | "beautifulsoup4" = "*" 15 | 16 | 17 | [requires] 18 | 19 | python_version = "3.7" 20 | -------------------------------------------------------------------------------- /zappa_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "app_function": "metaicon.app", 4 | "aws_region": "ap-southeast-2", 5 | "profile_name": "default", 6 | "project_name": "metaicon", 7 | "runtime": "python3.7", 8 | "s3_bucket": "zappa-3hjx9xj4s", 9 | "cors": true, 10 | "timeout_seconds": 10, 11 | "log_level": "INFO", 12 | "memory_size": 192 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /metaicon.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import logging 3 | import json 4 | import re 5 | import time 6 | import sys 7 | import hashlib 8 | 9 | from io import BytesIO 10 | from urllib.parse import urljoin 11 | 12 | import requests 13 | from bs4 import BeautifulSoup 14 | 15 | from PIL import Image, ImageDraw 16 | 17 | from flask import Flask, send_file 18 | 19 | from popular.icons import POPULAR_ICONS 20 | 21 | 22 | app = Flask(__name__) 23 | 24 | logging.basicConfig() 25 | logging.getLogger().setLevel(logging.INFO) 26 | 27 | def get(url): 28 | return requests.get( 29 | url, 30 | headers={ 31 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0" 32 | }, 33 | timeout=2, 34 | ) 35 | 36 | @app.route("/") 37 | def home(): 38 | return "Nothing to see here." 39 | 40 | 41 | @app.route("/api//32.png") 42 | def metaicon(domain): 43 | if not is_valid_hostname(domain): 44 | logging.info(f"Request for invalid hostname: {domain}") 45 | return ("Invalid hostname", 400) 46 | 47 | try: 48 | b = get_popular_icon(domain) 49 | 50 | if not b: 51 | b = get_icon(domain) 52 | 53 | if b: 54 | b.seek(0) 55 | return send_file(b, mimetype="image/png") 56 | except Exception as e: 57 | logging.warn(e) 58 | b = get_default_image(domain) 59 | return send_file(b, mimetype="image/png") 60 | 61 | 62 | def get_default_image(domain): 63 | logging.info(f'Using "default" image for {domain}') 64 | m = hashlib.sha256() 65 | m.update(domain.encode()) 66 | colour = m.hexdigest()[:6] 67 | 68 | i = Image.new('RGB', (32, 32)) 69 | d = ImageDraw.Draw(i) 70 | d.rectangle([0, 0, 32, 32], f'#{colour}', f'#{colour}') 71 | 72 | b = BytesIO() 73 | i.save(b, "PNG") 74 | b.seek(0) 75 | return b 76 | 77 | def get_popular_icon(domain): 78 | result = POPULAR_ICONS.get(domain) 79 | 80 | if not result: 81 | result = POPULAR_ICONS.get('www.' + domain) 82 | 83 | if result: 84 | logging.info(f'Cache hit for domain: {domain}') 85 | return BytesIO(base64.b64decode(result)) 86 | 87 | 88 | def get_icon(domain): 89 | start = time.time() 90 | logging.info(f"Getting content from {domain}") 91 | 92 | try: 93 | response = get(f"https://{domain}") 94 | except: 95 | response = get(f"http://{domain}") 96 | 97 | html = BeautifulSoup(response.content, features="html.parser") 98 | logging.info(f"Content received {time.time() - start}") 99 | 100 | icons = [] 101 | for icon in html.find_all("link"): 102 | rel = icon.attrs.get("rel", []) 103 | rel = [x.lower() for x in rel] 104 | 105 | if any([x in rel for x in ["icon", "apple-touch-icon"]]): 106 | href = icon.attrs.get("href") 107 | if not href or href.endswith(".svg"): 108 | continue 109 | icons.append(icon) 110 | 111 | if not icons: 112 | favicon_url = urljoin(response.url, "favicon.ico") 113 | logging.info(f"Defaulting to favicon url {favicon_url} {time.time() - start}") 114 | r = get(favicon_url) 115 | 116 | if r.status_code != 200: 117 | return 118 | else: 119 | icon_url = icons[0].attrs["href"] 120 | if "://" not in icon_url: 121 | icon_url = urljoin(response.url, icon_url) 122 | 123 | logging.info(f"{icon_url} {time.time() - start}") 124 | r = get(icon_url) 125 | 126 | i = Image.open(BytesIO(r.content)) 127 | i = i.resize((32, 32), resample=Image.BICUBIC) 128 | 129 | logging.info(f"{i.size} {time.time() - start}") 130 | 131 | b = BytesIO() 132 | i.save(b, "PNG") 133 | 134 | logging.info(f"Done {time.time() - start}") 135 | return b 136 | 137 | 138 | def is_valid_hostname(hostname): 139 | if len(hostname) > 255: 140 | return False 141 | if hostname[-1] == ".": 142 | hostname = hostname[:-1] # strip exactly one dot from the right, if present 143 | allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?= '3.7'", 41 | "version": "==1.26.25" 42 | }, 43 | "botocore": { 44 | "hashes": [ 45 | "sha256:a204140c9d7adadf3919d8024d79278f1865a20c869e4f216eaea599ca3a1743", 46 | "sha256:cb489ca8fbc043cd9bf901e3e105f0dec316ed438ee883e55c9f9c77bd0f6a2d" 47 | ], 48 | "markers": "python_version >= '3.7'", 49 | "version": "==1.29.25" 50 | }, 51 | "certifi": { 52 | "hashes": [ 53 | "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", 54 | "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" 55 | ], 56 | "index": "pypi", 57 | "version": "==2022.12.7" 58 | }, 59 | "cfn-flip": { 60 | "hashes": [ 61 | "sha256:003e02a089c35e1230ffd0e1bcfbbc4b12cc7d2deb2fcc6c4228ac9819307362", 62 | "sha256:faca8e77f0d32fb84cce1db1ef4c18b14a325d31125dae73c13bcc01947d2722" 63 | ], 64 | "version": "==1.3.0" 65 | }, 66 | "chardet": { 67 | "hashes": [ 68 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 69 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 70 | ], 71 | "version": "==3.0.4" 72 | }, 73 | "click": { 74 | "hashes": [ 75 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", 76 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" 77 | ], 78 | "markers": "python_version >= '3.7'", 79 | "version": "==8.1.3" 80 | }, 81 | "docutils": { 82 | "hashes": [ 83 | "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6", 84 | "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc" 85 | ], 86 | "markers": "python_version >= '3.7'", 87 | "version": "==0.19" 88 | }, 89 | "durationpy": { 90 | "hashes": [ 91 | "sha256:5ef9416b527b50d722f34655becfb75e49228eb82f87b855ed1911b3314b5408" 92 | ], 93 | "version": "==0.5" 94 | }, 95 | "flask": { 96 | "hashes": [ 97 | "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", 98 | "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" 99 | ], 100 | "index": "pypi", 101 | "version": "==1.1.1" 102 | }, 103 | "future": { 104 | "hashes": [ 105 | "sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb" 106 | ], 107 | "version": "==0.16.0" 108 | }, 109 | "hjson": { 110 | "hashes": [ 111 | "sha256:1d1727faa6aaef2973921877125a3ab7c5f6d34b93233179d01770f41fab51f9", 112 | "sha256:febbfbd43e64d2a822efe8b6c720683954b48c0bb1532170c05a7fc8470d3426" 113 | ], 114 | "version": "==3.0.1" 115 | }, 116 | "idna": { 117 | "hashes": [ 118 | "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", 119 | "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" 120 | ], 121 | "version": "==2.8" 122 | }, 123 | "importlib-metadata": { 124 | "hashes": [ 125 | "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b", 126 | "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313" 127 | ], 128 | "markers": "python_version < '3.8'", 129 | "version": "==5.1.0" 130 | }, 131 | "itsdangerous": { 132 | "hashes": [ 133 | "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", 134 | "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" 135 | ], 136 | "markers": "python_version >= '3.7'", 137 | "version": "==2.1.2" 138 | }, 139 | "jinja2": { 140 | "hashes": [ 141 | "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", 142 | "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" 143 | ], 144 | "markers": "python_version >= '3.7'", 145 | "version": "==3.1.2" 146 | }, 147 | "jmespath": { 148 | "hashes": [ 149 | "sha256:6a81d4c9aa62caf061cb517b4d9ad1dd300374cd4706997aff9cd6aedd61fc64", 150 | "sha256:f11b4461f425740a1d908e9a3f7365c3d2e569f6ca68a2ff8bc5bcd9676edd63" 151 | ], 152 | "version": "==0.9.3" 153 | }, 154 | "kappa": { 155 | "hashes": [ 156 | "sha256:4b5b372872f25d619e427e04282551048dc975a107385b076b3ffc6406a15833", 157 | "sha256:4d6b7b3accce4a0aaaac92b36237a6304f0f2fffbbe3caea3f7c9f52d12c9989" 158 | ], 159 | "version": "==0.6.0" 160 | }, 161 | "lambda-packages": { 162 | "hashes": [ 163 | "sha256:b5e3b81ecef5f7c1b0903b5c40813536ba2343a33868a567e4e4ff1e26243406" 164 | ], 165 | "version": "==0.20.0" 166 | }, 167 | "markupsafe": { 168 | "hashes": [ 169 | "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", 170 | "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", 171 | "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", 172 | "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", 173 | "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", 174 | "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", 175 | "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", 176 | "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", 177 | "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", 178 | "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", 179 | "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", 180 | "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", 181 | "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", 182 | "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", 183 | "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", 184 | "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", 185 | "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", 186 | "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", 187 | "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", 188 | "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", 189 | "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", 190 | "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", 191 | "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", 192 | "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", 193 | "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", 194 | "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", 195 | "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", 196 | "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", 197 | "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", 198 | "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", 199 | "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", 200 | "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", 201 | "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", 202 | "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", 203 | "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", 204 | "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", 205 | "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", 206 | "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", 207 | "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", 208 | "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" 209 | ], 210 | "markers": "python_version >= '3.7'", 211 | "version": "==2.1.1" 212 | }, 213 | "pillow": { 214 | "hashes": [ 215 | "sha256:047d9473cf68af50ac85f8ee5d5f21a60f849bc17d348da7fc85711287a75031", 216 | "sha256:0f66dc6c8a3cc319561a633b6aa82c44107f12594643efa37210d8c924fc1c71", 217 | "sha256:12c9169c4e8fe0a7329e8658c7e488001f6b4c8e88740e76292c2b857af2e94c", 218 | "sha256:248cffc168896982f125f5c13e9317c059f74fffdb4152893339f3be62a01340", 219 | "sha256:27faf0552bf8c260a5cee21a76e031acaea68babb64daf7e8f2e2540745082aa", 220 | "sha256:285edafad9bc60d96978ed24d77cdc0b91dace88e5da8c548ba5937c425bca8b", 221 | "sha256:384b12c9aa8ef95558abdcb50aada56d74bc7cc131dd62d28c2d0e4d3aadd573", 222 | "sha256:38950b3a707f6cef09cd3cbb142474357ad1a985ceb44d921bdf7b4647b3e13e", 223 | "sha256:4aad1b88933fd6dc2846552b89ad0c74ddbba2f0884e2c162aa368374bf5abab", 224 | "sha256:4ac6148008c169603070c092e81f88738f1a0c511e07bd2bb0f9ef542d375da9", 225 | "sha256:4deb1d2a45861ae6f0b12ea0a786a03d19d29edcc7e05775b85ec2877cb54c5e", 226 | "sha256:59aa2c124df72cc75ed72c8d6005c442d4685691a30c55321e00ed915ad1a291", 227 | "sha256:5a47d2123a9ec86660fe0e8d0ebf0aa6bc6a17edc63f338b73ea20ba11713f12", 228 | "sha256:5cc901c2ab9409b4b7ac7b5bcc3e86ac14548627062463da0af3b6b7c555a871", 229 | "sha256:6c1db03e8dff7b9f955a0fb9907eb9ca5da75b5ce056c0c93d33100a35050281", 230 | "sha256:7ce80c0a65a6ea90ef9c1f63c8593fcd2929448613fc8da0adf3e6bfad669d08", 231 | "sha256:809c19241c14433c5d6135e1b6c72da4e3b56d5c865ad5736ab99af8896b8f41", 232 | "sha256:83792cb4e0b5af480588601467c0764242b9a483caea71ef12d22a0d0d6bdce2", 233 | "sha256:846fa202bd7ee0f6215c897a1d33238ef071b50766339186687bd9b7a6d26ac5", 234 | "sha256:9f5529fc02009f96ba95bea48870173426879dc19eec49ca8e08cd63ecd82ddb", 235 | "sha256:a423c2ea001c6265ed28700df056f75e26215fd28c001e93ef4380b0f05f9547", 236 | "sha256:ac4428094b42907aba5879c7c000d01c8278d451a3b7cccd2103e21f6397ea75", 237 | "sha256:b1ae48d87f10d1384e5beecd169c77502fcc04a2c00a4c02b85f0a94b419e5f9", 238 | "sha256:bf4e972a88f8841d8fdc6db1a75e0f8d763e66e3754b03006cbc3854d89f1cb1", 239 | "sha256:c6414f6aad598364aaf81068cabb077894eb88fed99c6a65e6e8217bab62ae7a", 240 | "sha256:c710fcb7ee32f67baf25aa9ffede4795fd5d93b163ce95fdc724383e38c9df96", 241 | "sha256:c7be4b8a09852291c3c48d3c25d1b876d2494a0a674980089ac9d5e0d78bd132", 242 | "sha256:c9e5ffb910b14f090ac9c38599063e354887a5f6d7e6d26795e916b4514f2c1a", 243 | "sha256:e0697b826da6c2472bb6488db4c0a7fa8af0d52fa08833ceb3681358914b14e5", 244 | "sha256:e9a3edd5f714229d41057d56ac0f39ad9bdba6767e8c888c951869f0bdd129b0" 245 | ], 246 | "index": "pypi", 247 | "version": "==6.2.1" 248 | }, 249 | "pip": { 250 | "hashes": [ 251 | "sha256:65fd48317359f3af8e593943e6ae1506b66325085ea64b706a998c6e83eeaf38", 252 | "sha256:908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077" 253 | ], 254 | "markers": "python_version >= '3.7'", 255 | "version": "==22.3.1" 256 | }, 257 | "placebo": { 258 | "hashes": [ 259 | "sha256:390db04f3f3486790b583dc18cb0bc116f195f196d4e58195adb4bb543ebe0bd" 260 | ], 261 | "version": "==0.10.0" 262 | }, 263 | "python-dateutil": { 264 | "hashes": [ 265 | "sha256:891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca", 266 | "sha256:95511bae634d69bc7329ba55e646499a842bc4ec342ad54a8cdb65645a0aad3c" 267 | ], 268 | "markers": "python_version >= '2.7'", 269 | "version": "==2.6.1" 270 | }, 271 | "python-slugify": { 272 | "hashes": [ 273 | "sha256:57a385df7a1c6dbd15f7666eaff0ff29d3f60363b228b1197c5308ed3ba5f824", 274 | "sha256:c3733135d3b184196fdb8844f6a74bbfb9cf6720d1dcce3254bdc434353f938f" 275 | ], 276 | "version": "==1.2.4" 277 | }, 278 | "pyyaml": { 279 | "hashes": [ 280 | "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", 281 | "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", 282 | "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", 283 | "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", 284 | "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", 285 | "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", 286 | "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", 287 | "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", 288 | "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", 289 | "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", 290 | "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", 291 | "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", 292 | "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", 293 | "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", 294 | "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", 295 | "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", 296 | "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", 297 | "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", 298 | "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", 299 | "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", 300 | "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", 301 | "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", 302 | "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", 303 | "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", 304 | "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", 305 | "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", 306 | "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", 307 | "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", 308 | "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", 309 | "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", 310 | "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", 311 | "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", 312 | "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", 313 | "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", 314 | "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", 315 | "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", 316 | "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", 317 | "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", 318 | "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", 319 | "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" 320 | ], 321 | "markers": "python_version >= '3.6'", 322 | "version": "==6.0" 323 | }, 324 | "requests": { 325 | "hashes": [ 326 | "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", 327 | "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" 328 | ], 329 | "index": "pypi", 330 | "version": "==2.22.0" 331 | }, 332 | "s3transfer": { 333 | "hashes": [ 334 | "sha256:06176b74f3a15f61f1b4f25a1fc29a4429040b7647133a463da8fa5bd28d5ecd", 335 | "sha256:2ed07d3866f523cc561bf4a00fc5535827981b117dd7876f036b0c1aca42c947" 336 | ], 337 | "markers": "python_version >= '3.7'", 338 | "version": "==0.6.0" 339 | }, 340 | "six": { 341 | "hashes": [ 342 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 343 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 344 | ], 345 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 346 | "version": "==1.16.0" 347 | }, 348 | "soupsieve": { 349 | "hashes": [ 350 | "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759", 351 | "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d" 352 | ], 353 | "markers": "python_version >= '3.6'", 354 | "version": "==2.3.2.post1" 355 | }, 356 | "toml": { 357 | "hashes": [ 358 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 359 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 360 | ], 361 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 362 | "version": "==0.10.2" 363 | }, 364 | "tqdm": { 365 | "hashes": [ 366 | "sha256:ba650e08b8b102923a05896bf9d7e1c9cdc20b484156df0511a4bbf1f6b6f89b", 367 | "sha256:fa6d2ea6285f56e75d7efe9259805deadc450f16066a1f82ad0629ea9be2cd0f" 368 | ], 369 | "version": "==4.19.1" 370 | }, 371 | "troposphere": { 372 | "hashes": [ 373 | "sha256:97569622767326cff9526496edb55073b9c19feb2cdda273c237385d97cd3ac6", 374 | "sha256:a6b3d91cfdaa764fa2784c0afddc921360814f8853ada897397670c4fa4f83d1" 375 | ], 376 | "markers": "python_version >= '3.7'", 377 | "version": "==4.2.0" 378 | }, 379 | "typing-extensions": { 380 | "hashes": [ 381 | "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", 382 | "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" 383 | ], 384 | "markers": "python_version < '3.8'", 385 | "version": "==4.4.0" 386 | }, 387 | "unidecode": { 388 | "hashes": [ 389 | "sha256:547d7c479e4f377b430dd91ac1275d593308dce0fc464fb2ab7d41f82ec653be", 390 | "sha256:fed09cf0be8cf415b391642c2a5addfc72194407caee4f98719e40ec2a72b830" 391 | ], 392 | "markers": "python_version >= '3.5'", 393 | "version": "==1.3.6" 394 | }, 395 | "urllib3": { 396 | "hashes": [ 397 | "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2", 398 | "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e" 399 | ], 400 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", 401 | "version": "==1.25.11" 402 | }, 403 | "werkzeug": { 404 | "hashes": [ 405 | "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f", 406 | "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5" 407 | ], 408 | "markers": "python_version >= '3.7'", 409 | "version": "==2.2.2" 410 | }, 411 | "wheel": { 412 | "hashes": [ 413 | "sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac", 414 | "sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8" 415 | ], 416 | "markers": "python_version >= '3.7'", 417 | "version": "==0.38.4" 418 | }, 419 | "wsgi-request-logger": { 420 | "hashes": [ 421 | "sha256:445d7ec52799562f812006394d0b4a7064b37084c6ea6bd74ea7a2136c97ed83" 422 | ], 423 | "version": "==0.4.6" 424 | }, 425 | "zappa": { 426 | "hashes": [ 427 | "sha256:621209ceaf2cf5fcc18ed6bb6cf53aeb2315e38989a6929cbb49c66b5454d656", 428 | "sha256:86b125c0e9696b177f61bf636ab19ead7aba1bb9281cdba0651825358337008e", 429 | "sha256:b7a04172407cdb9277cb166b42920d3c5d745fd50204d1ce7f42769e61b6649e" 430 | ], 431 | "index": "pypi", 432 | "version": "==0.48.2" 433 | }, 434 | "zipp": { 435 | "hashes": [ 436 | "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa", 437 | "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766" 438 | ], 439 | "markers": "python_version >= '3.7'", 440 | "version": "==3.11.0" 441 | } 442 | }, 443 | "develop": {} 444 | } 445 | --------------------------------------------------------------------------------