drydock-cli 3.0.98__tar.gz → 3.0.99__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.98/drydock_cli.egg-info → drydock_cli-3.0.99}/PKG-INFO +1 -1
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tools/__init__.py +42 -14
- {drydock_cli-3.0.98 → drydock_cli-3.0.99/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock_cli.egg-info/SOURCES.txt +1 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/pyproject.toml +1 -1
- drydock_cli-3.0.99/tests/test_tool_arg_coercion.py +49 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/LICENSE +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/NOTICE +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/README.md +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/__init__.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/__main__.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/advisor.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/agent.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/cci.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/cli.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/compaction.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/config.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/detect.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/extract.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/gittools.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/graphrag.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/guards.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/mcp.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/poam.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/providers.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/rmf.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/skills.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/stig.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tui/app.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/tuning.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock/web.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/setup.cfg +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_advisor.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_approval.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_back_command.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_cci.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_compaction.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_config.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_detect.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_extract.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_gittools.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_mcp.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_poam.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_read_index.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_rmf.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_skills.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_stig.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_stop.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_subagent.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_todo.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_tui.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_tuning.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.0.98 → drydock_cli-3.0.99}/tests/test_xccdf.py +0 -0
|
@@ -26,6 +26,36 @@ _DEFAULT_TIMEOUT = 120
|
|
|
26
26
|
_MAX_TIMEOUT = 1800 # 30 min hard ceiling — a single command shouldn't hang longer
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def _as_text(v, default: str = "") -> str:
|
|
30
|
+
"""Coerce a text-body arg (file content, replacement text) to a string. Local
|
|
31
|
+
models sometimes send it as a JSON array of lines → newline-join; None →
|
|
32
|
+
default; other scalars → str()."""
|
|
33
|
+
if isinstance(v, (list, tuple)):
|
|
34
|
+
return "\n".join(str(x) for x in v)
|
|
35
|
+
if v is None:
|
|
36
|
+
return default
|
|
37
|
+
return v if isinstance(v, str) else str(v)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _as_str_arg(v, default: str = "") -> str:
|
|
41
|
+
"""Coerce a scalar string arg (a path, a pattern) to a string. A single-value
|
|
42
|
+
list is unwrapped (models sometimes wrap a lone path/pattern in an array)."""
|
|
43
|
+
if isinstance(v, (list, tuple)):
|
|
44
|
+
return str(v[0]) if v else default
|
|
45
|
+
if v is None:
|
|
46
|
+
return default
|
|
47
|
+
return v if isinstance(v, str) else str(v)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _coerce_int(value, default: int):
|
|
51
|
+
"""Coerce a model-supplied int arg (offset/limit) that may arrive as a string
|
|
52
|
+
("5") or junk. Falls back to default on anything non-numeric."""
|
|
53
|
+
try:
|
|
54
|
+
return int(float(value))
|
|
55
|
+
except (TypeError, ValueError):
|
|
56
|
+
return default
|
|
57
|
+
|
|
58
|
+
|
|
29
59
|
def _coerce_timeout(value) -> int:
|
|
30
60
|
"""Make the model-supplied timeout robust: local models often send it as a
|
|
31
61
|
string ("10"), and a 0/negative/absurd value would make EVERY command time
|
|
@@ -585,13 +615,13 @@ def tool_viewimage(params: dict, config: dict) -> str:
|
|
|
585
615
|
|
|
586
616
|
|
|
587
617
|
def tool_read(params: dict, config: dict) -> str:
|
|
588
|
-
fp = _resolve_path(params
|
|
618
|
+
fp = _resolve_path(_as_str_arg(params.get("file_path")), config)
|
|
589
619
|
# Reading an image as text yields binary garbage — point at the vision tool.
|
|
590
620
|
if os.path.splitext(fp)[1].lower() in _IMAGE_EXTS and os.path.isfile(fp):
|
|
591
621
|
return (f"{params['file_path']} is an image — Read would return binary "
|
|
592
622
|
"garbage. Use the ViewImage tool to actually SEE it.")
|
|
593
|
-
limit = params.get("limit")
|
|
594
|
-
offset = params.get("offset", 0)
|
|
623
|
+
limit = None if params.get("limit") is None else _coerce_int(params.get("limit"), 2000)
|
|
624
|
+
offset = _coerce_int(params.get("offset", 0), 0)
|
|
595
625
|
try:
|
|
596
626
|
with open(fp, "r", encoding="utf-8", errors="replace") as f:
|
|
597
627
|
lines = f.readlines()
|
|
@@ -670,14 +700,10 @@ def tool_write(params: dict, config: dict) -> str:
|
|
|
670
700
|
fp = _resolve_path(str(fp).strip(), config)
|
|
671
701
|
if Path(fp).is_dir():
|
|
672
702
|
return f"Error: {fp} is a directory, not a file. Pass a file path."
|
|
673
|
-
content = params.get("content", "")
|
|
674
703
|
# Local models sometimes send content as a JSON array of lines (or a number),
|
|
675
|
-
# which f.write() can't take — coerce instead of crashing
|
|
676
|
-
#
|
|
677
|
-
|
|
678
|
-
content = "\n".join(str(x) for x in content)
|
|
679
|
-
elif not isinstance(content, str):
|
|
680
|
-
content = "" if content is None else str(content)
|
|
704
|
+
# which f.write() can't take — coerce instead of crashing (tools must return
|
|
705
|
+
# errors, never raise). A list → newline-joined lines.
|
|
706
|
+
content = _as_text(params.get("content", ""))
|
|
681
707
|
if has_conflict_markers(content):
|
|
682
708
|
return conflict_marker_refusal(fp)
|
|
683
709
|
prev = _snapshot(fp)
|
|
@@ -800,8 +826,10 @@ def tool_edit(params: dict, config: dict) -> str:
|
|
|
800
826
|
if not fp or not str(fp).strip():
|
|
801
827
|
return "Error: Edit needs a real file_path (the path was empty or blank)."
|
|
802
828
|
fp = _resolve_path(str(fp).strip(), config)
|
|
803
|
-
old
|
|
804
|
-
|
|
829
|
+
# Coerce non-string old/new (a JSON array of lines, a number) instead of
|
|
830
|
+
# crashing with a TypeError in the substring search / replace.
|
|
831
|
+
old = _as_text(params.get("old_string", ""))
|
|
832
|
+
new = _as_text(params.get("new_string", ""))
|
|
805
833
|
if has_conflict_markers(new):
|
|
806
834
|
return conflict_marker_refusal(fp)
|
|
807
835
|
# If a directory was passed, try to infer the intended file (avoids a
|
|
@@ -1105,8 +1133,8 @@ def tool_glob(params: dict, config: dict) -> str:
|
|
|
1105
1133
|
|
|
1106
1134
|
|
|
1107
1135
|
def tool_grep(params: dict, config: dict) -> str:
|
|
1108
|
-
pattern = params
|
|
1109
|
-
path = params.get("path") or config.get("cwd") or "."
|
|
1136
|
+
pattern = _as_str_arg(params.get("pattern"))
|
|
1137
|
+
path = _as_str_arg(params.get("path")) or config.get("cwd") or "."
|
|
1110
1138
|
include = params.get("include", "")
|
|
1111
1139
|
try:
|
|
1112
1140
|
cmd = ["grep", "-rn", "--color=never"]
|
|
@@ -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.99"
|
|
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
|
+
"""Model-supplied tool args that arrive as the wrong type (a JSON array of lines,
|
|
2
|
+
a number, a stringified int, a single-element-list-wrapped path) must be coerced,
|
|
3
|
+
never crash — tools return results, never raise. Systematic across the file tools."""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from drydock.tools import (
|
|
7
|
+
_as_text, _as_str_arg, _coerce_int,
|
|
8
|
+
tool_edit, tool_read, tool_grep, tool_write,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_helpers():
|
|
13
|
+
assert _as_text(["a", "b"]) == "a\nb"
|
|
14
|
+
assert _as_text(None) == "" and _as_text(42) == "42" and _as_text("x") == "x"
|
|
15
|
+
assert _as_str_arg(["/p"]) == "/p" and _as_str_arg(None) == "" and _as_str_arg(5) == "5"
|
|
16
|
+
assert _coerce_int("5", 0) == 5 and _coerce_int("junk", 7) == 7 and _coerce_int(None, 3) == 3
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _cfg(tmp): return {"cwd": str(tmp)}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_edit_non_string_new(tmp_path):
|
|
23
|
+
f = tmp_path / "e.txt"; f.write_text("alpha beta\n")
|
|
24
|
+
out = tool_edit({"file_path": str(f), "old_string": "alpha", "new_string": ["x", "y"]}, _cfg(tmp_path))
|
|
25
|
+
assert "Error" not in out and f.read_text().startswith("x\ny")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_edit_int_new(tmp_path):
|
|
29
|
+
f = tmp_path / "e.txt"; f.write_text("beta\n")
|
|
30
|
+
out = tool_edit({"file_path": str(f), "old_string": "beta", "new_string": 99}, _cfg(tmp_path))
|
|
31
|
+
assert "99" in f.read_text() and "Error" not in out
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_read_list_path_and_str_offsets(tmp_path):
|
|
35
|
+
f = tmp_path / "r.txt"; f.write_text("line1\nline2\n")
|
|
36
|
+
out = tool_read({"file_path": [str(f)], "offset": "0", "limit": "5"}, _cfg(tmp_path))
|
|
37
|
+
assert "line1" in out
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_grep_list_pattern(tmp_path):
|
|
41
|
+
f = tmp_path / "g.txt"; f.write_text("needle here\n")
|
|
42
|
+
out = tool_grep({"pattern": ["needle"], "path": str(f)}, _cfg(tmp_path))
|
|
43
|
+
assert "needle" in out
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_write_list_content(tmp_path):
|
|
47
|
+
f = tmp_path / "w.txt"
|
|
48
|
+
tool_write({"file_path": str(f), "content": ["a", "b"]}, _cfg(tmp_path))
|
|
49
|
+
assert f.read_text() == "a\nb"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|