idf-build-apps 2.10.3__tar.gz → 2.11.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.
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/CHANGELOG.md +6 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/PKG-INFO +1 -1
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/references/config_file.rst +1 -1
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/__init__.py +1 -1
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/args.py +25 -9
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/pyproject.toml +1 -1
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/setup.py +1 -1
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/test_args.py +9 -2
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/test_finder.py +106 -3
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.editorconfig +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.git-blame-ignore-revs +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.gitattributes +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.github/dependabot.yml +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.github/workflows/publish-pypi.yml +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.github/workflows/sync-jira.yml +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.github/workflows/test-build-docs.yml +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.github/workflows/test-build-idf-apps.yml +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.gitignore +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.pre-commit-config.yaml +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/.readthedocs.yml +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/CONTRIBUTING.md +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/LICENSE +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/README.md +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/_apidoc_templates/module.rst_t +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/_apidoc_templates/package.rst_t +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/_apidoc_templates/toc.rst_t +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/_static/espressif-logo.svg +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/_static/theme_overrides.css +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/_templates/layout.html +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/conf_common.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/Makefile +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/conf.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/explanations/build.rst +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/explanations/config_rules.rst +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/explanations/dependency_driven_build.rst +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/explanations/find.rst +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/guides/1.x_to_2.x.md +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/guides/custom_app.md +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/index.rst +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/others/CHANGELOG.md +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/others/CONTRIBUTING.md +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/references/cli.rst +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/references/manifest.rst +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/__main__.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/app.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/autocompletions.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/constants.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/finder.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/junit/__init__.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/junit/report.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/junit/utils.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/log.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/main.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/manifest/__init__.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/manifest/manifest.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/manifest/soc_header.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/py.typed +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/session_args.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/utils.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/vendors/__init__.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/vendors/pydantic_sources.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/yaml/__init__.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/idf_build_apps/yaml/parser.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/license_header.txt +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/conftest.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/test_app.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/test_build.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/test_cmd.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/test_manifest.py +0 -0
- {idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/tests/test_utils.py +0 -0
|
@@ -101,7 +101,7 @@ This indicates that in the configuration file, you should specify it with the na
|
|
|
101
101
|
Expand Environment Variables
|
|
102
102
|
******************************
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
All configuration options support environment variables. You can use environment variables in the configuration file by using the syntax ``${VAR_NAME}`` or ``$VAR_NAME``. Undeclared environment variables will be replaced with an empty string. For example:
|
|
105
105
|
|
|
106
106
|
.. code:: toml
|
|
107
107
|
|
|
@@ -39,7 +39,6 @@ LOGGER = logging.getLogger(__name__)
|
|
|
39
39
|
|
|
40
40
|
class ValidateMethod(str, enum.Enum):
|
|
41
41
|
TO_LIST = 'to_list'
|
|
42
|
-
EXPAND_VARS = 'expand_vars'
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
@dataclass
|
|
@@ -174,12 +173,17 @@ class BaseArguments(BaseSettings):
|
|
|
174
173
|
if info.field_name and info.field_name in cls.model_fields:
|
|
175
174
|
f = cls.model_fields[info.field_name]
|
|
176
175
|
meta = get_meta(f)
|
|
176
|
+
|
|
177
|
+
# always expand vars for all fields
|
|
178
|
+
if isinstance(v, str):
|
|
179
|
+
v = expand_vars(v)
|
|
180
|
+
elif isinstance(v, list):
|
|
181
|
+
v = [expand_vars(item) if isinstance(item, str) else item for item in v]
|
|
182
|
+
|
|
177
183
|
if meta and meta.validate_method:
|
|
178
184
|
for method in meta.validate_method:
|
|
179
185
|
if method == ValidateMethod.TO_LIST:
|
|
180
186
|
v = to_list(v)
|
|
181
|
-
elif method == ValidateMethod.EXPAND_VARS:
|
|
182
|
-
v = expand_vars(v)
|
|
183
187
|
else:
|
|
184
188
|
raise NotImplementedError(f'Unknown validate method: {method}')
|
|
185
189
|
|
|
@@ -241,9 +245,7 @@ class DependencyDrivenBuildArguments(GlobalArguments):
|
|
|
241
245
|
default=None, # type: ignore
|
|
242
246
|
)
|
|
243
247
|
manifest_rootpath: str = field(
|
|
244
|
-
|
|
245
|
-
validate_method=[ValidateMethod.EXPAND_VARS],
|
|
246
|
-
),
|
|
248
|
+
None,
|
|
247
249
|
description='Root path to resolve the relative paths defined in the manifest files. '
|
|
248
250
|
'By default set to the current directory. Support environment variables.',
|
|
249
251
|
default=os.curdir, # type: ignore
|
|
@@ -420,6 +422,15 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
420
422
|
description='Filter the apps by target. By default set to "all"',
|
|
421
423
|
default='all', # type: ignore
|
|
422
424
|
)
|
|
425
|
+
extra_pythonpaths: t.Optional[t.List[str]] = field(
|
|
426
|
+
FieldMetadata(
|
|
427
|
+
validate_method=[ValidateMethod.TO_LIST],
|
|
428
|
+
nargs='+',
|
|
429
|
+
),
|
|
430
|
+
description='space-separated list of additional Python paths to search for the app classes. '
|
|
431
|
+
'Will be injected into the head of sys.path.',
|
|
432
|
+
default=None, # type: ignore
|
|
433
|
+
)
|
|
423
434
|
build_system: t.Union[str, t.Type[App]] = field(
|
|
424
435
|
None,
|
|
425
436
|
description='Filter the apps by build system. By default set to "cmake". '
|
|
@@ -608,6 +619,14 @@ class FindBuildArguments(DependencyDrivenBuildArguments):
|
|
|
608
619
|
if self.override_sdkconfig_files or self.override_sdkconfig_items:
|
|
609
620
|
SESSION_ARGS.set(self)
|
|
610
621
|
|
|
622
|
+
# update PYTHONPATH
|
|
623
|
+
if self.extra_pythonpaths:
|
|
624
|
+
LOGGER.debug('Adding extra Python paths: %s', self.extra_pythonpaths)
|
|
625
|
+
for path in self.extra_pythonpaths:
|
|
626
|
+
abs_path = to_absolute_path(path)
|
|
627
|
+
if abs_path not in sys.path:
|
|
628
|
+
sys.path.insert(0, abs_path)
|
|
629
|
+
|
|
611
630
|
# load build system
|
|
612
631
|
# here could be a string or a class of type App
|
|
613
632
|
if not isinstance(self.build_system, str):
|
|
@@ -770,7 +789,6 @@ class BuildArguments(FindBuildArguments):
|
|
|
770
789
|
FieldMetadata(
|
|
771
790
|
deprecates={'collect_size_info': {}},
|
|
772
791
|
hidden=True,
|
|
773
|
-
validate_method=[ValidateMethod.EXPAND_VARS],
|
|
774
792
|
),
|
|
775
793
|
description='Record size json filepath of the built apps to the specified file. '
|
|
776
794
|
'Each line is a json string. Can expand placeholders @p. Support environment variables.',
|
|
@@ -782,7 +800,6 @@ class BuildArguments(FindBuildArguments):
|
|
|
782
800
|
FieldMetadata(
|
|
783
801
|
deprecates={'collect_app_info': {}},
|
|
784
802
|
hidden=True,
|
|
785
|
-
validate_method=[ValidateMethod.EXPAND_VARS],
|
|
786
803
|
),
|
|
787
804
|
description='Record serialized app model of the built apps to the specified file. '
|
|
788
805
|
'Each line is a json string. Can expand placeholders @p. Support environment variables.',
|
|
@@ -794,7 +811,6 @@ class BuildArguments(FindBuildArguments):
|
|
|
794
811
|
FieldMetadata(
|
|
795
812
|
deprecates={'junitxml': {}},
|
|
796
813
|
hidden=True,
|
|
797
|
-
validate_method=[ValidateMethod.EXPAND_VARS],
|
|
798
814
|
),
|
|
799
815
|
description='Path to the junitxml file to record the build results. Can expand placeholder @p. '
|
|
800
816
|
'Support environment variables.',
|
|
@@ -38,7 +38,7 @@ entry_points = \
|
|
|
38
38
|
{'console_scripts': ['idf-build-apps = idf_build_apps:main.main']}
|
|
39
39
|
|
|
40
40
|
setup(name='idf-build-apps',
|
|
41
|
-
version='2.
|
|
41
|
+
version='2.11.0',
|
|
42
42
|
description='Tools for building ESP-IDF related apps.',
|
|
43
43
|
author=None,
|
|
44
44
|
author_email='Fu Hanxi <fuhanxi@espressif.com>',
|
|
@@ -97,12 +97,19 @@ def test_empty_argument():
|
|
|
97
97
|
assert args.config_rules is None
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
def test_build_args_expansion():
|
|
100
|
+
def test_build_args_expansion(monkeypatch):
|
|
101
|
+
monkeypatch.setenv('FOO', '2')
|
|
102
|
+
|
|
101
103
|
args = BuildArguments(
|
|
102
|
-
parallel_index=2,
|
|
104
|
+
parallel_index=2,
|
|
105
|
+
parallel_count='$FOO',
|
|
106
|
+
collect_app_info='@p.txt',
|
|
107
|
+
junitxml='x_@p.txt',
|
|
108
|
+
collect_size_info='@p_@p.txt',
|
|
103
109
|
)
|
|
104
110
|
assert args.collect_app_info == '2.txt'
|
|
105
111
|
assert args.junitxml == 'x_2.txt'
|
|
112
|
+
assert args.parallel_count == 2
|
|
106
113
|
|
|
107
114
|
args.parallel_index = 3
|
|
108
115
|
assert args.collect_app_info == '3.txt'
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import os
|
|
5
|
+
import sys
|
|
5
6
|
import tempfile
|
|
6
7
|
from pathlib import (
|
|
7
8
|
Path,
|
|
@@ -25,8 +26,9 @@ from idf_build_apps.manifest.manifest import Manifest
|
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class TestFindWithManifest:
|
|
28
|
-
def test_manifest_rootpath_chdir(self, capsys):
|
|
29
|
-
test_dir =
|
|
29
|
+
def test_manifest_rootpath_chdir(self, capsys, tmp_path):
|
|
30
|
+
test_dir = tmp_path / 'examples' / 'get-started'
|
|
31
|
+
create_project('hello_world', test_dir)
|
|
30
32
|
|
|
31
33
|
yaml_file = test_dir / 'test.yml'
|
|
32
34
|
yaml_file.write_text(
|
|
@@ -38,7 +40,7 @@ examples/get-started:
|
|
|
38
40
|
encoding='utf8',
|
|
39
41
|
)
|
|
40
42
|
|
|
41
|
-
os.chdir(
|
|
43
|
+
os.chdir(tmp_path)
|
|
42
44
|
assert not find_apps(str(test_dir), 'esp32', recursive=True, manifest_files=str(yaml_file))
|
|
43
45
|
assert not capsys.readouterr().err
|
|
44
46
|
|
|
@@ -769,3 +771,104 @@ def test_find_apps_with_duplicated_paths(tmp_path):
|
|
|
769
771
|
== len(find_apps(str(tmp_path / 'folder1'), 'esp32', recursive=True))
|
|
770
772
|
== 2
|
|
771
773
|
)
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
class TestFindWithExtraPythonPaths:
|
|
777
|
+
custom_app_code = """
|
|
778
|
+
import os
|
|
779
|
+
import typing as t
|
|
780
|
+
from idf_build_apps import App
|
|
781
|
+
from idf_build_apps.constants import BuildStatus
|
|
782
|
+
from idf_build_apps.utils import Literal
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
class ExtraPathTestApp(App):
|
|
786
|
+
build_system: Literal['extra_path_test'] = 'extra_path_test' # type: ignore
|
|
787
|
+
|
|
788
|
+
@property
|
|
789
|
+
def supported_targets(self) -> t.List[str]:
|
|
790
|
+
return ['esp32', 'esp32s2', 'esp32c3']
|
|
791
|
+
|
|
792
|
+
def build(self, *args, **kwargs):
|
|
793
|
+
if not self.dry_run:
|
|
794
|
+
os.makedirs(self.build_path, exist_ok=True)
|
|
795
|
+
with open(os.path.join(self.build_path, 'extra_path_test_marker.txt'), 'w') as f:
|
|
796
|
+
f.write('Extra path test build successful')
|
|
797
|
+
self.build_status = BuildStatus.SUCCESS
|
|
798
|
+
|
|
799
|
+
@classmethod
|
|
800
|
+
def is_app(cls, path: str) -> bool:
|
|
801
|
+
return True
|
|
802
|
+
"""
|
|
803
|
+
|
|
804
|
+
@pytest.fixture
|
|
805
|
+
def setup_custom_module_and_app(self, tmp_path):
|
|
806
|
+
"""Set up a custom module in a separate directory and a test app"""
|
|
807
|
+
# Create custom module directory (separate from app directory)
|
|
808
|
+
custom_module_dir = tmp_path / 'custom_modules'
|
|
809
|
+
custom_module_dir.mkdir()
|
|
810
|
+
|
|
811
|
+
# Create the custom module file
|
|
812
|
+
custom_module_file = custom_module_dir / 'extra_path_test_module.py'
|
|
813
|
+
custom_module_file.write_text(self.custom_app_code)
|
|
814
|
+
|
|
815
|
+
# Create test app directory
|
|
816
|
+
test_app_dir = tmp_path / 'test_app'
|
|
817
|
+
test_app_dir.mkdir()
|
|
818
|
+
|
|
819
|
+
# Create basic app structure
|
|
820
|
+
main_dir = test_app_dir / 'main'
|
|
821
|
+
main_dir.mkdir()
|
|
822
|
+
(main_dir / 'main.c').write_text('void app_main() {}')
|
|
823
|
+
(main_dir / 'CMakeLists.txt').write_text('idf_component_register(SRCS "main.c")')
|
|
824
|
+
(test_app_dir / 'CMakeLists.txt').write_text(
|
|
825
|
+
'cmake_minimum_required(VERSION 3.16)\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(test_app)'
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
return {
|
|
829
|
+
'custom_module_dir': str(custom_module_dir),
|
|
830
|
+
'test_app_dir': str(test_app_dir),
|
|
831
|
+
'custom_module_file': str(custom_module_file),
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
def test_extra_pythonpaths_with_custom_build_system(self, setup_custom_module_and_app):
|
|
835
|
+
"""Test that extra_pythonpaths allows loading custom build system classes"""
|
|
836
|
+
setup = setup_custom_module_and_app
|
|
837
|
+
|
|
838
|
+
original_path = sys.path.copy()
|
|
839
|
+
|
|
840
|
+
try:
|
|
841
|
+
# First verify that without extra_pythonpaths, the module cannot be found
|
|
842
|
+
with pytest.raises(ImportError, match=r'Failed to import module extra_path_test_module'):
|
|
843
|
+
find_apps(
|
|
844
|
+
paths=[setup['test_app_dir']],
|
|
845
|
+
target='esp32',
|
|
846
|
+
build_system='extra_path_test_module:ExtraPathTestApp',
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
# Now test with extra_pythonpaths - this should work
|
|
850
|
+
apps = find_apps(
|
|
851
|
+
paths=[setup['test_app_dir']],
|
|
852
|
+
target='esp32',
|
|
853
|
+
build_system='extra_path_test_module:ExtraPathTestApp',
|
|
854
|
+
extra_pythonpaths=[setup['custom_module_dir']],
|
|
855
|
+
)
|
|
856
|
+
|
|
857
|
+
# Verify we found the app
|
|
858
|
+
assert len(apps) == 1
|
|
859
|
+
app = apps[0]
|
|
860
|
+
|
|
861
|
+
# Verify it's using our custom class
|
|
862
|
+
assert app.build_system == 'extra_path_test'
|
|
863
|
+
assert app.__class__.__name__ == 'ExtraPathTestApp'
|
|
864
|
+
|
|
865
|
+
# Verify the custom module dir was added to sys.path
|
|
866
|
+
assert setup['custom_module_dir'] in sys.path
|
|
867
|
+
|
|
868
|
+
# Test building the app
|
|
869
|
+
app.build(dry_run=True)
|
|
870
|
+
assert app.build_status == BuildStatus.SUCCESS
|
|
871
|
+
|
|
872
|
+
finally:
|
|
873
|
+
# Restore original sys.path
|
|
874
|
+
sys.path[:] = original_path
|
|
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
|
{idf_build_apps-2.10.3 → idf_build_apps-2.11.0}/docs/en/explanations/dependency_driven_build.rst
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|