librelane 3.0.0.dev27__py3-none-any.whl → 3.0.0.dev28__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.
Potentially problematic release.
This version of librelane might be problematic. Click here for more details.
- librelane/common/__init__.py +1 -1
- librelane/common/metrics/__main__.py +2 -1
- librelane/common/misc.py +18 -6
- librelane/flows/cli.py +2 -2
- librelane/pdk_hashes.yaml +3 -0
- librelane/scripts/klayout/stream_out.py +26 -2
- librelane/scripts/pyosys/json_header.py +1 -1
- librelane/scripts/pyosys/synthesize.py +1 -1
- librelane/steps/klayout.py +14 -1
- librelane/steps/yosys.py +1 -1
- {librelane-3.0.0.dev27.dist-info → librelane-3.0.0.dev28.dist-info}/METADATA +1 -1
- {librelane-3.0.0.dev27.dist-info → librelane-3.0.0.dev28.dist-info}/RECORD +14 -14
- librelane/open_pdks_rev +0 -1
- {librelane-3.0.0.dev27.dist-info → librelane-3.0.0.dev28.dist-info}/WHEEL +0 -0
- {librelane-3.0.0.dev27.dist-info → librelane-3.0.0.dev28.dist-info}/entry_points.txt +0 -0
librelane/common/__init__.py
CHANGED
|
@@ -158,7 +158,8 @@ def _compare_metric_folders(
|
|
|
158
158
|
continue
|
|
159
159
|
basename = basename[: -len(".metrics.json")]
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
# We have to rsplit, since ihp-sg13g2 contains a "-"
|
|
162
|
+
parts = basename.rsplit("-", maxsplit=2)
|
|
162
163
|
if len(parts) != 3:
|
|
163
164
|
raise ValueError(
|
|
164
165
|
f"Invalid filename {basename}: not in the format {{pdk}}-{{scl}}-{{design_name}}"
|
librelane/common/misc.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# Copyright 2025 LibreLane Contributors
|
|
2
|
+
#
|
|
3
|
+
# Adapted from OpenLane
|
|
4
|
+
#
|
|
1
5
|
# Copyright 2023 Efabless Corporation
|
|
2
6
|
#
|
|
3
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -16,6 +20,7 @@ import os
|
|
|
16
20
|
import re
|
|
17
21
|
import glob
|
|
18
22
|
import gzip
|
|
23
|
+
import yaml
|
|
19
24
|
import typing
|
|
20
25
|
import pathlib
|
|
21
26
|
import fnmatch
|
|
@@ -37,6 +42,7 @@ import httpx
|
|
|
37
42
|
|
|
38
43
|
from ..__version__ import __version__
|
|
39
44
|
from .types import AnyPath, Path
|
|
45
|
+
from ..logging import err
|
|
40
46
|
|
|
41
47
|
T = TypeVar("T")
|
|
42
48
|
|
|
@@ -68,15 +74,21 @@ def get_script_dir() -> str:
|
|
|
68
74
|
)
|
|
69
75
|
|
|
70
76
|
|
|
71
|
-
def
|
|
77
|
+
def get_pdk_hash(pdk_variant) -> str:
|
|
72
78
|
"""
|
|
73
|
-
Gets the
|
|
79
|
+
Gets the PDK version hash confirmed compatible with this version of LibreLane.
|
|
74
80
|
"""
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.
|
|
78
|
-
|
|
81
|
+
|
|
82
|
+
with open(os.path.join(get_librelane_root(), "pdk_hashes.yaml"), "r") as file:
|
|
83
|
+
pdk_hashes = yaml.safe_load(file)
|
|
84
|
+
for pdk_family in pdk_hashes:
|
|
85
|
+
if pdk_family in pdk_variant:
|
|
86
|
+
return pdk_hashes[pdk_family]
|
|
87
|
+
|
|
88
|
+
err(
|
|
89
|
+
f"Could not find a PDK family for '{pdk_variant}'. Please specify a PDK manually with '--manual-pdk'."
|
|
79
90
|
)
|
|
91
|
+
exit(1)
|
|
80
92
|
|
|
81
93
|
|
|
82
94
|
# The following code snippet has been adapted under the following license:
|
librelane/flows/cli.py
CHANGED
|
@@ -34,7 +34,7 @@ from cloup.constraints import (
|
|
|
34
34
|
from cloup.typing import Decorator
|
|
35
35
|
|
|
36
36
|
from .flow import Flow
|
|
37
|
-
from ..common import set_tpe, cli,
|
|
37
|
+
from ..common import set_tpe, cli, get_pdk_hash, _get_process_limit
|
|
38
38
|
from ..logging import set_log_level, verbose, err, options, LogLevels
|
|
39
39
|
from ..state import State, InvalidState
|
|
40
40
|
|
|
@@ -421,7 +421,7 @@ def cloup_flow_opts(
|
|
|
421
421
|
import ciel
|
|
422
422
|
from ciel.source import StaticWebDataSource
|
|
423
423
|
|
|
424
|
-
opdks_rev = volare_pdk_override or
|
|
424
|
+
opdks_rev = volare_pdk_override or get_pdk_hash(pdk)
|
|
425
425
|
ciel_home = ciel.get_ciel_home(pdk_root)
|
|
426
426
|
|
|
427
427
|
include_libraries = ["default"]
|
|
@@ -90,6 +90,13 @@ import click
|
|
|
90
90
|
"input",
|
|
91
91
|
type=click.Path(exists=True, file_okay=True, dir_okay=False),
|
|
92
92
|
)
|
|
93
|
+
@click.option(
|
|
94
|
+
"--conflict-resolution",
|
|
95
|
+
"conflict_resolution",
|
|
96
|
+
type=str,
|
|
97
|
+
default="RenameCell",
|
|
98
|
+
help="Cell conflict resolution handling.",
|
|
99
|
+
)
|
|
93
100
|
def stream_out(
|
|
94
101
|
output: str,
|
|
95
102
|
input_lefs: Tuple[str, ...],
|
|
@@ -100,6 +107,7 @@ def stream_out(
|
|
|
100
107
|
seal_gds: Optional[str],
|
|
101
108
|
design_name: str,
|
|
102
109
|
input: str,
|
|
110
|
+
conflict_resolution: str,
|
|
103
111
|
): # Load technology file
|
|
104
112
|
try:
|
|
105
113
|
tech = pya.Technology()
|
|
@@ -109,6 +117,22 @@ def stream_out(
|
|
|
109
117
|
layout_options.lefdef_config.lef_files = list(input_lefs)
|
|
110
118
|
layout_options.lefdef_config.map_file = lym
|
|
111
119
|
|
|
120
|
+
cell_conflict_resolution = {
|
|
121
|
+
"AddToCell": pya.LoadLayoutOptions.CellConflictResolution.AddToCell,
|
|
122
|
+
"OverwriteCell": pya.LoadLayoutOptions.CellConflictResolution.OverwriteCell,
|
|
123
|
+
"RenameCell": pya.LoadLayoutOptions.CellConflictResolution.RenameCell,
|
|
124
|
+
"SkipNewCell": pya.LoadLayoutOptions.CellConflictResolution.SkipNewCell,
|
|
125
|
+
}.get(conflict_resolution)
|
|
126
|
+
|
|
127
|
+
if cell_conflict_resolution is None:
|
|
128
|
+
print(
|
|
129
|
+
f"[ERROR] Unknown conflict resolution: '{conflict_resolution}'.",
|
|
130
|
+
file=sys.stderr,
|
|
131
|
+
)
|
|
132
|
+
exit(1)
|
|
133
|
+
else:
|
|
134
|
+
layout_options.cell_conflict_resolution = cell_conflict_resolution
|
|
135
|
+
|
|
112
136
|
# Load def file
|
|
113
137
|
main_layout = pya.Layout()
|
|
114
138
|
# main_layout.load_layer_props(props_file)
|
|
@@ -126,7 +150,7 @@ def stream_out(
|
|
|
126
150
|
# Load in the gds to merge
|
|
127
151
|
print("[INFO] Merging GDS files…")
|
|
128
152
|
for gds in input_gds_files:
|
|
129
|
-
main_layout.read(gds)
|
|
153
|
+
main_layout.read(gds, layout_options)
|
|
130
154
|
|
|
131
155
|
# Copy the top level only to a new layout
|
|
132
156
|
print(f"[INFO] Copying top level cell '{design_name}'…")
|
|
@@ -138,7 +162,7 @@ def stream_out(
|
|
|
138
162
|
print("[INFO] Checking for missing GDS…")
|
|
139
163
|
missing_gds = False
|
|
140
164
|
for i in top_only_layout.each_cell():
|
|
141
|
-
if i.
|
|
165
|
+
if i.is_ghost_cell():
|
|
142
166
|
missing_gds = True
|
|
143
167
|
print(
|
|
144
168
|
f"[ERROR] LEF Cell '{i.name}' has no matching GDS cell.",
|
|
@@ -227,7 +227,7 @@ def synthesize(
|
|
|
227
227
|
|
|
228
228
|
includes = config.get("VERILOG_INCLUDE_DIRS") or []
|
|
229
229
|
defines = (config.get("VERILOG_DEFINES") or []) + [
|
|
230
|
-
f"PDK_{config['PDK']}",
|
|
230
|
+
f"PDK_{config['PDK'].replace('-','_')}",
|
|
231
231
|
f"SCL_{config['STD_CELL_LIBRARY']}",
|
|
232
232
|
"__librelane__",
|
|
233
233
|
"__pnr__",
|
librelane/steps/klayout.py
CHANGED
|
@@ -24,7 +24,7 @@ import subprocess
|
|
|
24
24
|
from os.path import abspath
|
|
25
25
|
from base64 import b64encode
|
|
26
26
|
from tempfile import NamedTemporaryFile
|
|
27
|
-
from typing import Any, Dict, Optional, List, Sequence, Tuple, Union
|
|
27
|
+
from typing import Any, Dict, Optional, List, Literal, Sequence, Tuple, Union
|
|
28
28
|
|
|
29
29
|
from .step import ViewsUpdate, MetricsUpdate, Step, StepError, StepException
|
|
30
30
|
|
|
@@ -201,6 +201,17 @@ class StreamOut(KLayoutStep):
|
|
|
201
201
|
inputs = [DesignFormat.DEF]
|
|
202
202
|
outputs = [DesignFormat.GDS, DesignFormat.KLAYOUT_GDS]
|
|
203
203
|
|
|
204
|
+
config_vars = KLayoutStep.config_vars + [
|
|
205
|
+
Variable(
|
|
206
|
+
"KLAYOUT_CONFLICT_RESOLUTION",
|
|
207
|
+
Optional[
|
|
208
|
+
Literal["AddToCell", "OverwriteCell", "RenameCell", "SkipNewCell"]
|
|
209
|
+
],
|
|
210
|
+
"Specifies the conflict resolution if a cell name conflict arises.",
|
|
211
|
+
default="RenameCell",
|
|
212
|
+
),
|
|
213
|
+
]
|
|
214
|
+
|
|
204
215
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
205
216
|
views_updates: ViewsUpdate = {}
|
|
206
217
|
|
|
@@ -223,6 +234,8 @@ class StreamOut(KLayoutStep):
|
|
|
223
234
|
abspath(klayout_gds_out),
|
|
224
235
|
"--top",
|
|
225
236
|
self.config["DESIGN_NAME"],
|
|
237
|
+
"--conflict-resolution",
|
|
238
|
+
self.config["KLAYOUT_CONFLICT_RESOLUTION"],
|
|
226
239
|
]
|
|
227
240
|
+ self.get_cli_args(include_lefs=True, include_gds=True),
|
|
228
241
|
env=env,
|
librelane/steps/yosys.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
librelane/__init__.py,sha256=EMpoZrRmS_wsweKjhyAg52OXCK7HWQ8o8CVrYaX4ub0,1220
|
|
2
2
|
librelane/__main__.py,sha256=Zq2h2ZTQqA0T7qpGFELJ1bzVQnv-951nnhJ0-9WzNaM,14541
|
|
3
3
|
librelane/__version__.py,sha256=dbE4stCACDmIoxgKksesAkTa-_hi5dW6nPLWw9Pfq3Q,1486
|
|
4
|
-
librelane/common/__init__.py,sha256=
|
|
4
|
+
librelane/common/__init__.py,sha256=FYBKTUKpAwexQSgCaH_IfbozmDk0hA1ITpl66J8Qcwo,1550
|
|
5
5
|
librelane/common/cli.py,sha256=xi48GBGHRsYrLGwx40ARwpykHx7GnuHbJjHxjOwtZ5Y,2349
|
|
6
6
|
librelane/common/drc.py,sha256=l1quZbHXGb7yjKCO5IFn-Xxf_zIx4f6kxqpNm3YmpOs,12809
|
|
7
7
|
librelane/common/generic_dict.py,sha256=ASa5wtVcLuGlsBqGfLxLYXrYksqQB62iHljV04plIqI,10010
|
|
8
8
|
librelane/common/metrics/__init__.py,sha256=nzdmeia1fN4CDPT604v-OHaBVydz-M4hz232g-jxJ6M,1521
|
|
9
|
-
librelane/common/metrics/__main__.py,sha256=
|
|
9
|
+
librelane/common/metrics/__main__.py,sha256=1w23V_1-f0WUSfxG36ewNHctgPisQFFG4p-R-wZsyNs,12539
|
|
10
10
|
librelane/common/metrics/library.py,sha256=CG7rubLdjuCQL9-9bzAC-64hf-KlH-iu_Fg0oKuesqs,7373
|
|
11
11
|
librelane/common/metrics/metric.py,sha256=h3Xd26z5M80IJgVmmrBTjKcdGLb4I0wyjM-H4jdyi_0,6990
|
|
12
12
|
librelane/common/metrics/util.py,sha256=Bl_9znlot7-Os2VigYLSmMf56aAkGdv3evWz9vfK7K4,9344
|
|
13
|
-
librelane/common/misc.py,sha256=
|
|
13
|
+
librelane/common/misc.py,sha256=vjSfFT2KV5TNTxqeLt5EFqcprRrjrgNvgOJpBl7JpM4,13627
|
|
14
14
|
librelane/common/ring_buffer.py,sha256=DGFen9y0JOmiL7E27tmzDTVSJKZtV-waF9hl5Rz9uek,1898
|
|
15
15
|
librelane/common/tcl.py,sha256=AfTxbSLA0VUXVMMwoAQndyQTcEZQoQfMa4FFizZiEgU,4341
|
|
16
16
|
librelane/common/toolbox.py,sha256=ijR__rVqQ_nJtfm34H-VdSCIeArKns7lVAc1TcTUSsQ,20975
|
|
@@ -42,7 +42,7 @@ librelane/examples/spm-user_project_wrapper/user_project_wrapper.v,sha256=zc6GC5
|
|
|
42
42
|
librelane/flows/__init__.py,sha256=ghtmUG-taVpHJ3CKJRYZGn3dU0r93araT1EIGlBEsxg,896
|
|
43
43
|
librelane/flows/builtins.py,sha256=tR14Qc1ZUey2w-Ar4DWOvxuP7LGPtMecCJq8WgcYJpk,773
|
|
44
44
|
librelane/flows/classic.py,sha256=JB9gVgP2hHPhMuCJg7hvoj2BvJcvRec7suEXPgHmz14,10971
|
|
45
|
-
librelane/flows/cli.py,sha256=
|
|
45
|
+
librelane/flows/cli.py,sha256=_aJjlalCsmUeLiqy1D8VFmBJ0dLelx24erqaK2q-AOs,16706
|
|
46
46
|
librelane/flows/flow.py,sha256=qly_ENbw8zHSS6ubUY56JrCRjKnfuSoN78suz1k4chw,36997
|
|
47
47
|
librelane/flows/misc.py,sha256=32Om3isexesfKKiJZCajNmINc-xdv7eVx_tgoh9SR6U,2015
|
|
48
48
|
librelane/flows/optimizing.py,sha256=OwZz6WGmXpliwO8vtmhjKHD-kzDyNv-zoCECZIigXsI,6076
|
|
@@ -50,14 +50,14 @@ librelane/flows/sequential.py,sha256=kBpR9kxfEfdTaNy9Ter2KNQXkW6qojCwoBsFJBwTq6I
|
|
|
50
50
|
librelane/flows/synth_explore.py,sha256=8mpeuG6oxeEXVQi4NwS4I415eCu7Ak6DN4oK30h1eCQ,7418
|
|
51
51
|
librelane/logging/__init__.py,sha256=mrTnzjpH6AOu2CiDZYfOMCVByAS2Xeg9HS4FJyXsJOE,1043
|
|
52
52
|
librelane/logging/logger.py,sha256=kA61TGsR00Fi6kQSxgTC1pHpS_-zqC1PdQnYqnk2TWY,8632
|
|
53
|
-
librelane/
|
|
53
|
+
librelane/pdk_hashes.yaml,sha256=wHPz6Ze4e1uhZTo7IKS4wcmU6ShcZdBtHcdACP5tYNI,153
|
|
54
54
|
librelane/plugins.py,sha256=G5o2h1LT4a1LO1Q0gKXXuhqcEdjdTFkYU8QUSg2D2eM,820
|
|
55
55
|
librelane/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
56
|
librelane/scripts/base.sdc,sha256=zGPSBLDt-5dbYvm3AGbjsZsyKxjFOc4znyjwZM4wIps,3145
|
|
57
57
|
librelane/scripts/klayout/Readme.md,sha256=hJs44QIB3lHPD3E-Z-tbAC1RBmt5Fl1khzQF2gRewLE,76
|
|
58
58
|
librelane/scripts/klayout/open_design.py,sha256=0cBELVhSBGmp_KxDN0vsCEh6x1JPW0Q6cXkBd3S-XKk,2395
|
|
59
59
|
librelane/scripts/klayout/render.py,sha256=FH-rp7Q363T0gD9_p-n4_suya4hfAPzL2jZIF0fmLwA,3833
|
|
60
|
-
librelane/scripts/klayout/stream_out.py,sha256=
|
|
60
|
+
librelane/scripts/klayout/stream_out.py,sha256=MLpe0oGl7oy2bD4ddk0ixRJgsiBUDzEv_UPwYspgT3s,6796
|
|
61
61
|
librelane/scripts/klayout/xml_drc_report_to_json.py,sha256=6nwTymQ1ypA5OgSvqySxzIWqDgGlW_1tlbtauc0BUdE,1412
|
|
62
62
|
librelane/scripts/klayout/xor.drc,sha256=Nm_6JR_png-31uajL3DrW3dVGo7Kd6G-zS9RTftL25o,3131
|
|
63
63
|
librelane/scripts/magic/Readme.md,sha256=NaQrlxY8l8GT-kokJNlMHeAR3PksWVbFpSznOWWshhw,126
|
|
@@ -141,8 +141,8 @@ librelane/scripts/openroad/ungpl.tcl,sha256=vhHxou1W3VROwJePoQzmWn0h0d5lQrrt1vof
|
|
|
141
141
|
librelane/scripts/openroad/write_cdl.tcl,sha256=uPO1IROPTr5NrW0-VZA8tXQD8aseGeXDXDsU8TX-9nQ,460
|
|
142
142
|
librelane/scripts/openroad/write_views.tcl,sha256=-MxTJsB4EF7l5trDaZe-VBFjhfzqRt8F5_DZrADTs0U,892
|
|
143
143
|
librelane/scripts/pyosys/construct_abc_script.py,sha256=3CCDz5ZTEPpWLco-OvikTmn361-BNitqjQE_-5zHm14,6733
|
|
144
|
-
librelane/scripts/pyosys/json_header.py,sha256=
|
|
145
|
-
librelane/scripts/pyosys/synthesize.py,sha256=
|
|
144
|
+
librelane/scripts/pyosys/json_header.py,sha256=gKla0V4tFhF5fR-zzudrTr6TjpqkV3c69PWk1fVfMgg,2332
|
|
145
|
+
librelane/scripts/pyosys/synthesize.py,sha256=soDbOObGdCix3zDUQFIF6FvZn6_mT_GonkvH5exGQiA,16927
|
|
146
146
|
librelane/scripts/pyosys/ys_common.py,sha256=t5LLEYoy4cfCIeEaAo8Nr51rXtlI8ZPe1h_kSbrky5M,3891
|
|
147
147
|
librelane/scripts/tclsh/hello.tcl,sha256=kkR3akY7QnGHYXsQODYwLkMkUEOgWcNFtzaMTTEV2bY,34
|
|
148
148
|
librelane/state/__init__.py,sha256=DZ_RyKMr2oj4p5d32u8MmDKfCxR7OEdDw-1HWKTpatA,949
|
|
@@ -154,7 +154,7 @@ librelane/steps/__main__.py,sha256=GQZiV4s-9GIF4AwP34W61zwgzMvPp-QTR4cNELi7r5c,1
|
|
|
154
154
|
librelane/steps/checker.py,sha256=HD5YFPAbHQKsFmBDrIAbo_0clZcCszNhIXb4lHaNIeQ,21629
|
|
155
155
|
librelane/steps/common_variables.py,sha256=eih2eA1m0FpL8ydF5WWattwh_SxtzI55eb8gggJtBuY,12494
|
|
156
156
|
librelane/steps/cvc_rv.py,sha256=qeroQPjidSAMYSp3nJNiQBYt8V73kkz3JK97uioo7J8,5294
|
|
157
|
-
librelane/steps/klayout.py,sha256=
|
|
157
|
+
librelane/steps/klayout.py,sha256=18B7trKjyD8HnGUVwrjQV8XRzGu298CuosM1WOzg9oM,23255
|
|
158
158
|
librelane/steps/magic.py,sha256=m4cZH2VomJs0RudtV8avSaZVqRj1NP7Pm2P6qo2z2X0,20919
|
|
159
159
|
librelane/steps/misc.py,sha256=8ubCvFeFEspXrgnzNWINY5-TXTyalNtlvcX8TSw0qdg,5685
|
|
160
160
|
librelane/steps/netgen.py,sha256=R9sDWv-9wKMdi2rkuLQdOc4uLlbYhXcKKd6WsZsnLt0,8953
|
|
@@ -165,8 +165,8 @@ librelane/steps/pyosys.py,sha256=LY7qqxkhjfoyBBR7vdkm7ylabbxMJDwIoYm7mAUbLVY,233
|
|
|
165
165
|
librelane/steps/step.py,sha256=THIxZkhtkNYt1iRgMduD0ywrOTCaV7cCfUB2EqXN6-k,55751
|
|
166
166
|
librelane/steps/tclstep.py,sha256=8-zpYOo562E86nm7f4DiTqUsLKY0AFtEJgrp9CnWWDw,10083
|
|
167
167
|
librelane/steps/verilator.py,sha256=MWx2TpLqYyea9_jSeLG9c2S5ujvYERQZRFNaMhfHxZE,7916
|
|
168
|
-
librelane/steps/yosys.py,sha256=
|
|
169
|
-
librelane-3.0.0.
|
|
170
|
-
librelane-3.0.0.
|
|
171
|
-
librelane-3.0.0.
|
|
172
|
-
librelane-3.0.0.
|
|
168
|
+
librelane/steps/yosys.py,sha256=lYdZPFvjcmdu_NE6rtB94_dysIK2qwGdGb480W6pg2w,12711
|
|
169
|
+
librelane-3.0.0.dev28.dist-info/METADATA,sha256=G4c7el3lW3tANOTRs4enKF5MHT-YYMOrBeLpARSsmIw,6561
|
|
170
|
+
librelane-3.0.0.dev28.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
171
|
+
librelane-3.0.0.dev28.dist-info/entry_points.txt,sha256=GTBvXykNMMFsNKiJFgtEw7P1wb_VZIqVM35EFSpyZQE,263
|
|
172
|
+
librelane-3.0.0.dev28.dist-info/RECORD,,
|
librelane/open_pdks_rev
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0fe599b2afb6708d281543108caf8310912f54af
|
|
File without changes
|
|
File without changes
|