qbraid-cli 0.15.4__tar.gz → 0.16.1__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.
- {qbraid_cli-0.15.4/qbraid_cli.egg-info → qbraid_cli-0.16.1}/PKG-INFO +2 -2
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/pyproject.toml +2 -2
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/agents/app.py +53 -7
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/skills/app.py +40 -4
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1/qbraid_cli.egg-info}/PKG-INFO +2 -2
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli.egg-info/requires.txt +1 -1
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/LICENSE +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/README.md +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/_build_info.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/_version.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/account/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/account/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/admin/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/admin/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/admin/headers.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/admin/validation.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/agents/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/agents/permission_response.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/ai/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/ai/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/ai/token.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/compute/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/compute/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/compute/instances.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/compute/profiles.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/compute/server.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/compute/ssh.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/configure/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/configure/actions.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/configure/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/devices/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/devices/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/devices/validation.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/activate.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/create.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/data_handling.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/groups.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/publish.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/registry.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/envs/share.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/exceptions.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/handlers.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/jobs/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/jobs/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/jobs/groups.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/kernels/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/kernels/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/lab/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/lab/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/main.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/pip/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/pip/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/pip/hooks.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/projects/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/projects/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/py.typed +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/skills/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/troubleshoot/__init__.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli/troubleshoot/app.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli.egg-info/SOURCES.txt +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli.egg-info/dependency_links.txt +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli.egg-info/entry_points.txt +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/qbraid_cli.egg-info/top_level.txt +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/setup.cfg +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/tests/test_cli_e2e.py +0 -0
- {qbraid_cli-0.15.4 → qbraid_cli-0.16.1}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qbraid-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.1
|
|
4
4
|
Summary: Command Line Interface for interacting with all parts of the qBraid platform.
|
|
5
5
|
Author-email: qBraid Development Team <contact@qbraid.com>
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
Requires-Dist: typer>=0.12.1
|
|
30
30
|
Requires-Dist: rich>=10.11.0
|
|
31
|
-
Requires-Dist: click<=8.
|
|
31
|
+
Requires-Dist: click<=8.5.0
|
|
32
32
|
Requires-Dist: questionary>=2.0.0
|
|
33
33
|
Requires-Dist: qbraid-core>=0.6.5
|
|
34
34
|
Provides-Extra: compute
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "qbraid-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.16.1"
|
|
8
8
|
description = "Command Line Interface for interacting with all parts of the qBraid platform."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "qBraid Development Team", email = "contact@qbraid.com" }]
|
|
@@ -30,7 +30,7 @@ classifiers = [
|
|
|
30
30
|
dependencies = [
|
|
31
31
|
"typer>=0.12.1",
|
|
32
32
|
"rich>=10.11.0",
|
|
33
|
-
"click<=8.
|
|
33
|
+
"click<=8.5.0",
|
|
34
34
|
"questionary>=2.0.0",
|
|
35
35
|
"qbraid-core>=0.6.5",
|
|
36
36
|
]
|
|
@@ -327,7 +327,12 @@ def agents_list(
|
|
|
327
327
|
remote_flags.extend(["--limit", str(limit)])
|
|
328
328
|
remote_flags.extend(["--page", str(page)])
|
|
329
329
|
|
|
330
|
-
|
|
330
|
+
# Nothing but the payload on stdout when --json is set: a caller
|
|
331
|
+
# piping this into a parser gets the status line too, and Rich
|
|
332
|
+
# would read square brackets in the payload as markup and mangle
|
|
333
|
+
# it. Status goes to stderr, the payload through plain print.
|
|
334
|
+
if not json_output:
|
|
335
|
+
console.print(f"[dim]Listing agents on {compute}...[/dim]")
|
|
331
336
|
result = subprocess.run(
|
|
332
337
|
["ssh", "-o", "ConnectTimeout=10", compute, " ".join(remote_flags)],
|
|
333
338
|
capture_output=True,
|
|
@@ -336,8 +341,27 @@ def agents_list(
|
|
|
336
341
|
timeout=30,
|
|
337
342
|
)
|
|
338
343
|
if result.returncode == 0:
|
|
339
|
-
|
|
344
|
+
if json_output:
|
|
345
|
+
payload = result.stdout.strip()
|
|
346
|
+
if not payload:
|
|
347
|
+
# Exit 0 with nothing on stdout means the remote did
|
|
348
|
+
# not produce a listing -- most likely a remote CLI
|
|
349
|
+
# too old to know --json. Printing the blank through
|
|
350
|
+
# would hand a parser a bare newline while still
|
|
351
|
+
# reporting success; an empty result is "[]", never "".
|
|
352
|
+
typer.echo(
|
|
353
|
+
f"No JSON returned by 'qbraid agents list' on {compute} "
|
|
354
|
+
"(is the remote qbraid-cli recent enough to support --json?)",
|
|
355
|
+
err=True,
|
|
356
|
+
)
|
|
357
|
+
raise typer.Exit(code=1)
|
|
358
|
+
print(payload)
|
|
359
|
+
else:
|
|
360
|
+
console.print(result.stdout)
|
|
340
361
|
else:
|
|
362
|
+
if json_output:
|
|
363
|
+
typer.echo(f"Failed: {result.stderr.strip()}", err=True)
|
|
364
|
+
raise typer.Exit(code=1)
|
|
341
365
|
console.print(f"[red]Failed: {result.stderr.strip()}[/red]")
|
|
342
366
|
return
|
|
343
367
|
|
|
@@ -825,11 +849,25 @@ def agents_update(
|
|
|
825
849
|
def agents_kill(
|
|
826
850
|
target: str = typer.Argument(..., help="Agent name, ID prefix, or PID"),
|
|
827
851
|
force: bool = typer.Option(False, "--force", "-f", help="Use SIGKILL instead of SIGTERM"),
|
|
852
|
+
compute: Optional[str] = typer.Option(None, "--compute", "-c", help="SSH alias for remote compute"),
|
|
828
853
|
):
|
|
829
|
-
"""Stop an agent by name, session ID, or PID.
|
|
854
|
+
"""Stop an agent by name, session ID, or PID.
|
|
855
|
+
|
|
856
|
+
With ``--compute`` the agent is stopped on that machine. Without it, an
|
|
857
|
+
agent running elsewhere is simply not in this host's registry and reports
|
|
858
|
+
as not found -- the registry is per-host.
|
|
859
|
+
"""
|
|
830
860
|
try:
|
|
831
861
|
from qbraid_core.services.agents import AgentSessionRegistryManager
|
|
832
862
|
|
|
863
|
+
if compute:
|
|
864
|
+
import shlex
|
|
865
|
+
|
|
866
|
+
flags = " --force" if force else ""
|
|
867
|
+
_ssh_cmd(compute, f"qbraid agents kill {shlex.quote(target)}{flags}")
|
|
868
|
+
console.print(f"[green]Stopped '{target}' on {compute}.[/green]")
|
|
869
|
+
return
|
|
870
|
+
|
|
833
871
|
registry = AgentSessionRegistryManager()
|
|
834
872
|
all_sessions = registry.load_registry().sessions
|
|
835
873
|
|
|
@@ -1712,6 +1750,12 @@ def agents_send(
|
|
|
1712
1750
|
):
|
|
1713
1751
|
"""Send text to a running agent's terminal."""
|
|
1714
1752
|
try:
|
|
1753
|
+
# Imported before anything else in this try: the `except
|
|
1754
|
+
# AgentLauncherError` clause below cannot be evaluated unless the name
|
|
1755
|
+
# is bound, so a failure in the --compute branch above would raise
|
|
1756
|
+
# UnboundLocalError and bury the real error instead of reporting it.
|
|
1757
|
+
from qbraid_core.services.agents import AgentLauncher, AgentLauncherError
|
|
1758
|
+
|
|
1715
1759
|
if compute:
|
|
1716
1760
|
import shlex
|
|
1717
1761
|
|
|
@@ -1719,8 +1763,6 @@ def agents_send(
|
|
|
1719
1763
|
console.print(f"[green]Sent text to session {session_id} on {compute}.[/green]")
|
|
1720
1764
|
return
|
|
1721
1765
|
|
|
1722
|
-
from qbraid_core.services.agents import AgentLauncher, AgentLauncherError
|
|
1723
|
-
|
|
1724
1766
|
launcher = AgentLauncher()
|
|
1725
1767
|
launcher.send(session_id, text)
|
|
1726
1768
|
console.print(f"[green]Sent text to session {session_id}.[/green]")
|
|
@@ -1748,6 +1790,12 @@ def agents_read(
|
|
|
1748
1790
|
):
|
|
1749
1791
|
"""Read recent terminal output from an agent."""
|
|
1750
1792
|
try:
|
|
1793
|
+
# Imported before anything else in this try: the `except
|
|
1794
|
+
# AgentLauncherError` clause below cannot be evaluated unless the name
|
|
1795
|
+
# is bound, so a failure in the --compute branch above would raise
|
|
1796
|
+
# UnboundLocalError and bury the real error instead of reporting it.
|
|
1797
|
+
from qbraid_core.services.agents import AgentLauncher, AgentLauncherError
|
|
1798
|
+
|
|
1751
1799
|
if compute:
|
|
1752
1800
|
import shlex
|
|
1753
1801
|
|
|
@@ -1755,8 +1803,6 @@ def agents_read(
|
|
|
1755
1803
|
console.print(output)
|
|
1756
1804
|
return
|
|
1757
1805
|
|
|
1758
|
-
from qbraid_core.services.agents import AgentLauncher, AgentLauncherError
|
|
1759
|
-
|
|
1760
1806
|
launcher = AgentLauncher()
|
|
1761
1807
|
output = launcher.read(session_id, lines)
|
|
1762
1808
|
console.print(output)
|
|
@@ -6,6 +6,7 @@ Module defining commands in the 'qbraid skills' namespace.
|
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
import json
|
|
9
10
|
from enum import Enum
|
|
10
11
|
from typing import Optional
|
|
11
12
|
|
|
@@ -68,6 +69,23 @@ class VisibilityOption(str, Enum):
|
|
|
68
69
|
# =============================================================================
|
|
69
70
|
|
|
70
71
|
|
|
72
|
+
def _emit_skills_json(skills) -> None:
|
|
73
|
+
"""Print skills as a JSON array on stdout, and nothing else.
|
|
74
|
+
|
|
75
|
+
Agents discover most skills through `qbraid skills list` / `search` rather
|
|
76
|
+
than having them installed, so this output is a discovery surface, not a
|
|
77
|
+
convenience. The table truncates descriptions (40-50 chars), and a
|
|
78
|
+
description is exactly what an agent matches against to decide whether a
|
|
79
|
+
skill applies -- truncating it hides the words that would have triggered it.
|
|
80
|
+
JSON carries them in full.
|
|
81
|
+
|
|
82
|
+
Uses `print`, not `console.print`: Rich would interpret square brackets in a
|
|
83
|
+
description as markup and mangle the payload.
|
|
84
|
+
"""
|
|
85
|
+
payload = [skill.model_dump(mode="json", by_alias=True, exclude_none=True) for skill in skills]
|
|
86
|
+
print(json.dumps(payload, indent=2))
|
|
87
|
+
|
|
88
|
+
|
|
71
89
|
@skills_app.command(name="list")
|
|
72
90
|
def skills_list(
|
|
73
91
|
query: Optional[str] = typer.Option(None, "--query", "-q", help="Search query for skills"),
|
|
@@ -76,8 +94,12 @@ def skills_list(
|
|
|
76
94
|
None, "--visibility", "-v", help="Filter by visibility"
|
|
77
95
|
),
|
|
78
96
|
limit: int = typer.Option(20, "--limit", "-l", help="Maximum number of results"),
|
|
97
|
+
json_output: bool = typer.Option(False, "--json", help="Output as JSON array (for programmatic use)"),
|
|
79
98
|
) -> None:
|
|
80
|
-
"""List available qBraid skills.
|
|
99
|
+
"""List available qBraid skills.
|
|
100
|
+
|
|
101
|
+
Pass --json for the full, untruncated records.
|
|
102
|
+
"""
|
|
81
103
|
|
|
82
104
|
def fetch_skills():
|
|
83
105
|
from qbraid_core.services.skills import SkillsClient
|
|
@@ -88,7 +110,13 @@ def skills_list(
|
|
|
88
110
|
return client.list_skills(query=query, tags=tag_list, visibility=vis, limit=limit)
|
|
89
111
|
|
|
90
112
|
try:
|
|
91
|
-
|
|
113
|
+
# Skip the progress spinner for --json: Rich writes it to the same
|
|
114
|
+
# stream, and a caller piping this into a parser gets the spinner too.
|
|
115
|
+
skills = fetch_skills() if json_output else run_progress_task(fetch_skills)
|
|
116
|
+
|
|
117
|
+
if json_output:
|
|
118
|
+
_emit_skills_json(skills)
|
|
119
|
+
return
|
|
92
120
|
|
|
93
121
|
console = Console()
|
|
94
122
|
|
|
@@ -128,8 +156,12 @@ def skills_list(
|
|
|
128
156
|
def skills_search(
|
|
129
157
|
query: str = typer.Argument(..., help="Search query"),
|
|
130
158
|
limit: int = typer.Option(10, "--limit", "-l", help="Maximum number of results"),
|
|
159
|
+
json_output: bool = typer.Option(False, "--json", help="Output as JSON array (for programmatic use)"),
|
|
131
160
|
) -> None:
|
|
132
|
-
"""Search for qBraid skills.
|
|
161
|
+
"""Search for qBraid skills.
|
|
162
|
+
|
|
163
|
+
Pass --json for the full, untruncated records.
|
|
164
|
+
"""
|
|
133
165
|
|
|
134
166
|
def fetch_skills():
|
|
135
167
|
from qbraid_core.services.skills import SkillsClient
|
|
@@ -138,7 +170,11 @@ def skills_search(
|
|
|
138
170
|
return client.list_skills(query=query, limit=limit)
|
|
139
171
|
|
|
140
172
|
try:
|
|
141
|
-
skills = run_progress_task(fetch_skills)
|
|
173
|
+
skills = fetch_skills() if json_output else run_progress_task(fetch_skills)
|
|
174
|
+
|
|
175
|
+
if json_output:
|
|
176
|
+
_emit_skills_json(skills)
|
|
177
|
+
return
|
|
142
178
|
|
|
143
179
|
console = Console()
|
|
144
180
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qbraid-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.1
|
|
4
4
|
Summary: Command Line Interface for interacting with all parts of the qBraid platform.
|
|
5
5
|
Author-email: qBraid Development Team <contact@qbraid.com>
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
Requires-Dist: typer>=0.12.1
|
|
30
30
|
Requires-Dist: rich>=10.11.0
|
|
31
|
-
Requires-Dist: click<=8.
|
|
31
|
+
Requires-Dist: click<=8.5.0
|
|
32
32
|
Requires-Dist: questionary>=2.0.0
|
|
33
33
|
Requires-Dist: qbraid-core>=0.6.5
|
|
34
34
|
Provides-Extra: compute
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|