instructor 1.2.0__tar.gz → 1.2.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.
- {instructor-1.2.0 → instructor-1.2.2}/PKG-INFO +4 -2
- {instructor-1.2.0 → instructor-1.2.2}/instructor/__init__.py +5 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/cli/usage.py +5 -5
- {instructor-1.2.0 → instructor-1.2.2}/instructor/client.py +3 -1
- {instructor-1.2.0 → instructor-1.2.2}/instructor/client_anthropic.py +4 -2
- {instructor-1.2.0 → instructor-1.2.2}/instructor/client_cohere.py +4 -2
- {instructor-1.2.0 → instructor-1.2.2}/instructor/client_groq.py +4 -2
- instructor-1.2.2/instructor/client_mistral.py +57 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/patch.py +12 -6
- {instructor-1.2.0 → instructor-1.2.2}/instructor/retry.py +45 -6
- {instructor-1.2.0 → instructor-1.2.2}/instructor/utils.py +3 -0
- {instructor-1.2.0 → instructor-1.2.2}/pyproject.toml +6 -3
- {instructor-1.2.0 → instructor-1.2.2}/LICENSE +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/README.md +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/_types/__init__.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/_types/_alias.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/cli/__init__.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/cli/cli.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/cli/files.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/cli/hub.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/cli/jobs.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/distil.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/__init__.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/citation.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/iterable.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/maybe.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/parallel.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/partial.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/simple_type.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/dsl/validators.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/exceptions.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/function_calls.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/mode.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/process_response.py +0 -0
- {instructor-1.2.0 → instructor-1.2.2}/instructor/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: instructor
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: structured outputs for llm
|
|
5
5
|
Home-page: https://github.com/jxnl/instructor
|
|
6
6
|
License: MIT
|
|
@@ -16,15 +16,17 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
16
16
|
Provides-Extra: anthropic
|
|
17
17
|
Provides-Extra: cohere
|
|
18
18
|
Provides-Extra: groq
|
|
19
|
+
Provides-Extra: mistralai
|
|
19
20
|
Provides-Extra: test-docs
|
|
20
21
|
Requires-Dist: aiohttp (>=3.9.1,<4.0.0)
|
|
21
22
|
Requires-Dist: anthropic (>=0.23.1,<0.24.0) ; extra == "anthropic" or extra == "test-docs"
|
|
22
23
|
Requires-Dist: cohere (>=5.1.8,<6.0.0) ; extra == "cohere" or extra == "test-docs"
|
|
23
24
|
Requires-Dist: diskcache (>=5.6.3,<6.0.0) ; extra == "test-docs"
|
|
24
|
-
Requires-Dist: docstring-parser (>=0.
|
|
25
|
+
Requires-Dist: docstring-parser (>=0.16,<0.17)
|
|
25
26
|
Requires-Dist: fastapi (>=0.109.2,<0.110.0) ; extra == "test-docs"
|
|
26
27
|
Requires-Dist: groq (>=0.4.2,<0.5.0) ; extra == "groq" or extra == "test-docs"
|
|
27
28
|
Requires-Dist: litellm (>=1.0.0,<2.0.0) ; extra == "test-docs"
|
|
29
|
+
Requires-Dist: mistralai (>=0.1.8,<0.2.0) ; extra == "test-docs" or extra == "mistralai"
|
|
28
30
|
Requires-Dist: openai (>=1.1.0,<2.0.0)
|
|
29
31
|
Requires-Dist: pandas (>=2.2.0,<3.0.0) ; extra == "test-docs"
|
|
30
32
|
Requires-Dist: pydantic (==2.7.0)
|
|
@@ -57,6 +57,11 @@ if importlib.util.find_spec("groq") is not None:
|
|
|
57
57
|
|
|
58
58
|
__all__ += ["from_groq"]
|
|
59
59
|
|
|
60
|
+
if importlib.util.find_spec("mistralai") is not None:
|
|
61
|
+
from .client_mistral import from_mistral
|
|
62
|
+
|
|
63
|
+
__all__ += ["from_mistral"]
|
|
64
|
+
|
|
60
65
|
if importlib.util.find_spec("cohere") is not None:
|
|
61
66
|
from .client_cohere import from_cohere
|
|
62
67
|
|
|
@@ -114,11 +114,11 @@ def calculate_cost(
|
|
|
114
114
|
|
|
115
115
|
def group_and_sum_by_date_and_snapshot(usage_data: List[Dict[str, Any]]) -> Table:
|
|
116
116
|
"""Group and sum the usage data by date and snapshot, including costs."""
|
|
117
|
-
summary: DefaultDict[
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
summary: DefaultDict[
|
|
118
|
+
str, DefaultDict[str, Dict[str, Union[int, float]]]
|
|
119
|
+
] = defaultdict(
|
|
120
|
+
lambda: defaultdict(
|
|
121
|
+
lambda: {"total_requests": 0, "total_tokens": 0, "total_cost": 0.0}
|
|
122
122
|
)
|
|
123
123
|
)
|
|
124
124
|
|
|
@@ -280,6 +280,7 @@ def from_openai(
|
|
|
280
280
|
instructor.Mode.TOOLS,
|
|
281
281
|
instructor.Mode.JSON,
|
|
282
282
|
instructor.Mode.JSON_SCHEMA,
|
|
283
|
+
instructor.Mode.MD_JSON,
|
|
283
284
|
}
|
|
284
285
|
|
|
285
286
|
if provider in {Provider.OPENAI}:
|
|
@@ -315,7 +316,8 @@ def from_litellm(
|
|
|
315
316
|
completion: Callable,
|
|
316
317
|
mode: instructor.Mode = instructor.Mode.TOOLS,
|
|
317
318
|
**kwargs,
|
|
318
|
-
) -> Instructor:
|
|
319
|
+
) -> Instructor:
|
|
320
|
+
...
|
|
319
321
|
|
|
320
322
|
|
|
321
323
|
@overload
|
|
@@ -13,7 +13,8 @@ def from_anthropic(
|
|
|
13
13
|
| anthropic.AnthropicVertex,
|
|
14
14
|
mode: instructor.Mode = instructor.Mode.ANTHROPIC_JSON,
|
|
15
15
|
**kwargs,
|
|
16
|
-
) -> instructor.Instructor:
|
|
16
|
+
) -> instructor.Instructor:
|
|
17
|
+
...
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
@overload
|
|
@@ -23,7 +24,8 @@ def from_anthropic(
|
|
|
23
24
|
| anthropic.AsyncAnthropicVertex,
|
|
24
25
|
mode: instructor.Mode = instructor.Mode.ANTHROPIC_JSON,
|
|
25
26
|
**kwargs,
|
|
26
|
-
) -> instructor.Instructor:
|
|
27
|
+
) -> instructor.Instructor:
|
|
28
|
+
...
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
def from_anthropic(
|
|
@@ -23,7 +23,8 @@ def from_cohere(
|
|
|
23
23
|
client: cohere.Client,
|
|
24
24
|
mode: instructor.Mode = instructor.Mode.COHERE_TOOLS,
|
|
25
25
|
**kwargs,
|
|
26
|
-
) -> instructor.Instructor:
|
|
26
|
+
) -> instructor.Instructor:
|
|
27
|
+
...
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
@overload
|
|
@@ -31,7 +32,8 @@ def from_cohere(
|
|
|
31
32
|
client: cohere.AsyncClient,
|
|
32
33
|
mode: instructor.Mode = instructor.Mode.COHERE_TOOLS,
|
|
33
34
|
**kwargs,
|
|
34
|
-
) -> instructor.AsyncInstructor:
|
|
35
|
+
) -> instructor.AsyncInstructor:
|
|
36
|
+
...
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
def from_cohere(
|
|
@@ -11,7 +11,8 @@ def from_groq(
|
|
|
11
11
|
client: groq.Groq,
|
|
12
12
|
mode: instructor.Mode = instructor.Mode.TOOLS,
|
|
13
13
|
**kwargs,
|
|
14
|
-
) -> instructor.Instructor:
|
|
14
|
+
) -> instructor.Instructor:
|
|
15
|
+
...
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
@overload
|
|
@@ -19,7 +20,8 @@ def from_groq(
|
|
|
19
20
|
client: groq.AsyncGroq,
|
|
20
21
|
mode: instructor.Mode = instructor.Mode.TOOLS,
|
|
21
22
|
**kwargs,
|
|
22
|
-
) -> instructor.Instructor:
|
|
23
|
+
) -> instructor.Instructor:
|
|
24
|
+
...
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
def from_groq(
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Future imports to ensure compatibility with Python 3.9
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import mistralai.client
|
|
5
|
+
import mistralai.async_client as mistralaiasynccli
|
|
6
|
+
import instructor
|
|
7
|
+
from typing import overload
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@overload
|
|
11
|
+
def from_mistral(
|
|
12
|
+
client: mistralai.client.MistralClient,
|
|
13
|
+
mode: instructor.Mode = instructor.Mode.MISTRAL_TOOLS,
|
|
14
|
+
**kwargs,
|
|
15
|
+
) -> instructor.Instructor: ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@overload
|
|
19
|
+
def from_mistral(
|
|
20
|
+
client: mistralaiasynccli.MistralAsyncClient,
|
|
21
|
+
mode: instructor.Mode = instructor.Mode.MISTRAL_TOOLS,
|
|
22
|
+
**kwargs,
|
|
23
|
+
) -> instructor.AsyncInstructor: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def from_mistral(
|
|
27
|
+
client: mistralai.client.MistralClient | mistralaiasynccli.MistralAsyncClient,
|
|
28
|
+
mode: instructor.Mode = instructor.Mode.MISTRAL_TOOLS,
|
|
29
|
+
**kwargs,
|
|
30
|
+
) -> instructor.Instructor | instructor.AsyncInstructor:
|
|
31
|
+
assert mode in {
|
|
32
|
+
instructor.Mode.MISTRAL_TOOLS,
|
|
33
|
+
}, "Mode be one of {instructor.Mode.MISTRAL_TOOLS}"
|
|
34
|
+
|
|
35
|
+
assert isinstance(
|
|
36
|
+
client, (mistralai.client.MistralClient, mistralaiasynccli.MistralAsyncClient)
|
|
37
|
+
), "Client must be an instance of mistralai.client.MistralClient or mistralai.async_cli.MistralAsyncClient"
|
|
38
|
+
|
|
39
|
+
if isinstance(client, mistralai.client.MistralClient):
|
|
40
|
+
|
|
41
|
+
return instructor.Instructor(
|
|
42
|
+
client=client,
|
|
43
|
+
create=instructor.patch(create=client.chat, mode=mode),
|
|
44
|
+
provider=instructor.Provider.MISTRAL,
|
|
45
|
+
mode=mode,
|
|
46
|
+
**kwargs,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
else:
|
|
50
|
+
|
|
51
|
+
return instructor.AsyncInstructor(
|
|
52
|
+
client=client,
|
|
53
|
+
create=instructor.patch(create=client.chat, mode=mode),
|
|
54
|
+
provider=instructor.Provider.MISTRAL,
|
|
55
|
+
mode=mode,
|
|
56
|
+
**kwargs,
|
|
57
|
+
)
|
|
@@ -36,7 +36,8 @@ class InstructorChatCompletionCreate(Protocol):
|
|
|
36
36
|
max_retries: int = 1,
|
|
37
37
|
*args: T_ParamSpec.args,
|
|
38
38
|
**kwargs: T_ParamSpec.kwargs,
|
|
39
|
-
) -> T_Model:
|
|
39
|
+
) -> T_Model:
|
|
40
|
+
...
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
class AsyncInstructorChatCompletionCreate(Protocol):
|
|
@@ -47,35 +48,40 @@ class AsyncInstructorChatCompletionCreate(Protocol):
|
|
|
47
48
|
max_retries: int = 1,
|
|
48
49
|
*args: T_ParamSpec.args,
|
|
49
50
|
**kwargs: T_ParamSpec.kwargs,
|
|
50
|
-
) -> T_Model:
|
|
51
|
+
) -> T_Model:
|
|
52
|
+
...
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
@overload
|
|
54
56
|
def patch(
|
|
55
57
|
client: OpenAI,
|
|
56
58
|
mode: Mode = Mode.TOOLS,
|
|
57
|
-
) -> OpenAI:
|
|
59
|
+
) -> OpenAI:
|
|
60
|
+
...
|
|
58
61
|
|
|
59
62
|
|
|
60
63
|
@overload
|
|
61
64
|
def patch(
|
|
62
65
|
client: AsyncOpenAI,
|
|
63
66
|
mode: Mode = Mode.TOOLS,
|
|
64
|
-
) -> AsyncOpenAI:
|
|
67
|
+
) -> AsyncOpenAI:
|
|
68
|
+
...
|
|
65
69
|
|
|
66
70
|
|
|
67
71
|
@overload
|
|
68
72
|
def patch(
|
|
69
73
|
create: Callable[T_ParamSpec, T_Retval],
|
|
70
74
|
mode: Mode = Mode.TOOLS,
|
|
71
|
-
) -> InstructorChatCompletionCreate:
|
|
75
|
+
) -> InstructorChatCompletionCreate:
|
|
76
|
+
...
|
|
72
77
|
|
|
73
78
|
|
|
74
79
|
@overload
|
|
75
80
|
def patch(
|
|
76
81
|
create: Awaitable[T_Retval],
|
|
77
82
|
mode: Mode = Mode.TOOLS,
|
|
78
|
-
) -> InstructorChatCompletionCreate:
|
|
83
|
+
) -> InstructorChatCompletionCreate:
|
|
84
|
+
...
|
|
79
85
|
|
|
80
86
|
|
|
81
87
|
def patch(
|
|
@@ -30,6 +30,23 @@ T_ParamSpec = ParamSpec("T_ParamSpec")
|
|
|
30
30
|
T = TypeVar("T")
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
class InstructorRetryException(Exception):
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
*args,
|
|
37
|
+
last_completion,
|
|
38
|
+
messages: list,
|
|
39
|
+
n_attempts: int,
|
|
40
|
+
total_usage,
|
|
41
|
+
**kwargs,
|
|
42
|
+
):
|
|
43
|
+
self.last_completion = last_completion
|
|
44
|
+
self.messages = messages
|
|
45
|
+
self.n_attempts = n_attempts
|
|
46
|
+
self.total_usage = total_usage
|
|
47
|
+
super().__init__(*args, **kwargs)
|
|
48
|
+
|
|
49
|
+
|
|
33
50
|
def reask_messages(response: ChatCompletion, mode: Mode, exception: Exception):
|
|
34
51
|
if mode == Mode.ANTHROPIC_TOOLS:
|
|
35
52
|
# The original response
|
|
@@ -144,10 +161,21 @@ def retry_sync(
|
|
|
144
161
|
kwargs["messages"] = merge_consecutive_messages(
|
|
145
162
|
kwargs["messages"]
|
|
146
163
|
)
|
|
147
|
-
raise
|
|
164
|
+
raise InstructorRetryException(
|
|
165
|
+
e,
|
|
166
|
+
last_completion=response,
|
|
167
|
+
n_attempts=attempt.retry_state.attempt_number,
|
|
168
|
+
messages=kwargs["messages"],
|
|
169
|
+
total_usage=total_usage,
|
|
170
|
+
) from e
|
|
148
171
|
except RetryError as e:
|
|
149
|
-
|
|
150
|
-
|
|
172
|
+
raise InstructorRetryException(
|
|
173
|
+
e,
|
|
174
|
+
last_completion=response,
|
|
175
|
+
n_attempts=attempt.retry_state.attempt_number,
|
|
176
|
+
messages=kwargs["messages"],
|
|
177
|
+
total_usage=total_usage,
|
|
178
|
+
) from e
|
|
151
179
|
|
|
152
180
|
|
|
153
181
|
async def retry_async(
|
|
@@ -161,7 +189,6 @@ async def retry_async(
|
|
|
161
189
|
mode: Mode = Mode.TOOLS,
|
|
162
190
|
) -> T:
|
|
163
191
|
total_usage = CompletionUsage(completion_tokens=0, prompt_tokens=0, total_tokens=0)
|
|
164
|
-
|
|
165
192
|
# If max_retries is int, then create a AsyncRetrying object
|
|
166
193
|
if isinstance(max_retries, int):
|
|
167
194
|
logger.debug(f"max_retries: {max_retries}")
|
|
@@ -197,7 +224,19 @@ async def retry_async(
|
|
|
197
224
|
kwargs["messages"] = merge_consecutive_messages(
|
|
198
225
|
kwargs["messages"]
|
|
199
226
|
)
|
|
200
|
-
raise
|
|
227
|
+
raise InstructorRetryException(
|
|
228
|
+
e,
|
|
229
|
+
last_completion=response,
|
|
230
|
+
n_attempts=e.attempt_number,
|
|
231
|
+
messages=kwargs["messages"],
|
|
232
|
+
total_usage=total_usage,
|
|
233
|
+
) from e
|
|
201
234
|
except RetryError as e:
|
|
202
235
|
logger.exception(f"Failed after retries: {e.last_attempt.exception}")
|
|
203
|
-
raise
|
|
236
|
+
raise InstructorRetryException(
|
|
237
|
+
e,
|
|
238
|
+
last_completion=response,
|
|
239
|
+
n_attempts=e.attempt_number,
|
|
240
|
+
messages=kwargs["messages"],
|
|
241
|
+
total_usage=total_usage,
|
|
242
|
+
) from e
|
|
@@ -23,6 +23,7 @@ class Provider(Enum):
|
|
|
23
23
|
ANYSCALE = "anyscale"
|
|
24
24
|
TOGETHER = "together"
|
|
25
25
|
GROQ = "groq"
|
|
26
|
+
MISTRAL = "mistral"
|
|
26
27
|
COHERE = "cohere"
|
|
27
28
|
UNKNOWN = "unknown"
|
|
28
29
|
|
|
@@ -38,6 +39,8 @@ def get_provider(base_url: str) -> Provider:
|
|
|
38
39
|
return Provider.GROQ
|
|
39
40
|
elif "openai" in str(base_url):
|
|
40
41
|
return Provider.OPENAI
|
|
42
|
+
elif "mistral" in str(base_url):
|
|
43
|
+
return Provider.MISTRAL
|
|
41
44
|
elif "cohere" in str(base_url):
|
|
42
45
|
return Provider.COHERE
|
|
43
46
|
return Provider.UNKNOWN
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "instructor"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.2"
|
|
4
4
|
description = "structured outputs for llm"
|
|
5
5
|
authors = ["Jason Liu <jason@jxnl.co>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -12,7 +12,7 @@ repository = "https://github.com/jxnl/instructor"
|
|
|
12
12
|
python = "^3.9"
|
|
13
13
|
openai = "^1.1.0"
|
|
14
14
|
pydantic = "2.7.0"
|
|
15
|
-
docstring-parser = "^0.
|
|
15
|
+
docstring-parser = "^0.16"
|
|
16
16
|
typer = ">=0.9.0,<1.0.0"
|
|
17
17
|
rich = "^13.7.0"
|
|
18
18
|
aiohttp = "^3.9.1"
|
|
@@ -31,12 +31,14 @@ anthropic = { version = "^0.23.1", optional = true }
|
|
|
31
31
|
xmltodict = { version = "^0.13.0", optional = true }
|
|
32
32
|
groq = { version = "^0.4.2", optional = true }
|
|
33
33
|
cohere = { version = "^5.1.8", optional = true }
|
|
34
|
+
mistralai = { version = "^0.1.8", optional = true }
|
|
34
35
|
|
|
35
36
|
[tool.poetry.extras]
|
|
36
37
|
anthropic = ["anthropic", "xmltodict"]
|
|
37
38
|
groq = ["groq"]
|
|
38
39
|
cohere = ["cohere"]
|
|
39
|
-
test-docs = ["fastapi", "redis", "diskcache", "pandas", "tabulate", "pydantic_extra_types", "litellm", "anthropic", "groq", "cohere"]
|
|
40
|
+
test-docs = ["fastapi", "redis", "diskcache", "pandas", "tabulate", "pydantic_extra_types", "litellm", "anthropic", "groq", "cohere", "mistralai"]
|
|
41
|
+
mistralai = ["mistralai"]
|
|
40
42
|
|
|
41
43
|
[tool.poetry.scripts]
|
|
42
44
|
instructor = "instructor.cli.cli:app"
|
|
@@ -74,6 +76,7 @@ xmltodict = "^0.13.0"
|
|
|
74
76
|
groq = "^0.4.2"
|
|
75
77
|
phonenumbers = "^8.13.33"
|
|
76
78
|
cohere = "^5.1.8"
|
|
79
|
+
mistralai = "^0.1.8"
|
|
77
80
|
|
|
78
81
|
[build-system]
|
|
79
82
|
requires = ["poetry-core"]
|
|
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
|