simulo 0.31.0__tar.gz → 0.31.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.
- {simulo-0.31.0/src/simulo.egg-info → simulo-0.31.2}/PKG-INFO +1 -1
- {simulo-0.31.0 → simulo-0.31.2}/pyproject.toml +1 -1
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/builtin_aliases.py +8 -15
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/cli.py +78 -27
- {simulo-0.31.0 → simulo-0.31.2/src/simulo.egg-info}/PKG-INFO +1 -1
- {simulo-0.31.0 → simulo-0.31.2}/MANIFEST.in +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/PYPI.md +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/setup.cfg +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/__init__.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/__init__.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/_arguments.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/_mounts.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/_runner.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/_secure_downloads.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/app.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/asset.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/asset_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/asset_package.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/asset_pins.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/bundle.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/cancel_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/config.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/credentials.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/discovery.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/export_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/facades.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/http.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/identity_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/install_samples.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/jobs_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/learning.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/login.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/mode.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/onnx_bundle.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/outputs.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/packaging.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/policies_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/preflight_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/preflight_render.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/preview_report.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/registry.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/runtime.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/runtime_display.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/stub.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/submit_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/templates/__init__.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/templates/training/play.py.tmpl +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/templates/training/preview.py.tmpl +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/templates/training/simuloignore.tmpl +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/templates/training/task.py.tmpl +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/templates/training/train.py.tmpl +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/view_fragment.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/view_session_api.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/_client/volume.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/callbacks.py +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo/py.typed +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo.egg-info/SOURCES.txt +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo.egg-info/dependency_links.txt +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo.egg-info/entry_points.txt +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo.egg-info/requires.txt +0 -0
- {simulo-0.31.0 → simulo-0.31.2}/src/simulo.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simulo
|
|
3
|
-
Version: 0.31.
|
|
3
|
+
Version: 0.31.2
|
|
4
4
|
Summary: Python SDK and CLI for cloud-native robotics simulation, reinforcement learning, and robot policy training on managed GPUs.
|
|
5
5
|
Author-email: Simulo Team <team@simulo.ai>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simulo"
|
|
7
|
-
version = "0.31.
|
|
7
|
+
version = "0.31.2"
|
|
8
8
|
description = "Python SDK and CLI for cloud-native robotics simulation, reinforcement learning, and robot policy training on managed GPUs."
|
|
9
9
|
readme = "PYPI.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -9,21 +9,12 @@ equivalent has been seeded — pointing the user at the ``simulo/robot/...`` idi
|
|
|
9
9
|
Two pieces:
|
|
10
10
|
|
|
11
11
|
* :data:`BUILTIN_ASSET_ALIASES` — the ``<builtin-name> -> <catalog-ref>`` table.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
PR-13) genuinely has NOT been seeded — it failed real validation or could
|
|
19
|
-
not be localized into a self-contained package — so the scan below finds
|
|
20
|
-
nothing for it and NO notice is printed; that ``builtin://`` ref still
|
|
21
|
-
resolves through the legacy path. Do not add entries here by hand: a name
|
|
22
|
-
belongs in this table only once ``scripts/seed-global-catalog.py`` has
|
|
23
|
-
actually published + validated its ``simulo/robot/<name>`` catalog entry
|
|
24
|
-
(the script's own ``update_alias_table`` appends here, additively, keyed
|
|
25
|
-
on the SAME name it published under — see that script for the current
|
|
26
|
-
seed report), or the notice would send users to a ref that 404s.
|
|
12
|
+
Every entry was published by the catalog seeding script and passed real
|
|
13
|
+
validation. A builtin that is not here has not, so the scan below prints no
|
|
14
|
+
notice for it and its ``builtin://`` reference still resolves the old way.
|
|
15
|
+
Add entries only after a real publish and validation (the seeding script
|
|
16
|
+
appends them itself); otherwise the notice would send users to a catalog
|
|
17
|
+
reference that does not exist.
|
|
27
18
|
|
|
28
19
|
* :func:`scan_source_for_builtin_aliases` — a textual scan of the packaged source
|
|
29
20
|
files at submit, returning every ``(builtin_name, catalog_ref)`` pair whose
|
|
@@ -45,7 +36,9 @@ from typing import Dict, List, Tuple
|
|
|
45
36
|
BUILTIN_ASSET_ALIASES: Dict[str, str] = {
|
|
46
37
|
"anymal": "simulo/robot/anymal-c",
|
|
47
38
|
"anymal_c": "simulo/robot/anymal-c",
|
|
39
|
+
"cartpole": "simulo/robot/cartpole",
|
|
48
40
|
"h1": "simulo/robot/unitree-h1",
|
|
41
|
+
"humanoid": "simulo/robot/humanoid",
|
|
49
42
|
"jetbot": "simulo/robot/jetbot",
|
|
50
43
|
"pick_and_place": "simulo/robot/pick-and-place",
|
|
51
44
|
"unitree_h1": "simulo/robot/unitree-h1",
|
|
@@ -168,7 +168,7 @@ from simulo._client.asset_package import (
|
|
|
168
168
|
slugify_name,
|
|
169
169
|
validate_asset_name,
|
|
170
170
|
)
|
|
171
|
-
from simulo._client.asset_pins import collect_asset_refs
|
|
171
|
+
from simulo._client.asset_pins import collect_asset_refs, resolve_and_pin_assets
|
|
172
172
|
from simulo._client.builtin_aliases import format_builtin_deprecation_notice, scan_source_for_builtin_aliases
|
|
173
173
|
from simulo._client.bundle import build_manifest
|
|
174
174
|
from simulo._client.cancel_api import CancelApiClient, CancelApiHTTPError
|
|
@@ -673,6 +673,14 @@ def _resolve_client_context() -> tuple[str, Optional[str]]:
|
|
|
673
673
|
return base_url, token
|
|
674
674
|
|
|
675
675
|
|
|
676
|
+
def _client_with_fresh_token(client: JobsApiClient) -> JobsApiClient:
|
|
677
|
+
"""Return a client with current stored credentials, preserving its target."""
|
|
678
|
+
creds = credentials.try_get_valid_credentials(base_url=client.base_url)
|
|
679
|
+
if creds is None:
|
|
680
|
+
return client
|
|
681
|
+
return JobsApiClient(client.base_url, token=str(creds["access_token"]))
|
|
682
|
+
|
|
683
|
+
|
|
676
684
|
def _is_uuid_text(value: Any) -> bool:
|
|
677
685
|
try:
|
|
678
686
|
UUID(str(value))
|
|
@@ -1470,10 +1478,16 @@ def _follow_and_report(handle: JobHandle, app_path: str) -> int:
|
|
|
1470
1478
|
job_ref = str(getattr(handle, "public_id", None) or handle.job_id)
|
|
1471
1479
|
exit_code = _drain_logs(client, job_ref, follow=True, scope=JOB_SCOPE_MINE)
|
|
1472
1480
|
if handle.job_type is JobType.PREVIEW:
|
|
1481
|
+
client = _client_with_fresh_token(client)
|
|
1473
1482
|
return _report_preview(client, job_ref, display_id, app_path, fallback_exit_code=exit_code)
|
|
1474
1483
|
if exit_code == 0:
|
|
1475
1484
|
if handle.job_type is JobType.TRAIN:
|
|
1476
|
-
|
|
1485
|
+
client = _client_with_fresh_token(client)
|
|
1486
|
+
_print_training_next_steps(
|
|
1487
|
+
PoliciesApiClient(client.base_url, token=client._token),
|
|
1488
|
+
handle,
|
|
1489
|
+
app_path,
|
|
1490
|
+
)
|
|
1477
1491
|
elif handle.job_type is JobType.PLAY:
|
|
1478
1492
|
print(f"Next: simulo recordings {display_id}")
|
|
1479
1493
|
return exit_code
|
|
@@ -1566,12 +1580,11 @@ def _checkpoint_iteration(handle: JobHandle, checkpoint_ref: str) -> Optional[in
|
|
|
1566
1580
|
return None
|
|
1567
1581
|
|
|
1568
1582
|
|
|
1569
|
-
def _print_training_next_steps(handle: JobHandle, app_path: str) -> None:
|
|
1583
|
+
def _print_training_next_steps(client: PoliciesApiClient, handle: JobHandle, app_path: str) -> None:
|
|
1570
1584
|
"""Print the sealed policy's checkpoints and the three canonical next steps."""
|
|
1571
|
-
assert handle.base_url is not None
|
|
1572
1585
|
policy_id = str(policy_id_for_job(_handle_display_id(handle)))
|
|
1573
1586
|
try:
|
|
1574
|
-
record =
|
|
1587
|
+
record = client.get_policy(policy_id)
|
|
1575
1588
|
except http.HttpError:
|
|
1576
1589
|
return
|
|
1577
1590
|
rendered: list[str] = []
|
|
@@ -1693,8 +1706,8 @@ def _render_preflight_outcome(app_file: Path, outcome: PreflightOutcome) -> int:
|
|
|
1693
1706
|
|
|
1694
1707
|
|
|
1695
1708
|
def _cmd_prepare(args: argparse.Namespace) -> int:
|
|
1696
|
-
"""``simulo prepare <app>`` — build the manifest
|
|
1697
|
-
whether
|
|
1709
|
+
"""``simulo prepare <app>`` — build the manifest, resolve its assets when
|
|
1710
|
+
authenticated, and ask whether the app would submit cleanly before upload.
|
|
1698
1711
|
|
|
1699
1712
|
Never uploads a package, never creates a job — safe to run as often as
|
|
1700
1713
|
you like before ``simulo run``. It DOES import your app file to discover
|
|
@@ -1710,22 +1723,46 @@ def _cmd_prepare(args: argparse.Namespace) -> int:
|
|
|
1710
1723
|
if not app_file.is_file():
|
|
1711
1724
|
raise SystemExit(f"No such app file: {app_file}")
|
|
1712
1725
|
project_root = app_file.parent
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1726
|
+
with capture_constructed_assets() as captured_assets:
|
|
1727
|
+
app = discover(app_file)
|
|
1728
|
+
if not isinstance(app, App):
|
|
1729
|
+
raise TypeError(f"Discovered object is not a simulo.App: {app!r}")
|
|
1730
|
+
_validate_app_job_file(app, app_file)
|
|
1731
|
+
# Builds the manifest only — no source tree copy, no tar, no upload. The
|
|
1732
|
+
# #285 platform-pinned-package denylist (``build_manifest``'s own
|
|
1733
|
+
# ``SystemExit``) still applies here exactly as it does at `simulo run`;
|
|
1734
|
+
# it is a DIFFERENT, client-side-only mechanism from the preflight HTTP
|
|
1735
|
+
# call below and must never be confused with a preflight finding (see
|
|
1736
|
+
# the preflight API/rendering separation verified by the CLI tests).
|
|
1737
|
+
manifest = build_manifest(app, app_file, project_root, extra_assets=captured_assets)
|
|
1724
1738
|
manifest_data = json.loads(manifest.to_json())
|
|
1725
1739
|
asset_refs = collect_asset_refs(manifest_data)
|
|
1726
|
-
|
|
1740
|
+
try:
|
|
1741
|
+
base_url, token = _resolve_client_context()
|
|
1742
|
+
except credentials.TokenRefreshError as exc:
|
|
1743
|
+
if not _caused_by(exc, http.HttpUnavailable):
|
|
1744
|
+
raise
|
|
1745
|
+
# Asset resolution and preflight are optional checks. Preserve a
|
|
1746
|
+
# rejected refresh as a hard authentication error, while allowing a
|
|
1747
|
+
# network-only refresh failure to use the saved target without sending
|
|
1748
|
+
# the expired bearer.
|
|
1749
|
+
stale_creds = credentials.load_credentials()
|
|
1750
|
+
base_url, token = config.resolve_base_url(stale_creds), None
|
|
1751
|
+
resolved_assets: Optional[list[dict[str, str]]] = [] if not asset_refs else None
|
|
1752
|
+
if asset_refs:
|
|
1753
|
+
if token is None:
|
|
1754
|
+
print("Asset references were not checked.", file=sys.stderr)
|
|
1755
|
+
else:
|
|
1756
|
+
try:
|
|
1757
|
+
resolved_assets = resolve_and_pin_assets(SubmitApiClient(base_url, token=token), asset_refs)
|
|
1758
|
+
except http.HttpUnavailable:
|
|
1759
|
+
print("Asset references were not checked.", file=sys.stderr)
|
|
1760
|
+
except http.HttpHTTPError as exc:
|
|
1761
|
+
if exc.status != 404 and not 500 <= exc.status <= 599:
|
|
1762
|
+
raise
|
|
1763
|
+
print("Asset references were not checked.", file=sys.stderr)
|
|
1727
1764
|
client = PreflightApiClient(base_url, token=token)
|
|
1728
|
-
outcome = client.evaluate(manifest, assets=
|
|
1765
|
+
outcome = client.evaluate(manifest, assets=resolved_assets)
|
|
1729
1766
|
return _render_preflight_outcome(app_file, outcome)
|
|
1730
1767
|
|
|
1731
1768
|
|
|
@@ -2386,6 +2423,7 @@ def _wait_for_job(client: JobsApiClient, job_id: str, *, scope: str = JOB_SCOPE_
|
|
|
2386
2423
|
"""Poll until ``job_id`` exists — lets a user arm the tail BEFORE the job is created."""
|
|
2387
2424
|
waiting_announced = False
|
|
2388
2425
|
while True:
|
|
2426
|
+
client = _client_with_fresh_token(client)
|
|
2389
2427
|
try:
|
|
2390
2428
|
return client.get_job(job_id, scope=scope)
|
|
2391
2429
|
except JobsApiHTTPError as exc:
|
|
@@ -2414,6 +2452,7 @@ def _wait_for_latest_job(client: JobsApiClient) -> dict[str, Any]:
|
|
|
2414
2452
|
"""
|
|
2415
2453
|
waiting_announced = False
|
|
2416
2454
|
while True:
|
|
2455
|
+
client = _client_with_fresh_token(client)
|
|
2417
2456
|
try:
|
|
2418
2457
|
latest = client.get_latest_job()
|
|
2419
2458
|
except JobsApiHTTPError as exc:
|
|
@@ -2608,6 +2647,8 @@ def _drain_logs(
|
|
|
2608
2647
|
post-``simulo run`` default follow — one follow loop, one
|
|
2609
2648
|
exit-code-mirrors-outcome rule.
|
|
2610
2649
|
"""
|
|
2650
|
+
if follow:
|
|
2651
|
+
client = _client_with_fresh_token(client)
|
|
2611
2652
|
offset = 0
|
|
2612
2653
|
if tail_lines is not None:
|
|
2613
2654
|
try:
|
|
@@ -2633,6 +2674,8 @@ def _drain_logs(
|
|
|
2633
2674
|
# Not honored (old server): the loop below simply continues the full
|
|
2634
2675
|
# history from where the server's offset-0 answer left off.
|
|
2635
2676
|
while True:
|
|
2677
|
+
if follow:
|
|
2678
|
+
client = _client_with_fresh_token(client)
|
|
2636
2679
|
try:
|
|
2637
2680
|
chunk, offset, status, _ = client.get_log_chunk(job_id, offset, scope=scope)
|
|
2638
2681
|
except JobsApiHTTPError as exc:
|
|
@@ -2770,9 +2813,9 @@ def _cmd_result(args: argparse.Namespace) -> int:
|
|
|
2770
2813
|
announced on stderr.
|
|
2771
2814
|
A job whose run announced typed outputs gets a second
|
|
2772
2815
|
stderr line, ``⚠ 1 anomaly (non_finite_reward)`` (:func:`_outputs_flag_summary`)
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2816
|
+
while built-in training results omit anomaly-capture paths. Those paths
|
|
2817
|
+
are exposed through the recordings and outputs commands instead. Both
|
|
2818
|
+
lines print to
|
|
2776
2819
|
stderr so stdout stays pure result JSON for pipelines. Best-effort: for
|
|
2777
2820
|
an explicit JOB_ID this needs one extra ``get_job`` call, and a failure
|
|
2778
2821
|
there (e.g. an older control plane) skips both lines rather than failing a
|
|
@@ -2806,6 +2849,13 @@ def _cmd_result(args: argparse.Namespace) -> int:
|
|
|
2806
2849
|
if exc.status == 404:
|
|
2807
2850
|
display_ref = _human_job_ref(job_id)
|
|
2808
2851
|
hint_ref = display_ref if display_ref.startswith("job_") else "<JOB_ID>"
|
|
2852
|
+
if (job_record or {}).get("job_type") == "export":
|
|
2853
|
+
print(
|
|
2854
|
+
f"{_human_job_subject(job_id)} produces a bundle rather than a result. "
|
|
2855
|
+
f"List its outputs with `simulo outputs {hint_ref}`.",
|
|
2856
|
+
file=sys.stderr,
|
|
2857
|
+
)
|
|
2858
|
+
return 1
|
|
2809
2859
|
print(
|
|
2810
2860
|
f"No result for {display_ref}: {_safe_cli_error_text(exc.message)}\n"
|
|
2811
2861
|
"A result exists once the job has finished and returned one — check `simulo jobs` "
|
|
@@ -8085,10 +8135,11 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
8085
8135
|
prepare = sub.add_parser(
|
|
8086
8136
|
"prepare",
|
|
8087
8137
|
help=(
|
|
8088
|
-
"Check a Simulo app against the platform BEFORE submitting it
|
|
8089
|
-
"and
|
|
8090
|
-
"
|
|
8091
|
-
"
|
|
8138
|
+
"Check a Simulo app against the platform BEFORE submitting it. Builds the manifest "
|
|
8139
|
+
"and, when signed in, resolves its catalog asset references before asking whether it "
|
|
8140
|
+
"would work (pip version conflicts, invalid job timeouts, and more). Signed-out or "
|
|
8141
|
+
"unreachable asset checks are reported and skipped. Imports your app file, same as "
|
|
8142
|
+
"`simulo run`. Never uploads anything and never creates a job."
|
|
8092
8143
|
),
|
|
8093
8144
|
)
|
|
8094
8145
|
prepare.add_argument("app_file", help="Path to the Python file declaring the simulo.App.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simulo
|
|
3
|
-
Version: 0.31.
|
|
3
|
+
Version: 0.31.2
|
|
4
4
|
Summary: Python SDK and CLI for cloud-native robotics simulation, reinforcement learning, and robot policy training on managed GPUs.
|
|
5
5
|
Author-email: Simulo Team <team@simulo.ai>
|
|
6
6
|
License: BSD-3-Clause
|
|
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
|