certora-cli-alpha-master 20250708.14.24.383763__py3-none-any.whl → 20250708.16.32.202680__py3-none-any.whl
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.
- certora_cli/CertoraProver/certoraBuildRust.py +30 -1
- certora_cli/{Shared/rustProverCommon.py → CertoraProver/certoraBuildSui.py} +24 -18
- certora_cli/CertoraProver/certoraCloudIO.py +18 -0
- certora_cli/CertoraProver/certoraContext.py +5 -1
- certora_cli/CertoraProver/certoraContextAttributes.py +34 -0
- certora_cli/Shared/proverCommon.py +3 -1
- certora_cli/certoraSolanaProver.py +1 -1
- certora_cli/certoraSorobanProver.py +1 -1
- {certora_cli_alpha_master-20250708.14.24.383763.dist-info → certora_cli_alpha_master-20250708.16.32.202680.dist-info}/METADATA +2 -2
- {certora_cli_alpha_master-20250708.14.24.383763.dist-info → certora_cli_alpha_master-20250708.16.32.202680.dist-info}/RECORD +16 -16
- certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
- certora_jars/Typechecker.jar +0 -0
- {certora_cli_alpha_master-20250708.14.24.383763.dist-info → certora_cli_alpha_master-20250708.16.32.202680.dist-info}/LICENSE +0 -0
- {certora_cli_alpha_master-20250708.14.24.383763.dist-info → certora_cli_alpha_master-20250708.16.32.202680.dist-info}/WHEEL +0 -0
- {certora_cli_alpha_master-20250708.14.24.383763.dist-info → certora_cli_alpha_master-20250708.16.32.202680.dist-info}/entry_points.txt +0 -0
- {certora_cli_alpha_master-20250708.14.24.383763.dist-info → certora_cli_alpha_master-20250708.16.32.202680.dist-info}/top_level.txt +0 -0
@@ -13,10 +13,20 @@
|
|
13
13
|
# You should have received a copy of the GNU General Public License
|
14
14
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
15
15
|
|
16
|
+
from __future__ import annotations
|
17
|
+
|
18
|
+
import sys
|
19
|
+
from pathlib import Path
|
20
|
+
|
21
|
+
scripts_dir_path = Path(__file__).parent.parent.resolve() # containing directory
|
22
|
+
sys.path.insert(0, str(scripts_dir_path))
|
23
|
+
|
16
24
|
import glob
|
17
25
|
import shutil
|
26
|
+
import time
|
27
|
+
import logging
|
18
28
|
from pathlib import Path
|
19
|
-
from typing import Set
|
29
|
+
from typing import Set, Dict
|
20
30
|
|
21
31
|
from CertoraProver.certoraBuild import build_source_tree
|
22
32
|
from CertoraProver.certoraContextClass import CertoraContext
|
@@ -25,6 +35,25 @@ import CertoraProver.certoraContextAttributes as Attrs
|
|
25
35
|
from Shared import certoraUtils as Util
|
26
36
|
|
27
37
|
|
38
|
+
log = logging.getLogger(__name__)
|
39
|
+
|
40
|
+
|
41
|
+
def build_rust_project(context: CertoraContext, timings: Dict) -> None:
|
42
|
+
"""
|
43
|
+
Compile the Rust artefact and record elapsed time in *timings*.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
context: The CertoraContext object containing the configuration.
|
47
|
+
timings: A dictionary to store timing information.
|
48
|
+
"""
|
49
|
+
log.debug("Build Rust target")
|
50
|
+
start = time.perf_counter()
|
51
|
+
set_rust_build_directory(context)
|
52
|
+
timings["buildTime"] = round(time.perf_counter() - start, 4)
|
53
|
+
if context.test == str(Util.TestValue.AFTER_BUILD):
|
54
|
+
raise Util.TestResultsReady(context)
|
55
|
+
|
56
|
+
|
28
57
|
def set_rust_build_directory(context: CertoraContext) -> None:
|
29
58
|
if not context.files:
|
30
59
|
build_rust_app(context)
|
@@ -13,13 +13,6 @@
|
|
13
13
|
# You should have received a copy of the GNU General Public License
|
14
14
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
15
15
|
|
16
|
-
"""
|
17
|
-
Shared helpers for Rust-based targets (Solana & Soroban).
|
18
|
-
|
19
|
-
Placing the build logic in one module removes
|
20
|
-
duplication from the dedicated entry scripts.
|
21
|
-
"""
|
22
|
-
|
23
16
|
from __future__ import annotations
|
24
17
|
|
25
18
|
import sys
|
@@ -28,25 +21,21 @@ from pathlib import Path
|
|
28
21
|
scripts_dir_path = Path(__file__).parent.parent.resolve() # containing directory
|
29
22
|
sys.path.insert(0, str(scripts_dir_path))
|
30
23
|
|
24
|
+
import shutil
|
31
25
|
import time
|
32
26
|
import logging
|
33
|
-
from
|
34
|
-
|
35
|
-
from Shared import certoraUtils as Util
|
27
|
+
from pathlib import Path
|
28
|
+
from typing import Set, Dict
|
36
29
|
|
30
|
+
from CertoraProver.certoraBuild import build_source_tree
|
37
31
|
from CertoraProver.certoraContextClass import CertoraContext
|
38
|
-
|
39
|
-
from CertoraProver.certoraBuildRust import set_rust_build_directory
|
32
|
+
from Shared import certoraUtils as Util
|
40
33
|
|
41
34
|
|
42
35
|
log = logging.getLogger(__name__)
|
43
36
|
|
44
37
|
|
45
|
-
|
46
|
-
# Build
|
47
|
-
# --------------------------------------------------------------------------- #
|
48
|
-
|
49
|
-
def build_rust_project(context: CertoraContext, timings: Dict) -> None:
|
38
|
+
def build_sui_project(context: CertoraContext, timings: Dict) -> None:
|
50
39
|
"""
|
51
40
|
Compile the Rust artefact and record elapsed time in *timings*.
|
52
41
|
|
@@ -56,7 +45,24 @@ def build_rust_project(context: CertoraContext, timings: Dict) -> None:
|
|
56
45
|
"""
|
57
46
|
log.debug("Build Rust target")
|
58
47
|
start = time.perf_counter()
|
59
|
-
|
48
|
+
set_sui_build_directory(context)
|
60
49
|
timings["buildTime"] = round(time.perf_counter() - start, 4)
|
61
50
|
if context.test == str(Util.TestValue.AFTER_BUILD):
|
62
51
|
raise Util.TestResultsReady(context)
|
52
|
+
|
53
|
+
|
54
|
+
def set_sui_build_directory(context: CertoraContext) -> None:
|
55
|
+
assert context.move_path, "build_sui_project: expecting move_path to link to a build directory"
|
56
|
+
|
57
|
+
shutil.copytree(context.move_path, Util.get_build_dir() / Path(context.move_path).name)
|
58
|
+
|
59
|
+
sources: Set[Path] = set()
|
60
|
+
if getattr(context, 'conf_file', None) and Path(context.conf_file).exists():
|
61
|
+
sources.add(Path(context.conf_file).absolute())
|
62
|
+
|
63
|
+
try:
|
64
|
+
# Create generators
|
65
|
+
build_source_tree(sources, context)
|
66
|
+
|
67
|
+
except Exception as e:
|
68
|
+
raise Util.CertoraUserInputError(f"Collecting build files failed with the exception: {e}")
|
@@ -73,6 +73,7 @@ class EcoEnum(Util.NoValEnum):
|
|
73
73
|
EVM = Util.auto()
|
74
74
|
SOROBAN = Util.auto()
|
75
75
|
SOLANA = Util.auto()
|
76
|
+
SUI = Util.auto()
|
76
77
|
|
77
78
|
class ProductEnum(Util.NoValEnum):
|
78
79
|
PROVER = Util.auto()
|
@@ -623,6 +624,11 @@ class CloudVerification:
|
|
623
624
|
rust_jar_settings.append(paths_in_source_dir(self.context.solana_inlining))
|
624
625
|
|
625
626
|
auth_data["jarSettings"] = rust_jar_settings + jar_settings
|
627
|
+
|
628
|
+
elif Attrs.is_sui_app():
|
629
|
+
sui_jar_settings = ['-movePath', Path(self.context.move_path).name]
|
630
|
+
auth_data["jarSettings"] = sui_jar_settings + jar_settings
|
631
|
+
|
626
632
|
else:
|
627
633
|
auth_data["jarSettings"] = jar_settings
|
628
634
|
|
@@ -644,6 +650,8 @@ class CloudVerification:
|
|
644
650
|
auth_data["ecosystem"] = EcoEnum.SOLANA.name
|
645
651
|
elif Attrs.is_soroban_app():
|
646
652
|
auth_data["ecosystem"] = EcoEnum.SOROBAN.name
|
653
|
+
elif Attrs.is_sui_app():
|
654
|
+
auth_data["ecosystem"] = EcoEnum.SUI.name
|
647
655
|
else:
|
648
656
|
auth_data["ecosystem"] = EcoEnum.EVM.name
|
649
657
|
|
@@ -773,6 +781,16 @@ class CloudVerification:
|
|
773
781
|
|
774
782
|
result = compress_files(self.ZipFilePath, *files_list,
|
775
783
|
short_output=Ctx.is_minimal_cli_output(self.context))
|
784
|
+
elif Attrs.is_sui_app():
|
785
|
+
files_list = [Util.get_certora_metadata_file(),
|
786
|
+
Util.get_configuration_layout_data_file(),
|
787
|
+
Util.get_build_dir() / Path(self.context.move_path).name]
|
788
|
+
|
789
|
+
if Util.get_certora_sources_dir().exists():
|
790
|
+
files_list.append(Util.get_certora_sources_dir())
|
791
|
+
|
792
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
793
|
+
short_output=Ctx.is_minimal_cli_output(self.context))
|
776
794
|
|
777
795
|
else:
|
778
796
|
# Zip the log file first separately and again with the rest of the files, so it will not be decompressed
|
@@ -122,7 +122,11 @@ def get_local_run_cmd(context: CertoraContext) -> List[str]:
|
|
122
122
|
"""
|
123
123
|
run_args = []
|
124
124
|
|
125
|
-
if Attrs.
|
125
|
+
if Attrs.is_sui_app():
|
126
|
+
# For local runs, we want path to be relative to cwd instead of zip root.
|
127
|
+
move_rel_path = os.path.relpath(Path(context.move_path), os.getcwd())
|
128
|
+
run_args.extend(['-movePath', move_rel_path])
|
129
|
+
elif Attrs.is_rust_app():
|
126
130
|
# For local runs, we want path to be relative to cwd instead of zip root.
|
127
131
|
rust_rel_path = os.path.relpath(Path(context.files[0]), os.getcwd())
|
128
132
|
run_args.append(rust_rel_path)
|
@@ -1672,6 +1672,36 @@ class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAt
|
|
1672
1672
|
)
|
1673
1673
|
|
1674
1674
|
|
1675
|
+
class SuiProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes):
|
1676
|
+
FILES = AttrUtil.AttributeDefinition(
|
1677
|
+
attr_validation_func=Vf.validate_dir,
|
1678
|
+
arg_type=AttrUtil.AttrArgType.LIST,
|
1679
|
+
argparse_args={
|
1680
|
+
'nargs': AttrUtil.MULTIPLE_OCCURRENCES
|
1681
|
+
},
|
1682
|
+
affects_build_cache_key=True,
|
1683
|
+
disables_build_cache=False,
|
1684
|
+
config_data=AttributeJobConfigData(
|
1685
|
+
main_section=MainSection.NEW_SECTION
|
1686
|
+
)
|
1687
|
+
)
|
1688
|
+
|
1689
|
+
MOVE_PATH = AttrUtil.AttributeDefinition(
|
1690
|
+
attr_validation_func=Vf.validate_dir,
|
1691
|
+
arg_type=AttrUtil.AttrArgType.STRING,
|
1692
|
+
help_msg="path to a directory which includes all binary .mv files for the Prover",
|
1693
|
+
default_desc="",
|
1694
|
+
argparse_args={
|
1695
|
+
'action': AttrUtil.UniqueStore
|
1696
|
+
},
|
1697
|
+
affects_build_cache_key=True,
|
1698
|
+
disables_build_cache=False,
|
1699
|
+
config_data=AttributeJobConfigData(
|
1700
|
+
main_section=MainSection.NEW_SECTION
|
1701
|
+
)
|
1702
|
+
)
|
1703
|
+
|
1704
|
+
|
1675
1705
|
class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes, RustAttributes):
|
1676
1706
|
FILES = AttrUtil.AttributeDefinition(
|
1677
1707
|
attr_validation_func=Vf.validate_solana_extension,
|
@@ -1753,3 +1783,7 @@ def is_ranger_app() -> bool:
|
|
1753
1783
|
|
1754
1784
|
def is_sophy_app() -> bool:
|
1755
1785
|
return False # wait for the tool to be added
|
1786
|
+
|
1787
|
+
|
1788
|
+
def is_sui_app() -> bool:
|
1789
|
+
return get_attribute_class() == SuiProverAttributes
|
@@ -156,11 +156,13 @@ def ensure_version_compatibility(context: CertoraContext) -> None:
|
|
156
156
|
"""
|
157
157
|
validate_version_and_branch(context)
|
158
158
|
|
159
|
+
|
159
160
|
# --------------------------------------------------------------------------- #
|
160
161
|
# Verification helpers
|
161
162
|
# --------------------------------------------------------------------------- #
|
162
163
|
|
163
|
-
def run_local(context: CertoraContext, timings: Dict, additional_commands: Optional[List[str]] = None,
|
164
|
+
def run_local(context: CertoraContext, timings: Dict, additional_commands: Optional[List[str]] = None,
|
165
|
+
compare_with_expected_file: bool = False) -> int:
|
164
166
|
"""
|
165
167
|
Run the verifier locally and return its exit code (0 = success).
|
166
168
|
Args:
|
@@ -25,7 +25,7 @@ sys.path.insert(0, str(scripts_dir_path))
|
|
25
25
|
|
26
26
|
|
27
27
|
import CertoraProver.certoraContextAttributes as Attrs
|
28
|
-
from
|
28
|
+
from CertoraProver.certoraBuildRust import build_rust_project
|
29
29
|
from Shared.proverCommon import (
|
30
30
|
build_context,
|
31
31
|
collect_and_dump_metadata,
|
@@ -26,7 +26,7 @@ from typing import List, Optional, Dict
|
|
26
26
|
|
27
27
|
import CertoraProver.certoraContextAttributes as Attrs
|
28
28
|
|
29
|
-
from
|
29
|
+
from CertoraProver.certoraBuildRust import build_rust_project
|
30
30
|
from Shared.proverCommon import (
|
31
31
|
build_context,
|
32
32
|
collect_and_dump_metadata,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: certora-cli-alpha-master
|
3
|
-
Version: 20250708.
|
3
|
+
Version: 20250708.16.32.202680
|
4
4
|
Summary: Runner for the Certora Prover
|
5
5
|
Home-page: https://pypi.org/project/certora-cli-alpha-master
|
6
6
|
Author: Certora
|
@@ -38,4 +38,4 @@ Dynamic: requires-dist
|
|
38
38
|
Dynamic: requires-python
|
39
39
|
Dynamic: summary
|
40
40
|
|
41
|
-
Commit
|
41
|
+
Commit 74f300a. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
@@ -5,21 +5,22 @@ certora_cli/certoraEqCheck.py,sha256=qfZq7bpU1kbAIezC66W61VfKNZz7Uywg2Ygup62qYeo
|
|
5
5
|
certora_cli/certoraMutate.py,sha256=XhFHyNVP_sk-3XkY6AAV5fVliEFAVRq-JeDGsqE5IQQ,3333
|
6
6
|
certora_cli/certoraRanger.py,sha256=cwejxWTNlHsbwtu6Lew0SNsynSeq_ZKJu1Cr9uu0DhE,1314
|
7
7
|
certora_cli/certoraRun.py,sha256=ueQiuTUb_zTzZDoD2VTAj9rXn8MLCTZMvIJciXGPiEY,6652
|
8
|
-
certora_cli/certoraSolanaProver.py,sha256=
|
9
|
-
certora_cli/certoraSorobanProver.py,sha256=
|
8
|
+
certora_cli/certoraSolanaProver.py,sha256=PIuJiFHPq8oeU1Q_RMb3C7Lcc4_LyaaLrp3TKBNBMl4,3281
|
9
|
+
certora_cli/certoraSorobanProver.py,sha256=thqd0mAcjAOZO5oHByihbGhpGfrIz3ImqLzwSfd-xOw,2872
|
10
10
|
certora_cli/rustMutator.py,sha256=6AvOGU8Ijz89zW_ZJCWlfXkeobJsk7EsqZhK7Eqwn-Y,14544
|
11
11
|
certora_cli/CertoraProver/__init__.py,sha256=QHNr-PJQAoyuPgTkO7gg23GRchiWSXglWNG7yLSQZvs,849
|
12
12
|
certora_cli/CertoraProver/certoraBuild.py,sha256=yk4zzGATe-HPqVUPwNBejaCqPN3WqLQPEsiNJobTdE0,212894
|
13
13
|
certora_cli/CertoraProver/certoraBuildCacheManager.py,sha256=I60x0ykMFPzciD193cPXihsHh0fdV--UOmNKbIZW6Rc,13238
|
14
14
|
certora_cli/CertoraProver/certoraBuildDataClasses.py,sha256=8tPny9-pasC7CCRKQclaVQ3qcEDNa6EdOUu1ZWh0MZY,14704
|
15
|
-
certora_cli/CertoraProver/certoraBuildRust.py,sha256=
|
16
|
-
certora_cli/CertoraProver/
|
15
|
+
certora_cli/CertoraProver/certoraBuildRust.py,sha256=s_tZpzQQLASYiv27LLqn6S_FVUKn5UOljXQgIGrjlBo,6051
|
16
|
+
certora_cli/CertoraProver/certoraBuildSui.py,sha256=oOY6l3JnxYtFl3i3ibEcOp69x0mKsFg4Z86UnVC6CwY,2383
|
17
|
+
certora_cli/CertoraProver/certoraCloudIO.py,sha256=0DI7RHqyJ2ZdBSJvnJ0UXfgr1Ii7KAenTu6es1Orl8U,54224
|
17
18
|
certora_cli/CertoraProver/certoraCollectConfigurationLayout.py,sha256=6aHEGrhT_Y9aYfM5n_Mk--awgcQfdtc-chBPRl7FU4E,14095
|
18
19
|
certora_cli/CertoraProver/certoraCollectRunMetadata.py,sha256=i31dkYt8kwlX44SHZtV_b8QI1Egi6cbB5-uuh5beYN0,12630
|
19
20
|
certora_cli/CertoraProver/certoraCompilerParameters.py,sha256=r35y03IRwWIoz1GCNC7PuW3n8JPz9J1NGwhwUYKdYtI,1452
|
20
21
|
certora_cli/CertoraProver/certoraConfigIO.py,sha256=UGgAI03xtsmTMRGUXNCXUYcNP5IR3ex8_MYoHlL3hr8,7517
|
21
|
-
certora_cli/CertoraProver/certoraContext.py,sha256=
|
22
|
-
certora_cli/CertoraProver/certoraContextAttributes.py,sha256=
|
22
|
+
certora_cli/CertoraProver/certoraContext.py,sha256=s6Zv_QBP_jGIyZlFopGwYwD4mmIdozGfMZOLqUFUaKg,27209
|
23
|
+
certora_cli/CertoraProver/certoraContextAttributes.py,sha256=x9E4GIFkV0sFhGTGrcP4WUM45cHm7jjrHGSxhAk31HI,65078
|
23
24
|
certora_cli/CertoraProver/certoraContextClass.py,sha256=d7HDqM72K7YnswR7kEcAHGwkFNrTqRz5-_0m7cl2Mso,900
|
24
25
|
certora_cli/CertoraProver/certoraContextValidator.py,sha256=QiJoWU6uADjVmw13wXEDg-cWiZO7BgdN91x8_7GmX4g,45197
|
25
26
|
certora_cli/CertoraProver/certoraContractFuncs.py,sha256=ipSwge5QQzp8qhUavY44bZ-eCR6szK_HWwSIWqQyuR0,6921
|
@@ -62,14 +63,13 @@ certora_cli/Shared/certoraAttrUtil.py,sha256=ZsoS6xbSZnAjEoPEcfiJi6CvHU-1ySBKubv
|
|
62
63
|
certora_cli/Shared/certoraLogging.py,sha256=cV2UQMhQ5j8crGXgeq9CEamI-Lk4HgdiA3HCrP-kSR4,14013
|
63
64
|
certora_cli/Shared/certoraUtils.py,sha256=3imWdLsEQhpEHCpfERHet_zJLu1aShgf3XQFs8Qvbr8,55006
|
64
65
|
certora_cli/Shared/certoraValidateFuncs.py,sha256=jnXIH7ii2yCH9QZs7nXA9RUJ-r0fSSFmCz-RgY7Hhto,41836
|
65
|
-
certora_cli/Shared/proverCommon.py,sha256=
|
66
|
-
|
67
|
-
certora_jars/
|
68
|
-
certora_jars/Typechecker.jar,sha256=RI-Ye2qtfGhjaQIA5pnLBmX5jFEPZUXrBhoL8Y9fOsU,17224880
|
66
|
+
certora_cli/Shared/proverCommon.py,sha256=3oPMsHXZcETkHlqgLBTFRWYxpuEeYBrMLcP1CpPu7iQ,11306
|
67
|
+
certora_jars/CERTORA-CLI-VERSION-METADATA.json,sha256=Z1q7fbsUXkz7CcNSTf7L9iSZft3gIkV05QuPGWhq73w,170
|
68
|
+
certora_jars/Typechecker.jar,sha256=EzG3lhClFRI60XRAcX9HpzT7LMnQGrfdK-pPb86GtiU,17236797
|
69
69
|
certora_jars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
70
|
-
certora_cli_alpha_master-20250708.
|
71
|
-
certora_cli_alpha_master-20250708.
|
72
|
-
certora_cli_alpha_master-20250708.
|
73
|
-
certora_cli_alpha_master-20250708.
|
74
|
-
certora_cli_alpha_master-20250708.
|
75
|
-
certora_cli_alpha_master-20250708.
|
70
|
+
certora_cli_alpha_master-20250708.16.32.202680.dist-info/LICENSE,sha256=UGKSKIJSetF8m906JLKqNLkUS2CL60XfQdNvxBvpQXo,620
|
71
|
+
certora_cli_alpha_master-20250708.16.32.202680.dist-info/METADATA,sha256=PNCWKgxT-73zEQvHkD4zOMT7VZolsxuhW3m43iTCAVA,1271
|
72
|
+
certora_cli_alpha_master-20250708.16.32.202680.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
73
|
+
certora_cli_alpha_master-20250708.16.32.202680.dist-info/entry_points.txt,sha256=_SQ5_uYOAJXtqEW992nIvq7blW9cWFSUVEdbMGuy--4,443
|
74
|
+
certora_cli_alpha_master-20250708.16.32.202680.dist-info/top_level.txt,sha256=8C77w3JLanY0-NW45vpJsjRssyCqVP-qmPiN9FjWiX4,38
|
75
|
+
certora_cli_alpha_master-20250708.16.32.202680.dist-info/RECORD,,
|
@@ -1 +1 @@
|
|
1
|
-
{"name": "certora-cli-alpha-master", "tag": "", "branch": "master", "commit": "
|
1
|
+
{"name": "certora-cli-alpha-master", "tag": "", "branch": "master", "commit": "74f300a", "timestamp": "20250708.16.32.202680", "version": "20250708.16.32.202680+74f300a"}
|
certora_jars/Typechecker.jar
CHANGED
Binary file
|
File without changes
|
File without changes
|
File without changes
|