aes-cli 0.4.0__tar.gz → 0.4.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.
- {aes_cli-0.4.0 → aes_cli-0.4.2}/PKG-INFO +4 -1
- {aes_cli-0.4.0 → aes_cli-0.4.2}/README.md +3 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/__init__.py +1 -1
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/sync.py +21 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/i18n/_messages.py +1 -1
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/i18n/ja.py +1 -1
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/registry.py +22 -40
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/targets/claude.py +4 -2
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes_cli.egg-info/PKG-INFO +4 -1
- {aes_cli-0.4.0 → aes_cli-0.4.2}/pyproject.toml +1 -1
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_registry.py +2 -2
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/__main__.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/analyzer.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/__init__.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/init.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/inspect.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/install.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/publish.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/search.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/status.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/commands/validate.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/config.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/domains.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/frameworks.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/global_config.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/i18n/__init__.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/i18n/domains_ja.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/mcp_server.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/agent.yaml.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/agentignore.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/instructions.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/ja/instructions.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/ja/operations.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/ja/orchestrator.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/ja/setup.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/ja/skill.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/ja/workflow_command.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/local.example.yaml.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/local.yaml.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/operations.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/orchestrator.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/permissions.yaml.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/setup.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/skill.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/skill.yaml.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/workflow.yaml.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/scaffold/workflow_command.md.jinja +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/schemas/agent.schema.json +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/schemas/permissions.schema.json +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/schemas/registry.schema.json +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/schemas/skill.schema.json +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/schemas/workflow.schema.json +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/targets/__init__.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/targets/_base.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/targets/_composer.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/targets/copilot.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/targets/cursor.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/targets/windsurf.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes/validator.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes_cli.egg-info/SOURCES.txt +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes_cli.egg-info/dependency_links.txt +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes_cli.egg-info/entry_points.txt +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes_cli.egg-info/requires.txt +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/aes_cli.egg-info/top_level.txt +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/setup.cfg +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_analyzer.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_frameworks.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_init.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_inspect.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_install.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_mcp_server.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_publish.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_search.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_status.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_sync.py +0 -0
- {aes_cli-0.4.0 → aes_cli-0.4.2}/tests/test_validate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aes-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: CLI tool for the Agentic Engineering Standard
|
|
5
5
|
Author: Hiro
|
|
6
6
|
License: Apache-2.0
|
|
@@ -40,6 +40,9 @@ AES treats agent instructions, skills, permissions, and memory as **first-class
|
|
|
40
40
|
## Installation
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
+
pipx install aes-cli
|
|
44
|
+
|
|
45
|
+
# Or inside a virtual environment
|
|
43
46
|
pip install aes-cli
|
|
44
47
|
```
|
|
45
48
|
|
|
@@ -30,6 +30,19 @@ console = Console()
|
|
|
30
30
|
SYNC_MANIFEST = ".aes-sync.json"
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
def _validate_subpath(base: Path, child: Path) -> None:
|
|
34
|
+
"""Ensure *child* resolves to a location under *base*.
|
|
35
|
+
|
|
36
|
+
Raises click.ClickException on path traversal attempts.
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
child.resolve().relative_to(base.resolve())
|
|
40
|
+
except ValueError:
|
|
41
|
+
raise click.ClickException(
|
|
42
|
+
f"Path traversal blocked: {child} escapes {base}"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
33
46
|
def run_sync(
|
|
34
47
|
project_root: Path,
|
|
35
48
|
target_names: Optional[List[str]] = None,
|
|
@@ -60,6 +73,7 @@ def run_sync(
|
|
|
60
73
|
for gf in sync_plan.files:
|
|
61
74
|
if gf.action in ("create", "update"):
|
|
62
75
|
full_path = project_root / gf.relative_path
|
|
76
|
+
_validate_subpath(project_root, full_path)
|
|
63
77
|
full_path.parent.mkdir(parents=True, exist_ok=True)
|
|
64
78
|
full_path.write_text(gf.content)
|
|
65
79
|
sync_manifest["files"][gf.relative_path] = {
|
|
@@ -106,6 +120,7 @@ def _load_agent_context(project_root: Path) -> AgentContext:
|
|
|
106
120
|
instructions: Optional[str] = None
|
|
107
121
|
instructions_rel = agent_section.get("instructions", "instructions.md")
|
|
108
122
|
instructions_path = agent_dir / instructions_rel
|
|
123
|
+
_validate_subpath(agent_dir, instructions_path)
|
|
109
124
|
if instructions_path.exists():
|
|
110
125
|
instructions = instructions_path.read_text()
|
|
111
126
|
|
|
@@ -114,6 +129,7 @@ def _load_agent_context(project_root: Path) -> AgentContext:
|
|
|
114
129
|
orchestrator_rel = agent_section.get("orchestrator")
|
|
115
130
|
if orchestrator_rel:
|
|
116
131
|
orchestrator_path = agent_dir / orchestrator_rel
|
|
132
|
+
_validate_subpath(agent_dir, orchestrator_path)
|
|
117
133
|
if orchestrator_path.exists():
|
|
118
134
|
orchestrator = orchestrator_path.read_text()
|
|
119
135
|
|
|
@@ -125,12 +141,14 @@ def _load_agent_context(project_root: Path) -> AgentContext:
|
|
|
125
141
|
runbook_rel = skill_ref.get("runbook")
|
|
126
142
|
if runbook_rel:
|
|
127
143
|
runbook_path = agent_dir / runbook_rel
|
|
144
|
+
_validate_subpath(agent_dir, runbook_path)
|
|
128
145
|
if runbook_path.exists():
|
|
129
146
|
skill_runbooks[skill_id] = runbook_path.read_text()
|
|
130
147
|
# Load skill manifest for name/description/activation metadata
|
|
131
148
|
manifest_rel = skill_ref.get("manifest")
|
|
132
149
|
if manifest_rel:
|
|
133
150
|
skill_manifest_path = agent_dir / manifest_rel
|
|
151
|
+
_validate_subpath(agent_dir, skill_manifest_path)
|
|
134
152
|
if skill_manifest_path.exists():
|
|
135
153
|
with open(skill_manifest_path) as f:
|
|
136
154
|
skill_data = yaml.safe_load(f) or {}
|
|
@@ -154,6 +172,7 @@ def _load_agent_context(project_root: Path) -> AgentContext:
|
|
|
154
172
|
permissions: Optional[dict] = None
|
|
155
173
|
permissions_rel = agent_section.get("permissions", PERMISSIONS_FILE)
|
|
156
174
|
permissions_path = agent_dir / permissions_rel
|
|
175
|
+
_validate_subpath(agent_dir, permissions_path)
|
|
157
176
|
if permissions_path.exists():
|
|
158
177
|
with open(permissions_path) as f:
|
|
159
178
|
permissions = yaml.safe_load(f) or {}
|
|
@@ -163,6 +182,7 @@ def _load_agent_context(project_root: Path) -> AgentContext:
|
|
|
163
182
|
for cmd_ref in manifest.get("commands", []):
|
|
164
183
|
cmd_data = dict(cmd_ref)
|
|
165
184
|
cmd_path = agent_dir / cmd_ref["path"]
|
|
185
|
+
_validate_subpath(agent_dir, cmd_path)
|
|
166
186
|
if cmd_path.exists():
|
|
167
187
|
cmd_data["content"] = cmd_path.read_text()
|
|
168
188
|
else:
|
|
@@ -320,6 +340,7 @@ def sync_cmd(
|
|
|
320
340
|
|
|
321
341
|
if gf.action in ("create", "update") and not dry_run:
|
|
322
342
|
full_path = project_root / gf.relative_path
|
|
343
|
+
_validate_subpath(project_root, full_path)
|
|
323
344
|
full_path.parent.mkdir(parents=True, exist_ok=True)
|
|
324
345
|
full_path.write_text(gf.content)
|
|
325
346
|
sync_manifest["files"][gf.relative_path] = {
|
|
@@ -190,7 +190,7 @@ MESSAGES: dict = {
|
|
|
190
190
|
"init.specific_label": "{type}-specific",
|
|
191
191
|
"init.synced_to": "Synced to {count} tool config(s):",
|
|
192
192
|
"init.mcp_configured": "MCP: {file} configured (AES registry tools)",
|
|
193
|
-
"init.mcp_install_hint": "Install MCP server:
|
|
193
|
+
"init.mcp_install_hint": "Install MCP server: pipx install aes-cli[mcp]",
|
|
194
194
|
"init.next_steps": "Next: Start a new agent session, then type /setup to fine-tune{hint}.",
|
|
195
195
|
"init.or_begin": ", or {trigger} to begin",
|
|
196
196
|
"init.from_template": "Initialized from template:",
|
|
@@ -190,7 +190,7 @@ MESSAGES: dict = {
|
|
|
190
190
|
"init.specific_label": "{type}向け",
|
|
191
191
|
"init.synced_to": "{count} 件のツール設定に同期しました:",
|
|
192
192
|
"init.mcp_configured": "MCP: {file} を設定しました(AESレジストリツール)",
|
|
193
|
-
"init.mcp_install_hint": "MCPサーバーのインストール:
|
|
193
|
+
"init.mcp_install_hint": "MCPサーバーのインストール: pipx install aes-cli[mcp]",
|
|
194
194
|
"init.next_steps": "次のステップ: 新しいエージェントセッションを開始し、/setup で調整{hint}。",
|
|
195
195
|
"init.or_begin": "、または {trigger} で開始",
|
|
196
196
|
"init.from_template": "テンプレートから初期化しました:",
|
|
@@ -203,11 +203,16 @@ def upload_package(
|
|
|
203
203
|
tarball_data = tarball_path.read_bytes()
|
|
204
204
|
sha = hashlib.sha256(tarball_data).hexdigest()
|
|
205
205
|
|
|
206
|
-
# Upload tarball
|
|
206
|
+
# Upload tarball — server auto-updates index from X-AES-* headers
|
|
207
207
|
upload_url = f"{base.rstrip('/')}/{PACKAGES_PATH}/{name}/{version}.tar.gz"
|
|
208
208
|
req = urllib.request.Request(upload_url, data=tarball_data, method="PUT")
|
|
209
209
|
req.add_header("Authorization", f"Bearer {token}")
|
|
210
210
|
req.add_header("Content-Type", "application/gzip")
|
|
211
|
+
req.add_header("X-AES-Description", description)
|
|
212
|
+
req.add_header("X-AES-Type", pkg_type)
|
|
213
|
+
req.add_header("X-AES-Visibility", visibility)
|
|
214
|
+
if tags:
|
|
215
|
+
req.add_header("X-AES-Tags", ",".join(tags))
|
|
211
216
|
try:
|
|
212
217
|
urllib.request.urlopen(req, timeout=120)
|
|
213
218
|
except urllib.error.HTTPError as exc:
|
|
@@ -216,51 +221,28 @@ def upload_package(
|
|
|
216
221
|
f"Version {version} of '{name}' already exists in the registry. "
|
|
217
222
|
"Bump the version in your skill manifest and try again."
|
|
218
223
|
) from None
|
|
219
|
-
|
|
224
|
+
# Wrap to avoid leaking auth headers in tracebacks
|
|
225
|
+
raise RuntimeError(
|
|
226
|
+
f"Registry upload failed (HTTP {exc.code}): {exc.reason}"
|
|
227
|
+
) from None
|
|
220
228
|
|
|
221
|
-
|
|
222
|
-
try:
|
|
223
|
-
index = fetch_index(registry_url)
|
|
224
|
-
except (urllib.error.URLError, urllib.error.HTTPError):
|
|
225
|
-
index = {"packages": {}}
|
|
229
|
+
from datetime import datetime, timezone
|
|
226
230
|
|
|
227
|
-
|
|
228
|
-
packages = index.setdefault("packages", {})
|
|
229
|
-
pkg = packages.setdefault(name, {
|
|
231
|
+
return {
|
|
230
232
|
"description": description,
|
|
233
|
+
"type": pkg_type,
|
|
234
|
+
"visibility": visibility,
|
|
235
|
+
"tags": tags or [],
|
|
231
236
|
"latest": version,
|
|
232
|
-
"versions": {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
from datetime import datetime, timezone
|
|
241
|
-
pkg["versions"][version] = {
|
|
242
|
-
"url": f"{PACKAGES_PATH}/{name}/{version}.tar.gz",
|
|
243
|
-
"sha256": sha,
|
|
244
|
-
"published_at": datetime.now(timezone.utc).isoformat(),
|
|
237
|
+
"versions": {
|
|
238
|
+
version: {
|
|
239
|
+
"url": f"{PACKAGES_PATH}/{name}/{version}.tar.gz",
|
|
240
|
+
"sha256": sha,
|
|
241
|
+
"published_at": datetime.now(timezone.utc).isoformat(),
|
|
242
|
+
}
|
|
243
|
+
},
|
|
245
244
|
}
|
|
246
245
|
|
|
247
|
-
# Update "latest" if this version is higher
|
|
248
|
-
try:
|
|
249
|
-
if _parse_version(version) >= _parse_version(pkg.get("latest", "0.0.0")):
|
|
250
|
-
pkg["latest"] = version
|
|
251
|
-
except ValueError:
|
|
252
|
-
pkg["latest"] = version
|
|
253
|
-
|
|
254
|
-
# Upload updated index
|
|
255
|
-
index_data = json.dumps(index, indent=2).encode()
|
|
256
|
-
index_url = f"{base.rstrip('/')}/{INDEX_PATH}"
|
|
257
|
-
req = urllib.request.Request(index_url, data=index_data, method="PUT")
|
|
258
|
-
req.add_header("Authorization", f"Bearer {token}")
|
|
259
|
-
req.add_header("Content-Type", "application/json")
|
|
260
|
-
urllib.request.urlopen(req, timeout=30)
|
|
261
|
-
|
|
262
|
-
return pkg
|
|
263
|
-
|
|
264
246
|
|
|
265
247
|
def search_packages(
|
|
266
248
|
query: str = "",
|
|
@@ -77,7 +77,8 @@ class ClaudeTarget(SyncTarget):
|
|
|
77
77
|
|
|
78
78
|
# 3. .claude/commands/*.md (user-defined commands)
|
|
79
79
|
for cmd in ctx.commands:
|
|
80
|
-
|
|
80
|
+
cmd_id = cmd['id'].replace("/", "-").replace("\\", "-")
|
|
81
|
+
rel_path = f".claude/commands/{cmd_id}.md"
|
|
81
82
|
cmd_content = AES_SENTINEL_MD + "\n" + cmd.get("content", "")
|
|
82
83
|
action = self._check_conflict(ctx.project_root, rel_path, force)
|
|
83
84
|
plan.files.append(GeneratedFile(
|
|
@@ -89,7 +90,8 @@ class ClaudeTarget(SyncTarget):
|
|
|
89
90
|
|
|
90
91
|
# 4. .claude/commands/skills/<id>.md (skill runbooks as slash commands)
|
|
91
92
|
for skill_id, runbook in ctx.skill_runbooks.items():
|
|
92
|
-
|
|
93
|
+
safe_id = skill_id.replace("/", "-").replace("\\", "-")
|
|
94
|
+
rel_path = f".claude/commands/skills/{safe_id}.md"
|
|
93
95
|
skill_content = AES_SENTINEL_MD + "\n" + runbook
|
|
94
96
|
|
|
95
97
|
# Append per-skill metadata (negative triggers, permissions)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aes-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: CLI tool for the Agentic Engineering Standard
|
|
5
5
|
Author: Hiro
|
|
6
6
|
License: Apache-2.0
|
|
@@ -40,6 +40,9 @@ AES treats agent instructions, skills, permissions, and memory as **first-class
|
|
|
40
40
|
## Installation
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
+
pipx install aes-cli
|
|
44
|
+
|
|
45
|
+
# Or inside a virtual environment
|
|
43
46
|
pip install aes-cli
|
|
44
47
|
```
|
|
45
48
|
|
|
@@ -331,7 +331,7 @@ class TestUploadPackage:
|
|
|
331
331
|
|
|
332
332
|
assert result["visibility"] == "public"
|
|
333
333
|
|
|
334
|
-
def
|
|
334
|
+
def test_500_still_raises_error(self, tmp_path):
|
|
335
335
|
tarball = tmp_path / "deploy-1.0.0.tar.gz"
|
|
336
336
|
tarball.write_bytes(b"fake tarball content")
|
|
337
337
|
|
|
@@ -345,7 +345,7 @@ class TestUploadPackage:
|
|
|
345
345
|
|
|
346
346
|
with patch.dict(os.environ, {"AES_REGISTRY_KEY": "test-token"}):
|
|
347
347
|
with patch("aes.registry.urllib.request.urlopen", side_effect=err_500):
|
|
348
|
-
with pytest.raises(
|
|
348
|
+
with pytest.raises(RuntimeError, match="HTTP 500"):
|
|
349
349
|
upload_package(
|
|
350
350
|
tarball_path=tarball,
|
|
351
351
|
name="deploy",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|