autonomous-app 0.3.36__tar.gz → 0.3.38__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.
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/PKG-INFO +1 -1
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/__init__.py +1 -1
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/audioagent.py +0 -1
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/models/local_model.py +114 -37
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous_app.egg-info/PKG-INFO +1 -1
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/README.md +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/pyproject.toml +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/requirements.txt +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/setup.cfg +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/setup.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/baseagent.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/imageagent.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/jsonagent.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/models/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/models/gemini.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/ai/textagent.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/GHCallbacks.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/GHOrganization.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/GHRepo.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/GHVersionControl.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/auth/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/auth/autoauth.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/auth/github.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/auth/google.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/auth/user.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/cli.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/base/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/base/common.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/base/datastructures.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/base/document.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/base/fields.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/base/metaclasses.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/base/utils.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/common.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/connection.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/context_managers.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/db_sync.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/dereference.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/document.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/errors.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/fields.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/mongodb_support.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/pymongo_support.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/queryset/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/queryset/base.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/queryset/field_list.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/queryset/manager.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/queryset/queryset.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/queryset/transform.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/queryset/visitor.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/db/signals.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/logger.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/model/autoattr.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/model/automodel.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/storage/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/storage/imagestorage.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/storage/localstorage.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/taskrunner/__init__.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/taskrunner/autotasks.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/taskrunner/task_router.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/utils/markdown.py +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous_app.egg-info/SOURCES.txt +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous_app.egg-info/dependency_links.txt +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous_app.egg-info/requires.txt +0 -0
- {autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous_app.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autonomous-app
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.38
|
|
4
4
|
Summary: Containerized application framework built on Flask with additional libraries and tools for rapid development of web applications.
|
|
5
5
|
Author-email: Steven A Moore <samoore@binghamton.edu>
|
|
6
6
|
Project-URL: homepage, https://github.com/Sallenmoore/autonomous
|
|
@@ -2,13 +2,8 @@ import io
|
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
4
|
import random
|
|
5
|
-
import re
|
|
6
5
|
|
|
7
|
-
import numpy as np
|
|
8
|
-
import pymongo
|
|
9
|
-
import redis
|
|
10
6
|
import requests
|
|
11
|
-
from bson.objectid import ObjectId
|
|
12
7
|
from pydub import AudioSegment
|
|
13
8
|
|
|
14
9
|
from autonomous import log
|
|
@@ -44,17 +39,39 @@ class LocalAIModel(AutoModel):
|
|
|
44
39
|
return json.dumps(schema, indent=2)
|
|
45
40
|
|
|
46
41
|
def _clean_json_response(self, text):
|
|
47
|
-
"""
|
|
42
|
+
"""
|
|
43
|
+
Robust cleaner for Llama 3 outputs.
|
|
44
|
+
It handles markdown blocks, chatter before/after, and malformed endings.
|
|
45
|
+
"""
|
|
48
46
|
text = text.strip()
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
|
|
48
|
+
# 1. Strip Markdown Code Blocks (```json ... ```)
|
|
49
|
+
if "```" in text:
|
|
50
|
+
import re
|
|
51
|
+
|
|
52
|
+
# Regex to capture content inside ```json ... ``` or just ``` ... ```
|
|
53
|
+
# flags=re.DOTALL allows . to match newlines
|
|
54
|
+
pattern = r"```(?:json)?\s*(\{.*?\})\s*```"
|
|
55
|
+
match = re.search(pattern, text, re.DOTALL)
|
|
56
|
+
if match:
|
|
57
|
+
text = match.group(1)
|
|
58
|
+
else:
|
|
59
|
+
# Fallback: simple finding if regex fails due to weird chars
|
|
60
|
+
start = text.find("```")
|
|
61
|
+
end = text.rfind("```")
|
|
62
|
+
# Adjust start to skip the "json" part if present
|
|
63
|
+
first_newline = text.find("\n", start)
|
|
64
|
+
if first_newline != -1 and first_newline < end:
|
|
65
|
+
text = text[first_newline:end]
|
|
66
|
+
|
|
67
|
+
# 2. Heuristic extraction: Find the first '{' and the last '}'
|
|
68
|
+
# This fixes cases where Llama says "Here is the JSON: { ... }"
|
|
69
|
+
start_idx = text.find("{")
|
|
70
|
+
end_idx = text.rfind("}")
|
|
71
|
+
|
|
72
|
+
if start_idx != -1 and end_idx != -1:
|
|
73
|
+
text = text[start_idx : end_idx + 1]
|
|
74
|
+
|
|
58
75
|
return text.strip()
|
|
59
76
|
|
|
60
77
|
def generate_json(
|
|
@@ -62,51 +79,60 @@ class LocalAIModel(AutoModel):
|
|
|
62
79
|
):
|
|
63
80
|
schema_str = self._convert_tools_to_json_schema(function)
|
|
64
81
|
|
|
65
|
-
# 1.
|
|
82
|
+
# 1. Improved System Prompt
|
|
83
|
+
# We explicitly warn about nested quotes, which is the #1 killer of complex JSON
|
|
66
84
|
full_system_prompt = (
|
|
67
85
|
f"{self.instructions}. {additional_instructions}\n"
|
|
68
86
|
f"You are a strict JSON generator. Output ONLY a valid JSON object matching this schema:\n"
|
|
69
87
|
f"{schema_str}\n"
|
|
70
|
-
f"IMPORTANT
|
|
88
|
+
f"IMPORTANT RULES:\n"
|
|
89
|
+
f"1. Do not include markdown formatting or explanations.\n"
|
|
90
|
+
f"2. DOUBLE CHECK nested quotes inside strings. Escape them properly.\n"
|
|
91
|
+
f"3. Ensure all arrays and objects are closed.\n"
|
|
71
92
|
)
|
|
72
93
|
|
|
73
94
|
if context:
|
|
74
95
|
full_system_prompt += (
|
|
75
96
|
f"\n\n### GROUND TRUTH CONTEXT ###\n"
|
|
76
|
-
f"
|
|
77
|
-
f"If this context contradicts your internal knowledge (e.g., physics, facts), "
|
|
78
|
-
f"YOU MUST FOLLOW THE CONTEXT.\n"
|
|
97
|
+
f"Adhere strictly to this context:\n"
|
|
79
98
|
f"{json.dumps(context, indent=2)}"
|
|
80
99
|
)
|
|
81
100
|
elif uri:
|
|
82
101
|
full_system_prompt += f"Use the following URI for reference: {uri}"
|
|
83
102
|
|
|
84
|
-
# 3.
|
|
103
|
+
# 3. Payload with INCREASED CONTEXT and LOWER TEMPERATURE
|
|
85
104
|
payload = {
|
|
86
105
|
"model": self._json_model,
|
|
87
106
|
"messages": [
|
|
88
107
|
{"role": "system", "content": full_system_prompt},
|
|
89
108
|
{"role": "user", "content": message},
|
|
90
109
|
],
|
|
91
|
-
"format": "json",
|
|
110
|
+
"format": "json",
|
|
92
111
|
"stream": False,
|
|
93
112
|
"keep_alive": "24h",
|
|
113
|
+
"options": {
|
|
114
|
+
"num_ctx": 8192, # <--- Prevents cutoff on large schemas
|
|
115
|
+
"temperature": 0.2, # <--- Increases structural stability
|
|
116
|
+
},
|
|
94
117
|
}
|
|
95
118
|
|
|
119
|
+
log("==== LocalAI JSON Payload ====", payload, _print=True)
|
|
120
|
+
result_text = ""
|
|
96
121
|
try:
|
|
97
122
|
# print(f"==== {self._ollama_url}: LocalAI JSON Payload ====")
|
|
98
123
|
response = requests.post(f"{self._ollama_url}/chat", json=payload)
|
|
124
|
+
log(response)
|
|
99
125
|
response.raise_for_status()
|
|
100
126
|
|
|
101
127
|
result_text = response.json().get("message", {}).get("content", "{}")
|
|
102
128
|
|
|
103
|
-
# Clean
|
|
129
|
+
# Clean
|
|
104
130
|
clean_text = self._clean_json_response(result_text)
|
|
105
131
|
|
|
106
132
|
# Parse
|
|
107
133
|
result_dict = json.loads(clean_text)
|
|
108
134
|
|
|
109
|
-
# Unwrap
|
|
135
|
+
# Unwrap
|
|
110
136
|
if "parameters" in result_dict and isinstance(
|
|
111
137
|
result_dict["parameters"], dict
|
|
112
138
|
):
|
|
@@ -116,8 +142,16 @@ class LocalAIModel(AutoModel):
|
|
|
116
142
|
return result_dict
|
|
117
143
|
|
|
118
144
|
except Exception as e:
|
|
145
|
+
# If it fails, print the RAW text so you can see WHERE it broke.
|
|
119
146
|
log(f"==== LocalAI JSON Error: {e} ====", _print=True)
|
|
120
|
-
|
|
147
|
+
if result_text:
|
|
148
|
+
log(
|
|
149
|
+
f"--- FAILED RAW OUTPUT ---\n{result_text}\n-----------------------",
|
|
150
|
+
_print=True,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Returning empty prevents the whole app from dying on one bad generation.
|
|
154
|
+
return {}
|
|
121
155
|
|
|
122
156
|
def generate_text(self, message, additional_instructions="", uri="", context={}):
|
|
123
157
|
# 1. Base System Prompt
|
|
@@ -193,7 +227,6 @@ class LocalAIModel(AutoModel):
|
|
|
193
227
|
self,
|
|
194
228
|
prompt,
|
|
195
229
|
voice=None,
|
|
196
|
-
display_name="audio.mp3",
|
|
197
230
|
):
|
|
198
231
|
voice = voice or random.choice(list(self.VOICES.keys()))
|
|
199
232
|
try:
|
|
@@ -209,6 +242,27 @@ class LocalAIModel(AutoModel):
|
|
|
209
242
|
log(f"TTS Error: {e}", _print=True)
|
|
210
243
|
return None
|
|
211
244
|
|
|
245
|
+
# ... inside LocalAIModel class ...
|
|
246
|
+
|
|
247
|
+
def _get_dimensions(self, aspect_ratio):
|
|
248
|
+
"""
|
|
249
|
+
Maps abstract aspect ratios to optimal SDXL resolutions.
|
|
250
|
+
SDXL performs best at ~1024x1024 total pixels.
|
|
251
|
+
"""
|
|
252
|
+
resolutions = {
|
|
253
|
+
"1:1": (1024, 1024),
|
|
254
|
+
"3:4": (896, 1152),
|
|
255
|
+
"4:3": (1152, 896),
|
|
256
|
+
"16:9": (1216, 832),
|
|
257
|
+
"2K": (2048, 1080),
|
|
258
|
+
"4K": (3840, 2160),
|
|
259
|
+
"9:16": (832, 1216),
|
|
260
|
+
"3:2": (1216, 832),
|
|
261
|
+
"2:3": (832, 1216),
|
|
262
|
+
}
|
|
263
|
+
# Default to 1:1 (1024x1024) if unknown
|
|
264
|
+
return resolutions.get(aspect_ratio, (1024, 1024))
|
|
265
|
+
|
|
212
266
|
def generate_image(
|
|
213
267
|
self,
|
|
214
268
|
prompt,
|
|
@@ -217,32 +271,55 @@ class LocalAIModel(AutoModel):
|
|
|
217
271
|
aspect_ratio="3:4",
|
|
218
272
|
image_size="2K",
|
|
219
273
|
):
|
|
274
|
+
# 1. CLIP Token Limit Fix (Auto-Summarize)
|
|
275
|
+
if len(prompt) > 300:
|
|
276
|
+
log("⚠️ Prompt exceeds CLIP limit. rewriting...", _print=True)
|
|
277
|
+
summary_instruction = (
|
|
278
|
+
"Convert the description into a comma-separated Stable Diffusion prompt. "
|
|
279
|
+
"Keep visual elements and style. Under 50 words."
|
|
280
|
+
)
|
|
281
|
+
new_prompt = self.generate_text(
|
|
282
|
+
message=prompt, additional_instructions=summary_instruction, context={}
|
|
283
|
+
)
|
|
284
|
+
if new_prompt and len(new_prompt) > 10:
|
|
285
|
+
prompt = new_prompt
|
|
286
|
+
|
|
287
|
+
# 2. Resolution Calculation
|
|
288
|
+
width, height = self._get_dimensions(aspect_ratio)
|
|
289
|
+
|
|
290
|
+
# 3. Construct Payload
|
|
291
|
+
# We send both the abstract params (for logging/metadata)
|
|
292
|
+
# and the concrete pixels (for the engine).
|
|
293
|
+
data = {
|
|
294
|
+
"prompt": prompt,
|
|
295
|
+
"negative_prompt": negative_prompt,
|
|
296
|
+
"aspect_ratio": aspect_ratio,
|
|
297
|
+
"width": width, # <--- Calculated Pixel Width
|
|
298
|
+
"height": height, # <--- Calculated Pixel Height
|
|
299
|
+
}
|
|
300
|
+
|
|
220
301
|
try:
|
|
221
|
-
|
|
302
|
+
# Handle Files (Dict -> List of Tuples for requests)
|
|
222
303
|
img_files = {}
|
|
223
|
-
if files:
|
|
304
|
+
if files and isinstance(files, dict):
|
|
224
305
|
for fn, f_bytes in files.items():
|
|
225
306
|
if isinstance(f_bytes, bytes):
|
|
226
307
|
file_obj = io.BytesIO(f_bytes)
|
|
227
308
|
else:
|
|
228
309
|
file_obj = f_bytes
|
|
229
310
|
img_files["file"] = (fn, file_obj, "image/png")
|
|
311
|
+
|
|
312
|
+
# Send Request
|
|
313
|
+
if img_files:
|
|
230
314
|
response = requests.post(
|
|
231
315
|
f"{self._media_url}/generate-image", data=data, files=img_files
|
|
232
316
|
)
|
|
233
317
|
else:
|
|
234
318
|
response = requests.post(f"{self._media_url}/generate-image", data=data)
|
|
319
|
+
|
|
235
320
|
response.raise_for_status()
|
|
236
321
|
return response.content
|
|
322
|
+
|
|
237
323
|
except Exception as e:
|
|
238
324
|
log(f"Image Gen Error: {e}", _print=True)
|
|
239
325
|
return None
|
|
240
|
-
|
|
241
|
-
def list_voices(self, filters=[]):
|
|
242
|
-
if not filters:
|
|
243
|
-
return list(self.VOICES.keys())
|
|
244
|
-
voices = []
|
|
245
|
-
for voice, attribs in self.VOICES.items():
|
|
246
|
-
if any(f.lower() in attribs for f in filters):
|
|
247
|
-
voices.append(voice)
|
|
248
|
-
return voices
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autonomous-app
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.38
|
|
4
4
|
Summary: Containerized application framework built on Flask with additional libraries and tools for rapid development of web applications.
|
|
5
5
|
Author-email: Steven A Moore <samoore@binghamton.edu>
|
|
6
6
|
Project-URL: homepage, https://github.com/Sallenmoore/autonomous
|
|
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
|
{autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/GHCallbacks.py
RENAMED
|
File without changes
|
|
File without changes
|
{autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/GHRepo.py
RENAMED
|
File without changes
|
|
File without changes
|
{autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous/apis/version_control/__init__.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
|
|
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
|
{autonomous_app-0.3.36 → autonomous_app-0.3.38}/src/autonomous_app.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|