clerk-sdk 0.4.9__tar.gz → 0.4.10__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.
- {clerk_sdk-0.4.9/clerk_sdk.egg-info → clerk_sdk-0.4.10}/PKG-INFO +1 -1
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/client_actor/client_actor.py +2 -2
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_actions/actions.py +43 -8
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_inspector/models.py +14 -2
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_machine/state_machine.py +1 -1
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10/clerk_sdk.egg-info}/PKG-INFO +1 -1
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk_sdk.egg-info/SOURCES.txt +0 -1
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/setup.py +1 -1
- clerk_sdk-0.4.9/clerk/gui_automation/ui_state_machine/models.py +0 -40
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/LICENSE +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/MANIFEST.in +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/README.md +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/base.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/client.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/decorator/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/decorator/models.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/decorator/task_decorator.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/exceptions/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/exceptions/exceptions.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/exceptions/remote_device.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/action_model/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/action_model/model.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/action_model/utils.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/client.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/client_actor/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/client_actor/exception.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/client_actor/model.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/decorators/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/decorators/gui_automation.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/exceptions/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/exceptions/agent_manager.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/exceptions/modality/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/exceptions/modality/exc.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/exceptions/websocket.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/requirements.txt +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_actions/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_actions/base.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_actions/support.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_inspector/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_inspector/gui_vision.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_machine/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_machine/ai_recovery.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_machine/decorators.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/gui_automation/ui_state_machine/exceptions.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/models/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/models/document.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/models/document_statuses.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/models/file.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/models/remote_device.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/models/response_model.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/models/ui_operator.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/utils/__init__.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/utils/logger.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk/utils/save_artifact.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk_sdk.egg-info/dependency_links.txt +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk_sdk.egg-info/requires.txt +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/clerk_sdk.egg-info/top_level.txt +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/pyproject.toml +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/requirements.txt +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/setup.cfg +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_base.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_client.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_document_models.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_exceptions.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_file_models.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_gui_automation.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_task_decorator.py +0 -0
- {clerk_sdk-0.4.9 → clerk_sdk-0.4.10}/tests/test_utils.py +0 -0
|
@@ -42,9 +42,9 @@ async def _perform_action_ws(payload: Dict[str, Any]) -> PerformActionResponse:
|
|
|
42
42
|
|
|
43
43
|
# 2. wait for ack message
|
|
44
44
|
try:
|
|
45
|
-
ack = await asyncio.wait_for(global_ws.recv(),
|
|
45
|
+
ack = await asyncio.wait_for(global_ws.recv(), 10)
|
|
46
46
|
if ack == "OK":
|
|
47
|
-
action_info = await asyncio.wait_for(global_ws.recv(),
|
|
47
|
+
action_info = await asyncio.wait_for(global_ws.recv(), 10)
|
|
48
48
|
return PerformActionResponse(**json.loads(action_info))
|
|
49
49
|
else:
|
|
50
50
|
raise RuntimeError("Received ACK != OK")
|
|
@@ -24,7 +24,7 @@ from ..client_actor.model import (
|
|
|
24
24
|
from ..client_actor.exception import GetScreenError
|
|
25
25
|
from ..exceptions.modality.exc import ModalityNotKnownError
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
MAX_TRIES = 3
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class File(BaseModel):
|
|
@@ -80,7 +80,7 @@ class LeftClick(BaseAction):
|
|
|
80
80
|
@backoff.on_exception(
|
|
81
81
|
backoff.expo,
|
|
82
82
|
(RuntimeError, GetScreenError),
|
|
83
|
-
|
|
83
|
+
max_tries=MAX_TRIES,
|
|
84
84
|
on_giveup=maybe_engage_operator_ui_action,
|
|
85
85
|
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
86
86
|
)
|
|
@@ -123,7 +123,7 @@ class RightClick(BaseAction):
|
|
|
123
123
|
@backoff.on_exception(
|
|
124
124
|
backoff.expo,
|
|
125
125
|
(RuntimeError, GetScreenError),
|
|
126
|
-
|
|
126
|
+
max_tries=MAX_TRIES,
|
|
127
127
|
on_giveup=maybe_engage_operator_ui_action,
|
|
128
128
|
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
129
129
|
)
|
|
@@ -166,7 +166,7 @@ class MiddleClickAction(BaseAction):
|
|
|
166
166
|
@backoff.on_exception(
|
|
167
167
|
backoff.expo,
|
|
168
168
|
(RuntimeError, GetScreenError),
|
|
169
|
-
|
|
169
|
+
max_tries=MAX_TRIES,
|
|
170
170
|
on_giveup=maybe_engage_operator_ui_action,
|
|
171
171
|
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
172
172
|
)
|
|
@@ -209,7 +209,7 @@ class DoubleClick(BaseAction):
|
|
|
209
209
|
@backoff.on_exception(
|
|
210
210
|
backoff.expo,
|
|
211
211
|
(RuntimeError, GetScreenError),
|
|
212
|
-
|
|
212
|
+
max_tries=MAX_TRIES,
|
|
213
213
|
on_giveup=maybe_engage_operator_ui_action,
|
|
214
214
|
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
215
215
|
)
|
|
@@ -256,7 +256,7 @@ class Scroll(BaseAction):
|
|
|
256
256
|
@backoff.on_exception(
|
|
257
257
|
backoff.expo,
|
|
258
258
|
(RuntimeError, GetScreenError),
|
|
259
|
-
|
|
259
|
+
max_tries=MAX_TRIES,
|
|
260
260
|
on_giveup=maybe_engage_operator_ui_action,
|
|
261
261
|
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
262
262
|
)
|
|
@@ -306,6 +306,13 @@ class SendKeys(BaseAction):
|
|
|
306
306
|
)
|
|
307
307
|
return self
|
|
308
308
|
|
|
309
|
+
@backoff.on_exception(
|
|
310
|
+
backoff.expo,
|
|
311
|
+
(RuntimeError, GetScreenError),
|
|
312
|
+
max_tries=MAX_TRIES,
|
|
313
|
+
on_giveup=maybe_engage_operator_ui_action,
|
|
314
|
+
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
315
|
+
)
|
|
309
316
|
def do(self):
|
|
310
317
|
payload: Screenshot
|
|
311
318
|
try:
|
|
@@ -356,6 +363,13 @@ class PressKeys(BaseAction):
|
|
|
356
363
|
action_type: ActionTypes = "press_keys"
|
|
357
364
|
keys: str
|
|
358
365
|
|
|
366
|
+
@backoff.on_exception(
|
|
367
|
+
backoff.expo,
|
|
368
|
+
(RuntimeError, GetScreenError),
|
|
369
|
+
max_tries=MAX_TRIES,
|
|
370
|
+
on_giveup=maybe_engage_operator_ui_action,
|
|
371
|
+
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
372
|
+
)
|
|
359
373
|
def do(self):
|
|
360
374
|
# provide widget + screen to the action model via http request
|
|
361
375
|
execute_payload = ExecutePayload(
|
|
@@ -484,6 +498,13 @@ class ForceCloseApplication(BaseAction):
|
|
|
484
498
|
description="Process name from task manager. Example: process.exe"
|
|
485
499
|
)
|
|
486
500
|
|
|
501
|
+
@backoff.on_exception(
|
|
502
|
+
backoff.expo,
|
|
503
|
+
(RuntimeError, GetScreenError),
|
|
504
|
+
max_tries=MAX_TRIES,
|
|
505
|
+
on_giveup=maybe_engage_operator_ui_action,
|
|
506
|
+
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
507
|
+
)
|
|
487
508
|
def do(self):
|
|
488
509
|
payload = ApplicationExecutePayload(
|
|
489
510
|
action_type=self.action_type,
|
|
@@ -531,6 +552,13 @@ class SaveFiles(BaseAction):
|
|
|
531
552
|
files_details.append(file)
|
|
532
553
|
return files_details
|
|
533
554
|
|
|
555
|
+
@backoff.on_exception(
|
|
556
|
+
backoff.expo,
|
|
557
|
+
(RuntimeError, GetScreenError),
|
|
558
|
+
max_tries=MAX_TRIES,
|
|
559
|
+
on_giveup=maybe_engage_operator_ui_action,
|
|
560
|
+
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
561
|
+
)
|
|
534
562
|
def do(self):
|
|
535
563
|
payload = SaveFilesExecutePayload(
|
|
536
564
|
action_type=self.action_type,
|
|
@@ -558,6 +586,13 @@ class DeleteFiles(BaseAction):
|
|
|
558
586
|
action_type: ActionTypes = "delete_files"
|
|
559
587
|
files_location: List[str]
|
|
560
588
|
|
|
589
|
+
@backoff.on_exception(
|
|
590
|
+
backoff.expo,
|
|
591
|
+
(RuntimeError, GetScreenError),
|
|
592
|
+
max_tries=MAX_TRIES,
|
|
593
|
+
on_giveup=maybe_engage_operator_ui_action,
|
|
594
|
+
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
595
|
+
)
|
|
561
596
|
def do(self):
|
|
562
597
|
payload = DeleteFilesExecutePayload(
|
|
563
598
|
action_type=self.action_type, files_location=self.files_location
|
|
@@ -714,7 +749,7 @@ class GetText(BaseAction):
|
|
|
714
749
|
@backoff.on_exception(
|
|
715
750
|
backoff.expo,
|
|
716
751
|
(RuntimeError, GetScreenError),
|
|
717
|
-
|
|
752
|
+
max_tries=MAX_TRIES,
|
|
718
753
|
on_giveup=maybe_engage_operator_ui_action,
|
|
719
754
|
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
720
755
|
)
|
|
@@ -759,7 +794,7 @@ class PasteText(BaseAction):
|
|
|
759
794
|
@backoff.on_exception(
|
|
760
795
|
backoff.expo,
|
|
761
796
|
(RuntimeError, GetScreenError),
|
|
762
|
-
|
|
797
|
+
max_tries=MAX_TRIES,
|
|
763
798
|
on_giveup=maybe_engage_operator_ui_action,
|
|
764
799
|
raise_on_giveup=False, # Exception might be raised in the giveup handler instead
|
|
765
800
|
)
|
|
@@ -161,7 +161,9 @@ class ActionString(BaseModel):
|
|
|
161
161
|
|
|
162
162
|
Attributes:
|
|
163
163
|
action_string (str): The string representation of the action.
|
|
164
|
-
|
|
164
|
+
action_comment (str, optional): An optional comment about the action.
|
|
165
|
+
observation (str, optional): An optional observation related to the action.
|
|
166
|
+
interrupt_process (bool, optional): A flag indicating whether the action should interrupt the process.
|
|
165
167
|
|
|
166
168
|
Methods:
|
|
167
169
|
ensure_format(v: str) -> str:
|
|
@@ -170,7 +172,9 @@ class ActionString(BaseModel):
|
|
|
170
172
|
"""
|
|
171
173
|
|
|
172
174
|
action_string: str
|
|
173
|
-
|
|
175
|
+
action_comment: Optional[str] = None
|
|
176
|
+
observation: Optional[str] = None
|
|
177
|
+
interrupt_process: Optional[bool] = False
|
|
174
178
|
|
|
175
179
|
@field_validator("action_string", mode="before")
|
|
176
180
|
@classmethod
|
|
@@ -180,3 +184,11 @@ class ActionString(BaseModel):
|
|
|
180
184
|
if not v.endswith(".do()") and not v.startswith("NoAction"):
|
|
181
185
|
raise ValueError("Action string must end with '.do()'")
|
|
182
186
|
return v
|
|
187
|
+
|
|
188
|
+
@field_validator("interrupt_process", mode="before")
|
|
189
|
+
def convert_to_bool(cls, v: str | bool | None):
|
|
190
|
+
if v is None:
|
|
191
|
+
return False
|
|
192
|
+
elif isinstance(v, str):
|
|
193
|
+
return v.lower() in ["true", "1", "yes"]
|
|
194
|
+
return v
|
|
@@ -21,7 +21,7 @@ from .exceptions import (
|
|
|
21
21
|
CourseCorrectionImpossible,
|
|
22
22
|
SuccessfulCompletion,
|
|
23
23
|
)
|
|
24
|
-
from
|
|
24
|
+
from gui_automation.ui_state_inspector.models import ActionString
|
|
25
25
|
from .ai_recovery import CourseCorrector, course_corrector_v1
|
|
26
26
|
from ..client_actor.exception import PerformActionException
|
|
27
27
|
from ..ui_state_inspector.gui_vision import Vision
|
|
@@ -41,7 +41,6 @@ clerk/gui_automation/ui_state_machine/__init__.py
|
|
|
41
41
|
clerk/gui_automation/ui_state_machine/ai_recovery.py
|
|
42
42
|
clerk/gui_automation/ui_state_machine/decorators.py
|
|
43
43
|
clerk/gui_automation/ui_state_machine/exceptions.py
|
|
44
|
-
clerk/gui_automation/ui_state_machine/models.py
|
|
45
44
|
clerk/gui_automation/ui_state_machine/state_machine.py
|
|
46
45
|
clerk/models/__init__.py
|
|
47
46
|
clerk/models/document.py
|
|
@@ -13,7 +13,7 @@ gui_requirements = get_requirements("./clerk/gui_automation")
|
|
|
13
13
|
|
|
14
14
|
setup(
|
|
15
15
|
name="clerk-sdk",
|
|
16
|
-
version="0.4.
|
|
16
|
+
version="0.4.10",
|
|
17
17
|
description="Library for interacting with Clerk",
|
|
18
18
|
long_description=open("README.md").read(),
|
|
19
19
|
long_description_content_type="text/markdown",
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from typing import Any, Optional
|
|
2
|
-
from pydantic import BaseModel, field_validator
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ActionString(BaseModel):
|
|
6
|
-
"""
|
|
7
|
-
ActionString class represents a string that represents an action in an application.
|
|
8
|
-
|
|
9
|
-
Attributes:
|
|
10
|
-
action_string (str): The string representation of the action.
|
|
11
|
-
comment (str, optional): An optional comment or description for the action.
|
|
12
|
-
interrupt_process (bool, optional): A flag indicating whether the action should interrupt the process.
|
|
13
|
-
|
|
14
|
-
Methods:
|
|
15
|
-
ensure_format(v: str) -> str:
|
|
16
|
-
Validator function that ensures the action string has the correct format.
|
|
17
|
-
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
action_string: str
|
|
21
|
-
action_comment: Optional[str] = None
|
|
22
|
-
observation: Optional[str] = None
|
|
23
|
-
interrupt_process: Optional[bool] = False
|
|
24
|
-
|
|
25
|
-
@field_validator("action_string", mode="before")
|
|
26
|
-
@classmethod
|
|
27
|
-
def ensure_format(cls, v: Any):
|
|
28
|
-
if not isinstance(v, str):
|
|
29
|
-
raise ValueError("Action string must be a string")
|
|
30
|
-
if not v.endswith(".do()") and not v.startswith("NoAction"):
|
|
31
|
-
raise ValueError("Action string must end with '.do()'")
|
|
32
|
-
return v
|
|
33
|
-
|
|
34
|
-
@field_validator("interrupt_process", mode="before")
|
|
35
|
-
def convert_to_bool(cls, v: str | bool | None):
|
|
36
|
-
if v is None:
|
|
37
|
-
return False
|
|
38
|
-
elif isinstance(v, str):
|
|
39
|
-
return v.lower() in ["true", "1", "yes"]
|
|
40
|
-
return v
|
|
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
|
|
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
|