├── .gitignore ├── Pipfile ├── Pipfile.lock ├── README.md ├── app ├── __init__.py ├── __main__.py ├── common │ ├── __init__.py │ ├── clean_data.py │ ├── convert_to_geo_json.py │ └── parameters.py ├── data │ └── richest.png ├── imperative │ ├── playwright_runner.py │ ├── selenium_multi_runner.py │ ├── selenium_runner.py │ └── selenium_singleton_runner.py ├── pipeline │ ├── base.py │ ├── playwright.py │ └── selenium.py ├── playwright_based │ ├── __init__.py │ ├── compile_profile.py │ ├── generate_map.py │ ├── get_coordinates.py │ └── process_profile.py ├── run_benchmark.py ├── selenium_based │ ├── __init__.py │ ├── compile_profile.py │ ├── generate_map.py │ ├── get_coordinates.py │ ├── process_profile.py │ └── utils.py └── tests │ └── create_test.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | temp* 2 | .vscode 3 | .venv 4 | .neptune 5 | tmp* 6 | *__pycache__* 7 | */.env 8 | wandb -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | selenium = ">=3.141.0" 8 | helium = ">=3.0.7" 9 | webdriver-manager = ">=3.4.2" 10 | playwright = ">=1.14.1" 11 | dagster = ">=0.12.8" 12 | dagit = ">=0.12.8" 13 | tenacity = ">=8.0.1" 14 | mpire = ">=2.2.1" 15 | neptune-client = ">=0.10.8" 16 | python-dotenv = ">=0.19.0" 17 | wandb = ">=0.12.1" 18 | 19 | [dev-packages] 20 | 21 | [requires] 22 | python_version = "3.8" 23 | 24 | [scripts] 25 | playwright = "python -m app playwright" 26 | selenium = "python -m app selenium" 27 | selenium_single = "python -m app selenium_single" 28 | selenium_multi = "python -m app selenium_multi" 29 | selenium_dagster = "python -m app selenium_dagster" 30 | playwright_dagster = "python -m app playwright_dagster" 31 | benchmark = "python -m app.run_benchmark" 32 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "25efbe395ef482616c79d6f2bff80254a441e8b430fe8da7cf29b1fdc683c148" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "alembic": { 20 | "hashes": [ 21 | "sha256:a21fedebb3fb8f6bbbba51a11114f08c78709377051384c9c5ead5705ee93a51", 22 | "sha256:e78be5b919f5bb184e3e0e2dd1ca986f2362e29a2bc933c446fe89f39dbe4e9c" 23 | ], 24 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 25 | "version": "==1.6.5" 26 | }, 27 | "aniso8601": { 28 | "hashes": [ 29 | "sha256:513d2b6637b7853806ae79ffaca6f3e8754bdd547048f5ccc1420aec4b714f1e", 30 | "sha256:d10a4bf949f619f719b227ef5386e31f49a2b6d453004b21f02661ccc8670c7b" 31 | ], 32 | "version": "==7.0.0" 33 | }, 34 | "attrs": { 35 | "hashes": [ 36 | "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", 37 | "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" 38 | ], 39 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 40 | "version": "==21.2.0" 41 | }, 42 | "bleach": { 43 | "hashes": [ 44 | "sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da", 45 | "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994" 46 | ], 47 | "markers": "python_version >= '3.6'", 48 | "version": "==4.1.0" 49 | }, 50 | "bravado": { 51 | "hashes": [ 52 | "sha256:1bb6ef75d84140c851fffe6420baaee5037d840070cfe11d60913be6ab8e0530", 53 | "sha256:8ac8bbb645e49607917a5c07808116c708521f51e80d9c29bc4a168ff4dd22c6" 54 | ], 55 | "markers": "python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 56 | "version": "==11.0.3" 57 | }, 58 | "bravado-core": { 59 | "hashes": [ 60 | "sha256:b3b06ae86d3c80de5694340e55df7c9097857ff965b76642979e2a961f332abf", 61 | "sha256:fa53e796ea574f905635a43871439a44713c2ef128c62a8fcc1d0ca8765cf855" 62 | ], 63 | "markers": "python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 64 | "version": "==5.17.0" 65 | }, 66 | "certifi": { 67 | "hashes": [ 68 | "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", 69 | "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" 70 | ], 71 | "version": "==2021.5.30" 72 | }, 73 | "cffi": { 74 | "hashes": [ 75 | "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d", 76 | "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771", 77 | "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872", 78 | "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c", 79 | "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc", 80 | "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762", 81 | "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202", 82 | "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5", 83 | "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548", 84 | "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a", 85 | "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f", 86 | "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20", 87 | "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218", 88 | "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c", 89 | "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e", 90 | "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56", 91 | "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224", 92 | "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a", 93 | "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2", 94 | "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a", 95 | "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819", 96 | "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346", 97 | "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b", 98 | "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e", 99 | "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534", 100 | "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb", 101 | "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0", 102 | "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156", 103 | "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd", 104 | "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87", 105 | "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc", 106 | "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195", 107 | "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33", 108 | "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f", 109 | "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d", 110 | "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd", 111 | "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728", 112 | "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7", 113 | "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca", 114 | "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99", 115 | "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf", 116 | "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e", 117 | "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c", 118 | "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5", 119 | "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69" 120 | ], 121 | "markers": "platform_python_implementation == 'CPython' and sys_platform == 'win32'", 122 | "version": "==1.14.6" 123 | }, 124 | "charset-normalizer": { 125 | "hashes": [ 126 | "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b", 127 | "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3" 128 | ], 129 | "markers": "python_version >= '3'", 130 | "version": "==2.0.4" 131 | }, 132 | "click": { 133 | "hashes": [ 134 | "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", 135 | "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" 136 | ], 137 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 138 | "version": "==7.1.2" 139 | }, 140 | "colorama": { 141 | "hashes": [ 142 | "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", 143 | "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" 144 | ], 145 | "markers": "platform_system == 'Windows'", 146 | "version": "==0.4.4" 147 | }, 148 | "coloredlogs": { 149 | "hashes": [ 150 | "sha256:346f58aad6afd48444c2468618623638dadab76e4e70d5e10822676f2d32226a", 151 | "sha256:a1fab193d2053aa6c0a97608c4342d031f1f93a3d1218432c59322441d31a505" 152 | ], 153 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 154 | "version": "==14.0" 155 | }, 156 | "configparser": { 157 | "hashes": [ 158 | "sha256:85d5de102cfe6d14a5172676f09d19c465ce63d6019cf0a4ef13385fc535e828", 159 | "sha256:af59f2cdd7efbdd5d111c1976ecd0b82db9066653362f0962d7bf1d3ab89a1fa" 160 | ], 161 | "markers": "python_version >= '3.6'", 162 | "version": "==5.0.2" 163 | }, 164 | "crayons": { 165 | "hashes": [ 166 | "sha256:bd33b7547800f2cfbd26b38431f9e64b487a7de74a947b0fafc89b45a601813f", 167 | "sha256:e73ad105c78935d71fe454dd4b85c5c437ba199294e7ffd3341842bc683654b1" 168 | ], 169 | "version": "==0.4.0" 170 | }, 171 | "croniter": { 172 | "hashes": [ 173 | "sha256:0f97b361fe343301a8f66f852e7d84e4fb7f21379948f71e1bbfe10f5d015fbd", 174 | "sha256:a70dfc9d52de9fc1a886128b9148c89dd9e76b67d55f46516ca94d2d73d58219" 175 | ], 176 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 177 | "version": "==1.0.15" 178 | }, 179 | "dagit": { 180 | "hashes": [ 181 | "sha256:8f93381fa0c4c6dd0ce6b2b2b0482c458add728eb3e11eb873f45b0caee19eb8", 182 | "sha256:c9c9f1194e5a8b5361bd08bc84f477a77e9a0d31d23b24cf5640f415dffdfb58" 183 | ], 184 | "index": "pypi", 185 | "version": "==0.12.9" 186 | }, 187 | "dagster": { 188 | "hashes": [ 189 | "sha256:90c809cabe46adb47e23d3a99bfeb90f6d02f24059ea3b7eb92d82718f445370", 190 | "sha256:9c26042cc08f9a0fa5694a9de9f048d7a14c5887086ec7400586d56a55fe5323" 191 | ], 192 | "index": "pypi", 193 | "version": "==0.12.9" 194 | }, 195 | "dagster-graphql": { 196 | "hashes": [ 197 | "sha256:14e73eb59f3da47e0c0589f4dd6965d6ed9c36cfd2c4f8cc7fe7d47ab50cdf5e", 198 | "sha256:8e6b9b5a6964f992e00b2355d78ed11573f202a23a17499e45b851aeecadedce" 199 | ], 200 | "version": "==0.12.9" 201 | }, 202 | "defusedxml": { 203 | "hashes": [ 204 | "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", 205 | "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" 206 | ], 207 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 208 | "version": "==0.7.1" 209 | }, 210 | "docker-pycreds": { 211 | "hashes": [ 212 | "sha256:6ce3270bcaf404cc4c3e27e4b6c70d3521deae82fb508767870fdbf772d584d4", 213 | "sha256:7266112468627868005106ec19cd0d722702d2b7d5912a28e19b826c3d37af49" 214 | ], 215 | "version": "==0.4.0" 216 | }, 217 | "docstring-parser": { 218 | "hashes": [ 219 | "sha256:d75c81533f70e3902c54d0cfe5f896b65905772004c1eb9ee38a2526b077940d" 220 | ], 221 | "markers": "python_version >= '3.5'", 222 | "version": "==0.10" 223 | }, 224 | "entrypoints": { 225 | "hashes": [ 226 | "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", 227 | "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451" 228 | ], 229 | "markers": "python_version >= '2.7'", 230 | "version": "==0.3" 231 | }, 232 | "flask": { 233 | "hashes": [ 234 | "sha256:0fbeb6180d383a9186d0d6ed954e0042ad9f18e0e8de088b2b419d526927d196", 235 | "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22" 236 | ], 237 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 238 | "version": "==1.1.4" 239 | }, 240 | "flask-cors": { 241 | "hashes": [ 242 | "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438", 243 | "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de" 244 | ], 245 | "version": "==3.0.10" 246 | }, 247 | "flask-graphql": { 248 | "hashes": [ 249 | "sha256:825578c044df436cd74503a38bbd31c919a90acda5e9b6e0e45736964bc5235d" 250 | ], 251 | "version": "==2.0.1" 252 | }, 253 | "flask-sockets": { 254 | "hashes": [ 255 | "sha256:072927da8edca0e81e024f5787e643c87d80b351b714de95d723becb30e0643b", 256 | "sha256:350a76d55f5889f64afd2ca9b32f262680b7960965f0830365576307d30cfe1e" 257 | ], 258 | "version": "==0.2.1" 259 | }, 260 | "future": { 261 | "hashes": [ 262 | "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" 263 | ], 264 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 265 | "version": "==0.18.2" 266 | }, 267 | "gevent": { 268 | "hashes": [ 269 | "sha256:02d1e8ca227d0ab0b7917fd7e411f9a534475e0a41fb6f434e9264b20155201a", 270 | "sha256:0c7b4763514fec74c9fe6ad10c3de62d8fe7b926d520b1e35eb6887181b954ff", 271 | "sha256:1c9c87b15f792af80edc950a83ab8ef4f3ba3889712211c2c42740ddb57b5492", 272 | "sha256:23077d87d1589ac141c22923fd76853d2cc5b7e3c5e1f1f9cdf6ff23bc9790fc", 273 | "sha256:37a469a99e6000b42dd0b9bbd9d716dbd66cdc6e5738f136f6a266c29b90ee99", 274 | "sha256:3b600145dc0c5b39c6f89c2e91ec6c55eb0dd52dc8148228479ca42cded358e4", 275 | "sha256:3f5ba654bdd3c774079b553fef535ede5b52c7abd224cb235a15da90ae36251b", 276 | "sha256:43e93e1a4738c922a2416baf33f0afb0a20b22d3dba886720bc037cd02a98575", 277 | "sha256:473f918bdf7d2096e391f66bd8ce1e969639aa235e710aaf750a37774bb585bd", 278 | "sha256:4c94d27be9f0439b28eb8bd0f879e6142918c62092fda7fb96b6d06f01886b94", 279 | "sha256:55ede95f41b74e7506fab293ad04cc7fc2b6f662b42281e9f2d668ad3817b574", 280 | "sha256:6cad37a55e904879beef2a7e7c57c57d62fde2331fef1bec7f2b2a7ef14da6a2", 281 | "sha256:72d4c2a8e65bbc702db76456841c7ddd6de2d9ab544a24aa74ad9c2b6411a269", 282 | "sha256:75c29ed5148c916021d39d2fac90ccc0e19adf854626a34eaee012aa6b1fcb67", 283 | "sha256:84e1af2dfb4ea9495cb914b00b6303ca0d54bf0a92e688a17e60f6b033873df2", 284 | "sha256:8d8655ce581368b7e1ab42c8a3a166c0b43ea04e59970efbade9448864585e99", 285 | "sha256:90131877d3ce1a05da1b718631860815b89ff44e93c42d168c9c9e8893b26318", 286 | "sha256:9d46bea8644048ceac5737950c08fc89c37a66c34a56a6c9e3648726e60cb767", 287 | "sha256:a8656d6e02bf47d7fa47728cf7a7cbf408f77ef1fad12afd9e0e3246c5de1707", 288 | "sha256:aaf1451cd0d9c32f65a50e461084a0540be52b8ea05c18669c95b42e1f71592a", 289 | "sha256:afc877ff4f277d0e51a1206d748fdab8c1e0256f7a05e1b1067abbed71c64da9", 290 | "sha256:b10c3326edb76ec3049646dc5131608d6d3733b5adfc75d34852028ecc67c52c", 291 | "sha256:ceec7c5f15fb2f9b767b194daa55246830db6c7c3c2f0b1c7e9e90cb4d01f3f9", 292 | "sha256:e00dc0450f79253b7a3a7f2a28e6ca959c8d0d47c0f9fa2c57894c7974d5965f", 293 | "sha256:e91632fdcf1c9a33e97e35f96edcbdf0b10e36cf53b58caa946dca4836bb688c", 294 | "sha256:f39d5defda9443b5fb99a185050e94782fe7ac38f34f751b491142216ad23bc7" 295 | ], 296 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 297 | "version": "==21.8.0" 298 | }, 299 | "gevent-websocket": { 300 | "hashes": [ 301 | "sha256:17b67d91282f8f4c973eba0551183fc84f56f1c90c8f6b6b30256f31f66f5242", 302 | "sha256:7eaef32968290c9121f7c35b973e2cc302ffb076d018c9068d2f5ca8b2d85fb0" 303 | ], 304 | "version": "==0.10.1" 305 | }, 306 | "gitdb": { 307 | "hashes": [ 308 | "sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0", 309 | "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005" 310 | ], 311 | "markers": "python_version >= '3.4'", 312 | "version": "==4.0.7" 313 | }, 314 | "gitpython": { 315 | "hashes": [ 316 | "sha256:b838a895977b45ab6f0cc926a9045c8d1c44e2b653c1fcc39fe91f42c6e8f05b", 317 | "sha256:fce760879cd2aebd2991b3542876dc5c4a909b30c9d69dfc488e504a8db37ee8" 318 | ], 319 | "markers": "python_version >= '3.6'", 320 | "version": "==3.1.18" 321 | }, 322 | "gql": { 323 | "hashes": [ 324 | "sha256:35032ddd4bfe6b8f3169f806b022168932385d751eacc5c5f7122e0b3f4d6b88", 325 | "sha256:fe8d3a08047f77362ddfcfddba7cae377da2dd66f5e61c59820419c9283d4fb5" 326 | ], 327 | "version": "==2.0.0" 328 | }, 329 | "graphene": { 330 | "hashes": [ 331 | "sha256:3d446eb1237c551052bc31155cf1a3a607053e4f58c9172b83a1b597beaa0868", 332 | "sha256:b9f2850e064eebfee9a3ef4a1f8aa0742848d97652173ab44c82cc8a62b9ed93" 333 | ], 334 | "version": "==2.1.9" 335 | }, 336 | "graphql-core": { 337 | "hashes": [ 338 | "sha256:44c9bac4514e5e30c5a595fac8e3c76c1975cae14db215e8174c7fe995825bad", 339 | "sha256:aac46a9ac524c9855910c14c48fc5d60474def7f99fd10245e76608eba7af746" 340 | ], 341 | "version": "==2.3.2" 342 | }, 343 | "graphql-relay": { 344 | "hashes": [ 345 | "sha256:870b6b5304123a38a0b215a79eace021acce5a466bf40cd39fa18cb8528afabb", 346 | "sha256:ac514cb86db9a43014d7e73511d521137ac12cf0101b2eaa5f0a3da2e10d913d" 347 | ], 348 | "version": "==2.0.1" 349 | }, 350 | "graphql-server-core": { 351 | "hashes": [ 352 | "sha256:04ee90da0322949f7b49ff6905688e3a21a9efbd5a7d7835997e431a0afdbd11" 353 | ], 354 | "version": "==1.2.0" 355 | }, 356 | "graphql-ws": { 357 | "hashes": [ 358 | "sha256:2ce29b2dad178f288a469bc6e06b74b4a02edccfcc968c4b5cfaa820e6136b95", 359 | "sha256:ad711b974511b229cbc0aabff6ed6dda0706a91df8892cc9e2fce21a827e69f0" 360 | ], 361 | "version": "==0.3.1" 362 | }, 363 | "greenlet": { 364 | "hashes": [ 365 | "sha256:04e1849c88aa56584d4a0a6e36af5ec7cc37993fdc1fda72b56aa1394a92ded3", 366 | "sha256:05e72db813c28906cdc59bd0da7c325d9b82aa0b0543014059c34c8c4ad20e16", 367 | "sha256:07e6d88242e09b399682b39f8dfa1e7e6eca66b305de1ff74ed9eb1a7d8e539c", 368 | "sha256:090126004c8ab9cd0787e2acf63d79e80ab41a18f57d6448225bbfcba475034f", 369 | "sha256:1796f2c283faab2b71c67e9b9aefb3f201fdfbee5cb55001f5ffce9125f63a45", 370 | "sha256:2f89d74b4f423e756a018832cd7a0a571e0a31b9ca59323b77ce5f15a437629b", 371 | "sha256:34e6675167a238bede724ee60fe0550709e95adaff6a36bcc97006c365290384", 372 | "sha256:3e594015a2349ec6dcceda9aca29da8dc89e85b56825b7d1f138a3f6bb79dd4c", 373 | "sha256:3f8fc59bc5d64fa41f58b0029794f474223693fd00016b29f4e176b3ee2cfd9f", 374 | "sha256:3fc6a447735749d651d8919da49aab03c434a300e9f0af1c886d560405840fd1", 375 | "sha256:40abb7fec4f6294225d2b5464bb6d9552050ded14a7516588d6f010e7e366dcc", 376 | "sha256:44556302c0ab376e37939fd0058e1f0db2e769580d340fb03b01678d1ff25f68", 377 | "sha256:476ba9435afaead4382fbab8f1882f75e3fb2285c35c9285abb3dd30237f9142", 378 | "sha256:4870b018ca685ff573edd56b93f00a122f279640732bb52ce3a62b73ee5c4a92", 379 | "sha256:4adaf53ace289ced90797d92d767d37e7cdc29f13bd3830c3f0a561277a4ae83", 380 | "sha256:4eae94de9924bbb4d24960185363e614b1b62ff797c23dc3c8a7c75bbb8d187e", 381 | "sha256:5317701c7ce167205c0569c10abc4bd01c7f4cf93f642c39f2ce975fa9b78a3c", 382 | "sha256:5c3b735ccf8fc8048664ee415f8af5a3a018cc92010a0d7195395059b4b39b7d", 383 | "sha256:5cde7ee190196cbdc078511f4df0be367af85636b84d8be32230f4871b960687", 384 | "sha256:655ab836324a473d4cd8cf231a2d6f283ed71ed77037679da554e38e606a7117", 385 | "sha256:6ce9d0784c3c79f3e5c5c9c9517bbb6c7e8aa12372a5ea95197b8a99402aa0e6", 386 | "sha256:6e0696525500bc8aa12eae654095d2260db4dc95d5c35af2b486eae1bf914ccd", 387 | "sha256:75ff270fd05125dce3303e9216ccddc541a9e072d4fc764a9276d44dee87242b", 388 | "sha256:8039f5fe8030c43cd1732d9a234fdcbf4916fcc32e21745ca62e75023e4d4649", 389 | "sha256:84488516639c3c5e5c0e52f311fff94ebc45b56788c2a3bfe9cf8e75670f4de3", 390 | "sha256:84782c80a433d87530ae3f4b9ed58d4a57317d9918dfcc6a59115fa2d8731f2c", 391 | "sha256:8ddb38fb6ad96c2ef7468ff73ba5c6876b63b664eebb2c919c224261ae5e8378", 392 | "sha256:98b491976ed656be9445b79bc57ed21decf08a01aaaf5fdabf07c98c108111f6", 393 | "sha256:990e0f5e64bcbc6bdbd03774ecb72496224d13b664aa03afd1f9b171a3269272", 394 | "sha256:9b02e6039eafd75e029d8c58b7b1f3e450ca563ef1fe21c7e3e40b9936c8d03e", 395 | "sha256:a11b6199a0b9dc868990456a2667167d0ba096c5224f6258e452bfbe5a9742c5", 396 | "sha256:a414f8e14aa7bacfe1578f17c11d977e637d25383b6210587c29210af995ef04", 397 | "sha256:a91ee268f059583176c2c8b012a9fce7e49ca6b333a12bbc2dd01fc1a9783885", 398 | "sha256:ac991947ca6533ada4ce7095f0e28fe25d5b2f3266ad5b983ed4201e61596acf", 399 | "sha256:b050dbb96216db273b56f0e5960959c2b4cb679fe1e58a0c3906fa0a60c00662", 400 | "sha256:b97a807437b81f90f85022a9dcfd527deea38368a3979ccb49d93c9198b2c722", 401 | "sha256:bad269e442f1b7ffa3fa8820b3c3aa66f02a9f9455b5ba2db5a6f9eea96f56de", 402 | "sha256:bf3725d79b1ceb19e83fb1aed44095518c0fcff88fba06a76c0891cfd1f36837", 403 | "sha256:c0f22774cd8294078bdf7392ac73cf00bfa1e5e0ed644bd064fdabc5f2a2f481", 404 | "sha256:c1862f9f1031b1dee3ff00f1027fcd098ffc82120f43041fe67804b464bbd8a7", 405 | "sha256:c8d4ed48eed7414ccb2aaaecbc733ed2a84c299714eae3f0f48db085342d5629", 406 | "sha256:cf31e894dabb077a35bbe6963285d4515a387ff657bd25b0530c7168e48f167f", 407 | "sha256:d15cb6f8706678dc47fb4e4f8b339937b04eda48a0af1cca95f180db552e7663", 408 | "sha256:dfcb5a4056e161307d103bc013478892cfd919f1262c2bb8703220adcb986362", 409 | "sha256:e02780da03f84a671bb4205c5968c120f18df081236d7b5462b380fd4f0b497b", 410 | "sha256:e2002a59453858c7f3404690ae80f10c924a39f45f6095f18a985a1234c37334", 411 | "sha256:e22a82d2b416d9227a500c6860cf13e74060cf10e7daf6695cbf4e6a94e0eee4", 412 | "sha256:e41f72f225192d5d4df81dad2974a8943b0f2d664a2a5cfccdf5a01506f5523c", 413 | "sha256:f253dad38605486a4590f9368ecbace95865fea0f2b66615d121ac91fd1a1563", 414 | "sha256:fddfb31aa2ac550b938d952bca8a87f1db0f8dc930ffa14ce05b5c08d27e7fd1" 415 | ], 416 | "markers": "python_version >= '3' and platform_python_implementation == 'CPython' and platform_machine in 'x86_64 X86_64 aarch64 AARCH64 ppc64le PPC64LE amd64 AMD64 win32 WIN32'", 417 | "version": "==1.1.1" 418 | }, 419 | "grpcio": { 420 | "hashes": [ 421 | "sha256:005fe14e67291498989da67d454d805be31d57a988af28ed3a2a0a7cabb05c53", 422 | "sha256:1708a0ba90c798b4313f541ffbcc25ed47e790adaafb02111204362723dabef0", 423 | "sha256:17ed13d43450ef9d1f9b78cc932bcf42844ca302235b93026dfd07fb5208d146", 424 | "sha256:1d9eabe2eb2f78208f9ae67a591f73b024488449d4e0a5b27c7fca2d6901a2d4", 425 | "sha256:1f9ccc9f5c0d5084d1cd917a0b5ff0142a8d269d0755592d751f8ce9e7d3d7f1", 426 | "sha256:24277aab99c346ca36a1aa8589a0624e19a8e6f2b74c83f538f7bb1cc5ee8dbc", 427 | "sha256:27dee6dcd1c04c4e9ceea49f6143003569292209d2c24ca100166660805e2440", 428 | "sha256:33dc4259fecb96e6eac20f760656b911bcb1616aa3e58b3a1d2f125714a2f5d3", 429 | "sha256:3d172158fe886a2604db1b6e17c2de2ab465fe0fe36aba2ec810ca8441cefe3a", 430 | "sha256:41e250ec7cd7523bf49c815b5509d5821728c26fac33681d4b0d1f5f34f59f06", 431 | "sha256:45704b9b5b85f9bcb027f90f2563d11d995c1b870a9ee4b3766f6c7ff6fc3505", 432 | "sha256:49155dfdf725c0862c428039123066b25ce61bd38ce50a21ce325f1735aac1bd", 433 | "sha256:4967949071c9e435f9565ec2f49700cebeda54836a04710fe21f7be028c0125a", 434 | "sha256:4c2baa438f51152c9b7d0835ff711add0b4bc5056c0f5df581a6112153010696", 435 | "sha256:5729ca9540049f52c2e608ca110048cfabab3aeaa0d9f425361d9f8ba8506cac", 436 | "sha256:5f6d6b638698fa6decf7f040819aade677b583eaa21b43366232cb254a2bbac8", 437 | "sha256:5ff0dcf66315f3f00e1a8eb7244c6a49bdb0cc59bef4fb65b9db8adbd78e6acb", 438 | "sha256:6b9b432f5665dfc802187384693b6338f05c7fc3707ebf003a89bd5132074e27", 439 | "sha256:6f8f581787e739945e6cda101f312ea8a7e7082bdbb4993901eb828da6a49092", 440 | "sha256:72b7b8075ee822dad4b39c150d73674c1398503d389e38981e9e35a894c476de", 441 | "sha256:886d056f5101ac513f4aefe4d21a816d98ee3f9a8e77fc3bcb4ae1a3a24efe26", 442 | "sha256:8a35b5f87247c893b01abf2f4f7493a18c2c5bf8eb3923b8dd1654d8377aa1a7", 443 | "sha256:913916823efa2e487b2ee9735b7759801d97fd1974bacdb1900e3bbd17f7d508", 444 | "sha256:a4389e26a8f9338ca91effdc5436dfec67d6ecd296368dba115799ae8f8e5bdb", 445 | "sha256:a66a30513d2e080790244a7ac3d7a3f45001f936c5c2c9613e41e2a5d7a11794", 446 | "sha256:a812164ceb48cb62c3217bd6245274e693c624cc2ac0c1b11b4cea96dab054dd", 447 | "sha256:a93490e6eff5fce3748fb2757cb4273dc21eb1b56732b8c9640fd82c1997b215", 448 | "sha256:b1b34e5a6f1285d1576099c663dae28c07b474015ed21e35a243aff66a0c2aed", 449 | "sha256:ba9dd97ea1738be3e81d34e6bab8ff91a0b80668a4ec81454b283d3c828cebde", 450 | "sha256:bf114be0023b145f7101f392a344692c1efd6de38a610c54a65ed3cba035e669", 451 | "sha256:c26de909cfd54bacdb7e68532a1591a128486af47ee3a5f828df9aa2165ae457", 452 | "sha256:d271e52038dec0db7c39ad9303442d6087c55e09b900e2931b86e837cf0cbc2e", 453 | "sha256:d3b4b41eb0148fca3e6e6fc61d1332a7e8e7c4074fb0d1543f0b255d7f5f1588", 454 | "sha256:d487b4daf84a14741ca1dc1c061ffb11df49d13702cd169b5837fafb5e84d9c0", 455 | "sha256:d760a66c9773780837915be85a39d2cd4ab42ef32657c5f1d28475e23ab709fc", 456 | "sha256:e12d776a240fee3ebd002519c02d165d94ec636d3fe3d6185b361bfc9a2d3106", 457 | "sha256:e19de138199502d575fcec5cf68ae48815a6efe7e5c0d0b8c97eba8c77ae9f0e", 458 | "sha256:e2367f2b18dd4ba64cdcd9f626a920f9ec2e8228630839dc8f4a424d461137ea", 459 | "sha256:ecfd80e8ea03c46b3ea7ed37d2040fcbfe739004b9e4329b8b602d06ac6fb113", 460 | "sha256:edddc849bed3c5dfe215a9f9532a9bd9f670b57d7b8af603be80148b4c69e9a8", 461 | "sha256:eedc8c3514c10b6f11c6f406877e424ca29610883b97bb97e33b1dd2a9077f6c", 462 | "sha256:f06e07161c21391682bfcac93a181a037a8aa3d561546690e9d0501189729aac", 463 | "sha256:fb06708e3d173e387326abcd5182d52beb60e049db5c3d317bd85509e938afdc", 464 | "sha256:fbe3b66bfa2c2f94535f6063f6db62b5b150d55a120f2f9e1175d3087429c4d9" 465 | ], 466 | "version": "==1.40.0" 467 | }, 468 | "grpcio-health-checking": { 469 | "hashes": [ 470 | "sha256:0bc4b6163e43b4792f55bcf0db1aa777aefb13557012277ea2e0881d254e5939", 471 | "sha256:64812f295dbf9822614fb9eda71ae92ecad677518dfa1dedf883b2af83727f24" 472 | ], 473 | "version": "==1.40.0" 474 | }, 475 | "helium": { 476 | "hashes": [ 477 | "sha256:ede0b76162ea182005a3851af6ce6f0cb7a03a38ce041ef6fd1018aa5ebf5eaf" 478 | ], 479 | "index": "pypi", 480 | "version": "==3.0.8" 481 | }, 482 | "humanfriendly": { 483 | "hashes": [ 484 | "sha256:332da98c24cc150efcc91b5508b19115209272bfdf4b0764a56795932f854271", 485 | "sha256:f7dba53ac7935fd0b4a2fc9a29e316ddd9ea135fb3052d3d0279d10c18ff9c48" 486 | ], 487 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 488 | "version": "==9.2" 489 | }, 490 | "idna": { 491 | "hashes": [ 492 | "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", 493 | "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" 494 | ], 495 | "markers": "python_version >= '3'", 496 | "version": "==3.2" 497 | }, 498 | "ipython-genutils": { 499 | "hashes": [ 500 | "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", 501 | "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" 502 | ], 503 | "version": "==0.2.0" 504 | }, 505 | "itsdangerous": { 506 | "hashes": [ 507 | "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", 508 | "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" 509 | ], 510 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 511 | "version": "==1.1.0" 512 | }, 513 | "jinja2": { 514 | "hashes": [ 515 | "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", 516 | "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6" 517 | ], 518 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 519 | "version": "==2.11.3" 520 | }, 521 | "jsonpointer": { 522 | "hashes": [ 523 | "sha256:150f80c5badd02c757da6644852f612f88e8b4bc2f9852dcbf557c8738919686", 524 | "sha256:5a34b698db1eb79ceac454159d3f7c12a451a91f6334a4f638454327b7a89962" 525 | ], 526 | "version": "==2.1" 527 | }, 528 | "jsonref": { 529 | "hashes": [ 530 | "sha256:b1e82fa0b62e2c2796a13e5401fe51790b248f6d9bf9d7212a3e31a3501b291f", 531 | "sha256:f3c45b121cf6257eafabdc3a8008763aed1cd7da06dbabc59a9e4d2a5e4e6697" 532 | ], 533 | "version": "==0.2" 534 | }, 535 | "jsonschema": { 536 | "extras": [ 537 | "format" 538 | ], 539 | "hashes": [ 540 | "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", 541 | "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" 542 | ], 543 | "version": "==3.2.0" 544 | }, 545 | "jupyter-core": { 546 | "hashes": [ 547 | "sha256:79025cb3225efcd36847d0840f3fc672c0abd7afd0de83ba8a1d3837619122b4", 548 | "sha256:8c6c0cac5c1b563622ad49321d5ec47017bd18b94facb381c6973a0486395f8e" 549 | ], 550 | "markers": "python_version >= '3.6'", 551 | "version": "==4.7.1" 552 | }, 553 | "mako": { 554 | "hashes": [ 555 | "sha256:169fa52af22a91900d852e937400e79f535496191c63712e3b9fda5a9bed6fc3", 556 | "sha256:6804ee66a7f6a6416910463b00d76a7b25194cd27f1918500c5bd7be2a088a23" 557 | ], 558 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 559 | "version": "==1.1.5" 560 | }, 561 | "markupsafe": { 562 | "hashes": [ 563 | "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", 564 | "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", 565 | "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", 566 | "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", 567 | "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", 568 | "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", 569 | "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", 570 | "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", 571 | "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", 572 | "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", 573 | "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", 574 | "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", 575 | "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", 576 | "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", 577 | "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", 578 | "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", 579 | "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", 580 | "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", 581 | "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", 582 | "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", 583 | "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", 584 | "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", 585 | "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", 586 | "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", 587 | "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", 588 | "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", 589 | "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", 590 | "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", 591 | "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", 592 | "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", 593 | "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", 594 | "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", 595 | "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", 596 | "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", 597 | "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", 598 | "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", 599 | "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", 600 | "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", 601 | "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", 602 | "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", 603 | "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", 604 | "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", 605 | "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", 606 | "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", 607 | "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", 608 | "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", 609 | "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", 610 | "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", 611 | "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", 612 | "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", 613 | "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", 614 | "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", 615 | "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", 616 | "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" 617 | ], 618 | "markers": "python_version >= '3.6'", 619 | "version": "==2.0.1" 620 | }, 621 | "mistune": { 622 | "hashes": [ 623 | "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e", 624 | "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4" 625 | ], 626 | "version": "==0.8.4" 627 | }, 628 | "monotonic": { 629 | "hashes": [ 630 | "sha256:3a55207bcfed53ddd5c5bae174524062935efed17792e9de2ad0205ce9ad63f7", 631 | "sha256:68687e19a14f11f26d140dd5c86f3dba4bf5df58003000ed467e0e2a69bca96c" 632 | ], 633 | "version": "==1.6" 634 | }, 635 | "mpire": { 636 | "hashes": [ 637 | "sha256:93286627ccda0b1d1eb61c17cd0cd5b8f33ceac040fc05c5fa5f6af51d78566a", 638 | "sha256:c3d7caa0cd9df96c7ec612883d8d450054f65f51e5b25bfac506d8e8fc32824d" 639 | ], 640 | "index": "pypi", 641 | "version": "==2.2.1" 642 | }, 643 | "msgpack": { 644 | "hashes": [ 645 | "sha256:0cb94ee48675a45d3b86e61d13c1e6f1696f0183f0715544976356ff86f741d9", 646 | "sha256:1026dcc10537d27dd2d26c327e552f05ce148977e9d7b9f1718748281b38c841", 647 | "sha256:26a1759f1a88df5f1d0b393eb582ec022326994e311ba9c5818adc5374736439", 648 | "sha256:2a5866bdc88d77f6e1370f82f2371c9bc6fc92fe898fa2dec0c5d4f5435a2694", 649 | "sha256:31c17bbf2ae5e29e48d794c693b7ca7a0c73bd4280976d408c53df421e838d2a", 650 | "sha256:497d2c12426adcd27ab83144057a705efb6acc7e85957a51d43cdcf7f258900f", 651 | "sha256:5a9ee2540c78659a1dd0b110f73773533ee3108d4e1219b5a15a8d635b7aca0e", 652 | "sha256:8521e5be9e3b93d4d5e07cb80b7e32353264d143c1f072309e1863174c6aadb1", 653 | "sha256:87869ba567fe371c4555d2e11e4948778ab6b59d6cc9d8460d543e4cfbbddd1c", 654 | "sha256:8ffb24a3b7518e843cd83538cf859e026d24ec41ac5721c18ed0c55101f9775b", 655 | "sha256:92be4b12de4806d3c36810b0fe2aeedd8d493db39e2eb90742b9c09299eb5759", 656 | "sha256:9ea52fff0473f9f3000987f313310208c879493491ef3ccf66268eff8d5a0326", 657 | "sha256:a4355d2193106c7aa77c98fc955252a737d8550320ecdb2e9ac701e15e2943bc", 658 | "sha256:a99b144475230982aee16b3d249170f1cccebf27fb0a08e9f603b69637a62192", 659 | "sha256:ac25f3e0513f6673e8b405c3a80500eb7be1cf8f57584be524c4fa78fe8e0c83", 660 | "sha256:b28c0876cce1466d7c2195d7658cf50e4730667196e2f1355c4209444717ee06", 661 | "sha256:b55f7db883530b74c857e50e149126b91bb75d35c08b28db12dcb0346f15e46e", 662 | "sha256:b6d9e2dae081aa35c44af9c4298de4ee72991305503442a5c74656d82b581fe9", 663 | "sha256:c747c0cc08bd6d72a586310bda6ea72eeb28e7505990f342552315b229a19b33", 664 | "sha256:d6c64601af8f3893d17ec233237030e3110f11b8a962cb66720bf70c0141aa54", 665 | "sha256:d8167b84af26654c1124857d71650404336f4eb5cc06900667a493fc619ddd9f", 666 | "sha256:de6bd7990a2c2dabe926b7e62a92886ccbf809425c347ae7de277067f97c2887", 667 | "sha256:e36a812ef4705a291cdb4a2fd352f013134f26c6ff63477f20235138d1d21009", 668 | "sha256:e89ec55871ed5473a041c0495b7b4e6099f6263438e0bd04ccd8418f92d5d7f2", 669 | "sha256:f3e6aaf217ac1c7ce1563cf52a2f4f5d5b1f64e8729d794165db71da57257f0c", 670 | "sha256:f484cd2dca68502de3704f056fa9b318c94b1539ed17a4c784266df5d6978c87", 671 | "sha256:fae04496f5bc150eefad4e9571d1a76c55d021325dcd484ce45065ebbdd00984", 672 | "sha256:fe07bc6735d08e492a327f496b7850e98cb4d112c56df69b0c844dbebcbb47f6" 673 | ], 674 | "version": "==1.0.2" 675 | }, 676 | "nbconvert": { 677 | "hashes": [ 678 | "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523", 679 | "sha256:f0d6ec03875f96df45aa13e21fd9b8450c42d7e1830418cccc008c0df725fcee" 680 | ], 681 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 682 | "version": "==5.6.1" 683 | }, 684 | "nbformat": { 685 | "hashes": [ 686 | "sha256:b516788ad70771c6250977c1374fcca6edebe6126fd2adb5a69aa5c2356fd1c8", 687 | "sha256:eb8447edd7127d043361bc17f2f5a807626bc8e878c7709a1c647abda28a9171" 688 | ], 689 | "markers": "python_version >= '3.5'", 690 | "version": "==5.1.3" 691 | }, 692 | "neptune-client": { 693 | "hashes": [ 694 | "sha256:576949d7e5211e9934a3f9473c6f6d123a7cef247f2623472128a2bf5f464732" 695 | ], 696 | "index": "pypi", 697 | "version": "==0.10.8" 698 | }, 699 | "numpy": { 700 | "hashes": [ 701 | "sha256:09858463db6dd9f78b2a1a05c93f3b33d4f65975771e90d2cf7aadb7c2f66edf", 702 | "sha256:209666ce9d4a817e8a4597cd475b71b4878a85fa4b8db41d79fdb4fdee01dde2", 703 | "sha256:298156f4d3d46815eaf0fcf0a03f9625fc7631692bd1ad851517ab93c3168fc6", 704 | "sha256:30fc68307c0155d2a75ad19844224be0f2c6f06572d958db4e2053f816b859ad", 705 | "sha256:423216d8afc5923b15df86037c6053bf030d15cc9e3224206ef868c2d63dd6dc", 706 | "sha256:426a00b68b0d21f2deb2ace3c6d677e611ad5a612d2c76494e24a562a930c254", 707 | "sha256:466e682264b14982012887e90346d33435c984b7fead7b85e634903795c8fdb0", 708 | "sha256:51a7b9db0a2941434cd930dacaafe0fc9da8f3d6157f9d12f761bbde93f46218", 709 | "sha256:52a664323273c08f3b473548bf87c8145b7513afd63e4ebba8496ecd3853df13", 710 | "sha256:550564024dc5ceee9421a86fc0fb378aa9d222d4d0f858f6669eff7410c89bef", 711 | "sha256:5de64950137f3a50b76ce93556db392e8f1f954c2d8207f78a92d1f79aa9f737", 712 | "sha256:640c1ccfd56724f2955c237b6ccce2e5b8607c3bc1cc51d3933b8c48d1da3723", 713 | "sha256:7fdc7689daf3b845934d67cb221ba8d250fdca20ac0334fea32f7091b93f00d3", 714 | "sha256:805459ad8baaf815883d0d6f86e45b3b0b67d823a8f3fa39b1ed9c45eaf5edf1", 715 | "sha256:92a0ab128b07799dd5b9077a9af075a63467d03ebac6f8a93e6440abfea4120d", 716 | "sha256:9f2dc79c093f6c5113718d3d90c283f11463d77daa4e83aeeac088ec6a0bda52", 717 | "sha256:a5109345f5ce7ddb3840f5970de71c34a0ff7fceb133c9441283bb8250f532a3", 718 | "sha256:a55e4d81c4260386f71d22294795c87609164e22b28ba0d435850fbdf82fc0c5", 719 | "sha256:a9da45b748caad72ea4a4ed57e9cd382089f33c5ec330a804eb420a496fa760f", 720 | "sha256:b160b9a99ecc6559d9e6d461b95c8eec21461b332f80267ad2c10394b9503496", 721 | "sha256:b342064e647d099ca765f19672696ad50c953cac95b566af1492fd142283580f", 722 | "sha256:b5e8590b9245803c849e09bae070a8e1ff444f45e3f0bed558dd722119eea724", 723 | "sha256:bf75d5825ef47aa51d669b03ce635ecb84d69311e05eccea083f31c7570c9931", 724 | "sha256:c01b59b33c7c3ba90744f2c695be571a3bd40ab2ba7f3d169ffa6db3cfba614f", 725 | "sha256:d96a6a7d74af56feb11e9a443150216578ea07b7450f7c05df40eec90af7f4a7", 726 | "sha256:dd0e3651d210068d13e18503d75aaa45656eef51ef0b261f891788589db2cc38", 727 | "sha256:e167b9805de54367dcb2043519382be541117503ce99e3291cc9b41ca0a83557", 728 | "sha256:e42029e184008a5fd3d819323345e25e2337b0ac7f5c135b7623308530209d57", 729 | "sha256:f545c082eeb09ae678dd451a1b1dbf17babd8a0d7adea02897a76e639afca310", 730 | "sha256:fde50062d67d805bc96f1a9ecc0d37bfc2a8f02b937d2c50824d186aa91f2419" 731 | ], 732 | "markers": "python_version < '3.11' and python_version >= '3.7'", 733 | "version": "==1.21.2" 734 | }, 735 | "oauthlib": { 736 | "hashes": [ 737 | "sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc", 738 | "sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3" 739 | ], 740 | "markers": "python_version >= '3.6'", 741 | "version": "==3.1.1" 742 | }, 743 | "packaging": { 744 | "hashes": [ 745 | "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7", 746 | "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14" 747 | ], 748 | "markers": "python_version >= '3.6'", 749 | "version": "==21.0" 750 | }, 751 | "pandas": { 752 | "hashes": [ 753 | "sha256:0cd5776be891331a3e6b425b5abeab9596abea18435c5982191356f9b24ae731", 754 | "sha256:1099e2a0cd3a01ec62cca183fc1555833a2d43764950ef8cb5948c8abfc51014", 755 | "sha256:132def05e73d292c949b02e7ef873debb77acc44a8b119d215921046f0c3a91d", 756 | "sha256:1738154049062156429a5cf2fd79a69c9f3fa4f231346a7ec6fd156cd1a9a621", 757 | "sha256:34ced9ce5d5b17b556486da7256961b55b471d64a8990b56e67a84ebeb259416", 758 | "sha256:53b17e4debba26b7446b1e4795c19f94f0c715e288e08145e44bdd2865e819b3", 759 | "sha256:59a78d7066d1c921a77e3306aa0ebf6e55396c097d5dfcc4df8defe3dcecb735", 760 | "sha256:66a95361b81b4ba04b699ecd2416b0591f40cd1e24c60a8bfe0d19009cfa575a", 761 | "sha256:69e1b2f5811f46827722fd641fdaeedb26002bd1e504eacc7a8ec36bdc25393e", 762 | "sha256:7996d311413379136baf0f3cf2a10e331697657c87ced3f17ac7c77f77fe34a3", 763 | "sha256:89f40e5d21814192802421df809f948247d39ffe171e45fe2ab4abf7bd4279d8", 764 | "sha256:9cce01f6d655b4add966fcd36c32c5d1fe84628e200626b3f5e2f40db2d16a0f", 765 | "sha256:a56246de744baf646d1f3e050c4653d632bc9cd2e0605f41051fea59980e880a", 766 | "sha256:ba7ceb8abc6dbdb1e34612d1173d61e4941f1a1eb7e6f703b2633134ae6a6c89", 767 | "sha256:c9e8e0ce5284ebebe110efd652c164ed6eab77f5de4c3533abc756302ee77765", 768 | "sha256:cbcb84d63867af3411fa063af3de64902665bb5b3d40b25b2059e40603594e87", 769 | "sha256:f07a9745ca075ae73a5ce116f5e58f691c0dc9de0bff163527858459df5c176f", 770 | "sha256:fa54dc1d3e5d004a09ab0b1751473698011ddf03e14f1f59b84ad9a6ac630975", 771 | "sha256:fcb71b1935249de80e3a808227189eee381d4d74a31760ced2df21eedc92a8e3" 772 | ], 773 | "markers": "python_full_version >= '3.7.1'", 774 | "version": "==1.3.2" 775 | }, 776 | "pandocfilters": { 777 | "hashes": [ 778 | "sha256:bc63fbb50534b4b1f8ebe1860889289e8af94a23bff7445259592df25a3906eb" 779 | ], 780 | "version": "==1.4.3" 781 | }, 782 | "pathtools": { 783 | "hashes": [ 784 | "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0" 785 | ], 786 | "version": "==0.1.2" 787 | }, 788 | "pendulum": { 789 | "hashes": [ 790 | "sha256:0731f0c661a3cb779d398803655494893c9f581f6488048b3fb629c2342b5394", 791 | "sha256:1245cd0075a3c6d889f581f6325dd8404aca5884dea7223a5566c38aab94642b", 792 | "sha256:29c40a6f2942376185728c9a0347d7c0f07905638c83007e1d262781f1e6953a", 793 | "sha256:2d1619a721df661e506eff8db8614016f0720ac171fe80dda1333ee44e684087", 794 | "sha256:318f72f62e8e23cd6660dbafe1e346950281a9aed144b5c596b2ddabc1d19739", 795 | "sha256:33fb61601083f3eb1d15edeb45274f73c63b3c44a8524703dc143f4212bf3269", 796 | "sha256:3481fad1dc3f6f6738bd575a951d3c15d4b4ce7c82dce37cf8ac1483fde6e8b0", 797 | "sha256:4c9c689747f39d0d02a9f94fcee737b34a5773803a64a5fdb046ee9cac7442c5", 798 | "sha256:7c5ec650cb4bec4c63a89a0242cc8c3cebcec92fcfe937c417ba18277d8560be", 799 | "sha256:94b1fc947bfe38579b28e1cccb36f7e28a15e841f30384b5ad6c5e31055c85d7", 800 | "sha256:9702069c694306297ed362ce7e3c1ef8404ac8ede39f9b28b7c1a7ad8c3959e3", 801 | "sha256:b06a0ca1bfe41c990bbf0c029f0b6501a7f2ec4e38bfec730712015e8860f207", 802 | "sha256:b6c352f4bd32dff1ea7066bd31ad0f71f8d8100b9ff709fb343f3b86cee43efe", 803 | "sha256:c501749fdd3d6f9e726086bf0cd4437281ed47e7bca132ddb522f86a1645d360", 804 | "sha256:c807a578a532eeb226150d5006f156632df2cc8c5693d778324b43ff8c515dd0", 805 | "sha256:db0a40d8bcd27b4fb46676e8eb3c732c67a5a5e6bfab8927028224fbced0b40b", 806 | "sha256:de42ea3e2943171a9e95141f2eecf972480636e8e484ccffaf1e833929e9e052", 807 | "sha256:e95d329384717c7bf627bf27e204bc3b15c8238fa8d9d9781d93712776c14002", 808 | "sha256:f5e236e7730cab1644e1b87aca3d2ff3e375a608542e90fe25685dae46310116", 809 | "sha256:f888f2d2909a414680a29ae74d0592758f2b9fcdee3549887779cd4055e975db", 810 | "sha256:fb53ffa0085002ddd43b6ca61a7b34f2d4d7c3ed66f931fe599e1a531b42af9b" 811 | ], 812 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 813 | "version": "==2.1.2" 814 | }, 815 | "pillow": { 816 | "hashes": [ 817 | "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30", 818 | "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9", 819 | "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71", 820 | "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9", 821 | "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b", 822 | "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630", 823 | "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875", 824 | "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2", 825 | "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1", 826 | "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7", 827 | "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3", 828 | "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b", 829 | "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6", 830 | "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba", 831 | "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4", 832 | "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864", 833 | "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056", 834 | "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228", 835 | "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8", 836 | "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb", 837 | "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d", 838 | "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da", 839 | "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073", 840 | "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3", 841 | "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616", 842 | "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa", 843 | "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979", 844 | "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a", 845 | "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b", 846 | "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6", 847 | "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441", 848 | "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624", 849 | "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd", 850 | "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550", 851 | "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09", 852 | "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196", 853 | "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b", 854 | "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1", 855 | "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6", 856 | "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83", 857 | "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f", 858 | "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4", 859 | "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19", 860 | "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341", 861 | "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96", 862 | "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355", 863 | "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c", 864 | "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c", 865 | "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629", 866 | "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2", 867 | "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87", 868 | "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5", 869 | "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e" 870 | ], 871 | "markers": "python_version >= '3.6'", 872 | "version": "==8.3.2" 873 | }, 874 | "playwright": { 875 | "hashes": [ 876 | "sha256:0ed8ae65e8a6cfab285abc500e2e1335c1200836c91316bf49a2bef4e4a40a66", 877 | "sha256:1fda94b06c62750915ac30f40fd5244a690a3f569a90f7d1cef92304f5d3dded", 878 | "sha256:41f158a850af1e0a2b1a666e42edf56569606ce8bf27a7338dcbbe76f1ef69c2", 879 | "sha256:537d72d20bf3a5d9b29d695fa063b2371083a5d1d445a6e497fc65b94691564b", 880 | "sha256:fbf0413b31a016240bca070f9177bb4eb62fd00745f9df1b4f9fc39a0ba03b5b" 881 | ], 882 | "index": "pypi", 883 | "version": "==1.14.1" 884 | }, 885 | "promise": { 886 | "hashes": [ 887 | "sha256:dfd18337c523ba4b6a58801c164c1904a9d4d1b1747c7d5dbf45b693a49d93d0" 888 | ], 889 | "version": "==2.3" 890 | }, 891 | "protobuf": { 892 | "hashes": [ 893 | "sha256:13ee7be3c2d9a5d2b42a1030976f760f28755fcf5863c55b1460fd205e6cd637", 894 | "sha256:145ce0af55c4259ca74993ddab3479c78af064002ec8227beb3d944405123c71", 895 | "sha256:14c1c9377a7ffbeaccd4722ab0aa900091f52b516ad89c4b0c3bb0a4af903ba5", 896 | "sha256:1556a1049ccec58c7855a78d27e5c6e70e95103b32de9142bae0576e9200a1b0", 897 | "sha256:26010f693b675ff5a1d0e1bdb17689b8b716a18709113288fead438703d45539", 898 | "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87", 899 | "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e", 900 | "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde", 901 | "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1", 902 | "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d", 903 | "sha256:6ce4d8bf0321e7b2d4395e253f8002a1a5ffbcfd7bcc0a6ba46712c07d47d0b4", 904 | "sha256:6d847c59963c03fd7a0cd7c488cadfa10cda4fff34d8bc8cba92935a91b7a037", 905 | "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b", 906 | "sha256:7a4c97961e9e5b03a56f9a6c82742ed55375c4a25f2692b625d4087d02ed31b9", 907 | "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d", 908 | "sha256:8727ee027157516e2c311f218ebf2260a18088ffb2d29473e82add217d196b1c", 909 | "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1", 910 | "sha256:9b7a5c1022e0fa0dbde7fd03682d07d14624ad870ae52054849d8960f04bc764", 911 | "sha256:a22b3a0dbac6544dacbafd4c5f6a29e389a50e3b193e2c70dae6bbf7930f651d", 912 | "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554", 913 | "sha256:a981222367fb4210a10a929ad5983ae93bd5a050a0824fc35d6371c07b78caf6", 914 | "sha256:ab6bb0e270c6c58e7ff4345b3a803cc59dbee19ddf77a4719c5b635f1d547aa8", 915 | "sha256:c56c050a947186ba51de4f94ab441d7f04fcd44c56df6e922369cc2e1a92d683", 916 | "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47", 917 | "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2", 918 | "sha256:f0e59430ee953184a703a324b8ec52f571c6c4259d496a19d1cabcdc19dabc62", 919 | "sha256:ffea251f5cd3c0b9b43c7a7a912777e0bc86263436a87c2555242a348817221b" 920 | ], 921 | "version": "==3.17.3" 922 | }, 923 | "psutil": { 924 | "hashes": [ 925 | "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64", 926 | "sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131", 927 | "sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c", 928 | "sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6", 929 | "sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023", 930 | "sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df", 931 | "sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394", 932 | "sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4", 933 | "sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b", 934 | "sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2", 935 | "sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d", 936 | "sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65", 937 | "sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d", 938 | "sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef", 939 | "sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7", 940 | "sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60", 941 | "sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6", 942 | "sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8", 943 | "sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b", 944 | "sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d", 945 | "sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac", 946 | "sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935", 947 | "sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d", 948 | "sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28", 949 | "sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876", 950 | "sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0", 951 | "sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3", 952 | "sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563" 953 | ], 954 | "markers": "platform_system == 'Windows'", 955 | "version": "==5.8.0" 956 | }, 957 | "pycparser": { 958 | "hashes": [ 959 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", 960 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" 961 | ], 962 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 963 | "version": "==2.20" 964 | }, 965 | "pyee": { 966 | "hashes": [ 967 | "sha256:5c7e60f8df95710dbe17550e16ce0153f83990c00ef744841b43f371ed53ebea", 968 | "sha256:c09f56e36eb10bf23aa2aacf145f690ded75b990a3d9523fd478b005940303d2" 969 | ], 970 | "version": "==8.2.2" 971 | }, 972 | "pygments": { 973 | "hashes": [ 974 | "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380", 975 | "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" 976 | ], 977 | "markers": "python_version >= '3.5'", 978 | "version": "==2.10.0" 979 | }, 980 | "pyjwt": { 981 | "hashes": [ 982 | "sha256:934d73fbba91b0483d3857d1aff50e96b2a892384ee2c17417ed3203f173fca1", 983 | "sha256:fba44e7898bbca160a2b2b501f492824fc8382485d3a6f11ba5d0c1937ce6130" 984 | ], 985 | "markers": "python_version >= '3.6'", 986 | "version": "==2.1.0" 987 | }, 988 | "pyparsing": { 989 | "hashes": [ 990 | "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", 991 | "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" 992 | ], 993 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", 994 | "version": "==2.4.7" 995 | }, 996 | "pyreadline": { 997 | "hashes": [ 998 | "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1", 999 | "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e", 1000 | "sha256:9ce5fa65b8992dfa373bddc5b6e0864ead8f291c94fbfec05fbd5c836162e67b" 1001 | ], 1002 | "markers": "sys_platform == 'win32'", 1003 | "version": "==2.1" 1004 | }, 1005 | "pyrsistent": { 1006 | "hashes": [ 1007 | "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2", 1008 | "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7", 1009 | "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea", 1010 | "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426", 1011 | "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710", 1012 | "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1", 1013 | "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396", 1014 | "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2", 1015 | "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680", 1016 | "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35", 1017 | "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427", 1018 | "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b", 1019 | "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b", 1020 | "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f", 1021 | "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef", 1022 | "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c", 1023 | "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4", 1024 | "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d", 1025 | "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78", 1026 | "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b", 1027 | "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72" 1028 | ], 1029 | "markers": "python_version >= '3.6'", 1030 | "version": "==0.18.0" 1031 | }, 1032 | "python-dateutil": { 1033 | "hashes": [ 1034 | "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", 1035 | "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" 1036 | ], 1037 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 1038 | "version": "==2.8.2" 1039 | }, 1040 | "python-dotenv": { 1041 | "hashes": [ 1042 | "sha256:aae25dc1ebe97c420f50b81fb0e5c949659af713f31fdb63c749ca68748f34b1", 1043 | "sha256:f521bc2ac9a8e03c736f62911605c5d83970021e3fa95b37d769e2bbbe9b6172" 1044 | ], 1045 | "index": "pypi", 1046 | "version": "==0.19.0" 1047 | }, 1048 | "python-editor": { 1049 | "hashes": [ 1050 | "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d", 1051 | "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b", 1052 | "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8", 1053 | "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77", 1054 | "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522" 1055 | ], 1056 | "version": "==1.0.4" 1057 | }, 1058 | "pytz": { 1059 | "hashes": [ 1060 | "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", 1061 | "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" 1062 | ], 1063 | "version": "==2021.1" 1064 | }, 1065 | "pytzdata": { 1066 | "hashes": [ 1067 | "sha256:3efa13b335a00a8de1d345ae41ec78dd11c9f8807f522d39850f2dd828681540", 1068 | "sha256:e1e14750bcf95016381e4d472bad004eef710f2d6417240904070b3d6654485f" 1069 | ], 1070 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 1071 | "version": "==2020.1" 1072 | }, 1073 | "pywin32": { 1074 | "hashes": [ 1075 | "sha256:595d397df65f1b2e0beaca63a883ae6d8b6df1cdea85c16ae85f6d2e648133fe", 1076 | "sha256:87604a4087434cd814ad8973bd47d6524bd1fa9e971ce428e76b62a5e0860fdf", 1077 | "sha256:88981dd3cfb07432625b180f49bf4e179fb8cbb5704cd512e38dd63636af7a17", 1078 | "sha256:8c9d33968aa7fcddf44e47750e18f3d034c3e443a707688a008a2e52bbef7e96", 1079 | "sha256:93367c96e3a76dfe5003d8291ae16454ca7d84bb24d721e0b74a07610b7be4a7", 1080 | "sha256:9635df6998a70282bd36e7ac2a5cef9ead1627b0a63b17c731312c7a0daebb72", 1081 | "sha256:98f62a3f60aa64894a290fb7494bfa0bfa0a199e9e052e1ac293b2ad3cd2818b", 1082 | "sha256:c866f04a182a8cb9b7855de065113bbd2e40524f570db73ef1ee99ff0a5cc2f0", 1083 | "sha256:dafa18e95bf2a92f298fe9c582b0e205aca45c55f989937c52c454ce65b93c78", 1084 | "sha256:fb3b4933e0382ba49305cc6cd3fb18525df7fd96aa434de19ce0878133bf8e4a" 1085 | ], 1086 | "markers": "sys_platform == 'win32' and platform_system == 'Windows'", 1087 | "version": "==301" 1088 | }, 1089 | "pyyaml": { 1090 | "hashes": [ 1091 | "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", 1092 | "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", 1093 | "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", 1094 | "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", 1095 | "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", 1096 | "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", 1097 | "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", 1098 | "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", 1099 | "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", 1100 | "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", 1101 | "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", 1102 | "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", 1103 | "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347", 1104 | "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", 1105 | "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541", 1106 | "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", 1107 | "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", 1108 | "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc", 1109 | "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", 1110 | "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa", 1111 | "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", 1112 | "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122", 1113 | "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", 1114 | "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", 1115 | "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", 1116 | "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc", 1117 | "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247", 1118 | "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", 1119 | "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0" 1120 | ], 1121 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 1122 | "version": "==5.4.1" 1123 | }, 1124 | "requests": { 1125 | "hashes": [ 1126 | "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", 1127 | "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" 1128 | ], 1129 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 1130 | "version": "==2.26.0" 1131 | }, 1132 | "requests-oauthlib": { 1133 | "hashes": [ 1134 | "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d", 1135 | "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a", 1136 | "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc" 1137 | ], 1138 | "version": "==1.3.0" 1139 | }, 1140 | "rfc3987": { 1141 | "hashes": [ 1142 | "sha256:10702b1e51e5658843460b189b185c0366d2cf4cff716f13111b0ea9fd2dce53", 1143 | "sha256:d3c4d257a560d544e9826b38bc81db676890c79ab9d7ac92b39c7a253d5ca733" 1144 | ], 1145 | "version": "==1.3.8" 1146 | }, 1147 | "rx": { 1148 | "hashes": [ 1149 | "sha256:13a1d8d9e252625c173dc795471e614eadfe1cf40ffc684e08b8fff0d9748c23", 1150 | "sha256:7357592bc7e881a95e0c2013b73326f704953301ab551fbc8133a6fadab84105" 1151 | ], 1152 | "version": "==1.6.1" 1153 | }, 1154 | "selenium": { 1155 | "hashes": [ 1156 | "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c", 1157 | "sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d" 1158 | ], 1159 | "index": "pypi", 1160 | "version": "==3.141.0" 1161 | }, 1162 | "sentry-sdk": { 1163 | "hashes": [ 1164 | "sha256:ebe99144fa9618d4b0e7617e7929b75acd905d258c3c779edcd34c0adfffe26c", 1165 | "sha256:f33d34c886d0ba24c75ea8885a8b3a172358853c7cbde05979fc99c29ef7bc52" 1166 | ], 1167 | "version": "==1.3.1" 1168 | }, 1169 | "shortuuid": { 1170 | "hashes": [ 1171 | "sha256:3c11d2007b915c43bee3e10625f068d8a349e04f0d81f08f5fa08507427ebf1f", 1172 | "sha256:492c7402ff91beb1342a5898bd61ea953985bf24a41cd9f247409aa2e03c8f77" 1173 | ], 1174 | "markers": "python_version >= '3.5'", 1175 | "version": "==1.0.1" 1176 | }, 1177 | "simplejson": { 1178 | "hashes": [ 1179 | "sha256:065230b9659ac38c8021fa512802562d122afb0cf8d4b89e257014dcddb5730a", 1180 | "sha256:07707ba69324eaf58f0c6f59d289acc3e0ed9ec528dae5b0d4219c0d6da27dc5", 1181 | "sha256:10defa88dd10a0a4763f16c1b5504e96ae6dc68953cfe5fc572b4a8fcaf9409b", 1182 | "sha256:140eb58809f24d843736edb8080b220417e22c82ac07a3dfa473f57e78216b5f", 1183 | "sha256:188f2c78a8ac1eb7a70a4b2b7b9ad11f52181044957bf981fb3e399c719e30ee", 1184 | "sha256:1c2688365743b0f190392e674af5e313ebe9d621813d15f9332e874b7c1f2d04", 1185 | "sha256:24e413bd845bd17d4d72063d64e053898543fb7abc81afeae13e5c43cef9c171", 1186 | "sha256:2b59acd09b02da97728d0bae8ff48876d7efcbbb08e569c55e2d0c2e018324f5", 1187 | "sha256:2df15814529a4625ea6f7b354a083609b3944c269b954ece0d0e7455872e1b2a", 1188 | "sha256:352c11582aa1e49a2f0f7f7d8fd5ec5311da890d1354287e83c63ab6af857cf5", 1189 | "sha256:36b08b886027eac67e7a0e822e3a5bf419429efad7612e69501669d6252a21f2", 1190 | "sha256:376023f51edaf7290332dacfb055bc00ce864cb013c0338d0dea48731f37e42f", 1191 | "sha256:3ba82f8b421886f4a2311c43fb98faaf36c581976192349fef2a89ed0fcdbdef", 1192 | "sha256:3d72aa9e73134dacd049a2d6f9bd219f7be9c004d03d52395831611d66cedb71", 1193 | "sha256:40ece8fa730d1a947bff792bcc7824bd02d3ce6105432798e9a04a360c8c07b0", 1194 | "sha256:417b7e119d66085dc45bdd563dcb2c575ee10a3b1c492dd3502a029448d4be1c", 1195 | "sha256:42b7c7264229860fe879be961877f7466d9f7173bd6427b3ba98144a031d49fb", 1196 | "sha256:457d9cfe7ece1571770381edccdad7fc255b12cd7b5b813219441146d4f47595", 1197 | "sha256:4a6943816e10028eeed512ea03be52b54ea83108b408d1049b999f58a760089b", 1198 | "sha256:5b94df70bd34a3b946c0eb272022fb0f8a9eb27cad76e7f313fedbee2ebe4317", 1199 | "sha256:5f5051a13e7d53430a990604b532c9124253c5f348857e2d5106d45fc8533860", 1200 | "sha256:5f7f53b1edd4b23fb112b89208377480c0bcee45d43a03ffacf30f3290e0ed85", 1201 | "sha256:5fe8c6dcb9e6f7066bdc07d3c410a2fca78c0d0b4e0e72510ffd20a60a20eb8e", 1202 | "sha256:71a54815ec0212b0cba23adc1b2a731bdd2df7b9e4432718b2ed20e8aaf7f01a", 1203 | "sha256:7332f7b06d42153255f7bfeb10266141c08d48cc1a022a35473c95238ff2aebc", 1204 | "sha256:78c6f0ed72b440ebe1892d273c1e5f91e55e6861bea611d3b904e673152a7a4c", 1205 | "sha256:7c9b30a2524ae6983b708f12741a31fbc2fb8d6fecd0b6c8584a62fd59f59e09", 1206 | "sha256:86fcffc06f1125cb443e2bed812805739d64ceb78597ac3c1b2d439471a09717", 1207 | "sha256:87572213965fd8a4fb7a97f837221e01d8fddcfb558363c671b8aa93477fb6a2", 1208 | "sha256:8e595de17178dd3bbeb2c5b8ea97536341c63b7278639cb8ee2681a84c0ef037", 1209 | "sha256:917f01db71d5e720b731effa3ff4a2c702a1b6dacad9bcdc580d86a018dfc3ca", 1210 | "sha256:91cfb43fb91ff6d1e4258be04eee84b51a4ef40a28d899679b9ea2556322fb50", 1211 | "sha256:aa86cfdeb118795875855589934013e32895715ec2d9e8eb7a59be3e7e07a7e1", 1212 | "sha256:ade09aa3c284d11f39640aebdcbb748e1996f0c60504f8c4a0c5a9fec821e67a", 1213 | "sha256:b2a5688606dffbe95e1347a05b77eb90489fe337edde888e23bbb7fd81b0d93b", 1214 | "sha256:b92fbc2bc549c5045c8233d954f3260ccf99e0f3ec9edfd2372b74b350917752", 1215 | "sha256:c2d5334d935af711f6d6dfeec2d34e071cdf73ec0df8e8bd35ac435b26d8da97", 1216 | "sha256:cb0afc3bad49eb89a579103616574a54b523856d20fc539a4f7a513a0a8ba4b2", 1217 | "sha256:ce66f730031b9b3683b2fc6ad4160a18db86557c004c3d490a29bf8d450d7ab9", 1218 | "sha256:e29b9cea4216ec130df85d8c36efb9985fda1c9039e4706fb30e0fb6a67602ff", 1219 | "sha256:e2cc4b68e59319e3de778325e34fbff487bfdb2225530e89995402989898d681", 1220 | "sha256:e90d2e219c3dce1500dda95f5b893c293c4d53c4e330c968afbd4e7a90ff4a5b", 1221 | "sha256:f13c48cc4363829bdfecc0c181b6ddf28008931de54908a492dc8ccd0066cd60", 1222 | "sha256:f550730d18edec4ff9d4252784b62adfe885d4542946b6d5a54c8a6521b56afd", 1223 | "sha256:fa843ee0d34c7193f5a816e79df8142faff851549cab31e84b526f04878ac778", 1224 | "sha256:fe1c33f78d2060719d52ea9459d97d7ae3a5b707ec02548575c4fbed1d1d345b" 1225 | ], 1226 | "markers": "python_version >= '2.5' and python_version not in '3.0, 3.1, 3.2, 3.3'", 1227 | "version": "==3.17.5" 1228 | }, 1229 | "six": { 1230 | "hashes": [ 1231 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 1232 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 1233 | ], 1234 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 1235 | "version": "==1.16.0" 1236 | }, 1237 | "smmap": { 1238 | "hashes": [ 1239 | "sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182", 1240 | "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2" 1241 | ], 1242 | "markers": "python_version >= '3.5'", 1243 | "version": "==4.0.0" 1244 | }, 1245 | "sqlalchemy": { 1246 | "hashes": [ 1247 | "sha256:059c5f41e8630f51741a234e6ba2a034228c11b3b54a15478e61d8b55fa8bd9d", 1248 | "sha256:07b9099a95dd2b2620498544300eda590741ac54915c6b20809b6de7e3c58090", 1249 | "sha256:0aa312f9906ecebe133d7f44168c3cae4c76f27a25192fa7682f3fad505543c9", 1250 | "sha256:0aa746d1173587743960ff17b89b540e313aacfe6c1e9c81aa48393182c36d4f", 1251 | "sha256:1c15191f2430a30082f540ec6f331214746fc974cfdf136d7a1471d1c61d68ff", 1252 | "sha256:25e9b2e5ca088879ce3740d9ccd4d58cb9061d49566a0b5e12166f403d6f4da0", 1253 | "sha256:2bca9a6e30ee425cc321d988a152a5fe1be519648e7541ac45c36cd4f569421f", 1254 | "sha256:355024cf061ed04271900414eb4a22671520241d2216ddb691bdd8a992172389", 1255 | "sha256:370f4688ce47f0dc1e677a020a4d46252a31a2818fd67f5c256417faefc938af", 1256 | "sha256:37f2bd1b8e32c5999280f846701712347fc0ee7370e016ede2283c71712e127a", 1257 | "sha256:3a0d3b3d51c83a66f5b72c57e1aad061406e4c390bd42cf1fda94effe82fac81", 1258 | "sha256:43fc207be06e50158e4dae4cc4f27ce80afbdbfa7c490b3b22feb64f6d9775a0", 1259 | "sha256:448612570aa1437a5d1b94ada161805778fe80aba5b9a08a403e8ae4e071ded6", 1260 | "sha256:4803a481d4c14ce6ad53dc35458c57821863e9a079695c27603d38355e61fb7f", 1261 | "sha256:512f52a8872e8d63d898e4e158eda17e2ee40b8d2496b3b409422e71016db0bd", 1262 | "sha256:6a8dbf3d46e889d864a57ee880c4ad3a928db5aa95e3d359cbe0da2f122e50c4", 1263 | "sha256:76ff246881f528089bf19385131b966197bb494653990396d2ce138e2a447583", 1264 | "sha256:82c03325111eab88d64e0ff48b6fe15c75d23787429fa1d84c0995872e702787", 1265 | "sha256:967307ea52985985224a79342527c36ec2d1daa257a39748dd90e001a4be4d90", 1266 | "sha256:9b128a78581faea7a5ee626ad4471353eee051e4e94616dfeff4742b6e5ba262", 1267 | "sha256:a8395c4db3e1450eef2b68069abf500cc48af4b442a0d98b5d3c9535fe40cde8", 1268 | "sha256:ae07895b55c7d58a7dd47438f437ac219c0f09d24c2e7d69fdebc1ea75350f00", 1269 | "sha256:bd41f8063a9cd11b76d6d7d6af8139ab3c087f5dbbe5a50c02cb8ece7da34d67", 1270 | "sha256:be185b3daf651c6c0639987a916bf41e97b60e68f860f27c9cb6574385f5cbb4", 1271 | "sha256:cd0e85dd2067159848c7672acd517f0c38b7b98867a347411ea01b432003f8d9", 1272 | "sha256:cd68c5f9d13ffc8f4d6802cceee786678c5b1c668c97bc07b9f4a60883f36cd1", 1273 | "sha256:cec1a4c6ddf5f82191301a25504f0e675eccd86635f0d5e4c69e0661691931c5", 1274 | "sha256:d9667260125688c71ccf9af321c37e9fb71c2693575af8210f763bfbbee847c7", 1275 | "sha256:e0ce4a2e48fe0a9ea3a5160411a4c5135da5255ed9ac9c15f15f2bcf58c34194", 1276 | "sha256:e9d4f4552aa5e0d1417fc64a2ce1cdf56a30bab346ba6b0dd5e838eb56db4d29" 1277 | ], 1278 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 1279 | "version": "==1.4.23" 1280 | }, 1281 | "strict-rfc3339": { 1282 | "hashes": [ 1283 | "sha256:5cad17bedfc3af57b399db0fed32771f18fc54bbd917e85546088607ac5e1277" 1284 | ], 1285 | "version": "==0.7" 1286 | }, 1287 | "subprocess32": { 1288 | "hashes": [ 1289 | "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b", 1290 | "sha256:e45d985aef903c5b7444d34350b05da91a9e0ea015415ab45a21212786c649d0", 1291 | "sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d" 1292 | ], 1293 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' and python_version < '4'", 1294 | "version": "==3.5.4" 1295 | }, 1296 | "swagger-spec-validator": { 1297 | "hashes": [ 1298 | "sha256:d1514ec7e3c058c701f27cc74f85ceb876d6418c9db57786b9c54085ed5e29eb", 1299 | "sha256:f4f23ee4dbd52bfcde90b1144dde22304add6260e9f29252e9fd7814c9b8fd16" 1300 | ], 1301 | "version": "==2.7.3" 1302 | }, 1303 | "tabulate": { 1304 | "hashes": [ 1305 | "sha256:d7c013fe7abbc5e491394e10fa845f8f32fe54f8dc60c6622c6cf482d25d47e4", 1306 | "sha256:eb1d13f25760052e8931f2ef80aaf6045a6cceb47514db8beab24cded16f13a7" 1307 | ], 1308 | "version": "==0.8.9" 1309 | }, 1310 | "tenacity": { 1311 | "hashes": [ 1312 | "sha256:43242a20e3e73291a28bcbcacfd6e000b02d3857a9a9fff56b297a27afdc932f", 1313 | "sha256:f78f4ea81b0fabc06728c11dc2a8c01277bfc5181b321a4770471902e3eb844a" 1314 | ], 1315 | "index": "pypi", 1316 | "version": "==8.0.1" 1317 | }, 1318 | "testpath": { 1319 | "hashes": [ 1320 | "sha256:1acf7a0bcd3004ae8357409fc33751e16d37ccc650921da1094a86581ad1e417", 1321 | "sha256:8044f9a0bab6567fc644a3593164e872543bb44225b0e24846e2c89237937589" 1322 | ], 1323 | "markers": "python_version >= '3.5'", 1324 | "version": "==0.5.0" 1325 | }, 1326 | "toposort": { 1327 | "hashes": [ 1328 | "sha256:2ade83028dd067a1d43c142469cbaf4136b92fdc1c4303f16c40f126442fdaf3", 1329 | "sha256:a7428f56ef844f5055bb9e9e44b343983773ae6dce0fe5b101e08e27ffbd50ac" 1330 | ], 1331 | "version": "==1.6" 1332 | }, 1333 | "tqdm": { 1334 | "hashes": [ 1335 | "sha256:80aead664e6c1672c4ae20dc50e1cdc5e20eeff9b14aa23ecd426375b28be588", 1336 | "sha256:a4d6d112e507ef98513ac119ead1159d286deab17dffedd96921412c2d236ff5" 1337 | ], 1338 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 1339 | "version": "==4.62.2" 1340 | }, 1341 | "traitlets": { 1342 | "hashes": [ 1343 | "sha256:03f172516916220b58c9f19d7f854734136dd9528103d04e9bf139a92c9f54c4", 1344 | "sha256:bd382d7ea181fbbcce157c133db9a829ce06edffe097bcf3ab945b435452b46d" 1345 | ], 1346 | "markers": "python_version >= '3.7'", 1347 | "version": "==5.1.0" 1348 | }, 1349 | "typing-compat": { 1350 | "hashes": [ 1351 | "sha256:a7159db80406de342bc128ab315fae3afe1ddc87cbc2df7a023763090fdfe5d2", 1352 | "sha256:a8b94eb34c95982fbd34b8daa46fd78c43db33c075b98c79b6e1d77e8f7dd4d5" 1353 | ], 1354 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 1355 | "version": "==0.1.0" 1356 | }, 1357 | "typing-extensions": { 1358 | "hashes": [ 1359 | "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e", 1360 | "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7", 1361 | "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34" 1362 | ], 1363 | "markers": "python_version < '3.9'", 1364 | "version": "==3.10.0.2" 1365 | }, 1366 | "urllib3": { 1367 | "hashes": [ 1368 | "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", 1369 | "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" 1370 | ], 1371 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", 1372 | "version": "==1.26.6" 1373 | }, 1374 | "wandb": { 1375 | "hashes": [ 1376 | "sha256:723e81cca072def483422b9ae45d5c1b5c8f2d011dc5c85c8891696f8504a55e", 1377 | "sha256:739f205b5c9a5bc25e742f1c707e65322cd6aafba8ec64299e5757f992f34be3" 1378 | ], 1379 | "index": "pypi", 1380 | "version": "==0.12.1" 1381 | }, 1382 | "watchdog": { 1383 | "hashes": [ 1384 | "sha256:28777dbed3bbd95f9c70f461443990a36c07dbf49ae7cd69932cdd1b8fb2850c", 1385 | "sha256:41d44ef21a77a32b55ce9bf59b75777063751f688de51098859b7c7f6466589a", 1386 | "sha256:43bf728eb7830559f329864ab5da2302c15b2efbac24ad84ccc09949ba753c40", 1387 | "sha256:50a7f81f99d238f72185f481b493f9de80096e046935b60ea78e1276f3d76960", 1388 | "sha256:51af09ae937ada0e9a10cc16988ec03c649754a91526170b6839b89fc56d6acb", 1389 | "sha256:5563b005907613430ef3d4aaac9c78600dd5704e84764cb6deda4b3d72807f09", 1390 | "sha256:58ae842300cbfe5e62fb068c83901abe76e4f413234b7bec5446e4275eb1f9cb", 1391 | "sha256:59767f476cd1f48531bf378f0300565d879688c82da8369ca8c52f633299523c", 1392 | "sha256:5cf78f794c9d7bc64a626ef4f71aff88f57a7ae288e0b359a9c6ea711a41395f", 1393 | "sha256:5f57ce4f7e498278fb2a091f39359930144a0f2f90ea8cbf4523c4e25de34028", 1394 | "sha256:6f3ad1d973fe8fc8fe64ba38f6a934b74346342fa98ef08ad5da361a05d46044", 1395 | "sha256:78b1514067ff4089f4dac930b043a142997a5b98553120919005e97fbaba6546", 1396 | "sha256:814d396859c95598f7576d15bc257c3bd3ba61fa4bc1db7dfc18f09070ded7da", 1397 | "sha256:8874d5ad6b7f43b18935d9b0183e29727a623a216693d6938d07dfd411ba462f", 1398 | "sha256:8b74d0d92a69a7ab5f101f9fe74e44ba017be269efa824337366ccbb4effde85", 1399 | "sha256:9391003635aa783957b9b11175d9802d3272ed67e69ef2e3394c0b6d9d24fa9a", 1400 | "sha256:a2888a788893c4ef7e562861ec5433875b7915f930a5a7ed3d32c048158f1be5", 1401 | "sha256:a7053d4d22dc95c5e0c90aeeae1e4ed5269d2f04001798eec43a654a03008d22", 1402 | "sha256:b0cc7d8b7d60da6c313779d85903ce39a63d89d866014b085f720a083d5f3e9a", 1403 | "sha256:e40e33a4889382824846b4baa05634e1365b47c6fa40071dc2d06b4d7c715fc1", 1404 | "sha256:e60d3bb7166b7cb830b86938d1eb0e6cfe23dfd634cce05c128f8f9967895193", 1405 | "sha256:eab14adfc417c2c983fbcb2c73ef3f28ba6990d1fff45d1180bf7e38bda0d98d", 1406 | "sha256:ed4ca4351cd2bb0d863ee737a2011ca44d8d8be19b43509bd4507f8a449b376b" 1407 | ], 1408 | "markers": "python_version >= '3.6'", 1409 | "version": "==2.1.5" 1410 | }, 1411 | "webcolors": { 1412 | "hashes": [ 1413 | "sha256:76f360636957d1c976db7466bc71dcb713bb95ac8911944dffc55c01cb516de6", 1414 | "sha256:b8cd5d865a25c51ff1218f0c90d0c0781fc64312a49b746b320cf50de1648f6e" 1415 | ], 1416 | "version": "==1.11.1" 1417 | }, 1418 | "webdriver-manager": { 1419 | "hashes": [ 1420 | "sha256:50a6e174106542f5335cacc387cec7ada26812babc1aeca61c208a1bab2ac2c5", 1421 | "sha256:c6d81590aae6fc0fb10cf7dd20c8c1b9bb043501f9cf62c316a854a0de841e32" 1422 | ], 1423 | "index": "pypi", 1424 | "version": "==3.4.2" 1425 | }, 1426 | "webencodings": { 1427 | "hashes": [ 1428 | "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", 1429 | "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" 1430 | ], 1431 | "version": "==0.5.1" 1432 | }, 1433 | "websocket-client": { 1434 | "hashes": [ 1435 | "sha256:0133d2f784858e59959ce82ddac316634229da55b498aac311f1620567a710ec", 1436 | "sha256:8dfb715d8a992f5712fff8c843adae94e22b22a99b2c5e6b0ec4a1a981cc4e0d" 1437 | ], 1438 | "markers": "python_version >= '3.6'", 1439 | "version": "==1.2.1" 1440 | }, 1441 | "websockets": { 1442 | "hashes": [ 1443 | "sha256:0dd4eb8e0bbf365d6f652711ce21b8fd2b596f873d32aabb0fbb53ec604418cc", 1444 | "sha256:1d0971cc7251aeff955aa742ec541ee8aaea4bb2ebf0245748fbec62f744a37e", 1445 | "sha256:1d6b4fddb12ab9adf87b843cd4316c4bd602db8d5efd2fb83147f0458fe85135", 1446 | "sha256:230a3506df6b5f446fed2398e58dcaafdff12d67fe1397dff196411a9e820d02", 1447 | "sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3", 1448 | "sha256:2cf04601633a4ec176b9cc3d3e73789c037641001dbfaf7c411f89cd3e04fcaf", 1449 | "sha256:3ddff38894c7857c476feb3538dd847514379d6dc844961dc99f04b0384b1b1b", 1450 | "sha256:48c222feb3ced18f3dc61168ca18952a22fb88e5eb8902d2bf1b50faefdc34a2", 1451 | "sha256:51d04df04ed9d08077d10ccbe21e6805791b78eac49d16d30a1f1fe2e44ba0af", 1452 | "sha256:597c28f3aa7a09e8c070a86b03107094ee5cdafcc0d55f2f2eac92faac8dc67d", 1453 | "sha256:5c8f0d82ea2468282e08b0cf5307f3ad022290ed50c45d5cb7767957ca782880", 1454 | "sha256:7189e51955f9268b2bdd6cc537e0faa06f8fffda7fb386e5922c6391de51b077", 1455 | "sha256:7df3596838b2a0c07c6f6d67752c53859a54993d4f062689fdf547cb56d0f84f", 1456 | "sha256:826ccf85d4514609219725ba4a7abd569228c2c9f1968e8be05be366f68291ec", 1457 | "sha256:836d14eb53b500fd92bd5db2fc5894f7c72b634f9c2a28f546f75967503d8e25", 1458 | "sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0", 1459 | "sha256:85e701a6c316b7067f1e8675c638036a796fe5116783a4c932e7eb8e305a3ffe", 1460 | "sha256:900589e19200be76dd7cbaa95e9771605b5ce3f62512d039fb3bc5da9014912a", 1461 | "sha256:9147868bb0cc01e6846606cd65cbf9c58598f187b96d14dd1ca17338b08793bb", 1462 | "sha256:9e7fdc775fe7403dbd8bc883ba59576a6232eac96dacb56512daacf7af5d618d", 1463 | "sha256:ab5ee15d3462198c794c49ccd31773d8a2b8c17d622aa184f669d2b98c2f0857", 1464 | "sha256:ad893d889bc700a5835e0a95a3e4f2c39e91577ab232a3dc03c262a0f8fc4b5c", 1465 | "sha256:b2e71c4670ebe1067fa8632f0d081e47254ee2d3d409de54168b43b0ba9147e0", 1466 | "sha256:b43b13e5622c5a53ab12f3272e6f42f1ce37cd5b6684b2676cb365403295cd40", 1467 | "sha256:b4ad84b156cf50529b8ac5cc1638c2cf8680490e3fccb6121316c8c02620a2e4", 1468 | "sha256:be5fd35e99970518547edc906efab29afd392319f020c3c58b0e1a158e16ed20", 1469 | "sha256:caa68c95bc1776d3521f81eeb4d5b9438be92514ec2a79fececda814099c8314", 1470 | "sha256:d144b350045c53c8ff09aa1cfa955012dd32f00c7e0862c199edcabb1a8b32da", 1471 | "sha256:d2c2d9b24d3c65b5a02cac12cbb4e4194e590314519ed49db2f67ef561c3cf58", 1472 | "sha256:e9e5fd6dbdf95d99bc03732ded1fc8ef22ebbc05999ac7e0c7bf57fe6e4e5ae2", 1473 | "sha256:ebf459a1c069f9866d8569439c06193c586e72c9330db1390af7c6a0a32c4afd", 1474 | "sha256:f31722f1c033c198aa4a39a01905951c00bd1c74f922e8afc1b1c62adbcdd56a", 1475 | "sha256:f68c352a68e5fdf1e97288d5cec9296664c590c25932a8476224124aaf90dbcd" 1476 | ], 1477 | "markers": "python_full_version >= '3.6.1'", 1478 | "version": "==9.1" 1479 | }, 1480 | "werkzeug": { 1481 | "hashes": [ 1482 | "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", 1483 | "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c" 1484 | ], 1485 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 1486 | "version": "==1.0.1" 1487 | }, 1488 | "zope.event": { 1489 | "hashes": [ 1490 | "sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42", 1491 | "sha256:5e76517f5b9b119acf37ca8819781db6c16ea433f7e2062c4afc2b6fbedb1330" 1492 | ], 1493 | "version": "==4.5.0" 1494 | }, 1495 | "zope.interface": { 1496 | "hashes": [ 1497 | "sha256:08f9636e99a9d5410181ba0729e0408d3d8748026ea938f3b970a0249daa8192", 1498 | "sha256:0b465ae0962d49c68aa9733ba92a001b2a0933c317780435f00be7ecb959c702", 1499 | "sha256:0cba8477e300d64a11a9789ed40ee8932b59f9ee05f85276dbb4b59acee5dd09", 1500 | "sha256:0cee5187b60ed26d56eb2960136288ce91bcf61e2a9405660d271d1f122a69a4", 1501 | "sha256:0ea1d73b7c9dcbc5080bb8aaffb776f1c68e807767069b9ccdd06f27a161914a", 1502 | "sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3", 1503 | "sha256:15e7d1f7a6ee16572e21e3576d2012b2778cbacf75eb4b7400be37455f5ca8bf", 1504 | "sha256:17776ecd3a1fdd2b2cd5373e5ef8b307162f581c693575ec62e7c5399d80794c", 1505 | "sha256:194d0bcb1374ac3e1e023961610dc8f2c78a0f5f634d0c737691e215569e640d", 1506 | "sha256:1c0e316c9add0db48a5b703833881351444398b04111188069a26a61cfb4df78", 1507 | "sha256:205e40ccde0f37496904572035deea747390a8b7dc65146d30b96e2dd1359a83", 1508 | "sha256:273f158fabc5ea33cbc936da0ab3d4ba80ede5351babc4f577d768e057651531", 1509 | "sha256:2876246527c91e101184f63ccd1d716ec9c46519cc5f3d5375a3351c46467c46", 1510 | "sha256:2c98384b254b37ce50eddd55db8d381a5c53b4c10ee66e1e7fe749824f894021", 1511 | "sha256:2e5a26f16503be6c826abca904e45f1a44ff275fdb7e9d1b75c10671c26f8b94", 1512 | "sha256:334701327f37c47fa628fc8b8d28c7d7730ce7daaf4bda1efb741679c2b087fc", 1513 | "sha256:3748fac0d0f6a304e674955ab1365d515993b3a0a865e16a11ec9d86fb307f63", 1514 | "sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54", 1515 | "sha256:3dd4952748521205697bc2802e4afac5ed4b02909bb799ba1fe239f77fd4e117", 1516 | "sha256:3f24df7124c323fceb53ff6168da70dbfbae1442b4f3da439cd441681f54fe25", 1517 | "sha256:469e2407e0fe9880ac690a3666f03eb4c3c444411a5a5fddfdabc5d184a79f05", 1518 | "sha256:4de4bc9b6d35c5af65b454d3e9bc98c50eb3960d5a3762c9438df57427134b8e", 1519 | "sha256:5208ebd5152e040640518a77827bdfcc73773a15a33d6644015b763b9c9febc1", 1520 | "sha256:52de7fc6c21b419078008f697fd4103dbc763288b1406b4562554bd47514c004", 1521 | "sha256:5bb3489b4558e49ad2c5118137cfeaf59434f9737fa9c5deefc72d22c23822e2", 1522 | "sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e", 1523 | "sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f", 1524 | "sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f", 1525 | "sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120", 1526 | "sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f", 1527 | "sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1", 1528 | "sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9", 1529 | "sha256:7d97a4306898b05404a0dcdc32d9709b7d8832c0c542b861d9a826301719794e", 1530 | "sha256:7df1e1c05304f26faa49fa752a8c690126cf98b40b91d54e6e9cc3b7d6ffe8b7", 1531 | "sha256:8270252effc60b9642b423189a2fe90eb6b59e87cbee54549db3f5562ff8d1b8", 1532 | "sha256:867a5ad16892bf20e6c4ea2aab1971f45645ff3102ad29bd84c86027fa99997b", 1533 | "sha256:877473e675fdcc113c138813a5dd440da0769a2d81f4d86614e5d62b69497155", 1534 | "sha256:8892f89999ffd992208754851e5a052f6b5db70a1e3f7d54b17c5211e37a98c7", 1535 | "sha256:9a9845c4c6bb56e508651f005c4aeb0404e518c6f000d5a1123ab077ab769f5c", 1536 | "sha256:a1e6e96217a0f72e2b8629e271e1b280c6fa3fe6e59fa8f6701bec14e3354325", 1537 | "sha256:a8156e6a7f5e2a0ff0c5b21d6bcb45145efece1909efcbbbf48c56f8da68221d", 1538 | "sha256:a9506a7e80bcf6eacfff7f804c0ad5350c8c95b9010e4356a4b36f5322f09abb", 1539 | "sha256:af310ec8335016b5e52cae60cda4a4f2a60a788cbb949a4fbea13d441aa5a09e", 1540 | "sha256:b0297b1e05fd128d26cc2460c810d42e205d16d76799526dfa8c8ccd50e74959", 1541 | "sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7", 1542 | "sha256:d0c1bc2fa9a7285719e5678584f6b92572a5b639d0e471bb8d4b650a1a910920", 1543 | "sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e", 1544 | "sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48", 1545 | "sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8", 1546 | "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4", 1547 | "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263" 1548 | ], 1549 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 1550 | "version": "==5.4.0" 1551 | } 1552 | }, 1553 | "develop": {} 1554 | } 1555 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Scrapper Pipeline 2 | 3 | This is a demo project to compare two web scrapping frameworks, Playwright and Selenium and using the new Pipelining tool Dagster 4 | 5 | 6 | ## Getting Started 7 | 8 | ### Install Dependencies 9 | 10 | To install dependencies simply run: 11 | 12 | `pip install -r requirements.txt` 13 | 14 | Alternatively, to use virtual environments easily you can run: 15 | 16 | `pip install pipenv` 17 | 18 | And then: 19 | 20 | `pipenv install` 21 | 22 | ### Individual modes 23 | 24 | To run with a particular configuration simply run `python -m app {mode}` 25 | 26 | Available modes are: 27 | 28 | - playwright 29 | - selenium 30 | - selenium_multi 31 | - selenium_dagster 32 | - playwright_dagster 33 | 34 | ### Benchmark 35 | 36 | To run the benchmark: 37 | 38 | 1. Update your Neptune.AI key in the `.env` file 39 | 1. Run `python -m app.run_benchmark` 40 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import asyncio 4 | 5 | from .common import parameters 6 | 7 | MODES = [ 8 | "playwright", 9 | "selenium", 10 | "selenium_multi", 11 | "selenium_dagster", 12 | "playwright_dagster", 13 | ] 14 | 15 | if __name__ == "__main__": 16 | mode = sys.argv[1] 17 | 18 | if len(sys.argv) >= 3: 19 | parameters.PROFILE_COUNT = int(sys.argv[2]) 20 | 21 | if mode not in MODES: 22 | raise ValueError(f"Mode: {mode} should be in {MODES}") 23 | 24 | if mode == "playwright": 25 | from .imperative.playwright_runner import runner as playwright_run 26 | 27 | print(f"PROCESS STARTED: {mode}") 28 | start_time = time.perf_counter() 29 | asyncio.run(playwright_run()) 30 | end_time = time.perf_counter() 31 | 32 | elif mode == "selenium": 33 | from .imperative.selenium_runner import runner as selenium_single 34 | 35 | print(f"PROCESS STARTED: {mode}") 36 | start_time = time.perf_counter() 37 | selenium_single() 38 | end_time = time.perf_counter() 39 | 40 | elif mode == "selenium_multi": 41 | from .imperative.selenium_multi_runner import runner as selenium_multi 42 | 43 | print(f"PROCESS STARTED: {mode}") 44 | start_time = time.perf_counter() 45 | selenium_multi() 46 | end_time = time.perf_counter() 47 | 48 | elif mode == "selenium_single": 49 | from .imperative.selenium_singleton_runner import runner as selenium_single 50 | 51 | print(f"PROCESS STARTED: {mode}") 52 | start_time = time.perf_counter() 53 | selenium_single() 54 | end_time = time.perf_counter() 55 | 56 | from .imperative.selenium_singleton_runner import close_driver 57 | close_driver() 58 | 59 | 60 | elif mode == "selenium_dagster": 61 | from .pipeline.selenium import selenium_pipeline 62 | from dagster import execute_pipeline, reconstructable, DagsterInstance 63 | 64 | print(f"PROCESS STARTED: {mode}") 65 | start_time = time.perf_counter() 66 | execute_pipeline( 67 | reconstructable(selenium_pipeline), 68 | run_config={"execution": {"multiprocess": {}}}, 69 | instance=DagsterInstance.local_temp(), 70 | ) 71 | end_time = time.perf_counter() 72 | 73 | elif mode == "playwright_dagster": 74 | from .pipeline.playwright import playwright_pipeline 75 | from dagster import execute_pipeline, reconstructable, DagsterInstance 76 | 77 | print(f"PROCESS STARTED: {mode}") 78 | start_time = time.perf_counter() 79 | execute_pipeline( 80 | reconstructable(playwright_pipeline), 81 | run_config={"execution": {"multiprocess": {}}}, 82 | instance=DagsterInstance.local_temp(), 83 | ) 84 | end_time = time.perf_counter() 85 | 86 | elapsed_time = end_time - start_time 87 | 88 | print(f"Elapsed Time: {elapsed_time:.2f}s") 89 | -------------------------------------------------------------------------------- /app/common/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def parse_strings(string: str) -> float: 3 | return float(string.strip("@,")) 4 | 5 | 6 | def round_coordinates(coordinate: float) -> float: 7 | return round(coordinate * 1e2) * 1e-2 8 | -------------------------------------------------------------------------------- /app/common/clean_data.py: -------------------------------------------------------------------------------- 1 | from .parameters import DATA_PATH 2 | 3 | 4 | def delete_data(): 5 | return 6 | for file_ in DATA_PATH.rglob("*"): 7 | if file_.is_dir(): 8 | continue 9 | file_.unlink() 10 | -------------------------------------------------------------------------------- /app/common/convert_to_geo_json.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import List, Dict 3 | 4 | from ..common.parameters import PROFILE_COUNT 5 | from ..tests.create_test import test_agains_expected 6 | 7 | 8 | def process(profiles: List[Dict[str, str]]) -> str: 9 | 10 | assert test_agains_expected(PROFILE_COUNT, "profiles_with_coordinates", profiles) 11 | 12 | points = [] 13 | 14 | for profile in profiles: 15 | point = (profile["latitude"], profile["longitude"]) 16 | points.append(point) 17 | 18 | geojson = {"type": "MultiPoint", "coordinates": points} 19 | 20 | geojson_string = json.dumps(geojson) 21 | 22 | assert test_agains_expected(PROFILE_COUNT, "geojson", json.loads(geojson_string)) 23 | 24 | return geojson_string 25 | -------------------------------------------------------------------------------- /app/common/parameters.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | from dotenv import load_dotenv 5 | 6 | load_dotenv() 7 | 8 | DATA_PATH = Path(__file__).resolve().parent.parent / "data" 9 | 10 | DATA_PATH.mkdir(exist_ok=True, parents=True) 11 | 12 | BASE_URL = "https://www.forbes.com/" 13 | 14 | LATLONG_URL = "https://www.google.com/maps/" 15 | 16 | MAP_URL = "https://geojson.io/" 17 | 18 | PROFILE_COUNT = 1 19 | 20 | MAX_ATTEMPS = 1 21 | 22 | NEPTUNE_KEY = os.environ["NEPTUNE_KEY"] 23 | -------------------------------------------------------------------------------- /app/data/richest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ELC/web-scraping-pipeline/9dfaa9cd431ec478c4df80bacb197d13e516e8b5/app/data/richest.png -------------------------------------------------------------------------------- /app/imperative/playwright_runner.py: -------------------------------------------------------------------------------- 1 | import json 2 | import asyncio 3 | 4 | from tenacity import retry, stop_after_attempt, stop_after_delay 5 | 6 | from ..common import clean_data, convert_to_geo_json 7 | 8 | from ..common.parameters import MAX_ATTEMPS, PROFILE_COUNT 9 | 10 | from ..playwright_based import ( 11 | compile_profile, 12 | process_profile, 13 | generate_map, 14 | get_coordinates, 15 | ) 16 | 17 | from ..tests.create_test import test_agains_expected 18 | 19 | 20 | stop_criterion = stop_after_attempt(MAX_ATTEMPS) 21 | 22 | clean_data.delete_data = retry(clean_data.delete_data, stop=stop_criterion) 23 | compile_profile.compile_profiles = retry( 24 | compile_profile.compile_profiles, 25 | stop=(stop_criterion | stop_after_delay(20 * MAX_ATTEMPS)), 26 | ) 27 | process_profile.process = retry( 28 | process_profile.process, stop=(stop_criterion | stop_after_delay(120)) 29 | ) 30 | generate_map.process = retry( 31 | generate_map.process, stop=(stop_criterion | stop_after_delay(120)) 32 | ) 33 | get_coordinates.process = retry( 34 | get_coordinates.process, stop=(stop_criterion | stop_after_delay(120)) 35 | ) 36 | convert_to_geo_json.process = retry( 37 | convert_to_geo_json.process, stop=(stop_criterion | stop_after_delay(20)) 38 | ) 39 | 40 | 41 | async def process_profile_async(profile): 42 | profile_residence = await process_profile.process(profile) 43 | profile_coordinates = await get_coordinates.process(profile_residence) 44 | return profile_coordinates 45 | 46 | 47 | async def runner(): 48 | clean_data.delete_data() 49 | profiles = await compile_profile.compile_profiles() 50 | assert test_agains_expected(PROFILE_COUNT, "profiles", profiles) 51 | 52 | profiles_with_coordinates = [] 53 | 54 | coroutines = [process_profile_async(profile) for profile in profiles] 55 | profiles_with_coordinates = await asyncio.gather(*coroutines) 56 | assert test_agains_expected( 57 | PROFILE_COUNT, "profiles_with_coordinates", profiles_with_coordinates 58 | ) 59 | 60 | geojson = convert_to_geo_json.process(profiles_with_coordinates) 61 | assert test_agains_expected(PROFILE_COUNT, "geojson", json.loads(geojson)) 62 | 63 | await generate_map.process(geojson) 64 | -------------------------------------------------------------------------------- /app/imperative/selenium_multi_runner.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from mpire import WorkerPool 4 | from tenacity import retry, stop_after_attempt, stop_after_delay 5 | 6 | from ..common import clean_data, convert_to_geo_json 7 | 8 | from ..common.parameters import MAX_ATTEMPS, PROFILE_COUNT 9 | 10 | from ..selenium_based import ( 11 | compile_profile, 12 | process_profile, 13 | generate_map, 14 | get_coordinates, 15 | ) 16 | 17 | from ..tests.create_test import test_agains_expected 18 | 19 | stop_criterion = stop_after_attempt(MAX_ATTEMPS) 20 | 21 | clean_data.delete_data = retry(clean_data.delete_data, stop=stop_criterion) 22 | compile_profile.compile_profiles = retry( 23 | compile_profile.compile_profiles, 24 | stop=(stop_criterion | stop_after_delay(20 * MAX_ATTEMPS)), 25 | ) 26 | process_profile.process = retry( 27 | process_profile.process, stop=(stop_criterion | stop_after_delay(120)) 28 | ) 29 | generate_map.process = retry( 30 | generate_map.process, stop=(stop_criterion | stop_after_delay(120)) 31 | ) 32 | get_coordinates.process = retry( 33 | get_coordinates.process, stop=(stop_criterion | stop_after_delay(120)) 34 | ) 35 | convert_to_geo_json.process = retry( 36 | convert_to_geo_json.process, stop=(stop_criterion | stop_after_delay(20)) 37 | ) 38 | 39 | 40 | def process(profile): 41 | profile_residence = process_profile.process(profile) 42 | return get_coordinates.process(profile_residence) 43 | 44 | 45 | def runner(): 46 | clean_data.delete_data() 47 | profiles = compile_profile.compile_profiles() 48 | assert test_agains_expected(PROFILE_COUNT, "profiles", profiles) 49 | 50 | args = [{"profile": profile} for profile in profiles] 51 | 52 | with WorkerPool(n_jobs=5) as pool: 53 | profiles_with_coordinates = pool.map_unordered( 54 | process, args, iterable_len=len(profiles) 55 | ) 56 | assert test_agains_expected( 57 | PROFILE_COUNT, "profiles_with_coordinates", profiles_with_coordinates 58 | ) 59 | 60 | geojson = convert_to_geo_json.process(profiles_with_coordinates) 61 | assert test_agains_expected(PROFILE_COUNT, "geojson", json.loads(geojson)) 62 | 63 | return generate_map.process(geojson) 64 | -------------------------------------------------------------------------------- /app/imperative/selenium_runner.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from tenacity import retry, stop_after_attempt, stop_after_delay 4 | 5 | from ..common import clean_data, convert_to_geo_json 6 | 7 | from ..common.parameters import MAX_ATTEMPS, PROFILE_COUNT 8 | 9 | from ..selenium_based import ( 10 | compile_profile, 11 | process_profile, 12 | generate_map, 13 | get_coordinates, 14 | ) 15 | 16 | from ..tests.create_test import test_agains_expected 17 | 18 | stop_criterion = stop_after_attempt(MAX_ATTEMPS) 19 | 20 | 21 | clean_data.delete_data = retry(clean_data.delete_data, stop=stop_criterion) 22 | compile_profile.compile_profiles = retry( 23 | compile_profile.compile_profiles, 24 | stop=(stop_criterion | stop_after_delay(20 * MAX_ATTEMPS)), 25 | ) 26 | process_profile.process = retry( 27 | process_profile.process, stop=(stop_criterion | stop_after_delay(120)) 28 | ) 29 | generate_map.process = retry( 30 | generate_map.process, stop=(stop_criterion | stop_after_delay(120)) 31 | ) 32 | get_coordinates.process = retry( 33 | get_coordinates.process, stop=(stop_criterion | stop_after_delay(120)) 34 | ) 35 | convert_to_geo_json.process = retry( 36 | convert_to_geo_json.process, stop=(stop_criterion | stop_after_delay(20)) 37 | ) 38 | 39 | 40 | def process(profile): 41 | profile_residence = process_profile.process(profile) 42 | return get_coordinates.process(profile_residence) 43 | 44 | 45 | def runner(): 46 | clean_data.delete_data() 47 | profiles = compile_profile.compile_profiles() 48 | assert test_agains_expected(PROFILE_COUNT, "profiles", profiles) 49 | 50 | profiles_with_coordinates = [process(profile) for profile in profiles] 51 | assert test_agains_expected( 52 | PROFILE_COUNT, "profiles_with_coordinates", profiles_with_coordinates 53 | ) 54 | 55 | geojson = convert_to_geo_json.process(profiles_with_coordinates) 56 | assert test_agains_expected(PROFILE_COUNT, "geojson", json.loads(geojson)) 57 | 58 | return generate_map.process(geojson) 59 | -------------------------------------------------------------------------------- /app/imperative/selenium_singleton_runner.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from tenacity import retry, stop_after_attempt, stop_after_delay 4 | 5 | from ..common import clean_data, convert_to_geo_json 6 | 7 | from ..common.parameters import MAX_ATTEMPS, PROFILE_COUNT 8 | 9 | from ..selenium_based import utils 10 | 11 | 12 | old_decorator = utils.get_driver 13 | utils.get_driver = utils.get_singleton_driver 14 | close_driver = utils.close_singleton_driver 15 | 16 | 17 | from ..selenium_based import ( 18 | compile_profile, 19 | process_profile, 20 | generate_map, 21 | get_coordinates, 22 | ) 23 | 24 | from ..tests.create_test import test_agains_expected 25 | 26 | 27 | stop_criterion = stop_after_attempt(MAX_ATTEMPS) 28 | 29 | 30 | clean_data.delete_data = retry(clean_data.delete_data, stop=stop_criterion) 31 | compile_profile.compile_profiles = retry( 32 | compile_profile.compile_profiles, 33 | stop=(stop_criterion | stop_after_delay(20 * MAX_ATTEMPS)), 34 | ) 35 | process_profile.process = retry( 36 | process_profile.process, stop=(stop_criterion | stop_after_delay(120)) 37 | ) 38 | generate_map.process = retry( 39 | generate_map.process, stop=(stop_criterion | stop_after_delay(120)) 40 | ) 41 | get_coordinates.process = retry( 42 | get_coordinates.process, stop=(stop_criterion | stop_after_delay(120)) 43 | ) 44 | convert_to_geo_json.process = retry( 45 | convert_to_geo_json.process, stop=(stop_criterion | stop_after_delay(20)) 46 | ) 47 | 48 | 49 | def process(profile): 50 | profile_residence = process_profile.process(profile) 51 | return get_coordinates.process(profile_residence) 52 | 53 | 54 | def runner(): 55 | clean_data.delete_data() 56 | profiles = compile_profile.compile_profiles() 57 | assert test_agains_expected(PROFILE_COUNT, "profiles", profiles) 58 | 59 | profiles_with_coordinates = [process(profile) for profile in profiles] 60 | assert test_agains_expected( 61 | PROFILE_COUNT, "profiles_with_coordinates", profiles_with_coordinates 62 | ) 63 | 64 | geojson = convert_to_geo_json.process(profiles_with_coordinates) 65 | assert test_agains_expected(PROFILE_COUNT, "geojson", json.loads(geojson)) 66 | 67 | return generate_map.process(geojson) 68 | 69 | -------------------------------------------------------------------------------- /app/pipeline/base.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict, Any 2 | 3 | import warnings 4 | 5 | from ..common import convert_to_geo_json, clean_data as clean 6 | 7 | from ..common.parameters import MAX_ATTEMPS 8 | 9 | from dagster import ( 10 | solid, 11 | RetryPolicy, 12 | Nothing, 13 | ExperimentalWarning, 14 | ) 15 | 16 | warnings.filterwarnings("ignore", category=ExperimentalWarning) 17 | 18 | SOLID_COMMON_PARAMS = {"retry_policy": RetryPolicy(max_retries=MAX_ATTEMPS, delay=30)} 19 | 20 | 21 | @solid(**SOLID_COMMON_PARAMS) 22 | def clean_data() -> Nothing: 23 | clean.delete_data() 24 | 25 | 26 | @solid(**SOLID_COMMON_PARAMS) 27 | def convert_geojson(profiles: List[Dict[str, Any]]) -> str: 28 | return convert_to_geo_json.process(profiles) 29 | -------------------------------------------------------------------------------- /app/pipeline/playwright.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from dagster import ( 4 | pipeline, 5 | solid, 6 | Nothing, 7 | DynamicOutputDefinition, 8 | ModeDefinition, 9 | fs_io_manager, 10 | DynamicOutput, 11 | InputDefinition, 12 | ) 13 | 14 | from ..playwright_based import ( 15 | compile_profile, 16 | process_profile, 17 | get_coordinates, 18 | generate_map, 19 | ) 20 | 21 | from .base import SOLID_COMMON_PARAMS, clean_data, convert_geojson 22 | from ..tests.create_test import test_agains_expected 23 | from ..common.parameters import PROFILE_COUNT 24 | 25 | 26 | @solid( 27 | input_defs=[InputDefinition("delete", Nothing)], 28 | output_defs=[DynamicOutputDefinition(Dict[str, str])], 29 | **SOLID_COMMON_PARAMS 30 | ) 31 | async def compile_profile_list_playwright() -> Dict[str, str]: 32 | profiles = await compile_profile.compile_profiles() 33 | assert test_agains_expected(PROFILE_COUNT, "profiles", profiles) 34 | for profile in profiles: 35 | mapping_key = str(hash(str(profile)))[-7:] 36 | yield DynamicOutput(profile, mapping_key=mapping_key) 37 | 38 | 39 | @solid(**SOLID_COMMON_PARAMS) 40 | async def add_residence_playwright(profile: Dict[str, str]) -> Dict[str, str]: 41 | return await process_profile.process(profile) 42 | 43 | 44 | @solid(**SOLID_COMMON_PARAMS) 45 | async def add_coordinates_playwright(profile: Dict[str, str]) -> Dict[str, Any]: 46 | return await get_coordinates.process(profile) 47 | 48 | 49 | @solid(**SOLID_COMMON_PARAMS) 50 | async def geojson_to_map_playwright(geojson: str) -> Nothing: 51 | return await generate_map.process(geojson) 52 | 53 | 54 | @pipeline(mode_defs=[ModeDefinition(resource_defs={"io_manager": fs_io_manager})]) 55 | def playwright_pipeline(): 56 | data_cleaned = clean_data() 57 | profiles = compile_profile_list_playwright(delete=data_cleaned) 58 | 59 | profile_with_residence = profiles.map(add_residence_playwright) 60 | profile_with_coordinates = profile_with_residence.map(add_coordinates_playwright) 61 | 62 | geojson = convert_geojson(profile_with_coordinates.collect()) 63 | 64 | geojson_to_map_playwright(geojson) 65 | -------------------------------------------------------------------------------- /app/pipeline/selenium.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | import json 3 | 4 | from dagster import ( 5 | pipeline, 6 | solid, 7 | Nothing, 8 | DynamicOutputDefinition, 9 | ModeDefinition, 10 | fs_io_manager, 11 | DynamicOutput, 12 | InputDefinition, 13 | ) 14 | 15 | from ..selenium_based import ( 16 | compile_profile, 17 | generate_map, 18 | get_coordinates, 19 | process_profile, 20 | ) 21 | 22 | from .base import SOLID_COMMON_PARAMS, clean_data, convert_geojson 23 | 24 | from ..common.parameters import PROFILE_COUNT 25 | from ..tests.create_test import test_agains_expected 26 | 27 | # Dynamic 28 | @solid( 29 | input_defs=[InputDefinition("delete", Nothing)], 30 | output_defs=[DynamicOutputDefinition(Dict[str, str])], 31 | **SOLID_COMMON_PARAMS 32 | ) 33 | def compile_profile_list_selenium() -> Dict[str, str]: 34 | profiles = compile_profile.compile_profiles() 35 | assert test_agains_expected(PROFILE_COUNT, "profiles", profiles) 36 | for profile in profiles: 37 | mapping_key = str(hash(str(profile)))[-7:] 38 | yield DynamicOutput(profile, mapping_key=mapping_key) 39 | 40 | 41 | @solid(**SOLID_COMMON_PARAMS) 42 | def add_residence_selenium(profile: Dict[str, str]) -> Dict[str, str]: 43 | return process_profile.process(profile) 44 | 45 | 46 | @solid(**SOLID_COMMON_PARAMS) 47 | def add_coordinates_selenium(profile: Dict[str, str]) -> Dict[str, Any]: 48 | return get_coordinates.process(profile) 49 | 50 | 51 | @solid(**SOLID_COMMON_PARAMS) 52 | def geojson_to_map_selenium(geojson: str) -> Nothing: 53 | return generate_map.process(geojson) 54 | 55 | 56 | @pipeline(mode_defs=[ModeDefinition(resource_defs={"io_manager": fs_io_manager})]) 57 | def selenium_pipeline(): 58 | data_cleaned = clean_data() 59 | profiles = compile_profile_list_selenium(delete=data_cleaned) 60 | 61 | profile_with_residence = profiles.map(add_residence_selenium) 62 | profile_with_coordinates = profile_with_residence.map(add_coordinates_selenium) 63 | 64 | geojson = convert_geojson(profile_with_coordinates.collect()) 65 | 66 | geojson_to_map_selenium(geojson) 67 | -------------------------------------------------------------------------------- /app/playwright_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ELC/web-scraping-pipeline/9dfaa9cd431ec478c4df80bacb197d13e516e8b5/app/playwright_based/__init__.py -------------------------------------------------------------------------------- /app/playwright_based/compile_profile.py: -------------------------------------------------------------------------------- 1 | from playwright.async_api import async_playwright 2 | 3 | from ..common import parameters 4 | 5 | 6 | async def compile_profiles(): 7 | async with async_playwright() as p: 8 | browser = await p.chromium.launch(headless=False) 9 | page = await browser.new_page() 10 | 11 | await page.goto(parameters.BASE_URL) 12 | await page.click('[aria-label="Open Navigation Menu"]') 13 | await page.hover("text=Billionaires") 14 | await page.click("text=World's Billionaires") 15 | 16 | await page.wait_for_selector(".table-row") 17 | rows = await page.query_selector_all(".table-row") 18 | 19 | first_row = rows[0] 20 | await first_row.click() 21 | 22 | profiles = [] 23 | 24 | for row in rows: 25 | await row.click() 26 | 27 | full_profile = await page.query_selector("text=Full Profile") 28 | profile_button = await full_profile.query_selector("xpath=//..") 29 | profile_url = await profile_button.get_attribute("href") 30 | 31 | person_node = await row.query_selector(".personName") 32 | name = await person_node.inner_text() 33 | 34 | profile = {"name": name, "profile_url": profile_url} 35 | 36 | profiles.append(profile) 37 | 38 | if len(profiles) >= parameters.PROFILE_COUNT: 39 | break 40 | 41 | return profiles 42 | -------------------------------------------------------------------------------- /app/playwright_based/generate_map.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import Dict 3 | import asyncio 4 | 5 | from ..common import parameters 6 | 7 | from playwright.async_api import async_playwright 8 | 9 | 10 | async def process(geojson: str) -> None: 11 | async with async_playwright() as p: 12 | browser = await p.chromium.launch(headless=False) 13 | page = await browser.new_page() 14 | 15 | await page.goto(parameters.MAP_URL) 16 | 17 | for _ in range(100): 18 | await page.keyboard.press("Backspace") 19 | await page.keyboard.press("Delete") 20 | 21 | await page.keyboard.type(geojson) 22 | 23 | await page.keyboard.press("F11") 24 | 25 | await page.click('[title="Collapse"]') 26 | await asyncio.sleep(0.5) 27 | await page.click('[title="Collapse"]') 28 | await asyncio.sleep(0.5) 29 | await page.click('[title="Collapse"]') 30 | 31 | await asyncio.sleep(0.5) 32 | 33 | await page.screenshot(path=str(parameters.DATA_PATH / "richest.png")) 34 | -------------------------------------------------------------------------------- /app/playwright_based/get_coordinates.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | from typing import Dict 3 | import asyncio 4 | 5 | from ..common import parameters, parse_strings, round_coordinates 6 | 7 | from playwright.async_api import async_playwright 8 | from playwright._impl._api_types import TimeoutError 9 | 10 | 11 | async def process(profile: Dict[str, str]) -> Dict[str, str]: 12 | async with async_playwright() as p: 13 | browser = await p.chromium.launch(headless=False) 14 | page = await browser.new_page() 15 | 16 | await page.goto(parameters.LATLONG_URL) 17 | 18 | await page.type("#searchboxinput", profile["residence"]) 19 | 20 | await page.keyboard.press("Enter") 21 | 22 | await asyncio.sleep(5) 23 | 24 | try: 25 | await page.wait_for_url("**/place/**data=**") 26 | except TimeoutError: 27 | pass 28 | 29 | await asyncio.sleep(5) 30 | 31 | url = page.url 32 | 33 | longitude_raw, latitude_raw = url.split("/")[6].split(",")[:2] 34 | longitude = parse_strings(longitude_raw) 35 | latitude = parse_strings(latitude_raw) 36 | 37 | profile_updated = profile.copy() 38 | profile_updated["longitude"] = round_coordinates(longitude) 39 | profile_updated["latitude"] = round_coordinates(latitude) 40 | 41 | return profile_updated 42 | -------------------------------------------------------------------------------- /app/playwright_based/process_profile.py: -------------------------------------------------------------------------------- 1 | from playwright.async_api import async_playwright 2 | 3 | from ..common import parameters 4 | 5 | 6 | async def process(profile): 7 | 8 | async with async_playwright() as p: 9 | browser = await p.chromium.launch(headless=False) 10 | page = await browser.new_page() 11 | 12 | await page.goto(profile["profile_url"]) 13 | 14 | personal_information = await page.query_selector_all(".profile-stats__item") 15 | 16 | residence_row = None 17 | for personal_field in personal_information: 18 | personal_field_text = await personal_field.inner_text() 19 | if "residence" in personal_field_text.lower(): 20 | residence_row = personal_field 21 | break 22 | 23 | residence_element = await residence_row.query_selector(".profile-stats__text") 24 | residence = await residence_element.inner_text() 25 | 26 | profile_updated = profile.copy() 27 | profile_updated["residence"] = residence 28 | 29 | return profile_updated 30 | -------------------------------------------------------------------------------- /app/run_benchmark.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import time 3 | 4 | import wandb 5 | 6 | from .common import parameters 7 | 8 | MODES = [ 9 | "selenium", 10 | "playwright", 11 | "selenium_single", 12 | # "selenium_multi", 13 | "selenium_dagster", 14 | "playwright_dagster", 15 | ] 16 | 17 | counts = [1, 3, 5, 10, 15, 25, 50, 75, 100] 18 | 19 | replicas = 5 20 | 21 | if __name__ == "__main__": 22 | 23 | image_path = str(parameters.DATA_PATH / "richest.png") 24 | 25 | mode = "selenium" 26 | for count in counts: 27 | run = wandb.init(project="web_scraper", reinit=True) 28 | run.config["Method"] = mode 29 | run.config["ATTEMPS"] = parameters.MAX_ATTEMPS 30 | run.config["LATLONG_URL"] = parameters.LATLONG_URL 31 | run.config["PROFILE_COUNT"] = count 32 | 33 | start_time = time.perf_counter() 34 | 35 | completed = subprocess.run(f"python -m app {mode} {count}") 36 | success = "SUCCESS" if completed.returncode == 0 else "FAILURE" 37 | 38 | end_time = time.perf_counter() 39 | 40 | elapsed_time = end_time - start_time 41 | 42 | try: 43 | map_ = wandb.Image(image_path) 44 | except FileNotFoundError: 45 | map_ = None 46 | 47 | log_metrics = { 48 | "execution_time": elapsed_time, 49 | "map": map_, 50 | "success": success, 51 | } 52 | 53 | wandb.log(log_metrics) 54 | 55 | run.finish() 56 | 57 | for count in counts: 58 | for mode in MODES: 59 | for _ in range(replicas): 60 | run = wandb.init(project="web_scraper", reinit=True) 61 | run.config["Method"] = mode 62 | run.config["ATTEMPS"] = parameters.MAX_ATTEMPS 63 | run.config["LATLONG_URL"] = parameters.LATLONG_URL 64 | run.config["PROFILE_COUNT"] = count 65 | 66 | start_time = time.perf_counter() 67 | 68 | completed = subprocess.run(f"python -m app {mode} {count}") 69 | success = "SUCCESS" if completed.returncode == 0 else "FAILURE" 70 | 71 | end_time = time.perf_counter() 72 | 73 | elapsed_time = end_time - start_time 74 | 75 | try: 76 | map_ = wandb.Image(image_path) 77 | except FileNotFoundError: 78 | map_ = None 79 | 80 | log_metrics = { 81 | "execution_time": elapsed_time, 82 | "map": map_, 83 | "success": success, 84 | } 85 | 86 | wandb.log(log_metrics) 87 | 88 | run.finish() 89 | -------------------------------------------------------------------------------- /app/selenium_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ELC/web-scraping-pipeline/9dfaa9cd431ec478c4df80bacb197d13e516e8b5/app/selenium_based/__init__.py -------------------------------------------------------------------------------- /app/selenium_based/compile_profile.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | 3 | from .utils import get_driver, get_headless_driver 4 | from ..common import parameters 5 | 6 | import helium as he 7 | 8 | 9 | def compile_profiles() -> List[Dict[str, str]]: 10 | with get_driver() as driver: 11 | he.set_driver(driver) 12 | he.go_to(parameters.BASE_URL) 13 | 14 | menu_button = he.find_all(he.S("nav .icon--hamburger"))[0] 15 | he.click(menu_button) 16 | 17 | billonaries = he.Text("Billionaires") 18 | 19 | he.wait_until(billonaries.exists) 20 | he.hover(billonaries) 21 | 22 | worlds = he.Text("World's Billionaires") 23 | he.wait_until(worlds.exists) 24 | he.click(worlds) 25 | 26 | rows = he.find_all(he.S(".table .table-row")) 27 | 28 | first_row = rows[0] 29 | he.click(first_row) 30 | 31 | profiles = [] 32 | 33 | for row in rows: 34 | he.click(row) 35 | 36 | profile_button = he.Text("Full Profile") 37 | he.wait_until(profile_button.exists, interval_secs=0.1) 38 | 39 | name = row.web_element.find_element_by_class_name("personName").text 40 | profile_url = profile_button.web_element.get_attribute("href") 41 | 42 | profile = {"name": name, "profile_url": profile_url} 43 | 44 | profiles.append(profile) 45 | 46 | if len(profiles) >= parameters.PROFILE_COUNT: 47 | break 48 | 49 | return profiles 50 | -------------------------------------------------------------------------------- /app/selenium_based/generate_map.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from .utils import get_driver, get_headless_driver 4 | from ..common import parameters 5 | 6 | import helium as he 7 | 8 | 9 | def process(geojson: str) -> None: 10 | with get_driver() as driver: 11 | he.set_driver(driver) 12 | he.go_to(parameters.MAP_URL) 13 | 14 | text_area = he.find_all(he.S(".CodeMirror"))[0] 15 | he.click(text_area) 16 | 17 | he.press([he.BACK_SPACE] * 100) 18 | he.press([he.DELETE] * 100) 19 | he.press(geojson) 20 | 21 | he.click(he.find_all(he.S(".collapse-button"))[0]) 22 | 23 | time.sleep(0.2) 24 | 25 | driver.save_screenshot(str(parameters.DATA_PATH / "richest.png")) 26 | -------------------------------------------------------------------------------- /app/selenium_based/get_coordinates.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | import time 3 | 4 | from .utils import get_driver 5 | from ..common import parameters, parse_strings, round_coordinates 6 | 7 | import helium as he 8 | 9 | 10 | def process(profile: Dict[str, str]) -> Dict[str, str]: 11 | with get_driver() as driver: 12 | he.set_driver(driver) 13 | he.go_to(parameters.LATLONG_URL) 14 | 15 | search_box = he.find_all(he.S("#searchboxinput"))[0] 16 | 17 | source_url = driver.current_url 18 | 19 | he.write(profile["residence"], into=search_box) 20 | he.press(he.ENTER) 21 | 22 | he.wait_until(lambda: source_url != driver.current_url, timeout_secs=15) 23 | time.sleep(5) 24 | 25 | url = driver.current_url 26 | 27 | longitude_raw, latitude_raw = url.split("/")[6].split(",")[:2] 28 | longitude = parse_strings(longitude_raw) 29 | latitude = parse_strings(latitude_raw) 30 | 31 | profile_updated = profile.copy() 32 | profile_updated["longitude"] = round_coordinates(longitude) 33 | profile_updated["latitude"] = round_coordinates(latitude) 34 | 35 | return profile_updated 36 | -------------------------------------------------------------------------------- /app/selenium_based/process_profile.py: -------------------------------------------------------------------------------- 1 | from .utils import get_driver, get_headless_driver 2 | 3 | import helium as he 4 | 5 | 6 | def process(profile): 7 | with get_driver() as driver: 8 | he.set_driver(driver) 9 | he.go_to(profile["profile_url"]) 10 | 11 | personal_information = he.find_all(he.S(".profile-stats__item")) 12 | 13 | residence_row = None 14 | for personal_field in personal_information: 15 | if "residence" in personal_field.web_element.text.lower(): 16 | residence_row = personal_field.web_element 17 | break 18 | 19 | residence = residence_row.find_element_by_class_name("profile-stats__text").text 20 | 21 | profile_updated = profile.copy() 22 | profile_updated["residence"] = residence 23 | 24 | return profile_updated 25 | -------------------------------------------------------------------------------- /app/selenium_based/utils.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | 3 | from selenium import webdriver 4 | from selenium.webdriver.chrome.options import Options 5 | 6 | from webdriver_manager.chrome import ChromeDriverManager 7 | from webdriver_manager.utils import ChromeType 8 | 9 | 10 | chrome_driver = ChromeDriverManager().install() 11 | 12 | 13 | @contextmanager 14 | def get_driver() -> webdriver.Chrome: 15 | options = Options() 16 | 17 | pref = {"profile.default_content_setting_values.notifications": 2} 18 | options.add_argument("window-size=1840,1050") 19 | options.add_experimental_option("prefs", pref) 20 | 21 | try: 22 | driver = webdriver.Chrome(chrome_driver, options=options) 23 | yield driver 24 | finally: 25 | driver.quit() 26 | 27 | 28 | options = Options() 29 | pref = {"profile.default_content_setting_values.notifications": 2} 30 | options.add_argument("window-size=1840,1050") 31 | options.add_experimental_option("prefs", pref) 32 | 33 | singleton_driver = webdriver.Chrome(chrome_driver, options=options) 34 | 35 | 36 | @contextmanager 37 | def get_singleton_driver() -> webdriver.Chrome: 38 | yield singleton_driver 39 | 40 | 41 | def close_singleton_driver() -> None: 42 | singleton_driver.quit() 43 | 44 | 45 | @contextmanager 46 | def get_headless_driver() -> webdriver.Chrome: 47 | options = Options() 48 | options.add_argument("--headless") 49 | options.add_argument("window-size=1920,1080") 50 | 51 | try: 52 | driver = webdriver.Chrome(chrome_driver, options=options) 53 | yield driver 54 | finally: 55 | driver.quit() 56 | -------------------------------------------------------------------------------- /app/tests/create_test.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | 5 | def save_data(count, /, **kwargs): 6 | destination = Path("app", "tests", str(count)) 7 | destination.mkdir(parents=True, exist_ok=True) 8 | 9 | for parameter, value in kwargs.items(): 10 | with open(destination / f"{parameter}.json", "w") as json_file: 11 | json.dump(value, json_file, indent=4) 12 | 13 | 14 | def test_agains_expected(count, parameter, value): 15 | source = Path("app", "tests", str(count)) 16 | 17 | json_file_path = source / f"{parameter}.json" 18 | 19 | if not json_file_path.exists(): 20 | kwargs = {parameter: value} 21 | save_data(count, **kwargs) 22 | return True 23 | 24 | with open(json_file_path) as json_file: 25 | expected = json.load(json_file) 26 | 27 | return value == expected 28 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium>=3.141.0 2 | helium>=3.0.7 3 | webdriver-manager>=3.4.2 4 | playwright>=1.14.1 5 | dagster>=0.12.8 6 | dagit>=0.12.8 7 | tenacity>=8.0.1 8 | mpire>=2.2.1 9 | neptune-client>=0.10.8 10 | python-dotenv>=0.19.0 11 | wandb>=0.12.1 12 | --------------------------------------------------------------------------------