comodor 0.2.2__tar.gz → 0.2.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.
- {comodor-0.2.2 → comodor-0.2.3}/PKG-INFO +1 -1
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/_version.py +2 -2
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/uninstall.py +80 -18
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_uninstall.py +39 -1
- {comodor-0.2.2 → comodor-0.2.3}/.gitignore +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/LICENSE +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/README.md +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/pyproject.toml +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/__main__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/agent/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/agent/context.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/agent/loop.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/agent/prompts.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/agent/tokens.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/catalogue.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/cli.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/config.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/doctor.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/events.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/bm25.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/hotindex.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/memory.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/progress.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/reflect.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/rules.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/signals.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/store.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/learning/writer.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/mcp/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/mcp/catalogue.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/mcp/commands.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/mcp/manager.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/mcp/protocol.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/net/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/net/http.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/net/sse.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/paths.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/providers/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/providers/anthropic.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/providers/base.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/providers/fake.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/providers/gateway.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/providers/openai_compat.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/providers/registry.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/safety/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/safety/checkpoints.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/safety/permissions.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/safety/redact.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/session/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/session/search.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/session/store.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/setup.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/skills/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/skills/examples.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/skills/loader.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/skills/propose.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/skills/registry.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/base.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/fs.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/history.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/mcp.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/registry.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/search.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/shell.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/skills.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/todo.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/tools/web.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/app.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/chooser.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/console.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/input/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/input/keys.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/input/reader.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/layout.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/markdown.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/screen.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/theme.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/__init__.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/buttons.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/chat.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/history.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/overlay.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/panel.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/progress.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/prompt.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/statusbar.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/src/comodor/ui/widgets/toast.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/conftest.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/support/fake_mcp_server.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_agent_loop.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_app.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_chooser.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_doctor.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_history.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_input.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_layout.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_learning.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_markdown.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_mcp.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_performance.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_progress.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_propose.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_providers.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_reflex.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_run_loop.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_setup.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_skills.py +0 -0
- {comodor-0.2.2 → comodor-0.2.3}/tests/test_tools.py +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
21
|
+
__version__ = version = '0.2.3'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 3)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -439,7 +439,7 @@ def survey(config: Config | None = None, cwd: Path | None = None) -> Survey:
|
|
|
439
439
|
detail=install.detail,
|
|
440
440
|
path=install.root,
|
|
441
441
|
size=directory_size(install.root) if install.root else 0,
|
|
442
|
-
remove=lambda tool=tool: _run_uninstaller(tool),
|
|
442
|
+
remove=lambda tool=tool, root=install.root: _run_uninstaller(tool, root),
|
|
443
443
|
deferred=sys.platform == "win32",
|
|
444
444
|
))
|
|
445
445
|
elif install.method == "venv" and install.owned:
|
|
@@ -490,9 +490,17 @@ def survey(config: Config | None = None, cwd: Path | None = None) -> Survey:
|
|
|
490
490
|
|
|
491
491
|
others = _other_launchers(BIN_DIR)
|
|
492
492
|
if others:
|
|
493
|
+
# Named, not counted. "2 other programs live there" leaves the reader
|
|
494
|
+
# with a decision they have no information for; `uv, uvx` tells them
|
|
495
|
+
# whether the line is worth keeping, and those two in particular were
|
|
496
|
+
# very likely fetched by this installer in the first place.
|
|
497
|
+
listed = ", ".join(others[:4])
|
|
498
|
+
if len(others) > 4:
|
|
499
|
+
listed += f" and {len(others) - 4} more"
|
|
493
500
|
found.notes.append(
|
|
494
|
-
f"{BIN_DIR} stays on your PATH
|
|
495
|
-
f"{
|
|
501
|
+
f"{BIN_DIR} stays on your PATH, and so does the line that put it "
|
|
502
|
+
f"there: {listed} still live in it. Remove the line by hand if "
|
|
503
|
+
f"none of those matter to you.")
|
|
496
504
|
else:
|
|
497
505
|
for profile, _ in profile_edits(BIN_DIR):
|
|
498
506
|
found.add(Item(
|
|
@@ -525,30 +533,84 @@ def _within(path: Path, root: Path) -> bool:
|
|
|
525
533
|
return False
|
|
526
534
|
|
|
527
535
|
|
|
528
|
-
def _other_launchers(directory: Path) ->
|
|
529
|
-
"""
|
|
536
|
+
def _other_launchers(directory: Path) -> list[str]:
|
|
537
|
+
"""What else lives in the launcher directory, by name."""
|
|
530
538
|
if not directory.is_dir():
|
|
531
|
-
return
|
|
539
|
+
return []
|
|
532
540
|
ours = {"comodor", "comodor.exe", "comodor.cmd", "comodor-script.py"}
|
|
533
541
|
try:
|
|
534
|
-
return
|
|
542
|
+
return sorted(entry.name for entry in directory.iterdir()
|
|
543
|
+
if entry.name not in ours)
|
|
535
544
|
except OSError:
|
|
536
|
-
return
|
|
537
|
-
|
|
545
|
+
return []
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
#: Where a tool manager lives when it is not on PATH. The same list the
|
|
549
|
+
#: installer searches, and for the same reason: `curl | sh` runs without the
|
|
550
|
+
#: user's profile, so `uv` gets bootstrapped into ~/.local/bin and nothing in
|
|
551
|
+
#: that session ever puts it on PATH.
|
|
552
|
+
TOOL_DIRS = (
|
|
553
|
+
Path.home() / ".local" / "bin",
|
|
554
|
+
Path.home() / ".cargo" / "bin",
|
|
555
|
+
Path.home() / "bin",
|
|
556
|
+
Path("/opt/homebrew/bin"),
|
|
557
|
+
Path("/usr/local/bin"),
|
|
558
|
+
Path("/home/linuxbrew/.linuxbrew/bin"),
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def find_tool(name: str) -> str | None:
|
|
563
|
+
"""`name` on PATH, or in the places an installer would have put it."""
|
|
564
|
+
found = shutil.which(name)
|
|
565
|
+
if found:
|
|
566
|
+
return found
|
|
567
|
+
suffixes = (".exe", ".cmd", "") if sys.platform == "win32" else ("",)
|
|
568
|
+
for directory in TOOL_DIRS:
|
|
569
|
+
for suffix in suffixes:
|
|
570
|
+
candidate = directory / f"{name}{suffix}"
|
|
571
|
+
if candidate.is_file():
|
|
572
|
+
return str(candidate)
|
|
573
|
+
return None
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def _run_uninstaller(tool: str, root: Path | None = None) -> str:
|
|
577
|
+
"""Hand the package back to whatever installed it.
|
|
578
|
+
|
|
579
|
+
And if that is not possible, take it off anyway.
|
|
580
|
+
|
|
581
|
+
uv and pipx keep a record of the tools they manage, so asking them is the
|
|
582
|
+
tidy way: it removes the environment *and* the entry. But the installer
|
|
583
|
+
fetches `uv` into `~/.local/bin` when the machine has none, and a shell
|
|
584
|
+
that ran `curl | sh` never read a profile, so `uv` is frequently installed
|
|
585
|
+
and simultaneously not on PATH — which is how a real uninstall reported
|
|
586
|
+
"No such file or directory: 'uv'" and left seventy megabytes behind.
|
|
587
|
+
|
|
588
|
+
So the tool is looked for where an installer would have put it, and if it
|
|
589
|
+
genuinely is not there the environment is deleted directly. That leaves uv
|
|
590
|
+
with an entry for something that is gone, which is worth saying out loud —
|
|
591
|
+
and is a great deal better than leaving the thing itself.
|
|
592
|
+
"""
|
|
593
|
+
if tool == "pip":
|
|
594
|
+
command = [sys.executable, "-m", "pip", "uninstall", "-y", "comodor"]
|
|
595
|
+
else:
|
|
596
|
+
executable = find_tool(tool)
|
|
597
|
+
if executable is None:
|
|
598
|
+
if root is None:
|
|
599
|
+
raise RuntimeError(f"{tool} is not installed any more")
|
|
600
|
+
_rmtree(root)
|
|
601
|
+
return f"{root} (removed directly: {tool} is not on this machine)"
|
|
602
|
+
command = ([executable, "tool", "uninstall", "comodor"] if tool == "uv"
|
|
603
|
+
else [executable, "uninstall", "comodor"])
|
|
538
604
|
|
|
539
|
-
def _run_uninstaller(tool: str) -> str:
|
|
540
|
-
"""Hand the package back to whatever installed it."""
|
|
541
|
-
commands = {
|
|
542
|
-
"uv": ["uv", "tool", "uninstall", "comodor"],
|
|
543
|
-
"pipx": ["pipx", "uninstall", "comodor"],
|
|
544
|
-
"pip": [sys.executable, "-m", "pip", "uninstall", "-y", "comodor"],
|
|
545
|
-
}
|
|
546
|
-
command = commands[tool]
|
|
547
605
|
result = subprocess.run(command, capture_output=True, text=True, timeout=180)
|
|
548
606
|
if result.returncode != 0:
|
|
607
|
+
if root is not None and root.exists():
|
|
608
|
+
_rmtree(root)
|
|
609
|
+
reason = (result.stderr or result.stdout).strip().splitlines()
|
|
610
|
+
return f"{root} (removed directly: {reason[-1][:80] if reason else tool})"
|
|
549
611
|
raise RuntimeError((result.stderr or result.stdout).strip()[:200]
|
|
550
612
|
or f"{tool} exited {result.returncode}")
|
|
551
|
-
return " ".join(command[
|
|
613
|
+
return " ".join(command[1:])
|
|
552
614
|
|
|
553
615
|
|
|
554
616
|
# --------------------------------------------------------------------------- #
|
|
@@ -22,6 +22,7 @@ Comodor and then checks it starts failed with "command not found".
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
24
|
import json
|
|
25
|
+
import os
|
|
25
26
|
from pathlib import Path
|
|
26
27
|
|
|
27
28
|
import pytest
|
|
@@ -211,7 +212,8 @@ def test_a_shared_bin_directory_keeps_its_place_on_path(tmp_path, monkeypatch):
|
|
|
211
212
|
found = survey(config)
|
|
212
213
|
|
|
213
214
|
assert not [item for item in found.items if item.kind == "path"]
|
|
214
|
-
|
|
215
|
+
# Named, so the reader can judge whether the line is worth keeping.
|
|
216
|
+
assert any("ruff" in note for note in found.notes)
|
|
215
217
|
|
|
216
218
|
|
|
217
219
|
def test_a_directory_that_was_only_ours_gives_the_path_line_back(tmp_path,
|
|
@@ -305,6 +307,42 @@ def test_the_command_itself_goes_too(tmp_path, monkeypatch):
|
|
|
305
307
|
assert not launcher.exists()
|
|
306
308
|
|
|
307
309
|
|
|
310
|
+
def test_a_tool_manager_off_the_path_is_still_found(tmp_path, monkeypatch):
|
|
311
|
+
"""`curl | sh` bootstraps uv into ~/.local/bin and never reads a profile.
|
|
312
|
+
|
|
313
|
+
So the shell that installed Comodor frequently has uv installed and not on
|
|
314
|
+
PATH at the same time, and `shutil.which` says it is not there at all.
|
|
315
|
+
"""
|
|
316
|
+
from comodor.uninstall import find_tool
|
|
317
|
+
|
|
318
|
+
tool = Path.home() / ".local" / "bin" / ("uv.exe" if os.name == "nt" else "uv")
|
|
319
|
+
tool.write_text("#!/bin/sh", encoding="utf-8")
|
|
320
|
+
monkeypatch.setattr("comodor.uninstall.TOOL_DIRS", (tool.parent,))
|
|
321
|
+
monkeypatch.setattr("shutil.which", lambda name: None)
|
|
322
|
+
|
|
323
|
+
assert find_tool("uv") == str(tool)
|
|
324
|
+
assert find_tool("pipx") is None
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def test_a_missing_tool_manager_does_not_leave_the_environment_behind(tmp_path,
|
|
328
|
+
monkeypatch):
|
|
329
|
+
"""Reported honestly and left on disk is still left on disk.
|
|
330
|
+
|
|
331
|
+
Deleting it directly leaves uv with an entry for something that is gone.
|
|
332
|
+
Seventy megabytes of environment is the worse of the two.
|
|
333
|
+
"""
|
|
334
|
+
from comodor.uninstall import _run_uninstaller
|
|
335
|
+
|
|
336
|
+
environment = tmp_path / "uv" / "tools" / "comodor"
|
|
337
|
+
(environment / "bin").mkdir(parents=True)
|
|
338
|
+
monkeypatch.setattr("comodor.uninstall.find_tool", lambda name: None)
|
|
339
|
+
|
|
340
|
+
outcome = _run_uninstaller("uv", environment)
|
|
341
|
+
|
|
342
|
+
assert not environment.exists()
|
|
343
|
+
assert "removed directly" in outcome
|
|
344
|
+
|
|
345
|
+
|
|
308
346
|
def test_a_removal_that_fails_is_reported_rather_than_raised(tmp_path):
|
|
309
347
|
"""One thing that will not go must not stop the rest from going."""
|
|
310
348
|
def explode() -> str:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|