singlestoredb 1.2.0__cp38-abi3-macosx_10_9_universal2.whl → 1.3.0__cp38-abi3-macosx_10_9_universal2.whl
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 singlestoredb might be problematic. Click here for more details.
- _singlestoredb_accel.abi3.so +0 -0
- singlestoredb/__init__.py +1 -1
- singlestoredb/connection.py +20 -1
- singlestoredb/http/connection.py +18 -1
- singlestoredb/mysql/connection.py +80 -16
- singlestoredb/mysql/cursors.py +8 -6
- singlestoredb/utils/results.py +5 -1
- {singlestoredb-1.2.0.dist-info → singlestoredb-1.3.0.dist-info}/METADATA +1 -1
- {singlestoredb-1.2.0.dist-info → singlestoredb-1.3.0.dist-info}/RECORD +13 -13
- {singlestoredb-1.2.0.dist-info → singlestoredb-1.3.0.dist-info}/LICENSE +0 -0
- {singlestoredb-1.2.0.dist-info → singlestoredb-1.3.0.dist-info}/WHEEL +0 -0
- {singlestoredb-1.2.0.dist-info → singlestoredb-1.3.0.dist-info}/entry_points.txt +0 -0
- {singlestoredb-1.2.0.dist-info → singlestoredb-1.3.0.dist-info}/top_level.txt +0 -0
_singlestoredb_accel.abi3.so
CHANGED
|
Binary file
|
singlestoredb/__init__.py
CHANGED
singlestoredb/connection.py
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
"""SingleStoreDB connections and cursors."""
|
|
3
3
|
import abc
|
|
4
4
|
import inspect
|
|
5
|
+
import io
|
|
6
|
+
import queue
|
|
5
7
|
import re
|
|
8
|
+
import sys
|
|
6
9
|
import warnings
|
|
7
10
|
import weakref
|
|
8
11
|
from collections.abc import Mapping
|
|
@@ -33,6 +36,11 @@ from .config import get_option
|
|
|
33
36
|
from .utils.results import Description
|
|
34
37
|
from .utils.results import Result
|
|
35
38
|
|
|
39
|
+
if sys.version_info < (3, 10):
|
|
40
|
+
InfileQueue = queue.Queue
|
|
41
|
+
else:
|
|
42
|
+
InfileQueue = queue.Queue[Union[bytes, str]]
|
|
43
|
+
|
|
36
44
|
|
|
37
45
|
# DB-API settings
|
|
38
46
|
apilevel = '2.0'
|
|
@@ -496,6 +504,14 @@ class Cursor(metaclass=abc.ABCMeta):
|
|
|
496
504
|
def execute(
|
|
497
505
|
self, query: str,
|
|
498
506
|
args: Optional[Union[Sequence[Any], Dict[str, Any], Any]] = None,
|
|
507
|
+
infile_stream: Optional[ # type: ignore
|
|
508
|
+
Union[
|
|
509
|
+
io.RawIOBase,
|
|
510
|
+
io.TextIOBase,
|
|
511
|
+
Iterator[Union[bytes, str]],
|
|
512
|
+
InfileQueue,
|
|
513
|
+
]
|
|
514
|
+
] = None,
|
|
499
515
|
) -> int:
|
|
500
516
|
"""
|
|
501
517
|
Execute a SQL statement.
|
|
@@ -510,6 +526,8 @@ class Cursor(metaclass=abc.ABCMeta):
|
|
|
510
526
|
The SQL statement to execute
|
|
511
527
|
args : Sequence or dict, optional
|
|
512
528
|
Parameters to substitute into the SQL code
|
|
529
|
+
infile_stream : io.RawIOBase or io.TextIOBase or Iterator[bytes|str], optional
|
|
530
|
+
Data stream for ``LOCAL INFILE`` statement
|
|
513
531
|
|
|
514
532
|
Examples
|
|
515
533
|
--------
|
|
@@ -1339,7 +1357,8 @@ def connect(
|
|
|
1339
1357
|
autocommit : bool, optional
|
|
1340
1358
|
Enable autocommits
|
|
1341
1359
|
results_type : str, optional
|
|
1342
|
-
The form of the query results: tuples, namedtuples, dicts
|
|
1360
|
+
The form of the query results: tuples, namedtuples, dicts,
|
|
1361
|
+
numpy, polars, pandas, arrow
|
|
1343
1362
|
results_format : str, optional
|
|
1344
1363
|
Deprecated. This option has been renamed to results_type.
|
|
1345
1364
|
program_name : str, optional
|
singlestoredb/http/connection.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import datetime
|
|
4
4
|
import decimal
|
|
5
5
|
import functools
|
|
6
|
+
import io
|
|
6
7
|
import json
|
|
7
8
|
import math
|
|
8
9
|
import os
|
|
@@ -420,6 +421,14 @@ class Cursor(connection.Cursor):
|
|
|
420
421
|
def execute(
|
|
421
422
|
self, query: str,
|
|
422
423
|
args: Optional[Union[Sequence[Any], Dict[str, Any]]] = None,
|
|
424
|
+
infile_stream: Optional[ # type: ignore
|
|
425
|
+
Union[
|
|
426
|
+
io.RawIOBase,
|
|
427
|
+
io.TextIOBase,
|
|
428
|
+
Iterable[Union[bytes, str]],
|
|
429
|
+
connection.InfileQueue,
|
|
430
|
+
]
|
|
431
|
+
] = None,
|
|
423
432
|
) -> int:
|
|
424
433
|
"""
|
|
425
434
|
Execute a SQL statement.
|
|
@@ -432,7 +441,7 @@ class Cursor(connection.Cursor):
|
|
|
432
441
|
Parameters to substitute into the SQL code
|
|
433
442
|
|
|
434
443
|
"""
|
|
435
|
-
return self._execute(query, args)
|
|
444
|
+
return self._execute(query, args, infile_stream=infile_stream)
|
|
436
445
|
|
|
437
446
|
def _validate_param_subs(
|
|
438
447
|
self, query: str,
|
|
@@ -496,6 +505,14 @@ class Cursor(connection.Cursor):
|
|
|
496
505
|
self, oper: str,
|
|
497
506
|
params: Optional[Union[Sequence[Any], Dict[str, Any]]] = None,
|
|
498
507
|
is_callproc: bool = False,
|
|
508
|
+
infile_stream: Optional[ # type: ignore
|
|
509
|
+
Union[
|
|
510
|
+
io.RawIOBase,
|
|
511
|
+
io.TextIOBase,
|
|
512
|
+
Iterable[Union[bytes, str]],
|
|
513
|
+
connection.InfileQueue,
|
|
514
|
+
]
|
|
515
|
+
] = None,
|
|
499
516
|
) -> int:
|
|
500
517
|
self._descriptions = []
|
|
501
518
|
self._schemas = []
|
|
@@ -5,12 +5,15 @@
|
|
|
5
5
|
# https://dev.mysql.com/doc/refman/5.5/en/error-handling.html
|
|
6
6
|
import errno
|
|
7
7
|
import functools
|
|
8
|
+
import io
|
|
8
9
|
import os
|
|
10
|
+
import queue
|
|
9
11
|
import socket
|
|
10
12
|
import struct
|
|
11
13
|
import sys
|
|
12
14
|
import traceback
|
|
13
15
|
import warnings
|
|
16
|
+
from typing import Iterable
|
|
14
17
|
|
|
15
18
|
try:
|
|
16
19
|
import _singlestoredb_accel
|
|
@@ -353,6 +356,7 @@ class Connection(BaseConnection):
|
|
|
353
356
|
)
|
|
354
357
|
|
|
355
358
|
self._local_infile = bool(local_infile)
|
|
359
|
+
self._local_infile_stream = None
|
|
356
360
|
if self._local_infile:
|
|
357
361
|
client_flag |= CLIENT.LOCAL_FILES
|
|
358
362
|
if multi_statements:
|
|
@@ -843,7 +847,7 @@ class Connection(BaseConnection):
|
|
|
843
847
|
return self.cursorclass(self)
|
|
844
848
|
|
|
845
849
|
# The following methods are INTERNAL USE ONLY (called from Cursor)
|
|
846
|
-
def query(self, sql, unbuffered=False):
|
|
850
|
+
def query(self, sql, unbuffered=False, infile_stream=None):
|
|
847
851
|
"""
|
|
848
852
|
Run a query on the server.
|
|
849
853
|
|
|
@@ -859,8 +863,10 @@ class Connection(BaseConnection):
|
|
|
859
863
|
else:
|
|
860
864
|
if isinstance(sql, str):
|
|
861
865
|
sql = sql.encode(self.encoding, 'surrogateescape')
|
|
866
|
+
self._local_infile_stream = infile_stream
|
|
862
867
|
self._execute_command(COMMAND.COM_QUERY, sql)
|
|
863
868
|
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
|
|
869
|
+
self._local_infile_stream = None
|
|
864
870
|
return self._affected_rows
|
|
865
871
|
|
|
866
872
|
def next_result(self, unbuffered=False):
|
|
@@ -1871,24 +1877,82 @@ class LoadLocalFile:
|
|
|
1871
1877
|
def send_data(self):
|
|
1872
1878
|
"""Send data packets from the local file to the server"""
|
|
1873
1879
|
if not self.connection._sock:
|
|
1874
|
-
raise err.InterfaceError(0, '')
|
|
1880
|
+
raise err.InterfaceError(0, 'Connection is closed')
|
|
1881
|
+
|
|
1875
1882
|
conn = self.connection
|
|
1883
|
+
infile = conn._local_infile_stream
|
|
1884
|
+
|
|
1885
|
+
# 16KB is efficient enough
|
|
1886
|
+
packet_size = min(conn.max_allowed_packet, 16 * 1024)
|
|
1876
1887
|
|
|
1877
1888
|
try:
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1889
|
+
|
|
1890
|
+
if self.filename in [':stream:', b':stream:']:
|
|
1891
|
+
|
|
1892
|
+
if infile is None:
|
|
1893
|
+
raise err.OperationalError(
|
|
1894
|
+
ER.FILE_NOT_FOUND,
|
|
1895
|
+
':stream: specified for LOCAL INFILE, but no stream was supplied',
|
|
1896
|
+
)
|
|
1897
|
+
|
|
1898
|
+
# Binary IO
|
|
1899
|
+
elif isinstance(infile, io.RawIOBase):
|
|
1900
|
+
while True:
|
|
1901
|
+
chunk = infile.read(packet_size)
|
|
1902
|
+
if not chunk:
|
|
1903
|
+
break
|
|
1904
|
+
conn.write_packet(chunk)
|
|
1905
|
+
|
|
1906
|
+
# Text IO
|
|
1907
|
+
elif isinstance(infile, io.TextIOBase):
|
|
1908
|
+
while True:
|
|
1909
|
+
chunk = infile.read(packet_size)
|
|
1910
|
+
if not chunk:
|
|
1911
|
+
break
|
|
1912
|
+
conn.write_packet(chunk.encode('utf8'))
|
|
1913
|
+
|
|
1914
|
+
# Iterable of bytes or str
|
|
1915
|
+
elif isinstance(infile, Iterable):
|
|
1916
|
+
for chunk in infile:
|
|
1917
|
+
if not chunk:
|
|
1918
|
+
continue
|
|
1919
|
+
if isinstance(chunk, str):
|
|
1920
|
+
conn.write_packet(chunk.encode('utf8'))
|
|
1921
|
+
else:
|
|
1922
|
+
conn.write_packet(chunk)
|
|
1923
|
+
|
|
1924
|
+
# Queue (empty value ends the iteration)
|
|
1925
|
+
elif isinstance(infile, queue.Queue):
|
|
1926
|
+
while True:
|
|
1927
|
+
chunk = infile.get()
|
|
1928
|
+
if not chunk:
|
|
1929
|
+
break
|
|
1930
|
+
if isinstance(chunk, str):
|
|
1931
|
+
conn.write_packet(chunk.encode('utf8'))
|
|
1932
|
+
else:
|
|
1933
|
+
conn.write_packet(chunk)
|
|
1934
|
+
|
|
1935
|
+
else:
|
|
1936
|
+
raise err.OperationalError(
|
|
1937
|
+
ER.FILE_NOT_FOUND,
|
|
1938
|
+
':stream: specified for LOCAL INFILE, ' +
|
|
1939
|
+
f'but stream type is unrecognized: {infile}',
|
|
1940
|
+
)
|
|
1941
|
+
|
|
1942
|
+
else:
|
|
1943
|
+
try:
|
|
1944
|
+
with open(self.filename, 'rb') as open_file:
|
|
1945
|
+
while True:
|
|
1946
|
+
chunk = open_file.read(packet_size)
|
|
1947
|
+
if not chunk:
|
|
1948
|
+
break
|
|
1949
|
+
conn.write_packet(chunk)
|
|
1950
|
+
except OSError:
|
|
1951
|
+
raise err.OperationalError(
|
|
1952
|
+
ER.FILE_NOT_FOUND,
|
|
1953
|
+
f"Can't find file '{self.filename!s}'",
|
|
1954
|
+
)
|
|
1955
|
+
|
|
1892
1956
|
finally:
|
|
1893
1957
|
if not conn._closed:
|
|
1894
1958
|
# send the empty packet to signify we are done sending data
|
singlestoredb/mysql/cursors.py
CHANGED
|
@@ -178,7 +178,7 @@ class Cursor(BaseCursor):
|
|
|
178
178
|
|
|
179
179
|
return query
|
|
180
180
|
|
|
181
|
-
def execute(self, query, args=None):
|
|
181
|
+
def execute(self, query, args=None, infile_stream=None):
|
|
182
182
|
"""
|
|
183
183
|
Execute a query.
|
|
184
184
|
|
|
@@ -192,6 +192,8 @@ class Cursor(BaseCursor):
|
|
|
192
192
|
Query to execute.
|
|
193
193
|
args : Sequence[Any] or Dict[str, Any] or Any, optional
|
|
194
194
|
Parameters used with query. (optional)
|
|
195
|
+
infile_stream : io.BytesIO or Iterator[bytes], optional
|
|
196
|
+
Data stream for ``LOCAL INFILE`` statements
|
|
195
197
|
|
|
196
198
|
Returns
|
|
197
199
|
-------
|
|
@@ -205,7 +207,7 @@ class Cursor(BaseCursor):
|
|
|
205
207
|
|
|
206
208
|
query = self.mogrify(query, args)
|
|
207
209
|
|
|
208
|
-
result = self._query(query)
|
|
210
|
+
result = self._query(query, infile_stream=infile_stream)
|
|
209
211
|
self._executed = query
|
|
210
212
|
return result
|
|
211
213
|
|
|
@@ -387,10 +389,10 @@ class Cursor(BaseCursor):
|
|
|
387
389
|
raise IndexError('out of range')
|
|
388
390
|
self._rownumber = r
|
|
389
391
|
|
|
390
|
-
def _query(self, q):
|
|
392
|
+
def _query(self, q, infile_stream=None):
|
|
391
393
|
conn = self._get_db()
|
|
392
394
|
self._clear_result()
|
|
393
|
-
conn.query(q)
|
|
395
|
+
conn.query(q, infile_stream=infile_stream)
|
|
394
396
|
self._do_get_result()
|
|
395
397
|
return self.rowcount
|
|
396
398
|
|
|
@@ -680,10 +682,10 @@ class SSCursor(Cursor):
|
|
|
680
682
|
|
|
681
683
|
__del__ = close
|
|
682
684
|
|
|
683
|
-
def _query(self, q):
|
|
685
|
+
def _query(self, q, infile_stream=None):
|
|
684
686
|
conn = self._get_db()
|
|
685
687
|
self._clear_result()
|
|
686
|
-
conn.query(q, unbuffered=True)
|
|
688
|
+
conn.query(q, unbuffered=True, infile_stream=infile_stream)
|
|
687
689
|
self._do_get_result()
|
|
688
690
|
return self.rowcount
|
|
689
691
|
|
singlestoredb/utils/results.py
CHANGED
|
@@ -515,6 +515,8 @@ _schema_converters: Dict[
|
|
|
515
515
|
'namedtuples': _no_schema,
|
|
516
516
|
'dict': _no_schema,
|
|
517
517
|
'dicts': _no_schema,
|
|
518
|
+
'structsequence': _no_schema,
|
|
519
|
+
'structsequences': _no_schema,
|
|
518
520
|
'numpy': _description_to_numpy_schema,
|
|
519
521
|
'pandas': _description_to_numpy_schema,
|
|
520
522
|
'polars': _description_to_polars_schema,
|
|
@@ -578,4 +580,6 @@ def get_schema(
|
|
|
578
580
|
for the given format type
|
|
579
581
|
|
|
580
582
|
"""
|
|
581
|
-
|
|
583
|
+
if format in _schema_converters:
|
|
584
|
+
return _schema_converters[format](desc) or {}
|
|
585
|
+
return {}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
_singlestoredb_accel.abi3.so,sha256=
|
|
2
|
-
singlestoredb-1.
|
|
3
|
-
singlestoredb-1.
|
|
4
|
-
singlestoredb-1.
|
|
5
|
-
singlestoredb-1.
|
|
6
|
-
singlestoredb-1.
|
|
7
|
-
singlestoredb-1.
|
|
1
|
+
_singlestoredb_accel.abi3.so,sha256=UxjCadI_UT1uCyJFel3lMm2PEB7c8-x409GIYdtoVjY,206605
|
|
2
|
+
singlestoredb-1.3.0.dist-info/RECORD,,
|
|
3
|
+
singlestoredb-1.3.0.dist-info/LICENSE,sha256=Mlq78idURT-9G026aMYswwwnnrLcgzTLuXeAs5hjDLM,11341
|
|
4
|
+
singlestoredb-1.3.0.dist-info/WHEEL,sha256=_VEguvlLpUd-c8RbFMA4yMIVNMBv2LhpxYLCEQ-Bogk,113
|
|
5
|
+
singlestoredb-1.3.0.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
|
|
6
|
+
singlestoredb-1.3.0.dist-info/top_level.txt,sha256=SDtemIXf-Kp-_F2f_S6x0db33cHGOILdAEsIQZe2LZc,35
|
|
7
|
+
singlestoredb-1.3.0.dist-info/METADATA,sha256=PLBzts-ZoiYv7LrQvRGSKycJ9DJ7W2KsnLMDkFJ_1LA,5570
|
|
8
8
|
singlestoredb/auth.py,sha256=u8D9tpKzrqa4ssaHjyZnGDX1q8XBpGtuoOkTkSv7B28,7599
|
|
9
9
|
singlestoredb/config.py,sha256=H4pQxqBEGGCmVHg40VEnAdqGXHun8ougZzj-Ed6ZLH4,11822
|
|
10
|
-
singlestoredb/__init__.py,sha256=
|
|
10
|
+
singlestoredb/__init__.py,sha256=juu9u0zHHRDvLViF83NCU4pBRNBPEDElq5-VpoIoErg,1634
|
|
11
11
|
singlestoredb/types.py,sha256=FIqO1A7e0Gkk7ITmIysBy-P5S--ItbMSlYvblzqGS30,9969
|
|
12
|
-
singlestoredb/connection.py,sha256=
|
|
12
|
+
singlestoredb/connection.py,sha256=aLc9_9q5pJ2DCHbmBkWP-4KlDPGoCyB92yaQfNtcnSA,44958
|
|
13
13
|
singlestoredb/pytest.py,sha256=OyF3BO9mgxenifYhOihnzGk8WzCJ_zN5_mxe8XyFPOc,9074
|
|
14
14
|
singlestoredb/exceptions.py,sha256=HuoA6sMRL5qiCiee-_5ddTGmFbYC9Euk8TYUsh5GvTw,3234
|
|
15
15
|
singlestoredb/converters.py,sha256=t1hRMZfccWJs_WyOw-W-Kh87fxsOkpOnKXAeh_Nr-zU,20681
|
|
@@ -53,7 +53,7 @@ singlestoredb/management/workspace.py,sha256=jHNTZ_zqi80U20BS6ezJX5DLZxWX_68fV1G
|
|
|
53
53
|
singlestoredb/management/manager.py,sha256=m8I5zTmEqjMCEE4fmmVdzza8TvofhnIHvO0np0WH-Y8,8810
|
|
54
54
|
singlestoredb/management/billing_usage.py,sha256=9ighjIpcopgIyJOktBYQ6pahBZmWGHOPyyCW4gu9FGs,3735
|
|
55
55
|
singlestoredb/utils/config.py,sha256=m3Xn6hsbdKyLufSnbokhFJ9Vfaz9Qpkj1IEnIiH9oJQ,24503
|
|
56
|
-
singlestoredb/utils/results.py,sha256=
|
|
56
|
+
singlestoredb/utils/results.py,sha256=bJtaUaDiFq26IsPAKZ2FHGB7csMn94EAxLKrP4HaEEA,15277
|
|
57
57
|
singlestoredb/utils/convert_rows.py,sha256=A6up7a8Bq-eV2BXdGCotQviqp1Q7XdJ2MA9339hLYVQ,1816
|
|
58
58
|
singlestoredb/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
59
|
singlestoredb/utils/dtypes.py,sha256=1qUiB4BJFJ7rOVh2mItQssYbJupV7uq1x8uwX-Eu2Ks,5898
|
|
@@ -61,12 +61,12 @@ singlestoredb/utils/xdict.py,sha256=S9HKgrPrnu_6b7iOwa2KrW8CmU1Uqx0BWdEyogFzWbE,
|
|
|
61
61
|
singlestoredb/utils/debug.py,sha256=0JiLA37u_9CKiDGiN9BK_PtFMUku3vIcNjERWaTNRSU,349
|
|
62
62
|
singlestoredb/utils/mogrify.py,sha256=-a56IF70U6CkfadeaZgfjRSVsAD3PuqRrzPpjZlgbwY,4050
|
|
63
63
|
singlestoredb/http/__init__.py,sha256=A_2ZUCCpvRYIA6YDpPy57wL5R1eZ5SfP6I1To5nfJ2s,912
|
|
64
|
-
singlestoredb/http/connection.py,sha256=
|
|
64
|
+
singlestoredb/http/connection.py,sha256=HUYzgiGYRUblHhgDi-ghfXykGkdB9iQ3i_XVvhtqH88,39349
|
|
65
65
|
singlestoredb/mysql/protocol.py,sha256=2GG8qTXy5npqo7z2D2K5T0S8PtoUOS-hFDEXy8VConw,14451
|
|
66
|
-
singlestoredb/mysql/cursors.py,sha256=
|
|
66
|
+
singlestoredb/mysql/cursors.py,sha256=Eqe7jITRvOo4P_TxIarTumg_2PG1DcCfZ4Uo9IFdDa8,26794
|
|
67
67
|
singlestoredb/mysql/__init__.py,sha256=olUTAvkiERhDW41JXQMawkg-i0tvBEkoTkII1tt6lxU,4492
|
|
68
68
|
singlestoredb/mysql/times.py,sha256=2j7purNVnJmjhOUgwUze-r3kNlCWqxjXj-jtqOzBfZI,463
|
|
69
|
-
singlestoredb/mysql/connection.py,sha256=
|
|
69
|
+
singlestoredb/mysql/connection.py,sha256=WZZl3cWLsyuKlQfB3CzXRmXnAXcTLDBUG8eAViYEwDw,70301
|
|
70
70
|
singlestoredb/mysql/charset.py,sha256=-FlONDS_oAUF5B3mIgeHBPb_SCt4zHD33arUeBNctU0,10510
|
|
71
71
|
singlestoredb/mysql/converters.py,sha256=CVe8SDmjbIAhy1xpQ2N5OKWw6t5eWpw-EU3QTlA0Hh0,7500
|
|
72
72
|
singlestoredb/mysql/optionfile.py,sha256=DqL-rOQcqQncD5eVbPRkwZqo7Pj3Vh40VLx3E_e87TU,655
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|