├── EorzeaEnv ├── py.typed ├── Data │ ├── __init__.py │ ├── WeatherRate.py │ ├── TerritoryWeather.py │ └── Weather.py ├── eorzea_lang.py ├── errors.py ├── __init__.py ├── eorzea_rainwbow.py ├── eorzea_place_name.py ├── eorzea_weather.py └── eorzea_time.py ├── test ├── __init__.py ├── test_data.py ├── test_rainbow.py ├── test_place_name.py ├── test_time.py └── test_forecast.py ├── requirements.txt ├── setup.cfg ├── .pre-commit-config.yaml ├── LICENSE ├── requirements-test.txt ├── Makefile ├── .github └── workflows │ ├── pypi_publish.yml │ └── CI.yml ├── tox.ini ├── .gitignore ├── utils └── sync_version.py ├── pyproject.toml ├── constraints.txt ├── requirements-dev.txt ├── CHANGELOG.md ├── README.md └── poetry.lock /EorzeaEnv/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /EorzeaEnv/Data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /EorzeaEnv/eorzea_lang.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class EorzeaLang(str, Enum): 5 | EN = "en" 6 | JA = "ja" 7 | DE = "de" 8 | FR = "fr" 9 | KO = "ko" 10 | ZH_SC = "cn" 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.24.4 ; python_version >= "3.8" and python_version < "3.12" 2 | numpy==2.0.0 ; python_version >= "3.12" and python_full_version <= "3.13.0" 3 | rapidfuzz==2.15.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = 3 | E701 4 | E704 5 | W503 6 | W604 7 | count = true 8 | exit-zero = true 9 | statistics = true 10 | exclude = 11 | .git, 12 | __pycache__, 13 | docs/*, 14 | /usr/local/*, 15 | .pytest_cache/*, 16 | .tox, 17 | .venv 18 | max-complexity = 10 19 | max-line-length = 88 20 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.2.3 4 | hooks: 5 | - id: flake8 6 | - id: check-merge-conflict 7 | - id: check-yaml 8 | 9 | - repo: https://github.com/pre-commit/mirrors-mypy 10 | rev: "v0.971" 11 | hooks: 12 | - id: mypy 13 | 14 | - repo: https://github.com/psf/black 15 | rev: "24.4.2" 16 | hooks: 17 | - id: black 18 | -------------------------------------------------------------------------------- /EorzeaEnv/errors.py: -------------------------------------------------------------------------------- 1 | class EorzeaEnvError(Exception): ... 2 | 3 | 4 | class InvalidEorzeaPlaceName(EorzeaEnvError, ValueError): 5 | def __init__(self, *, place_name: str, is_strict: bool) -> None: 6 | mode_msg = "strict" if is_strict else "fuzzy" 7 | message = f"`{place_name}` is not a valid Eorzea placename in {mode_msg} mode.)" 8 | super().__init__(message) 9 | 10 | 11 | class WeatherRateDataError(EorzeaEnvError): ... 12 | -------------------------------------------------------------------------------- /EorzeaEnv/__init__.py: -------------------------------------------------------------------------------- 1 | from .eorzea_lang import EorzeaLang 2 | from .eorzea_place_name import EorzeaPlaceName 3 | from .eorzea_rainwbow import EorzeaRainbow 4 | from .eorzea_time import EorzeaTime 5 | from .eorzea_weather import EorzeaWeather 6 | 7 | __all__ = [ 8 | "EorzeaTime", 9 | "EorzeaWeather", 10 | "EorzeaPlaceName", 11 | "EorzeaLang", 12 | "EorzeaRainbow", 13 | ] 14 | 15 | 16 | __title__ = "EorzeaEnv" 17 | __author__ = "Elton H.Y. Chou" 18 | __license__ = "MIT" 19 | __version__ = "2.2.12" 20 | -------------------------------------------------------------------------------- /test/test_data.py: -------------------------------------------------------------------------------- 1 | from EorzeaEnv import EorzeaLang 2 | from EorzeaEnv.Data.PlaceName import place_name 3 | from EorzeaEnv.Data.TerritoryWeather import territory_weather 4 | from EorzeaEnv.Data.Weather import weather 5 | from EorzeaEnv.Data.WeatherRate import weather_rate 6 | 7 | 8 | def test_data_integrity(): 9 | locales = [ 10 | EorzeaLang.DE, 11 | EorzeaLang.EN, 12 | EorzeaLang.FR, 13 | EorzeaLang.JA, 14 | EorzeaLang.KO, 15 | EorzeaLang.ZH_SC, 16 | ] 17 | for k in locales: 18 | place_dict = place_name[k] 19 | assert place_dict 20 | for v in place_dict.values(): 21 | territory_index = v["index"] 22 | weather_rate_index = territory_weather[territory_index] 23 | the_weather_rate = weather_rate[weather_rate_index] 24 | for weather_target in the_weather_rate: 25 | assert weather_target[1] in weather 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Elton H.Y. Chou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.4.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" and sys_platform == "win32" 2 | attrs==23.2.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 3 | colorama==0.4.6 ; python_version >= "3.8" and python_full_version <= "3.13.0" and sys_platform == "win32" 4 | coverage[toml]==6.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 5 | iniconfig==2.0.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 6 | numpy==1.24.4 ; python_version >= "3.8" and python_version < "3.12" 7 | numpy==2.0.0 ; python_version >= "3.12" and python_full_version <= "3.13.0" 8 | packaging==24.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 9 | pluggy==1.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 10 | py==1.11.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 11 | pytest==6.2.5 ; python_version >= "3.8" and python_full_version <= "3.13.0" 12 | rapidfuzz==2.15.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 13 | toml==0.10.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 14 | tomli==2.0.1 ; python_full_version <= "3.11.0a6" and python_version >= "3.8" 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help 2 | .SILENT: 3 | 4 | help: # Show this help message. 5 | @grep -E '^[a-zA-Z_-]+:.*?# .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?# "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 6 | 7 | install: # Install requirements of project. 8 | poetry install 9 | 10 | cov-test: # Run the tests. 11 | coverage run -m pytest 12 | 13 | cov-report: cov-test # Show the coverage of tests. 14 | coverage report -m 15 | 16 | freeze: # Export the requirements.txt file. 17 | poetry export --without-hashes -f requirements.txt --output requirements.txt 18 | poetry export --with dev --without-hashes -f requirements.txt --output requirements-dev.txt 19 | poetry export --with test --without-hashes -f requirements.txt --output requirements-test.txt 20 | poetry export --with dev --without-hashes -f constraints.txt --output constraints.txt 21 | 22 | lint: # Lint the code. 23 | flake8 24 | 25 | type-check: # Check the type. 26 | mypy 27 | 28 | format: # Format the code. 29 | black . 30 | 31 | update-version: # Sync package file version. 32 | # sed -i -E "s/[0-9]+\.[0-9]+\.[0-9]+/$$(poetry version --short)/1" EorzeaEnv/__init__.py 33 | python utils/sync_version.py 34 | 35 | print-changelog: # Print changelog of current version. 36 | @awk -v ver=$$(poetry version --short) '/^#+ \[/ { if (p) { exit }; if ($$2 == "["ver"]") { p=1; next } } p && NF' CHANGELOG.md 37 | -------------------------------------------------------------------------------- /.github/workflows/pypi_publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package 2 | 3 | on: 4 | push: 5 | tags: ["*.*.*"] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | 13 | - name: Set up Python 14 | uses: actions/setup-python@v5 15 | with: 16 | python-version: "3.12" 17 | 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install poetry==1.8.3 22 | poetry install 23 | 24 | - name: Run test 25 | run: | 26 | poetry run tox -e "py312, lint, type, gh-cov-report" 27 | 28 | - name: Publish package 29 | run: | 30 | poetry publish --build -u __token__ -p ${{ secrets.PYPI_API_TOKEN }} 31 | 32 | - name: Set release data 33 | id: release_settings 34 | run: | 35 | BODY_FILE=release_note.md 36 | make print-changelog >> ${BODY_FILE} 37 | echo "release_body_filename=${BODY_FILE}" >> $GITHUB_OUTPUT 38 | 39 | - name: Create Repository Release 40 | uses: ncipollo/release-action@v1 41 | with: 42 | name: "EorzeaEnv ${{ github.ref_name }}" 43 | token: ${{ secrets.GITHUB_TOKEN }} 44 | bodyFile: ${{ steps.release_settings.outputs.release_body_filename }} 45 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [gh] 2 | python = 3 | 3.12 = py312, gh-cov-report 4 | 3.11 = py311, lint, type, gh-cov-report 5 | 3.10 = py310, gh-cov-report 6 | 3.9 = py39, gh-cov-report 7 | 3.8 = py38, gh-cov-report 8 | 9 | [tox] 10 | skipsdist = true 11 | isolated_build = true 12 | envlist = clean, py{38, 39, 310, 311, 312}, lint, type, cov-report 13 | 14 | [testenv] 15 | description = run tests 16 | deps = 17 | -r requirements-test.txt 18 | commands = 19 | coverage run -m pytest 20 | 21 | [testenv:lint] 22 | description = run linters 23 | skip_install = true 24 | deps = 25 | black >= 24.3 26 | flake8 >= 5.0.4 27 | commands = 28 | black {posargs:.} 29 | flake8 30 | 31 | [testenv:type] 32 | description = run type checks 33 | skip_install = true 34 | deps = 35 | mypy > 0.971 36 | commands = 37 | mypy 38 | 39 | [testenv:cov-report] 40 | depends = py{38, 39, 310, 311, 312} 41 | description = report coverage 42 | skip_install = true 43 | deps = coverage[toml] 44 | commands = 45 | coverage combine 46 | coverage report 47 | coverage html 48 | 49 | [testenv:gh-cov-report] 50 | depends = py{38, 39, 310, 311, 312} 51 | description = combine coverage 52 | skip_install = true 53 | deps = coverage[toml] 54 | commands = 55 | coverage combine 56 | coverage report 57 | coverage xml 58 | 59 | [testenv:clean] 60 | deps = coverage[toml] 61 | skip_install = true 62 | commands = coverage erase 63 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [master, dev] 6 | tags-ignore: 7 | - "*.*.*" 8 | pull_request: 9 | branches: [master] 10 | 11 | concurrency: 12 | group: ci-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | test: 17 | name: test with python${{ matrix.python-version }} on ${{ matrix.os }} 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | os: 22 | - ubuntu-latest 23 | - macos-latest 24 | - windows-latest 25 | python-version: 26 | - "3.8" 27 | - "3.9" 28 | - "3.10" 29 | - "3.11" 30 | - "3.12" 31 | steps: 32 | - uses: actions/checkout@v4 33 | 34 | - name: Set up Python ${{ matrix.python-version }} 35 | uses: actions/setup-python@v5 36 | with: 37 | python-version: ${{ matrix.python-version }} 38 | 39 | - name: Install tox 40 | run: | 41 | python -m pip install --upgrade pip 42 | python -m pip install tox-gh>=1.2 43 | 44 | - name: Run test 45 | run: tox 46 | 47 | - name: Upload coverage reports to Codecov 48 | uses: codecov/codecov-action@v4.0.1 49 | with: 50 | token: ${{ secrets.CODECOV_TOKEN }} 51 | flags: ${{ format('python{0} ({1})', matrix.python-version, matrix.os) }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # VSCode stuff: 2 | .devcontainer/ 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | .vscode/ 9 | .DS_Store 10 | eorzea/ 11 | test.py 12 | 13 | # C extensions 14 | *.so 15 | 16 | # Distribution / packaging 17 | .Python 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | .hypothesis/ 55 | .pytest_cache/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # pyenv 83 | .python-version 84 | 85 | # celery beat schedule file 86 | celerybeat-schedule 87 | 88 | # SageMath parsed files 89 | *.sage.py 90 | 91 | # Environments 92 | .env 93 | .venv 94 | env/ 95 | venv/ 96 | ENV/ 97 | env.bak/ 98 | venv.bak/ 99 | 100 | # Spyder project settings 101 | .spyderproject 102 | .spyproject 103 | 104 | # Rope project settings 105 | .ropeproject 106 | 107 | # mkdocs documentation 108 | /site 109 | 110 | # mypy 111 | .mypy_cache/ -------------------------------------------------------------------------------- /test/test_rainbow.py: -------------------------------------------------------------------------------- 1 | import random 2 | from datetime import datetime 3 | 4 | from EorzeaEnv import EorzeaPlaceName, EorzeaRainbow, EorzeaTime, EorzeaWeather 5 | 6 | 7 | class TestRainbow: 8 | def test_rainbow(self): 9 | place_name1 = EorzeaPlaceName("eastern la noscea") 10 | place_name2 = EorzeaPlaceName("fields of glory") 11 | 12 | the_rainbow = EorzeaRainbow(place_name1) 13 | impossible_rainbow = EorzeaRainbow(place_name2) 14 | 15 | assert the_rainbow.place_name is place_name1 16 | assert impossible_rainbow.place_name is place_name2 17 | 18 | et1 = EorzeaTime(1661184000) 19 | et2 = EorzeaTime(1661185440) 20 | 21 | weather1 = EorzeaWeather.forecast(place_name1, et1, raw=True) 22 | weather2 = EorzeaWeather.forecast(place_name1, et2, raw=True) 23 | the_rainbow.append(et1, weather1) 24 | the_rainbow.append(et2, weather2) 25 | 26 | weather1 = EorzeaWeather.forecast(place_name2, et1, raw=True) 27 | weather2 = EorzeaWeather.forecast(place_name2, et2, raw=True) 28 | impossible_rainbow.append(et1, weather1) 29 | impossible_rainbow.append(et2, weather2) 30 | 31 | assert the_rainbow.is_appear 32 | assert not impossible_rainbow.is_appear 33 | 34 | def test_used_with_weather_period_generator(self): 35 | place = EorzeaPlaceName("東ラノシア") 36 | the_rainbow = EorzeaRainbow(place_name=place) 37 | rainbow_times: list[datetime] = [] 38 | expected_rainbow_count = random.randint(1, 20) 39 | 40 | for et in EorzeaTime.weather_period( 41 | step="inf", from_=datetime(2022, 8, 25, 0, 0).timestamp() 42 | ): 43 | the_rainbow.append(et, EorzeaWeather.forecast(place, et, raw=True)) 44 | if the_rainbow.is_appear: 45 | rainbow_times.append(datetime.fromtimestamp(et.get_unix_time())) 46 | if len(rainbow_times) == expected_rainbow_count: 47 | break 48 | 49 | assert len(rainbow_times) == expected_rainbow_count 50 | -------------------------------------------------------------------------------- /utils/sync_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Script to sync the package version from pyproject.toml to __init__.py 4 | """ 5 | 6 | import re 7 | from pathlib import Path 8 | 9 | 10 | def get_version_from_pyproject(project_root: Path) -> str: 11 | """Extract version from pyproject.toml""" 12 | pyproject_path = project_root / "pyproject.toml" 13 | 14 | if not pyproject_path.exists(): 15 | raise FileNotFoundError(f"pyproject.toml not found at {pyproject_path}") 16 | 17 | with open(pyproject_path, "r", encoding="utf-8") as f: 18 | content = f.read() 19 | 20 | # Match version = "X.Y.Z" in pyproject.toml 21 | match = re.search(r'version\s*=\s*"([^"]+)"', content) 22 | if not match: 23 | raise ValueError("Could not find version in pyproject.toml") 24 | 25 | return match.group(1) 26 | 27 | 28 | def sync_version_to_init(project_root: Path, version: str) -> None: 29 | """Update __version__ in package __init__.py""" 30 | init_path = project_root / "EorzeaEnv" / "__init__.py" 31 | 32 | if not init_path.exists(): 33 | raise FileNotFoundError(f"__init__.py not found at {init_path}") 34 | 35 | with open(init_path, "r", encoding="utf-8") as f: 36 | content = f.read() 37 | 38 | # Replace __version__ = "X.Y.Z" with new version 39 | updated_content = re.sub( 40 | r'__version__\s*=\s*"[^"]+"', f'__version__ = "{version}"', content 41 | ) 42 | 43 | if content == updated_content: 44 | print(f"✓ Version is already up to date: {version}") 45 | return 46 | 47 | with open(init_path, "w", encoding="utf-8") as f: 48 | f.write(updated_content) 49 | 50 | print(f"✓ Successfully synced version to {version}") 51 | 52 | 53 | def main(): 54 | """Main entry point""" 55 | project_root = Path(__file__).parent.parent.resolve() 56 | 57 | try: 58 | # Get version from pyproject.toml 59 | version = get_version_from_pyproject(project_root) 60 | print(f"Found version in pyproject.toml: {version}") 61 | 62 | # Sync to __init__.py 63 | sync_version_to_init(project_root, version) 64 | 65 | except (FileNotFoundError, ValueError) as e: 66 | print(f"✗ Error: {e}") 67 | exit(1) 68 | 69 | 70 | if __name__ == "__main__": 71 | main() 72 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "EorzeaEnv" 3 | version = "2.2.12" 4 | description = "Final Fantasy XIV weather & time tools." 5 | keywords = ["eorzea", "ffxiv", "ff14", "final fantasy"] 6 | authors = ["Elton Chou "] 7 | maintainers = ["Elton Chou "] 8 | homepage = "https://github.com/EltonChou/EorzeaEnv" 9 | repository = "https://github.com/EltonChou/EorzeaEnv" 10 | license = "MIT" 11 | classifiers = [ 12 | "Development Status :: 5 - Production/Stable", 13 | "Intended Audience :: Developers", 14 | "Topic :: Utilities", 15 | "Programming Language :: Python :: 3.8", 16 | "Programming Language :: Python :: 3.9", 17 | "Programming Language :: Python :: 3.10", 18 | "Programming Language :: Python :: 3.11", 19 | "Programming Language :: Python :: 3.12", 20 | "License :: OSI Approved :: MIT License", 21 | "Operating System :: OS Independent", 22 | ] 23 | readme = "README.md" 24 | packages = [{ include = "EorzeaEnv", from = "." }] 25 | include = ["README.md", "CHANGELOG.md", "LICENSE"] 26 | 27 | [tool.poetry.urls] 28 | "Bug Reports" = "https://github.com/EltonChou/EorzeaEnv/issues" 29 | 30 | [tool.poetry.dependencies] 31 | python = ">=3.8,<=3.13" 32 | numpy = [ 33 | { version = "^1.19.0", python = ">=3.8,<3.12" }, 34 | { version = "^2.0", python = ">=3.12" }, 35 | ] 36 | rapidfuzz = "^2.0.11" 37 | 38 | [tool.poetry.group.test.dependencies] 39 | pytest = "^6.2.5" 40 | coverage = { extras = ["toml"], version = "^6.4.4" } 41 | 42 | [tool.poetry.dev-dependencies] 43 | pytest = "^6.2.5" 44 | autopep8 = "^1.6.0" 45 | tox = "^3.25.1" 46 | coverage = { extras = ["toml"], version = "^6.4.4" } 47 | flake8 = "^5.0.4" 48 | pre-commit = "^2.20.0" 49 | mypy = ">0.971" 50 | black = "^24.3.0" 51 | 52 | [build-system] 53 | requires = ["poetry-core>=1.0.0"] 54 | build-backend = "poetry.core.masonry.api" 55 | 56 | [tool.mypy] 57 | files = ["EorzeaEnv/**/*.py"] 58 | ignore_missing_imports = true 59 | 60 | [tool.black] 61 | line-length = 88 62 | target-version = ['py311'] 63 | 64 | [tool.pytest.ini_options] 65 | junit_family = "xunit2" 66 | addopts = "-ra -q" 67 | testpaths = ["test"] 68 | 69 | [tool.coverage.run] 70 | omit = ["*/site-packages/*", "*/tests/*", "*/test/*"] 71 | parallel = true 72 | 73 | [tool.coverage.report] 74 | show_missing = true 75 | skip_covered = true 76 | exclude_lines = [ 77 | "pragma: no cover", 78 | "@abstract", 79 | "@overload", 80 | "pass", 81 | "raise NotImplementedError", 82 | "warnings.warn", 83 | ] 84 | -------------------------------------------------------------------------------- /EorzeaEnv/eorzea_rainwbow.py: -------------------------------------------------------------------------------- 1 | import copy 2 | from collections import deque 3 | from dataclasses import dataclass 4 | from typing import MutableSequence, Set 5 | 6 | from .Data.TerritoryWeather import territory_weather as _territory_weather 7 | from .Data.WeatherRate import weather_rate as _weather_rate 8 | from .eorzea_place_name import EorzeaPlaceName 9 | from .eorzea_time import EorzeaTime 10 | 11 | RAINY_WEATHERS = {7, 8, 10} 12 | 13 | 14 | @dataclass 15 | class WeatherInfo: 16 | time: EorzeaTime 17 | raw_weather: int 18 | 19 | 20 | class EorzeaRainbow: 21 | _weather_slot: MutableSequence[WeatherInfo] 22 | _is_possible: bool 23 | _place_name: EorzeaPlaceName 24 | 25 | def __init__(self, place_name: EorzeaPlaceName) -> None: 26 | self._place_name = place_name 27 | self._weather_slot = deque([], maxlen=2) 28 | self._is_possible = _is_rainbow_possible(place_name) 29 | 30 | @property 31 | def place_name(self): 32 | return self._place_name 33 | 34 | @property 35 | def is_possible(self): 36 | return self._is_possible 37 | 38 | @property 39 | def is_appear(self): 40 | if len(self._weather_slot) != 2 or not self.is_possible: 41 | return False 42 | 43 | prev_weather, current_weather = self._weather_slot 44 | if ( 45 | prev_weather.raw_weather not in RAINY_WEATHERS 46 | or current_weather.raw_weather in RAINY_WEATHERS 47 | ): 48 | return False 49 | 50 | if ( 51 | not _check_sun(current_weather.time.sun) 52 | or current_weather.time <= prev_weather.time 53 | ): 54 | return False 55 | 56 | time_ticket = _generate_time_ticket(current_weather.time) 57 | return 600 <= time_ticket <= 1800 58 | 59 | def append(self, time: EorzeaTime, raw_weather: int): 60 | self._weather_slot.append( 61 | WeatherInfo(time=copy.copy(time), raw_weather=raw_weather) 62 | ) 63 | 64 | 65 | def _is_rainbow_possible(place_name: EorzeaPlaceName) -> bool: 66 | weather_rate_index = _territory_weather[place_name.index] 67 | weather_rate = _weather_rate[weather_rate_index] 68 | possible_weathers: Set[int] = {w[1] for w in weather_rate} 69 | return bool( 70 | possible_weathers - RAINY_WEATHERS and RAINY_WEATHERS & possible_weathers 71 | ) 72 | 73 | 74 | def _check_sun(sun: int): 75 | return sun >= 27 or sun <= 6 76 | 77 | 78 | def _generate_time_ticket(time: EorzeaTime) -> int: 79 | return time.hour * 100 + time.minute 80 | -------------------------------------------------------------------------------- /test/test_place_name.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from EorzeaEnv import EorzeaLang, EorzeaPlaceName 3 | from EorzeaEnv.errors import InvalidEorzeaPlaceName 4 | 5 | 6 | class TestPlaceName: 7 | def test_default(self): 8 | EorzeaPlaceName("The Ruby Sea") 9 | EorzeaPlaceName("the ruby sea") 10 | EorzeaPlaceName("ruby sea") 11 | EorzeaPlaceName("rubinsee") 12 | EorzeaPlaceName("紅玉海") 13 | EorzeaPlaceName("黑衣森林东部林区") 14 | EorzeaPlaceName("수투 훈련장") 15 | with pytest.raises(InvalidEorzeaPlaceName): 16 | EorzeaPlaceName("The Ruby See") 17 | 18 | def test_specified_locale_scope(self): 19 | EorzeaPlaceName("The Ruby Sea", locale_scopes=[EorzeaLang.EN]) 20 | with pytest.raises(InvalidEorzeaPlaceName): 21 | EorzeaPlaceName( 22 | "The Ruby Sea", locale_scopes=[EorzeaLang.JA, EorzeaLang.DE] 23 | ) 24 | 25 | def test_fuzzy(self): 26 | EorzeaPlaceName("ruby Sea", strict=False) 27 | EorzeaPlaceName("rubisee", strict=False) 28 | with pytest.raises(InvalidEorzeaPlaceName): 29 | EorzeaPlaceName("diamond sea", strict=False) 30 | 31 | def test_fuzzy_with_locale_scope(self): 32 | EorzeaPlaceName( 33 | "rubby sea", strict=False, locale_scopes=[EorzeaLang.EN, EorzeaLang.DE] 34 | ) 35 | with pytest.raises(InvalidEorzeaPlaceName): 36 | EorzeaPlaceName( 37 | "rubby sea", strict=False, locale_scopes=[EorzeaLang.JA, EorzeaLang.DE] 38 | ) 39 | 40 | def test_acted_as_string(self): 41 | place = EorzeaPlaceName("The Ruby Sea") 42 | assert str(place) == "The Ruby Sea" 43 | 44 | def test_equal(self): 45 | the_ruby_sea = EorzeaPlaceName("The Ruby Sea") 46 | the_ruby_see = EorzeaPlaceName("ruby sea", strict=False) 47 | assert the_ruby_sea == the_ruby_see 48 | assert not the_ruby_sea == "The Ruby Sea" 49 | 50 | def test_validate_method(self): 51 | assert EorzeaPlaceName.validate("The Ruby Sea", strict=True) 52 | assert not EorzeaPlaceName.validate("The Ruby See", strict=True) 53 | with pytest.raises(ValueError): 54 | EorzeaPlaceName.validate("The Ruby Sea", strict=True, fuzzy_cutoff=120) 55 | ruby_sea = EorzeaPlaceName("The Ruby Sea") 56 | assert EorzeaPlaceName.validate(ruby_sea, strict=True) 57 | assert not EorzeaPlaceName.validate(1, strict=False) # type: ignore 58 | 59 | def test_place_name_property(self): 60 | place_name = EorzeaPlaceName("The Ruby Sea") 61 | assert type(place_name.index) is int 62 | assert type(place_name.value) is str 63 | 64 | def test_bad_type_place_name(self): 65 | with pytest.raises(TypeError): 66 | EorzeaPlaceName(1) # type: ignore 67 | 68 | def test_repr(self): 69 | place = EorzeaPlaceName("The Ruby Sea") 70 | assert eval(repr(place)) == place 71 | -------------------------------------------------------------------------------- /constraints.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.4.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" and sys_platform == "win32" 2 | attrs==23.2.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 3 | autopep8==1.7.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 4 | black==24.4.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 5 | cfgv==3.4.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 6 | click==8.1.7 ; python_version >= "3.8" and python_full_version <= "3.13.0" 7 | colorama==0.4.6 ; python_version >= "3.8" and python_full_version <= "3.13.0" and (sys_platform == "win32" or platform_system == "Windows") 8 | coverage==6.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 9 | distlib==0.3.8 ; python_version >= "3.8" and python_full_version <= "3.13.0" 10 | filelock==3.15.4 ; python_version >= "3.8" and python_full_version <= "3.13.0" 11 | flake8==5.0.4 ; python_version >= "3.8" and python_full_version <= "3.13.0" 12 | identify==2.5.36 ; python_version >= "3.8" and python_full_version <= "3.13.0" 13 | iniconfig==2.0.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 14 | mccabe==0.7.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 15 | mypy-extensions==1.0.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 16 | mypy==1.10.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 17 | nodeenv==1.9.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 18 | numpy==1.24.4 ; python_version >= "3.8" and python_version < "3.12" 19 | numpy==2.0.0 ; python_version >= "3.12" and python_full_version <= "3.13.0" 20 | packaging==24.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 21 | pathspec==0.12.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 22 | platformdirs==4.2.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 23 | pluggy==1.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 24 | pre-commit==2.21.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 25 | py==1.11.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 26 | pycodestyle==2.9.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 27 | pyflakes==2.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 28 | pytest==6.2.5 ; python_version >= "3.8" and python_full_version <= "3.13.0" 29 | pyyaml==6.0.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 30 | rapidfuzz==2.15.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 31 | six==1.16.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 32 | toml==0.10.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 33 | tomli==2.0.1 ; python_version >= "3.8" and python_full_version <= "3.11.0a6" 34 | tox==3.28.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 35 | typing-extensions==4.12.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 36 | virtualenv==20.26.3 ; python_version >= "3.8" and python_full_version <= "3.13.0" 37 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.4.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" and sys_platform == "win32" 2 | attrs==23.2.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 3 | autopep8==1.7.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 4 | black==24.4.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 5 | cfgv==3.4.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 6 | click==8.1.7 ; python_version >= "3.8" and python_full_version <= "3.13.0" 7 | colorama==0.4.6 ; python_version >= "3.8" and python_full_version <= "3.13.0" and (sys_platform == "win32" or platform_system == "Windows") 8 | coverage[toml]==6.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 9 | distlib==0.3.8 ; python_version >= "3.8" and python_full_version <= "3.13.0" 10 | filelock==3.15.4 ; python_version >= "3.8" and python_full_version <= "3.13.0" 11 | flake8==5.0.4 ; python_version >= "3.8" and python_full_version <= "3.13.0" 12 | identify==2.5.36 ; python_version >= "3.8" and python_full_version <= "3.13.0" 13 | iniconfig==2.0.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 14 | mccabe==0.7.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 15 | mypy-extensions==1.0.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 16 | mypy==1.10.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 17 | nodeenv==1.9.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 18 | numpy==1.24.4 ; python_version >= "3.8" and python_version < "3.12" 19 | numpy==2.0.0 ; python_version >= "3.12" and python_full_version <= "3.13.0" 20 | packaging==24.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 21 | pathspec==0.12.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 22 | platformdirs==4.2.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 23 | pluggy==1.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 24 | pre-commit==2.21.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 25 | py==1.11.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 26 | pycodestyle==2.9.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 27 | pyflakes==2.5.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 28 | pytest==6.2.5 ; python_version >= "3.8" and python_full_version <= "3.13.0" 29 | pyyaml==6.0.1 ; python_version >= "3.8" and python_full_version <= "3.13.0" 30 | rapidfuzz==2.15.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 31 | six==1.16.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 32 | toml==0.10.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 33 | tomli==2.0.1 ; python_version >= "3.8" and python_full_version <= "3.11.0a6" 34 | tox==3.28.0 ; python_version >= "3.8" and python_full_version <= "3.13.0" 35 | typing-extensions==4.12.2 ; python_version >= "3.8" and python_full_version <= "3.13.0" 36 | virtualenv==20.26.3 ; python_version >= "3.8" and python_full_version <= "3.13.0" 37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | - Diamondust predictor. 5 | - Aurora predictor. 6 | 7 | ## [2.2.12] - 2025-12-15 8 | ### Added 9 | - Update data to 7.38 10 | 11 | ## [2.2.11] - 2024-09-11 12 | ### Fixed 13 | - Fix `EorzeaTime` rollover issue([#14](https://github.com/EltonChou/EorzeaEnv/issues/14)) by [@mwishum](https://github.com/mwishum) 14 | 15 | ## [2.2.10] - 2024-07-02 16 | ### Added 17 | - Add patch 7.0 data. 18 | - Add python 3.11 support. 19 | - Add python 3.12 support. 20 | 21 | ## [2.2.9] - 2023-02-01 22 | ### Added 23 | - Add patch 6.3 data. 24 | - Add CN and KO patch data. 25 | 26 | ## [2.2.8] - 2022-10-05 27 | ### Change 28 | - change `EorzeaWeather.forecast` arguments. (5309a6b) 29 | 30 | ## [2.2.7] - 2022-09-21 31 | ### Fixed 32 | - Add `EorzeaLang.KO` and `EorzeaLang.ZH_SC` to default locale scopes for EorzeaPlaceName. 33 | 34 | ## [2.2.6] - 2022-09-21 35 | ### Added 36 | - Add Chinese data and Korean data. 37 | 38 | ## [2.2.5] - 2022-09-07 39 | ### Added 40 | - Suuport type checking. 41 | 42 | ## [2.2.4] - 2022-08-29 43 | ### Fixed 44 | - Fix package python requirement. 45 | 46 | ## [2.2.3] - 2022-08-29 47 | ### Changed 48 | - Refined type hint 49 | 50 | ## [2.2.2] - 2022-08-27 51 | ### Fixed 52 | - Fixed WeatherRate data missing. (452d11b) 53 | 54 | ## [2.2.1] - 2022-08-26 55 | ### Changed 56 | - `EorzeaTime.weather_period` accepts base timestamp. (a6cbb3e) 57 | - Make `EorzeaRainbow` stricter. (22d015b)(c72a32b) 58 | ### Fixed 59 | - Fixed `EorzeaRainbow` bug. (c72a32b) 60 | 61 | ## [2.2.0] - 2022-08-25 62 | ### Added 63 | - Add patch 6.2 weather data. (14799ec) 64 | - Add `EorzeaRainbow` to predict rainbow occurrence. (fead17f)(52d3829) 65 | ### Changed 66 | - Refactor `EorzeaTime`, the behavior didn't change too much. (b20519c) 67 | - Instance of `EorzeaTime` can compare to each other. (b20519c) 68 | - Add argument in `EorzeaWeather.forecast` that can return weather index instead of weather name. (602da0c) 69 | - `EorzeaWeather.weather_period` can generate infinite period with argument `step='inf'`. (42e9681) 70 | - `timestamp` argument in `EorzeaWeather.forecast` accepts `EorzeaTime` instance. 71 | ### Deprecated 72 | - float and int type of `timestamp` argument supporting in `EorzeaWeather.forecast` would be removed from 2.5.0. 73 | 74 | ## [2.1.0] - 2022-08-23 75 | ### Added 76 | - Add python3.10 supporting 77 | ### Fixed 78 | - Fix EorzeaWeather.forecast timestamp type issue. 79 | - Fix EorzeaTime.weather_period timestamp type issue. 80 | - Fix type hint. 81 | ### Removed 82 | - **Discard python3.6 supporting.** 83 | - **Discard python3.7 supporting.** 84 | 85 | ## [2.0.0] - 2022-05-30 86 | ### Added 87 | - EorzeaPlaceName 88 | 89 | ## [1.5.2] - 2022-05-08 90 | ### Added 91 | - 6.1 weather data 92 | 93 | ## [1.5.1] - 2021-12-04 94 | ### Removed 95 | - Remove python 3.10 support 96 | 97 | ## [1.5.0] - 2021-12-04 98 | ### Added 99 | - 6.0 weather data 100 | 101 | ## [1.4.6] - 2021-05-05 102 | ### Added 103 | - 5.5 weather data 104 | 105 | ## [1.4.5] - 2021-01-15 106 | ### Added 107 | - 5.4 weather data 108 | 109 | ## [1.4.4] - 2020-10-22 110 | ### Added 111 | - EorzeaLang 112 | - EorzeaWeather.forecast with overload 113 | 114 | ## [1.4.3] - 2020-10-20 115 | ### Added 116 | - 5.35 weather data 117 | 118 | ## [1.4.1] - 2019-06-29 119 | ### Added 120 | - 5.1 weather data 121 | 122 | ## [1.4.0] - 2019-06-29 123 | ### Added 124 | - 5.0 weather data 125 | ### Deleted 126 | - `EorzeaWeather.forecast_weather()` 127 | 128 | ## [1.3.0] - 2019-06-25 129 | ### Added 130 | - forecast in EorzeaWeather 131 | ### Changed 132 | - rewrite docstring 133 | ### Deprecated 134 | - forecast_weather in EorzeaWeather is deprecated 135 | 136 | -------------------------------------------------------------------------------- /test/test_time.py: -------------------------------------------------------------------------------- 1 | import time 2 | from datetime import datetime 3 | 4 | import pytest 5 | from EorzeaEnv import EorzeaTime 6 | 7 | 8 | class TestTime: 9 | def test_weather_period(self): 10 | timelist = [t for t in EorzeaTime.weather_period(10)] 11 | assert len(timelist) == 10 12 | 13 | count = 0 14 | for _ in EorzeaTime.weather_period(step="inf"): 15 | count += 1 16 | if count == 1000: 17 | break 18 | 19 | assert count == 1000 20 | 21 | with pytest.raises(TypeError): 22 | for _ in EorzeaTime.weather_period("many"): # type: ignore 23 | pass 24 | 25 | with pytest.raises(TypeError): 26 | for _ in EorzeaTime.weather_period([1, 2, 3]): # type: ignore 27 | pass 28 | 29 | future_date = datetime(3000, 3, 3, 3, 3) 30 | for t in EorzeaTime.weather_period(step=10, from_=future_date.timestamp()): 31 | assert t.get_unix_time() > datetime.now().timestamp() 32 | 33 | def test_time_operator(self): 34 | t1 = EorzeaTime(12345678) 35 | t2 = EorzeaTime(12345700) 36 | 37 | assert t1 < t2 38 | assert t1 <= t2 39 | assert t1 != t2 40 | assert not t1 >= t2 41 | assert not t1 > t1 42 | 43 | fixed_ts = time.time() 44 | t1 = EorzeaTime(fixed_ts) 45 | t2 = EorzeaTime(fixed_ts) 46 | assert t1 == t2 47 | 48 | t1 = EorzeaTime.now() 49 | t2 = EorzeaTime.now() 50 | assert t1 == t2 51 | 52 | with pytest.raises(TypeError): 53 | assert t1 > 1 54 | with pytest.raises(TypeError): 55 | assert t1 >= 1 56 | with pytest.raises(TypeError): 57 | assert not t1 <= 1 58 | with pytest.raises(TypeError): 59 | assert t1 < 1 60 | assert t1 != 1 61 | assert not t1 == 1 62 | 63 | def test_positive_rollover(self): 64 | et = EorzeaTime() 65 | et.minute = 59 66 | et.bell = 23 67 | et.sun = 32 68 | et.moon = 12 69 | et.year = 999 70 | 71 | et.minute += 1 72 | 73 | assert et.minute == 0 74 | assert et.bell == 0 75 | assert et.sun == 1 76 | assert et.moon == 1 77 | assert et.year == 1000 78 | 79 | et.minute += 121 80 | 81 | assert et.minute == 1 82 | assert et.bell == 2 83 | 84 | et.bell += 49 85 | 86 | assert et.bell == 3 87 | assert et.sun == 3 88 | 89 | def test_negative_rollover(self): 90 | et = EorzeaTime() 91 | et.minute = 0 92 | et.bell = 0 93 | et.sun = 1 94 | et.moon = 2 95 | et.year = 1000 96 | 97 | et.minute -= 1 98 | 99 | assert et.minute == 59 100 | assert et.bell == 23 101 | assert et.sun == 32 102 | assert et.moon == 1 103 | 104 | et.minute -= 119 105 | 106 | assert et.minute == 0 107 | assert et.bell == 22 108 | 109 | et.bell -= 48 110 | 111 | assert et.minute == 0 112 | assert et.bell == 22 113 | assert et.sun == 30 114 | assert et.moon == 1 115 | 116 | et.moon -= 11 117 | 118 | assert et.moon == 2 119 | assert et.year == 999 120 | 121 | def test_property(self): 122 | ts = 12700000 123 | et = EorzeaTime(ts) 124 | assert et.guardian == "Nophica" 125 | assert et.moon_phase == 0.75 126 | assert et.moon_name == "Sixth Astral Moon" 127 | 128 | ts = 12879000 129 | et = EorzeaTime(ts) 130 | assert et.guardian == "Althyk" 131 | assert et.moon_phase == 0.50 132 | assert et.moon_name == "Sixth Embral Moon" 133 | 134 | def test_repr(self): 135 | et = EorzeaTime.now() 136 | assert repr(et) == f"EorzeaTime({et.get_unix_time()})" 137 | 138 | def test_act_as_str(self): 139 | et = EorzeaTime.now() 140 | assert str(et) 141 | -------------------------------------------------------------------------------- /test/test_forecast.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | import pytest 4 | 5 | from EorzeaEnv import EorzeaLang, EorzeaPlaceName, EorzeaTime, EorzeaWeather 6 | from EorzeaEnv.errors import WeatherRateDataError 7 | 8 | 9 | class MockDict(dict): 10 | def __getitem__(self, __k): 11 | return () 12 | 13 | 14 | class TestForecast: 15 | def test_legacy_forecast(self): 16 | assert ( 17 | EorzeaWeather.forecast(EorzeaPlaceName("sea of clouds"), 1542591400) 18 | == "Fog" 19 | ) 20 | assert EorzeaWeather.forecast("sea of clouds", EorzeaTime(1542591400)) == "Fog" 21 | 22 | def test_forecast(self): 23 | assert ( 24 | EorzeaWeather.forecast( 25 | EorzeaPlaceName("Eureka Pagos"), EorzeaTime(1542651599.999) 26 | ) 27 | == "Fog" 28 | ) 29 | assert ( 30 | EorzeaWeather.forecast( 31 | EorzeaPlaceName("Eureka Pyros"), EorzeaTime(1542591400.045) 32 | ) 33 | == "Umbral Wind" 34 | ) 35 | assert ( 36 | EorzeaWeather.forecast( 37 | EorzeaPlaceName("Sigmascape V4.0"), EorzeaTime(1542591400.045) 38 | ) 39 | == "Dimensional Disruption" 40 | ) 41 | assert ( 42 | EorzeaWeather.forecast( 43 | EorzeaPlaceName("Bowl of Embers"), EorzeaTime(1542591400.045) 44 | ) 45 | == "Heat Waves" 46 | ) 47 | assert ( 48 | EorzeaWeather.forecast( 49 | EorzeaPlaceName("the ruby sea"), EorzeaTime(1542591400.045) 50 | ) 51 | == "Fair Skies" 52 | ) 53 | assert ( 54 | EorzeaWeather.forecast( 55 | EorzeaPlaceName("sea of clouds"), EorzeaTime(1542591400) 56 | ) 57 | == "Fog" 58 | ) 59 | assert ( 60 | EorzeaWeather.forecast( 61 | EorzeaPlaceName( 62 | "asdfUpper aetheroacoustic exploratory sitea dsf", strict=False 63 | ), 64 | EorzeaTime(1542591400.045), 65 | strict=False, 66 | ) 67 | == "Fair Skies" 68 | ) 69 | 70 | with pytest.raises(TypeError): 71 | EorzeaWeather.forecast( 72 | EorzeaPlaceName("sea of clouds"), "1542591400" # type: ignore 73 | ) 74 | 75 | def test_field(self): 76 | weathers = EorzeaWeather.forecast( 77 | EorzeaPlaceName("Eureka Pyros"), EorzeaTime.weather_period(10) 78 | ) 79 | 80 | for weather in weathers: 81 | assert isinstance(weather, str) 82 | 83 | def test_localize(self): 84 | eureka_pagos = EorzeaPlaceName("Eureka Pagos") 85 | assert ( 86 | EorzeaWeather.forecast( 87 | eureka_pagos, EorzeaTime(1542651599.999), lang=EorzeaLang.EN 88 | ) 89 | == "Fog" 90 | ) 91 | assert ( 92 | EorzeaWeather.forecast( 93 | eureka_pagos, EorzeaTime(1542651599.999), lang=EorzeaLang.JA 94 | ) 95 | == "霧" 96 | ) 97 | assert ( 98 | EorzeaWeather.forecast( 99 | eureka_pagos, EorzeaTime(1542651599.999), lang=EorzeaLang.DE 100 | ) 101 | == "Neblig" 102 | ) 103 | assert ( 104 | EorzeaWeather.forecast( 105 | eureka_pagos, EorzeaTime(1542651599.999), lang=EorzeaLang.FR 106 | ) 107 | == "Brouillard" 108 | ) 109 | 110 | def test_cutoff_setter(self): 111 | EorzeaWeather.set_fuzzy_cutoff(50) 112 | assert EorzeaWeather.FUZZY_CUTOFF == 50 113 | 114 | with pytest.raises(ValueError): 115 | EorzeaWeather.set_fuzzy_cutoff(500) 116 | 117 | def test_get_weather_name_by_weather_index_and_lang(self): 118 | weather = EorzeaWeather.get_weather(index=10, lang=EorzeaLang.JA) 119 | assert weather == "雷雨" 120 | 121 | def test_get_weather_result_as_raw_value(self): 122 | raw_weather = EorzeaWeather.forecast( 123 | EorzeaPlaceName("Eureka Pagos"), EorzeaTime(1542651599.999), raw=True 124 | ) 125 | assert raw_weather == 4 126 | 127 | @mock.patch("EorzeaEnv.eorzea_weather._weather_rate", MockDict()) 128 | def test_weather_data_missing(self): 129 | with pytest.raises(WeatherRateDataError): 130 | EorzeaWeather.forecast( 131 | EorzeaPlaceName("Eureka Pagos"), EorzeaTime(1542651599.999), raw=True 132 | ) 133 | -------------------------------------------------------------------------------- /EorzeaEnv/eorzea_place_name.py: -------------------------------------------------------------------------------- 1 | import re 2 | from dataclasses import dataclass 3 | from typing import List, Mapping, Union 4 | 5 | from rapidfuzz import process as fuzz_process 6 | 7 | from .Data.PlaceName import PlaceInfoDict 8 | from .Data.PlaceName import place_name as _place_names 9 | from .eorzea_lang import EorzeaLang 10 | from .errors import InvalidEorzeaPlaceName 11 | 12 | FuzzyCutoff = Union[int, float] 13 | LocaleScope = Union[EorzeaLang, str] 14 | 15 | DEFAULT_CUTOFF = 80 16 | DEFAULT_LOCALE_SCOPES: List[LocaleScope] = [ 17 | EorzeaLang.EN, 18 | EorzeaLang.JA, 19 | EorzeaLang.FR, 20 | EorzeaLang.DE, 21 | EorzeaLang.KO, 22 | EorzeaLang.ZH_SC, 23 | ] 24 | 25 | 26 | @dataclass 27 | class PlaceInfo: 28 | index: int 29 | place_name: str 30 | 31 | 32 | class EorzeaPlaceName: 33 | """EorzeaPlaceName 34 | 35 | An EorzeaPlaceName instance is always a valid place name in EorzeaEnv. 36 | 37 | 38 | Parameters 39 | ---------- 40 | place_name : str 41 | should be a valid Eorzea place name. 42 | strict : bool 43 | True: strict mode. 44 | False: fuzzy mode. 45 | by default True. 46 | locale_scopes : List[LocaleScope] 47 | Locale scope for searching placename, by default full scopes. 48 | fuzzy_cutoff : int | float 49 | The cutoff score used in fuzzy mode, should be 100 <= value <= 0, by default 80. 50 | 51 | Raises 52 | ---------- 53 | :class:`EorzeaEnv.errors.InvalidEorzeaPlaceName` 54 | When place_name is invalid. 55 | """ 56 | 57 | __index: int 58 | __value: str 59 | 60 | def __init__( 61 | self, 62 | place_name: str, 63 | strict: bool = True, 64 | locale_scopes: List[LocaleScope] = DEFAULT_LOCALE_SCOPES, 65 | fuzzy_cutoff: FuzzyCutoff = DEFAULT_CUTOFF, 66 | ) -> None: 67 | place_info = _validate_place_name( 68 | place_name, 69 | is_strict=strict, 70 | fuzzy_cutoff=fuzzy_cutoff, 71 | locale_scopes=locale_scopes, 72 | ) 73 | 74 | self.__index = place_info.index 75 | self.__value = place_info.place_name 76 | 77 | @property 78 | def value(self): 79 | return self.__value 80 | 81 | @property 82 | def index(self): 83 | return self.__index 84 | 85 | @staticmethod 86 | def validate( 87 | place_name: Union[str, "EorzeaPlaceName"], 88 | strict: bool, 89 | locale_scopes: List[LocaleScope] = DEFAULT_LOCALE_SCOPES, 90 | fuzzy_cutoff: FuzzyCutoff = DEFAULT_CUTOFF, 91 | ) -> bool: 92 | if type(place_name) is EorzeaPlaceName: 93 | return True 94 | 95 | if type(place_name) is str: 96 | try: 97 | place_info = _validate_place_name( 98 | place_name, strict, locale_scopes, fuzzy_cutoff 99 | ) 100 | return bool(place_info) 101 | except InvalidEorzeaPlaceName: 102 | return False 103 | 104 | return False 105 | 106 | def __str__(self): 107 | return self.value 108 | 109 | def __repr__(self) -> str: 110 | return f"{self.__class__.__name__}('{self.value}')" 111 | 112 | def __eq__(self, that: object) -> bool: 113 | if isinstance(that, EorzeaPlaceName): 114 | return that.index == self.index and that.value == self.value 115 | 116 | return False 117 | 118 | 119 | def _validate_place_name( 120 | place_name: str, 121 | is_strict: bool, 122 | locale_scopes: List[LocaleScope], 123 | fuzzy_cutoff: FuzzyCutoff, 124 | ) -> PlaceInfo: 125 | if type(place_name) is not str: 126 | raise TypeError( 127 | f"place_name should be `str`. ({place_name} is {type(place_name)})" 128 | ) 129 | if fuzzy_cutoff > 100 or fuzzy_cutoff < 0: 130 | raise ValueError("Cutoff value should be in 0-100.") 131 | 132 | possible_place_name = None 133 | place_name = place_name.lower() 134 | place_name = re.sub("^the ", "", place_name) 135 | place_names_reference = _bulid_reference_by_locales(locale_scopes) 136 | 137 | if is_strict: 138 | place_info = place_names_reference.get(place_name) 139 | if place_info: 140 | return PlaceInfo(**place_info) 141 | 142 | else: 143 | result = fuzz_process.extractOne( 144 | place_name, place_names_reference.keys(), score_cutoff=fuzzy_cutoff 145 | ) 146 | 147 | if result: 148 | possible_place_name, score, index = result 149 | place_info = place_names_reference.get(possible_place_name) 150 | if place_info: 151 | return PlaceInfo(**place_info) 152 | 153 | raise InvalidEorzeaPlaceName(place_name=place_name, is_strict=is_strict) 154 | 155 | 156 | def _bulid_reference_by_locales( 157 | locales: List[LocaleScope], 158 | ) -> Mapping[str, PlaceInfoDict]: 159 | dictionary: Mapping[str, PlaceInfoDict] = {} 160 | for locale in locales: 161 | dictionary.update(_place_names[locale]) # type: ignore 162 | 163 | return dictionary 164 | -------------------------------------------------------------------------------- /EorzeaEnv/eorzea_weather.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | from typing import Any, Iterable, List, Literal, Union, overload 3 | 4 | from numpy import uint32 5 | 6 | from .Data.TerritoryWeather import territory_weather as _territory_weather 7 | from .Data.Weather import weather as _weather 8 | from .Data.WeatherRate import weather_rate as _weather_rate 9 | from .eorzea_lang import EorzeaLang 10 | from .eorzea_place_name import EorzeaPlaceName 11 | from .eorzea_time import EorzeaTime 12 | from .errors import WeatherRateDataError 13 | 14 | Lang = Union[Literal["en", "ja", "de", "fr", "ko", "cn"], EorzeaLang] 15 | ValidPlaceName = Union[str, EorzeaPlaceName] 16 | Timestamp = Union[EorzeaTime, float, int] 17 | 18 | 19 | class EorzeaWeather: 20 | """ 21 | EoreaWeather 22 | """ 23 | 24 | FUZZY_CUTOFF: Union[int, float] = 80 25 | 26 | @classmethod 27 | def set_fuzzy_cutoff(cls, cutoff: Union[int, float]): 28 | if cutoff > 100 or cutoff < 0: 29 | raise ValueError("Cutoff value should be in 0-100.") 30 | cls.FUZZY_CUTOFF = cutoff 31 | 32 | @overload 33 | @classmethod 34 | def forecast( 35 | cls, 36 | place_name: ValidPlaceName, 37 | timestamp: Timestamp, 38 | *, 39 | lang: Lang = EorzeaLang.EN, 40 | strict: bool = True, 41 | raw: Literal[False] = False, 42 | ) -> str: ... 43 | 44 | @overload 45 | @classmethod 46 | def forecast( 47 | cls, 48 | place_name: ValidPlaceName, 49 | timestamp: Timestamp, 50 | *, 51 | lang: Lang = EorzeaLang.EN, 52 | strict: bool = True, 53 | raw: Literal[True], 54 | ) -> int: ... 55 | 56 | @overload 57 | @classmethod 58 | def forecast( 59 | cls, 60 | place_name: ValidPlaceName, 61 | timestamp: Iterable[Timestamp], 62 | *, 63 | lang: Lang = EorzeaLang.EN, 64 | strict: bool = True, 65 | raw: Literal[False] = False, 66 | ) -> List[str]: ... 67 | 68 | @overload 69 | @classmethod 70 | def forecast( 71 | cls, 72 | place_name: ValidPlaceName, 73 | timestamp: Iterable[Timestamp], 74 | *, 75 | lang: Lang = EorzeaLang.EN, 76 | strict: bool = True, 77 | raw: Literal[True], 78 | ) -> List[int]: ... 79 | 80 | @classmethod 81 | def forecast( 82 | cls, 83 | place_name: ValidPlaceName, 84 | timestamp: Union[Timestamp, Iterable[Timestamp]], 85 | *, 86 | lang: Lang = EorzeaLang.EN, 87 | strict: bool = True, 88 | raw: bool = False, 89 | ): 90 | """Forecast Eorzea weather by place 91 | 92 | Parameters 93 | ---------- 94 | place_name : Union[str, EorzeaPlaceName] 95 | a valid Eorzea place name 96 | timestamp : Union[ 97 | int, 98 | float, 99 | EorzeaTime, 100 | Iterable[Union[int, float, EorzeaTime]] 101 | ] 102 | unix timestamp or EorzeaTime instance. 103 | int and float type supporting would be removed from 2.5.0 104 | lang : Lang, optional 105 | Recommend use `EorzeaEnv.EorzeaLang` 106 | valid lang from ffxiv , by default "en" 107 | strict : bool, optional 108 | option of search mode, by default True 109 | + `True` for strict mode 110 | + `False` for fuzzy mode 111 | raw : bool, optional 112 | option for return raw weather value instead of weather name. 113 | 114 | Returns 115 | ------- 116 | Union[str, List[str], int, List[int]] 117 | result of forecast 118 | 119 | Raises 120 | ------- 121 | EorzeaEnv.errors.InvalidEorzeaPlaceName 122 | When place_name is invalid. 123 | """ 124 | ... 125 | if type(place_name) is str: 126 | warnings.warn( 127 | "place_name in `str` is deprecated from 2.5.0." 128 | " Please use the EorzeaPlaceName instead.", 129 | DeprecationWarning, 130 | ) 131 | place_name = EorzeaPlaceName( 132 | place_name, strict, fuzzy_cutoff=cls.FUZZY_CUTOFF 133 | ) 134 | 135 | assert type(place_name) is EorzeaPlaceName 136 | weather_rate = _territory_weather[place_name.index] 137 | 138 | def make_result(timestamp: EorzeaTime): 139 | target = _calculate_forecast_target(timestamp) 140 | result = _generate_result(target, weather_rate) 141 | if not raw: 142 | result = cls.get_weather(result, lang) 143 | assert result 144 | return result 145 | 146 | if isinstance(timestamp, Iterable): 147 | results = [] 148 | 149 | for t in timestamp: 150 | t = _ensure_timestamp(t) 151 | result = make_result(t) 152 | results.append(result) 153 | 154 | return results 155 | 156 | timestamp = _ensure_timestamp(timestamp) 157 | result = make_result(timestamp) 158 | return result 159 | 160 | @staticmethod 161 | def get_weather(index: int, lang: Lang): 162 | return _weather[index][lang] 163 | 164 | 165 | def _ensure_timestamp(timestamp: Any) -> EorzeaTime: 166 | if type(timestamp) is EorzeaTime: 167 | return timestamp 168 | if type(timestamp) in (float, int): 169 | warnings.warn( 170 | "timestamp in float and int type is deprecated." 171 | " It will be unsupported at 2.5.0. Please use EorzeaTime instead.", 172 | DeprecationWarning, 173 | ) 174 | return EorzeaTime(timestamp=timestamp) 175 | raise TypeError("timestamp should be type of int, float, EorzeaTime.") 176 | 177 | 178 | def _generate_result(target: int, weather_rate: int) -> int: 179 | for rate, weather in _weather_rate[weather_rate]: 180 | if target < rate: 181 | return weather 182 | 183 | raise WeatherRateDataError( 184 | "No matched rate in data. Please contact with developer." 185 | ) 186 | 187 | 188 | def _calculate_forecast_target(the_time: EorzeaTime) -> int: 189 | """ 190 | Thanks to Rogueadyn's SaintCoinach library for this calculation 191 | -------------- 192 | [1] Do the magic 'cause for calculations 193 | 194 | [2] 16:00 is 0, 00:00 is 8 and 08:00 is 16. 195 | 196 | [3] Take Eorzea days since unix epoch. 197 | 198 | Parameters 199 | ---------- 200 | the_time : EorzeaTime 201 | time to calculate the target. 202 | 203 | Returns 204 | ------- 205 | int 206 | weather period start 207 | """ 208 | 209 | ts = the_time.get_unix_time() 210 | 211 | bell = ts / 175 212 | increment = uint32(bell + 8 - (bell % 8)) % 24 213 | total_days = uint32(ts / 4200) 214 | calc_base = total_days * 0x64 + increment 215 | step1 = uint32(calc_base << 0xB) ^ calc_base 216 | step2 = uint32(step1 >> 8) ^ step1 217 | return int(step2 % 100) 218 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Pypi](https://img.shields.io/pypi/v/eorzeaenv.svg?style=flat-square)](https://pypi.org/project/EorzeaEnv/) 2 | [![Pypi](https://img.shields.io/pypi/pyversions/eorzeaenv.svg?style=flat-square)](https://pypi.org/project/EorzeaEnv/) 3 | [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FEltonChou%2FEorzeaEnv%2Fbadge&style=flat-square)](https://github.com/EltonChou/EorzeaEnv/actions) 4 | ![PyPI - Downloads](https://img.shields.io/pypi/dm/EorzeaEnv?style=flat-square) 5 | [![codecov](https://codecov.io/gh/EltonChou/EorzeaEnv/branch/master/graph/badge.svg?token=U9US0CQUTI)](https://codecov.io/gh/EltonChou/EorzeaEnv) 6 | 7 | # EorzeaEnv 8 | 9 | + [CHANGELOG](https://github.com/EltonChou/EorzeaEnv/blob/master/CHANGELOG.md) 10 | 11 | ## Installation 12 | ``` 13 | pip install eorzeaenv 14 | ``` 15 | 16 | ## Usage 17 | ```py 18 | from EorzeaEnv import EorzeaLang, EorzeaTime, EorzeaWeather, EorzeaPlaceName 19 | ``` 20 | 21 | ### Eorzea Language enum 22 | ```py 23 | support_langs = [ 24 | EorzeaLang.EN, 25 | EorzeaLang.JA, 26 | EorzeaLang.DE, 27 | EorzeaLang.FR, 28 | EorzeaLang.ZH_SC, 29 | EorzeaLang.KO, 30 | ] 31 | ``` 32 | 33 | ### Eorzea Time 34 | 35 | ```sh 36 | >>> EorzeaTime.now() 37 | 'EorzeaTime(Sixth Embral Moon, 11, 21, 56, Phase:0.50, Althyk)' 38 | 39 | >>> EorzeaTime.now().moon 40 | 'Sixth Embral Moon' 41 | 42 | >>> EorzeaTime.now().sun 43 | 11 44 | 45 | >>> EorzeaTime.now().hour 46 | 21 47 | 48 | >>> EorzeaTime.now().minute 49 | 56 50 | 51 | >>> EorzeaTime.now().phase 52 | 0.50 53 | 54 | >>> EorzeaTime.now().guardian 55 | 'Althyk' 56 | ``` 57 | + Get the unix timestamp (int not float) 58 | ```sh 59 | >>> EorzeaTime.now().get_unix_time() 60 | 1661114514 61 | ``` 62 | + Get the eorzea timestamp (int not float) 63 | ```sh 64 | >>> EorzeaTime.now().get_eorzea_time() 65 | 34177649220 66 | ``` 67 | 68 | ### Weather Forecast 69 | + Using period as tuple or list 70 | ```python 71 | # defalut step value is 5 72 | # This method return a generator if you need to re-use it save the values as `tuple` or `list`. 73 | t = tuple(EorzeaTime.weather_period(step=3)) 74 | 75 | # Use EorzeaPlaceName to ensure the place is valid or 76 | # you can directly pass the place string to forecast. 77 | place_name = EorzeaPlaceName('Eureka Pyros') 78 | 79 | # Defalut lang is 'en' 80 | # Defalut strict is `True` for strict mode `False` for fuzzy mode. 81 | # eg. `eurekaa puros` is valid in fuzzy mode. 82 | 83 | # In fuzzy mode, you can set the cutoff score to prevent unexpected place name to be passed. 84 | # default value is 80. (100 >= value >= 0) 85 | EorzeaWeather.set_fuzzy_cutoff(95) 86 | 87 | weather_en = EorzeaWeather.forecast(place_name, t, strict=True) 88 | weather_ja = EorzeaWeather.forecast(place_name, t, lang=EorzeaLang.JA, strict=True) 89 | weather_de = EorzeaWeather.forecast(place_name, t, lang=EorzeaLang.DE, strict=True) 90 | weather_fr = EorzeaWeather.forecast(place_name, t, lang=EorzeaLang.FR, strict=True) 91 | ``` 92 | ```sh 93 | >>> print(weather_en) 94 | ['Thunder', 'Snow', 'Blizzards'] 95 | 96 | >>> print(weather_ja) 97 | ['雷', '雪', '吹雪'] 98 | 99 | >>> print(weather_de) 100 | ['Gewittrig', 'Schnee', 'Schneesturm'] 101 | 102 | >>> print(weather_fr) 103 | ['Orages', 'Neige', 'Blizzard'] 104 | ``` 105 | + Using period in for-loop 106 | ```py 107 | weather_en = [] 108 | for t in EorzeaTime.weather_period(step=3): 109 | w = EorzeaWeather.forecast('Eureka Pyros', t) 110 | weather_en.append(w) 111 | ``` 112 | ```sh 113 | >>> print(weather_en) 114 | ['Thunder', 'Snow', 'Blizzards'] 115 | ``` 116 | + Provide a desired base time to calculate. 117 | ```py 118 | for t in EorzeaTime.weather_period(step=3, from_=datetime(2025, 10, 25).timestamp()): 119 | w = EorzeaWeather.forecast('Eureka Pyros', t) 120 | print(w) 121 | ``` 122 | + Using period generator directly 123 | ```py 124 | weathers = EorzeaWeather.forecast('Eureka Pyros', EorzeaTime.weather_period(step=3)) 125 | ``` 126 | ```sh 127 | >>> print(weathers) 128 | ['Thunder', 'Snow', 'Blizzards'] 129 | ``` 130 | 131 | ### Eorzea place name 132 | 133 | An instance of EorzeaPlaceName would be always a valid place name in this pacakge. 134 | 135 | An invalid place name will raises `InvalidEorzeaPlaceName` error. 136 | 137 | ```py 138 | place_name = EorzeaPlaceName( 139 | 'The Ruby Sea', 140 | # `False` to fuzzy mode, default is `True` 141 | strict=True, 142 | # Stricted scope for validation of place name. 143 | # default is all supports locale. 144 | locale_scopes=[ 145 | EorzeaLang.EN, 146 | EorzeaLang.JA, 147 | EorzeaLang.FR, 148 | EorzeaLang.DE], 149 | # Used in fuzzy mode to cut-off the result under the score. 150 | # default is `80`. 151 | fuzzy_cutoff=80 152 | ) 153 | ``` 154 | ```sh 155 | >>> place_name 156 | EorrzeaPlaceName('The Ruby Sea') 157 | 158 | >>> print(place_name) 159 | 'The Ruby Sea` 160 | ``` 161 | 162 | Belowings are valid place names in strict mode with full locale scopes (default settings). 163 | ```py 164 | EorzeaPlaceName('The Ruby Sea') # valid `The Ruby Sea` 165 | EorzeaPlaceName('the ruby sea') # valid `The Ruby Sea` 166 | EorzeaPlaceName('ruby sea') # valid `The Ruby Sea` 167 | EorzeaPlaceName('rubinsee') # valid `Rubinsee` 168 | EorzeaPlaceName('紅玉海') # valid `紅玉海` 169 | ``` 170 | 171 | With stricted scopes. 172 | ```py 173 | scopes = [EorzeaLang.JA, EorzeaLang.DE] 174 | 175 | EorzeaPlaceName('The Ruby Sea', locale_scopes=scopes) # raises error 176 | EorzeaPlaceName('the ruby sea', locale_scopes=scopes) # raises error 177 | EorzeaPlaceName('ruby sea', locale_scopes=scopes) # raises error 178 | EorzeaPlaceName('rubinsee', locale_scopes=scopes) # valid `Rubinsee` 179 | EorzeaPlaceName('紅玉海', locale_scopes=scopes) # valid `紅玉海` 180 | ``` 181 | 182 | In fuzzy mode. 183 | ```py 184 | EorzeaPlaceName('the ruby see', strict=False) # valid `The Ruby Sea` 185 | EorzeaPlaceName('ruby see', strict=False) # valid `The Ruby Sea` 186 | EorzeaPlaceName('rubisee', strict=False) # valid `Rubinsee` 187 | EorzeaPlaceName('紅玉貝', strict=False) # raises error 188 | EorzeaPlaceName('紅玉貝', strict=False, fuzzy_cutoff=66) # valid `紅玉海` 189 | ``` 190 | 191 | ### Eorzea rainbow predict 192 | 193 | Use EorzeaRainbow to predict when will the rainbow appears. 194 | 195 | ```py 196 | from datetime import datetime 197 | 198 | from EorzeaEnv import EorzeaPlaceName, EorzeaRainbow, EorzeaTime, EorzeaWeather 199 | 200 | rainbow_times: list[datetime] = [] 201 | 202 | place = EorzeaPlaceName("東ラノシア") 203 | the_rainbow = EorzeaRainbow(place_name=place) 204 | 205 | 206 | for t in EorzeaTime.weather_period(step='inf'): 207 | the_rainbow.append(t, EorzeaWeather.forecast(place, t, raw=True)) 208 | if the_rainbow.is_appear: 209 | rainbow_times.append(datetime.fromtimestamp(t)) 210 | if len(rainbow_times) == 20: 211 | break 212 | 213 | print(rainbow_times) 214 | ``` 215 | 216 | ### Errors 217 | ```py 218 | from EorzeaEnv.errors import \ 219 | EorzeaEnvError, \ 220 | InvalidEorzeaPlaceName, \ 221 | WeatherRateDataError 222 | ``` 223 | 224 | ``` 225 | Exception 226 | |- EorzeaEnvError 227 | |- InvalidEorzeaPlaceName 228 | |- WeatherRateDataError 229 | ``` 230 | 231 | ## Thanks 232 | - [Rogueadyn-SaintCoinach](https://github.com/Rogueadyn/SaintCoinach) 233 | -------------------------------------------------------------------------------- /EorzeaEnv/eorzea_time.py: -------------------------------------------------------------------------------- 1 | import math 2 | from datetime import datetime, timezone 3 | from time import time as _time 4 | from typing import Iterator, Literal, Optional, Union 5 | 6 | _EORZEA_TIME_CONST = 3600.0 / 175.0 7 | _LOCAL_WEATHER_INTERVAL = 1400 8 | # _EROZEA_WEATHER_INTERVAL = 28800 9 | _DATETIME_ZERO = datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc) 10 | _GUARDIANS = ( 11 | "Halone", 12 | "Menphina", 13 | "Thaliak", 14 | "Nymeia", 15 | "Llymlaen", 16 | "Oschon", 17 | "Byregot", 18 | "Rhalgr", 19 | "Azeyma", 20 | "Nald'thal", 21 | "Nophica", 22 | "Althyk", 23 | ) 24 | _MOON_PREFIXS = ("First", "Second", "Third", "Fourth", "Fifth", "Sixth") 25 | 26 | 27 | class EorzeaTime: 28 | """ 29 | EorzeaTime 30 | """ 31 | 32 | _bell: int 33 | _minute: int 34 | _moon: int 35 | _sun: int 36 | _year: int 37 | 38 | _last_now_update: int = int(round(_time())) 39 | _now: Optional["EorzeaTime"] = None 40 | 41 | def __init__(self, timestamp: Optional[float] = None): 42 | ts = timestamp or _time() 43 | et = ts * _EORZEA_TIME_CONST 44 | minutes = et / 60 45 | bells = minutes / 60 46 | suns = bells / 24 47 | moons = suns / 32 48 | years = moons / 12 49 | 50 | self._minute = int(minutes % 60) 51 | self._bell = int(bells % 24) 52 | self._sun = int(suns % 32) + 1 53 | self._moon = int(moons % 12) + 1 54 | self._year = int(years) 55 | 56 | @property 57 | def year(self): 58 | return self._year 59 | 60 | @year.setter 61 | def year(self, value): 62 | self._year = value 63 | 64 | @property 65 | def moon(self): 66 | return self._moon 67 | 68 | @moon.setter 69 | def moon(self, value): 70 | self._moon = value 71 | while self._moon < 1: 72 | self._moon += 12 73 | self.year = self.year - 1 74 | 75 | while self._moon > 12: 76 | self._moon -= 12 77 | self.year = self.year + 1 78 | 79 | @property 80 | def sun(self): 81 | return self._sun 82 | 83 | @sun.setter 84 | def sun(self, value): 85 | self._sun = value 86 | while self._sun < 1: 87 | self._sun += 32 88 | self.moon = self.moon - 1 89 | 90 | while self._sun > 32: 91 | self._sun -= 32 92 | self.moon = self.moon + 1 93 | 94 | @property 95 | def hour(self): 96 | return self.bell 97 | 98 | @property 99 | def bell(self): 100 | return self._bell 101 | 102 | @bell.setter 103 | def bell(self, value): 104 | self._bell = value 105 | while self._bell < 0: 106 | self._bell += 24 107 | self.sun = self.sun - 1 108 | 109 | while self._bell >= 24: 110 | self._bell -= 24 111 | self.sun = self.sun + 1 112 | 113 | @property 114 | def minute(self): 115 | return self._minute 116 | 117 | @minute.setter 118 | def minute(self, value): 119 | self._minute = value 120 | while self._minute < 0: 121 | self._minute += 60 122 | self.bell = self.bell - 1 123 | 124 | while self._minute >= 60: 125 | self._minute -= 60 126 | self.bell = self.bell + 1 127 | 128 | @property 129 | def moon_phase(self): 130 | return _calculate_phase(self.sun) 131 | 132 | @property 133 | def guardian(self): 134 | return _get_guardian_by_moon(self.moon) 135 | 136 | @property 137 | def moon_name(self): 138 | return _calculate_moon(self.moon) 139 | 140 | def get_eorzea_time(self) -> int: 141 | years = self.year 142 | moons = (years * 12) + self.moon - 1 143 | suns = (moons * 32) + self.sun - 1 144 | bells = (suns * 24) + self.bell 145 | minutes = (bells * 60) + self.minute 146 | seconds = minutes * 60 147 | 148 | return seconds 149 | 150 | def get_unix_time(self) -> int: 151 | et = self.get_eorzea_time() 152 | return round(et / _EORZEA_TIME_CONST) 153 | 154 | @classmethod 155 | def now(cls): 156 | now = _time() 157 | diff = now - cls._last_now_update 158 | if diff <= 1 and cls._now: 159 | return cls._now 160 | 161 | cls._now = cls() 162 | cls._last_now_update = int(round(now)) 163 | return cls._now 164 | 165 | @classmethod 166 | def weather_period( 167 | cls, step: Union[int, Literal["inf"]] = 5, from_: Optional[float] = None 168 | ) -> Iterator["EorzeaTime"]: 169 | """ 170 | generate weather period 171 | 172 | Parameters 173 | ---------- 174 | step : Union[int, Literal['inf']], optional 175 | quantity of period you want, by default 5. 176 | 'inf' means infinite. 177 | 178 | from_ : Optional[float] 179 | The base timestamp for calculate the weather period. 180 | 181 | Returns 182 | ------- 183 | Iterator[EorzeaTime] 184 | a generator of weather period. 185 | """ 186 | 187 | if not isinstance(step, (int, str)): 188 | raise TypeError("integer or Literal['inf'] argument required") 189 | 190 | if type(step) is str: 191 | if step != "inf": 192 | raise TypeError("integer or Literal['inf'] argument required") 193 | 194 | ts = from_ or _time() 195 | weather_start = cls(timestamp=ts - (ts % _LOCAL_WEATHER_INTERVAL)) 196 | 197 | current_step = 0 198 | while True if step == "inf" else current_step < step: 199 | yield weather_start 200 | weather_start.bell = weather_start.bell + 8 201 | current_step += 1 202 | 203 | def __repr__(self): 204 | return "{}({})".format(self.__class__.__qualname__, self.get_unix_time()) 205 | 206 | def __str__(self): 207 | return "{}({}, {}, {:02d}, {:02d}, Phase:{:.2f}, {})".format( 208 | self.__class__.__qualname__, 209 | self.moon_name, 210 | self.sun, 211 | self.hour, 212 | self.minute, 213 | self.moon_phase, 214 | self.guardian, 215 | ) 216 | 217 | def __lt__(self, that: object): 218 | if isinstance(that, self.__class__): 219 | return self.get_unix_time() < that.get_unix_time() 220 | return NotImplemented 221 | 222 | def __le__(self, that: object): 223 | if isinstance(that, self.__class__): 224 | return self.get_unix_time() <= that.get_unix_time() 225 | return NotImplemented 226 | 227 | def __eq__(self, that: object): 228 | if isinstance(that, self.__class__): 229 | return self.get_unix_time() == that.get_unix_time() 230 | return NotImplemented 231 | 232 | def __ne__(self, that: object): 233 | if isinstance(that, self.__class__): 234 | return self.get_unix_time() != that.get_unix_time() 235 | return NotImplemented 236 | 237 | def __ge__(self, that: object): 238 | if isinstance(that, self.__class__): 239 | return self.get_unix_time() >= that.get_unix_time() 240 | return NotImplemented 241 | 242 | def __gt__(self, that: object): 243 | if isinstance(that, self.__class__): 244 | return self.get_unix_time() > that.get_unix_time() 245 | return NotImplemented 246 | 247 | 248 | def _get_guardian_by_moon(moon: int) -> str: 249 | return _GUARDIANS[moon - 1] 250 | 251 | 252 | def _calculate_moon(moon: int) -> str: 253 | moon_order = _MOON_PREFIXS[math.ceil(moon / 2) - 1] 254 | moon_type = _astral_or_embral(moon) 255 | return "{} {} Moon".format(moon_order, moon_type) 256 | 257 | 258 | def _astral_or_embral(moon: int) -> str: 259 | return "Astral" if moon % 2 else "Embral" 260 | 261 | 262 | def _calculate_phase(sun: int) -> float: 263 | if sun <= 20: 264 | return 1 - int(abs(20 - sun) / 4) / 4 265 | else: 266 | return int(abs(36 - sun) / 4) / 4 267 | -------------------------------------------------------------------------------- /EorzeaEnv/Data/WeatherRate.py: -------------------------------------------------------------------------------- 1 | from typing import Mapping, Sequence, Tuple 2 | 3 | weather_rate: Mapping[int, Sequence[Tuple[int, int]]] = { 4 | 0: [(100, 2)], 5 | 1: [(5, 7), (20, 7), (30, 4), (40, 3), (55, 2), (85, 1), (100, 2)], 6 | 2: [(5, 7), (20, 7), (30, 4), (40, 3), (55, 2), (85, 1), (100, 2)], 7 | 3: [(5, 9), (20, 7), (30, 4), (40, 3), (55, 2), (85, 1), (100, 2)], 8 | 4: [(5, 9), (20, 7), (30, 4), (40, 3), (55, 2), (85, 1), (100, 2)], 9 | 5: [(5, 4), (10, 10), (25, 9), (30, 4), (40, 3), (70, 2), (100, 1)], 10 | 6: [(5, 4), (10, 8), (25, 7), (30, 4), (40, 3), (70, 2), (100, 1)], 11 | 7: [(40, 1), (60, 2), (85, 3), (95, 4), (100, 7)], 12 | 8: [(40, 1), (60, 2), (85, 3), (95, 4), (100, 7)], 13 | 9: [(40, 1), (60, 2), (85, 3), (95, 4), (100, 7)], 14 | 10: [(15, 11), (55, 1), (75, 2), (85, 3), (95, 4), (100, 7)], 15 | 11: [(40, 1), (60, 2), (70, 3), (80, 4), (85, 7), (100, 8)], 16 | 12: [(20, 14), (60, 1), (80, 2), (90, 3), (100, 4)], 17 | 13: [(5, 1), (20, 2), (50, 3), (100, 4)], 18 | 14: [(20, 3), (50, 1), (80, 2), (90, 4), (100, 7)], 19 | 15: [(20, 3), (50, 1), (80, 2), (90, 4), (100, 7)], 20 | 16: [(20, 3), (50, 1), (70, 2), (80, 5), (90, 4), (100, 7)], 21 | 17: [(20, 3), (50, 1), (70, 2), (80, 5), (90, 4), (100, 7)], 22 | 18: [(5, 4), (50, 1), (80, 2), (90, 3), (95, 7), (100, 8)], 23 | 19: [(10, 4), (40, 1), (60, 2), (80, 3), (90, 5), (100, 6)], 24 | 20: [(30, 1), (50, 2), (70, 3), (80, 4), (90, 9), (100, 10)], 25 | 21: [(20, 16), (60, 15), (70, 2), (75, 1), (90, 3), (100, 4)], 26 | 22: [(15, 3), (30, 4), (60, 17), (75, 1), (100, 2)], 27 | 23: [(100, 29)], 28 | 24: [(30, 1), (50, 2), (70, 3), (85, 4), (100, 7)], 29 | 25: [(100, 26)], 30 | 26: [(100, 28)], 31 | 27: [(100, 15)], 32 | 28: [(100, 3)], 33 | 29: [(20, 3), (50, 1), (80, 2), (90, 4), (100, 10)], 34 | 30: [(100, 27)], 35 | 31: [(100, 25)], 36 | 32: [(20, 3), (50, 1), (70, 2), (80, 2), (90, 4), (100, 7)], 37 | 33: [(40, 1), (60, 2), (85, 3), (95, 4), (100, 7)], 38 | 34: [(5, 3), (20, 7), (30, 4), (40, 3), (55, 2), (85, 1), (100, 2)], 39 | 35: [(100, 15)], 40 | 36: [(100, 5)], 41 | 37: [(100, 9)], 42 | 38: [(100, 23)], 43 | 39: [(100, 24)], 44 | 40: [(100, 4)], 45 | 41: [(100, 11)], 46 | 42: [(100, 16)], 47 | 43: [(100, 22)], 48 | 44: [(100, 36)], 49 | 45: [(100, 20)], 50 | 46: [(100, 35)], 51 | 47: [(60, 15), (70, 2), (75, 1), (90, 3), (100, 4)], 52 | 48: [(60, 15), (70, 2), (75, 1), (90, 3), (100, 4)], 53 | 49: [(20, 16), (60, 15), (70, 2), (75, 1), (90, 3), (100, 4)], 54 | 50: [(10, 3), (20, 4), (30, 9), (40, 11), (70, 1), (100, 2)], 55 | 51: [(10, 3), (20, 4), (30, 7), (40, 8), (70, 1), (100, 2)], 56 | 52: [(10, 3), (20, 6), (40, 50), (70, 1), (100, 2)], 57 | 53: [(30, 1), (60, 2), (70, 3), (80, 4), (90, 5), (100, 49)], 58 | 54: [(35, 2), (70, 3), (100, 9)], 59 | 55: [(10, 3), (20, 4), (30, 7), (40, 8), (70, 1), (100, 2)], 60 | 56: [(100, 44)], 61 | 57: [(100, 51)], 62 | 58: [(100, 1)], 63 | 59: [(15, 4), (40, 7), (100, 2)], 64 | 60: [(40, 2), (75, 4), (95, 5), (99, 49), (100, 54)], 65 | 61: [(40, 2), (60, 4), (95, 5), (99, 49), (100, 54)], 66 | 62: [(40, 2), (65, 4), (90, 5), (98, 49), (100, 54)], 67 | 63: [(100, 7)], 68 | 64: [(60, 2), (100, 7)], 69 | 65: [(50, 2), (100, 7)], 70 | 66: [(100, 60)], 71 | 67: [(35, 2), (65, 15), (85, 16), (100, 4)], 72 | 68: [(100, 14)], 73 | 69: [(100, 69)], 74 | 70: [(100, 54)], 75 | 71: [(30, 2), (60, 4), (90, 5), (100, 49)], 76 | 72: [(65, 2), (100, 7)], 77 | 73: [(65, 2), (100, 7)], 78 | 74: [(100, 17)], 79 | 75: [(100, 74)], 80 | 76: [(100, 84)], 81 | 77: [(100, 80)], 82 | 78: [(15, 1), (60, 2), (80, 3), (90, 4), (100, 9)], 83 | 79: [(15, 1), (60, 2), (80, 3), (90, 4), (100, 9)], 84 | 80: [(10, 1), (60, 2), (75, 3), (85, 4), (95, 5), (100, 11)], 85 | 81: [(20, 1), (60, 2), (80, 3), (90, 4), (100, 10)], 86 | 82: [(10, 7), (20, 4), (40, 3), (80, 2), (100, 1)], 87 | 83: [(10, 9), (20, 5), (35, 3), (75, 2), (100, 1)], 88 | 84: [(5, 8), (15, 7), (25, 4), (40, 3), (80, 2), (100, 1)], 89 | 85: [(5, 6), (10, 5), (17, 7), (25, 4), (35, 3), (75, 2), (100, 1)], 90 | 86: [(100, 50)], 91 | 87: [(100, 82)], 92 | 88: [(100, 79)], 93 | 89: [(100, 88)], 94 | 90: [(100, 2)], 95 | 91: [(30, 2), (60, 6), (90, 8), (100, 15)], 96 | 92: [(100, 77)], 97 | 93: [(100, 92)], 98 | 94: [(10, 2), (28, 4), (46, 14), (64, 15), (82, 9), (100, 16)], 99 | 95: [(100, 101)], 100 | 96: [(10, 2), (28, 14), (46, 9), (64, 16), (82, 49), (100, 15)], 101 | 97: [(100, 12)], 102 | 98: [(100, 102)], 103 | 99: [(100, 113)], 104 | 100: [(12, 2), (34, 8), (56, 17), (78, 10), (100, 15)], 105 | 101: [(100, 119)], 106 | 102: [(100, 118)], 107 | 103: [(100, 122)], 108 | 104: [(100, 125)], 109 | 105: [(100, 120)], 110 | 106: [(20, 1), (60, 2), (75, 3), (85, 4), (95, 7), (100, 10)], 111 | 107: [(10, 6), (20, 7), (30, 4), (45, 3), (85, 2), (100, 1)], 112 | 108: [(45, 2), (60, 3), (70, 11), (80, 14), (100, 1)], 113 | 109: [(10, 7), (20, 4), (35, 3), (45, 10), (60, 1), (100, 2)], 114 | 110: [(10, 4), (20, 7), (30, 49), (45, 1), (85, 2), (100, 3)], 115 | 111: [(20, 3), (80, 2), (100, 1)], 116 | 112: [(20, 1), (60, 2), (75, 3), (85, 4), (95, 7), (100, 10)], 117 | 113: [(10, 6), (20, 7), (30, 4), (45, 3), (85, 2), (100, 1)], 118 | 114: [(100, 105)], 119 | 115: [(100, 10)], 120 | 116: [(100, 127)], 121 | 117: [(50, 2), (80, 5), (90, 7), (95, 6), (100, 4)], 122 | 118: [(50, 1), (100, 2)], 123 | 119: [(45, 2), (63, 3), (80, 4), (95, 7), (100, 8)], 124 | 120: [(40, 2), (55, 3), (70, 4), (95, 5), (100, 6)], 125 | 121: [(35, 2), (50, 3), (65, 4), (85, 15), (100, 16)], 126 | 122: [(82, 2), (87, 3), (92, 4), (97, 11), (100, 14)], 127 | 123: [(100, 138)], 128 | 124: [(52, 2), (64, 7), (76, 5), (88, 9), (100, 11)], 129 | 125: [(100, 137)], 130 | 126: [(100, 147)], 131 | 127: [(50, 2), (65, 3), (80, 4), (95, 9), (100, 10)], 132 | 128: [(40, 2), (58, 3), (75, 4), (93, 7), (100, 8)], 133 | 129: [(44, 2), (59, 3), (73, 4), (93, 9), (100, 10)], 134 | 130: [(60, 2), (70, 7), (80, 5), (90, 9), (100, 15)], 135 | 131: [(15, 1), (60, 2), (85, 3), (100, 7)], 136 | 132: [(10, 4), (20, 7), (25, 8), (40, 1), (80, 2), (100, 3)], 137 | 133: [(45, 15), (50, 9), (55, 7), (60, 4), (85, 3), (95, 2), (100, 1)], 138 | 134: [(25, 3), (40, 49), (85, 2), (100, 1)], 139 | 135: [(15, 49), (30, 148), (100, 2)], 140 | 136: [(15, 149), (85, 2), (100, 49)], 141 | 137: [(10, 1), (50, 2), (70, 3), (85, 4), (100, 15)], 142 | 138: [(10, 4), (25, 7), (40, 1), (80, 2), (100, 3)], 143 | 139: [(100, 151)], 144 | 140: [(100, 156)], 145 | 141: [(100, 150)], 146 | 142: [(5, 15), (25, 2), (65, 1), (80, 3), (90, 4)], 147 | 143: [(100, 160)], 148 | 144: [(100, 161)], 149 | 145: [(100, 157)], 150 | 146: [(100, 128)], 151 | 147: [(100, 162)], 152 | 148: [(25, 1), (70, 2), (80, 3), (90, 7), (95, 4), (100, 8)], 153 | 149: [(100, 171)], 154 | 150: [(100, 77)], 155 | 151: [(50, 2), (65, 3), (80, 4), (95, 7), (100, 10)], 156 | 152: [(50, 2), (65, 3), (80, 4), (95, 7), (100, 8)], 157 | 153: [(40, 2), (55, 3), (70, 4), (90, 5), (100, 9)], 158 | 154: [(50, 2), (65, 3), (80, 4), (95, 7), (100, 8)], 159 | 155: [(100, 179)], 160 | 156: [(100, 10)], 161 | 157: [(100, 183)], 162 | 158: [(100, 181)], 163 | 159: [(40, 1), (80, 2), (85, 3), (95, 4), (100, 7)], 164 | 160: [(20, 1), (50, 2), (70, 3), (80, 4), (90, 5), (100, 15)], 165 | 161: [(25, 1), (60, 2), (75, 3), (85, 4), (95, 7), (100, 8)], 166 | 162: [(15, 1), (55, 2), (70, 3), (85, 4), (100, 7)], 167 | 163: [(100, 2)], 168 | 164: [(5, 1), (50, 2), (70, 3), (85, 11), (100, 6)], 169 | 165: [(5, 2), (25, 3), (40, 4), (45, 7), (50, 10), (100, 50)], 170 | 166: [(10, 7), (20, 4), (40, 3), (100, 2)], 171 | 167: [(100, 193)], 172 | 168: [(10, 1), (55, 2), (70, 3), (80, 7), (95, 190), (100, 191)], 173 | 169: [(15, 148), (85, 2), (100, 49)], 174 | 170: [(100, 198)], 175 | 171: [(60, 2), (80, 3), (100, 7)], 176 | } 177 | -------------------------------------------------------------------------------- /EorzeaEnv/Data/TerritoryWeather.py: -------------------------------------------------------------------------------- 1 | territory_weather = { 2 | 0: 0, 3 | 28: 14, 4 | 29: 15, 5 | 30: 16, 6 | 31: 17, 7 | 32: 18, 8 | 33: 19, 9 | 34: 20, 10 | 35: 0, 11 | 36: 37, 12 | 37: 0, 13 | 40: 7, 14 | 41: 8, 15 | 42: 9, 16 | 43: 10, 17 | 44: 11, 18 | 45: 12, 19 | 46: 13, 20 | 47: 0, 21 | 48: 0, 22 | 49: 0, 23 | 50: 41, 24 | 52: 1, 25 | 53: 2, 26 | 54: 3, 27 | 55: 4, 28 | 56: 5, 29 | 57: 6, 30 | 58: 0, 31 | 59: 0, 32 | 61: 0, 33 | 63: 21, 34 | 64: 0, 35 | 65: 0, 36 | 67: 22, 37 | 112: 0, 38 | 125: 40, 39 | 128: 28, 40 | 152: 0, 41 | 153: 0, 42 | 230: 28, 43 | 260: 0, 44 | 346: 0, 45 | 347: 0, 46 | 350: 24, 47 | 351: 14, 48 | 354: 0, 49 | 356: 0, 50 | 357: 25, 51 | 358: 29, 52 | 359: 23, 53 | 360: 30, 54 | 361: 26, 55 | 379: 0, 56 | 386: 0, 57 | 392: 21, 58 | 401: 42, 59 | 404: 42, 60 | 406: 28, 61 | 418: 74, 62 | 425: 14, 63 | 426: 34, 64 | 427: 33, 65 | 430: 0, 66 | 457: 0, 67 | 459: 26, 68 | 462: 0, 69 | 464: 0, 70 | 465: 0, 71 | 466: 0, 72 | 467: 0, 73 | 468: 0, 74 | 469: 0, 75 | 477: 31, 76 | 478: 0, 77 | 481: 0, 78 | 493: 0, 79 | 496: 59, 80 | 548: 0, 81 | 617: 0, 82 | 694: 0, 83 | 695: 0, 84 | 733: 0, 85 | 1100: 0, 86 | 1101: 0, 87 | 1102: 0, 88 | 1103: 0, 89 | 1104: 0, 90 | 1105: 0, 91 | 1106: 0, 92 | 1107: 0, 93 | 1108: 0, 94 | 1157: 0, 95 | 1158: 0, 96 | 1159: 0, 97 | 1227: 0, 98 | 1228: 0, 99 | 1229: 0, 100 | 1301: 0, 101 | 1302: 28, 102 | 1303: 0, 103 | 1304: 0, 104 | 1305: 0, 105 | 1334: 38, 106 | 1363: 43, 107 | 1374: 0, 108 | 1377: 0, 109 | 1390: 0, 110 | 1399: 46, 111 | 1406: 0, 112 | 1407: 0, 113 | 1408: 0, 114 | 1409: 44, 115 | 1410: 0, 116 | 1429: 0, 117 | 1431: 0, 118 | 1484: 0, 119 | 1500: 0, 120 | 1628: 0, 121 | 1633: 0, 122 | 1638: 0, 123 | 1645: 0, 124 | 1647: 71, 125 | 1660: 0, 126 | 1664: 65, 127 | 1665: 0, 128 | 1708: 0, 129 | 1714: 0, 130 | 1723: 0, 131 | 1731: 0, 132 | 1740: 67, 133 | 1742: 0, 134 | 1759: 0, 135 | 1792: 40, 136 | 1793: 0, 137 | 1799: 0, 138 | 1800: 0, 139 | 1801: 0, 140 | 1802: 0, 141 | 1803: 0, 142 | 1804: 0, 143 | 1811: 0, 144 | 1812: 0, 145 | 1813: 0, 146 | 1814: 0, 147 | 1815: 0, 148 | 1816: 0, 149 | 1834: 0, 150 | 1835: 0, 151 | 1841: 0, 152 | 1847: 0, 153 | 1853: 0, 154 | 1857: 40, 155 | 1868: 58, 156 | 1887: 0, 157 | 1893: 0, 158 | 1894: 0, 159 | 1895: 0, 160 | 1960: 36, 161 | 2000: 50, 162 | 2001: 51, 163 | 2002: 52, 164 | 2031: 28, 165 | 2034: 0, 166 | 2036: 0, 167 | 2038: 0, 168 | 2041: 0, 169 | 2050: 28, 170 | 2081: 57, 171 | 2082: 55, 172 | 2083: 0, 173 | 2088: 0, 174 | 2090: 0, 175 | 2100: 53, 176 | 2101: 54, 177 | 2130: 0, 178 | 2147: 0, 179 | 2148: 0, 180 | 2151: 28, 181 | 2178: 56, 182 | 2179: 0, 183 | 2181: 37, 184 | 2200: 49, 185 | 2214: 42, 186 | 2256: 66, 187 | 2265: 69, 188 | 2266: 75, 189 | 2270: 0, 190 | 2271: 0, 191 | 2272: 0, 192 | 2273: 0, 193 | 2284: 92, 194 | 2294: 0, 195 | 2295: 77, 196 | 2296: 0, 197 | 2297: 36, 198 | 2298: 0, 199 | 2299: 87, 200 | 2300: 47, 201 | 2301: 48, 202 | 2310: 0, 203 | 2313: 0, 204 | 2320: 0, 205 | 2327: 58, 206 | 2335: 0, 207 | 2336: 0, 208 | 2337: 0, 209 | 2339: 0, 210 | 2340: 0, 211 | 2354: 93, 212 | 2357: 88, 213 | 2358: 88, 214 | 2359: 88, 215 | 2360: 88, 216 | 2367: 0, 217 | 2370: 0, 218 | 2371: 0, 219 | 2372: 0, 220 | 2391: 0, 221 | 2392: 0, 222 | 2403: 78, 223 | 2404: 82, 224 | 2406: 79, 225 | 2407: 80, 226 | 2408: 81, 227 | 2409: 83, 228 | 2410: 84, 229 | 2411: 85, 230 | 2412: 82, 231 | 2413: 82, 232 | 2414: 91, 233 | 2448: 0, 234 | 2449: 26, 235 | 2450: 0, 236 | 2451: 0, 237 | 2462: 94, 238 | 2483: 0, 239 | 2485: 0, 240 | 2496: 98, 241 | 2498: 0, 242 | 2499: 0, 243 | 2510: 99, 244 | 2527: 0, 245 | 2528: 0, 246 | 2529: 0, 247 | 2530: 96, 248 | 2545: 100, 249 | 2548: 0, 250 | 2549: 0, 251 | 2586: 0, 252 | 2589: 0, 253 | 2665: 0, 254 | 2691: 0, 255 | 2707: 0, 256 | 2708: 76, 257 | 2709: 0, 258 | 2715: 76, 259 | 2717: 92, 260 | 2718: 92, 261 | 2719: 92, 262 | 2720: 92, 263 | 2725: 92, 264 | 2727: 92, 265 | 2736: 92, 266 | 2737: 92, 267 | 2762: 0, 268 | 2775: 0, 269 | 2779: 0, 270 | 2799: 0, 271 | 2801: 0, 272 | 2805: 84, 273 | 2813: 84, 274 | 2833: 0, 275 | 2847: 0, 276 | 2851: 97, 277 | 2862: 0, 278 | 2864: 0, 279 | 2927: 0, 280 | 2936: 0, 281 | 2951: 112, 282 | 2952: 113, 283 | 2953: 106, 284 | 2954: 107, 285 | 2955: 108, 286 | 2956: 109, 287 | 2957: 110, 288 | 2958: 111, 289 | 2979: 0, 290 | 2982: 0, 291 | 2985: 105, 292 | 2997: 102, 293 | 3007: 0, 294 | 3017: 0, 295 | 3018: 102, 296 | 3050: 102, 297 | 3139: 102, 298 | 3214: 0, 299 | 3215: 0, 300 | 3216: 38, 301 | 3217: 23, 302 | 3218: 103, 303 | 3219: 104, 304 | 3221: 0, 305 | 3222: 112, 306 | 3223: 0, 307 | 3225: 0, 308 | 3228: 102, 309 | 3229: 0, 310 | 3378: 117, 311 | 3385: 0, 312 | 3425: 0, 313 | 3427: 0, 314 | 3435: 47, 315 | 3442: 28, 316 | 3467: 0, 317 | 3468: 0, 318 | 3469: 0, 319 | 3470: 0, 320 | 3471: 0, 321 | 3477: 14, 322 | 3478: 0, 323 | 3486: 123, 324 | 3487: 46, 325 | 3492: 0, 326 | 3511: 125, 327 | 3534: 124, 328 | 3542: 0, 329 | 3568: 125, 330 | 3570: 0, 331 | 3571: 0, 332 | 3576: 0, 333 | 3581: 0, 334 | 3590: 0, 335 | 3595: 0, 336 | 3596: 0, 337 | 3597: 0, 338 | 3620: 0, 339 | 3635: 0, 340 | 3644: 0, 341 | 3647: 0, 342 | 3662: 130, 343 | 3663: 0, 344 | 3684: 139, 345 | 3685: 139, 346 | 3686: 116, 347 | 3689: 0, 348 | 3690: 0, 349 | 3691: 0, 350 | 3692: 0, 351 | 3693: 0, 352 | 3694: 0, 353 | 3695: 0, 354 | 3696: 0, 355 | 3706: 137, 356 | 3707: 138, 357 | 3708: 131, 358 | 3709: 132, 359 | 3710: 133, 360 | 3711: 135, 361 | 3712: 136, 362 | 3713: 134, 363 | 3736: 0, 364 | 3759: 0, 365 | 3769: 145, 366 | 3770: 0, 367 | 3783: 140, 368 | 3797: 145, 369 | 3798: 145, 370 | 3799: 157, 371 | 3817: 137, 372 | 3818: 137, 373 | 3926: 0, 374 | 4015: 141, 375 | 4022: 0, 376 | 4023: 0, 377 | 4024: 0, 378 | 4031: 147, 379 | 4032: 0, 380 | 4034: 137, 381 | 4038: 149, 382 | 4039: 138, 383 | 4040: 0, 384 | 4042: 136, 385 | 4043: 148, 386 | 4045: 149, 387 | 4098: 0, 388 | 4100: 144, 389 | 4111: 0, 390 | 4118: 28, 391 | 4135: 145, 392 | 4139: 142, 393 | 4146: 0, 394 | 4154: 0, 395 | 4167: 147, 396 | 4180: 149, 397 | 4196: 145, 398 | 4197: 149, 399 | 4198: 145, 400 | 4199: 0, 401 | 4227: 0, 402 | 4249: 145, 403 | 4250: 145, 404 | 4258: 147, 405 | 4270: 42, 406 | 4287: 0, 407 | 4288: 150, 408 | 4289: 0, 409 | 4293: 0, 410 | 4296: 149, 411 | 4297: 0, 412 | 4307: 145, 413 | 4308: 0, 414 | 4338: 74, 415 | 4358: 0, 416 | 4362: 145, 417 | 4375: 145, 418 | 4377: 114, 419 | 4380: 138, 420 | 4381: 133, 421 | 4382: 149, 422 | 4431: 149, 423 | 4441: 149, 424 | 4442: 155, 425 | 4468: 0, 426 | 4469: 0, 427 | 4480: 0, 428 | 4503: 163, 429 | 4504: 159, 430 | 4505: 160, 431 | 4506: 161, 432 | 4507: 162, 433 | 4508: 164, 434 | 4509: 165, 435 | 4510: 166, 436 | 4523: 159, 437 | 4526: 0, 438 | 4540: 159, 439 | 4602: 0, 440 | 4654: 0, 441 | 4655: 0, 442 | 4748: 165, 443 | 4749: 0, 444 | 4751: 0, 445 | 4754: 27, 446 | 4755: 0, 447 | 4757: 0, 448 | 4758: 0, 449 | 4759: 0, 450 | 4760: 0, 451 | 4909: 0, 452 | 4926: 0, 453 | 4932: 168, 454 | 4948: 0, 455 | 4949: 160, 456 | 5000: 0, 457 | 5007: 156, 458 | 5027: 0, 459 | 5102: 0, 460 | 5103: 0, 461 | 5104: 0, 462 | 5105: 150, 463 | 5114: 0, 464 | 5116: 157, 465 | 5117: 158, 466 | 5120: 0, 467 | 5121: 0, 468 | 5126: 86, 469 | 5137: 0, 470 | 5139: 0, 471 | 5153: 0, 472 | 5155: 0, 473 | 5156: 0, 474 | 5175: 0, 475 | 5176: 0, 476 | 5177: 0, 477 | 5219: 169, 478 | 5240: 150, 479 | 5266: 0, 480 | 5276: 0, 481 | 5277: 0, 482 | 5284: 0, 483 | 5297: 0, 484 | 5301: 171, 485 | } 486 | -------------------------------------------------------------------------------- /EorzeaEnv/Data/Weather.py: -------------------------------------------------------------------------------- 1 | from typing import Literal, Mapping, Optional, Union 2 | 3 | from ..eorzea_lang import EorzeaLang 4 | 5 | weather: Mapping[ 6 | int, 7 | Mapping[ 8 | Union[EorzeaLang, Literal["de", "en", "fr", "ja", "ko", "cn"]], Optional[str] 9 | ], 10 | ] = { 11 | 0: { 12 | "cn": None, 13 | "de": None, 14 | "en": None, 15 | "fr": None, 16 | "ja": None, 17 | "ko": "●설명용 날씨", 18 | }, 19 | 1: { 20 | "cn": "碧空", 21 | "de": "Klar", 22 | "en": "Clear Skies", 23 | "fr": "Dégagé", 24 | "ja": "快晴", 25 | "ko": "쾌청", 26 | }, 27 | 2: { 28 | "cn": "晴朗", 29 | "de": "Heiter", 30 | "en": "Fair Skies", 31 | "fr": "Clair", 32 | "ja": "晴れ", 33 | "ko": "맑음", 34 | }, 35 | 3: { 36 | "cn": "阴云", 37 | "de": "Wolkig", 38 | "en": "Clouds", 39 | "fr": "Couvert", 40 | "ja": "曇り", 41 | "ko": "흐림", 42 | }, 43 | 4: { 44 | "cn": "薄雾", 45 | "de": "Neblig", 46 | "en": "Fog", 47 | "fr": "Brouillard", 48 | "ja": "霧", 49 | "ko": "안개", 50 | }, 51 | 5: { 52 | "cn": "微风", 53 | "de": "Windig", 54 | "en": "Wind", 55 | "fr": "Vent", 56 | "ja": "風", 57 | "ko": "바람", 58 | }, 59 | 6: { 60 | "cn": "强风", 61 | "de": "Stürmisch", 62 | "en": "Gales", 63 | "fr": "Vents violents", 64 | "ja": "暴風", 65 | "ko": "폭풍", 66 | }, 67 | 7: { 68 | "cn": "小雨", 69 | "de": "Regnerisch", 70 | "en": "Rain", 71 | "fr": "Pluie", 72 | "ja": "雨", 73 | "ko": "비", 74 | }, 75 | 8: { 76 | "cn": "暴雨", 77 | "de": "Wolkenbruch", 78 | "en": "Showers", 79 | "fr": "Pluie torrentielle", 80 | "ja": "暴雨", 81 | "ko": "폭우", 82 | }, 83 | 9: { 84 | "cn": "打雷", 85 | "de": "Gewittrig", 86 | "en": "Thunder", 87 | "fr": "Orages", 88 | "ja": "雷", 89 | "ko": "번개", 90 | }, 91 | 10: { 92 | "cn": "雷雨", 93 | "de": "Gewitter", 94 | "en": "Thunderstorms", 95 | "fr": "Orages violents", 96 | "ja": "雷雨", 97 | "ko": "뇌우", 98 | }, 99 | 11: { 100 | "cn": "扬沙", 101 | "de": "Staubig", 102 | "en": "Dust Storms", 103 | "fr": "Tempêtes de poussière", 104 | "ja": "砂塵", 105 | "ko": "모래먼지", 106 | }, 107 | 12: { 108 | "cn": "沙尘暴", 109 | "de": "Sandsturm", 110 | "en": "Sandstorms", 111 | "fr": "Tempêtes de sable", 112 | "ja": "砂嵐", 113 | "ko": "모래폭풍", 114 | }, 115 | 13: { 116 | "cn": "高温", 117 | "de": "Heiß", 118 | "en": "Hot Spells", 119 | "fr": "Chaud", 120 | "ja": "熱波", 121 | "ko": "열파", 122 | }, 123 | 14: { 124 | "cn": "热浪", 125 | "de": "Gluthitze", 126 | "en": "Heat Waves", 127 | "fr": "Torride", 128 | "ja": "灼熱波", 129 | "ko": "작열파", 130 | }, 131 | 15: { 132 | "cn": "小雪", 133 | "de": "Schnee", 134 | "en": "Snow", 135 | "fr": "Neige", 136 | "ja": "雪", 137 | "ko": "눈", 138 | }, 139 | 16: { 140 | "cn": "暴雪", 141 | "de": "Schneesturm", 142 | "en": "Blizzards", 143 | "fr": "Blizzard", 144 | "ja": "吹雪", 145 | "ko": "눈보라", 146 | }, 147 | 17: { 148 | "cn": "妖雾", 149 | "de": "Unheimlich", 150 | "en": "Gloom", 151 | "fr": "Nébuleux", 152 | "ja": "妖霧", 153 | "ko": "요마의 안개", 154 | }, 155 | 18: { 156 | "cn": "极光", 157 | "de": "Aurora", 158 | "en": "Auroras", 159 | "fr": "Aurore", 160 | "ja": "オーロラ", 161 | "ko": "오로라", 162 | }, 163 | 19: { 164 | "cn": "黑暗", 165 | "de": "Dunkel", 166 | "en": "Darkness", 167 | "fr": "Ténèbres", 168 | "ja": "闇", 169 | "ko": "어둠", 170 | }, 171 | 20: { 172 | "cn": "绝命", 173 | "de": "Düsternis", 174 | "en": "Tension", 175 | "fr": "Désespérance", 176 | "ja": "闘気", 177 | "ko": "투기", 178 | }, 179 | 21: { 180 | "cn": "阴云", 181 | "de": "Wolkig", 182 | "en": "Clouds", 183 | "fr": "Couvert", 184 | "ja": "曇り", 185 | "ko": "흐림", 186 | }, 187 | 22: { 188 | "cn": "雷云", 189 | "de": "Wetterleuchten", 190 | "en": "Storm Clouds", 191 | "fr": "Orageux", 192 | "ja": "雷雲", 193 | "ko": "뇌운", 194 | }, 195 | 23: { 196 | "cn": "暴风雨", 197 | "de": "Tosend", 198 | "en": "Rough Seas", 199 | "fr": "Houle", 200 | "ja": "時化", 201 | "ko": "파랑", 202 | }, 203 | 24: { 204 | "cn": "暴风雨", 205 | "de": "Tosend", 206 | "en": "Rough Seas", 207 | "fr": "Houle", 208 | "ja": "時化", 209 | "ko": "파랑", 210 | }, 211 | 25: { 212 | "cn": "阴沉", 213 | "de": "Finster", 214 | "en": "Louring", 215 | "fr": "Nuageux", 216 | "ja": "曇天", 217 | "ko": "먹구름", 218 | }, 219 | 26: { 220 | "cn": "热浪", 221 | "de": "Gluthitze", 222 | "en": "Heat Waves", 223 | "fr": "Torride", 224 | "ja": "灼熱波", 225 | "ko": "작열파", 226 | }, 227 | 27: { 228 | "cn": "妖雾", 229 | "de": "Unheimlich", 230 | "en": "Gloom", 231 | "fr": "Nébuleux", 232 | "ja": "妖霧", 233 | "ko": "요마의 안개", 234 | }, 235 | 28: { 236 | "cn": "暴风", 237 | "de": "Stürmisch", 238 | "en": "Gales", 239 | "fr": "Vents violents", 240 | "ja": "暴風", 241 | "ko": "폭풍", 242 | }, 243 | 29: { 244 | "cn": "烟雾", 245 | "de": "Rauchschwaden", 246 | "en": "Eruptions", 247 | "fr": "Éruptions", 248 | "ja": "噴煙", 249 | "ko": "분화", 250 | }, 251 | 30: { 252 | "cn": "晴朗", 253 | "de": "Heiter", 254 | "en": "Fair Skies", 255 | "fr": "Clair", 256 | "ja": "晴れ", 257 | "ko": "맑음", 258 | }, 259 | 31: { 260 | "cn": "晴朗", 261 | "de": "Heiter", 262 | "en": "Fair Skies", 263 | "fr": "Clair", 264 | "ja": "晴れ", 265 | "ko": "맑음", 266 | }, 267 | 32: { 268 | "cn": "晴朗", 269 | "de": "Heiter", 270 | "en": "Fair Skies", 271 | "fr": "Clair", 272 | "ja": "晴れ", 273 | "ko": "맑음", 274 | }, 275 | 33: { 276 | "cn": "晴朗", 277 | "de": "Heiter", 278 | "en": "Fair Skies", 279 | "fr": "Clair", 280 | "ja": "晴れ", 281 | "ko": "맑음", 282 | }, 283 | 34: { 284 | "cn": "晴朗", 285 | "de": "Heiter", 286 | "en": "Fair Skies", 287 | "fr": "Clair", 288 | "ja": "晴れ", 289 | "ko": "맑음", 290 | }, 291 | 35: { 292 | "cn": "极光", 293 | "de": "Blendend", 294 | "en": "Irradiance", 295 | "fr": "Rayonnement", 296 | "ja": "極光", 297 | "ko": "극광", 298 | }, 299 | 36: { 300 | "cn": "辉核", 301 | "de": "Kernstrahlung", 302 | "en": "Core Radiation", 303 | "fr": "Radiations du Cœur", 304 | "ja": "龍核", 305 | "ko": "용핵", 306 | }, 307 | 37: { 308 | "cn": "辉核", 309 | "de": "Kernstrahlung", 310 | "en": "Core Radiation", 311 | "fr": "Radiations du Cœur", 312 | "ja": "龍核", 313 | "ko": "용핵", 314 | }, 315 | 38: { 316 | "cn": "辉核", 317 | "de": "Kernstrahlung", 318 | "en": "Core Radiation", 319 | "fr": "Radiations du Cœur", 320 | "ja": "龍核", 321 | "ko": "용핵", 322 | }, 323 | 39: { 324 | "cn": "辉核", 325 | "de": "Kernstrahlung", 326 | "en": "Core Radiation", 327 | "fr": "Radiations du Cœur", 328 | "ja": "龍核", 329 | "ko": "용핵", 330 | }, 331 | 40: { 332 | "cn": "滩云", 333 | "de": "Wolkenschleier", 334 | "en": "Shelf Clouds", 335 | "fr": "Amas nuageux", 336 | "ja": "群雲", 337 | "ko": "떼구름", 338 | }, 339 | 41: { 340 | "cn": "滩云", 341 | "de": "Wolkenschleier", 342 | "en": "Shelf Clouds", 343 | "fr": "Amas nuageux", 344 | "ja": "群雲", 345 | "ko": "떼구름", 346 | }, 347 | 42: { 348 | "cn": "滩云", 349 | "de": "Wolkenschleier", 350 | "en": "Shelf Clouds", 351 | "fr": "Amas nuageux", 352 | "ja": "群雲", 353 | "ko": "떼구름", 354 | }, 355 | 43: { 356 | "cn": "滩云", 357 | "de": "Wolkenschleier", 358 | "en": "Shelf Clouds", 359 | "fr": "Amas nuageux", 360 | "ja": "群雲", 361 | "ko": "떼구름", 362 | }, 363 | 44: { 364 | "cn": "神意", 365 | "de": "Bedrückend", 366 | "en": "Oppression", 367 | "fr": "Oppression", 368 | "ja": "神意", 369 | "ko": "섭리", 370 | }, 371 | 45: { 372 | "cn": "神意", 373 | "de": "Bedrückend", 374 | "en": "Oppression", 375 | "fr": "Oppression", 376 | "ja": "神意", 377 | "ko": "섭리", 378 | }, 379 | 46: { 380 | "cn": "神意", 381 | "de": "Bedrückend", 382 | "en": "Oppression", 383 | "fr": "Oppression", 384 | "ja": "神意", 385 | "ko": "섭리", 386 | }, 387 | 47: { 388 | "cn": "神意", 389 | "de": "Bedrückend", 390 | "en": "Oppression", 391 | "fr": "Oppression", 392 | "ja": "神意", 393 | "ko": "섭리", 394 | }, 395 | 48: { 396 | "cn": "神意", 397 | "de": "Bedrückend", 398 | "en": "Oppression", 399 | "fr": "Oppression", 400 | "ja": "神意", 401 | "ko": "섭리", 402 | }, 403 | 49: { 404 | "cn": "灵风", 405 | "de": "Schattenwind", 406 | "en": "Umbral Wind", 407 | "fr": "Vent ombral", 408 | "ja": "霊風", 409 | "ko": "그림자바람", 410 | }, 411 | 50: { 412 | "cn": "灵电", 413 | "de": "Schattengewitter", 414 | "en": "Umbral Static", 415 | "fr": "Charges ombrales", 416 | "ja": "放電", 417 | "ko": "방전", 418 | }, 419 | 51: { 420 | "cn": "烟武", 421 | "de": "Qualm", 422 | "en": "Smoke", 423 | "fr": "Fumées", 424 | "ja": "煙霧", 425 | "ko": "연무", 426 | }, 427 | 52: { 428 | "cn": "晴朗", 429 | "de": "Heiter", 430 | "en": "Fair Skies", 431 | "fr": "Clair", 432 | "ja": "晴れ", 433 | "ko": "맑음", 434 | }, 435 | 53: { 436 | "cn": "兽雷", 437 | "de": "Königsgewitter", 438 | "en": "Royal Levin", 439 | "fr": "Éclairs royaux", 440 | "ja": "獣雷", 441 | "ko": "야수번개", 442 | }, 443 | 54: { 444 | "cn": "雷波", 445 | "de": "Hochspannung", 446 | "en": "Hyperelectricity", 447 | "fr": "Hyperélectricité", 448 | "ja": "雷波", 449 | "ko": "번개파동", 450 | }, 451 | 55: { 452 | "cn": "兽雷", 453 | "de": "Königsgewitter", 454 | "en": "Royal Levin", 455 | "fr": "Éclairs royaux", 456 | "ja": "獣雷", 457 | "ko": "야수번개", 458 | }, 459 | 56: { 460 | "cn": "神意", 461 | "de": "Numinos", 462 | "en": "Oppression", 463 | "fr": "Oppression", 464 | "ja": "神意", 465 | "ko": "섭리", 466 | }, 467 | 57: { 468 | "cn": "打雷", 469 | "de": "Gewittrig", 470 | "en": "Thunder", 471 | "fr": "Orages", 472 | "ja": "雷", 473 | "ko": "번개", 474 | }, 475 | 58: { 476 | "cn": "打雷", 477 | "de": "Gewittrig", 478 | "en": "Thunder", 479 | "fr": "Orages", 480 | "ja": "雷", 481 | "ko": "번개", 482 | }, 483 | 59: {"cn": None, "de": None, "en": "CutScene", "fr": None, "ja": None, "ko": None}, 484 | 60: { 485 | "cn": "神秘", 486 | "de": "Mystisch", 487 | "en": "Multiplicity", 488 | "fr": "Multiplicité", 489 | "ja": "神秘", 490 | "ko": "신비", 491 | }, 492 | 61: { 493 | "cn": "神秘", 494 | "de": "Mystisch", 495 | "en": "Multiplicity", 496 | "fr": "Multiplicité", 497 | "ja": "神秘", 498 | "ko": "신비", 499 | }, 500 | 62: { 501 | "cn": "小雨", 502 | "de": "Regnerisch", 503 | "en": "Rain", 504 | "fr": "Pluie", 505 | "ja": "雨", 506 | "ko": "비", 507 | }, 508 | 63: { 509 | "cn": "晴朗", 510 | "de": "Heiter", 511 | "en": "Fair Skies", 512 | "fr": "Clair", 513 | "ja": "晴れ", 514 | "ko": "맑음", 515 | }, 516 | 64: { 517 | "cn": "小雨", 518 | "de": "Regnerisch", 519 | "en": "Rain", 520 | "fr": "Pluie", 521 | "ja": "雨", 522 | "ko": "비", 523 | }, 524 | 65: { 525 | "cn": "晴朗", 526 | "de": "Heiter", 527 | "en": "Fair Skies", 528 | "fr": "Clair", 529 | "ja": "晴れ", 530 | "ko": "맑음", 531 | }, 532 | 66: { 533 | "cn": "邪天", 534 | "de": "Hass", 535 | "en": "Dragonstorms", 536 | "fr": "Tempête de haine", 537 | "ja": "邪天", 538 | "ko": "사룡의 원념", 539 | }, 540 | 67: { 541 | "cn": "邪天", 542 | "de": "Hass", 543 | "en": "Dragonstorms", 544 | "fr": "Tempête de haine", 545 | "ja": "邪天", 546 | "ko": "사룡의 원념", 547 | }, 548 | 68: { 549 | "cn": "晴朗", 550 | "de": "Unterirdisch", 551 | "en": "Subterrain", 552 | "fr": "Souterrain", 553 | "ja": "晴れ", 554 | "ko": "맑음", 555 | }, 556 | 69: { 557 | "cn": "平衡", 558 | "de": "Gerechtigkeit", 559 | "en": "Concordance", 560 | "fr": "Harmonie", 561 | "ja": "調和", 562 | "ko": "조화", 563 | }, 564 | 70: { 565 | "cn": "平衡", 566 | "de": "Gerechtigkeit", 567 | "en": "Concordance", 568 | "fr": "Harmonie", 569 | "ja": "調和", 570 | "ko": "조화", 571 | }, 572 | 71: { 573 | "cn": "时光", 574 | "de": "Zeitfluss", 575 | "en": "Beyond Time", 576 | "fr": "Hors du temps", 577 | "ja": "時流", 578 | "ko": "시류", 579 | }, 580 | 72: { 581 | "cn": "时光", 582 | "de": "Zeitfluss", 583 | "en": "Beyond Time", 584 | "fr": "Hors du temps", 585 | "ja": "時流", 586 | "ko": "시류", 587 | }, 588 | 73: { 589 | "cn": "时光", 590 | "de": "Zeitfluss", 591 | "en": "Beyond Time", 592 | "fr": "Hors du temps", 593 | "ja": "時流", 594 | "ko": "시류", 595 | }, 596 | 74: { 597 | "cn": "鬼气", 598 | "de": "Dämonisch unendlich", 599 | "en": "Demonic Infinity", 600 | "fr": "Infini démoniaque", 601 | "ja": "鬼気", 602 | "ko": "귀기", 603 | }, 604 | 75: { 605 | "cn": "鬼气", 606 | "de": "Dämonisch unendlich", 607 | "en": "Demonic Infinity", 608 | "fr": "Infini démoniaque", 609 | "ja": "鬼気", 610 | "ko": "귀기", 611 | }, 612 | 76: { 613 | "cn": "鬼气", 614 | "de": "Dämonisch unendlich", 615 | "en": "Demonic Infinity", 616 | "fr": "Infini démoniaque", 617 | "ja": "鬼気", 618 | "ko": "귀기", 619 | }, 620 | 77: { 621 | "cn": "次元", 622 | "de": "Dimensionsspaltend", 623 | "en": "Dimensional Disruption", 624 | "fr": "Perturbation dimensionnelle", 625 | "ja": "次元", 626 | "ko": "차원", 627 | }, 628 | 78: { 629 | "cn": "次元", 630 | "de": "Dimensionsspaltend", 631 | "en": "Dimensional Disruption", 632 | "fr": "Perturbation dimensionnelle", 633 | "ja": "次元", 634 | "ko": "차원", 635 | }, 636 | 79: { 637 | "cn": "次元", 638 | "de": "Dimensionsspaltend", 639 | "en": "Dimensional Disruption", 640 | "fr": "Perturbation dimensionnelle", 641 | "ja": "次元", 642 | "ko": "차원", 643 | }, 644 | 80: { 645 | "cn": "豪雨", 646 | "de": "Feiersturm", 647 | "en": "Revelstorms", 648 | "fr": "Tempête festive", 649 | "ja": "嵐天", 650 | "ko": "호우", 651 | }, 652 | 81: { 653 | "cn": "豪雨", 654 | "de": "Feiersturm", 655 | "en": "Revelstorms", 656 | "fr": "Tempête festive", 657 | "ja": "嵐天", 658 | "ko": "호우", 659 | }, 660 | 82: { 661 | "cn": "极乐", 662 | "de": "Ewigschön", 663 | "en": "Eternal Bliss", 664 | "fr": "Béatitude éternelle", 665 | "ja": "美天", 666 | "ko": "미혹", 667 | }, 668 | 83: { 669 | "cn": "极乐", 670 | "de": "Ewigschön", 671 | "en": "Eternal Bliss", 672 | "fr": "Béatitude éternelle", 673 | "ja": "美天", 674 | "ko": "미혹", 675 | }, 676 | 84: { 677 | "cn": "龙威", 678 | "de": "Drachensturm", 679 | "en": "Wyrmstorms", 680 | "fr": "Tempête draconique", 681 | "ja": "龍天", 682 | "ko": "신룡의 폭풍", 683 | }, 684 | 85: { 685 | "cn": "龙威", 686 | "de": "Drachensturm", 687 | "en": "Wyrmstorms", 688 | "fr": "Tempête draconique", 689 | "ja": "龍天", 690 | "ko": "신룡의 폭풍", 691 | }, 692 | 86: { 693 | "cn": "豪雨", 694 | "de": "Feiersturm", 695 | "en": "Revelstorms", 696 | "fr": "Tempête festive", 697 | "ja": "嵐天", 698 | "ko": "호우", 699 | }, 700 | 87: { 701 | "cn": "迅雷", 702 | "de": "Blitzsturm", 703 | "en": "Quicklevin", 704 | "fr": "Vif-orage", 705 | "ja": "迅雷", 706 | "ko": "전선뇌우", 707 | }, 708 | 88: { 709 | "cn": "打雷", 710 | "de": "Gewittrig", 711 | "en": "Thunder", 712 | "fr": "Orages", 713 | "ja": "雷", 714 | "ko": "번개", 715 | }, 716 | 89: { 717 | "cn": "次元", 718 | "de": "Dimensionsspaltend", 719 | "en": "Dimensional Disruption", 720 | "fr": "Perturbation dimensionnelle", 721 | "ja": "次元", 722 | "ko": "차원", 723 | }, 724 | 90: { 725 | "cn": "晴朗", 726 | "de": "Heiter", 727 | "en": "Fair Skies", 728 | "fr": "Clair", 729 | "ja": "晴れ", 730 | "ko": "맑음", 731 | }, 732 | 91: { 733 | "cn": "碧空", 734 | "de": "Klar", 735 | "en": "Clear Skies", 736 | "fr": "Dégagé", 737 | "ja": "快晴", 738 | "ko": "쾌청", 739 | }, 740 | 92: { 741 | "cn": "白旋风", 742 | "de": "Weißer Zyklon", 743 | "en": "White Cyclones", 744 | "fr": "Tempête blanche", 745 | "ja": "白嵐", 746 | "ko": "하얀 폭풍", 747 | }, 748 | 93: { 749 | "cn": "白旋风", 750 | "de": "Weißer Zyklon", 751 | "en": "White Cyclones", 752 | "fr": "Tempête blanche", 753 | "ja": "白嵐", 754 | "ko": "하얀 폭풍", 755 | }, 756 | 94: { 757 | "cn": "白旋风", 758 | "de": "Weißer Zyklon", 759 | "en": "White Cyclones", 760 | "fr": "Tempête blanche", 761 | "ja": "白嵐", 762 | "ko": "하얀 폭풍", 763 | }, 764 | 95: { 765 | "cn": "幻想", 766 | "de": "Ultimativ", 767 | "en": "Ultimania", 768 | "fr": "Fantasmagorique", 769 | "ja": "幻想", 770 | "ko": "환상", 771 | }, 772 | 96: { 773 | "cn": "白旋风", 774 | "de": "Weißer Zyklon", 775 | "en": "White Cyclones", 776 | "fr": "Tempête blanche", 777 | "ja": "白嵐", 778 | "ko": "하얀 폭풍", 779 | }, 780 | 97: { 781 | "cn": "月夜", 782 | "de": "Dunkle Mondnacht", 783 | "en": "Moonlight", 784 | "fr": "Clair de lune", 785 | "ja": "月夜", 786 | "ko": "달빛", 787 | }, 788 | 98: { 789 | "cn": "月夜", 790 | "de": "Dunkle Mondnacht", 791 | "en": "Moonlight", 792 | "fr": "Clair de lune", 793 | "ja": "月夜", 794 | "ko": "달빛", 795 | }, 796 | 99: { 797 | "cn": "月夜", 798 | "de": "Dunkle Mondnacht", 799 | "en": "Moonlight", 800 | "fr": "Clair de lune", 801 | "ja": "月夜", 802 | "ko": "달빛", 803 | }, 804 | 100: { 805 | "cn": "月夜", 806 | "de": "Dunkle Mondnacht", 807 | "en": "Moonlight", 808 | "fr": "Clair de lune", 809 | "ja": "月夜", 810 | "ko": "달빛", 811 | }, 812 | 101: { 813 | "cn": "红月下", 814 | "de": "Roter Mond", 815 | "en": "Red Moon", 816 | "fr": "Lune rouge", 817 | "ja": "紅月下", 818 | "ko": "붉은 달", 819 | }, 820 | 102: { 821 | "cn": "朱炎", 822 | "de": "Rotlodernd", 823 | "en": "Scarlet", 824 | "fr": "Vermillon", 825 | "ja": "朱炎", 826 | "ko": "붉은 불꽃 ", 827 | }, 828 | 103: { 829 | "cn": "朱炎", 830 | "de": "Rotlodernd", 831 | "en": "Scarlet", 832 | "fr": "Vermillon", 833 | "ja": "朱炎", 834 | "ko": "붉은 불꽃 ", 835 | }, 836 | 104: { 837 | "cn": "朱炎", 838 | "de": "Rotlodernd", 839 | "en": "Scarlet", 840 | "fr": "Vermillon", 841 | "ja": "朱炎", 842 | "ko": "붉은 불꽃 ", 843 | }, 844 | 105: { 845 | "cn": "晴朗", 846 | "de": "Heiter", 847 | "en": "Fair Skies", 848 | "fr": "Clair", 849 | "ja": "晴れ", 850 | "ko": "맑음", 851 | }, 852 | 106: { 853 | "cn": "晴朗", 854 | "de": "Heiter", 855 | "en": "Fair Skies", 856 | "fr": "Clair", 857 | "ja": "晴れ", 858 | "ko": "맑음", 859 | }, 860 | 107: { 861 | "cn": "晴朗", 862 | "de": "Heiter", 863 | "en": "Fair Skies", 864 | "fr": "Clair", 865 | "ja": "晴れ", 866 | "ko": "맑음", 867 | }, 868 | 108: { 869 | "cn": "晴朗", 870 | "de": "Heiter", 871 | "en": "Fair Skies", 872 | "fr": "Clair", 873 | "ja": "晴れ", 874 | "ko": "맑음", 875 | }, 876 | 109: { 877 | "cn": "烈焰", 878 | "de": "Feuer", 879 | "en": "Flames", 880 | "fr": "Flammes", 881 | "ja": "火炎", 882 | "ko": "화염", 883 | }, 884 | 110: { 885 | "cn": "海啸", 886 | "de": "Tsunami", 887 | "en": "Tsunamis", 888 | "fr": "Raz-de-marée", 889 | "ja": "津波", 890 | "ko": "해일", 891 | }, 892 | 111: { 893 | "cn": "龙卷风", 894 | "de": "Tornado", 895 | "en": "Cyclones", 896 | "fr": "Tornade", 897 | "ja": "竜巻", 898 | "ko": "회오리", 899 | }, 900 | 112: { 901 | "cn": "地震", 902 | "de": "Erdbeben", 903 | "en": "Geostorms", 904 | "fr": "Séisme", 905 | "ja": "地震", 906 | "ko": "지진", 907 | }, 908 | 113: { 909 | "cn": "青空", 910 | "de": "Blauschimmernd", 911 | "en": "True Blue", 912 | "fr": "Azur", 913 | "ja": "青春", 914 | "ko": "푸른 봄날", 915 | }, 916 | 114: { 917 | "cn": "青空", 918 | "de": "Blauschimmernd", 919 | "en": "True Blue", 920 | "fr": "Azur", 921 | "ja": "青春", 922 | "ko": "푸른 봄날", 923 | }, 924 | 115: { 925 | "cn": "青空", 926 | "de": "Blauschimmernd", 927 | "en": "True Blue", 928 | "fr": "Azur", 929 | "ja": "青春", 930 | "ko": "푸른 봄날", 931 | }, 932 | 116: { 933 | "cn": "乱灵流", 934 | "de": "Astrale Turbulenzen", 935 | "en": "Umbral Turbulence", 936 | "fr": "Turbulences ombrales", 937 | "ja": "乱霊流", 938 | "ko": "난령류", 939 | }, 940 | 117: { 941 | "cn": "青空", 942 | "de": "Blauschimmernd", 943 | "en": "True Blue", 944 | "fr": "Azur", 945 | "ja": "青春", 946 | "ko": "푸른 봄날", 947 | }, 948 | 118: { 949 | "cn": "无尽光", 950 | "de": "Ewiges Licht", 951 | "en": "Everlasting Light", 952 | "fr": "Clarté éternelle", 953 | "ja": "無尽光", 954 | "ko": "끝없는 빛", 955 | }, 956 | 119: { 957 | "cn": "暴风", 958 | "de": "Stürmisch", 959 | "en": "Gales", 960 | "fr": "Vents violents", 961 | "ja": "暴風", 962 | "ko": "폭풍", 963 | }, 964 | 120: { 965 | "cn": "末日", 966 | "de": "Apokalyptisch", 967 | "en": "Termination", 968 | "fr": "Apocalypse", 969 | "ja": "終末", 970 | "ko": "종말", 971 | }, 972 | 121: { 973 | "cn": "末日", 974 | "de": "Apokalyptisch", 975 | "en": "Termination", 976 | "fr": "Apocalypse", 977 | "ja": "終末", 978 | "ko": "종말", 979 | }, 980 | 122: { 981 | "cn": "妖梦", 982 | "de": "Feenträume", 983 | "en": "Dreams", 984 | "fr": "Rêverie", 985 | "ja": "妖夢", 986 | "ko": "이상한 꿈", 987 | }, 988 | 123: { 989 | "cn": "妖梦", 990 | "de": "Feenträume", 991 | "en": "Dreams", 992 | "fr": "Rêverie", 993 | "ja": "妖夢", 994 | "ko": "이상한 꿈", 995 | }, 996 | 124: { 997 | "cn": "妖梦", 998 | "de": "Feenträume", 999 | "en": "Dreams", 1000 | "fr": "Rêverie", 1001 | "ja": "妖夢", 1002 | "ko": "이상한 꿈", 1003 | }, 1004 | 125: { 1005 | "cn": "光天", 1006 | "de": "Strahlende Glanzhaftigkeit", 1007 | "en": "Brilliance", 1008 | "fr": "Radiance divine", 1009 | "ja": "光天", 1010 | "ko": "눈부신 하늘", 1011 | }, 1012 | 126: { 1013 | "cn": "光天", 1014 | "de": "Strahlende Glanzhaftigkeit", 1015 | "en": "Brilliance", 1016 | "fr": "Radiance divine", 1017 | "ja": "光天", 1018 | "ko": "눈부신 하늘", 1019 | }, 1020 | 127: { 1021 | "cn": "末日", 1022 | "de": "Apokalyptisch", 1023 | "en": "Termination", 1024 | "fr": "Apocalypse", 1025 | "ja": "終末", 1026 | "ko": "종말", 1027 | }, 1028 | 128: { 1029 | "cn": "末日", 1030 | "de": "Apokalyptisch", 1031 | "en": "Termination", 1032 | "fr": "Apocalypse", 1033 | "ja": "終末", 1034 | "ko": "종말", 1035 | }, 1036 | 129: { 1037 | "cn": "无尽光", 1038 | "de": "Ewiges Licht", 1039 | "en": "Everlasting Light", 1040 | "fr": "Clarté éternelle", 1041 | "ja": "無尽光", 1042 | "ko": "끝없는 빛", 1043 | }, 1044 | 130: { 1045 | "cn": "烟雾", 1046 | "de": "Rauchschwaden", 1047 | "en": "Eruptions", 1048 | "fr": "Éruptions", 1049 | "ja": "噴煙", 1050 | "ko": "분화", 1051 | }, 1052 | 131: { 1053 | "cn": "末日", 1054 | "de": "Apokalyptisch", 1055 | "en": "Termination", 1056 | "fr": "Apocalypse", 1057 | "ja": "終末", 1058 | "ko": "종말", 1059 | }, 1060 | 132: { 1061 | "cn": "晴朗", 1062 | "de": "Heiter", 1063 | "en": "Fair Skies", 1064 | "fr": "Clair", 1065 | "ja": "晴れ", 1066 | "ko": "맑음", 1067 | }, 1068 | 133: { 1069 | "cn": "灵烈火", 1070 | "de": "Feuerseelenwinde", 1071 | "en": "Umbral Flare", 1072 | "fr": "Vent ombral de feu", 1073 | "ja": "焔霊風", 1074 | "ko": "화속성풍", 1075 | }, 1076 | 134: { 1077 | "cn": "灵飘尘", 1078 | "de": "Erdseelenwinde", 1079 | "en": "Umbral Duststorms", 1080 | "fr": "Vent ombral de terre", 1081 | "ja": "土霊風", 1082 | "ko": "토속성풍", 1083 | }, 1084 | 135: { 1085 | "cn": "灵飞电", 1086 | "de": "Donnerseelenwinde", 1087 | "en": "Umbral Levin", 1088 | "fr": "Vent ombral de foudre", 1089 | "ja": "雷霊風", 1090 | "ko": "뇌속성풍", 1091 | }, 1092 | 136: { 1093 | "cn": "灵罡风", 1094 | "de": "Sturmseelenwinde", 1095 | "en": "Umbral Tempest", 1096 | "fr": "Vent ombral des tempêtes", 1097 | "ja": "嵐霊風", 1098 | "ko": "풍속성풍", 1099 | }, 1100 | 137: { 1101 | "cn": "流星雨", 1102 | "de": "Sternenregen", 1103 | "en": "Starshower", 1104 | "fr": "Pluie d'étoiles", 1105 | "ja": "流星雨", 1106 | "ko": "유성우", 1107 | }, 1108 | 138: { 1109 | "cn": "记忆乱流", 1110 | "de": "Erinnerungsturbulenzen", 1111 | "en": "Delirium", 1112 | "fr": "Tempête de souvenirs", 1113 | "ja": "記憶乱流", 1114 | "ko": "기억난류", 1115 | }, 1116 | 139: { 1117 | "cn": "阴云", 1118 | "de": "Wolkig", 1119 | "en": "Clouds", 1120 | "fr": "Couvert", 1121 | "ja": "曇り", 1122 | "ko": "흐림", 1123 | }, 1124 | 140: { 1125 | "cn": "阴云", 1126 | "de": "Wolkig", 1127 | "en": "Clouds", 1128 | "fr": "Couvert", 1129 | "ja": "曇り", 1130 | "ko": "흐림", 1131 | }, 1132 | 141: { 1133 | "cn": "极光", 1134 | "de": "Blendend", 1135 | "en": "Irradiance", 1136 | "fr": "Rayonnement", 1137 | "ja": "極光", 1138 | "ko": "극광", 1139 | }, 1140 | 142: { 1141 | "cn": "极光", 1142 | "de": "Blendend", 1143 | "en": "Irradiance", 1144 | "fr": "Rayonnement", 1145 | "ja": "極光", 1146 | "ko": "극광", 1147 | }, 1148 | 143: { 1149 | "cn": "雷云", 1150 | "de": "Wetterleuchten", 1151 | "en": "Storm Clouds", 1152 | "fr": "Orageux", 1153 | "ja": "雷雲", 1154 | "ko": "뇌운", 1155 | }, 1156 | 144: { 1157 | "cn": "火风暴", 1158 | "de": "Flammensturm", 1159 | "en": "Firestorms", 1160 | "fr": "Tempête de feu", 1161 | "ja": "焔嵐\xa0", 1162 | "ko": "불바람", 1163 | }, 1164 | 145: { 1165 | "cn": "幻海流", 1166 | "de": "Phantomströmung", 1167 | "en": "Spectral Current", 1168 | "fr": "Courant spectral", 1169 | "ja": "幻海流\xa0", 1170 | "ko": "환해류", 1171 | }, 1172 | 146: {"cn": None, "de": None, "en": None, "fr": None, "ja": None, "ko": None}, 1173 | 147: { 1174 | "cn": "决战", 1175 | "de": "Endzeitig", 1176 | "en": "Climactic", 1177 | "fr": "Fatidique", 1178 | "ja": "決戦", 1179 | "ko": "결전", 1180 | }, 1181 | 148: { 1182 | "cn": "月尘", 1183 | "de": "Mondstaubig", 1184 | "en": "Moon Dust", 1185 | "fr": "Tempêtes de régolithe", 1186 | "ja": "月砂塵", 1187 | "ko": "달모래먼지", 1188 | }, 1189 | 149: { 1190 | "cn": "磁暴", 1191 | "de": "Magnetsturm", 1192 | "en": "Astromagnetic Storms", 1193 | "fr": "Astromagnétique", 1194 | "ja": "磁気嵐", 1195 | "ko": "자기 폭풍", 1196 | }, 1197 | 150: { 1198 | "cn": "末日", 1199 | "de": "Apokalypse", 1200 | "en": "Apocalypse", 1201 | "fr": "Apocalypse", 1202 | "ja": "終末", 1203 | "ko": "종말", 1204 | }, 1205 | 151: { 1206 | "cn": "星灵", 1207 | "de": "Polarisierend", 1208 | "en": "Polarization", 1209 | "fr": "Polarisation", 1210 | "ja": "星霊", 1211 | "ko": "별빛그림자", 1212 | }, 1213 | 152: { 1214 | "cn": "星灵", 1215 | "de": "Polarisierend", 1216 | "en": "Polarization", 1217 | "fr": "Polarisation", 1218 | "ja": "星霊", 1219 | "ko": "별빛그림자", 1220 | }, 1221 | 153: { 1222 | "cn": "星灵", 1223 | "de": "Polarisierend", 1224 | "en": "Polarization", 1225 | "fr": "Polarisation", 1226 | "ja": "星霊", 1227 | "ko": "별빛그림자", 1228 | }, 1229 | 154: { 1230 | "cn": "星灵", 1231 | "de": "Polarisierend", 1232 | "en": "Polarization", 1233 | "fr": "Polarisation", 1234 | "ja": "星霊", 1235 | "ko": "별빛그림자", 1236 | }, 1237 | 155: { 1238 | "cn": "星灵", 1239 | "de": "Polarisierend", 1240 | "en": "Polarization", 1241 | "fr": "Polarisation", 1242 | "ja": "星霊", 1243 | "ko": "별빛그림자", 1244 | }, 1245 | 156: { 1246 | "cn": "虚拟", 1247 | "de": "Imaginär", 1248 | "en": "Projection", 1249 | "fr": "Virtuel", 1250 | "ja": "仮想", 1251 | "ko": "가상", 1252 | }, 1253 | 157: { 1254 | "cn": "万魔殿", 1255 | "de": "Pandæmonium", 1256 | "en": "Pandæmonium", 1257 | "fr": "Pandæmonium", 1258 | "ja": "万魔殿", 1259 | "ko": "마의 전당", 1260 | }, 1261 | 158: { 1262 | "cn": "万魔殿", 1263 | "de": "Pandæmonium", 1264 | "en": "Pandæmonium", 1265 | "fr": "Pandæmonium", 1266 | "ja": "万魔殿", 1267 | "ko": "마의 전당", 1268 | }, 1269 | 159: { 1270 | "cn": "万魔殿", 1271 | "de": "Pandæmonium", 1272 | "en": "Pandæmonium", 1273 | "fr": "Pandæmonium", 1274 | "ja": "万魔殿", 1275 | "ko": "마의 전당", 1276 | }, 1277 | 160: { 1278 | "cn": "终极", 1279 | "de": "Eschatologie", 1280 | "en": "Ultimatum", 1281 | "fr": "Eschatologique", 1282 | "ja": "終極", 1283 | "ko": "종극", 1284 | }, 1285 | 161: { 1286 | "cn": "绝望", 1287 | "de": "Verzweifelnd", 1288 | "en": "Inevitability", 1289 | "fr": "Désespoir", 1290 | "ja": "絶望", 1291 | "ko": "절망", 1292 | }, 1293 | 162: { 1294 | "cn": "神域", 1295 | "de": "Götterwetter", 1296 | "en": "Transcendence", 1297 | "fr": "Mythologique", 1298 | "ja": "神域", 1299 | "ko": "신역", 1300 | }, 1301 | 163: { 1302 | "cn": "神域", 1303 | "de": "Götterwetter", 1304 | "en": "Transcendence", 1305 | "fr": "Mythologique", 1306 | "ja": "神域", 1307 | "ko": "신역", 1308 | }, 1309 | 164: { 1310 | "cn": "神域", 1311 | "de": "Götterwetter", 1312 | "en": "Transcendence", 1313 | "fr": "Mythologique", 1314 | "ja": "神域", 1315 | "ko": "신역", 1316 | }, 1317 | 165: { 1318 | "cn": "神域", 1319 | "de": "Götterwetter", 1320 | "en": "Transcendence", 1321 | "fr": "Mythologique", 1322 | "ja": "神域", 1323 | "ko": "신역", 1324 | }, 1325 | 166: { 1326 | "cn": "神域", 1327 | "de": "Götterwetter", 1328 | "en": "Transcendence", 1329 | "fr": "Mythologique", 1330 | "ja": "神域", 1331 | "ko": "신역", 1332 | }, 1333 | 167: { 1334 | "cn": "神域", 1335 | "de": "Götterwetter", 1336 | "en": "Transcendence", 1337 | "fr": "Mythologique", 1338 | "ja": "神域", 1339 | "ko": "신역", 1340 | }, 1341 | 168: { 1342 | "cn": "神域", 1343 | "de": "Götterwetter", 1344 | "en": "Transcendence", 1345 | "fr": "Mythologique", 1346 | "ja": "神域", 1347 | "ko": "신역", 1348 | }, 1349 | 169: { 1350 | "cn": "神域", 1351 | "de": "Götterwetter", 1352 | "en": "Transcendence", 1353 | "fr": "Mythologique", 1354 | "ja": "神域", 1355 | "ko": "신역", 1356 | }, 1357 | 170: { 1358 | "cn": "邪天", 1359 | "de": "Hass", 1360 | "en": "Dragonstorms", 1361 | "fr": "Tempête de haine", 1362 | "ja": "邪天", 1363 | "ko": "사룡의 원념", 1364 | }, 1365 | 171: { 1366 | "cn": "虚无", 1367 | "de": "Leere", 1368 | "en": "Vacuity", 1369 | "fr": "Néant", 1370 | "ja": "虚無", 1371 | "ko": "허무", 1372 | }, 1373 | 172: { 1374 | "cn": "虚无", 1375 | "de": "Leere", 1376 | "en": "Vacuity", 1377 | "fr": "Néant", 1378 | "ja": "虚無", 1379 | "ko": "허무", 1380 | }, 1381 | 173: { 1382 | "cn": "虚无", 1383 | "de": "Leere", 1384 | "en": "Vacuity", 1385 | "fr": "Néant", 1386 | "ja": "虚無", 1387 | "ko": "허무", 1388 | }, 1389 | 174: { 1390 | "cn": "次元", 1391 | "de": "Dimensionsspaltend", 1392 | "en": "Dimensional Disruption", 1393 | "fr": "Perturbation dimensionnelle", 1394 | "ja": "次元", 1395 | "ko": "차원", 1396 | }, 1397 | 175: { 1398 | "cn": "次元", 1399 | "de": "Dimensionsspaltend", 1400 | "en": "Dimensional Disruption", 1401 | "fr": "Perturbation dimensionnelle", 1402 | "ja": "次元", 1403 | "ko": "차원", 1404 | }, 1405 | 176: { 1406 | "cn": "次元", 1407 | "de": "Dimensionsspaltend", 1408 | "en": "Dimensional Disruption", 1409 | "fr": "Perturbation dimensionnelle", 1410 | "ja": "次元", 1411 | "ko": "차원", 1412 | }, 1413 | 177: { 1414 | "cn": "万魔殿", 1415 | "de": "Pandæmonium", 1416 | "en": "Pandæmonium", 1417 | "fr": "Pandæmonium", 1418 | "ja": "万魔殿", 1419 | "ko": "마의 전당", 1420 | }, 1421 | 178: { 1422 | "cn": "万魔殿", 1423 | "de": "Pandæmonium", 1424 | "en": "Pandæmonium", 1425 | "fr": "Pandæmonium", 1426 | "ja": "万魔殿", 1427 | "ko": "마의 전당", 1428 | }, 1429 | 179: { 1430 | "cn": "诗想", 1431 | "de": "Dichterisch", 1432 | "en": "Lyrical Catharsis", 1433 | "fr": "Imaginaire", 1434 | "ja": "詩想", 1435 | "ko": "시상", 1436 | }, 1437 | 180: { 1438 | "cn": "虚无", 1439 | "de": "Leere", 1440 | "en": "Vacuity", 1441 | "fr": "Néant", 1442 | "ja": "虚無", 1443 | "ko": "허무", 1444 | }, 1445 | 181: { 1446 | "cn": "阈限", 1447 | "de": "Verhangen", 1448 | "en": "Liminality", 1449 | "fr": "Ombrageux", 1450 | "ja": "暗天", 1451 | "ko": "어두운 하늘", 1452 | }, 1453 | 182: { 1454 | "cn": "阈限", 1455 | "de": "Verhangen", 1456 | "en": "Liminality", 1457 | "fr": "Ombrageux", 1458 | "ja": "暗天", 1459 | "ko": "어두운 하늘", 1460 | }, 1461 | 183: { 1462 | "cn": "虚拟", 1463 | "de": "Imaginär", 1464 | "en": "Projection", 1465 | "fr": "Virtuel", 1466 | "ja": "仮想", 1467 | "ko": "가상", 1468 | }, 1469 | 184: { 1470 | "cn": "虚拟", 1471 | "de": "Imaginär", 1472 | "en": "Projection", 1473 | "fr": "Virtuel", 1474 | "ja": "仮想", 1475 | "ko": "가상", 1476 | }, 1477 | 185: { 1478 | "cn": "虚拟", 1479 | "de": "Imaginär", 1480 | "en": "Projection", 1481 | "fr": "Virtuel", 1482 | "ja": "仮想", 1483 | "ko": "가상", 1484 | }, 1485 | 186: { 1486 | "cn": "虚拟", 1487 | "de": "Imaginär", 1488 | "en": "Projection", 1489 | "fr": "Virtuel", 1490 | "ja": "仮想", 1491 | "ko": "가상", 1492 | }, 1493 | 187: { 1494 | "cn": "记忆", 1495 | "de": "Reminiszenz", 1496 | "en": "Reminiscence", 1497 | "fr": "Mémoriel", 1498 | "ja": "記憶", 1499 | "ko": "기억", 1500 | }, 1501 | 188: { 1502 | "cn": "战云", 1503 | "de": "Gespenstisch", 1504 | "en": "Ominous Clouds", 1505 | "fr": "Brume spectrale", 1506 | "ja": "暗雲", 1507 | "ko": "암운", 1508 | }, 1509 | 189: { 1510 | "cn": "虚拟", 1511 | "de": "Virtuell", 1512 | "en": "Projection", 1513 | "fr": "Virtuel", 1514 | "ja": "仮想", 1515 | "ko": "가상", 1516 | }, 1517 | 190: { 1518 | "cn": "幻怪", 1519 | "de": "Phantasmagorien", 1520 | "en": "Atmospheric Phantasms", 1521 | "fr": "Fantasmes", 1522 | "ja": "幻怪", 1523 | "ko": "환영", 1524 | }, 1525 | 191: { 1526 | "cn": "幻妖", 1527 | "de": "Trugbilder", 1528 | "en": "Illusory Disturbances", 1529 | "fr": "Illusions", 1530 | "ja": "幻妖", 1531 | "ko": "환시", 1532 | }, 1533 | 192: { 1534 | "cn": "蜃景", 1535 | "de": "Luftspiegelungen", 1536 | "en": "Auroral Mirages", 1537 | "fr": "Mirages", 1538 | "ja": "蜃気楼", 1539 | "ko": "신기루", 1540 | }, 1541 | 193: { 1542 | "cn": "魔尘", 1543 | "de": "Dünstig trüb", 1544 | "en": "Electrostatic Dust", 1545 | "fr": "Malsain", 1546 | "ja": "魔塵", 1547 | "ko": "정전기먼지", 1548 | }, 1549 | 194: { 1550 | "cn": "流星雨", 1551 | "de": "Meteoritenschauer", 1552 | "en": "Meteor Showers", 1553 | "fr": "Pluie de météorites", 1554 | "ja": "流星", 1555 | "ko": "유성", 1556 | }, 1557 | 195: { 1558 | "cn": "流星雨", 1559 | "de": "Meteoritenschauer", 1560 | "en": "Meteor Showers", 1561 | "fr": "Pluie de météorites", 1562 | "ja": "流星", 1563 | "ko": "유성", 1564 | }, 1565 | 196: { 1566 | "cn": "磁暴", 1567 | "de": "Magnetsturm", 1568 | "en": "Astromagnetic Storms", 1569 | "fr": "Tempête magnétique", 1570 | "ja": "磁気嵐", 1571 | "ko": "자기 폭풍", 1572 | }, 1573 | 197: { 1574 | "cn": "孢子雾", 1575 | "de": "Sporennebel", 1576 | "en": "Sporing Mist", 1577 | "fr": "Nuages de spores", 1578 | "ja": "胞子霧", 1579 | "ko": "포자 안개", 1580 | }, 1581 | 198: { 1582 | "cn": "死气", 1583 | "de": "Fürchterlich", 1584 | "en": "Dying Breath", 1585 | "fr": "Atmosphère mortifère", 1586 | "ja": "死気", 1587 | "ko": "죽음의 기운", 1588 | }, 1589 | 199: { 1590 | "cn": "死气", 1591 | "de": "Fürchterlich", 1592 | "en": "Dying Breath", 1593 | "fr": "Atmosphère mortifère", 1594 | "ja": "死気", 1595 | "ko": "죽음의 기운", 1596 | }, 1597 | 200: { 1598 | "cn": "死气", 1599 | "de": "Fürchterlich", 1600 | "en": "Dying Breath", 1601 | "fr": "Atmosphère mortifère", 1602 | "ja": "死気", 1603 | "ko": "죽음의 기운", 1604 | }, 1605 | 201: { 1606 | "cn": "寒冷气流", 1607 | "de": "Kältefront", 1608 | "en": "Annealing Winds", 1609 | "fr": "Courants glaciaux", 1610 | "ja": "寒冷気流", 1611 | "ko": "한랭 기류", 1612 | }, 1613 | 202: { 1614 | "cn": "玻璃雨", 1615 | "de": "Glasregen", 1616 | "en": "Glass Storms", 1617 | "fr": "Pluie de verre", 1618 | "ja": "グラスレイン", 1619 | "ko": "유리비", 1620 | }, 1621 | } 1622 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "atomicwrites" 5 | version = "1.4.1" 6 | description = "Atomic file writes." 7 | optional = false 8 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 9 | files = [ 10 | {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, 11 | ] 12 | 13 | [[package]] 14 | name = "attrs" 15 | version = "23.2.0" 16 | description = "Classes Without Boilerplate" 17 | optional = false 18 | python-versions = ">=3.7" 19 | files = [ 20 | {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, 21 | {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, 22 | ] 23 | 24 | [package.extras] 25 | cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] 26 | dev = ["attrs[tests]", "pre-commit"] 27 | docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] 28 | tests = ["attrs[tests-no-zope]", "zope-interface"] 29 | tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] 30 | tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] 31 | 32 | [[package]] 33 | name = "autopep8" 34 | version = "1.7.0" 35 | description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" 36 | optional = false 37 | python-versions = "*" 38 | files = [ 39 | {file = "autopep8-1.7.0-py2.py3-none-any.whl", hash = "sha256:6f09e90a2be784317e84dc1add17ebfc7abe3924239957a37e5040e27d812087"}, 40 | {file = "autopep8-1.7.0.tar.gz", hash = "sha256:ca9b1a83e53a7fad65d731dc7a2a2d50aa48f43850407c59f6a1a306c4201142"}, 41 | ] 42 | 43 | [package.dependencies] 44 | pycodestyle = ">=2.9.1" 45 | toml = "*" 46 | 47 | [[package]] 48 | name = "black" 49 | version = "24.4.2" 50 | description = "The uncompromising code formatter." 51 | optional = false 52 | python-versions = ">=3.8" 53 | files = [ 54 | {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, 55 | {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, 56 | {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, 57 | {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, 58 | {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, 59 | {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, 60 | {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, 61 | {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, 62 | {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, 63 | {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, 64 | {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, 65 | {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, 66 | {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, 67 | {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, 68 | {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, 69 | {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, 70 | {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, 71 | {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, 72 | {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, 73 | {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, 74 | {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, 75 | {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, 76 | ] 77 | 78 | [package.dependencies] 79 | click = ">=8.0.0" 80 | mypy-extensions = ">=0.4.3" 81 | packaging = ">=22.0" 82 | pathspec = ">=0.9.0" 83 | platformdirs = ">=2" 84 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 85 | typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} 86 | 87 | [package.extras] 88 | colorama = ["colorama (>=0.4.3)"] 89 | d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] 90 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 91 | uvloop = ["uvloop (>=0.15.2)"] 92 | 93 | [[package]] 94 | name = "cfgv" 95 | version = "3.4.0" 96 | description = "Validate configuration and produce human readable error messages." 97 | optional = false 98 | python-versions = ">=3.8" 99 | files = [ 100 | {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, 101 | {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, 102 | ] 103 | 104 | [[package]] 105 | name = "click" 106 | version = "8.1.7" 107 | description = "Composable command line interface toolkit" 108 | optional = false 109 | python-versions = ">=3.7" 110 | files = [ 111 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, 112 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, 113 | ] 114 | 115 | [package.dependencies] 116 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 117 | 118 | [[package]] 119 | name = "colorama" 120 | version = "0.4.6" 121 | description = "Cross-platform colored terminal text." 122 | optional = false 123 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 124 | files = [ 125 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 126 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 127 | ] 128 | 129 | [[package]] 130 | name = "coverage" 131 | version = "6.5.0" 132 | description = "Code coverage measurement for Python" 133 | optional = false 134 | python-versions = ">=3.7" 135 | files = [ 136 | {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, 137 | {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, 138 | {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, 139 | {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, 140 | {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, 141 | {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, 142 | {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, 143 | {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, 144 | {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, 145 | {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, 146 | {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, 147 | {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, 148 | {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, 149 | {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, 150 | {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, 151 | {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, 152 | {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, 153 | {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, 154 | {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, 155 | {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, 156 | {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, 157 | {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, 158 | {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, 159 | {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, 160 | {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, 161 | {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, 162 | {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, 163 | {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, 164 | {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, 165 | {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, 166 | {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, 167 | {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, 168 | {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, 169 | {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, 170 | {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, 171 | {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, 172 | {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, 173 | {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, 174 | {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, 175 | {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, 176 | {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, 177 | {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, 178 | {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, 179 | {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, 180 | {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, 181 | {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, 182 | {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, 183 | {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, 184 | {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, 185 | {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, 186 | ] 187 | 188 | [package.dependencies] 189 | tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} 190 | 191 | [package.extras] 192 | toml = ["tomli"] 193 | 194 | [[package]] 195 | name = "distlib" 196 | version = "0.3.8" 197 | description = "Distribution utilities" 198 | optional = false 199 | python-versions = "*" 200 | files = [ 201 | {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, 202 | {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, 203 | ] 204 | 205 | [[package]] 206 | name = "filelock" 207 | version = "3.15.4" 208 | description = "A platform independent file lock." 209 | optional = false 210 | python-versions = ">=3.8" 211 | files = [ 212 | {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, 213 | {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, 214 | ] 215 | 216 | [package.extras] 217 | docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] 218 | testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] 219 | typing = ["typing-extensions (>=4.8)"] 220 | 221 | [[package]] 222 | name = "flake8" 223 | version = "5.0.4" 224 | description = "the modular source code checker: pep8 pyflakes and co" 225 | optional = false 226 | python-versions = ">=3.6.1" 227 | files = [ 228 | {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, 229 | {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, 230 | ] 231 | 232 | [package.dependencies] 233 | mccabe = ">=0.7.0,<0.8.0" 234 | pycodestyle = ">=2.9.0,<2.10.0" 235 | pyflakes = ">=2.5.0,<2.6.0" 236 | 237 | [[package]] 238 | name = "identify" 239 | version = "2.5.36" 240 | description = "File identification library for Python" 241 | optional = false 242 | python-versions = ">=3.8" 243 | files = [ 244 | {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, 245 | {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, 246 | ] 247 | 248 | [package.extras] 249 | license = ["ukkonen"] 250 | 251 | [[package]] 252 | name = "iniconfig" 253 | version = "2.0.0" 254 | description = "brain-dead simple config-ini parsing" 255 | optional = false 256 | python-versions = ">=3.7" 257 | files = [ 258 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 259 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 260 | ] 261 | 262 | [[package]] 263 | name = "mccabe" 264 | version = "0.7.0" 265 | description = "McCabe checker, plugin for flake8" 266 | optional = false 267 | python-versions = ">=3.6" 268 | files = [ 269 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, 270 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, 271 | ] 272 | 273 | [[package]] 274 | name = "mypy" 275 | version = "1.10.1" 276 | description = "Optional static typing for Python" 277 | optional = false 278 | python-versions = ">=3.8" 279 | files = [ 280 | {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, 281 | {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, 282 | {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, 283 | {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, 284 | {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, 285 | {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, 286 | {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, 287 | {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, 288 | {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, 289 | {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, 290 | {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, 291 | {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, 292 | {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, 293 | {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, 294 | {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, 295 | {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, 296 | {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, 297 | {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, 298 | {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, 299 | {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, 300 | {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, 301 | {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, 302 | {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, 303 | {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, 304 | {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, 305 | {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, 306 | {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, 307 | ] 308 | 309 | [package.dependencies] 310 | mypy-extensions = ">=1.0.0" 311 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 312 | typing-extensions = ">=4.1.0" 313 | 314 | [package.extras] 315 | dmypy = ["psutil (>=4.0)"] 316 | install-types = ["pip"] 317 | mypyc = ["setuptools (>=50)"] 318 | reports = ["lxml"] 319 | 320 | [[package]] 321 | name = "mypy-extensions" 322 | version = "1.0.0" 323 | description = "Type system extensions for programs checked with the mypy type checker." 324 | optional = false 325 | python-versions = ">=3.5" 326 | files = [ 327 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 328 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 329 | ] 330 | 331 | [[package]] 332 | name = "nodeenv" 333 | version = "1.9.1" 334 | description = "Node.js virtual environment builder" 335 | optional = false 336 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 337 | files = [ 338 | {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, 339 | {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, 340 | ] 341 | 342 | [[package]] 343 | name = "numpy" 344 | version = "1.24.4" 345 | description = "Fundamental package for array computing in Python" 346 | optional = false 347 | python-versions = ">=3.8" 348 | files = [ 349 | {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, 350 | {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, 351 | {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, 352 | {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, 353 | {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, 354 | {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, 355 | {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, 356 | {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, 357 | {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, 358 | {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, 359 | {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, 360 | {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, 361 | {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, 362 | {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, 363 | {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, 364 | {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, 365 | {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, 366 | {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, 367 | {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, 368 | {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, 369 | {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, 370 | {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, 371 | {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, 372 | {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, 373 | {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, 374 | {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, 375 | {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, 376 | {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, 377 | ] 378 | 379 | [[package]] 380 | name = "numpy" 381 | version = "2.0.0" 382 | description = "Fundamental package for array computing in Python" 383 | optional = false 384 | python-versions = ">=3.9" 385 | files = [ 386 | {file = "numpy-2.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:04494f6ec467ccb5369d1808570ae55f6ed9b5809d7f035059000a37b8d7e86f"}, 387 | {file = "numpy-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2635dbd200c2d6faf2ef9a0d04f0ecc6b13b3cad54f7c67c61155138835515d2"}, 388 | {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:0a43f0974d501842866cc83471bdb0116ba0dffdbaac33ec05e6afed5b615238"}, 389 | {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:8d83bb187fb647643bd56e1ae43f273c7f4dbcdf94550d7938cfc32566756514"}, 390 | {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e843d186c8fb1b102bef3e2bc35ef81160ffef3194646a7fdd6a73c6b97196"}, 391 | {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7696c615765091cc5093f76fd1fa069870304beaccfd58b5dcc69e55ef49c1"}, 392 | {file = "numpy-2.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b4c76e3d4c56f145d41b7b6751255feefae92edbc9a61e1758a98204200f30fc"}, 393 | {file = "numpy-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd3a644e4807e73b4e1867b769fbf1ce8c5d80e7caaef0d90dcdc640dfc9787"}, 394 | {file = "numpy-2.0.0-cp310-cp310-win32.whl", hash = "sha256:cee6cc0584f71adefe2c908856ccc98702baf95ff80092e4ca46061538a2ba98"}, 395 | {file = "numpy-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:ed08d2703b5972ec736451b818c2eb9da80d66c3e84aed1deeb0c345fefe461b"}, 396 | {file = "numpy-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad0c86f3455fbd0de6c31a3056eb822fc939f81b1618f10ff3406971893b62a5"}, 397 | {file = "numpy-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7f387600d424f91576af20518334df3d97bc76a300a755f9a8d6e4f5cadd289"}, 398 | {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:34f003cb88b1ba38cb9a9a4a3161c1604973d7f9d5552c38bc2f04f829536609"}, 399 | {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b6f6a8f45d0313db07d6d1d37bd0b112f887e1369758a5419c0370ba915b3871"}, 400 | {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f64641b42b2429f56ee08b4f427a4d2daf916ec59686061de751a55aafa22e4"}, 401 | {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7039a136017eaa92c1848152827e1424701532ca8e8967fe480fe1569dae581"}, 402 | {file = "numpy-2.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46e161722e0f619749d1cd892167039015b2c2817296104487cd03ed4a955995"}, 403 | {file = "numpy-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0e50842b2295ba8414c8c1d9d957083d5dfe9e16828b37de883f51fc53c4016f"}, 404 | {file = "numpy-2.0.0-cp311-cp311-win32.whl", hash = "sha256:2ce46fd0b8a0c947ae047d222f7136fc4d55538741373107574271bc00e20e8f"}, 405 | {file = "numpy-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd6acc766814ea6443628f4e6751d0da6593dae29c08c0b2606164db026970c"}, 406 | {file = "numpy-2.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:354f373279768fa5a584bac997de6a6c9bc535c482592d7a813bb0c09be6c76f"}, 407 | {file = "numpy-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d2f62e55a4cd9c58c1d9a1c9edaedcd857a73cb6fda875bf79093f9d9086f85"}, 408 | {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:1e72728e7501a450288fc8e1f9ebc73d90cfd4671ebbd631f3e7857c39bd16f2"}, 409 | {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:84554fc53daa8f6abf8e8a66e076aff6ece62de68523d9f665f32d2fc50fd66e"}, 410 | {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73aafd1afca80afecb22718f8700b40ac7cab927b8abab3c3e337d70e10e5a2"}, 411 | {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49d9f7d256fbc804391a7f72d4a617302b1afac1112fac19b6c6cec63fe7fe8a"}, 412 | {file = "numpy-2.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0ec84b9ba0654f3b962802edc91424331f423dcf5d5f926676e0150789cb3d95"}, 413 | {file = "numpy-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:feff59f27338135776f6d4e2ec7aeeac5d5f7a08a83e80869121ef8164b74af9"}, 414 | {file = "numpy-2.0.0-cp312-cp312-win32.whl", hash = "sha256:c5a59996dc61835133b56a32ebe4ef3740ea5bc19b3983ac60cc32be5a665d54"}, 415 | {file = "numpy-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a356364941fb0593bb899a1076b92dfa2029f6f5b8ba88a14fd0984aaf76d0df"}, 416 | {file = "numpy-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e61155fae27570692ad1d327e81c6cf27d535a5d7ef97648a17d922224b216de"}, 417 | {file = "numpy-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4554eb96f0fd263041baf16cf0881b3f5dafae7a59b1049acb9540c4d57bc8cb"}, 418 | {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:903703372d46bce88b6920a0cd86c3ad82dae2dbef157b5fc01b70ea1cfc430f"}, 419 | {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:3e8e01233d57639b2e30966c63d36fcea099d17c53bf424d77f088b0f4babd86"}, 420 | {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cde1753efe513705a0c6d28f5884e22bdc30438bf0085c5c486cdaff40cd67a"}, 421 | {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821eedb7165ead9eebdb569986968b541f9908979c2da8a4967ecac4439bae3d"}, 422 | {file = "numpy-2.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a1712c015831da583b21c5bfe15e8684137097969c6d22e8316ba66b5baabe4"}, 423 | {file = "numpy-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9c27f0946a3536403efb0e1c28def1ae6730a72cd0d5878db38824855e3afc44"}, 424 | {file = "numpy-2.0.0-cp39-cp39-win32.whl", hash = "sha256:63b92c512d9dbcc37f9d81b123dec99fdb318ba38c8059afc78086fe73820275"}, 425 | {file = "numpy-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f6bed7f840d44c08ebdb73b1825282b801799e325bcbdfa6bc5c370e5aecc65"}, 426 | {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9416a5c2e92ace094e9f0082c5fd473502c91651fb896bc17690d6fc475128d6"}, 427 | {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:17067d097ed036636fa79f6a869ac26df7db1ba22039d962422506640314933a"}, 428 | {file = "numpy-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ecb5b0582cd125f67a629072fed6f83562d9dd04d7e03256c9829bdec027ad"}, 429 | {file = "numpy-2.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cef04d068f5fb0518a77857953193b6bb94809a806bd0a14983a8f12ada060c9"}, 430 | {file = "numpy-2.0.0.tar.gz", hash = "sha256:cf5d1c9e6837f8af9f92b6bd3e86d513cdc11f60fd62185cc49ec7d1aba34864"}, 431 | ] 432 | 433 | [[package]] 434 | name = "packaging" 435 | version = "24.1" 436 | description = "Core utilities for Python packages" 437 | optional = false 438 | python-versions = ">=3.8" 439 | files = [ 440 | {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, 441 | {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, 442 | ] 443 | 444 | [[package]] 445 | name = "pathspec" 446 | version = "0.12.1" 447 | description = "Utility library for gitignore style pattern matching of file paths." 448 | optional = false 449 | python-versions = ">=3.8" 450 | files = [ 451 | {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, 452 | {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, 453 | ] 454 | 455 | [[package]] 456 | name = "platformdirs" 457 | version = "4.2.2" 458 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." 459 | optional = false 460 | python-versions = ">=3.8" 461 | files = [ 462 | {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, 463 | {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, 464 | ] 465 | 466 | [package.extras] 467 | docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] 468 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] 469 | type = ["mypy (>=1.8)"] 470 | 471 | [[package]] 472 | name = "pluggy" 473 | version = "1.5.0" 474 | description = "plugin and hook calling mechanisms for python" 475 | optional = false 476 | python-versions = ">=3.8" 477 | files = [ 478 | {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, 479 | {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, 480 | ] 481 | 482 | [package.extras] 483 | dev = ["pre-commit", "tox"] 484 | testing = ["pytest", "pytest-benchmark"] 485 | 486 | [[package]] 487 | name = "pre-commit" 488 | version = "2.21.0" 489 | description = "A framework for managing and maintaining multi-language pre-commit hooks." 490 | optional = false 491 | python-versions = ">=3.7" 492 | files = [ 493 | {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, 494 | {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, 495 | ] 496 | 497 | [package.dependencies] 498 | cfgv = ">=2.0.0" 499 | identify = ">=1.0.0" 500 | nodeenv = ">=0.11.1" 501 | pyyaml = ">=5.1" 502 | virtualenv = ">=20.10.0" 503 | 504 | [[package]] 505 | name = "py" 506 | version = "1.11.0" 507 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 508 | optional = false 509 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 510 | files = [ 511 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 512 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 513 | ] 514 | 515 | [[package]] 516 | name = "pycodestyle" 517 | version = "2.9.1" 518 | description = "Python style guide checker" 519 | optional = false 520 | python-versions = ">=3.6" 521 | files = [ 522 | {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, 523 | {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, 524 | ] 525 | 526 | [[package]] 527 | name = "pyflakes" 528 | version = "2.5.0" 529 | description = "passive checker of Python programs" 530 | optional = false 531 | python-versions = ">=3.6" 532 | files = [ 533 | {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, 534 | {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, 535 | ] 536 | 537 | [[package]] 538 | name = "pytest" 539 | version = "6.2.5" 540 | description = "pytest: simple powerful testing with Python" 541 | optional = false 542 | python-versions = ">=3.6" 543 | files = [ 544 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, 545 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, 546 | ] 547 | 548 | [package.dependencies] 549 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 550 | attrs = ">=19.2.0" 551 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 552 | iniconfig = "*" 553 | packaging = "*" 554 | pluggy = ">=0.12,<2.0" 555 | py = ">=1.8.2" 556 | toml = "*" 557 | 558 | [package.extras] 559 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 560 | 561 | [[package]] 562 | name = "pyyaml" 563 | version = "6.0.1" 564 | description = "YAML parser and emitter for Python" 565 | optional = false 566 | python-versions = ">=3.6" 567 | files = [ 568 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, 569 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, 570 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, 571 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, 572 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, 573 | {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, 574 | {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, 575 | {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, 576 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, 577 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, 578 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, 579 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, 580 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, 581 | {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, 582 | {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, 583 | {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, 584 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, 585 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, 586 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, 587 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, 588 | {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, 589 | {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, 590 | {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, 591 | {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, 592 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, 593 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, 594 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, 595 | {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, 596 | {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, 597 | {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, 598 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, 599 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, 600 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, 601 | {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, 602 | {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, 603 | {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, 604 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, 605 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, 606 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, 607 | {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, 608 | {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, 609 | {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, 610 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, 611 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, 612 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, 613 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, 614 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, 615 | {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, 616 | {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, 617 | {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, 618 | {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, 619 | ] 620 | 621 | [[package]] 622 | name = "rapidfuzz" 623 | version = "2.15.2" 624 | description = "rapid fuzzy string matching" 625 | optional = false 626 | python-versions = ">=3.7" 627 | files = [ 628 | {file = "rapidfuzz-2.15.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b2e64e08588965b2490ee6b581d3901dd207ec3f6919b1c8da495183acfde953"}, 629 | {file = "rapidfuzz-2.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0af367ecb515ae695d7da21b0bd05784f388621e9d6a2e21dc96e6ba5d18d95f"}, 630 | {file = "rapidfuzz-2.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:892d0d75f0b820d949b0bf9502f746cfcbaab98d8a47653fa8369607fde250f1"}, 631 | {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcf1d564ec948a4bf0750252579871be1790de66200f4cf8d624446017d74ee9"}, 632 | {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab2f86733fe34cd825b6cbc688d41b7eb19ae0ce1ea7dc57eac13862d4b9ecb5"}, 633 | {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8bdc497a8930428fa35158c58a744ddaa930621b80adfb61884456d8f184288a"}, 634 | {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97f6c4948ca07ad1a30e70da56ec672422ef6bf18d10b6a881e7a64ba73a126d"}, 635 | {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f3e2cc54edffd62ae38a03802b79c0f0cec6c2f89819607350fb5c4c00442d7"}, 636 | {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0a252ccb39d628d0f68bab80ba18a02e0d1853a0ec71991e665a6bf81a28c79a"}, 637 | {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ff82edd7ff9796e2ca349aa583fcb6b9ae96db0b6c5a76dcf0c1f67b1cb86964"}, 638 | {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0860877f455833e5ed7113e859a9b2bf9670b22fdc7a48b81384a04c4a8e8a48"}, 639 | {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:1a78c75ad082fdd58fdcf04551b7737c96aa9e870f1b008b881fc179e7dc6208"}, 640 | {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a9df54f67a22a2447b8b6648880de9ede5e2a2e568644e1de770df9bef5c2fb4"}, 641 | {file = "rapidfuzz-2.15.2-cp310-cp310-win32.whl", hash = "sha256:055e85bb1237142da4ed024f9986c3720d484036f8dd550b090582f288b71bb9"}, 642 | {file = "rapidfuzz-2.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:8f220df380c127ef8a9129d8878dabf99ed0f543597cf81dfdd30eca03843666"}, 643 | {file = "rapidfuzz-2.15.2-cp310-cp310-win_arm64.whl", hash = "sha256:49972e202251ba60de41a7add8e86a055478020eabf3339300f46a8fdc35d048"}, 644 | {file = "rapidfuzz-2.15.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29352510bcc2b7c3c7f3c1ab6f4c2115dc640cd79a9dc8e01adbae19fb96d359"}, 645 | {file = "rapidfuzz-2.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1ae3f741b9b3e95908158e6e56a5f11c1abc51754801dccd495e5cba734c541e"}, 646 | {file = "rapidfuzz-2.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a716bbded611cc82f7b27dcd7335b7bae49706c97a8738283464ff1536e7407"}, 647 | {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ff36fb50f02259402d7cbdc96f75671b2cb14550db5ad6534a09a7f4940d796"}, 648 | {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d60a2368e2564155d7209143a6b1dafa1eb457f31cf44698f917cba608d2341f"}, 649 | {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c02fd6d75de19633f622daf6584cb6ed3148eac3a2b6b08fd3539c166de2921f"}, 650 | {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5c875da0e0c9709dbdc6e33a7f061192e98943817e6d0e1f5d1d8b07050e349"}, 651 | {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb74dcfadf0c5f520074455fe51fa0f62876e5473f5f60521d153afef888ef70"}, 652 | {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5b31f65137e8e45c4fb2dda394bb31598cff8290fb0ce5e66c8cf47d1bc554cb"}, 653 | {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:689008633f88cf8802dbd281ac745775aeeee67525d532fcbabda0c8bc5b2e32"}, 654 | {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:02fd52352346c965fdc9de9d26f55d61941cc27c876a589eeb3f4efdb7dffdb1"}, 655 | {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:454ab8b5c8fc526243133dab013f0a3355efcc1200829cfba7ef56280c7763fc"}, 656 | {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fd40f263d1ad1cdd4b657e867654674315eea9abf3fce64269610b7bc81265ee"}, 657 | {file = "rapidfuzz-2.15.2-cp311-cp311-win32.whl", hash = "sha256:66db4817c54a6ca91234959c4f6d0cb1fd943ddfb379ee7f9e6dce99b522554e"}, 658 | {file = "rapidfuzz-2.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:3f8eaf74105ffea1d15198b109ff0ca7b6dccafc61e05fa5f98a53d925707c57"}, 659 | {file = "rapidfuzz-2.15.2-cp311-cp311-win_arm64.whl", hash = "sha256:ed0ec102b5e405d7562e4df05729a89467ae5c8a364c52fcf8c129398e82e6c5"}, 660 | {file = "rapidfuzz-2.15.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c0c8475f029a50bf65571b59d332fccd3eb33c5e49283868490a973e9ca7c33c"}, 661 | {file = "rapidfuzz-2.15.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ee9ee24eb431d5f73d0b255dc8e66272967a58cd6670cca984a81bbfc7dde904"}, 662 | {file = "rapidfuzz-2.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1ecd818c108cefea2c02a9a716e223f811e612a050c8625555336b65d1cabef"}, 663 | {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3eda119ebcf501dc35054abd9a187b5249b3d93b3965485371efb48e735b72c"}, 664 | {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7ba83d0846991f67c2ec12ff8530b5e0f929e32a57352080b5f95aade0a62e"}, 665 | {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c279864902a9538b17547e0d9399f05f36ebb9f3356bc5bc4cec2ba137fa5a17"}, 666 | {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c94e247011fa7eea14d210123ebda2ecdf98ccc114254353edb4501ee8a19d7"}, 667 | {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675c9052b3a04a4b33c92f0b8952ef2439163853422cc583286351ee82fc4d26"}, 668 | {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c2d64820ae7a795082208a2d762c6a291aca116b86e35c2831e468ae3d4bb5cd"}, 669 | {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:c0f12cc4a8216edfaa0511aae34d8b2f824a05cfe5a26a08de9cf180ae584e88"}, 670 | {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e27da009ef39dc64297bcdf09c8d4c79ac90d0015fcf0a01af2a802cd7e1803"}, 671 | {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:ea541d56fbb7de717a013790c2bce655252da220f23db0c6ce24f628cbe228e6"}, 672 | {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9f52338e4e69aff4260c84275c7a704d198315b9b84303e67e584971409347d0"}, 673 | {file = "rapidfuzz-2.15.2-cp312-cp312-win32.whl", hash = "sha256:d5550e0078b2618c4ea7ea761053337eb7c5f5cc515f4941d8108ce9b0c7ee8c"}, 674 | {file = "rapidfuzz-2.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:19f72cfe2553c83c5e383851aba2891dafbb6446b6ae1ec0637333558ddd564e"}, 675 | {file = "rapidfuzz-2.15.2-cp312-cp312-win_arm64.whl", hash = "sha256:423ef2ca785da77cd081d5bbc57035dc9b91500008a1b8e8e811a0ba3871a5ee"}, 676 | {file = "rapidfuzz-2.15.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0a02f1b08879a74aa7b4e562823f67a2e913fe3bd18c5346d9270d16fc588500"}, 677 | {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a100ca26804b9ac2b2c0f70c632102bc0005d2cafe6d748f5d01dbe569c378bf"}, 678 | {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e9fb88659cff92eba1b441efe426a4c349372137ee713b3a3933cc6ead73234"}, 679 | {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:58073d3ebed8c0f51e163654dcb5e34f1e8b67f7b23361441861c6021243184b"}, 680 | {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f55ad06ff79c2ffa3d1f5b38ce8f3082fa4db57c04be7de85243bd0625ca4ef"}, 681 | {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ceecb57ec9e5c0d5bd9bd2881731c59cdc9a2c51711fd0b29b5bf14bdcab465f"}, 682 | {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6c32c855e16ef3890037569f6f1299857172c674cd8946244e5fb7d5cacb771a"}, 683 | {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e46f82fda6f969da8be5a8f33a057b2a9c6e7b80ab8679344a72e6fb708a48fc"}, 684 | {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:6edc9b138797c60c1276171d8c97f53b17e304ade37c022ff97b1e995f79ba79"}, 685 | {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b32e4fd756a32f92b6f8b707a682ab4054b90c835021c01d81baba22f6277172"}, 686 | {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5fb89d3a8d389eca258aba913adc81a8b8231b48896abbcb2f05768455584c4e"}, 687 | {file = "rapidfuzz-2.15.2-cp37-cp37m-win32.whl", hash = "sha256:03ceea6cc9e4442379aa8581fbe61bad6e12d7938b16fbdc8442c8d915ad1154"}, 688 | {file = "rapidfuzz-2.15.2-cp37-cp37m-win_amd64.whl", hash = "sha256:cb9f24fafb5ed77fc2ce23b1d8351efcfdb4c05b5f3b96bf004e89344a3d30ed"}, 689 | {file = "rapidfuzz-2.15.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:aab133bea22acbd3fa3740989a2f21d0e275efede2bf406a25a84392086c32f9"}, 690 | {file = "rapidfuzz-2.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4e110224e0de4fe4876224104a79550d18df15459fe94adf24b4b644e31d69cc"}, 691 | {file = "rapidfuzz-2.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:780b006bd007e4a071a9c022733f56b0df1f8c269bb7e9dbe079a79e8d9d3b8d"}, 692 | {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:898bee3fd785ee695d4cb0d3c689407809cafca472851904aa78143ca6634903"}, 693 | {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34623f51ed5dcbb2ddb97b2fefda34e7b53a047c71aac5ec6b72e42d5263f8b2"}, 694 | {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02b3612c9318006290e6e6d82f1f98b83aa4cf062075c5ea03fac71ba4d31499"}, 695 | {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dd0aab9ffab0010ae28b60f64c98c09c93086b3dc0cb3da863e53a3ca14a2bd"}, 696 | {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e772677a84a166531f975301cb91db234a56eb5b6785e79ff5cb335251580efc"}, 697 | {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7a670aed23d9a8d27a0031fa059e8f50f3f7287bd5a075a448251029794de9"}, 698 | {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:830f799e5ec534633dee3b26c6d5398461dd3ced22118ab590f7fd0f91263058"}, 699 | {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e427a9c9c1a8adac7b0293ddfe8f5885edf4f425cfd8a3b7ceae20434ec0663c"}, 700 | {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3a3df80a264a999a120e637f98a1460d4f2c815323dd605e2022eef97db55448"}, 701 | {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1496540d2ce8b1b9f340e652b9306674fa657d8d3a0b9629421cf31ace219092"}, 702 | {file = "rapidfuzz-2.15.2-cp38-cp38-win32.whl", hash = "sha256:aabd9da406fec009c08d2cd1bfa444ee568edf8e7c9a9d5e609885fc81c243a3"}, 703 | {file = "rapidfuzz-2.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:d21c66b15fbe253d48399a9d9db361ab2b3462a59b78c9279d9d7d347f5ded91"}, 704 | {file = "rapidfuzz-2.15.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ef4dea11b87234e8b08ee47df9d869ae071bdacb5e55df82673ab9fa622f1e0"}, 705 | {file = "rapidfuzz-2.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ee3d9bc953f232bffcbd973137505f6cf5be5ed9c2cdc5e4a5db4be33bf5a734"}, 706 | {file = "rapidfuzz-2.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:efb94f6adbbbdacac9f687eb151ae9220ee9f141bb259fe07e82a2087114c17e"}, 707 | {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9c3e07d13661871aebc325b9b3acbd42355a1df1e21ad0435fc81980fd20607"}, 708 | {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01bae563a010900abba857e485c3747a78d61c88431cc3d9bea894c7c3e521f"}, 709 | {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09187df670e344468597b2c6f5ddc7651be75c4b594baa62c9261a144e5c058"}, 710 | {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcbfe5497c93a1b8717ea38b41b47f7e9d155fbc36a6bbfa84b8c901875465af"}, 711 | {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f997a93b85c5798fe139a46c68c85de06ff75b4fd52d52463e46573bff39774"}, 712 | {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:199676b8a19746017a0fbad0eb11380cbda4f635b6d2ee477544743b7f99d947"}, 713 | {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:499a170088049258d5118bff8cf88f88ef6054544edbea0f2920eba8669e5eb9"}, 714 | {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:a69ebe7b493557c425ca1d64bf0b5599f0405772b5179070adc2f62f7867836f"}, 715 | {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:00bd97cd31aad049400b70e0872b54457c4769b296176d5b064f6a5d6391909f"}, 716 | {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cadabe1287314bc5053f57c6043df04e33cf5fba33514ca0f4c7b0b8476063a0"}, 717 | {file = "rapidfuzz-2.15.2-cp39-cp39-win32.whl", hash = "sha256:301709491a7960473c34501602cd85a7653df7e0d4189c0ded1e0fd86a83b6ca"}, 718 | {file = "rapidfuzz-2.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:9c968a2330b6f2de93e6d54ef7ebd5e5724ee730cd6f225e977cebc7af1df366"}, 719 | {file = "rapidfuzz-2.15.2-cp39-cp39-win_arm64.whl", hash = "sha256:c6776c27385f3fe5810f3c389f01957d5fa6c3c7f7a76fd9815f2933674f787f"}, 720 | {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0b4c632b684478fd8780970685a0c575a5bee65692727ff9898acf75d61cb3ff"}, 721 | {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b1cfca399461e1f534fbeb3c87f39f2c37ed71f8d1dfb02b78a5b3f81bf0ef"}, 722 | {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba35ec7256a86270a5e2d193ff0089cf84787a1aa94a48f5f6105f86feb8ca38"}, 723 | {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdfc137bbe2e942321f725004395444d2594077932ad55f927d6b6e884c09142"}, 724 | {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:153366a00ea22e79f051298fb9606bf9472bca5ce1b82319070fcbea2f7b97d7"}, 725 | {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6bf1c60432755ed8ab5870a932b7c9382435a240d727d3b5e68f9ff9f83a3556"}, 726 | {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a358eb275eadad0ac44f0fdb2255d6b373908c742f94e06b2190dbfaaaaa49b8"}, 727 | {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34136ab5bbd1b9643f9072102a88471995100b5d734cfaa946d3b63e332e653"}, 728 | {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:796e53c5f78c159aff8e5003bca41bfe007c6a63ee7e7a289765a7db30429197"}, 729 | {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2ce4a91be05c28b57d5019b09cf0970305760623e34da95f2cddd9067e7fe91d"}, 730 | {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:237d5b4cbfacdef0a84f2ead0b4819c586bb74d05f4a380bd2f8489464b7b7fa"}, 731 | {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dff970af0474d7d551a953a0075840ced30315d4885e038a289857ed33365"}, 732 | {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c536fbbebb496a76cac3a45f139bf023807b1fb6e2262e77f875fc9b6802ec4e"}, 733 | {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e85579a698c9436c2dac1583d4b07cca635faeb9a7adeab03d42938ec0fe9f58"}, 734 | {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:77c540546c0ea7cb229cd9823f9cd174c93988657727880bfdd6db7f353f93d6"}, 735 | {file = "rapidfuzz-2.15.2.tar.gz", hash = "sha256:bfc1d38a7adcbe8912f980a5f46f27a801dd8655582ff0d4a2c0431c02b7ce33"}, 736 | ] 737 | 738 | [package.extras] 739 | full = ["numpy"] 740 | 741 | [[package]] 742 | name = "six" 743 | version = "1.16.0" 744 | description = "Python 2 and 3 compatibility utilities" 745 | optional = false 746 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 747 | files = [ 748 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 749 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 750 | ] 751 | 752 | [[package]] 753 | name = "toml" 754 | version = "0.10.2" 755 | description = "Python Library for Tom's Obvious, Minimal Language" 756 | optional = false 757 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 758 | files = [ 759 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 760 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 761 | ] 762 | 763 | [[package]] 764 | name = "tomli" 765 | version = "2.0.1" 766 | description = "A lil' TOML parser" 767 | optional = false 768 | python-versions = ">=3.7" 769 | files = [ 770 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 771 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 772 | ] 773 | 774 | [[package]] 775 | name = "tox" 776 | version = "3.28.0" 777 | description = "tox is a generic virtualenv management and test command line tool" 778 | optional = false 779 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 780 | files = [ 781 | {file = "tox-3.28.0-py2.py3-none-any.whl", hash = "sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea"}, 782 | {file = "tox-3.28.0.tar.gz", hash = "sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640"}, 783 | ] 784 | 785 | [package.dependencies] 786 | colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} 787 | filelock = ">=3.0.0" 788 | packaging = ">=14" 789 | pluggy = ">=0.12.0" 790 | py = ">=1.4.17" 791 | six = ">=1.14.0" 792 | tomli = {version = ">=2.0.1", markers = "python_version >= \"3.7\" and python_version < \"3.11\""} 793 | virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" 794 | 795 | [package.extras] 796 | docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] 797 | testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)"] 798 | 799 | [[package]] 800 | name = "typing-extensions" 801 | version = "4.12.2" 802 | description = "Backported and Experimental Type Hints for Python 3.8+" 803 | optional = false 804 | python-versions = ">=3.8" 805 | files = [ 806 | {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, 807 | {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, 808 | ] 809 | 810 | [[package]] 811 | name = "virtualenv" 812 | version = "20.26.3" 813 | description = "Virtual Python Environment builder" 814 | optional = false 815 | python-versions = ">=3.7" 816 | files = [ 817 | {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, 818 | {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, 819 | ] 820 | 821 | [package.dependencies] 822 | distlib = ">=0.3.7,<1" 823 | filelock = ">=3.12.2,<4" 824 | platformdirs = ">=3.9.1,<5" 825 | 826 | [package.extras] 827 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] 828 | test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] 829 | 830 | [metadata] 831 | lock-version = "2.0" 832 | python-versions = ">=3.8,<=3.13" 833 | content-hash = "bd67aeb58d68e8fa3ec1307fb74d955db205783fbf8d38c77a4cb4ac38ff8386" 834 | --------------------------------------------------------------------------------