vramd 0.2.0__tar.gz → 0.2.2__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.
- {vramd-0.2.0/src/vramd.egg-info → vramd-0.2.2}/PKG-INFO +1 -1
- {vramd-0.2.0 → vramd-0.2.2}/pyproject.toml +1 -1
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/__init__.py +1 -1
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/cli.py +11 -5
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/registry.py +13 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/toolchain.py +19 -1
- {vramd-0.2.0 → vramd-0.2.2/src/vramd.egg-info}/PKG-INFO +1 -1
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd.egg-info/SOURCES.txt +1 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_calibrate_cli.py +64 -0
- vramd-0.2.2/tests/test_toolchain.py +61 -0
- {vramd-0.2.0 → vramd-0.2.2}/LICENSE +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/README.md +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/setup.cfg +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/__main__.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/adapter.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/backend_manager.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/__init__.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/analysis.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/compare.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/emit.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/hw_auto.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/runner.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/sampler.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/calibrate/serde.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/client.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/data/backends.yaml +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/dispatcher.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/errors.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/footprints.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/gpu.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/idle_evictor.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/job_queue.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/logging.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/process_guard.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/protocol.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/py.typed +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/scheduler.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/server.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/stats.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/subprocess_pool.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/vram_planner.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/worker/__init__.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/worker/adapter.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/worker/protocol.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd/worker/serve.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd.egg-info/dependency_links.txt +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd.egg-info/entry_points.txt +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd.egg-info/requires.txt +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/src/vramd.egg-info/top_level.txt +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_abort_progress.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_backend_manager.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_backend_manager_hybrid.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_calibrate_analysis.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_calibrate_emit_compare.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_calibrate_hw_auto.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_calibrate_runner.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_calibrate_sampler.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_calibrate_serde.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_cli_debug_stats_bench.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_gpu_ids_load.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_idle_evictor.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_job_queue.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_job_wal.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_peak_profile.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_phase_progress.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_process_guard.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_protocol_env.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_queue_metrics_eta.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_registry.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_registry_layers.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_respawn.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_runtime_spawn.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_scheduler.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_server.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_stats.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_subprocess_integration.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_subprocess_per_backend_e2e.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_subprocess_pool.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_unload_frees_vram.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_vram_admit.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_vram_planner.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_vramd_coverage_100.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_worker.py +0 -0
- {vramd-0.2.0 → vramd-0.2.2}/tests/test_zero_vram.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vramd"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Controlo de admissão de VRAM para inferência generativa em GPUs de consumo"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Maikeu Locatelli" }]
|
|
@@ -1534,7 +1534,9 @@ def calibrate_cmd(
|
|
|
1534
1534
|
elif auto_kwargs:
|
|
1535
1535
|
console.print(f"[dim]hw-auto ({desc.tool}): {auto_kwargs}[/dim]")
|
|
1536
1536
|
load_kwargs.update(auto_kwargs)
|
|
1537
|
-
#
|
|
1537
|
+
# ``calibrate_load_kwargs`` do descriptor (config real de produção do
|
|
1538
|
+
# backend) ganha ao hw-auto; o explícito do CLI ganha a ambos.
|
|
1539
|
+
load_kwargs.update(desc.calibrate_load_kwargs)
|
|
1538
1540
|
load_kwargs.update(explicit_kwargs)
|
|
1539
1541
|
if quant:
|
|
1540
1542
|
load_kwargs.setdefault("sdnq_preset", quant)
|
|
@@ -1543,10 +1545,14 @@ def calibrate_cmd(
|
|
|
1543
1545
|
if request_json:
|
|
1544
1546
|
request = json.loads(Path(request_json).read_text(encoding="utf-8"))
|
|
1545
1547
|
else:
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1548
|
+
# Default do descriptor (prompt/output com a extensão certa por
|
|
1549
|
+
# backend) — sem isto ``calibrate <backend>`` falha em backends que
|
|
1550
|
+
# exigem inputs (mesh_path/output) ou formatos específicos.
|
|
1551
|
+
request = dict(desc.calibrate_request)
|
|
1552
|
+
request.setdefault("prompt", prompt or "calibration job")
|
|
1553
|
+
if output_path:
|
|
1554
|
+
request["output"] = output_path
|
|
1555
|
+
request.setdefault("output", f"/tmp/vramd-calibrate-{backend}.bin")
|
|
1550
1556
|
|
|
1551
1557
|
pool = SubprocessWorkerPool()
|
|
1552
1558
|
runner = CalibrationRunner(pool)
|
|
@@ -201,6 +201,15 @@ class BackendDescriptor:
|
|
|
201
201
|
shape_keys: Subconjunto que força reload quando muda. ``None`` = global.
|
|
202
202
|
vram: Bloco ``vram:`` medido (`vramd calibrate`), quando existe.
|
|
203
203
|
peak_profile: Bloco ``peak_profile:`` (quant, staged, unload_frees_vram…).
|
|
204
|
+
calibrate_request: Request de geração default para ``vramd calibrate``
|
|
205
|
+
(ex.: prompt + output com a extensão certa). Sem isto, o calibrador
|
|
206
|
+
usa ``{}`` e backends que exigem inputs (mesh_path/output) falham
|
|
207
|
+
com mensagens pouco acionáveis — o default vive no descriptor para
|
|
208
|
+
que ``vramd calibrate <backend>`` funcione sempre.
|
|
209
|
+
calibrate_load_kwargs: Kwargs de load default para ``vramd calibrate``
|
|
210
|
+
(ex.: ``sdnq_preset`` quando o perfil da tool não o resolve).
|
|
211
|
+
Fundidos com o hw-auto (este ganha) e com os explícitos do CLI
|
|
212
|
+
(``--load-kwargs``/``--quant`` ganham a este).
|
|
204
213
|
"""
|
|
205
214
|
|
|
206
215
|
name: str
|
|
@@ -214,6 +223,8 @@ class BackendDescriptor:
|
|
|
214
223
|
shape_keys: frozenset[str] | None = None
|
|
215
224
|
vram: Mapping[str, Any] = field(default_factory=dict)
|
|
216
225
|
peak_profile: Mapping[str, Any] = field(default_factory=dict)
|
|
226
|
+
calibrate_request: Mapping[str, Any] = field(default_factory=dict)
|
|
227
|
+
calibrate_load_kwargs: Mapping[str, Any] = field(default_factory=dict)
|
|
217
228
|
|
|
218
229
|
@property
|
|
219
230
|
def unload_frees_vram(self) -> bool:
|
|
@@ -316,6 +327,8 @@ def _to_descriptor(entry: Mapping[str, Any], *, source: str) -> BackendDescripto
|
|
|
316
327
|
shape_keys=frozenset(str(k) for k in shape_keys) if shape_keys else None,
|
|
317
328
|
vram=dict(entry.get("vram") or {}),
|
|
318
329
|
peak_profile=dict(entry.get("peak_profile") or {}),
|
|
330
|
+
calibrate_request=dict(entry.get("calibrate_request") or {}),
|
|
331
|
+
calibrate_load_kwargs=dict(entry.get("calibrate_load_kwargs") or {}),
|
|
319
332
|
)
|
|
320
333
|
|
|
321
334
|
|
|
@@ -25,10 +25,28 @@ ENV_TOOLS_ROOT = "VRAMD_TOOLS_ROOT"
|
|
|
25
25
|
|
|
26
26
|
# Nomes de pasta tentados para cada ``tool`` (o mesmo nome, e a forma
|
|
27
27
|
# capitalizada que muitos projetos usam para a pasta do componente).
|
|
28
|
+
def _camel_title(tool: str) -> str:
|
|
29
|
+
"""``text2icon`` → ``Text2Icon``; ``skymap2d`` → ``Skymap2D``.
|
|
30
|
+
|
|
31
|
+
O ``str.capitalize()`` só capitaliza a primeira letra — pastas com
|
|
32
|
+
camelCase após um dígito (Text2Icon, Paint3D, Skymap2D…) não eram
|
|
33
|
+
encontradas. Capitaliza o início de cada segmento alfanumérico.
|
|
34
|
+
"""
|
|
35
|
+
import re
|
|
36
|
+
|
|
37
|
+
return "".join(part.capitalize() if not part.isdigit() else part for part in re.split(r"(\d+)", tool))
|
|
38
|
+
|
|
39
|
+
|
|
28
40
|
def _candidate_dirs(tool: str) -> list[str]:
|
|
29
41
|
"""Variações de nome de pasta a tentar para ``tool``."""
|
|
30
42
|
seen: list[str] = []
|
|
31
|
-
for name in (
|
|
43
|
+
for name in (
|
|
44
|
+
tool,
|
|
45
|
+
tool.capitalize(),
|
|
46
|
+
_camel_title(tool),
|
|
47
|
+
tool.upper(),
|
|
48
|
+
tool.replace("_", "-"),
|
|
49
|
+
):
|
|
32
50
|
if name and name not in seen:
|
|
33
51
|
seen.append(name)
|
|
34
52
|
return seen
|
|
@@ -115,6 +115,70 @@ class TestCalibrateCommand:
|
|
|
115
115
|
assert result.exit_code == 0
|
|
116
116
|
assert patched["spec"].request["prompt"] == "uma pedra"
|
|
117
117
|
|
|
118
|
+
def test_descriptor_calibrate_defaults_are_used(self, runner, patched, tmp_path, monkeypatch):
|
|
119
|
+
"""`vramd calibrate <backend>` funciona sem flags quando o descriptor
|
|
120
|
+
declara ``calibrate_request``/``calibrate_load_kwargs`` — o utilizador
|
|
121
|
+
comum não precisa de saber que o backend exige mesh_path/output/quant."""
|
|
122
|
+
yaml_path = tmp_path / "backends.yaml"
|
|
123
|
+
yaml_path.write_text(
|
|
124
|
+
yaml.safe_dump(
|
|
125
|
+
{
|
|
126
|
+
"version": 2,
|
|
127
|
+
"backends": [
|
|
128
|
+
{
|
|
129
|
+
"name": "text3d",
|
|
130
|
+
"adapter": "x",
|
|
131
|
+
"vram_mib": 4000,
|
|
132
|
+
"tool": "text3d",
|
|
133
|
+
"calibrate_request": {"mesh_path": "/tmp/m.glb", "output": "/tmp/out.glb"},
|
|
134
|
+
"calibrate_load_kwargs": {"sdnq_preset": "sdnq-int4"},
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
encoding="utf-8",
|
|
140
|
+
)
|
|
141
|
+
monkeypatch.setenv("VRAMD_BACKENDS_FILE", str(yaml_path))
|
|
142
|
+
result = runner.invoke(cli_mod.cli, ["calibrate", "text3d", "--no-compare"])
|
|
143
|
+
assert result.exit_code == 0
|
|
144
|
+
spec = patched["spec"]
|
|
145
|
+
assert spec.request["mesh_path"] == "/tmp/m.glb"
|
|
146
|
+
assert spec.request["output"] == "/tmp/out.glb"
|
|
147
|
+
assert spec.load_kwargs["sdnq_preset"] == "sdnq-int4"
|
|
148
|
+
|
|
149
|
+
def test_explicit_flags_override_descriptor_defaults(self, runner, patched, tmp_path, monkeypatch):
|
|
150
|
+
"""--request-json/--load-kwargs do operador ganham ao descriptor."""
|
|
151
|
+
yaml_path = tmp_path / "backends.yaml"
|
|
152
|
+
yaml_path.write_text(
|
|
153
|
+
yaml.safe_dump(
|
|
154
|
+
{
|
|
155
|
+
"version": 2,
|
|
156
|
+
"backends": [
|
|
157
|
+
{
|
|
158
|
+
"name": "text3d",
|
|
159
|
+
"adapter": "x",
|
|
160
|
+
"vram_mib": 4000,
|
|
161
|
+
"tool": "text3d",
|
|
162
|
+
"calibrate_request": {"mesh_path": "/a.glb", "output": "/a-out.glb"},
|
|
163
|
+
"calibrate_load_kwargs": {"sdnq_preset": "sdnq-int4"},
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
encoding="utf-8",
|
|
169
|
+
)
|
|
170
|
+
monkeypatch.setenv("VRAMD_BACKENDS_FILE", str(yaml_path))
|
|
171
|
+
job = tmp_path / "job.json"
|
|
172
|
+
job.write_text(json.dumps({"mesh_path": "/b.glb", "output": "/b-out.glb"}), encoding="utf-8")
|
|
173
|
+
result = runner.invoke(
|
|
174
|
+
cli_mod.cli,
|
|
175
|
+
["calibrate", "text3d", "--no-compare", "--request-json", str(job), "--load-kwarg", "sdnq_preset=none"],
|
|
176
|
+
)
|
|
177
|
+
assert result.exit_code == 0
|
|
178
|
+
spec = patched["spec"]
|
|
179
|
+
assert spec.request["mesh_path"] == "/b.glb"
|
|
180
|
+
assert spec.load_kwargs["sdnq_preset"] is None # "none" é coergido a None
|
|
181
|
+
|
|
118
182
|
def test_repeats_and_cycles_flow_through(self, runner, patched):
|
|
119
183
|
runner.invoke(cli_mod.cli, ["calibrate", "text3d", "--no-compare", "--repeats", "5", "--cycles", "2"])
|
|
120
184
|
assert patched["spec"].repeats == 5
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Testes da descoberta do interpretador das tools (``VRAMD_TOOLS_ROOT``).
|
|
2
|
+
|
|
3
|
+
Regressão: pastas com camelCase após um dígito (Text2Icon, Paint3D,
|
|
4
|
+
Skymap2D — o layout do AiGameKit) não eram encontradas porque
|
|
5
|
+
``str.capitalize()`` só capitaliza a primeira letra.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from vramd.toolchain import _camel_title, _candidate_dirs, resolve_tool_python
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestCamelTitle:
|
|
16
|
+
def test_camel_case_after_digit(self) -> None:
|
|
17
|
+
# O layout do AiGameKit: pasta capitalizada por segmento.
|
|
18
|
+
assert _camel_title("text2icon") == "Text2Icon"
|
|
19
|
+
assert _camel_title("skymap2d") == "Skymap2D"
|
|
20
|
+
assert _camel_title("paint3d") == "Paint3D"
|
|
21
|
+
assert _camel_title("text2sound") == "Text2Sound"
|
|
22
|
+
assert _camel_title("motion3d") == "Motion3D"
|
|
23
|
+
|
|
24
|
+
def test_simple_names_unchanged_in_spirit(self) -> None:
|
|
25
|
+
assert _camel_title("whisper") == "Whisper"
|
|
26
|
+
assert _camel_title("my_tool") == "My_tool"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TestCandidateDirs:
|
|
30
|
+
def test_includes_camel_title(self) -> None:
|
|
31
|
+
dirs = _candidate_dirs("text2icon")
|
|
32
|
+
assert "Text2Icon" in dirs # o que o capitalize() não dava
|
|
33
|
+
assert "Text2icon" in dirs
|
|
34
|
+
assert "text2icon" in dirs
|
|
35
|
+
|
|
36
|
+
def test_no_duplicates(self) -> None:
|
|
37
|
+
assert len(_candidate_dirs("text2icon")) == len(set(_candidate_dirs("text2icon")))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TestResolveToolPython:
|
|
41
|
+
def test_finds_camel_case_folder(self, tmp_path: Path, monkeypatch) -> None:
|
|
42
|
+
venv = tmp_path / "Text2Icon" / ".venv" / "bin"
|
|
43
|
+
venv.mkdir(parents=True)
|
|
44
|
+
python = venv / "python"
|
|
45
|
+
python.write_text("#!/bin/sh\n")
|
|
46
|
+
python.chmod(0o755)
|
|
47
|
+
monkeypatch.setenv("VRAMD_TOOLS_ROOT", str(tmp_path))
|
|
48
|
+
assert resolve_tool_python("text2icon") == str(python)
|
|
49
|
+
|
|
50
|
+
def test_plain_name_still_works(self, tmp_path: Path, monkeypatch) -> None:
|
|
51
|
+
venv = tmp_path / "whisper" / ".venv" / "bin"
|
|
52
|
+
venv.mkdir(parents=True)
|
|
53
|
+
python = venv / "python"
|
|
54
|
+
python.write_text("#!/bin/sh\n")
|
|
55
|
+
python.chmod(0o755)
|
|
56
|
+
monkeypatch.setenv("VRAMD_TOOLS_ROOT", str(tmp_path))
|
|
57
|
+
assert resolve_tool_python("whisper") == str(python)
|
|
58
|
+
|
|
59
|
+
def test_no_env_means_no_discovery(self, tmp_path: Path, monkeypatch) -> None:
|
|
60
|
+
monkeypatch.delenv("VRAMD_TOOLS_ROOT", raising=False)
|
|
61
|
+
assert resolve_tool_python("text2icon") is None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|