python-mobius 0.10.1__tar.gz → 0.10.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.
- {python_mobius-0.10.1 → python_mobius-0.10.2}/CHANGELOG.md +5 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/PKG-INFO +1 -1
- {python_mobius-0.10.1 → python_mobius-0.10.2}/pyproject.toml +1 -1
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/__init__.py +1 -1
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/device.py +38 -9
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_networked_thread_devices.py +65 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/.forgejo/scripts/extract_changelog_section.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/.forgejo/workflows/release.yml +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/.gitignore +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/LICENSE +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/README.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/00-overview.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/01-ble-transport.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/02-framing-and-crc.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/03-attributes-and-opcodes.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/04-device-identity.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/05-scenes.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/06-light-schedule.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/07-pump-schedule.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/08-manufacturer-data.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/09-thread-coap-relay.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/10-known-gaps-and-open-questions.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/11-device-status-attributes.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/12-device-identity-and-address-stability.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/13-attribute-dump.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/14-attribute-reference.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/15-mob-template-format.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/16-python-library.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/17-configuration-checksums.md +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/checksums.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/cli.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/coap.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/constants.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/crc.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/device_status.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/discovery.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/dump.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/frame.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/manufacturer.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/mesh_address.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/mob.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/modifiers.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/power.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/pump_status.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/relay.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/scenes.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/schedule.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/src/mobius/timezone.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_attributes_batch.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_battery_settings.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_bluetooth_only.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_checksums.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_cli_group_targets.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_cli_mob_file.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_cli_schedule_file.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_coap.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_coap_indication_handling.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_configuration_cache.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_connection_cleanup.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_device_control.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_device_status.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_device_summary.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_device_time.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_discovery_company_ids.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_dump.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_extra_physical_values.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_fan_thresholds.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_firmware_versions.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_frame.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_frame_sniffer.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_full_poll_batch.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_group_bitmap.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_hyperdrive_device.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_insolation_detection.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_light_intensity_branching.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_light_poll_batch.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_light_schedule.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_manufacturer.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_manufacturer_lookup.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_mesh_address.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_mesh_discovery.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_mesh_discovery_direct_connect.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_metadata_batch.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_mob.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_modifiers.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_new_diagnostic_attributes.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_power.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_pump_param_ranges.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_pump_reverse.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_pump_schedule.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_pump_status.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_pump_supported_modes.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_pump_telemetry.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_relay.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_scenes.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_schedule_file_format.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_schedule_intensity_scalar.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_serial_decoding.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_serial_identity.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_shared_helpers.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_supported_attributes.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_time_zone.py +0 -0
- {python_mobius-0.10.1 → python_mobius-0.10.2}/tests/test_write_size.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: python-mobius
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.2
|
|
4
4
|
Summary: Reverse-engineered Python client for the Mobius BLE protocol (EcoTech Marine VorTech/Radion, AquaIllumination, Neptune Systems, NYOS)
|
|
5
5
|
Project-URL: Homepage, https://code.r3pek.org/r3pek/python-mobius
|
|
6
6
|
Project-URL: Documentation, https://code.r3pek.org/r3pek/python-mobius/src/branch/main/documentation
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-mobius"
|
|
7
|
-
version = "0.10.
|
|
7
|
+
version = "0.10.2"
|
|
8
8
|
description = "Reverse-engineered Python client for the Mobius BLE protocol (EcoTech Marine VorTech/Radion, AquaIllumination, Neptune Systems, NYOS)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "GPL-2.0-only" }
|
|
@@ -1842,7 +1842,7 @@ class MobiusDevice:
|
|
|
1842
1842
|
return None
|
|
1843
1843
|
return raw
|
|
1844
1844
|
|
|
1845
|
-
async def discover_mesh_peers(self) -> list[MeshPeer]:
|
|
1845
|
+
async def discover_mesh_peers(self, raise_errors: bool = False) -> list[MeshPeer]:
|
|
1846
1846
|
"""
|
|
1847
1847
|
Mesh peers from the ShortAddressArray/SerialNumberArray/
|
|
1848
1848
|
DeviceModelArray (3700/3701/3702) parallel arrays, with addresses
|
|
@@ -1852,10 +1852,12 @@ class MobiusDevice:
|
|
|
1852
1852
|
UnsupportedAttribute and this returns []. Whether the connected
|
|
1853
1853
|
device lists itself is not known. Empty slots (serial
|
|
1854
1854
|
"00000000000000") and short entries are skipped. Returns [] on any
|
|
1855
|
-
failure.
|
|
1855
|
+
failure, or raises it with raise_errors=True.
|
|
1856
1856
|
"""
|
|
1857
1857
|
own_address = await self.get_own_mesh_address()
|
|
1858
1858
|
if own_address is None:
|
|
1859
|
+
if raise_errors:
|
|
1860
|
+
raise IOError("own mesh address (MeshLocalAddresses) not readable")
|
|
1859
1861
|
return []
|
|
1860
1862
|
prefix = mesh_local_prefix_from_own_address(own_address)
|
|
1861
1863
|
|
|
@@ -1864,6 +1866,8 @@ class MobiusDevice:
|
|
|
1864
1866
|
models_raw = await self.get_attribute(C2Attribute.DeviceModelArray, index=0, count=ALL_ELEMENTS)
|
|
1865
1867
|
shorts_raw = await self.get_attribute(C2Attribute.ShortAddressArray, index=0, count=ALL_ELEMENTS)
|
|
1866
1868
|
except Exception:
|
|
1869
|
+
if raise_errors:
|
|
1870
|
+
raise
|
|
1867
1871
|
return []
|
|
1868
1872
|
|
|
1869
1873
|
peers: list[MeshPeer] = []
|
|
@@ -1882,7 +1886,7 @@ class MobiusDevice:
|
|
|
1882
1886
|
))
|
|
1883
1887
|
return peers
|
|
1884
1888
|
|
|
1885
|
-
async def discover_networked_thread_devices(self) -> list[MeshPeer]:
|
|
1889
|
+
async def discover_networked_thread_devices(self, raise_errors: bool = False) -> list[MeshPeer]:
|
|
1886
1890
|
"""
|
|
1887
1891
|
Every device on this device's Thread mesh, including itself, from
|
|
1888
1892
|
MLPrefix (2128) and NetworkedThreadDevices (1001). Supported more
|
|
@@ -1896,7 +1900,8 @@ class MobiusDevice:
|
|
|
1896
1900
|
12-13 model id, i16 LE
|
|
1897
1901
|
14-27 serial, ASCII
|
|
1898
1902
|
Empty slots are all zeros and are skipped, as are entries of any
|
|
1899
|
-
other length. Returns [] on any failure
|
|
1903
|
+
other length. Returns [] on any failure, or raises it with
|
|
1904
|
+
raise_errors=True.
|
|
1900
1905
|
"""
|
|
1901
1906
|
try:
|
|
1902
1907
|
mlprefix_raw = await self.get_attribute(C2Attribute.MLPrefix)
|
|
@@ -1904,8 +1909,15 @@ class MobiusDevice:
|
|
|
1904
1909
|
C2Attribute.NetworkedThreadDevices, index=0, count=ALL_ELEMENTS,
|
|
1905
1910
|
)
|
|
1906
1911
|
except Exception:
|
|
1912
|
+
if raise_errors:
|
|
1913
|
+
raise
|
|
1907
1914
|
return []
|
|
1908
1915
|
if not mlprefix_raw or len(mlprefix_raw[0]) != 24:
|
|
1916
|
+
if raise_errors:
|
|
1917
|
+
raise IOError(
|
|
1918
|
+
f"unexpected MLPrefix: {mlprefix_raw[0].hex() if mlprefix_raw else 'empty'} "
|
|
1919
|
+
f"(expected 24 bytes)"
|
|
1920
|
+
)
|
|
1909
1921
|
return []
|
|
1910
1922
|
prefix = mesh_local_prefix_from_mlprefix(mlprefix_raw[0])
|
|
1911
1923
|
|
|
@@ -1928,18 +1940,35 @@ class MobiusDevice:
|
|
|
1928
1940
|
))
|
|
1929
1941
|
return peers
|
|
1930
1942
|
|
|
1931
|
-
async def discover_mesh_peers_auto(self) -> list[MeshPeer]:
|
|
1943
|
+
async def discover_mesh_peers_auto(self, raise_errors: bool = False) -> list[MeshPeer]:
|
|
1932
1944
|
"""
|
|
1933
1945
|
discover_networked_thread_devices(), falling back to
|
|
1934
1946
|
discover_mesh_peers() when it finds nothing. The recommended entry
|
|
1935
1947
|
point. mobius.discovery.discover_mesh_peers_via_direct_connect() is
|
|
1936
1948
|
the remaining fallback, but it needs scan results and has to be
|
|
1937
1949
|
called explicitly.
|
|
1950
|
+
|
|
1951
|
+
raise_errors=True: a failure raises instead of looking like an
|
|
1952
|
+
empty mesh. The fallback is then only tried when
|
|
1953
|
+
NetworkedThreadDevices can't be read (an MXM hub), and the error
|
|
1954
|
+
raised names both attempts.
|
|
1938
1955
|
"""
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1956
|
+
if not raise_errors:
|
|
1957
|
+
peers = await self.discover_networked_thread_devices()
|
|
1958
|
+
if peers:
|
|
1959
|
+
return peers
|
|
1960
|
+
return await self.discover_mesh_peers()
|
|
1961
|
+
|
|
1962
|
+
try:
|
|
1963
|
+
return await self.discover_networked_thread_devices(raise_errors=True)
|
|
1964
|
+
except Exception as networked_error:
|
|
1965
|
+
try:
|
|
1966
|
+
return await self.discover_mesh_peers(raise_errors=True)
|
|
1967
|
+
except Exception as arrays_error:
|
|
1968
|
+
raise IOError(
|
|
1969
|
+
f"NetworkedThreadDevices: {networked_error or type(networked_error).__name__}; "
|
|
1970
|
+
f"peer arrays: {arrays_error or type(arrays_error).__name__}"
|
|
1971
|
+
) from networked_error
|
|
1943
1972
|
|
|
1944
1973
|
async def get_firmware_versions(self, model: Optional[Model] = None) -> dict:
|
|
1945
1974
|
"""{label: version} for every firmware component (FirmwareVersion,
|
|
@@ -328,3 +328,68 @@ async def test_discover_networked_thread_devices_real_hardware_capture():
|
|
|
328
328
|
assert p.model == Model.RadionXR15wG6Pro
|
|
329
329
|
assert p.age == 8490
|
|
330
330
|
assert p.short_address == 0x0400
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@pytest.mark.asyncio
|
|
334
|
+
async def test_raise_errors_reports_a_failed_read_instead_of_an_empty_mesh():
|
|
335
|
+
device = MobiusDevice(_fake_ble_device())
|
|
336
|
+
|
|
337
|
+
async def fake_get_attribute(attr_id, index=0, count=1):
|
|
338
|
+
raise IOError("timed out")
|
|
339
|
+
|
|
340
|
+
device.get_attribute = fake_get_attribute
|
|
341
|
+
|
|
342
|
+
assert await device.discover_networked_thread_devices() == []
|
|
343
|
+
with pytest.raises(IOError, match="timed out"):
|
|
344
|
+
await device.discover_networked_thread_devices(raise_errors=True)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
@pytest.mark.asyncio
|
|
348
|
+
async def test_raise_errors_reports_an_unexpected_mlprefix():
|
|
349
|
+
device = MobiusDevice(_fake_ble_device())
|
|
350
|
+
|
|
351
|
+
async def fake_get_attribute(attr_id, index=0, count=1):
|
|
352
|
+
if attr_id == C2Attribute.MLPrefix:
|
|
353
|
+
return [PREFIX] # 8 bytes instead of 24
|
|
354
|
+
return []
|
|
355
|
+
|
|
356
|
+
device.get_attribute = fake_get_attribute
|
|
357
|
+
|
|
358
|
+
with pytest.raises(IOError, match="unexpected MLPrefix"):
|
|
359
|
+
await device.discover_networked_thread_devices(raise_errors=True)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
@pytest.mark.asyncio
|
|
363
|
+
async def test_auto_with_raise_errors_names_both_attempts_when_both_fail():
|
|
364
|
+
device = MobiusDevice(_fake_ble_device())
|
|
365
|
+
|
|
366
|
+
async def fake_get_attribute(attr_id, index=0, count=1):
|
|
367
|
+
raise IOError(f"no answer for {int(attr_id)}")
|
|
368
|
+
|
|
369
|
+
async def no_own_address():
|
|
370
|
+
return None
|
|
371
|
+
|
|
372
|
+
device.get_attribute = fake_get_attribute
|
|
373
|
+
device.get_own_mesh_address = no_own_address
|
|
374
|
+
|
|
375
|
+
assert await device.discover_mesh_peers_auto() == []
|
|
376
|
+
with pytest.raises(IOError, match=r"NetworkedThreadDevices: no answer for 2128; peer arrays: own mesh address"):
|
|
377
|
+
await device.discover_mesh_peers_auto(raise_errors=True)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
@pytest.mark.asyncio
|
|
381
|
+
async def test_auto_with_raise_errors_returns_networked_devices():
|
|
382
|
+
device = MobiusDevice(_fake_ble_device())
|
|
383
|
+
suffix = bytes.fromhex("000000fffe00") + struct.pack("<H", 0x1234)
|
|
384
|
+
|
|
385
|
+
async def fake_get_attribute(attr_id, index=0, count=1):
|
|
386
|
+
if attr_id == C2Attribute.MLPrefix:
|
|
387
|
+
return [MLPREFIX_RAW]
|
|
388
|
+
if attr_id == C2Attribute.NetworkedThreadDevices:
|
|
389
|
+
return [_entry(suffix, 42, Model.VorTechMP40wG3QD, "00000000000001")]
|
|
390
|
+
raise AssertionError("the peer arrays must not be read")
|
|
391
|
+
|
|
392
|
+
device.get_attribute = fake_get_attribute
|
|
393
|
+
|
|
394
|
+
peers = await device.discover_mesh_peers_auto(raise_errors=True)
|
|
395
|
+
assert [p.serial for p in peers] == ["00000000000001"]
|
|
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
|
{python_mobius-0.10.1 → python_mobius-0.10.2}/documentation/10-known-gaps-and-open-questions.md
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
|