fullwave25 1.2.2.dev0__tar.gz → 1.2.3.dev1__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.
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/.bumpversion.toml +1 -1
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/PKG-INFO +1 -1
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/__init__.py +1 -1
- fullwave25-1.2.3.dev1/fullwave/solver/binary_manager.py +145 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/solver.py +3 -1
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/pyproject.toml +2 -2
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/uv.lock +1 -1
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda118 +0 -0
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda124 +0 -0
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda129 +0 -0
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda130 +0 -0
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda118 +0 -0
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda124 +0 -0
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda129 +0 -0
- fullwave25-1.2.2.dev0/fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda130 +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/.gitignore +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/.pre-commit-config.yaml +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/.python-version +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/20260120_0844.log +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/CITATION.cff +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/CLAUDE.md +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/CONTRIBUTING.md +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/LICENSE +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/Makefile +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/README.md +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/beamformer.m +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/experiments/__init__.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/experiments/exp_scatterer_diameter.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/beamformer/__init__.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/beamformer/beamformer.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/constants/__init__.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/constants/material_properties.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/grid.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/__init__.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/domain.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/medium_builder.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/__init__.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/data/.keep +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_abdominal_wall.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_background.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_scatterer.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_simple.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_water_gel.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/sensor.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/__init__.py +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118 +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda124 +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda129 +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda130 +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda118 +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda124 +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda129 +0 -0
- {fullwave25-1.2.2.dev0/fullwave/solver/bins/gpu → fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda130 +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/bins/database/relaxation_params_database_num_relax=2_20260113_0957.mat +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/cuda_utils.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/input_file_writer.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/launcher.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/pml_builder.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/solver/utils.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/source.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/transducer.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/__init__.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/check_functions.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/coordinates.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/memory_tempfile.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/numerical.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/plot_utils.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/pulse.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/relaxation_parameters.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/scatterer.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/utils/signal_process.py +0 -0
- {fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/ruff.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fullwave25
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3.dev1
|
|
4
4
|
Summary: Fullwave 2.5: Ultrasound wave propagation simulation with heterogeneous power law attenuation modelling capabilities
|
|
5
5
|
Author: Masashi Sode, Gianmarco Pinton
|
|
6
6
|
Maintainer: Masashi Sode
|
|
@@ -60,7 +60,7 @@ try:
|
|
|
60
60
|
__version__ = version("fullwave")
|
|
61
61
|
except PackageNotFoundError:
|
|
62
62
|
# Update via bump-my-version, not manually
|
|
63
|
-
__version__ = "1.2.
|
|
63
|
+
__version__ = "1.2.3-dev1"
|
|
64
64
|
|
|
65
65
|
VERSION = __version__ # for convenience
|
|
66
66
|
logger.info("Fullwave version: %s", __version__)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Binary manager for fullwave solver executables.
|
|
2
|
+
|
|
3
|
+
Handles locating, caching, and downloading solver binaries from GitHub releases.
|
|
4
|
+
|
|
5
|
+
Priority order when resolving a binary:
|
|
6
|
+
1. Bundled binary (shipped with the package or dev install).
|
|
7
|
+
2. Local cache at ``~/.cache/fullwave25/bins/``.
|
|
8
|
+
3. Download from the GitHub release pinned by ``BINARY_RELEASE_TAG``.
|
|
9
|
+
|
|
10
|
+
Binaries are versioned independently from the Python package — update
|
|
11
|
+
``BINARY_RELEASE_TAG`` only when new binaries are published.
|
|
12
|
+
|
|
13
|
+
The release tag can be overridden at runtime with the environment variable
|
|
14
|
+
``FULLWAVE25_BINARY_TAG`` (e.g. ``export FULLWAVE25_BINARY_TAG=v1.2.2``).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import os
|
|
19
|
+
import stat
|
|
20
|
+
import urllib.error
|
|
21
|
+
import urllib.request
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger("__main__." + __name__)
|
|
25
|
+
|
|
26
|
+
GITHUB_REPO = "pinton-lab/fullwave25"
|
|
27
|
+
CACHE_DIR = Path.home() / ".cache" / "fullwave25" / "bins"
|
|
28
|
+
|
|
29
|
+
# Pinned release tag for the solver binaries.
|
|
30
|
+
# Update this only when new binaries are uploaded to a GitHub release.
|
|
31
|
+
BINARY_RELEASE_TAG = "v1.2.2"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _download_url(filename: str, tag: str) -> str:
|
|
35
|
+
return f"https://github.com/{GITHUB_REPO}/releases/download/{tag}/{filename}"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _download_binary(url: str, dest: Path) -> None:
|
|
39
|
+
"""Download *url* to *dest*, showing a tqdm progress bar when available."""
|
|
40
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
tmp = dest.with_suffix(".download_tmp")
|
|
42
|
+
try:
|
|
43
|
+
try:
|
|
44
|
+
from tqdm import tqdm
|
|
45
|
+
|
|
46
|
+
class _Hook:
|
|
47
|
+
def __init__(self) -> None:
|
|
48
|
+
self._bar: tqdm | None = None
|
|
49
|
+
|
|
50
|
+
def __call__(self, block: int, block_size: int, total: int) -> None: # noqa: ARG002
|
|
51
|
+
if self._bar is None:
|
|
52
|
+
self._bar = tqdm(
|
|
53
|
+
total=total if total > 0 else None,
|
|
54
|
+
unit="B",
|
|
55
|
+
unit_scale=True,
|
|
56
|
+
desc=dest.name,
|
|
57
|
+
)
|
|
58
|
+
self._bar.update(block_size)
|
|
59
|
+
|
|
60
|
+
def close(self) -> None:
|
|
61
|
+
if self._bar is not None:
|
|
62
|
+
self._bar.close()
|
|
63
|
+
|
|
64
|
+
hook = _Hook()
|
|
65
|
+
try:
|
|
66
|
+
urllib.request.urlretrieve(url, tmp, reporthook=hook) # noqa: S310
|
|
67
|
+
finally:
|
|
68
|
+
hook.close()
|
|
69
|
+
|
|
70
|
+
except ImportError:
|
|
71
|
+
urllib.request.urlretrieve(url, tmp) # noqa: S310
|
|
72
|
+
|
|
73
|
+
tmp.rename(dest)
|
|
74
|
+
dest.chmod(dest.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
75
|
+
logger.info("Binary saved to %s", dest)
|
|
76
|
+
|
|
77
|
+
except Exception:
|
|
78
|
+
tmp.unlink(missing_ok=True)
|
|
79
|
+
raise
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def ensure_binary(local_path: Path) -> Path:
|
|
83
|
+
"""Return an executable path for the solver binary.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
local_path:
|
|
88
|
+
The expected bundled path (as computed by ``_retrieve_fullwave_simulation_path``).
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
Path
|
|
93
|
+
Resolved path to an executable binary.
|
|
94
|
+
|
|
95
|
+
Raises
|
|
96
|
+
------
|
|
97
|
+
RuntimeError
|
|
98
|
+
If the binary cannot be found locally and the download fails.
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
# 1. Bundled binary present (dev install or package that still ships binaries).
|
|
102
|
+
if local_path.exists():
|
|
103
|
+
logger.debug("Using bundled binary: %s", local_path)
|
|
104
|
+
return local_path
|
|
105
|
+
|
|
106
|
+
filename = local_path.name
|
|
107
|
+
cached = CACHE_DIR / filename
|
|
108
|
+
|
|
109
|
+
# 2. Previously downloaded and cached.
|
|
110
|
+
if cached.exists():
|
|
111
|
+
logger.debug("Using cached binary: %s", cached)
|
|
112
|
+
return cached
|
|
113
|
+
|
|
114
|
+
# 3. Download from GitHub releases.
|
|
115
|
+
tag = os.environ.get("FULLWAVE25_BINARY_TAG", BINARY_RELEASE_TAG)
|
|
116
|
+
url = _download_url(filename, tag)
|
|
117
|
+
|
|
118
|
+
logger.info(
|
|
119
|
+
"Binary '%s' not found locally. Downloading from GitHub release '%s' …",
|
|
120
|
+
filename,
|
|
121
|
+
tag,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
_download_binary(url, cached)
|
|
126
|
+
except urllib.error.HTTPError as e:
|
|
127
|
+
msg = (
|
|
128
|
+
f"Could not download binary '{filename}' from:\n {url}\n"
|
|
129
|
+
f"HTTP error: {e.code} {e.reason}\n\n"
|
|
130
|
+
"Possible fixes:\n"
|
|
131
|
+
f" • Check that release '{tag}' exists and contains '{filename}'.\n"
|
|
132
|
+
f" • Override the tag: export FULLWAVE25_BINARY_TAG=<tag>\n"
|
|
133
|
+
f" • Place the binary manually at: {cached}\n"
|
|
134
|
+
)
|
|
135
|
+
raise RuntimeError(msg) from e
|
|
136
|
+
except Exception as e:
|
|
137
|
+
msg = (
|
|
138
|
+
f"Failed to download binary '{filename}' from:\n {url}\n"
|
|
139
|
+
f"Error: {e}\n\n"
|
|
140
|
+
f" • Place the binary manually at: {cached}\n"
|
|
141
|
+
f" • Or override the tag: export FULLWAVE25_BINARY_TAG=<tag>\n"
|
|
142
|
+
)
|
|
143
|
+
raise RuntimeError(msg) from e
|
|
144
|
+
|
|
145
|
+
return cached
|
|
@@ -16,6 +16,7 @@ from fullwave.utils import (
|
|
|
16
16
|
check_functions,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
+
from .binary_manager import ensure_binary
|
|
19
20
|
from .cuda_utils import get_cuda_architecture, retrieve_cuda_version
|
|
20
21
|
|
|
21
22
|
logger = logging.getLogger("__main__." + __name__)
|
|
@@ -461,13 +462,14 @@ class Solver:
|
|
|
461
462
|
self.n_relax_mechanisms = medium.n_relaxation_mechanisms
|
|
462
463
|
|
|
463
464
|
if path_fullwave_simulation_bin is None:
|
|
464
|
-
|
|
465
|
+
local_path = _retrieve_fullwave_simulation_path(
|
|
465
466
|
use_gpu=use_gpu,
|
|
466
467
|
is_3d=self.is_3d,
|
|
467
468
|
use_exponential_attenuation=self.use_exponential_attenuation,
|
|
468
469
|
use_isotropic_relaxation=use_isotropic_relaxation,
|
|
469
470
|
n_relax_mechanisms=self.n_relax_mechanisms,
|
|
470
471
|
)
|
|
472
|
+
path_fullwave_simulation_bin = ensure_binary(local_path)
|
|
471
473
|
else:
|
|
472
474
|
check_functions.check_path_exists(path_fullwave_simulation_bin)
|
|
473
475
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fullwave25"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.3-dev1" # Update via bump-my-version, not manually
|
|
4
4
|
description = "Fullwave 2.5: Ultrasound wave propagation simulation with heterogeneous power law attenuation modelling capabilities"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -57,4 +57,4 @@ build-backend = "hatchling.build"
|
|
|
57
57
|
packages = ["fullwave", "fullwave.utils"]
|
|
58
58
|
|
|
59
59
|
[tool.hatch.build]
|
|
60
|
-
exclude = ["tests", "figs", "examples", ".vscode", ".github"]
|
|
60
|
+
exclude = ["tests", "figs", "examples", ".vscode", ".github", "fullwave/solver/bins/gpu", "fullwave/solver/bins/exponential_attenuation", "fullwave/solver/bins/_exponential_attenuation"]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
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
|
{fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_background.py
RENAMED
|
File without changes
|
{fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_scatterer.py
RENAMED
|
File without changes
|
{fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_simple.py
RENAMED
|
File without changes
|
{fullwave25-1.2.2.dev0 → fullwave25-1.2.3.dev1}/fullwave/medium_builder/presets/domain_water_gel.py
RENAMED
|
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
|