apify-client 3.2.1b2__tar.gz → 3.2.1b4__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.
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/CHANGELOG.md +2 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/PKG-INFO +1 -1
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/pyproject.toml +1 -1
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/pyproject.toml.orig +1 -1
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_status_message_watcher.py +30 -13
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_streamed_log.py +54 -9
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/types.py +2 -1
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/CONTRIBUTING.md +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/LICENSE +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/README.md +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/__init__.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_apify_client.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_client_registry.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_consts.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_docs.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_literals.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_logging.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_models.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_pagination.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/__init__.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/_resource_client.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_env_var.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_env_var_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_version.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_version_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/build.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/build_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/dataset.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/dataset_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/key_value_store.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/key_value_store_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/log.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/request_queue.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/request_queue_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/run.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/run_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/schedule.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/schedule_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/store_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/task.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/task_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/user.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/webhook.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/webhook_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/webhook_dispatch.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/webhook_dispatch_collection.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_statistics.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_typeddicts.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_utils/__init__.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_utils/crypto.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_utils/encoding.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_utils/errors.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_utils/http.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_utils/time.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_utils/try_import.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/errors.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_clients/__init__.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_clients/_base.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_clients/_httpx2.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_clients/_impit.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_compressors/__init__.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_compressors/_base.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_compressors/_brotli.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_compressors/_gzip.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/http_compressors/_resolve.py +0 -0
- {apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/py.typed +0 -0
|
@@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file.
|
|
|
8
8
|
### 🐛 Bug Fixes
|
|
9
9
|
|
|
10
10
|
- Stop dataset iterators from skipping items when unwind is used ([#1059](https://github.com/apify/apify-client-python/pull/1059)) ([8e30197](https://github.com/apify/apify-client-python/commit/8e301977ecb80b7c01251cacf071a3f6201469ba)) by [@vdusek](https://github.com/vdusek), closes [#1058](https://github.com/apify/apify-client-python/issues/1058)
|
|
11
|
+
- Keep a failing background watcher from breaking a successful actor call ([#1027](https://github.com/apify/apify-client-python/pull/1027)) ([efc009d](https://github.com/apify/apify-client-python/commit/efc009d78f08d3a03a10db386201e48e45d01c2d)) by [@vdusek](https://github.com/vdusek)
|
|
12
|
+
- Make `JsonSerializable` type alias read-only ([#1072](https://github.com/apify/apify-client-python/pull/1072)) ([bd82a26](https://github.com/apify/apify-client-python/commit/bd82a2645d3c64f0e4a30de3a016c16d92d48340)) by [@Pijukatel](https://github.com/Pijukatel)
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
<!-- git-cliff-unreleased-end -->
|
|
@@ -120,11 +120,19 @@ class StatusMessageWatcherAsync(StatusMessageWatcherBase):
|
|
|
120
120
|
await self.stop()
|
|
121
121
|
|
|
122
122
|
async def _log_changed_status_message(self) -> None:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
try:
|
|
124
|
+
while True:
|
|
125
|
+
run_data = await self._run_client.get()
|
|
126
|
+
if not self._log_run_data(run_data):
|
|
127
|
+
break
|
|
128
|
+
await asyncio.sleep(self._check_period)
|
|
129
|
+
except Exception as exc:
|
|
130
|
+
if self._run_client._http_client.is_timeout_error(exc): # noqa: SLF001
|
|
131
|
+
# An expected timeout, so warn rather than leak a traceback.
|
|
132
|
+
self._to_logger.warning('Status message redirection stopped: the status request timed out.')
|
|
133
|
+
else:
|
|
134
|
+
# A failed poll must not escape into `stop` and surface as a failure of the run.
|
|
135
|
+
self._to_logger.exception('Status message redirection stopped due to unexpected error:')
|
|
128
136
|
|
|
129
137
|
|
|
130
138
|
@docs_group('Other')
|
|
@@ -159,10 +167,11 @@ class StatusMessageWatcher(StatusMessageWatcherBase):
|
|
|
159
167
|
|
|
160
168
|
The caller is responsible for cleanup by calling the `stop` method when done.
|
|
161
169
|
"""
|
|
162
|
-
if self._logging_thread:
|
|
170
|
+
if self._logging_thread and self._logging_thread.is_alive():
|
|
163
171
|
raise RuntimeError('Logging thread already active')
|
|
164
172
|
self._stop_logging = False
|
|
165
|
-
|
|
173
|
+
# A daemon thread, so a watcher still polling cannot hold up interpreter shutdown.
|
|
174
|
+
self._logging_thread = threading.Thread(target=self._log_changed_status_message, daemon=True)
|
|
166
175
|
self._logging_thread.start()
|
|
167
176
|
return self._logging_thread
|
|
168
177
|
|
|
@@ -189,9 +198,17 @@ class StatusMessageWatcher(StatusMessageWatcherBase):
|
|
|
189
198
|
self.stop()
|
|
190
199
|
|
|
191
200
|
def _log_changed_status_message(self) -> None:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
201
|
+
try:
|
|
202
|
+
while True:
|
|
203
|
+
if not self._log_run_data(self._run_client.get()):
|
|
204
|
+
break
|
|
205
|
+
if self._stop_logging:
|
|
206
|
+
break
|
|
207
|
+
time.sleep(self._check_period)
|
|
208
|
+
except Exception as exc:
|
|
209
|
+
if self._run_client._http_client.is_timeout_error(exc): # noqa: SLF001
|
|
210
|
+
# An expected timeout, so warn rather than leak a traceback.
|
|
211
|
+
self._to_logger.warning('Status message redirection stopped: the status request timed out.')
|
|
212
|
+
else:
|
|
213
|
+
# A failed poll must not escape the background thread.
|
|
214
|
+
self._to_logger.exception('Status message redirection stopped due to unexpected error:')
|
|
@@ -15,6 +15,7 @@ if TYPE_CHECKING:
|
|
|
15
15
|
from types import TracebackType
|
|
16
16
|
|
|
17
17
|
from apify_client._resource_clients import LogClient, LogClientAsync
|
|
18
|
+
from apify_client.http_clients import HttpResponse
|
|
18
19
|
from apify_client.types import Timeout
|
|
19
20
|
|
|
20
21
|
|
|
@@ -98,6 +99,13 @@ class StreamedLog(StreamedLogBase):
|
|
|
98
99
|
call `start` and `stop` manually. Obtain an instance via `RunClient.get_streamed_log`.
|
|
99
100
|
"""
|
|
100
101
|
|
|
102
|
+
_stop_timeout_s: ClassVar[float] = 5
|
|
103
|
+
"""Upper bound on how long `stop` waits for the streaming thread to finish.
|
|
104
|
+
|
|
105
|
+
Closing the response only ends the read on a transport that honours it, which neither Impit nor HTTPX does, so
|
|
106
|
+
without a bound `stop` would wait for the next chunk, which on a quiet run may be hours away.
|
|
107
|
+
"""
|
|
108
|
+
|
|
101
109
|
def __init__(self, log_client: LogClient, *, to_logger: logging.Logger, from_start: bool = True) -> None:
|
|
102
110
|
"""Initialize `StreamedLog`.
|
|
103
111
|
|
|
@@ -111,6 +119,7 @@ class StreamedLog(StreamedLogBase):
|
|
|
111
119
|
super().__init__(to_logger=to_logger, from_start=from_start)
|
|
112
120
|
self._log_client = log_client
|
|
113
121
|
self._streaming_thread: Thread | None = None
|
|
122
|
+
self._log_stream: HttpResponse | None = None
|
|
114
123
|
self._stop_logging = False
|
|
115
124
|
|
|
116
125
|
def start(self) -> Thread:
|
|
@@ -118,7 +127,7 @@ class StreamedLog(StreamedLogBase):
|
|
|
118
127
|
|
|
119
128
|
The caller is responsible for cleanup by calling the `stop` method when done.
|
|
120
129
|
"""
|
|
121
|
-
if self._streaming_thread:
|
|
130
|
+
if self._streaming_thread and self._streaming_thread.is_alive():
|
|
122
131
|
raise RuntimeError('Streaming thread already active')
|
|
123
132
|
self._stop_logging = False
|
|
124
133
|
# A daemon thread so a stream still blocked on a read can never hold up interpreter shutdown.
|
|
@@ -127,13 +136,29 @@ class StreamedLog(StreamedLogBase):
|
|
|
127
136
|
return self._streaming_thread
|
|
128
137
|
|
|
129
138
|
def stop(self) -> None:
|
|
130
|
-
"""Signal the streaming thread to stop logging and wait for it to finish.
|
|
139
|
+
"""Signal the streaming thread to stop logging and wait up to `_stop_timeout_s` for it to finish.
|
|
140
|
+
|
|
141
|
+
A thread that outlives the wait is a daemon with `_stop_logging` set, so it exits after at most one more chunk,
|
|
142
|
+
and only then does its buffered tail reach the logger. Its handle is kept while it is alive, so `start` cannot
|
|
143
|
+
revive it beside a second thread on the same buffer.
|
|
144
|
+
"""
|
|
131
145
|
if not self._streaming_thread:
|
|
132
146
|
raise RuntimeError('Streaming thread is not active')
|
|
133
147
|
self._stop_logging = True
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
148
|
+
# Read once; the streaming thread clears the attribute as soon as the stream ends.
|
|
149
|
+
log_stream = self._log_stream
|
|
150
|
+
if log_stream is not None:
|
|
151
|
+
try:
|
|
152
|
+
log_stream.close()
|
|
153
|
+
except Exception:
|
|
154
|
+
# A failing `close` in a custom transport must not fail the caller.
|
|
155
|
+
self._to_logger.exception('Closing the log stream failed:')
|
|
156
|
+
self._streaming_thread.join(timeout=self._stop_timeout_s)
|
|
157
|
+
if self._streaming_thread.is_alive():
|
|
158
|
+
# Otherwise log messages arriving after `stop` returned have no explanation.
|
|
159
|
+
self._to_logger.debug('Log streaming thread outlived the stop timeout; it ends after the next chunk.')
|
|
160
|
+
else:
|
|
161
|
+
self._streaming_thread = None
|
|
137
162
|
|
|
138
163
|
def __enter__(self) -> Self:
|
|
139
164
|
"""Start the streaming thread within the context. Exiting the context will finish the streaming thread."""
|
|
@@ -151,15 +176,30 @@ class StreamedLog(StreamedLogBase):
|
|
|
151
176
|
with self._log_client.stream(raw=True, timeout=self._stream_timeout) as log_stream:
|
|
152
177
|
if not log_stream:
|
|
153
178
|
return
|
|
179
|
+
# Published so `stop` can close the response.
|
|
180
|
+
self._log_stream = log_stream
|
|
154
181
|
try:
|
|
182
|
+
# `stop` may have run before the response existed for it to close.
|
|
183
|
+
if self._stop_logging:
|
|
184
|
+
return
|
|
155
185
|
for data in log_stream.iter_bytes():
|
|
156
186
|
self._process_new_data(data)
|
|
157
187
|
if self._stop_logging:
|
|
158
188
|
break
|
|
159
189
|
finally:
|
|
160
|
-
|
|
161
|
-
|
|
190
|
+
self._log_stream = None
|
|
191
|
+
try:
|
|
192
|
+
# Flush the last buffered part even if the read timed out or was stopped.
|
|
193
|
+
self._log_buffer_content(include_last_part=True)
|
|
194
|
+
except Exception:
|
|
195
|
+
# A truncated stream leaves an undecodable tail, which is worth a traceback even while a stop
|
|
196
|
+
# is in progress.
|
|
197
|
+
self._to_logger.exception('Log redirection stopped due to unexpected error:')
|
|
162
198
|
except Exception as exc:
|
|
199
|
+
if self._stop_logging:
|
|
200
|
+
# `stop` closed the stream out from under the read, so the failure is expected.
|
|
201
|
+
self._to_logger.debug('Log streaming stopped while `stop` was in progress: %r', exc)
|
|
202
|
+
return
|
|
163
203
|
if self._log_client._http_client.is_timeout_error(exc): # noqa: SLF001
|
|
164
204
|
# The stream cannot continue, so warn and let the thread end instead of leaking a traceback.
|
|
165
205
|
self._to_logger.warning('Log streaming stopped: the log stream request timed out.')
|
|
@@ -236,8 +276,13 @@ class StreamedLogAsync(StreamedLogBase):
|
|
|
236
276
|
async for data in log_stream.aiter_bytes():
|
|
237
277
|
self._process_new_data(data)
|
|
238
278
|
finally:
|
|
239
|
-
|
|
240
|
-
|
|
279
|
+
try:
|
|
280
|
+
# Flush the last buffered part even if the task is cancelled by `stop()`.
|
|
281
|
+
self._log_buffer_content(include_last_part=True)
|
|
282
|
+
except Exception:
|
|
283
|
+
# A truncated stream leaves an undecodable tail. Keeping the failure here also keeps the
|
|
284
|
+
# cancellation `stop` raised propagating, so the task ends up cancelled as asyncio expects.
|
|
285
|
+
self._to_logger.exception('Log redirection stopped due to unexpected error:')
|
|
241
286
|
except Exception as exc:
|
|
242
287
|
if self._log_client._http_client.is_timeout_error(exc): # noqa: SLF001
|
|
243
288
|
# A timeout on the long-lived stream is an expected terminal condition, not an error.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Mapping, Sequence
|
|
3
4
|
from datetime import timedelta
|
|
4
5
|
from typing import Literal
|
|
5
6
|
|
|
@@ -38,7 +39,7 @@ to ad-hoc webhooks (e.g. `condition`) are ignored at runtime. The `*CamelDict` v
|
|
|
38
39
|
matching the Apify API spelling.
|
|
39
40
|
"""
|
|
40
41
|
|
|
41
|
-
JsonSerializable =
|
|
42
|
+
JsonSerializable = Mapping[str, 'JsonSerializable'] | Sequence['JsonSerializable'] | str | int | float | bool | None
|
|
42
43
|
"""Recursive type for JSON-serializable values - primitives plus objects and arrays with JSON-serializable contents.
|
|
43
44
|
|
|
44
45
|
Based on the definition discussed in https://github.com/python/typing/issues/182.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/__init__.py
RENAMED
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/_resource_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_collection.py
RENAMED
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_env_var.py
RENAMED
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/actor_version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/build_collection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/key_value_store.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/request_queue.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/run_collection.py
RENAMED
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/schedule.py
RENAMED
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/store_collection.py
RENAMED
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/task_collection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apify_client-3.2.1b2 → apify_client-3.2.1b4}/src/apify_client/_resource_clients/webhook_dispatch.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
|