sora-sdk 2026.2.0.dev2__tar.gz → 2026.2.0.dev3__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.
- {sora_sdk-2026.2.0.dev2/src/sora_sdk.egg-info → sora_sdk-2026.2.0.dev3}/PKG-INFO +1 -1
- sora_sdk-2026.2.0.dev3/VERSION +1 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk/sora_sdk_ext.cpython-312-darwin.so +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk/sora_sdk_ext.pyi +2 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3/src/sora_sdk.egg-info}/PKG-INFO +1 -1
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk.egg-info/SOURCES.txt +1 -0
- sora_sdk-2026.2.0.dev3/tests/test_rpc.py +202 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_type_switched.py +5 -1
- sora_sdk-2026.2.0.dev2/VERSION +0 -1
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/LICENSE +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/MANIFEST.in +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/README.md +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/buildbase.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/pypath.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/pyproject.toml +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/run.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/setup.cfg +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/setup.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk/__init__.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk/py.typed +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk.egg-info/dependency_links.txt +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk.egg-info/top_level.txt +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_amd_amf.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_apple_video_toolbox.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_audio_sink_callbacks.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_audio_sink_read_gil.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_audio_source_invalid_params.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_authz.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_authz_simulcast.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_ca_cert.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_capability.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_convert_json_value_int64.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_degradation_preference.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_disconnect_timeout.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_encoded_transform.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_field_trials.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_intel_vpl.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_key_frame_request.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_messaging.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_messaging_header.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_ndarray_parent_reference.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_nvidia_video_codec.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_openh264.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_openh264_simulcast.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_opus.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_raspberry_pi.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_re_offer_re_answer_sdp.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_rtc_log_refcount.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_send_data_channel_get_stats_after_disconnect.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_sendonly_recvonly.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_signaling.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_signaling_message.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_signaling_notify.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_simulcast.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_sora_disconnect.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_type_disconnect.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_vad.py +0 -0
- {sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/tests/test_version.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2026.2.0.dev3
|
{sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk/sora_sdk_ext.cpython-312-darwin.so
RENAMED
|
Binary file
|
|
@@ -185,6 +185,8 @@ class SoraConnection:
|
|
|
185
185
|
|
|
186
186
|
def send_data_channel(self, label: str, data: bytes) -> bool: ...
|
|
187
187
|
|
|
188
|
+
def send_rpc(self, id: int | None, method: str, params: object | None = None) -> bool: ...
|
|
189
|
+
|
|
188
190
|
def get_stats(self) -> str: ...
|
|
189
191
|
|
|
190
192
|
@property
|
|
@@ -40,6 +40,7 @@ tests/test_openh264_simulcast.py
|
|
|
40
40
|
tests/test_opus.py
|
|
41
41
|
tests/test_raspberry_pi.py
|
|
42
42
|
tests/test_re_offer_re_answer_sdp.py
|
|
43
|
+
tests/test_rpc.py
|
|
43
44
|
tests/test_rtc_log_refcount.py
|
|
44
45
|
tests/test_send_data_channel_get_stats_after_disconnect.py
|
|
45
46
|
tests/test_sendonly_recvonly.py
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sora の RPC 機能 (JSON-RPC 2.0 over DataChannel) の E2E テスト。
|
|
3
|
+
|
|
4
|
+
SoraConnection.send_rpc() が rpc ラベルへ JSON-RPC 2.0 のリクエストを送信し、
|
|
5
|
+
応答が on_rpc に届くことを確認する。rpc ラベルは Sora の RPC 機能が有効な場合に
|
|
6
|
+
だけ offer に含まれるため、rpc ラベルを必要とするテストは含まれない環境では
|
|
7
|
+
送信できないことを確認して skip する。
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from queue import Empty
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import pytest
|
|
16
|
+
from client import SoraClient, SoraRole
|
|
17
|
+
|
|
18
|
+
NOT_EXIST_METHOD = "9999.0.0/not_exist"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _create_rpc_client(settings) -> SoraClient:
|
|
22
|
+
"""
|
|
23
|
+
RPC のテストで使うクライアントを生成する (Sora への接続は with 文で行う)。
|
|
24
|
+
|
|
25
|
+
rpc ラベルは DataChannel 経由のシグナリングでのみ使うため data_channel_signaling を
|
|
26
|
+
有効にする。RPC は音声・映像とは独立して使えるため両方無効にするが、この構成では
|
|
27
|
+
ユーザー定義の DataChannel が 1 つも無いと Sora が接続メッセージを 4490
|
|
28
|
+
INVALID-MESSAGE で拒否するため、ダミーの #test ラベルを 1 つ用意する。
|
|
29
|
+
"""
|
|
30
|
+
return SoraClient(
|
|
31
|
+
settings,
|
|
32
|
+
SoraRole.SENDONLY,
|
|
33
|
+
data_channel_signaling=True,
|
|
34
|
+
audio=False,
|
|
35
|
+
video=False,
|
|
36
|
+
data_channels=[{"label": "#test", "direction": "sendonly"}],
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_send_rpc_request_and_response(settings):
|
|
41
|
+
"""
|
|
42
|
+
send_rpc() で送信した JSON-RPC 2.0 のリクエストに応答が返ることを確認する。
|
|
43
|
+
|
|
44
|
+
前提:
|
|
45
|
+
- RPC が有効な Sora に data_channel_signaling を有効にして接続する
|
|
46
|
+
- 払い出される rpc_methods に依存しないよう、存在しないメソッドを指定する
|
|
47
|
+
|
|
48
|
+
期待:
|
|
49
|
+
- send_rpc() が True を返す
|
|
50
|
+
- 応答が on_rpc に届き、送信した id と一致する
|
|
51
|
+
- 存在しないメソッドなので error を含む応答になる
|
|
52
|
+
- params に None / Array を指定した場合と、params を省略した場合も送信できる
|
|
53
|
+
"""
|
|
54
|
+
with _create_rpc_client(settings) as client:
|
|
55
|
+
if not client.wait_rpc_ready(timeout=5):
|
|
56
|
+
# rpc ラベルが使えない環境では送信されず False が返る
|
|
57
|
+
assert client.send_rpc(1, NOT_EXIST_METHOD, {"key": "value"}) is False
|
|
58
|
+
pytest.skip("rpc ラベルが使えない環境のため送信できない")
|
|
59
|
+
|
|
60
|
+
# 送信した id がそのまま応答に含まれることを確認する (0 と 2^64-1 は境界値)
|
|
61
|
+
for request_id in [0, 1, 2**64 - 1]:
|
|
62
|
+
assert client.send_rpc(request_id, NOT_EXIST_METHOD, {"key": "value"})
|
|
63
|
+
|
|
64
|
+
response = client.recv_rpc(timeout=5)
|
|
65
|
+
assert response["id"] == request_id
|
|
66
|
+
assert "error" in response
|
|
67
|
+
|
|
68
|
+
# params に None を指定した場合は params を含めずに送信する
|
|
69
|
+
assert client.send_rpc(2, NOT_EXIST_METHOD, None)
|
|
70
|
+
|
|
71
|
+
response = client.recv_rpc(timeout=5)
|
|
72
|
+
assert response["id"] == 2
|
|
73
|
+
|
|
74
|
+
# params には Object だけでなく Array も指定できる
|
|
75
|
+
assert client.send_rpc(3, NOT_EXIST_METHOD, [])
|
|
76
|
+
|
|
77
|
+
response = client.recv_rpc(timeout=5)
|
|
78
|
+
assert response["id"] == 3
|
|
79
|
+
|
|
80
|
+
# params を省略した 2 引数呼び出しではバインディングの既定値 (None) が使われる。
|
|
81
|
+
# ヘルパは常に params を渡すため、ここでは SDK を直接呼ぶ
|
|
82
|
+
assert client._connection.send_rpc(4, NOT_EXIST_METHOD)
|
|
83
|
+
|
|
84
|
+
response = client.recv_rpc(timeout=5)
|
|
85
|
+
assert response["id"] == 4
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_send_rpc_notification_has_no_response(settings):
|
|
89
|
+
"""
|
|
90
|
+
id に None を指定した Notification には Sora が応答を返さないことを確認する。
|
|
91
|
+
|
|
92
|
+
前提:
|
|
93
|
+
- RPC が有効な Sora に接続する
|
|
94
|
+
- id に None を指定してリクエストを送る
|
|
95
|
+
|
|
96
|
+
期待:
|
|
97
|
+
- send_rpc() が True を返す
|
|
98
|
+
- 応答が返らないため recv_rpc() が Empty でタイムアウトする
|
|
99
|
+
"""
|
|
100
|
+
with _create_rpc_client(settings) as client:
|
|
101
|
+
if not client.wait_rpc_ready(timeout=5):
|
|
102
|
+
pytest.skip("rpc ラベルが使えない環境のため送信できない")
|
|
103
|
+
|
|
104
|
+
assert client.send_rpc(None, NOT_EXIST_METHOD, {"key": "value"})
|
|
105
|
+
|
|
106
|
+
# Notification には Sora が応答を返さない
|
|
107
|
+
with pytest.raises(Empty):
|
|
108
|
+
client.recv_rpc(timeout=3)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_send_rpc_invalid_params(settings):
|
|
112
|
+
"""
|
|
113
|
+
params に送信できない値を指定したときの挙動を確認する。
|
|
114
|
+
|
|
115
|
+
JSON-RPC 2.0 の params は Object か Array でなければならないため、それ以外の値に
|
|
116
|
+
変換される場合は送信せず False が返る。JSON の値として扱えない型の場合は既存の
|
|
117
|
+
Sora::ConvertJsonValue() と同じく TypeError、int64 の範囲を超える整数とキーが
|
|
118
|
+
文字列でない dict は同じく RuntimeError になる。TypeError と RuntimeError は引数の
|
|
119
|
+
変換時に発生するため rpc ラベルの有無に依存しない。False はラベルが無い場合も
|
|
120
|
+
Object / Array 以外の場合も返る。
|
|
121
|
+
"""
|
|
122
|
+
with _create_rpc_client(settings) as client:
|
|
123
|
+
# 文字列・整数・浮動小数点数・真偽値は JSON の値には変換できるが params の要件を満たさない
|
|
124
|
+
for params in ["not-structured", 1, 1.5, True]:
|
|
125
|
+
assert client.send_rpc(1, NOT_EXIST_METHOD, params) is False
|
|
126
|
+
|
|
127
|
+
# JSON の値として扱えない型は TypeError になる
|
|
128
|
+
# 0.1 は float32 で厳密に表現できないため (Sora::ConvertJsonValue() の既知の制限)
|
|
129
|
+
for invalid_params in [
|
|
130
|
+
{"key": set()},
|
|
131
|
+
{"key": (1, 2)},
|
|
132
|
+
{"key": b"bytes"},
|
|
133
|
+
{"key": 0.1},
|
|
134
|
+
]:
|
|
135
|
+
with pytest.raises(TypeError, match="Invalid JSON value in params"):
|
|
136
|
+
client.send_rpc(1, NOT_EXIST_METHOD, invalid_params)
|
|
137
|
+
|
|
138
|
+
# int64 の範囲を超える整数は nb::cast_error 由来の RuntimeError になる
|
|
139
|
+
with pytest.raises(RuntimeError):
|
|
140
|
+
client.send_rpc(1, NOT_EXIST_METHOD, {"key": 2**70})
|
|
141
|
+
|
|
142
|
+
# キーが文字列でない dict も nb::cast_error 由来の RuntimeError になる
|
|
143
|
+
with pytest.raises(RuntimeError):
|
|
144
|
+
client.send_rpc(1, NOT_EXIST_METHOD, {1: "value"})
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_send_rpc_invalid_id(settings):
|
|
148
|
+
"""
|
|
149
|
+
id に None でも 0 以上 2^64-1 以下の整数でもない値を指定すると TypeError になることを確認する。
|
|
150
|
+
|
|
151
|
+
C++ SDK の SendRpc() の id は std::optional<uint64_t> のため、文字列・負の整数・
|
|
152
|
+
2^64 以上の整数は指定できない。
|
|
153
|
+
"""
|
|
154
|
+
with _create_rpc_client(settings) as client:
|
|
155
|
+
# 型注釈 (int | None) では通せない値も実行時に渡すため、Any のリストを経由する
|
|
156
|
+
invalid_ids: list[Any] = ["id", -1, 2**64]
|
|
157
|
+
for invalid_id in invalid_ids:
|
|
158
|
+
with pytest.raises(TypeError):
|
|
159
|
+
client.send_rpc(invalid_id, NOT_EXIST_METHOD, {"key": "value"})
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_send_rpc_without_rpc_label_returns_false(settings):
|
|
163
|
+
"""
|
|
164
|
+
rpc ラベルが使えない接続では send_rpc() が送信せず False を返すことを確認する。
|
|
165
|
+
|
|
166
|
+
前提:
|
|
167
|
+
- DataChannel 経由のシグナリングを使わずに接続する (offer の data_channels に
|
|
168
|
+
rpc ラベルが含まれない)
|
|
169
|
+
|
|
170
|
+
期待:
|
|
171
|
+
- send_rpc() が送信せず False を返す
|
|
172
|
+
- Sora の RPC 機能の有効無効に依存せず検証できる
|
|
173
|
+
"""
|
|
174
|
+
with SoraClient(
|
|
175
|
+
settings,
|
|
176
|
+
SoraRole.RECVONLY,
|
|
177
|
+
audio=True,
|
|
178
|
+
video=True,
|
|
179
|
+
data_channel_signaling=False,
|
|
180
|
+
ignore_disconnect_websocket=False,
|
|
181
|
+
) as client:
|
|
182
|
+
assert client.send_rpc(1, NOT_EXIST_METHOD, {"key": "value"}) is False
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_send_rpc_after_disconnect_raises_runtime_error(settings):
|
|
186
|
+
"""
|
|
187
|
+
disconnect() 後の send_rpc() が SEGV ではなく RuntimeError になることを確認する。
|
|
188
|
+
|
|
189
|
+
前提:
|
|
190
|
+
- Sora に接続してから disconnect() する
|
|
191
|
+
- disconnect() 後の SoraConnection インスタンスをそのまま使う
|
|
192
|
+
|
|
193
|
+
期待:
|
|
194
|
+
- RuntimeError が発生する (メッセージに Already disconnected を含む)
|
|
195
|
+
- プロセスが SEGV で落ちない
|
|
196
|
+
"""
|
|
197
|
+
with _create_rpc_client(settings) as client:
|
|
198
|
+
connection = client._connection
|
|
199
|
+
client.disconnect()
|
|
200
|
+
|
|
201
|
+
with pytest.raises(RuntimeError, match="Already disconnected"):
|
|
202
|
+
connection.send_rpc(1, NOT_EXIST_METHOD, {"key": "value"})
|
|
@@ -8,6 +8,8 @@ def test_websocket_signaling_only_type_switched(settings):
|
|
|
8
8
|
"""
|
|
9
9
|
- WebSocket シグナリングのみ
|
|
10
10
|
- type: switched 送られてこない
|
|
11
|
+
- signaling の redirect で張り直した WebSocket のクローズ (SELF-CLOSED) は
|
|
12
|
+
接続中の WebSocket のクローズではないため ws_close には記録されない
|
|
11
13
|
"""
|
|
12
14
|
|
|
13
15
|
with SoraClient(
|
|
@@ -29,6 +31,8 @@ def test_hybrid_signaling_type_switched(settings):
|
|
|
29
31
|
"""
|
|
30
32
|
- WebSocket シグナリング + DataChannel シグナリング
|
|
31
33
|
- type: switched 送られてくる
|
|
34
|
+
- signaling の redirect で張り直した WebSocket のクローズ (SELF-CLOSED) は
|
|
35
|
+
接続中の WebSocket のクローズではないため ws_close には記録されない
|
|
32
36
|
"""
|
|
33
37
|
with SoraClient(
|
|
34
38
|
settings,
|
|
@@ -49,7 +53,7 @@ def test_datachannel_signaling_only_type_switched(settings):
|
|
|
49
53
|
"""
|
|
50
54
|
- DataChannel シグナリングのみ
|
|
51
55
|
- type: switched 送られてくる
|
|
52
|
-
- Python SDK は WebSocket を自分で切断する
|
|
56
|
+
- Python SDK は WebSocket を自分で切断する (switched によるクローズは記録される)
|
|
53
57
|
"""
|
|
54
58
|
with SoraClient(
|
|
55
59
|
settings,
|
sora_sdk-2026.2.0.dev2/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2026.2.0.dev2
|
|
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
|
{sora_sdk-2026.2.0.dev2 → sora_sdk-2026.2.0.dev3}/src/sora_sdk.egg-info/dependency_links.txt
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
|