ScriptCollection 3.5.107__py3-none-any.whl → 3.5.109__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.
- ScriptCollection/Executables.py +26 -0
- ScriptCollection/ScriptCollectionCore.py +46 -15
- ScriptCollection/TasksForCommonProjectStructure.py +17 -16
- {scriptcollection-3.5.107.dist-info → scriptcollection-3.5.109.dist-info}/METADATA +4 -3
- {scriptcollection-3.5.107.dist-info → scriptcollection-3.5.109.dist-info}/RECORD +8 -8
- {scriptcollection-3.5.107.dist-info → scriptcollection-3.5.109.dist-info}/WHEEL +1 -1
- {scriptcollection-3.5.107.dist-info → scriptcollection-3.5.109.dist-info}/entry_points.txt +1 -0
- {scriptcollection-3.5.107.dist-info → scriptcollection-3.5.109.dist-info}/top_level.txt +0 -0
ScriptCollection/Executables.py
CHANGED
@@ -628,3 +628,29 @@ def CurrentUserHasElevatedPrivileges() -> int:
|
|
628
628
|
return 1
|
629
629
|
else:
|
630
630
|
return 0
|
631
|
+
|
632
|
+
|
633
|
+
def Espoc() -> int:
|
634
|
+
GeneralUtilities.write_message_to_stdout("check...")
|
635
|
+
parser = argparse.ArgumentParser(description="Espoc (appreviation for 'exit started programs on close') is a tool to ensure the started processes of your program will also get terminated when the execution of your program is finished.")
|
636
|
+
parser.add_argument('-p', '--processid', required=True)
|
637
|
+
parser.add_argument('-f', '--file', required=True, help='Specifies the file where the process-ids of the started processes are stored (line by line). This file will be deleted when all started processes are terminated.')
|
638
|
+
args = parser.parse_args()
|
639
|
+
process_id = args.processid
|
640
|
+
process_list_file: str = args.file
|
641
|
+
if not os.path.isabs(process_list_file):
|
642
|
+
process_list_file = GeneralUtilities.resolve_relative_path(process_list_file, os.getcwd())
|
643
|
+
GeneralUtilities.assert_condition(GeneralUtilities.process_is_running_by_id(process_id), f"Process with id {process_id} is not running.")
|
644
|
+
while GeneralUtilities.process_is_running_by_id(process_id):
|
645
|
+
time.sleep(1)
|
646
|
+
GeneralUtilities.write_message_to_stdout(f"Process with id {process_id} is not running anymore. Start terminating remaining processes.")
|
647
|
+
if os.path.exists(process_list_file):
|
648
|
+
for line in GeneralUtilities.read_lines_from_file(process_list_file):
|
649
|
+
if GeneralUtilities.string_has_content(line):
|
650
|
+
current_process_id = int(line.strip())
|
651
|
+
GeneralUtilities.kill_process(current_process_id, True)
|
652
|
+
GeneralUtilities.ensure_file_does_not_exist(process_list_file)
|
653
|
+
GeneralUtilities.write_message_to_stdout("All started processes terminated.")
|
654
|
+
else:
|
655
|
+
GeneralUtilities.write_message_to_stdout(f"File '{process_list_file}' does not exist. No processes to terminate.")
|
656
|
+
return 0
|
@@ -33,7 +33,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
|
|
33
33
|
from .ProgramRunnerPopen import ProgramRunnerPopen
|
34
34
|
from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
|
35
35
|
|
36
|
-
version = "3.5.
|
36
|
+
version = "3.5.109"
|
37
37
|
__version__ = version
|
38
38
|
|
39
39
|
|
@@ -603,6 +603,12 @@ class ScriptCollectionCore:
|
|
603
603
|
self.assert_is_git_repository(repository_folder)
|
604
604
|
return self.run_program_argsasarray("git", ["rev-parse", "--verify", "HEAD"], repository_folder, throw_exception_if_exitcode_is_not_zero=False)[0] == 0
|
605
605
|
|
606
|
+
@GeneralUtilities.check_arguments
|
607
|
+
def run_git_command_in_repository_and_submodules(self, repository_folder: str, arguments: list[str]) -> None:
|
608
|
+
self.assert_is_git_repository(repository_folder)
|
609
|
+
self.run_program_argsasarray("git", arguments, repository_folder)
|
610
|
+
self.run_program_argsasarray("git", ["submodule", "foreach", "--recursive", "git"]+arguments, repository_folder)
|
611
|
+
|
606
612
|
@GeneralUtilities.check_arguments
|
607
613
|
def export_filemetadata(self, folder: str, target_file: str, encoding: str = "utf-8", filter_function=None) -> None:
|
608
614
|
folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(folder)
|
@@ -881,7 +887,7 @@ class ScriptCollectionCore:
|
|
881
887
|
|
882
888
|
@GeneralUtilities.check_arguments
|
883
889
|
def __create_thumbnails(self, filename: str, fps: str, folder: str, tempname_for_thumbnails: str) -> list[str]:
|
884
|
-
argument = ['-i', filename, '-r',
|
890
|
+
argument = ['-i', filename, '-r', fps, '-vf', 'scale=-1:120', '-vcodec', 'png', f'{tempname_for_thumbnails}-%002d.png']
|
885
891
|
self.run_program_argsasarray("ffmpeg", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
886
892
|
files = GeneralUtilities.get_direct_files_of_folder(folder)
|
887
893
|
result: list[str] = []
|
@@ -898,8 +904,17 @@ class ScriptCollectionCore:
|
|
898
904
|
def __create_thumbnail(self, outputfilename: str, folder: str, length_in_seconds: float, tempname_for_thumbnails: str, amount_of_images: int) -> None:
|
899
905
|
duration = timedelta(seconds=length_in_seconds)
|
900
906
|
info = GeneralUtilities.timedelta_to_simple_string(duration)
|
901
|
-
|
902
|
-
|
907
|
+
next_square_number = GeneralUtilities.get_next_square_number(amount_of_images)
|
908
|
+
root = math.sqrt(next_square_number)
|
909
|
+
rows: int = root # 5
|
910
|
+
columns: int = root # math.ceil(amount_of_images/rows)
|
911
|
+
argument = ['-title', f'"{outputfilename} ({info})"', '-tile', f'{rows}x{columns}', f'{tempname_for_thumbnails}*.png', f'{outputfilename}.png']
|
912
|
+
self.run_program_argsasarray("montage", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
913
|
+
|
914
|
+
@GeneralUtilities.check_arguments
|
915
|
+
def __create_thumbnail2(self, outputfilename: str, folder: str, length_in_seconds: float, rows: int, columns: int, tempname_for_thumbnails: str, amount_of_images: int) -> None:
|
916
|
+
duration = timedelta(seconds=length_in_seconds)
|
917
|
+
info = GeneralUtilities.timedelta_to_simple_string(duration)
|
903
918
|
argument = ['-title', f'"{outputfilename} ({info})"', '-tile', f'{rows}x{columns}', f'{tempname_for_thumbnails}*.png', f'{outputfilename}.png']
|
904
919
|
self.run_program_argsasarray("montage", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
905
920
|
|
@@ -912,7 +927,7 @@ class ScriptCollectionCore:
|
|
912
927
|
return math.ceil(x * d) / d
|
913
928
|
|
914
929
|
@GeneralUtilities.check_arguments
|
915
|
-
def generate_thumbnail(self, file: str, frames_per_second:
|
930
|
+
def generate_thumbnail(self, file: str, frames_per_second: float, tempname_for_thumbnails: str = None, hook=None) -> None:
|
916
931
|
if tempname_for_thumbnails is None:
|
917
932
|
tempname_for_thumbnails = "t_"+str(uuid.uuid4())
|
918
933
|
|
@@ -923,16 +938,9 @@ class ScriptCollectionCore:
|
|
923
938
|
preview_files: list[str] = []
|
924
939
|
try:
|
925
940
|
length_in_seconds = self.__calculate_lengh_in_seconds(filename, folder)
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
frames_per_second_as_string = str(frames_per_second)
|
930
|
-
amounf_of_previewframes = int(math.floor(length_in_seconds*frames_per_second))
|
931
|
-
else:
|
932
|
-
# concrete amount of frame, examples: frames_per_second="16" => 16 frames for entire video
|
933
|
-
amounf_of_previewframes = int(float(frames_per_second))
|
934
|
-
# self.roundup((amounf_of_previewframes-2)/length_in_seconds, 2)
|
935
|
-
frames_per_second_as_string = f"{amounf_of_previewframes-2}/{length_in_seconds}"
|
941
|
+
# frames per second, example: frames_per_second="20fps" => 20 frames per second
|
942
|
+
frames_per_second = self.__roundup(float(frames_per_second[:-3]), 2)
|
943
|
+
frames_per_second_as_string = str(frames_per_second)
|
936
944
|
preview_files = self.__create_thumbnails(filename, frames_per_second_as_string, folder, tempname_for_thumbnails)
|
937
945
|
if hook is not None:
|
938
946
|
hook(file, preview_files)
|
@@ -942,6 +950,29 @@ class ScriptCollectionCore:
|
|
942
950
|
for thumbnail_to_delete in preview_files:
|
943
951
|
os.remove(thumbnail_to_delete)
|
944
952
|
|
953
|
+
@GeneralUtilities.check_arguments
|
954
|
+
def generate_thumbnail_by_amount_of_pictures(self, file: str, amount_of_columns: int, amount_of_rows: int, tempname_for_thumbnails: str = None, hook=None) -> None:
|
955
|
+
if tempname_for_thumbnails is None:
|
956
|
+
tempname_for_thumbnails = "t_"+str(uuid.uuid4())
|
957
|
+
|
958
|
+
file = GeneralUtilities.resolve_relative_path_from_current_working_directory(file)
|
959
|
+
filename = os.path.basename(file)
|
960
|
+
folder = os.path.dirname(file)
|
961
|
+
filename_without_extension = Path(file).stem
|
962
|
+
preview_files: list[str] = []
|
963
|
+
try:
|
964
|
+
length_in_seconds = self.__calculate_lengh_in_seconds(filename, folder)
|
965
|
+
amounf_of_previewframes = int(amount_of_columns*amount_of_rows)
|
966
|
+
frames_per_second_as_string = f"{amounf_of_previewframes-2}/{length_in_seconds}"
|
967
|
+
preview_files = self.__create_thumbnails(filename, frames_per_second_as_string, folder, tempname_for_thumbnails)
|
968
|
+
if hook is not None:
|
969
|
+
hook(file, preview_files)
|
970
|
+
actual_amounf_of_previewframes = len(preview_files)
|
971
|
+
self.__create_thumbnail2(filename_without_extension, folder, length_in_seconds, amount_of_rows, amount_of_columns, tempname_for_thumbnails, actual_amounf_of_previewframes)
|
972
|
+
finally:
|
973
|
+
for thumbnail_to_delete in preview_files:
|
974
|
+
os.remove(thumbnail_to_delete)
|
975
|
+
|
945
976
|
@GeneralUtilities.check_arguments
|
946
977
|
def extract_pdf_pages(self, file: str, from_page: int, to_page: int, outputfile: str) -> None:
|
947
978
|
pdf_reader: PdfReader = PdfReader(file)
|
@@ -1025,8 +1025,9 @@ class TasksForCommonProjectStructure:
|
|
1025
1025
|
|
1026
1026
|
if codeunit_has_testcases:
|
1027
1027
|
source_testcoveragereport = os.path.join(other_folder_in_repository, "Artifacts", "TestCoverageReport")
|
1028
|
-
|
1029
|
-
|
1028
|
+
if os.path.isdir(source_testcoveragereport): # check, because it is not a mandatory artifact. if the artifact is not available, the user gets already a warning.
|
1029
|
+
target_testcoveragereport = os.path.join(target_folder, "TestCoverageReport")
|
1030
|
+
shutil.copytree(source_testcoveragereport, target_testcoveragereport)
|
1030
1031
|
|
1031
1032
|
@GeneralUtilities.check_arguments
|
1032
1033
|
def __standardized_tasks_release_artifact(self, information: CreateReleaseInformationForProjectInCommonProjectFormat) -> None:
|
@@ -1560,9 +1561,9 @@ class TasksForCommonProjectStructure:
|
|
1560
1561
|
combined_file = os.path.join(codeunit_folder, file)
|
1561
1562
|
if not os.path.isfile(combined_file):
|
1562
1563
|
raise ValueError(f'The mandatory file "{file}" does not exist in the codeunit-folder.')
|
1563
|
-
|
1564
|
-
if os.path.isfile(os.path.join(codeunit_folder,"Other","requirements.txt")):
|
1565
|
-
self.install_requirementstxt_for_codeunit(codeunit_folder,verbosity)
|
1564
|
+
|
1565
|
+
if os.path.isfile(os.path.join(codeunit_folder, "Other", "requirements.txt")):
|
1566
|
+
self.install_requirementstxt_for_codeunit(codeunit_folder, verbosity)
|
1566
1567
|
|
1567
1568
|
# Check developer
|
1568
1569
|
if self.validate_developers_of_repository:
|
@@ -2271,9 +2272,9 @@ class TasksForCommonProjectStructure:
|
|
2271
2272
|
def update_dependencies_of_typical_python_repository_requirements(self, repository_folder: str, verbosity: int, cmd_args: list[str]) -> None:
|
2272
2273
|
verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
|
2273
2274
|
|
2274
|
-
development_requirements_file = os.path.join(repository_folder, "Other","requirements.txt")
|
2275
|
+
development_requirements_file = os.path.join(repository_folder, "Other", "requirements.txt")
|
2275
2276
|
if (os.path.isfile(development_requirements_file)):
|
2276
|
-
self.__sc.update_dependencies_of_python_in_requirementstxt_file(development_requirements_file,[], verbosity)
|
2277
|
+
self.__sc.update_dependencies_of_python_in_requirementstxt_file(development_requirements_file, [], verbosity)
|
2277
2278
|
|
2278
2279
|
@GeneralUtilities.check_arguments
|
2279
2280
|
def update_dependencies_of_typical_python_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
|
@@ -2282,17 +2283,17 @@ class TasksForCommonProjectStructure:
|
|
2282
2283
|
# TODO consider ignored_dependencies
|
2283
2284
|
verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
|
2284
2285
|
|
2285
|
-
setup_cfg=os.path.join(codeunit_folder, "setup.cfg")
|
2286
|
+
setup_cfg = os.path.join(codeunit_folder, "setup.cfg")
|
2286
2287
|
if (os.path.isfile(setup_cfg)):
|
2287
|
-
self.__sc.update_dependencies_of_python_in_setupcfg_file(setup_cfg,ignored_dependencies, verbosity)
|
2288
|
+
self.__sc.update_dependencies_of_python_in_setupcfg_file(setup_cfg, ignored_dependencies, verbosity)
|
2288
2289
|
|
2289
|
-
development_requirements_file = os.path.join(codeunit_folder, "requirements.txt")#required for codeunits which contain python-code which need third-party dependencies
|
2290
|
+
development_requirements_file = os.path.join(codeunit_folder, "requirements.txt") # required for codeunits which contain python-code which need third-party dependencies
|
2290
2291
|
if (os.path.isfile(development_requirements_file)):
|
2291
|
-
self.__sc.update_dependencies_of_python_in_requirementstxt_file(development_requirements_file,ignored_dependencies, verbosity)
|
2292
|
+
self.__sc.update_dependencies_of_python_in_requirementstxt_file(development_requirements_file, ignored_dependencies, verbosity)
|
2292
2293
|
|
2293
|
-
development_requirements_file2 = os.path.join(codeunit_folder, "Other","requirements.txt")#required for codeunits which contain python-scripts which needs third-party dependencies
|
2294
|
+
development_requirements_file2 = os.path.join(codeunit_folder, "Other", "requirements.txt") # required for codeunits which contain python-scripts which needs third-party dependencies
|
2294
2295
|
if (os.path.isfile(development_requirements_file2)):
|
2295
|
-
self.__sc.update_dependencies_of_python_in_requirementstxt_file(development_requirements_file2, ignored_dependencies,verbosity)
|
2296
|
+
self.__sc.update_dependencies_of_python_in_requirementstxt_file(development_requirements_file2, ignored_dependencies, verbosity)
|
2296
2297
|
|
2297
2298
|
@GeneralUtilities.check_arguments
|
2298
2299
|
def update_dependencies_of_typical_dotnet_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
|
@@ -3292,15 +3293,15 @@ class TasksForCommonProjectStructure:
|
|
3292
3293
|
self.__sc.git_commit(GeneralUtilities.resolve_relative_path("../..", folder_of_this_file), f"Updated content of {update_http_documentation_arguments.product_name} v{update_http_documentation_arguments.new_project_version} in {update_http_documentation_arguments.reference_repository_name}-submodule")
|
3293
3294
|
|
3294
3295
|
@GeneralUtilities.check_arguments
|
3295
|
-
def install_requirementstxt_for_codeunit(self,codeunit_folder:str,verbosity:int):
|
3296
|
+
def install_requirementstxt_for_codeunit(self, codeunit_folder: str, verbosity: int):
|
3296
3297
|
self.__sc.install_requirementstxt_file(codeunit_folder+"/Other/requirements.txt", verbosity)
|
3297
3298
|
|
3298
3299
|
@GeneralUtilities.check_arguments
|
3299
|
-
def install_requirementstxt_for_repository(self, repository_folde: str,verbosity:int):
|
3300
|
+
def install_requirementstxt_for_repository(self, repository_folde: str, verbosity: int):
|
3300
3301
|
self.__sc.install_requirementstxt_file(repository_folde+"/Other/requirements.txt", verbosity)
|
3301
3302
|
|
3302
3303
|
@GeneralUtilities.check_arguments
|
3303
|
-
def update_submodule(self, repository_folder: str, submodule_name:str):
|
3304
|
+
def update_submodule(self, repository_folder: str, submodule_name: str):
|
3304
3305
|
submodule_folder = GeneralUtilities.resolve_relative_path("Other/Resources/Submodules/"+submodule_name, repository_folder)
|
3305
3306
|
self.__sc.git_fetch(submodule_folder, "origin")
|
3306
3307
|
self.__sc.git_checkout(submodule_folder, "main")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ScriptCollection
|
3
|
-
Version: 3.5.
|
3
|
+
Version: 3.5.109
|
4
4
|
Summary: The ScriptCollection is the place for reusable scripts.
|
5
5
|
Home-page: https://github.com/anionDev/ScriptCollection
|
6
6
|
Author: Marius Göcke
|
@@ -24,13 +24,14 @@ Requires-Python: >=3.10
|
|
24
24
|
Description-Content-Type: text/markdown
|
25
25
|
Requires-Dist: build>=1.2.2.post1
|
26
26
|
Requires-Dist: coverage>=7.8.0
|
27
|
-
Requires-Dist: cyclonedx-bom>=
|
27
|
+
Requires-Dist: cyclonedx-bom>=6.0.0
|
28
28
|
Requires-Dist: defusedxml>=0.7.1
|
29
29
|
Requires-Dist: keyboard>=0.13.5
|
30
30
|
Requires-Dist: lcov-cobertura>=2.1.1
|
31
|
-
Requires-Dist: lxml>=5.
|
31
|
+
Requires-Dist: lxml>=5.4.0
|
32
32
|
Requires-Dist: ntplib>=0.4.0
|
33
33
|
Requires-Dist: Pillow>=11.2.1
|
34
|
+
Requires-Dist: psutil>=7.0.0
|
34
35
|
Requires-Dist: pycdlib>=1.14.0
|
35
36
|
Requires-Dist: Pygments>=2.19.1
|
36
37
|
Requires-Dist: pylint>=3.3.6
|
@@ -1,16 +1,16 @@
|
|
1
1
|
ScriptCollection/CertificateUpdater.py,sha256=pJopWFcwaLAEVljtC4O3SVrlpIpoJNUhT1V4mgiqLvE,8970
|
2
|
-
ScriptCollection/Executables.py,sha256=
|
2
|
+
ScriptCollection/Executables.py,sha256=BsDgpqU_XKXg-7paQdmamzU14-2kcqjz9v13r96EiEk,32319
|
3
3
|
ScriptCollection/GeneralUtilities.py,sha256=VO4a7xctkjN5dcBXc32gz0x9U07DEagasjvYVKqLmdM,44173
|
4
4
|
ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
|
5
5
|
ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
|
6
6
|
ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
|
7
7
|
ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
|
8
8
|
ScriptCollection/SCLog.py,sha256=Gw27Oclcb0ten7_89PD5CdNMoO-at2hGUOYbF-x1HPQ,2296
|
9
|
-
ScriptCollection/ScriptCollectionCore.py,sha256=
|
10
|
-
ScriptCollection/TasksForCommonProjectStructure.py,sha256=
|
9
|
+
ScriptCollection/ScriptCollectionCore.py,sha256=X3jRXN0FRstFN7kPFLnzSZUONMbh_YOPr22cKzDgU78,130404
|
10
|
+
ScriptCollection/TasksForCommonProjectStructure.py,sha256=SJ7V9HilnkCBJGCCrObWwAORSI_pXW9zC4uon1O6Xbg,232705
|
11
11
|
ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
-
scriptcollection-3.5.
|
13
|
-
scriptcollection-3.5.
|
14
|
-
scriptcollection-3.5.
|
15
|
-
scriptcollection-3.5.
|
16
|
-
scriptcollection-3.5.
|
12
|
+
scriptcollection-3.5.109.dist-info/METADATA,sha256=8glqA2n3AUjhZOZV4uXRsgdyHmqgyWwcHbkLUeeKqbc,7694
|
13
|
+
scriptcollection-3.5.109.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
|
14
|
+
scriptcollection-3.5.109.dist-info/entry_points.txt,sha256=3qMbfZEMhc_VTJj-bcLwB8AWcn9iXSB3l0AWpuu52Bs,3689
|
15
|
+
scriptcollection-3.5.109.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
|
16
|
+
scriptcollection-3.5.109.dist-info/RECORD,,
|
@@ -15,6 +15,7 @@ sccreatehashofallfiles = ScriptCollection.Executables:CreateHashOfAllFiles
|
|
15
15
|
sccreateisofilewithobfuscatedfiles = ScriptCollection.Executables:CreateISOFileWithObfuscatedFiles
|
16
16
|
sccreatesimplemergewithoutrelease = ScriptCollection.Executables:CreateSimpleMergeWithoutRelease
|
17
17
|
sccurrentuserhaselevatedprivileges = ScriptCollection.Executables:CurrentUserHasElevatedPrivileges
|
18
|
+
scespoc = ScriptCollection.Executables:Espoc
|
18
19
|
scextractpdfpages = ScriptCollection.Executables:ExtractPDFPages
|
19
20
|
scfilecontainscontent = ScriptCollection.Executables:FileContainsContent
|
20
21
|
scfileexists = ScriptCollection.Executables:FileExists
|
File without changes
|