chore: remove legacy Zola site and superseded files

The Astro app in apps/site is now the production build (root Dockerfile
already builds it, not `zola build`), so the old Zola templates, Sass,
static assets, and build tooling are dead weight:

- templates/, sass/, static/, themes/, zola.toml, Makefile, bin/update-zola
- content/posts/ (fully migrated to content/writings/) and the legacy
  content/archive, content/about.md, content/_index.md pages
- legacy OG-image/llms.txt generation scripts (superseded by the
  *.astro-site.mjs versions apps/site's build already uses)
- unrelated stray files (manimations/, build.sh)

Also drops apps/site/src/pages/search.astro, replaced by the search modal,
and swaps in the real favicon.ico.
This commit is contained in:
2026-09-12 20:38:20 +03:00
parent d958a298f7
commit ffc3b6f353
128 changed files with 0 additions and 211028 deletions
-3
View File
@@ -1,3 +0,0 @@
{
"snyk.advanced.autoSelectOrganization": true
}
-21
View File
@@ -1,21 +0,0 @@
#!/usr/bin/make -f
.PHONY: all build
BUILD_DIR := public
all: clean build
clean:
rm -rfd ./$(BUILD_DIR)
build:
node scripts/generate-llms.mjs
zola build
serve:
node scripts/generate-llms.mjs
zola serve
update-zola:
@./bin/update-zola
Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 2.9 KiB

-9
View File
@@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
<style>
path { fill: #000; }
@media (prefers-color-scheme: dark) {
path { fill: #FFF; }
}
</style>
</svg>

Before

Width:  |  Height:  |  Size: 749 B

-22
View File
@@ -1,22 +0,0 @@
---
import Base from "../layouts/Base.astro";
---
<Base title="Search">
<h1>Search</h1>
<p class="meta">
Search only works against a built site (`pnpm build` runs Pagefind after
`astro build`) — it has no index to query in `astro dev`.
</p>
<div id="search"></div>
<link href="/pagefind/pagefind-ui.css" rel="stylesheet" />
<script is:inline src="/pagefind/pagefind-ui.js"></script>
<script is:inline>
window.addEventListener("DOMContentLoaded", () => {
if (window.PagefindUI) {
// biome-ignore lint/correctness/noUndeclaredVariables: loaded from /pagefind/pagefind-ui.js above
new PagefindUI({ element: "#search", showSubResults: true });
}
});
</script>
</Base>
-62
View File
@@ -1,62 +0,0 @@
#!/usr/bin/env sh
set -e
: ${ZOLA_REPO='https://github.com/getzola/zola'}
: ${ZOLA_INSTALL_DIR="${HOME}/.cargo/bin"}
# Helpers for ANSI color and logging.
name="$(basename $0)"; esc=''; reset="${esc}[0m"
red() { local string="${1}"; echo "${esc}[31m${string}${reset}"; }
yellow() { local string="${1}"; echo "${esc}[33m${string}${reset}"; }
green() { local string="${1}"; echo "${esc}[32m${string}${reset}"; }
blue() { local string="${1}"; echo "${esc}[34m${string}${reset}"; }
magenta() { local string="${1}"; echo "${esc}[35m${string}${reset}"; }
log() { local string="${1}"; echo "[$(blue $name)] ${string}"; }
prompt_for_update() {
local current="${1}"
local latest="${2}"
[ -n "${current}" ] \
&& installed="You're using Zola $(yellow $current)" \
|| installed="Zola is $(red 'not installed')"
log "${installed}, but $(magenta $latest) is available."
# Prompt for an update. Exit the entire script if declined.
read -p "$(log "Would you like to install Zola $(magenta $latest)? [y/N]: ")" answer
case $answer in
[Yy]*) log "Downloading Zola $(magenta $latest) from GitHub." ;;
[Nn]*|*) log $(red "Aborted!"); exit ;;
esac
}
install_zola() {
local version="${1}"
local download_url="${ZOLA_REPO}/releases/download/${version}/zola-${version}-x86_64-unknown-linux-gnu.tar.gz"
curl --progress-bar --location $download_url | tar --gunzip --extract --directory=$ZOLA_INSTALL_DIR --file -
}
update_zola() {
# Find the current Zola version (if any).
[ -n "$(which zola 2> /dev/null)" ] && current_version=$(zola --version | awk '{print "v"$2}')
# Find the latest available Zola version. Use --refs to avoid listing
# annotated commit objects that include the dereference syntax '^{}'.
# Find more background at https://stackoverflow.com/a/15472310.
local latest_version=$(git ls-remote --tags --refs $ZOLA_REPO | # Fetch remote tags.
sort -t '/' -k 3 -V | # Sort them by version.
tail -n 1 | # Take the latest one.
awk -F / '{print $3}') # Return only the tag.
if [ "${current_version}" != "${latest_version}" ]; then
prompt_for_update "${current_version}" "${latest_version}"
install_zola "${latest_version}"
fi
log "You're using Zola $(magenta $latest_version). $(green "Everything is up-to-date!")"
}
update_zola
-17
View File
@@ -1,17 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ZOLA_VERSION=0.23.1
echo "Downloading Zola ${ZOLA_VERSION}..."
curl -sLJO "https://github.com/getzola/zola/releases/download/v${ZOLA_VERSION}/zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
echo "Extracting Zola..."
tar -xf zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz
echo "Building site with Zola..."
node scripts/generate-llms.mjs
./zola build
echo "Build complete! Generated files:"
ls -la public/
@@ -1,15 +0,0 @@
+++
title = "Why This Site Exists"
description = "A short note on what this new site is, and why it's more than a tech blog."
author = "andwati"
date = 2026-08-30
draft = false
[taxonomies]
tags = ["meta"]
[extra]
llms_description = "An introductory post explaining the purpose of this personal digital-legacy site."
+++
This is a placeholder post establishing the `writings` content schema. It will
be replaced once the design system and migration from the old Zola posts are
ready.
-136
View File
@@ -1,136 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
*.log
# Sphinx documentation
docs/_build/
docs/build/
docs/source/_autosummary/
docs/source/reference/
docs/source/_build/
docs/rendering_times.csv
#i18n
docs/i18n/gettext/.doctrees
docs/i18n/**/*.mo
docs/i18n/translatable.po
docs/i18n/untranslatable.po
# PyBuilder
target/
# Jupyter Notebook
jupyter/
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# PyCharm
/.idea/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
*.pyc
*.bak
.DS_Store
.floo
.flooignore
.vscode
.vs
*.xml
*.iml
media
.eggs/
build/
dist/
/media_dir.txt
# ^TODO: Remove the need for this with a proper config file
# Ignore the built dependencies
third_party/*
View File
-579
View File
@@ -1,579 +0,0 @@
from manim import *
# ─────────────────────────────────────────────
# Shared palette
# ─────────────────────────────────────────────
BG = "#0d1117"
ACCENT = "#58a6ff"
GREEN = "#3fb950"
ORANGE = "#f0883e"
RED = "#f85149"
PURPLE = "#bc8cff"
GRAY = "#8b949e"
WHITE = "#e6edf3"
config.background_color = BG
# ─────────────────────────────────────────────
# Helper: section title card
# ─────────────────────────────────────────────
def title_card(scene: Scene, title: str, subtitle: str = ""):
bg = Rectangle(width=14, height=8, fill_color=BG, fill_opacity=1, stroke_width=0)
bar = Line(LEFT * 6, RIGHT * 6, color=ACCENT, stroke_width=3)
t = Text(title, font="JetBrains Mono", color=WHITE, font_size=52, weight=BOLD)
s = Text(subtitle, font="JetBrains Mono", color=GRAY, font_size=28) if subtitle else VMobject()
t.move_to(UP * 0.4)
s.next_to(t, DOWN, buff=0.4)
bar.next_to(t, UP, buff=0.55)
grp = VGroup(bg, bar, t, s)
scene.play(FadeIn(bar), Write(t), FadeIn(s), run_time=1.4)
scene.wait(1.5)
scene.play(FadeOut(grp), run_time=0.6)
# ─────────────────────────────────────────────
# 1. Intro
# ─────────────────────────────────────────────
class S01_Intro(Scene):
def construct(self):
# Animated headline
headline = Text("From C to Machine Code", font="JetBrains Mono",
color=ACCENT, font_size=56, weight=BOLD)
sub = Text("What Actually Runs", font="JetBrains Mono",
color=WHITE, font_size=34)
byline = Text("mockingspectre", font="JetBrains Mono",
color=GRAY, font_size=22)
headline.move_to(UP * 1.2)
sub.next_to(headline, DOWN, buff=0.5)
byline.next_to(sub, DOWN, buff=0.7)
accent_line = Line(LEFT * 3.5, RIGHT * 3.5, color=ACCENT, stroke_width=2)
accent_line.next_to(sub, DOWN, buff=0.3)
self.play(Write(headline), run_time=1.6)
self.play(FadeIn(sub, shift=UP * 0.3), run_time=0.9)
self.play(GrowFromCenter(accent_line), run_time=0.6)
self.play(FadeIn(byline), run_time=0.7)
self.wait(2.5)
# C → ASM → Binary flow diagram
c_box = self._box("C Source", GREEN, LEFT * 4.5)
asm_box = self._box("Assembly", ORANGE, ORIGIN)
bin_box = self._box("Machine\nCode", RED, RIGHT * 4.5)
arr1 = Arrow(c_box.get_right(), asm_box.get_left(), color=ACCENT, buff=0.15)
arr2 = Arrow(asm_box.get_right(), bin_box.get_left(), color=ACCENT, buff=0.15)
lbl1 = Text("GCC compiler", font="JetBrains Mono", color=GRAY, font_size=18).next_to(arr1, UP, buff=0.1)
lbl2 = Text("assemble", font="JetBrains Mono", color=GRAY, font_size=18).next_to(arr2, UP, buff=0.1)
self.play(FadeOut(headline, sub, accent_line, byline), run_time=0.5)
self.play(FadeIn(c_box), run_time=0.5)
self.play(GrowArrow(arr1), FadeIn(lbl1), run_time=0.7)
self.play(FadeIn(asm_box), run_time=0.5)
self.play(GrowArrow(arr2), FadeIn(lbl2), run_time=0.7)
self.play(FadeIn(bin_box), run_time=0.5)
self.wait(2.5)
self.play(*[FadeOut(m) for m in self.mobjects])
@staticmethod
def _box(label, color, pos):
rect = RoundedRectangle(corner_radius=0.2, width=2.6, height=1.1,
fill_color=color, fill_opacity=0.15,
stroke_color=color, stroke_width=2)
txt = Text(label, font="JetBrains Mono", color=color, font_size=24)
grp = VGroup(rect, txt).move_to(pos)
return grp
# ─────────────────────────────────────────────
# 2. Hello World: C → Assembly walkthrough
# ─────────────────────────────────────────────
class S02_HelloWorld(Scene):
def construct(self):
title_card(self, "Hello World", "C → Assembly")
# Left: C code
c_src = [
("#include <stdio.h>", GRAY),
("", WHITE),
("int main(){", WHITE),
(' printf("hello world\\n");', GREEN),
(" return 0;", WHITE),
("}", WHITE),
]
c_lines = VGroup(*[
Text(line, font="JetBrains Mono", color=col, font_size=20)
for line, col in c_src
])
c_lines.arrange(DOWN, aligned_edge=LEFT, buff=0.18)
c_bg = BackgroundRectangle(c_lines, color="#161b22", fill_opacity=1,
buff=0.25, corner_radius=0.15)
c_code = VGroup(c_bg, c_lines).shift(LEFT * 3.4 + UP * 0.5)
c_label = Text("hello.c", font="JetBrains Mono", color=GREEN, font_size=22
).next_to(c_code, UP, buff=0.2)
self.play(FadeIn(c_label), FadeIn(c_code), run_time=1.0)
self.wait(0.8)
# Command
cmd_txt = Text("gcc -o hello hello.c && objdump -d -M intel hello",
font="JetBrains Mono", color=ORANGE, font_size=17
).shift(DOWN * 2.8)
self.play(Write(cmd_txt), run_time=1.2)
self.wait(0.5)
# Right: ASM output
asm_lines = [
("1139:", "55", "push rbp"),
("113a:", "48 89 e5", "mov rbp, rsp"),
("113d:", "48 8d 05 c0 0e", "lea rax, [rip+0xec0]"),
("1144:", "48 89 c7", "mov rdi, rax"),
("1147:", "e8 e4 fe ff ff", "call puts@plt"),
("114c:", "b8 00 00 00 00", "mov eax, 0x0"),
("1151:", "5d", "pop rbp"),
("1152:", "c3", "ret"),
]
asm_group = self._asm_block(asm_lines).shift(RIGHT * 3.1 + UP * 0.5)
asm_label = Text("objdump output", font="JetBrains Mono",
color=ORANGE, font_size=22).next_to(asm_group, UP, buff=0.2)
self.play(FadeIn(asm_label), FadeIn(asm_group), run_time=1.0)
self.wait(0.5)
# Annotate key lines — asm_group[0]=bg, asm_group[1]=VGroup of rows
rows = asm_group[1]
note = Text("rdi ← pointer to \"hello world\"",
font="JetBrains Mono", color=ACCENT, font_size=19
).next_to(asm_group, DOWN, buff=0.25)
self.play(rows[3].animate.set_color(ACCENT),
rows[4].animate.set_color(PURPLE),
Write(note), run_time=1.0)
self.wait(2.5)
self.play(*[FadeOut(m) for m in self.mobjects])
@staticmethod
def _asm_block(lines):
rows = VGroup()
for addr, hex_b, mnemonic in lines:
row = Text(f"{addr:<8} {hex_b:<20} {mnemonic}",
font="JetBrains Mono", color=WHITE, font_size=17)
rows.add(row)
rows.arrange(DOWN, aligned_edge=LEFT, buff=0.18)
bg = BackgroundRectangle(rows, color="#161b22", fill_opacity=1,
buff=0.2, corner_radius=0.15)
return VGroup(bg, rows)
# ─────────────────────────────────────────────
# 3. Registers
# ─────────────────────────────────────────────
class S03_Registers(Scene):
def construct(self):
title_card(self, "Registers", "The CPU's Workbench")
# Register diagram: rax broken into sub-registers
regs = [
("rax (64-bit / 8 bytes)", ACCENT, 4.8),
("eax (32-bit / 4 bytes)", GREEN, 3.2),
("ax (16-bit / 2 bytes)", ORANGE, 1.9),
("al ( 8-bit / 1 byte )", RED, 0.95),
]
bars = VGroup()
labels = VGroup()
for name, color, width in regs:
bar = Rectangle(width=width, height=0.52,
fill_color=color, fill_opacity=0.25,
stroke_color=color, stroke_width=2)
lbl = Text(name, font="JetBrains Mono", color=color, font_size=19)
lbl.next_to(bar, RIGHT, buff=0.25)
bars.add(bar)
labels.add(lbl)
for i, bar in enumerate(bars):
bar.align_to(bars[0], LEFT)
group = VGroup(*[VGroup(bars[i], labels[i]) for i in range(len(bars))])
group.arrange(DOWN, aligned_edge=LEFT, buff=0.22).shift(LEFT * 1 + UP * 0.5)
self.play(LaggedStart(*[FadeIn(g) for g in group], lag_ratio=0.3), run_time=1.6)
self.wait(1.0)
caption = Text("Smaller aliases point into the same physical register",
font="JetBrains Mono", color=GRAY, font_size=21
).shift(DOWN * 2.6)
self.play(Write(caption))
self.wait(1.5)
self.play(FadeOut(group, caption))
# Calling convention diagram
title_card(self, "Calling Convention", "Argument passing in x64 Linux")
args = [
("1st arg", "rdi", ACCENT),
("2nd arg", "rsi", GREEN),
("3rd arg", "rdx", ORANGE),
("4th arg", "rcx", PURPLE),
("5th arg", "r8", RED),
("6th arg", "r9", GRAY),
]
cols = VGroup()
for label, reg, color in args:
arg_t = Text(label, font="JetBrains Mono", color=WHITE, font_size=22)
arr = Arrow(LEFT * 0.1, RIGHT * 0.9, color=color, buff=0)
reg_t = Text(reg, font="JetBrains Mono", color=color,
font_size=26, weight=BOLD)
row = VGroup(arg_t, arr, reg_t).arrange(RIGHT, buff=0.3)
cols.add(row)
cols.arrange(DOWN, buff=0.28).shift(UP * 0.3)
ret_row = Text("return value → rax", font="JetBrains Mono",
color=ACCENT, font_size=24).next_to(cols, DOWN, buff=0.5)
self.play(LaggedStart(*[FadeIn(r) for r in cols], lag_ratio=0.22), run_time=1.8)
self.play(Write(ret_row))
self.wait(2.5)
self.play(*[FadeOut(m) for m in self.mobjects])
# ─────────────────────────────────────────────
# 4. The Stack
# ─────────────────────────────────────────────
class S04_Stack(Scene):
def construct(self):
title_card(self, "The Stack", "LIFO — Last In, First Out")
# Animated stack push/pop
stack_slots = VGroup()
slot_labels = []
N = 6
for i in range(N):
rect = Rectangle(width=3.2, height=0.72,
fill_color="#161b22", fill_opacity=1,
stroke_color=GRAY, stroke_width=1.5)
stack_slots.add(rect)
stack_slots.arrange(DOWN, buff=0).shift(LEFT * 3 + UP * 0.5)
self.play(FadeIn(stack_slots))
# Labels: lower address at top
addr_labels = VGroup()
for i, slot in enumerate(stack_slots):
a = Text(f"0x...{(0x28 - i*8):02x}", font="JetBrains Mono",
color=GRAY, font_size=16)
a.next_to(slot, RIGHT, buff=0.15)
addr_labels.add(a)
self.play(FadeIn(addr_labels))
# rsp / rbp pointers
rbp_ptr = Arrow(RIGHT * 0.8, stack_slots[-1].get_right() + LEFT * 0.01,
color=ORANGE, buff=0.05)
rbp_lbl = Text("rbp", font="JetBrains Mono", color=ORANGE,
font_size=22, weight=BOLD).next_to(rbp_ptr, RIGHT, buff=0.1)
rsp_ptr = Arrow(RIGHT * 0.8, stack_slots[-1].get_right() + LEFT * 0.01,
color=ACCENT, buff=0.05)
rsp_lbl = Text("rsp", font="JetBrains Mono", color=ACCENT,
font_size=22, weight=BOLD).next_to(rsp_ptr, RIGHT, buff=0.1)
self.play(FadeIn(rbp_ptr, rbp_lbl))
# Push simulation: fill slots from bottom up
push_values = ["saved rbp", "local: x=5", "saved rip", "arg 1", "arg 2"]
colors_ = [ORANGE, GREEN, RED, ACCENT, PURPLE]
current_top = N - 1
for val, col in zip(push_values, colors_):
slot = stack_slots[current_top]
fill = Rectangle(width=3.2, height=0.72,
fill_color=col, fill_opacity=0.22,
stroke_color=col, stroke_width=1.5)
fill.move_to(slot)
txt = Text(val, font="JetBrains Mono", color=col, font_size=18)
txt.move_to(slot)
rsp_ptr.put_start_and_end_on(
RIGHT * 0.8, stack_slots[current_top].get_right() + LEFT * 0.01)
rsp_lbl.next_to(rsp_ptr, RIGHT, buff=0.1)
if current_top == N - 1:
self.play(FadeIn(rsp_ptr, rsp_lbl))
self.play(FadeIn(fill), Write(txt), run_time=0.55)
current_top -= 1
if current_top >= 0:
new_end = stack_slots[current_top].get_right() + LEFT * 0.01
self.play(rsp_ptr.animate.put_start_and_end_on(RIGHT * 0.8, new_end),
rsp_lbl.animate.next_to(rsp_ptr, RIGHT, buff=0.1),
run_time=0.4)
caption = Text("Stack grows toward lower addresses",
font="JetBrains Mono", color=GRAY, font_size=20
).shift(DOWN * 3.1)
self.play(Write(caption))
self.wait(2.5)
# Show the C code + ASM side by side
self.play(*[FadeOut(m) for m in self.mobjects])
title_card(self, "Stack in Assembly", "sub rsp allocates space")
asm_lines = [
("1139:", "55", "push rbp"),
("113a:", "48 89 e5", "mov rbp, rsp"),
("113d:", "48 83 ec 10", "sub rsp, 0x10 ; allocate locals"),
("1141:", "c7 45 fc 05…", "mov DWORD PTR [rbp-0x4], 0x5"),
("1152:", "e8 d9 fe ff ff", "call puts@plt"),
("1157:", "b8 00 00 00 00", "mov eax, 0x0"),
("115c:", "c9", "leave"),
("115d:", "c3", "ret"),
]
asm_group = S02_HelloWorld._asm_block(asm_lines).scale(0.95).shift(UP * 0.3)
self.play(FadeIn(asm_group))
# Highlight sub rsp
rows = asm_group.submobjects[1]
self.play(rows[2].animate.set_color(ACCENT), run_time=0.5)
note = Text("Reserves 16 bytes on the stack for local variable x",
font="JetBrains Mono", color=ACCENT, font_size=20
).shift(DOWN * 2.8)
self.play(Write(note))
self.wait(2)
self.play(*[FadeOut(m) for m in self.mobjects])
# ─────────────────────────────────────────────
# 5. The Heap
# ─────────────────────────────────────────────
class S05_Heap(Scene):
def construct(self):
title_card(self, "The Heap", "Dynamic Memory & malloc/free")
# Memory layout diagram
segments = [
("Stack ↓", ORANGE, 1.2),
(" ... ", BG, 0.5),
("Heap ↑", GREEN, 1.2),
(".bss", PURPLE, 0.55),
(".data", PURPLE, 0.55),
(".text", ACCENT, 0.55),
]
layout = VGroup()
for label, color, h in segments:
rect = Rectangle(width=3.8, height=h,
fill_color=color, fill_opacity=0.18,
stroke_color=color if color != BG else GRAY,
stroke_width=1.5)
lbl = Text(label, font="JetBrains Mono", color=color if color != BG else GRAY,
font_size=22)
lbl.move_to(rect)
layout.add(VGroup(rect, lbl))
layout.arrange(DOWN, buff=0).shift(LEFT * 3.5)
low_lbl = Text("Low Address", font="JetBrains Mono", color=GRAY, font_size=17
).next_to(layout, DOWN, buff=0.2)
high_lbl = Text("High Address", font="JetBrains Mono", color=GRAY, font_size=17
).next_to(layout, UP, buff=0.2)
self.play(FadeIn(layout), Write(low_lbl), Write(high_lbl), run_time=1.2)
self.wait(0.6)
# malloc/free sequence on the right
steps = [
("char *buf = malloc(64);", GREEN, "allocate 64 bytes on heap"),
("strcpy(buf, \"hello\");", ORANGE, "write data into buffer"),
("free(buf);", RED, "return memory to allocator"),
]
step_group = VGroup()
for code, color, desc in steps:
code_t = Text(code, font="JetBrains Mono", color=color, font_size=19)
desc_t = Text(desc, font="JetBrains Mono", color=GRAY, font_size=16)
desc_t.next_to(code_t, DOWN, buff=0.12)
step_group.add(VGroup(code_t, desc_t))
step_group.arrange(DOWN, buff=0.5).shift(RIGHT * 2.2 + UP * 0.3)
for step in step_group:
self.play(FadeIn(step, shift=RIGHT * 0.3), run_time=0.7)
self.wait(0.6)
# Vulnerability callout
vuln_box = RoundedRectangle(corner_radius=0.2, width=6.5, height=1.8,
fill_color=RED, fill_opacity=0.1,
stroke_color=RED, stroke_width=2)
vuln_box.shift(DOWN * 2.8)
vuln_txt = Text(
"Forget free → Memory Leak\n"
"free + reuse → Use-After-Free\n"
"Overflow 64 bytes → Heap Overflow",
font="JetBrains Mono", color=RED, font_size=17, line_spacing=1.3)
vuln_txt.move_to(vuln_box)
self.play(FadeIn(vuln_box), Write(vuln_txt), run_time=1.2)
self.wait(2.5)
self.play(*[FadeOut(m) for m in self.mobjects])
# ─────────────────────────────────────────────
# 6. Instruction Set
# ─────────────────────────────────────────────
class S06_Instructions(Scene):
def construct(self):
title_card(self, "CPU Instructions", "mov · lea · push · call · ret")
categories = [
("Data Movement", [
("mov rax, rdx", "copy rdx into rax"),
("mov rax, [rdx]", "dereference: load value at addr rdx"),
("lea rdi, [rbx+0x10]","load address rbx+0x10 into rdi"),
], ACCENT),
("Arithmetic / Logic", [
("add rax, 0x4", "rax = rax + 4"),
("sub rsp, 0x10", "grow stack by 16 bytes"),
("xor rax, rax", "zero rax (optimised)"),
], GREEN),
("Stack", [
("push rbp", "decrement rsp; write rbp to [rsp]"),
("pop rbp", "read [rsp] into rbp; increment rsp"),
], ORANGE),
("Control Flow", [
("call 0x401234", "push rip; jump to function"),
("ret", "pop saved rip; resume caller"),
("jmp 0x401234", "unconditional jump"),
("jz / jnz", "jump if Zero Flag set / not set"),
], PURPLE),
]
for cat_name, instructions, color in categories:
self.play(*[FadeOut(m) for m in self.mobjects], run_time=0.3)
hdr = Text(cat_name, font="JetBrains Mono", color=color,
font_size=34, weight=BOLD).shift(UP * 3)
self.play(Write(hdr))
rows = VGroup()
for instr, desc in instructions:
instr_t = Text(instr, font="JetBrains Mono", color=color, font_size=24)
desc_t = Text(f" → {desc}", font="JetBrains Mono",
color=WHITE, font_size=20)
row = VGroup(instr_t, desc_t).arrange(RIGHT, buff=0.3)
rows.add(row)
rows.arrange(DOWN, aligned_edge=LEFT, buff=0.4).shift(UP * 0.4)
self.play(LaggedStart(*[FadeIn(r, shift=LEFT * 0.3) for r in rows],
lag_ratio=0.25), run_time=1.2)
self.wait(2.0)
self.play(*[FadeOut(m) for m in self.mobjects])
# ─────────────────────────────────────────────
# 7. CPU Flags
# ─────────────────────────────────────────────
class S07_Flags(Scene):
def construct(self):
title_card(self, "CPU Flags", "EFLAGS register")
# 16-bit flag register visual
bits = list(range(15, -1, -1))
important = {0: ("CF", RED), 2: ("PF", GRAY), 6: ("ZF", ACCENT),
7: ("SF", ORANGE), 11: ("OF", PURPLE)}
cells = VGroup()
for b in bits:
color = important.get(b, ("", GRAY))[1] if b in important else GRAY
rect = Square(side_length=0.55,
fill_color=color, fill_opacity=0.18,
stroke_color=color, stroke_width=1.5)
bit_n = Text(str(b), font="JetBrains Mono",
color=color, font_size=13).move_to(rect)
cells.add(VGroup(rect, bit_n))
cells.arrange(RIGHT, buff=0.04).shift(UP * 1.8)
self.play(FadeIn(cells), run_time=1.0)
# Flag abbreviations below important bits
for b, (abbr, color) in important.items():
idx = 15 - b
cell = cells[idx]
lbl = Text(abbr, font="JetBrains Mono", color=color, font_size=18,
weight=BOLD)
lbl.next_to(cell, DOWN, buff=0.15)
self.play(FadeIn(lbl), run_time=0.3)
self.wait(0.5)
# cmp / jz example
example = VGroup(
Text("cmp rax, 0x5 ; sets ZF=1 if rax == 5",
font="JetBrains Mono", color=WHITE, font_size=21),
Text("jz target ; jumps only if ZF=1",
font="JetBrains Mono", color=ACCENT, font_size=21),
).arrange(DOWN, aligned_edge=LEFT, buff=0.3).shift(DOWN * 0.4)
bg = BackgroundRectangle(example, color="#161b22", fill_opacity=1,
buff=0.25, corner_radius=0.15)
self.play(FadeIn(bg), FadeIn(example), run_time=1.0)
# Animate ZF cell lighting up
zf_idx = 15 - 6
zf_cell_rect = cells[zf_idx][0]
self.play(zf_cell_rect.animate.set_fill(ACCENT, opacity=0.75), run_time=0.7)
self.wait(0.5)
self.play(zf_cell_rect.animate.set_fill(ACCENT, opacity=0.18), run_time=0.4)
self.wait(2.0)
self.play(*[FadeOut(m) for m in self.mobjects])
# ─────────────────────────────────────────────
# 8. Outro
# ─────────────────────────────────────────────
class S08_Outro(Scene):
def construct(self):
recap_items = [
"C compiles to assembly, which becomes machine code",
"Registers: rip, rsp, rbp, argument registers",
"Calling convention: rdi → rsi → rdx → rcx → r8 → r9",
"Stack: LIFO, managed by rsp/rbp",
"Heap: dynamic memory via malloc/free",
"Instructions: mov, lea, push/pop, call/ret, jz/jnz",
"Flags register drives conditional branching",
]
title = Text("Recap", font="JetBrains Mono", color=ACCENT,
font_size=44, weight=BOLD).shift(UP * 3.1)
self.play(Write(title))
items_grp = VGroup()
for txt in recap_items:
bullet = Text(f"• {txt}", font="JetBrains Mono",
color=WHITE, font_size=20)
items_grp.add(bullet)
items_grp.arrange(DOWN, aligned_edge=LEFT, buff=0.28).shift(UP * 0.5)
self.play(LaggedStart(*[FadeIn(i, shift=LEFT * 0.2) for i in items_grp],
lag_ratio=0.18), run_time=2.5)
self.wait(1.5)
next_lbl = Text("Next: ELF Binary Structure",
font="JetBrains Mono", color=ORANGE, font_size=28,
weight=BOLD).shift(DOWN * 2.8)
self.play(Write(next_lbl))
self.wait(1.0)
support = Text("buymeacoffee.com/mockingspectre",
font="JetBrains Mono", color=GRAY, font_size=18
).shift(DOWN * 3.5)
self.play(FadeIn(support))
self.wait(3.0)
self.play(FadeOut(*self.mobjects))
# ─────────────────────────────────────────────
# Full video: concatenate all scenes
# ─────────────────────────────────────────────
class FullVideo(S01_Intro, S02_HelloWorld, S03_Registers,
S04_Stack, S05_Heap, S06_Instructions,
S07_Flags, S08_Outro):
"""Render all scenes back-to-back as a single video file."""
def construct(self):
S01_Intro.construct(self)
S02_HelloWorld.construct(self)
S03_Registers.construct(self)
S04_Stack.construct(self)
S05_Heap.construct(self)
S06_Instructions.construct(self)
S07_Flags.construct(self)
S08_Outro.construct(self)
-9
View File
@@ -1,9 +0,0 @@
[project]
name = "manimations"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"manim>=0.20.1",
]
-718
View File
@@ -1,718 +0,0 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "audioop-lts"
version = "0.2.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" },
{ url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" },
{ url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" },
{ url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" },
{ url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" },
{ url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" },
{ url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" },
{ url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" },
{ url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" },
{ url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" },
{ url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" },
{ url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" },
{ url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" },
{ url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" },
{ url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" },
{ url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" },
{ url = "https://files.pythonhosted.org/packages/58/a7/0a764f77b5c4ac58dc13c01a580f5d32ae8c74c92020b961556a43e26d02/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09", size = 47096, upload-time = "2025-08-05T16:42:40.684Z" },
{ url = "https://files.pythonhosted.org/packages/aa/ed/ebebedde1a18848b085ad0fa54b66ceb95f1f94a3fc04f1cd1b5ccb0ed42/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58", size = 27748, upload-time = "2025-08-05T16:42:41.992Z" },
{ url = "https://files.pythonhosted.org/packages/cb/6e/11ca8c21af79f15dbb1c7f8017952ee8c810c438ce4e2b25638dfef2b02c/audioop_lts-0.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19", size = 27329, upload-time = "2025-08-05T16:42:42.987Z" },
{ url = "https://files.pythonhosted.org/packages/84/52/0022f93d56d85eec5da6b9da6a958a1ef09e80c39f2cc0a590c6af81dcbb/audioop_lts-0.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911", size = 92407, upload-time = "2025-08-05T16:42:44.336Z" },
{ url = "https://files.pythonhosted.org/packages/87/1d/48a889855e67be8718adbc7a01f3c01d5743c325453a5e81cf3717664aad/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9", size = 91811, upload-time = "2025-08-05T16:42:45.325Z" },
{ url = "https://files.pythonhosted.org/packages/98/a6/94b7213190e8077547ffae75e13ed05edc488653c85aa5c41472c297d295/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe", size = 100470, upload-time = "2025-08-05T16:42:46.468Z" },
{ url = "https://files.pythonhosted.org/packages/e9/e9/78450d7cb921ede0cfc33426d3a8023a3bda755883c95c868ee36db8d48d/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132", size = 103878, upload-time = "2025-08-05T16:42:47.576Z" },
{ url = "https://files.pythonhosted.org/packages/4f/e2/cd5439aad4f3e34ae1ee852025dc6aa8f67a82b97641e390bf7bd9891d3e/audioop_lts-0.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753", size = 84867, upload-time = "2025-08-05T16:42:49.003Z" },
{ url = "https://files.pythonhosted.org/packages/68/4b/9d853e9076c43ebba0d411e8d2aa19061083349ac695a7d082540bad64d0/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb", size = 90001, upload-time = "2025-08-05T16:42:50.038Z" },
{ url = "https://files.pythonhosted.org/packages/58/26/4bae7f9d2f116ed5593989d0e521d679b0d583973d203384679323d8fa85/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093", size = 99046, upload-time = "2025-08-05T16:42:51.111Z" },
{ url = "https://files.pythonhosted.org/packages/b2/67/a9f4fb3e250dda9e9046f8866e9fa7d52664f8985e445c6b4ad6dfb55641/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7", size = 84788, upload-time = "2025-08-05T16:42:52.198Z" },
{ url = "https://files.pythonhosted.org/packages/70/f7/3de86562db0121956148bcb0fe5b506615e3bcf6e63c4357a612b910765a/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c", size = 94472, upload-time = "2025-08-05T16:42:53.59Z" },
{ url = "https://files.pythonhosted.org/packages/f1/32/fd772bf9078ae1001207d2df1eef3da05bea611a87dd0e8217989b2848fa/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5", size = 92279, upload-time = "2025-08-05T16:42:54.632Z" },
{ url = "https://files.pythonhosted.org/packages/4f/41/affea7181592ab0ab560044632571a38edaf9130b84928177823fbf3176a/audioop_lts-0.2.2-cp313-cp313t-win32.whl", hash = "sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917", size = 26568, upload-time = "2025-08-05T16:42:55.627Z" },
{ url = "https://files.pythonhosted.org/packages/28/2b/0372842877016641db8fc54d5c88596b542eec2f8f6c20a36fb6612bf9ee/audioop_lts-0.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547", size = 30942, upload-time = "2025-08-05T16:42:56.674Z" },
{ url = "https://files.pythonhosted.org/packages/ee/ca/baf2b9cc7e96c179bb4a54f30fcd83e6ecb340031bde68f486403f943768/audioop_lts-0.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969", size = 24603, upload-time = "2025-08-05T16:42:57.571Z" },
{ url = "https://files.pythonhosted.org/packages/5c/73/413b5a2804091e2c7d5def1d618e4837f1cb82464e230f827226278556b7/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6", size = 47104, upload-time = "2025-08-05T16:42:58.518Z" },
{ url = "https://files.pythonhosted.org/packages/ae/8c/daa3308dc6593944410c2c68306a5e217f5c05b70a12e70228e7dd42dc5c/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a", size = 27754, upload-time = "2025-08-05T16:43:00.132Z" },
{ url = "https://files.pythonhosted.org/packages/4e/86/c2e0f627168fcf61781a8f72cab06b228fe1da4b9fa4ab39cfb791b5836b/audioop_lts-0.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b", size = 27332, upload-time = "2025-08-05T16:43:01.666Z" },
{ url = "https://files.pythonhosted.org/packages/c7/bd/35dce665255434f54e5307de39e31912a6f902d4572da7c37582809de14f/audioop_lts-0.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6", size = 92396, upload-time = "2025-08-05T16:43:02.991Z" },
{ url = "https://files.pythonhosted.org/packages/2d/d2/deeb9f51def1437b3afa35aeb729d577c04bcd89394cb56f9239a9f50b6f/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf", size = 91811, upload-time = "2025-08-05T16:43:04.096Z" },
{ url = "https://files.pythonhosted.org/packages/76/3b/09f8b35b227cee28cc8231e296a82759ed80c1a08e349811d69773c48426/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd", size = 100483, upload-time = "2025-08-05T16:43:05.085Z" },
{ url = "https://files.pythonhosted.org/packages/0b/15/05b48a935cf3b130c248bfdbdea71ce6437f5394ee8533e0edd7cfd93d5e/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a", size = 103885, upload-time = "2025-08-05T16:43:06.197Z" },
{ url = "https://files.pythonhosted.org/packages/83/80/186b7fce6d35b68d3d739f228dc31d60b3412105854edb975aa155a58339/audioop_lts-0.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e", size = 84899, upload-time = "2025-08-05T16:43:07.291Z" },
{ url = "https://files.pythonhosted.org/packages/49/89/c78cc5ac6cb5828f17514fb12966e299c850bc885e80f8ad94e38d450886/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7", size = 89998, upload-time = "2025-08-05T16:43:08.335Z" },
{ url = "https://files.pythonhosted.org/packages/4c/4b/6401888d0c010e586c2ca50fce4c903d70a6bb55928b16cfbdfd957a13da/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5", size = 99046, upload-time = "2025-08-05T16:43:09.367Z" },
{ url = "https://files.pythonhosted.org/packages/de/f8/c874ca9bb447dae0e2ef2e231f6c4c2b0c39e31ae684d2420b0f9e97ee68/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9", size = 84843, upload-time = "2025-08-05T16:43:10.749Z" },
{ url = "https://files.pythonhosted.org/packages/3e/c0/0323e66f3daebc13fd46b36b30c3be47e3fc4257eae44f1e77eb828c703f/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602", size = 94490, upload-time = "2025-08-05T16:43:12.131Z" },
{ url = "https://files.pythonhosted.org/packages/98/6b/acc7734ac02d95ab791c10c3f17ffa3584ccb9ac5c18fd771c638ed6d1f5/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0", size = 92297, upload-time = "2025-08-05T16:43:13.139Z" },
{ url = "https://files.pythonhosted.org/packages/13/c3/c3dc3f564ce6877ecd2a05f8d751b9b27a8c320c2533a98b0c86349778d0/audioop_lts-0.2.2-cp314-cp314t-win32.whl", hash = "sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3", size = 27331, upload-time = "2025-08-05T16:43:14.19Z" },
{ url = "https://files.pythonhosted.org/packages/72/bb/b4608537e9ffcb86449091939d52d24a055216a36a8bf66b936af8c3e7ac/audioop_lts-0.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b", size = 31697, upload-time = "2025-08-05T16:43:15.193Z" },
{ url = "https://files.pythonhosted.org/packages/f6/22/91616fe707a5c5510de2cac9b046a30defe7007ba8a0c04f9c08f27df312/audioop_lts-0.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd", size = 25206, upload-time = "2025-08-05T16:43:16.444Z" },
]
[[package]]
name = "av"
version = "17.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b2/eb/abca886df3a091bc406feb5ff71b4c4f426beaae6b71b9697264ce8c7211/av-17.0.0.tar.gz", hash = "sha256:c53685df73775a8763c375c7b2d62a6cb149d992a26a4b098204da42ade8c3df", size = 4410769, upload-time = "2026-03-14T14:38:45.868Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b1/fb/55e3b5b5d1fc61466292f26fbcbabafa2642f378dc48875f8f554591e1a4/av-17.0.0-cp311-abi3-macosx_11_0_x86_64.whl", hash = "sha256:ed4013fac77c309a4a68141dcf6148f1821bb1073a36d4289379762a6372f711", size = 23238424, upload-time = "2026-03-14T14:38:05.856Z" },
{ url = "https://files.pythonhosted.org/packages/52/03/9ace1acc08bc9ae38c14bf3a4b1360e995e4d999d1d33c2cbd7c9e77582a/av-17.0.0-cp311-abi3-macosx_14_0_arm64.whl", hash = "sha256:e44b6c83e9f3be9f79ee87d0b77a27cea9a9cd67bd630362c86b7e56a748dfbb", size = 18709043, upload-time = "2026-03-14T14:38:08.288Z" },
{ url = "https://files.pythonhosted.org/packages/00/c0/637721f3cd5bb8bd16105a1a08efd781fc12f449931bdb3a4d0cfd63fa55/av-17.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b440da6ac47da0629d509316f24bcd858f33158dbdd0f1b7293d71e99beb26de", size = 34018780, upload-time = "2026-03-14T14:38:10.45Z" },
{ url = "https://files.pythonhosted.org/packages/d2/59/d19bc3257dd985d55337d7f0414c019414b97e16cd3690ebf9941a847543/av-17.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1060cba85f97f4a337311169d92c0b5e143452cfa5ca0e65fa499d7955e8592e", size = 36358757, upload-time = "2026-03-14T14:38:13.092Z" },
{ url = "https://files.pythonhosted.org/packages/52/6c/a1f4f2677bae6f2ade7a8a18e90ebdcf70690c9b1c4e40e118aa30fa313f/av-17.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:deda202e6021cfc7ba3e816897760ec5431309d59a4da1f75df3c0e9413d71e7", size = 35195281, upload-time = "2026-03-14T14:38:15.789Z" },
{ url = "https://files.pythonhosted.org/packages/90/ea/52b0fc6f69432c7bf3f5fbe6f707113650aa40a1a05b9096ffc2bba4f77d/av-17.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ffaf266a1a9c2148072de0a4b5ae98061465178d2cfaa69ee089761149342974", size = 37444817, upload-time = "2026-03-14T14:38:18.563Z" },
{ url = "https://files.pythonhosted.org/packages/34/ad/d2172966282cb8f146c13b6be7416efefde74186460c5e1708ddfc13dba6/av-17.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:45a35a40b2875bf2f98de7c952d74d960f92f319734e6d28e03b4c62a49e6f49", size = 28888553, upload-time = "2026-03-14T14:38:21.223Z" },
{ url = "https://files.pythonhosted.org/packages/b0/bb/c5a4c4172c514d631fb506e6366b503576b8c7f29809cf42aca73e28ff01/av-17.0.0-cp311-abi3-win_arm64.whl", hash = "sha256:3d32e9b5c5bbcb872a0b6917b352a1db8a42142237826c9b49a36d5dbd9e9c26", size = 21916910, upload-time = "2026-03-14T14:38:23.706Z" },
{ url = "https://files.pythonhosted.org/packages/7f/8e/c40ac08e63f79387c59f6ecc38f47d4c942b549130eee579ec1a91f6a291/av-17.0.0-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:d13250fb4b4522e9a6bec32da082556d5f257110ea223758151375748d9bbe25", size = 23483029, upload-time = "2026-03-14T14:38:25.758Z" },
{ url = "https://files.pythonhosted.org/packages/a9/fb/b4419494bfc249163ec393c613966d66db7e95c76da3345711cd115a79df/av-17.0.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:dbb56aa3b7ae72451d1bf6e9d37c7d83d39b97af712f73583ff419fbf08fc237", size = 18920446, upload-time = "2026-03-14T14:38:27.905Z" },
{ url = "https://files.pythonhosted.org/packages/30/62/c2306d91602ddad2c56106f21dcb334fd51d5ea2e952f7fa025bb8aa39fc/av-17.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:a213ac9e83b7ab12c2e9f277a09cac8e9d85cf0883efdab7a87a60e2e4e48879", size = 37477266, upload-time = "2026-03-14T14:38:30.404Z" },
{ url = "https://files.pythonhosted.org/packages/28/cd/c8510a9607886785c0b3ca019d503e888c3757529be42a7287fe2bfa92d5/av-17.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:e15c88bb0921f9435bcc5a27a0863dba571a80ad5e1389c4fcf2073833bb4a74", size = 39572988, upload-time = "2026-03-14T14:38:32.984Z" },
{ url = "https://files.pythonhosted.org/packages/7d/2d/207d9361e25b5abec9be335bbab4df6b6b838e2214be4b374f4cfb285427/av-17.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:096cfd1e9fc896506726c7c42aaf9b370e78c2f257cde4d6ddb6c889bfcc49ec", size = 38399591, upload-time = "2026-03-14T14:38:35.465Z" },
{ url = "https://files.pythonhosted.org/packages/73/ca/307740c6aa2980966bf11383ffcb04bacc5b13f3d268ab4cfb274ad6f793/av-17.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3649ab3d2c7f58049ded1a36e100c0d8fd529cf258f41dd88678ba824034d8c9", size = 40590681, upload-time = "2026-03-14T14:38:38.269Z" },
{ url = "https://files.pythonhosted.org/packages/35/f2/6fdb26d0651adf409864cb2a0d60da107e467d3d1aabc94b234ead54324a/av-17.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e5002271ab2135b551d980c2db8f3299d452e3b9d3633f24f6bb57fffe91cd10", size = 29216337, upload-time = "2026-03-14T14:38:40.83Z" },
{ url = "https://files.pythonhosted.org/packages/41/0a/0896b829a39b5669a2d811e1a79598de661693685cd62b31f11d0c18e65b/av-17.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dba98603fc4665b4f750de86fbaf6c0cfaece970671a9b529e0e3d1711e8367e", size = 22071058, upload-time = "2026-03-14T14:38:43.663Z" },
]
[[package]]
name = "beautifulsoup4"
version = "4.14.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "soupsieve" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" },
]
[[package]]
name = "click"
version = "8.3.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856, upload-time = "2026-04-03T19:14:45.118Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" },
]
[[package]]
name = "cloup"
version = "3.0.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f9/64/7f0a66021ff81d51859c66adc13f3c71f0306c2f8dfb9877a0694cbada05/cloup-3.0.9.tar.gz", hash = "sha256:519f524d3c64040e49a0866b5fc0bfd6af3eac0d3d6a4b2b50b33ab0247db2d7", size = 229896, upload-time = "2026-04-04T03:53:54.182Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/77/15/435bb5a24e3a2dc8c26afedab0c6f0cf4291c66fb99509c168c38eb81135/cloup-3.0.9-py2.py3-none-any.whl", hash = "sha256:c761ef4e975454335d50c0e1eb83595a932735aac06e8955b3ced774bc62ae7b", size = 54724, upload-time = "2026-04-04T03:53:52.909Z" },
]
[[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 = "cython"
version = "3.2.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/91/85/7574c9cd44b69a27210444b6650f6477f56c75fee1b70d7672d3e4166167/cython-3.2.4.tar.gz", hash = "sha256:84226ecd313b233da27dc2eb3601b4f222b8209c3a7216d8733b031da1dc64e6", size = 3280291, upload-time = "2026-01-04T14:14:14.473Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/b5/1cfca43b7d20a0fdb1eac67313d6bb6b18d18897f82dd0f17436bdd2ba7f/cython-3.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:28e8075087a59756f2d059273184b8b639fe0f16cf17470bd91c39921bc154e0", size = 2960506, upload-time = "2026-01-04T14:15:16.733Z" },
{ url = "https://files.pythonhosted.org/packages/ee/d7/3bda3efce0c5c6ce79cc21285dbe6f60369c20364e112f5a506ee8a1b067/cython-3.2.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d4b4fd5332ab093131fa6172e8362f16adef3eac3179fd24bbdc392531cb82fa", size = 2971496, upload-time = "2026-01-04T14:15:25.038Z" },
{ url = "https://files.pythonhosted.org/packages/0a/8b/fd393f0923c82be4ec0db712fffb2ff0a7a131707b842c99bf24b549274d/cython-3.2.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:36bf3f5eb56d5281aafabecbaa6ed288bc11db87547bba4e1e52943ae6961ccf", size = 2875622, upload-time = "2026-01-04T14:15:39.749Z" },
{ url = "https://files.pythonhosted.org/packages/ff/fa/d3c15189f7c52aaefbaea76fb012119b04b9013f4bf446cb4eb4c26c4e6b/cython-3.2.4-py3-none-any.whl", hash = "sha256:732fc93bc33ae4b14f6afaca663b916c2fdd5dcbfad7114e17fb2434eeaea45c", size = 1257078, upload-time = "2026-01-04T14:14:12.373Z" },
]
[[package]]
name = "decorator"
version = "5.2.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" },
]
[[package]]
name = "glcontext"
version = "3.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/3a/80/8238a0e6e972292061176141c1028b5e670aa8c94cf4c2f819bd730d314e/glcontext-3.0.0.tar.gz", hash = "sha256:57168edcd38df2fc0d70c318edf6f7e59091fba1cd3dadb289d0aa50449211ef", size = 16422, upload-time = "2024-08-10T20:01:20.004Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/12/be/0ef6a6710164fde818040238b041b02a082a2b9d210f18632ab2354d863e/glcontext-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5bd37089570d3cdb01c6c0b315c49ce8a4dcdab2c431f5ba9f37a8b633cebfdf", size = 9366, upload-time = "2024-08-10T20:00:30.531Z" },
{ url = "https://files.pythonhosted.org/packages/b9/d7/c3220898d72fbf938660ba5789c19cf245d21b45802a5d86cbcc67d66413/glcontext-3.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:857fd83e60f15580afd369dfb651a10d84a70ec35995622d253551bfb3ff9477", size = 9735, upload-time = "2024-08-10T20:00:31.708Z" },
{ url = "https://files.pythonhosted.org/packages/74/c1/2d57062d2f2f6e55c58b12bdeab2a39b209f959df32039d099ecdfe96bf7/glcontext-3.0.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93fda9b378ce6d91f366e83e71ebdafdd167280a9834d1d6341ce6457c4e42ed", size = 50166, upload-time = "2024-08-10T20:00:32.627Z" },
{ url = "https://files.pythonhosted.org/packages/03/4d/7fee00c76d678b06529e939ab6f3e3190af30208fe2e984526899026a437/glcontext-3.0.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89ad50d34aa62f03f6aaf6ae39fc27afd1b0eaefb0281aac51f686dc5672d473", size = 51186, upload-time = "2024-08-10T20:00:33.718Z" },
{ url = "https://files.pythonhosted.org/packages/f0/58/dc9a56192b889587e51ea511804bad5dec816de81ce16831db9fe19d5c40/glcontext-3.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2634d5e9647a6d7b0c5a5c0c57e91ac98aa79759bffb42459af4374b049fab01", size = 44658, upload-time = "2024-08-10T20:00:35.232Z" },
{ url = "https://files.pythonhosted.org/packages/aa/ed/acb12e67589deaa96ad29d6994c2b9383afd18700f4f2a42ff342628aac5/glcontext-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0140c5df37cb48271527355062d35589dc3e1e7e73b51adf9962ed5048115f69", size = 46882, upload-time = "2024-08-10T20:00:36.33Z" },
{ url = "https://files.pythonhosted.org/packages/e0/6d/033ba23466d596c945f5f31f5c4e50cba3bc6664fdee58f6ceab54b76f4b/glcontext-3.0.0-cp313-cp313-win32.whl", hash = "sha256:6678e0552b516fa8fe62f500ef2b953bec991e82a003be2a9840d16556d03d2e", size = 12220, upload-time = "2024-08-10T20:00:37.874Z" },
{ url = "https://files.pythonhosted.org/packages/53/b4/f0e0860526b8661ec6ae2b25a15b61100e551f57f488613c564752173a56/glcontext-3.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:18aa4b1df50e8c8ea39bd0f775f39bcc987521f92c4ed019ec7d70078471354d", size = 12971, upload-time = "2024-08-10T20:00:39.233Z" },
]
[[package]]
name = "isosurfaces"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/da/cf/bd7e70bb7b8dfd77afdc79aba8d83afd4a9263f045861cd4ddd34b7f6a12/isosurfaces-0.1.2.tar.gz", hash = "sha256:fa51ebe864ea9355b26830e27fdd6a41d5a58b419fa8d4b47e3b8b80718d6e21", size = 11348, upload-time = "2024-02-26T00:20:52.066Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b1/68/d5e9e6e0d6e43107d8393d2ee3d231dbb597bf93052c6f3117b313724980/isosurfaces-0.1.2-py3-none-any.whl", hash = "sha256:525a49ba93f4dbc35303cd2faf30976af0f99d9274cfa2787aec016b8ef96c64", size = 11649, upload-time = "2024-02-26T00:20:41.308Z" },
]
[[package]]
name = "manim"
version = "0.20.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "audioop-lts" },
{ name = "av" },
{ name = "beautifulsoup4" },
{ name = "click" },
{ name = "cloup" },
{ name = "decorator" },
{ name = "isosurfaces" },
{ name = "manimpango" },
{ name = "mapbox-earcut" },
{ name = "moderngl" },
{ name = "moderngl-window" },
{ name = "networkx" },
{ name = "numpy" },
{ name = "pillow" },
{ name = "pycairo" },
{ name = "pydub" },
{ name = "pygments" },
{ name = "rich" },
{ name = "scipy" },
{ name = "screeninfo" },
{ name = "skia-pathops" },
{ name = "srt" },
{ name = "svgelements" },
{ name = "tqdm" },
{ name = "typing-extensions" },
{ name = "watchdog" },
]
sdist = { url = "https://files.pythonhosted.org/packages/dc/3b/ad54ce02f3e95d17d016cb1254708ae3795b60d5661f3b2085655940a565/manim-0.20.1.tar.gz", hash = "sha256:1e9747fb2fc1bde58ad09bcbd77d141793ce4b61811726a7fce537193d92e16b", size = 553537, upload-time = "2026-02-27T07:32:53.54Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4b/74/7a54f81bbb3016036662c5497edc89c5d053a8ab1e8f7c8faaca5d43b174/manim-0.20.1-py3-none-any.whl", hash = "sha256:2c76784716aef88630eace2762645e1eb25f236fe750cb1b3c4fdd3558de49e1", size = 652109, upload-time = "2026-02-27T07:32:55.066Z" },
]
[[package]]
name = "manimations"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "manim" },
]
[package.metadata]
requires-dist = [{ name = "manim", specifier = ">=0.20.1" }]
[[package]]
name = "manimpango"
version = "0.6.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/47/55/d360e73eb4d04b102cef399ddebcba486a9b6c1977a26fe710beffd52e95/manimpango-0.6.1.tar.gz", hash = "sha256:59a00bbf8e99dab5f94341087c88e609fe946e79724627429cf59da84cbd40bf", size = 4080834, upload-time = "2025-10-23T06:04:48.564Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/23/ee/01cd6b3087a5ead9483add3023f46c135bddd7773d506b771b44bbe0830b/manimpango-0.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:79aafe6373cb31dcdd1ee505407ec2bea18e74aed877f93dcd27ec9d88584472", size = 7751685, upload-time = "2025-10-23T06:04:28.457Z" },
{ url = "https://files.pythonhosted.org/packages/70/93/905ac20a9190655870131940dadb5121645cf8a23e6ea0f04be7f4604f2e/manimpango-0.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1049bda27ca504d24b48bec21756f4d8a3310ea7bc690167c54d05e97b8f7639", size = 7062629, upload-time = "2025-10-23T06:04:30.059Z" },
{ url = "https://files.pythonhosted.org/packages/76/88/b2de7d2d3a0331cf79992f8c6da0f0abd873d4ec9f024cad5992f1cf7a6d/manimpango-0.6.1-cp313-cp313-win32.whl", hash = "sha256:8da8238147b96737b36725b0fc386dc1dd7901516dfd7e73b2e7d34cd5d934f1", size = 3626705, upload-time = "2025-10-23T06:04:31.527Z" },
{ url = "https://files.pythonhosted.org/packages/3b/ed/a7a57491b26e8fb85ac0be9c39b53a6690f3c39beaf06d3715cb6916932b/manimpango-0.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:e90d6b926d0e673ce624963d44cc28c55a368b6074108ab885a43305baeae26c", size = 4203874, upload-time = "2025-10-23T06:04:32.981Z" },
{ url = "https://files.pythonhosted.org/packages/f1/c0/318410215b409465a237c126a3e1f612c432d33b037b2f997870df327434/manimpango-0.6.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:318d14087901ee27ed6d0cfef0335aed57db217f8de831c8ca4e4c52b7805b45", size = 7751895, upload-time = "2025-10-23T06:04:34.874Z" },
{ url = "https://files.pythonhosted.org/packages/d1/83/f0a05e3e6312ca9673bc8b470c6a743cf2d0bd7f08b218efc993226e72e4/manimpango-0.6.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ffe2f8353857f0ca9a16894430d871051da450bc2d19beb969cf8b57b032f580", size = 7063387, upload-time = "2025-10-23T06:04:36.877Z" },
{ url = "https://files.pythonhosted.org/packages/13/76/0748323341647e8c338bd7af6fb527ffdc43d676003b57743740bdfcffcc/manimpango-0.6.1-cp314-cp314-win32.whl", hash = "sha256:c294ab801c8ffc217342dfeff7aeca97cbea86cd8b4e6e8c9a8d7da020b820e1", size = 3737933, upload-time = "2025-10-23T06:04:38.775Z" },
{ url = "https://files.pythonhosted.org/packages/2b/e9/42b995549cfd137780045e44b3bfba2cb1247b18bd2fb9f97079048e78ac/manimpango-0.6.1-cp314-cp314-win_amd64.whl", hash = "sha256:d8b0ee675eb30bbb67097cecb2be469847c3ccf574291f2bd43360caeb5f62ed", size = 4357908, upload-time = "2025-10-23T06:04:40.641Z" },
]
[[package]]
name = "mapbox-earcut"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bc/7b/bbf6b00488662be5d2eb7a188222c264b6f713bac10dc4a77bf37a4cb4b6/mapbox_earcut-2.0.0.tar.gz", hash = "sha256:81eab6b86cf99551deb698b98e3f7502c57900e5c479df15e1bdaf1a57f0f9d6", size = 39934, upload-time = "2025-11-16T18:41:27.251Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8b/7c/c5dd5b255b9828ba5df729e62fdd470a322c938f07ef392ca03c0592bb3a/mapbox_earcut-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:582329a81bd36cf0f82e443c395bcb8cfdb10caddafec76acaebac7c20bf1c31", size = 55619, upload-time = "2025-11-16T18:40:44.44Z" },
{ url = "https://files.pythonhosted.org/packages/1a/3f/03f23eac9831e7d0d8da3d6993695a9a3724659c94e9997f6b7aaccc199d/mapbox_earcut-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d2ac5f610b3e44a3a0c4df06b5552d503b4f1c2c409eeca20dbe05112bd60955", size = 52023, upload-time = "2025-11-16T18:40:45.857Z" },
{ url = "https://files.pythonhosted.org/packages/39/f3/a92ccee494b3e437e4bd81ecd358e39d231dc90af010d6c43930506c10ad/mapbox_earcut-2.0.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:58cc88513b87734b243d86f0d3fb87e96e0a78d9abd8fd615c55f766dd63f949", size = 56357, upload-time = "2025-11-16T18:40:47.27Z" },
{ url = "https://files.pythonhosted.org/packages/03/30/e54ececd0403a5495c340b693075abec92a6d17dc44283b6cb059534f7ed/mapbox_earcut-2.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:40218d887798451932f3c335992834aa807c35cd497c6e0733470fdbd77f9521", size = 59215, upload-time = "2025-11-16T18:40:48.682Z" },
{ url = "https://files.pythonhosted.org/packages/6e/e1/8fbff13a074c1fbf702b30ce7ec4d878bc664d659c1c2b1697831f4ea3a8/mapbox_earcut-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:39fa5cfa0e855b028ec9b0200c88ebfa252448f343ce2f67b6fc07fe1f22a3ae", size = 152304, upload-time = "2025-11-16T18:40:49.85Z" },
{ url = "https://files.pythonhosted.org/packages/b9/d5/c757030b3cb3a9f2278ded6f7312d2b9d3761db6f3da8d395f7f7303dd66/mapbox_earcut-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:476b558473b8a43f238d46e819bc0f830c427842ec5feb19e23b4dcac8ad2455", size = 157270, upload-time = "2025-11-16T18:40:51.093Z" },
{ url = "https://files.pythonhosted.org/packages/96/63/589c6decb1f032d8811f1066da552f0a718830f592e6d6539fa4c3c766b8/mapbox_earcut-2.0.0-cp313-cp313-win32.whl", hash = "sha256:8c2d125c182acbc490b39503c0dec4f937bae180d0849a26bcea0ee4a76024bd", size = 51207, upload-time = "2025-11-16T18:40:52.285Z" },
{ url = "https://files.pythonhosted.org/packages/76/75/a79a6020c46d4f07731e88ec5cc9324f6b43343aba835def1dc0bf59fecf/mapbox_earcut-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:e049e6a37c228d7a9cb2f54ae405aa21d35c5175d849530fb32064ddb38ad5ab", size = 56416, upload-time = "2025-11-16T18:40:53.474Z" },
{ url = "https://files.pythonhosted.org/packages/ce/5f/83e878c2b3e9e6db1f60b598a2cc5ed4c2b5bc8d281575c964869414a159/mapbox_earcut-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:8a833d73d63d4b6291bbd8b4d2f551e87f663282cdc547ecbbd9b423849ee996", size = 50103, upload-time = "2025-11-16T18:40:54.954Z" },
{ url = "https://files.pythonhosted.org/packages/96/fc/f1b74324c83f510213ff91eb8b1d2697ad5a12418c5fba966e80f1104a5f/mapbox_earcut-2.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ad1dc141797037b7d4c9d8d2e52b9665b36294913a8ec31008b282d1a95b9bdc", size = 55728, upload-time = "2025-11-16T18:40:56.098Z" },
{ url = "https://files.pythonhosted.org/packages/7b/59/053c04e29c4bd22157d3b6255f1e5c19c46cb7a594c4314298bdcbca723f/mapbox_earcut-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0f0f5c6f5ed8ffdce8efe6a003ba598089d0ee07eabd41868db183be50484f9f", size = 52063, upload-time = "2025-11-16T18:40:57.227Z" },
{ url = "https://files.pythonhosted.org/packages/a6/77/acc2d553c3bb8c769535a280545bb7d9608141e90511a2e6215a54611776/mapbox_earcut-2.0.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82cd92775f37fd1e4b8464c5e74a00e87130eecc55ee3df2492b8ca2bdf6ef3e", size = 56522, upload-time = "2025-11-16T18:40:58.349Z" },
{ url = "https://files.pythonhosted.org/packages/1a/f5/627dd6defd3c1a2b3069e9e27482aa04d268c841735e576c1e22848a34f6/mapbox_earcut-2.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:626ffc1310e0cc8910283e4ac3139e5fb0458f18f2c4874162f66159951933ff", size = 59204, upload-time = "2025-11-16T18:41:00.095Z" },
{ url = "https://files.pythonhosted.org/packages/4a/3e/819185542ab095ba1244ad65ececb3edcde6fd0111248a0f9318d695bfcf/mapbox_earcut-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ea951d764a356cad95b23fef950d8aa3b44b933795ad09d977fea7d4dbe377c3", size = 152550, upload-time = "2025-11-16T18:41:01.233Z" },
{ url = "https://files.pythonhosted.org/packages/a9/ad/85e0f815e4774b90ad6761bce55c80d13ee21b2a24014b0be0d5010b0049/mapbox_earcut-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:df1f217624abb5e02ecabcbd84369de970b8d8bc1e4e7c164c1cfcaddad76ca3", size = 157322, upload-time = "2025-11-16T18:41:02.866Z" },
{ url = "https://files.pythonhosted.org/packages/27/4c/0f56369e7a000d2f3177d17baf34263559b206ae524fcd0c4c5d1d960dab/mapbox_earcut-2.0.0-cp314-cp314-win32.whl", hash = "sha256:6fa61307d38b50fc9bd5449c00dbae46d270a32b372c6fc3b8af4b85c85746e4", size = 52916, upload-time = "2025-11-16T18:41:04.122Z" },
{ url = "https://files.pythonhosted.org/packages/c2/9d/8c557dd9b3d9fe2344f5bd5ff3bb0b2a42ed6addb7e43ca4358051743b04/mapbox_earcut-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:0da20ed3c81b240450118773bcedfac34e70a56998f66147222c46f4356fff67", size = 57713, upload-time = "2025-11-16T18:41:05.204Z" },
{ url = "https://files.pythonhosted.org/packages/3b/ec/678c5553938d3a29d02dd41dd898672267f054afc4e2821958dee6ec86ce/mapbox_earcut-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:847e74bd5878e4c64793dc100f9288f5443f87c55c3fe391fd90509029136ff6", size = 51872, upload-time = "2025-11-16T18:41:06.323Z" },
{ url = "https://files.pythonhosted.org/packages/18/37/94f2d973669cbfef811e536713fe56ec012ba74e5f8795a832337b1866a3/mapbox_earcut-2.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ddc9e7175fc903185c64afbbf91febee56b50787dd0962fce2bfb4f20cf80d27", size = 56447, upload-time = "2025-11-16T18:41:07.443Z" },
{ url = "https://files.pythonhosted.org/packages/c9/1c/e0afcc82659cc1727a7e59c4f9e9880bbc3f048a4a5325772b44d4a91dfd/mapbox_earcut-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6dc8a7568066af9a858018d6d92b7e77e164578f9fcd79093f1cbe4ec203461b", size = 53154, upload-time = "2025-11-16T18:41:08.618Z" },
{ url = "https://files.pythonhosted.org/packages/6c/2d/9845281c8c35da2bea733b8c2df5b9fe694e73e7b05fe8a1d4c3c439a1bc/mapbox_earcut-2.0.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6abc5340edd9b433ab2dab2ee033082a199d5c51cce445124626c0040ec0d81b", size = 56285, upload-time = "2025-11-16T18:41:09.728Z" },
{ url = "https://files.pythonhosted.org/packages/97/8e/eeea762a519490662b8f480e2b35bf03701b0bcc5a446b62a4c5a1500b06/mapbox_earcut-2.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df7afdd8078a9aa28f469d9242531d304e09a4b14e514f048e021a949f3777b4", size = 58601, upload-time = "2025-11-16T18:41:10.872Z" },
{ url = "https://files.pythonhosted.org/packages/b9/67/932f80aa6af9bc1a317b6119052c74f327d81e00b457003a049e324b810c/mapbox_earcut-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1a286f73e612a46cafd6d6c843365265090517af16823e2f37277c13cd8b6f09", size = 154924, upload-time = "2025-11-16T18:41:12.104Z" },
{ url = "https://files.pythonhosted.org/packages/87/38/5db4a91f9f90cbb447be61da5468a2955fad3a840ae4c7dbde789b09d45a/mapbox_earcut-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8d081fe1d00dc553e3e68c02fc395324aad0d8ed955f3ff59289264c9b21ace4", size = 159194, upload-time = "2025-11-16T18:41:13.364Z" },
{ url = "https://files.pythonhosted.org/packages/6b/03/de3843b13fe854a010fb2f8b25551d4d5fe1c879ff2e7c8d7d8d7d735a8e/mapbox_earcut-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:13049ca96431bbc7ef7fd7780dd1872209ca11a5c1977f7aa91a1b574a8af863", size = 54143, upload-time = "2025-11-16T18:41:14.564Z" },
{ url = "https://files.pythonhosted.org/packages/9a/89/fbdee5a56ba51df9be6098b5428636ad75aa994e98d8bec6113d5cba401e/mapbox_earcut-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6ace78e4fdba3b8cbb7768d44d77a981698305862a07f94bbb6f5cc16659adb4", size = 60833, upload-time = "2025-11-16T18:41:15.694Z" },
]
[[package]]
name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
]
[[package]]
name = "moderngl"
version = "5.12.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "glcontext" },
]
sdist = { url = "https://files.pythonhosted.org/packages/da/52/540e2f8c45060bb2709f56eb5a44ae828dfcc97ccecb342c1a7deb467889/moderngl-5.12.0.tar.gz", hash = "sha256:52936a98ccb2f2e1d6e3cb18528b2919f6831e7e3f924e788b5873badce5129b", size = 193232, upload-time = "2024-10-17T12:36:28.002Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/39/13/cf493bdc3cb4f7a6b4fb357e683404dc8a97d19f53d501e4afdd679538e2/moderngl-5.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f6efb432f5164f871471d1da36e3a4be9dc3efd7a1e48d0ac6b751e556af5d02", size = 112118, upload-time = "2024-10-17T12:37:14.892Z" },
{ url = "https://files.pythonhosted.org/packages/a9/1f/1d84bba5f42fb19ce240d08d5434fe8e2f34341e68bb9fa89336b6cbdcfc/moderngl-5.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9b09d8d15b2eaab41c8646a664429ec86af225fa25096758497cd212489d2e1e", size = 109371, upload-time = "2024-10-17T12:37:15.992Z" },
{ url = "https://files.pythonhosted.org/packages/be/ae/bda0b95878e2b36eac66f64d88c08e6c8ea759607f7d40e843a21c2f4f32/moderngl-5.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:071042dd4846e58cbe204cf49341b62cd209fdcb6d48018feb5a61c66707fcb2", size = 296206, upload-time = "2024-10-17T12:37:17.204Z" },
{ url = "https://files.pythonhosted.org/packages/28/bc/93dc73251bcdb9c0f6f5c9a1d97ec2134672c307c68e6106948eab1f73d4/moderngl-5.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91db8302ac7f5d7a82a967388677e1378ff078f1e16d05da37ce77f4633b93b1", size = 270443, upload-time = "2024-10-17T12:37:18.44Z" },
{ url = "https://files.pythonhosted.org/packages/2e/a1/bd72c788b16c2392d3e1ebb570e56d7f871eaa1854f57917c0f131acb365/moderngl-5.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:51971d65ec96a212a814350c8b324ae0754353e1b61826d1a06aa2d060df170e", size = 1345675, upload-time = "2024-10-17T12:37:20.077Z" },
{ url = "https://files.pythonhosted.org/packages/b2/ec/6aff8fa267d9f80e4d32b7a606fdf9f0563103441a7dbaa4f53e272a4ada/moderngl-5.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d56827360c19e831e986243b5daaf6a51006f1ec0d5372084ad446308763d19f", size = 1274906, upload-time = "2024-10-17T12:37:22.372Z" },
{ url = "https://files.pythonhosted.org/packages/9f/4d/dc3ff763c125080e71b1095875f5dcc80949402019abc073bdfdbed1f4c2/moderngl-5.12.0-cp313-cp313-win32.whl", hash = "sha256:caa432c12b138a6c9571719075c4d103bdc2504cd31aeda38a00ad10fcf268cb", size = 101215, upload-time = "2024-10-17T12:37:23.833Z" },
{ url = "https://files.pythonhosted.org/packages/2c/8b/0a264732e0ee49fca109e98ec28f4d0c326ffc31466aa6e9668e8961aabb/moderngl-5.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e34d1cd38f7998258f76a08bb5e87f351ec653b7ea1928b2711f8719c10cefd1", size = 108514, upload-time = "2024-10-17T12:37:25.304Z" },
]
[[package]]
name = "moderngl-window"
version = "3.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "moderngl" },
{ name = "numpy" },
{ name = "pillow" },
{ name = "pyglet" },
{ name = "pyglm" },
]
sdist = { url = "https://files.pythonhosted.org/packages/90/02/92e235891300c901f59647112a0267a07454f58aeb2041aa44f6b85f9cb3/moderngl_window-3.1.1.tar.gz", hash = "sha256:29c2827505f87399f3461d480b2778910fddeebe44ea803301215cf212a6c1bc", size = 353495, upload-time = "2025-01-19T10:07:56.133Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/23/41/d3503f07de8ad3597165f88b07e1064629f82e65385c4307875b2f6b137f/moderngl_window-3.1.1-py3-none-any.whl", hash = "sha256:e3b3ac2b4e23afcbfdac1971318a4db893bed3ba6a8fbde3367b1226af39b2e5", size = 382381, upload-time = "2025-01-19T10:07:53.606Z" },
]
[[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.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/14/1d/d0a583ce4fefcc3308806a749a536c201ed6b5ad6e1322e227ee4848979d/numpy-2.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50", size = 16684933, upload-time = "2026-03-29T13:19:22.47Z" },
{ url = "https://files.pythonhosted.org/packages/c1/62/2b7a48fbb745d344742c0277f01286dead15f3f68e4f359fbfcf7b48f70f/numpy-2.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115", size = 14694532, upload-time = "2026-03-29T13:19:25.581Z" },
{ url = "https://files.pythonhosted.org/packages/e5/87/499737bfba066b4a3bebff24a8f1c5b2dee410b209bc6668c9be692580f0/numpy-2.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af", size = 5199661, upload-time = "2026-03-29T13:19:28.31Z" },
{ url = "https://files.pythonhosted.org/packages/cd/da/464d551604320d1491bc345efed99b4b7034143a85787aab78d5691d5a0e/numpy-2.4.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c", size = 6547539, upload-time = "2026-03-29T13:19:30.97Z" },
{ url = "https://files.pythonhosted.org/packages/7d/90/8d23e3b0dafd024bf31bdec225b3bb5c2dbfa6912f8a53b8659f21216cbf/numpy-2.4.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103", size = 15668806, upload-time = "2026-03-29T13:19:33.887Z" },
{ url = "https://files.pythonhosted.org/packages/d1/73/a9d864e42a01896bb5974475438f16086be9ba1f0d19d0bb7a07427c4a8b/numpy-2.4.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83", size = 16632682, upload-time = "2026-03-29T13:19:37.336Z" },
{ url = "https://files.pythonhosted.org/packages/34/fb/14570d65c3bde4e202a031210475ae9cde9b7686a2e7dc97ee67d2833b35/numpy-2.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed", size = 17019810, upload-time = "2026-03-29T13:19:40.963Z" },
{ url = "https://files.pythonhosted.org/packages/8a/77/2ba9d87081fd41f6d640c83f26fb7351e536b7ce6dd9061b6af5904e8e46/numpy-2.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959", size = 18357394, upload-time = "2026-03-29T13:19:44.859Z" },
{ url = "https://files.pythonhosted.org/packages/a2/23/52666c9a41708b0853fa3b1a12c90da38c507a3074883823126d4e9d5b30/numpy-2.4.4-cp313-cp313-win32.whl", hash = "sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed", size = 5959556, upload-time = "2026-03-29T13:19:47.661Z" },
{ url = "https://files.pythonhosted.org/packages/57/fb/48649b4971cde70d817cf97a2a2fdc0b4d8308569f1dd2f2611959d2e0cf/numpy-2.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf", size = 12317311, upload-time = "2026-03-29T13:19:50.67Z" },
{ url = "https://files.pythonhosted.org/packages/ba/d8/11490cddd564eb4de97b4579ef6bfe6a736cc07e94c1598590ae25415e01/numpy-2.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d", size = 10222060, upload-time = "2026-03-29T13:19:54.229Z" },
{ url = "https://files.pythonhosted.org/packages/99/5d/dab4339177a905aad3e2221c915b35202f1ec30d750dd2e5e9d9a72b804b/numpy-2.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5", size = 14822302, upload-time = "2026-03-29T13:19:57.585Z" },
{ url = "https://files.pythonhosted.org/packages/eb/e4/0564a65e7d3d97562ed6f9b0fd0fb0a6f559ee444092f105938b50043876/numpy-2.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7", size = 5327407, upload-time = "2026-03-29T13:20:00.601Z" },
{ url = "https://files.pythonhosted.org/packages/29/8d/35a3a6ce5ad371afa58b4700f1c820f8f279948cca32524e0a695b0ded83/numpy-2.4.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93", size = 6647631, upload-time = "2026-03-29T13:20:02.855Z" },
{ url = "https://files.pythonhosted.org/packages/f4/da/477731acbd5a58a946c736edfdabb2ac5b34c3d08d1ba1a7b437fa0884df/numpy-2.4.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e", size = 15727691, upload-time = "2026-03-29T13:20:06.004Z" },
{ url = "https://files.pythonhosted.org/packages/e6/db/338535d9b152beabeb511579598418ba0212ce77cf9718edd70262cc4370/numpy-2.4.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40", size = 16681241, upload-time = "2026-03-29T13:20:09.417Z" },
{ url = "https://files.pythonhosted.org/packages/e2/a9/ad248e8f58beb7a0219b413c9c7d8151c5d285f7f946c3e26695bdbbe2df/numpy-2.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e", size = 17085767, upload-time = "2026-03-29T13:20:13.126Z" },
{ url = "https://files.pythonhosted.org/packages/b5/1a/3b88ccd3694681356f70da841630e4725a7264d6a885c8d442a697e1146b/numpy-2.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392", size = 18403169, upload-time = "2026-03-29T13:20:17.096Z" },
{ url = "https://files.pythonhosted.org/packages/c2/c9/fcfd5d0639222c6eac7f304829b04892ef51c96a75d479214d77e3ce6e33/numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008", size = 6083477, upload-time = "2026-03-29T13:20:20.195Z" },
{ url = "https://files.pythonhosted.org/packages/d5/e3/3938a61d1c538aaec8ed6fd6323f57b0c2d2d2219512434c5c878db76553/numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8", size = 12457487, upload-time = "2026-03-29T13:20:22.946Z" },
{ url = "https://files.pythonhosted.org/packages/97/6a/7e345032cc60501721ef94e0e30b60f6b0bd601f9174ebd36389a2b86d40/numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233", size = 10292002, upload-time = "2026-03-29T13:20:25.909Z" },
{ url = "https://files.pythonhosted.org/packages/6e/06/c54062f85f673dd5c04cbe2f14c3acb8c8b95e3384869bb8cc9bff8cb9df/numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0", size = 16684353, upload-time = "2026-03-29T13:20:29.504Z" },
{ url = "https://files.pythonhosted.org/packages/4c/39/8a320264a84404c74cc7e79715de85d6130fa07a0898f67fb5cd5bd79908/numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a", size = 14704914, upload-time = "2026-03-29T13:20:33.547Z" },
{ url = "https://files.pythonhosted.org/packages/91/fb/287076b2614e1d1044235f50f03748f31fa287e3dbe6abeb35cdfa351eca/numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a", size = 5210005, upload-time = "2026-03-29T13:20:36.45Z" },
{ url = "https://files.pythonhosted.org/packages/63/eb/fcc338595309910de6ecabfcef2419a9ce24399680bfb149421fa2df1280/numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b", size = 6544974, upload-time = "2026-03-29T13:20:39.014Z" },
{ url = "https://files.pythonhosted.org/packages/44/5d/e7e9044032a716cdfaa3fba27a8e874bf1c5f1912a1ddd4ed071bf8a14a6/numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a", size = 15684591, upload-time = "2026-03-29T13:20:42.146Z" },
{ url = "https://files.pythonhosted.org/packages/98/7c/21252050676612625449b4807d6b695b9ce8a7c9e1c197ee6216c8a65c7c/numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d", size = 16637700, upload-time = "2026-03-29T13:20:46.204Z" },
{ url = "https://files.pythonhosted.org/packages/b1/29/56d2bbef9465db24ef25393383d761a1af4f446a1df9b8cded4fe3a5a5d7/numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252", size = 17035781, upload-time = "2026-03-29T13:20:50.242Z" },
{ url = "https://files.pythonhosted.org/packages/e3/2b/a35a6d7589d21f44cea7d0a98de5ddcbb3d421b2622a5c96b1edf18707c3/numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f", size = 18362959, upload-time = "2026-03-29T13:20:54.019Z" },
{ url = "https://files.pythonhosted.org/packages/64/c9/d52ec581f2390e0f5f85cbfd80fb83d965fc15e9f0e1aec2195faa142cde/numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc", size = 6008768, upload-time = "2026-03-29T13:20:56.912Z" },
{ url = "https://files.pythonhosted.org/packages/fa/22/4cc31a62a6c7b74a8730e31a4274c5dc80e005751e277a2ce38e675e4923/numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74", size = 12449181, upload-time = "2026-03-29T13:20:59.548Z" },
{ url = "https://files.pythonhosted.org/packages/70/2e/14cda6f4d8e396c612d1bf97f22958e92148801d7e4f110cabebdc0eef4b/numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb", size = 10496035, upload-time = "2026-03-29T13:21:02.524Z" },
{ url = "https://files.pythonhosted.org/packages/b1/e8/8fed8c8d848d7ecea092dc3469643f9d10bc3a134a815a3b033da1d2039b/numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e", size = 14824958, upload-time = "2026-03-29T13:21:05.671Z" },
{ url = "https://files.pythonhosted.org/packages/05/1a/d8007a5138c179c2bf33ef44503e83d70434d2642877ee8fbb230e7c0548/numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113", size = 5330020, upload-time = "2026-03-29T13:21:08.635Z" },
{ url = "https://files.pythonhosted.org/packages/99/64/ffb99ac6ae93faf117bcbd5c7ba48a7f45364a33e8e458545d3633615dda/numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d", size = 6650758, upload-time = "2026-03-29T13:21:10.949Z" },
{ url = "https://files.pythonhosted.org/packages/6e/6e/795cc078b78a384052e73b2f6281ff7a700e9bf53bcce2ee579d4f6dd879/numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d", size = 15729948, upload-time = "2026-03-29T13:21:14.047Z" },
{ url = "https://files.pythonhosted.org/packages/5f/86/2acbda8cc2af5f3d7bfc791192863b9e3e19674da7b5e533fded124d1299/numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f", size = 16679325, upload-time = "2026-03-29T13:21:17.561Z" },
{ url = "https://files.pythonhosted.org/packages/bc/59/cafd83018f4aa55e0ac6fa92aa066c0a1877b77a615ceff1711c260ffae8/numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0", size = 17084883, upload-time = "2026-03-29T13:21:21.106Z" },
{ url = "https://files.pythonhosted.org/packages/f0/85/a42548db84e65ece46ab2caea3d3f78b416a47af387fcbb47ec28e660dc2/numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150", size = 18403474, upload-time = "2026-03-29T13:21:24.828Z" },
{ url = "https://files.pythonhosted.org/packages/ed/ad/483d9e262f4b831000062e5d8a45e342166ec8aaa1195264982bca267e62/numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871", size = 6155500, upload-time = "2026-03-29T13:21:28.205Z" },
{ url = "https://files.pythonhosted.org/packages/c7/03/2fc4e14c7bd4ff2964b74ba90ecb8552540b6315f201df70f137faa5c589/numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e", size = 12637755, upload-time = "2026-03-29T13:21:31.107Z" },
{ url = "https://files.pythonhosted.org/packages/58/78/548fb8e07b1a341746bfbecb32f2c268470f45fa028aacdbd10d9bc73aab/numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7", size = 10566643, upload-time = "2026-03-29T13:21:34.339Z" },
]
[[package]]
name = "pillow"
version = "12.2.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" },
{ url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" },
{ url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" },
{ url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" },
{ url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" },
{ url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" },
{ url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" },
{ url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" },
{ url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" },
{ url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" },
{ url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" },
{ url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" },
{ url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" },
{ url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" },
{ url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" },
{ url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" },
{ url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" },
{ url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" },
{ url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" },
{ url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" },
{ url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" },
{ url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" },
{ url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" },
{ url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" },
{ url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" },
{ url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" },
{ url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" },
{ url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" },
{ url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" },
{ url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" },
{ url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" },
{ url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" },
{ url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" },
{ url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" },
{ url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" },
{ url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" },
{ url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" },
{ url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" },
{ url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" },
{ url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" },
{ url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" },
{ url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" },
{ url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" },
{ url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" },
{ url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" },
{ url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" },
{ url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" },
{ url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" },
{ url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" },
{ url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" },
]
[[package]]
name = "pycairo"
version = "1.29.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/22/d9/1728840a22a4ef8a8f479b9156aa2943cd98c3907accd3849fb0d5f82bfd/pycairo-1.29.0.tar.gz", hash = "sha256:f3f7fde97325cae80224c09f12564ef58d0d0f655da0e3b040f5807bd5bd3142", size = 665871, upload-time = "2025-11-11T19:13:01.584Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f0/21/3f477dc318dd4e84a5ae6301e67284199d7e5a2384f3063714041086b65d/pycairo-1.29.0-cp313-cp313-win32.whl", hash = "sha256:3eb382a4141591807073274522f7aecab9e8fa2f14feafd11ac03a13a58141d7", size = 750949, upload-time = "2025-11-11T19:12:12.198Z" },
{ url = "https://files.pythonhosted.org/packages/43/34/7d27a333c558d6ac16dbc12a35061d389735e99e494ee4effa4ec6d99bed/pycairo-1.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:91114e4b3fbf4287c2b0788f83e1f566ce031bda49cf1c3c3c19c3e986e95c38", size = 844149, upload-time = "2025-11-11T19:12:19.171Z" },
{ url = "https://files.pythonhosted.org/packages/15/43/e782131e23df69e5c8e631a016ed84f94bbc4981bf6411079f57af730a23/pycairo-1.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:09b7f69a5ff6881e151354ea092137b97b0b1f0b2ab4eb81c92a02cc4a08e335", size = 693595, upload-time = "2025-11-11T19:12:23.445Z" },
{ url = "https://files.pythonhosted.org/packages/2d/fa/87eaeeb9d53344c769839d7b2854db7ff2cd596211e00dd1b702eeb1838f/pycairo-1.29.0-cp314-cp314-win32.whl", hash = "sha256:69e2a7968a3fbb839736257bae153f547bca787113cc8d21e9e08ca4526e0b6b", size = 767198, upload-time = "2025-11-11T19:12:42.336Z" },
{ url = "https://files.pythonhosted.org/packages/3c/90/3564d0f64d0a00926ab863dc3c4a129b1065133128e96900772e1c4421f8/pycairo-1.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:e91243437a21cc4c67c401eff4433eadc45745275fa3ade1a0d877e50ffb90da", size = 871579, upload-time = "2025-11-11T19:12:48.982Z" },
{ url = "https://files.pythonhosted.org/packages/5e/91/93632b6ba12ad69c61991e3208bde88486fdfc152be8cfdd13444e9bc650/pycairo-1.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:b72200ea0e5f73ae4c788cd2028a750062221385eb0e6d8f1ecc714d0b4fdf82", size = 719537, upload-time = "2025-11-11T19:12:55.016Z" },
{ url = "https://files.pythonhosted.org/packages/93/23/37053c039f8d3b9b5017af9bc64d27b680c48a898d48b72e6d6583cf0155/pycairo-1.29.0-cp314-cp314t-win_amd64.whl", hash = "sha256:5e45fce6185f553e79e4ef1722b8e98e6cde9900dbc48cb2637a9ccba86f627a", size = 874015, upload-time = "2025-11-11T19:12:28.47Z" },
{ url = "https://files.pythonhosted.org/packages/d7/54/123f6239685f5f3f2edc123f1e38d2eefacebee18cf3c532d2f4bd51d0ef/pycairo-1.29.0-cp314-cp314t-win_arm64.whl", hash = "sha256:caba0837a4b40d47c8dfb0f24cccc12c7831e3dd450837f2a356c75f21ce5a15", size = 721404, upload-time = "2025-11-11T19:12:36.919Z" },
]
[[package]]
name = "pydub"
version = "0.25.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/fe/9a/e6bca0eed82db26562c73b5076539a4a08d3cffd19c3cc5913a3e61145fd/pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f", size = 38326, upload-time = "2021-03-10T02:09:54.659Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327, upload-time = "2021-03-10T02:09:53.503Z" },
]
[[package]]
name = "pyglet"
version = "2.1.14"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e8/a6/ffd78b2d05a820ced85baa11210b8e5d0db0d951767021150be0a231df00/pyglet-2.1.14.tar.gz", hash = "sha256:feb3fba05a85f50f793688d88ddfbcdc57044d971f2d8d2107eb7578eb4af51e", size = 6595146, upload-time = "2026-04-05T08:24:35.549Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ae/d4/789d34a4674a4ccc0b65ad54d0f963f873d39000c3ebed0880574d5437e5/pyglet-2.1.14-py3-none-any.whl", hash = "sha256:70febf03f206607103e1f9806527019c589002626937aecdca4d095ce0a4b9b0", size = 1032928, upload-time = "2026-04-05T08:24:29.068Z" },
]
[[package]]
name = "pyglm"
version = "2.8.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/41/8b/bdaf7b9cacecd28f7b4c6fc2d7d136824c506ad38cfdb37a05ea7ec88694/pyglm-2.8.3.tar.gz", hash = "sha256:161781ea4d1267f796b645f85ebff53aeb8ee4f13b4e993c04d64c96d286e534", size = 584038, upload-time = "2025-11-26T12:12:59.47Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2d/22/ee11dff20adfc6aac3e0482ed275843e0b9854dbc2e812ab56cdacbed8d6/pyglm-2.8.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a6d07b6b73e55a36e1b6daa63acb53f4912f2ddf88f434af4cc70441435aef8", size = 1608547, upload-time = "2025-11-26T12:11:46.426Z" },
{ url = "https://files.pythonhosted.org/packages/1e/5f/10c4cd636c3e6c63328a476f84bb03501d8016f12053c3a82ba588fc61ce/pyglm-2.8.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eaf6241f7c3ff169575e11da78f4439422517e42558961332db4cd09e9599267", size = 1362651, upload-time = "2025-11-26T12:11:47.555Z" },
{ url = "https://files.pythonhosted.org/packages/ff/70/2c7fe768900ee9d0f87e7a89375fa7d83b5b0a8f0eee8d0ad06b22a96e37/pyglm-2.8.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e1ec0dfb8f2c848c4ee6330c70a1ca9333004776c8e5ec76096e0b67c739f688", size = 12157160, upload-time = "2025-11-26T12:11:49.042Z" },
{ url = "https://files.pythonhosted.org/packages/b0/a6/befefccf1c8a0a66f09a7a1a1d324a3f988cb5e6b634026280518e5a83cd/pyglm-2.8.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3eea9093210afb946769c84fe31f17a9f73696a1161ee84fb42e9255f8c5cc8a", size = 12787899, upload-time = "2025-11-26T12:11:50.946Z" },
{ url = "https://files.pythonhosted.org/packages/7c/d2/5475d0791b585ae26dc0d690862a0e1e6fda243552a1718628dd937e5543/pyglm-2.8.3-cp313-cp313-manylinux_2_34_aarch64.whl", hash = "sha256:0c652650912dbd88994fa02ec9dba2f3b35dc3995427b6ae8056ae542d5a060a", size = 10886936, upload-time = "2025-11-26T12:11:53.628Z" },
{ url = "https://files.pythonhosted.org/packages/e1/a1/035068410f60ed53007e0488af96f7e4634b679e9156d1090e70732b2159/pyglm-2.8.3-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:e3bdda68f75ad270e66b0fc7a1883749489cca14c44cbe22bac038fa170a8a1c", size = 11711601, upload-time = "2025-11-26T12:11:55.367Z" },
{ url = "https://files.pythonhosted.org/packages/b5/e6/286d1879eae87199f086136b08c70a3bff27880417f98dadc0cbcdb65e50/pyglm-2.8.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:08f8b1bd0d80ce396ee9cd5d3d4c7aeb4bbfa2a54dc73413924e3c9982412528", size = 11939755, upload-time = "2025-11-26T12:11:57.23Z" },
{ url = "https://files.pythonhosted.org/packages/72/58/f40f109ac025bb18412db78e6e73ffc20a17b6b495de90352f5aabfb9982/pyglm-2.8.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:12fa61feefa5a255097d0887415bce9dd72c1dd5e5a8c6577121ee5348336a16", size = 12774242, upload-time = "2025-11-26T12:11:59.051Z" },
{ url = "https://files.pythonhosted.org/packages/17/fd/71b44ee5ac341e9979731a7b868e237f3775e140a9481cea79bae7abb83c/pyglm-2.8.3-cp313-cp313-win_amd64.whl", hash = "sha256:33118ef1d678ab573546757dee7f0a1ca2fba8e8d7760c9fe6320fe0cfa3deb7", size = 1663010, upload-time = "2025-11-26T12:12:00.914Z" },
{ url = "https://files.pythonhosted.org/packages/fa/1e/9b8ba9d4627585797d8bda952412c93a4c09b70cb25e64756a52accddc1e/pyglm-2.8.3-cp313-cp313-win_arm64.whl", hash = "sha256:73ff3785dfc4ce017626d7ab56d6711a7119c29e2e71294efed73810c1d307f9", size = 1239893, upload-time = "2025-11-26T12:12:02.032Z" },
{ url = "https://files.pythonhosted.org/packages/65/fe/494d7dce3fcaf0123e787320b4a558d8fe733d6d0e23b7fe51e687f88dc2/pyglm-2.8.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:b312012458d0537b3d84f24f4ba51fd3930df7a0773fc643e36f8df27b807c7a", size = 1610593, upload-time = "2025-11-26T12:12:03.136Z" },
{ url = "https://files.pythonhosted.org/packages/27/c0/37cced4a1b29957a29baebc1f0034be5d5419adf12da4b99140c56152cdb/pyglm-2.8.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3249bfe5352e18cc777fac591665679a99f270e1ff27cd11dc349af07684f007", size = 1366295, upload-time = "2025-11-26T12:12:04.176Z" },
{ url = "https://files.pythonhosted.org/packages/a7/ba/186176d1c3e26196ae4bec4b228bdbb1304576f2038a7f1635070923ee48/pyglm-2.8.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb8ea0d6721c763a26eacde59b2c9165719050dcf49c99a2857f6e1e5a5f30bb", size = 12140715, upload-time = "2025-11-26T12:12:05.429Z" },
{ url = "https://files.pythonhosted.org/packages/eb/3e/8d9f307649e9b79b34ae51303e46e7012cc2550d60e6dd00ea8d3d8c9cf2/pyglm-2.8.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:83effb89e2cf6dd79cf9ebecf2f9fbda3d25a92b61af264de3cadad408911de6", size = 12764551, upload-time = "2025-11-26T12:12:07.403Z" },
{ url = "https://files.pythonhosted.org/packages/4c/d6/2481433abe537d7019d9ce75eba86b57e1731e3e0352fd1ac7f31f4d1883/pyglm-2.8.3-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:e958d65ed55f2716fd8a3a2ef872cc52893ea7300d7feec62dccb27ec25fbc2f", size = 10869966, upload-time = "2025-11-26T12:12:09.198Z" },
{ url = "https://files.pythonhosted.org/packages/fe/bf/3c78a9718e1d26c5b6ec468a584eb30cd797c46b6edd08e79cb1d67e8bf0/pyglm-2.8.3-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:ec7cc14d2eb9f46a18012ee7c1a164e0395b058ceb6e341bf6d986316b698574", size = 11693025, upload-time = "2025-11-26T12:12:10.948Z" },
{ url = "https://files.pythonhosted.org/packages/d3/0d/00ef293153b6ca7e56d1be6facbd9d0a8e331d0c6d3114f47f2cf2913eda/pyglm-2.8.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4beb0ada21e7641a577f274496451befcde79965467ef4027bd933334b3de39b", size = 11920727, upload-time = "2025-11-26T12:12:12.845Z" },
{ url = "https://files.pythonhosted.org/packages/4e/10/d8ecf9b5ac3b6fc1b179b33dfbd087b8f4d4b12bab99b5794f569a15a99a/pyglm-2.8.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:77878c1b8c713b9e39fe32f870d82e20c864da3b11a3b875eca06c270b04cdbe", size = 12759345, upload-time = "2025-11-26T12:12:14.705Z" },
{ url = "https://files.pythonhosted.org/packages/a1/d1/cc1f75ee77fd2f9bcb122bc7f3a628710fe3f0bc517333fa9f38268a7065/pyglm-2.8.3-cp314-cp314-win_amd64.whl", hash = "sha256:15c77bc46ff69d945565309e13ca99c4a001d6a941a80c45f26fbdec80fa16c4", size = 1710524, upload-time = "2025-11-26T12:12:16.486Z" },
{ url = "https://files.pythonhosted.org/packages/35/51/74c0a3107567dc769c06b6c04c7bc828f33792e089036c637334b7e4c573/pyglm-2.8.3-cp314-cp314-win_arm64.whl", hash = "sha256:2b16ec33bd43c514502bae8de2b319d168259090e101e1cde79cd0a7d33e1185", size = 1271521, upload-time = "2025-11-26T12:12:17.611Z" },
{ url = "https://files.pythonhosted.org/packages/32/8e/867045b54da8257b21c71c0255ba7a231c251aae4b5f26b12eb50b651cc7/pyglm-2.8.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:6a1f1ab8debc06e0fdedb3f4285ded4bec38bf075652c393039838504767e6cf", size = 1633871, upload-time = "2025-11-26T12:12:18.791Z" },
{ url = "https://files.pythonhosted.org/packages/93/f5/81bb8b52e132dc1ecc87b7ffb50c714b4fd2f71f98b801dd376e036f942b/pyglm-2.8.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a7835d18747ab9f8e736e343cc35bee0a514f18add282f1fc8035945fcf9d9bd", size = 1387757, upload-time = "2025-11-26T12:12:20.497Z" },
{ url = "https://files.pythonhosted.org/packages/32/40/8581283c00e2a18a6bb20a9192e25a792b605c53dee1c3abb8871eb0d3ca/pyglm-2.8.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:af3ddee3d150bbef68ee7338ccd3e0710b75b08121b8efd52d786b0d2b6731be", size = 12724921, upload-time = "2025-11-26T12:12:21.802Z" },
{ url = "https://files.pythonhosted.org/packages/a0/0e/bc3c03038da822d1a66c38e166d4c89b6bdab846e576ac226442813af7f4/pyglm-2.8.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a76c8eaba0c58f5738e87be5efcd16c4e75540fe6ebfdf15c236a799a61358e", size = 13317946, upload-time = "2025-11-26T12:12:23.947Z" },
{ url = "https://files.pythonhosted.org/packages/3b/21/b1f52dc73d610e36aa3ccf3ef61634530e6f97c2ca809a057839bf578667/pyglm-2.8.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:879ee9ab3c8ab47b1de59fe7e593eda854b8349f274ca60f057b83f3a405b84d", size = 11371582, upload-time = "2025-11-26T12:12:25.768Z" },
{ url = "https://files.pythonhosted.org/packages/16/aa/e03cc7a2daceb1bbdf98780a991a323e4078254584cf6664984a626ecfe1/pyglm-2.8.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:3e37c15b6c3e08f960b34ff9ec42e73469dfd868aec214e8a347da6c9d0245d6", size = 12192848, upload-time = "2025-11-26T12:12:28.606Z" },
{ url = "https://files.pythonhosted.org/packages/69/07/be893aee24a9a8b5400feda4d032fad9d281047d4379aa9f5ef4bea1f6a4/pyglm-2.8.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd34a8670debef4a55bc756b14cbe8b0a4daa49f8f6850c86c5e11d20554927f", size = 12414214, upload-time = "2025-11-26T12:12:30.438Z" },
{ url = "https://files.pythonhosted.org/packages/0c/06/6bb4e8a09f7dd2bf8dc1f4cc5edc938fc1247a1b2770833515fb418fc695/pyglm-2.8.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:699f852e0335b79d0b664ba1c2d02cb4689256cda786e7780e821f60b0824c46", size = 13237516, upload-time = "2025-11-26T12:12:32.412Z" },
{ url = "https://files.pythonhosted.org/packages/2b/5c/7f15edd05020540748dad8f5eae0a07ed7f14f699bff530172b8850bd998/pyglm-2.8.3-cp314-cp314t-win_amd64.whl", hash = "sha256:78caadaf9cc2ddea1c55b0d44fa8032f35c9f821a6f152b72422e5657d38f01d", size = 1764614, upload-time = "2025-11-26T12:12:34.498Z" },
{ url = "https://files.pythonhosted.org/packages/a7/f9/8bc8d010503a250319c55d2ceec5f90b0e807c7f85d581638c5ecd0a81de/pyglm-2.8.3-cp314-cp314t-win_arm64.whl", hash = "sha256:69400ad1852ca0972e4d9cbef9d9510941d4b81dc0fffebc5ac796a85440a119", size = 1292992, upload-time = "2025-11-26T12:12:35.681Z" },
]
[[package]]
name = "pygments"
version = "2.20.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
]
[[package]]
name = "pyobjc-core"
version = "12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b8/b6/d5612eb40be4fd5ef88c259339e6313f46ba67577a95d86c3470b951fce0/pyobjc_core-12.1.tar.gz", hash = "sha256:2bb3903f5387f72422145e1466b3ac3f7f0ef2e9960afa9bcd8961c5cbf8bd21", size = 1000532, upload-time = "2025-11-14T10:08:28.292Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f4/d2/29e5e536adc07bc3d33dd09f3f7cf844bf7b4981820dc2a91dd810f3c782/pyobjc_core-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:01c0cf500596f03e21c23aef9b5f326b9fb1f8f118cf0d8b66749b6cf4cbb37a", size = 677370, upload-time = "2025-11-14T09:33:05.273Z" },
{ url = "https://files.pythonhosted.org/packages/1b/f0/4b4ed8924cd04e425f2a07269943018d43949afad1c348c3ed4d9d032787/pyobjc_core-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:177aaca84bb369a483e4961186704f64b2697708046745f8167e818d968c88fc", size = 719586, upload-time = "2025-11-14T09:33:53.302Z" },
{ url = "https://files.pythonhosted.org/packages/25/98/9f4ed07162de69603144ff480be35cd021808faa7f730d082b92f7ebf2b5/pyobjc_core-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:844515f5d86395b979d02152576e7dee9cc679acc0b32dc626ef5bda315eaa43", size = 670164, upload-time = "2025-11-14T09:34:37.458Z" },
{ url = "https://files.pythonhosted.org/packages/62/50/dc076965c96c7f0de25c0a32b7f8aa98133ed244deaeeacfc758783f1f30/pyobjc_core-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:453b191df1a4b80e756445b935491b974714456ae2cbae816840bd96f86db882", size = 712204, upload-time = "2025-11-14T09:35:24.148Z" },
]
[[package]]
name = "pyobjc-framework-cocoa"
version = "12.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyobjc-core" },
]
sdist = { url = "https://files.pythonhosted.org/packages/02/a3/16ca9a15e77c061a9250afbae2eae26f2e1579eb8ca9462ae2d2c71e1169/pyobjc_framework_cocoa-12.1.tar.gz", hash = "sha256:5556c87db95711b985d5efdaaf01c917ddd41d148b1e52a0c66b1a2e2c5c1640", size = 2772191, upload-time = "2025-11-14T10:13:02.069Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ad/31/0c2e734165abb46215797bd830c4bdcb780b699854b15f2b6240515edcc6/pyobjc_framework_cocoa-12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5a3dcd491cacc2f5a197142b3c556d8aafa3963011110102a093349017705118", size = 384689, upload-time = "2025-11-14T09:41:41.478Z" },
{ url = "https://files.pythonhosted.org/packages/23/3b/b9f61be7b9f9b4e0a6db18b3c35c4c4d589f2d04e963e2174d38c6555a92/pyobjc_framework_cocoa-12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:914b74328c22d8ca261d78c23ef2befc29776e0b85555973927b338c5734ca44", size = 388843, upload-time = "2025-11-14T09:42:05.719Z" },
{ url = "https://files.pythonhosted.org/packages/59/bb/f777cc9e775fc7dae77b569254570fe46eb842516b3e4fe383ab49eab598/pyobjc_framework_cocoa-12.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:03342a60fc0015bcdf9b93ac0b4f457d3938e9ef761b28df9564c91a14f0129a", size = 384932, upload-time = "2025-11-14T09:42:29.771Z" },
{ url = "https://files.pythonhosted.org/packages/58/27/b457b7b37089cad692c8aada90119162dfb4c4a16f513b79a8b2b022b33b/pyobjc_framework_cocoa-12.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6ba1dc1bfa4da42d04e93d2363491275fb2e2be5c20790e561c8a9e09b8cf2cc", size = 388970, upload-time = "2025-11-14T09:42:53.964Z" },
]
[[package]]
name = "rich"
version = "14.3.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" },
]
[[package]]
name = "scipy"
version = "1.17.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" },
{ url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" },
{ url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" },
{ url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" },
{ url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" },
{ url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" },
{ url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" },
{ url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" },
{ url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" },
{ url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" },
{ url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" },
{ url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" },
{ url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" },
{ url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" },
{ url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" },
{ url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" },
{ url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" },
{ url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" },
{ url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" },
{ url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" },
{ url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" },
{ url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" },
{ url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" },
{ url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" },
{ url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" },
{ url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" },
{ url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" },
{ url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" },
{ url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" },
{ url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" },
{ url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" },
{ url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" },
{ url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" },
{ url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" },
{ url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" },
{ url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" },
{ url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" },
{ url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" },
{ url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" },
{ url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" },
]
[[package]]
name = "screeninfo"
version = "0.8.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cython", marker = "sys_platform == 'darwin'" },
{ name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ec/bb/e69e5e628d43f118e0af4fc063c20058faa8635c95a1296764acc8167e27/screeninfo-0.8.1.tar.gz", hash = "sha256:9983076bcc7e34402a1a9e4d7dabf3729411fd2abb3f3b4be7eba73519cd2ed1", size = 10666, upload-time = "2022-09-09T11:35:23.419Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6e/bf/c5205d480307bef660e56544b9e3d7ff687da776abb30c9cb3f330887570/screeninfo-0.8.1-py3-none-any.whl", hash = "sha256:e97d6b173856edcfa3bd282f81deb528188aff14b11ec3e195584e7641be733c", size = 12907, upload-time = "2022-09-09T11:35:21.351Z" },
]
[[package]]
name = "skia-pathops"
version = "0.9.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/4a/f6/ab37d6fa21f25965d4ad059745c76f13ddfb92a2c06a842a42ad77961c24/skia_pathops-0.9.2.tar.gz", hash = "sha256:4b6d8459f6f4a69282cb26fca0c2bb0b321cc58a9bf9cc6579a52a391edc0319", size = 65115346, upload-time = "2026-02-16T10:30:22.753Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/75/10/45af3ea2dee706a340601da315e450c449f76aaa18651cfe2677b0c65161/skia_pathops-0.9.2-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:c7a925b919c050df1e0545d26a69b64d9c8e1959e4dca73b06df088bf01d30f0", size = 2897494, upload-time = "2026-02-16T10:30:00.265Z" },
{ url = "https://files.pythonhosted.org/packages/b4/20/711d733b252696aedd78175e0f60acd42299de680d5a50a2750b96578841/skia_pathops-0.9.2-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d94c18a60b1e56910240a65dcc841cca37067f6432a4881d20baff17b6d77915", size = 3300314, upload-time = "2026-02-16T10:30:02.53Z" },
{ url = "https://files.pythonhosted.org/packages/95/47/bccbdb7ee12bbcc43c1051f9fd6933d16e3ffc8f20263155bd03709bde9e/skia_pathops-0.9.2-cp310-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70b28883f209a0df84da14e980e7a07c55ed93b913955694d90ddef2f29a261b", size = 2999370, upload-time = "2026-02-16T10:30:04.445Z" },
{ url = "https://files.pythonhosted.org/packages/5e/55/d5a1925d61ab683aaf08a3a80749371991f82fdeb53e3dbeae0046ce80ac/skia_pathops-0.9.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8122e50e03472657781c951f3019d9b85d9b1cbc93ebac635b673f99b18895b6", size = 3955374, upload-time = "2026-02-16T10:30:06.308Z" },
{ url = "https://files.pythonhosted.org/packages/36/49/c81e1a551726b8153c7a600b041e4480ac85db13985b7b260a01d85e0a6c/skia_pathops-0.9.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f8c72c70e57dd6655f880ae63642ff26753bb888f4c6411709a12cc10bee005e", size = 4316667, upload-time = "2026-02-16T10:30:08.326Z" },
{ url = "https://files.pythonhosted.org/packages/bb/b4/484ba09325c75d4470578b3f16bfe5a30cc348ece2566df59702c487084c/skia_pathops-0.9.2-cp310-abi3-win32.whl", hash = "sha256:3b9ef6629d2c8cb8604a7e22d4d2fe2c0160788b9792145a2cf0f968ec245751", size = 1450912, upload-time = "2026-02-16T10:30:09.762Z" },
{ url = "https://files.pythonhosted.org/packages/ff/96/bd1bfaf5335242a86d8af940ff2124861e9bc6a5520cf96fda374fd10945/skia_pathops-0.9.2-cp310-abi3-win_amd64.whl", hash = "sha256:9ae72d801b5f4c5dbb937fb25476a12fa2da70860f28dd637da2b529dbd8271c", size = 1782901, upload-time = "2026-02-16T10:30:11.546Z" },
]
[[package]]
name = "soupsieve"
version = "2.8.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" },
]
[[package]]
name = "srt"
version = "3.5.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/66/b7/4a1bc231e0681ebf339337b0cd05b91dc6a0d701fa852bb812e244b7a030/srt-3.5.3.tar.gz", hash = "sha256:4884315043a4f0740fd1f878ed6caa376ac06d70e135f306a6dc44632eed0cc0", size = 28296, upload-time = "2023-03-28T02:35:44.007Z" }
[[package]]
name = "svgelements"
version = "1.9.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5d/29/1c93c94a2289675ba2ff898612f9c9a03f46d69f253bdf4da0dfc08a599d/svgelements-1.9.6.tar.gz", hash = "sha256:7c02ad6404cd3d1771fd50e40fbfc0550b0893933466f86a6eb815f3ba3f37f7", size = 162145, upload-time = "2023-08-17T02:01:51.822Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/48/2c/6c9bb53db56c8a12a736d2158a8b842a5993b96daabc29d90a098e840280/svgelements-1.9.6-py2.py3-none-any.whl", hash = "sha256:8a5cf2cc066d98e713d5b875b1d6e5eeb9b92e855e835ebd7caab2713ae1dcad", size = 137856, upload-time = "2023-08-17T02:01:48.76Z" },
]
[[package]]
name = "tqdm"
version = "4.67.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]
[[package]]
name = "watchdog"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
{ url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
{ url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
{ url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" },
{ url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" },
{ url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" },
{ url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" },
{ url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" },
{ url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
{ url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
]
-50
View File
@@ -1,50 +0,0 @@
// 404 — Document Not Found
.notfound-wrap {
min-height: 60dvh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 0;
}
.case-notice {
max-width: 480px;
text-align: center;
}
.case-notice-ref {
font-family: var(--font-mono);
font-size: 0.75rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--accent-color);
margin-bottom: 1.5rem;
}
.case-notice-title {
margin-top: 0;
}
.case-notice-body {
color: var(--text-muted);
max-width: none;
}
.case-notice-links {
display: flex;
justify-content: center;
gap: 1.5rem;
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid var(--border-color);
font-family: var(--font-mono);
font-size: 0.9rem;
a {
color: var(--text-color);
&:hover {
color: var(--accent-color);
}
}
}
-611
View File
@@ -1,611 +0,0 @@
// Article details and content styling
.reading-progress-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background-color: transparent;
z-index: 1000;
pointer-events: none;
}
.reading-progress-bar {
height: 100%;
width: 0%;
background-color: var(--accent-color);
transition: width 0.1s cubic-bezier(0.25, 0.8, 0.25, 1);
}
// Post Detail
.post-detail {
max-width: 800px;
margin: 0 auto;
padding-top: 4rem;
}
.post-header {
margin-bottom: 4rem;
}
.post-title {
margin-bottom: 1rem;
}
.post-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.4rem 0.75rem;
color: var(--text-muted);
font-size: 0.9rem;
font-style: italic;
}
.post-meta-item {
display: inline-flex;
align-items: center;
gap: 0.35rem;
}
.post-meta-label {
font-style: normal;
font-size: 0.75rem;
font-family: var(--font-mono);
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--accent-color);
opacity: 0.8;
}
.post-meta-sep {
color: var(--border-color);
font-style: normal;
user-select: none;
}
.post-meta-updated time {
color: var(--text-muted);
}
// Heading anchor links
.post-body {
h2,
h3 {
position: relative;
.heading-anchor {
display: inline-block;
margin-left: 0.5em;
color: var(--accent-color);
font-family: var(--font-mono);
font-weight: 400;
font-size: 0.75em;
opacity: 0;
text-decoration: none;
vertical-align: middle;
transition: opacity 0.15s ease;
user-select: none;
}
&:hover .heading-anchor {
opacity: 1;
}
}
}
// ──────────────────────────────────────────
// Series Navigation Box
// ──────────────────────────────────────────
.series-nav {
background: var(--surface-color);
border: 1px solid var(--border-color);
border-left: 3px solid var(--accent-color);
padding: 1.25rem 1.5rem;
margin-bottom: 2rem;
}
.series-nav-header {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 0.4rem 0.75rem;
margin-bottom: 1rem;
}
.series-nav-eyebrow {
font-family: var(--font-mono);
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--accent-color);
opacity: 0.8;
}
.series-nav-title {
font-weight: 600;
font-size: 0.95rem;
color: var(--heading-color, var(--text-color));
flex: 1;
}
.series-nav-badge {
font-family: var(--font-mono);
font-size: 0.75rem;
color: var(--text-muted);
background: var(--bg-color);
border: 1px solid var(--border-color);
padding: 0.1em 0.6em;
white-space: nowrap;
}
.series-nav-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.series-nav-item {
display: flex;
align-items: baseline;
gap: 0.75rem;
&.is-current {
.series-nav-index {
color: var(--accent-color);
}
.series-nav-label {
color: var(--text-color);
font-weight: 600;
}
}
}
.series-nav-index {
font-family: var(--font-mono);
font-size: 0.7rem;
color: var(--text-muted);
opacity: 0.6;
flex-shrink: 0;
width: 1.5ch;
text-align: right;
}
.series-nav-label {
font-size: 0.9rem;
color: var(--text-muted);
text-decoration: none;
&:hover {
color: var(--accent-color);
}
}
.post-toc {
background: var(--surface-color);
border: 1px solid var(--border-color);
padding: 1.5rem;
margin-bottom: 3rem;
summary {
font-weight: 600;
cursor: pointer;
list-style: none; /* Hide default arrow */
display: flex;
align-items: center;
gap: 0.5rem;
&::before {
content: '↓';
color: var(--accent-color);
transition: transform 0.2s ease;
}
}
&[open] summary::before {
transform: rotate(180deg);
}
ul {
margin-top: 1rem;
margin-bottom: 0;
list-style-type: none;
padding-left: 1rem;
}
li {
margin-bottom: 0.5rem;
}
a {
color: var(--text-muted);
font-size: 0.95em;
&:hover {
color: var(--accent-color);
}
}
}
.post-tags-share {
display: flex;
flex-direction: column;
gap: 2rem;
margin-top: 4rem;
@media (min-width: 640px) {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
.post-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.social-share {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
.share-label {
font-weight: 500;
color: var(--text-color);
margin-right: 0.25rem;
}
.share-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--surface-color);
border: 1px solid var(--border-color);
color: var(--text-muted);
transition: var(--transition-smooth);
cursor: pointer;
&:hover {
color: var(--bg-color);
transform: translateY(-2px);
border-color: transparent;
&.x {
background: #000000;
color: #ffffff;
}
&.bluesky {
background: #0285ff;
}
&.linkedin {
background: #0077b5;
}
&.reddit {
background: #ff4500;
}
&.hackernews {
background: #ff6600;
}
&.email {
background: #6b7280;
}
}
}
}
.post-nav {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid var(--border-color);
}
.post-nav-link {
display: flex;
flex-direction: column;
gap: 0.35rem;
align-items: center;
text-align: center;
max-width: 34ch;
}
.post-nav-label {
color: var(--accent-color);
font-size: 0.9rem;
font-weight: 500;
}
.post-nav-title {
font-size: 1rem;
line-height: 1.35;
color: var(--text-muted);
transition: color 0.2s ease;
}
.post-nav-link:hover .post-nav-title,
.post-nav-link:hover .post-nav-label {
color: var(--accent-color);
}
@media (max-width: 640px) {
.post-nav-title {
font-size: 0.95rem;
}
}
@media (min-width: 900px) {
.post-nav {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 2rem;
align-items: start;
}
.post-nav-prev {
justify-self: start;
align-items: flex-start;
text-align: left;
}
.post-nav-next {
justify-self: end;
align-items: flex-end;
text-align: right;
}
}
// ──────────────────────────────────────────
// Sidebar TOC Layout
// ──────────────────────────────────────────
.post-layout {
display: contents;
@media (min-width: 1200px) {
display: grid;
grid-template-columns: minmax(0, 800px) 240px;
gap: 3rem;
align-items: start;
max-width: 1100px;
margin: 0 auto;
}
}
@media (min-width: 1200px) {
.post-detail {
max-width: none;
margin: 0;
}
// Hide inline TOC — sidebar takes over
.post-toc {
display: none !important;
}
}
.post-toc-sidebar {
display: none;
@media (min-width: 1200px) {
display: block;
position: sticky;
top: 5.5rem;
max-height: calc(100vh - 7rem);
overflow-y: auto;
padding-top: 4rem; // align with article content start
scrollbar-width: thin;
scrollbar-color: var(--border-color) transparent;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--border-color);
}
}
}
.toc-nav {
ul {
list-style: none;
padding: 0;
margin: 0;
// Nested level (h2 children)
ul {
padding-left: 1rem;
margin-top: 0.25rem;
}
}
li {
margin-bottom: 0.35rem;
}
a {
display: block;
color: var(--text-muted);
font-size: 0.85rem;
line-height: 1.4;
padding: 0.2rem 0;
border-left: 2px solid transparent;
padding-left: 0.75rem;
transition:
color 0.2s ease,
border-color 0.2s ease;
text-decoration: none;
&:hover {
color: var(--accent-color);
}
&.toc-active {
color: var(--accent-color);
border-left-color: var(--accent-color);
}
}
}
.toc-sidebar-title {
font-size: 0.75rem;
font-family: var(--font-mono);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--text-muted);
margin: 0 0 1rem 0;
padding-left: 0.75rem;
}
// ──────────────────────────────────────────
// Media Wrappers (YouTube, etc)
// ──────────────────────────────────────────
.youtube-wrapper {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
overflow: hidden;
border: 1px solid var(--border-color);
margin: 2rem 0;
background: #000;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
}
// ──────────────────────────────────────────
// Callouts / Admonitions
// ──────────────────────────────────────────
.callout {
margin: 2rem 0;
padding: 1.25rem 1.5rem;
border-left: 4px solid var(--callout-color, var(--border-color));
background: var(--surface-color);
color: var(--text-color);
font-size: 0.95rem;
line-height: 1.6;
.callout-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
font-weight: 600;
color: var(--callout-color, var(--heading-color));
}
.callout-icon {
width: 1.25rem;
height: 1.25rem;
flex-shrink: 0;
}
.callout-title {
font-family: var(--font-mono);
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: 0.85rem;
}
.callout-content {
> :first-child {
margin-top: 0;
}
> :last-child {
margin-bottom: 0;
}
}
// Variants
&.callout-note {
--callout-color: #3b82f6; // Blue
background: rgba(59, 130, 246, 0.05);
}
&.callout-warning {
--callout-color: #f59e0b; // Amber
background: rgba(245, 158, 11, 0.05);
}
&.callout-tip {
--callout-color: #16a34a; // Green
background: rgba(22, 163, 74, 0.05);
}
&.callout-danger {
--callout-color: #ef4444; // Red
background: rgba(239, 68, 68, 0.05);
}
}
.comments {
margin-top: 4rem;
}
// ──────────────────────────────────────────
// Related Posts
// ──────────────────────────────────────────
.related-posts-section {
margin-top: 4rem;
padding-top: 2rem;
border-top: 1px solid var(--border-color);
h3 {
margin-bottom: 2rem;
font-size: 1.5rem;
color: var(--heading-color);
letter-spacing: -0.02em;
}
.related-posts-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
@media (min-width: 768px) {
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 2.5rem;
}
// Override some constraints from feed-page cards when inside the grid
.feed-item {
border-bottom: none !important;
padding-bottom: 0 !important;
background: var(--surface-color);
border: 1px solid var(--border-color);
padding: 1.5rem !important;
height: 100%;
display: flex;
flex-direction: column;
transition: var(--transition-smooth);
&:hover {
border-color: var(--accent-color);
}
.item-snippet {
flex: 1;
}
}
}
}
-304
View File
@@ -1,304 +0,0 @@
// Post Feed Page Container
.feed-page {
max-width: 800px;
margin: 0 auto;
}
// Post Feed
.post-feed {
display: flex;
flex-direction: column;
margin-top: 1rem;
}
.post-feed .feed-item {
padding: 2rem 0;
border-bottom: 1px solid var(--border-color);
&:first-child {
padding-top: 0;
}
}
// Homepage "View all posts" CTA
.view-all-posts {
display: flex;
justify-content: center;
margin-top: 3rem;
}
.btn-view-all {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.6rem 1.5rem;
border: 1px solid var(--accent-color);
border-radius: 2px;
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--accent-color);
background: transparent;
text-decoration: none;
transition: var(--transition-smooth);
letter-spacing: 0.04em;
&::after {
content: '→';
transition: transform 0.2s ease;
}
&:hover {
background: var(--accent-color);
color: var(--bg-color);
&::after {
transform: translateX(4px);
}
}
}
.feed-item {
display: block;
}
// Homepage post list (post-card.html) — a numbered index of entries
.feed-heading {
font-size: 1.1rem;
margin: 0 0 1.5rem;
}
.post-feed-list {
display: flex;
flex-direction: column;
}
.feed-item.card {
display: flex;
gap: 1.25rem;
border-bottom: 1px solid var(--border-color);
padding: 2rem 0;
&:first-child {
padding-top: 0;
}
.item-title {
font-size: 1.25rem;
margin-bottom: 0.5rem;
font-weight: 600;
a {
transition: color 0.2s ease;
}
}
&:hover .item-title a {
color: var(--accent-color);
}
}
.item-index {
font-family: var(--font-mono);
font-size: 0.85rem;
color: var(--text-muted);
padding-top: 0.3rem;
flex-shrink: 0;
}
.item-body {
min-width: 0;
flex: 1;
}
.item-meta {
display: flex;
align-items: center;
gap: 0.35rem;
font-size: 0.85rem;
color: var(--text-muted);
margin-bottom: 1rem;
font-family: var(--font-mono);
}
.item-meta-sep {
opacity: 0.5;
}
.item-snippet {
color: var(--text-color);
opacity: 0.9;
margin-bottom: 1rem;
p {
margin: 0;
}
}
.item-footer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 0.75rem;
font-size: 0.85rem;
}
.item-readmore {
display: inline-flex;
align-items: center;
gap: 0.35rem;
color: var(--accent-color);
.readmore-arrow {
transition: transform 0.2s ease;
}
&:hover .readmore-arrow {
transform: translateX(4px);
}
}
.item-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.item-link {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.item-date-row {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.25rem;
}
.item-date {
font-family: var(--font-mono);
font-size: 0.85rem;
color: var(--text-muted);
font-variant-numeric: tabular-nums;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.item-reading-time {
color: var(--text-muted);
font-size: 0.85rem;
font-family: var(--font-mono);
}
.item-title {
margin: 0;
font-size: clamp(1.5rem, 2vw, 2rem);
transition: color 0.2s ease;
}
.item-link:hover .item-title {
color: var(--accent-color);
}
.item-desc {
margin: 0;
color: var(--text-muted);
}
// ──────────────────────────────────────────
// Pagination
// ──────────────────────────────────────────
.pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin-top: 5rem;
padding-top: 2rem;
border-top: 1px solid var(--border-color);
font-family: var(--font-mono);
}
.pagination-pages {
display: flex;
align-items: center;
gap: 0.25rem;
}
// Shared base for arrows + numbers
.pagination-arrow,
.pagination-num {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2.25rem;
height: 2.25rem;
padding: 0 0.5rem;
border-radius: 2px;
border: 1px solid var(--border-color);
background: var(--surface-color);
color: var(--text-muted);
font-size: 0.875rem;
text-decoration: none;
transition: var(--transition-smooth);
cursor: pointer;
user-select: none;
&:hover {
border-color: var(--accent-color);
color: var(--accent-color);
transform: translateY(-1px);
}
}
// Active / current page
.pagination-num.is-current {
background: var(--accent-color);
border-color: var(--accent-color);
color: #fff;
font-weight: 600;
cursor: default;
pointer-events: none;
&:hover {
transform: none;
}
}
// Disabled arrow (no prev/next page)
.pagination-arrow.is-disabled {
opacity: 0.3;
cursor: not-allowed;
pointer-events: none;
&:hover {
border-color: var(--border-color);
color: var(--text-muted);
transform: none;
}
}
// Ellipsis gap marker
.pagination-ellipsis {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2.25rem;
height: 2.25rem;
color: var(--text-muted);
font-size: 0.875rem;
letter-spacing: 0.05em;
}
// "Page N of M" helper text
.pagination-meta {
text-align: center;
margin-top: 1rem;
margin-bottom: 0;
font-size: 0.8rem;
color: var(--text-muted);
font-family: var(--font-mono);
letter-spacing: 0.05em;
}
-10
View File
@@ -1,10 +0,0 @@
// Footer
.site-footer {
padding: 2rem 0 3rem;
border-top: 3px solid var(--text-color);
color: var(--text-muted);
font-size: 0.85rem;
font-family: var(--font-mono);
display: flex;
justify-content: space-between;
}
-183
View File
@@ -1,183 +0,0 @@
// Component: Header
.site-header {
padding: 1.25rem 0;
position: sticky;
top: 0;
z-index: 50;
background-color: var(--bg-color);
border-bottom: 2px solid var(--text-color);
}
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
}
// Right side wrapper (links + controls)
.nav-right {
display: flex;
align-items: center;
gap: 1rem;
}
// Always-visible icon controls
.nav-controls {
display: flex;
align-items: center;
gap: 0.5rem;
}
.search-toggle {
background: none;
border: none;
color: var(--text-color);
cursor: pointer;
padding: 0.35rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: var(--transition-smooth);
&:hover {
color: var(--accent-color);
}
}
// Hamburger button — hidden on desktop, shown on mobile
.nav-toggle {
display: none;
background: none;
border: none;
color: var(--text-color);
cursor: pointer;
padding: 0.25rem;
align-items: center;
justify-content: center;
.close-icon {
display: none;
}
&[aria-expanded='true'] {
.hamburger-icon {
display: none;
}
.close-icon {
display: block;
}
}
}
@media (max-width: 640px) {
.nav-toggle {
display: flex;
}
// Hide the site name when the menu is open
.nav-container:has(#nav-toggle[aria-expanded='true']) .brand-link {
display: none;
}
// Make nav-right fill the full width so menu items span the container
.nav-container:has(#nav-toggle[aria-expanded='true']) .nav-right {
width: 100%;
}
.nav-right {
flex-wrap: wrap;
justify-content: flex-end;
}
.nav-links {
display: flex !important;
flex-direction: column !important;
align-items: flex-start !important;
gap: 0 !important;
width: 100%;
order: 10; // push below nav-controls
padding: 0;
margin-top: 0;
border-top: 1px solid transparent;
max-height: 0;
opacity: 0;
overflow: hidden;
transition:
max-height 0.3s cubic-bezier(0.16, 1, 0.3, 1),
opacity 0.2s ease;
&.is-open {
padding: 1rem 0;
margin-top: 0.5rem;
border-top-color: var(--border-color);
max-height: 320px;
opacity: 1;
}
.nav-item {
width: 100%;
padding: 0.75rem 0;
font-size: 1rem;
border-bottom: 1px solid var(--border-color);
&::after {
display: none;
}
}
}
}
// Brand reads like a running header on a printed document — quiet,
// small, letter-spaced — not competing with the masthead title below it.
.brand-text {
font-family: var(--font-mono);
font-weight: 600;
font-size: 0.8rem;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-muted);
}
.brand-link:hover .brand-text {
color: var(--accent-color);
}
.nav-links {
display: flex;
align-items: center;
gap: 1.75rem;
}
.nav-item {
font-family: var(--font-mono);
font-weight: 500;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-color);
position: relative;
}
.nav-item::after {
content: '';
position: absolute;
width: 100%;
height: 2px;
bottom: -4px;
left: 0;
background-color: var(--accent-color);
transform: scaleX(0);
transform-origin: left;
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-item:hover::after {
transform: scaleX(1);
}
.nav-item.is-active {
color: var(--accent-color);
&::after {
transform: scaleX(1);
}
}
-70
View File
@@ -1,70 +0,0 @@
// Hero Section
.hero {
padding: 8rem 0 6rem 0;
max-width: 800px;
}
.hero-compact {
padding-bottom: 2rem;
}
.hero-title {
color: var(--text-color);
}
.hero-subtitle {
font-size: clamp(1.1rem, 1.5vw, 1.3rem);
color: var(--text-muted);
}
// Homepage masthead — spans the full width of .site-container, matching the navbar
.masthead {
padding: 4rem 0 3rem;
}
.masthead-kicker {
font-family: var(--font-mono);
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--accent-color);
margin-bottom: 1rem;
}
.masthead-title {
margin-top: 0;
}
// Colophon-style contact line — quiet, small, middot-separated
.masthead-links {
display: flex;
flex-wrap: wrap;
row-gap: 0.4rem;
margin-top: 2rem;
font-family: var(--font-mono);
font-size: 0.8rem;
letter-spacing: 0.02em;
a {
display: inline-flex;
align-items: center;
gap: 0.4rem;
color: var(--text-muted);
transition: var(--transition-smooth);
svg {
flex-shrink: 0;
}
&:hover {
color: var(--accent-color);
}
&:not(:last-child)::after {
content: '·';
margin: 0 0.75rem;
color: var(--text-muted);
opacity: 0.5;
}
}
}
-37
View File
@@ -1,37 +0,0 @@
// Layout Constraints
.site-container {
width: 100%;
max-width: 1400px;
margin: 0 auto;
padding: 0 5vw;
display: flex;
flex-direction: column;
min-height: 100dvh;
box-sizing: border-box;
}
// Constrain all media & tables to their container
img,
video,
iframe,
table,
svg {
max-width: 100%;
}
table {
display: block;
overflow-x: auto;
@media (max-width: 640px) {
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
}
// Main Content
.main-content {
flex-grow: 1;
padding-bottom: 5rem;
}
-107
View File
@@ -1,107 +0,0 @@
// Archive & Tags list pages
.list-page-header {
margin-bottom: 3rem;
}
.list-page-title {
font-size: clamp(2.5rem, 5vw, 4.5rem);
}
.term-hash {
color: var(--text-muted);
}
.tag-description {
max-width: 65ch;
margin: 0.75rem 0 0;
color: var(--text-muted);
font-size: 1.05rem;
}
.archive-list {
max-width: 65ch;
margin: 0 auto;
}
.archive-year {
margin-bottom: 2rem;
}
.archive-year-title {
font-size: 1.5rem;
margin-top: 2rem;
margin-bottom: 1rem;
}
.archive-items {
list-style: none;
padding-left: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.archive-item {
display: flex;
gap: 1rem;
align-items: baseline;
}
.archive-date {
font-family: var(--font-mono);
color: var(--text-muted);
font-size: 0.95rem;
white-space: nowrap;
}
.archive-link {
color: var(--accent-color);
font-weight: 500;
font-size: 1.05rem;
}
// Tags index
.tags-page {
max-width: 65ch;
margin: 0 auto;
padding-top: 4rem;
text-align: center;
}
.tags-page-header {
margin-bottom: 3rem;
}
.page-title {
font-size: 2rem;
font-weight: 600;
}
.tags-container {
display: flex;
flex-wrap: wrap;
gap: 2rem;
justify-content: center;
align-items: center;
}
.tag-link {
font-size: 1.1rem;
color: var(--text-color);
font-weight: 400;
display: inline-flex;
align-items: flex-start;
&:hover {
color: var(--accent-color);
}
}
.tag-count {
font-size: 0.7em;
color: var(--text-muted);
margin-left: 0.15rem;
margin-top: 0.1rem;
}
-58
View File
@@ -1,58 +0,0 @@
// Global Reset & Base
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-family: var(--font-sans);
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
background-color: var(--bg-color);
color: var(--text-color);
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition:
background-color 0.3s ease,
color 0.3s ease;
// Firefox
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
// Webkit
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--scrollbar-track);
}
::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb);
border-radius: 0; // hard edges = terminal feel
border: 1px solid var(--scrollbar-track);
&:hover {
background: var(--scrollbar-thumb-hover);
}
}
body {
line-height: 1.7;
min-height: 100dvh;
display: flex;
flex-direction: column;
overflow-wrap: break-word; // break long words instead of overflowing
word-break: break-word;
}
a {
color: inherit;
text-decoration: none;
transition: var(--transition-smooth);
}
-64
View File
@@ -1,64 +0,0 @@
// Scroll to Top Floating Button
.scroll-to-top {
position: fixed;
bottom: 2rem;
right: 2rem;
display: flex;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
border-radius: 2px;
background: var(--bg-color);
color: var(--accent-color);
border: 1px solid var(--accent-color);
cursor: pointer;
z-index: 100;
// Hidden state by default
opacity: 0;
visibility: hidden;
transform: translateY(1rem);
transition:
transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
opacity 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
visibility 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
box-shadow 0.2s ease-out;
// Visible state triggered by JS
&.visible {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
@media (hover: hover) {
&:hover {
background: var(--accent-color);
color: var(--bg-color);
transform: translateY(-0.25rem);
box-shadow: 0 4px 12px color-mix(in srgb, var(--accent-color) 20%, transparent);
}
&:hover svg {
transform: translateY(-2px);
}
}
&:focus-visible {
outline: 2px solid var(--accent-color);
outline-offset: 4px;
}
svg {
transition: transform 0.2s ease;
}
// Responsive padding for mobile devices
@media (max-width: 768px) {
bottom: 1.5rem;
right: 1.5rem;
width: 2.75rem;
height: 2.75rem;
}
}
-149
View File
@@ -1,149 +0,0 @@
// Search Modal Styles
.search-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 10000;
display: flex;
justify-content: center;
align-items: flex-start;
padding-top: 10vh;
opacity: 0;
visibility: hidden;
transition:
opacity 0.2s ease,
visibility 0.2s ease;
&.active {
opacity: 1;
visibility: visible;
.search-modal {
transform: translateY(0) scale(1);
}
}
}
.search-modal {
width: 90%;
max-width: 600px;
background: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: 2px;
box-shadow: 0 12px 32px var(--shadow-color);
transform: translateY(-20px) scale(0.98);
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: flex;
flex-direction: column;
overflow: hidden;
}
.search-header {
display: flex;
align-items: center;
padding: 1rem 1.25rem;
border-bottom: 1px solid var(--border-color);
background: var(--surface-color);
svg {
color: var(--text-muted);
margin-right: 0.75rem;
}
}
#search-input {
flex: 1;
background: transparent;
border: none;
color: var(--text-color);
font-family: var(--font-mono);
font-size: 1rem;
outline: none;
&::placeholder {
color: var(--text-muted);
}
}
.search-footer {
padding: 0.5rem 1.25rem;
background: var(--surface-color);
border-top: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.75rem;
color: var(--text-muted);
kbd {
background: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: 4px;
padding: 0.1rem 0.3rem;
font-family: var(--font-mono);
font-size: 0.7rem;
margin: 0 0.2rem;
}
}
.search-results {
max-height: 50vh;
overflow-y: auto;
padding: 0.5rem;
// Custom scrollbar
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: var(--border-color);
border-radius: 4px;
}
.search-result-item {
display: flex;
flex-direction: column;
padding: 0.75rem 1rem;
border-radius: 2px;
text-decoration: none;
color: var(--text-color);
transition: background-color 0.15s ease;
border-left: 2px solid transparent;
&:hover,
&.selected {
background-color: var(--surface-color);
border-left-color: var(--accent-color);
}
.result-title {
font-weight: 500;
color: var(--accent-color);
margin-bottom: 0.25rem;
}
.result-summary {
font-size: 0.85rem;
color: var(--text-muted);
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
}
.no-results {
padding: 2rem;
text-align: center;
color: var(--text-muted);
font-style: italic;
}
}
-31
View File
@@ -1,31 +0,0 @@
// Component: Theme Toggle
.theme-toggle {
background: none;
border: none;
color: var(--text-color);
cursor: pointer;
padding: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: var(--transition-smooth);
svg {
width: 20px;
height: 20px;
}
}
html.dark .sun-icon {
display: block;
}
html.dark .moon-icon {
display: none;
}
html:not(.dark) .sun-icon {
display: none;
}
html:not(.dark) .moon-icon {
display: block;
}
-55
View File
@@ -1,55 +0,0 @@
/*
* Cross-Document View Transitions
* Enabled via <meta name="view-transition" content="same-origin" />
*/
// Disable default CSS transitions on the whole page during a view transition
// so they don't fight with the View Transition API animation.
html::view-transition-group(*) {
animation-duration: 0.3s;
animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}
// Custom animation for the old page leaving
@keyframes fade-out-scale {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.98);
}
}
// Custom animation for the new page entering
@keyframes fade-in-scale {
from {
opacity: 0;
transform: scale(1.02);
}
to {
opacity: 1;
transform: scale(1);
}
}
// Apply the custom animations to the root view transition pseudo-elements
html::view-transition-old(root) {
animation: fade-out-scale 0.25s cubic-bezier(0.4, 0, 1, 1) both;
}
html::view-transition-new(root) {
animation: fade-in-scale 0.35s cubic-bezier(0, 0, 0.2, 1) both;
// Delay slightly so the old page fades down first before the new one pops over
animation-delay: 0.05s;
}
// Respect user preference for reduced motion
@media (prefers-reduced-motion: reduce) {
html::view-transition-group(*),
html::view-transition-old(*),
html::view-transition-new(*) {
animation: none !important;
}
}
-195
View File
@@ -1,195 +0,0 @@
// Typography Scale (Fluid)
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--font-display);
font-weight: 700;
line-height: 1.15;
letter-spacing: -0.01em;
margin-top: 2em;
margin-bottom: 0.75em;
overflow-wrap: break-word;
word-break: break-word;
text-wrap: balance;
}
h1 {
font-size: clamp(1.75rem, 5vw, 4.5rem);
margin-top: 0;
}
h2 {
font-size: clamp(1.35rem, 3vw, 2.5rem);
}
h3 {
font-size: clamp(1.2rem, 2vw, 1.8rem);
}
h4 {
font-size: clamp(1.05rem, 1.5vw, 1.3rem);
}
h5 {
font-size: clamp(1rem, 1.25vw, 1.15rem);
}
h6 {
font-size: clamp(0.9rem, 1vw, 1rem);
}
p,
ul,
ol,
figure,
blockquote,
pre,
table {
margin-bottom: 1.5rem;
}
hr {
border: none;
border-top: 1px solid var(--border-color);
margin: 2rem 0;
}
p {
max-width: 65ch; // Optimal reading width
text-wrap: pretty;
}
// Footnotes
.footnote-reference {
font-size: 0.75em;
vertical-align: super;
line-height: 0;
a {
color: var(--accent-color);
font-family: var(--font-mono);
padding: 0 0.15em;
&:hover {
text-decoration: underline;
}
}
}
.footnote-definition {
display: flex;
gap: 0.75rem;
margin-bottom: 0.75rem;
font-size: 0.875rem;
color: var(--text-muted);
border-left: 2px solid var(--border-color);
padding-left: 1rem;
p {
margin: 0;
max-width: none;
}
}
.footnote-definition-label {
flex-shrink: 0;
font-family: var(--font-mono);
color: var(--accent-color);
font-size: 0.8em;
margin-top: 0.1em;
}
.footnote-backref {
font-family: var(--font-mono);
color: var(--accent-color);
font-size: 0.9em;
text-decoration: none;
opacity: 0.7;
transition: opacity 0.2s ease;
&:hover {
opacity: 1;
}
}
code,
pre {
font-family: var(--font-mono);
font-size: 0.9em;
font-feature-settings:
'liga' 1,
'calt' 1;
font-variant-ligatures: contextual;
}
.code-block-wrapper {
position: relative;
}
pre {
padding: 1.25rem;
border-radius: 2px;
overflow-x: auto;
max-width: 100%;
border: 1px solid var(--border-color);
background: #282828; // Gruvbox Dark bg0 (matches [markdown.highlighting] theme)
// Scrollbars visible on desktop, hidden on mobile
@media (max-width: 640px) {
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
font-size: 0.82em;
}
}
.copy-code-btn {
position: absolute;
top: 0.5rem;
right: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: rgba(235, 219, 178, 0.1);
color: #ebdbb2;
border: 1px solid rgba(235, 219, 178, 0.2);
border-radius: 2px;
cursor: pointer;
opacity: 1;
transition:
background 0.2s ease,
color 0.2s ease;
svg {
width: 16px;
height: 16px;
}
&:hover {
background: rgba(235, 219, 178, 0.2);
color: #fbf1c7;
}
&.copied {
background: var(--accent-color);
border-color: var(--accent-color);
color: var(--bg-color);
}
}
// Button is always visible, no hover-to-reveal needed
code {
background: var(--surface-color);
padding: 0.2em 0.4em;
border-radius: 2px;
color: var(--accent-color);
border: 1px solid var(--border-color);
}
pre code {
background: transparent;
color: inherit;
padding: 0;
border: none;
}
-39
View File
@@ -1,39 +0,0 @@
// Tag chip — a small filed label, shared by post-card and post-tags
.tag {
display: inline-block;
background: var(--surface-color);
border: 1px solid var(--border-color);
padding: 0.2rem 0.6rem;
border-radius: 2px;
font-size: 0.8rem;
font-family: var(--font-mono);
text-transform: uppercase;
letter-spacing: 0.03em;
color: var(--text-muted);
transition: var(--transition-smooth);
&:hover {
color: var(--accent-color);
border-color: var(--accent-color);
}
}
// Heavy hairline rule — the site's one recurring structural device
// (masthead, between list entries, above case-reference blocks)
.rule {
border: none;
border-top: 3px solid var(--text-color);
}
// Utilities / Interactions
.hover-scale {
transition: transform 140ms ease-out;
&:hover {
transform: scale(1.02);
}
&:active {
transform: scale(0.98);
}
}
-42
View File
@@ -1,42 +0,0 @@
// Design Variables — "Case File": a declassified incident-report aesthetic.
// One accent only; flat colors + hairline borders, no gradients or glass blur.
:root {
--bg-color: #e9e9e2; // paper (cool bone, not warm cream)
--surface-color: #dedecf; // slightly recessed paper — cards, code blocks
--text-color: #17181c; // ink
--text-muted: #68675f; // faded ink
--accent-color: #b42318; // classified-stamp red
--accent-hover: #8e1b12;
--border-color: rgba(23, 24, 28, 0.16);
--shadow-color: rgba(23, 24, 28, 0.08);
--font-sans: 'Source Serif 4', Georgia, serif; // body copy
--font-display: 'IBM Plex Serif', Georgia, serif; // headings, masthead
--font-mono: 'JetBrains Mono', monospace; // case-reference lines, tags, code
--transition-smooth:
transform 0.2s cubic-bezier(0.16, 1, 0.3, 1),
color 0.2s cubic-bezier(0.16, 1, 0.3, 1),
background-color 0.2s cubic-bezier(0.16, 1, 0.3, 1),
border-color 0.2s cubic-bezier(0.16, 1, 0.3, 1);
--scrollbar-track: #dedecf;
--scrollbar-thumb: #b0afa2;
--scrollbar-thumb-hover: #b42318;
}
// Dark mode — same document, read at night
html.dark {
--bg-color: #131311;
--surface-color: #1b1a17;
--text-color: #e9e7de;
--text-muted: #8b8a80;
--accent-color: #ff5a46;
--accent-hover: #ff7c6b;
--border-color: rgba(233, 231, 222, 0.14);
--shadow-color: rgba(0, 0, 0, 0.5);
--scrollbar-track: #1b1a17;
--scrollbar-thumb: #3a382f;
--scrollbar-thumb-hover: #ff5a46;
}
-19
View File
@@ -1,19 +0,0 @@
// Main SCSS entry point
// Organized by feature and section for maintainability
@import 'variables';
@import 'reset';
@import 'typography';
@import 'layout';
@import 'header';
@import 'theme';
@import 'hero';
@import 'feed';
@import 'lists';
@import 'article';
@import 'footer';
@import 'search';
@import 'transitions';
@import 'utilities';
@import 'scroll-top';
@import '404';
-13
View File
@@ -1,13 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEalcjtBYJKwYBBAHaRw8BAQdA55X1mRCKw9DA35kCAy+7Z30ye0rUHWBZsl7O
Wmar+RS0IklhbiBBbmR3YXRpIDxhbmR3YXRpaWFuQGdtYWlsLmNvbT6IkwQTFgoA
OxYhBK1YqreiDYUjy/WaeR8g/tCqBbDaBQJqVyO0AhsDBQsJCAcCAiICBhUKCQgL
AgQWAgMBAh4HAheAAAoJEB8g/tCqBbDace8BAN1SpkEMSYll+XupKHiaIUwnhm4N
eS79G1i+345Gl6CyAQDjgn+3rzG6sexjKh+10EKiy5omsQEGzUW03s7gS0T1Drg4
BGpXI7QSCisGAQQBl1UBBQEBB0CXofBIYYXG2+dZqgllhsbkNPF4qlyfPgbRW+zb
7Kw3IAMBCAeIeAQYFgoAIBYhBK1YqreiDYUjy/WaeR8g/tCqBbDaBQJqVyO0AhsM
AAoJEB8g/tCqBbDauMkA/RG4iqtPZOI3DQzFJYu7SnxaD81vdP0LyTLKDQkynySu
AQDrlWyF8LRlad4iX1yQPCuOV0aUpTNq5kPlWurtX99/BQ==
=uKsS
-----END PGP PUBLIC KEY BLOCK-----
-17
View File
@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Contact: mailto:[email protected]
Expires: 2027-07-16T00:00:00.000Z
Encryption: https://andwati.com/.well-known/pgp-key.txt
Encryption: https://keys.openpgp.org/vks/v1/by-fingerprint/AD58AAB7A20D8523CBF59A791F20FED0AA05B0DA
Encryption: https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xAD58AAB7A20D8523CBF59A791F20FED0AA05B0DA
Preferred-Languages: en
Canonical: https://andwati.com/.well-known/security.txt
-----BEGIN PGP SIGNATURE-----
iHUEARYKAB0WIQStWKq3og2FI8v1mnkfIP7QqgWw2gUCaljXlQAKCRAfIP7QqgWw
2qAoAP0Q7Cc0YsP2dvV7fqDlqcnjuJepQQSTZBz7ehkPyjGV5gEA3K9ZqQmuI2ea
KKADWxuKTTY43PBmuV9rMqLm8ZOPlAY=
=NUkY
-----END PGP SIGNATURE-----
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

