tsdynamics 2.4.0__tar.gz → 2.4.1__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.
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/PKG-INFO +1 -1
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/__init__.py +1 -1
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/base/ode_base.py +9 -1
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/climate_geophysics.py +31 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/physical_systems.py +40 -1
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/_sampling.py +11 -16
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_diffsol_backend.py +4 -4
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/.gitignore +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/LICENSE +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/README.md +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/pyproject.toml +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/analysis/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/analysis/fixed_points.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/analysis/lyapunov.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/analysis/orbit_diagram.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/analysis/poincare.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/backends/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/backends/diffsol.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/backends/rustcore.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/base/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/base/base.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/base/dde_base.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/base/map_base.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/base/protocol.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/_base.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/ensemble.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/poincare.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/projected.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/stroboscopic.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/tangent.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/derived/wrapped.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/py.typed +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/registry.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/sampling.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/chaotic_attractors.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/chem_bio_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/coupled_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/delayed_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/exotic_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/oscillatory_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/population_dynamics.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/discrete/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/discrete/chaotic_maps.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/discrete/exotic_maps.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/discrete/geometric_maps.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/discrete/polynomial_maps.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/discrete/population_maps.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/utils/__init__.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/utils/general.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/utils/sagitta_dt.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/conftest.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_analysis.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_base.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_cache_isolation.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_dde_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_derived.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_diffsol_translation.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_jacobians.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_known_values.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_map_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_ode_rhs_symbolic.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_ode_systems.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_protocol.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_registry.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_rustcore.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_rustcore_translation.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_sampling.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_signatures.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_smoke.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_utils.py +0 -0
- {tsdynamics-2.4.0 → tsdynamics-2.4.1}/tests/test_wrapped.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tsdynamics
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.1
|
|
4
4
|
Summary: Compiled ODE/DDE integration, discrete maps, and chaos analysis for dynamical systems.
|
|
5
5
|
Project-URL: Source, https://github.com/El3ssar/TSDynamics
|
|
6
6
|
Project-URL: Documentation, https://el3ssar.github.io/TSDynamics/
|
|
@@ -48,7 +48,7 @@ from .systems import continuous as _continuous
|
|
|
48
48
|
from .systems import discrete as _discrete
|
|
49
49
|
|
|
50
50
|
# Single source of truth for the package version; rewritten by python-semantic-release.
|
|
51
|
-
__version__ = "2.4.
|
|
51
|
+
__version__ = "2.4.1"
|
|
52
52
|
|
|
53
53
|
# Re-export every system class at the top level so ``from tsdynamics import Lorenz``
|
|
54
54
|
# works without users having to remember which submodule a system lives in.
|
|
@@ -153,6 +153,14 @@ class ContinuousSystem(SystemBase, ABC):
|
|
|
153
153
|
|
|
154
154
|
_default_method: ClassVar[str] = "RK45"
|
|
155
155
|
|
|
156
|
+
#: Whether JiTCODE should run SymEngine's ``simplify(ratio=1)`` on each RHS
|
|
157
|
+
#: expression before emitting C. ``None`` keeps JiTCODE's own default
|
|
158
|
+
#: (enabled for ``dim <= 10``). Set ``False`` on systems whose RHS is a
|
|
159
|
+
#: large rational expression: the simplify pass is super-linear and can
|
|
160
|
+
#: effectively hang at compile time, while the C compiler optimises the
|
|
161
|
+
#: unsimplified code just as well (see ``BlinkingRotlet``).
|
|
162
|
+
_compile_simplify: ClassVar[bool | None] = None
|
|
163
|
+
|
|
156
164
|
#: Parameters whose values affect the symbolic *structure* of _equations
|
|
157
165
|
#: (e.g. integer loop bounds). These are baked in at compile time.
|
|
158
166
|
_structural_params: ClassVar[frozenset[str]] = frozenset()
|
|
@@ -390,7 +398,7 @@ class ContinuousSystem(SystemBase, ABC):
|
|
|
390
398
|
ode = cls_jitc(
|
|
391
399
|
f_sym, n=self.dim, control_pars=control_par_list, verbose=False, **lyap_kwargs
|
|
392
400
|
)
|
|
393
|
-
ode.generate_f_C()
|
|
401
|
+
ode.generate_f_C(simplify=type(self)._compile_simplify)
|
|
394
402
|
so = pathlib.Path(ode.save_compiled(destination=str(dest), overwrite=True))
|
|
395
403
|
|
|
396
404
|
if for_lyap:
|
{tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/climate_geophysics.py
RENAMED
|
@@ -75,6 +75,28 @@ class DoubleGyre(ContinuousSystem):
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
class BlinkingRotlet(ContinuousSystem):
|
|
78
|
+
r"""Blinking-rotlet flow — a model of chaotic advection in Stokes mixing.
|
|
79
|
+
|
|
80
|
+
A passive tracer in a circular cell stirred by two off-centre rotlets at
|
|
81
|
+
radius ``+b`` and ``-b`` that alternate being active with period ``tau``,
|
|
82
|
+
the switch being a steep ``tanh`` ramp. The periodic blinking folds and
|
|
83
|
+
stretches material lines, producing chaotic advection (Aref-type *blinking*
|
|
84
|
+
flow). State is ``(r, theta, t)`` in polar coordinates with an explicit
|
|
85
|
+
clock; ``dtheta`` carries a ``1/r`` factor singular at the cell centre, so
|
|
86
|
+
``default_ic`` sits on a bounded orbit away from ``r = 0``.
|
|
87
|
+
|
|
88
|
+
Compile note
|
|
89
|
+
------------
|
|
90
|
+
The rotlet velocity field is a large rational expression. JiTCODE's
|
|
91
|
+
default ``simplify(ratio=1)`` codegen pass is super-linear in expression
|
|
92
|
+
size and effectively hangs while *compiling* this RHS — which is what made
|
|
93
|
+
the system look un-integrable. ``_compile_simplify = False`` skips that
|
|
94
|
+
pass (the C compiler optimises the unsimplified code), after which the flow
|
|
95
|
+
integrates in well under a millisecond at every tolerance, even at the
|
|
96
|
+
original steep ``tanh`` switch.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
reference = "Meleshko & Aref (1996), Phys. Fluids 8, 3215-3217"
|
|
78
100
|
params = {
|
|
79
101
|
"a": 1.0,
|
|
80
102
|
"b": 0.5298833894399929,
|
|
@@ -83,6 +105,15 @@ class BlinkingRotlet(ContinuousSystem):
|
|
|
83
105
|
"tau": 3.0,
|
|
84
106
|
}
|
|
85
107
|
dim = 3
|
|
108
|
+
variables = ("r", "theta", "t")
|
|
109
|
+
#: On a bounded orbit (``r`` stays in ``[0.8, 0.91]``) away from the
|
|
110
|
+
#: ``r = 0`` angular singularity, so default sweeps stay bounded.
|
|
111
|
+
default_ic = [0.8, 4.887, 0.0]
|
|
112
|
+
|
|
113
|
+
# The rotlet RHS is a large rational expression; JiTCODE's default
|
|
114
|
+
# simplify(ratio=1) pass is super-linear on it and effectively hangs the
|
|
115
|
+
# compile. Skip it — the C compiler optimises the unsimplified code.
|
|
116
|
+
_compile_simplify = False
|
|
86
117
|
|
|
87
118
|
@staticmethod
|
|
88
119
|
def _rotlet(r, theta, a, b, bc):
|
|
@@ -140,13 +140,52 @@ class JerkCircuit(ContinuousSystem):
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
class WindmiReduced(ContinuousSystem):
|
|
143
|
+
r"""Reduced WINDMI model of the solar-wind–magnetosphere–ionosphere coupling.
|
|
144
|
+
|
|
145
|
+
Three-variable reduction (field-aligned current ``i``, voltage ``v``,
|
|
146
|
+
pressure ``p``) of the WINDMI energy-conserving model. The pressure-loss
|
|
147
|
+
term carries a fractional power ``p**(5/4)`` gated by a steep
|
|
148
|
+
``tanh(d1*(i-1))`` switch (``d1 = 2200`` makes it a near-step at ``i = 1``,
|
|
149
|
+
the substorm-onset threshold).
|
|
150
|
+
|
|
151
|
+
Numerical guards (no change to the dynamics)
|
|
152
|
+
--------------------------------------------
|
|
153
|
+
Two robustness guards let every backend reproduce the same orbit that
|
|
154
|
+
JiTCODE's explicit dopri5 already handles:
|
|
155
|
+
|
|
156
|
+
* ``abs(p)`` under the fractional power. On the attractor ``p >= 0``, but
|
|
157
|
+
adaptive and implicit solvers probe trial states with ``p < 0`` where the
|
|
158
|
+
real ``p**(5/4)`` is complex. ``abs(p)`` is identical to ``p`` on the
|
|
159
|
+
physical trajectory and real, ``C^1`` everywhere.
|
|
160
|
+
|
|
161
|
+
* The ``tanh`` argument is clamped to ``[-_TANH_CLAMP, _TANH_CLAMP]``.
|
|
162
|
+
``tanh`` saturates to ``±1`` to machine precision past ``|arg| ≈ 20``, so
|
|
163
|
+
clamping leaves the switch value unchanged, but it stops the diffsol Rust
|
|
164
|
+
kernels' automatic differentiation from overflowing on ``exp`` of an
|
|
165
|
+
enormous ``d1*(i-1)`` (≈ ±1500 on the orbit) — the actual cause of their
|
|
166
|
+
Newton/error-test failures. The clamp uses ``abs`` only, which both the
|
|
167
|
+
JiTCODE and DiffSL paths support.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
reference = "Horton, Weigel & Sprott (2001), Phys. Plasmas 8, 2946-2952"
|
|
143
171
|
params = {"a1": 0.247, "b1": 10.8, "b2": 0.0752, "b3": 1.06, "d1": 2200, "vsw": 5}
|
|
144
172
|
dim = 3
|
|
173
|
+
variables = ("i", "v", "p")
|
|
174
|
+
|
|
175
|
+
#: Bound on the ``tanh`` switch argument; ``tanh(±20)`` already equals ``±1``
|
|
176
|
+
#: to ~1e-18, so clamping is dynamically invisible but autodiff-safe.
|
|
177
|
+
_TANH_CLAMP = 25.0
|
|
145
178
|
|
|
146
179
|
@staticmethod
|
|
147
180
|
def _equations(Y, t, *, a1, b1, b2, b3, d1, vsw):
|
|
148
181
|
i, v, p = Y(0), Y(1), Y(2)
|
|
182
|
+
# Clamp d1*(i-1) to [-C, C] via the abs identity
|
|
183
|
+
# clamp(z, -C, C) = (|z + C| - |z - C|) / 2 — smooth-enough (abs only)
|
|
184
|
+
# and translatable by both the JiTCODE and DiffSL backends.
|
|
185
|
+
c = WindmiReduced._TANH_CLAMP
|
|
186
|
+
z = d1 * (i - 1)
|
|
187
|
+
z_clamped = (abs(z + c) - abs(z - c)) / 2
|
|
149
188
|
idot = a1 * (vsw - v)
|
|
150
189
|
vdot = b1 * i - b2 * p**1 / 2 - b3 * v
|
|
151
|
-
pdot = vsw**2 - p ** (5 / 4) * vsw ** (1 / 2) * (1 + tanh(
|
|
190
|
+
pdot = vsw**2 - abs(p) ** (5 / 4) * vsw ** (1 / 2) * (1 + tanh(z_clamped)) / 2
|
|
152
191
|
return idot, vdot, pdot
|
|
@@ -56,25 +56,20 @@ INTEGRATION_SAMPLE: list[str] = [
|
|
|
56
56
|
]
|
|
57
57
|
|
|
58
58
|
# --- ODE systems excluded from the exhaustive integration sweeps ------------
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"needs a dedicated integration recipe — tracked separately"
|
|
66
|
-
),
|
|
67
|
-
}
|
|
59
|
+
# Systems that cannot be integrated by adaptive solvers in bounded time would
|
|
60
|
+
# hang the nightly full sweep rather than fail it, so they are skipped here.
|
|
61
|
+
# Currently empty: ``BlinkingRotlet`` (the former entry) only *looked*
|
|
62
|
+
# un-integrable because JiTCODE's simplify(ratio=1) codegen pass hangs on its
|
|
63
|
+
# large rational RHS — fixed with ``_compile_simplify = False`` on the class.
|
|
64
|
+
HARD_TO_INTEGRATE: dict[str, str] = {}
|
|
68
65
|
|
|
69
66
|
# Systems the diffsol backend specifically can't integrate (the default JiTCODE
|
|
70
67
|
# backend handles them fine). Excluded from the diffsol full-catalogue sweep.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
),
|
|
77
|
-
}
|
|
68
|
+
# Currently empty: ``WindmiReduced`` (the former entry) now integrates on every
|
|
69
|
+
# diffsol solver after guarding the fractional power with ``abs(p)`` and
|
|
70
|
+
# clamping the steep ``tanh`` argument (autodiff-safe) — both no-ops on the
|
|
71
|
+
# physical trajectory.
|
|
72
|
+
DIFFSOL_SKIP: dict[str, str] = {}
|
|
78
73
|
|
|
79
74
|
# --- Maps excluded from Lyapunov-spectrum shape tests -----------------------
|
|
80
75
|
MAP_LYAPUNOV_EXCLUDE: dict[str, str] = {
|
|
@@ -135,10 +135,10 @@ def test_diffsol_integrates_full_catalogue() -> None:
|
|
|
135
135
|
(``-m full``) with the diffsol extra.
|
|
136
136
|
|
|
137
137
|
Numeric agreement with JiTCODE is checked separately on the curated sample
|
|
138
|
-
(``test_cross_validation_over_sample``)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
(``test_cross_validation_over_sample``); here we only assert each diffsol
|
|
139
|
+
trajectory is finite. ``HARD_TO_INTEGRATE | DIFFSOL_SKIP`` is honoured as
|
|
140
|
+
an escape hatch for systems that genuinely cannot be integrated, but both
|
|
141
|
+
sets are currently empty — the whole ODE catalogue integrates on diffsol.
|
|
142
142
|
"""
|
|
143
143
|
import sys
|
|
144
144
|
import zlib
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/chaotic_attractors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/oscillatory_systems.py
RENAMED
|
File without changes
|
{tsdynamics-2.4.0 → tsdynamics-2.4.1}/src/tsdynamics/systems/continuous/population_dynamics.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
|
|
File without changes
|