sqlsaber 0.9.0__tar.gz → 0.11.0__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 sqlsaber might be problematic. Click here for more details.
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/CHANGELOG.md +15 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/PKG-INFO +8 -1
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/README.md +7 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/pyproject.toml +1 -1
- sqlsaber-0.11.0/src/sqlsaber/__init__.py +1 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/commands.py +26 -7
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/display.py +1 -6
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/database/schema.py +41 -53
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/uv.lock +1 -1
- sqlsaber-0.9.0/src/sqlsaber/__init__.py +0 -3
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/.github/workflows/publish.yml +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/.gitignore +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/.python-version +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/AGENT.md +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/CLAUDE.md +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/LICENSE +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/pytest.ini +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/sqlsaber.svg +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/__main__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/agents/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/agents/anthropic.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/agents/base.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/agents/mcp.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/agents/streaming.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/auth.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/completers.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/database.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/interactive.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/memory.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/models.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/cli/streaming.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/clients/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/clients/anthropic.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/clients/base.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/clients/exceptions.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/clients/models.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/clients/streaming.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/config/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/config/api_keys.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/config/auth.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/config/database.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/config/oauth_flow.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/config/oauth_tokens.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/config/settings.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/database/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/database/connection.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/mcp/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/mcp/mcp.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/memory/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/memory/manager.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/memory/storage.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/models/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/models/events.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/src/sqlsaber/models/types.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/conftest.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_agents/test_anthropic_oauth.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_cli/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_cli/test_commands.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_clients/test_anthropic_client.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_clients/test_streaming.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_config/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_config/test_database.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_config/test_oauth.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_config/test_settings.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_database/__init__.py +0 -0
- {sqlsaber-0.9.0 → sqlsaber-0.11.0}/tests/test_database/test_connection.py +0 -0
|
@@ -4,6 +4,21 @@ All notable changes to SQLSaber will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.11.0] - 2025-07-09
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Removed row counting from `list_tables` tool for all database types
|
|
12
|
+
|
|
13
|
+
## [0.10.0] - 2025-07-08
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Support for reading queries from stdin via pipe operator
|
|
18
|
+
- `echo 'show me all users' | saber` now works
|
|
19
|
+
- `cat query.txt | saber` reads query from file via stdin
|
|
20
|
+
- Allows integration with other command-line tools and scripts
|
|
21
|
+
|
|
7
22
|
## [0.9.0] - 2025-07-08
|
|
8
23
|
|
|
9
24
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlsaber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: SQLSaber - Agentic SQL assistant like Claude Code
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -139,6 +139,13 @@ Execute a single natural language query:
|
|
|
139
139
|
saber "show me all users created this month"
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
You can also pipe queries from stdin:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
echo "show me all users created this month" | saber
|
|
146
|
+
cat query.txt | saber
|
|
147
|
+
```
|
|
148
|
+
|
|
142
149
|
### Database Selection
|
|
143
150
|
|
|
144
151
|
Use a specific database connection:
|
|
@@ -118,6 +118,13 @@ Execute a single natural language query:
|
|
|
118
118
|
saber "show me all users created this month"
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
+
You can also pipe queries from stdin:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
echo "show me all users created this month" | saber
|
|
125
|
+
cat query.txt | saber
|
|
126
|
+
```
|
|
127
|
+
|
|
121
128
|
### Database Selection
|
|
122
129
|
|
|
123
130
|
Use a specific database connection:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""SQLSaber CLI - Agentic SQL assistant like Claude Code but for SQL."""
|
|
@@ -51,9 +51,11 @@ def meta_handler(
|
|
|
51
51
|
Query your database using natural language.
|
|
52
52
|
|
|
53
53
|
Examples:
|
|
54
|
-
saber
|
|
55
|
-
saber "show me all users"
|
|
56
|
-
saber -d mydb "show me users"
|
|
54
|
+
saber # Start interactive mode
|
|
55
|
+
saber "show me all users" # Run a single query with default database
|
|
56
|
+
saber -d mydb "show me users" # Run a query with specific database
|
|
57
|
+
echo "show me all users" | saber # Read query from stdin
|
|
58
|
+
cat query.txt | saber # Read query from file via stdin
|
|
57
59
|
"""
|
|
58
60
|
# Store database in app context for commands to access
|
|
59
61
|
app.meta["database"] = database
|
|
@@ -64,7 +66,7 @@ def query(
|
|
|
64
66
|
query_text: Annotated[
|
|
65
67
|
str | None,
|
|
66
68
|
cyclopts.Parameter(
|
|
67
|
-
help="SQL query in natural language (if not provided, starts interactive mode)",
|
|
69
|
+
help="SQL query in natural language (if not provided, reads from stdin or starts interactive mode)",
|
|
68
70
|
),
|
|
69
71
|
] = None,
|
|
70
72
|
database: Annotated[
|
|
@@ -77,11 +79,28 @@ def query(
|
|
|
77
79
|
):
|
|
78
80
|
"""Run a query against the database or start interactive mode.
|
|
79
81
|
|
|
80
|
-
When called without arguments
|
|
82
|
+
When called without arguments:
|
|
83
|
+
- If stdin has data, reads query from stdin
|
|
84
|
+
- Otherwise, starts interactive mode
|
|
85
|
+
|
|
81
86
|
When called with a query string, executes that query and exits.
|
|
87
|
+
|
|
88
|
+
Examples:
|
|
89
|
+
saber # Start interactive mode
|
|
90
|
+
saber "show me all users" # Run a single query
|
|
91
|
+
echo "show me all users" | saber # Read query from stdin
|
|
82
92
|
"""
|
|
83
93
|
|
|
84
94
|
async def run_session():
|
|
95
|
+
# Check if query_text is None and stdin has data
|
|
96
|
+
actual_query = query_text
|
|
97
|
+
if query_text is None and not sys.stdin.isatty():
|
|
98
|
+
# Read from stdin
|
|
99
|
+
actual_query = sys.stdin.read().strip()
|
|
100
|
+
if not actual_query:
|
|
101
|
+
# If stdin was empty, fall back to interactive mode
|
|
102
|
+
actual_query = None
|
|
103
|
+
|
|
85
104
|
# Get database configuration or handle direct CSV file
|
|
86
105
|
if database:
|
|
87
106
|
# Check if this is a direct CSV file path
|
|
@@ -119,13 +138,13 @@ def query(
|
|
|
119
138
|
agent = AnthropicSQLAgent(db_conn, db_name)
|
|
120
139
|
|
|
121
140
|
try:
|
|
122
|
-
if
|
|
141
|
+
if actual_query:
|
|
123
142
|
# Single query mode with streaming
|
|
124
143
|
streaming_handler = StreamingQueryHandler(console)
|
|
125
144
|
console.print(
|
|
126
145
|
f"[bold blue]Connected to:[/bold blue] {db_name} {agent._get_database_type_name()}\n"
|
|
127
146
|
)
|
|
128
|
-
await streaming_handler.execute_streaming_query(
|
|
147
|
+
await streaming_handler.execute_streaming_query(actual_query, agent)
|
|
129
148
|
else:
|
|
130
149
|
# Interactive mode
|
|
131
150
|
session = InteractiveSession(console, agent)
|
|
@@ -125,7 +125,6 @@ class DisplayManager:
|
|
|
125
125
|
{"name": "Schema", "style": "cyan"},
|
|
126
126
|
{"name": "Table Name", "style": "white"},
|
|
127
127
|
{"name": "Type", "style": "yellow"},
|
|
128
|
-
{"name": "Row Count", "justify": "right", "style": "magenta"},
|
|
129
128
|
]
|
|
130
129
|
table = self._create_table(columns)
|
|
131
130
|
|
|
@@ -134,12 +133,8 @@ class DisplayManager:
|
|
|
134
133
|
schema = table_info.get("schema", "")
|
|
135
134
|
name = table_info.get("name", "")
|
|
136
135
|
table_type = table_info.get("type", "")
|
|
137
|
-
row_count = table_info.get("row_count", 0)
|
|
138
136
|
|
|
139
|
-
|
|
140
|
-
formatted_count = f"{row_count:,}" if row_count else "0"
|
|
141
|
-
|
|
142
|
-
table.add_row(schema, name, table_type, formatted_count)
|
|
137
|
+
table.add_row(schema, name, table_type)
|
|
143
138
|
|
|
144
139
|
self.console.print(table)
|
|
145
140
|
|
|
@@ -42,7 +42,7 @@ class BaseSchemaIntrospector(ABC):
|
|
|
42
42
|
pass
|
|
43
43
|
|
|
44
44
|
@abstractmethod
|
|
45
|
-
async def list_tables_info(self, connection) -> dict[str, Any]:
|
|
45
|
+
async def list_tables_info(self, connection) -> list[dict[str, Any]]:
|
|
46
46
|
"""Get list of tables with basic information."""
|
|
47
47
|
pass
|
|
48
48
|
|
|
@@ -182,32 +182,31 @@ class PostgreSQLSchemaIntrospector(BaseSchemaIntrospector):
|
|
|
182
182
|
"""
|
|
183
183
|
return await conn.fetch(pk_query)
|
|
184
184
|
|
|
185
|
-
async def list_tables_info(self, connection) -> dict[str, Any]:
|
|
185
|
+
async def list_tables_info(self, connection) -> list[dict[str, Any]]:
|
|
186
186
|
"""Get list of tables with basic information for PostgreSQL."""
|
|
187
187
|
pool = await connection.get_pool()
|
|
188
188
|
async with pool.acquire() as conn:
|
|
189
|
-
# Get tables
|
|
189
|
+
# Get tables without row counts for better performance
|
|
190
190
|
tables_query = """
|
|
191
|
-
WITH table_stats AS (
|
|
192
|
-
SELECT
|
|
193
|
-
schemaname,
|
|
194
|
-
relname as tablename,
|
|
195
|
-
n_live_tup as approximate_row_count
|
|
196
|
-
FROM pg_stat_user_tables
|
|
197
|
-
)
|
|
198
191
|
SELECT
|
|
199
192
|
t.table_schema,
|
|
200
193
|
t.table_name,
|
|
201
|
-
t.table_type
|
|
202
|
-
COALESCE(ts.approximate_row_count, 0) as row_count
|
|
194
|
+
t.table_type
|
|
203
195
|
FROM information_schema.tables t
|
|
204
|
-
LEFT JOIN table_stats ts
|
|
205
|
-
ON t.table_schema = ts.schemaname
|
|
206
|
-
AND t.table_name = ts.tablename
|
|
207
196
|
WHERE t.table_schema NOT IN ('pg_catalog', 'information_schema')
|
|
208
197
|
ORDER BY t.table_schema, t.table_name;
|
|
209
198
|
"""
|
|
210
|
-
|
|
199
|
+
records = await conn.fetch(tables_query)
|
|
200
|
+
|
|
201
|
+
# Convert asyncpg.Record objects to dictionaries
|
|
202
|
+
return [
|
|
203
|
+
{
|
|
204
|
+
"table_schema": record["table_schema"],
|
|
205
|
+
"table_name": record["table_name"],
|
|
206
|
+
"table_type": record["table_type"],
|
|
207
|
+
}
|
|
208
|
+
for record in records
|
|
209
|
+
]
|
|
211
210
|
|
|
212
211
|
|
|
213
212
|
class MySQLSchemaIntrospector(BaseSchemaIntrospector):
|
|
@@ -353,24 +352,33 @@ class MySQLSchemaIntrospector(BaseSchemaIntrospector):
|
|
|
353
352
|
await cursor.execute(pk_query)
|
|
354
353
|
return await cursor.fetchall()
|
|
355
354
|
|
|
356
|
-
async def list_tables_info(self, connection) -> dict[str, Any]:
|
|
355
|
+
async def list_tables_info(self, connection) -> list[dict[str, Any]]:
|
|
357
356
|
"""Get list of tables with basic information for MySQL."""
|
|
358
357
|
pool = await connection.get_pool()
|
|
359
358
|
async with pool.acquire() as conn:
|
|
360
359
|
async with conn.cursor() as cursor:
|
|
361
|
-
# Get tables
|
|
360
|
+
# Get tables without row counts for better performance
|
|
362
361
|
tables_query = """
|
|
363
362
|
SELECT
|
|
364
363
|
t.table_schema,
|
|
365
364
|
t.table_name,
|
|
366
|
-
t.table_type
|
|
367
|
-
COALESCE(t.table_rows, 0) as row_count
|
|
365
|
+
t.table_type
|
|
368
366
|
FROM information_schema.tables t
|
|
369
367
|
WHERE t.table_schema NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys')
|
|
370
368
|
ORDER BY t.table_schema, t.table_name;
|
|
371
369
|
"""
|
|
372
370
|
await cursor.execute(tables_query)
|
|
373
|
-
|
|
371
|
+
rows = await cursor.fetchall()
|
|
372
|
+
|
|
373
|
+
# Convert rows to dictionaries
|
|
374
|
+
return [
|
|
375
|
+
{
|
|
376
|
+
"table_schema": row["table_schema"],
|
|
377
|
+
"table_name": row["table_name"],
|
|
378
|
+
"table_type": row["table_type"],
|
|
379
|
+
}
|
|
380
|
+
for row in rows
|
|
381
|
+
]
|
|
374
382
|
|
|
375
383
|
|
|
376
384
|
class SQLiteSchemaIntrospector(BaseSchemaIntrospector):
|
|
@@ -496,9 +504,9 @@ class SQLiteSchemaIntrospector(BaseSchemaIntrospector):
|
|
|
496
504
|
|
|
497
505
|
return primary_keys
|
|
498
506
|
|
|
499
|
-
async def list_tables_info(self, connection) -> dict[str, Any]:
|
|
507
|
+
async def list_tables_info(self, connection) -> list[dict[str, Any]]:
|
|
500
508
|
"""Get list of tables with basic information for SQLite."""
|
|
501
|
-
#
|
|
509
|
+
# Get table names without row counts for better performance
|
|
502
510
|
tables_query = """
|
|
503
511
|
SELECT
|
|
504
512
|
'main' as table_schema,
|
|
@@ -512,34 +520,15 @@ class SQLiteSchemaIntrospector(BaseSchemaIntrospector):
|
|
|
512
520
|
|
|
513
521
|
tables = await self._execute_query(connection, tables_query)
|
|
514
522
|
|
|
515
|
-
#
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
count_query = f"SELECT COUNT(*) as count FROM [{table_name}]"
|
|
525
|
-
count_result = await self._execute_query(connection, count_query)
|
|
526
|
-
row_count = count_result[0]["count"] if count_result else 0
|
|
527
|
-
except Exception:
|
|
528
|
-
# If count fails (e.g., table locked), default to 0
|
|
529
|
-
row_count = 0
|
|
530
|
-
else:
|
|
531
|
-
# For views, we don't count rows as it could be expensive
|
|
532
|
-
row_count = 0
|
|
533
|
-
|
|
534
|
-
result.append(
|
|
535
|
-
{
|
|
536
|
-
"table_schema": table["table_schema"],
|
|
537
|
-
"table_name": table_name,
|
|
538
|
-
"table_type": table_type,
|
|
539
|
-
"row_count": row_count,
|
|
540
|
-
}
|
|
541
|
-
)
|
|
542
|
-
return result
|
|
523
|
+
# Convert to expected format
|
|
524
|
+
return [
|
|
525
|
+
{
|
|
526
|
+
"table_schema": table["table_schema"],
|
|
527
|
+
"table_name": table["table_name"],
|
|
528
|
+
"table_type": table["table_type"],
|
|
529
|
+
}
|
|
530
|
+
for table in tables
|
|
531
|
+
]
|
|
543
532
|
|
|
544
533
|
|
|
545
534
|
class SchemaManager:
|
|
@@ -682,7 +671,7 @@ class SchemaManager:
|
|
|
682
671
|
)
|
|
683
672
|
|
|
684
673
|
async def list_tables(self) -> dict[str, Any]:
|
|
685
|
-
"""Get a list of all tables with basic information
|
|
674
|
+
"""Get a list of all tables with basic information."""
|
|
686
675
|
# Check cache first
|
|
687
676
|
cache_key = "list_tables"
|
|
688
677
|
cached_data = self._get_cached_tables(cache_key)
|
|
@@ -702,7 +691,6 @@ class SchemaManager:
|
|
|
702
691
|
"name": table["table_name"],
|
|
703
692
|
"full_name": f"{table['table_schema']}.{table['table_name']}",
|
|
704
693
|
"type": table["table_type"],
|
|
705
|
-
"row_count": table["row_count"],
|
|
706
694
|
}
|
|
707
695
|
)
|
|
708
696
|
|
|
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
|