agentic-fabriq-sdk 0.1.18__tar.gz → 0.1.20__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.
Potentially problematic release.
This version of agentic-fabriq-sdk might be problematic. Click here for more details.
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/PKG-INFO +3 -3
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/commands/tools.py +36 -54
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/core/client.py +29 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/fabriq_client.py +54 -2
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/models/__init__.py +0 -8
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/pyproject.toml +3 -3
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/README.md +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/commands/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/commands/applications.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/commands/auth.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/commands/config.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/commands/mcp_servers.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/commands/secrets.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/core/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/core/config.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/core/oauth.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/core/output.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/core/token_storage.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_cli/main.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/auth/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/auth/applications.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/auth/dpop.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/auth/oauth.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/auth/token_cache.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/connectors/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/connectors/base.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/connectors/registry.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/dx/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/dx/decorators.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/dx/runtime.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/events.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/exceptions.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/models/audit.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/models/types.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/py.typed +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/transport/__init__.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/transport/http.py +0 -0
- {agentic_fabriq_sdk-0.1.18 → agentic_fabriq_sdk-0.1.20}/af_sdk/vault.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-fabriq-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.20
|
|
4
4
|
Summary: Agentic Fabriq SDK: high-level client, CLI tool, DX helpers, and auth for AI agents
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: fabriq,agentic-fabriq,sdk,ai,agents,agentic,fabric,cli
|
|
@@ -17,7 +17,7 @@ Classifier: Typing :: Typed
|
|
|
17
17
|
Requires-Dist: PyJWT (>=2.8.0)
|
|
18
18
|
Requires-Dist: PyYAML (>=6.0.0)
|
|
19
19
|
Requires-Dist: aiohttp (>=3.9.0)
|
|
20
|
-
Requires-Dist: click (>=8.
|
|
20
|
+
Requires-Dist: click (>=8.1.0)
|
|
21
21
|
Requires-Dist: cryptography (>=41.0.0)
|
|
22
22
|
Requires-Dist: httpx (>=0.25.0)
|
|
23
23
|
Requires-Dist: keyring (>=25.0.0)
|
|
@@ -27,7 +27,7 @@ Requires-Dist: opentelemetry-instrumentation-httpx (>=0.41b0)
|
|
|
27
27
|
Requires-Dist: pydantic (>=2.4.0)
|
|
28
28
|
Requires-Dist: rich (>=13.7.0)
|
|
29
29
|
Requires-Dist: stevedore (>=5.1.0)
|
|
30
|
-
Requires-Dist: typer[all] (>=0.
|
|
30
|
+
Requires-Dist: typer[all] (>=0.20.0)
|
|
31
31
|
Requires-Dist: typing-extensions (>=4.0.0)
|
|
32
32
|
Project-URL: Documentation, https://docs.agentic-fabric.org
|
|
33
33
|
Project-URL: Homepage, https://github.com/agentic-fabric/agentic-fabric
|
|
@@ -121,17 +121,20 @@ def get(
|
|
|
121
121
|
|
|
122
122
|
@app.command()
|
|
123
123
|
def invoke(
|
|
124
|
-
|
|
124
|
+
connection_id: str = typer.Argument(..., help="Connection ID (e.g., 'slacker', 'gurt')"),
|
|
125
125
|
method: str = typer.Option(..., "--method", help="Tool method to invoke"),
|
|
126
126
|
params: str = typer.Option(None, "--params", help="JSON string of method parameters (e.g., '{\"channel\": \"test\", \"text\": \"Hello\"}')"),
|
|
127
127
|
format: str = typer.Option("json", "--format", help="Output format (json, table, yaml)"),
|
|
128
128
|
):
|
|
129
|
-
"""Invoke a tool
|
|
129
|
+
"""Invoke a tool using its connection ID.
|
|
130
|
+
|
|
131
|
+
The connection ID identifies which specific tool connection to use.
|
|
132
|
+
Run 'afctl tools list' to see your connection IDs.
|
|
130
133
|
|
|
131
134
|
Examples:
|
|
132
|
-
afctl tools invoke
|
|
133
|
-
afctl tools invoke
|
|
134
|
-
afctl tools invoke
|
|
135
|
+
afctl tools invoke slacker --method get_channels
|
|
136
|
+
afctl tools invoke slacker --method post_message --params '{"channel": "test", "text": "Hello!"}'
|
|
137
|
+
afctl tools invoke gurt --method list_files
|
|
135
138
|
"""
|
|
136
139
|
try:
|
|
137
140
|
# Parse parameters if provided
|
|
@@ -145,59 +148,29 @@ def invoke(
|
|
|
145
148
|
raise typer.Exit(1)
|
|
146
149
|
|
|
147
150
|
with get_client() as client:
|
|
148
|
-
|
|
149
|
-
tool_id = tool_identifier
|
|
150
|
-
try:
|
|
151
|
-
from uuid import UUID
|
|
152
|
-
UUID(tool_identifier)
|
|
153
|
-
# It's already a UUID, use it directly
|
|
154
|
-
except ValueError:
|
|
155
|
-
# Not a UUID, try to look up by name
|
|
156
|
-
info(f"Looking up tool '{tool_identifier}'...")
|
|
157
|
-
try:
|
|
158
|
-
tools_response = client.get("/api/v1/tools")
|
|
159
|
-
|
|
160
|
-
# Handle different response formats
|
|
161
|
-
if isinstance(tools_response, dict) and "tools" in tools_response:
|
|
162
|
-
tools = tools_response["tools"]
|
|
163
|
-
elif isinstance(tools_response, dict) and "items" in tools_response:
|
|
164
|
-
tools = tools_response["items"]
|
|
165
|
-
elif hasattr(tools_response, '__iter__') and not isinstance(tools_response, (str, dict)):
|
|
166
|
-
tools = list(tools_response)
|
|
167
|
-
else:
|
|
168
|
-
tools = []
|
|
169
|
-
|
|
170
|
-
# Find tool by name (case-insensitive)
|
|
171
|
-
matching_tools = [t for t in tools if isinstance(t, dict) and t.get("name", "").lower() == tool_identifier.lower()]
|
|
172
|
-
|
|
173
|
-
if not matching_tools:
|
|
174
|
-
error(f"Tool '{tool_identifier}' not found. Available tools:")
|
|
175
|
-
for t in tools:
|
|
176
|
-
if isinstance(t, dict):
|
|
177
|
-
print(f" - {t.get('name')} (ID: {t.get('id')})")
|
|
178
|
-
raise typer.Exit(1)
|
|
179
|
-
|
|
180
|
-
if len(matching_tools) > 1:
|
|
181
|
-
error(f"Multiple tools found with name '{tool_identifier}':")
|
|
182
|
-
for t in matching_tools:
|
|
183
|
-
print(f" - {t.get('name')} (ID: {t.get('id')})")
|
|
184
|
-
error("Please use the UUID instead.")
|
|
185
|
-
raise typer.Exit(1)
|
|
186
|
-
|
|
187
|
-
tool_id = matching_tools[0].get("id")
|
|
188
|
-
info(f"Resolved '{tool_identifier}' to tool ID: {tool_id}")
|
|
189
|
-
except Exception as lookup_error:
|
|
190
|
-
error(f"Failed to look up tool: {lookup_error}")
|
|
191
|
-
raise typer.Exit(1)
|
|
151
|
+
info(f"Invoking connection '{connection_id}' with method '{method}'...")
|
|
192
152
|
|
|
153
|
+
# Verify connection exists
|
|
154
|
+
connections = client.get("/api/v1/user-connections")
|
|
155
|
+
connection = next((c for c in connections if c.get("connection_id") == connection_id), None)
|
|
156
|
+
|
|
157
|
+
if not connection:
|
|
158
|
+
error(f"Connection '{connection_id}' not found")
|
|
159
|
+
info("Available connections:")
|
|
160
|
+
for conn in connections:
|
|
161
|
+
info(f" - {conn.get('connection_id')} ({conn.get('tool')})")
|
|
162
|
+
raise typer.Exit(1)
|
|
163
|
+
|
|
164
|
+
tool_name = connection.get("tool")
|
|
165
|
+
debug(f"Connection '{connection_id}' uses tool '{tool_name}'")
|
|
166
|
+
|
|
167
|
+
# Use the connection-based invoke endpoint (auto-creates tool if needed)
|
|
193
168
|
data = {
|
|
194
169
|
"method": method,
|
|
195
170
|
"parameters": parameters,
|
|
196
|
-
"context": {},
|
|
197
171
|
}
|
|
198
172
|
|
|
199
|
-
|
|
200
|
-
response = client.post(f"/api/v1/tools/{tool_id}/invoke", data)
|
|
173
|
+
response = client.post(f"/api/v1/tools/connections/{connection_id}/invoke", data)
|
|
201
174
|
|
|
202
175
|
success("Tool invoked successfully")
|
|
203
176
|
|
|
@@ -349,8 +322,11 @@ def add(
|
|
|
349
322
|
if redirect_uri:
|
|
350
323
|
config_payload["redirect_uri"] = redirect_uri
|
|
351
324
|
|
|
325
|
+
# For Google tools, pass tool_type parameter to prevent duplicates
|
|
326
|
+
tool_type_param = f"&tool_type={tool}" if api_tool_name == "google" else ""
|
|
327
|
+
|
|
352
328
|
client.post(
|
|
353
|
-
f"/api/v1/tools/{api_tool_name}/config?connection_id={connection_id}",
|
|
329
|
+
f"/api/v1/tools/{api_tool_name}/config?connection_id={connection_id}{tool_type_param}",
|
|
354
330
|
data=config_payload
|
|
355
331
|
)
|
|
356
332
|
success("✅ OAuth app credentials stored")
|
|
@@ -523,9 +499,15 @@ def disconnect(
|
|
|
523
499
|
info("Cancelled")
|
|
524
500
|
return
|
|
525
501
|
|
|
502
|
+
# Determine the API base tool name (Google tools all use "google")
|
|
503
|
+
api_tool_name = "google" if (tool.startswith("google_") or tool == "gmail") else tool
|
|
504
|
+
|
|
505
|
+
# For Google tools, pass tool_type parameter
|
|
506
|
+
tool_type_param = f"&tool_type={tool}" if api_tool_name == "google" else ""
|
|
507
|
+
|
|
526
508
|
# Delete connection credentials
|
|
527
509
|
client.delete(
|
|
528
|
-
f"/api/v1/tools/{
|
|
510
|
+
f"/api/v1/tools/{api_tool_name}/connection?connection_id={connection_id}{tool_type_param}"
|
|
529
511
|
)
|
|
530
512
|
|
|
531
513
|
success(f"✅ Disconnected: {connection_id}")
|
|
@@ -86,6 +86,35 @@ class AFClient:
|
|
|
86
86
|
|
|
87
87
|
return self._handle_response(response)
|
|
88
88
|
|
|
89
|
+
def try_post(self, path: str, data: Optional[Dict] = None) -> tuple[bool, int, Optional[Dict[str, Any]]]:
|
|
90
|
+
"""Make POST request without exiting on error. Returns (success, status_code, response_data)."""
|
|
91
|
+
url = urljoin(self.config.gateway_url, path)
|
|
92
|
+
debug(f"POST {url}")
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
response = self.client.post(
|
|
96
|
+
path,
|
|
97
|
+
json=data,
|
|
98
|
+
headers=self._get_headers(),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
debug(f"Response: {response.status_code} {response.url}")
|
|
102
|
+
|
|
103
|
+
if response.status_code >= 400:
|
|
104
|
+
try:
|
|
105
|
+
error_data = response.json()
|
|
106
|
+
return False, response.status_code, error_data
|
|
107
|
+
except:
|
|
108
|
+
return False, response.status_code, {"detail": response.text}
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
return True, response.status_code, response.json()
|
|
112
|
+
except:
|
|
113
|
+
return True, response.status_code, {"message": "Success"}
|
|
114
|
+
|
|
115
|
+
except Exception as e:
|
|
116
|
+
return False, 0, {"detail": str(e)}
|
|
117
|
+
|
|
89
118
|
def put(self, path: str, data: Optional[Dict] = None) -> Dict[str, Any]:
|
|
90
119
|
"""Make PUT request."""
|
|
91
120
|
url = urljoin(self.config.gateway_url, path)
|
|
@@ -85,6 +85,7 @@ class FabriqClient:
|
|
|
85
85
|
method: str,
|
|
86
86
|
parameters: Optional[Dict[str, Any]] = None,
|
|
87
87
|
context: Optional[Dict[str, Any]] = None,
|
|
88
|
+
connection_id: Optional[str] = None,
|
|
88
89
|
) -> Dict[str, Any]:
|
|
89
90
|
"""Invoke a tool by name or UUID.
|
|
90
91
|
|
|
@@ -93,6 +94,7 @@ class FabriqClient:
|
|
|
93
94
|
method: Method name to invoke
|
|
94
95
|
parameters: Method parameters
|
|
95
96
|
context: Additional context
|
|
97
|
+
connection_id: Specific connection ID to use (for multi-connection tools)
|
|
96
98
|
|
|
97
99
|
Returns:
|
|
98
100
|
Tool invocation result
|
|
@@ -101,6 +103,8 @@ class FabriqClient:
|
|
|
101
103
|
result = await client.invoke_tool("slack", method="get_channels")
|
|
102
104
|
result = await client.invoke_tool("slack", method="post_message",
|
|
103
105
|
parameters={"channel": "test", "text": "Hello!"})
|
|
106
|
+
result = await client.invoke_tool("slack", method="get_channels",
|
|
107
|
+
connection_id="slacker")
|
|
104
108
|
"""
|
|
105
109
|
# Try to resolve tool name to UUID if not already a UUID
|
|
106
110
|
tool_id = tool_identifier
|
|
@@ -142,10 +146,58 @@ class FabriqClient:
|
|
|
142
146
|
body = {"method": method}
|
|
143
147
|
if parameters is not None:
|
|
144
148
|
body["parameters"] = parameters
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
|
|
150
|
+
# Add connection_id to context if provided
|
|
151
|
+
if context is not None or connection_id is not None:
|
|
152
|
+
ctx = (context or {}).copy()
|
|
153
|
+
if connection_id is not None:
|
|
154
|
+
ctx["connection_id"] = connection_id
|
|
155
|
+
body["context"] = ctx
|
|
156
|
+
|
|
147
157
|
r = await self._http.post(f"/tools/{tool_id}/invoke", json=body, headers=self._extra_headers)
|
|
148
158
|
return r.json()
|
|
159
|
+
|
|
160
|
+
async def invoke_connection(
|
|
161
|
+
self,
|
|
162
|
+
connection_id: str,
|
|
163
|
+
*,
|
|
164
|
+
method: str,
|
|
165
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
166
|
+
) -> Dict[str, Any]:
|
|
167
|
+
"""Invoke a tool using its connection ID (preferred method).
|
|
168
|
+
|
|
169
|
+
This directly uses the connection_id (like 'slacker', 'gurt') to invoke
|
|
170
|
+
the tool without needing to look up UUIDs. This is the most efficient
|
|
171
|
+
and reliable way to invoke tools.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
connection_id: Connection identifier (e.g., 'slacker', 'gurt')
|
|
175
|
+
method: Method name to invoke
|
|
176
|
+
parameters: Method parameters
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Tool invocation result
|
|
180
|
+
|
|
181
|
+
Examples:
|
|
182
|
+
result = await client.invoke_connection("slacker", method="get_channels")
|
|
183
|
+
result = await client.invoke_connection("slacker", method="post_message",
|
|
184
|
+
parameters={"channel": "test", "text": "Hello!"})
|
|
185
|
+
result = await client.invoke_connection("gurt", method="list_files")
|
|
186
|
+
"""
|
|
187
|
+
# Use the direct connection-based invoke endpoint
|
|
188
|
+
# This matches what the CLI uses and is more efficient
|
|
189
|
+
body = {
|
|
190
|
+
"method": method,
|
|
191
|
+
"parameters": parameters or {},
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# Call the connection-based invoke endpoint
|
|
195
|
+
r = await self._http.post(
|
|
196
|
+
f"/tools/connections/{connection_id}/invoke",
|
|
197
|
+
json=body,
|
|
198
|
+
headers=self._extra_headers
|
|
199
|
+
)
|
|
200
|
+
return r.json()
|
|
149
201
|
|
|
150
202
|
# -----------------
|
|
151
203
|
# MCP Servers
|
|
@@ -3,10 +3,6 @@ Data models for Agentic Fabric SDK.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from .types import (
|
|
6
|
-
Agent,
|
|
7
|
-
AgentCreate,
|
|
8
|
-
AgentInvokeRequest,
|
|
9
|
-
AgentInvokeResult,
|
|
10
6
|
ErrorResponse,
|
|
11
7
|
HealthResponse,
|
|
12
8
|
McpServer,
|
|
@@ -25,10 +21,6 @@ from .types import (
|
|
|
25
21
|
)
|
|
26
22
|
|
|
27
23
|
__all__ = [
|
|
28
|
-
"Agent",
|
|
29
|
-
"AgentCreate",
|
|
30
|
-
"AgentInvokeRequest",
|
|
31
|
-
"AgentInvokeResult",
|
|
32
24
|
"Tool",
|
|
33
25
|
"ToolInvokeRequest",
|
|
34
26
|
"ToolInvokeResult",
|
|
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
5
5
|
|
|
6
6
|
[tool.poetry]
|
|
7
7
|
name = "agentic-fabriq-sdk"
|
|
8
|
-
version = "0.1.
|
|
8
|
+
version = "0.1.20"
|
|
9
9
|
description = "Agentic Fabriq SDK: high-level client, CLI tool, DX helpers, and auth for AI agents"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = "Apache-2.0"
|
|
@@ -43,11 +43,11 @@ aiohttp = ">=3.9.0"
|
|
|
43
43
|
# Plugin/extension system
|
|
44
44
|
stevedore = ">=5.1.0"
|
|
45
45
|
# CLI dependencies
|
|
46
|
-
typer = {extras = ["all"], version = ">=0.
|
|
46
|
+
typer = {extras = ["all"], version = ">=0.20.0"}
|
|
47
47
|
rich = ">=13.7.0"
|
|
48
48
|
keyring = ">=25.0.0"
|
|
49
49
|
cryptography = ">=41.0.0"
|
|
50
|
-
click = ">=8.
|
|
50
|
+
click = ">=8.1.0"
|
|
51
51
|
PyYAML = ">=6.0.0"
|
|
52
52
|
|
|
53
53
|
[tool.poetry.scripts]
|
|
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
|