Compare commits

..

11 Commits

Author SHA1 Message Date
a250ed85ac updated readme 2025-11-17 09:32:04 +01:00
ef72904fb5 integrated scgenerator to remove dependency 2025-11-17 08:56:30 +01:00
Benoît Sierro
e38c5b87ee better help text 2023-07-10 16:44:22 +02:00
Benoît Sierro
161f7dd8ea better build script 2023-07-10 16:35:19 +02:00
Benoît Sierro
7ac5b87016 fixed power label 2023-07-10 16:34:59 +02:00
Benoît Sierro
a462e80882 added build script 2023-07-10 16:13:30 +02:00
Benoît Sierro
1df45b1590 updated readme with correct url and interface 2023-07-10 16:04:07 +02:00
Benoît Sierro
3fbd8da66f added refractive index plot 2023-07-10 16:03:45 +02:00
Benoît Sierro
7b41673594 gitinore fix 2023-03-21 11:22:17 +01:00
Benoît Sierro
fd6590d819 docs + plot title 2023-03-21 11:20:36 +01:00
Benoît Sierro
6da66b5990 Better handling of no ZDW found 2023-03-21 10:52:21 +01:00
19 changed files with 6205 additions and 191 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
.conda-env
dispersion_config.toml
pyrightconfig.json
.DS_Store

View File

