exprmat 0.1.3__tar.gz → 0.1.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.
- {exprmat-0.1.3 → exprmat-0.1.4}/PKG-INFO +2 -2
- exprmat-0.1.4/exprmat/data/mmu/gencode.tsv.gz +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/__init__.py +10 -10
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/filter.py +2 -2
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reader/experiment.py +27 -5
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reader/matcher.py +113 -3
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat.egg-info/PKG-INFO +2 -2
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat.egg-info/SOURCES.txt +1 -1
- {exprmat-0.1.3 → exprmat-0.1.4}/setup.py +6 -3
- exprmat-0.1.3/exprmat.egg-info/.ipynb_checkpoints/requires-checkpoint.txt +0 -22
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/ansi.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/clustering/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/clustering/leiden.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/clustering/spectral.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/clustering/utils.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/cnv/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/cnv/cnvscore.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/cnv/infercnv.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/configuration.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/delim.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/finders.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/gff.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/hsa/genome.tsv.gz +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/mmu/genome.tsv.gz +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/private.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/data/ranges.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/descriptive/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/descriptive/de.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/descriptive/kde.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/plotting/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/plotting/cnv.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/plotting/de.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/plotting/expression.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/plotting/palettes.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/doublets/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/doublets/composite.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/doublets/scrublet.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/integrate.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/linear.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/normal.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/plot.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/qc.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/sctransform/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/sctransform/estimate.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/sctransform/ksmooth.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/sctransform/residual.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/sctransform/transform.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/sparse.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/preprocessing/uniform.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reader/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reader/metadata.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/__init__.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/forceatlas.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/mde.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/nn.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/pca.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/plot.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/pumap.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/tsne.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/reduction/umap.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat/utils.py +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat.egg-info/dependency_links.txt +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat.egg-info/not-zip-safe +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat.egg-info/requires.txt +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/exprmat.egg-info/top_level.txt +0 -0
- {exprmat-0.1.3 → exprmat-0.1.4}/setup.cfg +0 -0
|
Binary file
|
|
@@ -104,11 +104,11 @@ def highly_variable(
|
|
|
104
104
|
adata.var[dest + '.dispersions.norm'] = df['norm.disp']
|
|
105
105
|
if use_bounds:
|
|
106
106
|
adata.var[dest + '.hvg'] = (
|
|
107
|
-
df['means'] > min_mean &
|
|
108
|
-
df['means'] < max_mean &
|
|
109
|
-
df['norm.disp'] > min_disp &
|
|
110
|
-
df['norm.disp'] < max_disp
|
|
111
|
-
)
|
|
107
|
+
(df['means'] > min_mean) &
|
|
108
|
+
(df['means'] < max_mean) &
|
|
109
|
+
(df['norm.disp'] > min_disp) &
|
|
110
|
+
(df['norm.disp'] < max_disp)
|
|
111
|
+
).tolist()
|
|
112
112
|
|
|
113
113
|
else:
|
|
114
114
|
if n_top_genes > adata.n_vars:
|
|
@@ -129,11 +129,11 @@ def highly_variable(
|
|
|
129
129
|
adata.var[dest + '.dispersions.norm'] = df['norm.disp']
|
|
130
130
|
if use_bounds:
|
|
131
131
|
adata.var[dest + '.hvg'] = (
|
|
132
|
-
df['means'] > min_mean &
|
|
133
|
-
df['means'] < max_mean &
|
|
134
|
-
df['norm.disp'] > min_disp &
|
|
135
|
-
df['norm.disp'] < max_disp
|
|
136
|
-
)
|
|
132
|
+
(df['means'] > min_mean) &
|
|
133
|
+
(df['means'] < max_mean) &
|
|
134
|
+
(df['norm.disp'] > min_disp) &
|
|
135
|
+
(df['norm.disp'] < max_disp)
|
|
136
|
+
).tolist()
|
|
137
137
|
|
|
138
138
|
else:
|
|
139
139
|
if n_top_genes > adata.n_vars:
|
|
@@ -449,7 +449,7 @@ def highly_variable_nb(
|
|
|
449
449
|
|
|
450
450
|
# actually do the normalization
|
|
451
451
|
df["norm.disp"] = (df["dispersions"] - disp_stat["avg"]) / disp_stat["dev"]
|
|
452
|
-
df.index = var.index
|
|
452
|
+
# df.index = var.index
|
|
453
453
|
return df
|
|
454
454
|
|
|
455
455
|
|
|
@@ -477,7 +477,7 @@ def highly_variable_nb_log(
|
|
|
477
477
|
|
|
478
478
|
# actually do the normalization
|
|
479
479
|
df["norm.disp"] = (df["dispersions"] - disp_stat["avg"]) / disp_stat["dev"]
|
|
480
|
-
df.index = var.index
|
|
480
|
+
# df.index = var.index
|
|
481
481
|
return df
|
|
482
482
|
|
|
483
483
|
|
|
@@ -24,7 +24,7 @@ import os
|
|
|
24
24
|
|
|
25
25
|
from exprmat.reader.metadata import metadata, load_metadata
|
|
26
26
|
from exprmat.data.finders import get_genome
|
|
27
|
-
from exprmat.reader.matcher import read_mtx_rna
|
|
27
|
+
from exprmat.reader.matcher import read_mtx_rna, read_h5ad_rna, read_table_rna
|
|
28
28
|
from exprmat.ansi import warning, info, error, red, green
|
|
29
29
|
|
|
30
30
|
|
|
@@ -67,10 +67,31 @@ class experiment:
|
|
|
67
67
|
|
|
68
68
|
if i_mod == 'rna':
|
|
69
69
|
if not 'rna' in self.modalities.keys(): self.modalities['rna'] = {}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
|
|
71
|
+
# we automatically infer from the given location names to select
|
|
72
|
+
# the correct way of loading samples:
|
|
73
|
+
|
|
74
|
+
if i_loc.endswith('.tsv.gz') or i_loc.endswith('.csv.gz') or \
|
|
75
|
+
i_loc.endswith('.tsv') or i_loc.endswith('.csv'):
|
|
76
|
+
|
|
77
|
+
self.modalities['rna'][i_sample] = read_table_rna(
|
|
78
|
+
src = i_loc, metadata = meta, sample = i_sample,
|
|
79
|
+
raw = False, default_taxa = i_taxa
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
elif i_loc.endswith('.h5') or i_loc.endswith('.h5ad'):
|
|
83
|
+
|
|
84
|
+
self.modalities['rna'][i_sample] = read_h5ad_rna(
|
|
85
|
+
src = i_loc, metadata = meta, sample = i_sample,
|
|
86
|
+
raw = False, default_taxa = i_taxa
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
else:
|
|
90
|
+
self.modalities['rna'][i_sample] = read_mtx_rna(
|
|
91
|
+
src = i_loc, prefix = '', metadata = meta, sample = i_sample,
|
|
92
|
+
raw = False, default_taxa = i_taxa
|
|
93
|
+
)
|
|
94
|
+
|
|
74
95
|
self.modalities['rna'][i_sample].var = \
|
|
75
96
|
experiment.search_genes(self.modalities['rna'][i_sample].var_names.tolist())
|
|
76
97
|
|
|
@@ -612,6 +633,7 @@ class experiment:
|
|
|
612
633
|
orig = adata.obs[cluster_key].tolist()
|
|
613
634
|
merge = [x if x not in clusters else y.replace(',', '.') for x, y in zip(orig, temp)]
|
|
614
635
|
del adata.obs['.leiden.temp']
|
|
636
|
+
del adata.uns['.leiden.temp']
|
|
615
637
|
adata.obs[key_added] = merge
|
|
616
638
|
|
|
617
639
|
# for all categorical types:
|
|
@@ -230,9 +230,116 @@ def read_mtx_rna(
|
|
|
230
230
|
return final
|
|
231
231
|
|
|
232
232
|
|
|
233
|
+
def read_table_rna(
|
|
234
|
+
src: str,
|
|
235
|
+
metadata: metadata, sample: str, raw: bool = False,
|
|
236
|
+
default_taxa = 'mmu'
|
|
237
|
+
):
|
|
238
|
+
'''
|
|
239
|
+
Read from compressed or plain text tables.
|
|
240
|
+
|
|
241
|
+
Parameters
|
|
242
|
+
----------
|
|
243
|
+
|
|
244
|
+
src : str
|
|
245
|
+
The directory to the matrix.
|
|
246
|
+
|
|
247
|
+
metadata : exprmat.reader.metadata.metadata
|
|
248
|
+
The sample specific metadata table.
|
|
249
|
+
|
|
250
|
+
sample : str
|
|
251
|
+
The sample name according to the metadata.
|
|
252
|
+
|
|
253
|
+
raw : bool
|
|
254
|
+
Whether this expression matrix is confirmed to be unfiltered one. Unfiltered expression
|
|
255
|
+
matrix contains all detected beads or droplets, including the empty drops and doublets
|
|
256
|
+
at higher probabilities. We guess this field by default to see if a sample contains
|
|
257
|
+
unexpectedly high number of cells.
|
|
258
|
+
'''
|
|
259
|
+
|
|
260
|
+
# try:
|
|
261
|
+
|
|
262
|
+
# in csv/tsv texts, genes are rows and cells are columns.
|
|
263
|
+
adata = sc.read_text(
|
|
264
|
+
src, delimiter = '\t', first_column_names = True, dtype = 'float32'
|
|
265
|
+
).T
|
|
266
|
+
|
|
267
|
+
# except Exception as ex:
|
|
268
|
+
# warning('error occurs when reading matrix files:')
|
|
269
|
+
# warning(str(ex))
|
|
270
|
+
# return None
|
|
271
|
+
|
|
272
|
+
final = match_matrix_rna(
|
|
273
|
+
adata, metadata, sample,
|
|
274
|
+
force_filter = raw, default_taxa = default_taxa
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
del adata
|
|
278
|
+
return final
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def read_h5ad_rna(
|
|
282
|
+
src: str,
|
|
283
|
+
metadata: metadata, sample: str, raw: bool = False,
|
|
284
|
+
default_taxa = 'mmu'
|
|
285
|
+
):
|
|
286
|
+
'''
|
|
287
|
+
Read from a given h5ad. This typically occurs when you have to prepare the data yourself
|
|
288
|
+
from others who give you a complex atlas. The assignment of samples and batches happens
|
|
289
|
+
within a single h5ad file. Then, you would like to keep nearly all of the metadata you
|
|
290
|
+
prepared by hand as it is. Only `modality`, `taxa` and `ubc` are generated for you.
|
|
291
|
+
|
|
292
|
+
Thus, you must manually supply `sample`, `batch` and `group` yourself. Otherwise the program
|
|
293
|
+
may not work as usual. It permits multiple samples in one h5ad file.
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
|
|
298
|
+
src : str
|
|
299
|
+
The directory to the matrix.
|
|
300
|
+
|
|
301
|
+
prefix : str
|
|
302
|
+
Prefix before the file name convention.
|
|
303
|
+
|
|
304
|
+
metadata : exprmat.reader.metadata.metadata
|
|
305
|
+
The sample specific metadata table.
|
|
306
|
+
|
|
307
|
+
sample : str
|
|
308
|
+
The sample name according to the metadata.
|
|
309
|
+
|
|
310
|
+
raw : bool
|
|
311
|
+
Whether this expression matrix is confirmed to be unfiltered one. Unfiltered expression
|
|
312
|
+
matrix contains all detected beads or droplets, including the empty drops and doublets
|
|
313
|
+
at higher probabilities. We guess this field by default to see if a sample contains
|
|
314
|
+
unexpectedly high number of cells.
|
|
315
|
+
'''
|
|
316
|
+
|
|
317
|
+
# try:
|
|
318
|
+
|
|
319
|
+
adata = sc.read_h5ad(src)
|
|
320
|
+
|
|
321
|
+
# except Exception as ex:
|
|
322
|
+
# warning('error occurs when reading matrix files:')
|
|
323
|
+
# warning(str(ex))
|
|
324
|
+
# return None
|
|
325
|
+
|
|
326
|
+
final = match_matrix_rna(
|
|
327
|
+
adata, metadata, sample,
|
|
328
|
+
force_filter = raw, default_taxa = default_taxa,
|
|
329
|
+
# this switch tells the program not to alter the cell names (keep them
|
|
330
|
+
# directly to `barcodes`, not adding prefix to them), and keep the
|
|
331
|
+
# sample, batch, and group columns as is.
|
|
332
|
+
do_not_alter_obs_names = True
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
del adata
|
|
336
|
+
return final
|
|
337
|
+
|
|
338
|
+
|
|
233
339
|
def match_matrix_rna(
|
|
234
340
|
adata, metadata: metadata, sample: str,
|
|
235
|
-
force_filter = False, default_taxa = 'mmu'
|
|
341
|
+
force_filter = False, default_taxa = 'mmu',
|
|
342
|
+
do_not_alter_obs_names = False
|
|
236
343
|
):
|
|
237
344
|
|
|
238
345
|
# if more than 50000 cells in a single matrix, we just believe that it is
|
|
@@ -249,8 +356,9 @@ def match_matrix_rna(
|
|
|
249
356
|
assert len(rows) == 1
|
|
250
357
|
props = rows.iloc[0]
|
|
251
358
|
|
|
252
|
-
|
|
253
|
-
|
|
359
|
+
if not do_not_alter_obs_names:
|
|
360
|
+
# append the sample name to the barcode
|
|
361
|
+
adata_f.obs_names = props['sample'] + ':' + adata_f.obs_names
|
|
254
362
|
|
|
255
363
|
# map gene naming
|
|
256
364
|
gname = adata_f.var_names.tolist()
|
|
@@ -320,6 +428,8 @@ def match_matrix_rna(
|
|
|
320
428
|
# attach cell metadata onto the obs slot.
|
|
321
429
|
|
|
322
430
|
for k in props.index.tolist():
|
|
431
|
+
if do_not_alter_obs_names:
|
|
432
|
+
if k in ['sample', 'batch', 'group']: continue
|
|
323
433
|
if k not in ['location']: final.obs[k] = props[k]
|
|
324
434
|
|
|
325
435
|
final.obs['barcode'] = final.obs_names
|
|
@@ -9,7 +9,6 @@ exprmat.egg-info/dependency_links.txt
|
|
|
9
9
|
exprmat.egg-info/not-zip-safe
|
|
10
10
|
exprmat.egg-info/requires.txt
|
|
11
11
|
exprmat.egg-info/top_level.txt
|
|
12
|
-
exprmat.egg-info/.ipynb_checkpoints/requires-checkpoint.txt
|
|
13
12
|
exprmat/clustering/__init__.py
|
|
14
13
|
exprmat/clustering/leiden.py
|
|
15
14
|
exprmat/clustering/spectral.py
|
|
@@ -24,6 +23,7 @@ exprmat/data/gff.py
|
|
|
24
23
|
exprmat/data/private.py
|
|
25
24
|
exprmat/data/ranges.py
|
|
26
25
|
exprmat/data/hsa/genome.tsv.gz
|
|
26
|
+
exprmat/data/mmu/gencode.tsv.gz
|
|
27
27
|
exprmat/data/mmu/genome.tsv.gz
|
|
28
28
|
exprmat/descriptive/__init__.py
|
|
29
29
|
exprmat/descriptive/de.py
|
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
|
|
|
3
3
|
|
|
4
4
|
setup(
|
|
5
5
|
name = 'exprmat',
|
|
6
|
-
version = '0.1.
|
|
6
|
+
version = '0.1.4',
|
|
7
7
|
description = 'routines to process expression matrices',
|
|
8
8
|
url = 'https://github.com/yang-z-03/exprmat',
|
|
9
9
|
author = 'Zheng Yang',
|
|
@@ -34,9 +34,12 @@ setup(
|
|
|
34
34
|
'pynndescent',
|
|
35
35
|
'gseapy'
|
|
36
36
|
],
|
|
37
|
-
include_package_data =
|
|
37
|
+
include_package_data = False,
|
|
38
38
|
package_data = {
|
|
39
|
-
'exprmat.data': [
|
|
39
|
+
'exprmat.data': [
|
|
40
|
+
'mmu/*.tsv.gz',
|
|
41
|
+
'hsa/*.tsv.gz'
|
|
42
|
+
]
|
|
40
43
|
},
|
|
41
44
|
zip_safe = False
|
|
42
45
|
)
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
umap-learn>=0.5.0
|
|
2
|
-
scvi-tools>=1.3.0
|
|
3
|
-
scanpy
|
|
4
|
-
anndata
|
|
5
|
-
mudata
|
|
6
|
-
pandas
|
|
7
|
-
numpy
|
|
8
|
-
matplotlib
|
|
9
|
-
seaborn
|
|
10
|
-
torch>=2.0
|
|
11
|
-
annoy
|
|
12
|
-
scikit-image
|
|
13
|
-
scikit-misc
|
|
14
|
-
igraph
|
|
15
|
-
bbknn
|
|
16
|
-
scanorama
|
|
17
|
-
harmonypy
|
|
18
|
-
pymde
|
|
19
|
-
datashader
|
|
20
|
-
fa2_modified
|
|
21
|
-
pynndescent
|
|
22
|
-
gseapy
|
|
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
|