drydock-cli 3.0.104__tar.gz → 3.0.105__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.
- {drydock_cli-3.0.104/drydock_cli.egg-info → drydock_cli-3.0.105}/PKG-INFO +1 -1
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tools/__init__.py +38 -5
- {drydock_cli-3.0.104 → drydock_cli-3.0.105/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock_cli.egg-info/SOURCES.txt +1 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/pyproject.toml +1 -1
- drydock_cli-3.0.105/tests/test_bash_crossplatform.py +49 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/LICENSE +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/NOTICE +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/README.md +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/__init__.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/__main__.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/advisor.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/agent.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/cci.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/cli.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/compaction.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/config.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/detect.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/extract.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/gittools.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/graphrag.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/guards.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/mcp.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/poam.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/providers.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/rmf.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/skills.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/stig.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tui/app.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/tuning.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock/web.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/setup.cfg +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_advisor.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_approval.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_back_command.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_stop_partial.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_cci.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_compaction.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_config.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_detect.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_edit_replace_all.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_extract.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_gittools.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_glob_edit_edges.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_mcp.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_poam.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_read_index.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_rmf.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_skills.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_stig.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_stop.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_subagent.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_todo.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_tool_arg_coercion.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_tool_arg_coercion_more.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_tui.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_tuning.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.0.104 → drydock_cli-3.0.105}/tests/test_xccdf.py +0 -0
|
@@ -82,14 +82,20 @@ def _detect_bash() -> str | None:
|
|
|
82
82
|
found = shutil.which("bash")
|
|
83
83
|
if found:
|
|
84
84
|
return found
|
|
85
|
-
|
|
85
|
+
# Common absolute locations, incl. Git-for-Windows and WSL bash on Windows.
|
|
86
|
+
for p in ("/bin/bash", "/usr/bin/bash", "/usr/local/bin/bash",
|
|
87
|
+
r"C:\Program Files\Git\bin\bash.exe",
|
|
88
|
+
r"C:\Program Files (x86)\Git\bin\bash.exe",
|
|
89
|
+
r"C:\Windows\System32\bash.exe"):
|
|
86
90
|
if os.path.exists(p):
|
|
87
91
|
return p
|
|
88
92
|
return None
|
|
89
93
|
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
#
|
|
95
|
+
_IS_WINDOWS = os.name == "nt"
|
|
96
|
+
# Resolved once at import (in whatever environment drydock runs — host, the task
|
|
97
|
+
# container, Linux, or Windows). None → bash unavailable, fall back to the
|
|
98
|
+
# platform's default shell (cmd.exe on Windows, /bin/sh on POSIX).
|
|
93
99
|
_BASH_SHELL = _detect_bash()
|
|
94
100
|
|
|
95
101
|
|
|
@@ -928,6 +934,18 @@ def kill_process_group(proc) -> None:
|
|
|
928
934
|
if the group can't be resolved (e.g. process already gone)."""
|
|
929
935
|
if proc is None:
|
|
930
936
|
return
|
|
937
|
+
if _IS_WINDOWS:
|
|
938
|
+
# No process groups / SIGKILL on Windows — taskkill /T kills the whole
|
|
939
|
+
# child tree (the shell + everything it spawned).
|
|
940
|
+
try:
|
|
941
|
+
subprocess.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)],
|
|
942
|
+
capture_output=True, timeout=10)
|
|
943
|
+
except Exception: # noqa: BLE001
|
|
944
|
+
try:
|
|
945
|
+
proc.kill()
|
|
946
|
+
except Exception: # noqa: BLE001
|
|
947
|
+
pass
|
|
948
|
+
return
|
|
931
949
|
try:
|
|
932
950
|
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
|
|
933
951
|
except (ProcessLookupError, PermissionError, OSError):
|
|
@@ -1016,9 +1034,19 @@ def tool_bash(params: dict, config: dict) -> str:
|
|
|
1016
1034
|
# overall timeout between slices.
|
|
1017
1035
|
cancel = config.get("_cancel")
|
|
1018
1036
|
proc = None
|
|
1037
|
+
# Invoke bash explicitly as [bash, "-c", cmd] rather than shell=True +
|
|
1038
|
+
# executable — cross-platform correctness: on Windows shell=True builds
|
|
1039
|
+
# `{executable} /c {cmd}` (cmd.exe syntax), so a real bash.exe (Git Bash/WSL)
|
|
1040
|
+
# would be called as `bash /c ...` and fail. `[bash, "-c", cmd]` runs the same
|
|
1041
|
+
# on Linux and Windows. Without bash, fall back to the platform default shell
|
|
1042
|
+
# (cmd.exe on Windows, /bin/sh on POSIX) via shell=True.
|
|
1043
|
+
if _BASH_SHELL:
|
|
1044
|
+
popen_cmd, use_shell = [_BASH_SHELL, "-c", cmd], False
|
|
1045
|
+
else:
|
|
1046
|
+
popen_cmd, use_shell = cmd, True
|
|
1019
1047
|
try:
|
|
1020
1048
|
proc = subprocess.Popen(
|
|
1021
|
-
|
|
1049
|
+
popen_cmd, shell=use_shell,
|
|
1022
1050
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
|
1023
1051
|
# stdin=DEVNULL so a command that reads stdin gets immediate EOF
|
|
1024
1052
|
# (correct for a non-interactive tool) instead of inheriting the
|
|
@@ -1033,7 +1061,12 @@ def tool_bash(params: dict, config: dict) -> str:
|
|
|
1033
1061
|
# which killed the thread and handed the agent "(no output)", losing
|
|
1034
1062
|
# even the text parts of mixed output.
|
|
1035
1063
|
text=True, encoding="utf-8", errors="replace",
|
|
1036
|
-
cwd=config.get("cwd"),
|
|
1064
|
+
cwd=config.get("cwd"),
|
|
1065
|
+
# Own process group / job so kill_process_group takes down the whole
|
|
1066
|
+
# tree: setsid on POSIX; a new process group on Windows (getattr keeps
|
|
1067
|
+
# the Windows-only flag out of the POSIX code path — it resolves to 0).
|
|
1068
|
+
start_new_session=not _IS_WINDOWS,
|
|
1069
|
+
creationflags=getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0),
|
|
1037
1070
|
)
|
|
1038
1071
|
config.setdefault("_abort", {})["proc"] = proc
|
|
1039
1072
|
# Read output in a daemon thread with a HARD byte cap, so memory can't
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
# PyPI distribution name is drydock-cli (the established install name, continued
|
|
8
8
|
# from the retired v2 fork); the import package + CLI command stay `drydock`.
|
|
9
9
|
name = "drydock-cli"
|
|
10
|
-
version = "3.0.
|
|
10
|
+
version = "3.0.105"
|
|
11
11
|
description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.11"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""tool_bash must run on Linux AND Windows. The Windows blocker was shell=True +
|
|
2
|
+
executable=bash → Popen builds `bash /c cmd` (cmd.exe syntax) which a real
|
|
3
|
+
bash.exe rejects. Fix: invoke `[bash, "-c", cmd]` explicitly; use taskkill on
|
|
4
|
+
Windows for the process-tree kill; setsid only on POSIX."""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import subprocess
|
|
9
|
+
|
|
10
|
+
from drydock import tools
|
|
11
|
+
from drydock.tools import _detect_bash, _IS_WINDOWS, kill_process_group, tool_bash
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_platform_flag_matches_os():
|
|
15
|
+
assert _IS_WINDOWS == (os.name == "nt")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_detect_bash_returns_path_or_none():
|
|
19
|
+
r = _detect_bash()
|
|
20
|
+
assert r is None or (isinstance(r, str) and "bash" in r.lower())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_bash_invoked_as_argv_not_shell_c(monkeypatch):
|
|
24
|
+
"""When bash is available, Popen is called with [bash, '-c', cmd] and
|
|
25
|
+
shell=False — never shell=True+executable (which breaks on Windows)."""
|
|
26
|
+
if not tools._BASH_SHELL:
|
|
27
|
+
return
|
|
28
|
+
seen = {}
|
|
29
|
+
real = subprocess.Popen
|
|
30
|
+
|
|
31
|
+
def spy(popen_cmd, *a, **kw):
|
|
32
|
+
seen["cmd"] = popen_cmd
|
|
33
|
+
seen["shell"] = kw.get("shell")
|
|
34
|
+
return real(popen_cmd, *a, **kw)
|
|
35
|
+
|
|
36
|
+
monkeypatch.setattr(subprocess, "Popen", spy)
|
|
37
|
+
tool_bash({"command": "echo hi", "timeout": 5}, {"cwd": "/tmp"})
|
|
38
|
+
assert seen["shell"] is False
|
|
39
|
+
assert isinstance(seen["cmd"], list) and seen["cmd"][1] == "-c"
|
|
40
|
+
assert seen["cmd"][0].lower().endswith(("bash", "bash.exe"))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_kill_process_group_none_is_safe():
|
|
44
|
+
kill_process_group(None) # must not raise
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_command_still_runs_here():
|
|
48
|
+
out = tool_bash({"command": "echo cross_platform_ok", "timeout": 5}, {"cwd": "/tmp"})
|
|
49
|
+
assert "cross_platform_ok" in out
|
|
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
|
|
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
|