@@ -1,16 +1,65 @@
# Crash course on Python installation, with a few small side tracks
# Installation
1. If not already done so, create a virtual environment to contain all the packages required. Python 3.10 is recommended. The command below will create a new environment named 'app-env' with the latest version of Python 3.10.
conda create -y -n app-env python=3.10
I recommend installing using [uv](https://github.com/astral-sh/uv). Follow uv's installation instructions if you don't already have it. You can check (and update) by running the following command in a terminal:
```sh
uv self update
```
You may need to close and re-open your terminal after uv's first installation for all the changes to take effect.
2. activate said environment
Install `dispersionapp` by running
```sh
uv tool install https://git.dedebenui.me/dedebenui/dispersionapp.git
```
conda activate app-env
To update an existing installation, run
```sh
uv tool install --upgrade https://git.dedebenui.me/dedebenui/dispersionapp.git
```
3. The prompt should now read '(app-env)' on the left. The app is not published on Github or anywhere else. The link below points to my own personnal home server (I didn't find any way of getting a direct download link You are now ready to install everything with this command:
Check that everything works by running
```
dispersionapp --version
```
# Usage
Run the app with the command:
```sh
dispersionapp
```
Run `dispersionapp --help` to see available options.
The app saves a config file in your home directory. If you want to specify a custom config file location, use the `-c / --config` option. For example:
```sh
dispersionapp -c my_config.toml
```
This will create the file `my_config.toml` in your current working directory if it doesn't already exist.
Selecting the gas is not part of the GUI. To change it, you can either manually modify the configuration file, or you can run `dispersionapp` with the `-g / --gas` option:
```sh
dispersionapp --gas helium
```
This will start the app with Helium selected and save it in the config. Subsequent starts will remember this selection, unless you start the app with a different config file, or move/delete/rename the existing one.
# Interface
At the very top is a summary of the configuration as well as a few physical properties derived from the current parameters.
Below, you will find the parameter list. Each parameter has a couple elements. From left to right:
- The name of the parameter.
- A slider to quickly explore values.
- Arrow buttons to move from one value to the next.
- A text box where you can input your desired value. The closest possible value will then be selected. Possible values are hard-coded. I might add an option for custom values later on.
To navigate the plot:
- Left-click and drag to move around.
- Right-click and drag to zoom.
- Scroll wheel to zoom.
- For each of these movements, you can do it while the cursor is hovering over one of the axis. In that case, only that axis is affected.
- To go back to a view that fits everything, click on the small "A" at the bottom left. This is not ideal for the dispersion plot because of all the resonances, so you can find another reset button in the parameter list.
- To hide/show a line, click on it in the legend. You can also click and drag the legend to move it around.
- Click and drag between two plots to resize them.
- Click and drag on the purple title bar to move plots around (it's a bit buggy).
- Double-click on the purple title bar (left side or top) to pop out the plot in its own window.
pip install https://bao.dedebenui.me/s/f3KgiqMq7giN73i/download

View File

@@ -1,17 +1,19 @@
[project]
name = "dispersionapp"
version = "0.1.0"
version = "0.2.2"
description = "Model hollow capillary and revolver fiber interactively"
authors = [{ name = "Benoît Sierro", email = "benoit.sierro@unibe.ch" }]
authors = [{ name = "Dedebenui", email = "dedebenui@protonmail.com" }]
requires-python = ">=3.13"
dependencies = [
"scgenerator @ git+https://github.com/bsierro/scgenerator.git",
"click",
"pydantic",
"pydantic >= 2",
"tomli",
"tomli_w",
"PySide6 >= 6.4.0",
"pyqtgraph >= 0.13.1",
"numba>=0.62.1",
"scipy>=1.16.3",
]
license = { file = "LICENSE" }
@@ -25,5 +27,17 @@ classifiers = [
dispersionapp = "dispersionapp.__main__:main"
[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools >= 65.0.0"]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.pyright]
exclude = [".venv"]
venvPath = "."
venv = ".venv"
typeCheckingMode = "off"
[dependency-groups]
dev = [
"matplotlib>=3.10.7",
]

View File

@@ -3,7 +3,7 @@ import sys
import click
from dispersionapp.core import DEFAULT_CONFIG_FILE
from dispersionapp.core import DEFAULT_CONFIG_FILE, Config
from dispersionapp.gui import app
@@ -11,12 +11,17 @@ from dispersionapp.gui import app
@click.option(
"-c",
"--config",
"config_file",
default=DEFAULT_CONFIG_FILE,
help="configuration file in TOML format",
type=click.Path(file_okay=True, dir_okay=False, resolve_path=True),
)
@click.option("-g", "--gas", help="Gas. Must be one of ", type=str)
@click.version_option()
def main(config: os.PathLike):
def main(config_file: os.PathLike, gas: str | None = None):
config = Config.load(config_file)
if gas is not None:
config.gas = gas.lower()
app(config)

View File

@@ -1,33 +1,39 @@
from __future__ import annotations
import os
import sys
from pathlib import Path
from typing import NamedTuple
from typing import Annotated, NamedTuple, Self
import numpy as np
import scgenerator as sc
import tomli
import tomli_w
from pydantic import BaseModel, PrivateAttr, ValidationError, confloat, conint
from pydantic import BaseModel, PrivateAttr, ValidationError, Field
DEFAULT_CONFIG_FILE = "dispersion_config.toml"
import dispersionapp.physics.units as units
import dispersionapp.physics.materials as materials
import dispersionapp.physics.pulse as pulse
import dispersionapp.physics.fiber as fiber
import dispersionapp.math as math
DEFAULT_CONFIG_FILE = Path.home() / "dispersion_config.toml"
class CurrentState(BaseModel):
core_diameter_um: float
pressure_mbar: float
wall_thickness_um: float
num_resonances: Annotated[int, Field(ge=6, le=40)] = 6
n_tubes: int
gap_um: float
t_fwhm_fs: float
class Config(BaseModel):
wl_min: confloat(ge=100, le=1000) = 160
wl_max: confloat(ge=500, le=6000) = 1600
wl_pump: confloat(ge=200, le=6000) = 800
rep_rate: confloat(gt=0) = 8e3
num_resonances: conint(ge=6, le=20) = 6
wl_min: Annotated[float, Field(ge=100, le=1000)] = 160
wl_max: Annotated[float, Field(ge=500, le=6000)] = 1600
wl_pump: Annotated[float, Field(ge=200, le=6000)] = 800
rep_rate: Annotated[float, Field(gt=0)] = 8e3
gas: str = "argon"
safety_factor: float = 10.0
current_state: CurrentState | None = None
@@ -35,7 +41,7 @@ class Config(BaseModel):
_file_name: Path = PrivateAttr()
@classmethod
def load(cls, config_file: str | None = None) -> Config:
def load(cls, config_file: os.PathLike | None = None) -> Self:
config_file = Path(config_file or DEFAULT_CONFIG_FILE)
if not config_file.exists():
config_file.touch()
@@ -45,7 +51,7 @@ class Config(BaseModel):
try:
out = cls(**d)
except ValidationError as e:
s = f"invalid input in config file {config_file}:\n{e}"
s = f"invalid input in config file {config_file}:\n{e}\ncreating new config"
print(s)
sys.exit(1)
out._file_name = Path(config_file)
@@ -54,16 +60,24 @@ class Config(BaseModel):
def save(self):
tmp = self._file_name.parent / f"{self._file_name.name}.tmp"
with open(tmp, "wb") as file:
tomli_w.dump(self.dict(), file)
tomli_w.dump(self.model_dump(), file)
tmp.replace(self._file_name)
def update_current(
self, core_diameter_um, pressure_mbar, wall_thickness_um, n_tubes, gap_um, t_fwhm_fs
self,
core_diameter_um: float,
pressure_mbar: float,
wall_thickness_um: float,
num_resonances: int,
n_tubes: int,
gap_um: float,
t_fwhm_fs: float,
):
self.current_state = CurrentState(
core_diameter_um=core_diameter_um,
pressure_mbar=pressure_mbar,
wall_thickness_um=wall_thickness_um,
num_resonances=num_resonances,
n_tubes=n_tubes,
gap_um=gap_um,
t_fwhm_fs=t_fwhm_fs,
@@ -80,12 +94,16 @@ class LimitValues(NamedTuple):
def b2(w, n_eff):
dw = w[1] - w[0]
beta = sc.fiber.beta(w, n_eff)
return sc.math.differentiate_arr(beta, 2, 4, dw)
beta = fiber.beta(w, n_eff)
return math.differentiate_arr(beta, 2, 4, dw)
def N_sf_max(
wl: np.ndarray, t0: float, wl_zero_disp: float, gas: sc.materials.Gas, safety: float = 10.0
wl: np.ndarray,
t0: float,
wl_zero_disp: float,
gas: materials.Gas,
safety: float = 10.0,
) -> np.ndarray:
"""
maximum soliton number according to self focusing
@@ -97,30 +115,34 @@ def N_sf_max(
def N_ion_max(
wl: np.ndarray, t0: float, wl_zero_disp: float, gas: sc.materials.Gas, safety: float = 10.0
wl: np.ndarray,
t0: float,
wl_zero_disp: float,
gas: materials.Gas,
safety: float = 10.0,
) -> np.ndarray:
"""
eq. S16 in Travers2019
"""
ind = sc.math.argclosest(wl, wl_zero_disp)
ind = math.argclosest(wl, wl_zero_disp)
f = np.gradient(np.gradient(gas.sellmeier.chi(wl), wl), wl)
factor = (sc.math.u_nm(1, 1) / sc.units.c) ** 2 * (0.5 * wl / np.pi) ** 3
factor = (math.u_nm(1, 1) / units.c) ** 2 * (0.5 * wl / np.pi) ** 3
delta = factor * (f / f[ind] - 1)
denom = safety * np.pi * wl * np.abs(delta) * f[ind]
return t0 * sc.math.u_nm(1, 1) * np.sqrt(gas.n2() * gas.barrier_suppression / denom)
return t0 * math.u_nm(1, 1) * np.sqrt(gas.n2() * gas.barrier_suppression / denom)
def solition_num(
t0: float, w0: float, beta2: float, n2: float, core_radius: float, peak_power: float
) -> float:
gamma = sc.fiber.gamma_parameter(n2, w0, sc.fiber.A_eff_marcatili(core_radius))
ld = sc.pulse.L_D(t0, beta2)
gamma = fiber.gamma_parameter(n2, w0, fiber.effective_area_marcatili(core_radius))
ld = pulse.dispersion_length(t0, beta2)
return np.sqrt(gamma * ld * peak_power)
def energy(
t0: float, w0: float, beta2: float, n2: float, core_radius: float, solition_num: float
) -> float:
gamma = sc.fiber.gamma_parameter(n2, w0, sc.fiber.A_eff_marcatili(core_radius))
gamma = fiber.gamma_parameter(n2, w0, fiber.effective_area_marcatili(core_radius))
peak_power = solition_num**2 * abs(beta2) / (t0**2 * gamma)
return sc.pulse.P0_to_E0(peak_power, t0, "sech")
return pulse.P0_to_E0(peak_power, t0, "sech")

View File

@@ -0,0 +1,10 @@
# `materials.json`
Contains material property like Sellmeir coefficients, nonlinear refractive index and Van der Waals constants.
Sources are embeded in the document and are completed as such:
Van der Waals constants : https://en.wikipedia.org/wiki/Van_der_Waals_constants_(data_page)
Chi3 : Wahlstrand 2012
# `raman_response.csv`
Raman impulse response recovered from measured gain spectrum. This is used then `raman_type` is set to `"measured"` (Stolen1989).

View File

View File

@@ -0,0 +1,449 @@
{
"air":
{
"a": 0.1358,
"atomic_mass": 4.809e-26,
"atomic_number": 7.14,
"b": 3.64e-5,
"kerr":
{
"P0": 101325,
"T0": 293.15,
"n2": 4e-23,
"source": "Nibbering, E., Grillon, G., Franco, M.A., Prade, B., Mysyrowicz, A., 1997. JOSA B 14, 650660."
},
"sellmeier":
{
"B":
[
57921050000,
1679170000
],
"C":
[
2.380185e+14,
5.7362e+13
],
"P0": 101325,
"T0": 288.15,
"kind": 2
}
},
"argon":
{
"a": 0.1355,
"atomic_mass": 6.6338e-26,
"atomic_number": 18,
"b": 3.201e-5,
"ionization_energy": 2.5249661793774e-18,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 9.7e-24,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
2501410000,
500283000,
52234300000
],
"C":
[
9.1012e+13,
8.7892e+13,
2.1402e+14
],
"P0": 101325,
"T0": 273.15,
"kind": 2,
"source": "A. Bideau-Mehu, Y. Guern, R. Abjean, A. Johannin-Gilles. Measurement of refractive indices of neon, argon, krypton and xenon in the 253.7-140.4 nm wavelength range. Dispersion relations and estimated oscillator strengths of the resonance lines. J. Quant. Spectrosc. Rad. Transfer 25, 395-402 (1981)"
}
},
"argon_alt":
{
"a": 0.1355,
"atomic_mass": 6.6338e-26,
"atomic_number": 18,
"b": 3.201e-5,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 9.7e-24,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
0.0002033229,
0.0003445831
],
"C":
[
2.0612e-16,
8.066e-15
],
"P0": 101325,
"T0": 273.15,
"kind": 1,
"source": "A. Börzsönyi, Z. Heiner, M. P. Kalashnikov, A. P. Kovács, and K. Osvay, Dispersion measurement of inert gases and gas mixtures at 800 nm, Appl. Opt. 47, 4856-4863 (2008)"
}
},
"argon_alt2":
{
"a": 0.1355,
"b": 3.201e-5,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 9.7e-24,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
0.030182943
],
"C":
[
1.44e+14
],
"P0": 101325,
"T0": 273.15,
"const": 6.7867e-5,
"kind": 2,
"source": "E. R. Peck and D. J. Fisher. Dispersion of argon, J. Opt. Soc. Am. 54, 1362-1364 (1964)"
}
},
"d-zlaf52la":
{
"sellmeier":
{
"B":
[
-8487502830,
3.1753525,
3.71301651e-14,
-1.09609062e-27,
2.4418582e-40,
-8.94583294e-54
],
"C": [],
"kind": 3,
"reference":
[
"CDGM Zemax catalog 2017-09 (obtained from http://www.cdgmgd.com)"
]
}
},
"e7":
{
"sellmeier":
{
"B":
[
0,
7.2e-15,
3e-28
],
"C": [],
"kind": 3,
"reference":
[
"J. Li, C. H. Wen, S. Gauza, R. Lu and S. T. Wu. Refractive indices of liquid crystals for display applications, J. Disp. Technol. 1, 51-61, 2005"
]
}
},
"helium":
{
"a": 0.00346,
"atomic_mass": 6.646477e-27,
"atomic_number": 2,
"b": 2.38e-5,
"ionization_energy": 3.9393356074281e-18,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 3.1e-25,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
2.16463842e-5,
2.10561127e-7,
4.7509272e-5
],
"C":
[
-6.80769781e-16,
5.13251289e-15,
3.18621354e-15
],
"P0": 101325,
"T0": 273.15,
"kind": 1,
"source": "A. Ermolov, K. F. Mak, M. H. Frosz, J. C. Travers, P. St. J. Russell, Supercontinuum generation in the vacuum ultraviolet through dispersive-wave and soliton-plasma interaction in a noble-gas-filled hollow-core photonic crystal fiber, Phys. Rev. A 92, 033821 (2015)"
}
},
"helium_alt":
{
"a": 0.00346,
"b": 2.38e-5,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 3.1e-25
},
"sellmeier":
{
"B":
[
14755297000
],
"C":
[
4.262974e+14
],
"P0": 101325,
"T0": 273.15,
"kind": 2,
"source": " C. Cuthbertson and M. Cuthbertson. The refraction and dispersion of neon and helium. Proc. R. Soc. London A 135, 40-47 (1936)"
}
},
"hydrogen":
{
"a": 0.02453,
"atomic_mass": 1.674e-27,
"b": 2.651e-5,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 6.36e-24,
"source": "Shelton, D. P., & Rice, J. E. (1994). Measurements and calculations of the hyperpolarizabilities of atoms and small molecules in the gas phase. Chemical Reviews, 94(1), 3-29"
},
"sellmeier":
{
"B":
[
0.0148956,
0.0049037
],
"C":
[
1.807e-10,
9.2e-11
],
"P0": 101325,
"T0": 273.15,
"kind": 2,
"source": "E. R. Peck and S. Hung. Refractivity and dispersion of hydrogen in the visible and near infrared, J. Opt. Soc. Am. 67, 1550-1554 (1977)"
}
},
"krypton":
{
"a": 0.2349,
"atomic_mass": 1.3915e-25,
"atomic_number": 36,
"b": 3.978e-5,
"ionization_energy": 2.2429831039374e-18,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 2.2e-23,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
2536370000,
2736490000,
62080200000
],
"C":
[
6.54742e+13,
7.3698e+13,
1.8108e+14
],
"P0": 101325,
"T0": 273.15,
"kind": 2
}
},
"nbk7":
{
"sellmeier":
{
"B":
[
1.03961212,
0.231792344,
1.01046945
],
"C":
[
6.00069867e-15,
2.00179144e-14,
1.03560653e-10
],
"kind": 1,
"reference":
[
"SCHOTT Zemax catalog 2017-01-20b (obtained from http://www.schott.com)"
]
}
},
"neon":
{
"a": 0.02135,
"atomic_mass": 3.35092e-26,
"atomic_number": 10,
"b": 1.709e-5,
"ionization_energy": 3.45501365359425e-18,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 8.7e-25,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
1281450000,
22048600000
],
"C":
[
1.84661e+14,
3.7684e+14
],
"P0": 101325,
"T0": 273.15,
"kind": 2
}
},
"nitrogen":
{
"a": 0.137,
"atomic_mass": 2.3259e-26,
"atomic_number": 7,
"b": 1.709e-5,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 2.2e-23,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
32431570000
],
"C":
[
1.44e+14
],
"P0": 101325,
"T0": 273.15,
"const": 6.8552e-5,
"kind": 2
}
},
"silica":
{
"sellmeier":
{
"B":
[
0.6961663,
0.4079426,
0.8974794
],
"C":
[
4.67914826e-15,
1.35120631e-14,
9.79340025e-11
],
"kind": 1,
"reference":
[
"I. H. Malitson. Interspecimen comparison of the refractive index of fused silica, J. Opt. Soc. Am. 55, 1205-1208 (1965)",
"C. Z. Tan. Determination of refractive index of silica glass for infrared wavelengths by IR spectroscopy, J. Non-Cryst. Solids 223, 158-163 (1998)"
]
}
},
"vacuum":
{
"a": 0,
"atomic_mass": 0,
"atomic_number": 1,
"b": 0,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 0,
"source": "none"
},
"sellmeier":
{
"B": [],
"C": [],
"P0": 101325,
"T0": 273.15,
"kind": 1
}
},
"xenon":
{
"a": 0.425,
"atomic_mass": 2.18017e-25,
"atomic_number": 54,
"b": 5.105e-5,
"ionization_energy": 1.94342415157935e-18,
"kerr":
{
"P0": 30400,
"T0": 273.15,
"n2": 5.8e-23,
"source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904."
},
"sellmeier":
{
"B":
[
3228690000,
3553930000,
60676400000
],
"C":
[
4.6301e+13,
5.9578e+13,
1.1274e+14
],
"P0": 101325,
"T0": 273.15,
"kind": 2
}
}
}

Binary file not shown.

View File

@@ -1,43 +1,54 @@
from __future__ import annotations
import os
import warnings
from functools import cache
import numpy as np
import scgenerator as sc
import dispersionapp.math as math
import dispersionapp.physics.fiber as fiber
import dispersionapp.physics.materials as materials
import dispersionapp.physics.pulse as pulse
import dispersionapp.physics.units as units
from dispersionapp.core import Config, LimitValues, N_ion_max, N_sf_max, b2, energy
from dispersionapp.plotapp import PlotApp
from dispersionapp.plotapp import PlotApp, QtWidgets
def app(config_file: os.PathLike | None = None):
config = Config.load(config_file)
def app(config: Config):
# grid stuff
w = sc.w_from_wl(config.wl_min, config.wl_max, 2048)
wl = sc.units.m.inv(w)
wl_ind = sc.math.argclosest(wl, config.wl_pump * 1e-9)
w0 = w[wl_ind]
w = units.w_from_wl(config.wl_min, config.wl_max, 2048)
wl = units.m_rads(w)
wl_ind = math.argclosest(wl, config.wl_pump * 1e-9)
w0: float = w[wl_ind]
gas = sc.materials.Gas(config.gas)
gas = materials.Gas(config.gas)
with PlotApp(
f"Dispersion design with {config.gas.title()}",
core_diameter_um=np.linspace(50, 300),
core_diameter_um=np.arange(5, 301, dtype=float),
pressure_mbar=np.geomspace(1, 2000),
wall_thickness_um=np.geomspace(0.01, 10),
wall_thickness_um=np.geomspace(0.01, 10, 201),
num_resonances=np.arange(6, 41),
n_tubes=np.arange(6, 16),
gap_um=np.linspace(1, 15),
t_fwhm_fs=np.linspace(10, 200, 96),
gap_um=np.arange(1, 15.5, 0.5),
t_fwhm_fs=np.arange(10, 201, dtype=float),
) as app:
# initial setup
app[0].horizontal_line("reference", 0, color="gray")
app[0].set_xlabel("wavelength (nm)")
app[0].set_ylabel("beta2 (fs^2/cm)")
beta_ax = app["Dispersion plot"]
beta_ax.horizontal_line("reference", 0, color="gray")
beta_ax.set_xlabel("wavelength (nm)")
beta_ax.set_ylabel("beta2 (fs^2/cm)")
n_ax = app["Refractive index (real)"]
n_ax.link_x(beta_ax)
n_ax.set_xlabel("wavelength (nm)")
n_ax.set_ylabel("n")
if config.current_state is not None:
app.params["core_diameter_um"].value = config.current_state.core_diameter_um
app.params["pressure_mbar"].value = config.current_state.pressure_mbar
app.params["wall_thickness_um"].value = config.current_state.wall_thickness_um
app.params["num_resonances"].value = config.current_state.num_resonances
app.params["n_tubes"].value = config.current_state.n_tubes
app.params["gap_um"].value = config.current_state.gap_um
app.params["t_fwhm_fs"].value = config.current_state.t_fwhm_fs
@@ -45,10 +56,19 @@ def app(config_file: os.PathLike | None = None):
app.params["core_diameter_um"].value = 100
app.params["pressure_mbar"].value = 500
app.params["wall_thickness_um"].value = 1
app.params["num_resonances"].value = 6
app.params["n_tubes"].value = 7
app.params["gap_um"].value = 5
app.params["t_fwhm_fs"].value = 100
app[0].set_lim(ylim=(-4, 2))
def reset_view():
# reseting beta_ax resets n_ax as well since they're linked
beta_ax.set_lim(ylim=(-4, 2))
reset_button = QtWidgets.QPushButton("Reset axes")
reset_button.clicked.connect(reset_view)
app.params_layout.addWidget(reset_button)
reset_view()
app.update(config.update_current)
@@ -59,24 +79,28 @@ def app(config_file: os.PathLike | None = None):
t_fwhm = 1e-15 * t_fwhm_fs
pressure = 1e2 * pressure_mbar
core_radius = 0.5e-6 * core_diameter_um
t0 = sc.pulse.fwhm_to_T0_fac["sech"] * t_fwhm
t0 = pulse.fwhm_to_T0_fac["sech"] * t_fwhm
disp = compute_capillary(core_diameter_um, pressure_mbar)
wl_zero_disp = sc.math.all_zeros(wl, disp)
wl_zero_disp = math.all_zeros(wl, disp)
if len(wl_zero_disp) == 0:
return
wl_zero_disp = wl_zero_disp[0]
raise ValueError("No zero dispersion found")
single_wl_zero_disp: float = wl_zero_disp[0]
with warnings.catch_warnings():
warnings.simplefilter("ignore")
ion_limit = N_ion_max(wl, t0, wl_zero_disp, gas, config.safety_factor)[wl_ind]
sf_limit = N_sf_max(wl, t0, wl_zero_disp, gas, config.safety_factor)[wl_ind]
ion_limit: float = N_ion_max(
wl, t0, single_wl_zero_disp, gas, config.safety_factor
)[wl_ind]
sf_limit: float = N_sf_max(wl, t0, single_wl_zero_disp, gas, config.safety_factor)[
wl_ind
]
beta2 = disp[wl_ind]
n2 = gas.n2(pressure=pressure)
return LimitValues(
wl_zero_disp,
single_wl_zero_disp,
ion_limit,
sf_limit,
energy(t0, w0, beta2, n2, core_radius, ion_limit),
@@ -84,29 +108,36 @@ def app(config_file: os.PathLike | None = None):
)
@cache
def compute_vincetti(
def compute_n_eff_vincetti(
wall_thickness_um: float,
core_diameter_um: float,
pressure_mbar: float,
num_resonances: int,
n_tubes: int,
gap_um: float,
) -> np.ndarray:
):
core_diameter = core_diameter_um * 1e-6
wall_thickness = wall_thickness_um * 1e-6
gap = gap_um * 1e-6
pressure = pressure_mbar * 1e2
tr = sc.fiber.tube_radius_from_gap(core_diameter / 2, gap, n_tubes)
tr = fiber.tube_radius_from_gap(core_diameter / 2, gap, n_tubes)
n_gas_2 = gas.sellmeier.n_gas_2(wl, None, pressure)
n_eff_vinc = sc.fiber.n_eff_vincetti(
wl,
800e-9,
n_gas_2,
wall_thickness,
tr,
gap,
n_tubes,
n_terms=config.num_resonances,
return fiber.n_eff_vincetti(
wl, 800e-9, n_gas_2, wall_thickness, tr, gap, n_tubes, n_terms=num_resonances
)
@cache
def compute_vincetti_beta(
wall_thickness_um: float,
core_diameter_um: float,
pressure_mbar: float,
num_resonances: int,
n_tubes: int,
gap_um: float,
) -> np.ndarray:
n_eff_vinc = compute_n_eff_vincetti(
wall_thickness_um, core_diameter_um, pressure_mbar, num_resonances, n_tubes, gap_um
)
return b2(w, n_eff_vinc)
@@ -115,42 +146,64 @@ def app(config_file: os.PathLike | None = None):
pressure = pressure_mbar * 1e2
core_diameter = core_diameter_um * 1e-6
n_gas_2 = gas.sellmeier.n_gas_2(wl, None, pressure)
n_eff_cap = sc.fiber.n_eff_marcatili(wl, n_gas_2, core_diameter / 2)
n_eff_cap = fiber.n_eff_marcatili(wl, n_gas_2, core_diameter / 2)
return b2(w, n_eff_cap)
@app.update
def draw_vincetty(
def draw_vincetty_n_eff(
wall_thickness_um: float,
core_diameter_um: float,
pressure_mbar: float,
num_resonances: int,
n_tubes: int,
gap_um: float,
):
b2 = compute_vincetti(
wall_thickness_um, core_diameter_um, pressure_mbar, n_tubes, gap_um
n_eff = compute_n_eff_vincetti(
wall_thickness_um, core_diameter_um, pressure_mbar, num_resonances, n_tubes, gap_um
)
app[0].set_line_data("Vincetti", wl * 1e9, sc.units.beta2_fs_cm_inv(b2))
n_ax.set_line_data("Vincetti", wl * 1e9, n_eff)
@app.update
def draw_vincetty_beta(
wall_thickness_um: float,
core_diameter_um: float,
pressure_mbar: float,
num_resonances: int,
n_tubes: int,
gap_um: float,
):
b2 = compute_vincetti_beta(
wall_thickness_um, core_diameter_um, pressure_mbar, num_resonances, n_tubes, gap_um
)
beta_ax.set_line_data("Vincetti", wl * 1e9, units.beta2_fs_cm_inv(b2))
@app.update
def draw_capillary(core_diameter_um: float, pressure_mbar: float):
b2 = compute_capillary(core_diameter_um, pressure_mbar)
app[0].set_line_data("Capillary", wl * 1e9, sc.units.beta2_fs_cm_inv(b2))
beta_ax.set_line_data("Capillary", wl * 1e9, units.beta2_fs_cm_inv(b2))
@app.update
def draw_energy_limit(core_diameter_um: float, pressure_mbar: float, t_fwhm_fs: float):
lim = compute_max_energy(core_diameter_um, pressure_mbar, t_fwhm_fs)
zdw = lim.wl_zero_disp * 1e9
app[0].set_line_data("zdw", [zdw, zdw], [-3, 3])
info_lines = [
f"gas = {config.gas.title()}",
f"rep rate = {config.rep_rate*1e-3}kHz",
f"ZDW = {zdw:.0f}nm",
f"rep rate = {config.rep_rate * 1e-3}kHz",
]
try:
lim = compute_max_energy(core_diameter_um, pressure_mbar, t_fwhm_fs)
except ValueError:
info_lines.append("No ZDW found")
app.info_label.setText("\n".join(info_lines))
return
zdw = lim.wl_zero_disp * 1e9
beta_ax.set_line_data("zdw", [zdw, zdw], [-3, 3])
info_lines.append(f"ZDW = {zdw:.0f}nm")
if lim.ion_lim > lim.sf_lim:
power = lim.sf_lim * 1e3 * config.rep_rate
info_lines += [
f"max energy = {power:.0f}mW",
f"max power = {power:.0f}mW",
f"N = {lim.soliton_sf_limit:.1f}",
"limited by self-focusing",
]
@@ -161,6 +214,6 @@ def app(config_file: os.PathLike | None = None):
f"N = {lim.soliton_sf_limit:.1f}",
"limited by ionization",
]
app.info_label.setText("\n".join(info_lines))
app.info_label.setText(" ".join(info_lines))
config.save()

432
src/dispersionapp/io.py Normal file
View File

@@ -0,0 +1,432 @@
from __future__ import annotations
import datetime
import importlib.resources
import json
import os
import re
from dataclasses import dataclass
from functools import cache
from io import BytesIO
from pathlib import Path
from typing import Any, BinaryIO, Protocol, Sequence, overload
from zipfile import ZipFile
import numpy as np
class TimedMessage:
def __init__(self, interval: float = 10.0):
self.interval = datetime.timedelta(seconds=interval)
self.next = datetime.datetime.now()
def ready(self) -> bool:
t = datetime.datetime.now()
if self.next <= t:
self.next = t + self.interval
return True
return False
def data_file(path: str) -> Path:
"""returns a `Path` object pointing to the desired data file included in `scgenerator`"""
return Path(importlib.resources.files("dispersionapp") / "data" / path)
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (datetime.date, datetime.datetime)):
return obj.isoformat()
elif isinstance(obj, np.ndarray):
return tuple(obj)
elif isinstance(obj, DataFile):
return obj.__json__()
def _decode_datetime(s: str) -> datetime.date | datetime.datetime | str:
try:
return datetime.datetime.fromisoformat(s)
except Exception:
pass
try:
return datetime.date.fromisoformat(s)
except Exception:
pass
return s
def custom_decode_hook(obj):
"""
Some simple, non json-compatible objects are encoded as str, this function reconstructs the
original object and sets it in the decoded json structure
"""
for k, v in obj.items():
if isinstance(v, str):
obj[k] = _decode_datetime(v)
elif isinstance(v, list):
obj[k] = tuple(v)
return obj
@cache
def load_material_dico(name: str) -> dict[str, Any]:
"""
loads a material dictionary
Parameters
----------
name : str
name of the material
Returns
-------
material_dico : dict
"""
return json.loads(data_file("materials.json").read_text())[name]
class PropagationIOHandler(Protocol):
def __len__(self) -> int: ...
def keys(self) -> list[str]: ...
def save_spectrum(self, index: int, spectrum: np.ndarray): ...
def load_spectrum(self, index: int) -> np.ndarray: ...
def save_data(self, name: str, data: bytes): ...
def load_data(self, name: str) -> bytes: ...
def clear(self): ...
class MemoryIOHandler:
spectra: dict[int, np.ndarray]
data: dict[str, bytes]
def __init__(self):
self.spectra = {}
self.data = {}
def __len__(self) -> int:
return len(self.spectra)
def keys(self) -> list[str]:
return list(self.data.keys())
def save_spectrum(self, index: int, spectrum: np.ndarray):
self.spectra[index] = spectrum
def load_spectrum(self, index: int) -> np.ndarray:
return self.spectra[index]
def save_data(self, name: str, data: bytes):
self.data[name] = data
def load_data(self, name: str) -> bytes:
return self.data[name]
def clear(self):
self.spectra = {}
self.data = {}
class ZipFileIOHandler:
file: BinaryIO
SPECTRUM_FN = "spectra/spectrum_{}.npy"
def __init__(self, file: os.PathLike):
"""
Create a IO handler to be used in Propagation.
This handler saves spectra as numpy `.npy` files.
Parameters
----------
file : os.PathLike
path to the desired zip file. Will be created if it doesn't exist.
Passing in an already opened file-like object is not supported at the moment
"""
self.file = Path(file)
if not self.file.exists():
ZipFile(self.file, "w").close()
def __len__(self) -> int:
with ZipFile(self.file, "r") as zip_file:
i = 0
while True:
try:
zip_file.open(self.SPECTRUM_FN.format(i))
except KeyError:
return i
i += 1
def keys(self) -> list[str]:
with ZipFile(self.file, "r") as zip_file:
return zip_file.namelist()
def save_spectrum(self, index: int, spectrum: np.ndarray):
with (
ZipFile(self.file, "a") as zip_file,
zip_file.open(self.SPECTRUM_FN.format(index), "w") as file,
):
np.lib.format.write_array(file, spectrum, allow_pickle=False)
def load_spectrum(self, index: int) -> np.ndarray:
with (
ZipFile(self.file, "r") as zip_file,
zip_file.open(self.SPECTRUM_FN.format(index), "r") as file,
):
return np.load(file)
def save_data(self, name: str, data: bytes):
with ZipFile(self.file, "a") as zip_file, zip_file.open(name, "w") as file:
file.write(data)
def load_data(self, name: str) -> bytes:
with ZipFile(self.file, "r") as zip_file, zip_file.open(name, "r") as file:
return file.read()
def clear(self):
self.file.unlink(missing_ok=True)
@dataclass
class DataFile:
"""
Holds information about external files necessary for a simulation.
In the current implementation, only reading data from the file is supported
"""
prefix: str | None
path: str
io: PropagationIOHandler
PREFIX_SEP = "::"
@classmethod
def from_str(cls, s: str, io: PropagationIOHandler | None = None) -> DataFile:
if cls.PREFIX_SEP in s:
prefix, path = s.split(cls.PREFIX_SEP, 1)
else:
prefix = None
path = s
return cls(prefix, path, io)
@classmethod
def validate(cls, name: str, data: str | DataFile) -> DataFile:
"""To be used to automatically construct a DataFile when creating a Parameters obj"""
if isinstance(data, cls):
return data
elif isinstance(data, str):
return cls.from_str(data)
elif isinstance(data, Path):
return cls.from_str(os.fspath(data))
else:
raise TypeError(
f"{name!r} must be a path or a bundled file specifier, not a {type(data)!r}"
)
def __json__(self) -> str:
if self.prefix is None:
return os.fspath(Path(self.path))
return self.prefix + self.PREFIX_SEP + self.path
def load_bytes(self) -> bytes:
if self.prefix is not None and self.io is None:
raise ValueError(
f"a bundled file prefixed with {self.prefix} "
"must have a PropagationIOHandler attached"
)
# a DataFile obj may have a useless io obj attached to it
if self.prefix is not None:
return self.io.load_data(self.path)
else:
return Path(self.path).read_bytes()
@overload
def load_arrays(self, labels: str | tuple[str, ...]) -> tuple[np.ndarray]: ...
@overload
def load_arrays(
self, labels: str | tuple[str, ...], labels2: str | tuple[str, ...]
) -> tuple[np.ndarray, np.ndarray]: ...
def load_arrays(self, *labels: str | tuple[str, ...]) -> tuple[np.ndarray, ...]:
raw_data = self.load_bytes()
extension = self.path.lower().split(".")[-1]
return _parse_raw_data(raw_data, extension, *labels)
def similar_to(self, other: DataFile) -> bool:
return Path(self.path).name == Path(other.path).name
def open_data_file(path: os.PathLike, *labels: str) -> tuple[np.ndarray, ...]:
path = Path(path)
raw_data = path.read_bytes()
extension = path.suffix.lower()
return _parse_raw_data(raw_data, extension, *labels)
def _parse_raw_data(data: bytes, extension: str, *keys) -> tuple[np.ndarray, ...]:
if extension.endswith("npz"):
df = np.load(BytesIO(data))
return _parse_npz_data(df, *keys)
elif extension.endswith("npy"):
return tuple(np.load(BytesIO(data)))
else:
return _parse_text_data(data.decode())
def _parse_text_data(s: str) -> tuple[np.ndarray, ...]:
lines = s.splitlines()
for delimiter in ", \t;":
try:
return tuple(np.loadtxt(lines, delimiter=delimiter).T)
except ValueError:
continue
raise ValueError("Could not load text data as numpy array")
def _parse_npz_data(
df: np.lib.npyio.NpzFile, *labels: str | tuple[str, ...]
) -> tuple[np.ndarray, ...]:
if not labels:
return tuple(df.values())
out = []
for key in labels:
if not isinstance(key, (list, tuple, set)):
out.append(df[key])
continue
for possible_key in key:
try:
out.append(df[possible_key])
except KeyError:
continue
else:
break
else:
raise KeyError(f"no key of {key!r} present in {df}")
return tuple(out)
def unique_name(base_name: str, existing: set[str]) -> str:
name = base_name
p = Path(base_name)
base = p.stem
ext = p.suffix
i = 0
while name in existing:
name = f"{base}_{i}{ext}"
i += 1
return name
def format_graph(left_elements: Sequence[str], middle: str, right_elements: Sequence[str]):
if len(left_elements) == 0:
left_elements = [""]
if len(right_elements) == 0:
right_elements = [""]
mid_elements = ["."[:i] + el for i, el in enumerate(middle.split("."))]
left_height = len(left_elements)
right_height = len(right_elements)
max_left = max(len(el) for el in left_elements) + 1
max_right = max(len(el) for el in right_elements) + 1
max_mid = max(len(el) for el in mid_elements) + 2
right_elements = [fit_right(el, max_right) for el in right_elements][::-1]
left_elements = [fit_left(el, max_left) for el in left_elements][::-1]
mid_elements = ["" * max_mid] + [fit_mid(el, max_mid) for el in mid_elements][::-1]
total_height = max(len(left_elements), len(right_elements), len(mid_elements))
line_pos = total_height - len(mid_elements)
left = left_col(
left_elements, line_pos, total_height, max_left, start=max(0, line_pos - left_height + 1)
)
right = right_col(
right_elements, line_pos, total_height, max_right, start=max(0, line_pos - right_height + 1)
)
middle = mid_col(mid_elements, line_pos, total_height, max_mid)
final = "\n".join(l + m + r for l, m, r in zip(left, middle, right))
return final
def fit_left(el, length, line=1, pad=1):
return f"{' ' * length}{el}{' ' * pad}{'' * line}"[-(length + 1) :]
def fit_right(el, length, line=1, pad=1):
return f"{'' * line}{' ' * pad}{el}{' ' * length}"[: length + 1]
def fit_mid(el, length, pad=1):
return f"{' ' * pad}{el}{' ' * length}"[:length]
def mid_col(mid_els, line_pos, height, pad_length):
out = [" " * pad_length] * line_pos + mid_els
while len(out) < height:
out.append(" " * pad_length)
return out[::-1]
def left_col(left_els, line_pos, height, pad_length, start=0):
out = [" " * (pad_length + 1)] * start
for rel_i, el in enumerate(left_els):
abs_j = rel_i + start
out.append(el + get_symb(False, rel_i, abs_j, line_pos, len(left_els) - 1))
while len(out) < height:
out.append(" " * (pad_length + 2))
return out[::-1]
def right_col(right_els, line_pos, height, pad_length, start=0):
out = [" " * (pad_length + 1)] * start
for rel_i, el in enumerate(right_els):
abs_j = rel_i + start
out.append(get_symb(True, rel_i, abs_j, line_pos, len(right_els) - 1) + el)
while len(out) < height:
out.append(" " * (pad_length + 2))
return out[::-1]
def get_symb(right: bool, rel_i, abs_j, line_pos, max_ind):
if max_ind == 0:
return ""
elif rel_i == 0:
if abs_j < line_pos:
return "╯╰"[right]
elif abs_j == line_pos:
return ""
else:
raise ValueError("bottom of left columns cannot be above line")
elif rel_i < max_ind:
if abs_j == line_pos:
return ""
else:
return "┤├"[right]
else:
if abs_j == line_pos:
return ""
elif abs_j > line_pos:
return "╮╭"[right]
else:
raise ValueError("top of left columns cannot be below line")
def _to_num(s: str) -> str | float | int:
for f in int, float:
try:
return f(s)
except ValueError:
pass
return s
NUM_REGEX = r"[+-]?[\d]+(?:\.?[\d]+)?(?:[eE][+-]?\d+)?"
def logical_sort_key(s: os.PathLike | str) -> tuple:
return tuple(_to_num(el) for el in re.split(f"({NUM_REGEX})", str(s)) if el)

800
src/dispersionapp/math.py Normal file
View File

@@ -0,0 +1,800 @@
"""
collection of purely mathematical function
"""
import math
import warnings
from dataclasses import dataclass
from functools import cache
from typing import Callable, Sequence, overload
import numba
import numpy as np
from scipy import fft as sfft
from scipy.interpolate import interp1d, lagrange
from scipy.special import jn_zeros
pi = np.pi
c = 299792458.0
def fft_functions(
full_field: bool,
) -> tuple[Callable[[np.ndarray], np.ndarray], Callable[[np.ndarray], np.ndarray]]:
if full_field:
return sfft.rfft, sfft.irfft
else:
return sfft.fft, sfft.ifft
def expm1_int(y: np.ndarray, dx: float) -> np.ndarray:
"""evaluates 1 - exp( -∫func(y(x))dx ) from x=-inf to x"""
return -np.expm1(-cumulative_simpson(y) * dx)
def span(*vec: np.ndarray) -> tuple[float, float]:
"""returns the min and max of whatever array-like is given. can accept many args"""
out = (np.inf, -np.inf)
if len(vec) == 0 or len(vec[0]) == 0:
raise ValueError("did not provide any value to span")
for x in vec:
x = np.atleast_1d(x)
out = (min(np.min(x), out[0]), max(np.max(x), out[1]))
return out
def total_extent(*vec: np.ndarray) -> float:
"""measure the distance between the min and max value of all given arrays"""
left, right = span(*vec)
return right - left
def span_above(arr: np.ndarray, threshold: float) -> tuple[int, int]:
"""returns the first and last index where the array is above the specified threshold"""
ind = np.where(arr >= threshold)[-1]
return np.min(ind), np.max(ind)
@overload
def argclosest(array: np.ndarray, target: float | int) -> int: ...
@overload
def argclosest(array: np.ndarray, target: Sequence[float | int] | np.ndarray) -> np.ndarray: ...
def argclosest(
array: np.ndarray, target: float | int | Sequence[float | int] | np.ndarray
) -> int | np.ndarray:
"""
returns the index/indices corresponding to the closest matches of target in array
Parameters
----------
array : np.ndarray, shape (n,)
array of values
target : number | np.ndarray
find the closest value to target in `array`. The index of the closest match is returned.
Returns
-------
int | np.ndarray
index / indices of the closest match
"""
min_dist = np.inf
index = 0
if isinstance(target, (list, tuple, np.ndarray)):
return np.array([argclosest(array, t) for t in target])
for k, val in enumerate(array):
dist = abs(val - target)
if dist < min_dist:
min_dist = dist
index = k
return index
def extent(x):
return np.max(x) - np.min(x)
def power_fact(x, n):
"""
returns x ^ n / n!
"""
if isinstance(x, (int, float)):
return _power_fact_single(x, n)
elif isinstance(x, np.ndarray):
return _power_fact_array(x, n)
else:
raise TypeError(f"type {type(x)} of x not supported.")
def _power_fact_single(x, n):
result = 1.0
for k in range(n):
result = result * x / (n - k)
return result
def _power_fact_array(x, n):
"""returns x^2/n!"""
result = np.ones(len(x), dtype=np.float64)
for k in range(n):
result = result * x / (n - k)
return result
@numba.njit()
def abs2(z: np.ndarray) -> np.ndarray:
return z.real**2 + z.imag**2
def normalized(z: np.ndarray) -> np.ndarray:
ab = abs2(z)
return ab / ab.max()
def autocrop(
x, y, z, threshold: float = 1e-4, x_only: bool = False
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
thr = z.max()
yind, xind = np.where(z > thr * threshold)
xmin, xmax = xind.min(), xind.max()
if x_only:
ymin, ymax = 0, len(y) - 1
else:
ymin, ymax = yind.min(), yind.max()
return x[xmin : xmax + 1], y[ymin : ymax + 1], z[ymin : ymax + 1][:, xmin : xmax + 1]
def to_dB(arr: np.ndarray, ref=None, axis=None, default: float | None = None) -> np.ndarray:
"""
converts unitless values in dB
Parameters
----------
arr : np.ndarray
array of non-negative values. Any values 0 or below will be mapped to the minimum
positive value in dB
ref : float, optional
reference value corresponding to 0dB (default : max(arr))
axis : int | None, optional
on which axis to apply the transformation. If `ref` is given, this has no effect
Returns
----------
np.ndarray
array in dB
"""
if axis is not None and arr.ndim > 1 and ref is None:
return np.apply_along_axis(to_dB, axis, arr, default=default)
out = np.ones_like(arr)
if default is not None and math.isfinite(default):
out[:] *= default
else:
out *= np.nan
if ref is None:
ref = np.max(arr)
above_0 = arr > 0
if not np.any(above_0) or ref <= 0:
warnings.warn(f"invalid array to convert to dB, returning {default} instead")
if default is None:
out *= np.nan
return out
m = arr / ref
if default is None:
out *= 10 * np.log10(m[above_0].min())
return 10 * np.log10(m, out=out, where=above_0)
def u_nm(n, m):
"""
returns the mth zero of the Bessel function of order n-1
Parameters
----------
n-1 : order of the Bessel function
m : order of the zero
Returns
----------
float
"""
return jn_zeros(n - 1, m)[-1]
def all_zeros(x: np.ndarray, y: np.ndarray) -> np.ndarray:
"""find all the x values such that y(x)=0 with linear interpolation"""
pos = np.argwhere(y[1:] * y[:-1] < 0)[:, 0]
m = (y[pos + 1] - y[pos]) / (x[pos + 1] - x[pos])
return -y[pos] / m + x[pos]
def wspace(t: float | np.ndarray, t_num=0):
"""
frequency array such that x(t) <-> np.fft(x)(w)
Parameters
----------
t : float | np.ndarray
float : total width of the time window
array : time array
t_num : int-
if t is a float, specifies the number of points
Returns
-------
w : array
linspace of frencies corresponding to t
"""
if isinstance(t, (np.ndarray, list, tuple)):
dt = t[1] - t[0]
t_num = len(t)
else:
dt = t / t_num
return np.fft.fftfreq(t_num, dt) * 2 * np.pi
def tspace(time_window: float | None = None, t_num: int | None = None, dt: float | None = None):
"""
returns a time array centered on 0
Parameters
----------
time_window : float
total time spanned
t_num : int
number of points
dt : float
time resolution
at least 2 arguments must be given. They are prioritize as such
t_num > time_window > dt
Returns
-------
t : array
a linearily spaced time array
Raises
------
TypeError
missing at least 1 argument
"""
if t_num is not None:
if isinstance(time_window, (float, int)):
return np.linspace(-time_window / 2, time_window / 2, int(t_num))
elif isinstance(dt, (float, int)):
time_window = (t_num - 1) * dt
return np.linspace(-time_window / 2, time_window / 2, t_num)
elif isinstance(time_window, (float, int)) and isinstance(dt, (float, int)):
t_num = int(time_window / dt) + 1
return np.linspace(-time_window / 2, time_window / 2, t_num)
raise TypeError("not enough parameter to determine time vector")
def irfftfreq(freq: np.ndarray, retstep: bool = False):
"""
Given an array of positive only frequency, this returns the corresponding time array centered
around 0 that will be aligned with the `numpy.fft.irfft` of a spectrum aligned with `freq`.
if `retstep` is True, the sample spacing is returned as well
"""
df = freq[1] - freq[0]
nt = (len(freq) - 1) * 2
period = 1 / df
dt = period / nt
t = np.linspace(-(period - dt) / 2, (period - dt) / 2, nt)
if retstep:
return t, dt
else:
return t
def iwspace(w: np.ndarray, retstep: bool = False):
"""invserse of wspace: recovers the (symmetric) time array corresponsding to `w`"""
df = (w[1] - w[0]) * 0.5 / np.pi
nt = len(w)
period = 1 / df
dt = period / nt
t = np.linspace(-(period - dt) / 2, (period - dt) / 2, nt)
if retstep:
return t, dt
else:
return t
def dt_from_min_wl(wl_min: float, wavelength: float) -> float:
return 0.5 / c / (1 / wl_min - 1 / wavelength)
def min_wl_from_dt(dt: float, wavelength: float) -> float:
return wavelength / (1 + wavelength / (2 * c * dt))
def build_envelope_w_grid(t: np.ndarray, w0: float) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
convenience function to
Parameters
----------
t : np.ndarray, shape (t_num,)
time array
w0 : float
center frequency
Returns
-------
w_c : np.ndarray, shape (n, )
centered angular frequencies in rad/s where 0 is the pump frequency
w : np.ndarray, shape (n, )
angular frequency grid
w_order : np.ndarray, shape (n,)
arrays of indices such that w[w_order] is sorted
"""
w_c = wspace(t)
w = w_c + w0
w_order = np.argsort(w)
return w_c, w, w_order
def build_full_field_w_grid(t_num: int, dt: float) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
Paramters
---------
t_num : int
number of temporal sampling points
dt : float
uniform spacing between sample points
Returns
-------
w : np.ndarray, shape (n, )
angular frequency grid
w_order : np.ndarray, shape (n,)
arrays of indices such that w[w_order] is sorted
"""
w = 2 * pi * np.fft.rfftfreq(t_num, dt)
w_order = np.argsort(w)
ind = w != 0
wl = np.zeros(len(w))
wl[ind] = 2 * pi * c / w[ind]
if any(ind):
wl[~ind] = 2 * pi * c / (np.abs(w[ind]).min())
return w, w_order, wl
def build_z_grid(z_num: int, length: float) -> np.ndarray:
return np.linspace(0, length, z_num)
def build_t_grid(
time_window: float | None = None, t_num: int | None = None, dt: float | None = None
) -> tuple[np.ndarray, float, float, int]:
"""
Returns
-------
t : np.ndarray, shape (t_num, )
temporal points in s
time_window : float
total width of the temporal grid in s, by default None
dt : float
spacing of the temporal grid in s, by default None
t_num : int
number of temporal grid points, by default None
"""
t = tspace(time_window, t_num, dt)
time_window = t.max() - t.min()
dt = t[1] - t[0]
t_num = len(t)
return t, time_window, dt, t_num
def polynom_extrapolation(x: np.ndarray, y: np.ndarray, degree: int) -> np.ndarray:
"""
performs a polynomial extrapolation on both ends of the support
Parameters
----------
x : np.ndarray (n,)
x values
y : np.ndarray (n,)
y values. The shape must correspond to that of x.
degree : int
degree of the polynom.
Returns
-------
np.ndarray, shape (n,)
y array with zero values on either side replaces with polynomial extrapolation
Example
"""
out = y.copy()
order = np.argsort(x)
left_ind, *_, right_ind = np.nonzero(out[order])[0]
return _polynom_extrapolation_in_place(out[order], left_ind, right_ind, degree)[order.argsort]
def _polynom_extrapolation_in_place(y: np.ndarray, left_ind: int, right_ind: int, degree: float):
"""
extrapolates IN PLACE linearily on both side of the support
Parameters
----------
y : np.ndarray
array
left_ind : int
first value we want to keep (extrapolate to the left of that)
right_ind : int
last value we want to keep (extrapolate to the right of that)
"""
r_left = (1 + np.arange(left_ind))[::-1] ** degree
r_right = np.arange(len(y) - right_ind) ** degree
y[:left_ind] = r_left * (y[left_ind] - y[left_ind + 1]) + y[left_ind]
y[right_ind:] = r_right * (y[right_ind] - y[right_ind - 1]) + y[right_ind]
return y
def interp_2d(
old_x: np.ndarray,
old_y: np.ndarray,
z: np.ndarray,
new_x: np.ndarray | tuple,
new_y: np.ndarray | tuple,
kind="linear",
) -> np.ndarray:
if isinstance(new_x, tuple):
new_x = np.linspace(*new_x)
if isinstance(new_y, tuple):
new_y = np.linspace(*new_y)
z = interp1d(old_y, z, axis=0, kind=kind, bounds_error=False, fill_value=0)(new_y)
return interp1d(old_x, z, kind=kind, bounds_error=False, fill_value=0)(new_x)
@numba.jit(nopython=True)
def linear_interp_2d(old_x: np.ndarray, old_y: np.ndarray, new_x: np.ndarray):
new_vals = np.zeros((len(old_y), len(new_x)))
interpolable = (new_x > old_x[0]) & (new_x <= old_x[-1])
equal = new_x == old_x[0]
inds = np.searchsorted(old_x, new_x[interpolable])
for i, val in enumerate(old_y):
new_vals[i][interpolable] = val[inds - 1] + (new_x[interpolable] - old_x[inds - 1]) * (
val[inds] - val[inds - 1]
) / (old_x[inds] - old_x[inds - 1])
new_vals[i][equal] = val[0]
return new_vals
@numba.jit(nopython=True)
def linear_interp_1d(old_x: np.ndarray, old_y: np.ndarray, new_x: np.ndarray):
new_vals = np.zeros(len(new_x))
interpolable = (new_x > old_x[0]) & (new_x <= old_x[-1])
inds = np.searchsorted(old_x, new_x[interpolable])
new_vals[interpolable] = old_y[inds - 1] + (new_x[interpolable] - old_x[inds - 1]) * (
old_y[inds] - old_y[inds - 1]
) / (old_x[inds] - old_x[inds - 1])
new_vals[new_x == old_x[0]] = old_y[0]
return new_vals
def envelope_ind(
signal: np.ndarray, dmin: int = 1, dmax: int = 1, split: bool = False
) -> tuple[np.ndarray, np.ndarray]:
"""
Attempts to separate the envolope from a periodic signal and return the indices of the
top/bottom envelope of a signal
Parameters
----------
signal : np.ndarray, shape (n,)
signal array (must be sorted)
dmin, dmax : int, optional
size of chunks for lower/upper envelope
split: bool, optional
split the signal in half along its mean, might help to generate the envelope in some cases
this has the effect of forcing the envlopes to be on either side of the dc signal
by default False
Returns
-------
np.ndarray, shape (m,), m <= n
lower envelope indices
np.ndarray, shape (l,), l <= n
upper envelope indices
"""
local_min = (np.diff(np.sign(np.diff(signal))) > 0).nonzero()[0] + 1
local_max = (np.diff(np.sign(np.diff(signal))) < 0).nonzero()[0] + 1
if split:
dc_value = np.mean(signal)
local_min = local_min[signal[local_min] < dc_value]
local_max = local_max[signal[local_max] > dc_value]
if dmin > 1:
local_min = local_min[
[i + np.argmin(signal[local_min[i : i + dmin]]) for i in range(0, len(local_min), dmin)]
]
if dmax > 1:
local_max = local_max[
[i + np.argmax(signal[local_max[i : i + dmax]]) for i in range(0, len(local_max), dmax)]
]
return local_min, local_max
def envelope_2d(x: np.ndarray, values: np.ndarray) -> np.ndarray:
"""
returns the envelope of a 2d propagation-like array
Parameters
----------
x : np.ndarray, shape (nt,)
x axis
values : np.ndarray, shape (nz, nt)
values of which to find the envelope
Returns
-------
np.ndarray, shape (nz, nt)
interpolated values
"""
return np.array([envelope_1d(x, y) for y in values])
def envelope_1d(y: np.ndarray, x: np.ndarray | None = None) -> np.ndarray:
if x is None:
x = np.arange(len(y))
_, hi = envelope_ind(y)
return interp1d(x[hi], y[hi], kind="cubic", fill_value=0, bounds_error=False)(x)
@dataclass(frozen=True)
class LobeProps:
left_pos: float
left_fwhm: float
center: float
right_fwhm: float
right_pos: float
interp: interp1d
@property
@cache
def x(self) -> np.ndarray:
return np.array(
[self.left_pos, self.left_fwhm, self.center, self.right_fwhm, self.right_pos]
)
@property
@cache
def y(self) -> np.ndarray:
return self.interp(self.x)
@property
@cache
def fwhm(self) -> float:
return abs(self.right_fwhm - self.left_fwhm)
@property
@cache
def width(self) -> float:
return abs(self.right_pos - self.left_pos)
def measure_lobe(x_in, y_in, /, lobe_pos: int | None = None, thr_rel: float = 1 / 50) -> LobeProps:
"""
given a fairly smooth signal, finds the highest lobe and returns its position as well
as its fwhm points
Parameters
----------
x_in : np.ndarray, shape (n,)
x values
y_in : np.ndarray, shape (n,)
y values
lobe_pos : int, optional
index of the desired lobe, by default None (take highest peak)
thr_rel : float, optional
Returns
-------
np.ndarray
(left limit, left half maximum, maximum position, right half maximum, right limit)
"""
interp = interp1d(x_in, y_in)
lobe_index = lobe_pos or np.argmax(y_in)
maxi = y_in[lobe_index]
maxi2 = maxi / 2
thr_abs = maxi * thr_rel
half_max_left: float = all_zeros(x_in[:lobe_index], y_in[:lobe_index] - maxi2)[-1]
half_max_right: float = all_zeros(x_in[lobe_index:], y_in[lobe_index:] - maxi2)[0]
poly = lagrange((half_max_left, x_in[lobe_index], half_max_right), (maxi2, maxi2 * 2, maxi2))
parabola_left, parabola_right = sorted(poly.roots)
r_cand = x_in > half_max_right
x_right = x_in[r_cand]
y_right = y_in[r_cand]
l_cand = x_in < half_max_left
x_left = x_in[l_cand][::-1]
y_left = y_in[l_cand][::-1]
d = {}
for x, y, central_parabola_root, sign in [
(x_left, y_left, parabola_left, 1),
(x_right, y_right, parabola_right, -1),
]:
candidates = []
slope = sign * np.gradient(y, x)
for y_test, num_to_take in [
(sign * np.gradient(slope, x), 2),
(y - thr_abs, 1),
(slope, 3),
]:
candidates.extend(all_zeros(x, y_test)[:num_to_take])
candidates = np.array(sorted(candidates))
side_parabola_root = x[0] - 2 * y[0] / (sign * slope[0])
weights = (
np.abs(candidates - side_parabola_root)
+ np.abs(candidates - central_parabola_root)
+ interp(candidates) / thr_abs
)
d[sign] = candidates[np.argmin(weights)]
return LobeProps(d[1], half_max_left, x_in[lobe_index], half_max_right, d[-1], interp)
@numba.jit(nopython=True)
def cumulative_simpson(x: np.ndarray) -> np.ndarray:
out = np.zeros_like(x)
c1 = 1 / 3
c2 = 4 / 3
out[1] = (x[1] + x[0]) * 0.5
for i in range(2, len(x)):
out[i] = out[i - 2] + x[i - 2] * c1 + x[i - 1] * c2 + c1 * x[i]
return out
@numba.jit(nopython=True)
def cumulative_boole(x: np.ndarray) -> np.ndarray:
out = np.zeros_like(x)
c1 = 14 / 45
c2 = 64 / 45
c3 = 24 / 45
c = np.array([c1, c2, c3, c2, c1])
ind = np.arange(5)
out[ind] = cumulative_simpson(x[ind])
for i in range(4, len(x)):
out[i] = out[i - 4] + np.sum(c * x[i - 4 : i + 1])
return out
def stencil_coefficients(stencil_points: Sequence, order: int) -> np.ndarray:
"""
Reference
---------
https://en.wikipedia.org/wiki/Finite_difference_coefficient#Arbitrary_stencil_points
"""
mat = np.power.outer(stencil_points, np.arange(len(stencil_points))).T
d = np.zeros(len(stencil_points))
d[order] = math.factorial(order)
return np.linalg.solve(mat, d)
@cache
def central_stencil_coefficients(n: int, order: int) -> np.ndarray:
"""
returns the coefficients of a centered finite difference scheme
Parameters
----------
n : int
number of points
order : int
order of differentiation
"""
return stencil_coefficients(np.arange(n * 2 + 1) - n, order)
@cache
def stencil_coefficients_set(n: int, order: int) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
coefficients for a forward, centered and backward finite difference differentation scheme of
order `order` that extends `n` points away from the evaluation point (`x_0`)
"""
central = central_stencil_coefficients(n, order)
left = stencil_coefficients(np.arange(n + 1), order)
right = stencil_coefficients(-np.arange(n + 1)[::-1], order)
return left, central, right
def differentiate_arr(
values: np.ndarray,
diff_order: int,
extent: int | None = None,
h: float = 1.0,
correct_edges=True,
) -> np.ndarray:
"""
takes a derivative of order `diff_order` using equally spaced values
Parameters
---------
values : ndarray
equally spaced values
diff_order : int
order of differentiation
extent : int, optional
how many points away from the center the scheme uses. This determines accuracy.
example: extent=6 means that 13 (6 on either side + center) points are used to evaluate the
derivative at each point. by default diff_order + 2
h : float, optional
step size, by default 1.0
correct_edges : bool, optional
avoid artifacts by using forward/backward schemes on the edges, by default True
Reference
---------
https://en.wikipedia.org/wiki/Finite_difference_coefficient
"""
if extent is None:
extent = diff_order + 2
n_points = (diff_order + extent) // 2
if not correct_edges:
central_coefs = central_stencil_coefficients(n_points, diff_order)
result = np.convolve(values, central_coefs[::-1], mode="same")
else:
left_coefs, central_coefs, right_coefs = stencil_coefficients_set(n_points, diff_order)
result = np.concatenate(
(
np.convolve(values[: 2 * n_points], left_coefs[::-1], mode="valid"),
np.convolve(values, central_coefs[::-1], mode="valid"),
np.convolve(values[-2 * n_points :], right_coefs[::-1], mode="valid"),
)
)
return result / h**diff_order
def mean_angle(values: np.ndarray, axis: int = 0):
"""
computes the mean angle of an array along a given axis
Parameters
----------
spectra : np.ndarray
complex values from which to compute the mean phase
axis : int, optional
axis on which to take the mean, by default 0
Returns
----------
np.ndarray
array of complex numbers of unit length representing the mean phase, decimated along the
specified axis
Example
----------
>>> x = np.array([[1 + 1j, 0 + 2j, -3 - 1j],
[1 + 0j, 2 + 3j, -3 + 1j]])
>>> mean_angle(x)
array([ 0.92387953+0.38268343j, 0.28978415+0.95709203j, -1. +0.j ])
"""
values = np.divide(
values, np.abs(values), out=np.zeros(values.shape, dtype=values.dtype), where=values != 0
)
total_phase = np.sum(values, axis=axis)
return np.divide(total_phase, np.abs(total_phase), where=total_phase != 0, out=total_phase)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,445 @@
from __future__ import annotations
import warnings
from dataclasses import dataclass, field
from functools import cache
from typing import Any, overload
import numpy as np
import dispersionapp.io as io
import dispersionapp.math as math
import dispersionapp.physics.units as units
from dispersionapp.physics.units import NA, c, epsilon0, kB
type Num = np.floating | np.integer | float | int
@dataclass
class Sellmeier:
B: list[float] = field(default_factory=list)
C: list[float] = field(default_factory=list)
pressure_ref: float = 101325
temperature_ref: float = 273.15
kind: int = 2
constant: float = 0
@classmethod
@cache
def load(cls, name: str) -> Sellmeier:
mat_dico = io.load_material_dico(name)
s = mat_dico.get("sellmeier", {})
return cls(
**{
newk: s.get(k, None)
for newk, k in zip(
["B", "C", "pressure_ref", "temperature_ref", "kind", "constant"],
["B", "C", "P0", "T0", "kind", "const"],
)
if k in s
}
)
@overload
def chi(
self, wl: np.ndarray, temperature: float | None = None, pressure: float | None = None
) -> np.ndarray: ...
@overload
def chi(
self, wl: Num, temperature: float | None = None, pressure: float | None = None
) -> Num: ...
def chi(self, wl, temperature: float | None = None, pressure: float | None = None):
"""n^2 - 1"""
if isinstance(wl, np.ndarray):
chi = np.zeros_like(wl) # = n^2 - 1
else:
chi = 0
if self.kind == 1:
for b, c_ in zip(self.B, self.C):
chi += wl**2 * b / (wl**2 - c_)
elif self.kind == 2: # gives n-1
for b, c_ in zip(self.B, self.C):
chi += b / (c_ - 1 / wl**2)
chi += self.constant
chi = (chi + 1) ** 2 - 1
elif self.kind == 3: # Schott formula
for i, b in reversed(list(enumerate(self.B))):
chi += b * wl ** (-2 * (i - 1))
chi = chi - 1
else:
raise ValueError(f"kind {self.kind} is not recognized.")
if temperature is not None:
chi *= self.temperature_ref / temperature
if pressure is not None:
chi *= pressure / self.pressure_ref
return chi
@overload
def n_gas_2(
self, wl: np.ndarray, temperature: float | None = None, pressure: float | None = None
) -> np.ndarray: ...
@overload
def n_gas_2(
self, wl: Num, temperature: float | None = None, pressure: float | None = None
) -> float: ...
def n_gas_2(self, wl, temperature: float | None = None, pressure: float | None = None):
return self.chi(wl, temperature, pressure) + 1
@overload
def n(
self, wl: np.ndarray, temperature: float | None = None, pressure: float | None = None
) -> np.ndarray: ...
@overload
def n(
self, wl: Num, temperature: float | None = None, pressure: float | None = None
) -> float: ...
def n(self, wl, temperature: float | None = None, pressure: float | None = None):
return np.sqrt(self.n_gas_2(wl, temperature, pressure))
def delta(self, wl: np.ndarray, wl_zero_disp: float) -> np.ndarray:
"""
'delta' quantity that describes the gas dispersion according to eq. S7 in [1]
Parameters
----------
wl : ndarray
wavelength in m
wl_zero_disp : float
zero dispersion wavelength in m
Reference
---------
[1] TRAVERS, John C., GRIGOROVA, Teodora F., BRAHMS, Christian, et al. High-energy
pulse self-compression and ultraviolet generation through soliton dynamics in hollow
capillary fibres. Nature Photonics, 2019, vol. 13, no 8, p. 547-554.
"""
factor = (math.u_nm(1, 1) / c) ** 2 * (0.5 * wl / np.pi) ** 3
f = np.gradient(np.gradient(self.chi(wl), wl), wl)
ind = math.argclosest(wl, wl_zero_disp)
return factor * (f / f[ind] - 1)
class Gas:
name: str
sellmeier: Sellmeier
atomic_number: int | float
atomic_mass: float
chi3_0: float
ionization_energy: float | None
_raw_sellmeier: dict[str, Any]
_kerr_wl: np.ndarray
def __init__(self, gas_name: str):
self.name = gas_name
self._raw_sellmeier = io.load_material_dico(gas_name)
self.atomic_mass = self._raw_sellmeier["atomic_mass"]
self.atomic_number = self._raw_sellmeier["atomic_number"]
self.ionization_energy = self._raw_sellmeier.get("ionization_energy")
s = self._raw_sellmeier.get("sellmeier", {})
self.sellmeier = Sellmeier(
**{
newk: s.get(k, None)
for newk, k in zip(
["B", "C", "pressure_ref", "temperature_ref", "kind", "constant"],
["B", "C", "P0", "T0", "kind", "const"],
)
if k in s
}
)
kerr = self._raw_sellmeier["kerr"]
n2_0 = kerr["n2"]
self._kerr_wl = kerr.get("wavelength", 800e-9)
self.chi3_0 = (
4
/ 3
* units.epsilon0
* units.c
* self.sellmeier.n_gas_2(self._kerr_wl, kerr["T0"], kerr["P0"])
* n2_0
)
def pressure_from_relative_density(
self, density: float, temperature: float | None = None
) -> float:
temperature = temperature or self.sellmeier.temperature_ref
return self.sellmeier.temperature_ref / temperature * density * self.sellmeier.pressure_ref
def density_factor(self, temperature: float, pressure: float, ideal_gas: bool) -> float:
"""
returns the number density relative to reference values
Parameters
----------
temperature : float
target temperature in K
pressure : float
target pressure in Pa
ideal_gas : bool
whether to use ideal gas law
Returns
-------
float
N / N_0
"""
if ideal_gas:
return (
pressure
/ self.sellmeier.pressure_ref
* self.sellmeier.temperature_ref
/ temperature
)
else:
return self.number_density_van_der_waals(
pressure, temperature
) / self.number_density_van_der_waals(
self.sellmeier.pressure_ref,
self.sellmeier.temperature_ref,
)
def number_density(
self,
temperature: float | None = None,
pressure: float | None = None,
ideal_gas: bool = False,
) -> float:
"""
returns the number density in 1/m^3 using van der Waals equation
Parameters
----------
temperature : float, optional
temperature in K, by default None
pressure : float, optional
pressure in Pa, by default None
Returns
-------
float
number density in 1/m^3
"""
pressure = pressure or self.sellmeier.pressure_ref
temperature = temperature or self.sellmeier.temperature_ref
if ideal_gas:
return pressure / temperature / kB
else:
return self.number_density_van_der_waals(pressure, temperature)
def number_density_van_der_waals(
self, pressure: float | None = None, temperature: float | None = None
):
"""
returns the number density of a gas
Parameters
----------
pressure : float, optional
pressure in Pa, by default the reference pressure
temperature : float, optional
temperature in K, by default the reference temperature
Returns
----------
the numbers density (/m^3)
Raises
----------
ValueError : Since the Van der Waals equation is a cubic one, there could be more than one
real, positive solution
"""
if pressure == 0:
return 0
a = self._raw_sellmeier.get("a", 0)
b = self._raw_sellmeier.get("b", 0)
pressure = (
self._raw_sellmeier["sellmeier"].get("P0", 101325) if pressure is None else pressure
)
temperature = (
self._raw_sellmeier["sellmeier"].get("T0", 273.15)
if temperature is None
else temperature
)
ap = a / NA**2
bp = b / NA
# setup van der Waals equation for the number density
p3 = -ap * bp
p2 = ap
p1 = -(pressure * bp + kB * temperature)
p0 = pressure
# filter out unwanted matches
roots = np.roots([p3, p2, p1, p0])
roots = roots[np.isreal(roots)].real
roots = roots[roots > 0]
if len(roots) != 1:
s = f"Van der Waals eq with parameters P={pressure}, T={temperature}, a={a}, b={b}"
s += f", There is more than one possible number density : {roots}."
s += f", {np.min(roots)} was returned"
warnings.warn(s)
return np.min(roots)
def chi3(self, temperature: float | None = None, pressure: float | None = None) -> float:
"""nonlinear susceptibility"""
# if pressure and/or temperature are specified, adjustment is made
# according to number density ratio
if pressure is not None or temperature is not None:
N0 = self.number_density_van_der_waals()
N = self.number_density_van_der_waals(pressure, temperature)
ratio = N / N0
else:
ratio = 1
return ratio * self.chi3_0
def n2(self, temperature: float | None = None, pressure: float | None = None) -> float:
sellmeier = self.sellmeier.n_gas_2(self._kerr_wl, temperature, pressure)
chi3 = self.chi3(temperature, pressure)
return 0.75 * chi3 / (units.epsilon0 * units.c * sellmeier)
@property
def ionic_charge(self):
return 1
@property
def barrier_suppression(self) -> float:
"""
Compute the barrier suppression threshold (W/m^2)
"""
field_max = self.barrier_suppression_field
return 0.5 * units.c * units.epsilon0 * field_max**2
@property
def barrier_suppression_field(self) -> float:
"""
Barrier suppression threshold electric field
Reference
---------
[1] KRAINOV, V. P. Theory of barrier-suppression ionization of atoms. Journal of Nonlinear
Optical Physics & Materials, 1995, vol. 4, no 04, p. 775-798.
[2] BETHE, H. A. et SALPETER, E. E. Quantum mechanics of one-and two-electron atoms. 1977.
"""
# from [1-2] :
# field_max = 0.0625 / self.ionic_charge * (self.ionization_energy / 2.1787e-18) ** 2
# return field_max = 5.14220670712125e11
# from [3] :
if self.ionization_energy is None:
raise ValueError(f"no ionization_energy for {self.name}")
Z = self.ionic_charge
Ip_au = self.ionization_energy / 4.359744650021498e-18
ns = Z / np.sqrt(2 * Ip_au)
return Z**3 / (16 * ns**4) * 5.14220670712125e11
def get(self, key, default=None):
return self._raw_sellmeier.get(key, default)
def __getitem__(self, key):
return self._raw_sellmeier[key]
def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.name!r})"
def n_gas_2(
wl: np.ndarray, gas_name: str, pressure: float | None, temperature: float | None
) -> np.ndarray:
"""Returns the sqare of the index of refraction of the specified gas"""
return Sellmeier.load(gas_name).n_gas_2(wl, temperature, pressure)
def pressure_from_gradient(ratio: float, p0: float, p1: float) -> float:
"""
returns the pressure as function of distance with eq. 20 in Markos et al. (2017)
Parameters
----------
ratio : relative position in the fiber (0 = start, 1 = end)
p0 : pressure at the start
p1 : pressure at the end
Returns
-------
the pressure (float)
"""
return np.sqrt(p0**2 - ratio * (p0**2 - p1**2))
def delta_gas(w: np.ndarray, gas: Gas) -> np.ndarray:
"""
returns the value delta_t (eq. 24 in Markos(2017))
Parameters
----------
w : np.ndarray
angular frequency array
gas : Gas
Returns
-------
delta_t
since 2 gradients are computed, it is recommended to exclude the 2 extremum values
"""
chi = gas.sellmeier.chi(units.m_rads(w))
N0 = gas.number_density_van_der_waals()
dchi_dw = np.gradient(chi, w)
return 1 / (N0 * c) * (dchi_dw + w / 2 * np.gradient(dchi_dw, w))
def gas_n2(gas_name: str, pressure: float, temperature: float) -> float:
"""returns the nonlinear refractive index
Parameters
----------
gas_name : str
gas name
pressure : float
pressure in Pa
temperature : float
temperature in K
Returns
-------
float
n2 in m2/W
"""
return Gas(gas_name).n2(temperature, pressure)
def gas_chi3(gas_name: str, wavelength: float, pressure: float, temperature: float) -> float:
"""
returns the chi3 of a particular material
Parameters
----------
gas_name : str
[description]
pressure : float
[description]
temperature : float
[description]
Returns
-------
float
[description]
"""
gas = Gas(gas_name)
n = gas.sellmeier.n(wavelength, temperature, pressure)
n2 = gas.n2(temperature, pressure)
return n2_to_chi3(n2, n)
def n2_to_chi3(n2: float, n0: float) -> float:
return n2 * 4 * epsilon0 * n0**2 * c / 3
def chi3_to_n2(chi3: float, n0: float) -> float:
return 3.0 * chi3 / (4.0 * epsilon0 * c * n0**2)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,460 @@
# series of functions to convert different values to angular frequencies
# For example, nm(X) means "I give the number X in nm, figure out the ang. freq."
# to be used especially when giving plotting ranges : (400, 1400, nm), (-4, 8, ps), ...
from __future__ import annotations
from typing import Callable, Protocol, Sequence, Union, overload
import numpy as np
from numpy import pi
c = 299792458.0
h = 6.62607015e-34
hbar = 0.5 * h / np.pi
NA = 6.02214076e23
R = 8.31446261815324
kB = 1.380649e-23
epsilon0 = 8.85418781e-12
me = 9.1093837015e-31
e = 1.602176634e-19
prefix = dict(P=1e12, G=1e9, M=1e6, k=1e3, d=1e-1, c=1e-2, m=1e-3, u=1e-6, n=1e-9, p=1e-12, f=1e-15)
"""
Below are common units. You can define your own unit function
provided you decorate it with @unit and provide at least a type and a label
types are "WL", "FREQ", "AFREQ", "TIME", "PRESSURE", "TEMPERATURE", "OTHER"
"""
type _UT[T] = Callable[[T], T]
PRIMARIES = dict(WL="m", FREQ="Rad/s", AFREQ="Rad/s", TIME="s", PRESSURE="Pa", TEMPERATURE="K")
class Unit(Protocol):
@overload
def __call__(self, v: np.ndarray) -> np.ndarray: ...
@overload
def __call__(self, v: float | int | np.floating | np.integer) -> float: ...
def __call__(self, v): ...
@overload
def inv(self, v: np.ndarray) -> np.ndarray: ...
@overload
def inv(self, v: float | int | np.floating | np.integer) -> float: ...
def inv(self, v): ...
def inverse(self, f: _UT) -> Unit: ...
class UnitMap(dict):
def __setitem__(self, new_name, new_func):
super().__setitem__(new_name, new_func)
already_here = [name for name in self if isinstance(name, str)]
for old_name in already_here:
super().__setitem__((old_name, new_name), self._chain(old_name, new_name))
super().__setitem__((new_name, old_name), self._chain(new_name, old_name))
def _chain(self, name_1: str, name_2: str) -> _UT:
c1 = self[name_1]
c2 = self[name_2]
def chained_function[T](x: T) -> T:
return c2.inv(c1(x))
chained_function.name = f"{name_1}_to_{name_2}"
chained_function.__name__ = f"{name_1}_to_{name_2}"
chained_function.__doc__ = f"converts x from {name_1} to {name_2}"
return chained_function
units_map: dict[Union[str, tuple[str, str]], _UT] = UnitMap()
class To:
def __init__(self, name: str):
self.name = name
def __getstate__(self):
"""make pickle happy"""
return self.name
def __setstate__(self, name):
"""make pickle happy"""
self.name = name
def __getattr__(self, key: str):
try:
return units_map[self.name, key]
except KeyError:
raise KeyError(f"no registered unit named {key!r}") from None
def W_to_Vm(n0: float, effective_area: float) -> float:
"""returns the factor to convert from [|E|²] = W to [|E|] = V/m
Parameters
----------
n : float
refractive index
Returns
-------
float
p such that E_sqrt(W) * p = W_Vm
"""
return 1.0 / np.sqrt(effective_area * 0.5 * epsilon0 * c * n0)
def unit_formatter(
unit: str, decimals: int = 3, vmin: float | None = 1e-28
) -> Callable[[float | int], str]:
if not unit:
def formatter(val):
return f"{val:.{decimals}g}"
elif unit == "%":
def formatter(val):
return f"{100 * val:.{decimals}g}%"
else:
def formatter(val):
if vmin is not None and abs(val) < vmin:
return f"0{unit}"
base, true_exp = format(val, f".{3 + decimals}e").split("e")
true_exp = int(true_exp)
exp, mult = divmod(true_exp, 3)
if exp < -8:
mult -= -3 * (8 + exp)
exp = -8
elif exp > 8:
mult += 3 * (exp - 8)
exp = 8
prefix = "yzafpnµm kMGTPEZY"[8 + exp] if exp else ""
return f"{float(base) * 10**mult:.{decimals}g}{prefix}{unit}"
def _format(val):
if isinstance(val, (Sequence, np.ndarray)):
return f"({', '.join(_format(el) for el in val)})"
else:
return formatter(val)
def _format_mpl(val, _):
return _format(val)
setattr(_format, "for_mpl", _format_mpl)
return _format
class unit:
inv = None
def __init__(self, tpe: str, label: str):
self.type = tpe
self.label = label
def __call__(self, func) -> Unit:
self.name = func.__name__
self.func = func
self.inv = func
units_map[self.name] = self.func
func.to = To(self.name)
func.inv = func
func.inverse = self.inverse
func.type = self.type
func.label = self.label
func.name = self.name
func.__doc__ = f"Transform x from {self.name!r} to {PRIMARIES.get(self.type)!r}"
return func
def inverse(self, func: _UT):
if func.__name__ == self.name:
raise ValueError(
f"inverse function of {self.name} must be named something else than {self.name}"
)
self.inv = func
self.func.inv = func
return func
@unit("WL", r"Wavelength λ (m)")
def m(wl):
return wl
@unit("WL", r"Wavelength λ (nm)")
def nm(wl):
return wl * 1e-9
@nm.inverse
def nm_inv(wl):
return wl * 1e9
@unit("WL", r"Wavelength λ (μm)")
def um(wl):
return wl * 1e-6
@um.inverse
def um_inv(wl):
return wl * 1e6
@unit("FREQ", r"Frequency $f$ (Hz)")
def Hz(f):
return 2 * pi * f
@Hz.inverse
def Hz_inv(w):
return w / (2 * pi)
@unit("FREQ", r"Frequency $f$ (THz)")
def THz(f):
return 1e12 * 2 * pi * f
@THz.inverse
def THz_inv(w):
return w / (1e12 * 2 * pi)
@unit("FREQ", r"Frequency $f$ (PHz)")
def PHz(f):
return 1e15 * 2 * pi * f
@PHz.inverse
def PHz_inv(w):
return w / (1e15 * 2 * pi)
@unit("AFREQ", r"Angular frequency $\omega$ ($\frac{\mathrm{rad}}{\mathrm{s}}$)")
def rad_s(w):
return w
@unit("AFREQ", r"Angular frequency $\omega$ ($\frac{\mathrm{Prad}}{\mathrm{s}}$)")
def Prad_s(w):
return w * 1e15
@Prad_s.inverse
def Prad_s_inv(w):
return w * 1e-15
@unit("TIME", r"relative time ${\tau}/{\tau_\mathrm{0, FWHM}}$")
def rel_time(t):
return t
@unit("FREQ", r"relative angular freq. $(\omega - \omega_0)/\Delta\omega_0$")
def rel_freq(f):
return f
@unit("TIME", r"Time $t$ (s)")
def s(t):
return t
@unit("TIME", r"Time $t$ (us)")
def us(t):
return t * 1e-6
@us.inverse
def us_inv(t):
return t * 1e6
@unit("TIME", r"Time $t$ (ns)")
def ns(t):
return t * 1e-9
@ns.inverse
def ns_inv(t):
return t * 1e9
@unit("TIME", r"Time $t$ (ps)")
def ps(t):
return t * 1e-12
@ps.inverse
def ps_inv(t):
return t * 1e12
@unit("TIME", r"Time $t$ (fs)")
def fs(t):
return t * 1e-15
@fs.inverse
def fs_inv(t):
return t * 1e15
@unit("WL", "inverse")
def inv(x):
return 1 / x
@unit("PRESSURE", "Pressure (bar)")
def bar(p):
return 1e5 * p
@bar.inverse
def bar_inv(p):
return p * 1e-5
@unit("PRESSURE", "Pressure (mbar)")
def mbar(p):
return 1e2 * p
@mbar.inverse
def mbar_inv(p):
return 1e-2 * p
@unit("OTHER", r"$\beta_2$ (fs$^2$/cm)")
def beta2_fs_cm(b2):
return 1e-28 * b2
@beta2_fs_cm.inverse
def beta2_fs_cm_inv(b2):
return 1e28 * b2
@unit("OTHER", r"$\beta_2$ (ps$^2$/km)")
def beta2_ps_km(b2):
return 1e-27 * b2
@beta2_ps_km.inverse
def beta2_ps_km_inv(b2):
return 1e27 * b2
@unit("OTHER", r"$D$ (ps/(nm km))")
def D_ps_nm_km(D):
return 1e-6 * D
@D_ps_nm_km.inverse
def D_ps_nm_km_inv(D):
return 1e6 * D
@unit("OTHER", r"a.u.")
def unity(x):
return x
@unit("TEMPERATURE", r"Temperature (K)")
def K(t):
return t
@unit("TEMPERATURE", r"Temperature (°C)")
def C(t_C):
return t_C + 272.15
@C.inverse
def C_inv(t_K):
return t_K - 272.15
@unit("OTHER", r"a.u")
def no_unit(x):
return x
def nm_rads(nm):
return 2e9 * np.pi * c / nm
def nm_hz(nm):
return 1e9 * c / nm
def um_rads(um):
return 2e6 * np.pi * c / um
def um_hz(um):
return 1e6 * c / um
def m_rads(m):
return 2 * np.pi * c / m
def m_hz(m):
return c / m
def get_unit(unit: Union[str, Callable]) -> Callable[[float], float]:
if isinstance(unit, str):
return units_map[unit]
return unit
def beta2_coef(beta2_coefficients):
fac = 1e27
out = np.zeros_like(beta2_coefficients)
for i, b in enumerate(beta2_coefficients):
out[i] = fac * b
fac *= 1e12
return out
def to_WL(spectrum: np.ndarray, lambda_: np.ndarray) -> np.ndarray:
"""
rescales the spectrum because of uneven binning when going from freq to wl
Parameters
----------
spectrum : np.ndarray, shape (..., n)
intensity spectrum
lambda_ : np.ndarray, shape (n, )
wavelength in m
Returns
-------
np.ndarray, shape (n, )
intensity spectrum correctly scaled
"""
m = 2 * pi * c / (lambda_**2) * spectrum
return m
def w_from_wl(wl_min_nm: float, wl_max_nm: float, n: int) -> np.ndarray:
return np.linspace(nm_rads(wl_max_nm), nm_rads(wl_min_nm), n)
def normalize_wavelengths(wl: np.ndarray) -> np.ndarray:
"""attempts to guess the units of wl and return the same array in base SI units (m)"""
if np.all((wl > 0.01) & (wl < 20)):
return wl * 1e-6
elif np.all(wl >= 20):
return wl * 1e-9
return wl

View File

@@ -29,30 +29,17 @@ MPL_COLORS = [
key_type = Union[str, int]
class Field(QtWidgets.QWidget):
class SliderField(QtWidgets.QWidget):
dtype: Type
value: Any
value_changed: QtCore.Signal
timer: QtCore.QTimer
@property
def value(self) -> Any:
raise NotImplementedError()
def values(self) -> list[Any]:
raise NotImplementedError()
class SliderField(Field):
dtype: Type
possible_values: np.ndarray
_slider_max = 100
_tuple_signal = QtCore.Signal(tuple)
_int_signal = QtCore.Signal(int)
_float_signal = QtCore.Signal(float)
_str_signal = QtCore.Signal(str)
def __init__(self, name: str, values: Iterable) -> None:
def __init__(self, name: str, values: Iterable[float] | Iterable[int]) -> None:
super().__init__()
self.__value = None
self.slider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)
@@ -64,16 +51,18 @@ class SliderField(Field):
self.field.editingFinished.connect(self.field_changed)
self.step_backward_button = QtWidgets.QPushButton("<")
self.step_backward_button.setFixedWidth(30)
self.step_backward_button.clicked.connect(self.step_backward)
self.step_forward_button = QtWidgets.QPushButton(">")
self.step_forward_button.setFixedWidth(30)
self.step_forward_button.clicked.connect(self.step_forward)
self._layout = QtWidgets.QHBoxLayout()
self.setLayout(self._layout)
self._layout.setContentsMargins(10, 0, 10, 0)
pretty_name = " ".join(s.title() for s in name.split("_"))
pretty_name = " ".join(s for s in name.split("_"))
self.name_label = QtWidgets.QLabel(pretty_name + " :")
self._layout.addWidget(self.name_label)
@@ -86,13 +75,13 @@ class SliderField(Field):
self.value_changed = {
int: self._int_signal,
float: self._float_signal,
str: self._str_signal,
tuple: self._tuple_signal,
}[self.dtype]
self.value_changed.emit(self.__value)
def set_values(self, values: Iterable):
self.possible_values = np.array(values)
self.possible_values = (
np.array(values) if not isinstance(values, np.ndarray) else values.copy()
)
self.value_to_slider_map = {v: i for i, v in enumerate(self.possible_values)}
self._slider_max = len(self.possible_values) - 1
self.slider.setRange(0, self._slider_max)
@@ -115,7 +104,7 @@ class SliderField(Field):
self.update_slider()
@property
def value(self) -> float:
def value(self) -> float | int:
return self.__value
@value.setter
@@ -130,11 +119,8 @@ class SliderField(Field):
self.value_changed.emit(new_value)
def field_changed(self):
try:
new_val = self.dtype(self.field.text())
except (ValueError, TypeError):
self.update_label()
return
new_val = self.dtype(self.field.text())
new_val = min(self.value_to_slider_map, key=lambda el: abs(el - new_val))
self.value = new_val
def slider_changed(self):
@@ -168,7 +154,7 @@ class SliderField(Field):
if self.dtype is int:
return format(self.value)
elif self.dtype is float:
return format(self.value, ".3g")
return format(self.value, ".5g")
else:
return format(self.value)
@@ -176,66 +162,6 @@ class SliderField(Field):
return list(self.possible_values)
class AnimatedSliderField(SliderField):
def __init__(self, name: str, values: Iterable) -> None:
super().__init__(name, values)
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.step_forward)
self.play_button = QtWidgets.QPushButton("")
self.play_button.clicked.connect(self.toggle)
self.play_button.setMaximumWidth(30)
self.playing = False
self.interval_field = QtWidgets.QLineEdit()
self.interval_field.setMaximumWidth(60)
# self.interval_field.setValidator(QtGui.QIntValidator(1, 5000))
self.interval_field.editingFinished.connect(self.set_interval)
self.interval_field.inputRejected.connect(self.set_interval)
self.interval = 16
self.set_interval()
self._layout.addWidget(self.play_button)
self._layout.addWidget(self.interval_field)
def toggle(self):
if self.playing:
self.stop()
self.playing = False
else:
self.play()
self.playing = True
def play(self):
if self.slider.value() == self._slider_max:
self.slider.setValue(0)
self.timer.start(self.interval)
self.play_button.setStyleSheet("QPushButton {background-color: #DEF2DD;}")
def stop(self):
self.timer.stop()
self.play_button.setStyleSheet("QPushButton {background-color: none;}")
def set_interval(self):
try:
self.interval = max(1, int(self.interval_field.text()))
except ValueError:
self.interval_field.setText(str(self.interval))
if self.interval < 16:
self.increment = int(np.ceil(16 / self.interval))
self.interval *= self.increment
else:
self.increment = 1
def step_forward(self):
current = self.slider.value()
if current + self.increment <= self._slider_max:
self.slider.setValue(current + self.increment)
else:
self.slider.setValue(self._slider_max)
self.stop()
class Plot:
name: str
dock: Dock
@@ -511,11 +437,12 @@ class PlotApp:
self.params_widget = QtWidgets.QWidget()
self.header_widget = QtWidgets.QWidget()
self.info_label = QtWidgets.QLabel()
# self.info_label.setMaximumWidth(120)
self.window.setCentralWidget(self.central_widget)
self.central_layout = QtWidgets.QVBoxLayout()
self.params_layout = QtWidgets.QVBoxLayout()
self.header_layout = QtWidgets.QHBoxLayout()
self.params_layout = QtWidgets.QGridLayout()
self.header_layout = QtWidgets.QVBoxLayout()
_pl = QtWidgets.QSizePolicy.Policy.Preferred
info_sp = QtWidgets.QSizePolicy(_pl, _pl)
@@ -540,10 +467,10 @@ class PlotApp:
self.__ran = False
self.params = {}
for p_name, values in params.items():
field = AnimatedSliderField(p_name, values)
for i, (p_name, values) in enumerate(params.items()):
field = SliderField(p_name, values)
self.params[p_name] = field
self.params_layout.addWidget(field)
self.params_layout.addWidget(field, *divmod(i, 2))
def set_antialiasing(self, val: bool):
pg.setConfigOptions(antialias=val)
@@ -562,7 +489,7 @@ class PlotApp:
opts = dict(zip(["v_min", "v_max", "v_num", "v_init"], opts))
yield p_name, dtype, opts
def update(self, *p_names: str):
def update(self, first_param: str | Callable, *p_names: str):
"""
use this as a decorator to connect the decorated function to
the value_changed signal of some parameters
@@ -595,8 +522,12 @@ class PlotApp:
changes and is given its new value as argument
"""
if len(p_names) == 1 and callable(p_names[0]):
return self.update(*self._get_func_args(p_names[0]))(p_names[0])
if len(p_names) == 0 and callable(first_param) and not isinstance(first_param, str):
return self.update(*self._get_func_args(first_param))(first_param)
elif not isinstance(first_param, str):
raise TypeError()
p_names = (first_param, *p_names)
def wrapper(func):
def to_call(v=None):
@@ -724,12 +655,10 @@ class PlotApp:
self.app.exec()
@overload
def __getitem__(self, key: tuple[key_type, key_type]) -> PlotDataItem:
...
def __getitem__(self, key: tuple[key_type, key_type]) -> PlotDataItem: ...
@overload
def __getitem__(self, key: key_type) -> Plot:
...
def __getitem__(self, key: key_type) -> Plot: ...
def __getitem__(self, key: key_type) -> Plot:
if isinstance(key, tuple):

704
uv.lock generated Normal file
View File

@@ -0,0 +1,704 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "annotated-types"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
]
[[package]]
name = "click"
version = "8.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "contourpy"
version = "1.3.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" },
{ url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" },
{ url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" },
{ url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" },
{ url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" },
{ url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" },
{ url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" },
{ url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" },
{ url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" },
{ url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" },
{ url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" },
{ url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" },
{ url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" },
{ url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" },
{ url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" },
{ url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" },
{ url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" },
{ url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" },
{ url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" },
{ url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" },
{ url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" },
{ url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" },
{ url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" },
{ url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" },
{ url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" },
{ url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" },
{ url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" },
{ url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" },
{ url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" },
{ url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" },
{ url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" },
{ url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" },
{ url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" },
{ url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" },
{ url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" },
{ url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" },
{ url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" },
{ url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" },
{ url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" },
{ url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" },
{ url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" },
{ url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" },
{ url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" },
{ url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" },
]
[[package]]
name = "cycler"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" },
]
[[package]]
name = "dispersionapp"
version = "0.2.2"
source = { editable = "." }
dependencies = [
{ name = "click" },
{ name = "numba" },
{ name = "pydantic" },
{ name = "pyqtgraph" },
{ name = "pyside6" },
{ name = "scipy" },
{ name = "tomli" },
{ name = "tomli-w" },
]
[package.dev-dependencies]
dev = [
{ name = "matplotlib" },
]
[package.metadata]
requires-dist = [
{ name = "click" },
{ name = "numba", specifier = ">=0.62.1" },
{ name = "pydantic", specifier = ">=2" },
{ name = "pyqtgraph", specifier = ">=0.13.1" },
{ name = "pyside6", specifier = ">=6.4.0" },
{ name = "scipy", specifier = ">=1.16.3" },
{ name = "tomli" },
{ name = "tomli-w" },
]
[package.metadata.requires-dev]
dev = [{ name = "matplotlib", specifier = ">=3.10.7" }]
[[package]]
name = "fonttools"
version = "4.60.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823, upload-time = "2025-09-29T21:13:27.129Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7c/5b/cdd2c612277b7ac7ec8c0c9bc41812c43dc7b2d5f2b0897e15fdf5a1f915/fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb", size = 2825777, upload-time = "2025-09-29T21:12:01.22Z" },
{ url = "https://files.pythonhosted.org/packages/d6/8a/de9cc0540f542963ba5e8f3a1f6ad48fa211badc3177783b9d5cadf79b5d/fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4", size = 2348080, upload-time = "2025-09-29T21:12:03.785Z" },
{ url = "https://files.pythonhosted.org/packages/2d/8b/371ab3cec97ee3fe1126b3406b7abd60c8fec8975fd79a3c75cdea0c3d83/fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c", size = 4903082, upload-time = "2025-09-29T21:12:06.382Z" },
{ url = "https://files.pythonhosted.org/packages/04/05/06b1455e4bc653fcb2117ac3ef5fa3a8a14919b93c60742d04440605d058/fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77", size = 4960125, upload-time = "2025-09-29T21:12:09.314Z" },
{ url = "https://files.pythonhosted.org/packages/8e/37/f3b840fcb2666f6cb97038793606bdd83488dca2d0b0fc542ccc20afa668/fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199", size = 4901454, upload-time = "2025-09-29T21:12:11.931Z" },
{ url = "https://files.pythonhosted.org/packages/fd/9e/eb76f77e82f8d4a46420aadff12cec6237751b0fb9ef1de373186dcffb5f/fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c", size = 5044495, upload-time = "2025-09-29T21:12:15.241Z" },
{ url = "https://files.pythonhosted.org/packages/f8/b3/cede8f8235d42ff7ae891bae8d619d02c8ac9fd0cfc450c5927a6200c70d/fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272", size = 2217028, upload-time = "2025-09-29T21:12:17.96Z" },
{ url = "https://files.pythonhosted.org/packages/75/4d/b022c1577807ce8b31ffe055306ec13a866f2337ecee96e75b24b9b753ea/fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac", size = 2266200, upload-time = "2025-09-29T21:12:20.14Z" },
{ url = "https://files.pythonhosted.org/packages/9a/83/752ca11c1aa9a899b793a130f2e466b79ea0cf7279c8d79c178fc954a07b/fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3", size = 2822830, upload-time = "2025-09-29T21:12:24.406Z" },
{ url = "https://files.pythonhosted.org/packages/57/17/bbeab391100331950a96ce55cfbbff27d781c1b85ebafb4167eae50d9fe3/fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85", size = 2345524, upload-time = "2025-09-29T21:12:26.819Z" },
{ url = "https://files.pythonhosted.org/packages/3d/2e/d4831caa96d85a84dd0da1d9f90d81cec081f551e0ea216df684092c6c97/fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537", size = 4843490, upload-time = "2025-09-29T21:12:29.123Z" },
{ url = "https://files.pythonhosted.org/packages/49/13/5e2ea7c7a101b6fc3941be65307ef8df92cbbfa6ec4804032baf1893b434/fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003", size = 4944184, upload-time = "2025-09-29T21:12:31.414Z" },
{ url = "https://files.pythonhosted.org/packages/0c/2b/cf9603551c525b73fc47c52ee0b82a891579a93d9651ed694e4e2cd08bb8/fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08", size = 4890218, upload-time = "2025-09-29T21:12:33.936Z" },
{ url = "https://files.pythonhosted.org/packages/fd/2f/933d2352422e25f2376aae74f79eaa882a50fb3bfef3c0d4f50501267101/fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99", size = 4999324, upload-time = "2025-09-29T21:12:36.637Z" },
{ url = "https://files.pythonhosted.org/packages/38/99/234594c0391221f66216bc2c886923513b3399a148defaccf81dc3be6560/fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6", size = 2220861, upload-time = "2025-09-29T21:12:39.108Z" },
{ url = "https://files.pythonhosted.org/packages/3e/1d/edb5b23726dde50fc4068e1493e4fc7658eeefcaf75d4c5ffce067d07ae5/fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987", size = 2270934, upload-time = "2025-09-29T21:12:41.339Z" },
{ url = "https://files.pythonhosted.org/packages/fb/da/1392aaa2170adc7071fe7f9cfd181a5684a7afcde605aebddf1fb4d76df5/fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299", size = 2894340, upload-time = "2025-09-29T21:12:43.774Z" },
{ url = "https://files.pythonhosted.org/packages/bf/a7/3b9f16e010d536ce567058b931a20b590d8f3177b2eda09edd92e392375d/fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01", size = 2375073, upload-time = "2025-09-29T21:12:46.437Z" },
{ url = "https://files.pythonhosted.org/packages/9b/b5/e9bcf51980f98e59bb5bb7c382a63c6f6cac0eec5f67de6d8f2322382065/fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801", size = 4849758, upload-time = "2025-09-29T21:12:48.694Z" },
{ url = "https://files.pythonhosted.org/packages/e3/dc/1d2cf7d1cba82264b2f8385db3f5960e3d8ce756b4dc65b700d2c496f7e9/fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc", size = 5085598, upload-time = "2025-09-29T21:12:51.081Z" },
{ url = "https://files.pythonhosted.org/packages/5d/4d/279e28ba87fb20e0c69baf72b60bbf1c4d873af1476806a7b5f2b7fac1ff/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc", size = 4957603, upload-time = "2025-09-29T21:12:53.423Z" },
{ url = "https://files.pythonhosted.org/packages/78/d4/ff19976305e0c05aa3340c805475abb00224c954d3c65e82c0a69633d55d/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed", size = 4974184, upload-time = "2025-09-29T21:12:55.962Z" },
{ url = "https://files.pythonhosted.org/packages/63/22/8553ff6166f5cd21cfaa115aaacaa0dc73b91c079a8cfd54a482cbc0f4f5/fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259", size = 2282241, upload-time = "2025-09-29T21:12:58.179Z" },
{ url = "https://files.pythonhosted.org/packages/8a/cb/fa7b4d148e11d5a72761a22e595344133e83a9507a4c231df972e657579b/fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c", size = 2345760, upload-time = "2025-09-29T21:13:00.375Z" },
{ url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175, upload-time = "2025-09-29T21:13:24.134Z" },
]
[[package]]
name = "kiwisolver"
version = "1.4.9"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" },
{ url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" },
{ url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" },
{ url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" },
{ url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" },
{ url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" },
{ url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" },
{ url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" },
{ url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" },
{ url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" },
{ url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" },
{ url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" },
{ url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" },
{ url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" },
{ url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" },
{ url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" },
{ url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" },
{ url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" },
{ url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" },
{ url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" },
{ url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" },
{ url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" },
{ url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" },
{ url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" },
{ url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" },
{ url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" },
{ url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" },
{ url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" },
{ url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" },
{ url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" },
{ url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" },
{ url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" },
{ url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" },
{ url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" },
{ url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" },
{ url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" },
{ url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" },
{ url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" },
{ url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" },
{ url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" },
{ url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" },
{ url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" },
{ url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" },
{ url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" },
{ url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" },
{ url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" },
{ url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" },
{ url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" },
{ url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" },
{ url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" },
{ url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" },
]
[[package]]
name = "llvmlite"
version = "0.45.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/99/8d/5baf1cef7f9c084fb35a8afbde88074f0d6a727bc63ef764fe0e7543ba40/llvmlite-0.45.1.tar.gz", hash = "sha256:09430bb9d0bb58fc45a45a57c7eae912850bedc095cd0810a57de109c69e1c32", size = 185600, upload-time = "2025-10-01T17:59:52.046Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/e2/c185bb7e88514d5025f93c6c4092f6120c6cea8fe938974ec9860fb03bbb/llvmlite-0.45.1-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:d9ea9e6f17569a4253515cc01dade70aba536476e3d750b2e18d81d7e670eb15", size = 43043524, upload-time = "2025-10-01T18:03:43.249Z" },
{ url = "https://files.pythonhosted.org/packages/09/b8/b5437b9ecb2064e89ccf67dccae0d02cd38911705112dd0dcbfa9cd9a9de/llvmlite-0.45.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:c9f3cadee1630ce4ac18ea38adebf2a4f57a89bd2740ce83746876797f6e0bfb", size = 37253121, upload-time = "2025-10-01T18:04:30.557Z" },
{ url = "https://files.pythonhosted.org/packages/f7/97/ad1a907c0173a90dd4df7228f24a3ec61058bc1a9ff8a0caec20a0cc622e/llvmlite-0.45.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:57c48bf2e1083eedbc9406fb83c4e6483017879714916fe8be8a72a9672c995a", size = 56288210, upload-time = "2025-10-01T18:01:40.26Z" },
{ url = "https://files.pythonhosted.org/packages/32/d8/c99c8ac7a326e9735401ead3116f7685a7ec652691aeb2615aa732b1fc4a/llvmlite-0.45.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3aa3dfceda4219ae39cf18806c60eeb518c1680ff834b8b311bd784160b9ce40", size = 55140957, upload-time = "2025-10-01T18:02:46.244Z" },
{ url = "https://files.pythonhosted.org/packages/09/56/ed35668130e32dbfad2eb37356793b0a95f23494ab5be7d9bf5cb75850ee/llvmlite-0.45.1-cp313-cp313-win_amd64.whl", hash = "sha256:080e6f8d0778a8239cd47686d402cb66eb165e421efa9391366a9b7e5810a38b", size = 38132232, upload-time = "2025-10-01T18:05:14.477Z" },
]
[[package]]
name = "matplotlib"
version = "3.10.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "contourpy" },
{ name = "cycler" },
{ name = "fonttools" },
{ name = "kiwisolver" },
{ name = "numpy" },
{ name = "packaging" },
{ name = "pillow" },
{ name = "pyparsing" },
{ name = "python-dateutil" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ae/e2/d2d5295be2f44c678ebaf3544ba32d20c1f9ef08c49fe47f496180e1db15/matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7", size = 34804865, upload-time = "2025-10-09T00:28:00.669Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/02/9c/207547916a02c78f6bdd83448d9b21afbc42f6379ed887ecf610984f3b4e/matplotlib-3.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1d9d3713a237970569156cfb4de7533b7c4eacdd61789726f444f96a0d28f57f", size = 8273212, upload-time = "2025-10-09T00:26:56.752Z" },
{ url = "https://files.pythonhosted.org/packages/bc/d0/b3d3338d467d3fc937f0bb7f256711395cae6f78e22cef0656159950adf0/matplotlib-3.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37a1fea41153dd6ee061d21ab69c9cf2cf543160b1b85d89cd3d2e2a7902ca4c", size = 8128713, upload-time = "2025-10-09T00:26:59.001Z" },
{ url = "https://files.pythonhosted.org/packages/22/ff/6425bf5c20d79aa5b959d1ce9e65f599632345391381c9a104133fe0b171/matplotlib-3.10.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3c4ea4948d93c9c29dc01c0c23eef66f2101bf75158c291b88de6525c55c3d1", size = 8698527, upload-time = "2025-10-09T00:27:00.69Z" },
{ url = "https://files.pythonhosted.org/packages/d0/7f/ccdca06f4c2e6c7989270ed7829b8679466682f4cfc0f8c9986241c023b6/matplotlib-3.10.7-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22df30ffaa89f6643206cf13877191c63a50e8f800b038bc39bee9d2d4957632", size = 9529690, upload-time = "2025-10-09T00:27:02.664Z" },
{ url = "https://files.pythonhosted.org/packages/b8/95/b80fc2c1f269f21ff3d193ca697358e24408c33ce2b106a7438a45407b63/matplotlib-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b69676845a0a66f9da30e87f48be36734d6748024b525ec4710be40194282c84", size = 9593732, upload-time = "2025-10-09T00:27:04.653Z" },
{ url = "https://files.pythonhosted.org/packages/e1/b6/23064a96308b9aeceeffa65e96bcde459a2ea4934d311dee20afde7407a0/matplotlib-3.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:744991e0cc863dd669c8dc9136ca4e6e0082be2070b9d793cbd64bec872a6815", size = 8122727, upload-time = "2025-10-09T00:27:06.814Z" },
{ url = "https://files.pythonhosted.org/packages/b3/a6/2faaf48133b82cf3607759027f82b5c702aa99cdfcefb7f93d6ccf26a424/matplotlib-3.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:fba2974df0bf8ce3c995fa84b79cde38326e0f7b5409e7a3a481c1141340bcf7", size = 7992958, upload-time = "2025-10-09T00:27:08.567Z" },
{ url = "https://files.pythonhosted.org/packages/4a/f0/b018fed0b599bd48d84c08794cb242227fe3341952da102ee9d9682db574/matplotlib-3.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:932c55d1fa7af4423422cb6a492a31cbcbdbe68fd1a9a3f545aa5e7a143b5355", size = 8316849, upload-time = "2025-10-09T00:27:10.254Z" },
{ url = "https://files.pythonhosted.org/packages/b0/b7/bb4f23856197659f275e11a2a164e36e65e9b48ea3e93c4ec25b4f163198/matplotlib-3.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e38c2d581d62ee729a6e144c47a71b3f42fb4187508dbbf4fe71d5612c3433b", size = 8178225, upload-time = "2025-10-09T00:27:12.241Z" },
{ url = "https://files.pythonhosted.org/packages/62/56/0600609893ff277e6f3ab3c0cef4eafa6e61006c058e84286c467223d4d5/matplotlib-3.10.7-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:786656bb13c237bbcebcd402f65f44dd61ead60ee3deb045af429d889c8dbc67", size = 8711708, upload-time = "2025-10-09T00:27:13.879Z" },
{ url = "https://files.pythonhosted.org/packages/d8/1a/6bfecb0cafe94d6658f2f1af22c43b76cf7a1c2f0dc34ef84cbb6809617e/matplotlib-3.10.7-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09d7945a70ea43bf9248f4b6582734c2fe726723204a76eca233f24cffc7ef67", size = 9541409, upload-time = "2025-10-09T00:27:15.684Z" },
{ url = "https://files.pythonhosted.org/packages/08/50/95122a407d7f2e446fd865e2388a232a23f2b81934960ea802f3171518e4/matplotlib-3.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d0b181e9fa8daf1d9f2d4c547527b167cb8838fc587deabca7b5c01f97199e84", size = 9594054, upload-time = "2025-10-09T00:27:17.547Z" },
{ url = "https://files.pythonhosted.org/packages/13/76/75b194a43b81583478a81e78a07da8d9ca6ddf50dd0a2ccabf258059481d/matplotlib-3.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:31963603041634ce1a96053047b40961f7a29eb8f9a62e80cc2c0427aa1d22a2", size = 8200100, upload-time = "2025-10-09T00:27:20.039Z" },
{ url = "https://files.pythonhosted.org/packages/f5/9e/6aefebdc9f8235c12bdeeda44cc0383d89c1e41da2c400caf3ee2073a3ce/matplotlib-3.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:aebed7b50aa6ac698c90f60f854b47e48cd2252b30510e7a1feddaf5a3f72cbf", size = 8042131, upload-time = "2025-10-09T00:27:21.608Z" },
{ url = "https://files.pythonhosted.org/packages/0d/4b/e5bc2c321b6a7e3a75638d937d19ea267c34bd5a90e12bee76c4d7c7a0d9/matplotlib-3.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d883460c43e8c6b173fef244a2341f7f7c0e9725c7fe68306e8e44ed9c8fb100", size = 8273787, upload-time = "2025-10-09T00:27:23.27Z" },
{ url = "https://files.pythonhosted.org/packages/86/ad/6efae459c56c2fbc404da154e13e3a6039129f3c942b0152624f1c621f05/matplotlib-3.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07124afcf7a6504eafcb8ce94091c5898bbdd351519a1beb5c45f7a38c67e77f", size = 8131348, upload-time = "2025-10-09T00:27:24.926Z" },
{ url = "https://files.pythonhosted.org/packages/a6/5a/a4284d2958dee4116359cc05d7e19c057e64ece1b4ac986ab0f2f4d52d5a/matplotlib-3.10.7-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c17398b709a6cce3d9fdb1595c33e356d91c098cd9486cb2cc21ea2ea418e715", size = 9533949, upload-time = "2025-10-09T00:27:26.704Z" },
{ url = "https://files.pythonhosted.org/packages/de/ff/f3781b5057fa3786623ad8976fc9f7b0d02b2f28534751fd5a44240de4cf/matplotlib-3.10.7-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7146d64f561498764561e9cd0ed64fcf582e570fc519e6f521e2d0cfd43365e1", size = 9804247, upload-time = "2025-10-09T00:27:28.514Z" },
{ url = "https://files.pythonhosted.org/packages/47/5a/993a59facb8444efb0e197bf55f545ee449902dcee86a4dfc580c3b61314/matplotlib-3.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:90ad854c0a435da3104c01e2c6f0028d7e719b690998a2333d7218db80950722", size = 9595497, upload-time = "2025-10-09T00:27:30.418Z" },
{ url = "https://files.pythonhosted.org/packages/0d/a5/77c95aaa9bb32c345cbb49626ad8eb15550cba2e6d4c88081a6c2ac7b08d/matplotlib-3.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:4645fc5d9d20ffa3a39361fcdbcec731382763b623b72627806bf251b6388866", size = 8252732, upload-time = "2025-10-09T00:27:32.332Z" },
{ url = "https://files.pythonhosted.org/packages/74/04/45d269b4268d222390d7817dae77b159651909669a34ee9fdee336db5883/matplotlib-3.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:9257be2f2a03415f9105c486d304a321168e61ad450f6153d77c69504ad764bb", size = 8124240, upload-time = "2025-10-09T00:27:33.94Z" },
{ url = "https://files.pythonhosted.org/packages/4b/c7/ca01c607bb827158b439208c153d6f14ddb9fb640768f06f7ca3488ae67b/matplotlib-3.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1e4bbad66c177a8fdfa53972e5ef8be72a5f27e6a607cec0d8579abd0f3102b1", size = 8316938, upload-time = "2025-10-09T00:27:35.534Z" },
{ url = "https://files.pythonhosted.org/packages/84/d2/5539e66e9f56d2fdec94bb8436f5e449683b4e199bcc897c44fbe3c99e28/matplotlib-3.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d8eb7194b084b12feb19142262165832fc6ee879b945491d1c3d4660748020c4", size = 8178245, upload-time = "2025-10-09T00:27:37.334Z" },
{ url = "https://files.pythonhosted.org/packages/77/b5/e6ca22901fd3e4fe433a82e583436dd872f6c966fca7e63cf806b40356f8/matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d41379b05528091f00e1728004f9a8d7191260f3862178b88e8fd770206318", size = 9541411, upload-time = "2025-10-09T00:27:39.387Z" },
{ url = "https://files.pythonhosted.org/packages/9e/99/a4524db57cad8fee54b7237239a8f8360bfcfa3170d37c9e71c090c0f409/matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a74f79fafb2e177f240579bc83f0b60f82cc47d2f1d260f422a0627207008ca", size = 9803664, upload-time = "2025-10-09T00:27:41.492Z" },
{ url = "https://files.pythonhosted.org/packages/e6/a5/85e2edf76ea0ad4288d174926d9454ea85f3ce5390cc4e6fab196cbf250b/matplotlib-3.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:702590829c30aada1e8cef0568ddbffa77ca747b4d6e36c6d173f66e301f89cc", size = 9594066, upload-time = "2025-10-09T00:27:43.694Z" },
{ url = "https://files.pythonhosted.org/packages/39/69/9684368a314f6d83fe5c5ad2a4121a3a8e03723d2e5c8ea17b66c1bad0e7/matplotlib-3.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:f79d5de970fc90cd5591f60053aecfce1fcd736e0303d9f0bf86be649fa68fb8", size = 8342832, upload-time = "2025-10-09T00:27:45.543Z" },
{ url = "https://files.pythonhosted.org/packages/04/5f/e22e08da14bc1a0894184640d47819d2338b792732e20d292bf86e5ab785/matplotlib-3.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:cb783436e47fcf82064baca52ce748af71725d0352e1d31564cbe9c95df92b9c", size = 8172585, upload-time = "2025-10-09T00:27:47.185Z" },
]
[[package]]
name = "numba"
version = "0.62.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "llvmlite" },
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a3/20/33dbdbfe60e5fd8e3dbfde299d106279a33d9f8308346022316781368591/numba-0.62.1.tar.gz", hash = "sha256:7b774242aa890e34c21200a1fc62e5b5757d5286267e71103257f4e2af0d5161", size = 2749817, upload-time = "2025-09-29T10:46:31.551Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/22/76/501ea2c07c089ef1386868f33dff2978f43f51b854e34397b20fc55e0a58/numba-0.62.1-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:b72489ba8411cc9fdcaa2458d8f7677751e94f0109eeb53e5becfdc818c64afb", size = 2685766, upload-time = "2025-09-29T10:43:49.161Z" },
{ url = "https://files.pythonhosted.org/packages/80/68/444986ed95350c0611d5c7b46828411c222ce41a0c76707c36425d27ce29/numba-0.62.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:44a1412095534a26fb5da2717bc755b57da5f3053965128fe3dc286652cc6a92", size = 2688741, upload-time = "2025-09-29T10:44:10.07Z" },
{ url = "https://files.pythonhosted.org/packages/78/7e/bf2e3634993d57f95305c7cee4c9c6cb3c9c78404ee7b49569a0dfecfe33/numba-0.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8c9460b9e936c5bd2f0570e20a0a5909ee6e8b694fd958b210e3bde3a6dba2d7", size = 3804576, upload-time = "2025-09-29T10:42:59.53Z" },
{ url = "https://files.pythonhosted.org/packages/e8/b6/8a1723fff71f63bbb1354bdc60a1513a068acc0f5322f58da6f022d20247/numba-0.62.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:728f91a874192df22d74e3fd42c12900b7ce7190b1aad3574c6c61b08313e4c5", size = 3503367, upload-time = "2025-09-29T10:43:26.326Z" },
{ url = "https://files.pythonhosted.org/packages/9c/ec/9d414e7a80d6d1dc4af0e07c6bfe293ce0b04ea4d0ed6c45dad9bd6e72eb/numba-0.62.1-cp313-cp313-win_amd64.whl", hash = "sha256:bbf3f88b461514287df66bc8d0307e949b09f2b6f67da92265094e8fa1282dd8", size = 2745529, upload-time = "2025-09-29T10:44:31.738Z" },
]
[[package]]
name = "numpy"
version = "2.3.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" },
{ url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" },
{ url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" },
{ url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" },
{ url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" },
{ url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" },
{ url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" },
{ url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" },
{ url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" },
{ url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" },
{ url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" },
{ url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" },
{ url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" },
{ url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" },
{ url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" },
{ url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" },
{ url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" },
{ url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" },
{ url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" },
{ url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" },
{ url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" },
{ url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" },
{ url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" },
{ url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" },
{ url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" },
{ url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" },
{ url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" },
{ url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" },
{ url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" },
{ url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" },
{ url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" },
{ url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" },
{ url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" },
{ url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" },
{ url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" },
{ url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" },
{ url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" },
{ url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" },
{ url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" },
{ url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" },
{ url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" },
{ url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" },
{ url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" },
{ url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" },
]
[[package]]
name = "packaging"
version = "25.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
]
[[package]]
name = "pillow"
version = "12.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493, upload-time = "2025-10-15T18:22:25.758Z" },
{ url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461, upload-time = "2025-10-15T18:22:27.286Z" },
{ url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912, upload-time = "2025-10-15T18:22:28.751Z" },
{ url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132, upload-time = "2025-10-15T18:22:30.641Z" },
{ url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099, upload-time = "2025-10-15T18:22:32.73Z" },
{ url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808, upload-time = "2025-10-15T18:22:34.337Z" },
{ url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804, upload-time = "2025-10-15T18:22:36.402Z" },
{ url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553, upload-time = "2025-10-15T18:22:38.066Z" },
{ url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729, upload-time = "2025-10-15T18:22:39.769Z" },
{ url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789, upload-time = "2025-10-15T18:22:41.437Z" },
{ url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917, upload-time = "2025-10-15T18:22:43.152Z" },
{ url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391, upload-time = "2025-10-15T18:22:44.753Z" },
{ url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477, upload-time = "2025-10-15T18:22:46.838Z" },
{ url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918, upload-time = "2025-10-15T18:22:48.399Z" },
{ url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406, upload-time = "2025-10-15T18:22:49.905Z" },
{ url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218, upload-time = "2025-10-15T18:22:51.587Z" },
{ url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564, upload-time = "2025-10-15T18:22:53.215Z" },
{ url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260, upload-time = "2025-10-15T18:22:54.933Z" },
{ url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248, upload-time = "2025-10-15T18:22:56.605Z" },
{ url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043, upload-time = "2025-10-15T18:22:58.53Z" },
{ url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915, upload-time = "2025-10-15T18:23:00.582Z" },
{ url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998, upload-time = "2025-10-15T18:23:02.627Z" },
{ url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201, upload-time = "2025-10-15T18:23:04.709Z" },
{ url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165, upload-time = "2025-10-15T18:23:06.46Z" },
{ url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834, upload-time = "2025-10-15T18:23:08.194Z" },
{ url = "https://files.pythonhosted.org/packages/54/2a/9a8c6ba2c2c07b71bec92cf63e03370ca5e5f5c5b119b742bcc0cde3f9c5/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9", size = 4045531, upload-time = "2025-10-15T18:23:10.121Z" },
{ url = "https://files.pythonhosted.org/packages/84/54/836fdbf1bfb3d66a59f0189ff0b9f5f666cee09c6188309300df04ad71fa/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2", size = 4120554, upload-time = "2025-10-15T18:23:12.14Z" },
{ url = "https://files.pythonhosted.org/packages/0d/cd/16aec9f0da4793e98e6b54778a5fbce4f375c6646fe662e80600b8797379/pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a", size = 3576812, upload-time = "2025-10-15T18:23:13.962Z" },
{ url = "https://files.pythonhosted.org/packages/f6/b7/13957fda356dc46339298b351cae0d327704986337c3c69bb54628c88155/pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b", size = 5252689, upload-time = "2025-10-15T18:23:15.562Z" },
{ url = "https://files.pythonhosted.org/packages/fc/f5/eae31a306341d8f331f43edb2e9122c7661b975433de5e447939ae61c5da/pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad", size = 4650186, upload-time = "2025-10-15T18:23:17.379Z" },
{ url = "https://files.pythonhosted.org/packages/86/62/2a88339aa40c4c77e79108facbd307d6091e2c0eb5b8d3cf4977cfca2fe6/pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01", size = 6230308, upload-time = "2025-10-15T18:23:18.971Z" },
{ url = "https://files.pythonhosted.org/packages/c7/33/5425a8992bcb32d1cb9fa3dd39a89e613d09a22f2c8083b7bf43c455f760/pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c", size = 8039222, upload-time = "2025-10-15T18:23:20.909Z" },
{ url = "https://files.pythonhosted.org/packages/d8/61/3f5d3b35c5728f37953d3eec5b5f3e77111949523bd2dd7f31a851e50690/pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e", size = 6346657, upload-time = "2025-10-15T18:23:23.077Z" },
{ url = "https://files.pythonhosted.org/packages/3a/be/ee90a3d79271227e0f0a33c453531efd6ed14b2e708596ba5dd9be948da3/pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e", size = 7038482, upload-time = "2025-10-15T18:23:25.005Z" },
{ url = "https://files.pythonhosted.org/packages/44/34/a16b6a4d1ad727de390e9bd9f19f5f669e079e5826ec0f329010ddea492f/pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9", size = 6461416, upload-time = "2025-10-15T18:23:27.009Z" },
{ url = "https://files.pythonhosted.org/packages/b6/39/1aa5850d2ade7d7ba9f54e4e4c17077244ff7a2d9e25998c38a29749eb3f/pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab", size = 7131584, upload-time = "2025-10-15T18:23:29.752Z" },
{ url = "https://files.pythonhosted.org/packages/bf/db/4fae862f8fad0167073a7733973bfa955f47e2cac3dc3e3e6257d10fab4a/pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b", size = 6400621, upload-time = "2025-10-15T18:23:32.06Z" },
{ url = "https://files.pythonhosted.org/packages/2b/24/b350c31543fb0107ab2599464d7e28e6f856027aadda995022e695313d94/pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b", size = 7142916, upload-time = "2025-10-15T18:23:34.71Z" },
{ url = "https://files.pythonhosted.org/packages/0f/9b/0ba5a6fd9351793996ef7487c4fdbde8d3f5f75dbedc093bb598648fddf0/pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0", size = 2523836, upload-time = "2025-10-15T18:23:36.967Z" },
{ url = "https://files.pythonhosted.org/packages/f5/7a/ceee0840aebc579af529b523d530840338ecf63992395842e54edc805987/pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6", size = 5255092, upload-time = "2025-10-15T18:23:38.573Z" },
{ url = "https://files.pythonhosted.org/packages/44/76/20776057b4bfd1aef4eeca992ebde0f53a4dce874f3ae693d0ec90a4f79b/pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6", size = 4653158, upload-time = "2025-10-15T18:23:40.238Z" },
{ url = "https://files.pythonhosted.org/packages/82/3f/d9ff92ace07be8836b4e7e87e6a4c7a8318d47c2f1463ffcf121fc57d9cb/pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1", size = 6267882, upload-time = "2025-10-15T18:23:42.434Z" },
{ url = "https://files.pythonhosted.org/packages/9f/7a/4f7ff87f00d3ad33ba21af78bfcd2f032107710baf8280e3722ceec28cda/pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e", size = 8071001, upload-time = "2025-10-15T18:23:44.29Z" },
{ url = "https://files.pythonhosted.org/packages/75/87/fcea108944a52dad8cca0715ae6247e271eb80459364a98518f1e4f480c1/pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca", size = 6380146, upload-time = "2025-10-15T18:23:46.065Z" },
{ url = "https://files.pythonhosted.org/packages/91/52/0d31b5e571ef5fd111d2978b84603fce26aba1b6092f28e941cb46570745/pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925", size = 7067344, upload-time = "2025-10-15T18:23:47.898Z" },
{ url = "https://files.pythonhosted.org/packages/7b/f4/2dd3d721f875f928d48e83bb30a434dee75a2531bca839bb996bb0aa5a91/pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8", size = 6491864, upload-time = "2025-10-15T18:23:49.607Z" },
{ url = "https://files.pythonhosted.org/packages/30/4b/667dfcf3d61fc309ba5a15b141845cece5915e39b99c1ceab0f34bf1d124/pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4", size = 7158911, upload-time = "2025-10-15T18:23:51.351Z" },
{ url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045, upload-time = "2025-10-15T18:23:53.177Z" },
{ url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282, upload-time = "2025-10-15T18:23:55.316Z" },
{ url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" },
]
[[package]]
name = "pydantic"
version = "2.12.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-types" },
{ name = "pydantic-core" },
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/ad/a17bc283d7d81837c061c49e3eaa27a45991759a1b7eae1031921c6bd924/pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac", size = 821038, upload-time = "2025-11-05T10:50:08.59Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/82/2f/e68750da9b04856e2a7ec56fc6f034a5a79775e9b9a81882252789873798/pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e", size = 463400, upload-time = "2025-11-05T10:50:06.732Z" },
]
[[package]]
name = "pydantic-core"
version = "2.41.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
{ url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
{ url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
{ url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
{ url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
{ url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
{ url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
{ url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
{ url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
{ url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
{ url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
{ url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
{ url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
{ url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
{ url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
{ url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
{ url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
{ url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
{ url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
{ url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
{ url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
{ url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
{ url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
{ url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
{ url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
{ url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
{ url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
{ url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
{ url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
{ url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
{ url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
{ url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
{ url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
{ url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
{ url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
{ url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
{ url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
{ url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
{ url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
{ url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
{ url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
{ url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
]
[[package]]
name = "pyparsing"
version = "3.2.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" },
]
[[package]]
name = "pyqtgraph"
version = "0.14.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama" },
{ name = "numpy" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/32/36/4c242f81fdcbfa4fb62a5645f6af79191f4097a0577bd5460c24f19cc4ef/pyqtgraph-0.14.0-py3-none-any.whl", hash = "sha256:7abb7c3e17362add64f8711b474dffac5e7b0e9245abdf992e9a44119b7aa4f5", size = 1924755, upload-time = "2025-11-16T19:43:22.251Z" },
]
[[package]]
name = "pyside6"
version = "6.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyside6-addons" },
{ name = "pyside6-essentials" },
{ name = "shiboken6" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/e6/98/84b16f78b5d92dd234fb1eb9890a350a5b0c83d985bb8c44a92f813a2d02/pyside6-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:c2cbc5dc2a164e3c7c51b3435e24203e90e5edd518c865466afccbd2e5872bb0", size = 558115, upload-time = "2025-10-08T09:47:09.246Z" },
{ url = "https://files.pythonhosted.org/packages/4e/76/0961c8c5653ecb60a6881b649dcb6b71a6be5bd1c8d441ecc48ac7f50b1a/pyside6-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ae8c3c8339cd7c3c9faa7cc5c52670dcc8662ccf4b63a6fed61c6345b90c4c01", size = 557762, upload-time = "2025-10-08T09:47:11.819Z" },
{ url = "https://files.pythonhosted.org/packages/c8/73/6187502fff8b6599443d15c46dd900b2ded24be5aacb2becce33f6faf566/pyside6-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:9f402f883e640048fab246d36e298a5e16df9b18ba2e8c519877e472d3602820", size = 558299, upload-time = "2025-10-08T09:47:14.255Z" },
{ url = "https://files.pythonhosted.org/packages/43/67/94794ebaf198bbdb35cb77f19f38370f9b323b036ab149874bc33c38faab/pyside6-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:70a8bcc73ea8d6baab70bba311eac77b9a1d31f658d0b418e15eb6ea36c97e6f", size = 564367, upload-time = "2025-10-08T09:47:16.287Z" },
{ url = "https://files.pythonhosted.org/packages/1d/cc/552331d413c1b933d54ed45e33cc7ff29d0b239677975fe2528e7ac8bfbc/pyside6-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:4b709bdeeb89d386059343a5a706fc185cee37b517bda44c7d6b64d5fdaf3339", size = 548826, upload-time = "2025-10-08T09:47:18.399Z" },
]
[[package]]
name = "pyside6-addons"
version = "6.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyside6-essentials" },
{ name = "shiboken6" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/47/23/9fbdec2ce16244ac3fe28e6d44c39c70465c93a03325939a792fd00fde7f/pyside6_addons-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:88e61e21ee4643cdd9efb39ec52f4dc1ac74c0b45c5b7fa453d03c094f0a8a5c", size = 322248256, upload-time = "2025-10-08T09:47:37.844Z" },
{ url = "https://files.pythonhosted.org/packages/b7/b8/d129210f2c7366b4e1bf5bb6230be42052b29e8ba1b1d7db6ef333cf5a39/pyside6_addons-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:08d4ed46c4c9a353a9eb84134678f8fdd4ce17fb8cce2b3686172a7575025464", size = 170238987, upload-time = "2025-10-08T09:47:51.446Z" },
{ url = "https://files.pythonhosted.org/packages/cf/ae/ede1edd009395092219f3437d2ee59f9ba93739c28c040542ed47c6cc831/pyside6_addons-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:15d32229d681be0bba1b936c4a300da43d01e1917ada5b57f9e03a387c245ab0", size = 165939425, upload-time = "2025-10-08T09:48:02.073Z" },
{ url = "https://files.pythonhosted.org/packages/7d/5d/a3c32f85ac7f905c95679967c0ddda0ba043c273b75623cc90d8185064e4/pyside6_addons-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:99d93a32c17c5f6d797c3b90dd58f2a8bae13abde81e85802c34ceafaee11859", size = 164814172, upload-time = "2025-10-08T09:48:12.891Z" },
{ url = "https://files.pythonhosted.org/packages/a3/2a/4ff71b09571202c8e1320c45276fc1d0cd81ee53107dfc17bb22d4243f88/pyside6_addons-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:92536427413f3b6557cf53f1a515cd766725ee46a170aff57ad2ff1dfce0ffb1", size = 34104251, upload-time = "2025-10-08T09:48:18.287Z" },
]
[[package]]
name = "pyside6-essentials"
version = "6.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "shiboken6" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/e5/55/bad02ab890c8b8101abef0db4a2e5304be78a69e23a438e4d8555b664467/pyside6_essentials-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:003e871effe1f3e5b876bde715c15a780d876682005a6e989d89f48b8b93e93a", size = 105034090, upload-time = "2025-10-08T09:48:24.944Z" },
{ url = "https://files.pythonhosted.org/packages/5c/75/e17efc7eb900993e0e3925885635c6cf373c817196f09bcbcc102b00ac94/pyside6_essentials-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:1d5e013a8698e37ab8ef360e6960794eb5ef20832a8d562e649b8c5a0574b2d8", size = 76362150, upload-time = "2025-10-08T09:48:31.849Z" },
{ url = "https://files.pythonhosted.org/packages/06/62/fbd1e81caafcda97b147c03f5b06cfaadd8da5fa8298f527d2ec648fa5b7/pyside6_essentials-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:b1dd0864f0577a448fb44426b91cafff7ee7cccd1782ba66491e1c668033f998", size = 75454169, upload-time = "2025-10-08T09:48:38.21Z" },
{ url = "https://files.pythonhosted.org/packages/bb/3a/d8211d17e6ca70f641c6ebd309f08ef18930acda60e74082c75875a274da/pyside6_essentials-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:fc167eb211dd1580e20ba90d299e74898e7a5a1306d832421e879641fc03b6fe", size = 74361794, upload-time = "2025-10-08T09:48:44.335Z" },
{ url = "https://files.pythonhosted.org/packages/61/e9/0e22e3c10325c4ff09447fadb43f7962afb82cef0b65358f5704251c6b32/pyside6_essentials-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:6dd0936394cb14da2fd8e869899f5e0925a738b1c8d74c2f22503720ea363fb1", size = 55099467, upload-time = "2025-10-08T09:48:50.902Z" },
]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "six" },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
]
[[package]]
name = "scipy"
version = "1.16.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" },
{ url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" },
{ url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" },
{ url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" },
{ url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" },
{ url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" },
{ url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" },
{ url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" },
{ url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" },
{ url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" },
{ url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" },
{ url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" },
{ url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" },
{ url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" },
{ url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" },
{ url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" },
{ url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" },
{ url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" },
{ url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" },
{ url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" },
{ url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" },
{ url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" },
{ url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" },
{ url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" },
{ url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" },
{ url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" },
{ url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" },
{ url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" },
{ url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" },
{ url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" },
{ url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" },
{ url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" },
{ url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" },
{ url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" },
{ url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" },
{ url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" },
{ url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" },
{ url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" },
{ url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" },
{ url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" },
]
[[package]]
name = "shiboken6"
version = "6.10.0"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fd/78/3e730aea82089dd82b1e092bc265778bda329459e6ad9b7134eec5fff3f2/shiboken6-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:7a5f5f400ebfb3a13616030815708289c2154e701a60b9db7833b843e0bee543", size = 476535, upload-time = "2025-10-08T09:49:08Z" },
{ url = "https://files.pythonhosted.org/packages/ea/09/4ffa3284a17b6b765d45b41c9a7f1b2cde6c617c853ac6f170fb62bbbece/shiboken6-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:e612734da515d683696980107cdc0396a3ae0f07b059f0f422ec8a2333810234", size = 271098, upload-time = "2025-10-08T09:49:09.47Z" },
{ url = "https://files.pythonhosted.org/packages/31/29/00e26f33a0fb259c2edce9c761a7a438d7531ca514bdb1a4c072673bd437/shiboken6-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:b01377e68d14132360efb0f4b7233006d26aa8ae9bb50edf00960c2a5f52d148", size = 267698, upload-time = "2025-10-08T09:49:10.694Z" },
{ url = "https://files.pythonhosted.org/packages/11/30/e4624a7e3f0dc9796b701079b77defcce0d32d1afc86bb1d0df04bc3d9e2/shiboken6-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:0bc5631c1bf150cbef768a17f5f289aae1cb4db6c6b0c19b2421394e27783717", size = 1234227, upload-time = "2025-10-08T09:49:12.774Z" },
{ url = "https://files.pythonhosted.org/packages/dd/e5/0ab862005ea87dc8647ba958a3099b3b0115fd6491c65da5c5a0f6364db1/shiboken6-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:dfc4beab5fec7dbbebbb418f3bf99af865d6953aa0795435563d4cbb82093b61", size = 1794775, upload-time = "2025-10-08T09:49:14.641Z" },
]
[[package]]
name = "six"
version = "1.17.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
]
[[package]]
name = "tomli"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" },
{ url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" },
{ url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" },
{ url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" },
{ url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" },
{ url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" },
{ url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" },
{ url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" },
{ url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" },
{ url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" },
{ url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" },
{ url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" },
{ url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" },
{ url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" },
{ url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" },
{ url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" },
{ url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" },
{ url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" },
{ url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" },
{ url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" },
{ url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" },
{ url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" },
{ url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" },
{ url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" },
{ url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" },
]
[[package]]
name = "tomli-w"
version = "1.2.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]
[[package]]
name = "typing-inspection"
version = "0.4.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
]