mathjson-solver 2.1.1__tar.gz → 2.2.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.
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/CHANGELOG.md +8 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/PKG-INFO +31 -3
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/README.md +30 -2
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/pyproject.toml +1 -1
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/src/mathjson_solver/__init__.py +1 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/src/mathjson_solver/__main__.py +30 -1
- mathjson_solver-2.2.0/tests/test_legacy_compat.py +73 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/.gitignore +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/CODE_OF_CONDUCT.md +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/CONTRIBUTING.md +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/LICENSE +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/SECURITY.md +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/docs/README.md +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/docs/integration-test-cases.md +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_TrapezoidalIntegratel.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_atindex.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_cortexjs_compat.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_cortexjs_tier3.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_cumulative.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_datetime.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_equal.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_exceptions.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_extract_variables.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_findinterval.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_gail_model.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_interpolate.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_range.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_reduce_simple.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_scalars.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_sets.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_simple_cases.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_slice.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_state_tuples_reduce.py +0 -0
- {mathjson_solver-2.1.1 → mathjson_solver-2.2.0}/tests/test_with_pytest.py +0 -0
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [2.2.0] - 2026-09-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Migration helper for 1.x users:** `translate_v1_mathjson(expr)` rewrites the one breaking change from 2.0.0 (`["Log", x]`, previously natural log) to its 2.x equivalent (`["Ln", x]`), leaving everything else untouched. `create_solver(parameters, legacy_v1=True)` applies this automatically, so existing 1.x expressions keep evaluating to the same results on 2.x without hand-editing, while still gaining access to functions added in 2.x.
|
|
13
|
+
|
|
14
|
+
[2.2.0]: https://github.com/LongenesisLtd/mathjson-solver/compare/v2.1.1...v2.2.0
|
|
15
|
+
|
|
8
16
|
## [2.1.1] - 2026-08-19
|
|
9
17
|
|
|
10
18
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mathjson-solver
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Utilities for MathJSON evaluation
|
|
5
5
|
Project-URL: Homepage, https://github.com/LongenesisLtd/mathjson-solver
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
|
|
@@ -18,7 +18,7 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
[](https://pepy.tech/projects/mathjson-solver)
|
|
19
19
|
[](https://www.python.org/downloads/)
|
|
20
20
|
|
|
21
|
-
> **Heads up:** Version 2 introduces a
|
|
21
|
+
> **Heads up:** Version 2 introduces a breaking change (see [CHANGELOG.md](CHANGELOG.md)) as part of steering back towards greater compatibility with [CortexJS MathJSON](https://cortexjs.io/compute-engine/): `Log` is now log base 10 instead of natural log. Stuck on pre-2.0.0 expressions but want the functions added in 2.x? Pass `legacy_v1=True` to `create_solver()` (see [Migrating from 1.x](#migrating-from-1x)) instead of hand-migrating every expression. Bugfix releases for the 1.x line also continue on the [`1.x` branch](https://github.com/LongenesisLtd/mathjson-solver/tree/1.x).
|
|
22
22
|
|
|
23
23
|
A reliable Python library for numerically evaluating mathematical expressions in MathJSON format. Perfect for applications that need to safely execute user-provided formulas, calculate dynamic equations, or process mathematical data.
|
|
24
24
|
|
|
@@ -27,12 +27,14 @@ A reliable Python library for numerically evaluating mathematical expressions in
|
|
|
27
27
|
## Table of Contents
|
|
28
28
|
- [Installation](#installation)
|
|
29
29
|
- [Quick Start](#quick-start)
|
|
30
|
+
- [Migrating from 1.x](#migrating-from-1x)
|
|
30
31
|
- [Supported Operations](#supported-operations)
|
|
31
32
|
- [Error Handling](#error-handling)
|
|
32
33
|
- [Use Cases](#use-cases)
|
|
33
34
|
- [Testing](#testing)
|
|
34
35
|
- [Community](#community)
|
|
35
36
|
- [Contributing](#contributing)
|
|
37
|
+
- [Related Projects](#related-projects)
|
|
36
38
|
|
|
37
39
|
## Installation
|
|
38
40
|
|
|
@@ -82,6 +84,27 @@ solver(["Map", ["Array", 1, 2, 3, 4], ["Function", ["Multiply", "_", 2]]]) # [2
|
|
|
82
84
|
solver(["Reduce", ["Array", 1, 2, 3, 4], ["Add"]]) # 10
|
|
83
85
|
```
|
|
84
86
|
|
|
87
|
+
## Migrating from 1.x
|
|
88
|
+
|
|
89
|
+
Version 2.0.0's only breaking change is `Log`: pre-2.0.0 it was always natural log, `["Log", x]` == `math.log(x)`. From 2.0.0 on it matches [CortexJS](https://cortexjs.io/compute-engine/) — `["Log", x]` is log base 10, `["Log", x, b]` is log base `b` — and natural log moved to `Ln`.
|
|
90
|
+
|
|
91
|
+
If you have existing expressions built for 1.x and don't want to hand-edit every `Log` node just to pick up functions added in 2.x (`Product`, the CortexJS forms of `If`/`Map`/`Filter`/`Reduce`, the new aliases, etc.), pass `legacy_v1=True` when creating the solver. It rewrites every `["Log", x]` to `["Ln", x]` before evaluating, so old expressions keep producing the same results without modification:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
solver = create_solver(parameters, legacy_v1=True)
|
|
95
|
+
solver(["Log", 8]) # 2.0794... (natural log, matching pre-2.0.0 behavior)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
You can also run the rewrite yourself and inspect or store the translated expression:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from mathjson_solver import translate_v1_mathjson
|
|
102
|
+
|
|
103
|
+
translate_v1_mathjson(["Add", ["Log", 8], 1]) # ["Add", ["Ln", 8], 1]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`legacy_v1=True` only affects `Log`. Every other 1.x expression already evaluates identically on 2.x without any translation.
|
|
107
|
+
|
|
85
108
|
## Supported Operations
|
|
86
109
|
|
|
87
110
|
The library supports a comprehensive set of mathematical operations:
|
|
@@ -161,6 +184,9 @@ We welcome contributions! Please feel free to:
|
|
|
161
184
|
- Report bugs or request features via [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
162
185
|
- Submit pull requests with improvements
|
|
163
186
|
|
|
187
|
+
## Related Projects
|
|
188
|
+
|
|
189
|
+
We also created [`londec`](https://pypi.org/project/londec/) — evaluate tree-structured conditions against an ordered history of events. It uses mathjson-solver internally.
|
|
164
190
|
|
|
165
191
|
## License
|
|
166
192
|
|
|
@@ -168,7 +194,9 @@ We welcome contributions! Please feel free to:
|
|
|
168
194
|
|
|
169
195
|
## References
|
|
170
196
|
|
|
171
|
-
This
|
|
197
|
+
This library implements the [MathJSON](https://cortexjs.io/mathjson/) format as defined by the [CortexJS Compute Engine](https://cortexjs.io/compute-engine/). Since 2.0.0, mathjson-solver has been steering towards greater compatibility with CortexJS's calling conventions and function set — while remaining an independent Python implementation, not a port or dependency of CortexJS.
|
|
198
|
+
|
|
199
|
+
**Scope:** mathjson-solver targets compatibility with CortexJS's array-form calling conventions and standard function names — not the full [Compute Engine](https://cortexjs.io/compute-engine/), which is a symbolic CAS.
|
|
172
200
|
|
|
173
201
|
---
|
|
174
202
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://pepy.tech/projects/mathjson-solver)
|
|
5
5
|
[](https://www.python.org/downloads/)
|
|
6
6
|
|
|
7
|
-
> **Heads up:** Version 2 introduces a
|
|
7
|
+
> **Heads up:** Version 2 introduces a breaking change (see [CHANGELOG.md](CHANGELOG.md)) as part of steering back towards greater compatibility with [CortexJS MathJSON](https://cortexjs.io/compute-engine/): `Log` is now log base 10 instead of natural log. Stuck on pre-2.0.0 expressions but want the functions added in 2.x? Pass `legacy_v1=True` to `create_solver()` (see [Migrating from 1.x](#migrating-from-1x)) instead of hand-migrating every expression. Bugfix releases for the 1.x line also continue on the [`1.x` branch](https://github.com/LongenesisLtd/mathjson-solver/tree/1.x).
|
|
8
8
|
|
|
9
9
|
A reliable Python library for numerically evaluating mathematical expressions in MathJSON format. Perfect for applications that need to safely execute user-provided formulas, calculate dynamic equations, or process mathematical data.
|
|
10
10
|
|
|
@@ -13,12 +13,14 @@ A reliable Python library for numerically evaluating mathematical expressions in
|
|
|
13
13
|
## Table of Contents
|
|
14
14
|
- [Installation](#installation)
|
|
15
15
|
- [Quick Start](#quick-start)
|
|
16
|
+
- [Migrating from 1.x](#migrating-from-1x)
|
|
16
17
|
- [Supported Operations](#supported-operations)
|
|
17
18
|
- [Error Handling](#error-handling)
|
|
18
19
|
- [Use Cases](#use-cases)
|
|
19
20
|
- [Testing](#testing)
|
|
20
21
|
- [Community](#community)
|
|
21
22
|
- [Contributing](#contributing)
|
|
23
|
+
- [Related Projects](#related-projects)
|
|
22
24
|
|
|
23
25
|
## Installation
|
|
24
26
|
|
|
@@ -68,6 +70,27 @@ solver(["Map", ["Array", 1, 2, 3, 4], ["Function", ["Multiply", "_", 2]]]) # [2
|
|
|
68
70
|
solver(["Reduce", ["Array", 1, 2, 3, 4], ["Add"]]) # 10
|
|
69
71
|
```
|
|
70
72
|
|
|
73
|
+
## Migrating from 1.x
|
|
74
|
+
|
|
75
|
+
Version 2.0.0's only breaking change is `Log`: pre-2.0.0 it was always natural log, `["Log", x]` == `math.log(x)`. From 2.0.0 on it matches [CortexJS](https://cortexjs.io/compute-engine/) — `["Log", x]` is log base 10, `["Log", x, b]` is log base `b` — and natural log moved to `Ln`.
|
|
76
|
+
|
|
77
|
+
If you have existing expressions built for 1.x and don't want to hand-edit every `Log` node just to pick up functions added in 2.x (`Product`, the CortexJS forms of `If`/`Map`/`Filter`/`Reduce`, the new aliases, etc.), pass `legacy_v1=True` when creating the solver. It rewrites every `["Log", x]` to `["Ln", x]` before evaluating, so old expressions keep producing the same results without modification:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
solver = create_solver(parameters, legacy_v1=True)
|
|
81
|
+
solver(["Log", 8]) # 2.0794... (natural log, matching pre-2.0.0 behavior)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
You can also run the rewrite yourself and inspect or store the translated expression:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from mathjson_solver import translate_v1_mathjson
|
|
88
|
+
|
|
89
|
+
translate_v1_mathjson(["Add", ["Log", 8], 1]) # ["Add", ["Ln", 8], 1]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`legacy_v1=True` only affects `Log`. Every other 1.x expression already evaluates identically on 2.x without any translation.
|
|
93
|
+
|
|
71
94
|
## Supported Operations
|
|
72
95
|
|
|
73
96
|
The library supports a comprehensive set of mathematical operations:
|
|
@@ -147,6 +170,9 @@ We welcome contributions! Please feel free to:
|
|
|
147
170
|
- Report bugs or request features via [GitHub Issues](https://github.com/LongenesisLtd/mathjson-solver/issues)
|
|
148
171
|
- Submit pull requests with improvements
|
|
149
172
|
|
|
173
|
+
## Related Projects
|
|
174
|
+
|
|
175
|
+
We also created [`londec`](https://pypi.org/project/londec/) — evaluate tree-structured conditions against an ordered history of events. It uses mathjson-solver internally.
|
|
150
176
|
|
|
151
177
|
## License
|
|
152
178
|
|
|
@@ -154,7 +180,9 @@ We welcome contributions! Please feel free to:
|
|
|
154
180
|
|
|
155
181
|
## References
|
|
156
182
|
|
|
157
|
-
This
|
|
183
|
+
This library implements the [MathJSON](https://cortexjs.io/mathjson/) format as defined by the [CortexJS Compute Engine](https://cortexjs.io/compute-engine/). Since 2.0.0, mathjson-solver has been steering towards greater compatibility with CortexJS's calling conventions and function set — while remaining an independent Python implementation, not a port or dependency of CortexJS.
|
|
184
|
+
|
|
185
|
+
**Scope:** mathjson-solver targets compatibility with CortexJS's array-form calling conventions and standard function names — not the full [Compute Engine](https://cortexjs.io/compute-engine/), which is a symbolic CAS.
|
|
158
186
|
|
|
159
187
|
---
|
|
160
188
|
|
|
@@ -294,7 +294,29 @@ def comparison_safe_converter_for_pairs(
|
|
|
294
294
|
return v1, v2
|
|
295
295
|
|
|
296
296
|
|
|
297
|
-
def
|
|
297
|
+
def translate_v1_mathjson(expr):
|
|
298
|
+
"""
|
|
299
|
+
Rewrite a MathJSON expression written for mathjson-solver < 2.0.0 so it
|
|
300
|
+
evaluates to the same result on >= 2.0.0.
|
|
301
|
+
|
|
302
|
+
The only breaking change introduced in 2.0.0 is "Log": before 2.0.0 it
|
|
303
|
+
always meant natural log (`["Log", x]` == `math.log(x)`); from 2.0.0 on
|
|
304
|
+
it matches CortexJS (`["Log", x]` is log base 10, `["Log", x, b]` is log
|
|
305
|
+
base `b`), and natural log moved to "Ln". Since the pre-2.0.0 "Log" only
|
|
306
|
+
ever took one argument, every legacy `["Log", x]` node has exactly one
|
|
307
|
+
correct translation: `["Ln", x]`. This function walks the expression
|
|
308
|
+
tree and applies that rewrite, leaving everything else untouched, so
|
|
309
|
+
existing expressions don't need to be hand-migrated to keep working
|
|
310
|
+
while still gaining access to functions added in 2.x.
|
|
311
|
+
"""
|
|
312
|
+
if isinstance(expr, list):
|
|
313
|
+
if len(expr) == 2 and expr[0] == "Log":
|
|
314
|
+
return ["Ln", translate_v1_mathjson(expr[1])]
|
|
315
|
+
return [translate_v1_mathjson(item) for item in expr]
|
|
316
|
+
return expr
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def create_mathjson_solver(solver_parameters, legacy_v1=False):
|
|
298
320
|
def f(s, *args):
|
|
299
321
|
if args:
|
|
300
322
|
c = deepcopy(args[0])
|
|
@@ -1510,6 +1532,13 @@ def create_mathjson_solver(solver_parameters):
|
|
|
1510
1532
|
# raise KeyError(f"Parameter '{s}' is not defined")
|
|
1511
1533
|
return s
|
|
1512
1534
|
|
|
1535
|
+
if legacy_v1:
|
|
1536
|
+
|
|
1537
|
+
def legacy_v1_f(s, *args):
|
|
1538
|
+
return f(translate_v1_mathjson(s), *args)
|
|
1539
|
+
|
|
1540
|
+
return legacy_v1_f
|
|
1541
|
+
|
|
1513
1542
|
return f
|
|
1514
1543
|
|
|
1515
1544
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import math
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
sys.path.append(os.path.join(os.path.dirname(__file__), "../src/"))
|
|
7
|
+
|
|
8
|
+
from mathjson_solver import create_solver, translate_v1_mathjson
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.mark.parametrize(
|
|
12
|
+
"expression, expected_translation",
|
|
13
|
+
[
|
|
14
|
+
# The only rewrite: legacy 1-arg ["Log", x] -> ["Ln", x].
|
|
15
|
+
(["Log", 8], ["Ln", 8]),
|
|
16
|
+
(["Log", "x"], ["Ln", "x"]),
|
|
17
|
+
# Nested occurrences are rewritten too.
|
|
18
|
+
(["Add", ["Log", 8], 1], ["Add", ["Ln", 8], 1]),
|
|
19
|
+
(["Log", ["Log", 8]], ["Ln", ["Ln", 8]]),
|
|
20
|
+
# The 2.x 2-arg form is left alone (it never existed pre-2.0.0, so a
|
|
21
|
+
# legacy expression can never contain it).
|
|
22
|
+
(["Log", 8, 2], ["Log", 8, 2]),
|
|
23
|
+
# Everything else passes through unchanged.
|
|
24
|
+
(["Add", 1, 2], ["Add", 1, 2]),
|
|
25
|
+
(5, 5),
|
|
26
|
+
("x", "x"),
|
|
27
|
+
([], []),
|
|
28
|
+
],
|
|
29
|
+
)
|
|
30
|
+
def test_translate_v1_mathjson(expression, expected_translation):
|
|
31
|
+
assert translate_v1_mathjson(expression) == expected_translation
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_translate_v1_mathjson_does_not_mutate_input():
|
|
35
|
+
expression = ["Add", ["Log", 8], 1]
|
|
36
|
+
original = ["Add", ["Log", 8], 1]
|
|
37
|
+
translate_v1_mathjson(expression)
|
|
38
|
+
assert expression == original
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.mark.parametrize(
|
|
42
|
+
"parameters, expression, expected_result",
|
|
43
|
+
[
|
|
44
|
+
({}, ["Log", 8], math.log(8)),
|
|
45
|
+
({}, ["Add", ["Log", 8], 1], math.log(8) + 1),
|
|
46
|
+
# New (2.x-only) functions remain usable alongside legacy expressions.
|
|
47
|
+
({}, ["Product", ["Array", 2, 3, 4]], 24),
|
|
48
|
+
],
|
|
49
|
+
)
|
|
50
|
+
def test_create_solver_legacy_v1_mode(parameters, expression, expected_result):
|
|
51
|
+
solver = create_solver(parameters, legacy_v1=True)
|
|
52
|
+
assert solver(expression) == pytest.approx(expected_result)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_create_solver_legacy_v1_mode_matches_pre_2_0_0_log_semantics():
|
|
56
|
+
# Pre-2.0.0, ["Log", x] was always natural log - the exact behavior
|
|
57
|
+
# legacy_v1=True must reproduce for existing expressions.
|
|
58
|
+
solver = create_solver({}, legacy_v1=True)
|
|
59
|
+
assert solver(["Log", 8]) == pytest.approx(math.log(8))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_create_solver_non_legacy_v1_mode_uses_2_x_log_semantics():
|
|
63
|
+
# Without legacy_v1=True, current (2.x) semantics apply: base 10.
|
|
64
|
+
solver = create_solver({})
|
|
65
|
+
assert solver(["Log", 1000]) == pytest.approx(3)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_create_solver_legacy_v1_mode_with_parameter_reference():
|
|
69
|
+
# The translation happens on the whole expression tree up front, so a
|
|
70
|
+
# ["Log", x] whose argument is a solver parameter (not a literal) is
|
|
71
|
+
# rewritten and resolved correctly too.
|
|
72
|
+
solver = create_solver({"x": 8}, legacy_v1=True)
|
|
73
|
+
assert solver(["Log", "x"]) == pytest.approx(math.log(8))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|