dbagent-cli 0.9.1__tar.gz → 0.9.2__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.
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/PKG-INFO +1 -1
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/__init__.py +1 -1
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/conversation.py +5 -1
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/generator.py +41 -25
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/pipeline.py +13 -1
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/connectors/base.py +32 -4
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent_cli.egg-info/PKG-INFO +1 -1
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/pyproject.toml +1 -1
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/README.md +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/confidence.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/doctor.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/error_classifier.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/recommender.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/agent/validator.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/cli.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/config.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/connectors/factory.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/connectors/mongo.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/connectors/relational.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/execution/__init__.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/execution/cache.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/execution/changeset.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/execution/cost.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/execution/recovery.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/execution/sandbox.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/execution/streaming.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/anthropic_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/auto_setup.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/base.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/deepseek_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/factory.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/gemini_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/groq_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/mistral_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/mock_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/ollama_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/openai_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/llm/openrouter_provider.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/schema/cache.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/schema/formatter.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/schema/graph.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/schema/ground_truth.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/schema/models.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/schema/retriever.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/schema/selector.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/security/__init__.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/security/audit.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/security/environment.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/security/masking.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/security/modes.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/security/rbac.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/semantic/__init__.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/semantic/dictionary.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/semantic/knowledge.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/semantic/templates.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/sql/__init__.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/sql/optimizer.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/sql/validator.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/ui/chat_screen.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/ui/console.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/ui/grid_window.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/ui/viewer.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent/ui/visualizer.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent_cli.egg-info/SOURCES.txt +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent_cli.egg-info/dependency_links.txt +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent_cli.egg-info/entry_points.txt +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent_cli.egg-info/requires.txt +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/dbagent_cli.egg-info/top_level.txt +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/setup.cfg +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_cache.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_cli.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_connectors.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_direct_sql.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_doctor_and_viz.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_generator.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_graph.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_knowledge.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_providers.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_recovery.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_safety.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_sandbox.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_schema.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_security.py +0 -0
- {dbagent_cli-0.9.1 → dbagent_cli-0.9.2}/tests/test_semantic.py +0 -0
|
@@ -54,9 +54,13 @@ class ConversationContext:
|
|
|
54
54
|
if len(self.turns) > self.max_history:
|
|
55
55
|
self.turns.pop(0)
|
|
56
56
|
|
|
57
|
-
if tables
|
|
57
|
+
if tables:
|
|
58
58
|
self.active_tables.update(t.lower() for t in tables)
|
|
59
59
|
|
|
60
|
+
def get_active_tables(self) -> List[str]:
|
|
61
|
+
"""Returns currently active database table names discussed in this session."""
|
|
62
|
+
return list(self.active_tables)
|
|
63
|
+
|
|
60
64
|
def get_last_turn(self) -> Optional[ConversationTurn]:
|
|
61
65
|
if self.turns:
|
|
62
66
|
return self.turns[-1]
|
|
@@ -106,6 +106,11 @@ Provide ready-to-run, dialect-accurate SQL JOIN queries answering the user's spe
|
|
|
106
106
|
|
|
107
107
|
### 4. 💡 Architectural Insights & Best Practices
|
|
108
108
|
Mention indexing recommendations, cascade rules, or performance considerations for these join paths.
|
|
109
|
+
|
|
110
|
+
### 🛑 Critical Operational Directives:
|
|
111
|
+
1. NEVER ask passive questions like "Would you like me to inspect tables?" or "Should I run a query?". Always proactively inspect and deliver the full architectural blueprint immediately.
|
|
112
|
+
2. NEVER give generic textbook definitions. Always ground every explanation in the real database schema provided above.
|
|
113
|
+
3. Always include ALL 4 sections (Diagram, Theoretical Breakdown, SQL Queries, and Insights).
|
|
109
114
|
"""
|
|
110
115
|
|
|
111
116
|
|
|
@@ -142,37 +147,52 @@ class ScriptGenerator:
|
|
|
142
147
|
prompt_lower = user_prompt.lower().strip()
|
|
143
148
|
clean_prompt = prompt_lower.rstrip(".!?,:;~ ")
|
|
144
149
|
|
|
145
|
-
#
|
|
146
|
-
chat_triggers = [
|
|
147
|
-
"hello", "hi", "hey", "howdy", "greetings", "good morning", "good evening", "good afternoon",
|
|
148
|
-
"who are you", "what can you do", "what are you", "help me", "how to use",
|
|
149
|
-
"what is this", "tell me about this database", "how does this work",
|
|
150
|
-
"can you help", "thanks", "thank you", "thx", "bye", "goodbye", "see ya",
|
|
151
|
-
"good", "great", "nice", "cool", "awesome", "perfect", "ok", "okay",
|
|
152
|
-
"yes", "no", "sure", "got it", "understood", "nice work", "well done",
|
|
153
|
-
"sounds good", "looks good", "alright", "super", "neat", "excellent",
|
|
154
|
-
"amazing", "wonderful", "cool thanks", "great thanks", "thanks a lot",
|
|
155
|
-
]
|
|
156
|
-
for trig in chat_triggers:
|
|
157
|
-
if clean_prompt == trig or prompt_lower.startswith(f"{trig} ") or prompt_lower.startswith(f"{trig},") or prompt_lower.startswith(f"{trig}!"):
|
|
158
|
-
return "chat"
|
|
159
|
-
|
|
160
|
-
# Architecture / Relationship / Linkage / Analysis indicators
|
|
150
|
+
# 1. Architecture / Relationship / Linkage / Analysis indicators (Highest Priority)
|
|
161
151
|
analysis_keywords = [
|
|
162
152
|
"linkage architecture", "linkage", "architecture", "relationship between",
|
|
163
153
|
"how are", "how is", "how were", "how they were related", "how were they related",
|
|
164
|
-
"how they were mapped", "how to map", "mapped
|
|
154
|
+
"how they were mapped", "how to map", "where they mapped", "where is it mapped",
|
|
155
|
+
"how they were assigned", "how are they assigned", "how will be linked", "how is it linked",
|
|
156
|
+
"mapped to", "mapped with", "er diagram", "diagram of",
|
|
165
157
|
"data model", "explain relationship", "explain schema", "schema analysis",
|
|
166
158
|
"analyze the database", "analyze database", "table relationship",
|
|
167
159
|
"foreign key relationship", "how are tables related", "which sites in",
|
|
168
160
|
"how to know that which", "how to know which", "mapping architecture",
|
|
169
161
|
"entity relationship", "theoritical information", "theoretical information",
|
|
162
|
+
"check with my previous context", "check with previous context", "previous context",
|
|
163
|
+
"complete architecture", "scope architecture", "tenant level to user level",
|
|
164
|
+
"tenant level", "user level",
|
|
170
165
|
]
|
|
171
166
|
for kw in analysis_keywords:
|
|
172
167
|
if kw in prompt_lower:
|
|
173
168
|
return "analysis"
|
|
174
169
|
|
|
175
|
-
#
|
|
170
|
+
# Contextual clarification for analysis (e.g. "i mean ivis_scope", "i mean table_x")
|
|
171
|
+
if re.search(r'\bi mean\b', prompt_lower) and not re.search(r'\b(insert|update|delete|drop)\b', prompt_lower):
|
|
172
|
+
return "analysis"
|
|
173
|
+
|
|
174
|
+
# 2. Pure Greeting / Feedback / Help triggers (Only when not asking a technical question)
|
|
175
|
+
pure_chat_greetings = ["hello", "hi", "hey", "howdy", "greetings", "good morning", "good evening", "good afternoon"]
|
|
176
|
+
pure_chat_feedback = [
|
|
177
|
+
"thanks", "thank you", "thx", "bye", "goodbye", "see ya",
|
|
178
|
+
"good", "great", "nice", "cool", "awesome", "perfect", "ok", "okay",
|
|
179
|
+
"yes", "no", "sure", "got it", "understood", "nice work", "well done",
|
|
180
|
+
"sounds good", "looks good", "alright", "super", "neat", "excellent",
|
|
181
|
+
"amazing", "wonderful", "cool thanks", "great thanks", "thanks a lot",
|
|
182
|
+
]
|
|
183
|
+
pure_chat_help = [
|
|
184
|
+
"who are you", "what can you do", "what are you", "help me", "how to use",
|
|
185
|
+
"what is this", "tell me about this database", "how does this work", "can you help",
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
if clean_prompt in pure_chat_greetings or clean_prompt in pure_chat_feedback or clean_prompt in pure_chat_help:
|
|
189
|
+
return "chat"
|
|
190
|
+
|
|
191
|
+
for trig in pure_chat_greetings + pure_chat_help:
|
|
192
|
+
if prompt_lower.startswith(f"{trig} ") or prompt_lower.startswith(f"{trig},") or prompt_lower.startswith(f"{trig}!"):
|
|
193
|
+
return "chat"
|
|
194
|
+
|
|
195
|
+
# 3. DDL indicators
|
|
176
196
|
ddl_keywords = [
|
|
177
197
|
"create table", "alter table", "drop table", "add column",
|
|
178
198
|
"remove column", "rename column", "rename table", "modify column",
|
|
@@ -182,7 +202,7 @@ class ScriptGenerator:
|
|
|
182
202
|
if kw in prompt_lower:
|
|
183
203
|
return "ddl"
|
|
184
204
|
|
|
185
|
-
# Write indicators (word-boundary matching to avoid false positives like "show dataset")
|
|
205
|
+
# 4. Write indicators (word-boundary matching to avoid false positives like "show dataset")
|
|
186
206
|
write_phrases = [
|
|
187
207
|
"insert", "add record", "add row", "add new",
|
|
188
208
|
"update", "delete", "drop record",
|
|
@@ -191,14 +211,10 @@ class ScriptGenerator:
|
|
|
191
211
|
for kw in write_phrases:
|
|
192
212
|
if kw in prompt_lower:
|
|
193
213
|
return "write"
|
|
194
|
-
# Single-word write verbs need word boundary to avoid false positives
|
|
195
|
-
# e.g. "set" should not match "dataset", "change" should not match "show changes"
|
|
196
|
-
import re as _re
|
|
197
214
|
write_verbs = ["set", "change", "modify", "remove"]
|
|
198
215
|
for verb in write_verbs:
|
|
199
|
-
if
|
|
200
|
-
|
|
201
|
-
read_context = _re.search(r'\b(?:show|list|display|view|get|count)\b.*\b' + verb, prompt_lower)
|
|
216
|
+
if re.search(r'\b' + verb + r'\b', prompt_lower):
|
|
217
|
+
read_context = re.search(r'\b(?:show|list|display|view|get|count)\b.*\b' + verb, prompt_lower)
|
|
202
218
|
if not read_context:
|
|
203
219
|
return "write"
|
|
204
220
|
|
|
@@ -214,6 +214,12 @@ class QueryPipeline:
|
|
|
214
214
|
except Exception:
|
|
215
215
|
exact, fuzzy = [], []
|
|
216
216
|
|
|
217
|
+
# Inherit active tables from conversation context if follow-up prompt doesn't name tables explicitly
|
|
218
|
+
if not exact and not fuzzy:
|
|
219
|
+
inherited = self.conversation.get_active_tables()
|
|
220
|
+
if inherited:
|
|
221
|
+
exact = inherited[:4]
|
|
222
|
+
|
|
217
223
|
sub_schema, join_steps = self._get_fast_schema_context(user_prompt, exact, fuzzy)
|
|
218
224
|
result.schema = sub_schema
|
|
219
225
|
result.join_steps = join_steps
|
|
@@ -244,7 +250,13 @@ class QueryPipeline:
|
|
|
244
250
|
result.was_executed = True
|
|
245
251
|
result.query_type = "analysis"
|
|
246
252
|
result.execution_time_ms = (time.time() - t_start) * 1000
|
|
247
|
-
self.conversation.add_turn(
|
|
253
|
+
self.conversation.add_turn(
|
|
254
|
+
user_prompt=user_prompt,
|
|
255
|
+
sql="",
|
|
256
|
+
assistant_response=result.message,
|
|
257
|
+
tables=exact + fuzzy,
|
|
258
|
+
is_chat=True,
|
|
259
|
+
)
|
|
248
260
|
return result
|
|
249
261
|
except Exception as e:
|
|
250
262
|
result.error = f"Architecture analysis failed: {str(e)}"
|
|
@@ -44,14 +44,42 @@ class BaseConnector(ABC):
|
|
|
44
44
|
|
|
45
45
|
def resolve_tables(self, user_prompt: str) -> Tuple[List[str], List[str]]:
|
|
46
46
|
"""
|
|
47
|
-
Resolve which tables the user is referring to.
|
|
47
|
+
Resolve which tables the user is referring to with prefix stripping, pluralization handling, and fuzzy matching.
|
|
48
48
|
Returns (exact_matches, fuzzy_matches).
|
|
49
|
-
Default implementation uses get_table_names with simple substring matching.
|
|
50
49
|
"""
|
|
50
|
+
import re
|
|
51
51
|
all_tables = self.get_table_names()
|
|
52
52
|
prompt_lower = user_prompt.lower()
|
|
53
|
-
exact = [
|
|
54
|
-
|
|
53
|
+
exact = []
|
|
54
|
+
fuzzy = []
|
|
55
|
+
|
|
56
|
+
tokens = set(re.findall(r'\b[a-zA-Z0-9_]+\b', prompt_lower))
|
|
57
|
+
|
|
58
|
+
for t in all_tables:
|
|
59
|
+
t_lower = t.lower()
|
|
60
|
+
# 1. Exact full table name in prompt
|
|
61
|
+
if re.search(r'\b' + re.escape(t_lower) + r'\b', prompt_lower):
|
|
62
|
+
exact.append(t)
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
# 2. Match without common prefixes (e.g. "ivis_scope" -> "scope", "scopes")
|
|
66
|
+
unprefixed = re.sub(r'^(?:ivis_|tbl_|table_|app_)', '', t_lower)
|
|
67
|
+
if unprefixed and len(unprefixed) >= 3:
|
|
68
|
+
if (unprefixed in tokens or
|
|
69
|
+
f"{unprefixed}s" in tokens or
|
|
70
|
+
f"{unprefixed}es" in tokens or
|
|
71
|
+
re.search(r'\b' + re.escape(unprefixed) + r'(?:s|es)?\b', prompt_lower)):
|
|
72
|
+
if t not in exact:
|
|
73
|
+
exact.append(t)
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
# 3. Fuzzy partial match
|
|
77
|
+
for tok in tokens:
|
|
78
|
+
if len(tok) >= 4 and (tok in t_lower or t_lower in tok):
|
|
79
|
+
if t not in exact and t not in fuzzy:
|
|
80
|
+
fuzzy.append(t)
|
|
81
|
+
|
|
82
|
+
return exact, fuzzy
|
|
55
83
|
|
|
56
84
|
def refresh_cache(self) -> None:
|
|
57
85
|
"""Invalidate any cached metadata. Override in subclasses."""
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dbagent-cli"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.2"
|
|
8
8
|
description = "Enterprise AI Database Copilot, Schema Graph Introspector & Autonomous Recovery Agent (CLI)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|