alpiecode 10.7.1__tar.gz → 10.7.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.
- {alpiecode-10.7.1 → alpiecode-10.7.2}/PKG-INFO +1 -1
- {alpiecode-10.7.1 → alpiecode-10.7.2}/pyproject.toml +1 -1
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/alpiecode.egg-info/PKG-INFO +1 -1
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/__init__.py +1 -1
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/backends/local_backend.py +4 -4
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/cli.py +3 -2
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/context.py +2 -2
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/discovery.py +23 -3
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/orchestrator.py +16 -24
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_non_thinking_and_local_stream.py +95 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/README.md +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/setup.cfg +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/alpiecode/__init__.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/alpiecode.egg-info/SOURCES.txt +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/alpiecode.egg-info/dependency_links.txt +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/alpiecode.egg-info/entry_points.txt +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/alpiecode.egg-info/requires.txt +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/alpiecode.egg-info/top_level.txt +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/agent.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/assessment.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/backends/__init__.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/backends/base.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/backends/openai_backend.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/cache.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/client.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/compaction.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/config.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/doctor.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/dream_rsi.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/executor.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/extension/alpiecode.vsix +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/git_ops.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/github.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/guardian.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/guardrails.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/ipython_ext.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/local_model.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/media.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/memory.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/metrics.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/paths.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/progress.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/prompt.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/rephraser.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/server.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/session.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/system1.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/tools.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/updater.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/verifier.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/src/codeagent/vscode_installer.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_adaptive_resilience.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_cli_ui.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_context_and_trajectory.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_dream_rsi.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_local_model_download.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_task_assessment.py +0 -0
- {alpiecode-10.7.1 → alpiecode-10.7.2}/test/test_verifier.py +0 -0
|
@@ -17,7 +17,7 @@ Supports:
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from typing import Optional, Any, Dict
|
|
19
19
|
|
|
20
|
-
__version__ = "10.7.
|
|
20
|
+
__version__ = "10.7.2"
|
|
21
21
|
|
|
22
22
|
def run(task: str, workdir: str = ".", reasoning_level: str = "thinking", **kwargs):
|
|
23
23
|
"""Run an autonomous coding task programmatically."""
|
|
@@ -439,7 +439,7 @@ class LocalBackend:
|
|
|
439
439
|
"max_tokens": max_tokens,
|
|
440
440
|
"stream": False,
|
|
441
441
|
}
|
|
442
|
-
if tools:
|
|
442
|
+
if tools and getattr(self._cfg, "enable_native_tools", False):
|
|
443
443
|
payload["tools"] = tools
|
|
444
444
|
payload["tool_choice"] = "auto"
|
|
445
445
|
client = httpx.Client(http2=False, timeout=120.0)
|
|
@@ -496,7 +496,7 @@ class LocalBackend:
|
|
|
496
496
|
"max_tokens": max_tokens or 2048,
|
|
497
497
|
"stream": True,
|
|
498
498
|
}
|
|
499
|
-
if tools:
|
|
499
|
+
if tools and getattr(self._cfg, "enable_native_tools", False):
|
|
500
500
|
payload["tools"] = tools
|
|
501
501
|
payload["tool_choice"] = "auto"
|
|
502
502
|
client = httpx.Client(http2=False, timeout=120.0)
|
|
@@ -874,7 +874,7 @@ class iOSBackend(BasePlatformBackend):
|
|
|
874
874
|
"max_tokens": max_tokens,
|
|
875
875
|
"stream": False,
|
|
876
876
|
}
|
|
877
|
-
if tools:
|
|
877
|
+
if tools and getattr(self._cfg, "enable_native_tools", False):
|
|
878
878
|
payload["tools"] = tools
|
|
879
879
|
payload["tool_choice"] = "auto"
|
|
880
880
|
resp = httpx.post(f"{bridge_url}/v1/chat/completions", json=payload, timeout=300.0)
|
|
@@ -953,7 +953,7 @@ class iOSBackend(BasePlatformBackend):
|
|
|
953
953
|
"max_tokens": max_tokens or 2048,
|
|
954
954
|
"stream": True,
|
|
955
955
|
}
|
|
956
|
-
if tools:
|
|
956
|
+
if tools and getattr(self._cfg, "enable_native_tools", False):
|
|
957
957
|
payload["tools"] = tools
|
|
958
958
|
payload["tool_choice"] = "auto"
|
|
959
959
|
client = httpx.Client(timeout=httpx.Timeout(300.0, connect=10.0, read=300.0, write=30.0))
|
|
@@ -263,9 +263,10 @@ def main():
|
|
|
263
263
|
|
|
264
264
|
if getattr(args, "offline", False):
|
|
265
265
|
cfg.base_url = "offline"
|
|
266
|
-
# 8192 default fits 4.4GB model + KV cache 100% in 6GB VRAM (4.75GB / 6GB) with zero host-paging
|
|
267
266
|
import os
|
|
268
|
-
|
|
267
|
+
from .paths import is_android
|
|
268
|
+
default_ctx = 2048 if is_android() else 8192
|
|
269
|
+
cfg.n_ctx = int(os.environ.get("ALPIECODE_CTX_SIZE", default_ctx))
|
|
269
270
|
os.environ["ALPIECODE_BASE_URL"] = "offline"
|
|
270
271
|
|
|
271
272
|
if getattr(args, "ctx_size", None):
|
|
@@ -379,8 +379,8 @@ class ContextManager:
|
|
|
379
379
|
context_blocks.extend(recent_messages)
|
|
380
380
|
|
|
381
381
|
# ── Budget Verification ──
|
|
382
|
-
reserved_headroom = 2048 if effective_limit <= 8192 else 4096
|
|
383
|
-
prompt_budget = max(
|
|
382
|
+
reserved_headroom = 512 if effective_limit <= 2048 else (2048 if effective_limit <= 8192 else 4096)
|
|
383
|
+
prompt_budget = max(512, effective_limit - reserved_headroom)
|
|
384
384
|
|
|
385
385
|
if estimate_tokens(context_blocks) > prompt_budget:
|
|
386
386
|
context_blocks = compact_messages(context_blocks, keep_recent=4 if effective_limit <= 8192 else 8)
|
|
@@ -490,6 +490,15 @@ COMPLEXITY_CONFIG = {
|
|
|
490
490
|
|
|
491
491
|
# -- Pre-Read Context Injection ---------------------------------------------
|
|
492
492
|
|
|
493
|
+
def _is_home_or_root(path: Path) -> bool:
|
|
494
|
+
"""Check if path is the user home directory or system root."""
|
|
495
|
+
try:
|
|
496
|
+
resolved = path.resolve()
|
|
497
|
+
return resolved in (Path.home().resolve(), Path("/").resolve(), Path("C:\\").resolve())
|
|
498
|
+
except Exception:
|
|
499
|
+
return False
|
|
500
|
+
|
|
501
|
+
|
|
493
502
|
def gather_relevant_context(
|
|
494
503
|
task: str,
|
|
495
504
|
workdir: Path,
|
|
@@ -512,8 +521,12 @@ def gather_relevant_context(
|
|
|
512
521
|
|
|
513
522
|
task_lower = task.lower().strip()
|
|
514
523
|
|
|
515
|
-
# Skip pre-reading repo files for standalone algorithms or scripts (e.g. palindrome, calculator)
|
|
516
|
-
standalone_kws = [
|
|
524
|
+
# Skip pre-reading repo files for standalone algorithms or scripts (e.g. palindrome, calculator, primes)
|
|
525
|
+
standalone_kws = [
|
|
526
|
+
"palindrome", "fibonacci", "quicksort", "bubblesort", "factorial",
|
|
527
|
+
"hello world", "calculator", "reverse string", "reverse_string",
|
|
528
|
+
"prime", "primes", "prime number", "prime numbers",
|
|
529
|
+
]
|
|
517
530
|
if any(kw in task_lower for kw in standalone_kws):
|
|
518
531
|
return None
|
|
519
532
|
sections: List[str] = []
|
|
@@ -577,7 +590,9 @@ def gather_relevant_context(
|
|
|
577
590
|
task_lower = task.lower()
|
|
578
591
|
try:
|
|
579
592
|
all_files = []
|
|
580
|
-
|
|
593
|
+
is_broad = _is_home_or_root(workdir)
|
|
594
|
+
file_iter = workdir.glob("*") if is_broad else workdir.rglob("*")
|
|
595
|
+
for p in file_iter:
|
|
581
596
|
if p.is_file() and not any(
|
|
582
597
|
skip in str(p) for skip in [
|
|
583
598
|
".git/", "__pycache__", "node_modules", ".venv",
|
|
@@ -585,6 +600,8 @@ def gather_relevant_context(
|
|
|
585
600
|
]
|
|
586
601
|
):
|
|
587
602
|
all_files.append(str(p.relative_to(workdir)))
|
|
603
|
+
if len(all_files) >= 500:
|
|
604
|
+
break
|
|
588
605
|
# Match filenames or stems mentioned in the task
|
|
589
606
|
for rel in all_files:
|
|
590
607
|
fname = Path(rel).stem.lower()
|
|
@@ -609,6 +626,9 @@ def build_symbol_index(workdir: Path, max_files: int = 40) -> Dict[str, List[str
|
|
|
609
626
|
|
|
610
627
|
Extracts classes, methods, and functions across Python files.
|
|
611
628
|
"""
|
|
629
|
+
if _is_home_or_root(workdir):
|
|
630
|
+
return {}
|
|
631
|
+
|
|
612
632
|
symbols: Dict[str, List[str]] = {}
|
|
613
633
|
count = 0
|
|
614
634
|
import ast
|
|
@@ -453,39 +453,31 @@ class AgentOrchestrator:
|
|
|
453
453
|
yield AgentEvent("turn_start", {"turn": turn, "thinking": turn_enable_thinking})
|
|
454
454
|
|
|
455
455
|
# In offline mode, guide the model with current workspace progress
|
|
456
|
-
if is_offline and
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
rel = ep.relative_to(session.workdir).as_posix()
|
|
463
|
-
existing_files.add(rel)
|
|
464
|
-
except Exception:
|
|
465
|
-
pass
|
|
466
|
-
if existing_files:
|
|
467
|
-
file_list = ", ".join(sorted(list(existing_files)))
|
|
468
|
-
state_hint = f"[Workspace State: Files created so far: {file_list}. Do NOT re-create these files. Proceed with remaining files or tests.]"
|
|
469
|
-
last_msgs = session.context.messages
|
|
470
|
-
if last_msgs and not any(state_hint in str(m.get("content", "")) for m in last_msgs[-2:]):
|
|
471
|
-
session.context.add_user_message(state_hint)
|
|
456
|
+
if is_offline and session_touched_files:
|
|
457
|
+
file_list = ", ".join(sorted(list(session_touched_files)))
|
|
458
|
+
state_hint = f"[Workspace State: Files created so far: {file_list}. Do NOT re-create these files. Proceed with remaining files or tests.]"
|
|
459
|
+
last_msgs = session.context.messages
|
|
460
|
+
if last_msgs and not any(state_hint in str(m.get("content", "")) for m in last_msgs[-2:]):
|
|
461
|
+
session.context.add_user_message(state_hint)
|
|
472
462
|
|
|
473
463
|
try:
|
|
474
464
|
if is_offline:
|
|
475
465
|
# In offline mode, dynamically allocate output tokens based on context headroom
|
|
476
|
-
n_ctx = getattr(cfg, "n_ctx", 8192)
|
|
477
|
-
tools_overhead = 800 if active_tools else 0
|
|
466
|
+
n_ctx = getattr(cfg, "n_ctx", 2048 if getattr(session.workdir, "_is_mobile", False) else 8192)
|
|
478
467
|
try:
|
|
479
468
|
used_tokens = session.context.estimate_tokens()
|
|
480
469
|
except Exception:
|
|
481
|
-
used_tokens =
|
|
470
|
+
used_tokens = 600
|
|
482
471
|
|
|
483
|
-
#
|
|
484
|
-
if n_ctx
|
|
485
|
-
|
|
472
|
+
# Scale headroom threshold with context window (e.g. 512 for 2048 mobile ctx, 1500 for 8192 desktop ctx)
|
|
473
|
+
tight_headroom_threshold = 512 if n_ctx <= 2048 else 1500
|
|
474
|
+
if n_ctx - used_tokens < tight_headroom_threshold and hasattr(session.context, "compact_for_headroom"):
|
|
475
|
+
target_hr = 512 if n_ctx <= 2048 else 2048
|
|
476
|
+
used_tokens = session.context.compact_for_headroom(target_headroom=target_hr, n_ctx=n_ctx, tools_overhead=0)
|
|
486
477
|
|
|
487
|
-
available_headroom = max(
|
|
488
|
-
|
|
478
|
+
available_headroom = max(256, n_ctx - used_tokens - 32)
|
|
479
|
+
token_ceiling = 1024 if n_ctx <= 2048 else 4096
|
|
480
|
+
max_tokens = min(token_ceiling, available_headroom)
|
|
489
481
|
elif turn_enable_thinking:
|
|
490
482
|
max_tokens = max(effective_max_tokens, 16384)
|
|
491
483
|
else:
|
|
@@ -159,3 +159,98 @@ def test_android_backend_skips_mmproj_for_code_tasks(tmp_path):
|
|
|
159
159
|
assert "-c" in args
|
|
160
160
|
assert "2048" in args
|
|
161
161
|
|
|
162
|
+
|
|
163
|
+
def test_offline_orchestrator_turn1_no_workspace_file_explosion(tmp_path):
|
|
164
|
+
"""Verify that offline orchestrator on Turn 1 does not inject thousands of workspace files."""
|
|
165
|
+
from codeagent.orchestrator import AgentOrchestrator
|
|
166
|
+
from codeagent.session import SessionManager
|
|
167
|
+
from codeagent.backends.base import ChatResponse
|
|
168
|
+
|
|
169
|
+
# Create dummy files in workspace
|
|
170
|
+
for i in range(50):
|
|
171
|
+
(tmp_path / f"file_{i}.txt").write_text("hello")
|
|
172
|
+
|
|
173
|
+
cfg = Config(base_url="offline", n_ctx=2048)
|
|
174
|
+
mock_backend = MagicMock()
|
|
175
|
+
mock_backend.name = "MockOffline"
|
|
176
|
+
mock_backend.is_available = True
|
|
177
|
+
mock_backend.is_offline = True
|
|
178
|
+
mock_backend.context_window = 2048
|
|
179
|
+
|
|
180
|
+
captured_messages = []
|
|
181
|
+
def mock_chat_stream(messages, **kwargs):
|
|
182
|
+
captured_messages.append(list(messages))
|
|
183
|
+
yield ("token", {"delta": "DONE: completed"})
|
|
184
|
+
yield ("done", ChatResponse(content="DONE: completed"))
|
|
185
|
+
|
|
186
|
+
mock_backend.chat_completion_stream = mock_chat_stream
|
|
187
|
+
|
|
188
|
+
orchestrator = AgentOrchestrator(mock_backend)
|
|
189
|
+
session_mgr = SessionManager()
|
|
190
|
+
session = session_mgr.create_session(tmp_path, max_tokens=2048)
|
|
191
|
+
|
|
192
|
+
events = list(orchestrator.run_task(
|
|
193
|
+
session=session,
|
|
194
|
+
task="create a python script that calculates prime numbers",
|
|
195
|
+
cfg=cfg,
|
|
196
|
+
))
|
|
197
|
+
|
|
198
|
+
# Verify that captured messages did NOT inject workspace file list
|
|
199
|
+
assert len(captured_messages) > 0
|
|
200
|
+
first_turn_msgs = captured_messages[0]
|
|
201
|
+
for msg in first_turn_msgs:
|
|
202
|
+
content_str = str(msg.get("content", ""))
|
|
203
|
+
assert "file_49.txt" not in content_str
|
|
204
|
+
assert "Workspace State: Files created so far" not in content_str
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def test_local_backend_bridge_omits_tools_payload():
|
|
208
|
+
"""Verify that LocalBackend bridge requests do not include tools payload by default."""
|
|
209
|
+
from codeagent.backends.local_backend import LocalBackend
|
|
210
|
+
cfg = Config(base_url="offline")
|
|
211
|
+
backend = LocalBackend(cfg)
|
|
212
|
+
|
|
213
|
+
with patch("httpx.Client") as mock_client_cls:
|
|
214
|
+
mock_client = MagicMock()
|
|
215
|
+
mock_resp = MagicMock()
|
|
216
|
+
mock_resp.status_code = 200
|
|
217
|
+
mock_resp.text = '{"choices":[{"message":{"content":"hello"}}]}'
|
|
218
|
+
mock_resp.iter_lines.return_value = ['data: {"choices":[{"delta":{"content":"hi"}}]}', 'data: [DONE]']
|
|
219
|
+
mock_client.build_request.return_value = MagicMock()
|
|
220
|
+
mock_client.send.return_value = mock_resp
|
|
221
|
+
mock_client.post.return_value = mock_resp
|
|
222
|
+
mock_client_cls.return_value = mock_client
|
|
223
|
+
|
|
224
|
+
with patch.object(backend, "_get_bridge_url", return_value="http://127.0.0.1:8080"):
|
|
225
|
+
# Stream call
|
|
226
|
+
list(backend._bridge_chat_completion_stream(
|
|
227
|
+
messages=[{"role": "user", "content": "hi"}],
|
|
228
|
+
tools=[{"type": "function", "function": {"name": "test"}}],
|
|
229
|
+
))
|
|
230
|
+
_, kwargs = mock_client.build_request.call_args
|
|
231
|
+
assert "tools" not in kwargs["json"]
|
|
232
|
+
|
|
233
|
+
# Non-stream call
|
|
234
|
+
backend._bridge_chat_completion(
|
|
235
|
+
messages=[{"role": "user", "content": "hi"}],
|
|
236
|
+
tools=[{"type": "function", "function": {"name": "test"}}],
|
|
237
|
+
)
|
|
238
|
+
_, kwargs = mock_client.post.call_args
|
|
239
|
+
assert "tools" not in kwargs["json"]
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def test_discovery_guard_against_home_dir():
|
|
243
|
+
"""Verify that discovery functions safely handle home directory."""
|
|
244
|
+
from pathlib import Path
|
|
245
|
+
from codeagent.discovery import _is_home_or_root, build_symbol_index, gather_relevant_context, TaskContext
|
|
246
|
+
assert _is_home_or_root(Path.home()) is True
|
|
247
|
+
|
|
248
|
+
# build_symbol_index should return empty dict without scanning
|
|
249
|
+
assert build_symbol_index(Path.home()) == {}
|
|
250
|
+
|
|
251
|
+
# gather_relevant_context should return None for prime task
|
|
252
|
+
ctx = TaskContext(project_type="python", file_count=100)
|
|
253
|
+
res = gather_relevant_context("create a python script that calculates prime numbers", Path.home(), ctx)
|
|
254
|
+
assert res is None
|
|
255
|
+
|
|
256
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|