markdown-flow 0.2.80__tar.gz → 0.2.82__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.
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/PKG-INFO +1 -1
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/__init__.py +1 -1
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/constants.py +13 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/core.py +104 -10
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/system_prompt.md +2 -2
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow.egg-info/PKG-INFO +1 -1
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/LICENSE +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/README.md +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/constants_system_prompt.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/enums.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/exceptions.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/formatter/__init__.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/formatter/classifier.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/formatter/format.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/formatter/patterns.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/formatter/stream.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/formatter/types.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/llm.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/models.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/__init__.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/code_fence_utils.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/html_comment_utils.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/interaction.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/json_parser.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/output.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/preprocessor.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/validation.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/parser/variable.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/providers/__init__.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/providers/config.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/providers/openai.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/tag_filter.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow/utils.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow.egg-info/SOURCES.txt +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow.egg-info/dependency_links.txt +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/markdown_flow.egg-info/top_level.txt +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/pyproject.toml +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/setup.cfg +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_dynamic_interaction.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_formatter.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_formatter_stream.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_html_comment_utils.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_markdownflow_basic.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_parser_interaction.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_parser_output.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_parser_variable.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_preprocessor.py +0 -0
- {markdown_flow-0.2.80 → markdown_flow-0.2.82}/tests/test_preserved_simple.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: markdown-flow
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.82
|
|
4
4
|
Summary: An agent library designed to parse and process MarkdownFlow documents
|
|
5
5
|
Project-URL: Homepage, https://github.com/ai-shifu/markdown-flow-agent-py
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/ai-shifu/markdown-flow-agent-py/issues
|
|
@@ -237,3 +237,16 @@ CONTEXT_CONVERSATION_TEMPLATE = f"{CONTEXT_CONVERSATION_MARKER}\n{{content}}"
|
|
|
237
237
|
CONTEXT_BUTTON_OPTIONS_TEMPLATE = (
|
|
238
238
|
f"{CONTEXT_BUTTON_OPTIONS_MARKER}\n可选的预定义选项包括:{{button_options}}\n注意:用户如果选择了这些选项,都应该接受;如果输入了自定义内容,只要是对问题的合理回答即可接受。"
|
|
239
239
|
)
|
|
240
|
+
|
|
241
|
+
# Next interaction context prompt templates
|
|
242
|
+
NEXT_INTERACTION_CONTEXT_INTRO = (
|
|
243
|
+
"The next interaction will appear immediately after this content. When generating the current content, connect to it naturally. "
|
|
244
|
+
"You may briefly restate, explain, or set up the available choices so the user understands what they will decide next, but do not output the interaction syntax or answer on the user's behalf."
|
|
245
|
+
)
|
|
246
|
+
NEXT_INTERACTION_TEXT_INPUT_TEMPLATE = "The next interaction asks the user to answer in text: {question}"
|
|
247
|
+
NEXT_INTERACTION_SINGLE_CHOICE_TEMPLATE = "The next interaction is a single-choice question. The user will choose one option from: {options}"
|
|
248
|
+
NEXT_INTERACTION_MULTIPLE_CHOICE_TEMPLATE = "The next interaction is a multiple-choice question. The user can choose one or more options from: {options}"
|
|
249
|
+
NEXT_INTERACTION_SINGLE_CHOICE_WITH_TEXT_INTRO = "The next interaction is a single-choice question with an optional custom text answer."
|
|
250
|
+
NEXT_INTERACTION_MULTIPLE_CHOICE_WITH_TEXT_INTRO = "The next interaction is a multiple-choice question with an optional custom text answer."
|
|
251
|
+
NEXT_INTERACTION_PREDEFINED_OPTIONS_TEMPLATE = "The predefined options are: {options}."
|
|
252
|
+
NEXT_INTERACTION_CUSTOM_TEXT_PROMPT_TEMPLATE = "The custom text prompt is: {question}"
|
|
@@ -25,6 +25,14 @@ from .constants import (
|
|
|
25
25
|
INTERACTION_PROMPT_BASE,
|
|
26
26
|
INTERACTION_PROMPT_WITH_TRANSLATION,
|
|
27
27
|
LLM_PROVIDER_REQUIRED_ERROR,
|
|
28
|
+
NEXT_INTERACTION_CONTEXT_INTRO,
|
|
29
|
+
NEXT_INTERACTION_CUSTOM_TEXT_PROMPT_TEMPLATE,
|
|
30
|
+
NEXT_INTERACTION_MULTIPLE_CHOICE_TEMPLATE,
|
|
31
|
+
NEXT_INTERACTION_MULTIPLE_CHOICE_WITH_TEXT_INTRO,
|
|
32
|
+
NEXT_INTERACTION_PREDEFINED_OPTIONS_TEMPLATE,
|
|
33
|
+
NEXT_INTERACTION_SINGLE_CHOICE_TEMPLATE,
|
|
34
|
+
NEXT_INTERACTION_SINGLE_CHOICE_WITH_TEXT_INTRO,
|
|
35
|
+
NEXT_INTERACTION_TEXT_INPUT_TEMPLATE,
|
|
28
36
|
OUTPUT_LANGUAGE_INSTRUCTION_BOTTOM,
|
|
29
37
|
OUTPUT_LANGUAGE_INSTRUCTION_TOP,
|
|
30
38
|
UNSUPPORTED_PROMPT_TYPE_ERROR,
|
|
@@ -803,7 +811,7 @@ class MarkdownFlow:
|
|
|
803
811
|
# Basic validation
|
|
804
812
|
if not user_input or not any(values for values in user_input.values()):
|
|
805
813
|
error_msg = INPUT_EMPTY_ERROR
|
|
806
|
-
return self._render_error(error_msg, mode, context)
|
|
814
|
+
return self._render_error(error_msg, mode, context, variables)
|
|
807
815
|
|
|
808
816
|
# Get the target variable value from user_input
|
|
809
817
|
target_values = user_input.get(target_variable, [])
|
|
@@ -817,7 +825,7 @@ class MarkdownFlow:
|
|
|
817
825
|
|
|
818
826
|
if "error" in parse_result:
|
|
819
827
|
error_msg = INTERACTION_PARSE_ERROR.format(error=parse_result["error"])
|
|
820
|
-
return self._render_error(error_msg, mode, context)
|
|
828
|
+
return self._render_error(error_msg, mode, context, variables)
|
|
821
829
|
|
|
822
830
|
interaction_type = parse_result.get("type")
|
|
823
831
|
|
|
@@ -942,6 +950,7 @@ class MarkdownFlow:
|
|
|
942
950
|
mode,
|
|
943
951
|
interaction_type,
|
|
944
952
|
context,
|
|
953
|
+
variables,
|
|
945
954
|
)
|
|
946
955
|
|
|
947
956
|
if interaction_type == InteractionType.NON_ASSIGNMENT_BUTTON:
|
|
@@ -995,7 +1004,7 @@ class MarkdownFlow:
|
|
|
995
1004
|
context=context,
|
|
996
1005
|
)
|
|
997
1006
|
error_msg = f"No input provided for variable '{target_variable}'"
|
|
998
|
-
return self._render_error(error_msg, mode, context)
|
|
1007
|
+
return self._render_error(error_msg, mode, context, variables)
|
|
999
1008
|
|
|
1000
1009
|
def _match_button_values(
|
|
1001
1010
|
self,
|
|
@@ -1038,6 +1047,7 @@ class MarkdownFlow:
|
|
|
1038
1047
|
mode: ProcessMode,
|
|
1039
1048
|
interaction_type: InteractionType,
|
|
1040
1049
|
context: list[dict[str, str]] | None = None,
|
|
1050
|
+
variables: dict[str, str | list[str]] | None = None,
|
|
1041
1051
|
) -> LLMResult | Generator[LLMResult, None, None]:
|
|
1042
1052
|
"""
|
|
1043
1053
|
Simplified button validation with new input format.
|
|
@@ -1082,7 +1092,7 @@ class MarkdownFlow:
|
|
|
1082
1092
|
# Pure button mode requires input
|
|
1083
1093
|
button_displays = [btn["display"] for btn in buttons]
|
|
1084
1094
|
error_msg = f"Please select from: {', '.join(button_displays)}"
|
|
1085
|
-
return self._render_error(error_msg, mode, context)
|
|
1095
|
+
return self._render_error(error_msg, mode, context, variables)
|
|
1086
1096
|
|
|
1087
1097
|
# Validate input values against available buttons
|
|
1088
1098
|
valid_values = []
|
|
@@ -1107,7 +1117,7 @@ class MarkdownFlow:
|
|
|
1107
1117
|
if invalid_values and not allow_text_input:
|
|
1108
1118
|
button_displays = [btn["display"] for btn in buttons]
|
|
1109
1119
|
error_msg = f"Invalid options: {', '.join(invalid_values)}. Please select from: {', '.join(button_displays)}"
|
|
1110
|
-
return self._render_error(error_msg, mode, context)
|
|
1120
|
+
return self._render_error(error_msg, mode, context, variables)
|
|
1111
1121
|
|
|
1112
1122
|
# Success: return validated values
|
|
1113
1123
|
result = LLMResult(
|
|
@@ -1180,13 +1190,14 @@ class MarkdownFlow:
|
|
|
1180
1190
|
error_message: str,
|
|
1181
1191
|
mode: ProcessMode,
|
|
1182
1192
|
context: list[dict[str, str]] | None = None,
|
|
1193
|
+
variables: dict[str, str | list[str]] | None = None,
|
|
1183
1194
|
) -> LLMResult | Generator[LLMResult, None, None]:
|
|
1184
1195
|
"""Render user-friendly error message."""
|
|
1185
1196
|
# Truncate context to configured maximum length
|
|
1186
1197
|
truncated_context = self._truncate_context(context)
|
|
1187
1198
|
|
|
1188
1199
|
# Build error messages with context
|
|
1189
|
-
messages = self._build_error_render_messages(error_message, truncated_context)
|
|
1200
|
+
messages = self._build_error_render_messages(error_message, truncated_context, variables)
|
|
1190
1201
|
|
|
1191
1202
|
if mode == ProcessMode.COMPLETE:
|
|
1192
1203
|
if not self._llm_provider:
|
|
@@ -1283,11 +1294,88 @@ class MarkdownFlow:
|
|
|
1283
1294
|
if self._output_language:
|
|
1284
1295
|
user_content = f"<output_language_instruction>\n🚨 OUTPUT: 100% {self._output_language} - Translate ALL non-{self._output_language} words/phrases to {self._output_language} 🚨\n</output_language_instruction>\n\n{user_content}"
|
|
1285
1296
|
|
|
1297
|
+
next_interaction_context = self._build_next_interaction_context_prompt(block_index, variables)
|
|
1298
|
+
if next_interaction_context:
|
|
1299
|
+
user_content = f"{user_content}\n\n{next_interaction_context}"
|
|
1300
|
+
|
|
1286
1301
|
# Add processed content as user message (as instruction to LLM)
|
|
1287
1302
|
messages.append({"role": "user", "content": user_content})
|
|
1288
1303
|
|
|
1289
1304
|
return messages
|
|
1290
1305
|
|
|
1306
|
+
def _build_next_interaction_context_prompt(
|
|
1307
|
+
self,
|
|
1308
|
+
block_index: int,
|
|
1309
|
+
variables: dict[str, str | list[str]] | None,
|
|
1310
|
+
) -> str:
|
|
1311
|
+
"""Build natural prompt context from the immediately following interaction block."""
|
|
1312
|
+
blocks = self.get_all_blocks()
|
|
1313
|
+
next_index = block_index + 1
|
|
1314
|
+
if next_index >= len(blocks):
|
|
1315
|
+
return ""
|
|
1316
|
+
|
|
1317
|
+
next_block = blocks[next_index]
|
|
1318
|
+
if next_block.block_type != BlockType.INTERACTION:
|
|
1319
|
+
return ""
|
|
1320
|
+
|
|
1321
|
+
interaction_content = replace_variables_in_text(next_block.content, variables or {})
|
|
1322
|
+
parse_result = InteractionParser().parse(interaction_content)
|
|
1323
|
+
if parse_result.get("error"):
|
|
1324
|
+
return ""
|
|
1325
|
+
|
|
1326
|
+
question = parse_result.get("question", "").strip()
|
|
1327
|
+
buttons = parse_result.get("buttons") or []
|
|
1328
|
+
option_displays = [button.get("display", "").strip() for button in buttons if button.get("display", "").strip()]
|
|
1329
|
+
|
|
1330
|
+
detail = self._format_next_interaction_detail(parse_result.get("type"), question, option_displays)
|
|
1331
|
+
if not detail:
|
|
1332
|
+
return ""
|
|
1333
|
+
|
|
1334
|
+
return f"{NEXT_INTERACTION_CONTEXT_INTRO}\n{detail}"
|
|
1335
|
+
|
|
1336
|
+
def _format_next_interaction_detail(
|
|
1337
|
+
self,
|
|
1338
|
+
interaction_type: InteractionType | None,
|
|
1339
|
+
question: str,
|
|
1340
|
+
option_displays: list[str],
|
|
1341
|
+
) -> str:
|
|
1342
|
+
"""Format the type-specific part of the next interaction prompt."""
|
|
1343
|
+
options = json.dumps(option_displays, ensure_ascii=False) if option_displays else ""
|
|
1344
|
+
question_text = json.dumps(question, ensure_ascii=False) if question else ""
|
|
1345
|
+
|
|
1346
|
+
if interaction_type == InteractionType.TEXT_ONLY:
|
|
1347
|
+
if not question:
|
|
1348
|
+
return ""
|
|
1349
|
+
return NEXT_INTERACTION_TEXT_INPUT_TEMPLATE.format(question=question_text)
|
|
1350
|
+
|
|
1351
|
+
if interaction_type in [InteractionType.BUTTONS_ONLY, InteractionType.NON_ASSIGNMENT_BUTTON]:
|
|
1352
|
+
if not options:
|
|
1353
|
+
return ""
|
|
1354
|
+
return NEXT_INTERACTION_SINGLE_CHOICE_TEMPLATE.format(options=options)
|
|
1355
|
+
|
|
1356
|
+
if interaction_type == InteractionType.BUTTONS_MULTI_SELECT:
|
|
1357
|
+
if not options:
|
|
1358
|
+
return ""
|
|
1359
|
+
return NEXT_INTERACTION_MULTIPLE_CHOICE_TEMPLATE.format(options=options)
|
|
1360
|
+
|
|
1361
|
+
if interaction_type == InteractionType.BUTTONS_WITH_TEXT:
|
|
1362
|
+
detail_parts = [NEXT_INTERACTION_SINGLE_CHOICE_WITH_TEXT_INTRO]
|
|
1363
|
+
if options:
|
|
1364
|
+
detail_parts.append(NEXT_INTERACTION_PREDEFINED_OPTIONS_TEMPLATE.format(options=options))
|
|
1365
|
+
if question:
|
|
1366
|
+
detail_parts.append(NEXT_INTERACTION_CUSTOM_TEXT_PROMPT_TEMPLATE.format(question=question_text))
|
|
1367
|
+
return " ".join(detail_parts)
|
|
1368
|
+
|
|
1369
|
+
if interaction_type == InteractionType.BUTTONS_MULTI_WITH_TEXT:
|
|
1370
|
+
detail_parts = [NEXT_INTERACTION_MULTIPLE_CHOICE_WITH_TEXT_INTRO]
|
|
1371
|
+
if options:
|
|
1372
|
+
detail_parts.append(NEXT_INTERACTION_PREDEFINED_OPTIONS_TEMPLATE.format(options=options))
|
|
1373
|
+
if question:
|
|
1374
|
+
detail_parts.append(NEXT_INTERACTION_CUSTOM_TEXT_PROMPT_TEMPLATE.format(question=question_text))
|
|
1375
|
+
return " ".join(detail_parts)
|
|
1376
|
+
|
|
1377
|
+
return ""
|
|
1378
|
+
|
|
1291
1379
|
def _extract_translatable_content(self, interaction_content: str) -> tuple[str, dict[str, Any] | None]:
|
|
1292
1380
|
"""Extract translatable parts from interaction content as JSON format
|
|
1293
1381
|
|
|
@@ -1531,6 +1619,7 @@ class MarkdownFlow:
|
|
|
1531
1619
|
self,
|
|
1532
1620
|
error_message: str,
|
|
1533
1621
|
context: list[dict[str, str]] | None = None,
|
|
1622
|
+
variables: dict[str, str | list[str]] | None = None,
|
|
1534
1623
|
) -> list[dict[str, str]]:
|
|
1535
1624
|
"""Build error rendering messages."""
|
|
1536
1625
|
render_prompt = f"""{self._interaction_error_prompt}
|
|
@@ -1545,10 +1634,15 @@ Original Error: {error_message}
|
|
|
1545
1634
|
|
|
1546
1635
|
messages.append({"role": "system", "content": render_prompt})
|
|
1547
1636
|
|
|
1548
|
-
# Add conversation history context if provided
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1637
|
+
# Add conversation history context if provided.
|
|
1638
|
+
# Context is already truncated by the caller (_render_error), so reuse it
|
|
1639
|
+
# directly here. Transform interaction syntax in the context the same way
|
|
1640
|
+
# the content path does, so raw ?[...] blocks are expanded to
|
|
1641
|
+
# {user}/{assistant} pairs instead of leaking into this auxiliary LLM call.
|
|
1642
|
+
if context:
|
|
1643
|
+
transformed_context = self._transform_context_messages(context, variables)
|
|
1644
|
+
if transformed_context:
|
|
1645
|
+
messages.extend(transformed_context)
|
|
1552
1646
|
|
|
1553
1647
|
messages.append({"role": "user", "content": error_message})
|
|
1554
1648
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
每屏 = 一个铺满视口的固定容器,不可滚动。外层容器写法:
|
|
28
28
|
|
|
29
|
-
```
|
|
29
|
+
```text
|
|
30
30
|
<div style="width:100%; min-height:100vh; overflow-x:hidden; overflow-y:auto; display:flex; flex-direction:column; align-items:center; padding:1em; font-size:clamp(12px,calc(100vw/48),3vh)">
|
|
31
31
|
<!-- 内容 -->
|
|
32
32
|
</div>
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
每屏 HTML 后必须紧跟:
|
|
36
36
|
|
|
37
|
-
```
|
|
37
|
+
```text
|
|
38
38
|
<style>
|
|
39
39
|
*,*::before,*::after{box-sizing:border-box;overflow-wrap:break-word;word-wrap:break-word}
|
|
40
40
|
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: markdown-flow
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.82
|
|
4
4
|
Summary: An agent library designed to parse and process MarkdownFlow documents
|
|
5
5
|
Project-URL: Homepage, https://github.com/ai-shifu/markdown-flow-agent-py
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/ai-shifu/markdown-flow-agent-py/issues
|
|
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
|