FlowerPower 0.31.2__tar.gz → 0.31.4__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.
- {flowerpower-0.31.2/src/FlowerPower.egg-info → flowerpower-0.31.4}/PKG-INFO +2 -2
- {flowerpower-0.31.2 → flowerpower-0.31.4}/pyproject.toml +2 -2
- {flowerpower-0.31.2 → flowerpower-0.31.4/src/FlowerPower.egg-info}/PKG-INFO +2 -2
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/FlowerPower.egg-info/requires.txt +1 -1
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/pipeline.py +56 -40
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/executor.py +12 -13
- {flowerpower-0.31.2 → flowerpower-0.31.4}/LICENSE +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/README.md +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/setup.cfg +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/FlowerPower.egg-info/SOURCES.txt +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/FlowerPower.egg-info/dependency_links.txt +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/FlowerPower.egg-info/entry_points.txt +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/FlowerPower.egg-info/top_level.txt +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/base.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/exceptions.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/pipeline/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/pipeline/adapter.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/pipeline/builder.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/pipeline/builder_adapter.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/pipeline/builder_executor.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/pipeline/run.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/project/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cfg/project/adapter.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cli/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cli/cfg.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cli/pipeline.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/cli/utils.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/flowerpower.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/base.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/config_manager.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/executor.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/io.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/lifecycle_manager.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/manager.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/registry.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/pipeline/visualizer.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/plugins/io/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/settings/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/settings/_backend.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/settings/executor.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/settings/general.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/settings/hamilton.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/settings/logging.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/settings/retry.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/__init__.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/adapter.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/callback.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/config.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/filesystem.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/logging.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/misc.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/monkey.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/open_telemetry.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/security.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/src/flowerpower/utils/templates.py +0 -0
- {flowerpower-0.31.2 → flowerpower-0.31.4}/tests/test_flowerpower_project.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: FlowerPower
|
3
|
-
Version: 0.31.
|
3
|
+
Version: 0.31.4
|
4
4
|
Summary: A simple workflow framework for building and managing data processing pipelines
|
5
5
|
Author-email: "Volker L." <ligno.blades@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/legout/flowerpower
|
@@ -19,7 +19,7 @@ Requires-Dist: pyyaml>=6.0.1
|
|
19
19
|
Requires-Dist: rich>=13.9.3
|
20
20
|
Requires-Dist: s3fs>=2024.10.0
|
21
21
|
Requires-Dist: sf-hamilton-sdk>=0.5.2
|
22
|
-
Requires-Dist: sf-hamilton[rich,tqdm,visualization]
|
22
|
+
Requires-Dist: sf-hamilton[rich,tqdm,visualization]<=1.88.0
|
23
23
|
Requires-Dist: typer>=0.12.3
|
24
24
|
Provides-Extra: io
|
25
25
|
Requires-Dist: flowerpower-io>=0.1.1; extra == "io"
|
@@ -4,7 +4,7 @@ description = "A simple workflow framework for building and managing data proces
|
|
4
4
|
authors = [{ name = "Volker L.", email = "ligno.blades@gmail.com" }]
|
5
5
|
readme = "README.md"
|
6
6
|
requires-python = ">= 3.11"
|
7
|
-
version = "0.31.
|
7
|
+
version = "0.31.4"
|
8
8
|
keywords = ["hamilton", "workflow", "pipeline", "scheduler", "dask", "ray"]
|
9
9
|
|
10
10
|
dependencies = [
|
@@ -22,7 +22,7 @@ dependencies = [
|
|
22
22
|
'rich>=13.9.3',
|
23
23
|
's3fs>=2024.10.0',
|
24
24
|
'sf-hamilton-sdk>=0.5.2',
|
25
|
-
'sf-hamilton[visualization,rich,tqdm]
|
25
|
+
'sf-hamilton[visualization,rich,tqdm]<=1.88.0',
|
26
26
|
'typer>=0.12.3',
|
27
27
|
]
|
28
28
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: FlowerPower
|
3
|
-
Version: 0.31.
|
3
|
+
Version: 0.31.4
|
4
4
|
Summary: A simple workflow framework for building and managing data processing pipelines
|
5
5
|
Author-email: "Volker L." <ligno.blades@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/legout/flowerpower
|
@@ -19,7 +19,7 @@ Requires-Dist: pyyaml>=6.0.1
|
|
19
19
|
Requires-Dist: rich>=13.9.3
|
20
20
|
Requires-Dist: s3fs>=2024.10.0
|
21
21
|
Requires-Dist: sf-hamilton-sdk>=0.5.2
|
22
|
-
Requires-Dist: sf-hamilton[rich,tqdm,visualization]
|
22
|
+
Requires-Dist: sf-hamilton[rich,tqdm,visualization]<=1.88.0
|
23
23
|
Requires-Dist: typer>=0.12.3
|
24
24
|
Provides-Extra: io
|
25
25
|
Requires-Dist: flowerpower-io>=0.1.1; extra == "io"
|
@@ -9,10 +9,11 @@ import importlib.util
|
|
9
9
|
import random
|
10
10
|
import time
|
11
11
|
from typing import TYPE_CHECKING, Any, Callable
|
12
|
-
from requests.exceptions import HTTPError, ConnectionError, Timeout
|
12
|
+
from requests.exceptions import HTTPError, ConnectionError, Timeout # Example exception
|
13
13
|
|
14
14
|
import humanize
|
15
15
|
import msgspec
|
16
|
+
from loguru import logger
|
16
17
|
from hamilton import driver
|
17
18
|
from hamilton.execution import executors
|
18
19
|
from hamilton.registry import disable_autoload
|
@@ -23,6 +24,8 @@ from requests.exceptions import ConnectionError, HTTPError
|
|
23
24
|
from .. import settings
|
24
25
|
from ..utils.adapter import create_adapter_manager
|
25
26
|
from ..utils.executor import create_executor_factory
|
27
|
+
from ..utils.logging import setup_logging
|
28
|
+
|
26
29
|
|
27
30
|
if importlib.util.find_spec("opentelemetry"):
|
28
31
|
from hamilton.plugins import h_opentelemetry
|
@@ -37,11 +40,6 @@ if importlib.util.find_spec("mlflow"):
|
|
37
40
|
else:
|
38
41
|
h_mlflow = None
|
39
42
|
|
40
|
-
from hamilton.plugins import h_rich
|
41
|
-
from hamilton.plugins.h_threadpool import FutureAdapter
|
42
|
-
from hamilton_sdk.adapters import HamiltonTracker
|
43
|
-
from hamilton_sdk.tracking import constants
|
44
|
-
from loguru import logger
|
45
43
|
|
46
44
|
if importlib.util.find_spec("distributed"):
|
47
45
|
from dask import distributed
|
@@ -58,7 +56,7 @@ else:
|
|
58
56
|
ray = None
|
59
57
|
h_ray = None
|
60
58
|
|
61
|
-
from ..cfg import PipelineConfig
|
59
|
+
from ..cfg import PipelineConfig
|
62
60
|
from ..cfg.pipeline.adapter import AdapterConfig as PipelineAdapterConfig
|
63
61
|
from ..cfg.pipeline.run import ExecutorConfig, RunConfig
|
64
62
|
from ..cfg.project.adapter import AdapterConfig as ProjectAdapterConfig
|
@@ -67,6 +65,8 @@ from ..utils.config import merge_run_config_with_kwargs
|
|
67
65
|
if TYPE_CHECKING:
|
68
66
|
from ..flowerpower import FlowerPowerProject
|
69
67
|
|
68
|
+
setup_logging(level=settings.LOG_LEVEL)
|
69
|
+
|
70
70
|
|
71
71
|
class Pipeline(msgspec.Struct):
|
72
72
|
"""Active pipeline object that encapsulates its own execution logic.
|
@@ -100,12 +100,7 @@ class Pipeline(msgspec.Struct):
|
|
100
100
|
self._adapter_manager = create_adapter_manager()
|
101
101
|
self._executor_factory = create_executor_factory()
|
102
102
|
|
103
|
-
|
104
|
-
def run(
|
105
|
-
self,
|
106
|
-
run_config: RunConfig | None = None,
|
107
|
-
**kwargs
|
108
|
-
) -> dict[str, Any]:
|
103
|
+
def run(self, run_config: RunConfig | None = None, **kwargs) -> dict[str, Any]:
|
109
104
|
"""Execute the pipeline with the given parameters.
|
110
105
|
|
111
106
|
Args:
|
@@ -120,7 +115,7 @@ class Pipeline(msgspec.Struct):
|
|
120
115
|
|
121
116
|
# Initialize run_config with pipeline defaults if not provided
|
122
117
|
run_config = run_config or self.config.run
|
123
|
-
|
118
|
+
|
124
119
|
# Merge kwargs into the run_config
|
125
120
|
if kwargs:
|
126
121
|
run_config = merge_run_config_with_kwargs(run_config, kwargs)
|
@@ -131,7 +126,10 @@ class Pipeline(msgspec.Struct):
|
|
131
126
|
|
132
127
|
# Set up retry configuration
|
133
128
|
retry_config = self._setup_retry_config(
|
134
|
-
run_config.max_retries,
|
129
|
+
run_config.max_retries,
|
130
|
+
run_config.retry_delay,
|
131
|
+
run_config.jitter_factor,
|
132
|
+
run_config.retry_exceptions,
|
135
133
|
)
|
136
134
|
max_retries = retry_config["max_retries"]
|
137
135
|
retry_delay = retry_config["retry_delay"]
|
@@ -165,22 +163,22 @@ class Pipeline(msgspec.Struct):
|
|
165
163
|
converted_exceptions = []
|
166
164
|
# Safe mapping of exception names to classes
|
167
165
|
exception_mapping = {
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
166
|
+
"Exception": Exception,
|
167
|
+
"ValueError": ValueError,
|
168
|
+
"TypeError": TypeError,
|
169
|
+
"RuntimeError": RuntimeError,
|
170
|
+
"FileNotFoundError": FileNotFoundError,
|
171
|
+
"PermissionError": PermissionError,
|
172
|
+
"ConnectionError": ConnectionError,
|
173
|
+
"TimeoutError": TimeoutError,
|
174
|
+
"KeyError": KeyError,
|
175
|
+
"AttributeError": AttributeError,
|
176
|
+
"ImportError": ImportError,
|
177
|
+
"OSError": OSError,
|
178
|
+
"IOError": IOError,
|
179
|
+
"HTTPError": HTTPError,
|
180
|
+
"ConnectionError": ConnectionError,
|
181
|
+
"Timeout": Timeout,
|
184
182
|
}
|
185
183
|
for exc in retry_exceptions:
|
186
184
|
if isinstance(exc, str):
|
@@ -296,17 +294,33 @@ class Pipeline(msgspec.Struct):
|
|
296
294
|
) -> dict[str, Any]:
|
297
295
|
"""Execute the pipeline with Hamilton."""
|
298
296
|
# Set up execution context
|
299
|
-
executor, shutdown_func, adapters = self._setup_execution_context(
|
300
|
-
|
297
|
+
executor, shutdown_func, adapters = self._setup_execution_context(
|
298
|
+
run_config=run_config
|
299
|
+
)
|
300
|
+
if (
|
301
|
+
run_config.executor.type != "synchronous"
|
302
|
+
or run_config.executor.type == "local"
|
303
|
+
):
|
304
|
+
allow_experimental_mode = True
|
305
|
+
synchronous_executor = False
|
306
|
+
else:
|
307
|
+
allow_experimental_mode = False
|
301
308
|
try:
|
302
309
|
# Create Hamilton driver
|
303
310
|
dr = (
|
304
311
|
driver.Builder()
|
305
|
-
.with_config(run_config.config)
|
306
312
|
.with_modules(self.module)
|
313
|
+
.with_config(run_config.config)
|
307
314
|
.with_adapters(*adapters)
|
308
|
-
.
|
315
|
+
.enable_dynamic_execution(
|
316
|
+
allow_experimental_mode=allow_experimental_mode
|
317
|
+
)
|
318
|
+
.with_local_executor(executors.SynchronousLocalTaskExecutor())
|
309
319
|
)
|
320
|
+
if not synchronous_executor:
|
321
|
+
dr = dr.with_remote_executor(executor)
|
322
|
+
|
323
|
+
dr = dr.build()
|
310
324
|
|
311
325
|
# Execute the pipeline
|
312
326
|
result = dr.execute(
|
@@ -352,11 +366,11 @@ class Pipeline(msgspec.Struct):
|
|
352
366
|
cleanup_fn = None
|
353
367
|
if executor_cfg.type == "ray" and h_ray:
|
354
368
|
# Handle temporary case where project_context is PipelineManager
|
355
|
-
project_cfg = getattr(
|
356
|
-
self.project_context, "
|
357
|
-
)
|
369
|
+
project_cfg = getattr(self.project_context, "project_cfg", None) or getattr(
|
370
|
+
self.project_context, "_project_cfg", None
|
371
|
+
)
|
358
372
|
|
359
|
-
if project_cfg and hasattr(project_cfg.adapter,
|
373
|
+
if project_cfg and hasattr(project_cfg.adapter, "ray"):
|
360
374
|
cleanup_fn = (
|
361
375
|
ray.shutdown
|
362
376
|
if project_cfg.adapter.ray.shutdown_ray_on_completion
|
@@ -427,5 +441,7 @@ class Pipeline(msgspec.Struct):
|
|
427
441
|
logger.error(f"Failed to reload module for pipeline '{self.name}': {e}")
|
428
442
|
raise
|
429
443
|
except Exception as e:
|
430
|
-
logger.error(
|
444
|
+
logger.error(
|
445
|
+
f"Unexpected error reloading module for pipeline '{self.name}': {e}"
|
446
|
+
)
|
431
447
|
raise
|
@@ -25,8 +25,7 @@ class ExecutorFactory:
|
|
25
25
|
self._executor_cache: Dict[str, Any] = {}
|
26
26
|
|
27
27
|
def create_executor(
|
28
|
-
self,
|
29
|
-
executor_cfg: Union[str, Dict[str, Any], Any, None]
|
28
|
+
self, executor_cfg: Union[str, Dict[str, Any], Any, None]
|
30
29
|
) -> Any:
|
31
30
|
"""
|
32
31
|
Create an executor instance based on configuration.
|
@@ -52,8 +51,7 @@ class ExecutorFactory:
|
|
52
51
|
return executor
|
53
52
|
|
54
53
|
def _normalize_config(
|
55
|
-
self,
|
56
|
-
executor_cfg: Union[str, Dict[str, Any], Any, None]
|
54
|
+
self, executor_cfg: Union[str, Dict[str, Any], Any, None]
|
57
55
|
) -> Any:
|
58
56
|
"""Normalize executor configuration to ExecutorConfig instance."""
|
59
57
|
from ..cfg.pipeline.run import ExecutorConfig
|
@@ -95,17 +93,18 @@ class ExecutorFactory:
|
|
95
93
|
def _create_synchronous_executor(self) -> Any:
|
96
94
|
"""Create synchronous/local executor."""
|
97
95
|
from hamilton.execution.executors import SynchronousLocalTaskExecutor
|
96
|
+
|
98
97
|
return SynchronousLocalTaskExecutor()
|
99
98
|
|
100
99
|
def _create_threadpool_executor(self, executor_cfg: Any) -> Any:
|
101
100
|
"""Create thread pool executor."""
|
102
101
|
try:
|
103
|
-
from hamilton.
|
102
|
+
from hamilton.execution.executors import MultiThreadingExecutor
|
104
103
|
|
105
104
|
# Extract max workers from config
|
106
105
|
if executor_cfg.max_workers is not None:
|
107
|
-
return
|
108
|
-
return
|
106
|
+
return MultiThreadingExecutor(max_tasks=executor_cfg.max_workers)
|
107
|
+
return MultiThreadingExecutor()
|
109
108
|
except ImportError:
|
110
109
|
logger.warning(
|
111
110
|
"ThreadPool executor dependencies not installed. Using local executor."
|
@@ -115,12 +114,12 @@ class ExecutorFactory:
|
|
115
114
|
def _create_processpool_executor(self, executor_cfg: Any) -> Any:
|
116
115
|
"""Create process pool executor."""
|
117
116
|
try:
|
118
|
-
from hamilton.execution.executors import
|
117
|
+
from hamilton.execution.executors import MultiProcessingExecutor
|
119
118
|
|
120
119
|
# Extract max workers from config
|
121
120
|
if executor_cfg.max_workers is not None:
|
122
|
-
return
|
123
|
-
return
|
121
|
+
return MultiProcessingExecutor(max_tasks=executor_cfg.max_workers)
|
122
|
+
return MultiProcessingExecutor()
|
124
123
|
except ImportError:
|
125
124
|
logger.warning(
|
126
125
|
"ProcessPool executor dependencies not installed. Using local executor."
|
@@ -135,7 +134,7 @@ class ExecutorFactory:
|
|
135
134
|
# Extract configuration
|
136
135
|
config = {}
|
137
136
|
if executor_cfg.num_cpus is not None:
|
138
|
-
config[
|
137
|
+
config["num_cpus"] = executor_cfg.num_cpus
|
139
138
|
if config:
|
140
139
|
return RayTaskExecutor(**config)
|
141
140
|
return RayTaskExecutor()
|
@@ -153,7 +152,7 @@ class ExecutorFactory:
|
|
153
152
|
# Extract configuration
|
154
153
|
config = {}
|
155
154
|
if executor_cfg.num_cpus is not None:
|
156
|
-
config[
|
155
|
+
config["num_cpus"] = executor_cfg.num_cpus
|
157
156
|
if config:
|
158
157
|
return DaskExecutor(**config)
|
159
158
|
return DaskExecutor()
|
@@ -175,4 +174,4 @@ def create_executor_factory() -> ExecutorFactory:
|
|
175
174
|
Returns:
|
176
175
|
ExecutorFactory: Configured factory instance
|
177
176
|
"""
|
178
|
-
return ExecutorFactory()
|
177
|
+
return ExecutorFactory()
|
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
|
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
|