data-olympus 0.3.2__tar.gz → 0.3.3__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.
- {data_olympus-0.3.2 → data_olympus-0.3.3}/CHANGELOG.md +23 -1
- {data_olympus-0.3.2 → data_olympus-0.3.3}/PKG-INFO +1 -1
- {data_olympus-0.3.2 → data_olympus-0.3.3}/pyproject.toml +1 -1
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/config.py +11 -2
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/server.py +21 -2
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/session_metrics.py +51 -9
- {data_olympus-0.3.2 → data_olympus-0.3.3}/.gitignore +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/LICENSE +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/NOTICE +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/README.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/SPEC.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/benchmarks/README.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/bin/_kb_detect_workspace.sh +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/bin/_kb_enforce.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/bin/_kb_fallback.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/bin/kb +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/bin/kb-enforce-hook +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/bin/opencode/data-olympus-gate.ts +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/deploy/k8s/README.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/deploy/k8s/read-replica/README.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/docs/releases/README.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/example-bundle/projects/acme-app/README.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/example-bundle/projects/acme-app/components/api/README.md +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/__init__.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/audit_log.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/audit_trailers.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/auth.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/cli/__init__.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/cli/import_cmd.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/cli/indexgen.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/cli/main.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/cli/report_cmd.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/cooccurrence.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/dedup.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/durable.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/embeddings.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/enforce_policy.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/format/__init__.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/format/document.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/format/frontmatter.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/format/lint.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/format/validate.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/git_ops.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/health.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/importer/__init__.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/importer/adr.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/importer/flat.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/importer/model.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/importer/okf.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/importer/run.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/importer/stamp.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/index.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/markdown_parse.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/models.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/onboarding.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/onboarding_inflight.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/onboarding_playbook.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/pending.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/principals.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/prompts.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/push_queue.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/query_expansion.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/rate_limit.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/refresh.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/report.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/rest_api.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/safe_id.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/search_gate.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/search_shortcut.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/setup_wizard.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/thin_pointer.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/tools_audit.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/tools_enforce.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/tools_onboarding.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/tools_read.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/tools_write.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/trigram.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/viewer/__init__.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/viewer/generator.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/worktrees.py +0 -0
- {data_olympus-0.3.2 → data_olympus-0.3.3}/src/data_olympus/write_gate.py +0 -0
|
@@ -12,6 +12,27 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
## [0.3.3] - 2026-07-05
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **MCP streamable-HTTP session churn under long-lived clients.** A persistent
|
|
20
|
+
client (notably `opencode serve`) that holds the `GET /mcp` SSE stream open was
|
|
21
|
+
being forced to reconnect on a cycle, piling up abandoned transports on the
|
|
22
|
+
server and leaking event listeners on the client until it degraded. Two causes
|
|
23
|
+
addressed:
|
|
24
|
+
- The activity middleware now keeps a session non-idle for as long as its SSE
|
|
25
|
+
stream is actually open (re-stamping every `KB_SESSION_TOUCH_INTERVAL_SEC`,
|
|
26
|
+
default 30s, clamped to a third of the idle window), so the reaper evicts a
|
|
27
|
+
session only after its stream has genuinely closed. With that safety in
|
|
28
|
+
place, the idle-reap default (`KB_SESSION_IDLE_TIMEOUT_SEC`) drops from 1800s
|
|
29
|
+
to 300s, so an abandoned handshake is cleared in minutes instead of half an
|
|
30
|
+
hour.
|
|
31
|
+
- The shipped ingress manifest (`deploy/k8s/ingress.yaml`) now sets a long
|
|
32
|
+
`proxy-read-timeout`/`proxy-send-timeout` and disables buffering, so a proxy
|
|
33
|
+
with a short default idle timeout (nginx: 60s) no longer closes the SSE
|
|
34
|
+
stream and triggers the reconnect loop. See `docs/serving.md`.
|
|
35
|
+
|
|
15
36
|
## [0.3.2] - 2026-07-05
|
|
16
37
|
|
|
17
38
|
### Fixed
|
|
@@ -1029,7 +1050,8 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
1029
1050
|
- `docs/adoption.md`: bring-your-own-KB guide (author, lint, index, serve, wire an agent).
|
|
1030
1051
|
- `docs/comparison.md`: how data-olympus relates to OKF, enterprise catalogs, markdown KB tools, agent-context conventions, RAG, and ADR tooling.
|
|
1031
1052
|
|
|
1032
|
-
[Unreleased]: https://github.com/knaisoma/data-olympus/compare/v0.3.
|
|
1053
|
+
[Unreleased]: https://github.com/knaisoma/data-olympus/compare/v0.3.3...HEAD
|
|
1054
|
+
[0.3.3]: https://github.com/knaisoma/data-olympus/compare/v0.3.2...v0.3.3
|
|
1033
1055
|
[0.3.2]: https://github.com/knaisoma/data-olympus/compare/v0.3.1...v0.3.2
|
|
1034
1056
|
[0.3.1]: https://github.com/knaisoma/data-olympus/compare/v0.3.0...v0.3.1
|
|
1035
1057
|
[0.3.0]: https://github.com/knaisoma/data-olympus/compare/v0.2.0...v0.3.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: data-olympus
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Governance-grade knowledge-base format (OKF-compatible) plus CLI and single-writer MCP server
|
|
5
5
|
Project-URL: Homepage, https://github.com/knaisoma/data-olympus
|
|
6
6
|
Project-URL: Repository, https://github.com/knaisoma/data-olympus
|
|
@@ -65,8 +65,15 @@ class Config:
|
|
|
65
65
|
# Streamable-http session reaping: terminate transports idle beyond this many
|
|
66
66
|
# seconds to bound _server_instances (see session_metrics). 0 disables the
|
|
67
67
|
# reaper (observability-only). The scan runs every session_reap_interval_sec.
|
|
68
|
-
|
|
68
|
+
# An in-flight GET SSE stream is kept non-idle by the activity middleware, so
|
|
69
|
+
# this window only clears sessions whose stream has actually closed (an
|
|
70
|
+
# abandoned handshake); 5 minutes keeps those from piling up.
|
|
71
|
+
session_idle_timeout_sec: int = 300
|
|
69
72
|
session_reap_interval_sec: int = 60
|
|
73
|
+
# How often the activity middleware re-stamps a session while its GET SSE
|
|
74
|
+
# stream is open, so a quiet-but-connected client is never reaped. Clamped
|
|
75
|
+
# below session_idle_timeout_sec at wiring time.
|
|
76
|
+
session_touch_interval_sec: int = 30
|
|
70
77
|
# Optional override for the status-aware reranker's status->weight map
|
|
71
78
|
# (issue #37). None means "use the Index built-in default map". A negative
|
|
72
79
|
# weight boosts an in-force status, a positive one penalizes a retired one.
|
|
@@ -191,8 +198,9 @@ def load_config() -> Config:
|
|
|
191
198
|
auth_principals = parse_principals_env(os.getenv("KB_AUTH_PRINCIPALS", ""))
|
|
192
199
|
consult_ttl_sec = int(os.getenv("KB_CONSULT_TTL_SEC", "300"))
|
|
193
200
|
ledger_path = os.getenv("KB_LEDGER_PATH", "/state/ledger.json")
|
|
194
|
-
session_idle_timeout_sec = int(os.getenv("KB_SESSION_IDLE_TIMEOUT_SEC", "
|
|
201
|
+
session_idle_timeout_sec = int(os.getenv("KB_SESSION_IDLE_TIMEOUT_SEC", "300"))
|
|
195
202
|
session_reap_interval_sec = int(os.getenv("KB_SESSION_REAP_INTERVAL_SEC", "60"))
|
|
203
|
+
session_touch_interval_sec = int(os.getenv("KB_SESSION_TOUCH_INTERVAL_SEC", "30"))
|
|
196
204
|
status_weights = _load_status_weights(os.getenv("KB_STATUS_WEIGHTS", ""))
|
|
197
205
|
read_only = _env_bool(os.getenv("KB_READ_ONLY", ""))
|
|
198
206
|
from data_olympus.cooccurrence import (
|
|
@@ -254,6 +262,7 @@ def load_config() -> Config:
|
|
|
254
262
|
ledger_path=ledger_path,
|
|
255
263
|
session_idle_timeout_sec=session_idle_timeout_sec,
|
|
256
264
|
session_reap_interval_sec=session_reap_interval_sec,
|
|
265
|
+
session_touch_interval_sec=session_touch_interval_sec,
|
|
257
266
|
status_weights=status_weights,
|
|
258
267
|
read_only=read_only,
|
|
259
268
|
cooccurrence_enabled=cooc_enabled,
|
|
@@ -251,8 +251,9 @@ def build_app(
|
|
|
251
251
|
audit_hmac_key: str = "",
|
|
252
252
|
audit_max_bytes: int = 0,
|
|
253
253
|
ledger_path: str | None = None,
|
|
254
|
-
session_idle_timeout_sec: int =
|
|
254
|
+
session_idle_timeout_sec: int = 300,
|
|
255
255
|
session_reap_interval_sec: int = 60,
|
|
256
|
+
session_touch_interval_sec: int = 30,
|
|
256
257
|
status_weights: dict[str, float] | None = None,
|
|
257
258
|
read_only: bool = False,
|
|
258
259
|
embeddings_enabled: bool = False,
|
|
@@ -300,6 +301,7 @@ def build_app(
|
|
|
300
301
|
audit_max_bytes=audit_max_bytes,
|
|
301
302
|
session_idle_timeout_sec=session_idle_timeout_sec,
|
|
302
303
|
session_reap_interval_sec=session_reap_interval_sec,
|
|
304
|
+
session_touch_interval_sec=session_touch_interval_sec,
|
|
303
305
|
status_weights=status_weights,
|
|
304
306
|
read_only=read_only,
|
|
305
307
|
embeddings_enabled=embeddings_enabled,
|
|
@@ -888,6 +890,7 @@ def build_app_from_config(config: Config, *, bootstrap_now: bool = True) -> Fast
|
|
|
888
890
|
ledger_path=config.ledger_path,
|
|
889
891
|
session_idle_timeout_sec=config.session_idle_timeout_sec,
|
|
890
892
|
session_reap_interval_sec=config.session_reap_interval_sec,
|
|
893
|
+
session_touch_interval_sec=config.session_touch_interval_sec,
|
|
891
894
|
status_weights=config.status_weights,
|
|
892
895
|
read_only=config.read_only,
|
|
893
896
|
embeddings_enabled=config.embeddings_enabled,
|
|
@@ -983,9 +986,25 @@ def main() -> None:
|
|
|
983
986
|
)
|
|
984
987
|
|
|
985
988
|
tracker = SessionActivityTracker()
|
|
989
|
+
# Re-stamp an in-flight SSE session at least 3x per idle window, so a
|
|
990
|
+
# quiet-but-connected client is never reaped even if an operator sets a short
|
|
991
|
+
# idle timeout. Falls back to the configured interval when the idle window is
|
|
992
|
+
# generous.
|
|
993
|
+
_idle = config.session_idle_timeout_sec
|
|
994
|
+
_touch_interval = float(config.session_touch_interval_sec)
|
|
995
|
+
if _idle > 0:
|
|
996
|
+
# Always strictly below the idle window (>= 3 touches per window) even for
|
|
997
|
+
# a tiny idle value; a small positive floor avoids a zero/negative sleep.
|
|
998
|
+
_touch_interval = max(0.1, min(_touch_interval, _idle / 3))
|
|
986
999
|
http_app = app.http_app(
|
|
987
1000
|
transport="streamable-http",
|
|
988
|
-
middleware=[
|
|
1001
|
+
middleware=[
|
|
1002
|
+
StarletteMiddleware(
|
|
1003
|
+
SessionActivityMiddleware,
|
|
1004
|
+
tracker=tracker,
|
|
1005
|
+
touch_interval_sec=_touch_interval,
|
|
1006
|
+
)
|
|
1007
|
+
],
|
|
989
1008
|
)
|
|
990
1009
|
# Health surfaces the live session count; the manager is only reachable once
|
|
991
1010
|
# the lifespan has started, so this returns None before then (never raises).
|
|
@@ -45,6 +45,7 @@ these internals, discovery returns ``None`` and the count is reported as
|
|
|
45
45
|
from __future__ import annotations
|
|
46
46
|
|
|
47
47
|
import asyncio
|
|
48
|
+
import contextlib
|
|
48
49
|
import logging
|
|
49
50
|
import time
|
|
50
51
|
from typing import TYPE_CHECKING, Any, Protocol
|
|
@@ -195,20 +196,61 @@ class SessionActivityTracker:
|
|
|
195
196
|
|
|
196
197
|
class SessionActivityMiddleware:
|
|
197
198
|
"""ASGI middleware that stamps :class:`SessionActivityTracker` on each request
|
|
198
|
-
carrying an ``mcp-session-id`` header.
|
|
199
|
-
|
|
199
|
+
carrying an ``mcp-session-id`` header.
|
|
200
|
+
|
|
201
|
+
The ``GET /mcp`` Server-Sent-Events stream is a *single* long-lived request
|
|
202
|
+
that emits no further ASGI events while the session is quiet. Stamping only
|
|
203
|
+
at request start would let the idle reaper evict a still-connected client
|
|
204
|
+
after the idle window (forcing a reconnect, the exact churn that piles up
|
|
205
|
+
transports server-side and leaks listeners in a persistent client like
|
|
206
|
+
``opencode serve``). So for an in-flight GET stream this middleware re-stamps
|
|
207
|
+
the session every ``touch_interval_sec`` for as long as the stream stays open;
|
|
208
|
+
when the client disconnects the request completes, re-stamping stops, and only
|
|
209
|
+
then does the session go idle and become reap-eligible. Short GET/POST
|
|
210
|
+
requests finish before the first tick, so they pay only the initial stamp.
|
|
211
|
+
"""
|
|
200
212
|
|
|
201
|
-
def __init__(
|
|
213
|
+
def __init__(
|
|
214
|
+
self,
|
|
215
|
+
app: ASGIApp,
|
|
216
|
+
tracker: SessionActivityTracker,
|
|
217
|
+
*,
|
|
218
|
+
touch_interval_sec: float = 30.0,
|
|
219
|
+
) -> None:
|
|
202
220
|
self.app = app
|
|
203
221
|
self._tracker = tracker
|
|
222
|
+
self._touch_interval = touch_interval_sec
|
|
204
223
|
|
|
205
224
|
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
|
206
|
-
if scope.get("type")
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
225
|
+
if scope.get("type") != "http":
|
|
226
|
+
await self.app(scope, receive, send)
|
|
227
|
+
return
|
|
228
|
+
session_id = ""
|
|
229
|
+
for key, value in scope.get("headers", []):
|
|
230
|
+
if key.lower() == _MCP_SESSION_ID_HEADER and value:
|
|
231
|
+
session_id = value.decode("latin-1")
|
|
232
|
+
break
|
|
233
|
+
if not session_id:
|
|
234
|
+
await self.app(scope, receive, send)
|
|
235
|
+
return
|
|
236
|
+
self._tracker.touch(session_id)
|
|
237
|
+
# Only the long-lived GET SSE stream needs keep-alive re-stamping.
|
|
238
|
+
if scope.get("method") != "GET":
|
|
239
|
+
await self.app(scope, receive, send)
|
|
240
|
+
return
|
|
241
|
+
|
|
242
|
+
async def _keep_active() -> None:
|
|
243
|
+
while True:
|
|
244
|
+
await asyncio.sleep(self._touch_interval)
|
|
245
|
+
self._tracker.touch(session_id)
|
|
246
|
+
|
|
247
|
+
task = asyncio.create_task(_keep_active())
|
|
248
|
+
try:
|
|
249
|
+
await self.app(scope, receive, send)
|
|
250
|
+
finally:
|
|
251
|
+
task.cancel()
|
|
252
|
+
with contextlib.suppress(asyncio.CancelledError, Exception):
|
|
253
|
+
await task
|
|
212
254
|
|
|
213
255
|
|
|
214
256
|
async def reap_idle_sessions(
|
|
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
|
{data_olympus-0.3.2 → data_olympus-0.3.3}/example-bundle/projects/acme-app/components/api/README.md
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
|