sv-cli 0.5.0__tar.gz → 0.6.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.
Files changed (78) hide show
  1. {sv_cli-0.5.0 → sv_cli-0.6.0}/AGENT.md +16 -16
  2. {sv_cli-0.5.0 → sv_cli-0.6.0}/PKG-INFO +5 -5
  3. {sv_cli-0.5.0 → sv_cli-0.6.0}/README.md +4 -4
  4. {sv_cli-0.5.0 → sv_cli-0.6.0}/docs/commands.md +1 -1
  5. {sv_cli-0.5.0 → sv_cli-0.6.0}/pyproject.toml +1 -1
  6. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/__init__.py +1 -1
  7. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/adapters.py +8 -2
  8. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/tasks.py +1 -1
  9. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/test_help_filtering.py +12 -0
  10. {sv_cli-0.5.0 → sv_cli-0.6.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  11. {sv_cli-0.5.0 → sv_cli-0.6.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  12. {sv_cli-0.5.0 → sv_cli-0.6.0}/.github/workflows/publish.yml +0 -0
  13. {sv_cli-0.5.0 → sv_cli-0.6.0}/.github/workflows/release.yml +0 -0
  14. {sv_cli-0.5.0 → sv_cli-0.6.0}/.github/workflows/test.yml +0 -0
  15. {sv_cli-0.5.0 → sv_cli-0.6.0}/.gitignore +0 -0
  16. {sv_cli-0.5.0 → sv_cli-0.6.0}/CHANGELOG.md +0 -0
  17. {sv_cli-0.5.0 → sv_cli-0.6.0}/CODE_OF_CONDUCT.md +0 -0
  18. {sv_cli-0.5.0 → sv_cli-0.6.0}/CONTRIBUTING.md +0 -0
  19. {sv_cli-0.5.0 → sv_cli-0.6.0}/LICENSE +0 -0
  20. {sv_cli-0.5.0 → sv_cli-0.6.0}/PULL_REQUEST_TEMPLATE.md +0 -0
  21. {sv_cli-0.5.0 → sv_cli-0.6.0}/SECURITY.md +0 -0
  22. {sv_cli-0.5.0 → sv_cli-0.6.0}/docs/agent-usage.md +0 -0
  23. {sv_cli-0.5.0 → sv_cli-0.6.0}/docs/api-definition-format.md +0 -0
  24. {sv_cli-0.5.0 → sv_cli-0.6.0}/docs/authentication.md +0 -0
  25. {sv_cli-0.5.0 → sv_cli-0.6.0}/docs/examples.md +0 -0
  26. {sv_cli-0.5.0 → sv_cli-0.6.0}/docs/installation.md +0 -0
  27. {sv_cli-0.5.0 → sv_cli-0.6.0}/docs/troubleshooting.md +0 -0
  28. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/api_client.py +0 -0
  29. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/__init__.py +0 -0
  30. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/auth.py +0 -0
  31. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/better_keywords.py +0 -0
  32. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/call.py +0 -0
  33. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/config.py +0 -0
  34. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/content_quality.py +0 -0
  35. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/content_transformer.py +0 -0
  36. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/core_analysis.py +0 -0
  37. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/definitions.py +0 -0
  38. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/geo_audit.py +0 -0
  39. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/insight_igniter.py +0 -0
  40. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/marketplace_services.py +0 -0
  41. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/options.py +0 -0
  42. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/preliminary_audit.py +0 -0
  43. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/ranklens.py +0 -0
  44. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/seo_image.py +0 -0
  45. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/seo_mapping.py +0 -0
  46. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/seogpt.py +0 -0
  47. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/seogpt2.py +0 -0
  48. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/seogpt_compare.py +0 -0
  49. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/top_competitors.py +0 -0
  50. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/commands/topical_authority.py +0 -0
  51. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/config.py +0 -0
  52. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/definitions.py +0 -0
  53. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/errors.py +0 -0
  54. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/executor.py +0 -0
  55. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/formatter.py +0 -0
  56. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/main.py +0 -0
  57. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/renderers/__init__.py +0 -0
  58. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/renderers/csv_renderer.py +0 -0
  59. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/renderers/json_renderer.py +0 -0
  60. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/renderers/markdown_renderer.py +0 -0
  61. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/renderers/table_renderer.py +0 -0
  62. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/renderers/text_renderer.py +0 -0
  63. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/resolver.py +0 -0
  64. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/schemas/__init__.py +0 -0
  65. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/schemas/api_response.py +0 -0
  66. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/schemas/config.py +0 -0
  67. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/schemas/tool_definition.py +0 -0
  68. {sv_cli-0.5.0 → sv_cli-0.6.0}/src/sv_cli/utils.py +0 -0
  69. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/fixtures/api_root.json +0 -0
  70. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/fixtures/better_keywords_response.json +0 -0
  71. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/fixtures/ranklens_definitions.json +0 -0
  72. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/fixtures/seogpt2_definitions.json +0 -0
  73. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/fixtures/seogpt_definitions.json +0 -0
  74. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/test_config.py +0 -0
  75. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/test_definitions.py +0 -0
  76. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/test_executor.py +0 -0
  77. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/test_formatter.py +0 -0
  78. {sv_cli-0.5.0 → sv_cli-0.6.0}/tests/test_resolver.py +0 -0
@@ -64,7 +64,7 @@ All 16 available tools. Use exact command names — aliases are human shortcuts.
64
64
  | `ranklens` | — | `rank` | `--entity` `--url` | No |
65
65
  | `seo-image` | `image` | `generate` | `--keyword` | No |
66
66
  | `seogpt` | `seo-gpt` | `generate` | `--keyword` `--type` | No |
67
- | `seogpt2` | `seo-gpt2` | `create-task` | `--topic` *(`--keyword`/`--kw` is a separate, optional field)* | Yes |
67
+ | `prose` | `seogpt2`, `seo-gpt2` | `create-task` | `--topic` *(`--keyword`/`--kw` is a separate, optional field)* | Yes |
68
68
  | `seogpt-compare` | `compare` | `create-task` | `--url` `--keyword` | Yes |
69
69
  | `seo-mapping` | `mapping` | `create-task` | `--url` `--keyword` | Yes |
70
70
  | `topical-authority` | `topical` | `topics` | `--keyword` | No |
@@ -84,7 +84,7 @@ preliminary-audit: analyze, raw
84
84
  ranklens: rank, competitors, raw
85
85
  seo-image: generate, raw
86
86
  seogpt: generate, raw
87
- seogpt2: create-task, get-task-status, get-result, raw
87
+ prose: create-task, get-task-status, get-result, raw
88
88
  seogpt-compare: create-task, get-task-status, get-result, raw
89
89
  seo-mapping: create-task, get-task-status, get-result, raw
90
90
  topical-authority: topics, raw
@@ -118,11 +118,11 @@ sv seogpt engines
118
118
  sv image types
119
119
  sv image themes
120
120
  sv image themes --search wild
121
- sv seogpt2 types
122
- sv seogpt2 lengths
123
- sv seogpt2 languages
124
- sv seogpt2 tones
125
- sv seogpt2 engines
121
+ sv prose types
122
+ sv prose lengths
123
+ sv prose languages
124
+ sv prose tones
125
+ sv prose engines
126
126
  sv geo-audit types
127
127
  sv geo-audit languages
128
128
  sv seo-mapping types
@@ -190,7 +190,7 @@ Parse: `response["data"]["text"]`
190
190
  ```
191
191
  Parse: `response["data"]` — array of objects
192
192
 
193
- **Async task created** (`geo-audit create-task`, `seogpt2 create-task`, `seogpt-compare create-task`, `seo-mapping create-task`):
193
+ **Async task created** (`geo-audit create-task`, `prose create-task`, `seogpt-compare create-task`, `seo-mapping create-task`):
194
194
  ```json
195
195
  { "data": { "task_id": "wFEGe...", "status": "pending", "stage": "queued", "percent_complete": 1 } }
196
196
  ```
@@ -247,7 +247,7 @@ sv geo-audit get-task-status --task-id TASK_ID --format json
247
247
  sv geo-audit get-result --task-id TASK_ID --format json
248
248
  ```
249
249
 
250
- Same for `seogpt2`, `seogpt-compare`, `seo-mapping` — replace `geo-audit` with the tool name.
250
+ Same for `prose`, `seogpt-compare`, `seo-mapping` — replace `geo-audit` with the tool name.
251
251
 
252
252
  ---
253
253
 
@@ -255,17 +255,17 @@ Same for `seogpt2`, `seogpt-compare`, `seo-mapping` — replace `geo-audit` with
255
255
 
256
256
  These differ from the standard pattern — get them wrong and the call fails.
257
257
 
258
- ### seogpt2 — `--topic` maps to `Topic` (required), `--keyword`/`--kw` is a separate field
258
+ ### prose — `--topic` maps to `Topic` (required), `--keyword`/`--kw` is a separate field
259
259
 
260
260
  ```bash
261
261
  # CORRECT — --topic sends value as the required "Topic" API field
262
- sv seogpt2 create-task --topic "White Label SEO for Agencies" --type on-page-blog-article --wait --strict --no-fuzzy --non-interactive --format json
262
+ sv prose create-task --topic "White Label SEO for Agencies" --type on-page-blog-article --wait --strict --no-fuzzy --non-interactive --format json
263
263
 
264
264
  # --title is an alias for --topic (same field)
265
- sv seogpt2 create-task --title "White Label SEO for Agencies" --type on-page-blog-article --wait --strict --no-fuzzy --non-interactive --format json
265
+ sv prose create-task --title "White Label SEO for Agencies" --type on-page-blog-article --wait --strict --no-fuzzy --non-interactive --format json
266
266
 
267
267
  # --keyword/--kw maps to the separate, optional KW field — it does NOT set Topic
268
- sv seogpt2 create-task --topic "White Label SEO for Agencies" --keyword "white label seo" --type on-page-blog-article --wait --strict --no-fuzzy --non-interactive --format json
268
+ sv prose create-task --topic "White Label SEO for Agencies" --keyword "white label seo" --type on-page-blog-article --wait --strict --no-fuzzy --non-interactive --format json
269
269
  ```
270
270
 
271
271
  ### better-keywords `filter` — requires `data` array from prior `research` call
@@ -319,7 +319,7 @@ sv task status TASK_ID --tool geo-audit --format json
319
319
  |---|---|---|
320
320
  | `Could not resolve --type "X" in strict mode` | Value is not a valid slug or ID | Run `sv options TOOL type` → use `id` or `slug` column |
321
321
  | `Could not resolve --type "X"` (no strict) | No match found at any level | Run `sv options TOOL type --search X` to find closest match |
322
- | `Topic is required` | seogpt2 called without `--topic` | Add `--topic "your topic"` |
322
+ | `Topic is required` | prose called without `--topic` | Add `--topic "your topic"` |
323
323
  | `task_id is invalid` | Task has expired on the server | Create a new task |
324
324
  | `No local tool mapping found for task` | Task not in `~/.sv/tasks.json` | Add `--tool TOOL_NAME` explicitly |
325
325
  | `API authentication failed: HTTP 401` | Bad or missing API key | Check `SV_API_KEY` environment variable |
@@ -381,7 +381,7 @@ sv preliminary-audit analyze --url https://example.com --strict --no-fuzzy --non
381
381
  sv ranklens rank --entity "white label seo" --url https://example.com --strict --no-fuzzy --non-interactive --format json
382
382
  sv seo-image generate --keyword "white label seo" --type 33 --strict --no-fuzzy --non-interactive --format json
383
383
  sv seogpt generate --keyword "white label seo" --type 18 --strict --no-fuzzy --non-interactive --format json
384
- sv seogpt2 create-task --topic "White Label SEO for Agencies" --type 0 --wait --strict --no-fuzzy --non-interactive --format json
384
+ sv prose create-task --topic "White Label SEO for Agencies" --type 0 --wait --strict --no-fuzzy --non-interactive --format json
385
385
  sv seogpt-compare create-task --url https://example.com --keyword "white label seo" --wait --strict --no-fuzzy --non-interactive --format json
386
386
  sv seo-mapping create-task --url https://example.com --keyword "white label seo" --wait --strict --no-fuzzy --non-interactive --format json
387
387
  sv topical-authority topics --keyword "white label seo" --strict --no-fuzzy --non-interactive --format json
@@ -394,4 +394,4 @@ Common enum IDs (verify with `sv options` — these are from live API at time of
394
394
  - `seogpt --type 18` = Meta Description
395
395
  - `seogpt --type 8` = Page Title
396
396
  - `seo-image --type 33` = Blog Header Image
397
- - `seogpt2 --type 0` = On-Page Blog Article
397
+ - `prose --type 0` = On-Page Blog Article
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sv-cli
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: Open-source, definition-driven command-line client for SV AI API tools.
5
5
  Project-URL: Homepage, https://github.com/seovendorco/sv-cli
6
6
  Project-URL: Issues, https://github.com/seovendorco/sv-cli/issues
@@ -163,7 +163,7 @@ sv title --keyword "white label seo" --url https://example.com
163
163
  | `ranklens` | | `ranklens` |
164
164
  | `seo-image` | `image` | `seo-image` |
165
165
  | `seogpt` | `seo-gpt` | `seogpt` |
166
- | `seogpt2` | `seo-gpt2` | `seogpt2` |
166
+ | `prose` | `seogpt2`, `seo-gpt2` | `seogpt2` |
167
167
  | `seogpt-compare` | `compare` | `seogptcompare` |
168
168
  | `seo-mapping` | `mapping` | `seogptmapping` |
169
169
  | `topical-authority` | `topical` | `topical-authority` |
@@ -252,13 +252,13 @@ sv task status TASK_ID --tool geo-audit
252
252
  sv task result TASK_ID --tool geo-audit
253
253
  ```
254
254
 
255
- `seogpt2` is another async tool. Its required field is `Topic` (a title or subject), mapped via `--topic` (`--title` is an alias for the same field). `--keyword`/`--kw` is a separate, optional field for additional keywords — it does not set the topic:
255
+ `prose` (formerly `seogpt2`) is another async tool. Its required field is `Topic` (a title or subject), mapped via `--topic` (`--title` is an alias for the same field). `--keyword`/`--kw` is a separate, optional field for additional keywords — it does not set the topic:
256
256
 
257
257
  ```bash
258
- sv seogpt2 create-task --topic "White Label SEO for Agencies" --type on-page-blog-article --wait
258
+ sv prose create-task --topic "White Label SEO for Agencies" --type on-page-blog-article --wait
259
259
  ```
260
260
 
261
- See available types with `sv seogpt2 types`, lengths with `sv seogpt2 lengths`, engines with `sv seogpt2 engines`.
261
+ See available types with `sv prose types`, lengths with `sv prose lengths`, engines with `sv prose engines`.
262
262
 
263
263
  Manual 3-step flow (without `--wait`):
264
264
 
@@ -128,7 +128,7 @@ sv title --keyword "white label seo" --url https://example.com
128
128
  | `ranklens` | | `ranklens` |
129
129
  | `seo-image` | `image` | `seo-image` |
130
130
  | `seogpt` | `seo-gpt` | `seogpt` |
131
- | `seogpt2` | `seo-gpt2` | `seogpt2` |
131
+ | `prose` | `seogpt2`, `seo-gpt2` | `seogpt2` |
132
132
  | `seogpt-compare` | `compare` | `seogptcompare` |
133
133
  | `seo-mapping` | `mapping` | `seogptmapping` |
134
134
  | `topical-authority` | `topical` | `topical-authority` |
@@ -217,13 +217,13 @@ sv task status TASK_ID --tool geo-audit
217
217
  sv task result TASK_ID --tool geo-audit
218
218
  ```
219
219
 
220
- `seogpt2` is another async tool. Its required field is `Topic` (a title or subject), mapped via `--topic` (`--title` is an alias for the same field). `--keyword`/`--kw` is a separate, optional field for additional keywords — it does not set the topic:
220
+ `prose` (formerly `seogpt2`) is another async tool. Its required field is `Topic` (a title or subject), mapped via `--topic` (`--title` is an alias for the same field). `--keyword`/`--kw` is a separate, optional field for additional keywords — it does not set the topic:
221
221
 
222
222
  ```bash
223
- sv seogpt2 create-task --topic "White Label SEO for Agencies" --type on-page-blog-article --wait
223
+ sv prose create-task --topic "White Label SEO for Agencies" --type on-page-blog-article --wait
224
224
  ```
225
225
 
226
- See available types with `sv seogpt2 types`, lengths with `sv seogpt2 lengths`, engines with `sv seogpt2 engines`.
226
+ See available types with `sv prose types`, lengths with `sv prose lengths`, engines with `sv prose engines`.
227
227
 
228
228
  Manual 3-step flow (without `--wait`):
229
229
 
@@ -24,7 +24,7 @@ sv preliminary-audit run --url https://example.com
24
24
  sv ranklens analyze --brand "SV" --keyword "white label seo"
25
25
  sv seo-image generate --keyword "white label seo" --type blog-header
26
26
  sv seogpt generate --type meta-description --keyword "white label seo"
27
- sv seogpt2 article --keyword "white label seo" --wait
27
+ sv prose article --keyword "white label seo" --wait
28
28
  sv seogpt-compare run --url https://example.com --keyword "white label seo"
29
29
  sv seo-mapping run --url https://example.com --keywords "seo agency" --wait
30
30
  sv topical-authority generate --keyword "local seo"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sv-cli"
7
- version = "0.5.0"
7
+ version = "0.6.0"
8
8
  description = "Open-source, definition-driven command-line client for SV AI API tools."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """SV CLI package."""
2
2
 
3
- __version__ = "0.4.0"
3
+ __version__ = "0.6.0"
@@ -184,9 +184,15 @@ TOOL_ADAPTERS: dict[str, ToolAdapter] = {
184
184
  },
185
185
  ),
186
186
  "seogpt2": ToolAdapter(
187
+ # "Prose" is the current product name; seogpt2 is the original one, kept
188
+ # working as an alias so existing scripts don't break. canonical stays
189
+ # "seogpt2" deliberately - it's what the live API root still keys this
190
+ # tool under, and keeping it means the CLI works whether or not the
191
+ # /api/prose/ alias folder is deployed yet. Flip it to "prose" only when
192
+ # /api/seogpt2/ is actually retired.
187
193
  canonical="seogpt2",
188
- command="seogpt2",
189
- aliases=("seo-gpt2",),
194
+ command="prose",
195
+ aliases=("seogpt2", "seo-gpt2"),
190
196
  default_action="create-task",
191
197
  actions=("create-task", "get-task-status", "get-result", "raw"),
192
198
  field_aliases={
@@ -50,7 +50,7 @@ def get_task_tool(task_id: str, tool: str | None = None) -> str:
50
50
  return str(entry["tool"])
51
51
  raise ConfigError(
52
52
  f'No local tool mapping found for task "{task_id}". Re-run with --tool, for example: '
53
- f"sv task status {task_id} --tool seogpt2"
53
+ f"sv task status {task_id} --tool prose"
54
54
  )
55
55
 
56
56
 
@@ -78,3 +78,15 @@ def test_tool_help_separates_actions_from_option_lookups(tmp_path):
78
78
  actions_section = output.split("Option lookups")[0]
79
79
  assert "create-task" in actions_section
80
80
  assert "languages" not in actions_section
81
+
82
+
83
+ def test_prose_is_the_primary_name_and_seogpt2_still_works(tmp_path):
84
+ """Prose is the current product name; the old names stay as aliases.
85
+
86
+ All three must resolve to the same tool - dropping seogpt2/seo-gpt2 would
87
+ break any existing script that hardcodes them.
88
+ """
89
+ for name in ("prose", "seogpt2", "seo-gpt2"):
90
+ output = _run_cli(tmp_path, name, "create-task", "--help")
91
+ assert "--topic" in output, f"{name} did not resolve to the Prose tool"
92
+ assert "--keyword" in output
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