remoteRF-server-testing 0.0.8__tar.gz → 0.0.11__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.
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/PKG-INFO +1 -1
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/pyproject.toml +1 -1
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/device_manager.py +33 -15
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/rpc_manager.py +80 -37
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/serverrf_cli.py +7 -7
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server_testing.egg-info/PKG-INFO +1 -1
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/README.md +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/setup.cfg +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/grpc/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/grpc/grpc_host_pb2.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/grpc/grpc_host_pb2_grpc.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/grpc/grpc_pb2.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/idl/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/idl/device_schema.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/idl/pluto_schema.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/idl/schema.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/utils/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/utils/ansi_codes.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/utils/api_token.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/utils/db_connection.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/utils/db_location.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/utils/list_string.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/common/utils/process_arg.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/drivers/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/drivers/adalm_pluto/pluto_remote_server.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/host/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/host/host_auth_token.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/host/host_directory_store.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/host/host_tunnel_server.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/acc_perms.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/cert_provider.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/grpc_server.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/reservation.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/user_group_cli.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/server/user_group_handler.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/tools/__init__.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/tools/gen_certs.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/tools/gist_status.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/tools/gist_status_testing.py +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server_testing.egg-info/SOURCES.txt +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server_testing.egg-info/dependency_links.txt +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server_testing.egg-info/entry_points.txt +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server_testing.egg-info/requires.txt +0 -0
- {remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server_testing.egg-info/top_level.txt +0 -0
|
@@ -229,6 +229,21 @@ def _host_devices_str_snapshot() -> Dict[int, str]:
|
|
|
229
229
|
def _cfg_dir() -> Path:
|
|
230
230
|
return Path(os.getenv("REMOTERF_CONFIG_DIR", get_remoterf_root()))
|
|
231
231
|
|
|
232
|
+
def _super_token_path() -> Path:
|
|
233
|
+
path = _cfg_dir() / "super_token.txt"
|
|
234
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
235
|
+
path.touch(exist_ok=True)
|
|
236
|
+
return path
|
|
237
|
+
|
|
238
|
+
def _get_master_token() -> str:
|
|
239
|
+
"""Read the configured super token; blank file means the override is disabled."""
|
|
240
|
+
path = _super_token_path()
|
|
241
|
+
try:
|
|
242
|
+
return path.read_text(encoding="utf-8").strip()
|
|
243
|
+
except OSError as e:
|
|
244
|
+
print(f"Warning: could not read super token file {path}: {e}")
|
|
245
|
+
return ""
|
|
246
|
+
|
|
232
247
|
def _devices_yaml_path() -> Path:
|
|
233
248
|
p1 = _cfg_dir() / "devices.yml"
|
|
234
249
|
if p1.exists():
|
|
@@ -316,9 +331,6 @@ def _connect_from_record(rec: Dict[str, Any]):
|
|
|
316
331
|
devices_info: Dict[int, str] = {}
|
|
317
332
|
device_serialization: Dict[int, str] = {}
|
|
318
333
|
|
|
319
|
-
# master token (overrideable)
|
|
320
|
-
master_token = os.getenv("REMOTERF_MASTER_TOKEN", "SuperCoolTokenForIan")
|
|
321
|
-
|
|
322
334
|
def _init_from_env() -> None:
|
|
323
335
|
records = _load_device_records()
|
|
324
336
|
|
|
@@ -378,13 +390,15 @@ def _load_all_drivers() -> None:
|
|
|
378
390
|
|
|
379
391
|
_load_all_drivers()
|
|
380
392
|
_init_from_env()
|
|
393
|
+
_super_token_path()
|
|
381
394
|
|
|
382
395
|
# Legacy reservation helpers (master token parsing)
|
|
383
396
|
|
|
384
|
-
def parse_mastertoken(token: str):
|
|
385
|
-
if
|
|
397
|
+
def parse_mastertoken(token: str, configured_token: Optional[str] = None):
|
|
398
|
+
configured_token = _get_master_token() if configured_token is None else configured_token
|
|
399
|
+
if not token or not configured_token:
|
|
386
400
|
return None
|
|
387
|
-
prefix = re.escape(
|
|
401
|
+
prefix = re.escape(configured_token)
|
|
388
402
|
pattern = re.compile(rf"^{prefix}[_-](\d+)(?:_force)?$")
|
|
389
403
|
m = pattern.match(token)
|
|
390
404
|
if not m:
|
|
@@ -528,15 +542,16 @@ def get_schema_by_token(api_token: str):
|
|
|
528
542
|
|
|
529
543
|
_sync_host_devices()
|
|
530
544
|
gid: Optional[int] = None
|
|
545
|
+
configured_token = _get_master_token()
|
|
531
546
|
|
|
532
|
-
if api_token ==
|
|
547
|
+
if configured_token and api_token == configured_token:
|
|
533
548
|
with _state_lock:
|
|
534
549
|
for k, st in _devices.items():
|
|
535
550
|
if st.origin == "local" and _is_connected(st) and st.salt == "" and st.hsh == "":
|
|
536
551
|
gid = k
|
|
537
552
|
break
|
|
538
553
|
else:
|
|
539
|
-
parsed = parse_mastertoken(api_token)
|
|
554
|
+
parsed = parse_mastertoken(api_token, configured_token=configured_token)
|
|
540
555
|
if parsed:
|
|
541
556
|
cand, _ = parsed
|
|
542
557
|
with _state_lock:
|
|
@@ -577,9 +592,10 @@ def resolve_gid_for_token(api_token: str) -> Optional[int]:
|
|
|
577
592
|
return None
|
|
578
593
|
|
|
579
594
|
_sync_host_devices()
|
|
595
|
+
configured_token = _get_master_token()
|
|
580
596
|
|
|
581
597
|
# Parsed master-token: resolves any device directly by gid (local or host).
|
|
582
|
-
parsed = parse_mastertoken(api_token)
|
|
598
|
+
parsed = parse_mastertoken(api_token, configured_token=configured_token)
|
|
583
599
|
if parsed:
|
|
584
600
|
cand, _ = parsed
|
|
585
601
|
with _state_lock:
|
|
@@ -589,7 +605,7 @@ def resolve_gid_for_token(api_token: str) -> Optional[int]:
|
|
|
589
605
|
return None
|
|
590
606
|
|
|
591
607
|
# Raw master token — prefer local, fall back to any connected device.
|
|
592
|
-
if api_token ==
|
|
608
|
+
if configured_token and api_token == configured_token:
|
|
593
609
|
with _state_lock:
|
|
594
610
|
# local first
|
|
595
611
|
for k, st in _devices.items():
|
|
@@ -630,6 +646,7 @@ def get_device(*, api_token: str):
|
|
|
630
646
|
return None
|
|
631
647
|
|
|
632
648
|
_sync_host_devices()
|
|
649
|
+
configured_token = _get_master_token()
|
|
633
650
|
|
|
634
651
|
with _state_lock:
|
|
635
652
|
snapshot: List[Tuple[int, object, str, str, str]] = [
|
|
@@ -639,7 +656,7 @@ def get_device(*, api_token: str):
|
|
|
639
656
|
]
|
|
640
657
|
|
|
641
658
|
# Preserve "master prefers local" behavior
|
|
642
|
-
if api_token ==
|
|
659
|
+
if configured_token and api_token == configured_token:
|
|
643
660
|
# local first
|
|
644
661
|
for _, dev, salt, hsh, origin in snapshot:
|
|
645
662
|
if origin == "local" and dev is not None and salt == "" and hsh == "":
|
|
@@ -650,7 +667,7 @@ def get_device(*, api_token: str):
|
|
|
650
667
|
return dev
|
|
651
668
|
return None
|
|
652
669
|
|
|
653
|
-
parsed = parse_mastertoken(api_token)
|
|
670
|
+
parsed = parse_mastertoken(api_token, configured_token=configured_token)
|
|
654
671
|
if parsed:
|
|
655
672
|
device_id, force = parsed
|
|
656
673
|
with _state_lock:
|
|
@@ -679,8 +696,9 @@ def acquire_device(api_token: str) -> Iterator[Tuple[int, object]]:
|
|
|
679
696
|
_sync_host_devices()
|
|
680
697
|
|
|
681
698
|
gid: Optional[int] = None
|
|
699
|
+
configured_token = _get_master_token()
|
|
682
700
|
|
|
683
|
-
if api_token ==
|
|
701
|
+
if configured_token and api_token == configured_token:
|
|
684
702
|
with _state_lock:
|
|
685
703
|
# prefer local first
|
|
686
704
|
for k, st in _devices.items():
|
|
@@ -693,7 +711,7 @@ def acquire_device(api_token: str) -> Iterator[Tuple[int, object]]:
|
|
|
693
711
|
gid = k
|
|
694
712
|
break
|
|
695
713
|
else:
|
|
696
|
-
parsed = parse_mastertoken(api_token)
|
|
714
|
+
parsed = parse_mastertoken(api_token, configured_token=configured_token)
|
|
697
715
|
if parsed:
|
|
698
716
|
cand, force = parsed
|
|
699
717
|
with _state_lock:
|
|
@@ -790,4 +808,4 @@ def reload_devices() -> None:
|
|
|
790
808
|
|
|
791
809
|
def set_pluto(ip: str = "192.168.2.1"):
|
|
792
810
|
# kept for compatibility (no-op)
|
|
793
|
-
pass
|
|
811
|
+
pass
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
|
|
53
53
|
from .reservation import reservation_handler
|
|
54
54
|
from ..common.utils import *
|
|
55
|
-
from .
|
|
55
|
+
from ..common.grpc import grpc_pb2 as generic_pb2
|
|
56
|
+
from .device_manager import acquire_device, VirtualDevice, get_device_schema, find_device_id_by_name, get_device_by_id, resolve_gid_for_token
|
|
56
57
|
from ..host import host_tunnel_server as hts
|
|
57
58
|
|
|
58
59
|
|
|
@@ -181,6 +182,71 @@ class RpcManager:
|
|
|
181
182
|
|
|
182
183
|
raise ValueError(f"Unknown verb {verb!r} in {function_name!r}")
|
|
183
184
|
|
|
185
|
+
def _resolve_idl_target(self, args: dict) -> tuple[int | None, str | None]:
|
|
186
|
+
if 'token' in args:
|
|
187
|
+
api_token = str(unmap_arg(args['token']))
|
|
188
|
+
gid = resolve_gid_for_token(api_token)
|
|
189
|
+
if gid is None:
|
|
190
|
+
return None, 'No schema available for this token (invalid token or device offline)'
|
|
191
|
+
return gid, None
|
|
192
|
+
|
|
193
|
+
if 'device_id' in args:
|
|
194
|
+
try:
|
|
195
|
+
return int(unmap_arg(args['device_id'])), None
|
|
196
|
+
except (ValueError, TypeError):
|
|
197
|
+
return None, 'device_id must be an integer'
|
|
198
|
+
|
|
199
|
+
if 'device_name' in args:
|
|
200
|
+
name = str(unmap_arg(args['device_name']))
|
|
201
|
+
gid = find_device_id_by_name(name)
|
|
202
|
+
if gid is None:
|
|
203
|
+
return None, f'No device found with name {name!r}'
|
|
204
|
+
return gid, None
|
|
205
|
+
|
|
206
|
+
return None, 'IDL:get_drivers requires token, device_id, or device_name'
|
|
207
|
+
|
|
208
|
+
def _fetch_host_idl(self, *, gid: int, dev: VirtualDevice, args: dict) -> dict:
|
|
209
|
+
registry = hts.get_tunnel_registry(create=False)
|
|
210
|
+
if registry is None:
|
|
211
|
+
return {'error': map_arg('Host tunnel registry unavailable')}
|
|
212
|
+
|
|
213
|
+
req = generic_pb2.GenericRPCRequest(function_name="IDL:get_drivers")
|
|
214
|
+
for key, value in dict(args).items():
|
|
215
|
+
if str(key) == "token":
|
|
216
|
+
continue
|
|
217
|
+
req.args[str(key)].CopyFrom(value)
|
|
218
|
+
req.args["device_id"].CopyFrom(map_arg(int(gid)))
|
|
219
|
+
req.args["g"].CopyFrom(map_arg(int(gid)))
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
resp = hts.handle_host_device_request(
|
|
223
|
+
registry,
|
|
224
|
+
host_id=dev.host_id,
|
|
225
|
+
device_id=dev.device_id,
|
|
226
|
+
request=req,
|
|
227
|
+
timeout_sec=10.0,
|
|
228
|
+
)
|
|
229
|
+
except Exception as e:
|
|
230
|
+
return {'error': map_arg(str(e))}
|
|
231
|
+
|
|
232
|
+
results = dict(resp.results)
|
|
233
|
+
if 'error' in results:
|
|
234
|
+
return results
|
|
235
|
+
|
|
236
|
+
err = results.get('Error')
|
|
237
|
+
if err is not None:
|
|
238
|
+
return {'error': map_arg(str(unmap_arg(err)))}
|
|
239
|
+
|
|
240
|
+
ok = results.get('Ok')
|
|
241
|
+
if ok is not None:
|
|
242
|
+
try:
|
|
243
|
+
if not bool(unmap_arg(ok)):
|
|
244
|
+
return {'error': map_arg('Host schema fetch failed')}
|
|
245
|
+
except Exception:
|
|
246
|
+
return {'error': map_arg('Host schema fetch failed')}
|
|
247
|
+
|
|
248
|
+
return results
|
|
249
|
+
|
|
184
250
|
def _handle_idl(self, sub: str, args: dict) -> dict:
|
|
185
251
|
"""
|
|
186
252
|
IDL:get_drivers → schema + driver metadata for a device.
|
|
@@ -196,42 +262,19 @@ class RpcManager:
|
|
|
196
262
|
device_type str e.g. "pluto"
|
|
197
263
|
"""
|
|
198
264
|
if sub == "get_drivers":
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if schema is None:
|
|
213
|
-
return {'error': map_arg('No schema available for this token (invalid token or device offline)')}
|
|
214
|
-
|
|
215
|
-
elif 'device_id' in args:
|
|
216
|
-
try:
|
|
217
|
-
gid = int(unmap_arg(args['device_id']))
|
|
218
|
-
except (ValueError, TypeError):
|
|
219
|
-
return {'error': map_arg('device_id must be an integer')}
|
|
220
|
-
schema = get_device_schema(gid)
|
|
221
|
-
if schema is None:
|
|
222
|
-
return {'error': map_arg(f'No schema available for device {gid} (offline or host device)')}
|
|
223
|
-
|
|
224
|
-
elif 'device_name' in args:
|
|
225
|
-
name = str(unmap_arg(args['device_name']))
|
|
226
|
-
gid = find_device_id_by_name(name)
|
|
227
|
-
if gid is None:
|
|
228
|
-
return {'error': map_arg(f'No device found with name {name!r}')}
|
|
229
|
-
schema = get_device_schema(gid)
|
|
230
|
-
if schema is None:
|
|
231
|
-
return {'error': map_arg(f'No schema available for device {name!r} (offline or host device)')}
|
|
232
|
-
|
|
233
|
-
else:
|
|
234
|
-
return {'error': map_arg('IDL:get_drivers requires token, device_id, or device_name')}
|
|
265
|
+
gid, err = self._resolve_idl_target(args)
|
|
266
|
+
if err is not None or gid is None:
|
|
267
|
+
return {'error': map_arg(err or 'Unable to resolve device')}
|
|
268
|
+
|
|
269
|
+
resolved = get_device_by_id(gid)
|
|
270
|
+
dev = resolved[0] if resolved is not None else None
|
|
271
|
+
|
|
272
|
+
if isinstance(dev, VirtualDevice):
|
|
273
|
+
return self._fetch_host_idl(gid=gid, dev=dev, args=args)
|
|
274
|
+
|
|
275
|
+
schema = get_device_schema(gid)
|
|
276
|
+
if schema is None:
|
|
277
|
+
return {'error': map_arg(f'No schema available for device {gid} (offline)')}
|
|
235
278
|
|
|
236
279
|
return {
|
|
237
280
|
'schema': map_arg(schema.get_idl_json()),
|
{remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/serverrf_cli.py
RENAMED
|
@@ -186,13 +186,13 @@ def print_help() -> None:
|
|
|
186
186
|
" serverrf --host --show\n"
|
|
187
187
|
" serverrf --host --delete lab-host-01\n"
|
|
188
188
|
" serverrf --host --wipe -y\n"
|
|
189
|
-
"\n"
|
|
190
|
-
" serverrf --device --add --pluto 0:pluto_aaa:123123\n"
|
|
191
|
-
" serverrf --device --edit-name 0 \"New Pluto Name\"\n"
|
|
192
|
-
" serverrf --device --remove 0\n"
|
|
193
|
-
" serverrf --device --show\n"
|
|
194
|
-
" serverrf --device --wipe -y\n"
|
|
195
|
-
"\n"
|
|
189
|
+
# "\n"
|
|
190
|
+
# " serverrf --device --add --pluto 0:pluto_aaa:123123\n"
|
|
191
|
+
# " serverrf --device --edit-name 0 \"New Pluto Name\"\n"
|
|
192
|
+
# " serverrf --device --remove 0\n"
|
|
193
|
+
# " serverrf --device --show\n"
|
|
194
|
+
# " serverrf --device --wipe -y\n"
|
|
195
|
+
# "\n"
|
|
196
196
|
" serverrf -s\n"
|
|
197
197
|
" serverrf --serve\n"
|
|
198
198
|
"\n"
|
|
File without changes
|
|
File without changes
|
{remoterf_server_testing-0.0.8 → remoterf_server_testing-0.0.11}/src/remoteRF_server/__init__.py
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
|