deepcode-hku 1.0.2__tar.gz → 1.0.3__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.
- {deepcode_hku-1.0.2/deepcode_hku.egg-info → deepcode_hku-1.0.3}/PKG-INFO +1 -1
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/__init__.py +1 -1
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3/deepcode_hku.egg-info}/PKG-INFO +1 -1
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/SOURCES.txt +1 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/mcp_agent.config.yaml +9 -0
- deepcode_hku-1.0.3/tools/bocha_search_server.py +219 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agent_orchestration_engine.py +56 -7
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/.pre-commit-config.yaml +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/LICENSE +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/MANIFEST.in +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/README.md +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/__init__.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/cli_app.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/cli_interface.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/cli_launcher.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/main_cli.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/workflows/__init__.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/cli/workflows/cli_workflow_adapter.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/dependency_links.txt +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/entry_points.txt +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/requires.txt +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/deepcode_hku.egg-info/top_level.txt +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/mcp_agent.secrets.yaml +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/prompts/code_prompts.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/requirements.txt +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/schema/mcp-agent.config.schema.json +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/setup.cfg +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/setup.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/__init__.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/code_implementation_server.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/code_indexer.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/code_reference_indexer.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/command_executor.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/git_command.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/pdf_converter.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/pdf_downloader.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/tools/pdf_utils.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/__init__.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/app.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/components.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/handlers.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/layout.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/streamlit_app.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/ui/styles.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/__init__.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/cli_interface.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/dialogue_logger.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/file_processor.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/utils/simple_llm_logger.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/__init__.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/__init__.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/code_implementation_agent.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/memory_agent_concise.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/agents/memory_agent_concise_index.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/code_implementation_workflow.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/code_implementation_workflow_index.py +0 -0
- {deepcode_hku-1.0.2 → deepcode_hku-1.0.3}/workflows/codebase_index_workflow.py +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
$schema: ./schema/mcp-agent.config.schema.json
|
|
2
2
|
|
|
3
|
+
# Default search server configuration
|
|
4
|
+
# Options: "brave" or "bocha-mcp"
|
|
5
|
+
default_search_server: "brave"
|
|
3
6
|
|
|
4
7
|
execution_engine: asyncio
|
|
5
8
|
logger:
|
|
@@ -64,6 +67,12 @@ mcp:
|
|
|
64
67
|
env:
|
|
65
68
|
PYTHONPATH: "."
|
|
66
69
|
description: "Code reference indexer server - Provides intelligent code reference search from indexed repositories"
|
|
70
|
+
bocha-mcp:
|
|
71
|
+
command: "python3"
|
|
72
|
+
args: ["tools/bocha_search_server.py"]
|
|
73
|
+
env:
|
|
74
|
+
PYTHONPATH: "."
|
|
75
|
+
BOCHA_API_KEY: ""
|
|
67
76
|
|
|
68
77
|
openai:
|
|
69
78
|
# Secrets (API keys, etc.) are stored in an mcp_agent.secrets.yaml file which can be gitignored
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
from dotenv import load_dotenv
|
|
7
|
+
from mcp.server.fastmcp import FastMCP
|
|
8
|
+
|
|
9
|
+
load_dotenv()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Initialize FastMCP server
|
|
13
|
+
server = FastMCP(
|
|
14
|
+
"bocha-search-mcp",
|
|
15
|
+
prompt="""
|
|
16
|
+
# Bocha Search MCP Server
|
|
17
|
+
|
|
18
|
+
Bocha is a Chinese search engine for AI, This server provides tools for searching the web using Bocha Search API.
|
|
19
|
+
It allows you to get enhanced search details from billions of web documents, including weather, news, wikis, healthcare, train tickets, images, and more.
|
|
20
|
+
|
|
21
|
+
## Available Tools
|
|
22
|
+
|
|
23
|
+
### 1. bocha_web_search
|
|
24
|
+
Search with Bocha Web Search and get enhanced search details from billions of web documents, including page titles, urls, summaries, site names, site icons, publication dates, image links, and more.
|
|
25
|
+
|
|
26
|
+
### 2. bocha_ai_search
|
|
27
|
+
Search with Bocha AI Search, recognizes the semantics of search terms and additionally returns structured modal cards with content from vertical domains.
|
|
28
|
+
|
|
29
|
+
## Output Format
|
|
30
|
+
|
|
31
|
+
All search results will be formatted as text with clear sections for each
|
|
32
|
+
result item, including:
|
|
33
|
+
|
|
34
|
+
- Bocha Web search: Title, URL, Description, Published date and Site name
|
|
35
|
+
- Bocha AI search: Title, URL, Description, Published date, Site name, and structured data card
|
|
36
|
+
|
|
37
|
+
If the API key is missing or invalid, appropriate error messages will be returned.
|
|
38
|
+
""",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@server.tool()
|
|
43
|
+
async def bocha_web_search(
|
|
44
|
+
query: str, freshness: str = "noLimit", count: int = 10
|
|
45
|
+
) -> str:
|
|
46
|
+
"""Search with Bocha Web Search and get enhanced search details from billions of web documents,
|
|
47
|
+
including page titles, urls, summaries, site names, site icons, publication dates, image links, and more.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
query: Search query (required)
|
|
51
|
+
freshness: The time range for the search results. (Available options YYYY-MM-DD, YYYY-MM-DD..YYYY-MM-DD, noLimit, oneYear, oneMonth, oneWeek, oneDay. Default is noLimit)
|
|
52
|
+
count: Number of results (1-50, default 10)
|
|
53
|
+
"""
|
|
54
|
+
# Get API key from environment
|
|
55
|
+
boch_api_key = os.environ.get("BOCHA_API_KEY", "")
|
|
56
|
+
|
|
57
|
+
if not boch_api_key:
|
|
58
|
+
return (
|
|
59
|
+
"Error: Bocha API key is not configured. Please set the "
|
|
60
|
+
"BOCHA_API_KEY environment variable."
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Endpoint
|
|
64
|
+
endpoint = "https://api.bochaai.com/v1/web-search?utm_source=bocha-mcp-local"
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
payload = {
|
|
68
|
+
"query": query,
|
|
69
|
+
"summary": True,
|
|
70
|
+
"freshness": freshness,
|
|
71
|
+
"count": count,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
headers = {
|
|
75
|
+
"Authorization": f"Bearer {boch_api_key}",
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async with httpx.AsyncClient() as client:
|
|
80
|
+
response = await client.post(
|
|
81
|
+
endpoint, headers=headers, json=payload, timeout=10.0
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
response.raise_for_status()
|
|
85
|
+
resp = response.json()
|
|
86
|
+
if "data" not in resp:
|
|
87
|
+
return "Search error."
|
|
88
|
+
|
|
89
|
+
data = resp["data"]
|
|
90
|
+
|
|
91
|
+
if "webPages" not in data:
|
|
92
|
+
return "No results found."
|
|
93
|
+
|
|
94
|
+
results = []
|
|
95
|
+
for result in data["webPages"]["value"]:
|
|
96
|
+
results.append(
|
|
97
|
+
f"Title: {result['name']}\n"
|
|
98
|
+
f"URL: {result['url']}\n"
|
|
99
|
+
f"Description: {result['summary']}\n"
|
|
100
|
+
f"Published date: {result['datePublished']}\n"
|
|
101
|
+
f"Site name: {result['siteName']}"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return "\n\n".join(results)
|
|
105
|
+
|
|
106
|
+
except httpx.HTTPStatusError as e:
|
|
107
|
+
return f"Bocha Web Search API HTTP error occurred: {e.response.status_code} - {e.response.text}"
|
|
108
|
+
except httpx.RequestError as e:
|
|
109
|
+
return f"Error communicating with Bocha Web Search API: {str(e)}"
|
|
110
|
+
except Exception as e:
|
|
111
|
+
return f"Unexpected error: {str(e)}"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@server.tool()
|
|
115
|
+
async def bocha_ai_search(
|
|
116
|
+
query: str, freshness: str = "noLimit", count: int = 10
|
|
117
|
+
) -> str:
|
|
118
|
+
"""Search with Bocha AI Search, recognizes the semantics of search terms
|
|
119
|
+
and additionally returns structured modal cards with content from vertical domains.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
query: Search query (required)
|
|
123
|
+
freshness: The time range for the search results. (Available options noLimit, oneYear, oneMonth, oneWeek, oneDay. Default is noLimit)
|
|
124
|
+
count: Number of results (1-50, default 10)
|
|
125
|
+
"""
|
|
126
|
+
# Get API key from environment
|
|
127
|
+
boch_api_key = os.environ.get("BOCHA_API_KEY", "")
|
|
128
|
+
|
|
129
|
+
if not boch_api_key:
|
|
130
|
+
return (
|
|
131
|
+
"Error: Bocha API key is not configured. Please set the "
|
|
132
|
+
"BOCHA_API_KEY environment variable."
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Endpoint
|
|
136
|
+
endpoint = "https://api.bochaai.com/v1/ai-search?utm_source=bocha-mcp-local"
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
payload = {
|
|
140
|
+
"query": query,
|
|
141
|
+
"freshness": freshness,
|
|
142
|
+
"count": count,
|
|
143
|
+
"answer": False,
|
|
144
|
+
"stream": False,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
headers = {
|
|
148
|
+
"Authorization": f"Bearer {boch_api_key}",
|
|
149
|
+
"Content-Type": "application/json",
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async with httpx.AsyncClient() as client:
|
|
153
|
+
response = await client.post(
|
|
154
|
+
endpoint, headers=headers, json=payload, timeout=10.0
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
response.raise_for_status()
|
|
158
|
+
response = response.json()
|
|
159
|
+
results = []
|
|
160
|
+
if "messages" in response:
|
|
161
|
+
for message in response["messages"]:
|
|
162
|
+
content = {}
|
|
163
|
+
try:
|
|
164
|
+
content = json.loads(message["content"])
|
|
165
|
+
except (json.JSONDecodeError, TypeError):
|
|
166
|
+
content = {}
|
|
167
|
+
|
|
168
|
+
# 网页
|
|
169
|
+
if message["content_type"] == "webpage":
|
|
170
|
+
if "value" in content:
|
|
171
|
+
for item in content["value"]:
|
|
172
|
+
results.append(
|
|
173
|
+
f"Title: {item['name']}\n"
|
|
174
|
+
f"URL: {item['url']}\n"
|
|
175
|
+
f"Description: {item['summary']}\n"
|
|
176
|
+
f"Published date: {item['datePublished']}\n"
|
|
177
|
+
f"Site name: {item['siteName']}"
|
|
178
|
+
)
|
|
179
|
+
elif (
|
|
180
|
+
message["content_type"] != "image"
|
|
181
|
+
and message["content"] != "{}"
|
|
182
|
+
):
|
|
183
|
+
results.append(message["content"])
|
|
184
|
+
|
|
185
|
+
if not results:
|
|
186
|
+
return "No results found."
|
|
187
|
+
|
|
188
|
+
return "\n\n".join(results)
|
|
189
|
+
|
|
190
|
+
except httpx.HTTPStatusError as e:
|
|
191
|
+
return f"Bocha AI Search API HTTP error occurred: {e.response.status_code} - {e.response.text}"
|
|
192
|
+
except httpx.RequestError as e:
|
|
193
|
+
return f"Error communicating with Bocha AI Search API: {str(e)}"
|
|
194
|
+
except Exception as e:
|
|
195
|
+
return f"Unexpected error: {str(e)}"
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def main():
|
|
199
|
+
"""Initialize and run the MCP server."""
|
|
200
|
+
|
|
201
|
+
# Check for required environment variables
|
|
202
|
+
if "BOCHA_API_KEY" not in os.environ:
|
|
203
|
+
print(
|
|
204
|
+
"Error: BOCHA_API_KEY environment variable is required",
|
|
205
|
+
file=sys.stderr,
|
|
206
|
+
)
|
|
207
|
+
print(
|
|
208
|
+
"Get a Bocha API key from: " "https://open.bochaai.com",
|
|
209
|
+
file=sys.stderr,
|
|
210
|
+
)
|
|
211
|
+
sys.exit(1)
|
|
212
|
+
|
|
213
|
+
print("Starting Bocha Search MCP server...", file=sys.stderr)
|
|
214
|
+
|
|
215
|
+
server.run(transport="stdio")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
if __name__ == "__main__":
|
|
219
|
+
main()
|
|
@@ -31,7 +31,7 @@ import json
|
|
|
31
31
|
import os
|
|
32
32
|
import re
|
|
33
33
|
import yaml
|
|
34
|
-
from typing import Callable, Dict, Optional, Tuple
|
|
34
|
+
from typing import Callable, Dict, List, Optional, Tuple
|
|
35
35
|
|
|
36
36
|
# MCP Agent imports
|
|
37
37
|
from mcp_agent.agents.agent import Agent
|
|
@@ -99,6 +99,57 @@ def get_preferred_llm_class(config_path: str = "mcp_agent.secrets.yaml"):
|
|
|
99
99
|
return OpenAIAugmentedLLM
|
|
100
100
|
|
|
101
101
|
|
|
102
|
+
def get_default_search_server(config_path: str = "mcp_agent.config.yaml"):
|
|
103
|
+
"""
|
|
104
|
+
Get the default search server from configuration.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
config_path: Path to the main configuration file
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
str: The default search server name ("brave" or "bocha-mcp")
|
|
111
|
+
"""
|
|
112
|
+
try:
|
|
113
|
+
if os.path.exists(config_path):
|
|
114
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
115
|
+
config = yaml.safe_load(f)
|
|
116
|
+
|
|
117
|
+
default_server = config.get("default_search_server", "brave")
|
|
118
|
+
print(f"🔍 Using search server: {default_server}")
|
|
119
|
+
return default_server
|
|
120
|
+
else:
|
|
121
|
+
print(f"⚠️ Config file {config_path} not found, using default: brave")
|
|
122
|
+
return "brave"
|
|
123
|
+
except Exception as e:
|
|
124
|
+
print(f"⚠️ Error reading config file {config_path}: {e}")
|
|
125
|
+
print("🔍 Falling back to default search server: brave")
|
|
126
|
+
return "brave"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_search_server_names(
|
|
130
|
+
additional_servers: Optional[List[str]] = None,
|
|
131
|
+
) -> List[str]:
|
|
132
|
+
"""
|
|
133
|
+
Get server names list with the configured default search server.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
additional_servers: Optional list of additional servers to include
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
List[str]: List of server names including the default search server
|
|
140
|
+
"""
|
|
141
|
+
default_search = get_default_search_server()
|
|
142
|
+
server_names = [default_search]
|
|
143
|
+
|
|
144
|
+
if additional_servers:
|
|
145
|
+
# Add additional servers, avoiding duplicates
|
|
146
|
+
for server in additional_servers:
|
|
147
|
+
if server not in server_names:
|
|
148
|
+
server_names.append(server)
|
|
149
|
+
|
|
150
|
+
return server_names
|
|
151
|
+
|
|
152
|
+
|
|
102
153
|
def extract_clean_json(llm_output: str) -> str:
|
|
103
154
|
"""
|
|
104
155
|
Extract clean JSON from LLM output, removing all extra text and formatting.
|
|
@@ -193,7 +244,7 @@ async def run_research_analyzer(prompt_text: str, logger) -> str:
|
|
|
193
244
|
analyzer_agent = Agent(
|
|
194
245
|
name="ResearchAnalyzerAgent",
|
|
195
246
|
instruction=PAPER_INPUT_ANALYZER_PROMPT,
|
|
196
|
-
server_names=
|
|
247
|
+
server_names=get_search_server_names(),
|
|
197
248
|
)
|
|
198
249
|
|
|
199
250
|
async with analyzer_agent:
|
|
@@ -341,12 +392,12 @@ async def run_code_analyzer(paper_dir: str, logger) -> str:
|
|
|
341
392
|
algorithm_analysis_agent = Agent(
|
|
342
393
|
name="AlgorithmAnalysisAgent",
|
|
343
394
|
instruction=PAPER_ALGORITHM_ANALYSIS_PROMPT,
|
|
344
|
-
server_names=["filesystem"
|
|
395
|
+
server_names=get_search_server_names(additional_servers=["filesystem"]),
|
|
345
396
|
)
|
|
346
397
|
code_planner_agent = Agent(
|
|
347
398
|
name="CodePlannerAgent",
|
|
348
399
|
instruction=CODE_PLANNING_PROMPT,
|
|
349
|
-
server_names=
|
|
400
|
+
server_names=get_search_server_names(),
|
|
350
401
|
)
|
|
351
402
|
|
|
352
403
|
code_aggregator_agent = ParallelLLM(
|
|
@@ -931,9 +982,7 @@ async def run_chat_planning_agent(user_input: str, logger) -> str:
|
|
|
931
982
|
chat_planning_agent = Agent(
|
|
932
983
|
name="ChatPlanningAgent",
|
|
933
984
|
instruction=CHAT_AGENT_PLANNING_PROMPT,
|
|
934
|
-
server_names=
|
|
935
|
-
"brave"
|
|
936
|
-
], # Add tools if needed for web search or other capabilities
|
|
985
|
+
server_names=get_search_server_names(), # Dynamic search server configuration
|
|
937
986
|
)
|
|
938
987
|
|
|
939
988
|
async with chat_planning_agent:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|