codex-backend-sdk 0.5.0__tar.gz → 0.5.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.
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/CHANGELOG.md +6 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/PKG-INFO +1 -1
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/__init__.py +3 -1
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/remote_control.py +12 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/responses.py +3 -3
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/docs/api-reference.md +7 -4
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/docs/backend-api.md +3 -1
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/pyproject.toml +1 -1
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_remote_control_resource.py +29 -1
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_responses_resource.py +37 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/uv.lock +1 -1
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/.gitignore +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/LICENSE +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/README.md +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/_client.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/_models.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/_streaming.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/_transport.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/_utils.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/codex_client.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/oauth.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/pkce.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/__init__.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/_responses_payloads.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_apps.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_connectors.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_plugin_bundles.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_plugin_shares.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_plugins.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_writing_blocks.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/codex.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/codex_web_search.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/files.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/images.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/models.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/openai_oauth.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/realtime.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/responses_websocket.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/worktree_snapshots.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/storage.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/docs/desktop-endpoint-inventory.md +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/docs/endpoint-coverage.md +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/docs/openai-compatibility.md +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/examples/agent.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/conftest.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_account_info.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_basic.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_apps.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_connectors.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_plugin_bundles.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_plugin_shares.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_plugins.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_projects_gizmos.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_resources.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_search_files.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_chatgpt_writing_blocks.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_client_retry.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_codex_resources.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_codex_web_search.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_conversation.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_files_resource.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_hosted_mcp.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_images.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_oauth.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_openai_compatibility.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_openai_oauth_resources.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_prompt_cache_usage.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_realtime_resource.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_reasoning.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_responses_websocket.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_structured_output.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_tools.py +0 -0
- {codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/tests/test_worktree_snapshots.py +0 -0
|
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [0.5.1] - 2026-08-14
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Preserve ordered nonopaque remote-compaction output items instead of rejecting
|
|
11
|
+
any response containing more than the required opaque compaction anchor.
|
|
12
|
+
|
|
7
13
|
## [0.5.0] - 2026-08-13
|
|
8
14
|
|
|
9
15
|
### Added
|
|
@@ -17,7 +17,7 @@ Quickstart:
|
|
|
17
17
|
print(response.output_text)
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
-
__version__ = "0.5.
|
|
20
|
+
__version__ = "0.5.2"
|
|
21
21
|
|
|
22
22
|
from .oauth import (
|
|
23
23
|
DeviceCode,
|
|
@@ -32,6 +32,7 @@ from .resources.remote_control import (
|
|
|
32
32
|
RemoteControlClient,
|
|
33
33
|
RemoteControlClientPage,
|
|
34
34
|
RemoteControlConnection,
|
|
35
|
+
RemoteControlConnectionClosed,
|
|
35
36
|
RemoteControlDesktop,
|
|
36
37
|
RemoteControlEnrollment,
|
|
37
38
|
RemoteControlEnvironment,
|
|
@@ -120,6 +121,7 @@ __all__ = [
|
|
|
120
121
|
"RemoteControlClient",
|
|
121
122
|
"RemoteControlClientPage",
|
|
122
123
|
"RemoteControlConnection",
|
|
124
|
+
"RemoteControlConnectionClosed",
|
|
123
125
|
"RemoteControlDesktop",
|
|
124
126
|
"RemoteControlEnrollment",
|
|
125
127
|
"RemoteControlEnvironment",
|
{codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/remote_control.py
RENAMED
|
@@ -19,6 +19,10 @@ if TYPE_CHECKING:
|
|
|
19
19
|
REMOTE_CONTROL_ROOT = "/wham/remote/control"
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
class RemoteControlConnectionClosed(ConnectionError):
|
|
23
|
+
"""The Remote Control peer closed its WebSocket without an envelope."""
|
|
24
|
+
|
|
25
|
+
|
|
22
26
|
class RemoteControlEnrollment(CodexBaseModel):
|
|
23
27
|
server_id: str
|
|
24
28
|
environment_id: str
|
|
@@ -117,8 +121,16 @@ class RemoteControlConnection:
|
|
|
117
121
|
raise TypeError("Expected `envelope` to serialize to a JSON object.")
|
|
118
122
|
self._socket.send(json.dumps(payload, separators=(",", ":")))
|
|
119
123
|
|
|
124
|
+
def ping(self, payload: bytes = b"") -> None:
|
|
125
|
+
"""Send a WebSocket ping frame to keep the remote path alive."""
|
|
126
|
+
self._socket.ping(payload)
|
|
127
|
+
|
|
120
128
|
def receive(self) -> dict[str, Any]:
|
|
121
129
|
message = self._socket.recv()
|
|
130
|
+
if message in {"", b""}:
|
|
131
|
+
raise RemoteControlConnectionClosed(
|
|
132
|
+
"Remote Control WebSocket closed without a final envelope."
|
|
133
|
+
)
|
|
122
134
|
if isinstance(message, bytes):
|
|
123
135
|
message = message.decode("utf-8")
|
|
124
136
|
payload = json.loads(message)
|
{codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/responses.py
RENAMED
|
@@ -353,13 +353,13 @@ class Responses:
|
|
|
353
353
|
raise RuntimeError("Remote compaction v2 failed")
|
|
354
354
|
|
|
355
355
|
compaction_items = [item for item in output if item.get("type") == "compaction"]
|
|
356
|
-
if len(
|
|
356
|
+
if len(compaction_items) != 1:
|
|
357
357
|
raise RuntimeError(
|
|
358
|
-
"Remote compaction v2 expected
|
|
358
|
+
"Remote compaction v2 expected one compaction output item, "
|
|
359
359
|
f"received {len(compaction_items)} from {len(output)} output items"
|
|
360
360
|
)
|
|
361
361
|
return CompactedResponse(
|
|
362
362
|
id=completed.get("id", ""),
|
|
363
|
-
output=
|
|
363
|
+
output=output,
|
|
364
364
|
usage=_usage_from_backend(completed.get("usage")),
|
|
365
365
|
)
|
|
@@ -139,10 +139,13 @@ instance. Streaming is not exposed by `parse()`.
|
|
|
139
139
|
| `text` | object or unset | Text verbosity/format controls. |
|
|
140
140
|
| `tools`, `tool_choice` | JSON-compatible | Tool context retained during compaction. |
|
|
141
141
|
| `parallel_tool_calls`, `prompt_cache_key`, `service_tier` | optional | Forwarded when supplied. |
|
|
142
|
-
Returns `CompactedResponse`. Its `output`
|
|
143
|
-
|
|
144
|
-
backend token accounting. The
|
|
145
|
-
backend
|
|
142
|
+
Returns `CompactedResponse`. Its ordered `output` preserves every item emitted
|
|
143
|
+
by explicit remote compaction v2 and must contain exactly one opaque encrypted
|
|
144
|
+
`compaction` item; `usage` preserves backend token accounting. The current
|
|
145
|
+
backend normally emits only that anchor, but the SDK also retains any nonopaque
|
|
146
|
+
items a future or model-dependent response may carry. The public helper remains
|
|
147
|
+
stable even though the backend transport moved from `/responses/compact` to
|
|
148
|
+
`/responses`.
|
|
146
149
|
|
|
147
150
|
#### `client.responses.websocket`
|
|
148
151
|
|
|
@@ -271,7 +271,7 @@ explicit remote-compaction-v2 contract on the normal streaming Responses route.
|
|
|
271
271
|
}
|
|
272
272
|
```
|
|
273
273
|
|
|
274
|
-
**Response** — SSE
|
|
274
|
+
**Response** — SSE currently observed with exactly one completed compaction item:
|
|
275
275
|
```json
|
|
276
276
|
{
|
|
277
277
|
"id": "resp_...",
|
|
@@ -281,6 +281,8 @@ explicit remote-compaction-v2 contract on the normal streaming Responses route.
|
|
|
281
281
|
}
|
|
282
282
|
```
|
|
283
283
|
- `output` replaces the original history; pass it as `input` in subsequent calls.
|
|
284
|
+
- The SDK preserves any additional nonopaque output items in their emitted order
|
|
285
|
+
while still requiring exactly one opaque compaction anchor.
|
|
284
286
|
- The `compaction` item is opaque on the client side.
|
|
285
287
|
|
|
286
288
|
**SDK method**: `client.responses.compact(...)`
|
|
@@ -3,13 +3,18 @@ import json
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
5
|
from codex_backend_sdk import OpenAI
|
|
6
|
-
from codex_backend_sdk.resources.remote_control import
|
|
6
|
+
from codex_backend_sdk.resources.remote_control import (
|
|
7
|
+
RemoteControlConnection,
|
|
8
|
+
RemoteControlConnectionClosed,
|
|
9
|
+
RemoteControlEnrollment,
|
|
10
|
+
)
|
|
7
11
|
|
|
8
12
|
|
|
9
13
|
class FakeSocket:
|
|
10
14
|
def __init__(self):
|
|
11
15
|
self.connected = True
|
|
12
16
|
self.sent = []
|
|
17
|
+
self.pings = []
|
|
13
18
|
self.received = [json.dumps({"type": "ping", "cursor": "cursor-2"})]
|
|
14
19
|
|
|
15
20
|
def send(self, message):
|
|
@@ -18,6 +23,9 @@ class FakeSocket:
|
|
|
18
23
|
def recv(self):
|
|
19
24
|
return self.received.pop(0)
|
|
20
25
|
|
|
26
|
+
def ping(self, payload=b""):
|
|
27
|
+
self.pings.append(payload)
|
|
28
|
+
|
|
21
29
|
def close(self):
|
|
22
30
|
self.connected = False
|
|
23
31
|
|
|
@@ -277,6 +285,7 @@ def test_remote_control_connection_builds_codex_headers_and_tracks_cursor():
|
|
|
277
285
|
websocket_factory=factory,
|
|
278
286
|
)
|
|
279
287
|
connection.send({"type": "ack", "client_id": "client-1"})
|
|
288
|
+
connection.ping(b"heartbeat")
|
|
280
289
|
received = connection.receive()
|
|
281
290
|
connection.close()
|
|
282
291
|
|
|
@@ -287,6 +296,25 @@ def test_remote_control_connection_builds_codex_headers_and_tracks_cursor():
|
|
|
287
296
|
assert "Authorization: Bearer remote-token" in headers
|
|
288
297
|
assert "x-codex-subscribe-cursor: cursor-1" in headers
|
|
289
298
|
assert json.loads(socket.sent[0]) == {"type": "ack", "client_id": "client-1"}
|
|
299
|
+
assert socket.pings == [b"heartbeat"]
|
|
290
300
|
assert received["type"] == "ping"
|
|
291
301
|
assert connection.subscribe_cursor == "cursor-2"
|
|
292
302
|
assert connection.connected is False
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@pytest.mark.parametrize("closed_frame", ["", b""])
|
|
306
|
+
def test_remote_control_connection_reports_an_empty_close_frame(closed_frame):
|
|
307
|
+
socket = FakeSocket()
|
|
308
|
+
socket.received = [closed_frame]
|
|
309
|
+
connection = RemoteControlConnection(
|
|
310
|
+
socket,
|
|
311
|
+
websocket_url="wss://example.test/remote",
|
|
312
|
+
enrollment=enrollment(),
|
|
313
|
+
installation_id="installation-1",
|
|
314
|
+
server_name="Desktop",
|
|
315
|
+
protocol_version="3",
|
|
316
|
+
subscribe_cursor="stale-cursor",
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
with pytest.raises(RemoteControlConnectionClosed, match="closed without"):
|
|
320
|
+
connection.receive()
|
|
@@ -400,6 +400,43 @@ def test_responses_compact_sends_shared_request_fields():
|
|
|
400
400
|
assert compacted.output == [{"type": "compaction", "encrypted_content": "opaque"}]
|
|
401
401
|
|
|
402
402
|
|
|
403
|
+
def test_responses_compact_preserves_nonopaque_output_items_in_backend_order():
|
|
404
|
+
class PreservingFakeClient(FakeClient):
|
|
405
|
+
def _post(self, path, *, body, stream=False, **options):
|
|
406
|
+
self.posts.append((path, body, stream, options))
|
|
407
|
+
return FakeSSE([
|
|
408
|
+
(
|
|
409
|
+
'data: {"type":"response.output_item.done","item":'
|
|
410
|
+
'{"type":"message","role":"assistant","content":'
|
|
411
|
+
'[{"type":"output_text","text":"Recent work"}]}}'
|
|
412
|
+
),
|
|
413
|
+
"",
|
|
414
|
+
(
|
|
415
|
+
'data: {"type":"response.output_item.done","item":'
|
|
416
|
+
'{"type":"compaction","encrypted_content":"opaque"}}'
|
|
417
|
+
),
|
|
418
|
+
"",
|
|
419
|
+
(
|
|
420
|
+
'data: {"type":"response.completed","response":'
|
|
421
|
+
'{"id":"resp_preserved","model":"gpt-test",'
|
|
422
|
+
'"usage":{"input_tokens":11,"output_tokens":7,"total_tokens":18}}}'
|
|
423
|
+
),
|
|
424
|
+
])
|
|
425
|
+
|
|
426
|
+
compacted = PreservingFakeClient().responses.compact(
|
|
427
|
+
input=[{"role": "user", "content": "Long context"}],
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
assert compacted.output == [
|
|
431
|
+
{
|
|
432
|
+
"type": "message",
|
|
433
|
+
"role": "assistant",
|
|
434
|
+
"content": [{"type": "output_text", "text": "Recent work"}],
|
|
435
|
+
},
|
|
436
|
+
{"type": "compaction", "encrypted_content": "opaque"},
|
|
437
|
+
]
|
|
438
|
+
|
|
439
|
+
|
|
403
440
|
def test_responses_create_rejects_official_params_not_exposed_by_codex_backend():
|
|
404
441
|
client = FakeClient()
|
|
405
442
|
|
|
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
|
{codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_apps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/chatgpt_plugins.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/codex_web_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codex_backend_sdk-0.5.0 → codex_backend_sdk-0.5.2}/codex_backend_sdk/resources/openai_oauth.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
|