TypeDAL 3.12.2__tar.gz → 3.13.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.
Potentially problematic release.
This version of TypeDAL might be problematic. Click here for more details.
- {typedal-3.12.2 → typedal-3.13.1}/CHANGELOG.md +12 -0
- {typedal-3.12.2 → typedal-3.13.1}/PKG-INFO +2 -2
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/__about__.py +1 -1
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/core.py +101 -4
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/helpers.py +24 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_main.py +39 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_query_builder.py +2 -0
- {typedal-3.12.2 → typedal-3.13.1}/.github/workflows/su6.yml +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/.gitignore +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/.readthedocs.yml +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/README.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/coverage.svg +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/1_getting_started.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/2_defining_tables.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/3_building_queries.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/4_relationships.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/5_py4web.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/6_migrations.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/7_mixins.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/css/code_blocks.css +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/index.md +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/docs/requirements.txt +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/example_new.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/example_old.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/mkdocs.yml +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/pyproject.toml +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/__init__.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/caching.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/cli.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/config.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/fields.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/for_py4web.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/for_web2py.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/mixins.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/py.typed +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/serializers/as_json.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/types.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/src/typedal/web2py_py4web_shared.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/__init__.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/configs/simple.toml +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/configs/valid.env +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/configs/valid.toml +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_cli.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_config.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_docs_examples.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_helpers.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_json.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_mixins.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_mypy.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_orm.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_py4web.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_relationships.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_row.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_stats.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_table.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_web2py.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/test_xx_others.py +0 -0
- {typedal-3.12.2 → typedal-3.13.1}/tests/timings.py +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
<!--next-version-placeholder-->
|
|
4
4
|
|
|
5
|
+
## v3.13.1 (2025-04-28)
|
|
6
|
+
|
|
7
|
+
### Fix
|
|
8
|
+
|
|
9
|
+
* Pass select kwargs via `.column()` - so you can do e.g. `distinct=True` ([`e5bc168`](https://github.com/trialandsuccess/TypeDAL/commit/e5bc168b90d6a5d214f049de0ef31e544214cc23))
|
|
10
|
+
|
|
11
|
+
## v3.13.0 (2025-04-28)
|
|
12
|
+
|
|
13
|
+
### Feature
|
|
14
|
+
|
|
15
|
+
* Adding `_once` hooks ([`a69fbb3`](https://github.com/trialandsuccess/TypeDAL/commit/a69fbb361cdfec9352fca503206299c5bbb940d2))
|
|
16
|
+
|
|
5
17
|
## v3.12.2 (2025-04-25)
|
|
6
18
|
|
|
7
19
|
### Fix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: TypeDAL
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.13.1
|
|
4
4
|
Summary: Typing support for PyDAL
|
|
5
5
|
Project-URL: Documentation, https://typedal.readthedocs.io/
|
|
6
6
|
Project-URL: Issues, https://github.com/trialandsuccess/TypeDAL/issues
|
|
@@ -5,6 +5,7 @@ Core functionality of TypeDAL.
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import csv
|
|
7
7
|
import datetime as dt
|
|
8
|
+
import functools
|
|
8
9
|
import inspect
|
|
9
10
|
import json
|
|
10
11
|
import math
|
|
@@ -33,6 +34,7 @@ from .helpers import (
|
|
|
33
34
|
all_annotations,
|
|
34
35
|
all_dict,
|
|
35
36
|
as_lambda,
|
|
37
|
+
classproperty,
|
|
36
38
|
extract_type_optional,
|
|
37
39
|
filter_out,
|
|
38
40
|
instanciate,
|
|
@@ -796,6 +798,10 @@ class TypeDAL(pydal.DAL): # type: ignore
|
|
|
796
798
|
return to_snake(camel)
|
|
797
799
|
|
|
798
800
|
|
|
801
|
+
P = typing.ParamSpec("P")
|
|
802
|
+
R = typing.TypeVar("R")
|
|
803
|
+
|
|
804
|
+
|
|
799
805
|
class TableMeta(type):
|
|
800
806
|
"""
|
|
801
807
|
This metaclass contains functionality on table classes, that doesn't exist on its instances.
|
|
@@ -1012,6 +1018,15 @@ class TableMeta(type):
|
|
|
1012
1018
|
"""
|
|
1013
1019
|
return QueryBuilder(self).select(*a, **kw)
|
|
1014
1020
|
|
|
1021
|
+
def column(self: Type[T_MetaInstance], field: "TypedField[T] | T", **options: Unpack[SelectKwargs]) -> list[T]:
|
|
1022
|
+
"""
|
|
1023
|
+
Get all values in a specific column.
|
|
1024
|
+
|
|
1025
|
+
Shortcut for `.select(field).execute().column(field)`.
|
|
1026
|
+
"""
|
|
1027
|
+
|
|
1028
|
+
return QueryBuilder(self).select(field, **options).execute().column(field)
|
|
1029
|
+
|
|
1015
1030
|
def paginate(self: Type[T_MetaInstance], limit: int, page: int = 1) -> "PaginatedRows[T_MetaInstance]":
|
|
1016
1031
|
"""
|
|
1017
1032
|
See QueryBuilder.paginate!
|
|
@@ -1196,6 +1211,19 @@ class TableMeta(type):
|
|
|
1196
1211
|
return self.with_alias(key)
|
|
1197
1212
|
|
|
1198
1213
|
# hooks:
|
|
1214
|
+
def _hook_once(
|
|
1215
|
+
cls: Type[T_MetaInstance], hooks: list[typing.Callable[P, R]], fn: typing.Callable[P, R]
|
|
1216
|
+
) -> Type[T_MetaInstance]:
|
|
1217
|
+
@functools.wraps(fn)
|
|
1218
|
+
def wraps(*a: P.args, **kw: P.kwargs) -> R:
|
|
1219
|
+
try:
|
|
1220
|
+
return fn(*a, **kw)
|
|
1221
|
+
finally:
|
|
1222
|
+
hooks.remove(wraps)
|
|
1223
|
+
|
|
1224
|
+
hooks.append(wraps)
|
|
1225
|
+
return cls
|
|
1226
|
+
|
|
1199
1227
|
def before_insert(
|
|
1200
1228
|
cls: Type[T_MetaInstance],
|
|
1201
1229
|
fn: typing.Callable[[T_MetaInstance], Optional[bool]] | typing.Callable[[OpRow], Optional[bool]],
|
|
@@ -1207,6 +1235,15 @@ class TableMeta(type):
|
|
|
1207
1235
|
cls._before_insert.append(fn)
|
|
1208
1236
|
return cls
|
|
1209
1237
|
|
|
1238
|
+
def before_insert_once(
|
|
1239
|
+
cls: Type[T_MetaInstance],
|
|
1240
|
+
fn: typing.Callable[[T_MetaInstance], Optional[bool]] | typing.Callable[[OpRow], Optional[bool]],
|
|
1241
|
+
) -> Type[T_MetaInstance]:
|
|
1242
|
+
"""
|
|
1243
|
+
Add a before insert hook that only fires once and then removes itself.
|
|
1244
|
+
"""
|
|
1245
|
+
return cls._hook_once(cls._before_insert, fn) # type: ignore
|
|
1246
|
+
|
|
1210
1247
|
def after_insert(
|
|
1211
1248
|
cls: Type[T_MetaInstance],
|
|
1212
1249
|
fn: (
|
|
@@ -1221,6 +1258,18 @@ class TableMeta(type):
|
|
|
1221
1258
|
cls._after_insert.append(fn)
|
|
1222
1259
|
return cls
|
|
1223
1260
|
|
|
1261
|
+
def after_insert_once(
|
|
1262
|
+
cls: Type[T_MetaInstance],
|
|
1263
|
+
fn: (
|
|
1264
|
+
typing.Callable[[T_MetaInstance, Reference], Optional[bool]]
|
|
1265
|
+
| typing.Callable[[OpRow, Reference], Optional[bool]]
|
|
1266
|
+
),
|
|
1267
|
+
) -> Type[T_MetaInstance]:
|
|
1268
|
+
"""
|
|
1269
|
+
Add an after insert hook that only fires once and then removes itself.
|
|
1270
|
+
"""
|
|
1271
|
+
return cls._hook_once(cls._after_insert, fn) # type: ignore
|
|
1272
|
+
|
|
1224
1273
|
def before_update(
|
|
1225
1274
|
cls: Type[T_MetaInstance],
|
|
1226
1275
|
fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
|
|
@@ -1232,6 +1281,15 @@ class TableMeta(type):
|
|
|
1232
1281
|
cls._before_update.append(fn)
|
|
1233
1282
|
return cls
|
|
1234
1283
|
|
|
1284
|
+
def before_update_once(
|
|
1285
|
+
cls,
|
|
1286
|
+
fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
|
|
1287
|
+
) -> Type[T_MetaInstance]:
|
|
1288
|
+
"""
|
|
1289
|
+
Add a before update hook that only fires once and then removes itself.
|
|
1290
|
+
"""
|
|
1291
|
+
return cls._hook_once(cls._before_update, fn) # type: ignore
|
|
1292
|
+
|
|
1235
1293
|
def after_update(
|
|
1236
1294
|
cls: Type[T_MetaInstance],
|
|
1237
1295
|
fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
|
|
@@ -1243,6 +1301,15 @@ class TableMeta(type):
|
|
|
1243
1301
|
cls._after_update.append(fn)
|
|
1244
1302
|
return cls
|
|
1245
1303
|
|
|
1304
|
+
def after_update_once(
|
|
1305
|
+
cls: Type[T_MetaInstance],
|
|
1306
|
+
fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
|
|
1307
|
+
) -> Type[T_MetaInstance]:
|
|
1308
|
+
"""
|
|
1309
|
+
Add an after update hook that only fires once and then removes itself.
|
|
1310
|
+
"""
|
|
1311
|
+
return cls._hook_once(cls._after_update, fn) # type: ignore
|
|
1312
|
+
|
|
1246
1313
|
def before_delete(cls: Type[T_MetaInstance], fn: typing.Callable[[Set], Optional[bool]]) -> Type[T_MetaInstance]:
|
|
1247
1314
|
"""
|
|
1248
1315
|
Add a before delete hook.
|
|
@@ -1251,6 +1318,15 @@ class TableMeta(type):
|
|
|
1251
1318
|
cls._before_delete.append(fn)
|
|
1252
1319
|
return cls
|
|
1253
1320
|
|
|
1321
|
+
def before_delete_once(
|
|
1322
|
+
cls: Type[T_MetaInstance],
|
|
1323
|
+
fn: typing.Callable[[Set], Optional[bool]],
|
|
1324
|
+
) -> Type[T_MetaInstance]:
|
|
1325
|
+
"""
|
|
1326
|
+
Add a before delete hook that only fires once and then removes itself.
|
|
1327
|
+
"""
|
|
1328
|
+
return cls._hook_once(cls._before_delete, fn)
|
|
1329
|
+
|
|
1254
1330
|
def after_delete(cls: Type[T_MetaInstance], fn: typing.Callable[[Set], Optional[bool]]) -> Type[T_MetaInstance]:
|
|
1255
1331
|
"""
|
|
1256
1332
|
Add an after delete hook.
|
|
@@ -1259,6 +1335,15 @@ class TableMeta(type):
|
|
|
1259
1335
|
cls._after_delete.append(fn)
|
|
1260
1336
|
return cls
|
|
1261
1337
|
|
|
1338
|
+
def after_delete_once(
|
|
1339
|
+
cls: Type[T_MetaInstance],
|
|
1340
|
+
fn: typing.Callable[[Set], Optional[bool]],
|
|
1341
|
+
) -> Type[T_MetaInstance]:
|
|
1342
|
+
"""
|
|
1343
|
+
Add an after delete hook that only fires once and then removes itself.
|
|
1344
|
+
"""
|
|
1345
|
+
return cls._hook_once(cls._after_delete, fn)
|
|
1346
|
+
|
|
1262
1347
|
|
|
1263
1348
|
class TypedField(Expression, typing.Generic[T_Value]): # pragma: no cover
|
|
1264
1349
|
"""
|
|
@@ -1482,6 +1567,17 @@ class _TypedTable:
|
|
|
1482
1567
|
where you need a reference to the current database, which may not exist yet when defining the model.
|
|
1483
1568
|
"""
|
|
1484
1569
|
|
|
1570
|
+
@classproperty
|
|
1571
|
+
def _hooks(cls) -> dict[str, list[typing.Callable[..., Optional[bool]]]]:
|
|
1572
|
+
return {
|
|
1573
|
+
"before_insert": cls._before_insert,
|
|
1574
|
+
"after_insert": cls._after_insert,
|
|
1575
|
+
"before_update": cls._before_update,
|
|
1576
|
+
"after_update": cls._after_update,
|
|
1577
|
+
"before_delete": cls._before_delete,
|
|
1578
|
+
"after_delete": cls._after_delete,
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1485
1581
|
|
|
1486
1582
|
class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
1487
1583
|
"""
|
|
@@ -2608,24 +2704,25 @@ class QueryBuilder(typing.Generic[T_MetaInstance]):
|
|
|
2608
2704
|
return save_to_cache(typed_rows, rows)
|
|
2609
2705
|
|
|
2610
2706
|
@typing.overload
|
|
2611
|
-
def column(self, field: TypedField[T]) -> list[T]:
|
|
2707
|
+
def column(self, field: TypedField[T], **options: Unpack[SelectKwargs]) -> list[T]:
|
|
2612
2708
|
"""
|
|
2613
2709
|
If a typedfield is passed, the output type can be safely determined.
|
|
2614
2710
|
"""
|
|
2615
2711
|
|
|
2616
2712
|
@typing.overload
|
|
2617
|
-
def column(self, field: T) -> list[T]:
|
|
2713
|
+
def column(self, field: T, **options: Unpack[SelectKwargs]) -> list[T]:
|
|
2618
2714
|
"""
|
|
2619
2715
|
Otherwise, the output type is loosely determined (assumes `field: type` or Any).
|
|
2620
2716
|
"""
|
|
2621
2717
|
|
|
2622
|
-
def column(self, field: TypedField[T] | T) -> list[T]:
|
|
2718
|
+
def column(self, field: TypedField[T] | T, **options: Unpack[SelectKwargs]) -> list[T]:
|
|
2623
2719
|
"""
|
|
2624
2720
|
Get all values in a specific column.
|
|
2625
2721
|
|
|
2626
2722
|
Shortcut for `.select(field).execute().column(field)`.
|
|
2627
2723
|
"""
|
|
2628
|
-
|
|
2724
|
+
|
|
2725
|
+
return self.select(field, **options).execute().column(field)
|
|
2629
2726
|
|
|
2630
2727
|
def _handle_relationships_pre_select(
|
|
2631
2728
|
self,
|
|
@@ -303,3 +303,27 @@ def get_field(field: "TypedField[typing.Any] | Field") -> "Field":
|
|
|
303
303
|
"Field",
|
|
304
304
|
field, # Table.field already is a Field, but cast to make sure the editor knows this too.
|
|
305
305
|
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class classproperty:
|
|
309
|
+
def __init__(self, fget: typing.Callable[..., typing.Any]) -> None:
|
|
310
|
+
"""
|
|
311
|
+
Initialize the classproperty.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
fget: A function that takes the class as an argument and returns a value.
|
|
315
|
+
"""
|
|
316
|
+
self.fget = fget
|
|
317
|
+
|
|
318
|
+
def __get__(self, obj: typing.Any, owner: typing.Type[T]) -> typing.Any:
|
|
319
|
+
"""
|
|
320
|
+
Retrieve the property value.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
obj: The instance of the class (unused).
|
|
324
|
+
owner: The class that owns the property.
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
The value returned by the function.
|
|
328
|
+
"""
|
|
329
|
+
return self.fget(owner)
|
|
@@ -510,10 +510,49 @@ def test_hooks_duplicates():
|
|
|
510
510
|
HookedTableV3.after_insert(increase_counter_v2) # other hash
|
|
511
511
|
|
|
512
512
|
HookedTableV3.insert(name="Should increase counter twice")
|
|
513
|
+
assert counter == 3
|
|
514
|
+
|
|
515
|
+
for hook in HookedTableV3._hooks.values():
|
|
516
|
+
hook.clear()
|
|
513
517
|
|
|
518
|
+
HookedTableV3.insert(name="Should NOT increase counter")
|
|
514
519
|
assert counter == 3
|
|
515
520
|
|
|
516
521
|
|
|
522
|
+
def test_hooks_once():
|
|
523
|
+
@db.define()
|
|
524
|
+
class HookedTableV4(TypedTable):
|
|
525
|
+
name: str
|
|
526
|
+
|
|
527
|
+
counter = 0
|
|
528
|
+
|
|
529
|
+
def increase_counter_v2(_, __=None):
|
|
530
|
+
nonlocal counter
|
|
531
|
+
counter += 1
|
|
532
|
+
|
|
533
|
+
HookedTableV4.before_insert_once(increase_counter_v2)
|
|
534
|
+
HookedTableV4.after_insert_once(increase_counter_v2)
|
|
535
|
+
HookedTableV4.before_update_once(increase_counter_v2)
|
|
536
|
+
HookedTableV4.after_update_once(increase_counter_v2)
|
|
537
|
+
HookedTableV4.before_delete_once(increase_counter_v2)
|
|
538
|
+
HookedTableV4.after_delete_once(increase_counter_v2)
|
|
539
|
+
|
|
540
|
+
assert counter == 0
|
|
541
|
+
|
|
542
|
+
HookedTableV4.insert(name="1")
|
|
543
|
+
assert counter == 2
|
|
544
|
+
row = HookedTableV4.insert(name="2")
|
|
545
|
+
assert counter == 2
|
|
546
|
+
|
|
547
|
+
row.update_record(name="3")
|
|
548
|
+
assert counter == 4
|
|
549
|
+
row.update_record(name="4")
|
|
550
|
+
assert counter == 4
|
|
551
|
+
|
|
552
|
+
row.delete_record()
|
|
553
|
+
assert counter == 6
|
|
554
|
+
|
|
555
|
+
|
|
517
556
|
def test_try():
|
|
518
557
|
class SomeTableToRetry(TypedTable):
|
|
519
558
|
key: int
|
|
@@ -483,6 +483,8 @@ def test_column():
|
|
|
483
483
|
assert len(rows) == 4
|
|
484
484
|
assert set(rows) == {33}
|
|
485
485
|
|
|
486
|
+
assert TestRelationship.column(TestRelationship.value, distinct=True, orderby=~TestRelationship.value) == [33, 3]
|
|
487
|
+
|
|
486
488
|
|
|
487
489
|
def test_collect_with_extra_fields():
|
|
488
490
|
_setup_data()
|
|
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
|