nene2-python 1.8.51__tar.gz → 1.8.52__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nene2_python-1.8.51 → nene2_python-1.8.52}/PKG-INFO +1 -1
- nene2_python-1.8.52/docs/field-trials/2026-05-field-trial-181.md +269 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/INDEX.md +3 -2
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/todo/current.md +5 -4
- {nene2_python-1.8.51 → nene2_python-1.8.52}/pyproject.toml +1 -1
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.env.example +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.github/workflows/ci.yml +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.github/workflows/docs.yml +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.github/workflows/publish.yml +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.gitignore +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.vitepress/config.mts +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.vitepress/theme/custom.css +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/.vitepress/theme/index.ts +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/AGENTS.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/CHANGELOG.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/CLAUDE.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/Dockerfile +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/LICENSE +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/README.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/alembic/README +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/alembic/env.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/alembic/script.py.mako +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/alembic/versions/001_create_notes_and_tags_tables.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/alembic.ini +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/compose.yaml +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0001-toolchain.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0002-clean-architecture.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0003-security-first.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0004-ai-first-design.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0005-logging.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0006-rate-limiting.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0009-mcp-design.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0010-async-use-case.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/adr/0011-mcp-as-core-dependency.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/de/index.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/de/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/explanation/architecture.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/explanation/design-philosophy.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-1.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-10.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-100.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-101.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-102.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-103.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-104.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-105.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-106.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-107.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-108.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-109.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-11.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-110.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-111.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-112.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-113.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-114.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-115.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-116.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-117.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-118.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-119.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-12.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-120.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-121.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-122.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-123.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-124.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-125.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-126.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-127.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-128.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-129.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-13.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-130.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-131.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-132.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-133.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-134.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-135.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-136.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-137.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-138.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-139.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-14.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-140.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-141.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-142.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-143.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-144.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-145.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-146.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-147.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-148.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-149.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-15.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-150.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-151.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-152.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-153.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-154.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-155.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-156.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-157.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-158.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-159.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-16.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-160.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-161.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-162.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-163.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-164.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-165.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-166.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-167.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-168.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-169.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-17.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-170.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-171.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-172.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-173.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-174.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-175.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-176.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-177.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-178.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-179.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-18.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-180.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-19.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-2.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-20.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-21.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-22.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-23.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-24.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-25.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-26.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-27.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-28.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-29.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-3.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-30.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-31.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-32.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-33.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-34.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-35.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-36.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-37.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-38.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-39.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-4.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-40.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-41.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-42.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-43.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-44.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-45.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-46.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-47.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-48.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-49.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-5.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-50.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-51.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-52.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-53.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-54.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-55.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-56.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-57.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-58.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-59.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-6.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-60.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-61.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-62.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-63.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-64.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-65.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-66.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-67.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-68.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-69.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-7.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-70.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-71.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-72.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-73.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-74.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-75.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-76.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-77.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-78.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-79.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-8.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-80.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-81.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-82.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-83.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-84.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-85.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-86.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-87.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-88.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-89.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-9.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-90.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-91.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-92.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-93.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-94.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-95.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-96.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-97.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-98.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/field-trials/2026-05-field-trial-99.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/fr/index.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/fr/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/add-new-domain.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/api-versioning.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/async-use-case.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/background-tasks.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/configure-auth.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/cors.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/custom-auth-middleware.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/dependency-injection.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/domain-events.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/file-upload.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/lifespan-and-app-state.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/middleware-stack.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/new-project.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/problem-details.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/response-patterns.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/run-tests.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/soft-delete.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/sqlalchemy-repository.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/streaming.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/structured-logging.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/validation.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/how-to/webhook.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/howto/mcp-setup.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/index.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/explanation/architecture.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/explanation/design-philosophy.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/how-to/add-new-domain.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/how-to/configure-auth.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/how-to/new-project.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/how-to/run-tests.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/how-to/sqlalchemy-repository.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/howto/mcp-setup.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/index.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/reference/api.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/reference/configuration.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/reference/framework-modules.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/tutorials/first-domain.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/ja/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/pt-br/index.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/pt-br/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/reference/api.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/reference/configuration.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/reference/framework-modules.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/roadmap.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/templates/field-trial-report.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/tutorials/first-domain.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/zh/index.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/docs/zh/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/package-lock.json +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/package.json +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/__main__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/app.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/comment/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/comment/entity.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/comment/exceptions.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/comment/handler.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/comment/repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/comment/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/comment/use_case.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/mcp.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/async_use_case.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/entity.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/exceptions.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/handler.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/note/use_case.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/schema.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/tag/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/tag/entity.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/tag/exceptions.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/tag/handler.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/tag/repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/tag/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/example/tag/use_case.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/auth/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/auth/api_key.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/auth/bearer_token.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/auth/deps.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/auth/exceptions.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/auth/interfaces.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/auth/local_verifier.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/cache/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/cache/ttl.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/config/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/config/settings.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/database/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/database/exceptions.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/database/health.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/database/interfaces.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/database/sqlalchemy_executor.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/database/utils.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/http/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/http/etag.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/http/health.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/http/pagination.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/http/problem_details.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/log/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/log/setup.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/mcp/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/mcp/http_client.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/mcp/server.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/domain_exception.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/error_handler.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/request_id.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/request_logging.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/request_size_limit.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/security_headers.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/setup.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/middleware/throttle.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/py.typed +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/security/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/security/webhook.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/use_case/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/use_case/protocols.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/validation/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/nene2/validation/exceptions.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/scripts/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/src/scripts/export_openapi.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/conftest.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/comment/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/comment/test_comment_http.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/comment/test_comment_repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/comment/test_comment_use_case.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/conftest.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/note/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/note/test_async_note_use_case.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/note/test_list_notes.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/note/test_note_repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/tag/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/tag/test_tag_repository.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/tag/test_tags.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/test_cors.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/example/test_mcp.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/auth/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/auth/test_api_key.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/auth/test_bearer_token.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/auth/test_make_require_auth.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/auth/test_token_issuer.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/cache/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/cache/test_ttl.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/config/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/config/test_settings.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/database/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/database/test_transaction.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/database/test_utils.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/http/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/http/test_etag.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/http/test_health.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/http/test_pagination.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/http/test_problem_details.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/log/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/log/test_setup.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/mcp/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/mcp/test_http_client.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/mcp/test_server.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_error_handler.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_request_id.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_request_logging.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_request_size_limit.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_security_headers.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_setup_middlewares.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_simple_domain_handler.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/middleware/test_throttle.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/security/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/security/test_webhook.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/use_case/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/use_case/test_protocols.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/use_case/test_run_in_threadpool.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/validation/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/nene2/validation/test_exceptions.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/scripts/__init__.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/tests/scripts/test_export_openapi.py +0 -0
- {nene2_python-1.8.51 → nene2_python-1.8.52}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nene2-python
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.52
|
|
4
4
|
Summary: NENE2 Python — minimal API framework following NENE2's design philosophy
|
|
5
5
|
Project-URL: Homepage, https://github.com/hideyukiMORI/nene2-python
|
|
6
6
|
Project-URL: Repository, https://github.com/hideyukiMORI/nene2-python
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# FT181: gzip モジュール
|
|
2
|
+
|
|
3
|
+
**日付**: 2026-05-21
|
|
4
|
+
**テーマ**: gzip 圧縮・解凍・メタデータ操作・ビルド再現性
|
|
5
|
+
**セキュリティ診断**: なし(181 % 3 = 1)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 概要
|
|
10
|
+
|
|
11
|
+
Python 標準ライブラリの `gzip` モジュールを検証する。
|
|
12
|
+
FT179(zlib)との違いを意識しながら、gzip 固有のヘッダーメタデータ(ファイル名・mtime)、
|
|
13
|
+
展開爆弾対策付きのストリーミング解凍、mtime=0 による決定論的圧縮(ビルド再現性)まで網羅する。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 実装したサンプルアプリ
|
|
18
|
+
|
|
19
|
+
**場所**: `/home/xi/docker/nene2-python-FT/ft181-gzip/`
|
|
20
|
+
|
|
21
|
+
### 主要機能
|
|
22
|
+
|
|
23
|
+
| 関数/クラス | 概要 |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `compress(data, filename, level, mtime)` | gzip 圧縮(`CompressResult` 返却) |
|
|
26
|
+
| `compress_to_bytes(data, filename, level, mtime)` | gzip 圧縮して raw bytes を返す |
|
|
27
|
+
| `decompress(compressed)` | 展開爆弾対策付きストリーミング解凍(`DecompressResult` 返却) |
|
|
28
|
+
| `decompress_to_bytes(compressed)` | 解凍して raw bytes を返す |
|
|
29
|
+
| `_parse_gzip_header(data)` | gzip ヘッダーからファイル名・mtime を手動解析 |
|
|
30
|
+
| `read_gzip_info(compressed)` | メタデータ読み取り(`GzipInfo` 返却) |
|
|
31
|
+
| `roundtrip(data, level)` | 圧縮 → 解凍のラウンドトリップ検証 |
|
|
32
|
+
| `compress_streaming(chunks, level)` | チャンクリストのストリーミング圧縮 |
|
|
33
|
+
| `compress_deterministic(data, level)` | mtime=0 で決定論的圧縮 |
|
|
34
|
+
| `is_reproducible(data, level)` | 2 回圧縮して同一バイト列か確認 |
|
|
35
|
+
|
|
36
|
+
### HTTP エンドポイント
|
|
37
|
+
|
|
38
|
+
| メソッド | パス | 概要 |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| POST | `/compress` | gzip 圧縮(filename/level 指定可) |
|
|
41
|
+
| POST | `/decompress` | gzip 解凍 |
|
|
42
|
+
| POST | `/info` | gzip メタデータ読み取り |
|
|
43
|
+
| POST | `/roundtrip` | ラウンドトリップ検証 |
|
|
44
|
+
| POST | `/compress/streaming` | ストリーミング gzip 圧縮 |
|
|
45
|
+
| POST | `/compress/deterministic` | 決定論的圧縮(mtime=0) |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## テスト結果
|
|
50
|
+
|
|
51
|
+
**40 passed**(初回 33 通過 → F-1 修正後 40 全通過)
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
40 passed in 0.60s
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
mypy: Success / ruff: All checks passed / pip-audit: PYSEC-2025-183(継続監視)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 摩擦ポイント
|
|
62
|
+
|
|
63
|
+
### F-1: `GzipFile.name` は `fileobj=BytesIO` のとき常に空文字列を返す(深刻度: 中)
|
|
64
|
+
|
|
65
|
+
**事象**: `gzip.GzipFile(filename="test.txt", mode="wb", fileobj=BytesIO())` で
|
|
66
|
+
ファイル名を指定して圧縮しても、読み取り時に `gz.name` が `""` を返す。
|
|
67
|
+
|
|
68
|
+
**原因**: Python の `GzipFile.name` プロパティはファイルシステム上のパスを返す設計。
|
|
69
|
+
`fileobj` が `BytesIO` の場合、ディスク上のファイルパスが存在しないため常に空文字列になる。
|
|
70
|
+
ファイル名はバイト列として gzip ヘッダーの FNAME フィールドに書き込まれているが、
|
|
71
|
+
`gz.name` 経由では取得できない。
|
|
72
|
+
|
|
73
|
+
**対応**: gzip ヘッダーを直接解析する `_parse_gzip_header()` を実装:
|
|
74
|
+
```python
|
|
75
|
+
_GZIP_MAGIC = b"\x1f\x8b"
|
|
76
|
+
_FEXTRA = 4
|
|
77
|
+
_FNAME = 8
|
|
78
|
+
|
|
79
|
+
def _parse_gzip_header(data: bytes) -> tuple[str, int] | None:
|
|
80
|
+
if len(data) < 10 or data[:2] != _GZIP_MAGIC:
|
|
81
|
+
return None
|
|
82
|
+
flags = data[3]
|
|
83
|
+
mtime = int.from_bytes(data[4:8], "little")
|
|
84
|
+
offset = 10
|
|
85
|
+
if flags & _FEXTRA:
|
|
86
|
+
xlen = int.from_bytes(data[offset:offset+2], "little")
|
|
87
|
+
offset += 2 + xlen
|
|
88
|
+
filename = ""
|
|
89
|
+
if flags & _FNAME:
|
|
90
|
+
end = data.find(b"\x00", offset)
|
|
91
|
+
filename = data[offset:end].decode("latin-1")
|
|
92
|
+
return filename, mtime
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**副次効果**: 不正な gzip データ(マジックバイト不一致)を早期に拒否できるため、
|
|
96
|
+
`read_gzip_info()` の invalid data 検出も正確になった。
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 観察点
|
|
101
|
+
|
|
102
|
+
### 観察1: gzip = zlib + ヘッダーメタデータ
|
|
103
|
+
|
|
104
|
+
zlib(FT179)との主な違いは gzip ヘッダーの存在。
|
|
105
|
+
|
|
106
|
+
| 特性 | zlib | gzip |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| ファイルフォーマット | raw deflate + zlib wrapper | deflate + gzip header + trailer |
|
|
109
|
+
| ファイル名 | なし | FNAME フィールドに格納 |
|
|
110
|
+
| mtime | なし | MTIME フィールドに格納 |
|
|
111
|
+
| マジックバイト | なし | `\x1f\x8b` |
|
|
112
|
+
| 用途 | ネットワーク圧縮・インメモリ | .gz ファイル、HTTP Content-Encoding |
|
|
113
|
+
|
|
114
|
+
HTTP の `Content-Encoding: gzip` は gzip フォーマット、
|
|
115
|
+
`Transfer-Encoding: chunked` と組み合わせるストリーミングは zlib が適している。
|
|
116
|
+
|
|
117
|
+
### 観察2: mtime=0 でビルド再現性を確保できる
|
|
118
|
+
|
|
119
|
+
gzip ヘッダーには圧縮時刻(mtime)が埋め込まれる。
|
|
120
|
+
mtime がデフォルト(`time.time()`)の場合、同一データでも圧縮のたびにバイト列が変わる。
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# 問題: mtime が異なると出力が変わる → Docker イメージのレイヤーハッシュが毎回変わる
|
|
124
|
+
buf1 = io.BytesIO()
|
|
125
|
+
with gzip.GzipFile(mode="wb", fileobj=buf1, mtime=time.time()) as gz:
|
|
126
|
+
gz.write(data)
|
|
127
|
+
# buf1.getvalue() != buf2.getvalue()(別の時刻で生成)
|
|
128
|
+
|
|
129
|
+
# 解決: mtime=0 で決定論的
|
|
130
|
+
with gzip.GzipFile(mode="wb", fileobj=buf, mtime=0.0) as gz:
|
|
131
|
+
gz.write(data)
|
|
132
|
+
# 同一データ → 常に同一バイト列
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Docker イメージビルドや CI でのアーティファクトハッシュ検証に重要。
|
|
136
|
+
|
|
137
|
+
### 観察3: `GzipFile` の `mode` パラメータは省略できない
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
# 正: mode を明示
|
|
141
|
+
gzip.GzipFile(fileobj=buf, mode="rb")
|
|
142
|
+
|
|
143
|
+
# 誤: mode 省略 → TypeError または予期しない動作
|
|
144
|
+
gzip.GzipFile(fileobj=buf)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`open()` とは異なり `mode` のデフォルト値が `"rb"` になっている(Python 3.12 で確認)が、
|
|
148
|
+
明示指定するほうが意図が明確で安全。
|
|
149
|
+
|
|
150
|
+
### 観察4: 展開爆弾対策は zlib と同様にストリーミング読み取りが必須
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
# 危険: gzip.decompress() は全データをメモリに展開する
|
|
154
|
+
gzip.decompress(huge_gzip) # → OOM の危険
|
|
155
|
+
|
|
156
|
+
# 安全: チャンク読み取りで MAX_OUTPUT_BYTES を監視
|
|
157
|
+
with gzip.GzipFile(fileobj=buf, mode="rb") as gz:
|
|
158
|
+
while True:
|
|
159
|
+
chunk = gz.read(CHUNK_SIZE)
|
|
160
|
+
total += len(chunk)
|
|
161
|
+
if total > MAX_OUTPUT_BYTES:
|
|
162
|
+
return None # 早期終了
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## nene2-python フレームワークとの統合
|
|
168
|
+
|
|
169
|
+
- `compress_to_bytes(data, filename="...", mtime=0.0)` はファイルアップロード API のレスポンスに直接使える
|
|
170
|
+
- `_parse_gzip_header()` はヘッダー検証のユーティリティとして再利用可能
|
|
171
|
+
- `MAX_OUTPUT_BYTES = 50MB` の展開爆弾対策は zlib(FT179)と同じ定数で統一
|
|
172
|
+
- Pydantic `max_length=20_971_520` で 10MB のデータ(hex 換算 20MB)まで制限
|
|
173
|
+
- `compress_deterministic()` は CI アーティファクトのハッシュ検証に使える
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Developer Experience (DX) Review
|
|
178
|
+
|
|
179
|
+
### ペルソナ1: 初心者(Python 歴1年・独学中・女性・バックエンド志望)
|
|
180
|
+
|
|
181
|
+
API レスポンスのデータを gzip 圧縮して返す機能を実装しようとしている。
|
|
182
|
+
|
|
183
|
+
**ドキュメント理解**: `gzip.compress()` / `gzip.decompress()` はシンプルで分かりやすい。
|
|
184
|
+
`GzipFile` クラスの `filename` / `mtime` パラメータの意味は公式ドキュメントに書いてあるが、
|
|
185
|
+
なぜ `gz.name` で取り戻せないかは書いていない(F-1 の罠)。
|
|
186
|
+
**事故リスク**: 高。`gzip.decompress()` に信頼できないデータを渡すと OOM になりうる。
|
|
187
|
+
(zlib FT179 と同じリスク)
|
|
188
|
+
**規約の使いやすさ**: `gzip.open()` は通常のファイル操作に慣れた人には直感的。
|
|
189
|
+
`io.BytesIO` との組み合わせはやや初心者にはハードルがある。
|
|
190
|
+
|
|
191
|
+
### ペルソナ2: ロースキル経験者(Python 歴3-4年・スクリプト系・男性・SES)
|
|
192
|
+
|
|
193
|
+
既存の gzip ファイル処理コードをコピーして API に組み込もうとしている。
|
|
194
|
+
|
|
195
|
+
**コピペ可能性**: `gzip.compress()` / `gzip.decompress()` はスクリプト系コードにもよく登場するが、
|
|
196
|
+
展開爆弾対策を含むパターンは少ない。コピペ元次第でセキュリティが変わる。
|
|
197
|
+
**拡張時の罠**: `compress_to_bytes()` の `mtime=0.0` のデフォルトを削除すると
|
|
198
|
+
ビルド再現性が失われるが、エラーは出ない。「意味があるから付けてある」と分かりにくい。
|
|
199
|
+
**セキュリティ的な事故リスク**: 高。展開爆弾対策なしは DoS に直結。
|
|
200
|
+
|
|
201
|
+
### ペルソナ3: フロントエンド寄り経験者(React/TS 歴4年・バックエンド転向中・ノンバイナリ)
|
|
202
|
+
|
|
203
|
+
フロントエンドから `.gz` ファイルを送信するアップロード API を実装している。
|
|
204
|
+
|
|
205
|
+
**エラーレスポンスの質**: 不正な gzip データに 400 を返す設計は良い。
|
|
206
|
+
`gzip.BadGzipFile` を catch して適切なエラーメッセージを返すことで、
|
|
207
|
+
クライアント側でのデバッグが容易。
|
|
208
|
+
**Python 固有概念の学習コスト**: `io.BytesIO` を使ったインメモリ gzip 操作は、
|
|
209
|
+
JS の `Blob` / `ArrayBuffer` に慣れた人には少し概念が違う。
|
|
210
|
+
**事故リスク**: 低。HTTP 境界での Pydantic バリデーションが充実。
|
|
211
|
+
|
|
212
|
+
### ペルソナ4: バックエンド経験者(Django/FastAPI 歴5-6年・男性・リードエンジニア)
|
|
213
|
+
|
|
214
|
+
HTTP レスポンスの `Content-Encoding: gzip` や静的ファイルの事前圧縮を検討している。
|
|
215
|
+
|
|
216
|
+
**他フレームワークとの差異**: Django の `GZipMiddleware` は透過的に圧縮するため、
|
|
217
|
+
gzip を手動で操作することは少ない。FastAPI でも `GZipMiddleware` が利用可能。
|
|
218
|
+
ただし事前圧縮(pre-compressed static files)や S3 アップロード前圧縮には直接操作が必要。
|
|
219
|
+
**nene2-python の薄さへの評価**: `compress_deterministic()` の mtime=0 パターンは
|
|
220
|
+
CI/CD パイプラインでよく使うが、stdlib ドキュメントには目立たない。
|
|
221
|
+
フレームワーク側で「ビルド再現性のある圧縮」を推奨パターンとして提示する価値がある。
|
|
222
|
+
**本番投入可能性**: 展開爆弾対策 + ヘッダー手動解析は本番品質。
|
|
223
|
+
|
|
224
|
+
### ペルソナ5: シニアエンジニア(設計・コードレビュー担当・女性・10-12年)
|
|
225
|
+
|
|
226
|
+
**コードレビューチェックポイント**:
|
|
227
|
+
- [x] `gzip.decompress()` 直接使用でなく、ストリーミング解凍で上限チェックがあるか
|
|
228
|
+
- [x] `gz.name` でファイル名を取得しようとして空文字列を返すコードがないか(F-1)
|
|
229
|
+
- [x] `mtime` が指定されていないコードが「毎回違うバイト列」を生成していないか
|
|
230
|
+
|
|
231
|
+
**チームでの安全なパターン**: `compress_to_bytes(data, mtime=0.0)` を社内標準として
|
|
232
|
+
「再現可能圧縮はこれを使う」とドキュメント化することで、mtime の罠を全員が回避できる。
|
|
233
|
+
**ツール追加の必要性**: bandit B301 相当(`gzip.decompress` 直接使用)を
|
|
234
|
+
コードレビューチェックリストに追加すべき。ruff には相当ルールなし。
|
|
235
|
+
|
|
236
|
+
### ペルソナ6: 設計者・ポリシー照合(nene2-python 設計ポリシー目線)
|
|
237
|
+
|
|
238
|
+
**ポリシー達成度**: 高
|
|
239
|
+
**「初心者でも安全な API」達成度**: 中
|
|
240
|
+
— `gzip.decompress()` 直接使用の罠は FT179 と同じ。
|
|
241
|
+
zlib と gzip で同じ問題が繰り返されることは「stdlib の設計の一貫性のなさ」を示している。
|
|
242
|
+
**設計上の負債**: `_parse_gzip_header()` はプライベートだが、
|
|
243
|
+
gzip ヘッダーを扱う他のコードでも必要になりうる。
|
|
244
|
+
`nene2.io.gzip` モジュールとして昇格させる候補。
|
|
245
|
+
**Follow-up Issue 候補**: なし(現状の実装で十分)
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Follow-up Issues
|
|
250
|
+
|
|
251
|
+
| 優先度 | タイトル | 種別 |
|
|
252
|
+
|---|---|---|
|
|
253
|
+
| 低 | `GzipFile.name` が BytesIO で空になる挙動を How-to ドキュメントに記載 | docs |
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## まとめ
|
|
258
|
+
|
|
259
|
+
FT181 では `gzip` モジュールを中心に、圧縮・解凍・メタデータ操作・ビルド再現性を実装した。
|
|
260
|
+
40 テストが全通過し、mypy/ruff も問題なし。
|
|
261
|
+
|
|
262
|
+
最大の発見は F-1: `GzipFile.name` が `fileobj=BytesIO` のとき常に空文字列を返す問題。
|
|
263
|
+
gzip ヘッダーのファイル名フィールドを取得するには、バイト列を直接解析する `_parse_gzip_header()` が必要。
|
|
264
|
+
この発見により、不正な gzip データの早期検出も正確になった。
|
|
265
|
+
|
|
266
|
+
`mtime=0.0` による決定論的圧縮は Docker イメージビルドや CI での
|
|
267
|
+
アーティファクトハッシュ検証に重要な知見。
|
|
268
|
+
|
|
269
|
+
v1.8.52 としてリリース。
|
|
@@ -214,6 +214,7 @@
|
|
|
214
214
|
| [FT178](2026-05-field-trial-178.md) | base64 モジュール — エンコード・URL セーフ・データ URI | | |
|
|
215
215
|
| [FT179](2026-05-field-trial-179.md) | zlib モジュール — 圧縮・解凍・展開爆弾対策・チェックサム | | |
|
|
216
216
|
| [FT180](2026-05-field-trial-180.md) | xml モジュール — XXE/展開爆弾防御・構造検証・RSS パース | 🔒🔍 | [#506](https://github.com/hideyukiMORI/nene2-python/issues/506) [#507](https://github.com/hideyukiMORI/nene2-python/issues/507) |
|
|
217
|
+
| [FT181](2026-05-field-trial-181.md) | gzip モジュール — 圧縮・解凍・メタデータ・ビルド再現性 | | |
|
|
217
218
|
|
|
218
219
|
---
|
|
219
220
|
|
|
@@ -221,7 +222,7 @@
|
|
|
221
222
|
|
|
222
223
|
FT3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 174, 177, 180
|
|
223
224
|
|
|
224
|
-
合計: **61件**(
|
|
225
|
+
合計: **61件**(181 FT 中 約 34%)
|
|
225
226
|
|
|
226
227
|
## クラッカーペンテスト実施済み一覧(🔍)
|
|
227
228
|
|
|
@@ -229,4 +230,4 @@ FT172, FT176, FT180
|
|
|
229
230
|
|
|
230
231
|
---
|
|
231
232
|
|
|
232
|
-
*最終更新: 2026-05-21 (
|
|
233
|
+
*最終更新: 2026-05-21 (FT181 / v1.8.52)*
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# TODO — current
|
|
2
2
|
|
|
3
3
|
最終更新: 2026-05-21
|
|
4
|
-
現状: **v1.8.
|
|
4
|
+
現状: **v1.8.52 安定版 / フィールドトライアルループ継続中(FT181 完了)**
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
## 状態サマリー
|
|
9
9
|
|
|
10
|
-
v1.8.
|
|
11
|
-
フィールドトライアルループは
|
|
10
|
+
v1.8.52 完了済み。FT181(gzip / 圧縮・解凍・メタデータ・ビルド再現性)を含む FT181 件を実施済み。
|
|
11
|
+
フィールドトライアルループは FT182 以降も継続中。
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -34,6 +34,7 @@ v1.8.51 完了済み。FT180(xml / XXE防御・展開爆弾対策・RSS パー
|
|
|
34
34
|
|
|
35
35
|
| バージョン | 主な内容 |
|
|
36
36
|
|---|---|
|
|
37
|
+
| v1.8.52 | FT181: gzip — 圧縮・解凍・メタデータ手動解析・ビルド再現性 |
|
|
37
38
|
| v1.8.51 | FT180: xml — XXE/展開爆弾防御・RSS パース(診断+ペンテスト) |
|
|
38
39
|
| v1.8.50 | FT179: zlib — 圧縮・解凍・展開爆弾対策・CRC32/Adler-32 |
|
|
39
40
|
| v1.8.49 | FT178: base64 — エンコード・URL セーフ・データ URI・HTTP Basic Auth |
|
|
@@ -48,7 +49,7 @@ v1.8.51 完了済み。FT180(xml / XXE防御・展開爆弾対策・RSS パー
|
|
|
48
49
|
|
|
49
50
|
## フィールドトライアル進捗
|
|
50
51
|
|
|
51
|
-
**実施済み**: FT1〜
|
|
52
|
+
**実施済み**: FT1〜FT181(全 181 件)
|
|
52
53
|
|
|
53
54
|
索引: [`docs/field-trials/INDEX.md`](../field-trials/INDEX.md)
|
|
54
55
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nene2_python-1.8.51 → nene2_python-1.8.52}/alembic/versions/001_create_notes_and_tags_tables.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|