soprano-sdk 0.2.21__tar.gz → 0.2.22__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.
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/PKG-INFO +1 -1
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/pyproject.toml +1 -1
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/tools.py +16 -1
- soprano_sdk-0.2.22/tests/test_initial_context_override_bug.py +114 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/.claude/settings.local.json +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/.github/workflows/test_build_and_publish.yaml +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/.gitignore +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/.python-version +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/CLAUDE.md +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/LICENSE +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/README.md +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/docs/framework_flow_diagrams.md +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/concert_booking/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/concert_booking/booking_helpers.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/concert_booking/concert_ticket_booking.yaml +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/concert_booking/concert_tools.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/concert_booking/example_runner.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/concert_booking/tool.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/framework_example.yaml +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/greeting_functions.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/greeting_workflow.yaml +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/main.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/payment_async_functions.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/payment_async_workflow.yaml +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/persistence/README.md +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/persistence/conversation_based.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/persistence/entity_based.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/persistence/mongodb_demo.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/return_functions.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/return_workflow.yaml +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/structured_output_example.yaml +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/supervisors/README.md +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/supervisors/crewai_supervisor_ui.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/supervisors/langgraph_supervisor_ui.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/supervisors/tools/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/supervisors/tools/crewai_tools.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/supervisors/tools/langgraph_tools.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/supervisors/workflow_tools.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/test_payment_async.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/tools/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/tools/address.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/validator.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/legacy/langgraph_demo.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/legacy/langgraph_selfloop_demo.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/legacy/langgraph_v.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/legacy/main.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/legacy/return_fsm.excalidraw +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/legacy/return_state_machine.png +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/legacy/ui.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/scripts/visualize_workflow.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/scripts/workflow_demo.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/scripts/workflow_demo_ui.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/agents/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/agents/adaptor.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/agents/factory.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/agents/structured_output.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/authenticators/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/authenticators/mfa.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/core/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/core/constants.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/core/engine.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/core/rollback_strategies.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/core/state.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/engine.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/nodes/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/nodes/async_function.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/nodes/base.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/nodes/call_function.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/nodes/collect_input.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/nodes/factory.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/nodes/follow_up.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/routing/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/routing/router.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/utils/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/utils/function.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/utils/logger.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/utils/template.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/utils/tool.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/utils/tracing.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/validation/__init__.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/validation/schema.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/soprano_sdk/validation/validator.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/debug_jinja2.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_adaptor_logging.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_agent_factory.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_async_function.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_base_node.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_collect_input_refactor.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_engine_failure_message.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_external_values.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_follow_up.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_inputs_validation.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_jinja2_path.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_jinja2_standalone.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_mfa_scenarios.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_out_of_scope.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_persistence.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_structured_output.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_transition_routing.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/tests/test_workflow_tool_context_update.py +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/todo.md +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/.eslintrc.cjs +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/.gitignore +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/README.md +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/index.html +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/package-lock.json +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/package.json +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/src/App.jsx +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/src/CustomNode.jsx +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/src/StepDetailsModal.jsx +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/src/WorkflowGraph.jsx +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/src/WorkflowInfoPanel.jsx +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/src/assets/react.svg +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/src/main.jsx +0 -0
- {soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/workflow-visualizer/vite.config.js +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "soprano-sdk"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.22"
|
|
8
8
|
description = "YAML-driven workflow engine with AI agent integration for building conversational SOPs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -169,7 +169,8 @@ class WorkflowTool:
|
|
|
169
169
|
initial_context: Optional[Dict[str, Any]]
|
|
170
170
|
) -> Dict[str, Any]:
|
|
171
171
|
"""
|
|
172
|
-
Filter initial_context to exclude fields that have already been collected
|
|
172
|
+
Filter initial_context to exclude fields that have already been collected
|
|
173
|
+
or are currently being collected.
|
|
173
174
|
|
|
174
175
|
Args:
|
|
175
176
|
current_state: Current workflow state
|
|
@@ -193,6 +194,20 @@ class WorkflowTool:
|
|
|
193
194
|
if executed_node_id in node_to_field_map:
|
|
194
195
|
collected_fields.add(node_to_field_map[executed_node_id])
|
|
195
196
|
|
|
197
|
+
# Also exclude fields that are currently being collected (actively collecting)
|
|
198
|
+
# This prevents initial_context from overriding user input
|
|
199
|
+
current_status = current_state.get(WorkflowKeys.STATUS, "")
|
|
200
|
+
if "collecting" in current_status:
|
|
201
|
+
# Status format: "node_id_collecting" (e.g., "get_name_collecting")
|
|
202
|
+
for node_id, field in node_to_field_map.items():
|
|
203
|
+
if f"{node_id}_collecting" == current_status:
|
|
204
|
+
collected_fields.add(field)
|
|
205
|
+
logger.info(
|
|
206
|
+
f"[WorkflowTool] Field '{field}' is currently being collected. "
|
|
207
|
+
f"Excluding from initial_context to preserve user input."
|
|
208
|
+
)
|
|
209
|
+
break
|
|
210
|
+
|
|
196
211
|
# Filter initial_context to exclude already-collected fields
|
|
197
212
|
filtered_context = {
|
|
198
213
|
field: value
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit test for initial_context override bug.
|
|
3
|
+
|
|
4
|
+
Bug: When a collector node has interrupted and is waiting for user input,
|
|
5
|
+
if the caller passes initial_context with the same field, it overrides
|
|
6
|
+
the user's input instead of respecting it.
|
|
7
|
+
|
|
8
|
+
This test currently FAILS (documents the bug).
|
|
9
|
+
After fixing the bug, this test should PASS.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from unittest.mock import MagicMock, patch
|
|
14
|
+
from soprano_sdk.tools import WorkflowTool
|
|
15
|
+
from soprano_sdk.core.constants import WorkflowKeys
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestInitialContextOverrideBug:
|
|
19
|
+
"""
|
|
20
|
+
Test that initial_context should NOT override user input
|
|
21
|
+
when a field is actively being collected.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@patch('soprano_sdk.tools.load_workflow')
|
|
25
|
+
@patch('soprano_sdk.utils.tracing.trace_workflow_execution')
|
|
26
|
+
@patch('soprano_sdk.tools.CallbackHandler')
|
|
27
|
+
def test_initial_context_should_not_override_user_input_during_collection(
|
|
28
|
+
self, mock_callback_handler, mock_trace, mock_load_workflow
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Test that initial_context does NOT override user input for actively collecting field.
|
|
32
|
+
|
|
33
|
+
Scenario:
|
|
34
|
+
1. Node "get_name" has interrupted, asking "What's your name?"
|
|
35
|
+
2. User provides "John" via user_message
|
|
36
|
+
3. Caller also passes initial_context={"name": "Alice", "age": 30}
|
|
37
|
+
4. Expected: "name" should be "John" (from user), not "Alice" (from context)
|
|
38
|
+
5. Expected: "age" should be 30 (from context, not collected yet)
|
|
39
|
+
|
|
40
|
+
Current behavior (BUG):
|
|
41
|
+
- Both "name" and "age" are passed to engine.update_context
|
|
42
|
+
- _apply_context_value overwrites state["name"] = "Alice"
|
|
43
|
+
- User input "John" is lost
|
|
44
|
+
|
|
45
|
+
Expected behavior (AFTER FIX):
|
|
46
|
+
- Only "age" should be passed to engine.update_context
|
|
47
|
+
- "name" should be filtered out (actively collecting)
|
|
48
|
+
- User input "John" is preserved
|
|
49
|
+
"""
|
|
50
|
+
# Setup mocks
|
|
51
|
+
mock_graph = MagicMock()
|
|
52
|
+
mock_engine = MagicMock()
|
|
53
|
+
mock_load_workflow.return_value = (mock_graph, mock_engine)
|
|
54
|
+
|
|
55
|
+
# Mock trace context manager
|
|
56
|
+
mock_span = MagicMock()
|
|
57
|
+
mock_trace.return_value.__enter__.return_value = mock_span
|
|
58
|
+
|
|
59
|
+
# Simulate state when "get_name" node has interrupted
|
|
60
|
+
mock_state = MagicMock()
|
|
61
|
+
mock_state.next = ["get_name"] # Node is waiting for input
|
|
62
|
+
mock_state.values = {
|
|
63
|
+
WorkflowKeys.NODE_EXECUTION_ORDER: [], # Node hasn't completed yet
|
|
64
|
+
WorkflowKeys.STATUS: "get_name_collecting", # Actively collecting
|
|
65
|
+
"_active_input_field": "name", # Field being collected
|
|
66
|
+
"name": None # Field not collected yet
|
|
67
|
+
}
|
|
68
|
+
mock_graph.get_state.return_value = mock_state
|
|
69
|
+
|
|
70
|
+
# Mock collector_node_field_map (maps node_id -> field)
|
|
71
|
+
mock_engine.collector_node_field_map = {
|
|
72
|
+
"get_name": "name",
|
|
73
|
+
"get_age": "age"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Mock result
|
|
77
|
+
mock_result = {"outcome": "success"}
|
|
78
|
+
mock_graph.invoke.return_value = mock_result
|
|
79
|
+
mock_engine.get_outcome_message.return_value = "Success"
|
|
80
|
+
|
|
81
|
+
# Create workflow tool
|
|
82
|
+
workflow = WorkflowTool(
|
|
83
|
+
yaml_path="test.yaml",
|
|
84
|
+
name="TestWorkflow",
|
|
85
|
+
description="Test workflow"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Execute - resuming with user input "John" but initial_context has "Alice"
|
|
89
|
+
workflow.execute(
|
|
90
|
+
thread_id="test-thread",
|
|
91
|
+
user_message="John", # User's input
|
|
92
|
+
initial_context={"name": "Alice", "age": 30} # Context trying to override
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# ASSERTION: Verify that "name" was filtered out from context update
|
|
96
|
+
mock_engine.update_context.assert_called_once()
|
|
97
|
+
called_context = mock_engine.update_context.call_args[0][0]
|
|
98
|
+
|
|
99
|
+
# The actively collecting field "name" should NOT be in the context
|
|
100
|
+
assert "name" not in called_context, (
|
|
101
|
+
f"Bug: 'name' should be filtered out because it's actively being collected. "
|
|
102
|
+
f"Got context: {called_context}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# The uncollected field "age" SHOULD be in the context
|
|
106
|
+
assert "age" in called_context, (
|
|
107
|
+
f"Expected: 'age' should be in context for pre-population. "
|
|
108
|
+
f"Got context: {called_context}"
|
|
109
|
+
)
|
|
110
|
+
assert called_context["age"] == 30
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
pytest.main([__file__, "-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
|
{soprano_sdk-0.2.21 → soprano_sdk-0.2.22}/examples/concert_booking/concert_ticket_booking.yaml
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
|
|
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
|