beakr-cli 0.3.0__tar.gz → 0.3.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.
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/PKG-INFO +1 -1
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/pyproject.toml +1 -1
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/__init__.py +1 -1
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/main.py +2 -2
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/mcp_server.py +2 -2
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/updates.py +77 -9
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_updates.py +80 -1
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/uv.lock +1 -1
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/commands/kb-audit.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/commands/kb-research.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/commands/kb-search.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/commands/kb-write.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/SKILL.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/examples/answer-org-question.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/examples/research-topic.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/examples/write-decision-page.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/reference/auditing.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/reference/provenance.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/reference/research-workflow.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.claude/skills/beakr/reference/writing-pages.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.github/workflows/publish.yml +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/.gitignore +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/LICENSE +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/README.md +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/install.sh +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/citations.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/client.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/commands/__init__.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/commands/auth.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/commands/install.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/commands/kb.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/commands/workspace.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/config.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/src/beakr_cli/output.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/__init__.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_auth_cli.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_bundled_assets_vocabulary.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_citations.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_client.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_mcp_shared_vocabulary.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_mcp_source_rendering.py +0 -0
- {beakr_cli-0.3.0 → beakr_cli-0.3.1}/tests/test_packaging.py +0 -0
|
@@ -62,7 +62,7 @@ def version(
|
|
|
62
62
|
return
|
|
63
63
|
status = get_update_status(max_age=timedelta(hours=1))
|
|
64
64
|
if status.latest is None:
|
|
65
|
-
print("Latest release: unknown (could not
|
|
65
|
+
print("Latest release: unknown (PyPI could not be checked)")
|
|
66
66
|
elif status.update_available:
|
|
67
67
|
print(f"Update available: {status.latest}. {detect_install().instructions}")
|
|
68
68
|
else:
|
|
@@ -114,7 +114,7 @@ def update(
|
|
|
114
114
|
raise typer.Exit(1)
|
|
115
115
|
|
|
116
116
|
console.print(f"[dim]$ {' '.join(info.upgrade_command)}[/dim]")
|
|
117
|
-
result = run_upgrade(info)
|
|
117
|
+
result = run_upgrade(info, expected_version=status.latest)
|
|
118
118
|
if result.output:
|
|
119
119
|
console.print(f"[dim]{result.output}[/dim]", highlight=False)
|
|
120
120
|
if not result.ok:
|
|
@@ -831,7 +831,7 @@ async def beakr_version() -> str:
|
|
|
831
831
|
info = detect_install()
|
|
832
832
|
lines = [f"Installed: beakr-cli {status.current} ({info.method.value})"]
|
|
833
833
|
if status.latest is None:
|
|
834
|
-
lines.append("Latest release: unknown (could not
|
|
834
|
+
lines.append("Latest release: unknown (PyPI could not be checked).")
|
|
835
835
|
elif status.update_available:
|
|
836
836
|
lines.append(f"Update available: {status.latest}.")
|
|
837
837
|
if info.upgrade_command is not None:
|
|
@@ -865,7 +865,7 @@ async def update_beakr() -> str:
|
|
|
865
865
|
f"No update needed: installed {status.current}, latest release {status.latest}."
|
|
866
866
|
)
|
|
867
867
|
info = detect_install()
|
|
868
|
-
result = await asyncio.to_thread(run_upgrade, info)
|
|
868
|
+
result = await asyncio.to_thread(run_upgrade, info, expected_version=status.latest)
|
|
869
869
|
if not result.ok:
|
|
870
870
|
tail = f"\n\n{result.output[-2000:]}" if result.output else ""
|
|
871
871
|
return f"Update did not run: {result.message}{tail}"
|
|
@@ -104,20 +104,35 @@ def get_update_status(
|
|
|
104
104
|
allow_network: bool = True,
|
|
105
105
|
timeout: float = 2.0,
|
|
106
106
|
) -> UpdateStatus:
|
|
107
|
-
"""Current vs latest version, from cache when fresh enough, else from PyPI.
|
|
107
|
+
"""Current vs latest version, from cache when fresh enough, else from PyPI.
|
|
108
|
+
|
|
109
|
+
A "latest" older than the running version is never reported or cached. PyPI's
|
|
110
|
+
CDN serves the project JSON with ``max-age=900``, so for up to 15 minutes after
|
|
111
|
+
a release it can still list the previous one; caching that answer used to make
|
|
112
|
+
a freshly upgraded CLI report the version it had just replaced as the latest.
|
|
113
|
+
"""
|
|
108
114
|
cached_latest, checked_at = _read_cache()
|
|
115
|
+
if cached_latest is not None and _older_than_running(cached_latest):
|
|
116
|
+
cached_latest, checked_at = None, None
|
|
109
117
|
now = datetime.now(timezone.utc)
|
|
110
118
|
fresh = checked_at is not None and now - checked_at <= max_age
|
|
111
119
|
if fresh or not allow_network or check_disabled():
|
|
112
120
|
return UpdateStatus(__version__, cached_latest, checked_at)
|
|
113
121
|
latest = fetch_latest_version(timeout)
|
|
114
|
-
if latest is None:
|
|
115
|
-
# Offline
|
|
122
|
+
if latest is None or _older_than_running(latest):
|
|
123
|
+
# Offline, PyPI unavailable, or a stale CDN listing: keep what we last knew.
|
|
116
124
|
return UpdateStatus(__version__, cached_latest, checked_at)
|
|
117
125
|
_write_cache(latest, now)
|
|
118
126
|
return UpdateStatus(__version__, latest, now)
|
|
119
127
|
|
|
120
128
|
|
|
129
|
+
def _older_than_running(version: str) -> bool:
|
|
130
|
+
try:
|
|
131
|
+
return Version(version) < Version(__version__)
|
|
132
|
+
except InvalidVersion:
|
|
133
|
+
return True
|
|
134
|
+
|
|
135
|
+
|
|
121
136
|
# ---------------------------------------------------------------------------
|
|
122
137
|
# Install method detection
|
|
123
138
|
# ---------------------------------------------------------------------------
|
|
@@ -126,6 +141,7 @@ def get_update_status(
|
|
|
126
141
|
class InstallMethod(str, Enum):
|
|
127
142
|
uv_tool = "uv tool"
|
|
128
143
|
uv_tool_source = "uv tool (local source)"
|
|
144
|
+
uv_tool_pinned = "uv tool (pinned version)"
|
|
129
145
|
pipx = "pipx"
|
|
130
146
|
uvx = "uvx"
|
|
131
147
|
other = "other"
|
|
@@ -161,6 +177,19 @@ def _receipt_is_local_source(receipt: Path) -> bool:
|
|
|
161
177
|
return any(marker in text for marker in ("directory =", "path =", "git ="))
|
|
162
178
|
|
|
163
179
|
|
|
180
|
+
def _receipt_pins_version(receipt: Path) -> bool:
|
|
181
|
+
"""True when the uv tool was installed as ``beakr-cli==X``.
|
|
182
|
+
|
|
183
|
+
``uv tool upgrade`` honours the pin and does nothing, so offering it would
|
|
184
|
+
report an upgrade that never happens.
|
|
185
|
+
"""
|
|
186
|
+
try:
|
|
187
|
+
text = receipt.read_text()
|
|
188
|
+
except OSError:
|
|
189
|
+
return False
|
|
190
|
+
return f'name = "{PACKAGE_NAME}", specifier = "==' in text
|
|
191
|
+
|
|
192
|
+
|
|
164
193
|
def detect_install(prefix: Path | None = None) -> InstallInfo:
|
|
165
194
|
"""Work out how this interpreter's beakr-cli was installed."""
|
|
166
195
|
env = (prefix or Path(sys.prefix)).resolve()
|
|
@@ -180,16 +209,28 @@ def detect_install(prefix: Path | None = None) -> InstallInfo:
|
|
|
180
209
|
"`uv tool install --force <checkout>`, or switch to the published "
|
|
181
210
|
f"release with `uv tool install --force {PACKAGE_NAME}`.",
|
|
182
211
|
)
|
|
212
|
+
if _receipt_pins_version(receipt):
|
|
213
|
+
return InstallInfo(
|
|
214
|
+
InstallMethod.uv_tool_pinned,
|
|
215
|
+
None,
|
|
216
|
+
"Installed with uv pinned to one version, which `uv tool upgrade` keeps. "
|
|
217
|
+
f"Unpin it with `uv tool install --force {PACKAGE_NAME}`.",
|
|
218
|
+
)
|
|
219
|
+
# --reinstall-package implies --refresh-package (which `uv tool upgrade` does not
|
|
220
|
+
# accept directly). uv caches the package index, and without a refresh an
|
|
221
|
+
# upgrade run shortly after a release resolves the old version and exits 0.
|
|
183
222
|
return InstallInfo(
|
|
184
223
|
InstallMethod.uv_tool,
|
|
185
|
-
["uv", "tool", "upgrade", PACKAGE_NAME],
|
|
224
|
+
["uv", "tool", "upgrade", "--reinstall-package", PACKAGE_NAME, PACKAGE_NAME],
|
|
186
225
|
f"Run `beakr update` (or `uv tool upgrade {PACKAGE_NAME}`).",
|
|
187
226
|
)
|
|
188
227
|
|
|
189
|
-
|
|
228
|
+
pipx_home = os.environ.get("PIPX_HOME")
|
|
229
|
+
in_custom_pipx = bool(pipx_home) and env.parent == (Path(pipx_home) / "venvs").resolve()
|
|
230
|
+
if in_custom_pipx or ("pipx" in parts and "venvs" in parts):
|
|
190
231
|
return InstallInfo(
|
|
191
232
|
InstallMethod.pipx,
|
|
192
|
-
["pipx", "upgrade", PACKAGE_NAME],
|
|
233
|
+
["pipx", "upgrade", "--pip-args=--no-cache-dir", PACKAGE_NAME],
|
|
193
234
|
f"Run `beakr update` (or `pipx upgrade {PACKAGE_NAME}`).",
|
|
194
235
|
)
|
|
195
236
|
|
|
@@ -227,11 +268,16 @@ def _beakr_executable() -> str | None:
|
|
|
227
268
|
return shutil.which("beakr")
|
|
228
269
|
|
|
229
270
|
|
|
230
|
-
def run_upgrade(
|
|
231
|
-
|
|
271
|
+
def run_upgrade(
|
|
272
|
+
info: InstallInfo, *, expected_version: str | None = None, timeout: float = 300.0
|
|
273
|
+
) -> UpgradeResult:
|
|
274
|
+
"""Upgrade the package, confirm it moved, then refresh the skills it installed.
|
|
232
275
|
|
|
233
276
|
The skill refresh runs through the NEW binary on PATH, not this process: the
|
|
234
277
|
running interpreter still has the old code and the old bundled assets loaded.
|
|
278
|
+
A package manager exiting 0 is not proof of an upgrade (a cached index or a
|
|
279
|
+
pin both "succeed" without changing anything), so the binary's own version is
|
|
280
|
+
checked against ``expected_version`` before anything is reported as upgraded.
|
|
235
281
|
"""
|
|
236
282
|
if info.upgrade_command is None:
|
|
237
283
|
return UpgradeResult(False, info.instructions, "")
|
|
@@ -255,6 +301,17 @@ def run_upgrade(info: InstallInfo, *, timeout: float = 300.0) -> UpgradeResult:
|
|
|
255
301
|
False, f"`{' '.join(info.upgrade_command)}` failed (exit {upgrade.returncode}).", output
|
|
256
302
|
)
|
|
257
303
|
|
|
304
|
+
if expected_version is not None:
|
|
305
|
+
now = installed_version_on_path()
|
|
306
|
+
if now is None or _version_lt(now, expected_version):
|
|
307
|
+
return UpgradeResult(
|
|
308
|
+
False,
|
|
309
|
+
f"The upgrade ran but `beakr` on PATH is still {now or 'unknown'}, not "
|
|
310
|
+
f"{expected_version}. A new release can take a few minutes to reach PyPI's "
|
|
311
|
+
"mirrors; try again shortly.",
|
|
312
|
+
output,
|
|
313
|
+
)
|
|
314
|
+
|
|
258
315
|
beakr = _beakr_executable()
|
|
259
316
|
if beakr is None:
|
|
260
317
|
return UpgradeResult(
|
|
@@ -294,7 +351,11 @@ def installed_version_on_path() -> str | None:
|
|
|
294
351
|
return None
|
|
295
352
|
try:
|
|
296
353
|
result = subprocess.run(
|
|
297
|
-
[beakr, "version"
|
|
354
|
+
[beakr, "version", "--offline"],
|
|
355
|
+
capture_output=True,
|
|
356
|
+
text=True,
|
|
357
|
+
timeout=30,
|
|
358
|
+
check=False,
|
|
298
359
|
)
|
|
299
360
|
except subprocess.TimeoutExpired:
|
|
300
361
|
return None
|
|
@@ -303,3 +364,10 @@ def installed_version_on_path() -> str | None:
|
|
|
303
364
|
return None
|
|
304
365
|
# First line is "beakr-cli X.Y.Z"; later lines may describe update status.
|
|
305
366
|
return text[0].removeprefix(f"{PACKAGE_NAME} ").strip() or None
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def _version_lt(left: str, right: str) -> bool:
|
|
370
|
+
try:
|
|
371
|
+
return Version(left) < Version(right)
|
|
372
|
+
except InvalidVersion:
|
|
373
|
+
return True
|
|
@@ -102,6 +102,33 @@ def test_disabled_check_never_touches_network(monkeypatch) -> None:
|
|
|
102
102
|
assert route.call_count == 0
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
@respx.mock
|
|
106
|
+
def test_cached_latest_older_than_running_version_is_refetched() -> None:
|
|
107
|
+
"""Right after upgrading, a cache written by the old version must not be shown."""
|
|
108
|
+
route = respx.get(updates.PYPI_JSON_URL).mock(
|
|
109
|
+
return_value=httpx.Response(200, json=_pypi("0.2.1", "0.3.0"))
|
|
110
|
+
)
|
|
111
|
+
_write_cache("0.2.1", age=timedelta(minutes=5))
|
|
112
|
+
status = updates.get_update_status()
|
|
113
|
+
assert status.latest == "0.3.0"
|
|
114
|
+
assert route.call_count == 1
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@respx.mock
|
|
118
|
+
def test_stale_cdn_listing_older_than_running_version_is_not_cached() -> None:
|
|
119
|
+
"""PyPI's CDN can list the previous release for ~15 minutes after publishing.
|
|
120
|
+
|
|
121
|
+
That answer was cached for a day and shown as "latest release: 0.2.1" on 0.3.0.
|
|
122
|
+
"""
|
|
123
|
+
respx.get(updates.PYPI_JSON_URL).mock(
|
|
124
|
+
return_value=httpx.Response(200, json=_pypi("0.2.0", "0.2.1"))
|
|
125
|
+
)
|
|
126
|
+
status = updates.get_update_status()
|
|
127
|
+
assert status.latest is None
|
|
128
|
+
assert not status.update_available
|
|
129
|
+
assert not (config.CONFIG_DIR / "update_check.json").exists()
|
|
130
|
+
|
|
131
|
+
|
|
105
132
|
def test_running_ahead_of_pypi_is_not_an_update() -> None:
|
|
106
133
|
assert not updates.UpdateStatus("0.3.0", "0.2.1", None).update_available
|
|
107
134
|
|
|
@@ -119,7 +146,26 @@ def test_detects_pypi_uv_tool_install(tmp_path, monkeypatch) -> None:
|
|
|
119
146
|
monkeypatch.setenv("UV_TOOL_DIR", str(tools))
|
|
120
147
|
info = updates.detect_install(env)
|
|
121
148
|
assert info.method is updates.InstallMethod.uv_tool
|
|
122
|
-
|
|
149
|
+
# --reinstall-package implies a refresh of the cached index; without one an
|
|
150
|
+
# upgrade shortly after a release resolved the old version and still exited 0.
|
|
151
|
+
assert info.upgrade_command == [
|
|
152
|
+
"uv", "tool", "upgrade", "--reinstall-package", "beakr-cli", "beakr-cli",
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_version_pinned_uv_tool_is_reported_not_upgraded(tmp_path, monkeypatch) -> None:
|
|
157
|
+
"""`uv tool upgrade` keeps a `==X` pin, so running it would upgrade nothing."""
|
|
158
|
+
tools = tmp_path / "uv" / "tools"
|
|
159
|
+
env = tools / "beakr-cli"
|
|
160
|
+
env.mkdir(parents=True)
|
|
161
|
+
(env / "uv-receipt.toml").write_text(
|
|
162
|
+
'[tool]\nrequirements = [{ name = "beakr-cli", specifier = "==0.3.0" }]\n'
|
|
163
|
+
)
|
|
164
|
+
monkeypatch.setenv("UV_TOOL_DIR", str(tools))
|
|
165
|
+
info = updates.detect_install(env)
|
|
166
|
+
assert info.method is updates.InstallMethod.uv_tool_pinned
|
|
167
|
+
assert info.upgrade_command is None
|
|
168
|
+
assert "uv tool install --force beakr-cli" in info.instructions
|
|
123
169
|
|
|
124
170
|
|
|
125
171
|
def test_local_checkout_uv_tool_is_never_upgraded_from_pypi(tmp_path, monkeypatch) -> None:
|
|
@@ -151,6 +197,16 @@ def test_detects_other_install_methods(prefix, method, can_upgrade, monkeypatch,
|
|
|
151
197
|
assert (info.upgrade_command is not None) is can_upgrade
|
|
152
198
|
|
|
153
199
|
|
|
200
|
+
def test_detects_pipx_with_a_custom_pipx_home(tmp_path, monkeypatch) -> None:
|
|
201
|
+
monkeypatch.setenv("UV_TOOL_DIR", str(tmp_path / "no-tools-here"))
|
|
202
|
+
monkeypatch.setenv("PIPX_HOME", str(tmp_path / "custom-home"))
|
|
203
|
+
env = tmp_path / "custom-home" / "venvs" / "beakr-cli"
|
|
204
|
+
env.mkdir(parents=True)
|
|
205
|
+
info = updates.detect_install(env)
|
|
206
|
+
assert info.method is updates.InstallMethod.pipx
|
|
207
|
+
assert info.upgrade_command == ["pipx", "upgrade", "--pip-args=--no-cache-dir", "beakr-cli"]
|
|
208
|
+
|
|
209
|
+
|
|
154
210
|
def test_upgrade_without_a_safe_command_only_returns_instructions() -> None:
|
|
155
211
|
info = updates.InstallInfo(updates.InstallMethod.uvx, None, "use uvx --refresh")
|
|
156
212
|
result = updates.run_upgrade(info)
|
|
@@ -179,6 +235,29 @@ def test_upgrade_refreshes_skills_through_the_new_binary(monkeypatch) -> None:
|
|
|
179
235
|
assert calls == [["uv", "tool", "upgrade", "x"], ["/bin/beakr", "install", "--refresh"]]
|
|
180
236
|
|
|
181
237
|
|
|
238
|
+
def test_upgrade_that_did_not_move_the_version_is_a_failure(monkeypatch) -> None:
|
|
239
|
+
"""A package manager exiting 0 is not an upgrade; skills must not be refreshed."""
|
|
240
|
+
calls: list[list[str]] = []
|
|
241
|
+
|
|
242
|
+
class Done:
|
|
243
|
+
returncode = 0
|
|
244
|
+
stdout = ""
|
|
245
|
+
stderr = ""
|
|
246
|
+
|
|
247
|
+
def fake_run(cmd, **_kwargs):
|
|
248
|
+
calls.append(cmd)
|
|
249
|
+
return Done()
|
|
250
|
+
|
|
251
|
+
monkeypatch.setattr(updates.shutil, "which", lambda name: f"/bin/{name}")
|
|
252
|
+
monkeypatch.setattr(updates.subprocess, "run", fake_run)
|
|
253
|
+
monkeypatch.setattr(updates, "installed_version_on_path", lambda: "0.3.0")
|
|
254
|
+
info = updates.InstallInfo(updates.InstallMethod.uv_tool, ["uv", "tool", "upgrade", "x"], "")
|
|
255
|
+
result = updates.run_upgrade(info, expected_version="0.3.1")
|
|
256
|
+
assert not result.ok
|
|
257
|
+
assert "still 0.3.0" in result.message
|
|
258
|
+
assert calls == [["uv", "tool", "upgrade", "x"]]
|
|
259
|
+
|
|
260
|
+
|
|
182
261
|
# ---------------------------------------------------------------------------
|
|
183
262
|
# Skill refresh
|
|
184
263
|
# ---------------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|