-75
View File
@@ -1,75 +0,0 @@
/* IBM Plex Serif — display/headings */
@font-face {
font-family: 'IBM Plex Serif';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('../fonts/ibm-plex-serif/ibm-plex-serif-v20-latin-regular.woff2') format('woff2');
}
@font-face {
font-family: 'IBM Plex Serif';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('../fonts/ibm-plex-serif/ibm-plex-serif-v20-latin-600.woff2') format('woff2');
}
@font-face {
font-family: 'IBM Plex Serif';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('../fonts/ibm-plex-serif/ibm-plex-serif-v20-latin-700.woff2') format('woff2');
}
/* Source Serif 4 — body copy */
@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('../fonts/source-serif-4/source-serif-4-v14-latin-regular.woff2') format('woff2');
}
@font-face {
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('../fonts/source-serif-4/source-serif-4-v14-latin-italic.woff2') format('woff2');
}
@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('../fonts/source-serif-4/source-serif-4-v14-latin-600.woff2') format('woff2');
}
/* JetBrains Mono (official release — full ligature support) — case-reference lines, tags, code */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('../fonts/jetbrains-mono/JetBrainsMono-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('../fonts/jetbrains-mono/JetBrainsMono-Italic.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('../fonts/jetbrains-mono/JetBrainsMono-Bold.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url('../fonts/jetbrains-mono/JetBrainsMono-BoldItalic.woff2') format('woff2');
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1128
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

-73
View File
@@ -1,73 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
// Select all <pre> elements that contain code blocks
const preBlocks = document.querySelectorAll('pre');
const copyIcon =
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg>';
const checkIcon =
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>';
preBlocks.forEach((pre) => {
// Wrap the <pre> so the button can sit outside its horizontal
// scroll container — a child of pre would scroll along with the code.
const wrapper = document.createElement('div');
wrapper.className = 'code-block-wrapper';
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
// Create the copy button
const button = document.createElement('button');
button.innerHTML = copyIcon;
button.className = 'copy-code-btn';
button.setAttribute('aria-label', 'Copy code');
button.setAttribute('title', 'Copy code');
wrapper.appendChild(button);
button.addEventListener('click', async () => {
// Find the <code> element within the <pre>
const code = pre.querySelector('code');
if (!code) return;
// Get the text content, removing any leading/trailing whitespace
const text = code.innerText;
try {
if (navigator.clipboard && window.isSecureContext) {
// Modern Async Clipboard API
await navigator.clipboard.writeText(text);
} else {
// Fallback for insecure contexts (like local network IPs via HTTP)
const textArea = document.createElement('textarea');
textArea.value = text;
// Move outside the screen to make it invisible
textArea.style.position = 'absolute';
textArea.style.left = '-999999px';
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
textArea.remove();
}
// Add visual feedback
button.innerHTML = checkIcon;
button.classList.add('copied');
button.setAttribute('aria-label', 'Copied');
button.setAttribute('title', 'Copied!');
// Revert back after 2 seconds
setTimeout(() => {
button.innerHTML = copyIcon;
button.classList.remove('copied');
button.setAttribute('aria-label', 'Copy code');
button.setAttribute('title', 'Copy code');
}, 2000);
} catch (err) {
console.error('Failed to copy code: ', err);
}
});
});
});
-10
View File
File diff suppressed because one or more lines are too long
-32
View File
@@ -1,32 +0,0 @@
(function () {
'use strict';
const refs = document.querySelectorAll('sup.footnote-reference');
if (!refs.length) return;
refs.forEach(function (sup) {
const a = sup.querySelector('a');
if (!a) return;
const targetId = a.getAttribute('href').replace(/^#/, '');
const refId = 'fnref-' + targetId;
sup.id = refId;
const def = document.getElementById(targetId);
if (!def) return;
// Append ↩ to the last <p> inside the definition
const paras = def.querySelectorAll('p');
const lastPara = paras[paras.length - 1];
if (!lastPara) return;
const backlink = document.createElement('a');
backlink.href = '#' + refId;
backlink.className = 'footnote-backref';
backlink.setAttribute('aria-label', 'Back to reference');
backlink.textContent = '↩';
lastPara.appendChild(document.createTextNode('\u00a0'));
lastPara.appendChild(backlink);
});
})();
-13
View File
@@ -1,13 +0,0 @@
(function () {
'use strict';
document.querySelectorAll('.post-body h2[id], .post-body h3[id]').forEach(function (heading) {
var a = document.createElement('a');
a.href = '#' + heading.id;
a.className = 'heading-anchor';
a.setAttribute('aria-label', 'Link to this section');
a.setAttribute('tabindex', '-1');
a.textContent = '#';
heading.appendChild(a);
});
})();
-170
View File
@@ -1,170 +0,0 @@
!(function (e, t) {
'object' == typeof exports && 'object' == typeof module
? (module.exports = t(require('katex')))
: 'function' == typeof define && define.amd
? define(['katex'], t)
: 'object' == typeof exports
? (exports.renderMathInElement = t(require('katex')))
: (e.renderMathInElement = t(e.katex));
})('undefined' != typeof self ? self : this, function (e) {
return (function () {
'use strict';
var t = {
771: function (t) {
t.exports = e;
},
},
r = {};
function n(e) {
var i = r[e];
if (void 0 !== i) return i.exports;
var a = (r[e] = { exports: {} });
return (t[e](a, a.exports, n), a.exports);
}
((n.n = function (e) {
var t =
e && e.__esModule
? function () {
return e.default;
}
: function () {
return e;
};
return (n.d(t, { a: t }), t);
}),
(n.d = function (e, t) {
for (var r in t)
n.o(t, r) && !n.o(e, r) && Object.defineProperty(e, r, { enumerable: !0, get: t[r] });
}),
(n.o = function (e, t) {
return Object.prototype.hasOwnProperty.call(e, t);
}));
var i = {};
return (
(function () {
n.d(i, {
default: function () {
return s;
},
});
var e = n(771),
t = n.n(e),
r = function (e, t, r) {
for (var n = r, i = 0, a = e.length; n < t.length; ) {
var o = t[n];
if (i <= 0 && t.slice(n, n + a) === e) return n;
('\\' === o ? n++ : '{' === o ? i++ : '}' === o && i--, n++);
}
return -1;
},
a = /^\\begin{/,
o = function (e, t) {
for (
var n,
i = [],
o = new RegExp(
'(' +
t
.map(function (e) {
return e.left.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
})
.join('|') +
')',
);
-1 !== (n = e.search(o));
) {
n > 0 && (i.push({ type: 'text', data: e.slice(0, n) }), (e = e.slice(n)));
var l = t.findIndex(function (t) {
return e.startsWith(t.left);
});
if (-1 === (n = r(t[l].right, e, t[l].left.length))) break;
var d = e.slice(0, n + t[l].right.length),
s = a.test(d) ? d : e.slice(t[l].left.length, n);
(i.push({ type: 'math', data: s, rawData: d, display: t[l].display }),
(e = e.slice(n + t[l].right.length)));
}
return ('' !== e && i.push({ type: 'text', data: e }), i);
},
l = function (e, r) {
var n = o(e, r.delimiters);
if (1 === n.length && 'text' === n[0].type) return null;
for (var i = document.createDocumentFragment(), a = 0; a < n.length; a++)
if ('text' === n[a].type) i.appendChild(document.createTextNode(n[a].data));
else {
var l = document.createElement('span'),
d = n[a].data;
r.displayMode = n[a].display;
try {
(r.preProcess && (d = r.preProcess(d)), t().render(d, l, r));
} catch (e) {
if (!(e instanceof t().ParseError)) throw e;
(r.errorCallback(
'KaTeX auto-render: Failed to parse `' + n[a].data + '` with ',
e,
),
i.appendChild(document.createTextNode(n[a].rawData)));
continue;
}
i.appendChild(l);
}
return i;
},
d = function e(t, r) {
for (var n = 0; n < t.childNodes.length; n++) {
var i = t.childNodes[n];
if (3 === i.nodeType) {
for (
var a = i.textContent, o = i.nextSibling, d = 0;
o && o.nodeType === Node.TEXT_NODE;
)
((a += o.textContent), (o = o.nextSibling), d++);
var s = l(a, r);
if (s) {
for (var f = 0; f < d; f++) i.nextSibling.remove();
((n += s.childNodes.length - 1), t.replaceChild(s, i));
} else n += d;
} else
1 === i.nodeType &&
(function () {
var t = ' ' + i.className + ' ';
-1 === r.ignoredTags.indexOf(i.nodeName.toLowerCase()) &&
r.ignoredClasses.every(function (e) {
return -1 === t.indexOf(' ' + e + ' ');
}) &&
e(i, r);
})();
}
},
s = function (e, t) {
if (!e) throw new Error('No element provided to render');
var r = {};
for (var n in t) t.hasOwnProperty(n) && (r[n] = t[n]);
((r.delimiters = r.delimiters || [
{ left: '$$', right: '$$', display: !0 },
{ left: '\\(', right: '\\)', display: !1 },
{ left: '\\begin{equation}', right: '\\end{equation}', display: !0 },
{ left: '\\begin{align}', right: '\\end{align}', display: !0 },
{ left: '\\begin{alignat}', right: '\\end{alignat}', display: !0 },
{ left: '\\begin{gather}', right: '\\end{gather}', display: !0 },
{ left: '\\begin{CD}', right: '\\end{CD}', display: !0 },
{ left: '\\[', right: '\\]', display: !0 },
]),
(r.ignoredTags = r.ignoredTags || [
'script',
'noscript',
'style',
'textarea',
'pre',
'code',
'option',
]),
(r.ignoredClasses = r.ignoredClasses || []),
(r.errorCallback = r.errorCallback || console.error),
(r.macros = r.macros || {}),
d(e, r));
};
})(),
(i = i.default)
);
})();
});
-11562
View File
File diff suppressed because it is too large Load Diff
-192132
View File
File diff suppressed because one or more lines are too long
-34
View File
@@ -1,34 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const progressBar = document.getElementById('reading-progress-bar');
if (!progressBar) return;
const updateProgress = () => {
// Calculate how far the user has scrolled down the page
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// Calculate the total scrollable height
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
const clientHeight = document.documentElement.clientHeight || window.innerHeight;
const windowHeight = scrollHeight - clientHeight;
// Calculate percentage and update width
const scrollPercentage = windowHeight > 0 ? (scrollTop / windowHeight) * 100 : 0;
progressBar.style.width = scrollPercentage + '%';
};
// Update initially in case the user refreshes midway down the page
updateProgress();
// Throttle the scroll event listener a tiny bit for performance
let isTicking = false;
window.addEventListener('scroll', () => {
if (!isTicking) {
window.requestAnimationFrame(() => {
updateProgress();
isTicking = false;
});
isTicking = true;
}
});
});
-34
View File
@@ -1,34 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const scrollToTopBtn = document.getElementById('scroll-to-top');
if (!scrollToTopBtn) return;
// Show button when scrolled down 400px
const toggleVisibility = () => {
if (window.scrollY > 400) {
scrollToTopBtn.classList.add('visible');
} else {
scrollToTopBtn.classList.remove('visible');
}
};
// Smooth scroll to top when clicked
scrollToTopBtn.addEventListener('click', () => {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
});
// Throttle the scroll event listener a tiny bit for performance
let isTicking = false;
window.addEventListener('scroll', () => {
if (!isTicking) {
window.requestAnimationFrame(() => {
toggleVisibility();
isTicking = false;
});
isTicking = true;
}
});
});
-223
View File
@@ -1,223 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const searchToggleBtn = document.querySelector('.search-toggle');
if (!searchToggleBtn) return;
// Check if elasticlunr is available
if (typeof elasticlunr === 'undefined') {
console.warn('Elasticlunr not loaded. Search will not work.');
return;
}
// Modal elements
const overlay = document.getElementById('search-overlay');
const input = document.getElementById('search-input');
const resultsContainer = document.getElementById('search-results');
if (!overlay || !input || !resultsContainer) return;
let index = null;
let isIndexLoading = false;
let selectedIndex = -1;
let resultItems = [];
// Initialize search index (loaded lazily on first open)
const initSearch = async () => {
if (index || isIndexLoading) return;
isIndexLoading = true;
try {
// Fetch the Zola-generated index
const response = await fetch('/search_index.en.js');
const jsText = await response.text();
// The file defines `window.searchIndex = {...}`
// We use a safe evaluation approach if it's purely assignment
// Or just append it as a script tag
const script = document.createElement('script');
script.innerHTML = jsText;
document.body.appendChild(script);
// Wait for it to parse
setTimeout(() => {
if (window.searchIndex) {
index = elasticlunr.Index.load(window.searchIndex);
// Search immediately if there's text
if (input.value.trim().length > 0) {
performSearch();
}
}
}, 50);
} catch (e) {
console.error('Failed to load search index:', e);
}
};
// Open Modal
const openSearch = () => {
overlay.classList.add('active');
// Slight delay ensures the browser focuses the input after the display transition starts
setTimeout(() => {
input.focus();
}, 50);
initSearch();
document.body.style.overflow = 'hidden'; // Prevent background scrolling
};
// Close Modal
const closeSearch = () => {
overlay.classList.remove('active');
input.value = '';
resultsContainer.innerHTML = '';
document.body.style.overflow = '';
selectedIndex = -1;
resultItems = [];
};
// Bind Toggle Button
searchToggleBtn.addEventListener('click', (e) => {
e.preventDefault();
if (overlay.classList.contains('active')) {
closeSearch();
} else {
openSearch();
}
});
// Close on overlay click
overlay.addEventListener('click', (e) => {
if (e.target === overlay) closeSearch();
});
// Handle Keyboard Shortcuts
document.addEventListener('keydown', (e) => {
// Ctrl+K -> Open Search
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
openSearch();
}
if (!overlay.classList.contains('active')) return;
// Escape -> Close Search
if (e.key === 'Escape') {
closeSearch();
}
// Arrow Navigation
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault();
if (resultItems.length === 0) return;
if (e.key === 'ArrowDown') {
selectedIndex = (selectedIndex + 1) % resultItems.length;
} else {
selectedIndex = (selectedIndex - 1 + resultItems.length) % resultItems.length;
}
updateSelection();
}
// Enter -> Navigate to selected
if (e.key === 'Enter') {
e.preventDefault();
if (selectedIndex >= 0 && resultItems[selectedIndex]) {
window.location.href = resultItems[selectedIndex].href;
} else if (resultItems.length > 0) {
// Default to first item if none selected
window.location.href = resultItems[0].href;
}
}
});
const updateSelection = () => {
resultItems.forEach((el, i) => {
if (i === selectedIndex) {
el.classList.add('selected');
el.scrollIntoView({ block: 'nearest' });
} else {
el.classList.remove('selected');
}
});
};
// Perform the Search
const performSearch = () => {
if (!index) {
resultsContainer.innerHTML = '<div class="no-results">Loading search index...</div>';
return;
}
const query = input.value.trim();
if (query.length === 0) {
resultsContainer.innerHTML = '';
selectedIndex = -1;
resultItems = [];
return;
}
const options = {
bool: 'OR',
expand: true,
};
const results = index.search(query, options);
if (results.length === 0) {
resultsContainer.innerHTML = `<div class="no-results">No results found for "${query}"</div>`;
selectedIndex = -1;
resultItems = [];
return;
}
// Build HTML
let html = '';
results.forEach((res) => {
// The doc is stored inside the index.documentStore
// For Zola + elasticlunr, res.ref IS the URL.
const url = res.ref;
const doc = index.documentStore.docs[res.ref];
if (!doc) return;
// Truncate summary if needed
let body = doc.body || '';
if (body.length > 150) {
body = body.substring(0, 150) + '...';
}
const title = doc.title || url;
html += `
<a href="${url}" class="search-result-item">
<div class="result-title">${title}</div>
<div class="result-summary">${body}</div>
</a>
`;
});
resultsContainer.innerHTML = html;
// Cache DOM elements for keyboard navigation
resultItems = Array.from(resultsContainer.querySelectorAll('.search-result-item'));
selectedIndex = -1; // Reset selection on new search
// Mouse hover updates selection index
resultItems.forEach((item, i) => {
item.addEventListener('mouseenter', () => {
selectedIndex = i;
updateSelection();
});
});
};
// Debounce the input
let debounceTimer;
input.addEventListener('input', () => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
performSearch();
}, 150);
});
});
-81
View File
@@ -1,81 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const themeToggleBtn = document.getElementById('theme-toggle');
const htmlElement = document.documentElement;
const applyTheme = (theme) => {
if (theme === 'dark') {
htmlElement.classList.add('dark');
} else {
htmlElement.classList.remove('dark');
}
localStorage.setItem('theme', theme);
};
// Check local storage for theme preference
const currentTheme = localStorage.getItem('theme');
if (currentTheme === 'dark' || currentTheme === 'light') {
applyTheme(currentTheme);
} else {
// Fallback to system preference
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
applyTheme(prefersDarkScheme.matches ? 'dark' : 'light');
}
// Toggle theme on click
if (themeToggleBtn) {
themeToggleBtn.addEventListener('click', () => {
const nextTheme = htmlElement.classList.contains('dark') ? 'light' : 'dark';
applyTheme(nextTheme);
});
}
// Mobile nav toggle
const navToggle = document.getElementById('nav-toggle');
const navLinks = document.getElementById('nav-links');
if (navToggle && navLinks) {
navToggle.addEventListener('click', () => {
const isOpen = navLinks.classList.toggle('is-open');
navToggle.setAttribute('aria-expanded', isOpen);
});
// Close nav when a link is clicked
navLinks.querySelectorAll('.nav-item').forEach((link) => {
link.addEventListener('click', () => {
navLinks.classList.remove('is-open');
navToggle.setAttribute('aria-expanded', 'false');
});
});
}
// Sync Utterances (comments iframe) theme with the site theme.
// The iframe only reads its initial `theme` attribute once, so later
// changes must go through postMessage per the utterances protocol.
const syncUtterancesTheme = () => {
const commentsEl = document.getElementById('comments');
const frame = document.querySelector('.utterances-frame');
if (!commentsEl || !frame) return;
const theme = htmlElement.classList.contains('dark')
? commentsEl.dataset.utterancesThemeDark
: commentsEl.dataset.utterancesThemeLight;
// The iframe briefly shares our origin before it navigates to utteranc.es,
// so posting with that targetOrigin throws until the navigation completes.
try {
frame.contentWindow.postMessage({ type: 'set-theme', theme }, 'https://utteranc.es');
} catch (e) {
// Ignore: frame hasn't navigated to utteranc.es yet.
}
};
new MutationObserver(syncUtterancesTheme).observe(htmlElement, {
attributes: true,
attributeFilter: ['class'],
});
// The iframe loads asynchronously, so poll briefly until it's mounted.
let utterancesTries = 0;
const utterancesPoll = setInterval(() => {
if (document.querySelector('.utterances-frame') || ++utterancesTries > 20) {
clearInterval(utterancesPoll);
syncUtterancesTheme();
}
}, 250);
});
-59
View File
@@ -1,59 +0,0 @@
(function () {
'use strict';
const sidebar = document.querySelector('.post-toc-sidebar');
if (!sidebar) return;
const links = Array.from(sidebar.querySelectorAll('a[data-toc-id]'));
if (!links.length) return;
const headingIds = links.map((a) => a.dataset.tocId);
const headings = headingIds.map((id) => document.getElementById(id)).filter(Boolean);
let activeId = null;
function setActive(id) {
if (id === activeId) return;
activeId = id;
links.forEach((a) => {
if (a.dataset.tocId === id) {
a.classList.add('toc-active');
} else {
a.classList.remove('toc-active');
}
});
}
const observer = new IntersectionObserver(
(entries) => {
// Find the topmost visible heading
const visible = headings.filter((h) => {
const rect = h.getBoundingClientRect();
return rect.top >= 0 && rect.top < window.innerHeight * 0.6;
});
if (visible.length > 0) {
setActive(visible[0].id);
} else {
// If scrolled past all headings, keep last active
const above = headings.filter((h) => h.getBoundingClientRect().top < 0);
if (above.length > 0) {
setActive(above[above.length - 1].id);
}
}
},
{
rootMargin: '-10% 0px -60% 0px',
threshold: 0,
},
);
headings.forEach((h) => observer.observe(h));
// Set initial active on load
const firstVisible = headings.find((h) => {
const rect = h.getBoundingClientRect();
return rect.top >= 0;
});
if (firstVisible) setActive(firstVisible.id);
})();
-41
View File
@@ -1,41 +0,0 @@
# andwati.com
> Ian Andwati's personal blog about mathematics, computer science, binary exploitation, reverse engineering, capture-the-flag competitions, offensive security, Linux, and software development.
This site contains articles in English, often with commands, code samples, worked explanations, and material aimed at readers learning by doing.
## Main pages
- [Home](https://andwati.com/): Introduction and latest articles.
- [About](https://andwati.com/about/): About the author and contact information.
- [Posts](https://andwati.com/posts/): All published articles.
- [Tags](https://andwati.com/tags/): Articles grouped by topic.
- [Archive](https://andwati.com/archive/): Chronological article archive.
## Published articles
- [Self-Hosting Gitea and Automating GitHub Mirrors](https://andwati.com/posts/self-hosting-gitea-and-mirroring-github/): Self-Hosting Gitea and Automating GitHub Mirrors (and Everything Cloudflare Broke Along the Way)
- [The One Thing Nobody Tells You About WiFi Hotspots on Arch Linux](https://andwati.com/posts/wifi-hotspot-arch/): A minimal Arch install is great until NetworkManager silently fails to find a binary you didn't know you needed
- [From C to Machine Code: What Actually Runs](https://andwati.com/posts/from-c-to-machine-code/): Before diving into how to break a program, we need to understand what the computer is actually executing
- [The Single Byte That Kills Your Exploit: Understanding Endianness](https://andwati.com/posts/the-single-byte-that-kills-your-exploit-understanding-endianness/): Problem: Computers speak different languages, like people
- [What is pwn?](https://andwati.com/posts/what-is-pwn/): No not that one
- [ScriptCTF 2025 Writeup](https://andwati.com/posts/scriptctf2025/): ScriptCTF 2025 Writeup
- [mmuctf 2025 writeup](https://andwati.com/posts/mmuctf2025/): mmuctf 2025 challenges writeup
- [cognitive inertia](https://andwati.com/posts/inertia/): inertia
- [Export default and module.exports in Javascript](https://andwati.com/posts/javascript-exporting-modules/): Modules are the building blocks of modern JavaScript applications, allowing for the encapsulation of code into reusable components. Two primary systems govern the exportation of these modules: export default in ES6 and module.exports in CommonJS.
- [Setting up Obsidian sync in Windows](https://andwati.com/posts/obsidian-sync/): Syncing Obsidian in Windows with Windows Task Scheduler with git
- [A Fresh Coat Of Paint](https://andwati.com/posts/a-fresh-coat-of-paint/): Migrating to Zola
- [What say you?](https://andwati.com/posts/utterances-comments/): Adding a comment system by utterances
- [Subresource Integrity](https://andwati.com/posts/subresource-integrity/): Understanding Subresource Integrity
- [Install PostgreSQL on Arch | Manjaro | Garuda Linux](https://andwati.com/posts/install-postgresql-15-on-arch-manjaro-garuda-linux/): Getting PostgreSQL up and running on Arch Linux-based distros
- [Semantic Versioning(SemVer) and Conventional Commits](https://andwati.com/posts/semantic-version-and-conventional-commits/): Adopting best practices in your git and build workflows.
- [Integrating Netlify CMS](https://andwati.com/posts/integrating-netlify/): Integrating netlify cms
- [Django Secret Key Tutorial](https://andwati.com/posts/generate-django-secret-key/): Managing secrets
- [Hello World](https://andwati.com/posts/hello-world/): Hello world
- [Configure Vue.js app With Tailwind CSS](https://andwati.com/posts/vuejs-tailwind/): Tailwindcss in vuejs
## Feeds and discovery
- [RSS feed](https://andwati.com/rss.xml): Full site feed in RSS format.
- [JSON feed](https://andwati.com/feed.json): Full site feed in JSON format.
- [Sitemap](https://andwati.com/sitemap.xml): Machine-readable index of public pages.
-174
View File
@@ -1,174 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title><xsl:value-of select="/rss/channel/title"/> — RSS Feed</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<style>
:root {
--bg-color: #e9e9e2;
--surface-color: #dedecf;
--text-color: #17181c;
--text-muted: #68675f;
--accent-color: #b42318;
--accent-hover: #8e1b12;
--border-color: rgba(23, 24, 28, 0.16);
--font-sans: Georgia, 'Source Serif 4', serif;
--font-display: Georgia, 'IBM Plex Serif', serif;
--font-mono: ui-monospace, 'JetBrains Mono', 'SFMono-Regular', Menlo, monospace;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-color: #131311;
--surface-color: #1b1a17;
--text-color: #e9e7de;
--text-muted: #8b8a80;
--accent-color: #ff5a46;
--accent-hover: #ff7c6b;
--border-color: rgba(233, 231, 222, 0.14);
}
}
* {
box-sizing: border-box;
}
body {
font-family: var(--font-sans);
background-color: var(--bg-color);
color: var(--text-color);
line-height: 1.6;
margin: 0;
padding: 3rem 1.5rem;
}
.wrap {
max-width: 720px;
margin: 0 auto;
}
a {
color: var(--accent-color);
text-decoration: none;
}
a:hover {
color: var(--accent-hover);
text-decoration: underline;
}
.header {
margin-bottom: 2.5rem;
padding-bottom: 2rem;
border-bottom: 1px solid var(--border-color);
}
.header h1 {
font-family: var(--font-display);
font-size: 2rem;
font-weight: 700;
margin: 0 0 0.5rem 0;
color: var(--text-color);
}
.header p {
font-size: 1.05rem;
margin: 0;
color: var(--text-muted);
}
.notice {
background: var(--surface-color);
padding: 1rem 1.25rem;
border-left: 4px solid var(--accent-color);
margin-bottom: 2.5rem;
font-size: 0.9rem;
}
.notice strong {
font-family: var(--font-mono);
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: 0.8rem;
display: block;
margin-bottom: 0.35rem;
color: var(--accent-color);
}
.item {
padding: 1.75rem 0;
border-bottom: 1px solid var(--border-color);
}
.item:first-child {
padding-top: 0;
}
.item .meta {
font-family: var(--font-mono);
font-size: 0.8rem;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 0.5rem;
}
.item h2 {
font-family: var(--font-display);
font-size: 1.4rem;
font-weight: 700;
margin: 0 0 0.5rem 0;
}
.item h2 a {
color: var(--text-color);
}
.item h2 a:hover {
color: var(--accent-color);
text-decoration: none;
}
.item .excerpt {
color: var(--text-muted);
margin-bottom: 1rem;
}
.btn {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.4rem 0.9rem;
border: 1px solid var(--accent-color);
border-radius: 2px;
font-family: var(--font-mono);
font-size: 0.8rem;
letter-spacing: 0.03em;
color: var(--accent-color);
}
.btn:hover {
background: var(--accent-color);
color: var(--bg-color);
text-decoration: none;
}
</style>
</head>
<body>
<div class="wrap">
<div class="header">
<h1><xsl:value-of select="/rss/channel/title"/></h1>
<p><xsl:value-of select="/rss/channel/description"/></p>
</div>
<div class="notice">
<strong>RSS Feed</strong>
This is a feed, not a normal web page. Copy the URL from your address bar into a feed reader to subscribe.
</div>
<div class="items">
<xsl:for-each select="/rss/channel/item">
<div class="item">
<div class="meta">Published <xsl:value-of select="pubDate"/></div>
<h2>
<a href="{link}">
<xsl:value-of select="title"/>
</a>
</h2>
<div class="excerpt">
<xsl:value-of select="substring(description, 1, 220)"/>&#8230;
</div>
<a href="{link}" class="btn">Read article &#x2192;</a>
</div>
</xsl:for-each>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
-12
View File
@@ -1,12 +0,0 @@
{
"name": "Thoughts and Musings",
"short_name": "andwati.com",
"icons": [
{ "src": "/images/favicon-192x192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/images/favicon-512x512.png", "sizes": "512x512", "type": "image/png" }
],
"theme_color": "#131311",
"background_color": "#131311",
"display": "standalone",
"start_url": "/"
}
-21
View File
@@ -1,21 +0,0 @@
{% extends "base.html" %}
{% block title %}404 — {{ config.extra.notfound_title | default(value="Document Not Found") }} | {{ config.title }}{% endblock title %}
{% block description %}{{ config.extra.notfound_body | default(value="The page you requested could not be found.") }}{% endblock description %}
{% block content %}
<div class="notfound-wrap">
<div class="case-notice">
<p class="case-notice-ref">{{ config.extra.notfound_status | default(value="Status: Not Found") }}</p>
<h1 class="case-notice-title">{{ config.extra.notfound_title | default(value="Document Not Found") }}</h1>
<p class="case-notice-body">
{{ config.extra.notfound_body | default(value="This page couldn't be located in the archive. It may have been moved, renamed, or never filed.") }}
</p>
<div class="case-notice-links">
<a href="{{ get_url(path="") }}">Home</a>
<a href="{{ get_url(path="/posts") }}">Posts</a>
<a href="{{ get_url(path="/tags") }}">Tags</a>
</div>
</div>
</div>
{% endblock content %}
-41
View File
@@ -1,41 +0,0 @@
{% extends "base.html" %} {% block title %}{{ section.title }} | {{ config.title }}{% endblock title
%} {% block description %}Chronological archive of every post on {{ config.title }}.{% endblock
description %} {% block canonical %}{{ section.permalink }}{% endblock canonical %} {% block og_title
%}{{ section.title }} | {{ config.title }}{% endblock og_title %} {% block og_description %}Chronological
archive of every post on {{ config.title }}.{% endblock og_description %} {% block og_url %}{{
section.permalink }}{% endblock og_url %} {% block head %}
<!-- SEO: BreadcrumbList JSON-LD -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "{{ config.base_url | safe }}/" },
{ "@type": "ListItem", "position": 2, "name": {{ section.title | json_encode | safe }}, "item": "{{ section.permalink | safe }}" }
]
}
</script>
{% endblock head %} {% block content %}
<div class="post-detail">
<header class="post-header list-page-header">
<h1 class="post-title list-page-title">{{ config.extra.archive_page_title | default(value="Archive") }}</h1>
</header>
<div class="archive-list">
{% set section = get_section(path="posts/_index.md") %} {% for year, posts in section.pages |
sort(attribute="date") | reverse | group_by(attribute="year") %}
<div class="archive-year">
<h2 class="archive-year-title">{{ year }}</h2>
<ul class="archive-items">
{% for post in posts %}
<li class="archive-item hover-scale">
<time datetime="{{ post.date }}" class="archive-date">{{ post.date | date(format="%d-%b") }}</time>
<a href="{{ post.permalink }}" class="archive-link">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}
-160
View File
@@ -1,160 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
<meta name="description" content="{% block description %}{{ config.description }}{% endblock description %}">
<meta name="view-transition" content="same-origin">
<!-- Favicon -->
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
<meta name="theme-color" content="#131311">
{% if config.extra.google_site_verification %}
<meta name="google-site-verification" content="{{ config.extra.google_site_verification }}">
{% endif %}
<!-- Canonical URL -->
<link rel="canonical" href="{% block canonical %}{{ config.base_url }}/{% endblock canonical %}">
<!-- Open Graph -->
<meta property="og:site_name" content="{{ config.title }}">
<meta property="og:title" content="{% block og_title %}{{ config.title }}{% endblock og_title %}">
<meta property="og:description" content="{% block og_description %}{{ config.description }}{% endblock og_description %}">
<meta property="og:url" content="{% block og_url %}{{ config.base_url }}/{% endblock og_url %}">
<meta property="og:type" content="{% block og_type %}website{% endblock og_type %}">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="{% block og_image %}{{ config.base_url }}/images/og-image.png{% endblock og_image %}">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="{{ config.title }} — {{ config.description }}">
{% block og_extra %}{% endblock og_extra %}
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="{{ config.extra.twitter_handle | default(value="@andwati_") }}">
<meta name="twitter:title" content="{% block twitter_title %}{{ config.title }}{% endblock twitter_title %}">
<meta name="twitter:description" content="{% block twitter_description %}{{ config.description }}{% endblock twitter_description %}">
<meta name="twitter:image" content="{% block twitter_image %}{{ config.base_url }}/images/og-image.png{% endblock twitter_image %}">
{% block twitter_extra %}{% endblock twitter_extra %}
<!-- Theme initializer (runs before paint to avoid flash) -->
<script>
(function() {
try {
var storedTheme = localStorage.getItem('theme');
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
var shouldUseDark = storedTheme ? storedTheme === 'dark' : prefersDark;
if (shouldUseDark) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
} catch (e) {
document.documentElement.classList.add('dark');
}
})();
</script>
<!-- SEO: WebSite + Person JSON-LD (sitewide graph) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "WebSite",
"@id": "{{ config.base_url | safe }}/#website",
"url": "{{ config.base_url | safe }}/",
"name": {{ config.title | json_encode | safe }},
"description": {{ config.description | json_encode | safe }},
"inLanguage": "en-US"
},
{
"@type": "Person",
"@id": "{{ config.base_url | safe }}/#author",
"name": {{ config.extra.author | json_encode | safe }},
"url": "{{ config.base_url | safe }}/about/",
"sameAs": [
{% if config.extra.github_url %}"{{ config.extra.github_url | safe }}"{% if config.extra.twitter_url or config.extra.youtube_url %},{% endif %}{% endif %}
{% if config.extra.twitter_url %}"{{ config.extra.twitter_url | safe }}"{% if config.extra.youtube_url %},{% endif %}{% endif %}
{% if config.extra.youtube_url %}"{{ config.extra.youtube_url | safe }}"{% endif %}
]
}
]
}
</script>
{% if config.extra.google_analytics %}
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ config.extra.google_analytics }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{{ config.extra.google_analytics }}', { anonymize_ip: true });
</script>
{% endif %}
{% block head %}{% endblock head %}
<!-- Font preloads (eliminate FOUT on first paint) -->
<link rel="preload" href="{{ get_url(path="fonts/source-serif-4/source-serif-4-v14-latin-regular.woff2") }}" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="{{ get_url(path="fonts/ibm-plex-serif/ibm-plex-serif-v20-latin-700.woff2") }}" as="font" type="font/woff2" crossorigin>
<!-- CSS -->
<link rel="stylesheet" href="{{ get_url(path="main.css") }}">
<!-- Fonts (self-hosted) -->
<link rel="stylesheet" href="{{ get_url(path="css/fonts.css") }}">
<!-- RSS Feed -->
<link rel="alternate" type="application/rss+xml" title="{{ config.title }} RSS Feed" href="{{ get_url(path="rss.xml") }}">
</head>
<body class="smooth-scroll">
<div class="site-container">
{% include "partials/header.html" %}
<main class="main-content">
{% block content %}{% endblock content %}
</main>
{% include "partials/footer.html" %}
</div>
<button id="scroll-to-top" class="scroll-to-top" aria-label="Scroll to top">
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
<polyline points="18 15 12 9 6 15"></polyline>
</svg>
</button>
<!-- Search Modal Overlay -->
<div id="search-overlay" class="search-overlay" aria-hidden="true">
<div class="search-modal" role="dialog" aria-modal="true" aria-label="Search posts">
<div class="search-header">
<svg viewBox="0 0 24 24" width="18" height="18" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
<input type="text" id="search-input" placeholder="{{ config.extra.search_placeholder | default(value="Search posts...") }}" autocomplete="off">
</div>
<div id="search-results" class="search-results"></div>
<div class="search-footer">
<span>Navigate: <kbd>↑</kbd> <kbd>↓</kbd></span>
<span>Select: <kbd>Enter</kbd></span>
<span>Close: <kbd>ESC</kbd></span>
</div>
</div>
</div>
<!-- Global Scripts -->
<script defer src="{{ get_url(path="js/theme.js") }}"></script>
<script defer src="{{ get_url(path="js/scroll-top.js") }}"></script>
<script defer src="{{ get_url(path="js/copy-code.js") }}"></script>
<!-- Search Scripts -->
<script defer src="{{ get_url(path="js/elasticlunr.min.js") }}"></script>
<script defer src="{{ get_url(path="js/search.js") }}"></script>
{% block scripts %}{% endblock scripts %}
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More