sciveo 0.0.43__tar.gz → 0.0.45__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.
- {sciveo-0.0.43 → sciveo-0.0.45}/PKG-INFO +12 -1
- {sciveo-0.0.43 → sciveo-0.0.45}/README.md +11 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/__init__.py +4 -7
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/monitoring/monitor.py +5 -7
- sciveo-0.0.45/sciveo/monitoring/start.py +57 -0
- sciveo-0.0.45/sciveo/version.py +2 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo.egg-info/PKG-INFO +12 -1
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo.egg-info/SOURCES.txt +1 -0
- sciveo-0.0.45/test/test_monitoring.py +97 -0
- sciveo-0.0.43/sciveo/version.py +0 -2
- sciveo-0.0.43/test/test_monitoring.py +0 -26
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/api/__init__.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/api/base.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/api/upload.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/__init__.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/configuration.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/model.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/optimizers.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/sampling.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/tools/__init__.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/tools/daemon.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/tools/formating.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/tools/hardware.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/tools/logger.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/common/tools/synchronized.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/content/__init__.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/content/dataset.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/content/experiment.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/content/project.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/content/runner.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo/monitoring/__init__.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo.egg-info/dependency_links.txt +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo.egg-info/requires.txt +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/sciveo.egg-info/top_level.txt +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/setup.cfg +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/setup.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/test/test_configuration.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/test/test_runner.py +0 -0
- {sciveo-0.0.43 → sciveo-0.0.45}/test/test_sampling.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sciveo
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.45
|
|
4
4
|
Description-Content-Type: text/markdown
|
|
5
5
|
Provides-Extra: mon
|
|
6
6
|
|
|
@@ -10,6 +10,9 @@ Provides-Extra: mon
|
|
|
10
10
|
There are few configuration params samplers, which allows easy parameter tuning. The "auto" sampler perhaps is the easiest to use, but also
|
|
11
11
|
"random" and "grid" ones are available.
|
|
12
12
|
|
|
13
|
+
There is also the sciveo.monitor() which will start monitoring machine CPU/RAM/GPU etc.
|
|
14
|
+
|
|
15
|
+
|
|
13
16
|
## Features
|
|
14
17
|
|
|
15
18
|
- **Experiment Tracking:** Easily log and track your machine learning experiments.
|
|
@@ -19,8 +22,12 @@ There are few configuration params samplers, which allows easy parameter tuning.
|
|
|
19
22
|
|
|
20
23
|
## Installation
|
|
21
24
|
|
|
25
|
+
- main sciveo
|
|
22
26
|
pip install sciveo
|
|
23
27
|
|
|
28
|
+
- optional for sciveo monitoring
|
|
29
|
+
pip install sciveo[mon]
|
|
30
|
+
|
|
24
31
|
## Example usage
|
|
25
32
|
|
|
26
33
|
There are few public examples in sciveo.com.
|
|
@@ -30,6 +37,10 @@ The library has local and remote mode. The local one is ready to use, but for th
|
|
|
30
37
|
When have sciveo account:
|
|
31
38
|
export SCIVEO_SECRET_ACCESS_KEY='my_sciveo_user_auth_token'
|
|
32
39
|
|
|
40
|
+
When using sciveo monitoring just run, using suitable python environment
|
|
41
|
+
python -c "import sciveo; sciveo.monitor(period=120)"
|
|
42
|
+
|
|
43
|
+
When using sciveo experimental projects management
|
|
33
44
|
|
|
34
45
|
```python
|
|
35
46
|
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
There are few configuration params samplers, which allows easy parameter tuning. The "auto" sampler perhaps is the easiest to use, but also
|
|
5
5
|
"random" and "grid" ones are available.
|
|
6
6
|
|
|
7
|
+
There is also the sciveo.monitor() which will start monitoring machine CPU/RAM/GPU etc.
|
|
8
|
+
|
|
9
|
+
|
|
7
10
|
## Features
|
|
8
11
|
|
|
9
12
|
- **Experiment Tracking:** Easily log and track your machine learning experiments.
|
|
@@ -13,8 +16,12 @@ There are few configuration params samplers, which allows easy parameter tuning.
|
|
|
13
16
|
|
|
14
17
|
## Installation
|
|
15
18
|
|
|
19
|
+
- main sciveo
|
|
16
20
|
pip install sciveo
|
|
17
21
|
|
|
22
|
+
- optional for sciveo monitoring
|
|
23
|
+
pip install sciveo[mon]
|
|
24
|
+
|
|
18
25
|
## Example usage
|
|
19
26
|
|
|
20
27
|
There are few public examples in sciveo.com.
|
|
@@ -24,6 +31,10 @@ The library has local and remote mode. The local one is ready to use, but for th
|
|
|
24
31
|
When have sciveo account:
|
|
25
32
|
export SCIVEO_SECRET_ACCESS_KEY='my_sciveo_user_auth_token'
|
|
26
33
|
|
|
34
|
+
When using sciveo monitoring just run, using suitable python environment
|
|
35
|
+
python -c "import sciveo; sciveo.monitor(period=120)"
|
|
36
|
+
|
|
37
|
+
When using sciveo experimental projects management
|
|
27
38
|
|
|
28
39
|
```python
|
|
29
40
|
|
|
@@ -20,12 +20,11 @@ try:
|
|
|
20
20
|
from sciveo.common.tools.daemon import TasksDaemon, __upload_content__
|
|
21
21
|
from sciveo.content.runner import ProjectRunner
|
|
22
22
|
from sciveo.content.dataset import Dataset
|
|
23
|
-
from sciveo.monitoring.
|
|
23
|
+
from sciveo.monitoring.start import MonitorStart
|
|
24
24
|
from sciveo.version import __version__
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
TasksDaemon.current = TasksDaemon(num_threads=int(os.environ.get("SCIVEO_TASKS_NUM_THREADS", 1)))
|
|
28
|
-
TasksDaemon.current.start()
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
# New Experiment
|
|
@@ -36,6 +35,7 @@ try:
|
|
|
36
35
|
error("there is no started project")
|
|
37
36
|
|
|
38
37
|
def start(project, function, configuration={}, **kwargs):
|
|
38
|
+
TasksDaemon.current.start()
|
|
39
39
|
ProjectRunner.current = ProjectRunner(project=project, function=function, configuration=configuration, **kwargs)
|
|
40
40
|
ProjectRunner.current.run()
|
|
41
41
|
|
|
@@ -44,11 +44,8 @@ try:
|
|
|
44
44
|
return Dataset.get(info)
|
|
45
45
|
|
|
46
46
|
# Monitoring start
|
|
47
|
-
def monitor(
|
|
48
|
-
|
|
49
|
-
mon.start()
|
|
50
|
-
while(True):
|
|
51
|
-
time.sleep(60)
|
|
47
|
+
def monitor(**kwargs):
|
|
48
|
+
MonitorStart(**kwargs)()
|
|
52
49
|
|
|
53
50
|
except ImportError as e:
|
|
54
51
|
pass
|
|
@@ -15,6 +15,7 @@ import time
|
|
|
15
15
|
import datetime
|
|
16
16
|
import socket
|
|
17
17
|
import psutil
|
|
18
|
+
import uuid
|
|
18
19
|
import numpy as np
|
|
19
20
|
|
|
20
21
|
from sciveo.common.tools.logger import *
|
|
@@ -45,7 +46,7 @@ class BaseMonitor(DaemonBase):
|
|
|
45
46
|
|
|
46
47
|
machine_serial = self.getserial()
|
|
47
48
|
|
|
48
|
-
debug(type(self).__name__, "init", machine_serial, "initial_cpu_usage", initial_cpu_usage)
|
|
49
|
+
debug(type(self).__name__, f"init monitor with period={period}", machine_serial, "initial_cpu_usage", initial_cpu_usage)
|
|
49
50
|
|
|
50
51
|
def __call__(self):
|
|
51
52
|
return self.data
|
|
@@ -81,15 +82,12 @@ class BaseMonitor(DaemonBase):
|
|
|
81
82
|
def getserial(self):
|
|
82
83
|
machine_serial = None
|
|
83
84
|
try:
|
|
84
|
-
|
|
85
|
-
for line in fp:
|
|
86
|
-
if line.startswith('Serial'):
|
|
87
|
-
machine_serial = line[10:26]
|
|
85
|
+
machine_serial = f"{socket.gethostname()}-{uuid.getnode()}"
|
|
88
86
|
except Exception:
|
|
89
87
|
pass
|
|
90
88
|
if machine_serial is None:
|
|
91
89
|
try:
|
|
92
|
-
machine_serial =
|
|
90
|
+
machine_serial = f"UUID-{uuid.getnode()}"
|
|
93
91
|
except Exception:
|
|
94
92
|
pass
|
|
95
93
|
if machine_serial is None:
|
|
@@ -130,7 +128,7 @@ class BaseMonitor(DaemonBase):
|
|
|
130
128
|
|
|
131
129
|
|
|
132
130
|
if __name__ == "__main__":
|
|
133
|
-
mon = BaseMonitor(period=
|
|
131
|
+
mon = BaseMonitor(period=10)
|
|
134
132
|
mon.start()
|
|
135
133
|
|
|
136
134
|
while(True):
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
from sciveo.common.tools.logger import *
|
|
5
|
+
from sciveo.monitoring.monitor import BaseMonitor
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MonitorStart:
|
|
9
|
+
def __init__(self, **kwargs):
|
|
10
|
+
self.default_arguments = {
|
|
11
|
+
"period": 120,
|
|
12
|
+
"block": True,
|
|
13
|
+
"fork": False,
|
|
14
|
+
"fork_type": 0
|
|
15
|
+
}
|
|
16
|
+
self.arguments = {}
|
|
17
|
+
for k, v in self.default_arguments.items():
|
|
18
|
+
self.arguments[k] = kwargs.get(k, v)
|
|
19
|
+
|
|
20
|
+
if len(kwargs) == 0:
|
|
21
|
+
info("sciveo monitoring default options", self.default_arguments)
|
|
22
|
+
|
|
23
|
+
def __call__(self):
|
|
24
|
+
if self.arguments["fork"] and self.arguments["block"]:
|
|
25
|
+
self.fork()
|
|
26
|
+
self.start()
|
|
27
|
+
|
|
28
|
+
def start_multiprocessing(self):
|
|
29
|
+
self.start()
|
|
30
|
+
def start_fork(self):
|
|
31
|
+
os.setsid()
|
|
32
|
+
self.start()
|
|
33
|
+
def fork(self):
|
|
34
|
+
if self.arguments["fork_type"] == 0:
|
|
35
|
+
import multiprocessing
|
|
36
|
+
background_process = multiprocessing.Process(target=self.start_multiprocessing)
|
|
37
|
+
background_process.daemon = True
|
|
38
|
+
background_process.start()
|
|
39
|
+
info("monitoring service started with", self.arguments)
|
|
40
|
+
exit()
|
|
41
|
+
else:
|
|
42
|
+
pid = os.fork()
|
|
43
|
+
if pid == 0:
|
|
44
|
+
self.start_fork()
|
|
45
|
+
else:
|
|
46
|
+
info("sciveo monitor service started with pid", pid, self.arguments)
|
|
47
|
+
exit()
|
|
48
|
+
|
|
49
|
+
def start(self):
|
|
50
|
+
period = max(self.arguments["period"], 5)
|
|
51
|
+
mon = BaseMonitor(period=period)
|
|
52
|
+
mon.start()
|
|
53
|
+
mon.join()
|
|
54
|
+
|
|
55
|
+
if self.arguments["block"]:
|
|
56
|
+
while(True):
|
|
57
|
+
time.sleep(60)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sciveo
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.45
|
|
4
4
|
Description-Content-Type: text/markdown
|
|
5
5
|
Provides-Extra: mon
|
|
6
6
|
|
|
@@ -10,6 +10,9 @@ Provides-Extra: mon
|
|
|
10
10
|
There are few configuration params samplers, which allows easy parameter tuning. The "auto" sampler perhaps is the easiest to use, but also
|
|
11
11
|
"random" and "grid" ones are available.
|
|
12
12
|
|
|
13
|
+
There is also the sciveo.monitor() which will start monitoring machine CPU/RAM/GPU etc.
|
|
14
|
+
|
|
15
|
+
|
|
13
16
|
## Features
|
|
14
17
|
|
|
15
18
|
- **Experiment Tracking:** Easily log and track your machine learning experiments.
|
|
@@ -19,8 +22,12 @@ There are few configuration params samplers, which allows easy parameter tuning.
|
|
|
19
22
|
|
|
20
23
|
## Installation
|
|
21
24
|
|
|
25
|
+
- main sciveo
|
|
22
26
|
pip install sciveo
|
|
23
27
|
|
|
28
|
+
- optional for sciveo monitoring
|
|
29
|
+
pip install sciveo[mon]
|
|
30
|
+
|
|
24
31
|
## Example usage
|
|
25
32
|
|
|
26
33
|
There are few public examples in sciveo.com.
|
|
@@ -30,6 +37,10 @@ The library has local and remote mode. The local one is ready to use, but for th
|
|
|
30
37
|
When have sciveo account:
|
|
31
38
|
export SCIVEO_SECRET_ACCESS_KEY='my_sciveo_user_auth_token'
|
|
32
39
|
|
|
40
|
+
When using sciveo monitoring just run, using suitable python environment
|
|
41
|
+
python -c "import sciveo; sciveo.monitor(period=120)"
|
|
42
|
+
|
|
43
|
+
When using sciveo experimental projects management
|
|
33
44
|
|
|
34
45
|
```python
|
|
35
46
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Pavlin Georgiev, Softel Labs
|
|
3
|
+
#
|
|
4
|
+
# This is a proprietary file and may not be copied,
|
|
5
|
+
# distributed, or modified without express permission
|
|
6
|
+
# from the owner. For licensing inquiries, please
|
|
7
|
+
# contact pavlin@softel.bg.
|
|
8
|
+
#
|
|
9
|
+
# 2024
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
import unittest
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
from sciveo.common.tools.logger import *
|
|
16
|
+
from sciveo.monitoring.monitor import *
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestMonitoring(unittest.TestCase):
|
|
20
|
+
def test_cpu(self):
|
|
21
|
+
m = BaseMonitor()
|
|
22
|
+
m.get_cpu_usage()
|
|
23
|
+
print(m.data)
|
|
24
|
+
|
|
25
|
+
self.assertTrue("usage per core" in m.data["CPU"])
|
|
26
|
+
self.assertTrue("usage" in m.data["CPU"])
|
|
27
|
+
|
|
28
|
+
def test_gpu(self):
|
|
29
|
+
data = {
|
|
30
|
+
"GPU": {
|
|
31
|
+
"raw_lines": [
|
|
32
|
+
"uuid, name, index, power.draw [W], fan.speed [%], memory.total [MiB], memory.used [MiB], memory.free [MiB], utilization.gpu [%], utilization.memory [%], temperature.gpu",
|
|
33
|
+
"GPU-41e0e872-f8d5-95fb-6fd7-8c143c0db7c9, NVIDIA GeForce RTX 3060, 0, 11.57, 0, 12053, 13, 12040, 0, 0, 38",
|
|
34
|
+
"GPU-f7a1d225-58db-e209-aa84-574996d070cd, NVIDIA GeForce RTX 3060, 1, 12.08, 0, 12045, 477, 11568, 0, 39, 36"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
sample = {}
|
|
39
|
+
config = {
|
|
40
|
+
"CPU": {
|
|
41
|
+
"usage": {"ratio": 1.0, "metric": "%", "ylim": [0.0, 105.0]},
|
|
42
|
+
"usage per core": {"ratio": 1.0, "metric": "%", "ylim": [0.0, 105.0]},
|
|
43
|
+
},
|
|
44
|
+
"RAM": {
|
|
45
|
+
"used": {"ratio": 1.0 / (1024 * 1024 * 1024), "metric": "GB"},
|
|
46
|
+
},
|
|
47
|
+
"GPU": {
|
|
48
|
+
"fan.speed": {"ratio": 1.0, "metric": "%", "ylim": [0.0, 105.0]},
|
|
49
|
+
"power.draw": {"ratio": 1.0, "metric": "W", "ylim": [0.0, 250.0]},
|
|
50
|
+
"memory.free": {"ratio": 1.0 / 1024, "metric": "GB"},
|
|
51
|
+
"memory.used": {"ratio": 1.0 / 1024, "metric": "GB"},
|
|
52
|
+
"temperature.gpu": {"ratio": 1.0, "metric": "°C", "ylim": [10, 110]},
|
|
53
|
+
"utilization.gpu": {"ratio": 1.0, "metric": "%", "ylim": [0.0, 105.0]},
|
|
54
|
+
"utilization.memory": {"ratio": 1.0, "metric": "%", "ylim": [0.0, 105.0]},
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
lines = data["GPU"]["raw_lines"]
|
|
60
|
+
header = lines[0].split(", ")
|
|
61
|
+
|
|
62
|
+
keys = []
|
|
63
|
+
gpu_keys = []
|
|
64
|
+
for k in header:
|
|
65
|
+
k_split = k.split(' ')
|
|
66
|
+
key = k_split[0]
|
|
67
|
+
keys.append(key)
|
|
68
|
+
gpu_keys.append(f"GPU {key}")
|
|
69
|
+
|
|
70
|
+
for i, k in enumerate(keys):
|
|
71
|
+
if k in config["GPU"]:
|
|
72
|
+
sample[gpu_keys[i]] = []
|
|
73
|
+
else:
|
|
74
|
+
data["GPU"][keys[i]] = []
|
|
75
|
+
|
|
76
|
+
for i in range(1, len(lines)):
|
|
77
|
+
line_values = lines[i].split(", ")
|
|
78
|
+
for j, value in enumerate(line_values):
|
|
79
|
+
try:
|
|
80
|
+
value = float(value)
|
|
81
|
+
except ValueError:
|
|
82
|
+
pass
|
|
83
|
+
if keys[j] in config["GPU"]:
|
|
84
|
+
sample[gpu_keys[j]].append(value)
|
|
85
|
+
else:
|
|
86
|
+
data["GPU"][keys[j]].append(value)
|
|
87
|
+
|
|
88
|
+
if "memory.total" in data["GPU"]:
|
|
89
|
+
print("memory.total", data["GPU"]["memory.total"])
|
|
90
|
+
for k in ["memory.used", "memory.free"]:
|
|
91
|
+
config["GPU"][k]["ylim"] = [0, max(data["GPU"]["memory.total"]) * config["GPU"][k]["ratio"]]
|
|
92
|
+
print("ylim", config["GPU"][k]["ylim"])
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print("Exception", e)
|
|
95
|
+
|
|
96
|
+
print("memory.used", config["GPU"]["memory.used"])
|
|
97
|
+
print("free", config["GPU"]["memory.free"])
|
sciveo-0.0.43/sciveo/version.py
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Pavlin Georgiev, Softel Labs
|
|
3
|
-
#
|
|
4
|
-
# This is a proprietary file and may not be copied,
|
|
5
|
-
# distributed, or modified without express permission
|
|
6
|
-
# from the owner. For licensing inquiries, please
|
|
7
|
-
# contact pavlin@softel.bg.
|
|
8
|
-
#
|
|
9
|
-
# 2024
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
import unittest
|
|
13
|
-
import numpy as np
|
|
14
|
-
|
|
15
|
-
from sciveo.common.tools.logger import *
|
|
16
|
-
from sciveo.monitoring.monitor import *
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class TestMonitoring(unittest.TestCase):
|
|
20
|
-
def test_cpu(self):
|
|
21
|
-
m = BaseMonitor()
|
|
22
|
-
m.get_cpu_usage()
|
|
23
|
-
print(m.data)
|
|
24
|
-
|
|
25
|
-
self.assertTrue("usage_per_core" in m.data["CPU"])
|
|
26
|
-
self.assertTrue("usage" in m.data["CPU"])
|
|
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
|