cortexapps-cli 1.7.0__tar.gz → 1.10.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.
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/PKG-INFO +2 -2
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/backup.py +4 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/newrelic.py +59 -21
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/cortex_client.py +23 -2
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/pyproject.toml +2 -2
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/LICENSE +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/README.rst +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/cli.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/command_options.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/api_keys.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/audit_logs.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/backup_commands/cortex_export.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/catalog.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/custom_data.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/custom_events.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/custom_metrics.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/dependencies.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/deploys.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/discovery_audit.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/docs.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_relationship_types.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_relationships.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_types.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/gitops_logs.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/groups.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/initiatives.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/aws.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/azure_devops.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/azure_resources.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/circleci.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/coralogix.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/datadog.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/github.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/gitlab.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/incidentio.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/launchdarkly.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/pagerduty.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/prometheus.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/sonarqube.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/ip_allowlist.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/on_call.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/go.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/java.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/node.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/nuget.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/python.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/plugins.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/queries.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/rest.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/scim.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/scorecards.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/scorecards_commands/exemptions.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/secrets.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/teams.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/workflows.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/models/team.py +0 -0
- {cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cortexapps-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
4
4
|
Summary: Command Line Interface for cortexapps
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -18,7 +18,7 @@ Requires-Dist: click (<8.2)
|
|
|
18
18
|
Requires-Dist: pyyaml (>=6.0.1,<7)
|
|
19
19
|
Requires-Dist: requests (>=2.32.4,<3.0.0)
|
|
20
20
|
Requires-Dist: typer (>=0.12.5,<0.13.0)
|
|
21
|
-
Requires-Dist: urllib3 (>=2.
|
|
21
|
+
Requires-Dist: urllib3 (>=2.6.0)
|
|
22
22
|
Project-URL: Bug Tracker, https://github.com/cortexapps/cli/issues
|
|
23
23
|
Project-URL: Changes, https://github.com/cortexapps/cli/blob/main/HISTORY.md
|
|
24
24
|
Project-URL: Documentation, https://github.com/cortexapps/cli/blob/main/README.rst
|
|
@@ -698,3 +698,7 @@ def import_tenant(
|
|
|
698
698
|
print(f"cortex scorecards create -f \"{file_path}\"")
|
|
699
699
|
elif import_type == "workflows":
|
|
700
700
|
print(f"cortex workflows create -f \"{file_path}\"")
|
|
701
|
+
|
|
702
|
+
# Exit with non-zero code if any imports failed
|
|
703
|
+
if total_failed > 0:
|
|
704
|
+
raise typer.Exit(1)
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
from enum import Enum
|
|
1
2
|
import json
|
|
2
3
|
from rich import print_json
|
|
3
4
|
import typer
|
|
4
5
|
from typing_extensions import Annotated
|
|
6
|
+
from cortexapps_cli.command_options import ListCommandOptions
|
|
7
|
+
from cortexapps_cli.utils import print_output_with_context
|
|
5
8
|
|
|
6
9
|
app = typer.Typer(help="New Relic commands", no_args_is_help=True)
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
class Region(str, Enum):
|
|
12
|
+
US = "US"
|
|
13
|
+
EU = "EU"
|
|
14
|
+
|
|
15
|
+
@app.command(no_args_is_help=True)
|
|
9
16
|
def add(
|
|
10
17
|
ctx: typer.Context,
|
|
11
|
-
alias: str = typer.Option(
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
alias: str = typer.Option(None, "--alias", "-a", help="Alias for this configuration"),
|
|
19
|
+
account_id: str = typer.Option(None, "--account-id", "-acc", help="New Relic account ID"),
|
|
20
|
+
personal_key: str = typer.Option(None, "--personal-key", "-pk", help="New Relic personal API key"),
|
|
21
|
+
region: Region = typer.Option(Region.US, "--region", "-r", help="Region (US or EU)"),
|
|
14
22
|
is_default: bool = typer.Option(False, "--is-default", "-i", help="If this is the default configuration"),
|
|
15
23
|
file_input: Annotated[typer.FileText, typer.Option("--file", "-f", help="JSON file containing configurations, if command line options not used; can be passed as stdin with -, example: -f-")] = None,
|
|
16
24
|
):
|
|
@@ -21,40 +29,56 @@ def add(
|
|
|
21
29
|
client = ctx.obj["client"]
|
|
22
30
|
|
|
23
31
|
if file_input:
|
|
24
|
-
if alias or
|
|
25
|
-
raise typer.BadParameter("When providing a
|
|
32
|
+
if alias or account_id or personal_key:
|
|
33
|
+
raise typer.BadParameter("When providing a file, do not specify --alias, --account-id, or --personal-key")
|
|
26
34
|
data = json.loads("".join([line for line in file_input]))
|
|
27
35
|
else:
|
|
36
|
+
if not alias or not account_id or not personal_key:
|
|
37
|
+
raise typer.BadParameter("--alias, --account-id, and --personal-key are required when not using --file")
|
|
38
|
+
if not personal_key.startswith("NRAK"):
|
|
39
|
+
raise typer.BadParameter("--personal-key must start with 'NRAK'")
|
|
28
40
|
data = {
|
|
29
41
|
"alias": alias,
|
|
30
|
-
"
|
|
31
|
-
"
|
|
42
|
+
"accountId": account_id,
|
|
43
|
+
"personalKey": personal_key,
|
|
44
|
+
"region": region.value,
|
|
32
45
|
"isDefault": is_default,
|
|
33
|
-
}
|
|
46
|
+
}
|
|
34
47
|
|
|
35
|
-
# remove any data elements that are None - can only be is_default
|
|
36
|
-
data = {k: v for k, v in data.items() if v is not None}
|
|
37
|
-
|
|
38
48
|
r = client.post("api/v1/newrelic/configuration", data=data)
|
|
39
49
|
print_json(data=r)
|
|
40
50
|
|
|
41
|
-
@app.command()
|
|
51
|
+
@app.command(no_args_is_help=True)
|
|
42
52
|
def add_multiple(
|
|
43
53
|
ctx: typer.Context,
|
|
44
54
|
file_input: Annotated[typer.FileText, typer.Option("--file", "-f", help="JSON file containing configurations; can be passed as stdin with -, example: -f-")] = None,
|
|
45
55
|
):
|
|
46
56
|
"""
|
|
47
57
|
Add multiple configurations
|
|
58
|
+
|
|
59
|
+
JSON file format:
|
|
60
|
+
\b
|
|
61
|
+
{
|
|
62
|
+
"configurations": [
|
|
63
|
+
{
|
|
64
|
+
"accountId": 1,
|
|
65
|
+
"alias": "text",
|
|
66
|
+
"isDefault": true,
|
|
67
|
+
"personalKey": "text",
|
|
68
|
+
"region": "US"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
48
72
|
"""
|
|
49
73
|
|
|
50
74
|
client = ctx.obj["client"]
|
|
51
75
|
|
|
52
76
|
data = json.loads("".join([line for line in file_input]))
|
|
53
77
|
|
|
54
|
-
r = client.
|
|
78
|
+
r = client.post("api/v1/newrelic/configurations", data=data)
|
|
55
79
|
print_json(data=r)
|
|
56
80
|
|
|
57
|
-
@app.command()
|
|
81
|
+
@app.command(no_args_is_help=True)
|
|
58
82
|
def delete(
|
|
59
83
|
ctx: typer.Context,
|
|
60
84
|
alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
|
|
@@ -81,7 +105,7 @@ def delete_all(
|
|
|
81
105
|
r = client.delete("api/v1/newrelic/configurations")
|
|
82
106
|
print_json(data=r)
|
|
83
107
|
|
|
84
|
-
@app.command()
|
|
108
|
+
@app.command(no_args_is_help=True)
|
|
85
109
|
def get(
|
|
86
110
|
ctx: typer.Context,
|
|
87
111
|
alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
|
|
@@ -98,6 +122,12 @@ def get(
|
|
|
98
122
|
@app.command()
|
|
99
123
|
def list(
|
|
100
124
|
ctx: typer.Context,
|
|
125
|
+
table_output: ListCommandOptions.table_output = False,
|
|
126
|
+
csv_output: ListCommandOptions.csv_output = False,
|
|
127
|
+
columns: ListCommandOptions.columns = [],
|
|
128
|
+
no_headers: ListCommandOptions.no_headers = False,
|
|
129
|
+
filters: ListCommandOptions.filters = [],
|
|
130
|
+
sort: ListCommandOptions.sort = [],
|
|
101
131
|
):
|
|
102
132
|
"""
|
|
103
133
|
Get all configurations
|
|
@@ -105,8 +135,16 @@ def list(
|
|
|
105
135
|
|
|
106
136
|
client = ctx.obj["client"]
|
|
107
137
|
|
|
138
|
+
if (table_output or csv_output) and not ctx.params.get('columns'):
|
|
139
|
+
ctx.params['columns'] = [
|
|
140
|
+
"Alias=alias",
|
|
141
|
+
"AccountId=accountId",
|
|
142
|
+
"Region=region",
|
|
143
|
+
"IsDefault=isDefault",
|
|
144
|
+
]
|
|
145
|
+
|
|
108
146
|
r = client.get("api/v1/newrelic/configurations")
|
|
109
|
-
|
|
147
|
+
print_output_with_context(ctx, r)
|
|
110
148
|
|
|
111
149
|
@app.command()
|
|
112
150
|
def get_default(
|
|
@@ -122,7 +160,7 @@ def get_default(
|
|
|
122
160
|
print_json(data=r)
|
|
123
161
|
|
|
124
162
|
|
|
125
|
-
@app.command()
|
|
163
|
+
@app.command(no_args_is_help=True)
|
|
126
164
|
def update(
|
|
127
165
|
ctx: typer.Context,
|
|
128
166
|
alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
|
|
@@ -142,7 +180,7 @@ def update(
|
|
|
142
180
|
r = client.put("api/v1/newrelic/configuration/" + alias, data=data)
|
|
143
181
|
print_json(data=r)
|
|
144
182
|
|
|
145
|
-
@app.command()
|
|
183
|
+
@app.command(no_args_is_help=True)
|
|
146
184
|
def validate(
|
|
147
185
|
ctx: typer.Context,
|
|
148
186
|
alias: str = typer.Option(..., "--alias", "-a", help="The alias of the configuration"),
|
|
@@ -153,7 +191,7 @@ def validate(
|
|
|
153
191
|
|
|
154
192
|
client = ctx.obj["client"]
|
|
155
193
|
|
|
156
|
-
r = client.post("api/v1/newrelic/
|
|
194
|
+
r = client.post("api/v1/newrelic/configuration/validate/" + alias)
|
|
157
195
|
print_json(data=r)
|
|
158
196
|
|
|
159
197
|
@app.command()
|
|
@@ -166,5 +204,5 @@ def validate_all(
|
|
|
166
204
|
|
|
167
205
|
client = ctx.obj["client"]
|
|
168
206
|
|
|
169
|
-
r = client.post("api/v1/newrelic/
|
|
207
|
+
r = client.post("api/v1/newrelic/configuration/validate")
|
|
170
208
|
print_json(data=r)
|
|
@@ -149,6 +149,23 @@ class CortexClient:
|
|
|
149
149
|
# try to parse the error message
|
|
150
150
|
error = response.json()
|
|
151
151
|
status = response.status_code
|
|
152
|
+
|
|
153
|
+
# Check for validation error format with violations array
|
|
154
|
+
if 'violations' in error and isinstance(error['violations'], list):
|
|
155
|
+
print(f'[red][bold]HTTP Error {status}[/bold][/red]: Validation failed')
|
|
156
|
+
for violation in error['violations']:
|
|
157
|
+
title = violation.get('title', 'Validation Error')
|
|
158
|
+
description = violation.get('description', 'No description')
|
|
159
|
+
violation_type = violation.get('violationType', '')
|
|
160
|
+
pointer = violation.get('pointer', '')
|
|
161
|
+
print(f' [yellow]{title}[/yellow]: {description}')
|
|
162
|
+
if pointer:
|
|
163
|
+
print(f' [dim]Location: {pointer}[/dim]')
|
|
164
|
+
if violation_type:
|
|
165
|
+
print(f' [dim]Type: {violation_type}[/dim]')
|
|
166
|
+
raise typer.Exit(code=1)
|
|
167
|
+
|
|
168
|
+
# Standard error format with message/details
|
|
152
169
|
message = error.get('message', 'Unknown error')
|
|
153
170
|
details = error.get('details', 'No details')
|
|
154
171
|
request_id = error.get('requestId', 'No request ID')
|
|
@@ -156,8 +173,12 @@ class CortexClient:
|
|
|
156
173
|
print(error_str)
|
|
157
174
|
raise typer.Exit(code=1)
|
|
158
175
|
except json.JSONDecodeError:
|
|
159
|
-
# if we can't parse the error message,
|
|
160
|
-
response.
|
|
176
|
+
# if we can't parse the error message, print a clean error and exit
|
|
177
|
+
status = response.status_code
|
|
178
|
+
reason = response.reason or 'Unknown error'
|
|
179
|
+
error_str = f'[red][bold]HTTP Error {status}[/bold][/red]: {reason}'
|
|
180
|
+
print(error_str)
|
|
181
|
+
raise typer.Exit(code=1)
|
|
161
182
|
|
|
162
183
|
if raw_response:
|
|
163
184
|
return response
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "cortexapps-cli"
|
|
3
3
|
# version will be incremented via command line as part of github actions build
|
|
4
|
-
version = "1.
|
|
4
|
+
version = "1.10.0"
|
|
5
5
|
description = "Command Line Interface for cortexapps"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
authors = [
|
|
@@ -19,7 +19,7 @@ classifiers = [
|
|
|
19
19
|
python = "^3.11"
|
|
20
20
|
requests = "^2.32.4"
|
|
21
21
|
pyyaml = ">= 6.0.1, < 7"
|
|
22
|
-
urllib3 = ">= 2.
|
|
22
|
+
urllib3 = ">= 2.6.0"
|
|
23
23
|
typer = "^0.12.5"
|
|
24
24
|
click = "<8.2"
|
|
25
25
|
|
|
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
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_relationship_types.py
RENAMED
|
File without changes
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/entity_relationships.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/integrations_commands/aws.py
RENAMED
|
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
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/go.py
RENAMED
|
File without changes
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/java.py
RENAMED
|
File without changes
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/node.py
RENAMED
|
File without changes
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/nuget.py
RENAMED
|
File without changes
|
{cortexapps_cli-1.7.0 → cortexapps_cli-1.10.0}/cortexapps_cli/commands/packages_commands/python.py
RENAMED
|
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
|