ka9q-python 3.12.0__tar.gz → 3.13.0__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.
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/CHANGELOG.md +37 -0
- {ka9q_python-3.12.0/ka9q_python.egg-info → ka9q_python-3.13.0}/PKG-INFO +1 -1
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/__init__.py +1 -1
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/multi_stream.py +32 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0/ka9q_python.egg-info}/PKG-INFO +1 -1
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/pyproject.toml +1 -1
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_lifetime.py +88 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/LICENSE +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/MANIFEST.in +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/README.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/API_REFERENCE.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/ARCHITECTURE.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/CLI_GUIDE.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/GETTING_STARTED.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/INSTALLATION.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/MULTI_STREAM.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/RECIPES.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/RTP_TIMING_SUPPORT.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/SECURITY.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/TESTING_GUIDE.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/docs/TUI_GUIDE.md +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/advanced_features_demo.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/channel_cleanup_example.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/codar_oceanography.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/diagnostics/diagnose_packets.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/diagnostics/repro_utc_bug.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/discover_example.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/grape_integration_example.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/hf_band_scanner.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/multi_stream_smoke.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/rtp_recorder_example.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/simple_am_radio.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/spectrum_example.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/stream_example.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/superdarn_recorder.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/test_channel_operations.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/test_improvements.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/test_timing_fields.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/tune.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/examples/tune_example.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/addressing.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/cli.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/compat.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/control.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/discovery.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/exceptions.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/managed_stream.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/monitor.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/pps_calibrator.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/resequencer.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/rtp_recorder.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/spectrum_stream.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/status.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/stream.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/stream_quality.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/tui.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/types.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q/utils.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q_python.egg-info/SOURCES.txt +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q_python.egg-info/dependency_links.txt +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q_python.egg-info/entry_points.txt +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q_python.egg-info/requires.txt +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q_python.egg-info/top_level.txt +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/ka9q_radio_compat +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/scripts/check_upstream_drift.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/scripts/sync_types.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/setup.cfg +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/setup.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/__init__.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/conftest.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_addressing.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_channel_verification.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_create_split_encoding.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_decode_description.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_decode_functions.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_encode_functions.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_encode_socket.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_ensure_channel_encoding.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_filter_edges.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_integration.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_iq_20khz_f32.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_listen_multicast.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_managed_stream_recovery.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_monitor.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_multihomed.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_native_discovery.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_performance_fixes.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_protocol_compat.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_remove_channel.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_rtp_recorder.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_security_features.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_spectrum.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_ssrc_dest_unit.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_ssrc_encoding_unit.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_ssrc_radiod_host_unit.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_status_decoder.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_ttl_warning.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_tune.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_tune_cli.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_tune_debug.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_tune_live.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_tune_method.py +0 -0
- {ka9q_python-3.12.0 → ka9q_python-3.13.0}/tests/test_upstream_drift.py +0 -0
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.13.0] - 2026-05-08
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`MultiStream` channel-lifetime support**: closes the gap from 3.10.0 where
|
|
8
|
+
`RadiodControl.{create_channel,ensure_channel,tune}` accepted a `lifetime=`
|
|
9
|
+
kwarg but `MultiStream.add_channel()` did not, leaving MultiStream-based
|
|
10
|
+
clients (psk-recorder, hfdl-recorder, hf-timestd) unable to opt into
|
|
11
|
+
radiod's channel self-destruct timer for crash-resilient cleanup.
|
|
12
|
+
- `MultiStream.add_channel(..., lifetime=None)` — optional kwarg, forwarded
|
|
13
|
+
to the internal `ensure_channel` call. Stored per-slot.
|
|
14
|
+
- **Drop/restore path now re-applies lifetime**: `_attempt_restore` reads
|
|
15
|
+
the stored slot lifetime and passes it to `ensure_channel`. Previously,
|
|
16
|
+
a channel that radiod self-destructed and MultiStream restored would
|
|
17
|
+
silently lose its LIFETIME until the next external keep-alive — the
|
|
18
|
+
most dangerous failure mode now closed.
|
|
19
|
+
- `MultiStream.set_channel_lifetime(ssrc, lifetime)` — keep-alive method
|
|
20
|
+
that updates both the wire (via `RadiodControl.set_channel_lifetime`)
|
|
21
|
+
and the slot's stored lifetime, so the value survives subsequent
|
|
22
|
+
drop/restore cycles.
|
|
23
|
+
|
|
24
|
+
### Backward Compatibility
|
|
25
|
+
|
|
26
|
+
- Default behavior unchanged: omitting `lifetime` produces a packet with no
|
|
27
|
+
LIFETIME tag (ChannelSlot.lifetime defaults to None). Existing MultiStream
|
|
28
|
+
callers see no change in wire behavior.
|
|
29
|
+
|
|
30
|
+
### Tests
|
|
31
|
+
|
|
32
|
+
- 5 new unit tests in `tests/test_lifetime.py::TestMultiStreamLifetime` cover:
|
|
33
|
+
forward-on-add, lifetime=None default, restore-reapplies-lifetime,
|
|
34
|
+
set_channel_lifetime updates slot+wire, set_channel_lifetime is a no-op for
|
|
35
|
+
unknown SSRC. 258 unit tests still green.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
|
|
3
40
|
## [3.12.0] - 2026-05-07
|
|
4
41
|
|
|
5
42
|
### Added
|
|
@@ -81,6 +81,7 @@ class _ChannelSlot:
|
|
|
81
81
|
last_packet_time: float = 0.0
|
|
82
82
|
dropped: bool = False
|
|
83
83
|
first_rtp_timestamp: Optional[int] = None
|
|
84
|
+
lifetime: Optional[int] = None
|
|
84
85
|
|
|
85
86
|
|
|
86
87
|
class MultiStream:
|
|
@@ -132,6 +133,7 @@ class MultiStream:
|
|
|
132
133
|
low_edge: Optional[float] = None,
|
|
133
134
|
high_edge: Optional[float] = None,
|
|
134
135
|
kaiser_beta: Optional[float] = None,
|
|
136
|
+
lifetime: Optional[int] = None,
|
|
135
137
|
) -> ChannelInfo:
|
|
136
138
|
"""Provision a channel and register it for reception.
|
|
137
139
|
|
|
@@ -142,6 +144,15 @@ class MultiStream:
|
|
|
142
144
|
preset's default passband. None = use preset defaults. See
|
|
143
145
|
RadiodControl.ensure_channel for the full semantics.
|
|
144
146
|
|
|
147
|
+
``lifetime`` opts the channel into radiod's self-destruct timer
|
|
148
|
+
(radiod commit 0f8b622+, see RadiodControl.set_channel_lifetime).
|
|
149
|
+
The value is stored per-slot so the drop/restore path re-applies
|
|
150
|
+
it: a channel that radiod self-destructs and we then restore
|
|
151
|
+
won't silently lose its lifetime. The caller is still
|
|
152
|
+
responsible for periodic keep-alive via
|
|
153
|
+
``set_channel_lifetime()`` (or by calling
|
|
154
|
+
RadiodControl.set_channel_lifetime directly on the SSRC).
|
|
155
|
+
|
|
145
156
|
Returns the ChannelInfo from ensure_channel().
|
|
146
157
|
"""
|
|
147
158
|
channel_info = self._control.ensure_channel(
|
|
@@ -154,6 +165,7 @@ class MultiStream:
|
|
|
154
165
|
low_edge=low_edge,
|
|
155
166
|
high_edge=high_edge,
|
|
156
167
|
kaiser_beta=kaiser_beta,
|
|
168
|
+
lifetime=lifetime,
|
|
157
169
|
)
|
|
158
170
|
|
|
159
171
|
addr = channel_info.multicast_address
|
|
@@ -189,6 +201,7 @@ class MultiStream:
|
|
|
189
201
|
on_stream_dropped=on_stream_dropped,
|
|
190
202
|
on_stream_restored=on_stream_restored,
|
|
191
203
|
deliver_interval=self._deliver_interval,
|
|
204
|
+
lifetime=lifetime,
|
|
192
205
|
)
|
|
193
206
|
self._slots[ssrc] = slot
|
|
194
207
|
|
|
@@ -224,6 +237,24 @@ class MultiStream:
|
|
|
224
237
|
f"{self._multicast_address}:{self._port}"
|
|
225
238
|
)
|
|
226
239
|
|
|
240
|
+
def set_channel_lifetime(self, ssrc: int, lifetime: int) -> None:
|
|
241
|
+
"""Refresh the LIFETIME tag on one channel and update slot state.
|
|
242
|
+
|
|
243
|
+
Suitable as a periodic keep-alive: callers should invoke this on
|
|
244
|
+
every active SSRC at a cadence shorter than the lifetime so the
|
|
245
|
+
radiod self-destruct counter never reaches zero. The new value
|
|
246
|
+
is also stored in the slot, so a subsequent drop/restore will
|
|
247
|
+
re-apply this value rather than the original ``add_channel``
|
|
248
|
+
argument.
|
|
249
|
+
|
|
250
|
+
No-op if ``ssrc`` is not in this MultiStream.
|
|
251
|
+
"""
|
|
252
|
+
slot = self._slots.get(ssrc)
|
|
253
|
+
if slot is None:
|
|
254
|
+
return
|
|
255
|
+
self._control.set_channel_lifetime(ssrc, lifetime)
|
|
256
|
+
slot.lifetime = lifetime
|
|
257
|
+
|
|
227
258
|
def stop(self) -> None:
|
|
228
259
|
"""Stop threads and close socket."""
|
|
229
260
|
if not self._running:
|
|
@@ -426,6 +457,7 @@ class MultiStream:
|
|
|
426
457
|
preset=slot.preset,
|
|
427
458
|
sample_rate=slot.sample_rate,
|
|
428
459
|
encoding=slot.encoding,
|
|
460
|
+
lifetime=slot.lifetime,
|
|
429
461
|
)
|
|
430
462
|
new_ssrc = channel_info.ssrc
|
|
431
463
|
if new_ssrc != ssrc:
|
|
@@ -173,3 +173,91 @@ class TestCreateChannelLifetime:
|
|
|
173
173
|
)
|
|
174
174
|
assert sent
|
|
175
175
|
assert not _has_lifetime_tag(sent[0])
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class TestMultiStreamLifetime:
|
|
179
|
+
"""MultiStream stores ``lifetime`` per-slot and forwards it to
|
|
180
|
+
ensure_channel on both the initial add and the drop/restore path,
|
|
181
|
+
plus exposes a set_channel_lifetime() keep-alive method.
|
|
182
|
+
|
|
183
|
+
Asserted at the ``RadiodControl.ensure_channel`` boundary — these
|
|
184
|
+
tests don't exercise the wire encoding (covered above), they verify
|
|
185
|
+
that MultiStream wires the kwarg through correctly.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
def _make_multi_with_mock_control(self, ssrc=12345):
|
|
189
|
+
from ka9q.multi_stream import MultiStream
|
|
190
|
+
from ka9q.discovery import ChannelInfo
|
|
191
|
+
|
|
192
|
+
control = MagicMock()
|
|
193
|
+
control.ensure_channel.return_value = ChannelInfo(
|
|
194
|
+
ssrc=ssrc,
|
|
195
|
+
preset="iq",
|
|
196
|
+
sample_rate=12000,
|
|
197
|
+
frequency=14_074_000.0,
|
|
198
|
+
snr=0.0,
|
|
199
|
+
multicast_address="239.1.2.3",
|
|
200
|
+
port=5004,
|
|
201
|
+
)
|
|
202
|
+
multi = MultiStream(control=control)
|
|
203
|
+
return multi, control
|
|
204
|
+
|
|
205
|
+
def test_add_channel_forwards_lifetime(self):
|
|
206
|
+
multi, control = self._make_multi_with_mock_control()
|
|
207
|
+
multi.add_channel(
|
|
208
|
+
frequency_hz=14_074_000.0,
|
|
209
|
+
preset="iq",
|
|
210
|
+
sample_rate=12000,
|
|
211
|
+
lifetime=6000,
|
|
212
|
+
)
|
|
213
|
+
kwargs = control.ensure_channel.call_args.kwargs
|
|
214
|
+
assert kwargs["lifetime"] == 6000
|
|
215
|
+
|
|
216
|
+
def test_add_channel_lifetime_none_when_omitted(self):
|
|
217
|
+
multi, control = self._make_multi_with_mock_control()
|
|
218
|
+
multi.add_channel(
|
|
219
|
+
frequency_hz=14_074_000.0,
|
|
220
|
+
preset="iq",
|
|
221
|
+
sample_rate=12000,
|
|
222
|
+
)
|
|
223
|
+
kwargs = control.ensure_channel.call_args.kwargs
|
|
224
|
+
assert kwargs["lifetime"] is None
|
|
225
|
+
|
|
226
|
+
def test_restore_reapplies_stored_lifetime(self):
|
|
227
|
+
"""A slot added with lifetime=N must re-pass N on _attempt_restore."""
|
|
228
|
+
multi, control = self._make_multi_with_mock_control()
|
|
229
|
+
multi.add_channel(
|
|
230
|
+
frequency_hz=14_074_000.0,
|
|
231
|
+
preset="iq",
|
|
232
|
+
sample_rate=12000,
|
|
233
|
+
lifetime=6000,
|
|
234
|
+
)
|
|
235
|
+
ssrc = next(iter(multi._slots))
|
|
236
|
+
slot = multi._slots[ssrc]
|
|
237
|
+
slot.dropped = True
|
|
238
|
+
control.ensure_channel.reset_mock()
|
|
239
|
+
|
|
240
|
+
multi._attempt_restore(ssrc, slot)
|
|
241
|
+
|
|
242
|
+
kwargs = control.ensure_channel.call_args.kwargs
|
|
243
|
+
assert kwargs["lifetime"] == 6000
|
|
244
|
+
|
|
245
|
+
def test_set_channel_lifetime_updates_slot_and_wire(self):
|
|
246
|
+
multi, control = self._make_multi_with_mock_control()
|
|
247
|
+
multi.add_channel(
|
|
248
|
+
frequency_hz=14_074_000.0,
|
|
249
|
+
preset="iq",
|
|
250
|
+
sample_rate=12000,
|
|
251
|
+
lifetime=6000,
|
|
252
|
+
)
|
|
253
|
+
ssrc = next(iter(multi._slots))
|
|
254
|
+
|
|
255
|
+
multi.set_channel_lifetime(ssrc, 9000)
|
|
256
|
+
|
|
257
|
+
control.set_channel_lifetime.assert_called_once_with(ssrc, 9000)
|
|
258
|
+
assert multi._slots[ssrc].lifetime == 9000
|
|
259
|
+
|
|
260
|
+
def test_set_channel_lifetime_unknown_ssrc_is_noop(self):
|
|
261
|
+
multi, control = self._make_multi_with_mock_control()
|
|
262
|
+
multi.set_channel_lifetime(99999, 6000)
|
|
263
|
+
control.set_channel_lifetime.assert_not_called()
|
|
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
|
|
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
|