covjsonkit 0.2.16__tar.gz → 0.2.17__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.
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/PKG-INFO +1 -1
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/encoder.py +13 -3
- covjsonkit-0.2.17/covjsonkit/version.py +1 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/PKG-INFO +1 -1
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/SOURCES.txt +1 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/pyproject.toml +1 -1
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/conftest.py +1 -1
- covjsonkit-0.2.17/tests/geojsontest.py +16 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_bounding_box_from_polytope.py +1 -1
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_position_from_polytope.py +2 -2
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_time_series_from_polytope.py +43 -4
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_vertical_profile_from_polytope.py +1 -1
- covjsonkit-0.2.16/covjsonkit/version.py +0 -1
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.github/ci-hpc-config.yml +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.github/workflows/ci.yaml +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.github/workflows/label-public-pr.yml +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.gitignore +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.pre-commit-config.yaml +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/ACKNOWLEDGEMENTS.rst +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/LICENSE +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/MANIFEST.in +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/Makefile +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/README.md +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/Coverage.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/CoverageCollection.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/__init__.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/api.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/config.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/__init__.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/dwd/param.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/dwd/param_id.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/dwd/unit.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/ecmwf/param.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/ecmwf/param_id.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/ecmwf/unit.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/BoundingBox.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Circle.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Frame.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Grid.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Path.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Position.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Shapefile.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/TimeSeries.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/VerticalProfile.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Wkt.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/__init__.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/decoder.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/BoundingBox.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Circle.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Frame.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Grid.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Path.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Position.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Shapefile.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/TimeSeries.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/VerticalProfile.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Wkt.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/__init__.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/param_db.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/utils.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/dependency_links.txt +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/not-zip-safe +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/requires.txt +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/top_level.txt +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/docs/images/ECMWF_logo.svg.png +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/docs/images/Logo_Destination_Earth_Colours.png +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/example_config.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/requirements.txt +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/scripts/generate_param_db.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/setup.cfg +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/setup.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_coverage1.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_coverage2.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_geotiff.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_multipoint_coverage.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_path_coverage.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_timeseries_coverage.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_timeseries_xyz_coverage.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_verticalprofile_coverage.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_verticalprofile_xyz_coverage.json +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/requirements_test.txt +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_bounding_box.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_frame.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_grid.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_shapefile.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_time_series.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_vertical_profile.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_wkt.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_bounding_box.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_circle_from_polytope.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_frame.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_frame_from_polytope.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_grid.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_grid_from_polytope.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_path.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_path_from_polytope.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_shapefile.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_shapefile_from_polytope.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_time_series.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_wkt.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_wkt_from_polytope.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_geojson.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_geotiff.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_util_merge.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_multipoint.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_path.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_ts.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_vp.py +0 -0
- {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tox.ini +0 -0
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
+
import numpy as np
|
|
6
7
|
import orjson
|
|
7
8
|
import pandas as pd
|
|
8
9
|
from covjson_pydantic.coverage import CoverageCollection
|
|
@@ -176,7 +177,10 @@ class Encoder(ABC):
|
|
|
176
177
|
def handle_non_leaf_node(child):
|
|
177
178
|
non_leaf_axes = ["latitude", "longitude", "param", date_key]
|
|
178
179
|
if child.axis.name not in non_leaf_axes:
|
|
179
|
-
|
|
180
|
+
val = child.values[0]
|
|
181
|
+
if isinstance(val, np.datetime64):
|
|
182
|
+
val = str(val)
|
|
183
|
+
mars_metadata[child.axis.name] = val
|
|
180
184
|
|
|
181
185
|
def handle_specific_axes(child):
|
|
182
186
|
if child.axis.name == "latitude":
|
|
@@ -272,7 +276,10 @@ class Encoder(ABC):
|
|
|
272
276
|
def handle_non_leaf_node_step(child):
|
|
273
277
|
non_leaf_axes = ["latitude", "longitude", "param", "date", "time"]
|
|
274
278
|
if child.axis.name not in non_leaf_axes:
|
|
275
|
-
|
|
279
|
+
val = child.values[0]
|
|
280
|
+
if isinstance(val, np.datetime64):
|
|
281
|
+
val = str(val)
|
|
282
|
+
mars_metadata[child.axis.name] = val
|
|
276
283
|
|
|
277
284
|
def handle_specific_axes_step(child):
|
|
278
285
|
if child.axis.name == "latitude":
|
|
@@ -441,7 +448,10 @@ class Encoder(ABC):
|
|
|
441
448
|
def handle_non_leaf_node_month(child):
|
|
442
449
|
non_leaf_axes = ["latitude", "longitude", "param", "year", "month"]
|
|
443
450
|
if child.axis.name not in non_leaf_axes:
|
|
444
|
-
|
|
451
|
+
val = child.values[0]
|
|
452
|
+
if isinstance(val, np.datetime64):
|
|
453
|
+
val = str(val)
|
|
454
|
+
mars_metadata[child.axis.name] = val
|
|
445
455
|
|
|
446
456
|
def handle_specific_axes_month(child):
|
|
447
457
|
if child.axis.name == "latitude":
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.17"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from covjsonkit.api import Covjsonkit
|
|
5
|
+
|
|
6
|
+
current_dir = os.path.dirname(__file__)
|
|
7
|
+
timeseries = os.path.join(current_dir, "data/test_timeseries_coverage.json")
|
|
8
|
+
with open(timeseries, "r") as f:
|
|
9
|
+
timeseries = json.load(f)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
cov = Covjsonkit().decode(timeseries)
|
|
13
|
+
ts = cov.to_geojson()
|
|
14
|
+
print(ts)
|
|
15
|
+
assert ts["type"] == "FeatureCollection"
|
|
16
|
+
assert len(ts["features"]) == 16
|
|
@@ -130,7 +130,7 @@ class TestPositionFromPolytopeReforecast:
|
|
|
130
130
|
|
|
131
131
|
shared_metadata = {
|
|
132
132
|
"class": "ce",
|
|
133
|
-
"date":
|
|
133
|
+
"date": "2024-03-01",
|
|
134
134
|
"Forecast date": "2025-07-14T06:00:00Z",
|
|
135
135
|
"domain": "g",
|
|
136
136
|
"expver": "4321",
|
|
@@ -168,7 +168,7 @@ class TestPositionFromPolytopeReforecast:
|
|
|
168
168
|
|
|
169
169
|
shared_metadata = {
|
|
170
170
|
"class": "ce",
|
|
171
|
-
"date":
|
|
171
|
+
"date": "2024-03-01",
|
|
172
172
|
"domain": "g",
|
|
173
173
|
"expver": "4321",
|
|
174
174
|
"levtype": "sfc",
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
4
|
+
import orjson
|
|
5
|
+
import pytest
|
|
2
6
|
from conftest import chain, make_leaf, make_point, node, tip
|
|
3
7
|
from polytope_feature.datacube.tensor_index_tree import TensorIndexTree
|
|
4
8
|
|
|
@@ -29,7 +33,7 @@ def hdate_branch(hdate, lat, lon, result):
|
|
|
29
33
|
|
|
30
34
|
EXPECTED_HDATE_METADATA = {
|
|
31
35
|
"class": "ce",
|
|
32
|
-
"date":
|
|
36
|
+
"date": "2024-03-01",
|
|
33
37
|
"domain": "g",
|
|
34
38
|
"expver": "4321",
|
|
35
39
|
"levtype": "sfc",
|
|
@@ -199,12 +203,13 @@ class TestTimeseriesFromPolytope:
|
|
|
199
203
|
|
|
200
204
|
|
|
201
205
|
class TestTimeseriesFromPolytopeReforecast:
|
|
202
|
-
|
|
206
|
+
@pytest.mark.parametrize("date", [np.datetime64("2024-03-01"), np.datetime64("2024-03-01T00:00:00")])
|
|
207
|
+
def test_single_point(self, date):
|
|
203
208
|
# 1 hdate (with time pre-merged by polytope-mars), 1 point
|
|
204
209
|
tree = chain(
|
|
205
210
|
TensorIndexTree(),
|
|
206
211
|
node("class", ("ce",)),
|
|
207
|
-
node("date", (
|
|
212
|
+
node("date", (date,)),
|
|
208
213
|
hdate_branch(np.datetime64("2025-07-14T06:00:00"), 51.5, 6.5, [42.17]),
|
|
209
214
|
)
|
|
210
215
|
|
|
@@ -231,7 +236,11 @@ class TestTimeseriesFromPolytopeReforecast:
|
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
238
|
|
|
234
|
-
assert cov["mars:metadata"] == {
|
|
239
|
+
assert cov["mars:metadata"] == {
|
|
240
|
+
"Forecast date": "2025-07-14T06:00:00Z",
|
|
241
|
+
**EXPECTED_HDATE_METADATA,
|
|
242
|
+
"date": date.astype(str),
|
|
243
|
+
}
|
|
235
244
|
|
|
236
245
|
def test_multiple_times(self):
|
|
237
246
|
# 2 hdate values (pre-merged times from same day), 1 point → 2 coverages
|
|
@@ -453,3 +462,33 @@ class TestTimeseriesFromPolytopeReforecast:
|
|
|
453
462
|
assert cov["domain"]["axes"]["t"]["values"] == t
|
|
454
463
|
assert cov["ranges"]["dis06"]["values"] == vals
|
|
455
464
|
assert cov["mars:metadata"] == {"Forecast date": fc_date, **EXPECTED_HDATE_METADATA}
|
|
465
|
+
|
|
466
|
+
@pytest.mark.parametrize(
|
|
467
|
+
"json_module,date", [(json, np.datetime64("2024-03-01")), (orjson, np.datetime64("2024-03-01T00:00:00"))]
|
|
468
|
+
)
|
|
469
|
+
def test_reforecast_covjson_is_json_serialisable(self, json_module, date):
|
|
470
|
+
"""CoverageJSON produced by from_polytope_reforecast must be serialisable
|
|
471
|
+
with both stdlib json and orjson (i.e. no numpy.datetime64 left in the
|
|
472
|
+
mars:metadata dict — regression test for the date axis leak)."""
|
|
473
|
+
tree = chain(
|
|
474
|
+
TensorIndexTree(),
|
|
475
|
+
node("class", ("ce",)),
|
|
476
|
+
node("date", (date,)),
|
|
477
|
+
hdate_branch(np.datetime64("2025-07-14T06:00:00"), 51.5, 6.5, [42.17]),
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
covjson = Covjsonkit().encode("CoverageCollection", "PointSeries").from_polytope_reforecast(tree)
|
|
481
|
+
|
|
482
|
+
# stdlib json.dumps must not raise TypeError
|
|
483
|
+
serialised = json_module.dumps(covjson)
|
|
484
|
+
|
|
485
|
+
# The 'date' value in mars:metadata must be a plain string, not numpy.datetime64
|
|
486
|
+
for cov in covjson["coverages"]:
|
|
487
|
+
date_val = cov["mars:metadata"].get("date")
|
|
488
|
+
assert not isinstance(
|
|
489
|
+
date_val, np.datetime64
|
|
490
|
+
), f"mars:metadata['date'] is still a numpy.datetime64: {date_val!r}"
|
|
491
|
+
|
|
492
|
+
# Round-trip through the JSON module to ensure it can be deserialised back to a dict
|
|
493
|
+
deserialised = json_module.loads(serialised)
|
|
494
|
+
assert deserialised == covjson
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.16"
|
|
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
|
|
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
|