APIFlask 2.2.1__tar.gz → 2.3.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.
- {apiflask-2.2.1 → apiflask-2.3.0}/CHANGES.md +9 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/PKG-INFO +1 -1
- {apiflask-2.2.1 → apiflask-2.3.0}/pyproject.toml +1 -1
- {apiflask-2.2.1 → apiflask-2.3.0}/requirements/examples.txt +1 -1
- {apiflask-2.2.1 → apiflask-2.3.0}/requirements/min-versions.txt +1 -1
- {apiflask-2.2.1 → apiflask-2.3.0}/src/APIFlask.egg-info/PKG-INFO +1 -1
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/scaffold.py +58 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_decorator_input.py +136 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tox.ini +1 -1
- {apiflask-2.2.1 → apiflask-2.3.0}/LICENSE +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/MANIFEST.in +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/NOTICE +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/README.md +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/README.md +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/auth/basic_auth/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/auth/token_auth/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/base_response/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/basic/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/blueprint_tags/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/cbv/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/dataclass/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/file_upload/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/file_upload/upload/.gitkeep +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/openapi/basic/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/openapi/custom_decorators/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/openapi/static_docs/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/openapi/static_docs/generate_docs.sh +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/openapi/static_docs/index.html +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/openapi/static_docs/openapi.json +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/orm/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/pagination/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/requirements.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/examples/test_examples.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/requirements/dev.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/requirements/docs.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/requirements/tests.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/requirements/typing.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/setup.cfg +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/APIFlask.egg-info/SOURCES.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/APIFlask.egg-info/dependency_links.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/APIFlask.egg-info/entry_points.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/APIFlask.egg-info/requires.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/APIFlask.egg-info/top_level.txt +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/__init__.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/blueprint.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/commands.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/exceptions.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/fields.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/helpers.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/openapi.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/py.typed +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/route.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/schemas.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/security.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/settings.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/types.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/ui_templates.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/validators.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/src/apiflask/views.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/__init__.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/conftest.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/schemas.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_app.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_apps/__init__.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_async.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_base_response.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_blueprint.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_commands.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_decorator_auth_required.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_decorator_doc.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_decorator_output.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_decorators.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_exceptions.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_fields.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_helpers.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_basic.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_blueprint.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_extensions.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_headers.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_info.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_paths.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_security.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_openapi_tags.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_route.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_schemas.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_security.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_settings_api_docs.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_settings_auto_behaviour.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_settings_openapi_fields.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_settings_openapi_spec.py +0 -0
- {apiflask-2.2.1 → apiflask-2.3.0}/tests/test_settings_response_customization.py +0 -0
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## Version 2.3.0
|
|
2
|
+
|
|
3
|
+
Released: 2024/11/25
|
|
4
|
+
|
|
5
|
+
- Support skipping the validation for the request body with `@input(validation=False)` ([issue #573][issue_573]).
|
|
6
|
+
- Enable CI test for Python 3.13.
|
|
7
|
+
|
|
8
|
+
[issue_573]: https://github.com/apiflask/apiflask/issues/573
|
|
9
|
+
|
|
1
10
|
|
|
2
11
|
## Version 2.2.1
|
|
3
12
|
|
|
@@ -4,7 +4,7 @@ description = "A lightweight web API framework based on Flask and marshmallow-co
|
|
|
4
4
|
readme = "README.md"
|
|
5
5
|
license = { text = "MIT" }
|
|
6
6
|
authors = [{ name = "Grey Li", email = "withlihui@gmail.com" }]
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.3.0"
|
|
8
8
|
classifiers = [
|
|
9
9
|
"Development Status :: 3 - Alpha",
|
|
10
10
|
"Environment :: Web Environment",
|
|
@@ -6,6 +6,7 @@ from functools import wraps
|
|
|
6
6
|
|
|
7
7
|
from flask import current_app
|
|
8
8
|
from flask import jsonify
|
|
9
|
+
from flask import request
|
|
9
10
|
from flask import Response
|
|
10
11
|
from marshmallow import ValidationError as MarshmallowValidationError
|
|
11
12
|
from webargs.flaskparser import FlaskParser as BaseFlaskParser
|
|
@@ -100,6 +101,46 @@ def _generate_schema_from_mapping(schema: DictSchemaType, schema_name: str | Non
|
|
|
100
101
|
return Schema.from_dict(schema, name=schema_name)() # type: ignore
|
|
101
102
|
|
|
102
103
|
|
|
104
|
+
def _load_raw_data(location: str = 'json') -> dict[t.Any, t.Any]:
|
|
105
|
+
"""
|
|
106
|
+
Load raw data from the specified location in the request.
|
|
107
|
+
|
|
108
|
+
Arguments:
|
|
109
|
+
location (str): Specifies the source of the data to load, which can be one of the following:
|
|
110
|
+
- `json`: Load data from the request's JSON body.
|
|
111
|
+
- `form`: Load data from the request's form.
|
|
112
|
+
- `files` or `form_and_files`: Load data from both the request's form and files.
|
|
113
|
+
- `json_or_form`: Preferably load data from the request's JSON body or request's form.
|
|
114
|
+
- `query`: Load data from the request's query parameters.
|
|
115
|
+
- `path`: Load data from the request's view arguments.
|
|
116
|
+
|
|
117
|
+
`headers` and `cookies` are not supported by this function.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
dict: A dictionary containing the data loaded from the specified location.
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
ValueError: If the provided location argument is not one of the expected values.
|
|
124
|
+
"""
|
|
125
|
+
if location == 'json':
|
|
126
|
+
if request.is_json:
|
|
127
|
+
return request.get_json() or {}
|
|
128
|
+
return {}
|
|
129
|
+
if location == 'form':
|
|
130
|
+
return request.form.to_dict()
|
|
131
|
+
if location in ['files', 'form_and_files']:
|
|
132
|
+
return {**request.files.to_dict(), **request.form.to_dict()}
|
|
133
|
+
if location == 'json_or_form':
|
|
134
|
+
if request.is_json:
|
|
135
|
+
return request.get_json() or {}
|
|
136
|
+
return request.form.to_dict()
|
|
137
|
+
if location in ['query', 'querystring']:
|
|
138
|
+
return request.args.to_dict()
|
|
139
|
+
if location == 'path':
|
|
140
|
+
return request.view_args or {}
|
|
141
|
+
raise ValueError(f'Invalid location argument: {location}')
|
|
142
|
+
|
|
143
|
+
|
|
103
144
|
class APIScaffold:
|
|
104
145
|
"""A base class for [`APIFlask`][apiflask.app.APIFlask] and
|
|
105
146
|
[`APIBlueprint`][apiflask.blueprint.APIBlueprint].
|
|
@@ -209,6 +250,7 @@ class APIScaffold:
|
|
|
209
250
|
schema_name: str | None = None,
|
|
210
251
|
example: t.Any | None = None,
|
|
211
252
|
examples: dict[str, t.Any] | None = None,
|
|
253
|
+
validation: bool = True,
|
|
212
254
|
**kwargs: t.Any,
|
|
213
255
|
) -> t.Callable[[DecoratedType], DecoratedType]:
|
|
214
256
|
"""Add input settings for view functions.
|
|
@@ -262,6 +304,11 @@ class APIScaffold:
|
|
|
262
304
|
},
|
|
263
305
|
}
|
|
264
306
|
```
|
|
307
|
+
validation: Flag to allow disabling of validation on input. Default to `True`.
|
|
308
|
+
|
|
309
|
+
*Version changed: 2.2.2
|
|
310
|
+
|
|
311
|
+
- Add parameter `validation` to allow disabling of validation on input.
|
|
265
312
|
|
|
266
313
|
*Version changed: 2.0.0*
|
|
267
314
|
|
|
@@ -290,6 +337,17 @@ class APIScaffold:
|
|
|
290
337
|
|
|
291
338
|
def decorator(f):
|
|
292
339
|
f = _ensure_sync(f)
|
|
340
|
+
|
|
341
|
+
if not validation:
|
|
342
|
+
|
|
343
|
+
@wraps(f)
|
|
344
|
+
def wrapper(*args: t.Any, **kwargs: t.Any):
|
|
345
|
+
raw_data = _load_raw_data(location)
|
|
346
|
+
kwargs[f'{location}_data'] = raw_data
|
|
347
|
+
return f(*args, **kwargs)
|
|
348
|
+
|
|
349
|
+
return wrapper
|
|
350
|
+
|
|
293
351
|
is_body_location = location in BODY_LOCATIONS
|
|
294
352
|
if is_body_location and hasattr(f, '_spec') and 'body' in f._spec:
|
|
295
353
|
raise RuntimeError(
|
|
@@ -11,7 +11,10 @@ from .schemas import Files
|
|
|
11
11
|
from .schemas import Foo
|
|
12
12
|
from .schemas import Form
|
|
13
13
|
from .schemas import FormAndFiles
|
|
14
|
+
from apiflask import Schema
|
|
14
15
|
from apiflask.fields import String
|
|
16
|
+
from apiflask.validators import Length
|
|
17
|
+
from apiflask.validators import OneOf
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
def test_input(app, client):
|
|
@@ -413,3 +416,136 @@ def test_input_body_example(app, client):
|
|
|
413
416
|
rv.json['paths']['/baz']['post']['requestBody']['content']['application/json']['examples']
|
|
414
417
|
== examples
|
|
415
418
|
)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def test_skip_validation(app, client):
|
|
422
|
+
incorrect_json = {'name': 'Kitty', 'category': 'unknown'}
|
|
423
|
+
|
|
424
|
+
class PetIn(Schema):
|
|
425
|
+
name = String(required=True, validate=Length(0, 10))
|
|
426
|
+
category = String(required=True, validate=OneOf(['dog', 'cat']))
|
|
427
|
+
|
|
428
|
+
@app.patch('/pets_without_validation/<int:pet_id>')
|
|
429
|
+
@app.input(PetIn, validation=False)
|
|
430
|
+
def pets_without_validation(pet_id, json_data):
|
|
431
|
+
return {'pet_id': pet_id, 'json_data': json_data}
|
|
432
|
+
|
|
433
|
+
no_validated_rv = client.patch('/pets_without_validation/1', json=incorrect_json)
|
|
434
|
+
assert no_validated_rv.status_code == 200
|
|
435
|
+
assert no_validated_rv.json['json_data']['name'] == 'Kitty'
|
|
436
|
+
assert no_validated_rv.json['json_data']['category'] == 'unknown'
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def test_location_raw_data(app):
|
|
440
|
+
from apiflask.scaffold import _load_raw_data
|
|
441
|
+
|
|
442
|
+
# will raises ValueError
|
|
443
|
+
location = 'unknown'
|
|
444
|
+
with pytest.raises(ValueError, match=f'Invalid location argument: {location}'):
|
|
445
|
+
_load_raw_data('unknown')
|
|
446
|
+
|
|
447
|
+
# `json` location
|
|
448
|
+
with app.test_request_context('/load_raw_data', method='POST', json={'name': 'Kitty'}):
|
|
449
|
+
json_data = _load_raw_data()
|
|
450
|
+
assert json_data['name'] == 'Kitty'
|
|
451
|
+
|
|
452
|
+
with app.test_request_context('/load_raw_data', method='POST', data={'name': 'Kitty'}):
|
|
453
|
+
json_data = _load_raw_data()
|
|
454
|
+
assert json_data == {}
|
|
455
|
+
|
|
456
|
+
# `form` location
|
|
457
|
+
with app.test_request_context(
|
|
458
|
+
'/load_raw_data',
|
|
459
|
+
method='POST',
|
|
460
|
+
data={'username': 'Kitty', 'password': '<PASSWORD>'},
|
|
461
|
+
content_type='application/x-www-form-urlencoded',
|
|
462
|
+
):
|
|
463
|
+
form_data = _load_raw_data('form')
|
|
464
|
+
assert form_data['username'] == 'Kitty'
|
|
465
|
+
assert form_data['password'] == '<PASSWORD>'
|
|
466
|
+
|
|
467
|
+
with app.test_request_context(
|
|
468
|
+
'/load_raw_data',
|
|
469
|
+
method='POST',
|
|
470
|
+
json={'username': 'Kitty', 'password': '<PASSWORD>'},
|
|
471
|
+
):
|
|
472
|
+
form_data = _load_raw_data('form')
|
|
473
|
+
assert form_data == {}
|
|
474
|
+
|
|
475
|
+
# `files` or `form_and_files` location
|
|
476
|
+
with app.test_request_context(
|
|
477
|
+
'/load_raw_data',
|
|
478
|
+
method='POST',
|
|
479
|
+
data={'file': (io.BytesIO(b'Hello World!'), 'demo.txt')},
|
|
480
|
+
content_type='multipart/form-data',
|
|
481
|
+
):
|
|
482
|
+
files_data = _load_raw_data('files')
|
|
483
|
+
assert files_data['file'].filename == 'demo.txt'
|
|
484
|
+
assert files_data['file'].stream.read() == b'Hello World!'
|
|
485
|
+
|
|
486
|
+
with app.test_request_context(
|
|
487
|
+
'/load_raw_data',
|
|
488
|
+
method='POST',
|
|
489
|
+
data={'name': 'Kitty', 'file': (io.BytesIO(b'Hello World2!'), 'demo2.txt')},
|
|
490
|
+
content_type='multipart/form-data',
|
|
491
|
+
):
|
|
492
|
+
files_and_form_rv = _load_raw_data('form_and_files')
|
|
493
|
+
assert files_and_form_rv['file'].filename == 'demo2.txt'
|
|
494
|
+
assert files_and_form_rv['file'].stream.read() == b'Hello World2!'
|
|
495
|
+
assert files_and_form_rv['name'] == 'Kitty'
|
|
496
|
+
|
|
497
|
+
with app.test_request_context(
|
|
498
|
+
'/load_raw_data',
|
|
499
|
+
method='POST',
|
|
500
|
+
json={'username': 'Kitty', 'password': '<PASSWORD>'},
|
|
501
|
+
):
|
|
502
|
+
form_and_files_data = _load_raw_data('form_and_files')
|
|
503
|
+
assert form_and_files_data == {}
|
|
504
|
+
|
|
505
|
+
# `query` location
|
|
506
|
+
with app.test_request_context(
|
|
507
|
+
'/load_raw_data?name=Kitty',
|
|
508
|
+
method='GET',
|
|
509
|
+
):
|
|
510
|
+
query_data = _load_raw_data('query')
|
|
511
|
+
assert query_data == {'name': 'Kitty'}
|
|
512
|
+
|
|
513
|
+
with app.test_request_context(
|
|
514
|
+
'/load_raw_data',
|
|
515
|
+
method='POST',
|
|
516
|
+
):
|
|
517
|
+
query_data = _load_raw_data('query')
|
|
518
|
+
assert query_data == {}
|
|
519
|
+
|
|
520
|
+
# `json_or_form`
|
|
521
|
+
with app.test_request_context(
|
|
522
|
+
'/load_raw_data',
|
|
523
|
+
data={'username': 'Kitty', 'password': '<PASSWORD>'},
|
|
524
|
+
content_type='application/x-www-form-urlencoded',
|
|
525
|
+
):
|
|
526
|
+
json_or_form_rv = _load_raw_data('json_or_form')
|
|
527
|
+
assert json_or_form_rv['username'] == 'Kitty'
|
|
528
|
+
assert json_or_form_rv['password'] == '<PASSWORD>'
|
|
529
|
+
|
|
530
|
+
with app.test_request_context(
|
|
531
|
+
'/load_raw_data',
|
|
532
|
+
json={'currentId': '<current_id>'},
|
|
533
|
+
):
|
|
534
|
+
json_or_form_data = _load_raw_data('json_or_form')
|
|
535
|
+
json_or_form_data['currentId'] = '<current_id>'
|
|
536
|
+
|
|
537
|
+
with app.test_request_context(
|
|
538
|
+
'/load_raw_data',
|
|
539
|
+
method='POST',
|
|
540
|
+
):
|
|
541
|
+
json_or_form_data = _load_raw_data('json_or_form')
|
|
542
|
+
assert json_or_form_data == {}
|
|
543
|
+
|
|
544
|
+
# `path` location
|
|
545
|
+
@app.get('/load_raw_data/<int:pet_id>')
|
|
546
|
+
def load_raw_data(pet_id):
|
|
547
|
+
return _load_raw_data('path')
|
|
548
|
+
|
|
549
|
+
with app.test_request_context('/load_raw_data/1', method='GET'):
|
|
550
|
+
path_data = app.dispatch_request()
|
|
551
|
+
assert path_data == {'pet_id': 1}
|
|
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
|