tosnativeclient 1.0.1__tar.gz → 1.0.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.
Potentially problematic release.
This version of tosnativeclient might be problematic. Click here for more details.
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/Cargo.lock +18 -1
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/Cargo.toml +2 -1
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/PKG-INFO +1 -1
- tosnativeclient-1.0.2/python/tosnativeclient/__init__.py +25 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/python/tosnativeclient/tosnativeclient.pyi +56 -56
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/list_stream.rs +24 -41
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/tos_client.rs +20 -15
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/write_stream.rs +3 -5
- tosnativeclient-1.0.1/python/tosnativeclient/__init__.py +0 -21
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/.github/workflows/CI.yml +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/.gitignore +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/build.sh +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/pyproject.toml +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/lib.rs +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/read_stream.rs +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/tos_error.rs +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/tos_model.rs +0 -0
- {tosnativeclient-1.0.1 → tosnativeclient-1.0.2}/src/tos_raw_client.rs +0 -0
|
@@ -472,6 +472,12 @@ version = "0.5.0"
|
|
|
472
472
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
473
473
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
474
474
|
|
|
475
|
+
[[package]]
|
|
476
|
+
name = "hermit-abi"
|
|
477
|
+
version = "0.5.2"
|
|
478
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
479
|
+
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
|
480
|
+
|
|
475
481
|
[[package]]
|
|
476
482
|
name = "hex"
|
|
477
483
|
version = "0.4.3"
|
|
@@ -859,6 +865,16 @@ dependencies = [
|
|
|
859
865
|
"autocfg",
|
|
860
866
|
]
|
|
861
867
|
|
|
868
|
+
[[package]]
|
|
869
|
+
name = "num_cpus"
|
|
870
|
+
version = "1.17.0"
|
|
871
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
872
|
+
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
|
873
|
+
dependencies = [
|
|
874
|
+
"hermit-abi",
|
|
875
|
+
"libc",
|
|
876
|
+
]
|
|
877
|
+
|
|
862
878
|
[[package]]
|
|
863
879
|
name = "object"
|
|
864
880
|
version = "0.36.7"
|
|
@@ -1505,13 +1521,14 @@ dependencies = [
|
|
|
1505
1521
|
|
|
1506
1522
|
[[package]]
|
|
1507
1523
|
name = "tosnativeclient"
|
|
1508
|
-
version = "1.0.
|
|
1524
|
+
version = "1.0.2"
|
|
1509
1525
|
dependencies = [
|
|
1510
1526
|
"arc-swap",
|
|
1511
1527
|
"async-channel",
|
|
1512
1528
|
"async-trait",
|
|
1513
1529
|
"bytes",
|
|
1514
1530
|
"futures-util",
|
|
1531
|
+
"num_cpus",
|
|
1515
1532
|
"pyo3",
|
|
1516
1533
|
"tokio",
|
|
1517
1534
|
"tracing",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "tosnativeclient"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.2"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
publish = false
|
|
6
6
|
authors = ["xiangshijian"]
|
|
@@ -23,3 +23,4 @@ async-trait = "0.1.88"
|
|
|
23
23
|
futures-util = "0.3.30"
|
|
24
24
|
async-channel = "2.3.1"
|
|
25
25
|
tracing = { version = "0.1.41", features = ["log"] }
|
|
26
|
+
num_cpus = "1.17.0"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .tosnativeclient import TosClient, ListStream, ListObjectsResult, TosObject, ReadStream, WriteStream, TosError, \
|
|
2
|
+
TosException, TosRawClient, \
|
|
3
|
+
HeadObjectInput, HeadObjectOutput, GetObjectOutput, DeleteObjectInput, DeleteObjectOutput, GetObjectInput, \
|
|
4
|
+
PutObjectFromBufferInput, PutObjectFromFileInput, PutObjectOutput
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
'TosError',
|
|
8
|
+
'TosException',
|
|
9
|
+
'TosClient',
|
|
10
|
+
'ListStream',
|
|
11
|
+
'ListObjectsResult',
|
|
12
|
+
'TosObject',
|
|
13
|
+
'ReadStream',
|
|
14
|
+
'WriteStream',
|
|
15
|
+
'TosRawClient',
|
|
16
|
+
'HeadObjectInput',
|
|
17
|
+
'HeadObjectOutput',
|
|
18
|
+
'DeleteObjectInput',
|
|
19
|
+
'DeleteObjectOutput',
|
|
20
|
+
'GetObjectInput',
|
|
21
|
+
'GetObjectOutput',
|
|
22
|
+
'PutObjectFromBufferInput',
|
|
23
|
+
'PutObjectFromFileInput',
|
|
24
|
+
'PutObjectOutput'
|
|
25
|
+
]
|
|
@@ -3,31 +3,27 @@ from typing import List, Dict
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
part_size: int
|
|
12
|
-
max_retry_count: int
|
|
13
|
-
max_prefetch_tasks: int
|
|
6
|
+
class TosError(object):
|
|
7
|
+
message: str
|
|
8
|
+
status_code: Optional[int]
|
|
9
|
+
ec: str
|
|
10
|
+
request_id: str
|
|
14
11
|
|
|
15
|
-
def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', part_size: int = 8388608,
|
|
16
|
-
max_retry_count: int = 3, max_prefetch_tasks: int = 3, directives: str = '', directory: str = '',
|
|
17
|
-
file_name_prefix: str = '', shared_prefetch_tasks: int = 20):
|
|
18
|
-
...
|
|
19
12
|
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
class TosException(Exception):
|
|
14
|
+
args: List[TosError]
|
|
22
15
|
|
|
23
|
-
def head_object(self, bucket: str, key: str) -> TosObject:
|
|
24
|
-
...
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
class TosObject(object):
|
|
18
|
+
bucket: str
|
|
19
|
+
key: str
|
|
20
|
+
size: int
|
|
21
|
+
etag: str
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
|
|
24
|
+
class ListObjectsResult(object):
|
|
25
|
+
contents: List[TosObject]
|
|
26
|
+
common_prefixes: List[str]
|
|
31
27
|
|
|
32
28
|
|
|
33
29
|
class ListStream(object):
|
|
@@ -43,18 +39,6 @@ class ListStream(object):
|
|
|
43
39
|
def close(self) -> None: ...
|
|
44
40
|
|
|
45
41
|
|
|
46
|
-
class ListObjectsResult(object):
|
|
47
|
-
contents: List[TosObject]
|
|
48
|
-
common_prefixes: List[str]
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class TosObject(object):
|
|
52
|
-
bucket: str
|
|
53
|
-
key: str
|
|
54
|
-
size: int
|
|
55
|
-
etag: str
|
|
56
|
-
|
|
57
|
-
|
|
58
42
|
class ReadStream(object):
|
|
59
43
|
bucket: str
|
|
60
44
|
key: str
|
|
@@ -80,44 +64,30 @@ class WriteStream(object):
|
|
|
80
64
|
...
|
|
81
65
|
|
|
82
66
|
|
|
83
|
-
class
|
|
84
|
-
message: str
|
|
85
|
-
status_code: Optional[int]
|
|
86
|
-
ec: str
|
|
87
|
-
request_id: str
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
class TosException(Exception):
|
|
91
|
-
args: List[TosError]
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class TosRawClient(object):
|
|
67
|
+
class TosClient(object):
|
|
95
68
|
region: str
|
|
96
69
|
endpoint: str
|
|
97
70
|
ak: str
|
|
98
71
|
sk: str
|
|
99
|
-
|
|
100
|
-
request_timeout: int
|
|
101
|
-
max_connections: int
|
|
72
|
+
part_size: int
|
|
102
73
|
max_retry_count: int
|
|
74
|
+
max_prefetch_tasks: int
|
|
103
75
|
|
|
104
|
-
def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '',
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def head_object(self, input: HeadObjectInput) -> HeadObjectOutput:
|
|
76
|
+
def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', part_size: int = 8388608,
|
|
77
|
+
max_retry_count: int = 3, max_prefetch_tasks: int = 3, directives: str = '', directory: str = '',
|
|
78
|
+
file_name_prefix: str = '', shared_prefetch_tasks: int = 20):
|
|
109
79
|
...
|
|
110
80
|
|
|
111
|
-
def
|
|
81
|
+
def list_objects(self, bucket: str, prefix: str = '', max_keys: int = 1000, delimiter: str = '') -> ListStream:
|
|
112
82
|
...
|
|
113
83
|
|
|
114
|
-
def
|
|
84
|
+
def head_object(self, bucket: str, key: str) -> TosObject:
|
|
115
85
|
...
|
|
116
86
|
|
|
117
|
-
def
|
|
87
|
+
def get_object(self, bucket: str, key: str, etag: str, size: int) -> ReadStream:
|
|
118
88
|
...
|
|
119
89
|
|
|
120
|
-
def
|
|
90
|
+
def put_object(self, bucket: str, key: str, storage_class: Optional[str] = '') -> WriteStream:
|
|
121
91
|
...
|
|
122
92
|
|
|
123
93
|
|
|
@@ -209,3 +179,33 @@ class PutObjectOutput(object):
|
|
|
209
179
|
etag: str
|
|
210
180
|
version_id: str
|
|
211
181
|
hash_crc64ecma: int
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class TosRawClient(object):
|
|
185
|
+
region: str
|
|
186
|
+
endpoint: str
|
|
187
|
+
ak: str
|
|
188
|
+
sk: str
|
|
189
|
+
connection_timeout: int
|
|
190
|
+
request_timeout: int
|
|
191
|
+
max_connections: int
|
|
192
|
+
max_retry_count: int
|
|
193
|
+
|
|
194
|
+
def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', connection_timeout: int = 10000,
|
|
195
|
+
request_timeout: int = 120000, max_connections: int = 1024, max_retry_count: int = 3):
|
|
196
|
+
...
|
|
197
|
+
|
|
198
|
+
def head_object(self, input: HeadObjectInput) -> HeadObjectOutput:
|
|
199
|
+
...
|
|
200
|
+
|
|
201
|
+
def delete_object(self, input: DeleteObjectInput) -> DeleteObjectOutput:
|
|
202
|
+
...
|
|
203
|
+
|
|
204
|
+
def get_object(self, input: GetObjectInput) -> GetObjectOutput:
|
|
205
|
+
...
|
|
206
|
+
|
|
207
|
+
def put_object_from_buffer(self, input: PutObjectFromBufferInput) -> PutObjectOutput:
|
|
208
|
+
...
|
|
209
|
+
|
|
210
|
+
def put_object_from_file(self, input: PutObjectFromFileInput) -> PutObjectOutput:
|
|
211
|
+
...
|
|
@@ -46,14 +46,11 @@ impl ListStream {
|
|
|
46
46
|
return Err(map_error_from_string("ListStream is closed"));
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
*pg = slf.list_background(slf.py());
|
|
53
|
-
}
|
|
49
|
+
let mut pg = slf.paginator.write().unwrap();
|
|
50
|
+
if pg.is_none() {
|
|
51
|
+
*pg = slf.list_background(slf.py());
|
|
54
52
|
}
|
|
55
|
-
|
|
56
|
-
slf.next_page(slf.paginator.read().unwrap().as_ref(), slf.py())
|
|
53
|
+
slf.next_page(pg.as_ref(), slf.py())
|
|
57
54
|
}
|
|
58
55
|
|
|
59
56
|
pub fn close(&self) {
|
|
@@ -100,67 +97,54 @@ impl ListStream {
|
|
|
100
97
|
py.allow_threads(|| {
|
|
101
98
|
self.runtime.spawn(async move {
|
|
102
99
|
let mut need_break = false;
|
|
103
|
-
if input.delimiter() == "
|
|
104
|
-
let mut prefixes = Vec::with_capacity(16);
|
|
105
|
-
let mut last_page_end = false;
|
|
100
|
+
if input.delimiter() == "" {
|
|
106
101
|
loop {
|
|
107
|
-
if last_page_end {
|
|
108
|
-
if prefixes.is_empty() {
|
|
109
|
-
let _ = sender
|
|
110
|
-
.send((
|
|
111
|
-
true,
|
|
112
|
-
Err(TosError::TosClientError {
|
|
113
|
-
message: "invalid status error".to_string(),
|
|
114
|
-
cause: None,
|
|
115
|
-
}),
|
|
116
|
-
))
|
|
117
|
-
.await;
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
let prefix = prefixes.remove(0);
|
|
122
|
-
input.set_prefix(prefix);
|
|
123
|
-
input.set_start_after("");
|
|
124
|
-
input.set_continuation_token("");
|
|
125
|
-
last_page_end = false;
|
|
126
|
-
}
|
|
127
102
|
let result = client.list_objects_type2(&input).await;
|
|
128
103
|
if let Ok(ref o) = result {
|
|
129
104
|
if o.is_truncated() {
|
|
130
105
|
input.set_continuation_token(o.next_continuation_token());
|
|
131
106
|
} else {
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
for cp in o.common_prefixes() {
|
|
136
|
-
prefixes.push(cp.prefix().to_string());
|
|
107
|
+
need_break = true;
|
|
137
108
|
}
|
|
138
|
-
need_break = last_page_end && prefixes.is_empty();
|
|
139
109
|
} else {
|
|
140
110
|
need_break = true;
|
|
141
111
|
}
|
|
142
|
-
|
|
143
112
|
if let Err(_) = sender.send((need_break, result)).await {
|
|
144
|
-
need_break = true
|
|
113
|
+
need_break = true
|
|
145
114
|
}
|
|
146
115
|
if need_break {
|
|
147
116
|
break;
|
|
148
117
|
}
|
|
149
118
|
}
|
|
150
119
|
} else {
|
|
120
|
+
let mut prefixes = Vec::with_capacity(16);
|
|
121
|
+
let mut last_page_end = false;
|
|
151
122
|
loop {
|
|
123
|
+
if last_page_end {
|
|
124
|
+
let prefix = prefixes.remove(0);
|
|
125
|
+
input.set_prefix(prefix);
|
|
126
|
+
input.set_start_after("");
|
|
127
|
+
input.set_continuation_token("");
|
|
128
|
+
last_page_end = false;
|
|
129
|
+
}
|
|
152
130
|
let result = client.list_objects_type2(&input).await;
|
|
153
131
|
if let Ok(ref o) = result {
|
|
154
132
|
if o.is_truncated() {
|
|
155
133
|
input.set_continuation_token(o.next_continuation_token());
|
|
156
134
|
} else {
|
|
157
|
-
|
|
135
|
+
last_page_end = true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
for cp in o.common_prefixes() {
|
|
139
|
+
prefixes.push(cp.prefix().to_string());
|
|
158
140
|
}
|
|
141
|
+
need_break = last_page_end && prefixes.is_empty();
|
|
159
142
|
} else {
|
|
160
143
|
need_break = true;
|
|
161
144
|
}
|
|
145
|
+
|
|
162
146
|
if let Err(_) = sender.send((need_break, result)).await {
|
|
163
|
-
need_break = true
|
|
147
|
+
need_break = true;
|
|
164
148
|
}
|
|
165
149
|
if need_break {
|
|
166
150
|
break;
|
|
@@ -169,7 +153,6 @@ impl ListStream {
|
|
|
169
153
|
}
|
|
170
154
|
});
|
|
171
155
|
});
|
|
172
|
-
|
|
173
156
|
Some(Paginator {
|
|
174
157
|
is_end: ArcSwap::new(Arc::new(false)),
|
|
175
158
|
last_err: ArcSwap::new(Arc::new(None)),
|
|
@@ -10,8 +10,7 @@ use std::future::Future;
|
|
|
10
10
|
use std::sync::atomic::{AtomicIsize, Ordering};
|
|
11
11
|
use std::sync::Arc;
|
|
12
12
|
use std::time::Duration;
|
|
13
|
-
use tokio::runtime;
|
|
14
|
-
use tokio::runtime::{Handle, Runtime};
|
|
13
|
+
use tokio::runtime::{Builder, Handle, Runtime};
|
|
15
14
|
use tracing_appender::non_blocking::WorkerGuard;
|
|
16
15
|
use ve_tos_rust_sdk::asynchronous::object::ObjectAPI;
|
|
17
16
|
use ve_tos_rust_sdk::asynchronous::tos;
|
|
@@ -101,7 +100,12 @@ impl TosClient {
|
|
|
101
100
|
_guard = Some(init_tracing_log(directives, directory, file_name_prefix));
|
|
102
101
|
}
|
|
103
102
|
|
|
104
|
-
let
|
|
103
|
+
let logical_cores = num_cpus::get();
|
|
104
|
+
let mut builder = Builder::new_multi_thread();
|
|
105
|
+
if logical_cores > 0 {
|
|
106
|
+
builder.worker_threads(logical_cores);
|
|
107
|
+
}
|
|
108
|
+
let runtime = Arc::new(builder.enable_all().build()?);
|
|
105
109
|
let mut clients = Vec::with_capacity(2);
|
|
106
110
|
for _ in 0..2 {
|
|
107
111
|
match tos::builder()
|
|
@@ -188,22 +192,23 @@ impl TosClient {
|
|
|
188
192
|
|
|
189
193
|
#[pyo3(signature = (bucket, key, storage_class=None))]
|
|
190
194
|
pub fn put_object(
|
|
191
|
-
|
|
195
|
+
slf: PyRef<'_, Self>,
|
|
192
196
|
bucket: String,
|
|
193
197
|
key: String,
|
|
194
198
|
storage_class: Option<String>,
|
|
195
199
|
) -> PyResult<WriteStream> {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
200
|
+
let client = slf.wclient.clone();
|
|
201
|
+
let runtime = slf.runtime.clone();
|
|
202
|
+
let part_size = slf.part_size;
|
|
203
|
+
slf.py().allow_threads(|| {
|
|
204
|
+
runtime.clone().block_on(async move {
|
|
205
|
+
match WriteStream::new(client, runtime, bucket, key, storage_class, part_size).await
|
|
206
|
+
{
|
|
207
|
+
Err(ex) => Err(map_tos_error(ex)),
|
|
208
|
+
Ok(ws) => Ok(ws),
|
|
209
|
+
}
|
|
210
|
+
})
|
|
211
|
+
})
|
|
207
212
|
}
|
|
208
213
|
}
|
|
209
214
|
|
|
@@ -74,7 +74,7 @@ impl WriteStream {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
impl WriteStream {
|
|
77
|
-
pub(crate) fn new(
|
|
77
|
+
pub(crate) async fn new(
|
|
78
78
|
client: Arc<InnerTosClient>,
|
|
79
79
|
runtime: Arc<Runtime>,
|
|
80
80
|
bucket: String,
|
|
@@ -93,10 +93,8 @@ impl WriteStream {
|
|
|
93
93
|
let _key = key.clone();
|
|
94
94
|
let _storage_class = storage_class.clone();
|
|
95
95
|
|
|
96
|
-
let object_writer =
|
|
97
|
-
ObjectWriter::new(client, _bucket, _key, _storage_class, part_size).await
|
|
98
|
-
})?;
|
|
99
|
-
|
|
96
|
+
let object_writer =
|
|
97
|
+
ObjectWriter::new(client, _bucket, _key, _storage_class, part_size).await?;
|
|
100
98
|
Ok(Self {
|
|
101
99
|
object_writer: Arc::new(object_writer),
|
|
102
100
|
runtime,
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from .tosnativeclient import TosClient, ListStream, ListObjectsResult, TosObject, TosError, TosException, TosRawClient, \
|
|
2
|
-
HeadObjectInput, HeadObjectOutput, GetObjectOutput, DeleteObjectInput, DeleteObjectOutput, GetObjectInput, \
|
|
3
|
-
PutObjectFromBufferInput, PutObjectFromFileInput, PutObjectOutput
|
|
4
|
-
|
|
5
|
-
__all__ = ['TosClient',
|
|
6
|
-
'ListStream',
|
|
7
|
-
'ListObjectsResult',
|
|
8
|
-
'TosObject',
|
|
9
|
-
'TosError',
|
|
10
|
-
'TosException',
|
|
11
|
-
'TosRawClient',
|
|
12
|
-
'HeadObjectInput',
|
|
13
|
-
'HeadObjectOutput',
|
|
14
|
-
'DeleteObjectInput',
|
|
15
|
-
'DeleteObjectOutput',
|
|
16
|
-
'GetObjectInput',
|
|
17
|
-
'GetObjectOutput',
|
|
18
|
-
'PutObjectFromBufferInput',
|
|
19
|
-
'PutObjectFromFileInput',
|
|
20
|
-
'PutObjectOutput'
|
|
21
|
-
]
|
|
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
|