basic course content added, more TODO

This commit is contained in:
Thomas (Tom) C. Gorordo 2026-02-22 18:07:24 -08:00
commit 76468828e3
Signed by: tgorordo
GPG key ID: 0CBED22BB0D94490
94 changed files with 22022 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.stack-work
_cache
_site
.venv
Manifest.toml

2
Project.toml Normal file
View file

@ -0,0 +1,2 @@
[deps]
Pluto = "c3e4b0f8-55cb-11ea-2926-15256bba5781"

97
README.md Normal file
View file

@ -0,0 +1,97 @@
---
title: "Thomas (Tom) C. Gorordo"
---
(*he/him*)
| | |
| ------------- | ---------------------------------------------------- |
| **email**: | [tgorordo@uoregon.edu](mailto:tgorordo@uoregon.edu) |
| **office**: | 463 Willamette Hall (WIL 463) |
| **addr.**: | [Department of Physics](https://naturalsciences.uoregon.edu/physics/contact-us) |
| | 120 Willamette Hall, 1371 E 13th Avenue |
| | University of Oregon |
| | Eugene, OR 97403-1274 |
Welcome to my academic site! See also: [my personal site](https://tom.ket.dev),
[my UO Blog](https://blogs.uoregon.edu/tgorordo)[.](https://titanic.caltech.edu/~tgorordo)
I'm a Physics PhD candidate/[Graduate Student](https://cas.uoregon.edu/directory/profiles/all/tgorordo)
in the [Institute for Fundamental Science (IFS)](https://ifs.uoregon.edu/theory/)
at the University of Oregon working with [Graham Kribs](https://pages.uoregon.edu/kribs/).
I previously held a Research Assistant position at the Lawrence Berkeley National Laboratory (LBNL/LBL)
during 2020-2022, after finishing my undergraduate at the California Institute of Technology (Caltech) in 2019.
This site is under-construction at the moment, so a lot of content is missing and links may not terminate correctly - be sure to check back later :)
---
## Publications
[INSPIRE: T.Gorordo.1](https://inspirehep.net/authors/2051247)
[ORCID: 0009-0001-0342-6205](https://orcid.org/0009-0001-0342-6205)
---
## Software Contributions ([Git](https://git.ket.dev), [Gists](https://gist.ket.dev), [Github](https://github.com/tgorordo))
Selected:
- [`StandardHaloModelsPP.jl`](https://github.com/tgorordo/StandardHaloModelsPP.jl):
A package encoding galactic Dark Matter velocity distributions and various integrals.
- [`NRNuclearDMResponses.jl`](https://github.com/tgorordo/NRNuclearDMResponses.jl):
A package implementing general NREFT Dark Matter Nuclear Response functions.
- [`WignerSymbols.jl`](https://github.com/tgorordo/WignerSymbols.jl):
A fork of [`Jutho/WignerSymbols.jl`](https://github.com/Jutho/WignerSymbols.jl)
adding the Wigner 9j symbols (yet to be upstreamed).
For software collaboration I use the email: [tcgorordo@gmail.com](mailto:tcgorordo@gmail.com)
([public PGP key](/files/tgorordo-pub.pgp)).
---
## Presentations, Posts and Ponderings
Recent:
$partial("templates/post-list.html")$
or check the [archive](/archive.html) for more.
---
## Course Notes & (Extra) Content
- **UO Ph. 611 - Theoretical Mechanics** *(TA Fall 2025)*
- [TA Solution Sets](/courses/uoph611_Th-Mechanics/).
- **UO Ph. 410/510c - Scientific Computation** *(TA Spring 2024)*
- [Scientific Computation Resources List](/courses/uoph410-510c_Sci-Comp/resources.html).
- **UO Ph. 410/510a - Image Analysis** *(TA Fall 2024)*
- [Intro Python `venv` Setup Guide](/courses/uoph410-510a_Image-Analysis/setup.html)
- TA Solution Sets: [`s0.py.html`](/courses/uoph410-510a_Image-Analysis/wk1/s0.html),
[`s1.py.html`](/courses/uoph410-510a_Image-Analysis/wk1/s1.html),
[`s2.py.html`](/courses/uoph410-510a_Image-Analysis/wk2/s2.html),
[`s3.py.html`](/courses/uoph410-510a_Image-Analysis/wk3/s3.html),
[`s4.py.html`](/courses/uoph410-510a_Image-Analysis/wk4/s4.html),
[`s5.py.html`](/courses/uoph410-510a_Image-Analysis/wk5/s5.html),
[`s6.py.html`](/courses/uoph410-510a_Image-Analysis/wk6/s6.html),
[`s7.py.html`](/courses/uoph410-510a_Image-Analysis/wk7/s7.html),
[`s8.py.html`](/courses/uoph410-510a_Image-Analysis/wk8/s8.html)
- **UO Ph. 444/544 - Intro. BioPhysics** *(TA Fall 2023)*
- TA Solution Sets:
- **UO Ph. 20Xabc and Ph. 25Xabc - Foundations** *(TA Various)*
- Optics: [Fun with Fermat's principle of least time](/courses/uoph25X_Foundations/fermat.html).
---
## Misc./Tools
- [`dotfiles`](https://github.com/tgorordo/dots): Various software configurations, managed using [chezmoi](https://www.chezmoi.io/).
- Templates - [Copier]() project and environment templates: [`copier-python`](https://github.com/tgorordo/copier-python), [`copier-julia`](https://github.com/tgorordo/copier-julia)
- [`carousel`](https://github.com/tgorordo/carousel) (NONFUNCTIONAL [CGI App Form](/files/forms/carousel.html)):
A stable-matching solver that can e.g. be used to find optimal TA assignments.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -0,0 +1,175 @@
---
title: Setting up and Managing Python Environments
author: "[Thomas (Tom) C. Gorordo](https://pages.uoregon.edu/tgorordo) - your TA"
date: 2024-10-01
lang: en
...
To help you get started/possibly avoid at least some tech support/give some advice here's a brief note on Python development environments.
So, welcome to the zoo that is software configuration!
![standards.png](https://imgs.xkcd.com/comics/standards.png)
### POSIX Shells and Environments
It won't come up very often in the course assignments themselves, but for tech support I will generally assume you have access to
a [POSIX](https://en.wikipedia.org/wiki/POSIX) compliant shell (command-line) somewhere on your
machine. If you're using a Linux or Mac operating system
your default shell is likely [`bash`](https://www.gnu.org/software/bash/) or
[`zsh`](https://zsh.sourceforge.io/) (or some variant or equivalent thereof accessible through some kind of 'terminal' program), in which case you should be good-to-go.
If you're on Windows things may be more complicated -
I'm not very up to speed on the current state of [powershell](https://learn.microsoft.com/en-us/powershell/) -
but I can recommend looking into the [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/),
or [`git-bash`](https://gitforwindows.org/), and/or [CygWin](https://www.cygwin.com/)
as ways to get a \*nix-like environment on Windows that I'll be able to help with.
You may also want an editor like [Visual Studio Code](https://code.visualstudio.com/) or [Spyder](https://www.spyder-ide.org/) - though there are many other valid choices for writing/editing your software for this course.
(if you really want to be a shell guru there's always the likes of [neovim](https://neovim.io/);
beware the learning curve.)
You're welcome to set up your technology stack however you'd like, but I can't guarantee I'll be able to debug anything
or replicate your environment faithfully when testing your assignments if you deviate too far from modern Linux dev standards and/or common software (I can help with MATLAB or Julia as well as Python - this guide just anticipates Python will be the most common language choice, and that MATLAB is more self-contained/explanatory).
### Getting and Using Python
If you don't have it already in some form, you should [download and install Python3](https://www.python.org/downloads/) for your system.
You'll also, at a minimum, need to be able to [install packages](https://packaging.python.org/en/latest/tutorials/installing-packages/) (<-- READ THIS LINK if you're at all unsure about what is needed. If you have [`pip`](https://pypi.org/project/pip/) you're good to go with respect to this step).
There are some alternative ways of getting/using python (e.g. [`conda`](https://conda.io/projects/conda/en/latest/user-guide/getting-started.html)) -
but this note will focus on a pretty generic workflow that should be compatible with essentially *any* up-to-date system-level python installation.
Depending on your operating system, it might be more appropriate to use a package manager like
[`apt`](https://ubuntu.com/server/docs/package-management) (for Debian Linux derivatives like Ubuntu - others for other distros),
[homebrew](https://brew.sh/) (for MacOS), or
[winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/install?source=recommendations)/[chocolatey](https://chocolatey.org/) (for Windows)
instead of downloading and running the installer linked above.
Detailed installation instructions will vary a lot by OS, so I won't provide them here - learning how/where to look up system specific ways to do things
(and getting familiar with your machine and customizing it to your liking) is an important skill to develop, but you'll mostly have to find favorite resources and methods yourself over time.
### Dependency Management
We'll often want our code to depend on various external libraries rather than implement *everything* from scratch ourselves (even though that is often necessary or useful - there are situations we won't want to reinvent the wheel and where a better solution than we could write in a reasonable amount of time/effort exists).
The default Python package manager is [`pip`](https://pypi.org/project/pip/) (there are others: [`conda`](https://conda.io/projects/conda/en/latest/user-guide/getting-started.html)
is quite popular and handles some of the virtual environment features mentioned below -
there's also [`poetry`](https://python-poetry.org/), or I am personally partial to [`uv`](https://docs.astral.sh/uv/).
Each work a bit differently, so we'll just cover a barebones python workflow here).
Python projects often list their 'dependencies' in a `requirements.txt` with contents like:
```
jupyter
numpy
matplotlib
pandas
scipy
simpy
```
(some of these are dependencies that will come up in the course - relatively recent versions of each should all work identically well so this list does not specify version numbers [but if you need to lock specific version number down you can do so](https://pip.pypa.io/en/stable/reference/requirements-file-format/)). Given such a file you can install the dependencies for a project into the active environment (usually a venv - see below) via `pip`:
```bash
pip install -r requirements.txt
```
modules can also be installed explicitly by name:
```bash
pip install numpy scipy
```
(Depending on many OS particulars and settings, you may run into permission issues with these commands - let me know if you need help tracking down how to solve them for your particular setup.)
If `pip` is only present in your python installation but not exposed to your commandline you may need to use
```bash
python -m pip <remainder of the pip command goes here...>
```
### Virtual Environments
It can be important to manage dependencies carefully across projects and over time.
For example, suppose you write some code for this course which relies on some specific feature of the current version `numpy1.22` (you might use a particular niche function or rely on a name or shape for some arguments).
Two or three years from now the latest `numpy` version might change the name(s) or interface of the feature you used - and your code will stop working!
If you want to run your old code you'll need to use an older version of `numpy`, but that may be difficult if you have some newer project that wants to rely on the newer version of the library.
While you can ask `pip` to install any version of a library you want at any time (and store a list of required versions in a `requirements.txt`),
uninstalling and re-installing different versions of libraries all the time is messy and liable to break something (especially if you need to manage multiple libraries this way).
![workflow.png](https://imgs.xkcd.com/comics/workflow.png)
The somewhat standard solution to this kind of problem is a "virtual environment" - rather than rely on our global shell environment to keep track of all our projects somehow (hoping nothing winds up incompatible),
we'll manage an independent environment for each project.
Simple dependency management via a virtual environment can be done entirely with `python` and `pip` using the [`venv`](https://docs.python.org/3/library/venv.html) module - in your shell, in some directory relevant to your project(s) invoke:
```bash
# use the python venv module
# to make a new virtual environment stored in the env dir
python -m venv env
```
to create a new virtual environment. You can then activate the environment
(tell your shell it should use the contained version of python and associated libraries) anytime you want to use it by calling:
```bash
source env/bin/activate # run the activation script located in the env dir
```
Your shell will then use a self-contained version of `python` and any libraries you install with `pip` while in this mode.
I recommend using a `venv` of some kind while working on this course -
at the very least it will give you a place to experiment without mucking up your global python installation.
You can leave the virtual environment at any time by calling `exit`.
### All-together: an example
Suppose you want to run a local [`jupyter`](https://jupyter.org/) notebook for yourself - say, to play around a bit and get some ideas ready for an assignment that will require some [`numpy` functions](https://numpy.org/doc/2.1/reference/index.html#reference) and [`matplotlib`](https://matplotlib.org/stable/api/index.html) plotting - but don't yet have anything set up other than your global python installation.
Here's a basic workflow using the methods described above:
1) Set up a working directory along the lines of
```bash
# make a directory for the course and "change directory" (cd) into it
mkdir uoph410-510_image-analysis && cd uoph410-510_image-analysis
# create a virtual environment for the course and activate it
# in the currently open session with your shell (not persistent)
python -m venv env && source ./env/bin/activate
```
2) Install the prerequisite packages (in the venv):
```bash
pip install jupyter numpy matplotlib
```
It can be convenient to append these to a `requirements.txt` in case you want to send anyone else your code (you shouldn't send a `venv` directory - they're not portable between systems).
```bash
# create the .txt, ask pip for its requirements,
# and "pipe" (>>) the text output from pip into the end of the file
touch requirements.txt && pip freeze >> requirements.txt
```
4) Launch `jupyter notebook` & navigate creating a new `.ipynb` in the browser interface.
5) Voila! Notice that installing a new shell command for interacting with python (`jupyter`) could be managed in the same way as a package providing a library you can use in your code. Both are only enabled locally, and temporarily in the current session without polluting your global environment (you won't have any issues in the future anywhere else on your machine because of any software we just installed). If you have dependency issues, just shut down the notebook (`CTRL-C` in the running terminal) and repeat (2), adding any packages that are throwing various "not found" errors.
**Note:** `jupyter` is *not* required (nor even really emphasized) in this class - but it can still be a useful tool for quick sanity-checks and pretty-printed tests or document preparation.
Generally this course will prefer you to write your code in a more modular fashion than `jupyter`'s [stateful](https://en.wikipedia.org/wiki/State_(computer_science)) environment encourages, i.e. you should structure and think of your code overall as [module/library development](https://learn.scientific-python.org/development/) rather than each assignment a one-off notebook.
(Though an optional workflow can be to develop your own module, and import it into a notebook for use with particular values).
## Additional Considerations
The guide above covers just a very basic python environment and workflow.
For a more featureful development experience you may want to do your own research on (in addition to some of the things scattered above):
- Linters like [ruff](https://docs.astral.sh/ruff/) or [black](https://black.readthedocs.io/en/stable/), which help you ensure your code is written in a consistent style - to help with readability.
- Unit testing with [pytest](https://docs.pytest.org/en/8.0.x/) or [`unittest`](https://docs.python.org/3/library/unittest.html) (along with *many* plugins for each/either).
In particular, you might find [ipytest](https://jupyter-tutorial.readthedocs.io/en/stable/notebook/testing/ipytest.html) useful for checking that your code is behaving as you expect
while you develop your solutions.
- Type checkers like [mypy](https://www.mypy-lang.org/) or [pyright](https://microsoft.github.io/pyright/#/), while python does not have static typing
(the [interpreter](https://en.wikipedia.org/wiki/Interpreter_(computing)) does not know the [type](https://en.wikipedia.org/wiki/Data_type) of an object [before](https://en.wikipedia.org/wiki/Compile_time) [runtime](https://en.wikipedia.org/wiki/Execution_(computing)#Runtime)) - there is some loose tooling available to help you try to structure your code in a type-safe
(or at least [duck-typed](https://en.wikipedia.org/wiki/Duck_typing)) - and more likely to be correct - way. These tend to integrate well with testing frameworks mentioned in the last bullet.
- You may want to manage a version-controlled [git](https://git-scm.com/) repository for your work on the course. Git and [Github](https://github.com/) are ubiquitous in modern software development.
While we won't cover their use in this course, privately managing your work with these tools would be excellent practice.
Good luck, have fun, don't die!
(page [raw pandoc `.md`](setup.md), [github repo](https://github.com/tgorordo/pages.uoregon.edu))

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,99 @@
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "marimo>=0.19.7",
# ]
# ///
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import numpy as np
return (np,)
@app.cell
def _():
import matplotlib.pyplot as plt
return (plt,)
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework0.pdf"), width="100%", height="50vh")
return
@app.cell
def _(np):
def unit_gridcircle_mask(N):
ruler = np.arange(-(N + 1.5), (N + 2.5)) / N
xx, yy = np.meshgrid(ruler, ruler)
mask = np.sqrt(np.square(xx) + np.square(yy)) <= 1
return mask
return (unit_gridcircle_mask,)
@app.cell
def _(np, unit_gridcircle_mask):
def unit_gridcircle_area(N):
area = float(np.sum(unit_gridcircle_mask(N), dtype=float) / N**2)
return area
return (unit_gridcircle_area,)
@app.cell
def _(np, plt, unit_gridcircle_mask):
plt.matshow(unit_gridcircle_mask(5), cmap=plt.cm.gray_r)
plt.grid(visible=True, color="cyan")
plt.xticks(ticks=(np.arange(14) - 0.5))
plt.yticks(ticks=(np.arange(14) - 0.5))
f = plt.gca()
f.axes.xaxis.set_ticklabels([])
f.axes.yaxis.set_ticklabels([])
plt.show()
return
@app.cell
def _(np, plt, unit_gridcircle_area):
Npts = 100
Ns = np.unique(np.floor(np.logspace(np.log10(2), np.log10(2000), Npts)).astype(int))
As = list(map(unit_gridcircle_area, Ns))
plt.figure(figsize=(8,6))
plt.semilogx(Ns, As, 'o-', color='steelblue', markerfacecolor='lightblue', markersize=12)
xlim = plt.gca().get_xlim()
plt.semilogx((xlim[0], xlim[1]), (np.pi, np.pi), ':', linewidth=2.5, color='darkorange')
plt.xlabel('N', fontsize=14)
plt.ylabel('Area', fontsize=14)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,163 @@
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "marimo>=0.19.7",
# ]
# ///
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import numpy as np
return (np,)
@app.cell
def _():
import matplotlib.pyplot as plt
return (plt,)
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework1.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Puzzles
### a.
""")
return
@app.cell
def _(plt):
im_A_png = plt.imread("AuLait_gray.png")
im_A_tif = plt.imread("AuLait_gray.tif")
return im_A_png, im_A_tif
@app.cell
def _(im_A_png, plt):
plt.imshow(im_A_png, "gray")
return
@app.cell
def _(im_A_tif):
im_A_tif.shape
return
@app.cell
def _(im_A_png, np):
np.max(im_A_png)
return
@app.cell
def _(im_A_tif, plt):
plt.imshow(im_A_tif, "gray")
return
@app.cell
def _(im_A_tif):
im_A_tif.shape
return
@app.cell
def _(im_A_tif, np):
np.max(im_A_tif)
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## b.
""")
return
@app.cell
def _():
from skimage import io
return (io,)
@app.cell
def _(im_A_png, io):
io.imsave("AuLait_gray_png_skout_unscaled.tif", im_A_png)
return
@app.cell
def _(plt):
im_A_sk_tif_unscaled = plt.imread("AuLait_gray_png_skout_unscaled.tif")
return (im_A_sk_tif_unscaled,)
@app.cell
def _(im_A_sk_tif_unscaled):
im_A_sk_tif_unscaled.shape
return
@app.cell
def _(im_A_sk_tif_unscaled, plt):
plt.imshow(im_A_sk_tif_unscaled)
return
@app.cell
def _(im_A_png, io):
io.imsave("AuLait_gray_png_skout_scaledup.tif", im_A_png * 255)
return
@app.cell
def _(plt):
im_A_sk_tif_scaled = plt.imread("AuLait_gray_png_skout_scaledup.tif")
return (im_A_sk_tif_scaled,)
@app.cell
def _(im_A_sk_tif_scaled):
im_A_sk_tif_scaled.shape
return
@app.cell
def _(im_A_sk_tif_scaled, plt):
plt.imshow(im_A_sk_tif_scaled)
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1,357 @@
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import matplotlib, matplotlib.pyplot as plt
plt.ion()
return (plt,)
@app.cell
def _():
import numpy as np
return (np,)
@app.cell
def _():
from skimage import io
from skimage.filters import threshold_otsu, threshold_local
return io, threshold_local, threshold_otsu
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework2.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## 1. Thresholding
""")
return
@app.cell
def _(io):
robert_mapplethrope_calla_lily_1984_png = io.imread("robert-mapplethrope-calla-lily-1984.png", as_gray=True)
return (robert_mapplethrope_calla_lily_1984_png,)
@app.cell
def _(plt, robert_mapplethrope_calla_lily_1984_png):
fig1, ax1 = plt.subplots()
p1 = ax1.imshow(robert_mapplethrope_calla_lily_1984_png, cmap="gray")
fig1.colorbar(p1, ax=ax1)
fig1
return
@app.cell
def _(robert_mapplethrope_calla_lily_1984_png, threshold_otsu):
robert_mapplethrope_calla_lily_global_threshold = threshold_otsu(robert_mapplethrope_calla_lily_1984_png)
robert_mapplethrope_calla_lily_global_threshold # print
return (robert_mapplethrope_calla_lily_global_threshold,)
@app.cell
def _(
plt,
robert_mapplethrope_calla_lily_1984_png,
robert_mapplethrope_calla_lily_global_threshold,
):
fig2, (ax2a, ax2b) = plt.subplots(1, 2, figsize=(8, 4))
ax2a.hist(robert_mapplethrope_calla_lily_1984_png.flatten(), log=True, bins="auto")
ax2a.vlines(robert_mapplethrope_calla_lily_global_threshold, 0, 80_000, color="r")
p2b = ax2b.imshow(robert_mapplethrope_calla_lily_1984_png > robert_mapplethrope_calla_lily_global_threshold, cmap="gray")
fig2.colorbar(p2b, ax=ax2b)
fig2
return
@app.cell
def _(io, plt):
fig3, ax3 = plt.subplots()
istanbul_arch_museum_gray_crop_png = io.imread("istanbul_arch_museum_gray_crop.png", as_gray=True)
p3 = ax3.imshow(istanbul_arch_museum_gray_crop_png, cmap="gray")
fig3.colorbar(p3, ax=ax3)
fig3
return (istanbul_arch_museum_gray_crop_png,)
@app.cell
def _(istanbul_arch_museum_gray_crop_png, threshold_otsu):
istanbul_global_threshold = threshold_otsu(istanbul_arch_museum_gray_crop_png)
istanbul_global_threshold # print
return (istanbul_global_threshold,)
@app.cell
def _(istanbul_arch_museum_gray_crop_png, istanbul_global_threshold, plt):
fig4, (ax4a, ax4b) = plt.subplots(1, 2, figsize=(8, 4))
ax4a.hist(istanbul_arch_museum_gray_crop_png.flatten(), log=True, bins="auto")
ax4a.vlines(istanbul_global_threshold, 0, 300_000, color='r')
p4b = ax4b.imshow(istanbul_arch_museum_gray_crop_png > istanbul_global_threshold, cmap="gray")
fig4.colorbar(p4b, ax=ax4b)
fig4
return
@app.cell
def _(io):
robert_mapplethrope_calla_lily_1984_crop_png = io.imread("robert-mapplethrope-calla-lily-1984_CROP.png", as_gray=True)
return (robert_mapplethrope_calla_lily_1984_crop_png,)
@app.cell
def _(plt, robert_mapplethrope_calla_lily_1984_crop_png):
fig5, ax5 = plt.subplots()
p5 = ax5.imshow(robert_mapplethrope_calla_lily_1984_crop_png, cmap="gray")
fig5.colorbar(p5, ax=ax5)
fig5
return
@app.cell
def _(robert_mapplethrope_calla_lily_1984_crop_png, threshold_otsu):
robert_mapplethrope_calla_lily_crop_global_threshold = threshold_otsu(robert_mapplethrope_calla_lily_1984_crop_png)
robert_mapplethrope_calla_lily_crop_global_threshold # print
return (robert_mapplethrope_calla_lily_crop_global_threshold,)
@app.cell
def _(
plt,
robert_mapplethrope_calla_lily_1984_crop_png,
robert_mapplethrope_calla_lily_crop_global_threshold,
):
fig6, (ax6a, ax6b) = plt.subplots(1, 2, figsize=(8, 4))
ax6a.hist(robert_mapplethrope_calla_lily_1984_crop_png.flatten(), log=True, bins="auto")
ax6a.vlines(robert_mapplethrope_calla_lily_crop_global_threshold, 0, 80_000, color="r")
p6b = ax6b.imshow(robert_mapplethrope_calla_lily_1984_crop_png > robert_mapplethrope_calla_lily_crop_global_threshold, cmap="gray")
fig6.colorbar(p6b, ax=ax6b)
fig6
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## 2. Thresholding, again
""")
return
@app.cell
def _(
istanbul_arch_museum_gray_crop_png,
plt,
robert_mapplethrope_calla_lily_1984_crop_png,
robert_mapplethrope_calla_lily_1984_png,
threshold_local,
):
fig7, (ax7a, ax7b, ax7c) = plt.subplots(1, 3, figsize=(12, 4))
p7a = ax7a.imshow(robert_mapplethrope_calla_lily_1984_png > threshold_local(robert_mapplethrope_calla_lily_1984_png, block_size=123), cmap="gray")
fig7.colorbar(p7a, ax=ax7a)
p7b = ax7b.imshow(istanbul_arch_museum_gray_crop_png > threshold_local(istanbul_arch_museum_gray_crop_png, block_size=123), cmap="gray")
fig7.colorbar(p7b, ax=ax7b)
p7c = ax7c.imshow(robert_mapplethrope_calla_lily_1984_crop_png > threshold_local(robert_mapplethrope_calla_lily_1984_crop_png, block_size=123), cmap="gray")
fig7.colorbar(p7c, ax=ax7c)
fig7
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## 3. Protein density
""")
return
@app.cell
def _(io, plt):
fig8, ax8 = plt.subplots()
microarray_crop_png = io.imread("microarray_crop.png", as_gray=True)
p8 = ax8.imshow(microarray_crop_png, cmap="gray")
fig8.colorbar(p8, ax=ax8)
fig8
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## 4. Non-uniform background subtraction
""")
return
@app.cell
def _(io, plt):
fig9, ax9 = plt.subplots()
GUV24_bead_crop_png = io.imread("GUV24_bead_Crop.png", as_gray=True)
p9 = ax9.imshow(GUV24_bead_crop_png, cmap="gray")
fig9.colorbar(p9, ax=ax9)
fig9
return (GUV24_bead_crop_png,)
@app.cell
def _(GUV24_bead_crop_png, np):
x = np.arange(GUV24_bead_crop_png.shape[0])
y = np.arange(GUV24_bead_crop_png.shape[1])
xs, ys = np.meshgrid(x, y)
return x, xs, ys
@app.cell
def _(GUV24_bead_crop_png, plt, xs, ys):
fig10, ax10 = plt.subplots()
ax10 = plt.axes(projection ='3d')
p10 = ax10.plot_surface(xs, ys, GUV24_bead_crop_png, cmap="viridis")
fig10
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
### b.
""")
return
@app.cell
def _(GUV24_bead_crop_png, np, xs):
w = np.vstack([xs.ravel(), np.ones(xs.size)]).T
mx, c = np.linalg.lstsq(w, GUV24_bead_crop_png.ravel())[0] # (c-410) 3pt alternative
(mx, c)
return c, mx
@app.cell
def _(GUV24_bead_crop_png, c, mx, plt, x, xs, ys):
fig11, (ax11a, ax11b) = plt.subplots(1, 2, figsize=(8, 4))
ax11a.plot(x, mx * x + c, c='r')
ax11a.scatter(xs.ravel(), GUV24_bead_crop_png.ravel(), s=4)
ax11b.scatter(ys.ravel(), GUV24_bead_crop_png.ravel(), s=4)
fig11
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
### c.
#### 410:
""")
return
@app.cell
def _(GUV24_bead_crop_png, np, xs, ys):
# z = m @ w + c
w2 = np.vstack([xs.ravel(), ys.ravel(), np.ones(GUV24_bead_crop_png.size)]).T
mx2, my2, c2 = np.linalg.lstsq(w2, GUV24_bead_crop_png.ravel())[0]
(mx2, my2, c2)
return c2, mx2, my2
@app.cell
def _(GUV24_bead_crop_png, c2, mx2, my2, plt, xs, ys):
fig12, ax12 = plt.subplots()
ax12 = plt.axes(projection ='3d')
ax12.plot_surface(xs, ys, GUV24_bead_crop_png, cmap="viridis", alpha=0.3)
ax12.plot_surface(xs, ys, mx2 * xs + my2 * ys + c2, cmap="plasma")
fig12
return
@app.cell
def _(GUV24_bead_crop_png, c2, mx2, my2, plt, xs, ys):
fig13, ax13 = plt.subplots()
ax13 = plt.axes(projection ='3d')
ax13.plot_surface(xs, ys, GUV24_bead_crop_png - (mx2 * xs + my2 * ys + c2), cmap="viridis")
fig13
return
@app.cell
def _(GUV24_bead_crop_png, c2, mx2, my2, plt, xs, ys):
fig14, ax14 = plt.subplots()
p14 = ax14.imshow(GUV24_bead_crop_png - (mx2 * xs + my2 * ys + c2), cmap="gray")
fig14.colorbar(p14, ax=ax14)
fig14
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
#### 510:
""")
return
@app.cell
def _(GUV24_bead_crop_png, np, xs, ys):
# z = m @ w + c
w3 = np.vstack([xs.ravel(), np.square(xs.ravel()),
ys.ravel(), np.square(ys.ravel()),
np.ones(GUV24_bead_crop_png.size)]).T
mx3, mx3x, my3, my3y, c3 = np.linalg.lstsq(w3, GUV24_bead_crop_png.ravel())[0]
(mx3, mx3x, my3, my3y, c3)
return c3, mx3, mx3x, my3, my3y
@app.cell
def _(GUV24_bead_crop_png, c3, mx3, mx3x, my3, my3y, np, plt, xs, ys):
fig15, ax15 = plt.subplots()
ax15 = plt.axes(projection ='3d')
ax15.plot_surface(xs, ys, GUV24_bead_crop_png, cmap="viridis", alpha=0.3)
ax15.plot_surface(xs, ys, mx3 * xs + mx3x * np.square(xs) + my3 * ys + my3y * np.square(ys) + c3, cmap="plasma")
return
@app.cell
def _(GUV24_bead_crop_png, c3, mx3, mx3x, my3, my3y, np, plt, xs, ys):
fig16, ax16 = plt.subplots()
p16 = ax16.imshow(GUV24_bead_crop_png - (mx3 * xs + mx3x * np.square(xs) + my3 * ys + my3y * np.square(ys) + c3), cmap="gray")
fig16.colorbar(p16, ax=ax16)
fig16
return
@app.cell
def _(GUV24_bead_crop_png, c3, mx3, mx3x, my3, my3y, np, plt, xs, ys):
fig17, ax17 = plt.subplots()
ax17 = plt.axes(projection ='3d')
ax17.plot_surface(xs, ys, GUV24_bead_crop_png -
(mx3 * xs + mx3x * np.square(xs) + my3 * ys + my3y * np.square(ys) + c3), cmap="viridis")
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

View file

@ -0,0 +1,554 @@
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import matplotlib, matplotlib.pyplot as plt
plt.ion();
return (plt,)
@app.cell
def _():
import numpy as np
return (np,)
@app.cell
def _():
from skimage import io
from skimage.filters import gaussian, median, threshold_otsu
return gaussian, io, median, threshold_otsu
@app.cell
def _():
import scipy.ndimage as ndi
return (ndi,)
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework3.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Convolution and Filtering
""")
return
@app.cell
def _(io):
escher_relativity_png = io.imread("escher-relativity.png", as_gray=True)
return (escher_relativity_png,)
@app.cell
def _(escher_relativity_png, plt):
fig1, ax1 = plt.subplots()
p1 = ax1.imshow(escher_relativity_png, cmap="gray")
cbar1 = fig1.colorbar(p1, ax=ax1)
fig1
return
@app.cell
def _(np):
avgker11 = np.ones((11, 11)) / np.square(11)
return (avgker11,)
@app.cell
def _(avgker11, escher_relativity_png, ndi):
escher_relativity_png_avgd_const = ndi.convolve(escher_relativity_png, avgker11, mode="constant")
escher_relativity_png_avgd_miror = ndi.convolve(escher_relativity_png, avgker11, mode="mirror")
return escher_relativity_png_avgd_const, escher_relativity_png_avgd_miror
@app.cell
def _(escher_relativity_png_avgd_const, escher_relativity_png_avgd_miror, plt):
fig2, (ax2a, ax2b) = plt.subplots(1, 2, figsize=(8, 4))
p2a = ax2a.imshow(escher_relativity_png_avgd_const, cmap="gray")
p2b = ax2b.imshow(escher_relativity_png_avgd_miror, cmap="gray")
fig2.colorbar(p2a, ax=ax2a)
fig2.colorbar(p2b, ax=ax2b)
fig2
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Gaussian Filtering
""")
return
@app.cell
def _(np):
def gaussker(sgm2, shape=(11, 11)):
xs, ys = np.meshgrid(np.arange(shape[0]), np.arange(shape[1]))
r2s = np.square(xs - shape[0] // 2) + np.square(ys - shape[0] // 2)
e = np.exp(- r2s / (2 * sgm2))
return e / np.sum(e) # return normalized kernel
return (gaussker,)
@app.cell
def _(gaussker, plt):
fig3, (ax3a, ax3b) = plt.subplots(1, 2, figsize=(8, 4))
p3a = ax3a.imshow(gaussker(3))
p3b = ax3b.imshow(gaussker(7))
fig3.colorbar(p3a, ax=ax3a)
fig3.colorbar(p3b, ax=ax3b)
fig3
return
@app.cell
def _(escher_relativity_png, gaussker, ndi):
escher_relativity_png_gaussd3 = ndi.convolve(escher_relativity_png, gaussker(3))
escher_relativity_png_gaussd7 = ndi.convolve(escher_relativity_png, gaussker(7))
return escher_relativity_png_gaussd3, escher_relativity_png_gaussd7
@app.cell
def _(escher_relativity_png_gaussd3, escher_relativity_png_gaussd7, plt):
fig4, (ax4a, ax4b) = plt.subplots(1, 2, figsize=(8, 4))
p4a = ax4a.imshow(escher_relativity_png_gaussd3, cmap="gray")
p4b = ax4b.imshow(escher_relativity_png_gaussd7, cmap="gray")
fig4.colorbar(p4a, ax=ax4a)
fig4.colorbar(p4b, ax=ax4b)
fig4
return
@app.cell
def _(escher_relativity_png, gaussian, np):
escher_relativity_png_gaussdsk7 = gaussian(escher_relativity_png, np.sqrt(7))
return (escher_relativity_png_gaussdsk7,)
@app.cell
def _(escher_relativity_png_gaussdsk7, plt):
fig5, ax5 = plt.subplots()
p5 = ax5.imshow(escher_relativity_png_gaussdsk7, cmap="gray")
fig5.colorbar(p5, ax=ax5)
fig5
return
@app.cell
def _(escher_relativity_png_gaussd7, escher_relativity_png_gaussdsk7, np):
escher_relativity_png_skdiff = escher_relativity_png_gaussdsk7 - escher_relativity_png_gaussd7
escher_relativity_png_skdiff = escher_relativity_png_skdiff - np.min(escher_relativity_png_skdiff)
return (escher_relativity_png_skdiff,)
@app.cell
def _(escher_relativity_png_skdiff, plt):
fig6, ax6 = plt.subplots()
p6 = ax6.imshow(escher_relativity_png_skdiff, cmap="gray")
fig6.colorbar(p6, ax=ax6)
fig6
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Median Filtering
""")
return
@app.cell
def _(escher_relativity_png, median, np):
escher_relativity_png_median7 = median(escher_relativity_png, np.ones((7, 7)))
return (escher_relativity_png_median7,)
@app.cell
def _(escher_relativity_png_median7, plt):
fig7, ax7 = plt.subplots()
p7 = ax7.imshow(escher_relativity_png_median7, cmap="gray")
fig7.colorbar(p7, ax=ax7)
fig7
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Filtering and Thresholding
""")
return
@app.cell
def _(io):
makeup_richardprince_1983_gray_png = io.imread("MakeUp_RichardPrince_1983_gray.png", as_gray=True)
return (makeup_richardprince_1983_gray_png,)
@app.cell
def _(makeup_richardprince_1983_gray_png, plt):
fig8, ax8 = plt.subplots()
p8 = ax8.imshow(makeup_richardprince_1983_gray_png, cmap="gray")
fig8.colorbar(p8, ax=ax8)
fig8
return
@app.cell
def _(gaussian, makeup_richardprince_1983_gray_png, np, threshold_otsu):
makeup_richardprince_1983_gray_png_gaussian = 255 * gaussian(makeup_richardprince_1983_gray_png, np.sqrt(51))
makeup_richardprince_1983_gray_png_gaussian_gthreshold = threshold_otsu(makeup_richardprince_1983_gray_png_gaussian)
makeup_richardprince_1983_gray_png_gaussian_threshd = makeup_richardprince_1983_gray_png_gaussian > makeup_richardprince_1983_gray_png_gaussian_gthreshold
return (makeup_richardprince_1983_gray_png_gaussian_threshd,)
@app.cell
def _(makeup_richardprince_1983_gray_png, median, np, threshold_otsu):
makeup_richardprince_1983_gray_png_median = median(makeup_richardprince_1983_gray_png, np.ones((51, 51)))
makeup_richardprince_1983_gray_png_median_gthreshold = threshold_otsu(makeup_richardprince_1983_gray_png_median)
makeup_richardprince_1983_gray_png_median_threshd = makeup_richardprince_1983_gray_png_median > makeup_richardprince_1983_gray_png_median_gthreshold
return (makeup_richardprince_1983_gray_png_median_threshd,)
@app.cell
def _(
makeup_richardprince_1983_gray_png_gaussian_threshd,
makeup_richardprince_1983_gray_png_median_threshd,
plt,
):
fig9, (ax9a, ax9b) = plt.subplots(1, 2, figsize=(8, 4))
p9a = ax9a.imshow(makeup_richardprince_1983_gray_png_gaussian_threshd, cmap="gray")
fig9.colorbar(p9a, ax=ax9a)
p9b = ax9b.imshow(makeup_richardprince_1983_gray_png_median_threshd, cmap="gray")
fig9.colorbar(p9b, ax=ax9b)
fig9
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## High-pass Filtering
""")
return
@app.cell
def _(io):
elevator_to_the_gallows_png = io.imread("Elevator_to_the_gallows.png", as_gray=True)
return (elevator_to_the_gallows_png,)
@app.cell
def _(elevator_to_the_gallows_png, plt):
fig10, ax10 = plt.subplots()
ax10.imshow(elevator_to_the_gallows_png, cmap="gray")
fig10
return
@app.cell
def _(gaussian, np):
def gausshighpass(image, sigma=np.sqrt(7)):
gaussd = (np.max(image) - np.min(image)) * gaussian(image, sigma)
diff = image - gaussd
diff = diff - np.min(diff)
return (255 / np.max(diff)) * diff
return (gausshighpass,)
@app.cell
def _(elevator_to_the_gallows_png, gausshighpass):
elevator_to_the_gallows_png_highpass = gausshighpass(elevator_to_the_gallows_png, sigma=21)
return (elevator_to_the_gallows_png_highpass,)
@app.cell
def _(elevator_to_the_gallows_png_highpass, plt):
fig11, ax11 = plt.subplots()
ax11.imshow(elevator_to_the_gallows_png_highpass, cmap="gray")
fig11
return
@app.cell
def _(elevator_to_the_gallows_png_highpass, threshold_otsu):
elevator_to_the_gallows_png_highpass_threshold = threshold_otsu(elevator_to_the_gallows_png_highpass)
elevator_to_the_gallows_png_highthresh = elevator_to_the_gallows_png_highpass > elevator_to_the_gallows_png_highpass_threshold
return (elevator_to_the_gallows_png_highthresh,)
@app.cell
def _(elevator_to_the_gallows_png_highthresh, plt):
fig12, ax12 = plt.subplots()
ax12.imshow(elevator_to_the_gallows_png_highthresh, cmap="gray")
fig12
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Band-pass Filtering
""")
return
@app.cell
def _(io):
gaussians_s2_to_s50_px_tif = io.imread("gaussians_s2_to_s50_px.tif", as_gray=True)
return (gaussians_s2_to_s50_px_tif,)
@app.cell
def _(gaussians_s2_to_s50_px_tif, plt):
fig13, (ax13a, ax13b) = plt.subplots(1, 2, figsize=(8, 4))
ax13a.imshow(gaussians_s2_to_s50_px_tif, cmap="gray")
ax13a.hlines(1240, 0, 3200, color="magenta")
ax13b.plot(gaussians_s2_to_s50_px_tif[1240, :])
fig13
return
@app.cell
def _(gaussian, np):
def gausslowpass(image, sigma=np.sqrt(7)):
gaussd = (np.max(image) - np.min(image)) * gaussian(image, sigma)
return (255 / np.max(gaussd)) * gaussd
return (gausslowpass,)
@app.cell
def _(gausshighpass, gaussians_s2_to_s50_px_tif, gausslowpass):
gaussians_s2_to_s50_px_tif_bandpassed = gausslowpass(gausshighpass(
gaussians_s2_to_s50_px_tif,
sigma=20), sigma=10)
return (gaussians_s2_to_s50_px_tif_bandpassed,)
@app.cell
def _(gaussians_s2_to_s50_px_tif_bandpassed, plt):
fig14, (ax14a, ax14b) = plt.subplots(1, 2, figsize=(8, 4))
ax14a.imshow(gaussians_s2_to_s50_px_tif_bandpassed, cmap="gray")
ax14a.hlines(1240, 0, 3200, color="magenta")
ax14b.plot(gaussians_s2_to_s50_px_tif_bandpassed[1240, :])
fig14
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Signal to Noise Ratio
""")
return
@app.cell
def _(np):
rng = np.random.default_rng()
def sim_image(r, b=2, t=2, size=(27, 27)):
bg = rng.poisson(lam=b * t, size=size)
sg = np.zeros_like(bg)
sg[sg.shape[0] // 2, sg.shape[1] // 2] = rng.poisson(lam=r*t)
return bg + sg
return (sim_image,)
@app.cell
def _(plt, sim_image):
fig15, (ax15a, ax15b, ax15c) = plt.subplots(1, 3, figsize=(10, 4))
ax15a.imshow(sim_image(2, t=1), cmap="gray")
ax15b.imshow(sim_image(6, t=1), cmap="gray")
ax15c.imshow(sim_image(10, t=1), cmap="gray")
return
@app.cell
def _(np, sim_image):
exposure_sims = [ sim_image(0.5, t=t) for t in range(0, 300) ]
sns = [s[27//2, 27//2] / np.std(s) for s in exposure_sims]
return (sns,)
@app.cell
def _(plt, sns):
fig16, ax16 = plt.subplots()
ax16.scatter(range(0, 300), sns)
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## A little bit of Fourier Transforming
""")
return
@app.cell
def _(io):
Lincoln_Coleman_png = io.imread("Lincoln_Coleman_40-copyright-havecamerawilltravel-com_crop512_gray.png", as_gray=True)
return (Lincoln_Coleman_png,)
@app.cell
def _(Lincoln_Coleman_png, plt):
fig17, ax17 = plt.subplots()
ax17.imshow(Lincoln_Coleman_png, cmap="grey")
return
@app.cell
def _():
# %load fourier_masking_HWproblem.py
return
@app.cell
def _(io, np, plt):
# %load fourier_masking_HWproblem.py
# fourier_masking_HWproblem.py
"""
Author: Raghuveer Parthasarathy
Created on Tue Oct 8 07:25:53 2024
Last modified on Oct. 12, 2024
Description
-----------
For a homework problem on masking Fourier Transforms
"""
#import numpy as np
#import matplotlib.pyplot as plt
import os
#from skimage import io # input output sub-package
# %% Load the image
parentDir = r"./"
fileName = r"Lincoln_Coleman_40-copyright-havecamerawilltravel-com_crop512_gray.png"
im = io.imread(os.path.join(parentDir, fileName))
if im.ndim > 2:
# A bit silly, since I know this is 2D
im = np.mean(im, axis=2, dtype=im.dtype)
print("Image shape: ", im.shape)
# Image size; I'm not checking if it's square!
# The Lincoln Memorial image is 512x512
N = im.shape[0]
plt.figure()
plt.imshow(im, "gray")
plt.title("Original Image")
# %% Fourier Transform
# Perform 2D Fourier transform
F = np.fft.fft2(im) # Fast Fourier Transform
F_shifted = np.fft.fftshift(F) # Shift so zero frequency is in the center
# Calculate the amplitude and phase
amplitude = np.abs(F_shifted)
phase = np.angle(F_shifted)
# Display amplitude as an image
plt.figure()
plt.title("Fourier Transform Amplitude (log scale)")
# Should maybe add an offset to avoid -Inf,
# but I've tested and there are no zeros.
plt.imshow(np.log(amplitude), cmap="gray")
plt.colorbar()
plt.show()
# Display phase as an image
plt.figure()
plt.title("Fourier Transform Phase (radians)")
plt.imshow(phase)
plt.colorbar()
plt.show()
# %% Masking
# "Fundamental frequency" for the mask
f0 = 15 # I determined this "by hand"
# Full width of the mask -- should be an even number
df = 4
# Create a mask array
mask = np.ones((N, N))
for k in range(1, N // (2 * f0)):
center_f = N / 2 + k * f0
mask[:, int(center_f - df / 2) : int(center_f + df / 2)] = 0
center_f = N / 2 - k * f0
mask[:, int(center_f - df / 2) : int(center_f + df / 2)] = 0
# Create a new amplitude array that is the original multiplied by this mask
new_amplitude = amplitude * mask
# new_amplitude = amplitude * (1.0 - mask) # show just the *difference*!
# Display the new amplitude as an image
plt.figure()
plt.title("Amplitude * Mask")
plt.imshow(np.log(new_amplitude + 0.1), cmap="gray") # + 0.1 because of zeros.
plt.colorbar()
plt.show()
# Combine new amplitude with original phase
new_F_shifted = new_amplitude * np.exp(1j * phase)
# Perform the inverse Fourier transform
new_F = np.fft.ifftshift(new_F_shifted)
new_im = np.fft.ifft2(new_F)
new_im = np.abs(new_im)
# Display the resulting image
plt.figure()
plt.title("Image based on Inverse FT")
plt.imshow(new_im, cmap="gray")
plt.colorbar()
plt.show()
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
# frequency_modulation_hw.py
"""
Author: Raghuveer Parthasarathy
Created on Oct. 17, 2024
Last modified on Oct. 18, 2024
Description
-----------
For a homework problem on frequency modulation
"""
import numpy as np
import matplotlib.pyplot as plt
import os
from skimage import io # input output sub-package
#%% Load the image
parentDir = r'C:\Users\Raghu\Documents\Teaching\Image Analysis Course\Images for Class'
fileName = r'Buster_Keaton_General_Train_512.png'
im = io.imread(os.path.join(parentDir, fileName))
print('Image shape: ', im.shape)
N = im.shape[0]
plt.figure()
plt.imshow(im, 'gray')
plt.title('Original Image')
#%% Multiply by sine waves
xc = np.linspace(-N/2, N/2, N)
x, y = np.meshgrid(xc, xc)
Px = 8
Py = 15
sineWave = np.sin(2.0*np.pi*x/Px) # + np.sin(2.0*np.pi*y/Py)
im_mod = im*sineWave
# Rescale to [0, 255]
im_mod = 255.0*(im_mod - np.min(im_mod)) / (np.max(im_mod) - np.min(im_mod))
im_mod = np.clip(im_mod, 0, 255).astype('uint8')
plt.figure()
plt.imshow(im_mod, 'gray')
plt.title('Modified Image')
# Output
outputFileName = r'Buster_Keaton_General_Train_512_sineMod.png'
io.imsave(os.path.join(parentDir, outputFileName), im_mod)
#%% Fourier Transforms
# Perform 2D Fourier transform of the original
F = np.fft.fft2(im) # Fast Fourier Transform
F_shifted = np.fft.fftshift(F) # Shift so zero frequency is in the center
# Calculate the amplitude and phase
amplitude = np.abs(F_shifted)
phase = np.angle(F_shifted)
# Display amplitude as an image
plt.figure()
plt.title("Fourier Transform Amplitude (log scale)")
plt.imshow(np.log(amplitude), cmap='gray')
plt.colorbar()
plt.show()
# Perform 2D Fourier transform of the modified image
F_mod = np.fft.fft2(im_mod) # Fast Fourier Transform
F_shifted_mod = np.fft.fftshift(F_mod) # Shift so zero frequency is in the center
# Calculate the amplitude and phase
amplitude_mod = np.abs(F_shifted_mod)
phase_mod = np.angle(F_shifted_mod)
# Display amplitude as an image
plt.figure()
plt.title("Fourier Transform Amplitude (log scale): modified image")
plt.imshow(np.log(amplitude_mod), cmap='gray')
plt.colorbar()
plt.show()

View file

@ -0,0 +1,401 @@
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import numpy as np
return (np,)
@app.cell
def _():
from skimage import io, filters
return filters, io
@app.cell
def _():
import scipy as si
import scipy.ndimage as nd
return nd, si
@app.cell
def _():
import matplotlib
import matplotlib.pyplot as plt
plt.ion();
return (plt,)
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework4.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Frequency Modulation
""")
return
@app.cell
def _(io):
buster_keaton_general_train_512_png = io.imread("Buster_Keaton_General_Train_512.png", as_gray=True)
buster_keaton_general_train_512_sinmod_png = io.imread("Buster_Keaton_General_Train_512_sineMod.png", as_gray=True)
return (
buster_keaton_general_train_512_png,
buster_keaton_general_train_512_sinmod_png,
)
@app.cell
def _(
buster_keaton_general_train_512_png,
buster_keaton_general_train_512_sinmod_png,
plt,
):
fig1, (ax1a, ax1b) = plt.subplots(1, 2, figsize=(8, 4))
ax1a.imshow(buster_keaton_general_train_512_png, cmap="gray")
ax1b.imshow(buster_keaton_general_train_512_sinmod_png, cmap="gray")
return
@app.cell
def _(
buster_keaton_general_train_512_png,
buster_keaton_general_train_512_sinmod_png,
np,
):
buster_keaton_general_train_512_fft = np.abs(np.fft.fftshift(np.fft.fft2(buster_keaton_general_train_512_png)))
buster_keaton_general_train_512_sinmod_fft = np.abs(np.fft.fftshift(np.fft.fft2(buster_keaton_general_train_512_sinmod_png)))
return (
buster_keaton_general_train_512_fft,
buster_keaton_general_train_512_sinmod_fft,
)
@app.cell
def _(
buster_keaton_general_train_512_fft,
buster_keaton_general_train_512_sinmod_fft,
np,
plt,
):
fig2, (ax2a, ax2b) = plt.subplots(1, 2, figsize=(8, 4))
ax2a.imshow(np.log(buster_keaton_general_train_512_fft), cmap="gray")
ax2b.imshow(np.log(buster_keaton_general_train_512_sinmod_fft), cmap="gray")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Quantized Aggregates
""")
return
@app.cell
def _(io):
emitters_33px_100ph_png = io.imread("emitters_33px_100ph.png")
return (emitters_33px_100ph_png,)
@app.cell
def _(emitters_33px_100ph_png, plt):
fig3, ax3 = plt.subplots()
ax3.imshow(emitters_33px_100ph_png, cmap="gray")
return
@app.cell
def _(emitters_33px_100ph_png, plt):
fig4, ax4 = plt.subplots()
ax4.hist(emitters_33px_100ph_png.ravel(), bins="auto")
fig4
return
@app.cell
def _(emitters_33px_100ph_png, filters):
emitters_33px_100ph_hflt = emitters_33px_100ph_png - 255 * filters.gaussian(emitters_33px_100ph_png, 8, mode="nearest")
return (emitters_33px_100ph_hflt,)
@app.cell
def _(emitters_33px_100ph_hflt, plt):
fig6, (ax6a, ax6b) = plt.subplots(1, 2, figsize=(8, 4))
ax6a.imshow(emitters_33px_100ph_hflt, cmap="gray")
ax6b.hist(emitters_33px_100ph_hflt.ravel(), bins=20)
fig6
return
@app.cell
def _(emitters_33px_100ph_hflt, np):
ones = np.ones_like(emitters_33px_100ph_hflt, dtype=bool)
zeros = np.zeros_like(ones, dtype=bool)
x, y = np.arange(ones.shape[0]), np.arange(ones.shape[1])
xs, ys = np.meshgrid(x, y)
masks = [np.where((np.abs(xs - 33 * i) <= 2) & (np.abs(ys - 33 * j) <= 2), ones, zeros)
for i in range(1, 11) for j in range(1, 11)]
# mask = np.where((xs % (33 + 4) > (33 - 4)) & (ys % (33 + 4) > (33 - 4)), ones, zeros)
mask = sum(masks)
return mask, masks
@app.cell
def _(emitters_33px_100ph_hflt, masks, np):
intensities = [np.sum(emitters_33px_100ph_hflt, where=m) for m in masks]
return (intensities,)
@app.cell
def _(intensities, mask, plt):
fig7, (ax7a, ax7b) = plt.subplots(1, 2, figsize=(8, 4))
ax7a.imshow(mask, cmap="gray")
counts, edges, _ = ax7b.hist(intensities, bins=25)
fig7
return counts, edges
@app.cell
def _(counts, edges, np):
irange = (np.max(edges) - np.min(edges))
imin = np.min(edges)
(sum(counts[edges[1:] <= (irange/3) + imin]),
sum(counts[((irange/3) + imin < edges[1:]) & (edges[1:] <= (2*irange/3) + imin)]),
sum(counts[((2*irange/3) + imin < edges[1:])])
)
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## A High-Resolution PSF
""")
return
@app.cell
def _(np, si):
def psfker(l, NA=0.9, side=1.0, N=101, center=(0.0, 0.0)):
xs, ys = np.meshgrid(np.linspace(0.0, side, N), np.linspace(0.0, side, N))
r2s = np.square(xs - side / 2 - center[0]) + np.square(ys - side / 2 - center[1])
v = 2 * np.pi * NA * np.sqrt(r2s) / l
psf = 4 * np.square(si.special.j1(v) / v)
nans = np.isnan(psf)
psf[nans] = 1
return psf / np.sum(psf)
return (psfker,)
@app.cell
def _(plt, psfker):
fig8, (ax8a, ax8b, ax8c) = plt.subplots(1, 3, figsize=(8, 2))
ax8a.imshow(psfker(0.5), cmap="gray")
ax8b.imshow(psfker(0.4), cmap="gray")
ax8c.imshow(psfker(0.4, NA=0.5), cmap="gray")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## A Worse Worm Image
""")
return
@app.cell
def _(io):
fetter_celegans_cellfig10_png = io.imread("fetter_Celegans_cellfig10.jpg", as_gray=True)
return (fetter_celegans_cellfig10_png,)
@app.cell
def _(fetter_celegans_cellfig10_png, plt):
fig9, ax9 = plt.subplots()
ax9.imshow(fetter_celegans_cellfig10_png, cmap="gray")
return
@app.cell
def _(fetter_celegans_cellfig10_png, nd, psfker):
fetter_celegans_cellfig10_psf = nd.convolve(fetter_celegans_cellfig10_png, psfker(0.53, NA=0.7))
return (fetter_celegans_cellfig10_psf,)
@app.cell
def _(fetter_celegans_cellfig10_psf, plt):
fig10, ax10 = plt.subplots()
ax10.imshow(fetter_celegans_cellfig10_psf, cmap="gray")
return
@app.cell
def _(mo):
mo.md(r"""
## SNR and Poisson Noise
$$ N_\text{photon} \sim SNR^2 $$
""")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Simulated Point Sources
""")
return
@app.cell
def _(np):
def pixelate(image, inscale, shape=(15, 15)):
outscale = image.shape[0] * inscale / shape[0]
assert outscale == image.shape[1] * inscale / shape[1]
assert outscale.is_integer()
ii, jj = np.indices(image.shape)
ones = np.ones_like(image, dtype=bool)
zeros = np.zeros_like(image, dtype=bool)
masks = [np.where((i * outscale <= ii * inscale) &
(ii * inscale < (i + 1) * outscale)
& (j * outscale <= jj * inscale) &
(jj * inscale < (j + 1) * outscale),
ones, zeros)
for i in range(shape[0]) for j in range(shape[1])]
outage = np.array([np.sum(image, where=m) for m in masks]).reshape(shape)
return outage, outscale
return (pixelate,)
@app.cell
def _(pixelate, psfker):
simpoint, _ = pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150), 0.1)
return (simpoint,)
@app.cell
def _(plt, simpoint):
fig11, ax11 = plt.subplots()
ax11.imshow(simpoint, cmap="gray")
return
@app.cell
def _(np):
def fishify(image, N=1, rng=np.random.default_rng()):
return rng.poisson(lam=N * (image / np.sum(image)))
return (fishify,)
@app.cell
def _(fishify, pixelate, psfker):
simpoint50 = fishify(pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150), 0.1)[0], N=50)
simpoint500 = fishify(pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150), 0.1)[0], N=500)
return simpoint50, simpoint500
@app.cell
def _(plt, simpoint50, simpoint500):
fig12, (ax12a, ax12b) = plt.subplots(1, 2, figsize=(8, 4))
ax12a.imshow(simpoint50, cmap="gray")
ax12b.imshow(simpoint500, cmap="gray")
return
@app.cell
def _(fishify, pixelate, psfker):
simpoint50_shifted = fishify(pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150, center=(0.3, 0.3)), 0.1)[0], N=50)
simpoint500_shifted = fishify(pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150, center=(0.3, 0.3)), 0.1)[0], N=500)
return simpoint500_shifted, simpoint50_shifted
@app.cell
def _(plt, simpoint500_shifted, simpoint50_shifted):
fig13, (ax13a, ax13b) = plt.subplots(1, 2, figsize=(8, 4))
ax13a.imshow(simpoint50_shifted, cmap="gray")
ax13b.imshow(simpoint500_shifted, cmap="gray")
return
@app.cell
def _(fishify, np, pixelate, psfker):
uniform = np.ones((15, 15)) / np.sum(np.ones((15, 15)))
simpoint_i = fishify(pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150), 0.1)[0], N=50) + fishify(np.ones((15, 15)), N=2 * 15**2)
simpoint_ii = fishify(pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150, center=(0.03, 0.03)), 0.1)[0], N=50) + fishify(np.ones((15, 15)), N=2 * 15**2)
simpoint_iii = fishify(pixelate(psfker(0.5, NA=0.9, side=15 * 0.1, N = 150, center=(0.03, 0.03)), 0.1)[0], N=500) + fishify(np.ones((15, 15)), N=2 * 15**2)
return simpoint_i, simpoint_ii, simpoint_iii
@app.cell
def _(plt, simpoint_i, simpoint_ii, simpoint_iii):
fig14, (ax14a, ax14b, ax14c) = plt.subplots(1, 3, figsize=(8, 2))
ax14a.imshow(simpoint_i, cmap="gray")
ax14b.imshow(simpoint_ii, cmap="gray")
ax14c.imshow(simpoint_iii, cmap="gray")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Simulating a Ring
""")
return
@app.cell
def _(np):
def ring(inner, outer, center=(0, 0), scale=1, shape=(150, 150), rtol=1e-02, atol=1e-02):
ii, jj = np.indices(shape)
r2s = np.square((ii - shape[0] / 2) * scale - center[0]) + np.square((jj - shape[1] / 2) * scale - center[1])
return ((r2s < np.square(outer)) & (r2s >= np.square(inner))).astype(np.float32)
return (ring,)
@app.cell
def _(fishify, nd, plt, psfker, ring):
fig15, (ax15a, ax15b, ax15c) = plt.subplots(1, 3, figsize=(8, 4))
ax15a.imshow(ring(0.5, 0.6, scale=0.01), cmap="gray")
ax15b.imshow(nd.convolve(ring(0.5, 0.6, scale=0.01), psfker(0.1), mode="nearest"), cmap="gray")
ax15c.imshow(fishify(nd.convolve(ring(0.5, 0.6, scale=0.01), psfker(0.1), mode="nearest"), N=10_000), cmap="gray")
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -0,0 +1,290 @@
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import numpy as np
rng = np.random.default_rng()
return np, rng
@app.cell
def _():
import scipy as si
return (si,)
@app.cell
def _():
import matplotlib
import matplotlib.pyplot as plt
plt.ion();
return (plt,)
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework5.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## The Signal-to-Noise Ratio in Images
""")
return
@app.cell
def _(rng):
xs = rng.poisson(lam=200, size=1000 * 500).reshape(1000, 500)
xs.shape
return (xs,)
@app.cell
def _(np, xs):
np.mean(np.mean(xs, axis=0) / np.std(xs, axis=0))
return
@app.cell
def _(np):
As = np.logspace(-6, 6, 500)
As.shape
return (As,)
@app.cell
def _(As, np, xs):
np.mean(np.mean(As * xs, axis=0) / np.std(As * xs, axis=0))
return
@app.cell
def _(As, np, xs):
ras = np.mean(xs, axis=0) / np.std(xs, axis=0) - np.mean(As * xs, axis=0) / np.std(As * xs, axis=0)
np.mean(ras)
return (ras,)
@app.cell
def _(plt, ras):
fig, ax = plt.subplots()
ax.hist(ras, bins="auto")
fig
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
Zero! To within typical machine error.
""")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Centroid Warmup
""")
return
@app.cell
def _(np):
i = np.arange(0, 1000)
I = 0.2 * np.sqrt(i)
float(np.sum(i * I) / np.sum(I))
return (i,)
@app.cell
def _(i, np, rng):
J = 30 / (i + 20) + 0.05 * rng.poisson(lam=10, size=i.size)
float(np.sum(i * J) / np.sum(J))
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Centroid Localization
""")
return
@app.cell
def _(np, si):
def psfker(l, NA=0.9, side=1.0, N=210, center=(0.0, 0.0)):
xs, ys = np.meshgrid(np.linspace(- side / 2, side / 2, N),
np.linspace(- side / 2, side / 2, N))
r2s = np.square(xs - center[0]) + np.square(ys - center[1])
v = 2 * np.pi * NA * np.sqrt(r2s) / l
psf = 4 * np.square(si.special.j1(v) / v)
psf[np.isnan(psf)] = 1
scale = side / N
return psf / np.sum(psf), scale
return (psfker,)
@app.cell
def _(np):
def pixelate(image, inscale, shape=(7, 7)):
outscale = image.shape[0] * inscale / shape[0]
out = np.sum(image.reshape(shape[0], int(image.shape[0] / shape[0]),
shape[1], int(image.shape[1] / shape[1])),
axis=(1, 3))
return out, outscale
return (pixelate,)
@app.cell
def _(np):
def fishify(image, N=1, rng=np.random.default_rng()):
return rng.poisson(lam=N * (image / np.sum(image)))
return (fishify,)
@app.cell
def _(fishify, np, pixelate, psfker):
def sim(l=0.51, NA=0.9, side=0.7, center=(0.0, 0.0), Nphoton=500, Nfine=280, bgavg=10, shape=(7, 7)):
point, scale = psfker(l, NA=NA, side=side, N=Nfine, center=center)
pxpt, scale = pixelate(point, scale, shape=shape)
fg = fishify(pxpt, N=Nphoton)
bg = fishify(np.ones(shape), N=bgavg * np.prod(shape))
return fg + bg, scale
return (sim,)
@app.cell
def _(np):
def centroid(im, scale=None):
ys, xs = np.indices(im.shape)
c = np.hstack([np.sum(xs * im), np.sum(ys * im)]) / np.sum(im)
c = (im * np.mgrid[0:im.shape[0], 0:im.shape[1]]).sum(1).sum(1)/im.sum()
return c if scale is None else scale * (c - np.array(im.shape) // 2)
return (centroid,)
@app.cell
def _(np):
def rms(cs, center=(0.0, 0.0)):
return float(np.sqrt(np.mean(np.square(cs[:,0] - center[0]) + np.square(cs[:,1] - center[1]))))
return (rms,)
@app.cell
def _(centroid, np, sim):
sims1 = [sim(center=(0.0, 0.0)) for m in range(100)]
cs1 = np.array([centroid(s, scale=scale) for (s, scale) in sims1])
return cs1, sims1
@app.cell
def _(centroid, cs1, plt, sims1):
fig1, (ax1a, ax1b) = plt.subplots(1, 2, figsize=(8, 4))
ax1a.imshow(sims1[0][0], cmap="gray")
cx, cy = centroid(sims1[0][0])
ax1a.vlines(cx, 0, 6, color="red")
ax1a.hlines(cy, 0, 6, color="red")
ax1b.hist(cs1[:,0], bins="auto")
fig1.tight_layout()
fig1
return
@app.cell
def _(cs1, rms):
rms(cs1)
return
@app.cell
def _(centroid, np, rms, sim):
rmss = []
for n in np.logspace(0, 5, 15):
sims = [sim(Nphoton=n) for m in range(100)]
cs = np.array([centroid(s, scale=sc) for (s, sc) in sims])
rmss.append(rms(cs))
return (rmss,)
@app.cell
def _(np, plt, rmss):
fig2, ax2 = plt.subplots()
ax2.scatter(np.logspace(0, 5, 15), rmss)
ax2.loglog(np.logspace(0, 5, 10), 1 / np.sqrt(np.logspace(0, 5, 10)), color="orange")
ax2.set_aspect('equal', 'box')
fig2.tight_layout()
fig2
return
@app.cell
def _(centroid, np, sim):
sims3a = [sim(Nphoton=1000) for m in range(100)]
cs3a = np.array([centroid(s, scale=sc) for (s, sc) in sims3a])
sims3b = [sim(Nphoton=1000, center=(0.3, 0.0)) for m in range(100)]
cs3b = np.array([centroid(s, scale=sc) for (s, sc) in sims3b])
sims3c = [sim(Nphoton=1000, center=(-0.3, 0.0)) for m in range(100)]
cs3c = np.array([centroid(s, scale=sc) for (s, sc) in sims3c])
return cs3a, cs3b, cs3c
@app.cell
def _(cs3a, cs3b, cs3c, plt):
fig3, (ax3a, ax3b, ax3c) = plt.subplots(1, 3, figsize=(9, 3))
ax3a.hist(cs3a[:, 0] - 0.0, bins="auto")
ax3b.hist(cs3b[:, 0] - 0.3, bins="auto")
ax3c.hist(cs3c[:, 0] - (-0.3), bins="auto")
fig3.tight_layout()
fig3
return
@app.cell
def _(centroid, np, sim):
Dxs = []
for p in np.linspace(-7, 7, 10):
sms = [sim(Nphoton=1000) for m in range(100)]
Dxs.append(np.mean([centroid(s, scale=sc)[0] - p for (s, sc) in sms]))
return (Dxs,)
@app.cell
def _(Dxs, np, plt):
fig4, ax4 = plt.subplots()
ax4.scatter(np.linspace(-0.5, 0.5, 10), Dxs)
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -0,0 +1,418 @@
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import numpy as np
rng = np.random.default_rng()
return np, rng
@app.cell
def _():
import matplotlib
import matplotlib.pyplot as plt
plt.ion();
return (plt,)
@app.cell
def _():
from skimage import io
import scipy.ndimage as nd
return (io,)
@app.cell
def _():
import scipy as si
import scipy.optimize as sio
return si, sio
@app.cell
def _():
import timeit
return (timeit,)
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework6.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Cilia and temporal filtering
""")
return
@app.cell
def _(io):
cilia_movie_crop = io.imread("cilia_movie_crop.tif", plugin="tifffile")
cilia_movie_crop_nframes = cilia_movie_crop.shape[0]
return cilia_movie_crop, cilia_movie_crop_nframes
@app.cell
def _(cilia_movie_crop_nframes, mo):
i = mo.ui.slider(0, cilia_movie_crop_nframes - 1, 1)
i
return (i,)
@app.cell
def _(cilia_movie_crop, i, plt):
figi, axi = plt.subplots()
axi.imshow(cilia_movie_crop[0,:,:], cmap="gray")
axi.imshow(cilia_movie_crop[i.value,:,:], cmap="gray")
return
@app.cell
def _(cilia_movie_crop, np):
cilia_movie_crop_med = np.median(cilia_movie_crop, axis=0)
return (cilia_movie_crop_med,)
@app.cell
def _(cilia_movie_crop, cilia_movie_crop_med, cilia_movie_crop_nframes, np):
cilia_movie_crop_mmed = cilia_movie_crop - np.tile(cilia_movie_crop_med, (cilia_movie_crop_nframes, 1, 1))
return (cilia_movie_crop_mmed,)
@app.cell
def _(cilia_movie_crop_nframes, mo):
ii = mo.ui.slider(0, cilia_movie_crop_nframes - 1, 1)
ii
return (ii,)
@app.cell
def _(cilia_movie_crop, cilia_movie_crop_mmed, ii, plt):
figii, axii = plt.subplots()
axii.imshow(cilia_movie_crop[0,:,:], cmap="gray")
axii.imshow(cilia_movie_crop_mmed[ii.value,:,:], cmap="gray")
return
@app.cell
def _(cilia_movie_crop_mmed, plt):
fig1, (ax1a, ax1b) = plt.subplots(2, 1)
ax1a.imshow(cilia_movie_crop_mmed[0,:,:], cmap="gray")
ax1b.hist(cilia_movie_crop_mmed.flatten(), bins=100) #, log=True)
fig1
return
@app.cell
def _(cilia_movie_crop_mmed):
cilia_imin = -15
cilia_imax = 15
cilia_movie_crop_mmed_scaled = 255 * (cilia_movie_crop_mmed - cilia_imin) / (cilia_imax - cilia_imin)
return (cilia_movie_crop_mmed_scaled,)
@app.cell
def _(cilia_movie_crop_nframes, mo):
iii = mo.ui.slider(0, cilia_movie_crop_nframes - 1, 1)
iii
return (iii,)
@app.cell
def _(cilia_movie_crop_mmed_scaled, iii, plt):
fig4, ax4 = plt.subplots()
ax4.imshow(cilia_movie_crop_mmed_scaled[0,:,:], cmap="gray")
ax4.imshow(cilia_movie_crop_mmed_scaled[iii.value,:,:], cmap="gray")
return
@app.cell
def _(cilia_movie_crop_mmed_scaled, np):
cilia_movie_crop_mmed_scaled_std = np.std(cilia_movie_crop_mmed_scaled, 0)
return (cilia_movie_crop_mmed_scaled_std,)
@app.cell
def _(cilia_movie_crop_mmed_scaled_std, plt):
fig5, ax5 = plt.subplots()
ax5.imshow(cilia_movie_crop_mmed_scaled_std, cmap="gray")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## MLE Practice
""")
return
@app.cell
def _(np):
def A(x0, b, x = np.linspace(-3, 4, 100)):
return 3 * np.power(np.abs(x - x0), b) + 4
return
@app.cell
def _(mo):
mo.md(r"""
### Images for \#3-\#4
""")
return
@app.cell
def _(np, si):
def airypsf(xy, l=0.51, NA=0.9, side=0.7, N=210):
center = xy
xs, ys = np.meshgrid(np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N)/2, N),
np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N)/2, N))
r2s = np.square(xs - center[0]) + np.square(ys - center[1])
v = 2 * np.pi * NA * np.sqrt(r2s) / l
psf = 4 * np.square(si.special.j1(v) / v)
nans = np.isnan(psf)
psf[nans] = 1
scale = side / N
return psf / np.sum(psf), scale
return (airypsf,)
@app.cell
def _(np):
def pixelate(image, inscale, shape=(7, 7)):
outscale = image.shape[0] * inscale / shape[0]
assert image.shape[0] / image.shape[1] == shape[0] / shape[1], "Aspect Ratio must be preserved!"
out = np.sum(image.reshape(shape[0], int(image.shape[0] / shape[0]),
shape[1], int(image.shape[1] / shape[1])),
axis=(1, 3))
return out, outscale
return (pixelate,)
@app.cell
def _(np):
def fishify(image, N=1, rng=np.random.default_rng()):
return rng.poisson(lam=N * (image / np.sum(image)))
return (fishify,)
@app.cell
def _(airypsf, fishify, np, pixelate):
def simage4(xc, yc, N=7, Np = 1000, B=10):
a, iscale = airypsf(np.array([xc, yc]))
p, scale = pixelate(a, iscale, shape=(N, N))
return fishify(p, Np) + fishify(np.ones((N, N)),N=(B * (N ** 2))), scale
return (simage4,)
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Centroid Localization Timing
""")
return
@app.cell
def _(np):
def centroid(im, scale=None):
ys, xs = np.indices(im.shape)
c = np.hstack([np.sum(xs * im), np.sum(ys * im)]) / np.sum(im)
c = (im * np.mgrid[0:im.shape[0], 0:im.shape[1]]).sum(1).sum(1)/im.sum()
return c if scale is None else scale * (c - np.array(im.shape) // 2)
return (centroid,)
@app.cell
def _(centroid, rng, simage4, timeit):
xys = list(zip(rng.uniform(-0.35, 0.35, 100), rng.uniform(-0.35, 0.35, 100)))
ims = [simage4(x, y)[0] for x, y in xys]
startt = timeit.default_timer()
cs = [centroid(i) for i in ims]
print(timeit.default_timer() - startt, "seconds")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Gaussian MLE for particle localization!
""")
return
@app.cell
def _(plt, simage4):
fig2, ax2 = plt.subplots()
im, sc = simage4(-0.08, 0.03)
ax2.imshow(im)
return (im,)
@app.cell
def _(airypsf, np, pixelate):
def objcam(params, im, l, NA, side):
x, y = params
p, s = airypsf(np.array([x, y]), l=l, NA=NA, side=side)
A, _ = pixelate(p, s, shape=im.shape)
mlogp = np.sum(A - im * np.log(A))
return mlogp
return (objcam,)
@app.cell
def _(np, objcam, sio):
def MLElocalize_knowcam(im, l=0.51, NA=0.9, side=0.7, guess=np.array([-0.05, 0.1])):
bnd = ((-side / 2, side / 2), (-side / 2, side / 2))
res = sio.minimize(objcam, guess, args=(im, l, NA, side), bounds= bnd)
return res
return (MLElocalize_knowcam,)
@app.cell
def _(MLElocalize_knowcam, im):
MLElocalize_knowcam(im)
return
@app.cell
def _(np):
def gausspsf(xc, yc, A0, s, B, N=210, side=0.7):
xs = np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N) / 2, N)
ys = np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N) / 2, N)
xx, yy = np.meshgrid(xs, ys)
g = A0 * np.exp(-(np.square(xx - xc) + np.square(yy - yc)) / (2.0 * np.square(s))) + B
return g, (side / N)
return (gausspsf,)
@app.cell
def _(gausspsf, pixelate, plt):
fig3, ax3 = plt.subplots()
im3, sc3 = gausspsf(0, 0, 0.02, 0.1, 1) # initial guess
im3p, _ = pixelate(im3, sc3, shape=(7, 7))
ax3.imshow(im3p)
return
@app.cell
def _(gausspsf, np):
def objgauss(params, im, side):
xc, yc, A0, s, B = params
p, sc = gausspsf(xc, yc, A0, s, B, side=side, N=im.shape[0])
#A, _ = pixelate(p, sc, shape=im.shape)
mlogp = np.sum(p - im * np.log(p))
#mlogp = np.sum(A - im * np.log(A))
return mlogp
return (objgauss,)
@app.cell
def _(np, objgauss, sio):
def MLElocalize_gauss(im, side=0.7, guess=None):
if guess is None:
guess = np.array([0, 0, np.max(im), 0.1, np.min(im)])
bnd = ((-side / 2, side / 2), (-side / 2, side / 2), (0, np.max(im)), (1e-2, None), (0, None))
res = sio.minimize(objgauss, guess, args = (im, side), bounds= bnd)
return res
return (MLElocalize_gauss,)
@app.cell
def _(MLElocalize_gauss, im):
res = MLElocalize_gauss(im)
res
return (res,)
@app.cell
def _(gausspsf, plt, res):
fig8, ax8 = plt.subplots()
im8, _ = gausspsf(*res.x, side=0.7, N=7)
ax8.imshow(im8)
return
@app.cell
def _(MLElocalize_gauss, simage4):
resx = []
for _ in range(100):
im9, sc9 = simage4(0.03, 0.03)
res9 = MLElocalize_gauss(im9)
resx.append(res9.x[0] - 0.03)
return (resx,)
@app.cell
def _(plt, resx):
figh, axh = plt.subplots()
axh.hist(resx, bins="auto")
figh
return
@app.cell
def _(MLElocalize_gauss, np, plt, simage4):
figs, axs = plt.subplots()
xs = np.linspace(-0.05, 0.05, 10)
ys = np.zeros(10)
imss = [simage4(xs[i], ys[i])[0] for i in range(10)]
es = [MLElocalize_gauss(image).x[0] for image in imss]
axs.scatter(xs, es - xs)
#axs.set_ylim([-0.5, 0.5])
return
@app.cell
def _(MLElocalize_gauss, np, plt, rng, simage4):
figr, axr = plt.subplots()
xss = rng.uniform(-0.5 * 0.1, 0.5 * 0.1, 100)
yss = rng.uniform(-0.5 * 0.1, 0.5 * 0.1, 100)
imsss = [simage4(xss[i], yss[i])[0] for i in range(100)]
ess = np.array([MLElocalize_gauss(image).x[0] for image in imsss])
axr.scatter(xss, ess - xss)
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

View file

@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
# radialcenter_ImAnClass.py
"""
Author: Raghuveer Parthasarathy
Created on Mon Oct 31 13:33:05 2022
Last modified on Mon Oct 31 13:33:05 2022
Description
-----------
Particle localization by radial symmetry
Python translation of MATLAB radialcenter.m
** Version for Image Analysis Class**
Same as radialcenter.py , but with sigma and meand2 outputs removed,
and output positions returned relative to image center.
Uses 0 indexing of positions (unlike MATLAB)
NOTE: *Does not* optimize for image stacks (like radialcenter_stk.m);
just single image
Copyright 2011-2022, Raghuveer Parthasarathy, The University of Oregon
Calculates the center of a 2D intensity distribution.
Method: Considers lines passing through each half-pixel point with slope
parallel to the gradient of the intensity at that point. Considers the
distance of closest approach between these lines and the coordinate
origin, and determines (analytically) the origin that minimizes the
weighted sum of these distances-squared.
Applies simple smoothing if size > 3x3
Inputs
I : 2D intensity distribution (i.e. a grayscale image)
Size need not be an odd number of pixels along each dimension
Outputs
xc, yc : the center of radial symmetry, px, relative to image center
Note that y increases with increasing row number (i.e. "downward")
To do:
- Test more (like MATLAB version)
- Faster grid creation than meshgrid? (like in MATLAB code)
see notes August 19-25, Sept. 9, Sept. 19-20 2011
Raghuveer Parthasarathy
The University of Oregon
August 21, 2011 (begun)
"""
import numpy as np # Will assume numpy is already imported as np !
def radialcenter(I):
# The main function -- see header comments for details
(Ny, Nx) = I.shape
# grid coordinates are -n:n, where Nx (or Ny) = 2*n+1
# grid midpoint coordinates are -n+0.5:n-0.5
xm, ym = np.meshgrid(np.arange(-(Nx-1)/2.0 + 0.5, (Nx-1)/2.0+0.5),
np.arange(-(Ny-1)/2.0 + 0.5, (Ny-1)/2.0+0.5))
# Calculate derivatives along 45-degree shifted coordinates (u and v)
# Note that y increases "downward" (increasing row number) -- we'll deal
# with this when calculating "m" below.
dIdu = I[0:Ny-1,1:]-I[1:,0:Nx-1]
dIdv = I[0:Ny-1,0:Nx-1]-I[1:,1:]
# Smoothing -- perhaps should be optional
fdu = dIdu # will overwrite if smoothing
fdv = dIdv
if np.min((Nx, Ny))>3:
# Only smooth if image is >3px in the smallest dimension
# Smooth by simple 3x3 boxcar, which I'll code directly rather than
# calling a convolution.
# Zero-pad (expand by 1 on each side)
dIdu_pad = np.zeros((Ny+1,Nx+1)) # dIdu array is size Ny-1, Nx-1
dIdv_pad = np.zeros((Ny+1,Nx+1)) # dIdv array is size Ny-1, Nx-1
dIdu_pad[1:Ny, 1:Nx] = dIdu
dIdv_pad[1:Ny, 1:Nx] = dIdv
fdu = np.zeros_like(dIdu)
fdv = np.zeros_like(dIdv)
for j in range(Ny-1):
for k in range(Nx-1):
fdu[j,k] = np.mean(dIdu_pad[j:j+3,k:k+3])
fdv[j,k] = np.mean(dIdv_pad[j:j+3,k:k+3])
dImag2 = fdu*fdu + fdv*fdv # gradient magnitude, squared
# Slope of the gradient . Note that we need a 45 degree rotation of
# the u,v components to express the slope in the x-y coordinate system.
# The negative sign "flips" the array to account for y increasing
# "downward"
m = -(fdv + fdu) / (fdu-fdv)
# Not smoothed version: m = -(dIdv + dIdu) ./ (dIdu-dIdv)
infslope = 9e9 #replace infinite slope values with this extremely large number
m[np.isinf(m)] = infslope
# Shorthand "b", which also happens to be the
# y intercept of the line of slope m that goes through each grid midpoint
b = ym - m*xm
# Weighting: weight by square of gradient magnitude and inverse
# distance to gradient intensity centroid.
sdI2 = np.sum(dImag2)
xcentroid = np.sum(dImag2*xm)/sdI2
ycentroid = np.sum(dImag2*ym)/sdI2
w = dImag2/np.sqrt((xm-xcentroid)*(xm-xcentroid) +
(ym-ycentroid)*(ym-ycentroid))
# if the intensity is completely flat, m will be NaN (0/0)
# give these points zero weight (and set m, b = 0 to avoid 0*NaN=NaN)
w[np.isnan(m)]=0
b[np.isnan(m)]=0
m[np.isnan(m)]=0
# least-squares minimization to determine the translated coordinate
# system origin (xc, yc) such that lines y = mx+b have
# the minimal total distance^2 to the origin:
# Unilke the MATLAB version, where I have a separate function
# for this (lsradialcenterfit), I'll just write the calculation here:
# Note m, b, w are defined on a grid; w are the weights for each point
wm2p1 = w/(m*m+1)
sw = np.sum(wm2p1)
smmw = np.sum(m*m*wm2p1)
smw = np.sum(m*wm2p1)
smbw = np.sum(m*b*wm2p1)
sbw = np.sum(b*wm2p1)
det = smw*smw - smmw*sw
xc = (smbw*sw - smw*sbw)/det # relative to image center
yc = (smbw*smw - smmw*sbw)/det # relative to image center
return xc, yc

View file

@ -0,0 +1,362 @@
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import numpy as np
rng = np.random.default_rng()
return np, rng
@app.cell
def _():
import matplotlib
import matplotlib.pyplot as plt
plt.ion();
return (plt,)
@app.cell
def _():
from skimage import io, restoration
import scipy.ndimage as nd
return io, nd, restoration
@app.cell
def _():
import scipy as si
import scipy.optimize as sio
return si, sio
@app.cell
def _():
import timeit
return
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework7.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Gaussian MLE and number of photons
""")
return
@app.cell
def _(np, si):
def airypsf(xy, l=0.51, NA=0.9, side=0.7, N=210):
center = xy
xs, ys = np.meshgrid(np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N)/2, N),
np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N)/2, N))
r2s = np.square(xs - center[0]) + np.square(ys - center[1])
v = 2 * np.pi * NA * np.sqrt(r2s) / l
psf = 4 * np.square(si.special.j1(v) / v)
nans = np.isnan(psf)
psf[nans] = 1
scale = side / N
return psf / np.sum(psf), scale
return (airypsf,)
@app.cell
def _(np):
def pixelate(image, inscale, shape=(7, 7)):
outscale = image.shape[0] * inscale / shape[0]
assert image.shape[0] / image.shape[1] == shape[0] / shape[1], "Aspect Ratio must be preserved!"
out = np.sum(image.reshape(shape[0], int(image.shape[0] / shape[0]),
shape[1], int(image.shape[1] / shape[1])),
axis=(1, 3))
return out, outscale
return (pixelate,)
@app.cell
def _(np):
def fishify(image, N=1, rng=np.random.default_rng()):
return rng.poisson(lam=N * (image / np.sum(image)))
return (fishify,)
@app.cell
def _(airypsf, fishify, np, pixelate):
def simage4(xc, yc, N=7, Np = 1000, B=10):
a, iscale = airypsf(np.array([xc, yc]))
p, scale = pixelate(a, iscale, shape=(N, N))
return fishify(p, Np) + fishify(np.ones((N, N)),N=(B * (N ** 2))), scale
return (simage4,)
@app.cell
def _(np):
def gausspsf(xc, yc, A0, s, B, N=210, side=0.7):
xs = np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N) / 2, N)
ys = np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N) / 2, N)
xx, yy = np.meshgrid(xs, ys)
g = A0 * np.exp(-(np.square(xx - xc) + np.square(yy - yc)) / (2.0 * np.square(s))) + B
return g, (side / N)
return (gausspsf,)
@app.cell
def _(gausspsf, np):
def objgauss(params, im, side):
xc, yc, A0, s, B = params
p, sc = gausspsf(xc, yc, A0, s, B, side=side, N=im.shape[0])
#A, _ = pixelate(p, sc, shape=im.shape)
mlogp = np.sum(p - im * np.log(p))
#mlogp = np.sum(A - im * np.log(A))
return mlogp
return (objgauss,)
@app.cell
def _(np, objgauss, sio):
def MLElocalize_gauss(im, side=0.7, guess=None):
if guess is None:
guess = np.array([0, 0, np.max(im), 0.1, np.min(im)])
bnd = ((-side / 2, side / 2), (-side / 2, side / 2), (0, np.max(im)), (1e-2, None), (0, None))
res = sio.minimize(objgauss, guess, args = (im, side), bounds= bnd)
return res
return (MLElocalize_gauss,)
@app.cell
def _():
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
### a.
See solution from last week! Looks unbiased:
""")
return
@app.cell
def _(MLElocalize_gauss, np, plt, rng, simage4):
figr, axr = plt.subplots()
xs = rng.uniform(-0.5 * 0.1, 0.5 * 0.1, 100)
ys = rng.uniform(-0.5 * 0.1, 0.5 * 0.1, 100)
ims = [simage4(xs[i], ys[i])[0] for i in range(100)]
es = np.array([MLElocalize_gauss(image).x[0] for image in ims])
axr.scatter(xs, es - xs)
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
### b.
""")
return
@app.cell
def _(np):
def RMSE(xs, ts=None):
if ts is None:
ts = np.zeros_like(xs)
return np.sqrt(np.mean(np.square(xs - ts), axis=1))
return (RMSE,)
@app.cell
def _(MLElocalize_gauss, np, simage4):
Nps = np.logspace(1, 5, 30)
imss = [simage4(0, 0, Np=i)[0] for i in Nps]
ess = np.array([MLElocalize_gauss(image).x for image in imss])[:,0:2]
return Nps, ess
@app.cell
def _(Nps, RMSE, ess, np, plt):
fig2, ax2 = plt.subplots()
ax2.loglog(Nps, RMSE(ess))
ax2.loglog(Nps, 0.51 / 2 / 0.9 / np.sqrt(Nps)) # theoretical baseline
return
@app.cell
def _(mo):
mo.md(r"""
TODO: Need to RMSE over multiple samples for each Np, not just one like this, but trend is already looking on-point.
""")
return
@app.cell
def _(mo):
mo.md(r"""
## Radial-symmetry-based particle localization
TODO: Mostly running Prof. code.
""")
return
@app.cell
def _(mo):
mo.md(r"""
## Assessing Deconvolution
""")
return
@app.cell
def _(np):
def gausspsff(xc, yc, A0, s, B, N=210, side=0.7):
xs = np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N) / 2, N)
ys = np.linspace(- side * (1 - 1/N) / 2, side * (1 - 1/N) / 2, N)
xx, yy = np.meshgrid(xs, ys)
g = A0 * np.exp(-(np.square(xx - xc) + np.square(yy - yc)) / (2.0 * np.square(s))) + B
return g / np.sum(g), (side / N)
return (gausspsff,)
@app.cell
def _(np):
def fishifyf(image, N=1, rng=np.random.default_rng()):
return rng.poisson(lam=N * (image / np.sum(image)))
return
@app.cell
def _(gausspsff, plt):
fig, ax = plt.subplots()
gpsf = gausspsff(0, 0, 1, 7, 0, 35, 35)[0]
gpsf2 = gausspsff(0, 0, 1, 5, 0, 35, 35)[0]
ax.imshow(gpsf)
return (gpsf,)
@app.cell
def _(io):
mouse_glial_cells_crop_png = io.imread("mouse_glial_cells_RBurdan_crop.png", as_gray=True)
return (mouse_glial_cells_crop_png,)
@app.cell
def _(mouse_glial_cells_crop_png, plt):
fig3, ax3 = plt.subplots()
ax3.imshow(mouse_glial_cells_crop_png, cmap="gray")
return
@app.cell
def _(gpsf, mouse_glial_cells_crop_png, nd):
mouse_glial_cells_crop_conv = nd.convolve(mouse_glial_cells_crop_png, gpsf, mode="constant")
return (mouse_glial_cells_crop_conv,)
@app.cell
def _(mouse_glial_cells_crop_conv, plt):
fig4, ax4 = plt.subplots()
ax4.imshow(mouse_glial_cells_crop_conv, cmap="gray")
return
@app.cell
def _(mouse_glial_cells_crop_conv, rng):
mouse_glial_cells_crop_fish = rng.poisson(mouse_glial_cells_crop_conv)
return (mouse_glial_cells_crop_fish,)
@app.cell
def _(mouse_glial_cells_crop_fish, plt):
fig5, ax5 = plt.subplots()
ax5.imshow(mouse_glial_cells_crop_fish, cmap="gray")
return
@app.cell
def _(gpsf, mouse_glial_cells_crop_fish, restoration):
mouse_glial_cells_crop_restored = restoration.richardson_lucy(mouse_glial_cells_crop_fish, gpsf, num_iter=20, clip=False)
return (mouse_glial_cells_crop_restored,)
@app.cell
def _(mouse_glial_cells_crop_restored, plt):
fig6, ax6 = plt.subplots()
ax6.imshow(mouse_glial_cells_crop_restored, cmap="gray")
return
@app.cell
def _(
gpsf,
mouse_glial_cells_crop_fish,
mouse_glial_cells_crop_png,
np,
restoration,
):
rmss = []
imsi = []
for i in range(1, 250, 10):
mouse_glial_cells_crop_restorei = restoration.richardson_lucy(mouse_glial_cells_crop_fish, gpsf, num_iter=i, clip=False)
mouse_glial_cells_crop_restorei = mouse_glial_cells_crop_restorei[35:-35, 35:-35]
mouse_glial_cells_crop_restorei -= np.min(mouse_glial_cells_crop_restorei)
mouse_glial_cells_crop_restorei *= (np.max(mouse_glial_cells_crop_png[35:-35, 35:-35]) - np.min(mouse_glial_cells_crop_png[35:-35, 35:-35])) / np.max(mouse_glial_cells_crop_restorei)
mouse_glial_cells_crop_restorei += np.min(mouse_glial_cells_crop_png[35:-35, 35:-35])
imsi.append(mouse_glial_cells_crop_restorei)
rms = np.sqrt(np.mean(np.square(mouse_glial_cells_crop_restorei - mouse_glial_cells_crop_png[35:-35, 35:-35])))
rmss.append(rms)
return imsi, rmss
@app.cell
def _(plt, rmss):
fig7, ax7 = plt.subplots()
ax7.scatter(range(1, 250, 10), rmss)
return
@app.cell
def _(imsi, np, plt, rmss):
fig8, ax8 = plt.subplots()
ax8.imshow(imsi[np.argmin(rmss)], cmap="gray")
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

View file

@ -0,0 +1,88 @@
import marimo
__generated_with = "0.19.11"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _():
import numpy as np
rng = np.random.default_rng()
return
@app.cell
def _():
import scipy as si
return
@app.cell
def _():
from skimage import io, morphology as mf
return io, mf
@app.cell
def _():
import matplotlib
import matplotlib.pyplot as plt
plt.ion();
return (plt,)
@app.cell
def _(mo):
from pathlib import Path
mo.pdf(src=Path("Homework8.pdf"), width="100%", height="50vh")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## Spot Removal
""")
return
@app.cell
def _(io, plt):
lichtenstein_imageduplicator_1963_png = io.imread("Lichtenstein_imageDuplicator_1963.png")
lichtenstein_imageduplicator_1963_gray = io.imread("Lichtenstein_imageDuplicator_1963_gray.png")
fig0, (ax0a, ax0b) = plt.subplots(1, 2)
ax0a.imshow(lichtenstein_imageduplicator_1963_png)
ax0b.imshow(lichtenstein_imageduplicator_1963_gray, cmap="gray")
return (lichtenstein_imageduplicator_1963_gray,)
@app.cell
def _(lichtenstein_imageduplicator_1963_gray, mf):
lichtenstein_imageduplicator_1963_close = mf.closing(lichtenstein_imageduplicator_1963_gray, mf.disk(4))
lichtenstein_imageduplicator_1963_close = mf.closing(lichtenstein_imageduplicator_1963_gray, mf.disk(2))
return (lichtenstein_imageduplicator_1963_close,)
@app.cell
def _(lichtenstein_imageduplicator_1963_close, plt):
fig1, ax1 = plt.subplots()
ax1.imshow(lichtenstein_imageduplicator_1963_close, cmap="gray")
return
@app.cell
def _():
return
if __name__ == "__main__":
app.run()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,59 @@
---
title: "UO Ph.410-510c Scientific Computation (Spring 2024) TA Resources"
author: "[**Thomas (Tom) C. Gorordo**](https://pages.uoregon.edu/tgorordo)"
---
[Official Course Site](https://pages.uoregon.edu/jschombe/sci_comp)
Data Sources:
- [Sloan Digital Sky Survey](https://www.sdss.org/)
- [Gaia Archive](https://gea.esac.esa.int/archive/)
- [FiveThirtyEight Github](https://github.com/fivethirtyeight/data)
Reference & Python:
- [The Python Wiki](https://wiki.python.org/moin/)
- [The Python Tutorial](https://docs.python.org/3/tutorial/index.html#tutorial-index)
- [The Python Language Reference](https://docs.python.org/3/reference/)
- [The NumPy API Reference](https://numpy.org/doc/stable/reference/index.html)
- [SciPy documentation](https://docs.scipy.org/doc/scipy/)
- [pandas Documentation](https://pandas.pydata.org/docs/)
- [astropy Documentation](https://docs.astropy.org/en/stable/index.html)
- [matplotlib Documentation](https://matplotlib.org/stable/index.html)
- [Think Python: How to Think Like a Computer Scientist](https://greenteapress.com/wp/think-python-2e/)
- [Learning Scientific Programming with Python](https://scipython.com/)
- [Software Carpentry](https://software-carpentry.org/lessons/)
- [Compusalon](http://vallis.org/book/code.html) and [Python for Astronomers](https://prappleizer.github.io/) are both incomplete but have lots of good exercises and neat examples.
- [Python & OpenGL for Scientific Visualization](https://www.labri.fr/perso/nrougier/python-opengl/)
- [Instant Hacking](https://folk.idi.ntnu.no/mlh/hetland_org/writing/instant-hacking.html) and [Instant Python](https://folk.idi.ntnu.no/mlh/hetland_org/writing/instant-python.html) is dated (python2) but crams a lot of concepts into a short intro - think if it as pseudocode.
Good Practices:
- [Scientific Python Design Guide](https://learn.scientific-python.org/development/principles/design/)
- [The Architechture of Open Source Applications](https://aosabook.org/en/)
- [Python Style Guide](https://peps.python.org/pep-0008/)
- [The Black Code Style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html)
- [Boxes: Your Second Python Book](https://ralsina.gitlab.io/boxes-book/)
Algorithms & Computation:
- [Problem Solving with Algorithms and Data Structures using Python](https://runestone.academy/ns/books/published/pythonds/index.html)
- *Press, Teukolsky, Vetterling and Flannery*, [Numerical Recipes: The Art of Scientific Computing](https://numerical.recipes/book.html)
- *Abelson and Sussman*, [Structure and Interpretation of Computer Programs](https://web.mit.edu/6.001/6.037/sicp.pdf) ([html](https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book.html))
- *Knuth*, [The Art of Computer Programming](https://www-cs-faculty.stanford.edu/~knuth/taocp.html)
![1337](https://imgs.xkcd.com/comics/1337_part_2.png)
Some basic shell use if you need it:
- [Unix Shell Intro](https://rcc-uchicago.github.io/shell-intro/) or [Shell Novice](https://swcarpentry.github.io/shell-novice/)
- [The Linux Documentation Project](https://tldp.org/)'s [Absolute Basics](https://tldp.org/LDP/intro-linux/html/sect_02_02.html) and [Bash Guide for Beginners](https://tldp.org/LDP/Bash-Beginners-Guide/html/index.html)
Similar Course(s):
- [Caltech Ph. 20/21/22](http://pmaweb.caltech.edu/~physlab/dokuwiki/doku.php?id=ph20)
Additional Problems/Practice:
- [Project Euler](https://projecteuler.net/)

Binary file not shown.

File diff suppressed because it is too large Load diff

143
css/default.css Normal file
View file

@ -0,0 +1,143 @@
html {
font-size: 62.5%;
}
body {
font-size: 1.6rem;
color: #000;
font-family: "Aleo", serif;
font-optical-sizing: auto;
}
header {
border-bottom: 0.2rem solid #000;
}
nav {
text-align: right;
}
nav a {
font-size: 1.8rem;
font-weight: bold;
color: black;
text-decoration: none;
text-transform: uppercase;
}
footer {
margin-top: 3rem;
padding: 1.2rem 0;
border-top: 0.2rem solid #000;
font-size: 1.2rem;
color: #555;
}
h1 {
font-size: 2.4rem;
}
h2 {
font-size: 2rem;
}
article .header {
font-size: 1.4rem;
font-style: italic;
color: #555;
}
.logo a {
font-weight: bold;
color: #000;
text-decoration: none;
}
@media (max-width: 319px) {
body {
width: 90%;
margin: 0;
padding: 0 5%;
}
header {
margin: 4.2rem 0;
}
nav {
margin: 0 auto 3rem;
text-align: center;
}
footer {
text-align: center;
}
.logo {
text-align: center;
margin: 1rem auto 3rem;
}
.logo a {
font-size: 2.4rem;
}
nav a {
display: block;
line-height: 1.6;
}
}
@media (min-width: 320px) {
body {
width: 90%;
margin: 0;
padding: 0 5%;
}
header {
margin: 4.2rem 0;
}
nav {
margin: 0 auto 3rem;
text-align: center;
}
footer {
text-align: center;
}
.logo {
text-align: center;
margin: 1rem auto 3rem;
}
.logo a {
font-size: 2.4rem;
}
nav a {
display: inline;
margin: 0 0.6rem;
}
}
@media (min-width: 640px) {
body {
width: 60rem;
margin: 0 auto;
padding: 0;
}
header {
margin: 0 0 3rem;
padding: 1.2rem 0;
}
nav {
margin: 0;
text-align: right;
}
nav a {
margin: 0 0 0 1.2rem;
display: inline;
}
footer {
text-align: right;
}
.logo {
margin: 0;
text-align: left;
}
.logo a {
float: left;
font-size: 1.8rem;
}
}

54
files/forms/carousel.cgi Normal file
View file

@ -0,0 +1,54 @@
#!/usr/bin/env -S uv run python
import cgi, cgitb
import sys, os
import html
cgitb.enable()
form = cgi.FieldStorage()
if 'spreadsheet' in form:
message = """
<h1>Matching:</h1>
<p><a href="../carousel.html">Go Back</a></p>
"""
else:
message = """
<h1>Error</h1>
<p>No file field found in the form.</p>
<p><a href="../carousel.html">Go Back</a></p>
"""
response = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> Carousel - Stable Matching </title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 40px auto;
padding: 20px;
}
h1 {
font-size: 24px;
margin-bottom: 20px;
}
</style>
</head>
<body>
{message}
</body>
<footer>
<hr>
<p>Author: <a href="https://pages.uoregon.edu/tgorordo">Thomas (Tom) C. Gorordo</a>
Source: <a href="https://github.com/tgorordo/pages.uoregon.edu">pages.uoregon.edu/tgorordo</a>,
<a href="https://github.com/tgorordo/carousel">carousel</a></p>
</footer>
"""
print(response)

77
files/forms/carousel.html Normal file
View file

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> Carousel - Stable Matching </title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 40px auto;
padding: 20px;
}
h1 {
font-size: 24px;
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
}
input[type="file"] {
margin-bottom: 15px;
}
input[type="submit"] {
padding: 8px 16px;
}
</style>
</head>
<body>
<h1>Carousel: Stable Matcher - CGI Application Upload</h1>
<div class="form-container">
<form action="/files/forms/carousel.cgi" method="POST" enctype="multipart/form-data">
<label for="spreadsheet">Upload a preferences spreadsheet (.xlsx, .xls, .csv):</label>
<input type="file" id="spreadsheet" name="spreadsheet" accept=".xlsx,.xls,.csv" required>
<br>
<input type="submit" value="Upload and Match!">
</form>
</div>
<div class="explanation-container">
<h2>About</h2>
<p>This is an upload form for the <a href="https://github.com/tgorordo/carousel">carousel</a> stable matcher (intended only for small matchings), mainly to help assign UO Physics TAs to classes according to preference. This form uses the <a href="https://service.uoregon.edu/TDClient/2030/Portal/KB/ArticleDet?ID=43069">UO pages.uoregon.edu CGI Capability</a>, so the implementation of carousel being invoked can be
<a href="https://pages.uoregon.edu/tgorordo/files/carousel/"> inspected here</a>
and you may also inspect the source of this page to verify that <a href="https://pages.uoregon.edu/tgorordo/files/forms/carousel.cgi">this script<a> is called to invoke it.
</p>
<p>The <a href="https://en.wikipedia.org/wiki/Stable_matching_problem">Stable Matching Problem</a>
(actually the "college admissions" variant of the problem) solved by carousel is to find a
"stable" set of assignments between courses/roles and TAs. A stable assignment,
in this context, is one in which there is no pair of TA and course role
which would prefer each other to their respective assignment given under the matching.
This form uses default carousel settings to run a version of the the
Gale-Shapley (1962) deferred-acceptance algorithm which finds the stable matching that is
optimal for the TA preferences. If other stable solutions are desired, you will need to
run carousel as a python application yourself.
<h3>Input: Expected Spreadsheet Format</h3>
<p>A spreadsheet for matching should be organized as a list of TA assignment preferences
and a list of course preferences/constraints, i.e. with the following structure:</p>
<ul>
<li><strong>Column A:</strong> Name (text)</li>
</ul>
<h3>Output: Matching Result Format</h3>
<p>This form will return a matching in the form of </p>
</div>
</body>
<footer>
<hr>
<p>Author: <a href="https://pages.uoregon.edu/tgorordo">Thomas (Tom) C. Gorordo</a>
Source: <a href="https://github.com/tgorordo/pages.uoregon.edu">pages.uoregon.edu/tgorordo</a>,
<a href="https://github.com/tgorordo/carousel">carousel</a></p>
</footer>
</html>

BIN
files/haskell-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

52
files/tgorordo-pub.pgp Normal file
View file

@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGKme78BEADLDzYRmIkhyBV1D5rlwAUKnTG0pxBSVRhBmFqhbty7It+Lnx0L
clpUZ03sujDqFLzvuz3r/e3b9RPrXwH8Jx/t70rrWtcOEY0bgd9vk2ZFbe0/QFF9
bVH5N/W9qcaiu9zQESmOIsqsuhj26sqgV/pA+KJJLd9J7g/RHBmsZ07NbZhphXeM
xypmOI3GSHkMypictQUaqK+OWQ4m4X8AlDWOiIb9hmMokJyHYWqJZgyCAcaD6gGu
xJZwvUMv3xEdz5P6x0hTh8fW8/af6v90G0tcSeMHcj0cc76KR8m0upHVALg2GhBp
3jUSHQwgGh/XEQpZhVuH1o2mKZW2NsBsg4gfGx8L9ot+6n3F7jIyjYIsfqCgNHGP
n6x48b7hSMyAg84ds6mUU3ZVhRYzKS3fuznfL0sj8XPy/+H9EJDicUBmxXm/OjpU
k/h7fztsNyUR7CJeRFStqL/Do4lBQmxvqhsUsPTIPjnaKabop+k4VOSIk+glW9kf
KdRc/ya7jPIr3twgxqYdyVviwtDo0+7z1YXFRdIreAVDaQpzd65xFxwo21NWUHXe
OaHsFrATqT1gMAZjUKwcZ258l8bEzx9TFbkGSNoZU61cV+9sp95E80KE8P75Lho8
DAsNq8PyyV+oLqBZyXKaBGpYnmMDx/mCkO8iRXifYypQjqwq+50tmuNIwwARAQAB
tDxUaG9tYXMgKFRvbSkgQy4gR29yb3JkbyAocGVyc29uYWwga2V5KSA8dGNnb3Jv
cmRvQGdtYWlsLmNvbT6JAk4EEwEKADgWIQSSZPlH9afrRPDM4DwMvtIrsNlEkAUC
YqZ7vwIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAMvtIrsNlEkNuXD/9D
QaWtswI2yRfxfy0F0ly/7Db04Q+a6rt49Ki2yHwP7pIfqhcrnlfpN+PfB/mi+ySx
ACpN8w/sLSHWf7f9T+m8Wjl4jBHCACxV2S/kbk1abzr2UqYl0oboNAZeGyewXOsL
r+AyGqg8o4j67TCbv7z5DPobdnz/CQ3SvY3lfGFNznJrsMvx9jZmhpWcjAifxBbP
s5aH/5GPFZXm+o7S2Y/nALmEPIaYZh57XV36rpkd5wjx1Egd0KEI/sb10EFok5xo
SF6b61vmPPuCqpof+uyG2SXmJggOheiuuF/osHVADpMhrDh3Rlk9T2hTTHInB9X2
BZ6nFU1LgkmRWh4wRbF0Qg95Bupt3bnZ/WPPXztxTc2flN0VY7ChfB3pXIy5CVfd
ibNukjl2srHy2ecfHrfFwFkQI8A+I/k5MdTr6DbXBQW1VHqFdrE2OahcT4/umFGp
EqL3PrF+8JhrL2KJifK2By9ZS3co5IA8xdS/j7HSvQWbS+VviQSVmQGjV9rw+pFF
w3y+OWD86HRYV2deBuBXlzEblqjKrVHw8gMBoIANHQ0GJ0HTdE54HGiYO1iOeZqP
xBBSioQsh87CKt3yxnfaTlVpuUlg/hNKaoMeTzgnJqKm8hsXF7FhgjcCgE2yuerz
NxByd2ZcMl8Nl7o8OR0iLw9i6lx3TukUFsGTGqT3ZLkCDQRipnu/ARAAngA4pK22
NVjrmUN9tXtwBGx7gzlMbMFEQYyJH66QPpiqP/ARymhfi71eQ9/jhMpQ/U9BlvQi
PP1HLxJgul1G2FHcuFS/e/rKD1Z8TKwfhttCXu4Q0EGGjNMxK6bntiAvalD4rGlF
jUlhyEPT2Yl7BmXCGkm4aaL3PcfOSTsyqbh1piTCe0cWKi4KGAnANkjhnv7JEW2J
kQfNu3D99jA4YOwyAW3B47pdV6g7GihzMo/yaOVbNzBJCD6Yd32pzGnQLNsf2WF6
5IXhHFkcMlgkdpxkMTr7EhK5uzjVLvUXoOwLCtSenVwNm3hmGNQqImhIGXz2b8bH
q85FmK+FNqI1mrF9kOYYuFRzlJ7Hxb6X9wJfy19bTYuLmpNhAxga+urVIboGhMkf
NqSfb5Lq/ZXljyr6mgyv+BuXR+YKA79BW9MjWPMNGQdopCVRmtmJc1jTykHxehZC
JnatH2LATVsE3TMZ4t8aBVzhaMcIMRjCydSDA3absZSi9AJlSNk6wFo+UqxtgZm7
ucG/lOxWONyE/7U6Uvbpbs4vcBQ7T+ihOSxLb/lgst2PhaLErF9XCqocBPoosYbQ
Z3PF7iYwlxC1yhtDfB+WsqTcvpcR1DupvsDrkAE0jiiMtVpc+qzt1onNE25YUaqc
ZDLss9TOTx92pYX8pww+6ON4PFk9FH1RqXcAEQEAAYkCNgQYAQoAIBYhBJJk+Uf1
p+tE8MzgPAy+0iuw2USQBQJipnu/AhsMAAoJEAy+0iuw2USQRiQP/0HVmOG4k6Pt
ZPIaxCnKb40JI0DyxPcuC58NqoviTdm6nM3LmEmIjhcRTtkEEoOXUwDsNPdv3I5e
OGytldPVj54xEfg5H4bRy+nphHxYU8Co5wqv1hl8zqILCL1UB7pHgtUkz0pDe7Mf
av6ByZ5Saje5q512wj93qL6I8OLUOZ4WB98iUESnJez+xAvDunrFoZgkVJPFGd7h
FT21QRyovsN2tNqE3t5wA77A5uTm6QlMbyXH93clUXoVVcGT6VRVT8IcB/2kovnv
C2bfgJPdlTb0GIvnEQjZZjz9kDQymxFvhxAhVXXz3tU+X0yGcV2z0RPf121qt++k
07wxOeROxord8C5+P2JKHcr2Bymzr6TDWkwatwLOVgaga1DaM+Gdn1GVwZgRpMGQ
dBQy6x+FYAVHxlom5XN3scEqW5xJEZ2+oPPoTflU243y8F7z6Lk2eRhI/wEI3LuK
2ZlajsCAQdyrEx535KD1Ej3rjk43lGK+NAcXnGqMe2/UMLpDrPVMcgErP5VXk4o+
B10Yu9jiUcRqwwty0T+JqwQT5F5bRto/AcDnOejVULGX0edP0IT2VsaPRqHaArn7
xT6ZSO3J1PsF5O6MdFEhS38iCrTGOGOnHtckf07PzIjgUg9Wzkp92E8qmZ2ptTdc
8p6I8+YsOgBOjdjPU18Abyas/eD/Xql3
=6xCA
-----END PGP PUBLIC KEY BLOCK-----

14
pages-uoregon-edu.cabal Normal file
View file

@ -0,0 +1,14 @@
name: pages-uoregon-edu
version: 0.1.0.0
build-type: Simple
cabal-version: >= 1.10
executable site
main-is: site.hs
build-depends: base == 4.*
, hakyll == 4.16.*
, process
, filepath
, pandoc
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010

View file

@ -0,0 +1,76 @@
---
title: "Computing the Wigner 9j Symbols Efficiently"
author: "Thomas (Tom) C. Gorordo"
published: false
references:
- type: book
id: GrahamKnuthPatashnik1994ConcreteMathematics2e
author:
- family: Graham
given: Ronald L.
- family: Knuth
given: Donald E.
- family: Patashnik
given: Oren
title: 'Concrete Mathematics: A Foundation for Computer Science'
title-short: 'Concrete Mathematics'
---
As a test post, here's a transcription of some notes I have laying around from writing an [`add9j` PR](https://github.com/tgorordo/WignerSymbols.jl)
for [`Jutho/WignerSymbols.jl`](https://github.com/Jutho/WignerSymbols).
## Wigner Symbols Formulae
The Wigner \(3x\text{j}\) symbols are all exactly representable in the form
\[W_{3x} = \frac{n\sqrt{s}}{q}\hspace{1cm} n,s,q\in\mathbb{Z}\]
So, if one can use exact integer arithmetic in computing the three components,
a computer implementation of the symbols should be able to incur at-worst
typical floating point root and ratio errors.
This requires the usage of formulae that are amenible to such integer manipulations.
### \(3j\) Formula
Let \(\delta(j_1, j_2, j_3) = (j_1 \leq j_2 + j_3)\bigwedge (j_2 \leq j_1 + j_3)\bigwedge (j_3 \leq j_1 + j_2)\bigwedge(j_1 + j_2 + j_3\in\mathbb{Z})\)
for \(j_i\in\frac{1}{2}\mathbb{Z}\) a half-integer be called the "triangle condition". If not satisfied, a symbol is zero.
The \(3j\) symbol can be computed according to:
### \(6j\) Formula
The \(6j\) symbol, similarly, can be computed as:
Define the Wei square brackets purely in terms of binomial coefficients by
### \(9j\) Formula
The \(9j\) formula has a few additional pieces.
One might have some fun manipulating some of these forms using the tricks in
[@GrahamKnuthPatashnik1994ConcreteMathematics2e].
## Calculation and Tabulation
For fast, exact evaluation, the main integer-arithmetic idea is to simplify the evaluation
of the various sums of ratios of (potentially large) factorials by using prime factorizations
of those factorials to reduce ratios by an LCD ad extract common factors across the sums.
Remaining arithmetic can be done via a big integer implementation.
The core of this approach uses that prime factorizations of factorials are conveniently
obtained recursively (and thus, to tabulate). The crux is:
### Euclid's Lemma
> *If \( p | ab\) for prime \(p\), then \(p|a\) or \(p|b\).*
> *\(\implies\) If prime \(p|n!\) then \(p|k\) for \(k\leq n\) one of the factors.*
More specifically, *Legendre's Theorem* says:
\[\sharp_p(n!) = \sum_{k=1} \sharp_p(k) = \sum_{k=1}^{\lfloor\log_p(n)\rfloor} \lfloor\frac{n}{p^k}\rfloor\]
where \(\sharp_p(k)\) gives the number of times $p$ divides \(k\).

15
pyproject.toml Normal file
View file

@ -0,0 +1,15 @@
[project]
name = "pages-uoregon-edu"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
"matplotlib>=3.10.8",
"numpy>=2.4.2",
"scikit-image>=0.26.0",
"scipy>=1.17.0",
]
[dependency-groups]
dev = [
"marimo>=0.19.11",
]

136
site.hs Normal file
View file

@ -0,0 +1,136 @@
--------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
import Data.Monoid (mappend)
import Hakyll
import Text.Pandoc.Extensions (Extension(..), enableExtension)
import Text.Pandoc.Options
import System.Process (readCreateProcess, shell, CreateProcess(..))
import System.FilePath (takeDirectory, takeFileName)
import Data.Maybe (fromMaybe)
import Control.Monad (filterM)
--------------------------------------------------------------------------------
main :: IO ()
main = hakyll $ do
match "files/**" $ do
route idRoute
compile copyFileCompiler
match "css/*" $ do
route idRoute
compile compressCssCompiler
match (fromList []) $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= loadAndApplyTemplate "templates/default.html" defaultContext
>>= relativizeUrls
-- Courses
match "courses/uoph611_Th-Mechanics/*" $ do
route idRoute
compile copyFileCompiler
match "courses/uoph410-510c_Sci-Comp/resources.md" $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= loadAndApplyTemplate "templates/default.html" defaultContext
>>= relativizeUrls
match "courses/uoph410-510c_Sci-Comp/*" $ do
route idRoute
compile copyFileCompiler
match "courses/uoph410-510a_Image-Analysis/setup.md" $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= loadAndApplyTemplate "templates/default.html" defaultContext
>>= relativizeUrls
match (foldl1 (.||.) $
fromGlob "courses/uoph410-510a_Image-Analysis/wk1/s0.py" :
[ fromGlob ("courses/uoph410-510a_Image-Analysis/wk" ++ n ++ "/s" ++ n ++ ".py")
| n <- map show [1..8] ]) $ do
route $ setExtension "html"
compile $ do
fp <- toFilePath <$> getUnderlying
let dir = takeDirectory fp
fnm = takeFileName fp
outfp = fnm ++ ".html"
cmd = "cd " ++ dir ++ " && uv run marimo export html " ++ fnm ++ " --output " ++ outfp ++ " --force --no-sandbox"
unsafeCompiler $ readCreateProcess (shell cmd) ""
result <- unsafeCompiler $ readFile (dir ++ "/" ++ outfp)
makeItem result
match (foldl1 (.||.)
[ fromGlob ("courses/uoph410-510a_Image-Analysis/wk" ++ n ++ "/*")
| n <- map show [1..8] ]) $ do
route idRoute
compile copyFileCompiler
match "courses/uoph444-544_Intro-BioPhysics/**" $ do
route idRoute
compile copyFileCompiler
match "courses/uoph25X_Foundations/*" $ do
route idRoute
compile copyFileCompiler
match "posts/*" $ do
route $ setExtension "html"
compile $ getResourceString
>>= withItemBody (return . doubleBackslashes)
>>= renderPandoc
>>= loadAndApplyTemplate "templates/post.html" postCtx
>>= loadAndApplyTemplate "templates/default.html" postCtx
>>= relativizeUrls
create ["archive.html"] $ do
route idRoute
compile $ do
posts <- recentFirst =<< filterM (isPublished . itemIdentifier) =<< loadAll "posts/*"
let archiveCtx =
listField "posts" postCtx (return posts) `mappend`
constField "title" "Archives" `mappend`
defaultContext
makeItem ""
>>= loadAndApplyTemplate "templates/archive.html" archiveCtx
>>= loadAndApplyTemplate "templates/default.html" archiveCtx
>>= relativizeUrls
match "README.md" $ do
route $ constRoute "index.html"
compile $ do
posts <- recentFirst =<< filterM (isPublished . itemIdentifier) =<< loadAll "posts/*"
let indexCtx =
listField "posts" postCtx (return posts) `mappend`
defaultContext
getResourceString
>>= withItemBody (return . doubleBackslashes)
>>= renderPandoc
>>= applyAsTemplate indexCtx
>>= loadAndApplyTemplate "templates/default.html" indexCtx
>>= relativizeUrls
match "templates/*" $ compile templateBodyCompiler
--------------------------------------------------------------------------------
postCtx :: Context String
postCtx =
dateField "date" "%B %e, %Y" `mappend`
defaultContext
doubleBackslashes :: String -> String
doubleBackslashes = concatMap (\c -> if c == '\\' then "\\\\" else [c])
isPublished :: MonadMetadata m => Identifier -> m Bool
isPublished ident = do
val <- getMetadataField ident "published"
return $ fromMaybe False $ fmap (== "true") val

67
stack.yaml Normal file
View file

@ -0,0 +1,67 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/configure/yaml/
# A 'specific' Stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# snapshot: lts-23.0
# snapshot: nightly-2024-12-13
# snapshot: ghc-9.8.4
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# snapshot: ./custom-snapshot.yaml
# snapshot: https://example.com/snapshots/2024-01-01.yaml
snapshot:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/31.yaml
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the snapshot.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
# extra-deps: []
# Override default flag values for project packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=3.3"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

13
stack.yaml.lock Normal file
View file

@ -0,0 +1,13 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/topics/lock_files
packages: []
snapshots:
- completed:
sha256: d5dc0b770386350f61aa8310d3d347e6ea16466a0b0adb533b64689840eebfd6
size: 726797
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/31.yaml
original:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/31.yaml

2
templates/archive.html Normal file
View file

@ -0,0 +1,2 @@
Here you can find all my previous posts:
$partial("templates/post-list.html")$

49
templates/default.html Normal file
View file

@ -0,0 +1,49 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>$title$</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Aleo:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/default.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.28/dist/katex.min.css" integrity="sha384-Wsr4Nh3yrvMf2KCebJchRJoVo1gTU6kcP05uRSh5NV3sj9+a8IomuJoQzf3sMq4T" crossorigin="anonymous">
<!-- The loading of KaTeX is deferred to speed up page rendering -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.28/dist/katex.min.js" integrity="sha384-+W9OcrYK2/bD7BmUAk+xeFAyKp0QjyRQUCxeU31dfyTt/FrPsUgaBTLLkVf33qWt" crossorigin="anonymous"></script>
<!-- To automatically render math in text elements, include the auto-render extension: -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.28/dist/contrib/auto-render.min.js" integrity="sha384-hCXGrW6PitJEwbkoStFjeJxv+fSOOQKOPbJxSfM6G5sWZjAyWhXiTIIAmQqnlLlh" crossorigin="anonymous" onload="renderMathInElement(document.body, {
delimiters: [
{left: '\\[', right: '\\]', display: true},
{left: '\\(', right: '\\)', display: false}
]
});"></script>
</head>
<body>
<header>
<div class="logo">
<a href="mailto:tgorordo@uoregon.edu">tgorordo@uoregon.edu</a>
</div>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main role="main">
<h2>$title$</h2>
$body$
</main>
<footer>
Site generated with
<a href="http://jaspervdj.be/hakyll">Hakyll</a>,
so you can read the
<a href="https://github.com/tgorordo/pages.uoregon.edu/">source here</a>.
</footer>
</body>
</html>

7
templates/post-list.html Normal file
View file

@ -0,0 +1,7 @@
<ul>
$for(posts)$
<li>
<a href="$url$">$title$</a> - $date$
</li>
$endfor$
</ul>

11
templates/post.html Normal file
View file

@ -0,0 +1,11 @@
<article>
<section class="header">
Posted on $date$
$if(author)$
by $author$
$endif$
</section>
<section>
$body$
</section>
</article>

903
uv.lock generated Normal file
View file

@ -0,0 +1,903 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "anyio"
version = "4.12.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
]
[[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 = "docutils"
version = "0.22.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" },
]
[[package]]
name = "fonttools"
version = "4.61.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4b/cf/00ba28b0990982530addb8dc3e9e6f2fa9cb5c20df2abdda7baa755e8fe1/fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c", size = 2846454, upload-time = "2025-12-12T17:30:24.938Z" },
{ url = "https://files.pythonhosted.org/packages/5a/ca/468c9a8446a2103ae645d14fee3f610567b7042aba85031c1c65e3ef7471/fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e", size = 2398191, upload-time = "2025-12-12T17:30:27.343Z" },
{ url = "https://files.pythonhosted.org/packages/a3/4b/d67eedaed19def5967fade3297fed8161b25ba94699efc124b14fb68cdbc/fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5", size = 4928410, upload-time = "2025-12-12T17:30:29.771Z" },
{ url = "https://files.pythonhosted.org/packages/b0/8d/6fb3494dfe61a46258cd93d979cf4725ded4eb46c2a4ca35e4490d84daea/fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd", size = 4984460, upload-time = "2025-12-12T17:30:32.073Z" },
{ url = "https://files.pythonhosted.org/packages/f7/f1/a47f1d30b3dc00d75e7af762652d4cbc3dff5c2697a0dbd5203c81afd9c3/fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3", size = 4925800, upload-time = "2025-12-12T17:30:34.339Z" },
{ url = "https://files.pythonhosted.org/packages/a7/01/e6ae64a0981076e8a66906fab01539799546181e32a37a0257b77e4aa88b/fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d", size = 5067859, upload-time = "2025-12-12T17:30:36.593Z" },
{ url = "https://files.pythonhosted.org/packages/73/aa/28e40b8d6809a9b5075350a86779163f074d2b617c15d22343fce81918db/fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c", size = 2267821, upload-time = "2025-12-12T17:30:38.478Z" },
{ url = "https://files.pythonhosted.org/packages/1a/59/453c06d1d83dc0951b69ef692d6b9f1846680342927df54e9a1ca91c6f90/fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b", size = 2318169, upload-time = "2025-12-12T17:30:40.951Z" },
{ url = "https://files.pythonhosted.org/packages/32/8f/4e7bf82c0cbb738d3c2206c920ca34ca74ef9dabde779030145d28665104/fonttools-4.61.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd", size = 2846094, upload-time = "2025-12-12T17:30:43.511Z" },
{ url = "https://files.pythonhosted.org/packages/71/09/d44e45d0a4f3a651f23a1e9d42de43bc643cce2971b19e784cc67d823676/fonttools-4.61.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e", size = 2396589, upload-time = "2025-12-12T17:30:45.681Z" },
{ url = "https://files.pythonhosted.org/packages/89/18/58c64cafcf8eb677a99ef593121f719e6dcbdb7d1c594ae5a10d4997ca8a/fonttools-4.61.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c", size = 4877892, upload-time = "2025-12-12T17:30:47.709Z" },
{ url = "https://files.pythonhosted.org/packages/8a/ec/9e6b38c7ba1e09eb51db849d5450f4c05b7e78481f662c3b79dbde6f3d04/fonttools-4.61.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75", size = 4972884, upload-time = "2025-12-12T17:30:49.656Z" },
{ url = "https://files.pythonhosted.org/packages/5e/87/b5339da8e0256734ba0dbbf5b6cdebb1dd79b01dc8c270989b7bcd465541/fonttools-4.61.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063", size = 4924405, upload-time = "2025-12-12T17:30:51.735Z" },
{ url = "https://files.pythonhosted.org/packages/0b/47/e3409f1e1e69c073a3a6fd8cb886eb18c0bae0ee13db2c8d5e7f8495e8b7/fonttools-4.61.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2", size = 5035553, upload-time = "2025-12-12T17:30:54.823Z" },
{ url = "https://files.pythonhosted.org/packages/bf/b6/1f6600161b1073a984294c6c031e1a56ebf95b6164249eecf30012bb2e38/fonttools-4.61.1-cp314-cp314-win32.whl", hash = "sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c", size = 2271915, upload-time = "2025-12-12T17:30:57.913Z" },
{ url = "https://files.pythonhosted.org/packages/52/7b/91e7b01e37cc8eb0e1f770d08305b3655e4f002fc160fb82b3390eabacf5/fonttools-4.61.1-cp314-cp314-win_amd64.whl", hash = "sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c", size = 2323487, upload-time = "2025-12-12T17:30:59.804Z" },
{ url = "https://files.pythonhosted.org/packages/39/5c/908ad78e46c61c3e3ed70c3b58ff82ab48437faf84ec84f109592cabbd9f/fonttools-4.61.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa", size = 2929571, upload-time = "2025-12-12T17:31:02.574Z" },
{ url = "https://files.pythonhosted.org/packages/bd/41/975804132c6dea64cdbfbaa59f3518a21c137a10cccf962805b301ac6ab2/fonttools-4.61.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91", size = 2435317, upload-time = "2025-12-12T17:31:04.974Z" },
{ url = "https://files.pythonhosted.org/packages/b0/5a/aef2a0a8daf1ebaae4cfd83f84186d4a72ee08fd6a8451289fcd03ffa8a4/fonttools-4.61.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19", size = 4882124, upload-time = "2025-12-12T17:31:07.456Z" },
{ url = "https://files.pythonhosted.org/packages/80/33/d6db3485b645b81cea538c9d1c9219d5805f0877fda18777add4671c5240/fonttools-4.61.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba", size = 5100391, upload-time = "2025-12-12T17:31:09.732Z" },
{ url = "https://files.pythonhosted.org/packages/6c/d6/675ba631454043c75fcf76f0ca5463eac8eb0666ea1d7badae5fea001155/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7", size = 4978800, upload-time = "2025-12-12T17:31:11.681Z" },
{ url = "https://files.pythonhosted.org/packages/7f/33/d3ec753d547a8d2bdaedd390d4a814e8d5b45a093d558f025c6b990b554c/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118", size = 5006426, upload-time = "2025-12-12T17:31:13.764Z" },
{ url = "https://files.pythonhosted.org/packages/b4/40/cc11f378b561a67bea850ab50063366a0d1dd3f6d0a30ce0f874b0ad5664/fonttools-4.61.1-cp314-cp314t-win32.whl", hash = "sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5", size = 2335377, upload-time = "2025-12-12T17:31:16.49Z" },
{ url = "https://files.pythonhosted.org/packages/e4/ff/c9a2b66b39f8628531ea58b320d66d951267c98c6a38684daa8f50fb02f8/fonttools-4.61.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b", size = 2400613, upload-time = "2025-12-12T17:31:18.769Z" },
{ url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" },
]
[[package]]
name = "h11"
version = "0.16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
]
[[package]]
name = "idna"
version = "3.11"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
]
[[package]]
name = "imageio"
version = "2.37.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
{ name = "pillow" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a3/6f/606be632e37bf8d05b253e8626c2291d74c691ddc7bcdf7d6aaf33b32f6a/imageio-2.37.2.tar.gz", hash = "sha256:0212ef2727ac9caa5ca4b2c75ae89454312f440a756fcfc8ef1993e718f50f8a", size = 389600, upload-time = "2025-11-04T14:29:39.898Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/fe/301e0936b79bcab4cacc7548bf2853fc28dced0a578bab1f7ef53c9aa75b/imageio-2.37.2-py3-none-any.whl", hash = "sha256:ad9adfb20335d718c03de457358ed69f141021a333c40a53e57273d8a5bd0b9b", size = 317646, upload-time = "2025-11-04T14:29:37.948Z" },
]
[[package]]
name = "itsdangerous"
version = "2.2.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
]
[[package]]
name = "jedi"
version = "0.19.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "parso" },
]
sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
]
[[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 = "lazy-loader"
version = "0.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6f/6b/c875b30a1ba490860c93da4cabf479e03f584eba06fe5963f6f6644653d8/lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1", size = 15431, upload-time = "2024-04-05T13:03:12.261Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc", size = 12097, upload-time = "2024-04-05T13:03:10.514Z" },
]
[[package]]
name = "loro"
version = "1.10.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7d/27/ea6f3298fc87ea5f2d60ebfbca088e7d9b2ceb3993f67c83bfb81778ec01/loro-1.10.3.tar.gz", hash = "sha256:68184ab1c2ab94af6ad4aaba416d22f579cabee0b26cbb09a1f67858207bbce8", size = 68833, upload-time = "2025-12-09T10:14:06.644Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/75/67/8467cc1c119149ada86903b67ce10fc4b47fb6eb2a8ca5f94c0938fd010f/loro-1.10.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:380ef692c5272e8b607be2ee6a8eef5113e65dc38e6739526c30e3db6abc3fbc", size = 3239527, upload-time = "2025-12-09T10:11:33.884Z" },
{ url = "https://files.pythonhosted.org/packages/bc/3b/d1a01af3446cb98890349215bea7e71ba49dc3e50ffbfb90c5649657a8b8/loro-1.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed966ce6ff1fb3787b3f6c4ed6dd036baa5fb738b84a466a5e764f2ab534ccc2", size = 3044767, upload-time = "2025-12-09T10:11:18.777Z" },
{ url = "https://files.pythonhosted.org/packages/6b/93/37f891fa46767001ae2518697fb01fc187497e3a5238fe28102be626055d/loro-1.10.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d7c8d2f3d88578fdf69845a9ae16fc5ea3ac54aa838a6bf43a24ce11908220", size = 3292648, upload-time = "2025-12-09T10:08:15.404Z" },
{ url = "https://files.pythonhosted.org/packages/6c/67/82273eeba2416b0410595071eda1eefcdf4072c014d44d2501b660aa7145/loro-1.10.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62283c345bfeedef19c8a6d029cd8830e5d2c20b5fb45975d8a70a8a30a7944b", size = 3353181, upload-time = "2025-12-09T10:08:50.144Z" },
{ url = "https://files.pythonhosted.org/packages/82/33/894dccf132bece82168dfbe61fad25a13ed89d18f20649f99e87c38f9228/loro-1.10.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1e7e6ae091179fa5f0fca1f8612fde20236ee0a678744bf51ff7d26103ea04f", size = 3712583, upload-time = "2025-12-09T10:09:27.934Z" },
{ url = "https://files.pythonhosted.org/packages/b2/b7/99292729d8b271bcc4bff5faa20b33e4c749173af4c9cb9d34880ae3b4c8/loro-1.10.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6abc6de4876aa205498cef52a002bc38662fbd8d742351ea0f535479208b8b1c", size = 3421491, upload-time = "2025-12-09T10:10:01.63Z" },
{ url = "https://files.pythonhosted.org/packages/be/fb/188b808ef1d9b6d842d53969b99a16afb1b71f04739150959c8946345d0e/loro-1.10.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acbbfd24cf28a71bbdad8544852e9bbba0ba8535f8221f8859b2693555fa8356", size = 3352623, upload-time = "2025-12-09T10:10:57.361Z" },
{ url = "https://files.pythonhosted.org/packages/53/cc/e2d008cc24bddcf05d1a15b8907a73b1731921ab40897f73a3385fdd274a/loro-1.10.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5faf4ebbe8ca39605024f16dbbbde354365f4e2dcfda82c753797461b504bbd3", size = 3687687, upload-time = "2025-12-09T10:10:34.453Z" },
{ url = "https://files.pythonhosted.org/packages/ec/b6/4251822674230027103caa4fd46a1e83c4d676500074e7ab297468bf8f40/loro-1.10.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e049c21b292c4ff992b23a98812840735db84620721c10ae7f047a921202d090", size = 3474316, upload-time = "2025-12-09T10:11:51.207Z" },
{ url = "https://files.pythonhosted.org/packages/c4/54/ecff3ec08d814f3b9ec1c78a14ecf2e7ff132a71b8520f6aa6ad1ace0056/loro-1.10.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:20e8dacfb827c1f7ffb73e127029d7995a9ab2c3b7b7bc3ecc91d22ee32d78d0", size = 3622069, upload-time = "2025-12-09T10:12:27.059Z" },
{ url = "https://files.pythonhosted.org/packages/ac/84/c1b8251000f46df5f4d043af8c711bdbff9818727d26429378e0f3a5115e/loro-1.10.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1b743c1c4f93f5b4f0e12efbb352d26e9f80bcbf20f45d9c70f3d0b522f42060", size = 3667722, upload-time = "2025-12-09T10:13:02.012Z" },
{ url = "https://files.pythonhosted.org/packages/ef/13/c5c02776f4ad52c6361b95e1d7396c29071533cef45e3861a2e35745be27/loro-1.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:446d67bc9e28036a5a5e03526d28a1559ef2a47b3ccad6b07820dae123cc3697", size = 3564952, upload-time = "2025-12-09T10:13:37.227Z" },
{ url = "https://files.pythonhosted.org/packages/1e/f1/63d4bc63a1521a9b577f6d13538ec4790865584fdf87569d5af943792406/loro-1.10.3-cp313-cp313-win32.whl", hash = "sha256:45d7d8ec683599897695bb714771baccabc1b4c4a412283cc39787c7a59f7ff0", size = 2720952, upload-time = "2025-12-09T10:14:30.17Z" },
{ url = "https://files.pythonhosted.org/packages/29/3c/65c8b0b7f96c9b4fbd458867cf91f30fcd58ac25449d8ba9303586061671/loro-1.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:a42bf73b99b07fed11b65feb0a5362b33b19de098f2235848687f4c41204830e", size = 2953768, upload-time = "2025-12-09T10:14:11.965Z" },
{ url = "https://files.pythonhosted.org/packages/4e/e9/f6a242f61aa4d8b56bd11fa467be27d416401d89cc3244b58651a3a44c88/loro-1.10.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4866325b154aeebcd34be106c7597acf150c374481ac3c12035a1af715ac0f01", size = 3289791, upload-time = "2025-12-09T10:08:16.926Z" },
{ url = "https://files.pythonhosted.org/packages/a7/81/8f5f4d6805658c654264e99467f3f46facdbb2062cbf86743768ee4b942a/loro-1.10.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ea7b8849660a28ce8cd90a82db4f76c23453836fcbc88f5767feaaf8739045e2", size = 3348007, upload-time = "2025-12-09T10:08:53.305Z" },
{ url = "https://files.pythonhosted.org/packages/c3/15/bba0fad18ec5561a140e9781fd2b38672210b52e847d207c57ae85379efd/loro-1.10.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e82cdaf9a5892557d3167e07ed5093f87dfa31ef860a63b0eac6c0c2f435705", size = 3707937, upload-time = "2025-12-09T10:09:29.165Z" },
{ url = "https://files.pythonhosted.org/packages/7a/b2/5519c92bd4f9cde068dc60ba35d7f3e4f8cce41e7bf39febd4fb08908e97/loro-1.10.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7ee99e5dc844fb20fca830906a0d721022ad1c37aad0b1a440c4ecb98d0c02f", size = 3416744, upload-time = "2025-12-09T10:10:02.956Z" },
{ url = "https://files.pythonhosted.org/packages/81/ba/92d97c27582c0ce12bb83df19b9e080c0dfe95068966296a4fa2279c0477/loro-1.10.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:153c297672ad98d0fe6ff8985decf1e64528ad1dd01ae1452bb83bdeb31f858f", size = 3470978, upload-time = "2025-12-09T10:11:52.707Z" },
{ url = "https://files.pythonhosted.org/packages/f3/8b/acb39b0e74af1c317d3121e75a4bc5bc77d7fda5a79c60399746486f60d9/loro-1.10.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:0ed72f8c6a5f521252ee726954055339abba3fcf00404fb4b5c2da168f0cce79", size = 3615039, upload-time = "2025-12-09T10:12:28.631Z" },
{ url = "https://files.pythonhosted.org/packages/4f/c3/154e3361e5ef42012f6842dbd93f8fbace6eec06517b5a4a9f8c4a46e873/loro-1.10.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f612ab17acdac16c0139e63ff45b33175ebfb22e61a60eb7929a4583389348d6", size = 3663731, upload-time = "2025-12-09T10:13:03.557Z" },
{ url = "https://files.pythonhosted.org/packages/c6/dd/a283cf5b1c957e0bbc67503a10e17606a8f8c87f51d3cf3d83dc3a0ac88a/loro-1.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f2741db05c79f3618c954bac90f4572d28c01c243884453f379e9a8738f93d81", size = 3558807, upload-time = "2025-12-09T10:13:38.926Z" },
{ url = "https://files.pythonhosted.org/packages/8d/4a/a5340b6fdf4cd34d758bed23bd1f64063b3b1b41ff4ecc94ee39259ee9a7/loro-1.10.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:623cf7df17626aa55bc6ca54e89177dbe71a5f1c293e102d6153f43991a1a041", size = 3213589, upload-time = "2025-12-09T10:11:35.377Z" },
{ url = "https://files.pythonhosted.org/packages/00/93/5164e93a77e365a92def77c1258386daef233516a29fb674a3b9d973b8b8/loro-1.10.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d8e715d475f32a1462969aca27eeb3f998f309182978f55bc37ce5c515d92e90", size = 3029557, upload-time = "2025-12-09T10:11:20.076Z" },
{ url = "https://files.pythonhosted.org/packages/6c/30/94592d7c01f480ce99e1783b0d9203eb20ba2eab42575dabd384e3c9d1fa/loro-1.10.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e012a80e8c9fe248b9d0a76e91664c9479a72d976eaeed78f87b15b5d1d732", size = 3282335, upload-time = "2025-12-09T10:08:18.168Z" },
{ url = "https://files.pythonhosted.org/packages/e9/a8/7ae3c0b955aa638fa7dbd2d194c7759749a0d0d96a94805d5dec9b30eaea/loro-1.10.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:686ece56756acbaf80c986848915e9126a29a06d7a62209747e3ef1efc0bd8f6", size = 3333071, upload-time = "2025-12-09T10:08:55.314Z" },
{ url = "https://files.pythonhosted.org/packages/f7/10/151edebdb2bca626ad50911b761164ced16984b25b0b37b34b674ded8b29/loro-1.10.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aa821c8871deca98f4605eb0c40fb26bcf82bd29c9e7fa33b183516c5395b11", size = 3698226, upload-time = "2025-12-09T10:09:30.474Z" },
{ url = "https://files.pythonhosted.org/packages/f4/ac/02a490e38466506b1003df4910d2a8ae582265023dae9e2217c98b56ea3f/loro-1.10.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:507d34137adb4148f79e1da7f89a21a4aab18565621a5dc2b389773fe98ac25b", size = 3407322, upload-time = "2025-12-09T10:10:04.199Z" },
{ url = "https://files.pythonhosted.org/packages/81/db/da51f2bcad81ca3733bc21e83f3b6752446436b565b90f5c350ad227ad01/loro-1.10.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91d3b2e187ccfe2b14118a6e5617266fedcdf3435f6fa0a3db7b4afce8afa687", size = 3330268, upload-time = "2025-12-09T10:10:58.61Z" },
{ url = "https://files.pythonhosted.org/packages/4e/af/50d136c83d504a3a1f4ad33a6bf38b6933985a82741302255cf446a5f7ad/loro-1.10.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0016f834fd1626710081334400aed8494380b55ef131f7133d21c3bd22d892a", size = 3673582, upload-time = "2025-12-09T10:10:35.849Z" },
{ url = "https://files.pythonhosted.org/packages/63/4d/53288aae777218e05c43af9c080652bcdbbc8d97c031607eedd3fc15617d/loro-1.10.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:71c4275dca5a8a86219d60545d4f60e081b4af44b490ac912c0481906934bfc6", size = 3463731, upload-time = "2025-12-09T10:11:54.102Z" },
{ url = "https://files.pythonhosted.org/packages/75/01/2389f26ffe8bc3ffe48a0a578f610dd49c709bbcf0d5d2642c6e2b52f490/loro-1.10.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:490f12571b2ed1a8eaf1edd3a7fffc55adac5010b1875fe1bb9e9af9a3907c38", size = 3602334, upload-time = "2025-12-09T10:12:30.082Z" },
{ url = "https://files.pythonhosted.org/packages/a7/16/07b64af13f5fcea025e003ca27bbd6f748217abbd4803dad88ea0900526c/loro-1.10.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a374a43cadaa48528a5411496481df9ae52bf01e513f4509e37d6c986f199c0e", size = 3657896, upload-time = "2025-12-09T10:13:04.86Z" },
{ url = "https://files.pythonhosted.org/packages/c9/2f/4050770d7675ceced71651fe76971d5c27456b7098c0de03a4ecdbb0a02d/loro-1.10.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1a93b2ee59f1fa8d98dd552211fd5693551893b34c1dd2ba0324806d6d14022f", size = 3544339, upload-time = "2025-12-09T10:13:40.396Z" },
{ url = "https://files.pythonhosted.org/packages/c9/21/67e27cb404c968fc19a841d5c6277f13a17c69a56f49e3c15ea1c92a28eb/loro-1.10.3-cp314-cp314-win32.whl", hash = "sha256:baa863e3d869422e3320e822c0b1f87f5dc44cda903d1bd3b7a16f8413ce3d92", size = 2706731, upload-time = "2025-12-09T10:14:31.604Z" },
{ url = "https://files.pythonhosted.org/packages/08/54/6770cf36aeb994489375e9ab9c01201e70ab7cc286fa97e907aa41b1bae6/loro-1.10.3-cp314-cp314-win_amd64.whl", hash = "sha256:f10ed3ca89485f942b8b2de796ed9783edb990e7e570605232de77489e9f3548", size = 2933563, upload-time = "2025-12-09T10:14:13.805Z" },
{ url = "https://files.pythonhosted.org/packages/24/f5/eb089fd25eb428709dbe79fd4d36b82a00572aa54badd1dff62511a38fe3/loro-1.10.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b4d049efb1953aebfc16fa0b445ff5a37d4d08a1ab93f3b5a577a454b7a5ded", size = 3282369, upload-time = "2025-12-09T10:08:20.011Z" },
{ url = "https://files.pythonhosted.org/packages/30/d7/692cb87c908f6a8af6cbfc10ebab69e16780e3796e11454c2b481b5c3817/loro-1.10.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56ecad7fbac58aa8bee52bb261a764aeef6c7b39c20f0d69e8fad908ab2ca7d8", size = 3332530, upload-time = "2025-12-09T10:08:57.07Z" },
{ url = "https://files.pythonhosted.org/packages/54/46/ed3afbf749288b6f70f3b859a6762538818bf6a557ca873b07d6b036946b/loro-1.10.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d8d1be349d08b3a95592c6a17b80b1ea6aef892b1b8e2b93b540062d04e34e0", size = 3702599, upload-time = "2025-12-09T10:09:31.779Z" },
{ url = "https://files.pythonhosted.org/packages/fe/30/6cb616939c12bfe96a71a01a6e3551febf1c34bf9de114fafadbcfb65064/loro-1.10.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ec0a0b9bc4e32c46f14710062ec5b536c72110318aaf85632a4f8b37e9a470a", size = 3404412, upload-time = "2025-12-09T10:10:05.448Z" },
{ url = "https://files.pythonhosted.org/packages/02/a2/3d4006d3333589f9158ac6d403979bf5c985be8b461b18e7a2ea23b05414/loro-1.10.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c5d4437987f7a4a4ff5927f39d0f43ded5b34295dfb0a3c8e150687e25c3d6b8", size = 3462948, upload-time = "2025-12-09T10:11:55.405Z" },
{ url = "https://files.pythonhosted.org/packages/41/30/c640ccd3e570b08770a9f459decc2d8e7ceefdc34ac28a745418fb9cb5ba/loro-1.10.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:86d4f0c631ca274ad2fa2c0bdb8e1e141882d94339b7284a8bef5bf73fa6957d", size = 3599851, upload-time = "2025-12-09T10:12:31.759Z" },
{ url = "https://files.pythonhosted.org/packages/59/8f/062ea50554c47ae30e98b1f0442a458c0edecc6d4edc7fcfc4d901734dd0/loro-1.10.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:15e03084ff1b472e14623183ed6e1e43e0f717c2112697beda5e69b5bd0ff236", size = 3655558, upload-time = "2025-12-09T10:13:06.529Z" },
{ url = "https://files.pythonhosted.org/packages/f3/f5/c7dd8cdbd57454b23d89799c22cd42b6d2dda283cd87d7b198dc424a462c/loro-1.10.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:42d6a5ce5bc518eaa682413e82d597299650eeb03e8bc39341752d6e0d22503e", size = 3541282, upload-time = "2025-12-09T10:13:42.189Z" },
]
[[package]]
name = "marimo"
version = "0.19.11"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "docutils" },
{ name = "itsdangerous" },
{ name = "jedi" },
{ name = "loro" },
{ name = "markdown" },
{ name = "msgspec" },
{ name = "narwhals" },
{ name = "packaging" },
{ name = "psutil" },
{ name = "pygments" },
{ name = "pymdown-extensions" },
{ name = "pyyaml" },
{ name = "starlette" },
{ name = "tomlkit" },
{ name = "uvicorn" },
{ name = "websockets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/06/31/aa12298afce0c7cf6bc0d8ffe664b4cfb295451f9029ca7a461c6e30390d/marimo-0.19.11.tar.gz", hash = "sha256:1f65a19f9dced82ae2d041dbe31b3f47ba16993f6411d41ba526b3b322abd948", size = 38203731, upload-time = "2026-02-12T18:37:49.536Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/47/d4/817cfdcf9636fc75036b9e0f7aa458c0bedec420d79768005ccfcf7fc9d8/marimo-0.19.11-py3-none-any.whl", hash = "sha256:4f98b677c89cada69c330e38f0747b4fca73cedb6f81b66832df3035ab8b6cff", size = 38609582, upload-time = "2026-02-12T18:37:53.954Z" },
]
[[package]]
name = "markdown"
version = "3.10.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" },
]
[[package]]
name = "matplotlib"
version = "3.10.8"
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/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3d/b9/15fd5541ef4f5b9a17eefd379356cf12175fe577424e7b1d80676516031a/matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3f2e409836d7f5ac2f1c013110a4d50b9f7edc26328c108915f9075d7d7a91b6", size = 8261076, upload-time = "2025-12-10T22:55:44.648Z" },
{ url = "https://files.pythonhosted.org/packages/8d/a0/2ba3473c1b66b9c74dc7107c67e9008cb1782edbe896d4c899d39ae9cf78/matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56271f3dac49a88d7fca5060f004d9d22b865f743a12a23b1e937a0be4818ee1", size = 8148794, upload-time = "2025-12-10T22:55:46.252Z" },
{ url = "https://files.pythonhosted.org/packages/75/97/a471f1c3eb1fd6f6c24a31a5858f443891d5127e63a7788678d14e249aea/matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a7f52498f72f13d4a25ea70f35f4cb60642b466cbb0a9be951b5bc3f45a486", size = 8718474, upload-time = "2025-12-10T22:55:47.864Z" },
{ url = "https://files.pythonhosted.org/packages/01/be/cd478f4b66f48256f42927d0acbcd63a26a893136456cd079c0cc24fbabf/matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:646d95230efb9ca614a7a594d4fcacde0ac61d25e37dd51710b36477594963ce", size = 9549637, upload-time = "2025-12-10T22:55:50.048Z" },
{ url = "https://files.pythonhosted.org/packages/5d/7c/8dc289776eae5109e268c4fb92baf870678dc048a25d4ac903683b86d5bf/matplotlib-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f89c151aab2e2e23cb3fe0acad1e8b82841fd265379c4cecd0f3fcb34c15e0f6", size = 9613678, upload-time = "2025-12-10T22:55:52.21Z" },
{ url = "https://files.pythonhosted.org/packages/64/40/37612487cc8a437d4dd261b32ca21fe2d79510fe74af74e1f42becb1bdb8/matplotlib-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:e8ea3e2d4066083e264e75c829078f9e149fa119d27e19acd503de65e0b13149", size = 8142686, upload-time = "2025-12-10T22:55:54.253Z" },
{ url = "https://files.pythonhosted.org/packages/66/52/8d8a8730e968185514680c2a6625943f70269509c3dcfc0dcf7d75928cb8/matplotlib-3.10.8-cp313-cp313-win_arm64.whl", hash = "sha256:c108a1d6fa78a50646029cb6d49808ff0fc1330fda87fa6f6250c6b5369b6645", size = 8012917, upload-time = "2025-12-10T22:55:56.268Z" },
{ url = "https://files.pythonhosted.org/packages/b5/27/51fe26e1062f298af5ef66343d8ef460e090a27fea73036c76c35821df04/matplotlib-3.10.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ad3d9833a64cf48cc4300f2b406c3d0f4f4724a91c0bd5640678a6ba7c102077", size = 8305679, upload-time = "2025-12-10T22:55:57.856Z" },
{ url = "https://files.pythonhosted.org/packages/2c/1e/4de865bc591ac8e3062e835f42dd7fe7a93168d519557837f0e37513f629/matplotlib-3.10.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:eb3823f11823deade26ce3b9f40dcb4a213da7a670013929f31d5f5ed1055b22", size = 8198336, upload-time = "2025-12-10T22:55:59.371Z" },
{ url = "https://files.pythonhosted.org/packages/c6/cb/2f7b6e75fb4dce87ef91f60cac4f6e34f4c145ab036a22318ec837971300/matplotlib-3.10.8-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d9050fee89a89ed57b4fb2c1bfac9a3d0c57a0d55aed95949eedbc42070fea39", size = 8731653, upload-time = "2025-12-10T22:56:01.032Z" },
{ url = "https://files.pythonhosted.org/packages/46/b3/bd9c57d6ba670a37ab31fb87ec3e8691b947134b201f881665b28cc039ff/matplotlib-3.10.8-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b44d07310e404ba95f8c25aa5536f154c0a8ec473303535949e52eb71d0a1565", size = 9561356, upload-time = "2025-12-10T22:56:02.95Z" },
{ url = "https://files.pythonhosted.org/packages/c0/3d/8b94a481456dfc9dfe6e39e93b5ab376e50998cddfd23f4ae3b431708f16/matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a", size = 9614000, upload-time = "2025-12-10T22:56:05.411Z" },
{ url = "https://files.pythonhosted.org/packages/bd/cd/bc06149fe5585ba800b189a6a654a75f1f127e8aab02fd2be10df7fa500c/matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958", size = 8220043, upload-time = "2025-12-10T22:56:07.551Z" },
{ url = "https://files.pythonhosted.org/packages/e3/de/b22cf255abec916562cc04eef457c13e58a1990048de0c0c3604d082355e/matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5", size = 8062075, upload-time = "2025-12-10T22:56:09.178Z" },
{ url = "https://files.pythonhosted.org/packages/3c/43/9c0ff7a2f11615e516c3b058e1e6e8f9614ddeca53faca06da267c48345d/matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f", size = 8262481, upload-time = "2025-12-10T22:56:10.885Z" },
{ url = "https://files.pythonhosted.org/packages/6f/ca/e8ae28649fcdf039fda5ef554b40a95f50592a3c47e6f7270c9561c12b07/matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b", size = 8151473, upload-time = "2025-12-10T22:56:12.377Z" },
{ url = "https://files.pythonhosted.org/packages/f1/6f/009d129ae70b75e88cbe7e503a12a4c0670e08ed748a902c2568909e9eb5/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d", size = 9553896, upload-time = "2025-12-10T22:56:14.432Z" },
{ url = "https://files.pythonhosted.org/packages/f5/26/4221a741eb97967bc1fd5e4c52b9aa5a91b2f4ec05b59f6def4d820f9df9/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2cf5bd12cecf46908f286d7838b2abc6c91cda506c0445b8223a7c19a00df008", size = 9824193, upload-time = "2025-12-10T22:56:16.29Z" },
{ url = "https://files.pythonhosted.org/packages/1f/f3/3abf75f38605772cf48a9daf5821cd4f563472f38b4b828c6fba6fa6d06e/matplotlib-3.10.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:41703cc95688f2516b480f7f339d8851a6035f18e100ee6a32bc0b8536a12a9c", size = 9615444, upload-time = "2025-12-10T22:56:18.155Z" },
{ url = "https://files.pythonhosted.org/packages/93/a5/de89ac80f10b8dc615807ee1133cd99ac74082581196d4d9590bea10690d/matplotlib-3.10.8-cp314-cp314-win_amd64.whl", hash = "sha256:83d282364ea9f3e52363da262ce32a09dfe241e4080dcedda3c0db059d3c1f11", size = 8272719, upload-time = "2025-12-10T22:56:20.366Z" },
{ url = "https://files.pythonhosted.org/packages/69/ce/b006495c19ccc0a137b48083168a37bd056392dee02f87dba0472f2797fe/matplotlib-3.10.8-cp314-cp314-win_arm64.whl", hash = "sha256:2c1998e92cd5999e295a731bcb2911c75f597d937341f3030cc24ef2733d78a8", size = 8144205, upload-time = "2025-12-10T22:56:22.239Z" },
{ url = "https://files.pythonhosted.org/packages/68/d9/b31116a3a855bd313c6fcdb7226926d59b041f26061c6c5b1be66a08c826/matplotlib-3.10.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b5a2b97dbdc7d4f353ebf343744f1d1f1cca8aa8bfddb4262fcf4306c3761d50", size = 8305785, upload-time = "2025-12-10T22:56:24.218Z" },
{ url = "https://files.pythonhosted.org/packages/1e/90/6effe8103f0272685767ba5f094f453784057072f49b393e3ea178fe70a5/matplotlib-3.10.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3f5c3e4da343bba819f0234186b9004faba952cc420fbc522dc4e103c1985908", size = 8198361, upload-time = "2025-12-10T22:56:26.787Z" },
{ url = "https://files.pythonhosted.org/packages/d7/65/a73188711bea603615fc0baecca1061429ac16940e2385433cc778a9d8e7/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f62550b9a30afde8c1c3ae450e5eb547d579dd69b25c2fc7a1c67f934c1717a", size = 9561357, upload-time = "2025-12-10T22:56:28.953Z" },
{ url = "https://files.pythonhosted.org/packages/f4/3d/b5c5d5d5be8ce63292567f0e2c43dde9953d3ed86ac2de0a72e93c8f07a1/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:495672de149445ec1b772ff2c9ede9b769e3cb4f0d0aa7fa730d7f59e2d4e1c1", size = 9823610, upload-time = "2025-12-10T22:56:31.455Z" },
{ url = "https://files.pythonhosted.org/packages/4d/4b/e7beb6bbd49f6bae727a12b270a2654d13c397576d25bd6786e47033300f/matplotlib-3.10.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:595ba4d8fe983b88f0eec8c26a241e16d6376fe1979086232f481f8f3f67494c", size = 9614011, upload-time = "2025-12-10T22:56:33.85Z" },
{ url = "https://files.pythonhosted.org/packages/7c/e6/76f2813d31f032e65f6f797e3f2f6e4aab95b65015924b1c51370395c28a/matplotlib-3.10.8-cp314-cp314t-win_amd64.whl", hash = "sha256:25d380fe8b1dc32cf8f0b1b448470a77afb195438bafdf1d858bfb876f3edf7b", size = 8362801, upload-time = "2025-12-10T22:56:36.107Z" },
{ url = "https://files.pythonhosted.org/packages/5d/49/d651878698a0b67f23aa28e17f45a6d6dd3d3f933fa29087fa4ce5947b5a/matplotlib-3.10.8-cp314-cp314t-win_arm64.whl", hash = "sha256:113bb52413ea508ce954a02c10ffd0d565f9c3bc7f2eddc27dfe1731e71c7b5f", size = 8192560, upload-time = "2025-12-10T22:56:38.008Z" },
]
[[package]]
name = "msgspec"
version = "0.20.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ea/9c/bfbd12955a49180cbd234c5d29ec6f74fe641698f0cd9df154a854fc8a15/msgspec-0.20.0.tar.gz", hash = "sha256:692349e588fde322875f8d3025ac01689fead5901e7fb18d6870a44519d62a29", size = 317862, upload-time = "2025-11-24T03:56:28.934Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/d1/b902d38b6e5ba3bdddbec469bba388d647f960aeed7b5b3623a8debe8a76/msgspec-0.20.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9c1ff8db03be7598b50dd4b4a478d6fe93faae3bd54f4f17aa004d0e46c14c46", size = 196463, upload-time = "2025-11-24T03:55:43.405Z" },
{ url = "https://files.pythonhosted.org/packages/57/b6/eff0305961a1d9447ec2b02f8c73c8946f22564d302a504185b730c9a761/msgspec-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f6532369ece217fd37c5ebcfd7e981f2615628c21121b7b2df9d3adcf2fd69b8", size = 188650, upload-time = "2025-11-24T03:55:44.761Z" },
{ url = "https://files.pythonhosted.org/packages/99/93/f2ec1ae1de51d3fdee998a1ede6b2c089453a2ee82b5c1b361ed9095064a/msgspec-0.20.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9a1697da2f85a751ac3cc6a97fceb8e937fc670947183fb2268edaf4016d1ee", size = 218834, upload-time = "2025-11-24T03:55:46.441Z" },
{ url = "https://files.pythonhosted.org/packages/28/83/36557b04cfdc317ed8a525c4993b23e43a8fbcddaddd78619112ca07138c/msgspec-0.20.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7fac7e9c92eddcd24c19d9e5f6249760941485dff97802461ae7c995a2450111", size = 224917, upload-time = "2025-11-24T03:55:48.06Z" },
{ url = "https://files.pythonhosted.org/packages/8f/56/362037a1ed5be0b88aced59272442c4b40065c659700f4b195a7f4d0ac88/msgspec-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f953a66f2a3eb8d5ea64768445e2bb301d97609db052628c3e1bcb7d87192a9f", size = 222821, upload-time = "2025-11-24T03:55:49.388Z" },
{ url = "https://files.pythonhosted.org/packages/92/75/fa2370ec341cedf663731ab7042e177b3742645c5dd4f64dc96bd9f18a6b/msgspec-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:247af0313ae64a066d3aea7ba98840f6681ccbf5c90ba9c7d17f3e39dbba679c", size = 227227, upload-time = "2025-11-24T03:55:51.125Z" },
{ url = "https://files.pythonhosted.org/packages/f1/25/5e8080fe0117f799b1b68008dc29a65862077296b92550632de015128579/msgspec-0.20.0-cp313-cp313-win_amd64.whl", hash = "sha256:67d5e4dfad52832017018d30a462604c80561aa62a9d548fc2bd4e430b66a352", size = 189966, upload-time = "2025-11-24T03:55:52.458Z" },
{ url = "https://files.pythonhosted.org/packages/79/b6/63363422153937d40e1cb349c5081338401f8529a5a4e216865decd981bf/msgspec-0.20.0-cp313-cp313-win_arm64.whl", hash = "sha256:91a52578226708b63a9a13de287b1ec3ed1123e4a088b198143860c087770458", size = 175378, upload-time = "2025-11-24T03:55:53.721Z" },
{ url = "https://files.pythonhosted.org/packages/bb/18/62dc13ab0260c7d741dda8dc7f481495b93ac9168cd887dda5929880eef8/msgspec-0.20.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:eead16538db1b3f7ec6e3ed1f6f7c5dec67e90f76e76b610e1ffb5671815633a", size = 196407, upload-time = "2025-11-24T03:55:55.001Z" },
{ url = "https://files.pythonhosted.org/packages/dd/1d/b9949e4ad6953e9f9a142c7997b2f7390c81e03e93570c7c33caf65d27e1/msgspec-0.20.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:703c3bb47bf47801627fb1438f106adbfa2998fe586696d1324586a375fca238", size = 188889, upload-time = "2025-11-24T03:55:56.311Z" },
{ url = "https://files.pythonhosted.org/packages/1e/19/f8bb2dc0f1bfe46cc7d2b6b61c5e9b5a46c62298e8f4d03bbe499c926180/msgspec-0.20.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6cdb227dc585fb109305cee0fd304c2896f02af93ecf50a9c84ee54ee67dbb42", size = 219691, upload-time = "2025-11-24T03:55:57.908Z" },
{ url = "https://files.pythonhosted.org/packages/b8/8e/6b17e43f6eb9369d9858ee32c97959fcd515628a1df376af96c11606cf70/msgspec-0.20.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27d35044dd8818ac1bd0fedb2feb4fbdff4e3508dd7c5d14316a12a2d96a0de0", size = 224918, upload-time = "2025-11-24T03:55:59.322Z" },
{ url = "https://files.pythonhosted.org/packages/1c/db/0e833a177db1a4484797adba7f429d4242585980b90882cc38709e1b62df/msgspec-0.20.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b4296393a29ee42dd25947981c65506fd4ad39beaf816f614146fa0c5a6c91ae", size = 223436, upload-time = "2025-11-24T03:56:00.716Z" },
{ url = "https://files.pythonhosted.org/packages/c3/30/d2ee787f4c918fd2b123441d49a7707ae9015e0e8e1ab51aa7967a97b90e/msgspec-0.20.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:205fbdadd0d8d861d71c8f3399fe1a82a2caf4467bc8ff9a626df34c12176980", size = 227190, upload-time = "2025-11-24T03:56:02.371Z" },
{ url = "https://files.pythonhosted.org/packages/ff/37/9c4b58ff11d890d788e700b827db2366f4d11b3313bf136780da7017278b/msgspec-0.20.0-cp314-cp314-win_amd64.whl", hash = "sha256:7dfebc94fe7d3feec6bc6c9df4f7e9eccc1160bb5b811fbf3e3a56899e398a6b", size = 193950, upload-time = "2025-11-24T03:56:03.668Z" },
{ url = "https://files.pythonhosted.org/packages/e9/4e/cab707bf2fa57408e2934e5197fc3560079db34a1e3cd2675ff2e47e07de/msgspec-0.20.0-cp314-cp314-win_arm64.whl", hash = "sha256:2ad6ae36e4a602b24b4bf4eaf8ab5a441fec03e1f1b5931beca8ebda68f53fc0", size = 179018, upload-time = "2025-11-24T03:56:05.038Z" },
{ url = "https://files.pythonhosted.org/packages/4c/06/3da3fc9aaa55618a8f43eb9052453cfe01f82930bca3af8cea63a89f3a11/msgspec-0.20.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f84703e0e6ef025663dd1de828ca028774797b8155e070e795c548f76dde65d5", size = 200389, upload-time = "2025-11-24T03:56:06.375Z" },
{ url = "https://files.pythonhosted.org/packages/83/3b/cc4270a5ceab40dfe1d1745856951b0a24fd16ac8539a66ed3004a60c91e/msgspec-0.20.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7c83fc24dd09cf1275934ff300e3951b3adc5573f0657a643515cc16c7dee131", size = 193198, upload-time = "2025-11-24T03:56:07.742Z" },
{ url = "https://files.pythonhosted.org/packages/cd/ae/4c7905ac53830c8e3c06fdd60e3cdcfedc0bbc993872d1549b84ea21a1bd/msgspec-0.20.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f13ccb1c335a124e80c4562573b9b90f01ea9521a1a87f7576c2e281d547f56", size = 225973, upload-time = "2025-11-24T03:56:09.18Z" },
{ url = "https://files.pythonhosted.org/packages/d9/da/032abac1de4d0678d99eaeadb1323bd9d247f4711c012404ba77ed6f15ca/msgspec-0.20.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17c2b5ca19f19306fc83c96d85e606d2cc107e0caeea85066b5389f664e04846", size = 229509, upload-time = "2025-11-24T03:56:10.898Z" },
{ url = "https://files.pythonhosted.org/packages/69/52/fdc7bdb7057a166f309e0b44929e584319e625aaba4771b60912a9321ccd/msgspec-0.20.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d931709355edabf66c2dd1a756b2d658593e79882bc81aae5964969d5a291b63", size = 230434, upload-time = "2025-11-24T03:56:12.48Z" },
{ url = "https://files.pythonhosted.org/packages/cb/fe/1dfd5f512b26b53043884e4f34710c73e294e7cc54278c3fe28380e42c37/msgspec-0.20.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:565f915d2e540e8a0c93a01ff67f50aebe1f7e22798c6a25873f9fda8d1325f8", size = 231758, upload-time = "2025-11-24T03:56:13.765Z" },
{ url = "https://files.pythonhosted.org/packages/97/f6/9ba7121b8e0c4e0beee49575d1dbc804e2e72467692f0428cf39ceba1ea5/msgspec-0.20.0-cp314-cp314t-win_amd64.whl", hash = "sha256:726f3e6c3c323f283f6021ebb6c8ccf58d7cd7baa67b93d73bfbe9a15c34ab8d", size = 206540, upload-time = "2025-11-24T03:56:15.029Z" },
{ url = "https://files.pythonhosted.org/packages/c8/3e/c5187de84bb2c2ca334ab163fcacf19a23ebb1d876c837f81a1b324a15bf/msgspec-0.20.0-cp314-cp314t-win_arm64.whl", hash = "sha256:93f23528edc51d9f686808a361728e903d6f2be55c901d6f5c92e44c6d546bfc", size = 183011, upload-time = "2025-11-24T03:56:16.442Z" },
]
[[package]]
name = "narwhals"
version = "2.16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/fc/6f/713be67779028d482c6e0f2dde5bc430021b2578a4808c1c9f6d7ad48257/narwhals-2.16.0.tar.gz", hash = "sha256:155bb45132b370941ba0396d123cf9ed192bf25f39c4cea726f2da422ca4e145", size = 618268, upload-time = "2026-02-02T10:31:00.545Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/03/cc/7cb74758e6df95e0c4e1253f203b6dd7f348bf2f29cf89e9210a2416d535/narwhals-2.16.0-py3-none-any.whl", hash = "sha256:846f1fd7093ac69d63526e50732033e86c30ea0026a44d9b23991010c7d1485d", size = 443951, upload-time = "2026-02-02T10:30:58.635Z" },
]
[[package]]
name = "networkx"
version = "3.6.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
]
[[package]]
name = "numpy"
version = "2.4.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a1/22/815b9fe25d1d7ae7d492152adbc7226d3eff731dffc38fe970589fcaaa38/numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c", size = 16663696, upload-time = "2026-01-31T23:11:17.516Z" },
{ url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979", size = 14688322, upload-time = "2026-01-31T23:11:19.883Z" },
{ url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98", size = 5198157, upload-time = "2026-01-31T23:11:22.375Z" },
{ url = "https://files.pythonhosted.org/packages/74/09/826e4289844eccdcd64aac27d13b0fd3f32039915dd5b9ba01baae1f436c/numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef", size = 6546330, upload-time = "2026-01-31T23:11:23.958Z" },
{ url = "https://files.pythonhosted.org/packages/19/fb/cbfdbfa3057a10aea5422c558ac57538e6acc87ec1669e666d32ac198da7/numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7", size = 15660968, upload-time = "2026-01-31T23:11:25.713Z" },
{ url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499", size = 16607311, upload-time = "2026-01-31T23:11:28.117Z" },
{ url = "https://files.pythonhosted.org/packages/14/d9/4b5adfc39a43fa6bf918c6d544bc60c05236cc2f6339847fc5b35e6cb5b0/numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb", size = 17012850, upload-time = "2026-01-31T23:11:30.888Z" },
{ url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7", size = 18334210, upload-time = "2026-01-31T23:11:33.214Z" },
{ url = "https://files.pythonhosted.org/packages/78/0e/0a73b3dff26803a8c02baa76398015ea2a5434d9b8265a7898a6028c1591/numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110", size = 5958199, upload-time = "2026-01-31T23:11:35.385Z" },
{ url = "https://files.pythonhosted.org/packages/43/bc/6352f343522fcb2c04dbaf94cb30cca6fd32c1a750c06ad6231b4293708c/numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622", size = 12310848, upload-time = "2026-01-31T23:11:38.001Z" },
{ url = "https://files.pythonhosted.org/packages/6e/8d/6da186483e308da5da1cc6918ce913dcfe14ffde98e710bfeff2a6158d4e/numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71", size = 10221082, upload-time = "2026-01-31T23:11:40.392Z" },
{ url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262", size = 14815866, upload-time = "2026-01-31T23:11:42.495Z" },
{ url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913", size = 5325631, upload-time = "2026-01-31T23:11:44.7Z" },
{ url = "https://files.pythonhosted.org/packages/46/00/3a490938800c1923b567b3a15cd17896e68052e2145d8662aaf3e1ffc58f/numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab", size = 6646254, upload-time = "2026-01-31T23:11:46.341Z" },
{ url = "https://files.pythonhosted.org/packages/d3/e9/fac0890149898a9b609caa5af7455a948b544746e4b8fe7c212c8edd71f8/numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82", size = 15720138, upload-time = "2026-01-31T23:11:48.082Z" },
{ url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f", size = 16655398, upload-time = "2026-01-31T23:11:50.293Z" },
{ url = "https://files.pythonhosted.org/packages/4d/89/253db0fa0e66e9129c745e4ef25631dc37d5f1314dad2b53e907b8538e6d/numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554", size = 17079064, upload-time = "2026-01-31T23:11:52.927Z" },
{ url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257", size = 18379680, upload-time = "2026-01-31T23:11:55.22Z" },
{ url = "https://files.pythonhosted.org/packages/40/62/48f99ae172a4b63d981babe683685030e8a3df4f246c893ea5c6ef99f018/numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657", size = 6082433, upload-time = "2026-01-31T23:11:58.096Z" },
{ url = "https://files.pythonhosted.org/packages/07/38/e054a61cfe48ad9f1ed0d188e78b7e26859d0b60ef21cd9de4897cdb5326/numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b", size = 12451181, upload-time = "2026-01-31T23:11:59.782Z" },
{ url = "https://files.pythonhosted.org/packages/6e/a4/a05c3a6418575e185dd84d0b9680b6bb2e2dc3e4202f036b7b4e22d6e9dc/numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1", size = 10290756, upload-time = "2026-01-31T23:12:02.438Z" },
{ url = "https://files.pythonhosted.org/packages/18/88/b7df6050bf18fdcfb7046286c6535cabbdd2064a3440fca3f069d319c16e/numpy-2.4.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b", size = 16663092, upload-time = "2026-01-31T23:12:04.521Z" },
{ url = "https://files.pythonhosted.org/packages/25/7a/1fee4329abc705a469a4afe6e69b1ef7e915117747886327104a8493a955/numpy-2.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000", size = 14698770, upload-time = "2026-01-31T23:12:06.96Z" },
{ url = "https://files.pythonhosted.org/packages/fb/0b/f9e49ba6c923678ad5bc38181c08ac5e53b7a5754dbca8e581aa1a56b1ff/numpy-2.4.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1", size = 5208562, upload-time = "2026-01-31T23:12:09.632Z" },
{ url = "https://files.pythonhosted.org/packages/7d/12/d7de8f6f53f9bb76997e5e4c069eda2051e3fe134e9181671c4391677bb2/numpy-2.4.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74", size = 6543710, upload-time = "2026-01-31T23:12:11.969Z" },
{ url = "https://files.pythonhosted.org/packages/09/63/c66418c2e0268a31a4cf8a8b512685748200f8e8e8ec6c507ce14e773529/numpy-2.4.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a", size = 15677205, upload-time = "2026-01-31T23:12:14.33Z" },
{ url = "https://files.pythonhosted.org/packages/5d/6c/7f237821c9642fb2a04d2f1e88b4295677144ca93285fd76eff3bcba858d/numpy-2.4.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325", size = 16611738, upload-time = "2026-01-31T23:12:16.525Z" },
{ url = "https://files.pythonhosted.org/packages/c2/a7/39c4cdda9f019b609b5c473899d87abff092fc908cfe4d1ecb2fcff453b0/numpy-2.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909", size = 17028888, upload-time = "2026-01-31T23:12:19.306Z" },
{ url = "https://files.pythonhosted.org/packages/da/b3/e84bb64bdfea967cc10950d71090ec2d84b49bc691df0025dddb7c26e8e3/numpy-2.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a", size = 18339556, upload-time = "2026-01-31T23:12:21.816Z" },
{ url = "https://files.pythonhosted.org/packages/88/f5/954a291bc1192a27081706862ac62bb5920fbecfbaa302f64682aa90beed/numpy-2.4.2-cp314-cp314-win32.whl", hash = "sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a", size = 6006899, upload-time = "2026-01-31T23:12:24.14Z" },
{ url = "https://files.pythonhosted.org/packages/05/cb/eff72a91b2efdd1bc98b3b8759f6a1654aa87612fc86e3d87d6fe4f948c4/numpy-2.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75", size = 12443072, upload-time = "2026-01-31T23:12:26.33Z" },
{ url = "https://files.pythonhosted.org/packages/37/75/62726948db36a56428fce4ba80a115716dc4fad6a3a4352487f8bb950966/numpy-2.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05", size = 10494886, upload-time = "2026-01-31T23:12:28.488Z" },
{ url = "https://files.pythonhosted.org/packages/36/2f/ee93744f1e0661dc267e4b21940870cabfae187c092e1433b77b09b50ac4/numpy-2.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308", size = 14818567, upload-time = "2026-01-31T23:12:30.709Z" },
{ url = "https://files.pythonhosted.org/packages/a7/24/6535212add7d76ff938d8bdc654f53f88d35cddedf807a599e180dcb8e66/numpy-2.4.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef", size = 5328372, upload-time = "2026-01-31T23:12:32.962Z" },
{ url = "https://files.pythonhosted.org/packages/5e/9d/c48f0a035725f925634bf6b8994253b43f2047f6778a54147d7e213bc5a7/numpy-2.4.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d", size = 6649306, upload-time = "2026-01-31T23:12:34.797Z" },
{ url = "https://files.pythonhosted.org/packages/81/05/7c73a9574cd4a53a25907bad38b59ac83919c0ddc8234ec157f344d57d9a/numpy-2.4.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8", size = 15722394, upload-time = "2026-01-31T23:12:36.565Z" },
{ url = "https://files.pythonhosted.org/packages/35/fa/4de10089f21fc7d18442c4a767ab156b25c2a6eaf187c0db6d9ecdaeb43f/numpy-2.4.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5", size = 16653343, upload-time = "2026-01-31T23:12:39.188Z" },
{ url = "https://files.pythonhosted.org/packages/b8/f9/d33e4ffc857f3763a57aa85650f2e82486832d7492280ac21ba9efda80da/numpy-2.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e", size = 17078045, upload-time = "2026-01-31T23:12:42.041Z" },
{ url = "https://files.pythonhosted.org/packages/c8/b8/54bdb43b6225badbea6389fa038c4ef868c44f5890f95dd530a218706da3/numpy-2.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a", size = 18380024, upload-time = "2026-01-31T23:12:44.331Z" },
{ url = "https://files.pythonhosted.org/packages/a5/55/6e1a61ded7af8df04016d81b5b02daa59f2ea9252ee0397cb9f631efe9e5/numpy-2.4.2-cp314-cp314t-win32.whl", hash = "sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443", size = 6153937, upload-time = "2026-01-31T23:12:47.229Z" },
{ url = "https://files.pythonhosted.org/packages/45/aa/fa6118d1ed6d776b0983f3ceac9b1a5558e80df9365b1c3aa6d42bf9eee4/numpy-2.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236", size = 12631844, upload-time = "2026-01-31T23:12:48.997Z" },
{ url = "https://files.pythonhosted.org/packages/32/0a/2ec5deea6dcd158f254a7b372fb09cfba5719419c8d66343bab35237b3fb/numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181", size = 10565379, upload-time = "2026-01-31T23:12:51.345Z" },
]
[[package]]
name = "packaging"
version = "26.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
]
[[package]]
name = "pages-uoregon-edu"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "matplotlib" },
{ name = "numpy" },
{ name = "scikit-image" },
{ name = "scipy" },
]
[package.dev-dependencies]
dev = [
{ name = "marimo" },
]
[package.metadata]
requires-dist = [
{ name = "matplotlib", specifier = ">=3.10.8" },
{ name = "numpy", specifier = ">=2.4.2" },
{ name = "scikit-image", specifier = ">=0.26.0" },
{ name = "scipy", specifier = ">=1.17.0" },
]
[package.metadata.requires-dev]
dev = [{ name = "marimo", specifier = ">=0.19.11" }]
[[package]]
name = "parso"
version = "0.8.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621, upload-time = "2026-02-09T15:45:24.425Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894, upload-time = "2026-02-09T15:45:21.391Z" },
]
[[package]]
name = "pillow"
version = "12.1.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" },
{ url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" },
{ url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" },
{ url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" },
{ url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" },
{ url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" },
{ url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" },
{ url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" },
{ url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" },
{ url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" },
{ url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" },
{ url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" },
{ url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" },
{ url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" },
{ url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" },
{ url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" },
{ url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" },
{ url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" },
{ url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" },
{ url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" },
{ url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" },
{ url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" },
{ url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" },
{ url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" },
{ url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" },
{ url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" },
{ url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" },
{ url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" },
{ url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" },
{ url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" },
{ url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" },
{ url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" },
{ url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" },
{ url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" },
{ url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" },
{ url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" },
{ url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" },
{ url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" },
{ url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" },
{ url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" },
{ url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" },
{ url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" },
{ url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" },
{ url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" },
{ url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" },
{ url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" },
{ url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" },
{ url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" },
{ url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" },
{ url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" },
]
[[package]]
name = "psutil"
version = "7.2.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" },
{ url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" },
{ url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" },
{ url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" },
{ url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" },
{ url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" },
{ url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" },
{ url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" },
{ url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" },
{ url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" },
{ url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" },
{ url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" },
{ url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" },
{ url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" },
{ url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" },
{ url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" },
{ url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" },
{ url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" },
{ url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" },
{ url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
]
[[package]]
name = "pygments"
version = "2.19.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
]
[[package]]
name = "pymdown-extensions"
version = "10.21"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ba/63/06673d1eb6d8f83c0ea1f677d770e12565fb516928b4109c9e2055656a9e/pymdown_extensions-10.21.tar.gz", hash = "sha256:39f4a020f40773f6b2ff31d2cd2546c2c04d0a6498c31d9c688d2be07e1767d5", size = 853363, upload-time = "2026-02-15T20:44:06.748Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6f/2c/5b079febdc65e1c3fb2729bf958d18b45be7113828528e8a0b5850dd819a/pymdown_extensions-10.21-py3-none-any.whl", hash = "sha256:91b879f9f864d49794c2d9534372b10150e6141096c3908a455e45ca72ad9d3f", size = 268877, upload-time = "2026-02-15T20:44:05.464Z" },
]
[[package]]
name = "pyparsing"
version = "3.3.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
]
[[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 = "pyyaml"
version = "6.0.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
{ url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
{ url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
{ url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
{ url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
{ url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
{ url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
{ url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
{ url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
{ url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
{ url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
{ url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
{ url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
]
[[package]]
name = "scikit-image"
version = "0.26.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "imageio" },
{ name = "lazy-loader" },
{ name = "networkx" },
{ name = "numpy" },
{ name = "packaging" },
{ name = "pillow" },
{ name = "scipy" },
{ name = "tifffile" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a1/b4/2528bb43c67d48053a7a649a9666432dc307d66ba02e3a6d5c40f46655df/scikit_image-0.26.0.tar.gz", hash = "sha256:f5f970ab04efad85c24714321fcc91613fcb64ef2a892a13167df2f3e59199fa", size = 22729739, upload-time = "2025-12-20T17:12:21.824Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4f/48/02357ffb2cca35640f33f2cfe054a4d6d5d7a229b88880a64f1e45c11f4e/scikit_image-0.26.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a2e852eccf41d2d322b8e60144e124802873a92b8d43a6f96331aa42888491c7", size = 12346329, upload-time = "2025-12-20T17:11:11.599Z" },
{ url = "https://files.pythonhosted.org/packages/67/b9/b792c577cea2c1e94cda83b135a656924fc57c428e8a6d302cd69aac1b60/scikit_image-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:98329aab3bc87db352b9887f64ce8cdb8e75f7c2daa19927f2e121b797b678d5", size = 12031726, upload-time = "2025-12-20T17:11:13.871Z" },
{ url = "https://files.pythonhosted.org/packages/07/a9/9564250dfd65cb20404a611016db52afc6268b2b371cd19c7538ea47580f/scikit_image-0.26.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:915bb3ba66455cf8adac00dc8fdf18a4cd29656aec7ddd38cb4dda90289a6f21", size = 13094910, upload-time = "2025-12-20T17:11:16.2Z" },
{ url = "https://files.pythonhosted.org/packages/a3/b8/0d8eeb5a9fd7d34ba84f8a55753a0a3e2b5b51b2a5a0ade648a8db4a62f7/scikit_image-0.26.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b36ab5e778bf50af5ff386c3ac508027dc3aaeccf2161bdf96bde6848f44d21b", size = 13660939, upload-time = "2025-12-20T17:11:18.464Z" },
{ url = "https://files.pythonhosted.org/packages/2f/d6/91d8973584d4793d4c1a847d388e34ef1218d835eeddecfc9108d735b467/scikit_image-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:09bad6a5d5949c7896c8347424c4cca899f1d11668030e5548813ab9c2865dcb", size = 14138938, upload-time = "2025-12-20T17:11:20.919Z" },
{ url = "https://files.pythonhosted.org/packages/39/9a/7e15d8dc10d6bbf212195fb39bdeb7f226c46dd53f9c63c312e111e2e175/scikit_image-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:aeb14db1ed09ad4bee4ceb9e635547a8d5f3549be67fc6c768c7f923e027e6cd", size = 14752243, upload-time = "2025-12-20T17:11:23.347Z" },
{ url = "https://files.pythonhosted.org/packages/8f/58/2b11b933097bc427e42b4a8b15f7de8f24f2bac1fd2779d2aea1431b2c31/scikit_image-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:ac529eb9dbd5954f9aaa2e3fe9a3fd9661bfe24e134c688587d811a0233127f1", size = 11906770, upload-time = "2025-12-20T17:11:25.297Z" },
{ url = "https://files.pythonhosted.org/packages/ad/ec/96941474a18a04b69b6f6562a5bd79bd68049fa3728d3b350976eccb8b93/scikit_image-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:a2d211bc355f59725efdcae699b93b30348a19416cc9e017f7b2fb599faf7219", size = 11342506, upload-time = "2025-12-20T17:11:27.399Z" },
{ url = "https://files.pythonhosted.org/packages/03/e5/c1a9962b0cf1952f42d32b4a2e48eed520320dbc4d2ff0b981c6fa508b6b/scikit_image-0.26.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9eefb4adad066da408a7601c4c24b07af3b472d90e08c3e7483d4e9e829d8c49", size = 12663278, upload-time = "2025-12-20T17:11:29.358Z" },
{ url = "https://files.pythonhosted.org/packages/ae/97/c1a276a59ce8e4e24482d65c1a3940d69c6b3873279193b7ebd04e5ee56b/scikit_image-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6caec76e16c970c528d15d1c757363334d5cb3069f9cea93d2bead31820511f3", size = 12405142, upload-time = "2025-12-20T17:11:31.282Z" },
{ url = "https://files.pythonhosted.org/packages/d4/4a/f1cbd1357caef6c7993f7efd514d6e53d8fd6f7fe01c4714d51614c53289/scikit_image-0.26.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a07200fe09b9d99fcdab959859fe0f7db8df6333d6204344425d476850ce3604", size = 12942086, upload-time = "2025-12-20T17:11:33.683Z" },
{ url = "https://files.pythonhosted.org/packages/5b/6f/74d9fb87c5655bd64cf00b0c44dc3d6206d9002e5f6ba1c9aeb13236f6bf/scikit_image-0.26.0-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92242351bccf391fc5df2d1529d15470019496d2498d615beb68da85fe7fdf37", size = 13265667, upload-time = "2025-12-20T17:11:36.11Z" },
{ url = "https://files.pythonhosted.org/packages/a7/73/faddc2413ae98d863f6fa2e3e14da4467dd38e788e1c23346cf1a2b06b97/scikit_image-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:52c496f75a7e45844d951557f13c08c81487c6a1da2e3c9c8a39fcde958e02cc", size = 14001966, upload-time = "2025-12-20T17:11:38.55Z" },
{ url = "https://files.pythonhosted.org/packages/02/94/9f46966fa042b5d57c8cd641045372b4e0df0047dd400e77ea9952674110/scikit_image-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:20ef4a155e2e78b8ab973998e04d8a361d49d719e65412405f4dadd9155a61d9", size = 14359526, upload-time = "2025-12-20T17:11:41.087Z" },
{ url = "https://files.pythonhosted.org/packages/5d/b4/2840fe38f10057f40b1c9f8fb98a187a370936bf144a4ac23452c5ef1baf/scikit_image-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:c9087cf7d0e7f33ab5c46d2068d86d785e70b05400a891f73a13400f1e1faf6a", size = 12287629, upload-time = "2025-12-20T17:11:43.11Z" },
{ url = "https://files.pythonhosted.org/packages/22/ba/73b6ca70796e71f83ab222690e35a79612f0117e5aaf167151b7d46f5f2c/scikit_image-0.26.0-cp313-cp313t-win_arm64.whl", hash = "sha256:27d58bc8b2acd351f972c6508c1b557cfed80299826080a4d803dd29c51b707e", size = 11647755, upload-time = "2025-12-20T17:11:45.279Z" },
{ url = "https://files.pythonhosted.org/packages/51/44/6b744f92b37ae2833fd423cce8f806d2368859ec325a699dc30389e090b9/scikit_image-0.26.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:63af3d3a26125f796f01052052f86806da5b5e54c6abef152edb752683075a9c", size = 12365810, upload-time = "2025-12-20T17:11:47.357Z" },
{ url = "https://files.pythonhosted.org/packages/40/f5/83590d9355191f86ac663420fec741b82cc547a4afe7c4c1d986bf46e4db/scikit_image-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ce00600cd70d4562ed59f80523e18cdcc1fae0e10676498a01f73c255774aefd", size = 12075717, upload-time = "2025-12-20T17:11:49.483Z" },
{ url = "https://files.pythonhosted.org/packages/72/48/253e7cf5aee6190459fe136c614e2cbccc562deceb4af96e0863f1b8ee29/scikit_image-0.26.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6381edf972b32e4f54085449afde64365a57316637496c1325a736987083e2ab", size = 13161520, upload-time = "2025-12-20T17:11:51.58Z" },
{ url = "https://files.pythonhosted.org/packages/73/c3/cec6a3cbaadfdcc02bd6ff02f3abfe09eaa7f4d4e0a525a1e3a3f4bce49c/scikit_image-0.26.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6624a76c6085218248154cc7e1500e6b488edcd9499004dd0d35040607d7505", size = 13684340, upload-time = "2025-12-20T17:11:53.708Z" },
{ url = "https://files.pythonhosted.org/packages/d4/0d/39a776f675d24164b3a267aa0db9f677a4cb20127660d8bf4fd7fef66817/scikit_image-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f775f0e420faac9c2aa6757135f4eb468fb7b70e0b67fa77a5e79be3c30ee331", size = 14203839, upload-time = "2025-12-20T17:11:55.89Z" },
{ url = "https://files.pythonhosted.org/packages/ee/25/2514df226bbcedfe9b2caafa1ba7bc87231a0c339066981b182b08340e06/scikit_image-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede4d6d255cc5da9faeb2f9ba7fedbc990abbc652db429f40a16b22e770bb578", size = 14770021, upload-time = "2025-12-20T17:11:58.014Z" },
{ url = "https://files.pythonhosted.org/packages/8d/5b/0671dc91c0c79340c3fe202f0549c7d3681eb7640fe34ab68a5f090a7c7f/scikit_image-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:0660b83968c15293fd9135e8d860053ee19500d52bf55ca4fb09de595a1af650", size = 12023490, upload-time = "2025-12-20T17:12:00.013Z" },
{ url = "https://files.pythonhosted.org/packages/65/08/7c4cb59f91721f3de07719085212a0b3962e3e3f2d1818cbac4eeb1ea53e/scikit_image-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:b8d14d3181c21c11170477a42542c1addc7072a90b986675a71266ad17abc37f", size = 11473782, upload-time = "2025-12-20T17:12:01.983Z" },
{ url = "https://files.pythonhosted.org/packages/49/41/65c4258137acef3d73cb561ac55512eacd7b30bb4f4a11474cad526bc5db/scikit_image-0.26.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:cde0bbd57e6795eba83cb10f71a677f7239271121dc950bc060482834a668ad1", size = 12686060, upload-time = "2025-12-20T17:12:03.886Z" },
{ url = "https://files.pythonhosted.org/packages/e7/32/76971f8727b87f1420a962406388a50e26667c31756126444baf6668f559/scikit_image-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:163e9afb5b879562b9aeda0dd45208a35316f26cc7a3aed54fd601604e5cf46f", size = 12422628, upload-time = "2025-12-20T17:12:05.921Z" },
{ url = "https://files.pythonhosted.org/packages/37/0d/996febd39f757c40ee7b01cdb861867327e5c8e5f595a634e8201462d958/scikit_image-0.26.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724f79fd9b6cb6f4a37864fe09f81f9f5d5b9646b6868109e1b100d1a7019e59", size = 12962369, upload-time = "2025-12-20T17:12:07.912Z" },
{ url = "https://files.pythonhosted.org/packages/48/b4/612d354f946c9600e7dea012723c11d47e8d455384e530f6daaaeb9bf62c/scikit_image-0.26.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3268f13310e6857508bd87202620df996199a016a1d281b309441d227c822394", size = 13272431, upload-time = "2025-12-20T17:12:10.255Z" },
{ url = "https://files.pythonhosted.org/packages/0a/6e/26c00b466e06055a086de2c6e2145fe189ccdc9a1d11ccc7de020f2591ad/scikit_image-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fac96a1f9b06cd771cbbb3cd96c5332f36d4efd839b1d8b053f79e5887acde62", size = 14016362, upload-time = "2025-12-20T17:12:12.793Z" },
{ url = "https://files.pythonhosted.org/packages/47/88/00a90402e1775634043c2a0af8a3c76ad450866d9fa444efcc43b553ba2d/scikit_image-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c1e7bd342f43e7a97e571b3f03ba4c1293ea1a35c3f13f41efdc8a81c1dc8f2", size = 14364151, upload-time = "2025-12-20T17:12:14.909Z" },
{ url = "https://files.pythonhosted.org/packages/da/ca/918d8d306bd43beacff3b835c6d96fac0ae64c0857092f068b88db531a7c/scikit_image-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b702c3bb115e1dcf4abf5297429b5c90f2189655888cbed14921f3d26f81d3a4", size = 12413484, upload-time = "2025-12-20T17:12:17.046Z" },
{ url = "https://files.pythonhosted.org/packages/dc/cd/4da01329b5a8d47ff7ec3c99a2b02465a8017b186027590dc7425cee0b56/scikit_image-0.26.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0608aa4a9ec39e0843de10d60edb2785a30c1c47819b67866dd223ebd149acaf", size = 11769501, upload-time = "2025-12-20T17:12:19.339Z" },
]
[[package]]
name = "scipy"
version = "1.17.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/56/3e/9cca699f3486ce6bc12ff46dc2031f1ec8eb9ccc9a320fdaf925f1417426/scipy-1.17.0.tar.gz", hash = "sha256:2591060c8e648d8b96439e111ac41fd8342fdeff1876be2e19dea3fe8930454e", size = 30396830, upload-time = "2026-01-10T21:34:23.009Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/51/3468fdfd49387ddefee1636f5cf6d03ce603b75205bf439bbf0e62069bfd/scipy-1.17.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:65ec32f3d32dfc48c72df4291345dae4f048749bc8d5203ee0a3f347f96c5ce6", size = 31344101, upload-time = "2026-01-10T21:26:30.25Z" },
{ url = "https://files.pythonhosted.org/packages/b2/9a/9406aec58268d437636069419e6977af953d1e246df941d42d3720b7277b/scipy-1.17.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:1f9586a58039d7229ce77b52f8472c972448cded5736eaf102d5658bbac4c269", size = 27950385, upload-time = "2026-01-10T21:26:36.801Z" },
{ url = "https://files.pythonhosted.org/packages/4f/98/e7342709e17afdfd1b26b56ae499ef4939b45a23a00e471dfb5375eea205/scipy-1.17.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9fad7d3578c877d606b1150135c2639e9de9cecd3705caa37b66862977cc3e72", size = 20122115, upload-time = "2026-01-10T21:26:42.107Z" },
{ url = "https://files.pythonhosted.org/packages/fd/0e/9eeeb5357a64fd157cbe0302c213517c541cc16b8486d82de251f3c68ede/scipy-1.17.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:423ca1f6584fc03936972b5f7c06961670dbba9f234e71676a7c7ccf938a0d61", size = 22442402, upload-time = "2026-01-10T21:26:48.029Z" },
{ url = "https://files.pythonhosted.org/packages/c9/10/be13397a0e434f98e0c79552b2b584ae5bb1c8b2be95db421533bbca5369/scipy-1.17.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe508b5690e9eaaa9467fc047f833af58f1152ae51a0d0aed67aa5801f4dd7d6", size = 32696338, upload-time = "2026-01-10T21:26:55.521Z" },
{ url = "https://files.pythonhosted.org/packages/63/1e/12fbf2a3bb240161651c94bb5cdd0eae5d4e8cc6eaeceb74ab07b12a753d/scipy-1.17.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6680f2dfd4f6182e7d6db161344537da644d1cf85cf293f015c60a17ecf08752", size = 34977201, upload-time = "2026-01-10T21:27:03.501Z" },
{ url = "https://files.pythonhosted.org/packages/19/5b/1a63923e23ccd20bd32156d7dd708af5bbde410daa993aa2500c847ab2d2/scipy-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eec3842ec9ac9de5917899b277428886042a93db0b227ebbe3a333b64ec7643d", size = 34777384, upload-time = "2026-01-10T21:27:11.423Z" },
{ url = "https://files.pythonhosted.org/packages/39/22/b5da95d74edcf81e540e467202a988c50fef41bd2011f46e05f72ba07df6/scipy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d7425fcafbc09a03731e1bc05581f5fad988e48c6a861f441b7ab729a49a55ea", size = 37379586, upload-time = "2026-01-10T21:27:20.171Z" },
{ url = "https://files.pythonhosted.org/packages/b9/b6/8ac583d6da79e7b9e520579f03007cb006f063642afd6b2eeb16b890bf93/scipy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:87b411e42b425b84777718cc41516b8a7e0795abfa8e8e1d573bf0ef014f0812", size = 36287211, upload-time = "2026-01-10T21:28:43.122Z" },
{ url = "https://files.pythonhosted.org/packages/55/fb/7db19e0b3e52f882b420417644ec81dd57eeef1bd1705b6f689d8ff93541/scipy-1.17.0-cp313-cp313-win_arm64.whl", hash = "sha256:357ca001c6e37601066092e7c89cca2f1ce74e2a520ca78d063a6d2201101df2", size = 24312646, upload-time = "2026-01-10T21:28:49.893Z" },
{ url = "https://files.pythonhosted.org/packages/20/b6/7feaa252c21cc7aff335c6c55e1b90ab3e3306da3f048109b8b639b94648/scipy-1.17.0-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:ec0827aa4d36cb79ff1b81de898e948a51ac0b9b1c43e4a372c0508c38c0f9a3", size = 31693194, upload-time = "2026-01-10T21:27:27.454Z" },
{ url = "https://files.pythonhosted.org/packages/76/bb/bbb392005abce039fb7e672cb78ac7d158700e826b0515cab6b5b60c26fb/scipy-1.17.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:819fc26862b4b3c73a60d486dbb919202f3d6d98c87cf20c223511429f2d1a97", size = 28365415, upload-time = "2026-01-10T21:27:34.26Z" },
{ url = "https://files.pythonhosted.org/packages/37/da/9d33196ecc99fba16a409c691ed464a3a283ac454a34a13a3a57c0d66f3a/scipy-1.17.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:363ad4ae2853d88ebcde3ae6ec46ccca903ea9835ee8ba543f12f575e7b07e4e", size = 20537232, upload-time = "2026-01-10T21:27:40.306Z" },
{ url = "https://files.pythonhosted.org/packages/56/9d/f4b184f6ddb28e9a5caea36a6f98e8ecd2a524f9127354087ce780885d83/scipy-1.17.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:979c3a0ff8e5ba254d45d59ebd38cde48fce4f10b5125c680c7a4bfe177aab07", size = 22791051, upload-time = "2026-01-10T21:27:46.539Z" },
{ url = "https://files.pythonhosted.org/packages/9b/9d/025cccdd738a72140efc582b1641d0dd4caf2e86c3fb127568dc80444e6e/scipy-1.17.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:130d12926ae34399d157de777472bf82e9061c60cc081372b3118edacafe1d00", size = 32815098, upload-time = "2026-01-10T21:27:54.389Z" },
{ url = "https://files.pythonhosted.org/packages/48/5f/09b879619f8bca15ce392bfc1894bd9c54377e01d1b3f2f3b595a1b4d945/scipy-1.17.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e886000eb4919eae3a44f035e63f0fd8b651234117e8f6f29bad1cd26e7bc45", size = 35031342, upload-time = "2026-01-10T21:28:03.012Z" },
{ url = "https://files.pythonhosted.org/packages/f2/9a/f0f0a9f0aa079d2f106555b984ff0fbb11a837df280f04f71f056ea9c6e4/scipy-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:13c4096ac6bc31d706018f06a49abe0485f96499deb82066b94d19b02f664209", size = 34893199, upload-time = "2026-01-10T21:28:10.832Z" },
{ url = "https://files.pythonhosted.org/packages/90/b8/4f0f5cf0c5ea4d7548424e6533e6b17d164f34a6e2fb2e43ffebb6697b06/scipy-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cacbaddd91fcffde703934897c5cd2c7cb0371fac195d383f4e1f1c5d3f3bd04", size = 37438061, upload-time = "2026-01-10T21:28:19.684Z" },
{ url = "https://files.pythonhosted.org/packages/f9/cc/2bd59140ed3b2fa2882fb15da0a9cb1b5a6443d67cfd0d98d4cec83a57ec/scipy-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:edce1a1cf66298cccdc48a1bdf8fb10a3bf58e8b58d6c3883dd1530e103f87c0", size = 36328593, upload-time = "2026-01-10T21:28:28.007Z" },
{ url = "https://files.pythonhosted.org/packages/13/1b/c87cc44a0d2c7aaf0f003aef2904c3d097b422a96c7e7c07f5efd9073c1b/scipy-1.17.0-cp313-cp313t-win_arm64.whl", hash = "sha256:30509da9dbec1c2ed8f168b8d8aa853bc6723fede1dbc23c7d43a56f5ab72a67", size = 24625083, upload-time = "2026-01-10T21:28:35.188Z" },
{ url = "https://files.pythonhosted.org/packages/1a/2d/51006cd369b8e7879e1c630999a19d1fbf6f8b5ed3e33374f29dc87e53b3/scipy-1.17.0-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:c17514d11b78be8f7e6331b983a65a7f5ca1fd037b95e27b280921fe5606286a", size = 31346803, upload-time = "2026-01-10T21:28:57.24Z" },
{ url = "https://files.pythonhosted.org/packages/d6/2e/2349458c3ce445f53a6c93d4386b1c4c5c0c540917304c01222ff95ff317/scipy-1.17.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:4e00562e519c09da34c31685f6acc3aa384d4d50604db0f245c14e1b4488bfa2", size = 27967182, upload-time = "2026-01-10T21:29:04.107Z" },
{ url = "https://files.pythonhosted.org/packages/5e/7c/df525fbfa77b878d1cfe625249529514dc02f4fd5f45f0f6295676a76528/scipy-1.17.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f7df7941d71314e60a481e02d5ebcb3f0185b8d799c70d03d8258f6c80f3d467", size = 20139125, upload-time = "2026-01-10T21:29:10.179Z" },
{ url = "https://files.pythonhosted.org/packages/33/11/fcf9d43a7ed1234d31765ec643b0515a85a30b58eddccc5d5a4d12b5f194/scipy-1.17.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:aabf057c632798832f071a8dde013c2e26284043934f53b00489f1773b33527e", size = 22443554, upload-time = "2026-01-10T21:29:15.888Z" },
{ url = "https://files.pythonhosted.org/packages/80/5c/ea5d239cda2dd3d31399424967a24d556cf409fbea7b5b21412b0fd0a44f/scipy-1.17.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a38c3337e00be6fd8a95b4ed66b5d988bac4ec888fd922c2ea9fe5fb1603dd67", size = 32757834, upload-time = "2026-01-10T21:29:23.406Z" },
{ url = "https://files.pythonhosted.org/packages/b8/7e/8c917cc573310e5dc91cbeead76f1b600d3fb17cf0969db02c9cf92e3cfa/scipy-1.17.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00fb5f8ec8398ad90215008d8b6009c9db9fa924fd4c7d6be307c6f945f9cd73", size = 34995775, upload-time = "2026-01-10T21:29:31.915Z" },
{ url = "https://files.pythonhosted.org/packages/c5/43/176c0c3c07b3f7df324e7cdd933d3e2c4898ca202b090bd5ba122f9fe270/scipy-1.17.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f2a4942b0f5f7c23c7cd641a0ca1955e2ae83dedcff537e3a0259096635e186b", size = 34841240, upload-time = "2026-01-10T21:29:39.995Z" },
{ url = "https://files.pythonhosted.org/packages/44/8c/d1f5f4b491160592e7f084d997de53a8e896a3ac01cd07e59f43ca222744/scipy-1.17.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf133ced83889583156566d2bdf7a07ff89228fe0c0cb727f777de92092ec6b", size = 37394463, upload-time = "2026-01-10T21:29:48.723Z" },
{ url = "https://files.pythonhosted.org/packages/9f/ec/42a6657f8d2d087e750e9a5dde0b481fd135657f09eaf1cf5688bb23c338/scipy-1.17.0-cp314-cp314-win_amd64.whl", hash = "sha256:3625c631a7acd7cfd929e4e31d2582cf00f42fcf06011f59281271746d77e061", size = 37053015, upload-time = "2026-01-10T21:30:51.418Z" },
{ url = "https://files.pythonhosted.org/packages/27/58/6b89a6afd132787d89a362d443a7bddd511b8f41336a1ae47f9e4f000dc4/scipy-1.17.0-cp314-cp314-win_arm64.whl", hash = "sha256:9244608d27eafe02b20558523ba57f15c689357c85bdcfe920b1828750aa26eb", size = 24951312, upload-time = "2026-01-10T21:30:56.771Z" },
{ url = "https://files.pythonhosted.org/packages/e9/01/f58916b9d9ae0112b86d7c3b10b9e685625ce6e8248df139d0fcb17f7397/scipy-1.17.0-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:2b531f57e09c946f56ad0b4a3b2abee778789097871fc541e267d2eca081cff1", size = 31706502, upload-time = "2026-01-10T21:29:56.326Z" },
{ url = "https://files.pythonhosted.org/packages/59/8e/2912a87f94a7d1f8b38aabc0faf74b82d3b6c9e22be991c49979f0eceed8/scipy-1.17.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:13e861634a2c480bd237deb69333ac79ea1941b94568d4b0efa5db5e263d4fd1", size = 28380854, upload-time = "2026-01-10T21:30:01.554Z" },
{ url = "https://files.pythonhosted.org/packages/bd/1c/874137a52dddab7d5d595c1887089a2125d27d0601fce8c0026a24a92a0b/scipy-1.17.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:eb2651271135154aa24f6481cbae5cc8af1f0dd46e6533fb7b56aa9727b6a232", size = 20552752, upload-time = "2026-01-10T21:30:05.93Z" },
{ url = "https://files.pythonhosted.org/packages/3f/f0/7518d171cb735f6400f4576cf70f756d5b419a07fe1867da34e2c2c9c11b/scipy-1.17.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:c5e8647f60679790c2f5c76be17e2e9247dc6b98ad0d3b065861e082c56e078d", size = 22803972, upload-time = "2026-01-10T21:30:10.651Z" },
{ url = "https://files.pythonhosted.org/packages/7c/74/3498563a2c619e8a3ebb4d75457486c249b19b5b04a30600dfd9af06bea5/scipy-1.17.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fb10d17e649e1446410895639f3385fd2bf4c3c7dfc9bea937bddcbc3d7b9ba", size = 32829770, upload-time = "2026-01-10T21:30:16.359Z" },
{ url = "https://files.pythonhosted.org/packages/48/d1/7b50cedd8c6c9d6f706b4b36fa8544d829c712a75e370f763b318e9638c1/scipy-1.17.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8547e7c57f932e7354a2319fab613981cde910631979f74c9b542bb167a8b9db", size = 35051093, upload-time = "2026-01-10T21:30:22.987Z" },
{ url = "https://files.pythonhosted.org/packages/e2/82/a2d684dfddb87ba1b3ea325df7c3293496ee9accb3a19abe9429bce94755/scipy-1.17.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33af70d040e8af9d5e7a38b5ed3b772adddd281e3062ff23fec49e49681c38cf", size = 34909905, upload-time = "2026-01-10T21:30:28.704Z" },
{ url = "https://files.pythonhosted.org/packages/ef/5e/e565bd73991d42023eb82bb99e51c5b3d9e2c588ca9d4b3e2cc1d3ca62a6/scipy-1.17.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb55bb97d00f8b7ab95cb64f873eb0bf54d9446264d9f3609130381233483f", size = 37457743, upload-time = "2026-01-10T21:30:34.819Z" },
{ url = "https://files.pythonhosted.org/packages/58/a8/a66a75c3d8f1fb2b83f66007d6455a06a6f6cf5618c3dc35bc9b69dd096e/scipy-1.17.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1ff269abf702f6c7e67a4b7aad981d42871a11b9dd83c58d2d2ea624efbd1088", size = 37098574, upload-time = "2026-01-10T21:30:40.782Z" },
{ url = "https://files.pythonhosted.org/packages/56/a5/df8f46ef7da168f1bc52cd86e09a9de5c6f19cc1da04454d51b7d4f43408/scipy-1.17.0-cp314-cp314t-win_arm64.whl", hash = "sha256:031121914e295d9791319a1875444d55079885bbae5bdc9c5e0f2ee5f09d34ff", size = 25246266, upload-time = "2026-01-10T21:30:45.923Z" },
]
[[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 = "starlette"
version = "0.52.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
]
[[package]]
name = "tifffile"
version = "2026.2.20"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/90/80/0ddd8dc74c22e1e5efcfb152303b025f8f4a5010ae9936f1e57f7d7f9256/tifffile-2026.2.20.tar.gz", hash = "sha256:b98a7fc6ea4fa0e9919734857eebc6e2cb2c3a95468a930d4a948a9a49646ab7", size = 377196, upload-time = "2026-02-20T20:09:34.608Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/86/07/0cd5cad2fdb7d32515561bc26da041654f3b3c0abc299f4730f30b89271d/tifffile-2026.2.20-py3-none-any.whl", hash = "sha256:a83e0e991647e39d5912369998ef02d858f89effe30064403a1a123b5daef8fb", size = 234528, upload-time = "2026-02-20T20:09:33.278Z" },
]
[[package]]
name = "tomlkit"
version = "0.14.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c3/af/14b24e41977adb296d6bd1fb59402cf7d60ce364f90c890bd2ec65c43b5a/tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064", size = 187167, upload-time = "2026-01-13T01:14:53.304Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b5/11/87d6d29fb5d237229d67973a6c9e06e048f01cf4994dee194ab0ea841814/tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680", size = 39310, upload-time = "2026-01-13T01:14:51.965Z" },
]
[[package]]
name = "uvicorn"
version = "0.40.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "h11" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" },
]
[[package]]
name = "websockets"
version = "16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" },
{ url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" },
{ url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" },
{ url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" },
{ url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" },
{ url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" },
{ url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" },
{ url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" },
{ url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" },
{ url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" },
{ url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" },
{ url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" },
{ url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" },
{ url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" },
{ url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" },
{ url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" },
{ url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" },
{ url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" },
{ url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" },
{ url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" },
{ url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" },
{ url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" },
{ url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" },
{ url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" },
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
]