geoseeq 0.6.8a2__tar.gz → 0.6.9__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/PKG-INFO +1 -1
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/download.py +29 -3
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/main.py +1 -1
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/shared_params/id_handlers.py +31 -3
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/knex.py +2 -1
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/project.py +8 -3
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/utils.py +13 -5
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq.egg-info/PKG-INFO +1 -1
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/pyproject.toml +1 -1
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/LICENSE +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/README.md +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/app.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/blob_constructors.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/bulk_creators.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/constants.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/copy.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/detail.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/fastq_utils.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/get_eula.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/manage.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/progress_bar.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/project.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/raw.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/run.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/search.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/shared_params/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/shared_params/common_state.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/shared_params/config.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/shared_params/obj_getters.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/shared_params/opts_and_args.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/upload/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/upload/upload.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/upload/upload_advanced.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/upload/upload_reads.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/user.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/utils.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/cli/view.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/constants.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/contrib/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/contrib/ncbi/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/contrib/ncbi/api.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/contrib/ncbi/bioproject.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/contrib/ncbi/cli.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/contrib/ncbi/setup_logging.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/file_system_cache.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/id_constructors/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/id_constructors/from_blobs.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/id_constructors/from_ids.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/id_constructors/from_names.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/id_constructors/from_uuids.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/id_constructors/resolvers.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/id_constructors/utils.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/organization.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/pipeline.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/constants.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/highcharts.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/map/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/map/base_layer.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/map/map.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/map/overlay.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/plotting/selectable.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/remote_object.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/bioinfo.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/file_chunker.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/file_download.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/file_upload.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/result_file.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/result_folder.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/resumable_download_tracker.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/resumable_upload_tracker.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/result/utils.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/sample.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/search.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/upload_download_manager.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/user.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/checksum.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/cli.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/clone.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/constants.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/vc_cache.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/vc_dir.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/vc_sample.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/vc/vc_stub.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq/work_orders.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq.egg-info/SOURCES.txt +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq.egg-info/dependency_links.txt +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq.egg-info/entry_points.txt +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq.egg-info/requires.txt +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/geoseeq.egg-info/top_level.txt +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/setup.cfg +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/setup.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/tests/__init__.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/tests/test_api_client.py +0 -0
- {geoseeq-0.6.8a2 → geoseeq-0.6.9}/tests/test_plotting.py +0 -0
@@ -98,6 +98,7 @@ def cli_download_metadata(state, sample_ids):
|
|
98
98
|
|
99
99
|
cores_option = click.option('--cores', default=1, help='Number of downloads to run in parallel')
|
100
100
|
head_option = click.option('--head', default=None, type=int, help='Download the first N bytes of each file')
|
101
|
+
alt_id_option = click.option('--alt-sample-id', default=None, help='Specify an alternate sample id from the project metadata to id samples')
|
101
102
|
|
102
103
|
@cli_download.command("files")
|
103
104
|
@use_common_state
|
@@ -113,6 +114,7 @@ head_option = click.option('--head', default=None, type=int, help='Download the
|
|
113
114
|
@click.option("--extension", multiple=True, help="Only download files with this extension. e.g. 'fastq.gz', 'bam', 'csv'")
|
114
115
|
@click.option("--with-versions/--without-versions", default=False, help="Download all versions of a file, not just the latest")
|
115
116
|
@ignore_errors_option
|
117
|
+
@alt_id_option
|
116
118
|
@project_id_arg
|
117
119
|
@sample_ids_arg
|
118
120
|
def cli_download_files(
|
@@ -129,6 +131,7 @@ def cli_download_files(
|
|
129
131
|
with_versions,
|
130
132
|
download,
|
131
133
|
ignore_errors,
|
134
|
+
alt_sample_id,
|
132
135
|
project_id,
|
133
136
|
sample_ids,
|
134
137
|
):
|
@@ -164,6 +167,13 @@ def cli_download_files(
|
|
164
167
|
haib17CEM4890_H2NYMCCXY_SL254769 haib17CEM4890_H2NYMCCXY_SL254773 `# specify the samples by name` \\
|
165
168
|
--folder-type sample --extension '.contigs.fasta' # filter for contig files
|
166
169
|
|
170
|
+
\b
|
171
|
+
# Download files from a sample in the metasub project using an alternate sample id called "barcode"
|
172
|
+
$ geoseeq download files 'MetaSUB Consortium/Cell Paper' `# specify the project` \\
|
173
|
+
235183938 `# the alternate sample name (in this case a barcode number)` \\
|
174
|
+
--alt-sample-id barcode `# specify the alternate sample id column name` \\
|
175
|
+
--folder-type 'sample' `# only download files from sample folders`
|
176
|
+
|
167
177
|
---
|
168
178
|
|
169
179
|
Command Arguments:
|
@@ -184,7 +194,7 @@ def cli_download_files(
|
|
184
194
|
samples = []
|
185
195
|
if sample_ids:
|
186
196
|
logger.info(f"Fetching info for {len(sample_ids)} samples.")
|
187
|
-
samples = handle_multiple_sample_ids(knex, sample_ids, proj=proj)
|
197
|
+
samples = handle_multiple_sample_ids(knex, sample_ids, proj=proj, alternate_id_col=alt_sample_id)
|
188
198
|
|
189
199
|
response = proj.bulk_find_files(
|
190
200
|
sample_uuids=[s.uuid for s in samples],
|
@@ -377,9 +387,21 @@ def cli_download_ids(state, cores, target_dir, file_name, yes, download, head, i
|
|
377
387
|
@click.option("--download/--urls-only", default=True, help="Download files or just print urls")
|
378
388
|
@module_option(FASTQ_MODULE_NAMES, use_default=False)
|
379
389
|
@ignore_errors_option
|
390
|
+
@alt_id_option
|
380
391
|
@project_id_arg
|
381
392
|
@sample_ids_arg
|
382
|
-
def cli_download_fastqs(state,
|
393
|
+
def cli_download_fastqs(state,
|
394
|
+
cores,
|
395
|
+
target_dir,
|
396
|
+
yes,
|
397
|
+
first,
|
398
|
+
download,
|
399
|
+
module_name,
|
400
|
+
ignore_errors,
|
401
|
+
alt_sample_id,
|
402
|
+
project_id,
|
403
|
+
sample_ids
|
404
|
+
):
|
383
405
|
"""Download fastq files from a GeoSeeq project.
|
384
406
|
|
385
407
|
This command will download fastq files from a GeoSeeq project. You can filter
|
@@ -401,6 +423,10 @@ def cli_download_fastqs(state, cores, target_dir, yes, first, download, module_n
|
|
401
423
|
# Download all fastq files from two samples in "My Org/My Project"
|
402
424
|
$ geoseeq download fastqs "My Org/My Project" S1 S2
|
403
425
|
|
426
|
+
\b
|
427
|
+
# Download all fastq files from a single sample using an alternate sample id called "barcode"
|
428
|
+
$ geoseeq download fastqs 'MetaSUB Consortium/Cell Paper' 235183938 --alt-sample-id barcode
|
429
|
+
|
404
430
|
---
|
405
431
|
|
406
432
|
Command Arguments:
|
@@ -422,7 +448,7 @@ def cli_download_fastqs(state, cores, target_dir, yes, first, download, module_n
|
|
422
448
|
samples = []
|
423
449
|
if sample_ids:
|
424
450
|
logger.info(f"Fetching info for {len(sample_ids)} samples.")
|
425
|
-
samples = handle_multiple_sample_ids(knex, sample_ids, proj=proj)
|
451
|
+
samples = handle_multiple_sample_ids(knex, sample_ids, proj=proj, alternate_id_col=alt_sample_id)
|
426
452
|
else:
|
427
453
|
logger.info("Fetching info for all samples in project.")
|
428
454
|
samples = proj.get_samples()
|
@@ -54,7 +54,7 @@ def version():
|
|
54
54
|
Use of this tool implies acceptance of the GeoSeeq End User License Agreement.
|
55
55
|
Run `geoseeq eula show` to view the EULA.
|
56
56
|
"""
|
57
|
-
click.echo('0.6.
|
57
|
+
click.echo('0.6.9') # remember to update pyproject.toml
|
58
58
|
|
59
59
|
|
60
60
|
@main.group('advanced')
|
@@ -133,7 +133,30 @@ def handle_folder_id(knex, folder_id, yes=False, private=True, create=True):
|
|
133
133
|
raise ValueError('sample_folder_id must be a UUID, an organization name and project name, or a GRN')
|
134
134
|
|
135
135
|
|
136
|
-
def
|
136
|
+
def map_alternate_ids_to_uuids(proj, alternate_id_col, sample_ids):
|
137
|
+
"""Return a list of sample UUIDs
|
138
|
+
|
139
|
+
`proj` is a project object
|
140
|
+
`alternate_id_col` is the name of the column containing alternate IDs
|
141
|
+
`sample_ids` is a list of alternate IDs
|
142
|
+
"""
|
143
|
+
metadata = proj.get_sample_metadata()
|
144
|
+
if alternate_id_col not in metadata:
|
145
|
+
raise ValueError(f'Column "{alternate_id_col}" not found in project metadata')
|
146
|
+
alt_col_df = metadata[["uuid", alternate_id_col]]
|
147
|
+
# filter to the alt ids in our list- it is possible alt_id_col as a whole is not
|
148
|
+
# unique but that our list of alt ids is
|
149
|
+
alt_col_df = alt_col_df[alt_col_df[alternate_id_col].isin(sample_ids)]
|
150
|
+
if alt_col_df.shape[0] == 0:
|
151
|
+
raise ValueError(f'No samples found with the given alternate IDs in list')
|
152
|
+
if alt_col_df.shape[0] < len(sample_ids):
|
153
|
+
raise ValueError(f'Not all alternate IDs in list are found')
|
154
|
+
if alt_col_df.shape[0] > len(sample_ids):
|
155
|
+
raise ValueError(f'More than one sample found with the same alternate ID')
|
156
|
+
return list(alt_col_df['uuid'])
|
157
|
+
|
158
|
+
|
159
|
+
def handle_multiple_sample_ids(knex, sample_ids, proj=None, alternate_id_col=None):
|
137
160
|
"""Return a list of fetched sample objects
|
138
161
|
|
139
162
|
`sample_ids` may have three different structures:
|
@@ -144,7 +167,9 @@ def handle_multiple_sample_ids(knex, sample_ids, proj=None):
|
|
144
167
|
Any sample may in fact be a file containing sample IDs, in which case the file will be read line by line
|
145
168
|
and each element will be a sample ID
|
146
169
|
|
147
|
-
If `
|
170
|
+
If `proj` is provided then `alternate_id_col` may also be provided.
|
171
|
+
If so then alternate IDs will be used to fetch samples. If alternate ids are
|
172
|
+
not present or not unique then fail.
|
148
173
|
"""
|
149
174
|
project_as_arg = bool(proj)
|
150
175
|
if proj or (proj := el_is_project_id(knex, sample_ids[0])):
|
@@ -155,7 +180,10 @@ def handle_multiple_sample_ids(knex, sample_ids, proj=None):
|
|
155
180
|
return list(proj.get_samples(cache=False))
|
156
181
|
else:
|
157
182
|
samples = []
|
158
|
-
|
183
|
+
sample_ids = flatten_list_of_els_and_files(sample_ids)
|
184
|
+
if alternate_id_col:
|
185
|
+
sample_ids = map_alternate_ids_to_uuids(proj, alternate_id_col, sample_ids)
|
186
|
+
for el in sample_ids:
|
159
187
|
if is_grn_or_uuid(el):
|
160
188
|
el = el.split(':')[-1]
|
161
189
|
samples.append(sample_from_uuid(knex, el))
|
@@ -256,9 +256,14 @@ class Project(RemoteObject):
|
|
256
256
|
|
257
257
|
def get_sample_metadata(self):
|
258
258
|
"""Return a pandas dataframe with sample metadata."""
|
259
|
-
url = f"sample_groups/{self.uuid}/
|
260
|
-
|
261
|
-
|
259
|
+
url = f"sample_groups/{self.uuid}/samples-list?page=1&page_size=500&&"
|
260
|
+
rows = []
|
261
|
+
while url:
|
262
|
+
blob = self.knex.get(url)
|
263
|
+
rows.extend(blob["results"])
|
264
|
+
url = blob["next"]
|
265
|
+
return pd.DataFrame(rows)
|
266
|
+
|
262
267
|
|
263
268
|
@property
|
264
269
|
def n_samples(self):
|
@@ -16,11 +16,19 @@ logger.addHandler(logging.NullHandler()) # No output unless configured by calli
|
|
16
16
|
def load_auth_profile(profile=""):
|
17
17
|
"""Return an endpoit and a token"""
|
18
18
|
profile = profile or "__default__"
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
try:
|
20
|
+
with open(PROFILES_PATH, "r") as f:
|
21
|
+
profiles = json.load(f)
|
22
|
+
if profile in profiles:
|
23
|
+
return profiles[profile]["endpoint"], profiles[profile]["token"]
|
24
|
+
raise KeyError(f"Profile {profile} not found.")
|
25
|
+
except FileNotFoundError:
|
26
|
+
endpoint, token = environ.get("GEOSEEQ_ENDPOINT", DEFAULT_ENDPOINT), environ.get("GEOSEEQ_API_TOKEN", None)
|
27
|
+
if token:
|
28
|
+
logger.debug("Using environment variables for authentication.")
|
29
|
+
else:
|
30
|
+
logger.warning("Accessing anonymously, functionality may be limited. Configure profiles or set GEOSEEQ_API_TOKEN to authenticate.")
|
31
|
+
return endpoint, token
|
24
32
|
|
25
33
|
|
26
34
|
def set_profile(token, endpoint=DEFAULT_ENDPOINT, profile="", overwrite=False):
|
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
|
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
|