cuemsutils 0.1.0rc14__tar.gz → 0.1.0rc15__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.
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/PKG-INFO +2 -2
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/__init__.py +2 -1
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/FadeCue.py +17 -2
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/MediaCue.py +90 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/Parsers.py +6 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/XmlBuilder.py +28 -1
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/schemas/script.xsd +33 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/.gitignore +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/LICENSE +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/README.md +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/create_script.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/ActionCue.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/AudioCue.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/Cue.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/CueList.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/CueOutput.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/CuemsScript.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/DmxCue.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/FadeProfile.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/VideoCue.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/cues/__init__.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/helpers.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/log.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/timeoutloop.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/CTimecode.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/CTimecodeTimer.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/CommunicatorServices.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/ConfigBase.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/ConfigManager.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/CopyMoveVersioned.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/FadeCalculator.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/HubServices.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/SignalEngine.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/StringSanitizer.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/Uuid.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/tools/__init__.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/CMLCuemsConverter.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/Settings.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/XmlReaderWriter.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/__init__.py +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/schemas/network_map.xsd +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/schemas/outputs.xsd +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/schemas/project_mappings.xsd +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/schemas/project_settings.xsd +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/cuemsutils/xml/schemas/settings.xsd +0 -0
- {cuemsutils-0.1.0rc14 → cuemsutils-0.1.0rc15}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: cuemsutils
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0rc15
|
|
4
4
|
Summary: Reusable classes and methods for CueMS system
|
|
5
5
|
Project-URL: Documentation, https://stagesoft.github.io/cuems-utils/
|
|
6
6
|
Project-URL: Issues, https://github.com/stagesoft/cuems-utils/issues
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Stagelab Coop SCCL
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
# SPDX-FileContributor: Ion Reguera <ion@stagelab.coop>
|
|
4
|
+
|
|
1
5
|
from enum import Enum
|
|
2
6
|
|
|
3
7
|
from ..helpers import ensure_items, format_timecode
|
|
@@ -8,12 +12,22 @@ _ZERO_TC = CTimecode('00:00:00.000')
|
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
class FadeCurveType(Enum):
|
|
11
|
-
"""Enumeration of supported fade curve shapes.
|
|
15
|
+
"""Enumeration of supported fade curve shapes.
|
|
16
|
+
|
|
17
|
+
``linear``, ``sigmoid``, ``ease_in`` and ``ease_out`` are the shapes
|
|
18
|
+
gradient-motiond's CurveFactory implements; the editor UI submits these.
|
|
19
|
+
``exponential`` and ``logarithmic`` are legacy names kept so projects
|
|
20
|
+
authored by older editors still load — CurveFactory does NOT implement
|
|
21
|
+
them, and the frontend maps them onto ``ease_in``/``ease_out`` (the same
|
|
22
|
+
accelerating/decelerating shapes) on load, healing them on next save.
|
|
23
|
+
"""
|
|
12
24
|
|
|
13
25
|
linear = 'linear'
|
|
14
26
|
exponential = 'exponential'
|
|
15
27
|
logarithmic = 'logarithmic'
|
|
16
28
|
sigmoid = 'sigmoid'
|
|
29
|
+
ease_in = 'ease_in'
|
|
30
|
+
ease_out = 'ease_out'
|
|
17
31
|
|
|
18
32
|
def __str__(self):
|
|
19
33
|
return self.value
|
|
@@ -125,7 +139,8 @@ class FadeCue(ActionCue):
|
|
|
125
139
|
|
|
126
140
|
Args:
|
|
127
141
|
curve_type (FadeCurveType | str): A FadeCurveType member or its
|
|
128
|
-
string value ('linear', '
|
|
142
|
+
string value ('linear', 'sigmoid', 'ease_in', 'ease_out', or
|
|
143
|
+
the legacy 'exponential'/'logarithmic').
|
|
129
144
|
|
|
130
145
|
Raises:
|
|
131
146
|
ValueError: If curve_type is not a recognised value.
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Stagelab Coop SCCL
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
# SPDX-FileContributor: Ion Reguera <ion@stagelab.coop>
|
|
1
4
|
from typing import Tuple
|
|
2
5
|
|
|
3
6
|
from .Cue import Cue
|
|
@@ -237,6 +240,93 @@ class Media(CuemsDict):
|
|
|
237
240
|
|
|
238
241
|
regions: list[Region] = property(get_regions, set_regions)
|
|
239
242
|
|
|
243
|
+
# --- Stored size of the media file (869fat84r) --------------------------
|
|
244
|
+
#
|
|
245
|
+
# ``pixel_width`` / ``pixel_height`` are the original size of the file's
|
|
246
|
+
# first video stream, as ffprobe reports it, and ``file_size`` is the
|
|
247
|
+
# file's size in bytes when they were measured. ``file_md5`` (below)
|
|
248
|
+
# identifies the file itself. The editor stores them at
|
|
249
|
+
# upload so the engine does not have to probe the file when it arms a
|
|
250
|
+
# cue; ``file_size`` lets the engine notice a file replaced under the
|
|
251
|
+
# same name. All three are optional: absent means unknown.
|
|
252
|
+
#
|
|
253
|
+
# Parsing a project never calls these setters (the parsers assign keys
|
|
254
|
+
# raw), so the schema and MediaXmlBuilder, not these, guard what is read
|
|
255
|
+
# from and written to a file.
|
|
256
|
+
|
|
257
|
+
def _get_optional(self, key):
|
|
258
|
+
return self.get(key)
|
|
259
|
+
|
|
260
|
+
def _set_positive_int(self, key, value):
|
|
261
|
+
"""Store *value* as a positive ``int``; ``None`` removes the key.
|
|
262
|
+
|
|
263
|
+
Raises:
|
|
264
|
+
ValueError: for anything that is not a positive integer or a
|
|
265
|
+
string of digits (``bool`` included: it is an ``int``).
|
|
266
|
+
"""
|
|
267
|
+
if value is None:
|
|
268
|
+
self.pop(key, None)
|
|
269
|
+
return
|
|
270
|
+
if isinstance(value, bool):
|
|
271
|
+
raise ValueError(f"Media {key} must be a positive integer, not {value!r}")
|
|
272
|
+
if isinstance(value, str) and value.isdigit():
|
|
273
|
+
value = int(value)
|
|
274
|
+
if not isinstance(value, int) or value <= 0:
|
|
275
|
+
raise ValueError(f"Media {key} must be a positive integer, not {value!r}")
|
|
276
|
+
super().__setitem__(key, value)
|
|
277
|
+
|
|
278
|
+
def get_pixel_width(self):
|
|
279
|
+
"""Width in pixels of the media's first video stream, or ``None``."""
|
|
280
|
+
return self._get_optional('pixel_width')
|
|
281
|
+
|
|
282
|
+
def set_pixel_width(self, pixel_width):
|
|
283
|
+
"""Set the width in pixels; ``None`` removes it."""
|
|
284
|
+
self._set_positive_int('pixel_width', pixel_width)
|
|
285
|
+
|
|
286
|
+
pixel_width = property(get_pixel_width, set_pixel_width)
|
|
287
|
+
|
|
288
|
+
def get_pixel_height(self):
|
|
289
|
+
"""Height in pixels of the media's first video stream, or ``None``."""
|
|
290
|
+
return self._get_optional('pixel_height')
|
|
291
|
+
|
|
292
|
+
def set_pixel_height(self, pixel_height):
|
|
293
|
+
"""Set the height in pixels; ``None`` removes it."""
|
|
294
|
+
self._set_positive_int('pixel_height', pixel_height)
|
|
295
|
+
|
|
296
|
+
pixel_height = property(get_pixel_height, set_pixel_height)
|
|
297
|
+
|
|
298
|
+
def get_file_size(self):
|
|
299
|
+
"""Size in bytes of the file the dimensions were measured on, or ``None``."""
|
|
300
|
+
return self._get_optional('file_size')
|
|
301
|
+
|
|
302
|
+
def set_file_size(self, file_size):
|
|
303
|
+
"""Set the file size in bytes; ``None`` removes it."""
|
|
304
|
+
self._set_positive_int('file_size', file_size)
|
|
305
|
+
|
|
306
|
+
file_size = property(get_file_size, set_file_size)
|
|
307
|
+
|
|
308
|
+
def get_file_md5(self):
|
|
309
|
+
"""The file's MD5 (32 lowercase hex digits), or ``None``. Every media
|
|
310
|
+
type; it comes from the upload, which already carries it (D18)."""
|
|
311
|
+
return self._get_optional('file_md5')
|
|
312
|
+
|
|
313
|
+
def set_file_md5(self, file_md5):
|
|
314
|
+
"""Set the file's MD5 (any case, stored lowercase); ``None`` removes it.
|
|
315
|
+
|
|
316
|
+
Raises:
|
|
317
|
+
ValueError: for anything that is not 32 hex digits.
|
|
318
|
+
"""
|
|
319
|
+
if file_md5 is None:
|
|
320
|
+
self.pop('file_md5', None)
|
|
321
|
+
return
|
|
322
|
+
if not isinstance(file_md5, str) or len(file_md5) != 32 or any(
|
|
323
|
+
c not in '0123456789abcdef' for c in file_md5.lower()
|
|
324
|
+
):
|
|
325
|
+
raise ValueError(f"Media file_md5 must be 32 hex digits, not {file_md5!r}")
|
|
326
|
+
super().__setitem__('file_md5', file_md5.lower())
|
|
327
|
+
|
|
328
|
+
file_md5 = property(get_file_md5, set_file_md5)
|
|
329
|
+
|
|
240
330
|
class MediaCue(Cue):
|
|
241
331
|
"""Base class for media-related cues (audio and video).
|
|
242
332
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Stagelab Coop SCCL
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
# SPDX-FileContributor: Ion Reguera <ion@stagelab.coop>
|
|
1
4
|
from ..cues import *
|
|
2
5
|
from ..cues.FadeProfile import FadeFunctionParameter, FadeProfile
|
|
3
6
|
from ..cues.MediaCue import Media, Region
|
|
@@ -33,6 +36,9 @@ STRING_TYPED_KEYS = frozenset({
|
|
|
33
36
|
'name', 'description', 'file_name',
|
|
34
37
|
# defensive -- see above
|
|
35
38
|
'output_name', 'parameter_name', 'icon', 'color', 'unix_name',
|
|
39
|
+
# an MD5 is hex: about one in a million is all digits (-> int) or digits
|
|
40
|
+
# with one 'e' (-> float), and would no longer validate (869fat84r D18)
|
|
41
|
+
'file_md5',
|
|
36
42
|
})
|
|
37
43
|
|
|
38
44
|
class GenericDict(dict):
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Stagelab Coop SCCL
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
# SPDX-FileContributor: Ion Reguera <ion@stagelab.coop>
|
|
1
4
|
from enum import Enum
|
|
2
5
|
from xml.etree.ElementTree import Element, ElementTree, SubElement, register_namespace
|
|
3
6
|
|
|
@@ -170,10 +173,34 @@ class GenericComplexSubObjectXmlBuilder(CuemsScriptXmlBuilder):
|
|
|
170
173
|
class CTimecodeXmlBuilder(GenericSimpleSubObjectXmlBuilder):
|
|
171
174
|
pass
|
|
172
175
|
|
|
176
|
+
#: ``MediaType``'s element order in script.xsd. The writer follows it, not the
|
|
177
|
+
#: dict's order: the editor appends the stored dimensions after whatever the
|
|
178
|
+
#: frontend sent, and the parsers assign keys in arrival order (869fat84r).
|
|
179
|
+
MEDIA_ELEMENT_ORDER = (
|
|
180
|
+
'file_name', 'id', 'duration', 'regions',
|
|
181
|
+
'pixel_width', 'pixel_height', 'file_size', 'file_md5',
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
#: Optional MediaType elements: a ``None`` value writes no element at all
|
|
185
|
+
#: (an empty ``<pixel_width/>`` would fail ``xs:positiveInteger``).
|
|
186
|
+
MEDIA_OPTIONAL_ELEMENTS = frozenset({'pixel_width', 'pixel_height', 'file_size', 'file_md5'})
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _media_items_in_schema_order(media):
|
|
190
|
+
"""``media``'s items, known keys in schema order, then any others in
|
|
191
|
+
arrival order (so the validator, not this writer, rejects them)."""
|
|
192
|
+
known = [(k, media[k]) for k in MEDIA_ELEMENT_ORDER if k in media]
|
|
193
|
+
other = [(k, v) for k, v in media.items() if k not in MEDIA_ELEMENT_ORDER]
|
|
194
|
+
return [
|
|
195
|
+
(k, v) for k, v in known + other
|
|
196
|
+
if not (v is None and k in MEDIA_OPTIONAL_ELEMENTS)
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
|
|
173
200
|
class MediaXmlBuilder(GenericComplexSubObjectXmlBuilder):
|
|
174
201
|
def build(self):
|
|
175
202
|
if isinstance(self._object, dict):
|
|
176
|
-
for key, value in self._object
|
|
203
|
+
for key, value in _media_items_in_schema_order(self._object):
|
|
177
204
|
if isinstance(value, VALUE_TYPES):
|
|
178
205
|
cue_subelement = SubElement(self.xml_tree, key)
|
|
179
206
|
cue_subelement.text = str(value)
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
<?xml version="1.1" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
SPDX-FileCopyrightText: 2026 Stagelab Coop SCCL
|
|
4
|
+
SPDX-License-Identifier: GPL-3.0-or-later
|
|
5
|
+
SPDX-FileContributor: Ion Reguera <ion@stagelab.coop>
|
|
6
|
+
-->
|
|
2
7
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1" targetNamespace="https://stagelab.coop/cuems/" xmlns:cms="https://stagelab.coop/cuems/">
|
|
3
8
|
<!-- The main capsule to make it a whole, named CueMs -->
|
|
4
9
|
<!-- Our main object the script-->
|
|
@@ -181,9 +186,31 @@
|
|
|
181
186
|
<xs:element name="id" type="cms:TargetType" />
|
|
182
187
|
<xs:element name="duration" type="cms:TimecodeType" />
|
|
183
188
|
<xs:element name="regions" type="cms:RegionsType" />
|
|
189
|
+
<!-- Stored size of the media file (869fat84r), measured by the editor
|
|
190
|
+
at upload so the engine does not probe the file when it arms a cue.
|
|
191
|
+
pixel_width / pixel_height: the ORIGINAL size of the file's first
|
|
192
|
+
video stream, as ffprobe reports it; not the layer's size on screen
|
|
193
|
+
(that would get its own names) and unrelated to CanvasRegionType's
|
|
194
|
+
unit-float width / height. file_size: the file's size in bytes when
|
|
195
|
+
they were measured; the engine compares it with its own copy to
|
|
196
|
+
notice a file replaced under the same name. Optional: absent means
|
|
197
|
+
unknown, and the engine then probes as before. The pixel size is
|
|
198
|
+
for VideoCues only; file_size and file_md5 for every media type.
|
|
199
|
+
file_md5: the file's MD5 (lowercase hex), from the upload, which
|
|
200
|
+
already carries it; identifies the file for integrity checks. -->
|
|
201
|
+
<xs:element name="pixel_width" type="xs:positiveInteger" minOccurs="0" />
|
|
202
|
+
<xs:element name="pixel_height" type="xs:positiveInteger" minOccurs="0" />
|
|
203
|
+
<xs:element name="file_size" type="xs:positiveInteger" minOccurs="0" />
|
|
204
|
+
<xs:element name="file_md5" type="cms:Md5Type" minOccurs="0" />
|
|
184
205
|
</xs:sequence>
|
|
185
206
|
</xs:complexType>
|
|
186
207
|
|
|
208
|
+
<xs:simpleType name="Md5Type">
|
|
209
|
+
<xs:restriction base="xs:string">
|
|
210
|
+
<xs:pattern value="[0-9a-f]{32}" />
|
|
211
|
+
</xs:restriction>
|
|
212
|
+
</xs:simpleType>
|
|
213
|
+
|
|
187
214
|
<xs:complexType name="OutputsType">
|
|
188
215
|
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
|
189
216
|
<xs:element name="AudioCueOutput" type="cms:AudioCueOutputsType" />
|
|
@@ -251,12 +278,18 @@
|
|
|
251
278
|
</xs:restriction>
|
|
252
279
|
</xs:simpleType>
|
|
253
280
|
|
|
281
|
+
<!-- linear/sigmoid/ease_in/ease_out are the curves gradient-motiond's
|
|
282
|
+
CurveFactory implements (the editor UI submits only these);
|
|
283
|
+
exponential/logarithmic are legacy names kept so old projects still
|
|
284
|
+
load — the frontend heals them to ease_in/ease_out on next save. -->
|
|
254
285
|
<xs:simpleType name="FadeCurveType">
|
|
255
286
|
<xs:restriction base="xs:string">
|
|
256
287
|
<xs:enumeration value="linear" />
|
|
257
288
|
<xs:enumeration value="exponential" />
|
|
258
289
|
<xs:enumeration value="logarithmic" />
|
|
259
290
|
<xs:enumeration value="sigmoid" />
|
|
291
|
+
<xs:enumeration value="ease_in" />
|
|
292
|
+
<xs:enumeration value="ease_out" />
|
|
260
293
|
</xs:restriction>
|
|
261
294
|
</xs:simpleType>
|
|
262
295
|
|
|
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
|