commodutil 4.0.0__tar.gz → 4.1.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.
- {commodutil-4.0.0 → commodutil-4.1.0}/PKG-INFO +1 -1
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/__init__.py +6 -5
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/convfactors.py +21 -42
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil.egg-info/PKG-INFO +1 -1
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_conv.py +9 -9
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_standards_currency.py +29 -18
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_standards_units.py +0 -20
- {commodutil-4.0.0 → commodutil-4.1.0}/.coveragerc +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/.github/workflows/1_tests.yml +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/.github/workflows/2_coverage.yml +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/.github/workflows/3_linting.yml +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/.github/workflows/4_release.yml +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/.gitignore +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/.pypirc +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/azure-build-pipelines.yml +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/arb.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/dates.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/__init__.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/calendar.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/continuous.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/fly.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/quarterly.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/spreads.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/structure.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forward/util.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/forwards.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/pandasutil.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/standards/__init__.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/standards/analysis_types.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/standards/commodities.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/standards/commodity_groups.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/standards/currency.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/standards/regions.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/standards/units.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/stats.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil/transforms.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil.egg-info/SOURCES.txt +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil.egg-info/dependency_links.txt +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil.egg-info/requires.txt +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/commodutil.egg-info/top_level.txt +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/pyproject.toml +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/requirements-test.txt +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/requirements.txt +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/requirements_dev.txt +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/setup.cfg +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/__init__.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/conftest.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/__init__.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/conftest.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/test_calendar.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/test_continuous.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/test_fly.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/test_quarterly.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/test_spreads.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/test_structure.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/forward/test_util.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_arb.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_cl.csv +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_dates.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_forwards.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_pandasutils.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_price_conv.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_standards_analysis_types.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_standards_commodities.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_standards_commodity_groups.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_standards_regions.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_stats.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_transforms.py +0 -0
- {commodutil-4.0.0 → commodutil-4.1.0}/tests/test_weekly.csv +0 -0
|
@@ -25,16 +25,17 @@ _LAZY_EXPORTS = {
|
|
|
25
25
|
"ALIASES": "commodutil.convfactors",
|
|
26
26
|
"COMMODITIES": "commodutil.convfactors",
|
|
27
27
|
"Commodity": "commodutil.convfactors",
|
|
28
|
-
"FRACTIONAL_TO_MAJOR": "commodutil.convfactors",
|
|
29
|
-
"VALID_CURRENCY_TOKENS": "commodutil.convfactors",
|
|
30
28
|
"convert": "commodutil.convfactors",
|
|
31
29
|
"convert_price": "commodutil.convfactors",
|
|
32
30
|
"convfactor": "commodutil.convfactors",
|
|
33
|
-
"fractional_to_major": "commodutil.convfactors",
|
|
34
|
-
"is_fractional_currency": "commodutil.convfactors",
|
|
35
31
|
"list_commodities": "commodutil.convfactors",
|
|
36
32
|
"list_units": "commodutil.convfactors",
|
|
37
|
-
|
|
33
|
+
# standards.currency (stdlib-only -- cheap, no pint)
|
|
34
|
+
"FRACTIONAL_TO_MAJOR": "commodutil.standards.currency",
|
|
35
|
+
"VALID_CURRENCY_TOKENS": "commodutil.standards.currency",
|
|
36
|
+
"fractional_to_major": "commodutil.standards.currency",
|
|
37
|
+
"is_fractional_currency": "commodutil.standards.currency",
|
|
38
|
+
"split_currency_unit": "commodutil.standards.currency",
|
|
38
39
|
# dates
|
|
39
40
|
"curmon": "commodutil.dates",
|
|
40
41
|
"curmonyear": "commodutil.dates",
|
|
@@ -240,8 +240,8 @@ class CommodityConverter:
|
|
|
240
240
|
convert(series, 'kt/month', 'bbl/day', commodity='gasoline')
|
|
241
241
|
"""
|
|
242
242
|
# Normalize and parse units to handle daily/monthly rates
|
|
243
|
-
from_unit =
|
|
244
|
-
to_unit =
|
|
243
|
+
from_unit = _to_pint_token(from_unit)
|
|
244
|
+
to_unit = _to_pint_token(to_unit)
|
|
245
245
|
from_rate = self._parse_rate_unit(from_unit)
|
|
246
246
|
to_rate = self._parse_rate_unit(to_unit)
|
|
247
247
|
|
|
@@ -273,8 +273,8 @@ class CommodityConverter:
|
|
|
273
273
|
self, value: float, from_unit: str, to_unit: str, commodity: Optional[str]
|
|
274
274
|
) -> float:
|
|
275
275
|
"""Convert a scalar value across mass/volume/energy using commodity context when needed."""
|
|
276
|
-
from_unit =
|
|
277
|
-
to_unit =
|
|
276
|
+
from_unit = _to_pint_token(from_unit)
|
|
277
|
+
to_unit = _to_pint_token(to_unit)
|
|
278
278
|
qty = value * self.ureg(from_unit)
|
|
279
279
|
|
|
280
280
|
# Try direct conversion first
|
|
@@ -404,10 +404,10 @@ class CommodityConverter:
|
|
|
404
404
|
"""Parse units like 'bbl/day' or 'kt/month'."""
|
|
405
405
|
if "/" in unit:
|
|
406
406
|
base, period = unit.split("/", 1)
|
|
407
|
-
base =
|
|
407
|
+
base = _to_pint_token(base)
|
|
408
408
|
period = period.strip().lower().rstrip("s") # day(s), month(s), year(s)
|
|
409
409
|
return {"base": base, "period": period}
|
|
410
|
-
return {"base":
|
|
410
|
+
return {"base": _to_pint_token(unit), "period": None}
|
|
411
411
|
|
|
412
412
|
def _rate_factor_scalar(
|
|
413
413
|
self, from_period: Optional[str], to_period: Optional[str]
|
|
@@ -469,15 +469,6 @@ class CommodityConverter:
|
|
|
469
469
|
except DimensionalityError:
|
|
470
470
|
return False
|
|
471
471
|
|
|
472
|
-
def _normalize_unit(self, unit: str) -> str:
|
|
473
|
-
"""Normalize a unit string into a pint-parseable token.
|
|
474
|
-
|
|
475
|
-
Thin shim around :func:`commodutil.standards.units.to_pint_token`.
|
|
476
|
-
Kept as a bound method because it has six internal call sites and
|
|
477
|
-
is exercised by the public test surface (``converter._normalize_unit``).
|
|
478
|
-
"""
|
|
479
|
-
return _to_pint_token(unit)
|
|
480
|
-
|
|
481
472
|
@property
|
|
482
473
|
def available_commodities(self) -> list:
|
|
483
474
|
"""List all available commodities"""
|
|
@@ -545,28 +536,14 @@ def convfactor(from_unit: str, to_unit: str, commodity: Optional[str] = None) ->
|
|
|
545
536
|
|
|
546
537
|
# ---- Currency-aware price conversion helpers ----
|
|
547
538
|
#
|
|
548
|
-
#
|
|
549
|
-
#
|
|
550
|
-
#
|
|
551
|
-
#
|
|
552
|
-
#
|
|
539
|
+
# Currency vocabulary lives in commodutil.standards.currency (importable
|
|
540
|
+
# without dragging in pint / pandas). convfactors owns only the integrated
|
|
541
|
+
# unit + currency `convert_price` math (which depends on the pint registry
|
|
542
|
+
# above) and reads currency vocabulary directly from _currency. Callers
|
|
543
|
+
# wanting currency vocabulary should import from commodutil.standards.currency.
|
|
553
544
|
|
|
554
545
|
from commodutil.standards import currency as _currency
|
|
555
546
|
|
|
556
|
-
_FRACTIONAL_CURRENCY_DIVISORS = _currency.FRACTIONAL_CURRENCY_DIVISORS
|
|
557
|
-
_FRACTIONAL_TO_MAJOR = _currency.FRACTIONAL_TO_MAJOR
|
|
558
|
-
_VALID_CURRENCY_TOKENS = _currency.VALID_CURRENCY_TOKENS
|
|
559
|
-
|
|
560
|
-
# Public re-exports — preserve every existing public symbol so that
|
|
561
|
-
# `from commodutil.convfactors import VALID_CURRENCY_TOKENS, fractional_to_major, ...`
|
|
562
|
-
# continues to resolve for downstream packages (pyoilprice etc.).
|
|
563
|
-
VALID_CURRENCY_TOKENS = _VALID_CURRENCY_TOKENS
|
|
564
|
-
FRACTIONAL_TO_MAJOR = _FRACTIONAL_TO_MAJOR
|
|
565
|
-
fractional_to_major = _currency.fractional_to_major
|
|
566
|
-
is_fractional_currency = _currency.is_fractional_currency
|
|
567
|
-
split_currency_unit = _currency.split_currency_unit
|
|
568
|
-
_split_currency_unit = split_currency_unit
|
|
569
|
-
|
|
570
547
|
|
|
571
548
|
def convert_price(
|
|
572
549
|
value: Union[float, pd.Series],
|
|
@@ -626,15 +603,17 @@ def convert_price(
|
|
|
626
603
|
fx_series = pd.Series([1.07, 1.08, 1.06], index=p.index)
|
|
627
604
|
convert_price(p, 'EUR/MWh', 'USD/MMBtu', fx=fx_series)
|
|
628
605
|
"""
|
|
629
|
-
from_ccy, from_bare_unit = split_currency_unit(from_unit)
|
|
630
|
-
to_ccy, to_bare_unit = split_currency_unit(to_unit)
|
|
606
|
+
from_ccy, from_bare_unit = _currency.split_currency_unit(from_unit)
|
|
607
|
+
to_ccy, to_bare_unit = _currency.split_currency_unit(to_unit)
|
|
631
608
|
|
|
632
609
|
# Resolve the underlying "major" currency on each side for same-base detection
|
|
633
610
|
# (e.g. USc and USD share major USD — pure scale, no FX needed).
|
|
634
|
-
from_major =
|
|
611
|
+
from_major = _currency.FRACTIONAL_TO_MAJOR.get(
|
|
635
612
|
from_ccy, from_ccy.upper() if from_ccy else ""
|
|
636
613
|
)
|
|
637
|
-
to_major =
|
|
614
|
+
to_major = _currency.FRACTIONAL_TO_MAJOR.get(
|
|
615
|
+
to_ccy, to_ccy.upper() if to_ccy else ""
|
|
616
|
+
)
|
|
638
617
|
# Treat '$' as 'USD' for the purpose of major-currency comparison.
|
|
639
618
|
if from_major == "$":
|
|
640
619
|
from_major = "USD"
|
|
@@ -663,8 +642,8 @@ def convert_price(
|
|
|
663
642
|
# needed even though the literal currency tokens differ. Handle BEFORE the
|
|
664
643
|
# `fx is None` raise below.
|
|
665
644
|
if same_base_fractional:
|
|
666
|
-
from_div =
|
|
667
|
-
to_div =
|
|
645
|
+
from_div = _currency.FRACTIONAL_CURRENCY_DIVISORS.get(from_ccy, 1.0)
|
|
646
|
+
to_div = _currency.FRACTIONAL_CURRENCY_DIVISORS.get(to_ccy, 1.0)
|
|
668
647
|
# value is in source-currency units; divide by from_div to get majors,
|
|
669
648
|
# multiply by to_div to get target-currency units.
|
|
670
649
|
return unit_converted * (to_div / from_div)
|
|
@@ -680,7 +659,7 @@ def convert_price(
|
|
|
680
659
|
f"(source currency '{from_ccy}' is non-USD)"
|
|
681
660
|
)
|
|
682
661
|
|
|
683
|
-
fractional_divisor =
|
|
662
|
+
fractional_divisor = _currency.FRACTIONAL_CURRENCY_DIVISORS.get(from_ccy, 1.0)
|
|
684
663
|
|
|
685
664
|
if isinstance(unit_converted, pd.Series) and isinstance(fx, pd.Series):
|
|
686
665
|
target_idx = unit_converted.index
|
|
@@ -752,7 +731,7 @@ def list_commodities():
|
|
|
752
731
|
def list_units():
|
|
753
732
|
"""List common units"""
|
|
754
733
|
# Return normalized forms to avoid encoding issues
|
|
755
|
-
return [
|
|
734
|
+
return [_to_pint_token(u) for u in converter.available_units]
|
|
756
735
|
|
|
757
736
|
|
|
758
737
|
# Example usage
|
|
@@ -217,21 +217,21 @@ class TestUtils:
|
|
|
217
217
|
) # 7450 bbl/kt / 30.4375 days/month
|
|
218
218
|
|
|
219
219
|
def test_normalize_unit(self):
|
|
220
|
-
"""Test unit normalization"""
|
|
221
|
-
from commodutil.
|
|
220
|
+
"""Test unit normalization (delegates to standards.units.to_pint_token)."""
|
|
221
|
+
from commodutil.standards.units import to_pint_token
|
|
222
222
|
|
|
223
223
|
# Test cubic meter variations
|
|
224
|
-
assert
|
|
225
|
-
assert
|
|
226
|
-
assert
|
|
227
|
-
assert
|
|
224
|
+
assert to_pint_token("m³") == "m^3"
|
|
225
|
+
assert to_pint_token("m**3") == "m^3"
|
|
226
|
+
assert to_pint_token("cubic_meter") == "m^3"
|
|
227
|
+
assert to_pint_token("CUBIC_METER") == "m^3"
|
|
228
228
|
|
|
229
229
|
# Test energy unit normalization
|
|
230
|
-
assert
|
|
231
|
-
assert
|
|
230
|
+
assert to_pint_token("BTU") == "Btu"
|
|
231
|
+
assert to_pint_token("MMBTU") == "MMBtu"
|
|
232
232
|
|
|
233
233
|
# Test whitespace handling
|
|
234
|
-
assert
|
|
234
|
+
assert to_pint_token(" bbl ") == "bbl"
|
|
235
235
|
|
|
236
236
|
def test_commodity_properties(self):
|
|
237
237
|
"""Test commodity property access and helper functions"""
|
|
@@ -134,22 +134,33 @@ def test_currency_map_known_entries():
|
|
|
134
134
|
assert CURRENCY_MAP["canadian dollars"] == "CAD"
|
|
135
135
|
|
|
136
136
|
|
|
137
|
-
# ----
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def
|
|
141
|
-
"""
|
|
142
|
-
commodutil.convfactors
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
137
|
+
# ---- Shim-removal regression guard ----
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_legacy_convfactors_currency_shims_are_gone():
|
|
141
|
+
"""The 4.0 standards consolidation kept temporary back-compat re-exports
|
|
142
|
+
of the currency vocabulary on commodutil.convfactors. They were removed
|
|
143
|
+
in 4.1 after an in-repo consumer sweep across the stack confirmed zero
|
|
144
|
+
live downstream callers. This test is a positive guard against
|
|
145
|
+
accidental re-introduction of the shims -- importing any of these names
|
|
146
|
+
from commodutil.convfactors must fail. The canonical home is
|
|
147
|
+
commodutil.standards.currency.
|
|
148
|
+
"""
|
|
149
|
+
import pytest
|
|
150
|
+
|
|
151
|
+
import commodutil.convfactors as cf
|
|
152
|
+
|
|
153
|
+
legacy_names = (
|
|
154
|
+
"VALID_CURRENCY_TOKENS",
|
|
155
|
+
"FRACTIONAL_TO_MAJOR",
|
|
156
|
+
"fractional_to_major",
|
|
157
|
+
"is_fractional_currency",
|
|
158
|
+
"split_currency_unit",
|
|
159
|
+
"_split_currency_unit",
|
|
160
|
+
"_FRACTIONAL_CURRENCY_DIVISORS",
|
|
161
|
+
"_FRACTIONAL_TO_MAJOR",
|
|
162
|
+
"_VALID_CURRENCY_TOKENS",
|
|
149
163
|
)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
assert cf_is_fractional_currency("USc") is True
|
|
154
|
-
assert cf_fractional_to_major("GBp") == "GBP"
|
|
155
|
-
assert cf_split_currency_unit("EUR/MWh") == ("EUR", "MWh")
|
|
164
|
+
for name in legacy_names:
|
|
165
|
+
with pytest.raises(AttributeError):
|
|
166
|
+
getattr(cf, name)
|
|
@@ -129,26 +129,6 @@ def test_to_pint_token_exposed_via_standards_facade():
|
|
|
129
129
|
assert to_pint_token("m³") == "m^3"
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
def test_converter_normalize_unit_delegates_to_to_pint_token():
|
|
133
|
-
"""CommodityConverter._normalize_unit is a thin shim around the
|
|
134
|
-
standalone normaliser. Regression guard against accidental drift."""
|
|
135
|
-
from commodutil.convfactors import converter
|
|
136
|
-
from commodutil.standards.units import to_pint_token
|
|
137
|
-
|
|
138
|
-
for sample in [
|
|
139
|
-
"m³",
|
|
140
|
-
"m**3",
|
|
141
|
-
"cubic_meter",
|
|
142
|
-
"CUBIC_METER",
|
|
143
|
-
"BTU",
|
|
144
|
-
"MMBTU",
|
|
145
|
-
" bbl ",
|
|
146
|
-
"m3/day",
|
|
147
|
-
None,
|
|
148
|
-
]:
|
|
149
|
-
assert converter._normalize_unit(sample) == to_pint_token(sample)
|
|
150
|
-
|
|
151
|
-
|
|
152
132
|
def test_unit_map_parity_with_curvemetadata():
|
|
153
133
|
"""Regression guard: UNIT_MAP must match curvemetadata's previous local
|
|
154
134
|
copy byte-for-byte until curvemetadata's re-export PR lands. Skipped if
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|