Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/review-regen-week/collect_week.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def render_markdown(
if previous:
try:
cells.append(str(value(previous)))
except (KeyError, TypeError):
except KeyError, TypeError:
cells.append("–")
lines.append("| " + " | ".join(cells) + " |")
lines += ["", f"Reason codes: {', '.join(f'{k} {v}' for k, v in summary['codes'].items()) or 'none'}", ""]
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/verify-migrations/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ EOF
```

(`--no-project --python 3.12`: pgserver ships no wheels for the
project's Python 3.13, and `--no-project` sidesteps the
`requires-python >=3.13` constraint — the server is a separate
project's Python 3.14, and `--no-project` sidesteps the
`requires-python >=3.14` constraint — the server is a separate
process; alembic still runs in the project env.)

## 2 · The four checks (one Bash invocation)
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/zweitmeinung/gemini_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def search(self, pattern: str, path: str = "", glob: str = "") -> str:
if file.stat().st_size > 2_000_000:
continue
text = file.read_text(encoding="utf-8")
except (UnicodeDecodeError, OSError):
except UnicodeDecodeError, OSError:
continue
for number, line in enumerate(text.splitlines(), 1):
if len(line) <= MAX_SEARCH_LINE and regex.search(line):
Expand Down
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ Plot implementations are **simple, readable scripts** - like matplotlib gallery
```python
""" anyplot.ai
scatter-basic: Basic Scatter Plot
Library: matplotlib 3.10.0 | Python 3.13
Library: matplotlib 3.10.0 | Python 3.14
Quality: 92/100 | Created: 2025-01-10
"""

Expand Down Expand Up @@ -246,7 +246,7 @@ plt.savefig(f'plot-{THEME}.png', dpi=300, bbox_inches='tight') # THEME = os.get

## Tech Stack

- **Backend**: FastAPI, SQLAlchemy (async), PostgreSQL, Python 3.13+
- **Backend**: FastAPI, SQLAlchemy (async), PostgreSQL, Python 3.14+
- **Frontend**: React 19, TypeScript 6, Vite 8, MUI 9
- **Package Manager**: uv (Python), yarn (Node.js)
- **Linting**: Ruff (Python), ESLint (TypeScript)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:

- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
python-version: '3.14'

- name: Install uv
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/ci-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ jobs:
-e ANYPLOT_THEME=light -e MPLBACKEND=Agg -e MPLCONFIGDIR=/tmp/mpl -e ANYPLOT_MPL_SEED=/opt/mplconfig \
-e HOME=/tmp -e PYTHONDONTWRITEBYTECODE=1 -e OPENBLAS_NUM_THREADS=1 -e OMP_NUM_THREADS=1 \
-e ANYPLOT_RLIMIT_CPU_S=60 -e ANYPLOT_RLIMIT_FSIZE_MB=50 -e ANYPLOT_RLIMIT_AS_MB=1024 \
anyplot-renderer:ci /app/.venv/bin/python -I /opt/anyplot/harness.py plot.py > harness.out
anyplot-renderer:ci /app/.venv/bin/python -I -X disable-remote-debug /opt/anyplot/harness.py plot.py > harness.out
grep -qxF 'HARNESS {"event": "start"}' harness.out || { echo "::error::no HARNESS start line"; cat harness.out; exit 1; }
grep -q '^HARNESS {"event": "end"' harness.out || { echo "::error::no HARNESS end line"; cat harness.out; exit 1; }
python3 - <<'EOF'
Expand Down Expand Up @@ -687,7 +687,8 @@ jobs:
-e ANYPLOT_THEME=light -e MPLBACKEND=Agg -e MPLCONFIGDIR=/tmp/mpl \
-e HOME=/tmp -e PYTHONDONTWRITEBYTECODE=1 -e OPENBLAS_NUM_THREADS=1 -e OMP_NUM_THREADS=1 \
-e ANYPLOT_RLIMIT_CPU_S=60 -e ANYPLOT_RLIMIT_FSIZE_MB=50 -e ANYPLOT_RLIMIT_AS_MB=1024 \
"$@" anyplot-renderer:ci /app/.venv/bin/python -I /opt/anyplot/harness.py plot.py > "$work/harness.out"
"$@" anyplot-renderer:ci /app/.venv/bin/python -I -X disable-remote-debug /opt/anyplot/harness.py plot.py \
> "$work/harness.out"
grep -q '^HARNESS {"event": "end"' "$work/harness.out" || { echo "::error::no HARNESS end line in $work"; cat "$work/harness.out"; exit 1; }
}
render work-i18n -e ANYPLOT_MPL_SEED=/opt/mplconfig
Expand Down Expand Up @@ -724,7 +725,7 @@ jobs:
run: |
set -euo pipefail
echo "image size: $(docker image inspect --format '{{.Size}}' anyplot-renderer:ci) bytes"
docker run --rm anyplot-renderer:ci du -sh /app/.venv/lib/python3.13/site-packages/pyarrow
docker run --rm anyplot-renderer:ci du -sh /app/.venv/lib/python3.14/site-packages/pyarrow
docker run --rm anyplot-renderer:ci sh -c 'grep PRETTY_NAME /etc/os-release; cat /usr/share/doc/fonts-noto/versions.txt; ls -l /usr/share/fonts/noto; du -sh /usr/share/fonts/noto; head -n 5 /usr/share/doc/fonts-noto/fonts-noto-core.copyright'

