mijiaAPI 3.0.4__tar.gz → 3.1.0__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.
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/CHANGELOG.md +12 -1
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/FAQ.md +2 -1
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/PKG-INFO +4 -8
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/README.md +3 -7
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI/__main__.py +3 -5
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI/apis.py +2 -2
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI/devices.py +71 -57
- mijiaapi-3.1.0/mijiaAPI/version.py +1 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI.egg-info/PKG-INFO +4 -8
- mijiaapi-3.0.4/mijiaAPI/version.py +0 -1
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/.gitignore +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/LICENSE +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/demos/test_apis.py +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/demos/test_get_statistics.py +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/demos/test_login.py +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI/__init__.py +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI/errors.py +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI/logger.py +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI/miutils.py +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI.egg-info/SOURCES.txt +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI.egg-info/dependency_links.txt +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI.egg-info/entry_points.txt +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI.egg-info/requires.txt +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/mijiaAPI.egg-info/top_level.txt +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/pyproject.toml +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/setup.cfg +0 -0
- {mijiaapi-3.0.4 → mijiaapi-3.1.0}/uv.lock +0 -0
|
@@ -2,9 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
本文档记录了项目的v1.3.7以来的重要变更。
|
|
4
4
|
|
|
5
|
+
## [3.1.0](https://github.com/Do1e/mijia-api/compare/v3.0.5...v3.1.0) - 2026-05-27
|
|
6
|
+
### new feature
|
|
7
|
+
* 删除设备属性的单位`unit`属性,因为 home.miot-spec.com 上已废弃
|
|
8
|
+
### bugfix
|
|
9
|
+
* 适配 home.miot-spec.com 新的规格页格式
|
|
10
|
+
* 修复 execute-text-directive 中 quiet 参数的类型转换
|
|
11
|
+
|
|
12
|
+
## [3.0.5](https://github.com/Do1e/mijia-api/compare/v3.0.4...v3.0.5) - 2026-01-24
|
|
13
|
+
### bugfix
|
|
14
|
+
* 蓝牙设备控制返回 code 为 1 时表示网关已经接收指令,视为成功。
|
|
15
|
+
|
|
5
16
|
## [3.0.4](https://github.com/Do1e/mijia-api/compare/v3.0.3...v3.0.4) - 2026-01-12
|
|
6
17
|
### bugfix
|
|
7
|
-
* api不可用时不对`available`进行缓存,以修复刷新token
|
|
18
|
+
* api不可用时不对`available`进行缓存,以修复刷新token成功后依然提示不可用的问题
|
|
8
19
|
|
|
9
20
|
## [3.0.3](https://github.com/Do1e/mijia-api/compare/v3.0.2...v3.0.3) - 2026-01-02
|
|
10
21
|
### new feature
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
## 扫码登录后的有效期多长?
|
|
8
8
|
|
|
9
|
-
`serviceToken`
|
|
9
|
+
用于访问API的 `serviceToken` 有效期较短,但是已实现自动刷新。
|
|
10
|
+
用于刷新的 `passToken` 有效期也许是一个月,即扫码登录后理论上可以保活一个月。但实际上截至当前 commit,我一个半月前的 `passToken` 依然有效。
|
|
10
11
|
|
|
11
12
|
## XXX设备的XXX如何获取/设置?
|
|
12
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mijiaAPI
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: A Python API for Xiaomi Mijia
|
|
5
5
|
Author-email: Do1e <i@do1e.cn>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -26,12 +26,6 @@ Dynamic: license-file
|
|
|
26
26
|
[](https://pypi.org/project/mijiaAPI/)
|
|
27
27
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
28
28
|
|
|
29
|
-
## ⚠️ 重要提醒
|
|
30
|
-
|
|
31
|
-
**v1.5.0 和 v3.0.0包含多项破坏性变更!**
|
|
32
|
-
|
|
33
|
-
如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
|
|
34
|
-
|
|
35
29
|
常见问题见 [FAQ.md](FAQ.md)。
|
|
36
30
|
|
|
37
31
|
## 安装
|
|
@@ -40,6 +34,7 @@ Dynamic: license-file
|
|
|
40
34
|
|
|
41
35
|
```bash
|
|
42
36
|
pip install mijiaAPI
|
|
37
|
+
# Or `uv add mijiaAPI` for uv users
|
|
43
38
|
```
|
|
44
39
|
|
|
45
40
|
### 从源码安装
|
|
@@ -49,7 +44,8 @@ git clone https://github.com/Do1e/mijia-api.git
|
|
|
49
44
|
cd mijia-api
|
|
50
45
|
pip install .
|
|
51
46
|
# Or `pip install -e .` for editable mode
|
|
52
|
-
# Or `
|
|
47
|
+
# Or `pip install git+https://github.com/Do1e/mijia-api.git` for direct install
|
|
48
|
+
# Or `uv add git+https://github.com/Do1e/mijia-api.git` for uv users
|
|
53
49
|
```
|
|
54
50
|
|
|
55
51
|
### aur
|
|
@@ -6,12 +6,6 @@
|
|
|
6
6
|
[](https://pypi.org/project/mijiaAPI/)
|
|
7
7
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
8
8
|
|
|
9
|
-
## ⚠️ 重要提醒
|
|
10
|
-
|
|
11
|
-
**v1.5.0 和 v3.0.0包含多项破坏性变更!**
|
|
12
|
-
|
|
13
|
-
如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
|
|
14
|
-
|
|
15
9
|
常见问题见 [FAQ.md](FAQ.md)。
|
|
16
10
|
|
|
17
11
|
## 安装
|
|
@@ -20,6 +14,7 @@
|
|
|
20
14
|
|
|
21
15
|
```bash
|
|
22
16
|
pip install mijiaAPI
|
|
17
|
+
# Or `uv add mijiaAPI` for uv users
|
|
23
18
|
```
|
|
24
19
|
|
|
25
20
|
### 从源码安装
|
|
@@ -29,7 +24,8 @@ git clone https://github.com/Do1e/mijia-api.git
|
|
|
29
24
|
cd mijia-api
|
|
30
25
|
pip install .
|
|
31
26
|
# Or `pip install -e .` for editable mode
|
|
32
|
-
# Or `
|
|
27
|
+
# Or `pip install git+https://github.com/Do1e/mijia-api.git` for direct install
|
|
28
|
+
# Or `uv add git+https://github.com/Do1e/mijia-api.git` for uv users
|
|
33
29
|
```
|
|
34
30
|
|
|
35
31
|
### aur
|
|
@@ -265,8 +265,7 @@ def get(args):
|
|
|
265
265
|
api = init_api(args.auth_path)
|
|
266
266
|
device = mijiaDevice(api, did=args.did, dev_name=args.dev_name)
|
|
267
267
|
value = device.get(args.prop_name)
|
|
268
|
-
|
|
269
|
-
print(f"{device.name} ({device.did}) 的 {args.prop_name} 值为 {value} {unit if unit else ''}")
|
|
268
|
+
print(f"{device.name} ({device.did}) 的 {args.prop_name} 值为 {value}")
|
|
270
269
|
|
|
271
270
|
def set(args):
|
|
272
271
|
api = init_api(args.auth_path)
|
|
@@ -276,8 +275,7 @@ def set(args):
|
|
|
276
275
|
except Exception as e:
|
|
277
276
|
print(f"设置 {args.dev_name} 的 {args.prop_name} 值为 {args.value} 失败: {e}")
|
|
278
277
|
return
|
|
279
|
-
|
|
280
|
-
print(f"{device.name} ({device.did}) 的 {args.prop_name} 值已设置为 {args.value} {unit if unit else ''}")
|
|
278
|
+
print(f"{device.name} ({device.did}) 的 {args.prop_name} 值已设置为 {args.value}")
|
|
281
279
|
|
|
282
280
|
def main(args):
|
|
283
281
|
args = parse_args(args)
|
|
@@ -323,7 +321,7 @@ def main(args):
|
|
|
323
321
|
raise ValueError("未找到小爱音箱设备")
|
|
324
322
|
else:
|
|
325
323
|
wifispeaker = mijiaDevice(api, dev_name=args.wifispeaker_name)
|
|
326
|
-
wifispeaker.run_action('execute-text-directive', _in=[args.run, args.quiet])
|
|
324
|
+
wifispeaker.run_action('execute-text-directive', _in=[args.run, 1 if args.quiet else 0])
|
|
327
325
|
if hasattr(args, 'func') and args.func is not None:
|
|
328
326
|
if args.func == 'get':
|
|
329
327
|
get(args)
|
|
@@ -665,7 +665,7 @@ class mijiaAPI():
|
|
|
665
665
|
uri = "/miotspec/prop/set"
|
|
666
666
|
ret_data = self._request(uri, {"params": params})
|
|
667
667
|
for ret in ret_data:
|
|
668
|
-
if ret.get("code", 0)
|
|
668
|
+
if ret.get("code", 0) not in (0, 1):
|
|
669
669
|
ret.update({"message": ERROR_CODE.get(str(ret["code"]), "未知错误")})
|
|
670
670
|
else:
|
|
671
671
|
ret.update({"message": "成功"})
|
|
@@ -741,7 +741,7 @@ class mijiaAPI():
|
|
|
741
741
|
ret = self._request(uri, {"params": param})
|
|
742
742
|
ret_data.append(ret)
|
|
743
743
|
for ret in ret_data:
|
|
744
|
-
if ret.get("code", 0)
|
|
744
|
+
if ret.get("code", 0) not in (0, 1):
|
|
745
745
|
ret.update({"message": ERROR_CODE.get(str(ret["code"]), "未知错误")})
|
|
746
746
|
else:
|
|
747
747
|
ret.update({"message": "成功"})
|
|
@@ -30,7 +30,6 @@ class DevProp():
|
|
|
30
30
|
if self.type not in ["bool", "int", "uint", "float", "string"]:
|
|
31
31
|
raise ValueError(f"不支持的类型: {self.type}, 可选类型: bool, int, uint, float, string")
|
|
32
32
|
self.rw = prop_dict["rw"]
|
|
33
|
-
self.unit = prop_dict["unit"]
|
|
34
33
|
self.range = prop_dict["range"]
|
|
35
34
|
self.value_list = prop_dict.get("value-list", None)
|
|
36
35
|
self.method = prop_dict["method"]
|
|
@@ -38,7 +37,7 @@ class DevProp():
|
|
|
38
37
|
def __str__(self):
|
|
39
38
|
lines = [
|
|
40
39
|
f" {self.name}: {self.desc}",
|
|
41
|
-
f" valuetype: {self.type}, rw: {self.rw},
|
|
40
|
+
f" valuetype: {self.type}, rw: {self.rw}, range: {self.range}"
|
|
42
41
|
]
|
|
43
42
|
|
|
44
43
|
if self.value_list:
|
|
@@ -190,7 +189,9 @@ class mijiaDevice():
|
|
|
190
189
|
method["did"] = self.did
|
|
191
190
|
method["value"] = value
|
|
192
191
|
result = self.api.set_devices_prop(method)
|
|
193
|
-
if result["code"]
|
|
192
|
+
if result["code"] == 1:
|
|
193
|
+
logger.warning(f"网关已经接收指令,无法判断是否设置成功: {self.name} -> {name}, 值: {value}")
|
|
194
|
+
elif result["code"] != 0:
|
|
194
195
|
raise DeviceSetError(self.name, name, result["code"])
|
|
195
196
|
time.sleep(self.sleep_time)
|
|
196
197
|
logger.debug(f"设置属性: {self.name} -> {name}, 值: {value}, 结果: {result}")
|
|
@@ -228,7 +229,9 @@ class mijiaDevice():
|
|
|
228
229
|
raise ValueError(f"无效的参数: {k}. 请勿使用以下参数 ({', '.join(method.keys())})")
|
|
229
230
|
method[k] = v
|
|
230
231
|
result = self.api.run_action(method)
|
|
231
|
-
if result["code"]
|
|
232
|
+
if result["code"] == 1:
|
|
233
|
+
logger.warning(f"网关已经接收指令,无法判断是否执行成功: {self.name} -> {name}")
|
|
234
|
+
elif result["code"] != 0:
|
|
232
235
|
raise DeviceActionError(self.name, name, result["code"])
|
|
233
236
|
time.sleep(self.sleep_time)
|
|
234
237
|
logger.debug(f"执行动作: {self.name} -> {name}, 结果: {result}")
|
|
@@ -256,7 +259,6 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
|
|
|
256
259
|
- description (str): 属性描述
|
|
257
260
|
- type (str): 属性数据类型(int、uint、float、bool、string)
|
|
258
261
|
- rw (str): 读写权限('r' 可读,'w' 可写,'rw' 可读写)
|
|
259
|
-
- unit (str): 属性单位
|
|
260
262
|
- range (list): 属性值范围 [min, max, step]
|
|
261
263
|
- value-list (list): 枚举值列表
|
|
262
264
|
- method (dict): API 调用方法参数
|
|
@@ -284,72 +286,84 @@ def get_device_info(device_model: str, cache_path: Optional[Union[str, Path]] =
|
|
|
284
286
|
})
|
|
285
287
|
if response.status_code != 200:
|
|
286
288
|
raise GetDeviceInfoError(device_model)
|
|
287
|
-
content = re.search(r"data-page=\"(.*?)
|
|
289
|
+
content = re.search(r"<script data-page=\"app\" type=\"application/json\">(.*?)</script>", response.text)
|
|
288
290
|
if content is None:
|
|
289
291
|
raise GetDeviceInfoError(device_model)
|
|
290
292
|
content = content.group(1)
|
|
291
|
-
content = json.loads(content
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
name = content["props"]["spec"]["name"]
|
|
298
|
-
model = device_model
|
|
293
|
+
content = json.loads(content)
|
|
294
|
+
|
|
295
|
+
product = content["props"]["product"]
|
|
296
|
+
name = product["name"]
|
|
297
|
+
model = product["model"]
|
|
298
|
+
i18n_zh = content["props"]["i18n"]["zh_cn"]
|
|
299
299
|
result = {
|
|
300
300
|
"name": name,
|
|
301
301
|
"model": model,
|
|
302
302
|
"properties": [],
|
|
303
303
|
"actions": []
|
|
304
304
|
}
|
|
305
|
-
services = content["props"]["
|
|
305
|
+
services = content["props"]["tree"]["services"]
|
|
306
306
|
|
|
307
307
|
properties_name = []
|
|
308
308
|
actions_name = []
|
|
309
|
-
for
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
309
|
+
for svc in services:
|
|
310
|
+
siid = svc["iid"]
|
|
311
|
+
svc_type = svc["type"]
|
|
312
|
+
for prop in svc.get("properties", []):
|
|
313
|
+
piid = prop["iid"]
|
|
314
|
+
if prop["format"].startswith("int"):
|
|
315
|
+
prop_type = "int"
|
|
316
|
+
elif prop["format"].startswith("uint"):
|
|
317
|
+
prop_type = "uint"
|
|
318
|
+
else:
|
|
319
|
+
prop_type = prop["format"]
|
|
320
|
+
access_str = "".join([
|
|
321
|
+
"r" if "read" in prop["access"] else "",
|
|
322
|
+
"w" if "write" in prop["access"] else ""
|
|
323
|
+
])
|
|
324
|
+
zh_cn = i18n_zh.get(f"service:{siid:03d}:property:{piid:03d}", "")
|
|
325
|
+
item = {
|
|
326
|
+
"name": prop["type"],
|
|
327
|
+
"description": f"{prop['description']} / {zh_cn}".rstrip(" / "),
|
|
328
|
+
"type": prop_type,
|
|
329
|
+
"rw": access_str,
|
|
330
|
+
"range": prop.get("valueRange", None),
|
|
331
|
+
"value-list": None,
|
|
332
|
+
"method": {
|
|
333
|
+
"siid": siid,
|
|
334
|
+
"piid": piid
|
|
334
335
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
act["name"] = f"{services[siid]['name']}-{act['name']}"
|
|
344
|
-
actions_name.append(act["name"])
|
|
345
|
-
result["actions"].append({
|
|
346
|
-
"name": act["name"],
|
|
347
|
-
"description": f"{act.get('description', '')} / {act.get('desc_zh_cn', '')}",
|
|
348
|
-
"method": {
|
|
349
|
-
"siid": int(siid),
|
|
350
|
-
"aiid": int(aiid)
|
|
336
|
+
}
|
|
337
|
+
if prop.get("valueList"):
|
|
338
|
+
item["value-list"] = []
|
|
339
|
+
for vl_item in prop["valueList"]:
|
|
340
|
+
vl_zh = i18n_zh.get(vl_item.get("i18nKey", ""), "")
|
|
341
|
+
vl_entry = {
|
|
342
|
+
"value": vl_item["value"],
|
|
343
|
+
"description": vl_item["description"]
|
|
351
344
|
}
|
|
352
|
-
|
|
345
|
+
if vl_zh:
|
|
346
|
+
vl_entry["desc_zh_cn"] = vl_zh
|
|
347
|
+
item["value-list"].append(vl_entry)
|
|
348
|
+
if item["name"] in properties_name:
|
|
349
|
+
item["name"] = f"{svc_type}-{item['name']}"
|
|
350
|
+
properties_name.append(item["name"])
|
|
351
|
+
result["properties"].append(item)
|
|
352
|
+
for act in svc.get("actions", []):
|
|
353
|
+
aiid = act["iid"]
|
|
354
|
+
zh_cn = i18n_zh.get(f"service:{siid:03d}:action:{aiid:03d}", "")
|
|
355
|
+
act_item = {
|
|
356
|
+
"name": act["type"],
|
|
357
|
+
"description": f"{act['description']} / {zh_cn}".rstrip(" / "),
|
|
358
|
+
"method": {
|
|
359
|
+
"siid": siid,
|
|
360
|
+
"aiid": aiid
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if act_item["name"] in actions_name:
|
|
364
|
+
act_item["name"] = f"{svc_type}-{act_item['name']}"
|
|
365
|
+
actions_name.append(act_item["name"])
|
|
366
|
+
result["actions"].append(act_item)
|
|
353
367
|
|
|
354
368
|
if cache_path is not None:
|
|
355
369
|
cache_path = Path(cache_path)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "3.1.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mijiaAPI
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: A Python API for Xiaomi Mijia
|
|
5
5
|
Author-email: Do1e <i@do1e.cn>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -26,12 +26,6 @@ Dynamic: license-file
|
|
|
26
26
|
[](https://pypi.org/project/mijiaAPI/)
|
|
27
27
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
28
28
|
|
|
29
|
-
## ⚠️ 重要提醒
|
|
30
|
-
|
|
31
|
-
**v1.5.0 和 v3.0.0包含多项破坏性变更!**
|
|
32
|
-
|
|
33
|
-
如果您正在从旧版本升级,请务必查看 [CHANGELOG.md](CHANGELOG.md) 以了解详细的变更内容和迁移指南。
|
|
34
|
-
|
|
35
29
|
常见问题见 [FAQ.md](FAQ.md)。
|
|
36
30
|
|
|
37
31
|
## 安装
|
|
@@ -40,6 +34,7 @@ Dynamic: license-file
|
|
|
40
34
|
|
|
41
35
|
```bash
|
|
42
36
|
pip install mijiaAPI
|
|
37
|
+
# Or `uv add mijiaAPI` for uv users
|
|
43
38
|
```
|
|
44
39
|
|
|
45
40
|
### 从源码安装
|
|
@@ -49,7 +44,8 @@ git clone https://github.com/Do1e/mijia-api.git
|
|
|
49
44
|
cd mijia-api
|
|
50
45
|
pip install .
|
|
51
46
|
# Or `pip install -e .` for editable mode
|
|
52
|
-
# Or `
|
|
47
|
+
# Or `pip install git+https://github.com/Do1e/mijia-api.git` for direct install
|
|
48
|
+
# Or `uv add git+https://github.com/Do1e/mijia-api.git` for uv users
|
|
53
49
|
```
|
|
54
50
|
|
|
55
51
|
### aur
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "3.0.4"
|
|
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
|