punit 1.4.0__tar.gz → 1.4.4__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.
- punit-1.4.4/.scripts/punit +9 -0
- {punit-1.4.0/src/pUnit.egg-info → punit-1.4.4}/PKG-INFO +2 -5
- {punit-1.4.0 → punit-1.4.4}/pyproject.toml +2 -5
- {punit-1.4.0 → punit-1.4.4/src/pUnit.egg-info}/PKG-INFO +2 -5
- {punit-1.4.0 → punit-1.4.4}/src/punit/__init__.py +2 -2
- {punit-1.4.0 → punit-1.4.4}/src/punit/__main__.py +18 -7
- punit-1.4.4/src/punit/assertions/collections.py +76 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/cli.py +4 -4
- {punit-1.4.0 → punit-1.4.4}/src/punit/filters/FilterManager.py +3 -3
- punit-1.4.0/.scripts/punit +0 -8
- punit-1.4.0/src/punit/assertions/collections.py +0 -76
- {punit-1.4.0 → punit-1.4.4}/LICENSE +0 -0
- {punit-1.4.0 → punit-1.4.4}/README.md +0 -0
- {punit-1.4.0 → punit-1.4.4}/setup.cfg +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/pUnit.egg-info/SOURCES.txt +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/pUnit.egg-info/dependency_links.txt +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/pUnit.egg-info/requires.txt +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/pUnit.egg-info/top_level.txt +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/TestResult.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/assertions/__init__.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/assertions/exceptions.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/assertions/strings.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/discovery/TestModuleDiscovery.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/discovery/__init__.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/facts/Fact.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/facts/FactManager.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/facts/__init__.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/filters/Filter.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/filters/__init__.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/metadata/CallableMetadata.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/metadata/__init__.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/py.typed +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/reports/HtmlReportGenerator.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/reports/JUnitReportGenerator.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/reports/JsonReportGenerator.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/reports/__init__.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/runner.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/theories/Theory.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/theories/TheoryManager.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/theories/__init__.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/traits/Trait.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/traits/TraitManager.py +0 -0
- {punit-1.4.0 → punit-1.4.4}/src/punit/traits/__init__.py +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# SPDX-FileCopyrightText: © 2026 Shaun Wilson
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
##
|
|
5
|
+
from subprocess import run
|
|
6
|
+
from sys import executable, argv
|
|
7
|
+
from os import _exit
|
|
8
|
+
result = run([executable, "-m", "punit"] + argv[1:], check=False)
|
|
9
|
+
_exit(result.returncode)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pUnit
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.4
|
|
4
4
|
Summary: A modernized unit-test framework for Python.
|
|
5
5
|
Author-email: Shaun Wilson <mrshaunwilson@msn.com>
|
|
6
6
|
License: MIT License
|
|
@@ -30,10 +30,7 @@ Project-URL: Homepage, https://github.com/wilson0x4d/punit
|
|
|
30
30
|
Project-URL: Repository, https://github.com/wilson0x4d/punit.git
|
|
31
31
|
Keywords: test,unittest,unit-test,xUnit,nUnit,pytest
|
|
32
32
|
Classifier: Operating System :: OS Independent
|
|
33
|
-
Classifier: Programming Language :: Python
|
|
34
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
35
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
36
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
33
|
+
Classifier: Programming Language :: Python
|
|
37
34
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
38
35
|
Classifier: Intended Audience :: Developers
|
|
39
36
|
Requires-Python: >=3.11
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pUnit"
|
|
3
|
-
version = "1.4.
|
|
3
|
+
version = "1.4.4"
|
|
4
4
|
description = "A modernized unit-test framework for Python."
|
|
5
5
|
keywords = ["test", "unittest", "unit-test", "xUnit", "nUnit", "pytest"]
|
|
6
6
|
authors = [
|
|
@@ -11,10 +11,7 @@ license = {file = "LICENSE"}
|
|
|
11
11
|
requires-python = ">=3.11"
|
|
12
12
|
classifiers = [
|
|
13
13
|
"Operating System :: OS Independent",
|
|
14
|
-
"Programming Language :: Python
|
|
15
|
-
"Programming Language :: Python :: 3.12",
|
|
16
|
-
"Programming Language :: Python :: 3.13",
|
|
17
|
-
"Programming Language :: Python :: 3.14",
|
|
14
|
+
"Programming Language :: Python",
|
|
18
15
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
19
16
|
"Intended Audience :: Developers"
|
|
20
17
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pUnit
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.4
|
|
4
4
|
Summary: A modernized unit-test framework for Python.
|
|
5
5
|
Author-email: Shaun Wilson <mrshaunwilson@msn.com>
|
|
6
6
|
License: MIT License
|
|
@@ -30,10 +30,7 @@ Project-URL: Homepage, https://github.com/wilson0x4d/punit
|
|
|
30
30
|
Project-URL: Repository, https://github.com/wilson0x4d/punit.git
|
|
31
31
|
Keywords: test,unittest,unit-test,xUnit,nUnit,pytest
|
|
32
32
|
Classifier: Operating System :: OS Independent
|
|
33
|
-
Classifier: Programming Language :: Python
|
|
34
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
35
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
36
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
33
|
+
Classifier: Programming Language :: Python
|
|
37
34
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
38
35
|
Classifier: Intended Audience :: Developers
|
|
39
36
|
Requires-Python: >=3.11
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import os
|
|
6
|
+
import sys
|
|
6
7
|
import time
|
|
7
8
|
from .cli import CommandLineInterface
|
|
8
9
|
from .discovery import TestModuleDiscovery
|
|
@@ -13,11 +14,11 @@ from .runner import TestRunner
|
|
|
13
14
|
async def async_main() -> None:
|
|
14
15
|
ts = time.time()
|
|
15
16
|
cli = CommandLineInterface.parse()
|
|
16
|
-
if cli.help:
|
|
17
|
+
if cli.help: # pragma: no cover
|
|
17
18
|
cli.printHelp()
|
|
18
|
-
elif cli.verbose and not cli.quiet:
|
|
19
|
+
elif cli.verbose and not cli.quiet: # pragma: no cover
|
|
19
20
|
cli.printSummary()
|
|
20
|
-
elif not cli.quiet:
|
|
21
|
+
elif not cli.quiet: # pragma: no cover
|
|
21
22
|
cli.printVersion()
|
|
22
23
|
os.chdir(cli.workdir)
|
|
23
24
|
testModuleDiscovery = TestModuleDiscovery(
|
|
@@ -32,11 +33,11 @@ async def async_main() -> None:
|
|
|
32
33
|
failureCount = 0
|
|
33
34
|
for result in results:
|
|
34
35
|
if not result.isSuccess:
|
|
35
|
-
failureCount += 1
|
|
36
|
+
failureCount += 1 # pragma: no cover
|
|
36
37
|
if not cli.quiet:
|
|
37
38
|
print(f'Total: {len(results)}, Failures: {failureCount}, Took: {totalTime:.3f}s')
|
|
38
|
-
if cli.reportFormat is not None:
|
|
39
|
-
report:str = ''
|
|
39
|
+
if cli.reportFormat is not None: # pragma: no cover
|
|
40
|
+
report: str = ''
|
|
40
41
|
match cli.reportFormat:
|
|
41
42
|
case 'html':
|
|
42
43
|
report = HtmlReportGenerator().generate(results)
|
|
@@ -52,10 +53,20 @@ async def async_main() -> None:
|
|
|
52
53
|
file.write(report.encode())
|
|
53
54
|
print(f'\n("{cli.reportFormat}" report written to: {cli.outputFilename})')
|
|
54
55
|
if failureCount > 0:
|
|
55
|
-
|
|
56
|
+
sys.stdout.flush()
|
|
57
|
+
sys.stderr.flush()
|
|
58
|
+
try:
|
|
59
|
+
os.fsync(sys.stdout.fileno())
|
|
60
|
+
os.fsync(sys.stderr.fileno())
|
|
61
|
+
except (AttributeError, ValueError, OSError):
|
|
62
|
+
# Pass if the stream doesn't support fsync (e.g. some virtualized environments)
|
|
63
|
+
pass
|
|
64
|
+
os._exit(119) # pragma: no cover
|
|
65
|
+
|
|
56
66
|
|
|
57
67
|
def main() -> None:
|
|
58
68
|
asyncio.run(async_main())
|
|
59
69
|
|
|
70
|
+
|
|
60
71
|
if (__name__ == '__main__'):
|
|
61
72
|
main()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2024 Shaun Wilson
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
from typing import Any, Callable, Optional, Sequence, cast
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def areSame(actual: Sequence[Any] | set[Any] | dict[Any, Any] | None, expected: Sequence[Any] | set[Any] | dict[Any, Any] | None, sort: bool = False, sort_function: Optional[Callable[[Any], Any]] = None) -> bool:
|
|
8
|
+
"""
|
|
9
|
+
Check if two sequences contain the same elements in the same order.
|
|
10
|
+
|
|
11
|
+
:param actual: The sequence to check
|
|
12
|
+
:param expected: The sequence to compare against
|
|
13
|
+
:param sort: Sort sequences before performing comparisons.
|
|
14
|
+
:param sort_function: Custom function to use when sorting.
|
|
15
|
+
:returns bool: True if the sequences contain the same elements in the same order, False otherwise.
|
|
16
|
+
"""
|
|
17
|
+
if actual is expected:
|
|
18
|
+
return True
|
|
19
|
+
elif actual is None and expected is not None:
|
|
20
|
+
return False
|
|
21
|
+
elif actual is not None and expected is None:
|
|
22
|
+
return False
|
|
23
|
+
elif actual is not None and expected is not None:
|
|
24
|
+
if len(actual) != len(expected):
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
if sort:
|
|
28
|
+
if isinstance(actual, dict) or isinstance(expected, dict):
|
|
29
|
+
sort_function = sort_function if sort_function is not None else lambda e: e[0]
|
|
30
|
+
actual = sorted(cast(dict, actual).items(), key=sort_function)
|
|
31
|
+
expected = sorted(cast(dict, expected).items(), key=sort_function)
|
|
32
|
+
else:
|
|
33
|
+
sort_function = sort_function if sort_function is not None else lambda e: e
|
|
34
|
+
actual = sorted(actual, key=sort_function)
|
|
35
|
+
expected = sorted(expected, key=sort_function)
|
|
36
|
+
|
|
37
|
+
if isinstance(actual, dict) or isinstance(expected, dict):
|
|
38
|
+
for pairs in zip(cast(dict, actual).items(), cast(dict, expected).items()):
|
|
39
|
+
if not areSame(pairs[0], pairs[1]):
|
|
40
|
+
return False
|
|
41
|
+
else:
|
|
42
|
+
for pairs in zip(actual, expected):
|
|
43
|
+
if isinstance(pairs[0], dict) or isinstance(pairs[1], dict):
|
|
44
|
+
if not areSame(pairs[0], pairs[1]):
|
|
45
|
+
return False
|
|
46
|
+
elif pairs[0] != pairs[1]:
|
|
47
|
+
return False
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
def hasLength(actual: Sequence[Any] | set[Any] | dict[Any, Any] | None, expected: int | None) -> bool:
|
|
51
|
+
"""
|
|
52
|
+
Check if actual value has the expected number of elements.
|
|
53
|
+
|
|
54
|
+
:param actual: The actual value to check.
|
|
55
|
+
:param int|None expected: The expected number of elements
|
|
56
|
+
|
|
57
|
+
:returns bool: True if the sequence has exactly the expected number of elements, False otherwise
|
|
58
|
+
"""
|
|
59
|
+
if actual is None and (expected is None or expected == 0):
|
|
60
|
+
return True
|
|
61
|
+
elif actual is None and (expected is not None and expected != 0):
|
|
62
|
+
return False
|
|
63
|
+
elif actual is not None and expected is None:
|
|
64
|
+
return False
|
|
65
|
+
return actual is not None and len(actual) == expected
|
|
66
|
+
|
|
67
|
+
def isNoneOrEmpty(actual: Sequence[Any] | set[Any] | dict[Any, Any] | None) -> bool:
|
|
68
|
+
"""
|
|
69
|
+
Check if actual value is None or empty.
|
|
70
|
+
|
|
71
|
+
:param actual: The actual to check.
|
|
72
|
+
:returns: True if the value is None or empty, False otherwise.
|
|
73
|
+
"""
|
|
74
|
+
if actual is None:
|
|
75
|
+
return True
|
|
76
|
+
return len(actual) == 0
|
|
@@ -100,7 +100,7 @@ class CommandLineInterface:
|
|
|
100
100
|
case _:
|
|
101
101
|
print(f'Unsupported value "{arg}" for --report argument, aborting.')
|
|
102
102
|
print(f'(valid values are "json" and "junit")')
|
|
103
|
-
|
|
103
|
+
os._exit(4)
|
|
104
104
|
continue
|
|
105
105
|
elif extractOutputFilename:
|
|
106
106
|
extractOutputFilename = False
|
|
@@ -260,7 +260,7 @@ Options:
|
|
|
260
260
|
suppress any program output.
|
|
261
261
|
"""
|
|
262
262
|
)
|
|
263
|
-
|
|
263
|
+
os._exit(0)
|
|
264
264
|
|
|
265
265
|
def printSummary(self) -> None:
|
|
266
266
|
self.printVersion()
|
|
@@ -282,10 +282,10 @@ Options:
|
|
|
282
282
|
def validate(self) -> None:
|
|
283
283
|
if self.__workdir is None or len(self.__workdir.lstrip()) == 0 or self.__workdir.startswith('-'):
|
|
284
284
|
print(f'Invalid working directory specified: {self.__workdir}')
|
|
285
|
-
|
|
285
|
+
os._exit(1)
|
|
286
286
|
elif not os.path.isdir(self.__workdir):
|
|
287
287
|
print(f'Working directory does not exist: {self.__workdir}')
|
|
288
|
-
|
|
288
|
+
os._exit(2)
|
|
289
289
|
self.__workdir = os.path.abspath(self.__workdir)
|
|
290
290
|
if not self.__no_default_patterns:
|
|
291
291
|
# if no other patterns specified, default to including all files found in the directory matching `testPackageName`
|
|
@@ -45,15 +45,15 @@ class FilterManager:
|
|
|
45
45
|
ready, _, _ = select.select([sys.stdin], [], [], 5)
|
|
46
46
|
if not ready:
|
|
47
47
|
print('No data from stdin, aborting.')
|
|
48
|
-
|
|
48
|
+
os._exit(7)
|
|
49
49
|
lines = sys.stdin.read().splitlines()
|
|
50
50
|
if len(lines) == 0:
|
|
51
51
|
print('No filters from stdin, aborting.')
|
|
52
|
-
|
|
52
|
+
os._exit(6)
|
|
53
53
|
else:
|
|
54
54
|
if not os.path.exists(filepath):
|
|
55
55
|
print(f'file missing or not accessible: {filepath}')
|
|
56
|
-
|
|
56
|
+
os._exit(5)
|
|
57
57
|
with open(filepath, 'rb') as f:
|
|
58
58
|
lines = f.read().decode().splitlines()
|
|
59
59
|
for line in lines:
|
punit-1.4.0/.scripts/punit
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# SPDX-FileCopyrightText: © 2026 Shaun Wilson
|
|
3
|
-
# SPDX-License-Identifier: MIT
|
|
4
|
-
##
|
|
5
|
-
from subprocess import run
|
|
6
|
-
from sys import executable, argv, exit
|
|
7
|
-
result = run([ executable, "-m", "punit" ] + argv[1:], check=False)
|
|
8
|
-
exit(result.returncode)
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: © 2024 Shaun Wilson
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
|
|
4
|
-
from typing import Any, Callable, Sequence, Optional, cast
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def areSame(a:Sequence[Any]|list[Any]|dict[Any,Any]|None, b:Sequence[Any]|list[Any]|dict[Any,Any]|None, sort:bool=False, sortFunction:Optional[Callable[[Any], Any]]=None) -> bool:
|
|
8
|
-
"""
|
|
9
|
-
Check if two sequences contain the same elements in the same order.
|
|
10
|
-
|
|
11
|
-
:param Sequence[Any]|None a: The sequence to check
|
|
12
|
-
:param Sequence[Any]|None b: The sequence to compare against
|
|
13
|
-
:param Optional[bool] sort: Sort sequences before performing comparisons.
|
|
14
|
-
:param Optional[Callable[[Any], Any]] sortFunction: Custom function to use when sorting.
|
|
15
|
-
:returns bool: True if the sequences contain the same elements in the same order, False otherwise.
|
|
16
|
-
"""
|
|
17
|
-
if a is b:
|
|
18
|
-
return True
|
|
19
|
-
elif a is None and b is not None:
|
|
20
|
-
return False
|
|
21
|
-
elif a is not None and b is None:
|
|
22
|
-
return False
|
|
23
|
-
elif a is not None and b is not None:
|
|
24
|
-
if len(a) != len(b):
|
|
25
|
-
return False
|
|
26
|
-
|
|
27
|
-
if sort:
|
|
28
|
-
if isinstance(a, dict) or isinstance(b, dict):
|
|
29
|
-
sortFunction = sortFunction if sortFunction is not None else lambda e: e[0]
|
|
30
|
-
a = sorted(cast(dict,a).items(), key=sortFunction)
|
|
31
|
-
b = sorted(cast(dict,b).items(), key=sortFunction)
|
|
32
|
-
else:
|
|
33
|
-
sortFunction = sortFunction if sortFunction is not None else lambda e: e
|
|
34
|
-
a = sorted(a, key=sortFunction)
|
|
35
|
-
b = sorted(b, key=sortFunction)
|
|
36
|
-
|
|
37
|
-
if isinstance(a, dict) or isinstance(b, dict):
|
|
38
|
-
for pairs in zip(cast(dict,a).items(), cast(dict,b).items()):
|
|
39
|
-
if not areSame(pairs[0], pairs[1]):
|
|
40
|
-
return False
|
|
41
|
-
else:
|
|
42
|
-
for pairs in zip(a, b):
|
|
43
|
-
if isinstance(pairs[0], dict) or isinstance(pairs[1], dict):
|
|
44
|
-
if not areSame(pairs[0], pairs[1]):
|
|
45
|
-
return False
|
|
46
|
-
elif pairs[0] != pairs[1]:
|
|
47
|
-
return False
|
|
48
|
-
return True
|
|
49
|
-
|
|
50
|
-
def hasLength(sequence:Sequence[Any]|list[Any]|dict[Any,Any]|None, expected:int|None) -> bool:
|
|
51
|
-
"""
|
|
52
|
-
Check if a sequence has the expected number of elements.
|
|
53
|
-
|
|
54
|
-
:param Sequence[Any]|None sequence: The sequence to check
|
|
55
|
-
:param int|None expected: The expected number of elements
|
|
56
|
-
|
|
57
|
-
:returns bool: True if the sequence has exactly the expected number of elements, False otherwise
|
|
58
|
-
"""
|
|
59
|
-
if sequence is None and (expected is None or expected == 0):
|
|
60
|
-
return True
|
|
61
|
-
elif sequence is None and (expected is not None and expected != 0):
|
|
62
|
-
return False
|
|
63
|
-
elif sequence is not None and expected is None:
|
|
64
|
-
return False
|
|
65
|
-
return sequence is not None and len(sequence) == expected
|
|
66
|
-
|
|
67
|
-
def isNoneOrEmpty(sequence:Sequence[Any]|list[Any]|dict[Any,Any]|None) -> bool:
|
|
68
|
-
"""
|
|
69
|
-
Check if a sequence is None or empty.
|
|
70
|
-
|
|
71
|
-
:param Sequence[Any]|None sequence: The sequence to check
|
|
72
|
-
:returns bool: True if the sequence is None or empty, False otherwise
|
|
73
|
-
"""
|
|
74
|
-
if sequence is None:
|
|
75
|
-
return True
|
|
76
|
-
return len(sequence) == 0
|
|
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
|