omserv 0.0.0.dev476__tar.gz → 0.0.0.dev505__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.
Potentially problematic release.
This version of omserv might be problematic. Click here for more details.
- {omserv-0.0.0.dev476/omserv.egg-info → omserv-0.0.0.dev505}/PKG-INFO +4 -4
- omserv-0.0.0.dev505/omserv/README.md +9 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/__about__.py +1 -1
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/events.py +5 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/listener.py +1 -1
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/protocols/h2.py +12 -3
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/streams/httpstream.py +36 -2
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/streams/wsstream.py +7 -1
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505/omserv.egg-info}/PKG-INFO +4 -4
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv.egg-info/SOURCES.txt +1 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv.egg-info/requires.txt +3 -3
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/pyproject.toml +7 -4
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/LICENSE +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/MANIFEST.in +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/README.md +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/.omlish-manifests.json +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/apps/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/apps/base.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/apps/inject.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/apps/markers.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/apps/routes.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/apps/sessions.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/apps/templates.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nginx/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nginx/build.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nginx/logs.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nginx/patches/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nginx/patches/nginx-1.28.0_http_status.patch +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nginx/stubstatus.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nodes/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nodes/models.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nodes/registry.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nodes/sql.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/LICENSE +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/config.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/debug.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/default.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/headers.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/inject.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/lifespans.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/multiprocess.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/protocols/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/protocols/h11.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/protocols/protocols.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/protocols/types.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/resources/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/resources/favicon.ico +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/server.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/sockets.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/ssl.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/streams/__init__.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/streams/utils.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/taskspawner.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/types.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/server/workercontext.py +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv.egg-info/dependency_links.txt +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv.egg-info/entry_points.txt +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv.egg-info/top_level.txt +0 -0
- {omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: omserv
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev505
|
|
4
4
|
Summary: omserv
|
|
5
5
|
Author: wrmsr
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -14,18 +14,18 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
14
14
|
Requires-Python: >=3.13
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: omlish==0.0.0.
|
|
17
|
+
Requires-Dist: omlish==0.0.0.dev505
|
|
18
18
|
Provides-Extra: all
|
|
19
19
|
Requires-Dist: h11~=0.16; extra == "all"
|
|
20
20
|
Requires-Dist: h2~=4.3; extra == "all"
|
|
21
21
|
Requires-Dist: priority~=2.0; extra == "all"
|
|
22
|
-
Requires-Dist: wsproto~=1.
|
|
22
|
+
Requires-Dist: wsproto~=1.3; extra == "all"
|
|
23
23
|
Requires-Dist: jinja2~=3.1; extra == "all"
|
|
24
24
|
Provides-Extra: server
|
|
25
25
|
Requires-Dist: h11~=0.16; extra == "server"
|
|
26
26
|
Requires-Dist: h2~=4.3; extra == "server"
|
|
27
27
|
Requires-Dist: priority~=2.0; extra == "server"
|
|
28
|
-
Requires-Dist: wsproto~=1.
|
|
28
|
+
Requires-Dist: wsproto~=1.3; extra == "server"
|
|
29
29
|
Provides-Extra: templates
|
|
30
30
|
Requires-Dist: jinja2~=3.1; extra == "templates"
|
|
31
31
|
Dynamic: license-file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
Request serving code.
|
|
4
|
+
|
|
5
|
+
# Notable packages
|
|
6
|
+
|
|
7
|
+
- **[server](https://github.com/wrmsr/omlish/blob/master/omserv/server)** - Production web server based on
|
|
8
|
+
[hypercorn](https://github.com/pgjones/hypercorn). Converted to anyio, but still being refined and integrated with the
|
|
9
|
+
codebase.
|
|
@@ -174,7 +174,7 @@ class Listener:
|
|
|
174
174
|
binds = []
|
|
175
175
|
|
|
176
176
|
for sock in sockets.insecure_sockets:
|
|
177
|
-
listeners.append(anyio._core._eventloop.get_async_backend().create_tcp_listener(sock)) # noqa
|
|
177
|
+
listeners.append(anyio._core._eventloop.get_async_backend().create_tcp_listener(sock)) # type: ignore[attr-defined] # noqa
|
|
178
178
|
bind = repr_socket_addr(sock.family, sock.getsockname())
|
|
179
179
|
binds.append(f'http://{bind}')
|
|
180
180
|
log.info('Running on http://%s (CTRL + C to quit)', bind)
|
|
@@ -24,6 +24,7 @@ from ..events import Request
|
|
|
24
24
|
from ..events import Response
|
|
25
25
|
from ..events import ServerEvent
|
|
26
26
|
from ..events import StreamClosed
|
|
27
|
+
from ..events import Trailers
|
|
27
28
|
from ..events import Updated
|
|
28
29
|
from ..headers import filter_pseudo_headers
|
|
29
30
|
from ..headers import response_headers
|
|
@@ -239,6 +240,10 @@ class H2Protocol(Protocol):
|
|
|
239
240
|
await self.has_data.set()
|
|
240
241
|
await self.stream_buffers[event.stream_id].drain()
|
|
241
242
|
|
|
243
|
+
elif isinstance(event, Trailers):
|
|
244
|
+
self.connection.send_headers(event.stream_id, event.headers)
|
|
245
|
+
await self._flush()
|
|
246
|
+
|
|
242
247
|
elif isinstance(event, StreamClosed):
|
|
243
248
|
await self._close_stream(event.stream_id)
|
|
244
249
|
idle = len(self.streams) == 0 or all(
|
|
@@ -288,9 +293,13 @@ class H2Protocol(Protocol):
|
|
|
288
293
|
)
|
|
289
294
|
|
|
290
295
|
elif isinstance(event, h2.events.StreamEnded):
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
296
|
+
try:
|
|
297
|
+
stream = self.streams[check.not_none(event.stream_id)]
|
|
298
|
+
except KeyError:
|
|
299
|
+
# Response sent before full request received, nothing to do already closed.
|
|
300
|
+
pass
|
|
301
|
+
else:
|
|
302
|
+
await stream.handle(EndBody(stream_id=check.not_none(event.stream_id)))
|
|
294
303
|
|
|
295
304
|
elif isinstance(event, h2.events.StreamReset):
|
|
296
305
|
await self._close_stream(check.not_none(event.stream_id))
|
|
@@ -13,6 +13,7 @@ from ..events import ProtocolEvent
|
|
|
13
13
|
from ..events import Request
|
|
14
14
|
from ..events import Response
|
|
15
15
|
from ..events import StreamClosed
|
|
16
|
+
from ..events import Trailers
|
|
16
17
|
from ..taskspawner import TaskSpawner
|
|
17
18
|
from ..types import AppWrapper
|
|
18
19
|
from ..types import AsgiSendEvent
|
|
@@ -32,6 +33,7 @@ log = logs.get_module_logger(globals())
|
|
|
32
33
|
##
|
|
33
34
|
|
|
34
35
|
|
|
36
|
+
TRAILERS_VERSIONS = {'2', '3'}
|
|
35
37
|
PUSH_VERSIONS = {'2', '3'}
|
|
36
38
|
EARLY_HINTS_VERSIONS = {'2', '3'}
|
|
37
39
|
|
|
@@ -41,6 +43,7 @@ class AsgiHttpState(enum.Enum):
|
|
|
41
43
|
# hence why this state tracking is required.
|
|
42
44
|
REQUEST = enum.auto()
|
|
43
45
|
RESPONSE = enum.auto()
|
|
46
|
+
TRAILERS = enum.auto()
|
|
44
47
|
CLOSED = enum.auto()
|
|
45
48
|
|
|
46
49
|
|
|
@@ -101,6 +104,9 @@ class HttpStream:
|
|
|
101
104
|
'extensions': {},
|
|
102
105
|
}
|
|
103
106
|
|
|
107
|
+
if event.http_version in TRAILERS_VERSIONS:
|
|
108
|
+
self.scope['extensions']['http.response.trailers'] = {}
|
|
109
|
+
|
|
104
110
|
if event.http_version in PUSH_VERSIONS:
|
|
105
111
|
self.scope['extensions']['http.response.push'] = {}
|
|
106
112
|
|
|
@@ -200,7 +206,12 @@ class HttpStream:
|
|
|
200
206
|
await self.send(Body(stream_id=self.stream_id, data=bytes(message.get('body', b''))))
|
|
201
207
|
|
|
202
208
|
if not message.get('more_body', False):
|
|
203
|
-
|
|
209
|
+
await self.send(EndBody(stream_id=self.stream_id))
|
|
210
|
+
|
|
211
|
+
if self.response.get('trailers', False):
|
|
212
|
+
self.state = AsgiHttpState.TRAILERS
|
|
213
|
+
|
|
214
|
+
else:
|
|
204
215
|
self.state = AsgiHttpState.CLOSED
|
|
205
216
|
|
|
206
217
|
log_access(
|
|
@@ -210,7 +221,30 @@ class HttpStream:
|
|
|
210
221
|
time.time() - self.start_time,
|
|
211
222
|
)
|
|
212
223
|
|
|
213
|
-
await self.send(
|
|
224
|
+
await self.send(StreamClosed(stream_id=self.stream_id))
|
|
225
|
+
|
|
226
|
+
elif (
|
|
227
|
+
message['type'] == 'http.response.trailers' and
|
|
228
|
+
self.scope['http_version'] in TRAILERS_VERSIONS and
|
|
229
|
+
self.state == AsgiHttpState.TRAILERS
|
|
230
|
+
):
|
|
231
|
+
for name, value in self.scope['headers']:
|
|
232
|
+
if name == b'te' and value == b'trailers':
|
|
233
|
+
headers = build_and_validate_headers(message['headers'])
|
|
234
|
+
|
|
235
|
+
await self.send(Trailers(stream_id=self.stream_id, headers=headers))
|
|
236
|
+
|
|
237
|
+
break
|
|
238
|
+
|
|
239
|
+
if not message.get('more_trailers', False):
|
|
240
|
+
self.state = AsgiHttpState.CLOSED
|
|
241
|
+
|
|
242
|
+
log_access(
|
|
243
|
+
self.config,
|
|
244
|
+
self.scope,
|
|
245
|
+
self.response, # type: ignore # noqa
|
|
246
|
+
time.time() - self.start_time,
|
|
247
|
+
)
|
|
214
248
|
|
|
215
249
|
await self.send(StreamClosed(stream_id=self.stream_id))
|
|
216
250
|
|
|
@@ -65,6 +65,7 @@ class Handshake:
|
|
|
65
65
|
) -> None:
|
|
66
66
|
super().__init__()
|
|
67
67
|
|
|
68
|
+
self.accepted = False
|
|
68
69
|
self.http_version = http_version
|
|
69
70
|
self.connection_tokens: list[str] | None = None
|
|
70
71
|
self.extensions: list[str] | None = None
|
|
@@ -149,6 +150,7 @@ class Handshake:
|
|
|
149
150
|
|
|
150
151
|
headers.append((name, value))
|
|
151
152
|
|
|
153
|
+
self.accepted = True
|
|
152
154
|
return status_code, headers, wsp.Connection(wsp.ConnectionType.SERVER, extensions)
|
|
153
155
|
|
|
154
156
|
|
|
@@ -261,6 +263,10 @@ class WsStream:
|
|
|
261
263
|
self.connection.receive_data(event.data)
|
|
262
264
|
await self._handle_events()
|
|
263
265
|
|
|
266
|
+
elif isinstance(event, (Body, Data)) and not self.handshake.accepted:
|
|
267
|
+
await self._send_error_response(400)
|
|
268
|
+
self.closed = True
|
|
269
|
+
|
|
264
270
|
elif isinstance(event, StreamClosed):
|
|
265
271
|
self.closed = True
|
|
266
272
|
|
|
@@ -312,7 +318,7 @@ class WsStream:
|
|
|
312
318
|
elif message['type'] == 'websocket.send' and self.state == AsgiWebsocketState.CONNECTED:
|
|
313
319
|
event: wse.Event
|
|
314
320
|
if message.get('bytes') is not None:
|
|
315
|
-
event = wse.BytesMessage(data=
|
|
321
|
+
event = wse.BytesMessage(data=bytearray(message['bytes']))
|
|
316
322
|
|
|
317
323
|
elif not isinstance(message['text'], str):
|
|
318
324
|
raise TypeError(f'{message["text"]} should be a str')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: omserv
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev505
|
|
4
4
|
Summary: omserv
|
|
5
5
|
Author: wrmsr
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -14,18 +14,18 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
14
14
|
Requires-Python: >=3.13
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: omlish==0.0.0.
|
|
17
|
+
Requires-Dist: omlish==0.0.0.dev505
|
|
18
18
|
Provides-Extra: all
|
|
19
19
|
Requires-Dist: h11~=0.16; extra == "all"
|
|
20
20
|
Requires-Dist: h2~=4.3; extra == "all"
|
|
21
21
|
Requires-Dist: priority~=2.0; extra == "all"
|
|
22
|
-
Requires-Dist: wsproto~=1.
|
|
22
|
+
Requires-Dist: wsproto~=1.3; extra == "all"
|
|
23
23
|
Requires-Dist: jinja2~=3.1; extra == "all"
|
|
24
24
|
Provides-Extra: server
|
|
25
25
|
Requires-Dist: h11~=0.16; extra == "server"
|
|
26
26
|
Requires-Dist: h2~=4.3; extra == "server"
|
|
27
27
|
Requires-Dist: priority~=2.0; extra == "server"
|
|
28
|
-
Requires-Dist: wsproto~=1.
|
|
28
|
+
Requires-Dist: wsproto~=1.3; extra == "server"
|
|
29
29
|
Provides-Extra: templates
|
|
30
30
|
Requires-Dist: jinja2~=3.1; extra == "templates"
|
|
31
31
|
Dynamic: license-file
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
omlish==0.0.0.
|
|
1
|
+
omlish==0.0.0.dev505
|
|
2
2
|
|
|
3
3
|
[all]
|
|
4
4
|
h11~=0.16
|
|
5
5
|
h2~=4.3
|
|
6
6
|
priority~=2.0
|
|
7
|
-
wsproto~=1.
|
|
7
|
+
wsproto~=1.3
|
|
8
8
|
jinja2~=3.1
|
|
9
9
|
|
|
10
10
|
[server]
|
|
11
11
|
h11~=0.16
|
|
12
12
|
h2~=4.3
|
|
13
13
|
priority~=2.0
|
|
14
|
-
wsproto~=1.
|
|
14
|
+
wsproto~=1.3
|
|
15
15
|
|
|
16
16
|
[templates]
|
|
17
17
|
jinja2~=3.1
|
|
@@ -13,7 +13,7 @@ urls = {source = 'https://github.com/wrmsr/omlish'}
|
|
|
13
13
|
license = 'BSD-3-Clause'
|
|
14
14
|
readme = 'README.md'
|
|
15
15
|
requires-python = '>=3.13'
|
|
16
|
-
version = '0.0.0.
|
|
16
|
+
version = '0.0.0.dev505'
|
|
17
17
|
classifiers = [
|
|
18
18
|
'Development Status :: 2 - Pre-Alpha',
|
|
19
19
|
'Intended Audience :: Developers',
|
|
@@ -24,7 +24,7 @@ classifiers = [
|
|
|
24
24
|
]
|
|
25
25
|
description = 'omserv'
|
|
26
26
|
dependencies = [
|
|
27
|
-
'omlish == 0.0.0.
|
|
27
|
+
'omlish == 0.0.0.dev505',
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
[project.optional-dependencies]
|
|
@@ -32,14 +32,14 @@ all = [
|
|
|
32
32
|
'h11 ~= 0.16',
|
|
33
33
|
'h2 ~= 4.3',
|
|
34
34
|
'priority ~= 2.0',
|
|
35
|
-
'wsproto ~= 1.
|
|
35
|
+
'wsproto ~= 1.3',
|
|
36
36
|
'jinja2 ~= 3.1',
|
|
37
37
|
]
|
|
38
38
|
server = [
|
|
39
39
|
'h11 ~= 0.16',
|
|
40
40
|
'h2 ~= 4.3',
|
|
41
41
|
'priority ~= 2.0',
|
|
42
|
-
'wsproto ~= 1.
|
|
42
|
+
'wsproto ~= 1.3',
|
|
43
43
|
]
|
|
44
44
|
templates = [
|
|
45
45
|
'jinja2 ~= 3.1',
|
|
@@ -69,8 +69,11 @@ exclude = [
|
|
|
69
69
|
'*.h',
|
|
70
70
|
'*.hh',
|
|
71
71
|
'.omlish-manifests.json',
|
|
72
|
+
'README',
|
|
73
|
+
'README.md',
|
|
72
74
|
'LICENSE',
|
|
73
75
|
'LICENSE.txt',
|
|
76
|
+
'AUTHORS',
|
|
74
77
|
'nginx/patches/*.patch',
|
|
75
78
|
'server/resources/*.ico',
|
|
76
79
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omserv-0.0.0.dev476 → omserv-0.0.0.dev505}/omserv/nginx/patches/nginx-1.28.0_http_status.patch
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
|