toolsos 0.3.2__tar.gz → 0.4.0__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.
- {toolsos-0.3.2 → toolsos-0.4.0}/PKG-INFO +2 -2
- {toolsos-0.3.2 → toolsos-0.4.0}/pyproject.toml +7 -13
- toolsos-0.4.0/src/toolsos/huisstijl/tables/table_helpers.py +76 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/tables/table_styles.py +18 -4
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/tables/tables.py +12 -2
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos.egg-info/PKG-INFO +2 -2
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos.egg-info/SOURCES.txt +1 -2
- toolsos-0.3.2/src/toolsos/huisstijl/tables/table_helpers.py +0 -76
- toolsos-0.3.2/tests/test_tables.py +0 -56
- {toolsos-0.3.2 → toolsos-0.4.0}/README.md +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/setup.cfg +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/__init__.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/cbs_tools.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/create_tables.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/database/database_connection.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/database/database_transfer.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/download.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/geo.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/helpers.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/__init__.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/colors.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/graphs/__init__.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/graphs/bargraph.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/graphs/graph_styles.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/graphs/linegraph.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/graphs/piegraph.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/graphs/styler.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/maps/__init__.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/maps/choropleth.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/huisstijl/tables/__init__.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos/polars_helpers.py +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos.egg-info/dependency_links.txt +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos.egg-info/requires.txt +0 -0
- {toolsos-0.3.2 → toolsos-0.4.0}/src/toolsos.egg-info/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: toolsos
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: OS tools
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Daan Schmitz <d.schmitz@amsterdam.nl>
|
|
6
6
|
Keywords: tools,Onderzoek & Statistiek
|
|
7
7
|
Classifier: License :: OSI Approved :: MIT License
|
|
8
8
|
Classifier: Programming Language :: Python
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# pyproject.toml
|
|
2
2
|
|
|
3
3
|
[build-system]
|
|
4
|
-
requires
|
|
4
|
+
requires = ["setuptools>=61.0.0", "wheel"]
|
|
5
5
|
build-backend = "setuptools.build_meta"
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "toolsos"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.4.0"
|
|
10
10
|
description = "OS tools"
|
|
11
11
|
readme = "README.md"
|
|
12
|
-
authors = [{ name = "
|
|
12
|
+
authors = [{ name = "Daan Schmitz", email = "d.schmitz@amsterdam.nl" }]
|
|
13
13
|
|
|
14
14
|
# license = { file = "LICENSE" }
|
|
15
15
|
|
|
@@ -28,17 +28,11 @@ dependencies = []
|
|
|
28
28
|
requires-python = ">=3.10"
|
|
29
29
|
|
|
30
30
|
[project.optional-dependencies]
|
|
31
|
-
dev = [
|
|
32
|
-
"black",
|
|
33
|
-
"bumpver",
|
|
34
|
-
"isort",
|
|
35
|
-
"pip-tools",
|
|
36
|
-
"pytest"
|
|
37
|
-
]
|
|
31
|
+
dev = ["black", "bumpver", "isort", "pip-tools", "pytest"]
|
|
38
32
|
|
|
39
33
|
all = [
|
|
40
34
|
"keyring",
|
|
41
|
-
"openpyxl",
|
|
35
|
+
"openpyxl",
|
|
42
36
|
"pandas",
|
|
43
37
|
"plotly",
|
|
44
38
|
"polars",
|
|
@@ -48,8 +42,8 @@ all = [
|
|
|
48
42
|
"requests",
|
|
49
43
|
"sqlalchemy",
|
|
50
44
|
"geopandas",
|
|
51
|
-
"ipykernel"
|
|
52
|
-
|
|
45
|
+
"ipykernel",
|
|
46
|
+
]
|
|
53
47
|
|
|
54
48
|
# [project.urls]
|
|
55
49
|
#Homepage = ""
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# from pathlib import Path
|
|
2
|
+
|
|
3
|
+
# import pandas as pd
|
|
4
|
+
# import win32com.client as win32
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# def remove_underscores_from_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
8
|
+
# df.columns = df.columns.str.replace("_", " ")
|
|
9
|
+
# return df
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# def get_excel_files_from_folder(folder: str) -> list[str]:
|
|
13
|
+
# return [str(f.resolve()) for f in Path(folder).glob("*") if f.suffix == ".xlsx"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# def combine_excel_files(out_path: str, files: list[str] = None, overwrite: bool = True):
|
|
17
|
+
# out_path = Path(out_path)
|
|
18
|
+
|
|
19
|
+
# if overwrite:
|
|
20
|
+
# if out_path.exists():
|
|
21
|
+
# out_path.unlink()
|
|
22
|
+
|
|
23
|
+
# # INITIALIZE EXCEL COM APP
|
|
24
|
+
# try:
|
|
25
|
+
# xlapp = win32.gencache.EnsureDispatch("Excel.Application")
|
|
26
|
+
|
|
27
|
+
# # constants
|
|
28
|
+
# xlPasteValues = -4163
|
|
29
|
+
# lPasteFormats = -4122
|
|
30
|
+
# xlWorkbookDefault = 51
|
|
31
|
+
|
|
32
|
+
# # create new workbook
|
|
33
|
+
# new_wb = xlapp.Workbooks.Add()
|
|
34
|
+
# new_wb.SaveAs(Filename=str(out_path), FileFormat=xlWorkbookDefault)
|
|
35
|
+
|
|
36
|
+
# dup_count = 1
|
|
37
|
+
|
|
38
|
+
# for wb in files:
|
|
39
|
+
# xlwb = xlapp.Workbooks.Open(wb)
|
|
40
|
+
|
|
41
|
+
# for xlsh in xlwb.Worksheets:
|
|
42
|
+
# new_sh = new_wb.Worksheets.Add()
|
|
43
|
+
|
|
44
|
+
# try:
|
|
45
|
+
# new_sh.Name = xlsh.Name
|
|
46
|
+
|
|
47
|
+
# # Ugly non defined exception. Be aware that this wil caputre
|
|
48
|
+
# except Exception as e:
|
|
49
|
+
# new_sh.Name = f"{xlsh.Name}_{dup_count}"
|
|
50
|
+
# dup_count += 1
|
|
51
|
+
|
|
52
|
+
# new_wb.Save()
|
|
53
|
+
# new_sh.Move(After=new_wb.Worksheets(new_wb.Worksheets.Count))
|
|
54
|
+
|
|
55
|
+
# xlsh.Cells.Copy(new_sh.Cells)
|
|
56
|
+
# new_sh = None
|
|
57
|
+
|
|
58
|
+
# xlwb.Close(True)
|
|
59
|
+
# xlwb = None
|
|
60
|
+
|
|
61
|
+
# # remove default blad1
|
|
62
|
+
# new_wb.Worksheets("Blad1").Delete()
|
|
63
|
+
# new_wb.Save()
|
|
64
|
+
|
|
65
|
+
# except Exception as e:
|
|
66
|
+
# print(e)
|
|
67
|
+
|
|
68
|
+
# # RELEASE RESOURCES
|
|
69
|
+
# finally:
|
|
70
|
+
# xlsh = None
|
|
71
|
+
# new_sh = None
|
|
72
|
+
# xlwb = None
|
|
73
|
+
# new_wb = None
|
|
74
|
+
# xlapp.Quit()
|
|
75
|
+
# xlapp = None
|
|
76
|
+
# xlwb = None
|
|
@@ -7,13 +7,20 @@ STYLE_OLD = {
|
|
|
7
7
|
"fill": {"fill_type": "solid", "fgColor": "B1D9F5"},
|
|
8
8
|
"font": {"bold": False},
|
|
9
9
|
},
|
|
10
|
-
"calibri": {
|
|
10
|
+
"calibri": {
|
|
11
|
+
"font": {"name": "Calibri", "size": 9},
|
|
12
|
+
# "alignment": {"vertical": "center"},
|
|
13
|
+
},
|
|
11
14
|
"blue_border_bottom": {
|
|
12
15
|
"border_bottom": {"color": "00a0e6", "border_style": "medium"}
|
|
13
16
|
},
|
|
14
17
|
"left_align": {"alignment": {"horizontal": "left"}, "font": {"bold": False}},
|
|
15
18
|
"right_align": {"alignment": {"horizontal": "right"}},
|
|
16
|
-
"title_bold": {
|
|
19
|
+
"title_bold": {
|
|
20
|
+
"font": {"bold": True, "name": "Calibri", "size": 9},
|
|
21
|
+
"alignment": {"vertical": "center"},
|
|
22
|
+
},
|
|
23
|
+
"vert_align_middle": {"alignment": {"vertical": "center"}},
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
STYLE_NEW = {
|
|
@@ -25,11 +32,18 @@ STYLE_NEW = {
|
|
|
25
32
|
"fill": {"fill_type": "solid", "fgColor": "b8bcdd"},
|
|
26
33
|
"font": {"bold": True},
|
|
27
34
|
},
|
|
28
|
-
"calibri": {
|
|
35
|
+
"calibri": {
|
|
36
|
+
"font": {"name": "Calibri", "size": 9},
|
|
37
|
+
"alignment": {"vertical": "center"},
|
|
38
|
+
},
|
|
29
39
|
"blue_border_bottom": {
|
|
30
40
|
"border_bottom": {"color": "004699", "border_style": "medium"}
|
|
31
41
|
},
|
|
32
42
|
"left_align": {"alignment": {"horizontal": "left"}, "font": {"bold": True}},
|
|
33
43
|
"right_align": {"alignment": {"horizontal": "right"}},
|
|
34
|
-
"title_bold": {
|
|
44
|
+
"title_bold": {
|
|
45
|
+
"font": {"bold": True, "name": "Calibri", "size": 9},
|
|
46
|
+
# "alignment": {"vertical": "center"},
|
|
47
|
+
},
|
|
48
|
+
"vert_align_middle": {"alignment": {"vertical": "center"}},
|
|
35
49
|
}
|
|
@@ -322,6 +322,7 @@ def cell_formatting(
|
|
|
322
322
|
float_col_format: str | None = None,
|
|
323
323
|
blue_border_ids: bool | None = None,
|
|
324
324
|
number_format: str | None = None,
|
|
325
|
+
middle_vertical_aligment: list = None,
|
|
325
326
|
):
|
|
326
327
|
"""Function to create the nested list with the shape of the input data (including columns)
|
|
327
328
|
containing dictionaries with the formatting
|
|
@@ -382,6 +383,9 @@ def cell_formatting(
|
|
|
382
383
|
if blue_border_ids:
|
|
383
384
|
fmt = set_style_row(fmt, blue_border_ids, STYLES["blue_border_bottom"])
|
|
384
385
|
|
|
386
|
+
if middle_vertical_aligment:
|
|
387
|
+
fmt = set_style_row(fmt, middle_vertical_aligment, STYLES["vert_align_middle"])
|
|
388
|
+
|
|
385
389
|
return fmt
|
|
386
390
|
|
|
387
391
|
|
|
@@ -521,7 +525,7 @@ def write_table(
|
|
|
521
525
|
column_widths: list[int] | None = None,
|
|
522
526
|
min_column_width: int | None = None,
|
|
523
527
|
col_filter: bool | None = False,
|
|
524
|
-
style: str = "
|
|
528
|
+
style: str = "new",
|
|
525
529
|
combine_multiindex: bool | int = False,
|
|
526
530
|
column_names_to_string: bool = True,
|
|
527
531
|
):
|
|
@@ -733,7 +737,7 @@ def format_worksheet(
|
|
|
733
737
|
r_align_ids.extend(pr_id)
|
|
734
738
|
|
|
735
739
|
if float_ids:
|
|
736
|
-
|
|
740
|
+
f_ids.extend(float_ids)
|
|
737
741
|
|
|
738
742
|
if float_pattern:
|
|
739
743
|
fr_id = get_cols_id_with_pattern(df, float_pattern)
|
|
@@ -772,6 +776,11 @@ def format_worksheet(
|
|
|
772
776
|
else:
|
|
773
777
|
col_widths = None
|
|
774
778
|
|
|
779
|
+
# The top row of a table should be bottom aligned vertically. The rest of the table
|
|
780
|
+
# should vertically be aligned in the middle. If there is a title row the alignment
|
|
781
|
+
# needs to be shifted on row
|
|
782
|
+
row_vert_middle = [i for i in range(1, arr.shape[0] + 1)]
|
|
783
|
+
|
|
775
784
|
ws = wb.create_sheet(sheet_name)
|
|
776
785
|
|
|
777
786
|
fmt = cell_formatting(
|
|
@@ -788,6 +797,7 @@ def format_worksheet(
|
|
|
788
797
|
float_col_format=float_col_format,
|
|
789
798
|
number_format=number_format,
|
|
790
799
|
blue_border_ids=blue_border_ids,
|
|
800
|
+
middle_vertical_aligment=row_vert_middle,
|
|
791
801
|
)
|
|
792
802
|
|
|
793
803
|
write_to_worksheet(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: toolsos
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: OS tools
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Daan Schmitz <d.schmitz@amsterdam.nl>
|
|
6
6
|
Keywords: tools,Onderzoek & Statistiek
|
|
7
7
|
Classifier: License :: OSI Approved :: MIT License
|
|
8
8
|
Classifier: Programming Language :: Python
|
|
@@ -27,5 +27,4 @@ src/toolsos/huisstijl/maps/choropleth.py
|
|
|
27
27
|
src/toolsos/huisstijl/tables/__init__.py
|
|
28
28
|
src/toolsos/huisstijl/tables/table_helpers.py
|
|
29
29
|
src/toolsos/huisstijl/tables/table_styles.py
|
|
30
|
-
src/toolsos/huisstijl/tables/tables.py
|
|
31
|
-
tests/test_tables.py
|
|
30
|
+
src/toolsos/huisstijl/tables/tables.py
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
import pandas as pd
|
|
4
|
-
import win32com.client as win32
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def remove_underscores_from_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
8
|
-
df.columns = df.columns.str.replace("_", " ")
|
|
9
|
-
return df
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def get_excel_files_from_folder(folder: str) -> list[str]:
|
|
13
|
-
return [str(f.resolve()) for f in Path(folder).glob("*") if f.suffix == ".xlsx"]
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def combine_excel_files(out_path: str, files: list[str] = None, overwrite: bool = True):
|
|
17
|
-
out_path = Path(out_path)
|
|
18
|
-
|
|
19
|
-
if overwrite:
|
|
20
|
-
if out_path.exists():
|
|
21
|
-
out_path.unlink()
|
|
22
|
-
|
|
23
|
-
# INITIALIZE EXCEL COM APP
|
|
24
|
-
try:
|
|
25
|
-
xlapp = win32.gencache.EnsureDispatch("Excel.Application")
|
|
26
|
-
|
|
27
|
-
# constants
|
|
28
|
-
xlPasteValues = -4163
|
|
29
|
-
lPasteFormats = -4122
|
|
30
|
-
xlWorkbookDefault = 51
|
|
31
|
-
|
|
32
|
-
# create new workbook
|
|
33
|
-
new_wb = xlapp.Workbooks.Add()
|
|
34
|
-
new_wb.SaveAs(Filename=str(out_path), FileFormat=xlWorkbookDefault)
|
|
35
|
-
|
|
36
|
-
dup_count = 1
|
|
37
|
-
|
|
38
|
-
for wb in files:
|
|
39
|
-
xlwb = xlapp.Workbooks.Open(wb)
|
|
40
|
-
|
|
41
|
-
for xlsh in xlwb.Worksheets:
|
|
42
|
-
new_sh = new_wb.Worksheets.Add()
|
|
43
|
-
|
|
44
|
-
try:
|
|
45
|
-
new_sh.Name = xlsh.Name
|
|
46
|
-
|
|
47
|
-
# Ugly non defined exception. Be aware that this wil caputre
|
|
48
|
-
except Exception as e:
|
|
49
|
-
new_sh.Name = f"{xlsh.Name}_{dup_count}"
|
|
50
|
-
dup_count += 1
|
|
51
|
-
|
|
52
|
-
new_wb.Save()
|
|
53
|
-
new_sh.Move(After=new_wb.Worksheets(new_wb.Worksheets.Count))
|
|
54
|
-
|
|
55
|
-
xlsh.Cells.Copy(new_sh.Cells)
|
|
56
|
-
new_sh = None
|
|
57
|
-
|
|
58
|
-
xlwb.Close(True)
|
|
59
|
-
xlwb = None
|
|
60
|
-
|
|
61
|
-
# remove default blad1
|
|
62
|
-
new_wb.Worksheets("Blad1").Delete()
|
|
63
|
-
new_wb.Save()
|
|
64
|
-
|
|
65
|
-
except Exception as e:
|
|
66
|
-
print(e)
|
|
67
|
-
|
|
68
|
-
# RELEASE RESOURCES
|
|
69
|
-
finally:
|
|
70
|
-
xlsh = None
|
|
71
|
-
new_sh = None
|
|
72
|
-
xlwb = None
|
|
73
|
-
new_wb = None
|
|
74
|
-
xlapp.Quit()
|
|
75
|
-
xlapp = None
|
|
76
|
-
xlwb = None
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import openpyxl
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import pytest
|
|
4
|
-
|
|
5
|
-
from toolsos.huisstijl.tables.tables import write_table, write_table_from_dict
|
|
6
|
-
|
|
7
|
-
DATA = [["Noord", 1, 0.25], ["Zuid", 3, 0.75]]
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
COLUMNS = ["stadsdeel", "bewoners", "perc_bewoners"]
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@pytest.fixture(scope="class")
|
|
14
|
-
def workbook(data=DATA, columns=COLUMNS):
|
|
15
|
-
df1 = pd.DataFrame(data=DATA, columns=COLUMNS)
|
|
16
|
-
|
|
17
|
-
filename = "temp/singe_table.xlsx"
|
|
18
|
-
write_table(
|
|
19
|
-
df1, file=filename, header_row=0, perc_pattern="perc_bewoners", style="new"
|
|
20
|
-
)
|
|
21
|
-
return openpyxl.load_workbook(filename)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class TestTable:
|
|
25
|
-
@pytest.fixture(autouse=True)
|
|
26
|
-
def setup(self, workbook):
|
|
27
|
-
self.workbook = workbook
|
|
28
|
-
self.ws = workbook.active
|
|
29
|
-
|
|
30
|
-
def test_data(self, data=DATA):
|
|
31
|
-
rows = [[c.value for c in row] for row in self.ws.iter_rows(2)]
|
|
32
|
-
|
|
33
|
-
assert all(src == written for src, written in zip(DATA, rows))
|
|
34
|
-
|
|
35
|
-
def test_data_header(self):
|
|
36
|
-
header = [[c.value for c in row] for row in self.ws.iter_rows(2)]
|
|
37
|
-
|
|
38
|
-
assert all(src == written for src, written in zip(DATA, header))
|
|
39
|
-
|
|
40
|
-
def test_background_color_header(self):
|
|
41
|
-
header_color = [
|
|
42
|
-
[c.fill.fgColor.value for c in row] for row in self.ws.iter_rows(max_row=1)
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
assert all([[c == "004699" for c in row] for row in header_color])
|
|
46
|
-
|
|
47
|
-
# def test_text_color_header(self):
|
|
48
|
-
# header_text_color = [[c.font.color.value for in row] in self.ws]
|
|
49
|
-
|
|
50
|
-
def test_formatting(self):
|
|
51
|
-
perc_values = [
|
|
52
|
-
[c.number_format for c in row]
|
|
53
|
-
for row in self.ws.iter_rows(min_row=2, min_col=3)
|
|
54
|
-
]
|
|
55
|
-
|
|
56
|
-
all([[c == "'0.0%'" for c in row] for row in perc_values])
|
|
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
|