devops-bot-sdk 1.4.147__tar.gz → 1.4.149__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.
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/local_exec.py +14 -6
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/ip_allowlist.py +40 -4
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/server.py +16 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/service.py +17 -4
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/README.md +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/pyproject.toml +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agentd.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/inventory.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/cli.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/client.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ipc/handlers.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/api.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/dashboard.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/health.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/models.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/setup_manager.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/agents.html +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/app.js +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/custom-agents.html +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/default-agents.html +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/index.html +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/runs.html +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/setup.html +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/styles.css +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/ui/static/tickets.html +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/setup.cfg +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/tests/test_agent_prompt_models.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/tests/test_agents_connectors_builder.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/tests/test_git_action.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/tests/test_health.py +0 -0
- {devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/tests/test_updater_extras.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.149
|
|
4
4
|
|
|
5
5
|
Public surface:
|
|
6
6
|
BackendClient.from_config() — create client from ~/.agentos/config.toml
|
|
@@ -30,7 +30,7 @@ Rules:
|
|
|
30
30
|
- All data egress through submit_webhook only
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
-
__version__ = "1.4.
|
|
33
|
+
__version__ = "1.4.149" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
|
|
34
34
|
__author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -244,16 +244,24 @@ def claude_cli_path() -> str | None:
|
|
|
244
244
|
"""Absolute path to the `claude` CLI, or None if it isn't on PATH.
|
|
245
245
|
|
|
246
246
|
Resolution order:
|
|
247
|
-
1. ``AGENTOS_CLAUDE_CLI``
|
|
248
|
-
|
|
247
|
+
1. ``AGENTOS_CLAUDE_CLI`` — explicit path override, read from the process env
|
|
248
|
+
OR ``~/.agentos/.env`` (same file as the IP allowlist). Escape hatch for an
|
|
249
|
+
install in a location the service's PATH doesn't cover.
|
|
249
250
|
2. ``PATH`` (``shutil.which``) — cross-platform, no guessing.
|
|
250
251
|
|
|
251
|
-
The service
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
The service normally RUNs with a PATH that includes the CLI (the install step
|
|
253
|
+
bakes that in — see ``sdk.ui.service``: systemd ``Environment=PATH`` / launchd
|
|
254
|
+
``EnvironmentVariables``; Windows tasks inherit the user's PATH). When a unit
|
|
255
|
+
predates that or the CLI lives somewhere unusual, setting ``AGENTOS_CLAUDE_CLI``
|
|
256
|
+
in ``~/.agentos/.env`` fixes it with no unit editing.
|
|
255
257
|
"""
|
|
256
258
|
override = os.environ.get("AGENTOS_CLAUDE_CLI", "").strip()
|
|
259
|
+
if not override:
|
|
260
|
+
try:
|
|
261
|
+
from sdk.config import _dotenv_value
|
|
262
|
+
override = (_dotenv_value("AGENTOS_CLAUDE_CLI") or "").strip()
|
|
263
|
+
except Exception: # noqa: BLE001 — a config hiccup must never break resolution
|
|
264
|
+
override = ""
|
|
257
265
|
if override and Path(override).exists():
|
|
258
266
|
return override
|
|
259
267
|
return shutil.which("claude")
|
|
@@ -20,16 +20,52 @@ import ipaddress
|
|
|
20
20
|
import os
|
|
21
21
|
import socket
|
|
22
22
|
|
|
23
|
+
_TRUE = ("1", "true", "yes", "on")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _setting(name: str) -> str:
|
|
27
|
+
"""Read an ``AGENTOS_UI_*`` toggle from the process env OR ``~/.agentos/.env``
|
|
28
|
+
(or a CWD ``.env``), so an operator can set it in the same file as the IP
|
|
29
|
+
allowlist without editing the service unit. Process env wins."""
|
|
30
|
+
val = os.environ.get(name, "").strip()
|
|
31
|
+
if val:
|
|
32
|
+
return val
|
|
33
|
+
try:
|
|
34
|
+
from sdk.config import _dotenv_value
|
|
35
|
+
return (_dotenv_value(name) or "").strip()
|
|
36
|
+
except Exception: # noqa: BLE001 — a config hiccup must never break the server
|
|
37
|
+
return ""
|
|
38
|
+
|
|
23
39
|
|
|
24
40
|
def public_mode() -> bool:
|
|
25
41
|
"""Opt-in PUBLIC mode (``AGENTOS_UI_PUBLIC=1``).
|
|
26
42
|
|
|
27
43
|
When set, the SDK is a public, token-authenticated server: the IP gate is
|
|
28
|
-
lifted so Swagger (``/docs``) is browsable from any IP and every
|
|
29
|
-
path relies SOLELY on the ``co_`` token (``require_token``) as its
|
|
30
|
-
Off by default — a plain launch stays locked to loopback +
|
|
44
|
+
lifted so Swagger (``/docs``) is browsable from any IP over http and every
|
|
45
|
+
``/api/ui/*`` path relies SOLELY on the ``co_`` token (``require_token``) as its
|
|
46
|
+
credential. Off by default — a plain launch stays locked to loopback +
|
|
47
|
+
allowlisted IPs. Read from the process env or ``~/.agentos/.env``.
|
|
48
|
+
"""
|
|
49
|
+
return _setting("AGENTOS_UI_PUBLIC").lower() in _TRUE
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def cors_origins() -> list[str] | None:
|
|
53
|
+
"""Browser (CORS) origins to allow, or ``None`` to leave CORS disabled.
|
|
54
|
+
|
|
55
|
+
Enabled when the server is PUBLIC (``AGENTOS_UI_PUBLIC=1``) or explicitly via
|
|
56
|
+
``AGENTOS_UI_CORS=1``. Origins come from ``AGENTOS_UI_CORS_ORIGINS`` (comma/space
|
|
57
|
+
separated); default ``["*"]`` (any origin). ``*`` is safe here because every
|
|
58
|
+
data route is guarded by the ``co_`` token in the ``Authorization`` header (no
|
|
59
|
+
cookies), so a permissive origin can't be abused via ambient credentials.
|
|
60
|
+
|
|
61
|
+
Needed so a browser (e.g. Swagger "Try it out" served from another origin) can
|
|
62
|
+
call the API — without it the browser blocks the response as a CORS error.
|
|
31
63
|
"""
|
|
32
|
-
|
|
64
|
+
enabled = public_mode() or _setting("AGENTOS_UI_CORS").lower() in _TRUE
|
|
65
|
+
if not enabled:
|
|
66
|
+
return None
|
|
67
|
+
raw = _setting("AGENTOS_UI_CORS_ORIGINS").replace(",", " ").split()
|
|
68
|
+
return raw or ["*"]
|
|
33
69
|
|
|
34
70
|
|
|
35
71
|
def _loopback(ip: ipaddress._BaseAddress) -> bool:
|
|
@@ -41,6 +41,22 @@ def create_app():
|
|
|
41
41
|
# this host's own IPs, and whitelisted IPs (the AI backend) may reach the server
|
|
42
42
|
# AT ALL. Configure via AGENTOS_UI_ALLOWED_IPS or the config.toml `allowed_ips` key.
|
|
43
43
|
app.add_middleware(IPAllowlistMiddleware)
|
|
44
|
+
# CORS (opt-in — on automatically in PUBLIC mode, or via AGENTOS_UI_CORS=1). Added
|
|
45
|
+
# AFTER the allowlist so it is the OUTERMOST layer: it answers browser preflight
|
|
46
|
+
# (OPTIONS) and attaches CORS headers to EVERY response — including a 403 from the
|
|
47
|
+
# allowlist — so the browser can read the real result instead of a bare "CORS
|
|
48
|
+
# error". Data routes stay guarded by the co_ token regardless.
|
|
49
|
+
from sdk.ui.ip_allowlist import cors_origins
|
|
50
|
+
_cors = cors_origins()
|
|
51
|
+
if _cors is not None:
|
|
52
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
53
|
+
app.add_middleware(
|
|
54
|
+
CORSMiddleware,
|
|
55
|
+
allow_origins=_cors,
|
|
56
|
+
allow_methods=["*"],
|
|
57
|
+
allow_headers=["*"],
|
|
58
|
+
allow_credentials=False, # token is in the Authorization header, not cookies
|
|
59
|
+
)
|
|
44
60
|
app.include_router(api_router)
|
|
45
61
|
|
|
46
62
|
@app.get("/")
|
|
@@ -31,11 +31,24 @@ WIN_TASK = "AgentOS Control Panel" # Windows scheduled-task name
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def _exe() -> str:
|
|
34
|
-
"""
|
|
35
|
-
|
|
34
|
+
"""ABSOLUTE path to the ``agentos-ui`` console script.
|
|
35
|
+
|
|
36
|
+
Must be absolute: a service manager (systemd/launchd) does NOT search the
|
|
37
|
+
user's PATH for ExecStart, so a bare ``agentos-ui`` fails with 203/EXEC when
|
|
38
|
+
the script lives somewhere like ``~/.local/bin`` (a ``pip --user`` install) —
|
|
39
|
+
the common case on a VPS. Resolve, in order:
|
|
40
|
+
1. next to the running interpreter (venv installs),
|
|
41
|
+
2. on the current PATH (finds ``~/.local/bin`` at install time),
|
|
42
|
+
3. bare name as a last resort (kept only so install never hard-fails).
|
|
43
|
+
"""
|
|
36
44
|
name = "agentos-ui.exe" if IS_WINDOWS else "agentos-ui"
|
|
37
|
-
cand =
|
|
38
|
-
|
|
45
|
+
cand = Path(sys.executable).parent / name
|
|
46
|
+
if cand.exists():
|
|
47
|
+
return str(cand)
|
|
48
|
+
found = shutil.which(name)
|
|
49
|
+
if found:
|
|
50
|
+
return str(Path(found).resolve())
|
|
51
|
+
return name
|
|
39
52
|
|
|
40
53
|
|
|
41
54
|
def _run(argv: list[str]) -> tuple[int, str]:
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.147 → devops_bot_sdk-1.4.149}/devops_bot_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|