pyTMD 2.1.2__tar.gz → 2.1.3__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.
- {pytmd-2.1.2 → pytmd-2.1.3}/PKG-INFO +1 -1
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/FES.py +7 -6
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/model.py +193 -5
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD.egg-info/PKG-INFO +1 -1
- pytmd-2.1.3/version.txt +1 -0
- pytmd-2.1.2/version.txt +0 -1
- {pytmd-2.1.2 → pytmd-2.1.3}/.dockerignore +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/.gitignore +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/CODE_OF_CONDUCT.rst +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/CONTRIBUTORS.rst +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/LICENSE +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/MANIFEST.in +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/README.rst +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/postBuild +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/__init__.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/arguments.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/astro.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/check_points.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/compute.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/compute_tide_corrections.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/crs.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/data/opoleloadcoefcmcor.txt.gz +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/data/tab5.2e.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/data/tab5.3a.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/data/tab5.3b.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/ellipse.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/eop.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/interpolate.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/ATLAS.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/GOT.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/OTIS.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/__init__.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/constituents.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/io/ocean_pole_tide.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/predict.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/solve/__init__.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/solve/constants.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/spatial.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/time.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/tools.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/utilities.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD/version.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD.egg-info/SOURCES.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD.egg-info/dependency_links.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD.egg-info/requires.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/pyTMD.egg-info/top_level.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/requirements-dev.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/requirements.txt +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/arcticdata_tides.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/aviso_fes_tides.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/compute_LPET_elevations.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/compute_LPT_displacements.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/compute_OPT_displacements.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/compute_SET_displacements.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/compute_tidal_currents.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/compute_tidal_elevations.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/reduce_OTIS_files.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/usap_cats_tides.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/scripts/verify_box_tpxo.py +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/setup.cfg +0 -0
- {pytmd-2.1.2 → pytmd-2.1.3}/setup.py +0 -0
|
@@ -58,6 +58,7 @@ PROGRAM DEPENDENCIES:
|
|
|
58
58
|
|
|
59
59
|
UPDATE HISTORY:
|
|
60
60
|
Updated 07/2024: added new FES2022 to available known model versions
|
|
61
|
+
FES2022 have masked longitudes, only extract longitude data
|
|
61
62
|
Updated 01/2024: attempt to extract constituent IDs from filenames
|
|
62
63
|
Updated 06/2023: extract ocean tide model variables for FES2012
|
|
63
64
|
Updated 04/2023: added global HAMTIDE11 model
|
|
@@ -675,18 +676,18 @@ def read_netcdf_file(
|
|
|
675
676
|
# variable dimensions for each model
|
|
676
677
|
# amplitude and phase components for each type
|
|
677
678
|
if kwargs['version'] in ('FES2012',):
|
|
678
|
-
lon = fileID.variables['lon'][:]
|
|
679
|
-
lat = fileID.variables['lat'][:]
|
|
679
|
+
lon = fileID.variables['lon'][:].data
|
|
680
|
+
lat = fileID.variables['lat'][:].data
|
|
680
681
|
amp_key = dict(z='Ha', u='Ua', v='Va')[kwargs['type']]
|
|
681
682
|
phase_key = dict(z='Hg', u='Ug', v='Vg')[kwargs['type']]
|
|
682
683
|
elif kwargs['version'] in ('FES2014','FES2022','EOT20'):
|
|
683
|
-
lon = fileID.variables['lon'][:]
|
|
684
|
-
lat = fileID.variables['lat'][:]
|
|
684
|
+
lon = fileID.variables['lon'][:].data
|
|
685
|
+
lat = fileID.variables['lat'][:].data
|
|
685
686
|
amp_key = dict(z='amplitude', u='Ua', v='Va')[kwargs['type']]
|
|
686
687
|
phase_key = dict(z='phase', u='Ug', v='Vg')[kwargs['type']]
|
|
687
688
|
elif kwargs['version'] in ('HAMTIDE11',):
|
|
688
|
-
lon = fileID.variables['LON'][:]
|
|
689
|
-
lat = fileID.variables['LAT'][:]
|
|
689
|
+
lon = fileID.variables['LON'][:].data
|
|
690
|
+
lat = fileID.variables['LAT'][:].data
|
|
690
691
|
amp_key = dict(z='AMPL', u='UAMP', v='VAMP')[kwargs['type']]
|
|
691
692
|
phase_key = dict(z='PHAS', u='UPHA', v='VPHA')[kwargs['type']]
|
|
692
693
|
# get amplitude and phase components
|
|
@@ -7,6 +7,7 @@ Retrieves tide model parameters for named tide models and
|
|
|
7
7
|
|
|
8
8
|
UPDATE HISTORY:
|
|
9
9
|
Updated 07/2024: added new FES2022 and FES2022_load to list of models
|
|
10
|
+
added JSON format for model definition files
|
|
10
11
|
Updated 05/2024: make subscriptable and allow item assignment
|
|
11
12
|
Updated 04/2024: append v-components of velocity only to netcdf format
|
|
12
13
|
Updated 11/2023: revert TPXO9-atlas currents changes to separate dicts
|
|
@@ -44,6 +45,7 @@ from __future__ import annotations
|
|
|
44
45
|
import re
|
|
45
46
|
import io
|
|
46
47
|
import copy
|
|
48
|
+
import json
|
|
47
49
|
import pathlib
|
|
48
50
|
|
|
49
51
|
class model:
|
|
@@ -1337,7 +1339,10 @@ class model:
|
|
|
1337
1339
|
# return the complete output path
|
|
1338
1340
|
return output_file
|
|
1339
1341
|
|
|
1340
|
-
def from_file(self,
|
|
1342
|
+
def from_file(self,
|
|
1343
|
+
definition_file: str | pathlib.Path | io.IOBase,
|
|
1344
|
+
format: str = 'ascii'
|
|
1345
|
+
):
|
|
1341
1346
|
"""
|
|
1342
1347
|
Create a model object from an input definition file
|
|
1343
1348
|
|
|
@@ -1345,23 +1350,45 @@ class model:
|
|
|
1345
1350
|
----------
|
|
1346
1351
|
definition_file: str, pathlib.Path or io.IOBase
|
|
1347
1352
|
model definition file for creating model object
|
|
1353
|
+
format: str
|
|
1354
|
+
format of the input definition file
|
|
1355
|
+
|
|
1356
|
+
- ``'ascii'`` for tab-delimited definition file
|
|
1357
|
+
- ``'json'`` for JSON formatted definition file
|
|
1348
1358
|
"""
|
|
1349
|
-
# variable with parameter definitions
|
|
1350
|
-
parameters = {}
|
|
1351
1359
|
# Opening definition file and assigning file ID number
|
|
1352
1360
|
if isinstance(definition_file, io.IOBase):
|
|
1353
1361
|
fid = copy.copy(definition_file)
|
|
1354
1362
|
else:
|
|
1355
1363
|
definition_file = pathlib.Path(definition_file).expanduser()
|
|
1356
1364
|
fid = definition_file.open(mode="r", encoding='utf8')
|
|
1365
|
+
# load and parse definition file type
|
|
1366
|
+
if (format.lower() == 'ascii'):
|
|
1367
|
+
self.from_ascii(fid)
|
|
1368
|
+
elif (format.lower() == 'json'):
|
|
1369
|
+
self.from_json(fid)
|
|
1370
|
+
# close the definition file
|
|
1371
|
+
fid.close()
|
|
1372
|
+
# return the model object
|
|
1373
|
+
return self
|
|
1374
|
+
|
|
1375
|
+
def from_ascii(self, fid: io.IOBase):
|
|
1376
|
+
"""
|
|
1377
|
+
Load and parse tab-delimited definition file
|
|
1378
|
+
|
|
1379
|
+
Parameters
|
|
1380
|
+
----------
|
|
1381
|
+
fid: io.IOBase
|
|
1382
|
+
open definition file object
|
|
1383
|
+
"""
|
|
1384
|
+
# variable with parameter definitions
|
|
1385
|
+
parameters = {}
|
|
1357
1386
|
# for each line in the file will extract the parameter (name and value)
|
|
1358
1387
|
for fileline in fid:
|
|
1359
1388
|
# Splitting the input line between parameter name and value
|
|
1360
1389
|
part = fileline.rstrip().split(maxsplit=1)
|
|
1361
1390
|
# filling the parameter definition variable
|
|
1362
1391
|
parameters[part[0]] = part[1]
|
|
1363
|
-
# close the parameter file
|
|
1364
|
-
fid.close()
|
|
1365
1392
|
# convert from dictionary to model variable
|
|
1366
1393
|
temp = self.from_dict(parameters)
|
|
1367
1394
|
# verify model name, format and type
|
|
@@ -1539,6 +1566,167 @@ class model:
|
|
|
1539
1566
|
# return the model parameters
|
|
1540
1567
|
return temp
|
|
1541
1568
|
|
|
1569
|
+
def from_json(self, fid: io.IOBase):
|
|
1570
|
+
"""
|
|
1571
|
+
Load and parse JSON definition file
|
|
1572
|
+
|
|
1573
|
+
Parameters
|
|
1574
|
+
----------
|
|
1575
|
+
fid: io.IOBase
|
|
1576
|
+
open definition file object
|
|
1577
|
+
"""
|
|
1578
|
+
# load JSON file
|
|
1579
|
+
parameters = json.load(fid)
|
|
1580
|
+
# convert from dictionary to model variable
|
|
1581
|
+
temp = self.from_dict(parameters)
|
|
1582
|
+
# verify model name, format and type
|
|
1583
|
+
assert temp.name
|
|
1584
|
+
assert temp.format in ('OTIS','ATLAS','TMD3','netcdf','GOT','FES')
|
|
1585
|
+
assert temp.type
|
|
1586
|
+
assert temp.model_file
|
|
1587
|
+
# split model file into list if an ATLAS, GOT or FES file
|
|
1588
|
+
# model files can be comma, tab or space delimited
|
|
1589
|
+
# extract full path to tide model files
|
|
1590
|
+
# extract full path to tide grid file
|
|
1591
|
+
if temp.format in ('OTIS','ATLAS','TMD3'):
|
|
1592
|
+
assert temp.grid_file
|
|
1593
|
+
# check if grid file is relative
|
|
1594
|
+
if (temp.directory is not None):
|
|
1595
|
+
temp.grid_file = temp.directory.joinpath(temp.grid_file).resolve()
|
|
1596
|
+
else:
|
|
1597
|
+
temp.grid_file = pathlib.Path(temp.grid_file).expanduser()
|
|
1598
|
+
# extract model files
|
|
1599
|
+
if (temp.type == ['u','v']) and (temp.directory is not None):
|
|
1600
|
+
# use glob strings to find files in directory
|
|
1601
|
+
for key, glob_string in temp.model_file.items():
|
|
1602
|
+
temp.model_file[key] = list(temp.directory.glob(glob_string))
|
|
1603
|
+
# attempt to extract model directory
|
|
1604
|
+
try:
|
|
1605
|
+
temp.model_directory = temp.model_file['u'][0].parent
|
|
1606
|
+
except (IndexError, AttributeError) as exc:
|
|
1607
|
+
message = f'No model files found with {glob_string}'
|
|
1608
|
+
raise FileNotFoundError(message) from exc
|
|
1609
|
+
elif (temp.type == 'z') and (temp.directory is not None):
|
|
1610
|
+
# use glob strings to find files in directory
|
|
1611
|
+
glob_string = copy.copy(temp.model_file)
|
|
1612
|
+
|
|
1613
|
+
temp.model_file = list(temp.directory.glob(glob_string))
|
|
1614
|
+
# attempt to extract model directory
|
|
1615
|
+
try:
|
|
1616
|
+
temp.model_directory = temp.model_file[0].parent
|
|
1617
|
+
except (IndexError, AttributeError) as exc:
|
|
1618
|
+
message = f'No model files found with {glob_string}'
|
|
1619
|
+
raise FileNotFoundError(message) from exc
|
|
1620
|
+
elif (temp.type == ['u','v']) and isinstance(temp.model_file, dict):
|
|
1621
|
+
# resolve paths to model files for each direction
|
|
1622
|
+
for key, model_file in temp.model_file.items():
|
|
1623
|
+
temp.model_file[key] = [pathlib.Path(f).expanduser() for f in
|
|
1624
|
+
model_file]
|
|
1625
|
+
# copy directory dictionaries
|
|
1626
|
+
temp.model_directory = temp.model_file['u'][0].parent
|
|
1627
|
+
elif (temp.type == 'z') and isinstance(temp.model_file, list):
|
|
1628
|
+
# resolve paths to model files
|
|
1629
|
+
temp.model_file = [pathlib.Path(f).expanduser() for f in
|
|
1630
|
+
temp.model_file]
|
|
1631
|
+
temp.model_directory = temp.model_file[0].parent
|
|
1632
|
+
else:
|
|
1633
|
+
# fully defined single file case
|
|
1634
|
+
temp.model_file = pathlib.Path(temp.model_file).expanduser()
|
|
1635
|
+
temp.model_directory = temp.model_file.parent
|
|
1636
|
+
elif temp.format in ('netcdf',):
|
|
1637
|
+
assert temp.grid_file
|
|
1638
|
+
# check if grid file is relative
|
|
1639
|
+
if (temp.directory is not None):
|
|
1640
|
+
temp.grid_file = temp.directory.joinpath(temp.grid_file).resolve()
|
|
1641
|
+
else:
|
|
1642
|
+
temp.grid_file = pathlib.Path(temp.grid_file).expanduser()
|
|
1643
|
+
# extract model files
|
|
1644
|
+
if (temp.type == ['u','v']) and (temp.directory is not None):
|
|
1645
|
+
# use glob strings to find files in directory
|
|
1646
|
+
for key, glob_string in temp.model_file.items():
|
|
1647
|
+
temp.model_file[key] = list(temp.directory.glob(glob_string))
|
|
1648
|
+
# attempt to extract model directory
|
|
1649
|
+
try:
|
|
1650
|
+
temp.model_directory = temp.model_file['u'][0].parent
|
|
1651
|
+
except (IndexError, AttributeError) as exc:
|
|
1652
|
+
message = f'No model files found with {glob_string}'
|
|
1653
|
+
raise FileNotFoundError(message) from exc
|
|
1654
|
+
elif (temp.type == 'z') and (temp.directory is not None):
|
|
1655
|
+
# use glob strings to find files in directory
|
|
1656
|
+
glob_string = copy.copy(temp.model_file)
|
|
1657
|
+
temp.model_file = list(temp.directory.glob(glob_string))
|
|
1658
|
+
# attempt to extract model directory
|
|
1659
|
+
try:
|
|
1660
|
+
temp.model_directory = temp.model_file[0].parent
|
|
1661
|
+
except (IndexError, AttributeError) as exc:
|
|
1662
|
+
message = f'No model files found with {glob_string}'
|
|
1663
|
+
raise FileNotFoundError(message) from exc
|
|
1664
|
+
elif (temp.type == ['u','v']):
|
|
1665
|
+
# resolve paths to model files for each direction
|
|
1666
|
+
for key, model_file in temp.model_file.items():
|
|
1667
|
+
temp.model_file[key] = [pathlib.Path(f).expanduser() for f in
|
|
1668
|
+
model_file]
|
|
1669
|
+
# copy to directory dictionaries
|
|
1670
|
+
temp.model_directory = temp.model_file['u'][0].parent
|
|
1671
|
+
elif (temp.type == 'z'):
|
|
1672
|
+
# resolve paths to model files
|
|
1673
|
+
temp.model_file = [pathlib.Path(f).expanduser() for f in
|
|
1674
|
+
temp.model_file]
|
|
1675
|
+
temp.model_directory = temp.model_file[0].parent
|
|
1676
|
+
elif temp.format in ('FES','GOT'):
|
|
1677
|
+
# extract model files
|
|
1678
|
+
if (temp.type == ['u','v']) and (temp.directory is not None):
|
|
1679
|
+
# use glob strings to find files in directory
|
|
1680
|
+
for key, glob_string in temp.model_file.items():
|
|
1681
|
+
temp.model_file[key] = list(temp.directory.glob(glob_string))
|
|
1682
|
+
# build model directory dictionaries
|
|
1683
|
+
temp.model_directory = {}
|
|
1684
|
+
for key, val in temp.model_file.items():
|
|
1685
|
+
# attempt to extract model directory
|
|
1686
|
+
try:
|
|
1687
|
+
temp.model_directory[key] = val[0].parent
|
|
1688
|
+
except (IndexError, AttributeError) as exc:
|
|
1689
|
+
message = f'No model files found with {glob_string[key]}'
|
|
1690
|
+
raise FileNotFoundError(message) from exc
|
|
1691
|
+
elif (temp.type == 'z') and (temp.directory is not None):
|
|
1692
|
+
# use glob strings to find files in directory
|
|
1693
|
+
glob_string = copy.copy(temp.model_file)
|
|
1694
|
+
|
|
1695
|
+
temp.model_file = list(temp.directory.glob(glob_string))
|
|
1696
|
+
# attempt to extract model directory
|
|
1697
|
+
try:
|
|
1698
|
+
temp.model_directory = temp.model_file[0].parent
|
|
1699
|
+
except (IndexError, AttributeError) as exc:
|
|
1700
|
+
message = f'No model files found with {glob_string}'
|
|
1701
|
+
elif (temp.type == ['u','v']):
|
|
1702
|
+
# resolve paths to model files for each direction
|
|
1703
|
+
for key, model_file in temp.model_file.items():
|
|
1704
|
+
temp.model_file[key] = [pathlib.Path(f).expanduser() for f in
|
|
1705
|
+
model_file]
|
|
1706
|
+
# build model directory dictionaries
|
|
1707
|
+
temp.model_directory = {}
|
|
1708
|
+
for key, val in temp.model_file.items():
|
|
1709
|
+
temp.model_directory[key] = val[0].parent
|
|
1710
|
+
elif (temp.type == 'z'):
|
|
1711
|
+
# resolve paths to model files
|
|
1712
|
+
temp.model_file = [pathlib.Path(f).expanduser() for f in
|
|
1713
|
+
temp.model_file]
|
|
1714
|
+
temp.model_directory = temp.model_file[0].parent
|
|
1715
|
+
# verify that projection attribute exists for projected models
|
|
1716
|
+
if temp.format in ('OTIS','ATLAS','TMD3'):
|
|
1717
|
+
assert temp.projection
|
|
1718
|
+
# convert scale from string to float
|
|
1719
|
+
if temp.format in ('netcdf','GOT','FES'):
|
|
1720
|
+
assert temp.scale
|
|
1721
|
+
# assert that FES model has a version
|
|
1722
|
+
# get model constituents from constituent files
|
|
1723
|
+
if temp.format in ('FES',):
|
|
1724
|
+
assert temp.version
|
|
1725
|
+
if (temp.constituents is None):
|
|
1726
|
+
temp.parse_constituents()
|
|
1727
|
+
# return the model parameters
|
|
1728
|
+
return temp
|
|
1729
|
+
|
|
1542
1730
|
def parse_constituents(self) -> list:
|
|
1543
1731
|
"""
|
|
1544
1732
|
Parses tide model files for a list of model constituents
|
pytmd-2.1.3/version.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.1.3
|
pytmd-2.1.2/version.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2.1.2
|
|
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
|