meshcode 2.10.22__tar.gz → 2.10.26__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.
- {meshcode-2.10.22 → meshcode-2.10.26}/PKG-INFO +1 -1
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/__init__.py +1 -1
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/server.py +194 -31
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.10.22 → meshcode-2.10.26}/pyproject.toml +1 -1
- {meshcode-2.10.22 → meshcode-2.10.26}/README.md +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/ascii_art.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/cli.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/comms_v4.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/invites.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/launcher.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/launcher_install.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/preferences.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/run_agent.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/secrets.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/self_update.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode/setup_clients.py +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/setup.cfg +0 -0
- {meshcode-2.10.22 → meshcode-2.10.26}/tests/test_status_enum_coverage.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "2.10.
|
|
2
|
+
__version__ = "2.10.26"
|
|
@@ -156,9 +156,11 @@ def _try_auto_wake(from_agent: str, preview: str) -> None:
|
|
|
156
156
|
# Sanitize inputs: strip everything except alphanumeric, spaces, basic punctuation
|
|
157
157
|
safe_agent = re.sub(r'[^a-zA-Z0-9_\- ]', '', from_agent)[:50]
|
|
158
158
|
safe_preview = re.sub(r'[^a-zA-Z0-9_\-.,!? ]', '', preview)[:60]
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
# Plain-text nudge. ANSI colors were stripped 2026-04-16 because terminals
|
|
160
|
+
# that don't interpret escape sequences (TypeScript runners, some VSCode
|
|
161
|
+
# configurations, pipelines, tmux without termguicolors) render the raw
|
|
162
|
+
# bytes — "[91m[1m[mesh][0m …" — which is worse UX than no color at all.
|
|
163
|
+
nudge = f"[mesh] {safe_agent} > {safe_preview} — meshcode_check()"
|
|
162
164
|
system = platform.system()
|
|
163
165
|
try:
|
|
164
166
|
if system == "Darwin":
|
|
@@ -799,12 +801,11 @@ def _log_crash_to_db(reason: str = "unknown", error_detail: str = "") -> None:
|
|
|
799
801
|
|
|
800
802
|
|
|
801
803
|
|
|
802
|
-
# NOTE: Do NOT install
|
|
803
|
-
#
|
|
804
|
-
# handlers override Python's default KeyboardInterrupt, preventing anyio from
|
|
805
|
-
# cancelling tasks cleanly. Network calls inside signal/atexit handlers can
|
|
806
|
-
# deadlock or corrupt the event loop. The lease will be released by the
|
|
804
|
+
# NOTE: Do NOT install custom SIGTERM handlers or atexit hooks here — network
|
|
805
|
+
# calls inside them can deadlock the event loop. The lease is released by the
|
|
807
806
|
# lifespan shutdown handler instead.
|
|
807
|
+
#
|
|
808
|
+
# SIGINT handling is special — see run_server() for why we set SIG_IGN there.
|
|
808
809
|
|
|
809
810
|
|
|
810
811
|
# ============================================================
|
|
@@ -1345,14 +1346,12 @@ def meshcode_broadcast(payload: Any) -> Dict[str, Any]:
|
|
|
1345
1346
|
elif not isinstance(payload, dict):
|
|
1346
1347
|
return {"error": "payload must be a string or object", "got_type": type(payload).__name__}
|
|
1347
1348
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
sent += 1
|
|
1355
|
-
return {"broadcast": True, "agents_notified": sent}
|
|
1349
|
+
# Canonical broadcast: one row with to_agent='*'. Every agent's inbox
|
|
1350
|
+
# query includes `to_agent = '*'` so all recipients see it, without the
|
|
1351
|
+
# N-row fanout that caused duplicate-render bugs.
|
|
1352
|
+
be.send_message(_PROJECT_ID, AGENT_NAME, "*", payload, msg_type="broadcast",
|
|
1353
|
+
api_key=_get_api_key())
|
|
1354
|
+
return {"broadcast": True, "to": "*"}
|
|
1356
1355
|
|
|
1357
1356
|
|
|
1358
1357
|
@mcp.tool()
|
|
@@ -1488,7 +1487,7 @@ def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
|
|
|
1488
1487
|
|
|
1489
1488
|
@mcp.tool()
|
|
1490
1489
|
@with_working_status
|
|
1491
|
-
async def meshcode_wait(timeout_seconds: int =
|
|
1490
|
+
async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -> Dict[str, Any]:
|
|
1492
1491
|
"""Block until a mesh message arrives or a task needs attention.
|
|
1493
1492
|
|
|
1494
1493
|
INTERNAL LOOP: This function loops internally and only returns when
|
|
@@ -1498,7 +1497,10 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
|
|
|
1498
1497
|
accidentally using ScheduleWakeup or exiting the loop.
|
|
1499
1498
|
|
|
1500
1499
|
Args:
|
|
1501
|
-
timeout_seconds: Max wait time per poll cycle (default
|
|
1500
|
+
timeout_seconds: Max wait time per poll cycle (default 20, hard cap 20).
|
|
1501
|
+
Short cap keeps the outer tool call bounded so the user can press
|
|
1502
|
+
ESC in Claude Code without killing the MCP server — the inner
|
|
1503
|
+
loop continues polling across cycles at zero token cost.
|
|
1502
1504
|
"""
|
|
1503
1505
|
global _IN_WAIT, _CONSECUTIVE_IDLE_SECONDS, _LAST_SEEN_TS
|
|
1504
1506
|
|
|
@@ -1541,7 +1543,7 @@ async def meshcode_wait(timeout_seconds: int = 120, include_acks: bool = False)
|
|
|
1541
1543
|
|
|
1542
1544
|
_IN_WAIT = True
|
|
1543
1545
|
_set_state("waiting", "listening for messages")
|
|
1544
|
-
capped_timeout = min(max(1, int(timeout_seconds)),
|
|
1546
|
+
capped_timeout = min(max(1, int(timeout_seconds)), 20)
|
|
1545
1547
|
try:
|
|
1546
1548
|
# ── INTERNAL LOOP ──────────────────────────────────────────
|
|
1547
1549
|
# Keep polling until something actionable arrives.
|
|
@@ -1944,17 +1946,44 @@ def meshcode_task_create(title: str, description: str = "", assignee: str = "*",
|
|
|
1944
1946
|
|
|
1945
1947
|
@mcp.tool()
|
|
1946
1948
|
@with_working_status
|
|
1947
|
-
def meshcode_tasks(status_filter: Optional[str] = None) -> Dict[str, Any]:
|
|
1949
|
+
def meshcode_tasks(status_filter: Optional[str] = None, verbose: bool = False) -> Dict[str, Any]:
|
|
1948
1950
|
"""List tasks. Filter by status to find work.
|
|
1949
1951
|
|
|
1950
1952
|
Args:
|
|
1951
1953
|
status_filter: 'open' / 'in_progress' / 'done' / etc. None = all.
|
|
1954
|
+
verbose: When False (default), descriptions are truncated to 200 chars
|
|
1955
|
+
and null/empty fields are dropped to save tokens. Pass True for
|
|
1956
|
+
the full payload.
|
|
1952
1957
|
|
|
1953
1958
|
Returns: {"ok": true, "tasks": [...]}
|
|
1954
1959
|
"""
|
|
1955
1960
|
api_key = _get_api_key()
|
|
1956
1961
|
include_done = status_filter == "done"
|
|
1957
|
-
|
|
1962
|
+
result = be.task_list(api_key, _PROJECT_ID, AGENT_NAME, status_filter=status_filter, include_done=include_done)
|
|
1963
|
+
if verbose or not isinstance(result, dict) or not result.get("ok"):
|
|
1964
|
+
return result
|
|
1965
|
+
compact: List[Dict[str, Any]] = []
|
|
1966
|
+
for t in result.get("tasks", []):
|
|
1967
|
+
desc = t.get("description") or ""
|
|
1968
|
+
row: Dict[str, Any] = {
|
|
1969
|
+
"id": t.get("id"),
|
|
1970
|
+
"title": t.get("title"),
|
|
1971
|
+
"status": t.get("status"),
|
|
1972
|
+
"priority": t.get("priority"),
|
|
1973
|
+
"assignee": t.get("assignee"),
|
|
1974
|
+
}
|
|
1975
|
+
if t.get("claimed_by"):
|
|
1976
|
+
row["claimed_by"] = t["claimed_by"]
|
|
1977
|
+
if t.get("parent_task_id"):
|
|
1978
|
+
row["parent_task_id"] = t["parent_task_id"]
|
|
1979
|
+
if desc:
|
|
1980
|
+
if len(desc) > 200:
|
|
1981
|
+
row["description"] = desc[:200]
|
|
1982
|
+
row["_description_truncated"] = True
|
|
1983
|
+
else:
|
|
1984
|
+
row["description"] = desc
|
|
1985
|
+
compact.append(row)
|
|
1986
|
+
return {"ok": True, "tasks": compact}
|
|
1958
1987
|
|
|
1959
1988
|
|
|
1960
1989
|
@mcp.tool()
|
|
@@ -1967,9 +1996,32 @@ def meshcode_task_claim(task_id: str) -> Dict[str, Any]:
|
|
|
1967
1996
|
|
|
1968
1997
|
@mcp.tool()
|
|
1969
1998
|
@with_working_status
|
|
1970
|
-
def meshcode_task_complete(task_id: str, summary: str = "") -> Dict[str, Any]:
|
|
1971
|
-
"""Complete a claimed task with summary. Auto-remembers the task summary.
|
|
1999
|
+
def meshcode_task_complete(task_id: str, summary: str = "", force: bool = False) -> Dict[str, Any]:
|
|
2000
|
+
"""Complete a claimed task with summary. Auto-remembers the task summary.
|
|
2001
|
+
|
|
2002
|
+
Refuses if the task has open subtasks, unless force=True is passed with a
|
|
2003
|
+
reason in `summary`. This prevents closing a parent while lanes are still
|
|
2004
|
+
in flight.
|
|
2005
|
+
"""
|
|
1972
2006
|
api_key = _get_api_key()
|
|
2007
|
+
if not force:
|
|
2008
|
+
try:
|
|
2009
|
+
listing = be.task_list(api_key, _PROJECT_ID, AGENT_NAME, status_filter=None, include_done=False)
|
|
2010
|
+
if isinstance(listing, dict) and listing.get("ok"):
|
|
2011
|
+
open_subs = [
|
|
2012
|
+
{"id": t["id"][:8], "title": t["title"][:80], "status": t["status"]}
|
|
2013
|
+
for t in listing.get("tasks", [])
|
|
2014
|
+
if t.get("parent_task_id") == task_id
|
|
2015
|
+
and t.get("status") in ("open", "in_progress", "in_review")
|
|
2016
|
+
]
|
|
2017
|
+
if open_subs:
|
|
2018
|
+
return {
|
|
2019
|
+
"refused": True,
|
|
2020
|
+
"reason": f"Cannot complete — {len(open_subs)} open subtasks. Finish them or pass force=True with a reason in summary.",
|
|
2021
|
+
"open_subtasks": open_subs,
|
|
2022
|
+
}
|
|
2023
|
+
except Exception:
|
|
2024
|
+
pass # Best-effort check; don't block on listing failure.
|
|
1973
2025
|
result = be.task_complete(api_key, _PROJECT_ID, task_id, AGENT_NAME, summary=summary)
|
|
1974
2026
|
# Auto-remember task completion for future context
|
|
1975
2027
|
if isinstance(result, dict) and result.get("ok") and summary:
|
|
@@ -2020,6 +2072,62 @@ def meshcode_task_reject(task_id: str, feedback: str = "") -> Dict[str, Any]:
|
|
|
2020
2072
|
})
|
|
2021
2073
|
|
|
2022
2074
|
|
|
2075
|
+
@mcp.tool()
|
|
2076
|
+
@with_working_status
|
|
2077
|
+
def meshcode_task_search(title_contains: Optional[str] = None,
|
|
2078
|
+
status: Optional[str] = None,
|
|
2079
|
+
assignee: Optional[str] = None,
|
|
2080
|
+
limit: int = 20) -> Dict[str, Any]:
|
|
2081
|
+
"""Search tasks by title/status/assignee. Use before task_create to dedupe."""
|
|
2082
|
+
return be.sb_rpc("mc_search_tasks", {
|
|
2083
|
+
"p_api_key": _get_api_key(),
|
|
2084
|
+
"p_project_id": _PROJECT_ID,
|
|
2085
|
+
"p_caller_agent": AGENT_NAME,
|
|
2086
|
+
"p_title_contains": title_contains,
|
|
2087
|
+
"p_status": status,
|
|
2088
|
+
"p_assignee": assignee,
|
|
2089
|
+
"p_limit": limit,
|
|
2090
|
+
})
|
|
2091
|
+
|
|
2092
|
+
|
|
2093
|
+
@mcp.tool()
|
|
2094
|
+
@with_working_status
|
|
2095
|
+
def meshcode_agent_list() -> Dict[str, Any]:
|
|
2096
|
+
"""Roster of agents in this meshwork with status + last_heartbeat."""
|
|
2097
|
+
return be.sb_rpc("mc_list_agents", {
|
|
2098
|
+
"p_api_key": _get_api_key(),
|
|
2099
|
+
"p_project_id": _PROJECT_ID,
|
|
2100
|
+
})
|
|
2101
|
+
|
|
2102
|
+
|
|
2103
|
+
@mcp.tool()
|
|
2104
|
+
@with_working_status
|
|
2105
|
+
def meshcode_task_cancel(task_id: str, reason: str = "") -> Dict[str, Any]:
|
|
2106
|
+
"""Cancel a task. Creator or commander only. Works on open/in_progress/in_review."""
|
|
2107
|
+
api_key = _get_api_key()
|
|
2108
|
+
return be.sb_rpc("mc_task_cancel", {
|
|
2109
|
+
"p_api_key": api_key,
|
|
2110
|
+
"p_project_id": _PROJECT_ID,
|
|
2111
|
+
"p_task_id": task_id,
|
|
2112
|
+
"p_cancelling_agent": AGENT_NAME,
|
|
2113
|
+
"p_reason": reason,
|
|
2114
|
+
})
|
|
2115
|
+
|
|
2116
|
+
|
|
2117
|
+
@mcp.tool()
|
|
2118
|
+
@with_working_status
|
|
2119
|
+
def meshcode_task_reassign(task_id: str, new_assignee: str) -> Dict[str, Any]:
|
|
2120
|
+
"""Reassign an unclaimed open task to a different agent. Creator or commander only."""
|
|
2121
|
+
api_key = _get_api_key()
|
|
2122
|
+
return be.sb_rpc("mc_task_reassign", {
|
|
2123
|
+
"p_api_key": api_key,
|
|
2124
|
+
"p_project_id": _PROJECT_ID,
|
|
2125
|
+
"p_task_id": task_id,
|
|
2126
|
+
"p_reassigning_agent": AGENT_NAME,
|
|
2127
|
+
"p_new_assignee": new_assignee,
|
|
2128
|
+
})
|
|
2129
|
+
|
|
2130
|
+
|
|
2023
2131
|
# ----------------- PROACTIVE HEALTH SCAN -----------------
|
|
2024
2132
|
|
|
2025
2133
|
@mcp.tool()
|
|
@@ -2149,6 +2257,47 @@ def meshcode_links() -> Dict[str, Any]:
|
|
|
2149
2257
|
})
|
|
2150
2258
|
|
|
2151
2259
|
|
|
2260
|
+
@mcp.tool()
|
|
2261
|
+
@with_working_status
|
|
2262
|
+
def meshcode_link_invite(source_project: str, note: str = "") -> Dict[str, Any]:
|
|
2263
|
+
"""Generate a one-time invite token for another meshwork to link in.
|
|
2264
|
+
|
|
2265
|
+
Returns {token, expires_at}. Share the token out-of-band. The recipient
|
|
2266
|
+
calls meshcode_link_redeem(token, their_meshwork) to auto-link
|
|
2267
|
+
(no separate accept step).
|
|
2268
|
+
"""
|
|
2269
|
+
return be.sb_rpc("mc_create_link_invite", {
|
|
2270
|
+
"p_source_project": source_project,
|
|
2271
|
+
"p_note": note,
|
|
2272
|
+
})
|
|
2273
|
+
|
|
2274
|
+
|
|
2275
|
+
@mcp.tool()
|
|
2276
|
+
@with_working_status
|
|
2277
|
+
def meshcode_link_redeem(token: str, target_meshwork: str) -> Dict[str, Any]:
|
|
2278
|
+
"""Redeem an invite token — creates an ACTIVE mesh link in one step."""
|
|
2279
|
+
return be.sb_rpc("mc_redeem_link_invite", {
|
|
2280
|
+
"p_token": token,
|
|
2281
|
+
"p_target_project": target_meshwork,
|
|
2282
|
+
})
|
|
2283
|
+
|
|
2284
|
+
|
|
2285
|
+
@mcp.tool()
|
|
2286
|
+
@with_working_status
|
|
2287
|
+
def meshcode_link_invites(source_project: Optional[str] = None) -> Dict[str, Any]:
|
|
2288
|
+
"""List link invites this user has created (active/redeemed/expired/revoked)."""
|
|
2289
|
+
return be.sb_rpc("mc_list_my_link_invites", {
|
|
2290
|
+
"p_source_project": source_project,
|
|
2291
|
+
})
|
|
2292
|
+
|
|
2293
|
+
|
|
2294
|
+
@mcp.tool()
|
|
2295
|
+
@with_working_status
|
|
2296
|
+
def meshcode_link_invite_revoke(token: str) -> Dict[str, Any]:
|
|
2297
|
+
"""Revoke an outstanding (unredeemed) invite token."""
|
|
2298
|
+
return be.sb_rpc("mc_revoke_link_invite", {"p_token": token})
|
|
2299
|
+
|
|
2300
|
+
|
|
2152
2301
|
@mcp.tool()
|
|
2153
2302
|
@with_working_status
|
|
2154
2303
|
def meshcode_expand_link(link_id: str, agents: str) -> Dict[str, Any]:
|
|
@@ -2647,14 +2796,7 @@ def _auto_update() -> None:
|
|
|
2647
2796
|
|
|
2648
2797
|
|
|
2649
2798
|
def run_server():
|
|
2650
|
-
"""Start the MCP server on stdio (default for Claude Code).
|
|
2651
|
-
|
|
2652
|
-
IMPORTANT: Do NOT wrap mcp.run() with try/except, signal handlers, or
|
|
2653
|
-
atexit hooks. FastMCP/anyio manages its own event loop lifecycle and
|
|
2654
|
-
signal handling. Any interference (custom SIGINT handler, atexit network
|
|
2655
|
-
calls, catching KeyboardInterrupt) corrupts the event loop and causes
|
|
2656
|
-
the MCP server to crash when Claude Code cancels a tool call (ESC).
|
|
2657
|
-
"""
|
|
2799
|
+
"""Start the MCP server on stdio (default for Claude Code)."""
|
|
2658
2800
|
_auto_update()
|
|
2659
2801
|
print(
|
|
2660
2802
|
f"[meshcode-mcp] Starting server for {AGENT_NAME}@{PROJECT_NAME}",
|
|
@@ -2664,4 +2806,25 @@ def run_server():
|
|
|
2664
2806
|
# sys.stdout was redirected to stderr at module load to prevent
|
|
2665
2807
|
# accidental stdout writes from corrupting the MCP protocol.
|
|
2666
2808
|
sys.stdout = _REAL_STDOUT
|
|
2809
|
+
|
|
2810
|
+
# Claude Code cancels tool calls on ESC via TWO parallel channels:
|
|
2811
|
+
# (1) JSON-RPC `notifications/cancelled` over stdin (the correct path)
|
|
2812
|
+
# (2) SIGINT to the stdio subprocess (a destructive side-channel)
|
|
2813
|
+
# anyio's asyncio backend installs its own SIGINT handler inside
|
|
2814
|
+
# Runner.run() only if the current handler is `default_int_handler`
|
|
2815
|
+
# (see anyio/_backends/_asyncio.py ~L197-210). That handler cancels the
|
|
2816
|
+
# *main task* — which for a stdio server IS the whole server run —
|
|
2817
|
+
# tearing the event loop down and killing the subprocess. Setting
|
|
2818
|
+
# SIG_IGN before mcp.run() trips anyio's guard, so it leaves SIGINT
|
|
2819
|
+
# alone; the kernel drops the signal; only the notifications/cancelled
|
|
2820
|
+
# path remains, which cancels just the in-flight tool call as intended.
|
|
2821
|
+
# SIGTERM is deliberately untouched so Claude Code can still force-shut
|
|
2822
|
+
# the server on session end. stdin EOF remains the normal exit path.
|
|
2823
|
+
import signal
|
|
2824
|
+
try:
|
|
2825
|
+
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
2826
|
+
except (ValueError, OSError):
|
|
2827
|
+
# Non-main thread or platform that can't install handlers — harmless.
|
|
2828
|
+
pass
|
|
2829
|
+
|
|
2667
2830
|
mcp.run()
|
|
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
|