NGPIris 5.4.2.dev5__tar.gz → 5.4.2.dev7__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.
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/cli/__init__.py +24 -7
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hcp/hcp.py +49 -29
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7/NGPIris.egg-info}/PKG-INFO +2 -2
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris.egg-info/requires.txt +1 -1
- {ngpiris-5.4.2.dev5/NGPIris.egg-info → ngpiris-5.4.2.dev7}/PKG-INFO +2 -2
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/pyproject.toml +2 -2
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/test_hcp.py +12 -5
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/LICENSE +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/MANIFEST.in +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/__init__.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hci/__init__.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hci/exceptions.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hci/hci.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hci/helpers.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hcp/__init__.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hcp/exceptions.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hcp/helpers.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/hcp/statistics.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/parse_credentials/__init__.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/parse_credentials/parse_credentials.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/utils/__init__.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris/utils/utils.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris.egg-info/SOURCES.txt +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris.egg-info/dependency_links.txt +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris.egg-info/entry_points.txt +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/NGPIris.egg-info/top_level.txt +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/README.md +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/IRIS_5_changelog.md +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/Makefile +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/NGPIris.cli.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/NGPIris.hci.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/NGPIris.hcp.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/NGPIris.parse_credentials.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/NGPIris.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/NGPIris.utils.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/Tutorial.md +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/conf.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/index.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/make.bat +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/docs/modules.rst +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/setup.cfg +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/80MB_test_file +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/a folder of data/80MB_test_file_0 +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/a folder of data/80MB_test_file_1 +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/complete_creds_0.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/complete_creds_1.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/complete_creds_2.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/incomplete_creds_0.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/incomplete_creds_1.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/incomplete_creds_2.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/incomplete_creds_3.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/data/incomplete_creds_4.json +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/test_hci.py +0 -0
- {ngpiris-5.4.2.dev5 → ngpiris-5.4.2.dev7}/tests/test_parse_credentials.py +0 -0
|
@@ -79,13 +79,24 @@ def cli(context : Context, credentials : str, debug : bool, transfer_config : st
|
|
|
79
79
|
is_flag = True
|
|
80
80
|
)
|
|
81
81
|
@click.option(
|
|
82
|
-
"-
|
|
83
|
-
"--
|
|
84
|
-
help = "
|
|
85
|
-
|
|
82
|
+
"-um",
|
|
83
|
+
"--upload_mode",
|
|
84
|
+
help = "Choose an upload method. Default upload mode is STANDARD which uses a basic multipart upload. Use another mode than STANDARD if that mode misbehaves",
|
|
85
|
+
type = click.Choice(
|
|
86
|
+
["STANDARD", "SIMPLE", "EQUAL_PARTS"],
|
|
87
|
+
case_sensitive = False
|
|
88
|
+
),
|
|
89
|
+
default = "STANDARD"
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"-ep",
|
|
93
|
+
"--equal_parts",
|
|
94
|
+
help = "Supplementary option when using the EQUAL_PARTS upload mode. Splits each file into a given number of parts. Must be a positive integer",
|
|
95
|
+
type = int,
|
|
96
|
+
default = 5
|
|
86
97
|
)
|
|
87
98
|
@click.pass_context
|
|
88
|
-
def upload(context : Context, bucket : str, source : str, destination : str, dry_run : bool,
|
|
99
|
+
def upload(context : Context, bucket : str, source : str, destination : str, dry_run : bool, upload_mode : str, equal_parts : int):
|
|
89
100
|
"""
|
|
90
101
|
Upload files to an HCP bucket/namespace.
|
|
91
102
|
|
|
@@ -95,6 +106,12 @@ def upload(context : Context, bucket : str, source : str, destination : str, dry
|
|
|
95
106
|
|
|
96
107
|
DESTINATION is the destination path on the HCP.
|
|
97
108
|
"""
|
|
109
|
+
|
|
110
|
+
if equal_parts <= 0:
|
|
111
|
+
exit("Error: --equal_parts value must be a positive integer")
|
|
112
|
+
|
|
113
|
+
upload_mode_choice = HCPHandler.UploadMode(upload_mode.lower())
|
|
114
|
+
|
|
98
115
|
hcph : HCPHandler = get_HCPHandler(context)
|
|
99
116
|
hcph.mount_bucket(bucket)
|
|
100
117
|
destination = add_trailing_slash(destination)
|
|
@@ -103,14 +120,14 @@ def upload(context : Context, bucket : str, source : str, destination : str, dry
|
|
|
103
120
|
if dry_run:
|
|
104
121
|
click.echo("This command would have uploaded the folder \"" + source + "\" to \"" + destination + "\"")
|
|
105
122
|
else:
|
|
106
|
-
hcph.upload_folder(source, destination,
|
|
123
|
+
hcph.upload_folder(source, destination, upload_mode = upload_mode_choice, equal_parts = equal_parts)
|
|
107
124
|
else:
|
|
108
125
|
file_name = Path(source).name
|
|
109
126
|
destination += file_name
|
|
110
127
|
if dry_run:
|
|
111
128
|
click.echo("This command would have uploaded the file \"" + source + "\" to \"" + destination + "\"")
|
|
112
129
|
else:
|
|
113
|
-
hcph.upload_file(source, destination,
|
|
130
|
+
hcph.upload_file(source, destination, upload_mode = upload_mode_choice, equal_parts = equal_parts)
|
|
114
131
|
|
|
115
132
|
@cli.command()
|
|
116
133
|
@click.argument("bucket")
|
|
@@ -42,6 +42,7 @@ from urllib3 import disable_warnings
|
|
|
42
42
|
from tqdm import tqdm
|
|
43
43
|
from bitmath import TiB, Byte
|
|
44
44
|
|
|
45
|
+
from enum import Enum
|
|
45
46
|
from typing import Generator
|
|
46
47
|
|
|
47
48
|
_KB = 1024
|
|
@@ -468,9 +469,14 @@ class HCPHandler:
|
|
|
468
469
|
self.download_file(object["Key"], p.as_posix(), show_progress_bar = show_progress_bar)
|
|
469
470
|
else:
|
|
470
471
|
raise NotADirectory(local_folder_path + " is not a directory")
|
|
472
|
+
|
|
473
|
+
class UploadMode(Enum):
|
|
474
|
+
STANDARD = "standard"
|
|
475
|
+
SIMPLE = "simple"
|
|
476
|
+
EQUAL_PARTS = "equal_parts"
|
|
471
477
|
|
|
472
478
|
@check_mounted
|
|
473
|
-
def upload_file(self, local_file_path : str, key : str = "", show_progress_bar : bool = True,
|
|
479
|
+
def upload_file(self, local_file_path : str, key : str = "", show_progress_bar : bool = True, upload_mode : UploadMode = UploadMode.STANDARD, equal_parts : int = 5) -> None:
|
|
474
480
|
"""
|
|
475
481
|
Upload one file to the mounted bucket
|
|
476
482
|
|
|
@@ -483,6 +489,16 @@ class HCPHandler:
|
|
|
483
489
|
:param show_progress_bar: Boolean choice of displaying a progress bar. Defaults to True
|
|
484
490
|
:type show_progress_bar: bool, optional
|
|
485
491
|
|
|
492
|
+
:param upload_mode:
|
|
493
|
+
The upload mode of the transfer is any of the following:
|
|
494
|
+
HCPHandler.UploadMode.STANDARD,
|
|
495
|
+
HCPHandler.UploadMode.SIMPLE,
|
|
496
|
+
HCPHandler.UploadMode.EQUAL_PARTS\n
|
|
497
|
+
:type upload_mode: UploadMode, optional
|
|
498
|
+
|
|
499
|
+
:param equal_parts: The number of equal parts that each file should be divided into when using the HCPHandler.UploadMode.EQUAL_PARTS mode. Default is 5
|
|
500
|
+
:type equal_parts: int, optional
|
|
501
|
+
|
|
486
502
|
:raises RuntimeError: If the \"\\\" is used in the file path
|
|
487
503
|
|
|
488
504
|
:raises ObjectAlreadyExist: If the object already exist on the mounted bucket
|
|
@@ -499,47 +515,40 @@ class HCPHandler:
|
|
|
499
515
|
if self.object_exists(key):
|
|
500
516
|
raise ObjectAlreadyExist("The object \"" + key + "\" already exist in the mounted bucket")
|
|
501
517
|
else:
|
|
518
|
+
file_size : int = stat(local_file_path).st_size
|
|
519
|
+
|
|
520
|
+
match upload_mode:
|
|
521
|
+
case HCPHandler.UploadMode.STANDARD:
|
|
522
|
+
config = self.transfer_config
|
|
523
|
+
case HCPHandler.UploadMode.SIMPLE:
|
|
524
|
+
config = TransferConfig(multipart_chunksize = file_size)
|
|
525
|
+
case HCPHandler.UploadMode.EQUAL_PARTS:
|
|
526
|
+
config = TransferConfig(multipart_chunksize = round(file_size / equal_parts))
|
|
527
|
+
|
|
502
528
|
if show_progress_bar:
|
|
503
|
-
file_size : int = stat(local_file_path).st_size
|
|
504
529
|
with tqdm(
|
|
505
530
|
total = file_size,
|
|
506
531
|
unit = "B",
|
|
507
532
|
unit_scale = True,
|
|
508
533
|
desc = local_file_path
|
|
509
534
|
) as pbar:
|
|
510
|
-
if use_simple_upload:
|
|
511
|
-
self.s3_client.upload_file(
|
|
512
|
-
Filename = local_file_path,
|
|
513
|
-
Bucket = self.bucket_name,
|
|
514
|
-
Key = key,
|
|
515
|
-
Config = TransferConfig(multipart_chunksize = file_size),
|
|
516
|
-
Callback = lambda bytes_transferred : pbar.update(bytes_transferred)
|
|
517
|
-
)
|
|
518
|
-
else:
|
|
519
|
-
self.s3_client.upload_file(
|
|
520
|
-
Filename = local_file_path,
|
|
521
|
-
Bucket = self.bucket_name,
|
|
522
|
-
Key = key,
|
|
523
|
-
Config = self.transfer_config,
|
|
524
|
-
Callback = lambda bytes_transferred : pbar.update(bytes_transferred)
|
|
525
|
-
)
|
|
526
|
-
else:
|
|
527
|
-
if use_simple_upload:
|
|
528
535
|
self.s3_client.upload_file(
|
|
529
536
|
Filename = local_file_path,
|
|
530
537
|
Bucket = self.bucket_name,
|
|
531
538
|
Key = key,
|
|
539
|
+
Config = config,
|
|
540
|
+
Callback = lambda bytes_transferred : pbar.update(bytes_transferred)
|
|
532
541
|
)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
542
|
+
else:
|
|
543
|
+
self.s3_client.upload_file(
|
|
544
|
+
Filename = local_file_path,
|
|
545
|
+
Bucket = self.bucket_name,
|
|
546
|
+
Key = key,
|
|
547
|
+
Config = config,
|
|
548
|
+
)
|
|
540
549
|
|
|
541
550
|
@check_mounted
|
|
542
|
-
def upload_folder(self, local_folder_path : str, key : str = "", show_progress_bar : bool = True,
|
|
551
|
+
def upload_folder(self, local_folder_path : str, key : str = "", show_progress_bar : bool = True, upload_mode : UploadMode = UploadMode.STANDARD, equal_parts : int = 5) -> None:
|
|
543
552
|
"""
|
|
544
553
|
Upload the contents of a folder to the mounted bucket
|
|
545
554
|
|
|
@@ -551,6 +560,16 @@ class HCPHandler:
|
|
|
551
560
|
|
|
552
561
|
:param show_progress_bar: Boolean choice of displaying a progress bar. Defaults to True
|
|
553
562
|
:type show_progress_bar: bool, optional
|
|
563
|
+
|
|
564
|
+
:param upload_mode:
|
|
565
|
+
The upload mode of the transfer is any of the following:
|
|
566
|
+
HCPHandler.UploadMode.STANDARD,
|
|
567
|
+
HCPHandler.UploadMode.SIMPLE,
|
|
568
|
+
HCPHandler.UploadMode.EQUAL_PARTS\n
|
|
569
|
+
:type upload_mode: UploadMode, optional
|
|
570
|
+
|
|
571
|
+
:param equal_parts: The number of equal parts that each file should be divided into when using the HCPHandler.UploadMode.EQUAL_PARTS mode. Default is 5
|
|
572
|
+
:type equal_parts: int, optional
|
|
554
573
|
"""
|
|
555
574
|
raise_path_error(local_folder_path)
|
|
556
575
|
|
|
@@ -563,7 +582,8 @@ class HCPHandler:
|
|
|
563
582
|
local_folder_path + filename,
|
|
564
583
|
key + filename,
|
|
565
584
|
show_progress_bar = show_progress_bar,
|
|
566
|
-
|
|
585
|
+
upload_mode = upload_mode,
|
|
586
|
+
equal_parts = equal_parts
|
|
567
587
|
)
|
|
568
588
|
|
|
569
589
|
@check_mounted
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: NGPIris
|
|
3
|
-
Version: 5.4.2.
|
|
3
|
+
Version: 5.4.2.dev7
|
|
4
4
|
Author-email: Erik Brink <erik.brink@gu.se>, Isak Sylvin <isak.sylvin@gu.se>
|
|
5
5
|
Description-Content-Type: text/markdown
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Requires-Dist: requests>=2.31.0
|
|
8
8
|
Requires-Dist: urllib3==1.26.19
|
|
9
|
-
Requires-Dist: boto3==1.35
|
|
9
|
+
Requires-Dist: boto3==1.37.35
|
|
10
10
|
Requires-Dist: parse>=1.19.1
|
|
11
11
|
Requires-Dist: RapidFuzz>=3.10.1
|
|
12
12
|
Requires-Dist: tqdm>=4.66.2
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: NGPIris
|
|
3
|
-
Version: 5.4.2.
|
|
3
|
+
Version: 5.4.2.dev7
|
|
4
4
|
Author-email: Erik Brink <erik.brink@gu.se>, Isak Sylvin <isak.sylvin@gu.se>
|
|
5
5
|
Description-Content-Type: text/markdown
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Requires-Dist: requests>=2.31.0
|
|
8
8
|
Requires-Dist: urllib3==1.26.19
|
|
9
|
-
Requires-Dist: boto3==1.35
|
|
9
|
+
Requires-Dist: boto3==1.37.35
|
|
10
10
|
Requires-Dist: parse>=1.19.1
|
|
11
11
|
Requires-Dist: RapidFuzz>=3.10.1
|
|
12
12
|
Requires-Dist: tqdm>=4.66.2
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "NGPIris"
|
|
3
|
-
version = "5.4.2.
|
|
3
|
+
version = "5.4.2.dev7"
|
|
4
4
|
readme = "README.md"
|
|
5
5
|
dependencies = [
|
|
6
6
|
"requests >= 2.31.0",
|
|
7
7
|
"urllib3 == 1.26.19",
|
|
8
|
-
"boto3 == 1.35
|
|
8
|
+
"boto3 == 1.37.35",
|
|
9
9
|
"parse >= 1.19.1",
|
|
10
10
|
"RapidFuzz >= 3.10.1",
|
|
11
11
|
"tqdm >= 4.66.2",
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
from filecmp import cmp
|
|
5
4
|
from typing import Any, Callable
|
|
6
|
-
|
|
7
5
|
from conftest import CustomConfig
|
|
8
|
-
|
|
9
6
|
from NGPIris.hcp import HCPHandler
|
|
7
|
+
from icecream import ic
|
|
10
8
|
|
|
11
9
|
# --------------------------- Helper fucntions ---------------------------------
|
|
12
10
|
|
|
@@ -70,6 +68,15 @@ def test_upload_file(custom_config : CustomConfig) -> None:
|
|
|
70
68
|
show_progress_bar = False
|
|
71
69
|
)
|
|
72
70
|
|
|
71
|
+
# Test every upload mode
|
|
72
|
+
for mode in HCPHandler.UploadMode:
|
|
73
|
+
ic(mode, custom_config.test_file_path + "_" + str(mode).replace(".", "_"))
|
|
74
|
+
custom_config.hcp_h.upload_file(
|
|
75
|
+
custom_config.test_file_path,
|
|
76
|
+
custom_config.test_file_path + "_" + str(mode).replace(".", "_"),
|
|
77
|
+
upload_mode = mode
|
|
78
|
+
)
|
|
79
|
+
|
|
73
80
|
def test_upload_file_without_mounting(custom_config : CustomConfig) -> None:
|
|
74
81
|
_hcp_h = custom_config.hcp_h
|
|
75
82
|
_without_mounting(_hcp_h, HCPHandler.upload_file)
|
|
@@ -119,8 +126,6 @@ def test_get_file_in_sub_directory(custom_config : CustomConfig) -> None:
|
|
|
119
126
|
assert custom_config.hcp_h.object_exists(custom_config.test_file_path)
|
|
120
127
|
assert custom_config.hcp_h.get_object(custom_config.test_file_path)
|
|
121
128
|
|
|
122
|
-
from icecream import ic
|
|
123
|
-
|
|
124
129
|
def test_download_file(custom_config : CustomConfig) -> None:
|
|
125
130
|
test_mount_bucket(custom_config)
|
|
126
131
|
Path(custom_config.result_path).mkdir()
|
|
@@ -215,6 +220,8 @@ def test_delete_file(custom_config : CustomConfig) -> None:
|
|
|
215
220
|
test_mount_bucket(custom_config)
|
|
216
221
|
custom_config.hcp_h.delete_object(custom_config.test_file_path)
|
|
217
222
|
custom_config.hcp_h.delete_object(custom_config.test_file_path + "_no_progress_bar")
|
|
223
|
+
for mode in HCPHandler.UploadMode:
|
|
224
|
+
custom_config.hcp_h.delete_object(custom_config.test_file_path + "_" + str(mode).replace(".", "_"))
|
|
218
225
|
custom_config.hcp_h.delete_object("a_sub_directory/a_file")
|
|
219
226
|
custom_config.hcp_h.delete_object("a_sub_directory")
|
|
220
227
|
|
|
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
|