dyff-schema 0.30.0__tar.gz → 0.31.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.
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/.gitlab-ci.yml +7 -3
- {dyff_schema-0.30.0/dyff_schema.egg-info → dyff_schema-0.31.0}/PKG-INFO +2 -3
- dyff_schema-0.31.0/dyff/schema/_version.py +2 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/base.py +2 -4
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/dataset/arrow.py +52 -26
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/platform.py +12 -1
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/requests.py +2 -1
- {dyff_schema-0.30.0 → dyff_schema-0.31.0/dyff_schema.egg-info}/PKG-INFO +2 -3
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/pyproject.toml +1 -2
- dyff_schema-0.30.0/dyff/schema/_version.py +0 -2
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/.gitignore +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/.idea/dyff-schema.iml +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/.licenserc.yaml +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/.pre-commit-config.yaml +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/.prettierignore +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/.secrets.baseline +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/CODE_OF_CONDUCT.md +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/LICENSE +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/NOTICE +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/README.md +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/__init__.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/adapters.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/annotations.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/base.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/commands.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/copydoc.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/dataset/__init__.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/dataset/arrow.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/dataset/binary.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/dataset/classification.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/dataset/embedding.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/dataset/text.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/dataset/vision.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/errors.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/ids.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/io/__init__.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/io/vllm.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/platform.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/py.typed +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/quantity.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/requests.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/test.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/__init__.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/__init__.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/adapters.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/commands.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/dataset/__init__.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/dataset/binary.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/dataset/classification.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/dataset/embedding.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/dataset/text.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/dataset/vision.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/io/__init__.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/io/vllm.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/test.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/v0/r1/version.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff/schema/version.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff_schema.egg-info/SOURCES.txt +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff_schema.egg-info/dependency_links.txt +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff_schema.egg-info/requires.txt +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/dyff_schema.egg-info/top_level.txt +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/makefile +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/setup.cfg +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/tests/test_adapters.py +0 -0
- {dyff_schema-0.30.0 → dyff_schema-0.31.0}/tests/test_import.py +0 -0
|
@@ -8,7 +8,7 @@ stages:
|
|
|
8
8
|
|
|
9
9
|
include:
|
|
10
10
|
- project: saferatday0/library/gitlab
|
|
11
|
-
ref: 0.
|
|
11
|
+
ref: 0.16.0
|
|
12
12
|
file:
|
|
13
13
|
- gitlab-release.yml
|
|
14
14
|
- project: saferatday0/library/detect-secrets
|
|
@@ -20,7 +20,7 @@ include:
|
|
|
20
20
|
file:
|
|
21
21
|
- prettier.yml
|
|
22
22
|
- project: saferatday0/library/python
|
|
23
|
-
ref: 0.
|
|
23
|
+
ref: 0.21.0
|
|
24
24
|
file:
|
|
25
25
|
- python-autoflake.yml
|
|
26
26
|
- python-black.yml
|
|
@@ -37,6 +37,10 @@ include:
|
|
|
37
37
|
file:
|
|
38
38
|
- license-eye-header-check.yml
|
|
39
39
|
|
|
40
|
+
# Override image to use Go 1.24 to avoid golang.org/x/tools bug
|
|
41
|
+
license-eye-header-check:
|
|
42
|
+
image: "${CONTAINER_PROXY}golang:1.24-alpine"
|
|
43
|
+
|
|
40
44
|
variables:
|
|
41
45
|
PYTHON_PACKAGE: dyff/schema
|
|
42
46
|
PYTHON_REQUIREMENTS: .
|
|
@@ -58,4 +62,4 @@ python-twine-upload-pypi:
|
|
|
58
62
|
python-pytest:
|
|
59
63
|
parallel:
|
|
60
64
|
matrix:
|
|
61
|
-
- PYTHON_VERSION: ['3.
|
|
65
|
+
- PYTHON_VERSION: ['3.10', '3.11', '3.12']
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dyff-schema
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.31.0
|
|
4
4
|
Summary: Data models for the Dyff AI auditing platform.
|
|
5
5
|
Author-email: Digital Safety Research Institute <contact@dsri.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -12,12 +12,11 @@ Classifier: Intended Audience :: Science/Research
|
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.10
|
|
21
20
|
Description-Content-Type: text/markdown
|
|
22
21
|
License-File: LICENSE
|
|
23
22
|
License-File: NOTICE
|
|
@@ -431,13 +431,11 @@ def list_(
|
|
|
431
431
|
item_type: type[_ListElementT], *, list_size: Optional[int] = None
|
|
432
432
|
) -> type[list]:
|
|
433
433
|
if list_size is None:
|
|
434
|
-
return Annotated[list[
|
|
434
|
+
return Annotated[list[item_type], Field()] # type: ignore [return-value, valid-type]
|
|
435
435
|
else:
|
|
436
436
|
if list_size <= 0:
|
|
437
437
|
raise ValueError(f"list_size {list_size} must be > 0")
|
|
438
|
-
return Annotated[
|
|
439
|
-
list[_ListElementT], Field(min_length=list_size, max_length=list_size)
|
|
440
|
-
] # type: ignore [return-value]
|
|
438
|
+
return Annotated[list[item_type], Field(min_length=list_size, max_length=list_size)] # type: ignore [return-value, valid-type]
|
|
441
439
|
|
|
442
440
|
|
|
443
441
|
# mypy gets confused because 'dict' is the name of a method in DyffBaseModel
|
|
@@ -7,11 +7,13 @@ from __future__ import annotations
|
|
|
7
7
|
import functools
|
|
8
8
|
import inspect
|
|
9
9
|
import typing
|
|
10
|
+
import uuid
|
|
10
11
|
from typing import Any, Iterable, Literal, Optional
|
|
11
12
|
|
|
12
13
|
import pyarrow
|
|
13
14
|
import pyarrow.dataset
|
|
14
15
|
import pydantic
|
|
16
|
+
from pydantic.fields import FieldInfo
|
|
15
17
|
|
|
16
18
|
from ..base import DType
|
|
17
19
|
from . import binary
|
|
@@ -90,9 +92,12 @@ def subset_schema(schema: pyarrow.Schema, field_names: list[str]) -> pyarrow.Sch
|
|
|
90
92
|
|
|
91
93
|
|
|
92
94
|
def arrow_type(annotation: type) -> pyarrow.DataType:
|
|
93
|
-
"""Determine a suitable arrow type for a pydantic model field.
|
|
95
|
+
"""Determine a suitable arrow type for a pydantic model field.
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
Supports primitive types as well as pydantic sub-models, lists, and optional types.
|
|
98
|
+
Numeric types must have appropriate bounds specified, as Arrow cannot represent the
|
|
99
|
+
unbounded integer types used by Python 3.
|
|
100
|
+
"""
|
|
96
101
|
if origin := typing.get_origin(annotation):
|
|
97
102
|
if origin == list:
|
|
98
103
|
annotation_args = typing.get_args(annotation)
|
|
@@ -114,40 +119,61 @@ def arrow_type(annotation: type) -> pyarrow.DataType:
|
|
|
114
119
|
raise ValueError(
|
|
115
120
|
f"annotation {annotation}: only Optional[T] supported, not general Union"
|
|
116
121
|
)
|
|
117
|
-
return arrow_type(inner_type)
|
|
122
|
+
return arrow_type(inner_type) # All Arrow types are nullable
|
|
118
123
|
|
|
119
124
|
raise NotImplementedError(f"Python type {annotation}")
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if issubclass(annotation, DType):
|
|
127
|
-
# The dtype is in the metaclass
|
|
128
|
-
return pyarrow.from_numpy_dtype(type(annotation).dtype) # type: ignore[attr-defined]
|
|
126
|
+
if issubclass(annotation, pydantic.BaseModel):
|
|
127
|
+
subfields = []
|
|
128
|
+
for _name, subfield in annotation.model_fields.items():
|
|
129
|
+
subfields.append(arrow_field(_name, subfield))
|
|
130
|
+
return pyarrow.struct(subfields)
|
|
129
131
|
|
|
130
132
|
# Handle numpy-like types
|
|
131
133
|
if hasattr(annotation, "dtype"):
|
|
132
134
|
return pyarrow.from_numpy_dtype(annotation.dtype)
|
|
133
135
|
|
|
134
|
-
# Handle
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
136
|
+
# Handle Annotated list types (e.g., Annotated[list[str], Field(max_length=10)])
|
|
137
|
+
# This covers lists created by our list_() function in base.py which returns
|
|
138
|
+
# Annotated types with Field metadata for length constraints.
|
|
139
|
+
#
|
|
140
|
+
# We need custom logic here because:
|
|
141
|
+
# 1. Standard typing.List doesn't carry Pydantic Field constraints
|
|
142
|
+
# 2. Our list_() function wraps list[T] in Annotated[list[T], Field(...)]
|
|
143
|
+
# to embed validation metadata (min/max length) at the type level
|
|
144
|
+
# 3. PyArrow needs to know these constraints upfront to create proper schemas
|
|
145
|
+
# 4. The nested generic structure requires careful extraction:
|
|
146
|
+
# Annotated[list[str], Field(max_length=10)] needs to become
|
|
147
|
+
# pyarrow.list_(pyarrow.string(), 10)
|
|
148
|
+
if (
|
|
149
|
+
typing.get_origin(annotation) is typing.Annotated
|
|
150
|
+
and typing.get_args(annotation)[0] is list
|
|
151
|
+
):
|
|
152
|
+
metadata = typing.get_args(annotation)[1:]
|
|
153
|
+
item_type = typing.get_args(typing.get_args(annotation)[0])[0]
|
|
154
|
+
max_length = -1
|
|
155
|
+
for meta in metadata:
|
|
156
|
+
if isinstance(meta, FieldInfo):
|
|
157
|
+
max_length = getattr(meta, "max_length", -1)
|
|
158
|
+
return pyarrow.list_(arrow_type(item_type), max_length)
|
|
140
159
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
int: pyarrow.int64(),
|
|
145
|
-
float: pyarrow.float64(),
|
|
146
|
-
bool: pyarrow.bool_(),
|
|
147
|
-
}
|
|
160
|
+
if issubclass(annotation, DType):
|
|
161
|
+
# The dtype is in the metaclass
|
|
162
|
+
return pyarrow.from_numpy_dtype(type(annotation).dtype) # type: ignore[attr-defined]
|
|
148
163
|
|
|
149
|
-
if annotation
|
|
150
|
-
return
|
|
164
|
+
if annotation == bool:
|
|
165
|
+
return pyarrow.bool_()
|
|
166
|
+
if annotation == bytes:
|
|
167
|
+
return pyarrow.binary()
|
|
168
|
+
if annotation == float:
|
|
169
|
+
return pyarrow.float64()
|
|
170
|
+
if annotation == int:
|
|
171
|
+
raise ValueError("unconstrained integers cannot be represented in Arrow")
|
|
172
|
+
if annotation == uuid.UUID:
|
|
173
|
+
return pyarrow.binary(16)
|
|
174
|
+
|
|
175
|
+
if annotation == str:
|
|
176
|
+
return pyarrow.string()
|
|
151
177
|
|
|
152
178
|
raise NotImplementedError(f"Python type {annotation}")
|
|
153
179
|
|
|
@@ -1955,11 +1955,20 @@ class Method(DyffEntity, MethodBase):
|
|
|
1955
1955
|
return None
|
|
1956
1956
|
|
|
1957
1957
|
|
|
1958
|
+
class EntityIDMarker:
|
|
1959
|
+
"""Marker class to indicate that a field contains an entity ID that supports
|
|
1960
|
+
family@tag resolution."""
|
|
1961
|
+
|
|
1962
|
+
|
|
1963
|
+
# Type alias for entity ID fields that support family@tag resolution
|
|
1964
|
+
EntityIDField: TypeAlias = Annotated[str, EntityIDMarker]
|
|
1965
|
+
|
|
1966
|
+
|
|
1958
1967
|
class AnalysisInput(DyffSchemaBaseModel):
|
|
1959
1968
|
keyword: str = pydantic.Field(
|
|
1960
1969
|
description="The 'keyword' specified for this input in the MethodSpec."
|
|
1961
1970
|
)
|
|
1962
|
-
entity:
|
|
1971
|
+
entity: EntityIDField = pydantic.Field(
|
|
1963
1972
|
description="The ID of the entity whose data should be made available as 'keyword'."
|
|
1964
1973
|
)
|
|
1965
1974
|
|
|
@@ -2495,6 +2504,8 @@ __all__ = [
|
|
|
2495
2504
|
"Entities",
|
|
2496
2505
|
"EntityID",
|
|
2497
2506
|
"EntityIdentifier",
|
|
2507
|
+
"EntityIDField",
|
|
2508
|
+
"EntityIDMarker",
|
|
2498
2509
|
"EntityKindLiteral",
|
|
2499
2510
|
"Evaluation",
|
|
2500
2511
|
"EvaluationBase",
|
|
@@ -30,6 +30,7 @@ from .platform import (
|
|
|
30
30
|
DatasetBase,
|
|
31
31
|
DataView,
|
|
32
32
|
DocumentationBase,
|
|
33
|
+
EntityIDField,
|
|
33
34
|
Evaluation,
|
|
34
35
|
EvaluationBase,
|
|
35
36
|
FamilyBase,
|
|
@@ -95,7 +96,7 @@ class AnalysisCreateRequest(DyffEntityCreateRequest, AnalysisBase):
|
|
|
95
96
|
"""An Analysis transforms Datasets, Evaluations, and Measurements into new
|
|
96
97
|
Measurements or SafetyCases."""
|
|
97
98
|
|
|
98
|
-
method:
|
|
99
|
+
method: EntityIDField = pydantic.Field(description="Method ID")
|
|
99
100
|
|
|
100
101
|
@pydantic.field_validator("scope", check_fields=False)
|
|
101
102
|
def _validate_scope(cls, scope: AnalysisScope) -> AnalysisScope:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dyff-schema
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.31.0
|
|
4
4
|
Summary: Data models for the Dyff AI auditing platform.
|
|
5
5
|
Author-email: Digital Safety Research Institute <contact@dsri.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -12,12 +12,11 @@ Classifier: Intended Audience :: Science/Research
|
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.10
|
|
21
20
|
Description-Content-Type: text/markdown
|
|
22
21
|
License-File: LICENSE
|
|
23
22
|
License-File: NOTICE
|
|
@@ -23,7 +23,6 @@ classifiers=[
|
|
|
23
23
|
"License :: OSI Approved :: Apache Software License",
|
|
24
24
|
"Operating System :: OS Independent",
|
|
25
25
|
"Programming Language :: Python :: 3",
|
|
26
|
-
"Programming Language :: Python :: 3.9",
|
|
27
26
|
"Programming Language :: Python :: 3.10",
|
|
28
27
|
"Programming Language :: Python :: 3.11",
|
|
29
28
|
"Programming Language :: Python :: 3.12",
|
|
@@ -52,7 +51,7 @@ license = {"text" = "Apache-2.0"}
|
|
|
52
51
|
|
|
53
52
|
readme = "README.md"
|
|
54
53
|
|
|
55
|
-
requires-python = ">=3.
|
|
54
|
+
requires-python = ">=3.10"
|
|
56
55
|
|
|
57
56
|
[project.urls]
|
|
58
57
|
"Home" = "https://gitlab.com/dyff/packages/dyff-schema"
|
|
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
|