agent-first-data 0.13.0__tar.gz → 0.13.2__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.
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/PKG-INFO +3 -2
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/README.md +2 -1
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data/__init__.py +10 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data/cli.py +84 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data/format.py +55 -3
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data.egg-info/PKG-INFO +3 -2
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/pyproject.toml +1 -1
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/tests/test_cli.py +51 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/tests/test_format.py +8 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data/afdata_logging.py +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data/skill.py +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data.egg-info/SOURCES.txt +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data.egg-info/dependency_links.txt +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data.egg-info/top_level.txt +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/setup.cfg +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/tests/test_afdata_logging.py +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/tests/test_no_stderr_policy.py +0 -0
- {agent_first_data-0.13.0 → agent_first_data-0.13.2}/tests/test_skill.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-first-data
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.2
|
|
4
4
|
Summary: A naming convention that lets AI agents understand your data without being told what it means.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/agentfirstkit/agent-first-data
|
|
@@ -29,7 +29,7 @@ print(output_json(value))
|
|
|
29
29
|
print(output_plain(value))
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `cli_parse_output`, `cli_output`, and `
|
|
32
|
+
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
|
|
33
33
|
|
|
34
34
|
Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
|
|
35
35
|
|
|
@@ -46,6 +46,7 @@ init_logging_json("INFO", secret_names=("authorization",))
|
|
|
46
46
|
- YAML/plain quote and escape keys as well as values, sort by UTF-16 code unit order, and render nested objects in arrays as canonical JSON.
|
|
47
47
|
- Logging records use `code: "log"` plus a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
48
48
|
- `build_cli_error(message, hint?)` returns `{code:"error", error: message, hint?}` only.
|
|
49
|
+
- Use `cli_handle_version_or_continue()` before argument parsing so bare `--version` stays conventional and `--version --output json|yaml|plain` stays structured.
|
|
49
50
|
|
|
50
51
|
## Reference
|
|
51
52
|
|
|
@@ -20,7 +20,7 @@ print(output_json(value))
|
|
|
20
20
|
print(output_plain(value))
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `cli_parse_output`, `cli_output`, and `
|
|
23
|
+
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
|
|
24
24
|
|
|
25
25
|
Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
|
|
26
26
|
|
|
@@ -37,6 +37,7 @@ init_logging_json("INFO", secret_names=("authorization",))
|
|
|
37
37
|
- YAML/plain quote and escape keys as well as values, sort by UTF-16 code unit order, and render nested objects in arrays as canonical JSON.
|
|
38
38
|
- Logging records use `code: "log"` plus a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
39
39
|
- `build_cli_error(message, hint?)` returns `{code:"error", error: message, hint?}` only.
|
|
40
|
+
- Use `cli_handle_version_or_continue()` before argument parsing so bare `--version` stays conventional and `--version --output json|yaml|plain` stays structured.
|
|
40
41
|
|
|
41
42
|
## Reference
|
|
42
43
|
|
|
@@ -24,6 +24,8 @@ from agent_first_data.format import (
|
|
|
24
24
|
redact_url_secrets_with_options,
|
|
25
25
|
parse_size,
|
|
26
26
|
normalize_utc_offset,
|
|
27
|
+
is_valid_rfc3339_date,
|
|
28
|
+
is_valid_rfc3339_time,
|
|
27
29
|
)
|
|
28
30
|
|
|
29
31
|
from agent_first_data.afdata_logging import (
|
|
@@ -42,6 +44,9 @@ from agent_first_data.cli import (
|
|
|
42
44
|
cli_output,
|
|
43
45
|
cli_output_with_options,
|
|
44
46
|
build_cli_error,
|
|
47
|
+
build_cli_version,
|
|
48
|
+
cli_render_version,
|
|
49
|
+
cli_handle_version_or_continue,
|
|
45
50
|
)
|
|
46
51
|
|
|
47
52
|
from agent_first_data.skill import (
|
|
@@ -84,6 +89,8 @@ __all__ = [
|
|
|
84
89
|
"redact_url_secrets_with_options",
|
|
85
90
|
"parse_size",
|
|
86
91
|
"normalize_utc_offset",
|
|
92
|
+
"is_valid_rfc3339_date",
|
|
93
|
+
"is_valid_rfc3339_time",
|
|
87
94
|
"AfdataHandler",
|
|
88
95
|
"init_logging_json",
|
|
89
96
|
"init_logging_plain",
|
|
@@ -96,6 +103,9 @@ __all__ = [
|
|
|
96
103
|
"cli_output",
|
|
97
104
|
"cli_output_with_options",
|
|
98
105
|
"build_cli_error",
|
|
106
|
+
"build_cli_version",
|
|
107
|
+
"cli_render_version",
|
|
108
|
+
"cli_handle_version_or_continue",
|
|
99
109
|
"SkillSpec",
|
|
100
110
|
"SkillAction",
|
|
101
111
|
"SkillScope",
|
|
@@ -7,6 +7,7 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from agent_first_data.format import (
|
|
9
9
|
OutputOptions,
|
|
10
|
+
build_json,
|
|
10
11
|
output_json,
|
|
11
12
|
output_json_with_options,
|
|
12
13
|
output_yaml,
|
|
@@ -93,6 +94,89 @@ def cli_output_with_options(
|
|
|
93
94
|
return output_json_with_options(value, output_options)
|
|
94
95
|
|
|
95
96
|
|
|
97
|
+
def build_cli_version(version: str) -> dict:
|
|
98
|
+
"""Build a standard CLI version value."""
|
|
99
|
+
return build_json("version", {"version": version})
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def cli_render_version(
|
|
103
|
+
name: str,
|
|
104
|
+
version: str,
|
|
105
|
+
format: OutputFormat | None = None,
|
|
106
|
+
) -> str:
|
|
107
|
+
"""Render CLI version output.
|
|
108
|
+
|
|
109
|
+
Pass an OutputFormat for AFDATA JSON/YAML/plain. Pass None to preserve
|
|
110
|
+
conventional "<name> <version>" text.
|
|
111
|
+
"""
|
|
112
|
+
rendered = (
|
|
113
|
+
f"{name} {version}" if format is None else cli_output(build_cli_version(version), format)
|
|
114
|
+
)
|
|
115
|
+
return rendered.rstrip("\n") + "\n"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def cli_handle_version_or_continue(
|
|
119
|
+
raw_args: list[str],
|
|
120
|
+
name: str,
|
|
121
|
+
version: str,
|
|
122
|
+
default_output: OutputFormat | None = None,
|
|
123
|
+
output_flag: str = "--output",
|
|
124
|
+
allow_output_format: bool = True,
|
|
125
|
+
) -> str | None:
|
|
126
|
+
"""Render version output if --version/-V is present; otherwise return None.
|
|
127
|
+
|
|
128
|
+
Raises ValueError for malformed version requests, for example
|
|
129
|
+
``--version --output xml``. The caller should convert that to a CLI error
|
|
130
|
+
with ``build_cli_error``.
|
|
131
|
+
"""
|
|
132
|
+
version_requested = False
|
|
133
|
+
output_format: OutputFormat | None = None
|
|
134
|
+
output_error: ValueError | None = None
|
|
135
|
+
|
|
136
|
+
i = 0
|
|
137
|
+
while i < len(raw_args):
|
|
138
|
+
arg = raw_args[i]
|
|
139
|
+
if arg == "--":
|
|
140
|
+
break
|
|
141
|
+
if arg in ("--version", "-V"):
|
|
142
|
+
version_requested = True
|
|
143
|
+
i += 1
|
|
144
|
+
continue
|
|
145
|
+
if allow_output_format and (arg == output_flag or arg.startswith(f"{output_flag}=")):
|
|
146
|
+
value: str | None
|
|
147
|
+
if arg.startswith(f"{output_flag}="):
|
|
148
|
+
value = arg.split("=", 1)[1]
|
|
149
|
+
step = 1
|
|
150
|
+
elif i + 1 < len(raw_args) and not raw_args[i + 1].startswith("-"):
|
|
151
|
+
value = raw_args[i + 1]
|
|
152
|
+
step = 2
|
|
153
|
+
else:
|
|
154
|
+
value = None
|
|
155
|
+
step = 1
|
|
156
|
+
if value is None:
|
|
157
|
+
output_error = ValueError(
|
|
158
|
+
f"missing value for {output_flag}: expected json, yaml, or plain"
|
|
159
|
+
)
|
|
160
|
+
else:
|
|
161
|
+
try:
|
|
162
|
+
output_format = cli_parse_output(value)
|
|
163
|
+
except ValueError as e:
|
|
164
|
+
output_error = e
|
|
165
|
+
i += step
|
|
166
|
+
continue
|
|
167
|
+
i += 1
|
|
168
|
+
|
|
169
|
+
if not version_requested:
|
|
170
|
+
return None
|
|
171
|
+
if output_error is not None:
|
|
172
|
+
raise output_error
|
|
173
|
+
return cli_render_version(
|
|
174
|
+
name,
|
|
175
|
+
version,
|
|
176
|
+
output_format if allow_output_format and output_format is not None else default_output,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
96
180
|
def build_cli_error(message: str, hint: str | None = None) -> dict:
|
|
97
181
|
"""Build a standard CLI parse error value.
|
|
98
182
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""AFDATA output formatting and protocol templates.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
21 public APIs and 4 types: protocol builders, value redactors (copy and
|
|
4
4
|
in-place; cover _secret and _url fields), output formatters, URL-string
|
|
5
5
|
redactors (redact_url_secrets / _with_options), parse_size,
|
|
6
|
-
normalize_utc_offset,
|
|
7
|
-
OutputOptions.
|
|
6
|
+
normalize_utc_offset, is_valid_rfc3339_date, is_valid_rfc3339_time,
|
|
7
|
+
RedactionPolicy, RedactionOptions, OutputStyle, and OutputOptions.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
@@ -293,6 +293,38 @@ def normalize_utc_offset(value: str) -> str | None:
|
|
|
293
293
|
return f"{s[0]}{hours:02d}:{minutes:02d}"
|
|
294
294
|
|
|
295
295
|
|
|
296
|
+
def is_valid_rfc3339_date(value: str) -> bool:
|
|
297
|
+
"""Return true when value is an RFC 3339 full-date (YYYY-MM-DD)."""
|
|
298
|
+
if not isinstance(value, str):
|
|
299
|
+
return False
|
|
300
|
+
if len(value) != 10 or value[4] != "-" or value[7] != "-":
|
|
301
|
+
return False
|
|
302
|
+
year = _parse_ascii_int(value[0:4])
|
|
303
|
+
month = _parse_ascii_int(value[5:7])
|
|
304
|
+
day = _parse_ascii_int(value[8:10])
|
|
305
|
+
if year is None or month is None or day is None:
|
|
306
|
+
return False
|
|
307
|
+
return 1 <= month <= 12 and 1 <= day <= _days_in_month(year, month)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def is_valid_rfc3339_time(value: str) -> bool:
|
|
311
|
+
"""Return true when value is an RFC 3339 partial-time (HH:MM:SS[.fraction])."""
|
|
312
|
+
if not isinstance(value, str):
|
|
313
|
+
return False
|
|
314
|
+
if len(value) < 8 or value[2] != ":" or value[5] != ":":
|
|
315
|
+
return False
|
|
316
|
+
hour = _parse_ascii_int(value[0:2])
|
|
317
|
+
minute = _parse_ascii_int(value[3:5])
|
|
318
|
+
second = _parse_ascii_int(value[6:8])
|
|
319
|
+
if hour is None or minute is None or second is None:
|
|
320
|
+
return False
|
|
321
|
+
if hour > 23 or minute > 59 or second > 59:
|
|
322
|
+
return False
|
|
323
|
+
if len(value) == 8:
|
|
324
|
+
return True
|
|
325
|
+
return value[8] == "." and len(value) > 9 and value[9:].isdigit()
|
|
326
|
+
|
|
327
|
+
|
|
296
328
|
def _parse_utc_offset_body(body: str) -> tuple[int, int] | None:
|
|
297
329
|
if not body:
|
|
298
330
|
return None
|
|
@@ -315,6 +347,26 @@ def _parse_utc_offset_body(body: str) -> tuple[int, int] | None:
|
|
|
315
347
|
return None
|
|
316
348
|
|
|
317
349
|
|
|
350
|
+
def _parse_ascii_int(value: str) -> int | None:
|
|
351
|
+
if not value or not (value.isascii() and value.isdigit()):
|
|
352
|
+
return None
|
|
353
|
+
return int(value)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _days_in_month(year: int, month: int) -> int:
|
|
357
|
+
if month in (1, 3, 5, 7, 8, 10, 12):
|
|
358
|
+
return 31
|
|
359
|
+
if month in (4, 6, 9, 11):
|
|
360
|
+
return 30
|
|
361
|
+
if month == 2:
|
|
362
|
+
return 29 if _is_leap_year(year) else 28
|
|
363
|
+
return 0
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def _is_leap_year(year: int) -> bool:
|
|
367
|
+
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
|
|
368
|
+
|
|
369
|
+
|
|
318
370
|
# ═══════════════════════════════════════════
|
|
319
371
|
# Secret Redaction
|
|
320
372
|
# ═══════════════════════════════════════════
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-first-data
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.2
|
|
4
4
|
Summary: A naming convention that lets AI agents understand your data without being told what it means.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/agentfirstkit/agent-first-data
|
|
@@ -29,7 +29,7 @@ print(output_json(value))
|
|
|
29
29
|
print(output_plain(value))
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `cli_parse_output`, `cli_output`, and `
|
|
32
|
+
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain`, `output_json_with_options`, `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, and `cli_handle_version_or_continue`.
|
|
33
33
|
|
|
34
34
|
Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
|
|
35
35
|
|
|
@@ -46,6 +46,7 @@ init_logging_json("INFO", secret_names=("authorization",))
|
|
|
46
46
|
- YAML/plain quote and escape keys as well as values, sort by UTF-16 code unit order, and render nested objects in arrays as canonical JSON.
|
|
47
47
|
- Logging records use `code: "log"` plus a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
48
48
|
- `build_cli_error(message, hint?)` returns `{code:"error", error: message, hint?}` only.
|
|
49
|
+
- Use `cli_handle_version_or_continue()` before argument parsing so bare `--version` stays conventional and `--version --output json|yaml|plain` stays structured.
|
|
49
50
|
|
|
50
51
|
## Reference
|
|
51
52
|
|
|
@@ -9,6 +9,9 @@ from agent_first_data import (
|
|
|
9
9
|
cli_output,
|
|
10
10
|
cli_output_with_options,
|
|
11
11
|
build_cli_error,
|
|
12
|
+
build_cli_version,
|
|
13
|
+
cli_render_version,
|
|
14
|
+
cli_handle_version_or_continue,
|
|
12
15
|
output_json,
|
|
13
16
|
)
|
|
14
17
|
|
|
@@ -120,3 +123,51 @@ def test_cli_output_with_options_dispatches_raw_yaml():
|
|
|
120
123
|
)
|
|
121
124
|
assert "size_bytes: 1024" in out
|
|
122
125
|
assert "size:" not in out
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# ── version helpers ───────────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
def test_build_cli_version_standard_shape():
|
|
131
|
+
v = build_cli_version("1.2.3")
|
|
132
|
+
assert v["code"] == "version"
|
|
133
|
+
assert v["version"] == "1.2.3"
|
|
134
|
+
assert "trace" not in v
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_cli_render_version_is_conventional_by_default():
|
|
138
|
+
assert cli_render_version("agent-cli", "1.2.3") == "agent-cli 1.2.3\n"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_cli_render_version_can_render_json():
|
|
142
|
+
out = cli_render_version("agent-cli", "1.2.3", OutputFormat.JSON)
|
|
143
|
+
assert out.endswith("\n")
|
|
144
|
+
assert '"code":"version"' in out
|
|
145
|
+
assert '"version":"1.2.3"' in out
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_cli_handle_version_is_conventional_by_default():
|
|
149
|
+
assert cli_handle_version_or_continue(["--version"], "agent-cli", "1.2.3") == "agent-cli 1.2.3\n"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def test_cli_handle_version_honors_output_flag():
|
|
153
|
+
out = cli_handle_version_or_continue(
|
|
154
|
+
["--version", "--output", "plain"],
|
|
155
|
+
"agent-cli",
|
|
156
|
+
"1.2.3",
|
|
157
|
+
)
|
|
158
|
+
assert out is not None
|
|
159
|
+
assert "code=version" in out
|
|
160
|
+
assert "version=1.2.3" in out
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_cli_handle_version_returns_none_without_version():
|
|
164
|
+
assert cli_handle_version_or_continue(["ping"], "agent-cli", "1.2.3") is None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_cli_handle_version_rejects_invalid_output():
|
|
168
|
+
with pytest.raises(ValueError, match="xml"):
|
|
169
|
+
cli_handle_version_or_continue(
|
|
170
|
+
["--version", "--output", "xml"],
|
|
171
|
+
"agent-cli",
|
|
172
|
+
"1.2.3",
|
|
173
|
+
)
|
|
@@ -25,6 +25,8 @@ from agent_first_data import (
|
|
|
25
25
|
output_plain,
|
|
26
26
|
output_plain_with_options,
|
|
27
27
|
normalize_utc_offset,
|
|
28
|
+
is_valid_rfc3339_date,
|
|
29
|
+
is_valid_rfc3339_time,
|
|
28
30
|
)
|
|
29
31
|
from agent_first_data.format import (
|
|
30
32
|
_format_bytes_human,
|
|
@@ -149,6 +151,12 @@ def test_helper_fixtures():
|
|
|
149
151
|
elif name == "normalize_utc_offset":
|
|
150
152
|
got = normalize_utc_offset(inp)
|
|
151
153
|
assert got == expected, f"[helpers/{name}({inp!r})] got {got!r}"
|
|
154
|
+
elif name == "is_valid_rfc3339_date":
|
|
155
|
+
got = is_valid_rfc3339_date(inp)
|
|
156
|
+
assert got == expected, f"[helpers/{name}({inp!r})] got {got!r}"
|
|
157
|
+
elif name == "is_valid_rfc3339_time":
|
|
158
|
+
got = is_valid_rfc3339_time(inp)
|
|
159
|
+
assert got == expected, f"[helpers/{name}({inp!r})] got {got!r}"
|
|
152
160
|
|
|
153
161
|
|
|
154
162
|
def test_output_format_fixtures():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agent_first_data-0.13.0 → agent_first_data-0.13.2}/agent_first_data.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|