# Also after a failed assert, so the PNGs show what went wrong.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
if: steps.check.outputs.should_lint == 'true'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
python-version: '3.14'

- name: Install uv
if: steps.check.outputs.should_lint == 'true'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-migrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ jobs:
if: steps.check.outputs.should_check == 'true'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
python-version: '3.14'

- name: Install uv
if: steps.check.outputs.should_check == 'true'
Expand Down
15 changes: 8 additions & 7 deletions .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,18 @@ jobs:
echo "should_test=false" >> $GITHUB_OUTPUT
fi

# Unconditional: the spec check below runs on every event, and it imports
# regen_gate, whose PEP 758 `except A, B:` parses on Python 3.14 only.
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version-file: '.python-version'

# Runs on every event, whatever should_test says: spec-only PRs (spec-create,
# spec polish, the characteristics backfill) skip pytest, and this job is a
# required check. The contract (the shape the regen gate parses) is checked
# over every spec and blocks; house style is checked on the changed specs
# and only warns. Standard library only — the runner's python3, no uv.
# and only warns. Standard library only — setup-python's python3, no uv.
- name: Check spec characteristic sections
run: |
echo "python3: $(python3 --version)"
Expand All @@ -110,12 +117,6 @@ jobs:
fi
exit "$status"

- name: Set up Python
if: steps.check.outputs.should_test == 'true'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'

- name: Install uv
if: steps.check.outputs.should_test == 'true'
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/daily-regen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
python-version: '3.14'

- name: Install PyYAML
run: pip install pyyaml
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/impl-generate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
python-version: '3.14'

- name: Install uv
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
Expand Down Expand Up @@ -561,7 +561,7 @@ jobs:

mkdir -p "$METADATA_DIR"

# python_version = the Python interpreter that ran THIS pipeline (always 3.13).
# python_version = the Python interpreter that ran THIS pipeline (3.14 today).
# language_version = the implementation's own runtime — same as python_version for
# Python libs, the R version for ggplot2. The frontend renders language_version with
# the right language label, so we never mislabel R as "Python".
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/impl-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,14 @@ jobs:
with:
fetch-depth: 0

# regen_writeback imports regen_gate, whose PEP 758 `except A, B:` parses
# on Python 3.14 only; the runner image's own python3 is not pinned.
- name: Set up Python
if: steps.branch.outputs.run == 'true'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version-file: '.python-version'

# The PR must be the bot's write-back (open, head
# review-writeback/{spec}/{library}/{kept PR}, label review-writeback,
# author app/github-actions); anything else is a no-op. Its base must be
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/impl-repair.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
python-version: '3.14'

- name: Install uv
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/review-retest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ jobs:
fetch-depth: 0
persist-credentials: false

# review_retest, review_provenance and regen_gate use PEP 758 `except A, B:`,
# which parses on Python 3.14 only; the runner image's python3 is not pinned.
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version-file: '.python-version'

- name: Resolve rules_ref
id: rules
env:
Expand Down Expand Up @@ -223,6 +230,11 @@ jobs:
fetch-depth: 1
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version-file: '.python-version'

# The harness runs from a copy outside the workspace: the next step
# overlays prompts/ and regen_gate.py from the rules under test.
- name: Copy the harness out of the workspace
Expand Down Expand Up @@ -369,6 +381,11 @@ jobs:
fetch-depth: 1
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version-file: '.python-version'

- name: Download cells
continue-on-error: true
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sync-postgres.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
python-version: '3.14'

