pycaption 2.2.21__tar.gz → 2.2.23__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.
- {pycaption-2.2.21/pycaption.egg-info → pycaption-2.2.23}/PKG-INFO +2 -2
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/dfxp/base.py +7 -3
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/scc/__init__.py +17 -7
- {pycaption-2.2.21 → pycaption-2.2.23/pycaption.egg-info}/PKG-INFO +2 -2
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption.egg-info/requires.txt +1 -1
- {pycaption-2.2.21 → pycaption-2.2.23}/setup.py +2 -2
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/conftest.py +2 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/dfxp.py +29 -1
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/scc.py +16 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_dfxp.py +43 -1
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_scc.py +18 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_scc_conversion.py +33 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/LICENSE +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/MANIFEST.in +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/README.rst +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/__init__.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/base.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/dfxp/__init__.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/dfxp/extras.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/exceptions.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/geometry.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/microdvd.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/sami.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/scc/constants.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/scc/specialized_collections.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/scc/state_machines.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/scc/translator.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/srt.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/transcript.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/utils.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption/webvtt.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption.egg-info/SOURCES.txt +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption.egg-info/dependency_links.txt +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/pycaption.egg-info/top_level.txt +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/setup.cfg +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/__init__.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/__init__.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/microdvd.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/sami.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/srt.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/translated_scc.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/fixtures/webvtt.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/mixins.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_base.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_dfxp_conversion.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_dfxp_extras.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_functions.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_geometry.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_microdvd.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_microdvd_conversion.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_sami.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_sami_conversion.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_scc_translator.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_srt.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_srt_conversion.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_webvtt.py +0 -0
- {pycaption-2.2.21 → pycaption-2.2.23}/tests/test_webvtt_conversion.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycaption
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.23
|
|
4
4
|
Summary: Closed caption converter
|
|
5
5
|
Author: Joe Norton
|
|
6
6
|
Author-email: joey@nortoncrew.com
|
|
@@ -27,7 +27,7 @@ Provides-Extra: dev
|
|
|
27
27
|
Requires-Dist: pytest; extra == "dev"
|
|
28
28
|
Requires-Dist: pytest-lazy-fixture; extra == "dev"
|
|
29
29
|
Provides-Extra: transcript
|
|
30
|
-
Requires-Dist: nltk==3.9.
|
|
30
|
+
Requires-Dist: nltk==3.9.4; extra == "transcript"
|
|
31
31
|
Dynamic: author
|
|
32
32
|
Dynamic: author-email
|
|
33
33
|
Dynamic: classifier
|
|
@@ -147,9 +147,13 @@ class DFXPReader(BaseReader):
|
|
|
147
147
|
def _convert_div_to_caption_list(self, div):
|
|
148
148
|
return CaptionList(
|
|
149
149
|
[
|
|
150
|
-
|
|
151
|
-
for
|
|
152
|
-
|
|
150
|
+
caption
|
|
151
|
+
for caption in (
|
|
152
|
+
self._convert_p_tag_to_caption(p_tag)
|
|
153
|
+
for p_tag in div.find_all("p")
|
|
154
|
+
if p_tag.get_text().strip()
|
|
155
|
+
)
|
|
156
|
+
if caption is not None
|
|
153
157
|
],
|
|
154
158
|
div.layout_info,
|
|
155
159
|
)
|
|
@@ -484,8 +484,17 @@ class SCCReader(BaseReader):
|
|
|
484
484
|
|
|
485
485
|
# 942c - Erase Displayed Memory - Clear the current screen of any
|
|
486
486
|
# displayed captions or text.
|
|
487
|
-
elif word == "942c"
|
|
488
|
-
|
|
487
|
+
elif word == "942c":
|
|
488
|
+
edm_time = self.time_translator.get_time()
|
|
489
|
+
if self.pop_ons_queue:
|
|
490
|
+
self._pop_on(end=edm_time)
|
|
491
|
+
if self.buffer_dict.active_key in ("paint", "roll") \
|
|
492
|
+
and not self.buffer.is_empty():
|
|
493
|
+
self.caption_stash.create_and_store(
|
|
494
|
+
self.buffer, self.time, edm_time)
|
|
495
|
+
self.buffer = self.node_creator_factory.new_creator()
|
|
496
|
+
self.node_creator_factory.position_tracker.reset_for_new_caption()
|
|
497
|
+
self.time = edm_time
|
|
489
498
|
|
|
490
499
|
# If command is not one of the aforementioned, add it to buffer
|
|
491
500
|
else:
|
|
@@ -575,11 +584,12 @@ class SCCWriter(BaseWriter):
|
|
|
575
584
|
code_words = len(code) / 5 + 8
|
|
576
585
|
code_time_microseconds = code_words * MICROSECONDS_PER_CODEWORD
|
|
577
586
|
code_start = start - code_time_microseconds
|
|
578
|
-
if index
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
587
|
+
if index > 0:
|
|
588
|
+
previous_code, previous_start, previous_end = codes[index - 1]
|
|
589
|
+
if code_start < previous_start:
|
|
590
|
+
code_start = previous_start
|
|
591
|
+
if previous_end + 3 * MICROSECONDS_PER_CODEWORD >= code_start:
|
|
592
|
+
codes[index - 1] = (previous_code, previous_start, None)
|
|
583
593
|
codes[index] = (code, code_start, end)
|
|
584
594
|
|
|
585
595
|
# PASS 3:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycaption
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.23
|
|
4
4
|
Summary: Closed caption converter
|
|
5
5
|
Author: Joe Norton
|
|
6
6
|
Author-email: joey@nortoncrew.com
|
|
@@ -27,7 +27,7 @@ Provides-Extra: dev
|
|
|
27
27
|
Requires-Dist: pytest; extra == "dev"
|
|
28
28
|
Requires-Dist: pytest-lazy-fixture; extra == "dev"
|
|
29
29
|
Provides-Extra: transcript
|
|
30
|
-
Requires-Dist: nltk==3.9.
|
|
30
|
+
Requires-Dist: nltk==3.9.4; extra == "transcript"
|
|
31
31
|
Dynamic: author
|
|
32
32
|
Dynamic: author-email
|
|
33
33
|
Dynamic: classifier
|
|
@@ -16,11 +16,11 @@ dependencies = [
|
|
|
16
16
|
|
|
17
17
|
dev_dependencies = ["pytest", "pytest-lazy-fixture"]
|
|
18
18
|
|
|
19
|
-
transcript_dependencies = ["nltk==3.9.
|
|
19
|
+
transcript_dependencies = ["nltk==3.9.4"]
|
|
20
20
|
|
|
21
21
|
setup(
|
|
22
22
|
name="pycaption",
|
|
23
|
-
version="2.2.
|
|
23
|
+
version="2.2.23",
|
|
24
24
|
description="Closed caption converter",
|
|
25
25
|
long_description=open(README_PATH).read(),
|
|
26
26
|
author="Joe Norton",
|
|
@@ -45,6 +45,7 @@ from tests.fixtures.dfxp import ( # noqa: F401
|
|
|
45
45
|
sample_dfxp_with_relativized_positioning,
|
|
46
46
|
sample_dfxp_with_templated_style,
|
|
47
47
|
sample_dfxp_without_region_and_style,
|
|
48
|
+
sample_dfxp_concurrent_with_empty_p,
|
|
48
49
|
)
|
|
49
50
|
from tests.fixtures.microdvd import missing_fps_sample_microdvd # noqa: F401
|
|
50
51
|
from tests.fixtures.microdvd import (
|
|
@@ -123,6 +124,7 @@ from tests.fixtures.scc import ( # noqa: F401
|
|
|
123
124
|
sample_scc_with_spaces_at_eol_pop,
|
|
124
125
|
sample_scc_with_spaces_at_eol_roll,
|
|
125
126
|
sample_scc_with_unknown_commands,
|
|
127
|
+
sample_scc_paint_on_edm,
|
|
126
128
|
scc_that_generates_webvtt_with_proper_newlines,
|
|
127
129
|
)
|
|
128
130
|
from tests.fixtures.srt import (
|
|
@@ -963,7 +963,7 @@ def sample_dfxp_from_scc_output():
|
|
|
963
963
|
<p begin="00:00:20.086" end="00:00:22.088" region="r9" style="default">
|
|
964
964
|
2323
|
|
965
965
|
</p>
|
|
966
|
-
<p begin="00:00:22.088" end="00:00:
|
|
966
|
+
<p begin="00:00:22.088" end="00:00:36.169" region="r10" style="default">
|
|
967
967
|
4545<br/>
|
|
968
968
|
6767<br/>
|
|
969
969
|
8989
|
|
@@ -1521,3 +1521,31 @@ def sample_dfxp_default_styling_p_tags():
|
|
|
1521
1521
|
</div>
|
|
1522
1522
|
</body>
|
|
1523
1523
|
</tt>"""
|
|
1524
|
+
|
|
1525
|
+
|
|
1526
|
+
@pytest.fixture(scope="session")
|
|
1527
|
+
def sample_dfxp_concurrent_with_empty_p():
|
|
1528
|
+
return """\
|
|
1529
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
1530
|
+
<tt xml:lang="en" xmlns="http://www.w3.org/ns/ttml"
|
|
1531
|
+
xmlns:tts="http://www.w3.org/ns/ttml#styling">
|
|
1532
|
+
<head>
|
|
1533
|
+
<styling>
|
|
1534
|
+
<style xml:id="basic" tts:color="white"/>
|
|
1535
|
+
</styling>
|
|
1536
|
+
<layout>
|
|
1537
|
+
<region xml:id="pop1" tts:origin="17.5% 84.66%" tts:extent="62.5% 5.33%"/>
|
|
1538
|
+
<region xml:id="pop2" tts:origin="50% 84.66%" tts:extent="0% 5.33%"/>
|
|
1539
|
+
</layout>
|
|
1540
|
+
</head>
|
|
1541
|
+
<body>
|
|
1542
|
+
<div xml:lang="en">
|
|
1543
|
+
<p region="pop1" style="basic" begin="01:55:05:08" end="01:55:11:14"
|
|
1544
|
+
tts:origin="17.5% 84.66%" tts:extent="62.5% 5.33%">Subtitle End
|
|
1545
|
+
</p>
|
|
1546
|
+
<p region="pop2" style="basic" begin="01:55:05:08" end="01:55:11:14"
|
|
1547
|
+
tts:origin="50% 84.66%" tts:extent="0% 5.33%">
|
|
1548
|
+
</p>
|
|
1549
|
+
</div>
|
|
1550
|
+
</body>
|
|
1551
|
+
</tt>"""
|
|
@@ -643,3 +643,19 @@ Scenarist_SCC V1.0
|
|
|
643
643
|
00:00:01:24 9429 91d0 c180 c220 91e0 c1c2 2020 2080 92c2 c1c2 2080
|
|
644
644
|
|
|
645
645
|
"""
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
@pytest.fixture(scope="session")
|
|
649
|
+
def sample_scc_paint_on_edm():
|
|
650
|
+
return """\
|
|
651
|
+
Scenarist_SCC V1.0
|
|
652
|
+
|
|
653
|
+
00:00:00;00 9429 4920 f468 e96e 6b80
|
|
654
|
+
|
|
655
|
+
00:00:01;00 942c
|
|
656
|
+
|
|
657
|
+
00:00:02;00 9429 c8e5 ecec ef80
|
|
658
|
+
|
|
659
|
+
00:00:04;00 942c
|
|
660
|
+
|
|
661
|
+
"""
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
|
-
from pycaption import CaptionReadNoCaptions, DFXPReader
|
|
3
|
+
from pycaption import CaptionReadNoCaptions, DFXPReader, SRTWriter
|
|
4
|
+
from pycaption.base import merge_concurrent_captions
|
|
4
5
|
from pycaption.exceptions import (
|
|
5
6
|
CaptionReadError,
|
|
6
7
|
CaptionReadSyntaxError,
|
|
@@ -230,3 +231,44 @@ class TestDFXPReader(ReaderTestingMixIn):
|
|
|
230
231
|
caps = caption_set.get_captions("en-US")
|
|
231
232
|
|
|
232
233
|
assert len(caps) == 1
|
|
234
|
+
|
|
235
|
+
def test_concurrent_captions_with_empty_p_no_none_in_list(
|
|
236
|
+
self, sample_dfxp_concurrent_with_empty_p
|
|
237
|
+
):
|
|
238
|
+
caption_set = DFXPReader().read(sample_dfxp_concurrent_with_empty_p)
|
|
239
|
+
captions = caption_set.get_captions("en")
|
|
240
|
+
assert all(c is not None for c in captions)
|
|
241
|
+
assert len(captions) == 1
|
|
242
|
+
|
|
243
|
+
def test_concurrent_captions_with_empty_p_merge_does_not_crash(
|
|
244
|
+
self, sample_dfxp_concurrent_with_empty_p
|
|
245
|
+
):
|
|
246
|
+
caption_set = DFXPReader().read(sample_dfxp_concurrent_with_empty_p)
|
|
247
|
+
merged = merge_concurrent_captions(caption_set)
|
|
248
|
+
captions = merged.get_captions("en")
|
|
249
|
+
assert len(captions) >= 1
|
|
250
|
+
assert all(c is not None for c in captions)
|
|
251
|
+
|
|
252
|
+
def test_concurrent_captions_with_empty_p_srt_writer_does_not_crash(
|
|
253
|
+
self, sample_dfxp_concurrent_with_empty_p
|
|
254
|
+
):
|
|
255
|
+
caption_set = DFXPReader().read(sample_dfxp_concurrent_with_empty_p)
|
|
256
|
+
output = SRTWriter().write(caption_set)
|
|
257
|
+
assert "Subtitle End" in output
|
|
258
|
+
|
|
259
|
+
def test_none_from_convert_p_tag_is_filtered(self, sample_dfxp):
|
|
260
|
+
reader = DFXPReader()
|
|
261
|
+
original = reader._convert_p_tag_to_caption
|
|
262
|
+
call_count = [0]
|
|
263
|
+
|
|
264
|
+
def patched(p_tag):
|
|
265
|
+
call_count[0] += 1
|
|
266
|
+
if call_count[0] == 2:
|
|
267
|
+
return None
|
|
268
|
+
return original(p_tag)
|
|
269
|
+
|
|
270
|
+
reader._convert_p_tag_to_caption = patched
|
|
271
|
+
caption_set = reader.read(sample_dfxp)
|
|
272
|
+
captions = caption_set.get_captions("en-US")
|
|
273
|
+
assert all(c is not None for c in captions)
|
|
274
|
+
assert len(captions) == 6
|
|
@@ -1000,3 +1000,21 @@ class TestTimingCorrectingCaptionList:
|
|
|
1000
1000
|
num_captions = len(caption_set.get_captions("en-US"))
|
|
1001
1001
|
|
|
1002
1002
|
assert num_captions == 2
|
|
1003
|
+
|
|
1004
|
+
def test_paint_on_edm_erases_displayed(self, sample_scc_paint_on_edm):
|
|
1005
|
+
caption_set = SCCReader().read(sample_scc_paint_on_edm)
|
|
1006
|
+
captions = caption_set.get_captions("en-US")
|
|
1007
|
+
|
|
1008
|
+
assert len(captions) == 2
|
|
1009
|
+
|
|
1010
|
+
texts = [
|
|
1011
|
+
node.content
|
|
1012
|
+
for caption in captions
|
|
1013
|
+
for node in caption.nodes
|
|
1014
|
+
if node.type_ == CaptionNode.TEXT
|
|
1015
|
+
]
|
|
1016
|
+
assert texts == ["I think", "Hello"]
|
|
1017
|
+
|
|
1018
|
+
assert captions[0].end > captions[0].start
|
|
1019
|
+
assert captions[1].end > captions[1].start
|
|
1020
|
+
assert captions[0].end <= captions[1].start
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
1
3
|
import pytest
|
|
2
4
|
|
|
3
5
|
from pycaption import (
|
|
@@ -6,6 +8,7 @@ from pycaption import (
|
|
|
6
8
|
SCCWriter,
|
|
7
9
|
SRTReader,
|
|
8
10
|
SRTWriter,
|
|
11
|
+
WebVTTReader,
|
|
9
12
|
WebVTTWriter,
|
|
10
13
|
)
|
|
11
14
|
from tests.mixins import CaptionSetTestingMixIn
|
|
@@ -65,6 +68,36 @@ class TestSCCtoDFXP:
|
|
|
65
68
|
assert dfxp == sample_dfxp_with_ampersand_character
|
|
66
69
|
|
|
67
70
|
|
|
71
|
+
class TestSCCTimestampOrdering:
|
|
72
|
+
def test_scc_captions_are_in_order_when_short_text_followed_by_long(self):
|
|
73
|
+
"""When short caption text is followed by longer caption text,
|
|
74
|
+
the SCC output timestamps should remain in chronological order.
|
|
75
|
+
"""
|
|
76
|
+
vtt_input = (
|
|
77
|
+
"WEBVTT\n\n"
|
|
78
|
+
"0\n"
|
|
79
|
+
"00:00:02.200 --> 00:00:02.359\n"
|
|
80
|
+
"you know,\n\n"
|
|
81
|
+
"1\n"
|
|
82
|
+
"00:00:02.400 --> 00:00:03.760\n"
|
|
83
|
+
"the way he kind of looked at me.\n\n"
|
|
84
|
+
"2\n"
|
|
85
|
+
"00:00:04.700 --> 00:00:05.169\n"
|
|
86
|
+
"And I said,\n\n"
|
|
87
|
+
"3\n"
|
|
88
|
+
"00:00:05.210 --> 00:00:05.520\n"
|
|
89
|
+
"oh\n"
|
|
90
|
+
)
|
|
91
|
+
captions = WebVTTReader().read(vtt_input)
|
|
92
|
+
scc_output = SCCWriter().write(captions)
|
|
93
|
+
# SCC timestamps use HH:MM:SS:FF format (FF = frames)
|
|
94
|
+
timestamps = re.findall(r"(\d+:\d+:\d+:\d+)", scc_output)
|
|
95
|
+
for i in range(1, len(timestamps)):
|
|
96
|
+
assert timestamps[i] >= timestamps[i - 1], (
|
|
97
|
+
f"Timestamps out of order: {timestamps[i - 1]} > {timestamps[i]}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
68
101
|
class TestSCCToWebVTT:
|
|
69
102
|
def test_webvtt_newlines_are_properly_rendered(
|
|
70
103
|
self,
|
|
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
|