From 859e465da7ecf25c880cd509e911044fe188a019 Mon Sep 17 00:00:00 2001 From: letiziaia <45148109+letiziaia@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:36:02 +0200 Subject: [PATCH] Refactor/rename mutualcl (#3) * refactor * fix typing * update tests after refactoring * add mypy * add stubs * refactor: naming and types * default lint config * unused import * typing and linting * untyped import * revert to same pipfile * fix --- .github/workflows/validate.yml | 1 + Pipfile | 21 +- Pipfile.lock | 2495 ----------------- README.md | 5 +- RUNBOOK.md | 30 +- multilayer_alignment/alignment_score.py | 67 +- multilayer_alignment/consensus.py | 126 + multilayer_alignment/mutual_clusters.py | 121 - multilayer_alignment/null_models.py | 44 +- multilayer_alignment/visualizations.py | 72 +- ruff.toml | 77 + setup.py | 2 +- tests/test_compute_maximal_alignment_curve.py | 6 +- ...test_compute_multilayer_alignment_score.py | 4 +- ...labels.py => test_get_consensus_labels.py} | 24 +- ...ers.py => test_get_consensus_partition.py} | 100 +- ...test_get_consensus_partition_recursive.py} | 100 +- 17 files changed, 442 insertions(+), 2853 deletions(-) delete mode 100644 Pipfile.lock create mode 100644 multilayer_alignment/consensus.py delete mode 100644 multilayer_alignment/mutual_clusters.py create mode 100644 ruff.toml rename tests/{test_get_mutual_clusters_labels.py => test_get_consensus_labels.py} (51%) rename tests/{test_compute_mutual_clusters.py => test_get_consensus_partition.py} (68%) rename tests/{test_compute_mutual_clusters_recursive.py => test_get_consensus_partition_recursive.py} (68%) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 4444767..b3eb781 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -22,6 +22,7 @@ jobs: run: | python -m pip install --upgrade pip pip install pipenv + pipenv lock pipenv verify pipenv install --dev - name: Validate diff --git a/Pipfile b/Pipfile index 2f426fe..0216de1 100644 --- a/Pipfile +++ b/Pipfile @@ -4,21 +4,17 @@ verify_ssl = true name = "pypi" [packages] -click = ">=8.0" -clusim = "*" -cython = "*" +click = "*" joblib = "~=1.2.0" -loguru = "~=0.6.0" +loguru = "*" matplotlib = "~=3.6.1" networkx = "*" -numba = "*" -numpy = "~=1.24.0" +numpy = "*" pandas = "==1.3.5" -scikit-learn = "==1.0.2" +scikit-learn = "~=1.4.1" scipy = "*" seaborn = "*" setuptools = "*" -regex = "*" tqdm = "*" wheel = "*" @@ -26,12 +22,15 @@ wheel = "*" black = "*" coverage = "*" flake8 = "*" +mypy = "*" notebook = "*" -pip-audit = ">=2.4.10" +pandas-stubs = "*" +pip-audit = "*" ruff = "*" +types-tqdm = "*" [scripts] -validate = "bash -c 'python3 -m flake8 && python3 -m pip_audit'" +validate = "bash -c 'python3 -m flake8 && python3 -m mypy . && python3 -m pip_audit'" [requires] -python_version = "3.10" + diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 1ad152b..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,2495 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "c9bf231b4f294caece7297bc67a40768be5fc5fe8c0e2d4019073c7c5da2224d" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.10" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "click": { - "hashes": [ - "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", - "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" - ], - "index": "pypi", - "version": "==8.1.7" - }, - "clusim": { - "hashes": [ - "sha256:f2fc70ec9238610408072604a235b1598f02f3cca28b4bc4a3a6ec25024affa2" - ], - "index": "pypi", - "version": "==0.4" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.6" - }, - "contourpy": { - "hashes": [ - "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8", - "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956", - "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5", - "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063", - "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286", - "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a", - "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686", - "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9", - "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f", - "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4", - "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e", - "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0", - "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e", - "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488", - "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399", - "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431", - "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779", - "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9", - "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab", - "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0", - "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd", - "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e", - "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc", - "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6", - "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316", - "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808", - "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0", - "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f", - "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843", - "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9", - "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95", - "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9", - "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de", - "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4", - "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4", - "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa", - "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8", - "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776", - "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41", - "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108", - "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e", - "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8", - "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727", - "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a" - ], - "markers": "python_version >= '3.9'", - "version": "==1.2.0" - }, - "cycler": { - "hashes": [ - "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", - "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "cython": { - "hashes": [ - "sha256:000dc9e135d0eec6ecb2b40a5b02d0868a2f8d2e027a41b0fe16a908a9e6de02", - "sha256:05d7eddc668ae7993643f32c7661f25544e791edb745758672ea5b1a82ecffa6", - "sha256:0c38c9f0bcce2df0c3347285863621be904ac6b64c5792d871130569d893efd7", - "sha256:0cb2dcc565c7851f75d496f724a384a790fab12d1b82461b663e66605bec429a", - "sha256:115f0a50f752da6c99941b103b5cb090da63eb206abbc7c2ad33856ffc73f064", - "sha256:13c2a5e57a0358da467d97667297bf820b62a1a87ae47c5f87938b9bb593acbd", - "sha256:16873d78be63bd38ffb759da7ab82814b36f56c769ee02b1d5859560e4c3ac3c", - "sha256:171b27051253d3f9108e9759e504ba59ff06e7f7ba944457f94deaf9c21bf0b6", - "sha256:17a642bb01a693e34c914106566f59844b4461665066613913463a719e0dd15d", - "sha256:18bfa387d7a7f77d7b2526af69a65dbd0b731b8d941aaff5becff8e21f6d7717", - "sha256:1ab75242869ff71e5665fe5c96f3378e79e792fa3c11762641b6c5afbbbbe026", - "sha256:1aca1b97e0095b3a9a6c33eada3f661a4ed0d499067d121239b193e5ba3bb4f0", - "sha256:289ce7838208211cd166e975865fd73b0649bf118170b6cebaedfbdaf4a37795", - "sha256:2cde23c555470db3f149ede78b518e8274853745289c956a0e06ad8d982e4db9", - "sha256:2cdfc32252f3b6dc7c94032ab744dcedb45286733443c294d8f909a4854e7f83", - "sha256:2f020fa1c0552052e0660790b8153b79e3fc9a15dbd8f1d0b841fe5d204a6ae6", - "sha256:314f2355a1f1d06e3c431eaad4708cf10037b5e91e4b231d89c913989d0bdafd", - "sha256:3a3d67f079598af49e90ff9655bf85bd358f093d727eb21ca2708f467c489cae", - "sha256:45523fdc2b78d79b32834cc1cc12dc2ca8967af87e22a3ee1bff20e77c7f5520", - "sha256:4b983c8e6803f016146c26854d9150ddad5662960c804ea7f0c752c9266752f0", - "sha256:51d1426263b0e82fb22bda8ea60dc77a428581cc19e97741011b938445d383f1", - "sha256:547eb3cdb2f8c6f48e6865d5a741d9dd051c25b3ce076fbca571727977b28ac3", - "sha256:5a567d4b9ba70b26db89d75b243529de9e649a2f56384287533cf91512705bee", - "sha256:61a237bc9dd23c7faef0fcfce88c11c65d0c9bb73c74ccfa408b3a012073c20e", - "sha256:6717c06e9cfc6c1df18543cd31a21f5d8e378a40f70c851fa2d34f0597037abc", - "sha256:6c46939c3983217d140999de7c238c3141f56b1ea349e47ca49cae899969aa2c", - "sha256:78825a3774211e7d5089730f00cdf7f473042acc9ceb8b9eeebe13ed3a5541de", - "sha256:7990ca127e1f1beedaf8fc8bf66541d066ef4723ad7d8d47a7cbf842e0f47580", - "sha256:7e8f2454128974905258d86534f4fd4f91d2f1343605657ecab779d80c9d6d5e", - "sha256:80fd94c076e1e1b1ee40a309be03080b75f413e8997cddcf401a118879863388", - "sha256:8140597a8b5cc4f119a1190f5a2228a84f5ca6d8d9ec386cfce24663f48b2539", - "sha256:8333423d8fd5765e7cceea3a9985dd1e0a5dfeb2734629e1a2ed2d6233d39de6", - "sha256:85077915a93e359a9b920280d214dc0cf8a62773e1f3d7d30fab8ea4daed670c", - "sha256:870d2a0a7e3cbd5efa65aecdb38d715ea337a904ea7bb22324036e78fb7068e7", - "sha256:90d3fe31db55685d8cb97d43b0ec39ef614fcf660f83c77ed06aa670cb0e164f", - "sha256:96b028f044f5880e3cb18ecdcfc6c8d3ce9d0af28418d5ab464509f26d8adf12", - "sha256:97b2a45845b993304f1799664fa88da676ee19442b15fdcaa31f9da7e1acc434", - "sha256:9d3f74388db378a3c6fd06e79a809ed98df3f56484d317b81ee762dbf3c263e0", - "sha256:9e2be2b340fea46fb849d378f9b80d3c08ff2e81e2bfbcdb656e2e3cd8c6b2dc", - "sha256:a1df7a129344b1215c20096d33c00193437df1a8fcca25b71f17c23b1a44f782", - "sha256:a846e0a38e2b24e9a5c5dc74b0e54c6e29420d88d1dafabc99e0fc0f3e338636", - "sha256:a973268d7ca1a2bdf78575e459a94a78e1a0a9bb62a7db0c50041949a73b02ff", - "sha256:aae26f9663e50caf9657148403d9874eea41770ecdd6caf381d177c2b1bb82ba", - "sha256:ae7ac561fd8253a9ae96311e91d12af5f701383564edc11d6338a7b60b285a6f", - "sha256:baa0b7f3f841fe087410cab66778e2d3fb20ae2d2078a2be3dffe66c6574be39", - "sha256:bfabe115deef4ada5d23c87bddb11289123336dcc14347011832c07db616dd93", - "sha256:c1949d6aa7bc792554bee2b67a9fe41008acbfe22f4f8df7b6ec7b799613a4b3", - "sha256:c26daaeccda072459b48d211415fd1e5507c06bcd976fa0d5b8b9f1063467d7b", - "sha256:c8aa05f5e17f8042a3be052c24f2edc013fb8af874b0bf76907d16c51b4e7871", - "sha256:c9c0f29246734561c90f36e70ed0506b61aa3d044e4cc4cba559065a2a741fae", - "sha256:c9f2c6e1b8f3bcd6cb230bac1843f85114780bb8be8614855b1628b36bb510e0", - "sha256:de892422582f5758bd8de187e98ac829330ec1007bc42c661f687792999988a7", - "sha256:df8093deabc55f37028190cf5e575c26aad23fc673f34b85d5f45076bc37ce39", - "sha256:e24791ddae2324e88e3c902a765595c738f19ae34ee66bfb1a6dac54b1833419", - "sha256:e87294e33e40c289c77a135f491cd721bd089f193f956f7b8ed5aa2d0b8c558f", - "sha256:f05c0bf9d085c031df8f583f0d506aa3be1692023de18c45d0aaf78685bbb944", - "sha256:fa97893d99385386925d00074654aeae3a98867f298d1e12ceaf38a9054a9bae", - "sha256:fe81b339cffd87c0069c6049b4d33e28bdd1874625ee515785bf42c9fdff3658" - ], - "index": "pypi", - "version": "==3.0.8" - }, - "fonttools": { - "hashes": [ - "sha256:0255dbc128fee75fb9be364806b940ed450dd6838672a150d501ee86523ac61e", - "sha256:0a00bd0e68e88987dcc047ea31c26d40a3c61185153b03457956a87e39d43c37", - "sha256:0a1d313a415eaaba2b35d6cd33536560deeebd2ed758b9bfb89ab5d97dc5deac", - "sha256:0f750037e02beb8b3569fbff701a572e62a685d2a0e840d75816592280e5feae", - "sha256:13819db8445a0cec8c3ff5f243af6418ab19175072a9a92f6cc8ca7d1452754b", - "sha256:254d9a6f7be00212bf0c3159e0a420eb19c63793b2c05e049eb337f3023c5ecc", - "sha256:29495d6d109cdbabe73cfb6f419ce67080c3ef9ea1e08d5750240fd4b0c4763b", - "sha256:32ab2e9702dff0dd4510c7bb958f265a8d3dd5c0e2547e7b5f7a3df4979abb07", - "sha256:3480eeb52770ff75140fe7d9a2ec33fb67b07efea0ab5129c7e0c6a639c40c70", - "sha256:3a808f3c1d1df1f5bf39be869b6e0c263570cdafb5bdb2df66087733f566ea71", - "sha256:3b629108351d25512d4ea1a8393a2dba325b7b7d7308116b605ea3f8e1be88df", - "sha256:3d71606c9321f6701642bd4746f99b6089e53d7e9817fc6b964e90d9c5f0ecc6", - "sha256:3e2b95dce2ead58fb12524d0ca7d63a63459dd489e7e5838c3cd53557f8933e1", - "sha256:4a5a5318ba5365d992666ac4fe35365f93004109d18858a3e18ae46f67907670", - "sha256:4c811d3c73b6abac275babb8aa439206288f56fdb2c6f8835e3d7b70de8937a7", - "sha256:4e743935139aa485fe3253fc33fe467eab6ea42583fa681223ea3f1a93dd01e6", - "sha256:4ec558c543609e71b2275c4894e93493f65d2f41c15fe1d089080c1d0bb4d635", - "sha256:5465df494f20a7d01712b072ae3ee9ad2887004701b95cb2cc6dcb9c2c97a899", - "sha256:5b60e3afa9635e3dfd3ace2757039593e3bd3cf128be0ddb7a1ff4ac45fa5a50", - "sha256:63fbed184979f09a65aa9c88b395ca539c94287ba3a364517698462e13e457c9", - "sha256:69731e8bea0578b3c28fdb43dbf95b9386e2d49a399e9a4ad736b8e479b08085", - "sha256:6dd58cc03016b281bd2c74c84cdaa6bd3ce54c5a7f47478b7657b930ac3ed8eb", - "sha256:740947906590a878a4bde7dd748e85fefa4d470a268b964748403b3ab2aeed6c", - "sha256:7df26dd3650e98ca45f1e29883c96a0b9f5bb6af8d632a6a108bc744fa0bd9b3", - "sha256:7eb7ad665258fba68fd22228a09f347469d95a97fb88198e133595947a20a184", - "sha256:7ee48bd9d6b7e8f66866c9090807e3a4a56cf43ffad48962725a190e0dd774c8", - "sha256:86e0427864c6c91cf77f16d1fb9bf1bbf7453e824589e8fb8461b6ee1144f506", - "sha256:8f57ecd742545362a0f7186774b2d1c53423ed9ece67689c93a1055b236f638c", - "sha256:90f898cdd67f52f18049250a6474185ef6544c91f27a7bee70d87d77a8daf89c", - "sha256:94208ea750e3f96e267f394d5588579bb64cc628e321dbb1d4243ffbc291b18b", - "sha256:a1c154bb85dc9a4cf145250c88d112d88eb414bad81d4cb524d06258dea1bdc0", - "sha256:a5d77479fb885ef38a16a253a2f4096bc3d14e63a56d6246bfdb56365a12b20c", - "sha256:a86a5ab2873ed2575d0fcdf1828143cfc6b977ac448e3dc616bb1e3d20efbafa", - "sha256:ac71e2e201df041a2891067dc36256755b1229ae167edbdc419b16da78732c2f", - "sha256:b3e1304e5f19ca861d86a72218ecce68f391646d85c851742d265787f55457a4", - "sha256:b8be28c036b9f186e8c7eaf8a11b42373e7e4949f9e9f370202b9da4c4c3f56c", - "sha256:c19044256c44fe299d9a73456aabee4b4d06c6b930287be93b533b4737d70aa1", - "sha256:d49ce3ea7b7173faebc5664872243b40cf88814ca3eb135c4a3cdff66af71946", - "sha256:e040f905d542362e07e72e03612a6270c33d38281fd573160e1003e43718d68d", - "sha256:eabae77a07c41ae0b35184894202305c3ad211a93b2eb53837c2a1143c8bc952", - "sha256:f791446ff297fd5f1e2247c188de53c1bfb9dd7f0549eba55b73a3c2087a2703", - "sha256:f83a4daef6d2a202acb9bf572958f91cfde5b10c8ee7fb1d09a4c81e5d851fd8" - ], - "markers": "python_version >= '3.8'", - "version": "==4.47.2" - }, - "igraph": { - "hashes": [ - "sha256:14510f569bfc8ea7d2bf23017334b71bad4715c3ad11c14e4513d48f6af3cf40", - "sha256:17d4993815750bef109de185e1b4cdd39dcb6d189e2b2d402ab9fc55d9706b4c", - "sha256:23358cdcb6f7bf8b58363f3603b0d3b0ac375002d2786521382762a2a463294a", - "sha256:23e4eab6d06ad2f6a879a7fab7c6b5a77f6b08604ed5feaf23c3050abbe112e9", - "sha256:2507621877ea5c909e44e3cecf926b99779a05253a723df391079785b42f39fe", - "sha256:2769514695c5b8c207b44676ed4e24f20d132e0aa7eba6a14404e18de08d8c9a", - "sha256:2c1de38a025249d8e61c3e68c62d3332f389d3243aa7f5b44f5bd2ea49b967f5", - "sha256:423190fbb934f8bdbf0418c0dbd258d70365d5eb87216b628b9531e0193baeda", - "sha256:4816f57cd74d00c14f3fde320d0906d2c33ef8ebb679145826b478cd598913ed", - "sha256:4e1aaa2c7b7ca2942fa39e26b9c70b4cf836b4ba2b5879518dfa18bd31d893ee", - "sha256:4ec2ecbe6ce2811f0d9bb291d0a447ff92c3d2d51914245f0eadbcc172d280a5", - "sha256:52ab63b5f33816350bd6cbb39bd4da2c2a2a4b3628fb7775d5071a6c274b5c79", - "sha256:5af03882341320c92aa85cc5681d29f1ed19eb2c8c8d10c8db5999cbcf70f83d", - "sha256:5b3d95b588d1241fd60c70eac91fe534b57517585afd79620eca6d7cfca7a2a7", - "sha256:5d38fa33d702cdc1df6b1346b448fc3564e4449285ece3abed7de92110c71d89", - "sha256:646804f1ed843382958afac01fd83f589fc9268173ef3441d088d9a50f7cb4f4", - "sha256:69b76a986419c639eb9d35ed01a556e6edf9185f17b099dd15689e9c69fb7ad9", - "sha256:799bad487a42c1c8ce4d94c04d6f9c996096072e02f0494ca7ad4d73ca5692c7", - "sha256:7b132c9c23f4714ef6ec9eb641c0ee32204ae812ec5ae8e52b9f6ae606bd8455", - "sha256:84318a9d2469f44f4d1882c66838fde52858cc49cb1270d81eb829bdada15921", - "sha256:93888074f4c8bc00d75bcb0467987f325d3655fdda13e937de4627449a2e5863", - "sha256:94048fefae8d356fc9755b679e8c9fe2234a39a79453fb36dc58f0784e5a574b", - "sha256:96eb5873d230e8389eb6e01144e4bea2cd96d33eab01ab985e8bf2d1cc297fbb", - "sha256:a1b0009229ce713b7585904d52f3c3626d8136c2844231b15d18c22e7ad1cc4c", - "sha256:acce6e4cc0426fc473cbe2e85b63de6e15158405a5db1aa275c0cd68ac5de36c", - "sha256:bfb17b4d5a903f375ed3535e464e32416c1aa3b643107f8313c604d182aa2abc", - "sha256:c07d5d32ff51a9b7286bd4804e84c9c13dc2338f3e2bf95e0598db924f4245be", - "sha256:c92017c2958affd494440f1a4060dc2d744857a0007e3fbafeca6d0265080717", - "sha256:ceb512a3a9710cf1749bb612a2087a0fd8f909c5c630dc365afa8291c908009e", - "sha256:d111eb8058abe113b1a45241a9d68f4b1b58a06bc8bf317af06c8594f654a654", - "sha256:e2e6a4414613e80b921056e7c84ba4394a3ed5ce1b2e4d31105aef8a4dac7c21", - "sha256:e55df60f882a51b8e8c1c5e7e940c5f90685d75634ea6df63bebcc983397adfa", - "sha256:e9d61d8dde1d3b6b0762f2ebc1d923e4f8038fb69f4c00553d57b45b78dd8470", - "sha256:ec6610f6012c6d254a9c5c4f0024d3a7c7912067639b438b9edfb1a0e6eaaf38", - "sha256:f3b561e1634654cb1352f8c040d903c153f79e37612523252436a261cea1ee97", - "sha256:fec7529df2f7222d797e5e1ebea7848b4e868b10368b956b9099f630b863f4ef" - ], - "markers": "python_version >= '3.8'", - "version": "==0.11.3" - }, - "joblib": { - "hashes": [ - "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385", - "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018" - ], - "index": "pypi", - "version": "==1.2.0" - }, - "kiwisolver": { - "hashes": [ - "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf", - "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e", - "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af", - "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f", - "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046", - "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3", - "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5", - "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71", - "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee", - "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3", - "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9", - "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b", - "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985", - "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea", - "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16", - "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89", - "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c", - "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9", - "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712", - "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342", - "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a", - "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958", - "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d", - "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a", - "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130", - "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff", - "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898", - "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b", - "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f", - "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265", - "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93", - "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929", - "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635", - "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709", - "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b", - "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb", - "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a", - "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920", - "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e", - "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544", - "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45", - "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390", - "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77", - "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355", - "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff", - "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4", - "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7", - "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20", - "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c", - "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162", - "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228", - "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437", - "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc", - "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a", - "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901", - "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4", - "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770", - "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525", - "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad", - "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a", - "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29", - "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90", - "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250", - "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d", - "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3", - "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54", - "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f", - "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1", - "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da", - "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238", - "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa", - "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523", - "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0", - "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205", - "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3", - "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4", - "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac", - "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9", - "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb", - "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced", - "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd", - "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0", - "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da", - "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18", - "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9", - "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276", - "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333", - "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b", - "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db", - "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126", - "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9", - "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09", - "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0", - "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec", - "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7", - "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff", - "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9", - "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192", - "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8", - "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d", - "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6", - "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797", - "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892", - "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f" - ], - "markers": "python_version >= '3.7'", - "version": "==1.4.5" - }, - "llvmlite": { - "hashes": [ - "sha256:04725975e5b2af416d685ea0769f4ecc33f97be541e301054c9f741003085802", - "sha256:0dd0338da625346538f1173a17cabf21d1e315cf387ca21b294ff209d176e244", - "sha256:150d0bc275a8ac664a705135e639178883293cf08c1a38de3bbaa2f693a0a867", - "sha256:1eee5cf17ec2b4198b509272cf300ee6577229d237c98cc6e63861b08463ddc6", - "sha256:210e458723436b2469d61b54b453474e09e12a94453c97ea3fbb0742ba5a83d8", - "sha256:2181bb63ef3c607e6403813421b46982c3ac6bfc1f11fa16a13eaafb46f578e6", - "sha256:24091a6b31242bcdd56ae2dbea40007f462260bc9bdf947953acc39dffd54f8f", - "sha256:2b76acee82ea0e9304be6be9d4b3840208d050ea0dcad75b1635fa06e949a0ae", - "sha256:2d92c51e6e9394d503033ffe3292f5bef1566ab73029ec853861f60ad5c925d0", - "sha256:5940bc901fb0325970415dbede82c0b7f3e35c2d5fd1d5e0047134c2c46b3281", - "sha256:8454c1133ef701e8c050a59edd85d238ee18bb9a0eb95faf2fca8b909ee3c89a", - "sha256:855f280e781d49e0640aef4c4af586831ade8f1a6c4df483fb901cbe1a48d127", - "sha256:880cb57ca49e862e1cd077104375b9d1dfdc0622596dfa22105f470d7bacb309", - "sha256:8b0a9a47c28f67a269bb62f6256e63cef28d3c5f13cbae4fab587c3ad506778b", - "sha256:92c32356f669e036eb01016e883b22add883c60739bc1ebee3a1cc0249a50828", - "sha256:92f093986ab92e71c9ffe334c002f96defc7986efda18397d0f08534f3ebdc4d", - "sha256:9564c19b31a0434f01d2025b06b44c7ed422f51e719ab5d24ff03b7560066c9a", - "sha256:b67340c62c93a11fae482910dc29163a50dff3dfa88bc874872d28ee604a83be", - "sha256:bf14aa0eb22b58c231243dccf7e7f42f7beec48970f2549b3a6acc737d1a4ba4", - "sha256:c1e1029d47ee66d3a0c4d6088641882f75b93db82bd0e6178f7bd744ebce42b9", - "sha256:df75594e5a4702b032684d5481db3af990b69c249ccb1d32687b8501f0689432", - "sha256:f19f767a018e6ec89608e1f6b13348fa2fcde657151137cb64e56d48598a92db", - "sha256:f8afdfa6da33f0b4226af8e64cfc2b28986e005528fbf944d0a24a72acfc9432", - "sha256:fa1469901a2e100c17eb8fe2678e34bd4255a3576d1a543421356e9c14d6e2ae" - ], - "markers": "python_version >= '3.8'", - "version": "==0.41.1" - }, - "loguru": { - "hashes": [ - "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c", - "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3" - ], - "index": "pypi", - "version": "==0.6.0" - }, - "matplotlib": { - "hashes": [ - "sha256:01b7f521a9a73c383825813af255f8c4485d1706e4f3e2ed5ae771e4403a40ab", - "sha256:11011c97d62c1db7bc20509572557842dbb8c2a2ddd3dd7f20501aa1cde3e54e", - "sha256:1183877d008c752d7d535396096c910f4663e4b74a18313adee1213328388e1e", - "sha256:12f999661589981e74d793ee2f41b924b3b87d65fd929f6153bf0f30675c59b1", - "sha256:1c235bf9be052347373f589e018988cad177abb3f997ab1a2e2210c41562cc0c", - "sha256:1f4d69707b1677560cd952544ee4962f68ff07952fb9069ff8c12b56353cb8c9", - "sha256:1fcc4cad498533d3c393a160975acc9b36ffa224d15a6b90ae579eacee5d8579", - "sha256:2787a16df07370dcba385fe20cdd0cc3cfaabd3c873ddabca78c10514c799721", - "sha256:29f17b7f2e068dc346687cbdf80b430580bab42346625821c2d3abf3a1ec5417", - "sha256:38d38cb1ea1d80ee0f6351b65c6f76cad6060bbbead015720ba001348ae90f0c", - "sha256:3f56a7252eee8f3438447f75f5e1148a1896a2756a92285fe5d73bed6deebff4", - "sha256:5223affa21050fb6118353c1380c15e23aedfb436bf3e162c26dc950617a7519", - "sha256:57ad1aee29043163374bfa8990e1a2a10ff72c9a1bfaa92e9c46f6ea59269121", - "sha256:59400cc9451094b7f08cc3f321972e6e1db4cd37a978d4e8a12824bf7fd2f03b", - "sha256:68d94a436f62b8a861bf3ace82067a71bafb724b4e4f9133521e4d8012420dd7", - "sha256:6adc441b5b2098a4b904bbf9d9e92fb816fef50c55aa2ea6a823fc89b94bb838", - "sha256:6d81b11ede69e3a751424b98dc869c96c10256b2206bfdf41f9c720eee86844c", - "sha256:73b93af33634ed919e72811c9703e1105185cd3fb46d76f30b7f4cfbbd063f89", - "sha256:77b384cee7ab8cf75ffccbfea351a09b97564fc62d149827a5e864bec81526e5", - "sha256:79e501eb847f4a489eb7065bb8d3187117f65a4c02d12ea3a19d6c5bef173bcc", - "sha256:809119d1cba3ece3c9742eb01827fe7a0e781ea3c5d89534655a75e07979344f", - "sha256:80c166a0e28512e26755f69040e6bf2f946a02ffdb7c00bf6158cca3d2b146e6", - "sha256:81b409b2790cf8d7c1ef35920f01676d2ae7afa8241844e7aa5484fdf493a9a0", - "sha256:994637e2995b0342699b396a320698b07cd148bbcf2dd2fa2daba73f34dd19f2", - "sha256:9ceebaf73f1a3444fa11014f38b9da37ff7ea328d6efa1652241fe3777bfdab9", - "sha256:9fb8fb19d03abf3c5dab89a8677e62c4023632f919a62b6dd1d6d2dbf42cd9f5", - "sha256:acc3b1a4bddbf56fe461e36fb9ef94c2cb607fc90d24ccc650040bfcc7610de4", - "sha256:bbddfeb1495484351fb5b30cf5bdf06b3de0bc4626a707d29e43dfd61af2a780", - "sha256:bbf269e1d24bc25247095d71c7a969813f7080e2a7c6fa28931a603f747ab012", - "sha256:bebcff4c3ed02c6399d47329f3554193abd824d3d53b5ca02cf583bcd94470e2", - "sha256:c3f08df2ac4636249b8bc7a85b8b82c983bef1441595936f62c2918370ca7e1d", - "sha256:ca94f0362f6b6f424b555b956971dcb94b12d0368a6c3e07dc7a40d32d6d873d", - "sha256:d00c248ab6b92bea3f8148714837937053a083ff03b4c5e30ed37e28fc0e7e56", - "sha256:d2cfaa7fd62294d945b8843ea24228a27c8e7c5b48fa634f3c168153b825a21b", - "sha256:d5f18430f5cfa5571ab8f4c72c89af52aa0618e864c60028f11a857d62200cba", - "sha256:debeab8e2ab07e5e3dac33e12456da79c7e104270d2b2d1df92b9e40347cca75", - "sha256:dfba7057609ca9567b9704626756f0142e97ec8c5ba2c70c6e7bd1c25ef99f06", - "sha256:e0a64d7cc336b52e90f59e6d638ae847b966f68582a7af041e063d568e814740", - "sha256:eb9421c403ffd387fbe729de6d9a03005bf42faba5e8432f4e51e703215b49fc", - "sha256:faff486b36530a836a6b4395850322e74211cd81fc17f28b4904e1bd53668e3e", - "sha256:ff2aa84e74f80891e6bcf292ebb1dd57714ffbe13177642d65fee25384a30894" - ], - "index": "pypi", - "version": "==3.6.3" - }, - "mpmath": { - "hashes": [ - "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", - "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c" - ], - "version": "==1.3.0" - }, - "networkx": { - "hashes": [ - "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6", - "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2" - ], - "index": "pypi", - "version": "==3.2.1" - }, - "numba": { - "hashes": [ - "sha256:07f2fa7e7144aa6f275f27260e73ce0d808d3c62b30cff8906ad1dec12d87bbe", - "sha256:240e7a1ae80eb6b14061dc91263b99dc8d6af9ea45d310751b780888097c1aaa", - "sha256:45698b995914003f890ad839cfc909eeb9c74921849c712a05405d1a79c50f68", - "sha256:487ded0633efccd9ca3a46364b40006dbdaca0f95e99b8b83e778d1195ebcbaa", - "sha256:4e79b6cc0d2bf064a955934a2e02bf676bc7995ab2db929dbbc62e4c16551be6", - "sha256:55a01e1881120e86d54efdff1be08381886fe9f04fc3006af309c602a72bc44d", - "sha256:5c765aef472a9406a97ea9782116335ad4f9ef5c9f93fc05fd44aab0db486954", - "sha256:6fe7a9d8e3bd996fbe5eac0683227ccef26cba98dae6e5cee2c1894d4b9f16c1", - "sha256:7bf1ddd4f7b9c2306de0384bf3854cac3edd7b4d8dffae2ec1b925e4c436233f", - "sha256:811305d5dc40ae43c3ace5b192c670c358a89a4d2ae4f86d1665003798ea7a1a", - "sha256:81fe5b51532478149b5081311b0fd4206959174e660c372b94ed5364cfb37c82", - "sha256:898af055b03f09d33a587e9425500e5be84fc90cd2f80b3fb71c6a4a17a7e354", - "sha256:9e9356e943617f5e35a74bf56ff6e7cc83e6b1865d5e13cee535d79bf2cae954", - "sha256:a1eaa744f518bbd60e1f7ccddfb8002b3d06bd865b94a5d7eac25028efe0e0ff", - "sha256:bc2d904d0319d7a5857bd65062340bed627f5bfe9ae4a495aef342f072880d50", - "sha256:bcecd3fb9df36554b342140a4d77d938a549be635d64caf8bd9ef6c47a47f8aa", - "sha256:bd3dda77955be03ff366eebbfdb39919ce7c2620d86c906203bed92124989032", - "sha256:bf68df9c307fb0aa81cacd33faccd6e419496fdc621e83f1efce35cdc5e79cac", - "sha256:d3e2fe81fe9a59fcd99cc572002101119059d64d31eb6324995ee8b0f144a306", - "sha256:e63d6aacaae1ba4ef3695f1c2122b30fa3d8ba039c8f517784668075856d79e2", - "sha256:ea5bfcf7d641d351c6a80e8e1826eb4a145d619870016eeaf20bbd71ef5caa22" - ], - "index": "pypi", - "version": "==0.58.1" - }, - "numpy": { - "hashes": [ - "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f", - "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61", - "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7", - "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400", - "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef", - "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2", - "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d", - "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc", - "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835", - "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706", - "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5", - "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4", - "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6", - "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463", - "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a", - "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f", - "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e", - "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e", - "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694", - "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8", - "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64", - "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d", - "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc", - "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254", - "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2", - "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1", - "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810", - "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9" - ], - "index": "pypi", - "version": "==1.24.4" - }, - "packaging": { - "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" - ], - "markers": "python_version >= '3.7'", - "version": "==23.2" - }, - "pandas": { - "hashes": [ - "sha256:1e4285f5de1012de20ca46b188ccf33521bff61ba5c5ebd78b4fb28e5416a9f1", - "sha256:2651d75b9a167cc8cc572cf787ab512d16e316ae00ba81874b560586fa1325e0", - "sha256:2c21778a688d3712d35710501f8001cdbf96eb70a7c587a3d5613573299fdca6", - "sha256:32e1a26d5ade11b547721a72f9bfc4bd113396947606e00d5b4a5b79b3dcb006", - "sha256:3345343206546545bc26a05b4602b6a24385b5ec7c75cb6059599e3d56831da2", - "sha256:344295811e67f8200de2390093aeb3c8309f5648951b684d8db7eee7d1c81fb7", - "sha256:37f06b59e5bc05711a518aa10beaec10942188dccb48918bb5ae602ccbc9f1a0", - "sha256:552020bf83b7f9033b57cbae65589c01e7ef1544416122da0c79140c93288f56", - "sha256:5cce0c6bbeb266b0e39e35176ee615ce3585233092f685b6a82362523e59e5b4", - "sha256:5f261553a1e9c65b7a310302b9dbac31cf0049a51695c14ebe04e4bfd4a96f02", - "sha256:60a8c055d58873ad81cae290d974d13dd479b82cbb975c3e1fa2cf1920715296", - "sha256:62d5b5ce965bae78f12c1c0df0d387899dd4211ec0bdc52822373f13a3a022b9", - "sha256:7d28a3c65463fd0d0ba8bbb7696b23073efee0510783340a44b08f5e96ffce0c", - "sha256:8025750767e138320b15ca16d70d5cdc1886e8f9cc56652d89735c016cd8aea6", - "sha256:8b6dbec5f3e6d5dc80dcfee250e0a2a652b3f28663492f7dab9a24416a48ac39", - "sha256:a395692046fd8ce1edb4c6295c35184ae0c2bbe787ecbe384251da609e27edcb", - "sha256:a62949c626dd0ef7de11de34b44c6475db76995c2064e2d99c6498c3dba7fe58", - "sha256:aaf183a615ad790801fa3cf2fa450e5b6d23a54684fe386f7e3208f8b9bfbef6", - "sha256:adfeb11be2d54f275142c8ba9bf67acee771b7186a5745249c7d5a06c670136b", - "sha256:b6b87b2fb39e6383ca28e2829cddef1d9fc9e27e55ad91ca9c435572cdba51bf", - "sha256:bd971a3f08b745a75a86c00b97f3007c2ea175951286cdda6abe543e687e5f2f", - "sha256:c69406a2808ba6cf580c2255bcf260b3f214d2664a3a4197d0e640f573b46fd3", - "sha256:d3bc49af96cd6285030a64779de5b3688633a07eb75c124b0747134a63f4c05f", - "sha256:fd541ab09e1f80a2a1760032d665f6e032d8e44055d602d65eeea6e6e85498cb", - "sha256:fe95bae4e2d579812865db2212bb733144e34d0c6785c0685329e5b60fcb85dd" - ], - "index": "pypi", - "version": "==1.3.5" - }, - "pillow": { - "hashes": [ - "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", - "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", - "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", - "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", - "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", - "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", - "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", - "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", - "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", - "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", - "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", - "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", - "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", - "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", - "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", - "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", - "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", - "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", - "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", - "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", - "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", - "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", - "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", - "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", - "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", - "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", - "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", - "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", - "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", - "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", - "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", - "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", - "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", - "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", - "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", - "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", - "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", - "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", - "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", - "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", - "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", - "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", - "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", - "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", - "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", - "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", - "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", - "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", - "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", - "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", - "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", - "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", - "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", - "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", - "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", - "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", - "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", - "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", - "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", - "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", - "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", - "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", - "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", - "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", - "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", - "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", - "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", - "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" - ], - "markers": "python_version >= '3.8'", - "version": "==10.2.0" - }, - "pyparsing": { - "hashes": [ - "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb", - "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "python-igraph": { - "hashes": [ - "sha256:a350a482eda7f8ecdd54fd396eabe95dd27d01f074951279c67e80ae9cb6abdf", - "sha256:ae49dbe60693d1c0214a922e09e61916b47fc8f8e1eb13d948f4aab8b27af854" - ], - "markers": "python_version >= '3.6'", - "version": "==0.11.3" - }, - "pytz": { - "hashes": [ - "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", - "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7" - ], - "version": "==2023.3.post1" - }, - "regex": { - "hashes": [ - "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5", - "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770", - "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc", - "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105", - "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d", - "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b", - "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9", - "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630", - "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6", - "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c", - "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482", - "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6", - "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a", - "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80", - "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5", - "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1", - "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f", - "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf", - "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb", - "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2", - "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347", - "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20", - "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060", - "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5", - "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73", - "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f", - "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d", - "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3", - "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae", - "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4", - "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2", - "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457", - "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c", - "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4", - "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87", - "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0", - "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704", - "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f", - "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f", - "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b", - "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5", - "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923", - "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715", - "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c", - "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca", - "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1", - "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756", - "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360", - "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc", - "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445", - "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e", - "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4", - "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a", - "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8", - "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53", - "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697", - "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf", - "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a", - "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415", - "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f", - "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9", - "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400", - "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d", - "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392", - "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb", - "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd", - "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861", - "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232", - "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95", - "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7", - "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39", - "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887", - "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5", - "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39", - "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb", - "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586", - "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97", - "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423", - "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69", - "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7", - "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1", - "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7", - "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5", - "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8", - "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91", - "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590", - "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe", - "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c", - "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64", - "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd", - "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa", - "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31", - "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988" - ], - "index": "pypi", - "version": "==2023.12.25" - }, - "scikit-learn": { - "hashes": [ - "sha256:08ef968f6b72033c16c479c966bf37ccd49b06ea91b765e1cc27afefe723920b", - "sha256:158faf30684c92a78e12da19c73feff9641a928a8024b4fa5ec11d583f3d8a87", - "sha256:16455ace947d8d9e5391435c2977178d0ff03a261571e67f627c8fee0f9d431a", - "sha256:245c9b5a67445f6f044411e16a93a554edc1efdcce94d3fc0bc6a4b9ac30b752", - "sha256:285db0352e635b9e3392b0b426bc48c3b485512d3b4ac3c7a44ec2a2ba061e66", - "sha256:2f3b453e0b149898577e301d27e098dfe1a36943f7bb0ad704d1e548efc3b448", - "sha256:46f431ec59dead665e1370314dbebc99ead05e1c0a9df42f22d6a0e00044820f", - "sha256:55f2f3a8414e14fbee03782f9fe16cca0f141d639d2b1c1a36779fa069e1db57", - "sha256:5cb33fe1dc6f73dc19e67b264dbb5dde2a0539b986435fdd78ed978c14654830", - "sha256:75307d9ea39236cad7eea87143155eea24d48f93f3a2f9389c817f7019f00705", - "sha256:7626a34eabbf370a638f32d1a3ad50526844ba58d63e3ab81ba91e2a7c6d037e", - "sha256:7a93c1292799620df90348800d5ac06f3794c1316ca247525fa31169f6d25855", - "sha256:7d6b2475f1c23a698b48515217eb26b45a6598c7b1840ba23b3c5acece658dbb", - "sha256:80095a1e4b93bd33261ef03b9bc86d6db649f988ea4dbcf7110d0cded8d7213d", - "sha256:85260fb430b795d806251dd3bb05e6f48cdc777ac31f2bcf2bc8bbed3270a8f5", - "sha256:9369b030e155f8188743eb4893ac17a27f81d28a884af460870c7c072f114243", - "sha256:a053a6a527c87c5c4fa7bf1ab2556fa16d8345cf99b6c5a19030a4a7cd8fd2c0", - "sha256:a90b60048f9ffdd962d2ad2fb16367a87ac34d76e02550968719eb7b5716fd10", - "sha256:a999c9f02ff9570c783069f1074f06fe7386ec65b84c983db5aeb8144356a355", - "sha256:b1391d1a6e2268485a63c3073111fe3ba6ec5145fc957481cfd0652be571226d", - "sha256:b54a62c6e318ddbfa7d22c383466d38d2ee770ebdb5ddb668d56a099f6eaf75f", - "sha256:b5870959a5484b614f26d31ca4c17524b1b0317522199dc985c3b4256e030767", - "sha256:bc3744dabc56b50bec73624aeca02e0def06b03cb287de26836e730659c5d29c", - "sha256:d93d4c28370aea8a7cbf6015e8a669cd5d69f856cc2aa44e7a590fb805bb5583", - "sha256:d9aac97e57c196206179f674f09bc6bffcd0284e2ba95b7fe0b402ac3f986023", - "sha256:da3c84694ff693b5b3194d8752ccf935a665b8b5edc33a283122f4273ca3e687", - "sha256:e174242caecb11e4abf169342641778f68e1bfaba80cd18acd6bc84286b9a534", - "sha256:eabceab574f471de0b0eb3f2ecf2eee9f10b3106570481d007ed1c84ebf6d6a1", - "sha256:f14517e174bd7332f1cca2c959e704696a5e0ba246eb8763e6c24876d8710049", - "sha256:fa38a1b9b38ae1fad2863eff5e0d69608567453fdfc850c992e6e47eb764e846", - "sha256:ff3fa8ea0e09e38677762afc6e14cad77b5e125b0ea70c9bba1992f02c93b028", - "sha256:ff746a69ff2ef25f62b36338c615dd15954ddc3ab8e73530237dd73235e76d62" - ], - "index": "pypi", - "version": "==1.0.2" - }, - "scipy": { - "hashes": [ - "sha256:00150c5eae7b610c32589dda259eacc7c4f1665aedf25d921907f4d08a951b1c", - "sha256:028eccd22e654b3ea01ee63705681ee79933652b2d8f873e7949898dda6d11b6", - "sha256:1b7c3dca977f30a739e0409fb001056484661cb2541a01aba0bb0029f7b68db8", - "sha256:2c6ff6ef9cc27f9b3db93a6f8b38f97387e6e0591600369a297a50a8e96e835d", - "sha256:36750b7733d960d7994888f0d148d31ea3017ac15eef664194b4ef68d36a4a97", - "sha256:530f9ad26440e85766509dbf78edcfe13ffd0ab7fec2560ee5c36ff74d6269ff", - "sha256:5e347b14fe01003d3b78e196e84bd3f48ffe4c8a7b8a1afbcb8f5505cb710993", - "sha256:6550466fbeec7453d7465e74d4f4b19f905642c89a7525571ee91dd7adabb5a3", - "sha256:6df1468153a31cf55ed5ed39647279beb9cfb5d3f84369453b49e4b8502394fd", - "sha256:6e619aba2df228a9b34718efb023966da781e89dd3d21637b27f2e54db0410d7", - "sha256:8fce70f39076a5aa62e92e69a7f62349f9574d8405c0a5de6ed3ef72de07f446", - "sha256:90a2b78e7f5733b9de748f589f09225013685f9b218275257f8a8168ededaeaa", - "sha256:91af76a68eeae0064887a48e25c4e616fa519fa0d38602eda7e0f97d65d57937", - "sha256:933baf588daa8dc9a92c20a0be32f56d43faf3d1a60ab11b3f08c356430f6e56", - "sha256:acf8ed278cc03f5aff035e69cb511741e0418681d25fbbb86ca65429c4f4d9cd", - "sha256:ad669df80528aeca5f557712102538f4f37e503f0c5b9541655016dd0932ca79", - "sha256:b030c6674b9230d37c5c60ab456e2cf12f6784596d15ce8da9365e70896effc4", - "sha256:b9999c008ccf00e8fbcce1236f85ade5c569d13144f77a1946bef8863e8f6eb4", - "sha256:bc9a714581f561af0848e6b69947fda0614915f072dfd14142ed1bfe1b806710", - "sha256:ce7fff2e23ab2cc81ff452a9444c215c28e6305f396b2ba88343a567feec9660", - "sha256:cf00bd2b1b0211888d4dc75656c0412213a8b25e80d73898083f402b50f47e41", - "sha256:d10e45a6c50211fe256da61a11c34927c68f277e03138777bdebedd933712fea", - "sha256:ee410e6de8f88fd5cf6eadd73c135020bfbbbdfcd0f6162c36a7638a1ea8cc65", - "sha256:f313b39a7e94f296025e3cffc2c567618174c0b1dde173960cf23808f9fae4be", - "sha256:f3cd9e7b3c2c1ec26364856f9fbe78695fe631150f94cd1c22228456404cf1ec" - ], - "index": "pypi", - "version": "==1.11.4" - }, - "seaborn": { - "hashes": [ - "sha256:6baa69b6d1169ae59037971491c450c0b73332b42bd4b23570b62a546bc61cb8", - "sha256:bfad65e9c5989e5e1897e61bdbd2f22e62455940ca76fd49eca3ed69345b9179" - ], - "index": "pypi", - "version": "==0.13.1" - }, - "setuptools": { - "hashes": [ - "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", - "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" - ], - "index": "pypi", - "version": "==69.0.3" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "texttable": { - "hashes": [ - "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638", - "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917" - ], - "version": "==1.7.0" - }, - "threadpoolctl": { - "hashes": [ - "sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032", - "sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355" - ], - "markers": "python_version >= '3.8'", - "version": "==3.2.0" - }, - "tqdm": { - "hashes": [ - "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386", - "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7" - ], - "index": "pypi", - "version": "==4.66.1" - }, - "wheel": { - "hashes": [ - "sha256:177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d", - "sha256:c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8" - ], - "index": "pypi", - "version": "==0.42.0" - }, - "win32-setctime": { - "hashes": [ - "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2", - "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad" - ], - "markers": "sys_platform == 'win32'", - "version": "==1.1.0" - } - }, - "develop": { - "anyio": { - "hashes": [ - "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee", - "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f" - ], - "markers": "python_version >= '3.8'", - "version": "==4.2.0" - }, - "argon2-cffi": { - "hashes": [ - "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", - "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea" - ], - "markers": "python_version >= '3.7'", - "version": "==23.1.0" - }, - "argon2-cffi-bindings": { - "hashes": [ - "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670", - "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f", - "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583", - "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194", - "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", - "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a", - "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", - "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5", - "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", - "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7", - "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", - "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", - "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", - "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", - "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", - "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", - "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d", - "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", - "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb", - "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", - "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==21.2.0" - }, - "arrow": { - "hashes": [ - "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", - "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85" - ], - "markers": "python_version >= '3.8'", - "version": "==1.3.0" - }, - "asttokens": { - "hashes": [ - "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", - "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" - ], - "version": "==2.4.1" - }, - "async-lru": { - "hashes": [ - "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627", - "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224" - ], - "markers": "python_version >= '3.8'", - "version": "==2.0.4" - }, - "attrs": { - "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" - ], - "markers": "python_version >= '3.7'", - "version": "==23.2.0" - }, - "babel": { - "hashes": [ - "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", - "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" - ], - "markers": "python_version >= '3.7'", - "version": "==2.14.0" - }, - "beautifulsoup4": { - "hashes": [ - "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", - "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==4.12.3" - }, - "black": { - "hashes": [ - "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50", - "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f", - "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e", - "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec", - "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055", - "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3", - "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5", - "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54", - "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b", - "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e", - "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e", - "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba", - "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea", - "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59", - "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d", - "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0", - "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9", - "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a", - "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e", - "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba", - "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2", - "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2" - ], - "index": "pypi", - "version": "==23.12.1" - }, - "bleach": { - "hashes": [ - "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe", - "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6" - ], - "markers": "python_version >= '3.8'", - "version": "==6.1.0" - }, - "boolean.py": { - "hashes": [ - "sha256:17b9a181630e43dde1851d42bef546d616d5d9b4480357514597e78b203d06e4", - "sha256:2876f2051d7d6394a531d82dc6eb407faa0b01a0a0b3083817ccd7323b8d96bd" - ], - "version": "==4.0" - }, - "cachecontrol": { - "extras": [ - "filecache" - ], - "hashes": [ - "sha256:95dedbec849f46dda3137866dc28b9d133fc9af55f5b805ab1291833e4457aa4", - "sha256:f012366b79d2243a6118309ce73151bf52a38d4a5dac8ea57f09bd29087e506b" - ], - "markers": "python_version >= '3.7'", - "version": "==0.13.1" - }, - "certifi": { - "hashes": [ - "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", - "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==2023.11.17" - }, - "cffi": { - "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" - ], - "markers": "python_version >= '3.8'", - "version": "==1.16.0" - }, - "charset-normalizer": { - "hashes": [ - "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", - "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", - "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", - "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", - "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", - "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", - "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", - "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", - "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", - "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", - "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", - "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", - "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", - "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", - "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", - "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", - "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", - "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", - "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", - "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", - "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", - "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", - "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", - "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", - "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", - "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", - "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", - "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", - "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", - "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", - "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", - "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", - "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", - "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", - "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", - "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", - "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", - "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", - "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", - "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", - "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", - "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", - "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", - "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", - "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", - "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", - "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", - "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", - "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", - "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", - "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", - "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", - "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", - "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", - "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", - "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", - "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", - "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", - "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", - "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", - "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", - "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", - "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", - "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", - "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", - "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", - "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", - "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", - "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", - "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", - "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", - "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", - "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", - "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", - "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", - "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", - "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", - "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", - "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", - "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", - "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", - "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", - "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", - "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", - "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", - "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", - "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", - "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", - "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" - ], - "markers": "python_version >= '3.7'", - "version": "==3.3.2" - }, - "click": { - "hashes": [ - "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", - "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" - ], - "index": "pypi", - "version": "==8.1.7" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.6" - }, - "comm": { - "hashes": [ - "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a", - "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021" - ], - "markers": "python_version >= '3.8'", - "version": "==0.2.1" - }, - "coverage": { - "hashes": [ - "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca", - "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471", - "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a", - "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058", - "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85", - "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143", - "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446", - "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590", - "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a", - "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105", - "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9", - "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a", - "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac", - "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25", - "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2", - "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450", - "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932", - "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba", - "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137", - "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae", - "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614", - "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70", - "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e", - "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505", - "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870", - "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc", - "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451", - "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7", - "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e", - "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566", - "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5", - "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26", - "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2", - "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42", - "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555", - "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43", - "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed", - "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa", - "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516", - "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952", - "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd", - "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09", - "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c", - "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f", - "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6", - "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1", - "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0", - "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e", - "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9", - "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9", - "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e", - "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06" - ], - "index": "pypi", - "version": "==7.4.0" - }, - "cyclonedx-python-lib": { - "hashes": [ - "sha256:0e73c1036c2f7fc67adc28aef807e6b44340ea70202aab197fb06b20ea165de8", - "sha256:82f2489de3c0cadad5af1ad7fa6b6a185f985746370245d38769699c734533c6" - ], - "markers": "python_version >= '3.8' and python_version < '4.0'", - "version": "==6.3.0" - }, - "debugpy": { - "hashes": [ - "sha256:125b9a637e013f9faac0a3d6a82bd17c8b5d2c875fb6b7e2772c5aba6d082332", - "sha256:12af2c55b419521e33d5fb21bd022df0b5eb267c3e178f1d374a63a2a6bdccd0", - "sha256:3c6fb41c98ec51dd010d7ed650accfd07a87fe5e93eca9d5f584d0578f28f35f", - "sha256:46ab6780159eeabb43c1495d9c84cf85d62975e48b6ec21ee10c95767c0590aa", - "sha256:57161629133113c97b387382045649a2b985a348f0c9366e22217c87b68b73c6", - "sha256:5d9de202f5d42e62f932507ee8b21e30d49aae7e46d5b1dd5c908db1d7068637", - "sha256:60009b132c91951354f54363f8ebdf7457aeb150e84abba5ae251b8e9f29a8a6", - "sha256:61eab4a4c8b6125d41a34bad4e5fe3d2cc145caecd63c3fe953be4cc53e65bf8", - "sha256:7fb95ca78f7ac43393cd0e0f2b6deda438ec7c5e47fa5d38553340897d2fbdfb", - "sha256:8cd0197141eb9e8a4566794550cfdcdb8b3db0818bdf8c49a8e8f8053e56e38b", - "sha256:9c9b0ac1ce2a42888199df1a1906e45e6f3c9555497643a85e0bf2406e3ffbc4", - "sha256:a64093656c4c64dc6a438e11d59369875d200bd5abb8f9b26c1f5f723622e153", - "sha256:a8b7a2fd27cd9f3553ac112f356ad4ca93338feadd8910277aff71ab24d8775f", - "sha256:b05a6b503ed520ad58c8dc682749113d2fd9f41ffd45daec16e558ca884008cd", - "sha256:bdc5ef99d14b9c0fcb35351b4fbfc06ac0ee576aeab6b2511702e5a648a2e595", - "sha256:e3412f9faa9ade82aa64a50b602544efcba848c91384e9f93497a458767e6926", - "sha256:ef54404365fae8d45cf450d0544ee40cefbcb9cb85ea7afe89a963c27028261e", - "sha256:ef9ab7df0b9a42ed9c878afd3eaaff471fce3fa73df96022e1f5c9f8f8c87ada" - ], - "markers": "python_version >= '3.8'", - "version": "==1.8.0" - }, - "decorator": { - "hashes": [ - "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", - "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" - ], - "markers": "python_version >= '3.5'", - "version": "==5.1.1" - }, - "defusedxml": { - "hashes": [ - "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", - "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.7.1" - }, - "exceptiongroup": { - "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" - ], - "markers": "python_version < '3.11'", - "version": "==1.2.0" - }, - "executing": { - "hashes": [ - "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147", - "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc" - ], - "markers": "python_version >= '3.5'", - "version": "==2.0.1" - }, - "fastjsonschema": { - "hashes": [ - "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0", - "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d" - ], - "version": "==2.19.1" - }, - "filelock": { - "hashes": [ - "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e", - "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c" - ], - "version": "==3.13.1" - }, - "flake8": { - "hashes": [ - "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", - "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" - ], - "index": "pypi", - "version": "==7.0.0" - }, - "fqdn": { - "hashes": [ - "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", - "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014" - ], - "version": "==1.5.1" - }, - "html5lib": { - "hashes": [ - "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d", - "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.1" - }, - "idna": { - "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" - ], - "markers": "python_version >= '3.5'", - "version": "==3.6" - }, - "ipykernel": { - "hashes": [ - "sha256:076663ca68492576f051e4af7720d33f34383e655f2be0d544c8b1c9de915b2f", - "sha256:b5dd3013cab7b330df712891c96cd1ab868c27a7159e606f762015e9bf8ceb3f" - ], - "markers": "python_version >= '3.8'", - "version": "==6.29.0" - }, - "ipython": { - "hashes": [ - "sha256:2f21bd3fc1d51550c89ee3944ae04bbc7bc79e129ea0937da6e6c68bfdbf117a", - "sha256:bc9716aad6f29f36c449e30821c9dd0c1c1a7b59ddcc26931685b87b4c569619" - ], - "markers": "python_version >= '3.10'", - "version": "==8.20.0" - }, - "isoduration": { - "hashes": [ - "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", - "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042" - ], - "version": "==20.11.0" - }, - "jedi": { - "hashes": [ - "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", - "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==0.19.1" - }, - "jinja2": { - "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.3" - }, - "json5": { - "hashes": [ - "sha256:740c7f1b9e584a468dbb2939d8d458db3427f2c93ae2139d05f47e453eae964f", - "sha256:9ed66c3a6ca3510a976a9ef9b8c0787de24802724ab1860bc0153c7fdd589b02" - ], - "version": "==0.9.14" - }, - "jsonpointer": { - "hashes": [ - "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a", - "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88" - ], - "version": "==2.4" - }, - "jsonschema": { - "hashes": [ - "sha256:3ba18e27f7491ea4a1b22edce00fb820eec968d397feb3f9cb61d5894bb38167", - "sha256:70a09719d375c0a2874571b363c8a24be7df8071b80c9aa76bc4551e7297c63c" - ], - "markers": "python_version >= '3.8'", - "version": "==4.21.0" - }, - "jsonschema-specifications": { - "hashes": [ - "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", - "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" - ], - "markers": "python_version >= '3.8'", - "version": "==2023.12.1" - }, - "jupyter-client": { - "hashes": [ - "sha256:0642244bb83b4764ae60d07e010e15f0e2d275ec4e918a8f7b80fbbef3ca60c7", - "sha256:909c474dbe62582ae62b758bca86d6518c85234bdee2d908c778db6d72f39d99" - ], - "markers": "python_version >= '3.8'", - "version": "==8.6.0" - }, - "jupyter-core": { - "hashes": [ - "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7", - "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218" - ], - "markers": "python_version >= '3.8'", - "version": "==5.7.1" - }, - "jupyter-events": { - "hashes": [ - "sha256:81ad2e4bc710881ec274d31c6c50669d71bbaa5dd9d01e600b56faa85700d399", - "sha256:d853b3c10273ff9bc8bb8b30076d65e2c9685579db736873de6c2232dde148bf" - ], - "markers": "python_version >= '3.8'", - "version": "==0.9.0" - }, - "jupyter-lsp": { - "hashes": [ - "sha256:256d24620542ae4bba04a50fc1f6ffe208093a07d8e697fea0a8d1b8ca1b7e5b", - "sha256:3b95229e4168355a8c91928057c1621ac3510ba98b2a925e82ebd77f078b1aa5" - ], - "markers": "python_version >= '3.8'", - "version": "==2.2.2" - }, - "jupyter-server": { - "hashes": [ - "sha256:0edb626c94baa22809be1323f9770cf1c00a952b17097592e40d03e6a3951689", - "sha256:184a0f82809a8522777cfb6b760ab6f4b1bb398664c5860a27cec696cb884923" - ], - "markers": "python_version >= '3.8'", - "version": "==2.12.5" - }, - "jupyter-server-terminals": { - "hashes": [ - "sha256:16d3be9cf48be6a1f943f3a6c93c033be259cf4779184c66421709cf63dccfea", - "sha256:5e63e947ddd97bb2832db5ef837a258d9ccd4192cd608c1270850ad947ae5dd7" - ], - "markers": "python_version >= '3.8'", - "version": "==0.5.1" - }, - "jupyterlab": { - "hashes": [ - "sha256:46177eb8ede70dc73be922ac99f8ef943bdc2dfbc6a31b353c4bde848a35dee1", - "sha256:fe010ad9e37017488b468632ef2ead255fc7c671c5b64d9ca13e1f7b7e665c37" - ], - "markers": "python_version >= '3.8'", - "version": "==4.0.10" - }, - "jupyterlab-pygments": { - "hashes": [ - "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", - "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780" - ], - "markers": "python_version >= '3.8'", - "version": "==0.3.0" - }, - "jupyterlab-server": { - "hashes": [ - "sha256:5b1798c9cc6a44f65c757de9f97fc06fc3d42535afbf47d2ace5e964ab447aaf", - "sha256:bd0ec7a99ebcedc8bcff939ef86e52c378e44c2707e053fcd81d046ce979ee63" - ], - "markers": "python_version >= '3.8'", - "version": "==2.25.2" - }, - "license-expression": { - "hashes": [ - "sha256:1a7dc2bb2d09cdc983d072e4f9adc787e107e09def84cbb3919baaaf4f8e6fa1", - "sha256:599928edd995c43fc335e0af342076144dc71cb858afa1ed9c1c30c4e81794f5" - ], - "markers": "python_version >= '3.7'", - "version": "==30.2.0" - }, - "markdown-it-py": { - "hashes": [ - "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", - "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" - ], - "markers": "python_version >= '3.8'", - "version": "==3.0.0" - }, - "markupsafe": { - "hashes": [ - "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", - "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", - "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", - "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", - "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", - "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", - "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", - "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", - "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", - "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", - "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", - "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", - "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", - "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", - "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", - "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", - "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", - "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", - "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", - "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", - "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", - "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", - "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", - "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", - "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", - "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", - "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", - "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", - "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", - "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", - "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", - "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", - "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", - "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", - "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", - "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", - "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", - "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", - "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", - "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", - "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", - "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", - "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", - "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", - "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", - "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", - "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", - "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", - "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", - "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", - "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", - "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", - "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", - "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", - "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", - "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", - "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", - "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.3" - }, - "matplotlib-inline": { - "hashes": [ - "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311", - "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304" - ], - "markers": "python_version >= '3.5'", - "version": "==0.1.6" - }, - "mccabe": { - "hashes": [ - "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", - "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==0.7.0" - }, - "mdurl": { - "hashes": [ - "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", - "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" - ], - "markers": "python_version >= '3.7'", - "version": "==0.1.2" - }, - "mistune": { - "hashes": [ - "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205", - "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8" - ], - "markers": "python_version >= '3.7'", - "version": "==3.0.2" - }, - "msgpack": { - "hashes": [ - "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862", - "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d", - "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3", - "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672", - "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0", - "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9", - "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee", - "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46", - "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524", - "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819", - "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc", - "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc", - "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1", - "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82", - "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81", - "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6", - "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d", - "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2", - "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c", - "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87", - "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84", - "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e", - "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95", - "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f", - "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b", - "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93", - "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf", - "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61", - "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c", - "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8", - "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d", - "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c", - "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4", - "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba", - "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415", - "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee", - "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d", - "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9", - "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075", - "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f", - "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7", - "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681", - "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329", - "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1", - "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf", - "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c", - "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5", - "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b", - "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5", - "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e", - "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b", - "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad", - "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd", - "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7", - "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002", - "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc" - ], - "markers": "python_version >= '3.8'", - "version": "==1.0.7" - }, - "mypy-extensions": { - "hashes": [ - "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", - "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.0" - }, - "nbclient": { - "hashes": [ - "sha256:4b28c207877cf33ef3a9838cdc7a54c5ceff981194a82eac59d558f05487295e", - "sha256:a3a1ddfb34d4a9d17fc744d655962714a866639acd30130e9be84191cd97cd15" - ], - "markers": "python_version >= '3.8'", - "version": "==0.9.0" - }, - "nbconvert": { - "hashes": [ - "sha256:a7f8808fd4e082431673ac538400218dd45efd076fbeb07cc6e5aa5a3a4e949e", - "sha256:db28590cef90f7faf2ebbc71acd402cbecf13d29176df728c0a9025a49345ea1" - ], - "markers": "python_version >= '3.8'", - "version": "==7.14.2" - }, - "nbformat": { - "hashes": [ - "sha256:1c5172d786a41b82bcfd0c23f9e6b6f072e8fb49c39250219e4acfff1efe89e9", - "sha256:5f98b5ba1997dff175e77e0c17d5c10a96eaed2cbd1de3533d1fc35d5e111192" - ], - "markers": "python_version >= '3.8'", - "version": "==5.9.2" - }, - "nest-asyncio": { - "hashes": [ - "sha256:61ec07ef052e72e3de22045b81b2cc7d71fceb04c568ba0b2e4b2f9f5231bec2", - "sha256:d1e1144e9c6e3e6392e0fcf5211cb1c8374b5648a98f1ebe48e5336006b41907" - ], - "markers": "python_version >= '3.5'", - "version": "==1.5.9" - }, - "notebook": { - "hashes": [ - "sha256:0fe8f67102fea3744fedf652e4c15339390902ca70c5a31c4f547fa23da697cc", - "sha256:ec6113b06529019f7f287819af06c97a2baf7a95ac21a8f6e32192898e9f9a58" - ], - "index": "pypi", - "version": "==7.0.6" - }, - "notebook-shim": { - "hashes": [ - "sha256:a83496a43341c1674b093bfcebf0fe8e74cbe7eda5fd2bbc56f8e39e1486c0c7", - "sha256:f69388ac283ae008cd506dda10d0288b09a017d822d5e8c7129a152cbd3ce7e9" - ], - "markers": "python_version >= '3.7'", - "version": "==0.2.3" - }, - "overrides": { - "hashes": [ - "sha256:3ad24583f86d6d7a49049695efe9933e67ba62f0c7625d53c59fa832ce4b8b7d", - "sha256:9502a3cca51f4fac40b5feca985b6703a5c1f6ad815588a7ca9e285b9dca6757" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==7.4.0" - }, - "packageurl-python": { - "hashes": [ - "sha256:62aa13d60a0082ff115784fefdfe73a12f310e455365cca7c6d362161067f35f", - "sha256:6eb5e995009cc73387095e0b507ab65df51357d25ddc5fce3d3545ad6dcbbee8" - ], - "markers": "python_version >= '3.7'", - "version": "==0.13.4" - }, - "packaging": { - "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" - ], - "markers": "python_version >= '3.7'", - "version": "==23.2" - }, - "pandocfilters": { - "hashes": [ - "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38", - "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.0" - }, - "parso": { - "hashes": [ - "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", - "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==0.8.3" - }, - "pathspec": { - "hashes": [ - "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", - "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "pip": { - "hashes": [ - "sha256:5052d7889c1f9d05224cd41741acb7c5d6fa735ab34e339624a614eaaa7e7d76", - "sha256:7fd9972f96db22c8077a1ee2691b172c8089b17a5652a44494a9ecb0d78f9149" - ], - "markers": "python_version >= '3.7'", - "version": "==23.3.2" - }, - "pip-api": { - "hashes": [ - "sha256:2a0314bd31522eb9ffe8a99668b0d07fee34ebc537931e7b6483001dbedcbdc9", - "sha256:a05df2c7aa9b7157374bcf4273544201a0c7bae60a9c65bcf84f3959ef3896f3" - ], - "markers": "python_version >= '3.7'", - "version": "==0.0.30" - }, - "pip-audit": { - "hashes": [ - "sha256:67740c5b1d5d967a258c3dfefc46f9713a2819c48062505ddf4b29de101c2b75", - "sha256:83e039740653eb9ef1a78b1540ed441600cd88a560588ba2c0a169180685a522" - ], - "index": "pypi", - "version": "==2.7.0" - }, - "pip-requirements-parser": { - "hashes": [ - "sha256:4659bc2a667783e7a15d190f6fccf8b2486685b6dba4c19c3876314769c57526", - "sha256:b4fa3a7a0be38243123cf9d1f3518da10c51bdb165a2b2985566247f9155a7d3" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==32.0.1" - }, - "platformdirs": { - "hashes": [ - "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380", - "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420" - ], - "markers": "python_version >= '3.8'", - "version": "==4.1.0" - }, - "prometheus-client": { - "hashes": [ - "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1", - "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92" - ], - "markers": "python_version >= '3.8'", - "version": "==0.19.0" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d", - "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6" - ], - "markers": "python_version >= '3.7'", - "version": "==3.0.43" - }, - "psutil": { - "hashes": [ - "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340", - "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6", - "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284", - "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c", - "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7", - "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c", - "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e", - "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6", - "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056", - "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9", - "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68", - "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df", - "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e", - "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414", - "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508", - "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==5.9.7" - }, - "pure-eval": { - "hashes": [ - "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", - "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3" - ], - "version": "==0.2.2" - }, - "py-serializable": { - "hashes": [ - "sha256:389c2254d912bec3a44acdac667c947d73c59325050d5ae66386e1ed7108a45a", - "sha256:875bb9c01df77f563dfcd1e75bb4244b5596083d3aad4ccd3fb63e1f5a9d3e5f" - ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==0.17.1" - }, - "pycodestyle": { - "hashes": [ - "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", - "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67" - ], - "markers": "python_version >= '3.8'", - "version": "==2.11.1" - }, - "pycparser": { - "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" - ], - "version": "==2.21" - }, - "pyflakes": { - "hashes": [ - "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", - "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" - ], - "markers": "python_version >= '3.8'", - "version": "==3.2.0" - }, - "pygments": { - "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" - ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" - }, - "pyparsing": { - "hashes": [ - "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb", - "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "python-json-logger": { - "hashes": [ - "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c", - "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==2.0.7" - }, - "pywin32": { - "hashes": [ - "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d", - "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65", - "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", - "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", - "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4", - "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", - "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", - "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36", - "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8", - "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", - "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802", - "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a", - "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", - "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0" - ], - "markers": "sys_platform == 'win32' and platform_python_implementation != 'PyPy'", - "version": "==306" - }, - "pywinpty": { - "hashes": [ - "sha256:1617b729999eb6713590e17665052b1a6ae0ad76ee31e60b444147c5b6a35dca", - "sha256:189380469ca143d06e19e19ff3fba0fcefe8b4a8cc942140a6b863aed7eebb2d", - "sha256:21319cd1d7c8844fb2c970fb3a55a3db5543f112ff9cfcd623746b9c47501575", - "sha256:7520575b6546db23e693cbd865db2764097bd6d4ef5dc18c92555904cd62c3d4", - "sha256:8197de460ae8ebb7f5d1701dfa1b5df45b157bb832e92acba316305e18ca00dd", - "sha256:853985a8f48f4731a716653170cd735da36ffbdc79dcb4c7b7140bce11d8c722" - ], - "markers": "os_name == 'nt'", - "version": "==2.0.12" - }, - "pyyaml": { - "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==6.0.1" - }, - "pyzmq": { - "hashes": [ - "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565", - "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b", - "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979", - "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1", - "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f", - "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d", - "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee", - "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07", - "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98", - "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886", - "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7", - "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75", - "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220", - "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7", - "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a", - "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314", - "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a", - "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27", - "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611", - "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6", - "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6", - "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9", - "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561", - "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b", - "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755", - "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e", - "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc", - "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc", - "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289", - "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d", - "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62", - "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642", - "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3", - "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8", - "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0", - "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4", - "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097", - "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b", - "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181", - "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82", - "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68", - "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08", - "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7", - "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003", - "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0", - "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd", - "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8", - "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840", - "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8", - "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe", - "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438", - "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e", - "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d", - "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c", - "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b", - "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49", - "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d", - "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae", - "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e", - "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226", - "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6", - "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b", - "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3", - "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882", - "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15", - "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70", - "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d", - "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16", - "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05", - "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b", - "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737", - "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92", - "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348", - "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41", - "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add", - "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b", - "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7", - "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d", - "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96", - "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e", - "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2", - "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde", - "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8", - "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4", - "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec", - "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df", - "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73", - "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088", - "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244", - "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537", - "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6", - "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872", - "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==25.1.2" - }, - "referencing": { - "hashes": [ - "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3", - "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554" - ], - "markers": "python_version >= '3.8'", - "version": "==0.32.1" - }, - "requests": { - "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" - ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" - }, - "rfc3339-validator": { - "hashes": [ - "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", - "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.1.4" - }, - "rfc3986-validator": { - "hashes": [ - "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", - "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.1.1" - }, - "rich": { - "hashes": [ - "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", - "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" - ], - "markers": "python_version >= '3.7'", - "version": "==13.7.0" - }, - "rpds-py": { - "hashes": [ - "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147", - "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7", - "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2", - "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68", - "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1", - "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382", - "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d", - "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921", - "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38", - "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4", - "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a", - "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d", - "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518", - "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e", - "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d", - "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf", - "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5", - "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba", - "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6", - "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59", - "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253", - "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6", - "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f", - "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3", - "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea", - "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1", - "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76", - "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93", - "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad", - "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad", - "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc", - "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049", - "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d", - "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90", - "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d", - "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd", - "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25", - "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2", - "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f", - "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6", - "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4", - "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c", - "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8", - "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d", - "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b", - "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19", - "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453", - "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9", - "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde", - "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296", - "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58", - "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec", - "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99", - "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a", - "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb", - "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383", - "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d", - "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896", - "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc", - "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6", - "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b", - "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7", - "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22", - "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf", - "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394", - "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0", - "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57", - "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74", - "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83", - "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29", - "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9", - "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f", - "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745", - "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb", - "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811", - "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55", - "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342", - "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23", - "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82", - "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041", - "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb", - "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066", - "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55", - "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6", - "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a", - "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140", - "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b", - "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9", - "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256", - "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c", - "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772", - "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4", - "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae", - "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920", - "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a", - "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b", - "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361", - "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8", - "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a" - ], - "markers": "python_version >= '3.8'", - "version": "==0.17.1" - }, - "ruff": { - "hashes": [ - "sha256:226b517f42d59a543d6383cfe03cccf0091e3e0ed1b856c6824be03d2a75d3b6", - "sha256:2f59bcf5217c661254bd6bc42d65a6fd1a8b80c48763cb5c2293295babd945dd", - "sha256:5f0312ba1061e9b8c724e9a702d3c8621e3c6e6c2c9bd862550ab2951ac75c16", - "sha256:6bbbc3042075871ec17f28864808540a26f0f79a4478c357d3e3d2284e832998", - "sha256:7a36fa90eb12208272a858475ec43ac811ac37e91ef868759770b71bdabe27b6", - "sha256:9a1600942485c6e66119da294c6294856b5c86fd6df591ce293e4a4cc8e72989", - "sha256:9ebb40442f7b531e136d334ef0851412410061e65d61ca8ce90d894a094feb22", - "sha256:9fb6b3b86450d4ec6a6732f9f60c4406061b6851c4b29f944f8c9d91c3611c7a", - "sha256:a623349a505ff768dad6bd57087e2461be8db58305ebd5577bd0e98631f9ae69", - "sha256:b13ba5d7156daaf3fd08b6b993360a96060500aca7e307d95ecbc5bb47a69296", - "sha256:dcaab50e278ff497ee4d1fe69b29ca0a9a47cd954bb17963628fa417933c6eb1", - "sha256:e261f1baed6291f434ffb1d5c6bd8051d1c2a26958072d38dfbec39b3dda7352", - "sha256:e3fd36e0d48aeac672aa850045e784673449ce619afc12823ea7868fcc41d8ba", - "sha256:e6894b00495e00c27b6ba61af1fc666f17de6140345e5ef27dd6e08fb987259d", - "sha256:ee3febce7863e231a467f90e681d3d89210b900d49ce88723ce052c8761be8c7", - "sha256:f57de973de4edef3ad3044d6a50c02ad9fc2dff0d88587f25f1a48e3f72edf5e", - "sha256:f988746e3c3982bea7f824c8fa318ce7f538c4dfefec99cd09c8770bd33e6539" - ], - "index": "pypi", - "version": "==0.1.13" - }, - "send2trash": { - "hashes": [ - "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679", - "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.8.2" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "sniffio": { - "hashes": [ - "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", - "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" - ], - "markers": "python_version >= '3.7'", - "version": "==1.3.0" - }, - "sortedcontainers": { - "hashes": [ - "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", - "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0" - ], - "version": "==2.4.0" - }, - "soupsieve": { - "hashes": [ - "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", - "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" - ], - "markers": "python_version >= '3.8'", - "version": "==2.5" - }, - "stack-data": { - "hashes": [ - "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", - "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695" - ], - "version": "==0.6.3" - }, - "terminado": { - "hashes": [ - "sha256:1ea08a89b835dd1b8c0c900d92848147cef2537243361b2e3f4dc15df9b6fded", - "sha256:87b0d96642d0fe5f5abd7783857b9cab167f221a39ff98e3b9619a788a3c0f2e" - ], - "markers": "python_version >= '3.8'", - "version": "==0.18.0" - }, - "tinycss2": { - "hashes": [ - "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847", - "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627" - ], - "markers": "python_version >= '3.7'", - "version": "==1.2.1" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "tomli": { - "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "markers": "python_version < '3.11'", - "version": "==2.0.1" - }, - "tornado": { - "hashes": [ - "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0", - "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63", - "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263", - "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052", - "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f", - "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee", - "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78", - "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579", - "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212", - "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e", - "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2" - ], - "markers": "python_version >= '3.8'", - "version": "==6.4" - }, - "traitlets": { - "hashes": [ - "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74", - "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e" - ], - "markers": "python_version >= '3.8'", - "version": "==5.14.1" - }, - "types-python-dateutil": { - "hashes": [ - "sha256:1f8db221c3b98e6ca02ea83a58371b22c374f42ae5bbdf186db9c9a76581459f", - "sha256:efbbdc54590d0f16152fa103c9879c7d4a00e82078f6e2cf01769042165acaa2" - ], - "markers": "python_version >= '3.8'", - "version": "==2.8.19.20240106" - }, - "typing-extensions": { - "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" - ], - "markers": "python_version < '3.11'", - "version": "==4.9.0" - }, - "uri-template": { - "hashes": [ - "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", - "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363" - ], - "version": "==1.3.0" - }, - "urllib3": { - "hashes": [ - "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", - "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" - ], - "markers": "python_version >= '3.8'", - "version": "==2.1.0" - }, - "wcwidth": { - "hashes": [ - "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", - "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5" - ], - "version": "==0.2.13" - }, - "webcolors": { - "hashes": [ - "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf", - "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a" - ], - "version": "==1.13" - }, - "webencodings": { - "hashes": [ - "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", - "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" - ], - "version": "==0.5.1" - }, - "websocket-client": { - "hashes": [ - "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6", - "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588" - ], - "markers": "python_version >= '3.8'", - "version": "==1.7.0" - } - } -} diff --git a/README.md b/README.md index 5c1f75c..314035b 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,14 @@ # multilayer-alignment -This repository implements an algorithm for quantifying multilayer alignment. -You can refer to the [slide deck](https://docs.google.com/presentation/d/1HMEE5kOwwJPLBmAgycKIMSWRx0eCxd3RtSxVR1Jdczw/) for the general idea. +This repository implements an algorithm for quantifying multilayer alignment or higher-order alignment, that is, the alignment across n different dimensions. You can refer to the [slide deck](https://docs.google.com/presentation/d/1HMEE5kOwwJPLBmAgycKIMSWRx0eCxd3RtSxVR1Jdczw/) for the original idea. ## Structure of the repo - `\multilayer_alignment\`: source code - `\tests\`: tests for the source code -## Setting up +## Setting up the development environment ![python](https://img.shields.io/badge/Python-FFD43B?style=for-the-badge&logo=python&logoColor=blue) diff --git a/RUNBOOK.md b/RUNBOOK.md index ff04b6b..631f246 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -2,10 +2,10 @@ ## Overview -This repository contains code to extend pairwise measure of alignment -to N-wise case. +This repository contains code to extend a pairwise measure of alignment +based on mutual information to an N-wise case. -## Operational tasks +## Development tasks ### Install all dependencies and activate the environment @@ -25,26 +25,26 @@ From root directory, $ python -m unittest discover -v ``` -### Given partitions for each of the layers, compute mutual clusters +### Given opinion partitions for each of the topics, compute the consensus partition ```python # import needed modules >>> import pandas as pd ->>> from multilayer_alignment.mutual_clusters import compute_mutual_clusters_recursive +>>> from multilayer_alignment.consensus import get_consensus_partition -# load the partitions labels to a pandas DataFrame +# load the opinion labels to a pandas DataFrame >>> df = pd.DataFrame( { - # in layer A, nodes 0 and 1 have label 0, - # nodes 2 and 3 have label 1 + # on topic A, individuals 0 and 1 have opinion 0, + # individuals 2 and 3 have opinion 1 "A": [0, 0, 1, 1], "B": [0, 1, 0, 1], "C": [1, 0, 1, 0] } ) -# get mutual clusters ->>> compute_mutual_clusters_recursive(cluster_labels_df=df) +# get consensus partition +>>> get_consensus_partition(opinions=df) { "A0_B0_C1": {0}, "A0_B1_C0": {1}, @@ -58,21 +58,21 @@ Alternatively: ```python # import needed modules >>> import pandas as pd ->>> from multilayer_alignment.mutual_clusters import compute_mutual_clusters +>>> from multilayer_alignment.consensus import get_consensus_partition_recursive # load the partitions labels to a pandas DataFrame >>> df = pd.DataFrame( { - # in layer A, nodes 0 and 1 have label 0, - # nodes 2 and 3 have label 1 + # on topic A, individuals 0 and 1 have opinion 0, + # individuals 2 and 3 have opinion 1 "A": [0, 0, 1, 1], "B": [0, 1, 0, 1], "C": [1, 0, 1, 0] } ) -# get mutual clusters ->>> compute_mutual_clusters(cluster_labels_df=df) +# get consensus partition +>>> get_consensus_partition_recursive(opinions=df) { "A0_B0_C1": {0}, "A0_B1_C0": {1}, diff --git a/multilayer_alignment/alignment_score.py b/multilayer_alignment/alignment_score.py index dbc546a..b94b6da 100644 --- a/multilayer_alignment/alignment_score.py +++ b/multilayer_alignment/alignment_score.py @@ -3,23 +3,23 @@ import numpy as np from itertools import combinations from functools import partial -from joblib import dump +from joblib import dump # type: ignore -from sklearn.metrics.cluster import normalized_mutual_info_score -from sklearn.metrics import adjusted_mutual_info_score +from sklearn.metrics.cluster import normalized_mutual_info_score # type: ignore +from sklearn.metrics import adjusted_mutual_info_score # type: ignore import multiprocessing as mp from multiprocessing.pool import Pool from tqdm import tqdm -from multilayer_alignment.mutual_clusters import compute_mutual_clusters -from multilayer_alignment.mutual_clusters import get_mutual_clusters_labels +from multilayer_alignment.consensus import get_consensus_partition +from multilayer_alignment.consensus import get_consensus_labels from multilayer_alignment.utils.logging import logger def _compute_layer_expectation( - layer: np.array, scoring_function: typing.Callable + layer: typing.Iterable, scoring_function: typing.Callable ) -> float: """ :param layer: 1d np.array with clustering assignment @@ -29,22 +29,23 @@ def _compute_layer_expectation( _all_scores = [] with Pool(processes=mp.cpu_count() - 1) as pool: result = pool.map_async( - scoring_function, [np.random.permutation(layer) for _ in range(10)] - ) + scoring_function, [np.random.permutation(layer) for _ in range(10)] # type: ignore + ) # type: ignore for value in result.get(): - # NOTE: assuming scores are always >=0 + # NOTE: in case of AMI, it is possible to get negative scores, + # but we cap them to 0 so get only scores >= 0 _all_scores.append(max(value, 0)) return np.array(_all_scores).mean() -def compute_multilayer_alignment_score( - cluster_labels_df: pd.DataFrame, +def multilayer_alignment_score( + opinions: typing.Union[pd.DataFrame, pd.Series], mutual_clusters_labels: typing.List, which_score: str = "nmi", adjusted: bool = False, ) -> float: """ - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, + :param opinions: pd.DataFrame having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j :param mutual_clusters_labels: list, a list of labels for mutual clusters :param which_score: str, one of "nmi" or "ami" @@ -59,9 +60,9 @@ def compute_multilayer_alignment_score( _score_f = adjusted_mutual_info_score avg_nmi = 0 - _expected_nmi = 0 - for layer_id in cluster_labels_df.columns: - _layer = cluster_labels_df[layer_id].values + _expected_nmi = 0.0 + for layer_id in opinions.columns: + _layer = opinions[layer_id].values _score = _score_f(_layer, mutual_clusters_labels, average_method="arithmetic") avg_nmi += _score @@ -72,17 +73,17 @@ def compute_multilayer_alignment_score( _score_f, mutual_clusters_labels, **{"average_method": "arithmetic"} ), ) - return (avg_nmi - _expected_nmi) / len(cluster_labels_df.columns) + return (avg_nmi - _expected_nmi) / len(opinions.columns) -def compute_maximal_alignment_curve( - cluster_labels_df: pd.DataFrame, +def maximal_alignment_curve( + opinions: typing.Union[pd.DataFrame, pd.Series], which_score: str = "nmi", adjusted: bool = False, dump_to: typing.Optional[str] = None, ) -> typing.Tuple: """ - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, + :param opinions: pd.DataFrame having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j :param which_score: str, one of "nmi" or "ami" :param adjusted: bool, default: False @@ -103,39 +104,39 @@ def compute_maximal_alignment_curve( best_by_combination_size = dict() all_scores_by_combination_size = dict() - _num_of_layers = len(cluster_labels_df.columns) + _num_of_layers = len(opinions.columns) # skipping size 1 for length in range(2, _num_of_layers + 1): logger.info(f"combinations of size {length}") - # Get all combinations of cluster_labels_df.columns of length "length" - _columns_combinations = combinations(cluster_labels_df.columns, length) + # Get all combinations of opinions.columns of length "length" + _columns_combinations = combinations(opinions.columns, length) best_layers_combination = None - best_nmi = 0 + best_nmi = 0.0 # best_layers_combination_mutual_communities = dict() - for l_comb in tqdm(_columns_combinations): - l_comb = list(l_comb) - l_comb_df = cluster_labels_df[l_comb].copy() + for _l_comb in tqdm(_columns_combinations): + l_comb = list(_l_comb) + l_comb_df = opinions[l_comb].copy() # keep only items that have labels for all items in l_comb and reindex l_comb_df.dropna(inplace=True) l_comb_df.reset_index(drop=True, inplace=True) - mutual_clusters = compute_mutual_clusters(l_comb_df) - mutual_clusters_labels = get_mutual_clusters_labels(mutual_clusters) + mutual_clusters = get_consensus_partition(l_comb_df) + mutual_clusters_labels = get_consensus_labels(mutual_clusters) labels_list = ( mutual_clusters_labels.set_index("id") .iloc[l_comb_df.index]["label"] - .values + .to_list() ) # CRITERIA - nmi = compute_multilayer_alignment_score( + nmi = multilayer_alignment_score( l_comb_df, labels_list, which_score=which_score, adjusted=adjusted ) - all_scores_by_combination_size[ - f"{length}+" + "+".join(sorted(l_comb)) - ] = nmi + all_scores_by_combination_size[f"{length}+" + "+".join(sorted(l_comb))] = ( + nmi + ) # ( # nmi, # mutual_clusters, diff --git a/multilayer_alignment/consensus.py b/multilayer_alignment/consensus.py new file mode 100644 index 0000000..ebd2a4f --- /dev/null +++ b/multilayer_alignment/consensus.py @@ -0,0 +1,126 @@ +import pandas as pd +from typing import Any, Dict, Set, Union + + +def get_consensus_labels(consensus_partition: Dict[str, Set[Any]]) -> pd.DataFrame: + """ + :param consensus_partition: a dictionary of consensus group label (str) -> consesus group members (set) + :return: pd.DataFrame with column 'id' for the element id and column 'label' for the element label + """ + nodes_id = [] + labels = [] + for k, v in consensus_partition.items(): + for elm in v: + nodes_id.append(elm) + labels.append(k) + return pd.DataFrame({"id": nodes_id, "label": labels}).sort_values(by="id") + + +def get_consensus_partition( + opinions: Union[pd.DataFrame, pd.Series] +) -> Dict[str, Set[Any]]: + """ + Returns the consensus groups (faster) + :param opinions: pd.DataFrame having one column per topic and one row per individual, + where each element a_ij represents the opinion for individual i on topic j + and columns names are the topic names + :return: dict[str, set], a dictionary of consensus group label (str) -> consensus group members (set) + Note: Only non-empty sets are returned! + ------------ + Example + ------------ + E.g.: + opinions: A | B | C + --------- + 0 0 1 0 + 1 0 1 0 + 2 1 0 1 + consensus groups: + A0_B0_C0 -> {}, A0_B0_C1 -> {}, A0_B1_C0 -> {0, 1}, A0_B1_C1 -> {}, + A1_B0_C0 -> {}, A1_B0_C1 -> {2}, A1_B1_C0 -> {}, A1_B1_C1 -> {} + >>> df = pd.DataFrame({"A": [0, 0, 1], "B": [1, 1, 0], "C": [0, 0, 1]}) + >>> get_consensus_partition(opinions=df) + """ + consensus_groups = {} + _topics = list(opinions.columns) + _cg = opinions.groupby(by=_topics).groups + for key, value in _cg.items(): + if len(_topics) == 1: + _formatted_key = f"{_topics[0]}{key}" + else: + _joined_key = [ + "".join((str(col_name), str(label))) + for col_name, label in zip(_topics, key) # type: ignore + ] # type: ignore + _formatted_key = "_".join(_joined_key) + consensus_groups[_formatted_key] = set(value) + return consensus_groups + + +def get_consensus_partition_recursive( + opinions: Union[pd.DataFrame, pd.Series], + consensus_groups: Dict[str, Set[Any]] = {}, + next_topic_idx: int = 0, +) -> Dict[str, Set[Any]]: + """ + Recursive function that traverses all the topics and builds the consensus groups + :param opinions: pd.DataFrame having one column per topic and one row per individual, + where each element a_ij represents the opinion of individual i on topic j + :param consensus_groups: dict[str, set], a dictionary of consensus group label (str) -> consensus group members (set) + The consensus group labels are built at each step by combining the labels of the groups that are intersected. + Default: empty dictionary + :param next_topic_idx: int, the index of next topic to consider + Default: 0 (first column in opinions) + :return: current_sets, dict[str, set], a dictionary of consensus group label (str) -> consensus group members (set) + Note: Only non-empty sets are returned! + ------------ + Example + ------------ + E.g.: + opinions: A | B | C + --------- + 0 0 1 0 + 1 0 1 0 + 2 1 0 1 + consensus groups (first iteration): + A0_B0 -> {}, A0_B1 -> {0, 1}, A1_B0 -> {2}, A1_B1 -> {} + consensus groups (final iteration): + A0_B0_C0 -> {}, A0_B0_C1 -> {}, A0_B1_C0 -> {0, 1}, A0_B1_C1 -> {}, + A1_B0_C0 -> {}, A1_B0_C1 -> {2}, A1_B1_C0 -> {}, A1_B1_C1 -> {} + >>> df = pd.DataFrame({"A": [0, 0, 1], "B": [1, 1, 0], "C": [0, 0, 1]}) + >>> get_consensus_partition_recursive(opinions=df) + """ + _num_of_layers = len(opinions.columns) + # recursion base case: no layer left to be processed + if next_topic_idx == _num_of_layers: + return consensus_groups + else: + _next_layer = opinions.columns[next_topic_idx] + _updated_mutual_clusters = {} + if len(consensus_groups) == 0: + # in this case, we need to create the keys for the dictionary from scratch + for _cluster_label in opinions[_next_layer].unique(): + _cluster_content = opinions[opinions[_next_layer] == _cluster_label][ + _next_layer + ].index + _key = str(_next_layer) + str(_cluster_label) + _updated_mutual_clusters[_key] = set(_cluster_content) + return get_consensus_partition_recursive( + opinions, _updated_mutual_clusters, next_topic_idx + 1 + ) + else: + # in this case, we start from the current mutual clusters and compare with the current layer + _updated_mutual_clusters = {} + for mc_id, curr_mc in consensus_groups.items(): + for _cluster_label in opinions[_next_layer].unique(): + _cluster_content = opinions[ + opinions[_next_layer] == _cluster_label + ][_next_layer].index + _new_key_suffix = str(_next_layer) + str(_cluster_label) + _key = str(mc_id) + "_" + _new_key_suffix + _new_set = curr_mc.intersection(set(_cluster_content)) + if len(_new_set) > 0: + _updated_mutual_clusters[_key] = _new_set + return get_consensus_partition_recursive( + opinions, _updated_mutual_clusters, next_topic_idx + 1 + ) diff --git a/multilayer_alignment/mutual_clusters.py b/multilayer_alignment/mutual_clusters.py deleted file mode 100644 index fd4827d..0000000 --- a/multilayer_alignment/mutual_clusters.py +++ /dev/null @@ -1,121 +0,0 @@ -import pandas as pd - - -def get_mutual_clusters_labels(mutual_clusters: dict) -> pd.DataFrame: - """ - :param mutual_clusters: a dictionary of mutual cluster label (str) -> mutual cluster members (set) - :return: pd.DataFrame with column 'id' for the element id and column 'label' for the element label - """ - nodes_id = [] - labels = [] - for k, v in mutual_clusters.items(): - for elm in v: - nodes_id.append(elm) - labels.append(k) - return pd.DataFrame({"id": nodes_id, "label": labels}).sort_values(by="id") - - -def compute_mutual_clusters(cluster_labels_df: pd.DataFrame) -> dict: - """ - Returns the mutual clusters (faster) - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, - where each element a_ij is an integer representing the cluster labels for node i at layer j - and columns names are the layers names - :return: current_sets, dict[str, set], a dictionary of mutual cluster label (str) -> mutual cluster members (set) - Note: Only non-empty sets are returned! - ------------ - Example - ------------ - E.g.: - cluster_labels_df: A | B | C - --------- - 0 0 1 0 - 1 0 1 0 - 2 1 0 1 - mutual_clusters: - A0_B0_C0 -> {}, A0_B0_C1 -> {}, A0_B1_C0 -> {0, 1}, A0_B1_C1 -> {}, - A1_B0_C0 -> {}, A1_B0_C1 -> {2}, A1_B1_C0 -> {}, A1_B1_C1 -> {} - >>> df = pd.DataFrame({"A": [0, 0, 1], "B": [1, 1, 0], "C": [0, 0, 1]}) - >>> compute_mutual_clusters(cluster_labels_df=df) - """ - mutual_clusters = {} - _layers = list(cluster_labels_df.columns) - _mc = cluster_labels_df.groupby(by=_layers).groups - for key, value in _mc.items(): - if len(_layers) == 1: - _formatted_key = f"{_layers[0]}{key}" - else: - _joined_key = [ - "".join((str(col_name), str(label))) - for col_name, label in zip(_layers, key) - ] - _formatted_key = "_".join(_joined_key) - mutual_clusters[_formatted_key] = set(value) - return mutual_clusters - - -def compute_mutual_clusters_recursive( - cluster_labels_df: pd.DataFrame, mutual_clusters: dict = {}, next_layer_idx: int = 0 -) -> dict: - """ - Recursive function that traverses all the layers and builds the mutual clusters - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, - where each element a_ij is an integer representing the cluster labels for node i at layer j - :param mutual_clusters: dict[str, set], a dictionary of mutual cluster label (str) -> mutual cluster members (set) - The mutual cluster labels are built at each step by combining the labels of the clusters that are intersected. - Default: empty dictionary - :param next_layer_idx: int, the index of next layer to consider - Default: 0 (first column in cluster_labels_df) - :return: current_sets, dict[str, set], a dictionary of mutual cluster label (str) -> mutual cluster members (set) - Note: Only non-empty sets are returned! - ------------ - Example - ------------ - E.g.: - cluster_labels_df: A | B | C - --------- - 0 0 1 0 - 1 0 1 0 - 2 1 0 1 - mutual_clusters (first iteration): - A0_B0 -> {}, A0_B1 -> {0, 1}, A1_B0 -> {2}, A1_B1 -> {} - mutual_clusters (final iteration): - A0_B0_C0 -> {}, A0_B0_C1 -> {}, A0_B1_C0 -> {0, 1}, A0_B1_C1 -> {}, - A1_B0_C0 -> {}, A1_B0_C1 -> {2}, A1_B1_C0 -> {}, A1_B1_C1 -> {} - >>> df = pd.DataFrame({"A": [0, 0, 1], "B": [1, 1, 0], "C": [0, 0, 1]}) - >>> compute_mutual_clusters_recursive(cluster_labels_df=df) - """ - _num_of_layers = len(cluster_labels_df.columns) - # recursion base case: no layer left to be processed - if next_layer_idx == _num_of_layers: - return mutual_clusters - else: - _next_layer = cluster_labels_df.columns[next_layer_idx] - _updated_mutual_clusters = {} - if len(mutual_clusters) == 0: - # in this case, we need to create the keys for the dictionary from scratch - for _cluster_label in cluster_labels_df[_next_layer].unique(): - _cluster_content = cluster_labels_df[ - cluster_labels_df[_next_layer] == _cluster_label - ][_next_layer].index - _key = str(_next_layer) + str(_cluster_label) - _updated_mutual_clusters[_key] = set(_cluster_content) - return compute_mutual_clusters_recursive( - cluster_labels_df, _updated_mutual_clusters, next_layer_idx + 1 - ) - else: - # in this case, we start from the current mutual clusters and compare with the current layer - _updated_mutual_clusters = {} - for mc_id, curr_mc in mutual_clusters.items(): - for _cluster_label in cluster_labels_df[_next_layer].unique(): - _cluster_content = cluster_labels_df[ - cluster_labels_df[_next_layer] == _cluster_label - ][_next_layer].index - _new_key_suffix = str(_next_layer) + str(_cluster_label) - _key = str(mc_id) + "_" + _new_key_suffix - _new_set = curr_mc.intersection(set(_cluster_content)) - if len(_new_set) > 0: - _updated_mutual_clusters[_key] = _new_set - return compute_mutual_clusters_recursive( - cluster_labels_df, _updated_mutual_clusters, next_layer_idx + 1 - ) diff --git a/multilayer_alignment/null_models.py b/multilayer_alignment/null_models.py index c2f627e..0046ed9 100644 --- a/multilayer_alignment/null_models.py +++ b/multilayer_alignment/null_models.py @@ -1,49 +1,51 @@ import pandas as pd import numpy as np import os -from scipy.stats import entropy +from scipy.stats import entropy # type: ignore from itertools import combinations -from joblib import dump +from joblib import dump # type: ignore from functools import partial -import typing +from typing import Dict, List, Union import multiprocessing as mp from multiprocessing.pool import Pool from tqdm import tqdm -from multilayer_alignment.alignment_score import compute_maximal_alignment_curve +from multilayer_alignment.alignment_score import maximal_alignment_curve from multilayer_alignment.utils.logging import logger -def get_null_model(cluster_labels_df: pd.DataFrame) -> pd.DataFrame: +def get_null_model(opinions: Union[pd.DataFrame, pd.Series]) -> pd.DataFrame: """ - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, + :param opinions: pd.DataFrame having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j :return: pd.DataFrame, having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j """ null = pd.DataFrame() - for layer_id in cluster_labels_df.columns: - _layer = cluster_labels_df[layer_id].fillna(9).values - null[layer_id] = np.random.permutation(_layer) + for layer_id in opinions.columns: + _layer = opinions[layer_id].fillna(9).values + null[layer_id] = np.random.permutation(_layer) # type: ignore return null def _one_iter( - cluster_labels_df: pd.DataFrame, which_score: str = "ami", adjusted: bool = False -) -> dict: + opinions: Union[pd.DataFrame, pd.Series], + which_score: str = "ami", + adjusted: bool = False, +) -> Dict: """ - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, + :param opinions: pd.DataFrame having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j :param which_score: str :param adjusted: bool :return: dict """ - null = get_null_model(cluster_labels_df=cluster_labels_df) + null = get_null_model(opinions=opinions) - _full_res, _ = compute_maximal_alignment_curve( + _full_res, _ = maximal_alignment_curve( null, which_score=which_score, adjusted=adjusted ) return _full_res @@ -84,24 +86,24 @@ def random_full_alignment_curves( i += 1 -def expected_curve(cluster_labels_df: pd.DataFrame) -> typing.List: +def expected_curve(opinions: Union[pd.DataFrame, pd.Series]) -> List[float]: """ - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, + :param opinions: pd.DataFrame having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j :return: list of expected scores based on average NMI (normalized by arithmetic average) """ _expected_best_scores = [] - _layers = list(cluster_labels_df.columns) + _layers = list(opinions.columns) - _a = cluster_labels_df.copy() + _a = opinions.copy() _a["count"] = 1 for length in range(2, len(_layers) + 1): logger.info(f"combinations of size {length}") - # Get all combinations of cluster_labels_df.columns of length "length" + # Get all combinations of opinions.columns of length "length" _columns_combinations = combinations(_layers, length) - best_score = 0 + best_score = 0.0 for l_comb in tqdm(_columns_combinations): l_mc = [] @@ -121,5 +123,5 @@ def expected_curve(cluster_labels_df: pd.DataFrame) -> typing.List: return _expected_best_scores -def expected_curve_equal_sized_clusters(n_layers: int) -> typing.List: +def expected_curve_equal_sized_clusters(n_layers: int) -> List[float]: return [2 / (1 + k) for k in range(2, n_layers + 1)] diff --git a/multilayer_alignment/visualizations.py b/multilayer_alignment/visualizations.py index c3fc29c..536d6e8 100644 --- a/multilayer_alignment/visualizations.py +++ b/multilayer_alignment/visualizations.py @@ -1,33 +1,33 @@ import pandas as pd import numpy as np -from joblib import load -import matplotlib.pyplot as plt -import matplotlib.markers as markers -from mpl_toolkits.axes_grid1.inset_locator import inset_axes +from joblib import load # type: ignore +import matplotlib.pyplot as plt # type: ignore +import matplotlib.markers as markers # type: ignore +from mpl_toolkits.axes_grid1.inset_locator import inset_axes # type: ignore import random -import seaborn as sns +import seaborn as sns # type: ignore import typing -from multilayer_alignment.alignment_score import compute_maximal_alignment_curve +from multilayer_alignment.alignment_score import maximal_alignment_curve from multilayer_alignment.null_models import expected_curve_equal_sized_clusters from multilayer_alignment.utils.logging import logger def plot_maximal_alignment_curve( - cluster_labels_df: pd.DataFrame, + opinions: pd.DataFrame, which_score: str = "nmi", adjusted: bool = False, ) -> plt.Figure: """ - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, + :param opinions: pd.DataFrame having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j and column names are layers names :param which_score: str, one of "nmi" or "ami" :param adjusted: bool, default: False :return: plt.Figure with 2 subplots (1 row x 2 columns) """ - _, res = compute_maximal_alignment_curve( - cluster_labels_df=cluster_labels_df, which_score=which_score, adjusted=adjusted + _, res = maximal_alignment_curve( + opinions=opinions, which_score=which_score, adjusted=adjusted ) combination_sizes = [] anmi_scores = [] @@ -60,13 +60,13 @@ def plot_maximal_alignment_curve( def plot_full_alignment_curve( - cluster_labels_df: typing.Optional[pd.DataFrame], + opinions: typing.Optional[pd.DataFrame], which_score: typing.Optional[str], adjusted: typing.Optional[bool], full_dump_path: typing.Optional[str], ) -> plt.Figure: """ - :param cluster_labels_df: pd.DataFrame having one column per layer and one row per node, + :param opinions: pd.DataFrame having one column per layer and one row per node, where each element a_ij is an integer representing the cluster labels for node i at layer j and column names are layers names :param which_score: str, one of "nmi" or "ami" or None @@ -78,19 +78,19 @@ def plot_full_alignment_curve( all_results = load(full_dump_path) else: assert ( - cluster_labels_df is not None - and which_score is not None - and adjusted is not None + opinions is not None and which_score is not None and adjusted is not None ), "not enough inputs" - all_results, _ = compute_maximal_alignment_curve( - cluster_labels_df=cluster_labels_df, + all_results, _ = maximal_alignment_curve( + opinions=opinions, which_score=which_score, adjusted=adjusted, ) - points = [(k.split("+")[0], v[0], k.split("+")[1:]) for k, v in all_results.items()] - points = pd.DataFrame(points) - top = points.sort_values(by=[1, 0], ascending=False).groupby(0).head(1) + _points = [ + (k.split("+")[0], v[0], k.split("+")[1:]) for k, v in all_results.items() + ] + points = pd.DataFrame(_points) + top = points.sort_values(by=[1, 0], ascending=False).groupby(0).head(1) # type: ignore logger.info(f"Area under the curve: {np.trapz(top[1], dx=1 / (len(top) - 1))}") @@ -113,11 +113,11 @@ def plot_full_alignment_curve( # Annotate each point with its label for i, label in top[[2]].iterrows(): label = label[2] - text = [lab.replace("_", " ") for lab in label] - text = "\n".join(text) + _text = [lab.replace("_", " ") for lab in label] + text = "\n".join(_text) plt.annotate( text, - (x_top[i], y_top[i]), + (x_top[i], y_top[i]), # type: ignore textcoords="offset points", xytext=(0, 10), ha="left", @@ -147,23 +147,23 @@ def plot_full_alignment_with_null_models( full_result: str, full_null_path: str ) -> plt.Figure: r = load(full_result) - points = [(k.split("+")[0], v[0], k.split("+")[1:]) for k, v in r.items()] - points = pd.DataFrame(points) + _points = [(k.split("+")[0], v[0], k.split("+")[1:]) for k, v in r.items()] + points = pd.DataFrame(_points) - points_df = [] + _dfs = [] for i in range(10): r = load(f"{full_null_path}/null_{i}") _points = [(k.split("+")[0], v[0], k.split("+")[1:]) for k, v in r.items()] - points_df.append(pd.DataFrame(_points)) + _dfs.append(pd.DataFrame(_points)) - points_df = pd.concat(points_df, ignore_index=True) + points_df = pd.concat(_dfs, ignore_index=True) - top = points.sort_values(by=[1, 0], ascending=False).groupby(0).head(1) + top = points.sort_values(by=[1, 0], ascending=False).groupby(0).head(1) # type: ignore x_top = top[0] - x_top = [int(v) for v in x_top] + x_top = [int(v) for v in x_top] # type: ignore y_top = top[1] - _strip = points[~points.index.isin(top.index)] + _strip = points[~points.index.isin(top.index)] # type: ignore null_avg = points_df.groupby(0)[1].mean().to_dict() y_top_ = y_top.values - np.array([null_avg[k] for k in null_avg.keys()]) @@ -172,12 +172,12 @@ def plot_full_alignment_with_null_models( null_lower_q = points_df.groupby(0)[1].quantile(q=0.025).to_dict() sig = [ (_i, v - null_avg[_i]) - for _i, v in _strip[[0, 1]].values + for _i, v in _strip[[0, 1]].values # type: ignore if v > null_upper_q[_i] or v < null_lower_q[_i] ] not_sig = [ (_i, v - null_avg[_i]) - for _i, v in _strip[[0, 1]].values + for _i, v in _strip[[0, 1]].values # type: ignore if null_lower_q[_i] <= v <= null_upper_q[_i] ] @@ -191,10 +191,10 @@ def plot_full_alignment_with_null_models( alpha=1.0, ) # Annotate each point with its label - for j, (i, label) in enumerate(top[[2]].iterrows()): + for j, (i, label) in enumerate(top[[2]].iterrows()): # type: ignore label = label[2] - text = [lab.replace("_", " ") for lab in label] - text = "\n".join(text) + _text = [lab.replace("_", " ") for lab in label] + text = "\n".join(_text) ax.annotate( text, (x_top[j], y_top_[j]), diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..d28e492 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,77 @@ +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +# Same as Black. +line-length = 88 +indent-width = 4 + +# Assume Python 3.8 +target-version = "py38" + +[lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +select = ["E4", "E7", "E9", "F"] +ignore = [] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +# Enable auto-formatting of code examples in docstrings. Markdown, +# reStructuredText code/literal blocks and doctests are all supported. +# +# This is currently disabled by default, but it is planned for this +# to be opt-out in the future. +docstring-code-format = false + +# Set the line length limit used when formatting code snippets in +# docstrings. +# +# This only has an effect when the `docstring-code-format` setting is +# enabled. +docstring-code-line-length = "dynamic" diff --git a/setup.py b/setup.py index 0296d75..6198d29 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup, find_packages +from setuptools import setup, find_packages # type: ignore setup( name="multilayer_alignment", diff --git a/tests/test_compute_maximal_alignment_curve.py b/tests/test_compute_maximal_alignment_curve.py index 20e5176..5336b99 100644 --- a/tests/test_compute_maximal_alignment_curve.py +++ b/tests/test_compute_maximal_alignment_curve.py @@ -2,7 +2,7 @@ import pandas as pd -from multilayer_alignment.alignment_score import compute_maximal_alignment_curve +from multilayer_alignment.alignment_score import maximal_alignment_curve class TestComputeMaximalAlignmentCurve(unittest.TestCase): @@ -19,7 +19,7 @@ def test_on_empty(self): compute_maximal_alignment_curve returns a tuple with two dictionaries """ _a = pd.DataFrame() - _resall, _res0 = compute_maximal_alignment_curve(_a) + _resall, _res0 = maximal_alignment_curve(_a) self.assertIsInstance( _resall, dict, @@ -48,7 +48,7 @@ def test_on_one_layer(self): compute_maximal_alignment_curve returns a tuple with two dictionaries """ _a = pd.DataFrame({"A": [0, 1, 2]}) - _resall, _res0 = compute_maximal_alignment_curve(_a) + _resall, _res0 = maximal_alignment_curve(_a) self.assertIsInstance( _resall, dict, diff --git a/tests/test_compute_multilayer_alignment_score.py b/tests/test_compute_multilayer_alignment_score.py index b087030..00fc80c 100644 --- a/tests/test_compute_multilayer_alignment_score.py +++ b/tests/test_compute_multilayer_alignment_score.py @@ -2,7 +2,7 @@ import pandas as pd -from multilayer_alignment.alignment_score import compute_multilayer_alignment_score +from multilayer_alignment.alignment_score import multilayer_alignment_score class TestComputeMultilayerAlignmentScore(unittest.TestCase): @@ -20,7 +20,7 @@ def test_on_empty(self): """ _a = pd.DataFrame({"A": [0, 1, 2]}) _labels = ["a", "b", "c"] - _res0 = compute_multilayer_alignment_score(_a, _labels) + _res0 = multilayer_alignment_score(_a, _labels) self.assertIsInstance( _res0, float, diff --git a/tests/test_get_mutual_clusters_labels.py b/tests/test_get_consensus_labels.py similarity index 51% rename from tests/test_get_mutual_clusters_labels.py rename to tests/test_get_consensus_labels.py index 1ca777e..14814ca 100644 --- a/tests/test_get_mutual_clusters_labels.py +++ b/tests/test_get_consensus_labels.py @@ -2,51 +2,51 @@ import pandas as pd -from multilayer_alignment.mutual_clusters import get_mutual_clusters_labels +from multilayer_alignment.consensus import get_consensus_labels -class TestGetMutualClustersLabels(unittest.TestCase): +class TestGetConsensusLabels(unittest.TestCase): """ - Test functionality of mutual_clusters.get_mutual_clusters_labels() + Test functionality of mutual_clusters.get_consensus_labels() ------------ Example ------------ - >>> python3 -m unittest -v tests.test_get_mutual_clusters_labels + >>> python3 -m unittest -v tests.test_get_consensus_labels """ def test_on_empty(self): """ - get_mutual_clusters_labels returns a pd.DataFrame + get_consensus_labels returns a pd.DataFrame """ _a = pd.DataFrame() - _res0 = get_mutual_clusters_labels(_a) + _res0 = get_consensus_labels(_a) self.assertIsInstance( _res0, pd.DataFrame, - f"""get_mutual_clusters_labels should return a pd.DataFrame, + f"""get_consensus_labels should return a pd.DataFrame, but returned {type(_res0)}""", ) self.assertTrue( _res0.empty, - f"""get_mutual_clusters_labels called on empty dictionary should return + f"""get_consensus_labels called on empty dictionary should return an empty pd.DataFrame, but returned {_res0}""", ) def test_on_simple_sets(self): """ - get_mutual_clusters_labels returns a pd.DataFrame + get_consensus_labels returns a pd.DataFrame """ _a = {"A0_B1_C0": {0, 1}, "A1_B0_C1": {2}, "A1_B1_C0": {3}} - _res0 = get_mutual_clusters_labels(_a) + _res0 = get_consensus_labels(_a) self.assertIsInstance( _res0, pd.DataFrame, - f"""get_mutual_clusters_labels should return a pd.DataFrame, + f"""get_consensus_labels should return a pd.DataFrame, but returned {type(_res0)}""", ) self.assertFalse( _res0.empty, - f"""get_mutual_clusters_labels called on non-empty dictionary should return + f"""get_consensus_labels called on non-empty dictionary should return a non-empty pd.DataFrame, but returned {_res0}""", ) diff --git a/tests/test_compute_mutual_clusters.py b/tests/test_get_consensus_partition.py similarity index 68% rename from tests/test_compute_mutual_clusters.py rename to tests/test_get_consensus_partition.py index b8d4417..e0b168b 100644 --- a/tests/test_compute_mutual_clusters.py +++ b/tests/test_get_consensus_partition.py @@ -2,223 +2,223 @@ import pandas as pd -from multilayer_alignment.mutual_clusters import compute_mutual_clusters +from multilayer_alignment.consensus import get_consensus_partition -class TestComputeMutualClusters(unittest.TestCase): +class TestGetConsensusPartition(unittest.TestCase): """ - Test functionality of mutual_clusters.compute_mutual_clusters() + Test functionality of mutual_clusters.get_consensus_partition() ------------ Example ------------ - >>> python3 -m unittest -v tests.test_compute_mutual_clusters + >>> python3 -m unittest -v tests.test_get_consensus_partition """ def test_on_empty(self): """ - compute_mutual_clusters returns a dictionary + get_consensus_partition returns a dictionary """ _a = pd.DataFrame() - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertEqual( _res0, dict(), - f"""compute_mutual_clusters called on empty dataframe should return an empty dictionary, + f"""get_consensus_partition called on empty dataframe should return an empty dictionary, but returned {_res0}""", ) def test_on_one_layer(self): """ - compute_mutual_clusters returns a dictionary, and returns all the nodes + get_consensus_partition returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 1, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0": {0}, "A1": {1}, "A2": {2}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters called on non-empty dataframe should return a non-empty dictionary, + f"""get_consensus_partition called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters called on non-empty dataframe should return + f"""get_consensus_partition called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters called on non-empty dataframe should return all nodes""", + """get_consensus_partition called on non-empty dataframe should return all nodes""", ) def test_on_two_layers_0(self): """ - compute_mutual_clusters returns a dictionary, and returns all the nodes + get_consensus_partition returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 1, 2], "B": [3, 4, 5]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B3": {0}, "A1_B4": {1}, "A2_B5": {2}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters called on non-empty dataframe should return a + f"""get_consensus_partition called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters called on non-empty dataframe should return the expected non-empty + f"""get_consensus_partition called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters called on non-empty dataframe should return all nodes""", + """get_consensus_partition called on non-empty dataframe should return all nodes""", ) def test_on_two_layers_1(self): """ - compute_mutual_clusters returns a dictionary, and returns all the nodes + get_consensus_partition returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 2, 2], "B": [0, 0, 2, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B0": {0, 1}, "A2_B2": {2, 3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters called on non-empty dataframe should return a + f"""get_consensus_partition called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters called on non-empty dataframe should return + f"""get_consensus_partition called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters called on non-empty dataframe should return all nodes""", + """get_consensus_partition called on non-empty dataframe should return all nodes""", ) def test_on_two_layers_2(self): """ - compute_mutual_clusters returns a dictionary, and returns all the nodes + get_consensus_partition returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [3, 3, 3, 3], "B": [0, 0, 2, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A3_B0": {0, 1}, "A3_B2": {2, 3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters called on non-empty dataframe should return a + f"""get_consensus_partition called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters called on non-empty dataframe should return + f"""get_consensus_partition called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters called on non-empty dataframe should return all nodes""", + """get_consensus_partition called on non-empty dataframe should return all nodes""", ) def test_on_three_layers_0(self): """ - compute_mutual_clusters returns a dictionary, and returns all the nodes + get_consensus_partition returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 2, 2], "B": [0, 0, 2, 2], "C": [0, 0, 2, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B0_C0": {0, 1}, "A2_B2_C2": {2, 3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters called on non-empty dataframe should return a + f"""get_consensus_partition called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters called on non-empty dataframe should return + f"""get_consensus_partition called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters called on non-empty dataframe should return all nodes""", + """get_consensus_partition called on non-empty dataframe should return all nodes""", ) def test_on_three_layers_1(self): """ - compute_mutual_clusters returns a dictionary, and returns all the nodes + get_consensus_partition returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 1, 1], "B": [0, 1, 0, 1], "C": [1, 0, 1, 0]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = { "A0_B0_C1": {0}, @@ -230,63 +230,63 @@ def test_on_three_layers_1(self): self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters called on non-empty dataframe should return a non-empty dictionary, + f"""get_consensus_partition called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters called on non-empty dataframe should return + f"""get_consensus_partition called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters called on non-empty dataframe should return all nodes""", + """get_consensus_partition called on non-empty dataframe should return all nodes""", ) def test_on_three_layers_2(self): """ - compute_mutual_clusters returns a dictionary, and returns all the nodes + get_consensus_partition returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 1, 1], "B": [1, 1, 0, 1], "C": [0, 0, 1, 0]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters(cluster_labels_df=_a) + _res0 = get_consensus_partition(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B1_C0": {0, 1}, "A1_B0_C1": {2}, "A1_B1_C0": {3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters called on non-empty dataframe should return a non-empty dictionary, + f"""get_consensus_partition called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters called on non-empty dataframe should return the expected non-empty + f"""get_consensus_partition called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters called on non-empty dataframe should return all nodes""", + """get_consensus_partition called on non-empty dataframe should return all nodes""", ) diff --git a/tests/test_compute_mutual_clusters_recursive.py b/tests/test_get_consensus_partition_recursive.py similarity index 68% rename from tests/test_compute_mutual_clusters_recursive.py rename to tests/test_get_consensus_partition_recursive.py index f265373..93c1880 100644 --- a/tests/test_compute_mutual_clusters_recursive.py +++ b/tests/test_get_consensus_partition_recursive.py @@ -2,223 +2,223 @@ import pandas as pd -from multilayer_alignment.mutual_clusters import compute_mutual_clusters_recursive +from multilayer_alignment.consensus import get_consensus_partition_recursive -class TestComputeMutualClustersRecursive(unittest.TestCase): +class TestGetConsensusPartitionRecursive(unittest.TestCase): """ - Test functionality of mutual_clusters.compute_mutual_clusters_recursive() + Test functionality of consensus.get_consensus_partition_recursive() ------------ Example ------------ - >>> python3 -m unittest -v tests.test_compute_mutual_clusters_recursive + >>> python3 -m unittest -v tests.test_get_consensus_partition_recursive """ def test_on_empty(self): """ - compute_mutual_clusters_recursive returns a dictionary + get_consensus_partition_recursive returns a dictionary """ _a = pd.DataFrame() - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on empty dataframe should return an empty dictionary, + f"""get_consensus_partition_recursive called on empty dataframe should return an empty dictionary, but returned {_res0}""", ) def test_on_one_layer(self): """ - compute_mutual_clusters_recursive returns a dictionary, and returns all the nodes + get_consensus_partition_recursive returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 1, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0": {0}, "A1": {1}, "A2": {2}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return a non-empty dictionary, + f"""get_consensus_partition_recursive called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return + f"""get_consensus_partition_recursive called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters_recursive called on non-empty dataframe should return all nodes""", + """get_consensus_partition_recursive called on non-empty dataframe should return all nodes""", ) def test_on_two_layers_0(self): """ - compute_mutual_clusters_recursive returns a dictionary, and returns all the nodes + get_consensus_partition_recursive returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 1, 2], "B": [3, 4, 5]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B3": {0}, "A1_B4": {1}, "A2_B5": {2}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return a + f"""get_consensus_partition_recursive called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return the expected non-empty + f"""get_consensus_partition_recursive called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters_recursive called on non-empty dataframe should return all nodes""", + """get_consensus_partition_recursive called on non-empty dataframe should return all nodes""", ) def test_on_two_layers_1(self): """ - compute_mutual_clusters_recursive returns a dictionary, and returns all the nodes + get_consensus_partition_recursive returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 2, 2], "B": [0, 0, 2, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B0": {0, 1}, "A2_B2": {2, 3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return a + f"""get_consensus_partition_recursive called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return + f"""get_consensus_partition_recursive called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters_recursive called on non-empty dataframe should return all nodes""", + """get_consensus_partition_recursive called on non-empty dataframe should return all nodes""", ) def test_on_two_layers_2(self): """ - compute_mutual_clusters_recursive returns a dictionary, and returns all the nodes + get_consensus_partition_recursive returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [3, 3, 3, 3], "B": [0, 0, 2, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A3_B0": {0, 1}, "A3_B2": {2, 3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return a + f"""get_consensus_partition_recursive called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return + f"""get_consensus_partition_recursive called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters_recursive called on non-empty dataframe should return all nodes""", + """get_consensus_partition_recursive called on non-empty dataframe should return all nodes""", ) def test_on_three_layers_0(self): """ - compute_mutual_clusters_recursive returns a dictionary, and returns all the nodes + get_consensus_partition_recursive returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 2, 2], "B": [0, 0, 2, 2], "C": [0, 0, 2, 2]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B0_C0": {0, 1}, "A2_B2_C2": {2, 3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return a + f"""get_consensus_partition_recursive called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return + f"""get_consensus_partition_recursive called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters_recursive called on non-empty dataframe should return all nodes""", + """get_consensus_partition_recursive called on non-empty dataframe should return all nodes""", ) def test_on_three_layers_1(self): """ - compute_mutual_clusters_recursive returns a dictionary, and returns all the nodes + get_consensus_partition_recursive returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 1, 1], "B": [0, 1, 0, 1], "C": [1, 0, 1, 0]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = { "A0_B0_C1": {0}, @@ -230,63 +230,63 @@ def test_on_three_layers_1(self): self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return a non-empty dictionary, + f"""get_consensus_partition_recursive called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return + f"""get_consensus_partition_recursive called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters_recursive called on non-empty dataframe should return all nodes""", + """get_consensus_partition_recursive called on non-empty dataframe should return all nodes""", ) def test_on_three_layers_2(self): """ - compute_mutual_clusters_recursive returns a dictionary, and returns all the nodes + get_consensus_partition_recursive returns a dictionary, and returns all the nodes """ _a = pd.DataFrame({"A": [0, 0, 1, 1], "B": [1, 1, 0, 1], "C": [0, 0, 1, 0]}) _all_nodes = list(_a.index) - _res0 = compute_mutual_clusters_recursive(cluster_labels_df=_a) + _res0 = get_consensus_partition_recursive(opinions=_a) _returned_nodes = [n for mc in _res0.values() for n in mc] _expected0 = {"A0_B1_C0": {0, 1}, "A1_B0_C1": {2}, "A1_B1_C0": {3}} self.assertIsInstance( _res0, dict, - f"""compute_mutual_clusters_recursive should return a dictionary, but returned {type(_res0)}""", + f"""get_consensus_partition_recursive should return a dictionary, but returned {type(_res0)}""", ) self.assertNotEqual( _res0, dict(), - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return a non-empty dictionary, + f"""get_consensus_partition_recursive called on non-empty dataframe should return a non-empty dictionary, but returned {_res0}""", ) self.assertDictEqual( _res0, _expected0, - f"""compute_mutual_clusters_recursive called on non-empty dataframe should return the expected non-empty + f"""get_consensus_partition_recursive called on non-empty dataframe should return the expected non-empty dictionary, but returned {_res0}""", ) self.assertSetEqual( set(_all_nodes), set(_returned_nodes), - """compute_mutual_clusters_recursive called on non-empty dataframe should return all nodes""", + """get_consensus_partition_recursive called on non-empty dataframe should return all nodes""", )