- name: Install uv
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
Expand Down
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.13.12
3.14.9
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**→ [anyplot.ai](https://anyplot.ai)**

[![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/)
[![Python 3.14+](https://img.shields.io/badge/python-3.14+-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![Tests](https://github.com/MarkusNeusinger/anyplot/actions/workflows/ci-tests.yml/badge.svg?branch=main)](https://github.com/MarkusNeusinger/anyplot/actions/workflows/ci-tests.yml)
[![Ruff](https://github.com/MarkusNeusinger/anyplot/actions/workflows/ci-lint.yml/badge.svg?branch=main)](https://github.com/MarkusNeusinger/anyplot/actions/workflows/ci-lint.yml)
Expand Down Expand Up @@ -75,7 +75,7 @@ See [docs/reference/](docs/reference/) for details.

## Tech stack

**Backend**: FastAPI • PostgreSQL • SQLAlchemy • Python 3.13+
**Backend**: FastAPI • PostgreSQL • SQLAlchemy • Python 3.14+

**Frontend**: React 19 • Vite • TypeScript • MUI

Expand Down
4 changes: 2 additions & 2 deletions agentic/commands/audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Each specialist receives a focused prompt loaded from `agentic/commands/audit/<n
|---|---|---|
| **5 — Critical** | Production-breaking bugs, real security risks, data-loss potential, broken builds | Workflow uses unquoted `${{ github.event.issue.title }}` in `run:` (script injection); raw `ANTHROPIC_API_KEY` logged; Alembic migration without `downgrade()`; SQL constructed via f-string |
| **4 — High** | Significant code smells with concrete failure modes, test gaps for core paths, clear performance bottlenecks, or a high-impact exemplary gap | N+1 query in `core/database/repositories/`; missing retry/timeout on Anthropic SDK call; `any` covering an entire MUI component tree; prompt file references a removed library; no dark-mode contrast on a primary surface |
| **3 — Medium** | Modernization, consistency, maintainability — non-urgent but real debt; medium-impact exemplary gap | Outdated 3.10-style typing where 3.13 idioms apply; inconsistent router naming; duplicated pydantic schemas; missing CONTRIBUTING.md |
| **3 — Medium** | Modernization, consistency, maintainability — non-urgent but real debt; medium-impact exemplary gap | Outdated 3.10-style typing where 3.14 idioms apply; inconsistent router naming; duplicated pydantic schemas; missing CONTRIBUTING.md |
| **2 — Low** | Cosmetic, comment-only, nit-level | Inconsistent docstring style; unused dev-only `print`; trailing whitespace not auto-fixed |
| **1 — Positive** | Patterns worth preserving (no action needed; informational) | Solid repository pattern in `core/database/`; well-isolated cache layer in `api/cache.py`; clean theme-token usage |

Expand Down Expand Up @@ -154,7 +154,7 @@ Beyond "is anything broken?", each auditor should ask "what would the best repo
- **Security (exemplary):** least-privilege everywhere; secrets only in Secret Manager with rotation; all `pull_request_target`/`issue_comment` workflows gated by `author_association` and never interpolate untrusted `${{ github.event.* }}` into `run:`/prompts; third-party actions pinned to SHA; zero High/Critical dependency CVEs; documented threat model (`SECURITY.md`).
- **Speed (exemplary):** all Core Web Vitals in the "good" bucket (field + lab); a tracked JS/CSS bundle budget; no N+1; indexes on every filtered/ordered column; warm Cloud Run (min-instances tuned to traffic); cache hit-rate observable.
- **Looks (exemplary):** a single coherent design system; dark + light mode both correct (contrast, no hardcoded colors, theme tokens only); responsive at mobile/tablet/desktop; consistent spacing/typography scale; polished empty/loading/error states; WCAG AA.
- **Modern (exemplary):** current language idioms (Python ≥3.13, React 19, MUI 9 patterns), no deprecated APIs, dependencies near-current, modern CI (caching, matrix, pinned actions), structured data / JSON-LD for content pages.
- **Modern (exemplary):** current language idioms (Python ≥3.14, React 19, MUI 9 patterns), no deprecated APIs, dependencies near-current, modern CI (caching, matrix, pinned actions), structured data / JSON-LD for content pages.
- **Correctness (exemplary):** green CI on every required check; meaningful test coverage on core paths; no swallowed errors; migrations reversible; spec→impl pipeline idempotent.
- **Maintainability (exemplary):** complete repo-health set (README, CONTRIBUTING, CODE_OF_CONDUCT, SECURITY.md, issue/PR templates, `.editorconfig`); docs match code; no dead code; consistent naming; clean agent ergonomics (right-sized commands, fresh CLAUDE.md).

Expand Down
2 changes: 1 addition & 1 deletion agentic/commands/audit/backend-auditor.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ You are the **backend-auditor** on the audit team. Analyze `api/`, `core/`, and
- **Type safety**: Missing type hints, `Any` overuse, incorrect types, Protocol/ABC usage
- **Code smells**: Dead code, duplication, overly complex functions (high cyclomatic complexity), god classes
- **Error handling**: Consistency, missing error handlers, bare except clauses, error propagation
- **Python modernization**: Old patterns that could use modern 3.13 idioms, deprecated APIs
- **Python modernization**: Old patterns that could use modern 3.14 idioms, deprecated APIs
- **Performance**: N+1 queries, unnecessary computations, inefficient patterns, missing caching opportunities
- **Import hygiene**: Unused imports, circular imports, import order

Expand Down
2 changes: 1 addition & 1 deletion agentic/commands/prime.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ gh pr list --limit 5 2>/dev/null || echo "(gh CLI not available)"
- `automation/` — CI/CD helper scripts
- `.github/workflows/` — GitHub Actions pipelines

Stack: Python 3.13+ (uv), PostgreSQL, GCP (Cloud Run + Cloud SQL + GCS).
Stack: Python 3.14+ (uv), PostgreSQL, GCP (Cloud Run + Cloud SQL + GCS).

## GitHub pipeline (don't bypass it)

Expand Down
10 changes: 5 additions & 5 deletions agentic/docs/project-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ workflow_run: 12345678
issue: 42

# Versions
python_version: "3.13"
python_version: "3.14"
library_version: "3.10.0"

# Previews
Expand Down Expand Up @@ -317,7 +317,7 @@ review:
```python
""" anyplot.ai
scatter-basic: Basic Scatter Plot
Library: matplotlib 3.10.0 | Python 3.13
Library: matplotlib 3.10.0 | Python 3.14
Quality: 92/100 | Created: 2025-01-10
"""
```
Expand Down Expand Up @@ -430,7 +430,7 @@ an object URL must return 200 anonymously, while

## Tech Stack

- **Backend**: FastAPI, SQLAlchemy (async), PostgreSQL, Python 3.13+
- **Backend**: FastAPI, SQLAlchemy (async), PostgreSQL, Python 3.14+
- **Frontend**: React 19, Vite 8, TypeScript 6, MUI 9
- **Plotting (Python)**: matplotlib, seaborn, plotly, bokeh, altair, plotnine, pygal, lets-plot
- **Plotting (R)**: ggplot2 · **Plotting (Julia)**: Makie.jl
Expand Down Expand Up @@ -629,7 +629,7 @@ plt.savefig(f'plot-{THEME}.png', dpi=300, bbox_inches='tight') # THEME = os.get
- No `preview.png` files in repository (use GCS)
- No `quality_report.json` files (use GitHub Issues)
- No hardcoded API keys (use environment variables)
- Avoid version-specific files unless necessary (prefer single `default.py` for Python 3.10-3.13)
- No version-specific implementation files: one file per library (`implementations/python/{library}.py`) that runs on the project's Python (3.14)

## GitHub Actions Workflows

Expand Down Expand Up @@ -1062,7 +1062,7 @@ gcloud builds submit --config=app/cloudbuild.yaml --region=europe-west4 --projec
### Configuration Files

- **`api/cloudbuild.yaml`**: Backend build + deploy (includes Cloud SQL connection)
- **`api/Dockerfile`**: Python 3.13 + uv + FastAPI
- **`api/Dockerfile`**: Python 3.14 + uv + FastAPI
- **`app/cloudbuild.yaml`**: Frontend build + deploy
- **`app/Dockerfile`**: Multi-stage build (Node -> nginx)

Expand Down
2 changes: 1 addition & 1 deletion agentic/workflows/modules/regen/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def _now_iso() -> str:

def _python_version() -> str:
out = subprocess.check_output(["uv", "run", "python", "--version"], text=True).strip()
# "Python 3.13.12"
# "Python 3.14.9"
return out.split()[-1]


Expand Down
2 changes: 1 addition & 1 deletion agentic/workflows/modules/regen/picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _timestamp(blob: bytes | None) -> str | None:
return None
try:
data = yaml.load(blob.decode("utf-8"), Loader=_YAML_LOADER) or {}
except (UnicodeDecodeError, yaml.YAMLError):
except UnicodeDecodeError, yaml.YAMLError:
return None
if not isinstance(data, dict):
return None
Expand Down
6 changes: 3 additions & 3 deletions agentic/workflows/modules/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import json
import os
import sys
from typing import Any, Dict, Optional
from typing import Any, Dict, Self


class WorkflowState:
Expand Down Expand Up @@ -130,7 +130,7 @@ def save(self, working_dir: str, phase: str | None = None) -> str:
return state_path

@classmethod
def load(cls, run_id: str, working_dir: str) -> Optional["WorkflowState"]:
def load(cls, run_id: str, working_dir: str) -> Self | None:
"""Load state from file if it exists.

Returns:
Expand All @@ -153,7 +153,7 @@ def load(cls, run_id: str, working_dir: str) -> Optional["WorkflowState"]:
return None

@classmethod
def from_stdin(cls) -> Optional["WorkflowState"]:
def from_stdin(cls) -> Self | None:
"""Read state from stdin (for piped input from plan.py).

Returns:
Expand Down
Loading
Loading