wavespectra 4.3.0__tar.gz → 4.4.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.
- {wavespectra-4.3.0/wavespectra.egg-info → wavespectra-4.4.0}/PKG-INFO +3 -2
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/__init__.py +1 -1
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/utils.py +15 -0
- wavespectra-4.4.0/wavespectra/input/era5.py +114 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0/wavespectra.egg-info}/PKG-INFO +3 -2
- wavespectra-4.3.0/wavespectra/input/era5.py +0 -92
- {wavespectra-4.3.0 → wavespectra-4.4.0}/AUTHORS.rst +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/LICENSE.txt +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/README.rst +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/pyproject.toml +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/setup.cfg +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/setup.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/tests/test_cli.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/tests/test_cookiecutter_template.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/tests/test_partition.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/tests/test_specarray.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/cli.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/construct/__init__.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/construct/direction.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/construct/frequency.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/__init__.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/attributes.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/attributes.yml +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/fitting.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/npstats.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/select.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/swan.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/core/xrstats.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/__init__.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/awac.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/dataset.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/datawell.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/funwave.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/json.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/ncswan.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/ndbc.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/ndbc_ascii.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/netcdf.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/obscape.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/octopus.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/spotter.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/swan.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/triaxys.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/wavespectra.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/ww3.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/ww3_station.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/wwm.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/input/xwaves.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/__init__.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/funwave.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/json.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/netcdf.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/octopus.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/orcaflex.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/swan.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/ww3.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/output/ww3.yml +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/partition/__init__.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/partition/hanson_and_phillips_2001.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/partition/partition.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/partition/specpart/specpart.c +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/partition/specpart/specpart.h +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/partition/specpart/specpart_wrap.c +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/partition/tracking.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/plot.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/specarray.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra/specdataset.py +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra.egg-info/SOURCES.txt +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra.egg-info/dependency_links.txt +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra.egg-info/entry_points.txt +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra.egg-info/requires.txt +0 -0
- {wavespectra-4.3.0 → wavespectra-4.4.0}/wavespectra.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: wavespectra
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4.0
|
|
4
4
|
Summary: Library for ocean wave spectra
|
|
5
5
|
Author-email: Wavespectra Developers <r.guedes@oceanum.science>
|
|
6
6
|
Maintainer-email: Rafael Guedes <r.guedes@oceanum.science>, Tom Durrant <t.durrant@oceanum.science>
|
|
@@ -76,6 +76,7 @@ Requires-Dist: sphinx; extra == "docs"
|
|
|
76
76
|
Requires-Dist: sphinx-autobuild; extra == "docs"
|
|
77
77
|
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
78
78
|
Requires-Dist: sphinx-gallery; extra == "docs"
|
|
79
|
+
Dynamic: license-file
|
|
79
80
|
|
|
80
81
|
wavespectra
|
|
81
82
|
===========
|
|
@@ -15,6 +15,21 @@ D2R = np.pi / 180.0
|
|
|
15
15
|
R2D = 180.0 / np.pi
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def create_frequencies(f0: float, nf: int, df: float = 1.1) -> np.ndarray:
|
|
19
|
+
"""Create an array of logarithmically spaced frequencies.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
- f0 (float): First frequency value in Hz (e.g., 0.03453)
|
|
23
|
+
- nf (int): Number of frequencies to generate
|
|
24
|
+
- df (float, optional): Multiplicative increment between frequencies. Defaults to 1.1.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
- np.ndarray: Array of frequencies in Hz
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
return f0 * (df ** np.arange(nf))
|
|
31
|
+
|
|
32
|
+
|
|
18
33
|
def angle(dir1, dir2):
|
|
19
34
|
"""Relative angle between two directions.
|
|
20
35
|
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Read ERA5 2D Wave Spectra NetCDF files"""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import xarray as xr
|
|
5
|
+
from xarray.backends import BackendEntrypoint
|
|
6
|
+
|
|
7
|
+
from wavespectra.core.utils import create_frequencies
|
|
8
|
+
from wavespectra.core.attributes import attrs, set_spec_attributes
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
MAPPING = {
|
|
12
|
+
"time": attrs.TIMENAME,
|
|
13
|
+
"valid_time": attrs.TIMENAME,
|
|
14
|
+
"frequency": attrs.FREQNAME,
|
|
15
|
+
"frequencyNumber": attrs.FREQNAME,
|
|
16
|
+
"direction": attrs.DIRNAME,
|
|
17
|
+
"directionNumber": attrs.DIRNAME,
|
|
18
|
+
"d2fd": attrs.SPECNAME,
|
|
19
|
+
"longitude": attrs.LONNAME,
|
|
20
|
+
"latitude": attrs.LATNAME,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def read_era5(filename_or_fileglob, chunks={}, f0=0.03453, df=1.1, as_site=False):
|
|
25
|
+
"""Read Spectra from ECMWF ERA5 netCDF format.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
- filename_or_fileglob (str, list, filelike): filename, fileglob specifying multiple
|
|
29
|
+
files, or filelike object to read.
|
|
30
|
+
- chunks (dict): chunk sizes for dimensions in dataset. By default
|
|
31
|
+
dataset is loaded using single chunk for all dimensions (see
|
|
32
|
+
xr.open_mfdataset documentation).
|
|
33
|
+
- f0 (float): First frequency value in Hz (e.g., 0.03453)
|
|
34
|
+
- df (float): Multiplicative increment between frequencies.
|
|
35
|
+
- as_site (bool): If True locations are defined by 1D site dimension.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
- dset (SpecDataset): spectra dataset object read from netcdf file.
|
|
39
|
+
|
|
40
|
+
Note:
|
|
41
|
+
- This reader also supports ECMWF spectra from the operational forecast.
|
|
42
|
+
- Documentation describing how to construct the spectral grid can be found at
|
|
43
|
+
https://www.ecmwf.int/en/forecasts/documentation-and-support/2d-wave-spectra.
|
|
44
|
+
- If file is large to fit in memory, consider specifying chunks for
|
|
45
|
+
'time' and/or 'latitude/longitude' dims.
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
dset = xr.open_dataset(filename_or_fileglob).chunk(chunks)
|
|
50
|
+
return from_era5(dset, f0=f0, df=df, as_site=as_site)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def from_era5(dset, f0=0.03453, df=1.1, as_site=False):
|
|
54
|
+
"""Format ERA5 netcdf dataset to receive wavespectra accessor.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
- dset (xr.Dataset): Dataset created from a ERA5 netcdf file.
|
|
58
|
+
- f0 (float): First frequency value in Hz (e.g., 0.03453)
|
|
59
|
+
- df (float): Multiplicative increment between frequencies.
|
|
60
|
+
- as_site (bool): If True locations are defined by 1D site dimension.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
- Formated dataset with the SpecDataset accessor in the `spec` namespace.
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
mapping = {k: v for k, v in MAPPING.items() if k != v and k in dset.variables}
|
|
68
|
+
dset = dset.rename(mapping).reset_coords(drop=True)
|
|
69
|
+
|
|
70
|
+
# Convert ERA5 format to wavespectra format
|
|
71
|
+
dset[attrs.SPECNAME] = 10 ** dset[attrs.SPECNAME] * np.pi / 180
|
|
72
|
+
dset[attrs.SPECNAME] = dset[attrs.SPECNAME].fillna(0)
|
|
73
|
+
|
|
74
|
+
# Assign the logarithmic frequency grid
|
|
75
|
+
dset[attrs.FREQNAME] = create_frequencies(f0, dset[attrs.FREQNAME].size, df)
|
|
76
|
+
|
|
77
|
+
# Assign the coming-from direction grid
|
|
78
|
+
dd = 360 / dset[attrs.DIRNAME].size
|
|
79
|
+
dset[attrs.DIRNAME] = ((np.arange(0, 360, dd) + dd / 2) + 180) % 360
|
|
80
|
+
|
|
81
|
+
# Stack lat/lon dimensions if as_site is True
|
|
82
|
+
if as_site:
|
|
83
|
+
dset = (
|
|
84
|
+
dset.stack(site=[attrs.LATNAME, attrs.LONNAME], create_index=False)
|
|
85
|
+
.reset_coords()
|
|
86
|
+
.transpose(attrs.TIMENAME, attrs.SITENAME, attrs.FREQNAME, attrs.DIRNAME)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Setting standard attributes
|
|
90
|
+
set_spec_attributes(dset)
|
|
91
|
+
|
|
92
|
+
return dset
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class ERA5BackendEntrypoint(BackendEntrypoint):
|
|
96
|
+
"""ERA5 backend engine."""
|
|
97
|
+
|
|
98
|
+
def open_dataset(
|
|
99
|
+
self,
|
|
100
|
+
filename_or_obj,
|
|
101
|
+
*,
|
|
102
|
+
drop_variables=None,
|
|
103
|
+
f0=0.03453,
|
|
104
|
+
df=1.1,
|
|
105
|
+
as_site=False,
|
|
106
|
+
):
|
|
107
|
+
return read_era5(filename_or_obj, f0=f0, df=df)
|
|
108
|
+
|
|
109
|
+
def guess_can_open(self, filename_or_obj):
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
description = "Open ERA5 netcdf spectra files as a wavespectra dataset."
|
|
113
|
+
|
|
114
|
+
url = "https://github.com/wavespectra/wavespectra"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: wavespectra
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4.0
|
|
4
4
|
Summary: Library for ocean wave spectra
|
|
5
5
|
Author-email: Wavespectra Developers <r.guedes@oceanum.science>
|
|
6
6
|
Maintainer-email: Rafael Guedes <r.guedes@oceanum.science>, Tom Durrant <t.durrant@oceanum.science>
|
|
@@ -76,6 +76,7 @@ Requires-Dist: sphinx; extra == "docs"
|
|
|
76
76
|
Requires-Dist: sphinx-autobuild; extra == "docs"
|
|
77
77
|
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
78
78
|
Requires-Dist: sphinx-gallery; extra == "docs"
|
|
79
|
+
Dynamic: license-file
|
|
79
80
|
|
|
80
81
|
wavespectra
|
|
81
82
|
===========
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"""Read ERA5 2D Wave Spectra NetCDF files"""
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
from xarray.backends import BackendEntrypoint
|
|
5
|
-
|
|
6
|
-
from wavespectra.core.attributes import attrs, set_spec_attributes
|
|
7
|
-
from wavespectra.input.netcdf import read_netcdf
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
DEFAULT_FREQS = np.full(30, 0.03453) * (1.1 ** np.arange(0, 30))
|
|
11
|
-
DEFAULT_DIRS = (np.arange(7.5, 352.5 + 15, 15) + 180) % 360
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def read_era5(filename_or_fileglob, chunks={}, freqs=None, dirs=None):
|
|
15
|
-
"""Read Spectra from ECMWF ERA5 netCDF format.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
- filename_or_fileglob (str, list, filelike): filename, fileglob specifying multiple
|
|
19
|
-
files, or filelike object to read.
|
|
20
|
-
- chunks (dict): chunk sizes for dimensions in dataset. By default
|
|
21
|
-
dataset is loaded using single chunk for all dimensions (see
|
|
22
|
-
xr.open_mfdataset documentation).
|
|
23
|
-
- freqs (list): list of frequencies. By default use all 30 ERA5 frequencies.
|
|
24
|
-
- dirs (list): list of directions. By default use all 24 ERA5 directions.
|
|
25
|
-
|
|
26
|
-
Returns:
|
|
27
|
-
- dset (SpecDataset): spectra dataset object read from netcdf file.
|
|
28
|
-
|
|
29
|
-
Note:
|
|
30
|
-
- Frequency and diirection coordinates seem to have only integer positions
|
|
31
|
-
which is why they are allowed to be specified as a parameter.
|
|
32
|
-
- If file is large to fit in memory, consider specifying chunks for
|
|
33
|
-
'time' and/or 'station' dims.
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
dset = read_netcdf(
|
|
38
|
-
filename_or_fileglob,
|
|
39
|
-
specname="d2fd",
|
|
40
|
-
freqname="frequency",
|
|
41
|
-
dirname="direction",
|
|
42
|
-
lonname="longitude",
|
|
43
|
-
latname="latitude",
|
|
44
|
-
timename="time",
|
|
45
|
-
chunks=chunks,
|
|
46
|
-
)
|
|
47
|
-
return from_era5(dset, freqs=freqs, dirs=dirs)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def from_era5(dset, freqs=None, dirs=None):
|
|
51
|
-
"""Format ERA5 netcdf dataset to receive wavespectra accessor.
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
- dset (xr.Dataset): Dataset created from a SWAN netcdf file.
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
- Formated dataset with the SpecDataset accessor in the `spec` namespace.
|
|
58
|
-
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
# Convert ERA5 format to wavespectra format
|
|
62
|
-
dset = 10**dset * np.pi / 180
|
|
63
|
-
dset = dset.fillna(0)
|
|
64
|
-
|
|
65
|
-
dset[attrs.FREQNAME] = freqs if freqs else DEFAULT_FREQS
|
|
66
|
-
dset[attrs.DIRNAME] = dirs if dirs else DEFAULT_DIRS
|
|
67
|
-
|
|
68
|
-
# Setting standard attributes
|
|
69
|
-
set_spec_attributes(dset)
|
|
70
|
-
|
|
71
|
-
return dset
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class ERA5BackendEntrypoint(BackendEntrypoint):
|
|
75
|
-
"""ERA5 backend engine."""
|
|
76
|
-
|
|
77
|
-
def open_dataset(
|
|
78
|
-
self,
|
|
79
|
-
filename_or_obj,
|
|
80
|
-
*,
|
|
81
|
-
drop_variables=None,
|
|
82
|
-
freqs=None,
|
|
83
|
-
dirs=None,
|
|
84
|
-
):
|
|
85
|
-
return read_era5(filename_or_obj, freqs=freqs, dirs=dirs)
|
|
86
|
-
|
|
87
|
-
def guess_can_open(self, filename_or_obj):
|
|
88
|
-
return False
|
|
89
|
-
|
|
90
|
-
description = "Open ERA5 netcdf spectra files as a wavespectra dataset."
|
|
91
|
-
|
|
92
|
-
url = "https://github.com/wavespectra/wavespectra"
|
|
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
|
|
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
|