├── .gitignore
├── LICENSE
├── README.md
├── function_call_main.py
├── main.py
├── playground
└── playground.ipynb
├── requirements.txt
├── testing-directories
├── analyzer.py
├── data_processor.py
├── main.py
└── utils.py
└── testing-files
└── basic_python.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/windows,python,macos,linux
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=windows,python,macos,linux
3 |
4 | ### Linux ###
5 | *~
6 |
7 | # temporary files which can be created if a process still has a handle open of a deleted file
8 | .fuse_hidden*
9 |
10 | # KDE directory preferences
11 | .directory
12 |
13 | # Linux trash folder which might appear on any partition or disk
14 | .Trash-*
15 |
16 | # .nfs files are created when an open file is removed but is still being accessed
17 | .nfs*
18 |
19 | ### macOS ###
20 | # General
21 | .DS_Store
22 | .AppleDouble
23 | .LSOverride
24 |
25 | # Icon must end with two \r
26 | Icon
27 |
28 |
29 | # Thumbnails
30 | ._*
31 |
32 | # Files that might appear in the root of a volume
33 | .DocumentRevisions-V100
34 | .fseventsd
35 | .Spotlight-V100
36 | .TemporaryItems
37 | .Trashes
38 | .VolumeIcon.icns
39 | .com.apple.timemachine.donotpresent
40 |
41 | # Directories potentially created on remote AFP share
42 | .AppleDB
43 | .AppleDesktop
44 | Network Trash Folder
45 | Temporary Items
46 | .apdisk
47 |
48 | ### macOS Patch ###
49 | # iCloud generated files
50 | *.icloud
51 |
52 | ### Python ###
53 | # Byte-compiled / optimized / DLL files
54 | __pycache__/
55 | *.py[cod]
56 | *$py.class
57 |
58 | # C extensions
59 | *.so
60 |
61 | # Distribution / packaging
62 | .Python
63 | build/
64 | develop-eggs/
65 | dist/
66 | downloads/
67 | eggs/
68 | .eggs/
69 | lib/
70 | lib64/
71 | parts/
72 | sdist/
73 | var/
74 | wheels/
75 | share/python-wheels/
76 | *.egg-info/
77 | .installed.cfg
78 | *.egg
79 | MANIFEST
80 |
81 | # PyInstaller
82 | # Usually these files are written by a python script from a template
83 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
84 | *.manifest
85 | *.spec
86 |
87 | # Installer logs
88 | pip-log.txt
89 | pip-delete-this-directory.txt
90 |
91 | # Unit test / coverage reports
92 | htmlcov/
93 | .tox/
94 | .nox/
95 | .coverage
96 | .coverage.*
97 | .cache
98 | nosetests.xml
99 | coverage.xml
100 | *.cover
101 | *.py,cover
102 | .hypothesis/
103 | .pytest_cache/
104 | cover/
105 |
106 | # Translations
107 | *.mo
108 | *.pot
109 |
110 | # Django stuff:
111 | *.log
112 | local_settings.py
113 | db.sqlite3
114 | db.sqlite3-journal
115 |
116 | # Flask stuff:
117 | instance/
118 | .webassets-cache
119 |
120 | # Scrapy stuff:
121 | .scrapy
122 |
123 | # Sphinx documentation
124 | docs/_build/
125 |
126 | # PyBuilder
127 | .pybuilder/
128 | target/
129 |
130 | # Jupyter Notebook
131 | .ipynb_checkpoints
132 |
133 | # IPython
134 | profile_default/
135 | ipython_config.py
136 |
137 | # pyenv
138 | # For a library or package, you might want to ignore these files since the code is
139 | # intended to run in multiple environments; otherwise, check them in:
140 | # .python-version
141 |
142 | # pipenv
143 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
144 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
145 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
146 | # install all needed dependencies.
147 | #Pipfile.lock
148 |
149 | # poetry
150 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
151 | # This is especially recommended for binary packages to ensure reproducibility, and is more
152 | # commonly ignored for libraries.
153 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
154 | #poetry.lock
155 |
156 | # pdm
157 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
158 | #pdm.lock
159 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
160 | # in version control.
161 | # https://pdm.fming.dev/#use-with-ide
162 | .pdm.toml
163 |
164 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
165 | __pypackages__/
166 |
167 | # Celery stuff
168 | celerybeat-schedule
169 | celerybeat.pid
170 |
171 | # SageMath parsed files
172 | *.sage.py
173 |
174 | # Environments
175 | .env
176 | .venv
177 | env/
178 | venv/
179 | ENV/
180 | env.bak/
181 | venv.bak/
182 |
183 | # Spyder project settings
184 | .spyderproject
185 | .spyproject
186 |
187 | # Rope project settings
188 | .ropeproject
189 |
190 | # mkdocs documentation
191 | /site
192 |
193 | # mypy
194 | .mypy_cache/
195 | .dmypy.json
196 | dmypy.json
197 |
198 | # Pyre type checker
199 | .pyre/
200 |
201 | # pytype static type analyzer
202 | .pytype/
203 |
204 | # Cython debug symbols
205 | cython_debug/
206 |
207 | # PyCharm
208 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
209 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
210 | # and can be added to the global gitignore or merged into this file. For a more nuclear
211 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
212 | #.idea/
213 |
214 | ### Python Patch ###
215 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
216 | poetry.toml
217 |
218 | # ruff
219 | .ruff_cache/
220 |
221 | # LSP config files
222 | pyrightconfig.json
223 |
224 | ### Windows ###
225 | # Windows thumbnail cache files
226 | Thumbs.db
227 | Thumbs.db:encryptable
228 | ehthumbs.db
229 | ehthumbs_vista.db
230 |
231 | # Dump file
232 | *.stackdump
233 |
234 | # Folder config file
235 | [Dd]esktop.ini
236 |
237 | # Recycle Bin used on file shares
238 | $RECYCLE.BIN/
239 |
240 | # Windows Installer files
241 | *.cab
242 | *.msi
243 | *.msix
244 | *.msm
245 | *.msp
246 |
247 | # Windows shortcuts
248 | *.lnk
249 |
250 | # End of https://www.toptal.com/developers/gitignore/api/windows,python,macos,linux
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Vishal Padia
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CodeFlowMapper
2 |
3 | CodeFlowMapper is an open-source tool that generates 3D visualizations of Python codebases, helping developers quickly understand and navigate complex projects.
4 |
5 | ## How does it look?
6 | 
7 |
8 | ## Features
9 |
10 | - **3D Visualization**: Generate interactive 3D maps of your Python codebase.
11 | - **File and Function Mapping**: View files as parent nodes and functions as child nodes.
12 | - **Customizable Omissions**: Exclude specific directories from visualization.
13 | - **Obsidian-like Interface**: Familiar and intuitive visualization style.
14 |
15 | ## Quick Start
16 | To run CodeFlowMapper, you can use the following command-line interface:
17 | 1. Clone the repository and navigate to the project directory:
18 | ```bash
19 | $ git clone https://github.com/Vishal-Padia/CodeFlowMapper
20 | $ cd CodeFlowMapper
21 | ```
22 | 2. Create a virtual environment using the following command:
23 | ```bash
24 | $ python3 -m venv venv
25 | ```
26 | 3. Activate the virtual environment:
27 | ```bash
28 | $ source venv/bin/activate
29 | ```
30 | 4. Install the required dependencies:
31 | ```bash
32 | $ pip install -r requirements.txt
33 | ```
34 | 5. Run the CodeFlowMapper script:
35 | ```bash
36 | $ python main.py
37 | ```
38 | 6. Follow the prompts to input your project path and exclude directories.
39 |
40 | 7. Access the visualization at `http://localhost:5000`.
41 |
42 | **It takes some time to generate the visualization, so please be patient.**
43 | HAPPY VISUALIZING!
44 |
45 |
46 | ## Usage
47 |
48 | After launching, CodeFlowMapper will:
49 | - Download necessary models (first-time only).
50 | - Prompt for the path to your Python file or directory.
51 | - Ask for directories to exclude from the visualization.
52 | - Start a Flask server and generate the 3D visualization.
53 |
54 | ## Current Limitations
55 |
56 | - Python files and directories only
57 | - Basic Python feature support (no decorators or lambdas)
58 | - Static analysis only
59 |
60 | ## Roadmap
61 | - [ ] Add support for more programming languages
62 | - [ ] Enhance visualization with more features
63 | - [ ] Complex Python feature support
64 | - [x] AI-Powered Code Analysis
65 |
66 | ## Contributing
67 | We welcome contributions to CodeFlowMapper! If you have suggestions for improvements or bug fixes, please feel free to:
68 |
69 | - Fork the repository
70 | - Create a new branch `(git checkout -b feature/AmazingFeature)`
71 | - Commit your changes `(git commit -m 'Add some AmazingFeature')`
72 | - Push to the branch `(git push origin feature/AmazingFeature)`
73 | - Open a Pull Request
74 |
75 | ## License
76 | This project is licensed under the MIT License - see the LICENSE file for details.
77 |
78 | ## Contact
79 | Vishal Padia - vishalpadi9@gmail.com
80 |
81 | Project Link: https://github.com/Vishal-Padia/CodeFlowMapper
82 |
--------------------------------------------------------------------------------
/function_call_main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import ast
3 | import flask
4 | import networkx as nx
5 | from flask import Flask, render_template_string, jsonify
6 |
7 | app = Flask(__name__)
8 |
9 | G = None
10 |
11 |
12 | def network_to_visjs(G):
13 | nodes = [
14 | {"id": node, "label": G.nodes[node].get("label", node)} for node in G.nodes()
15 | ]
16 | edges = [{"from": source, "to": target} for source, target in G.edges()]
17 | return {"nodes": nodes, "edges": edges}
18 |
19 |
20 | def parse_directory(directory_path: str, omit_dirs: list):
21 | python_files = []
22 | for root, dirs, files in os.walk(directory_path):
23 | dirs[:] = [d for d in dirs if d not in omit_dirs]
24 |
25 | for file in files:
26 | if file.endswith(".py"):
27 | python_files.append(os.path.join(root, file))
28 | return python_files
29 |
30 |
31 | def parse_file(file_path: str):
32 | with open(file_path, "r", encoding="utf-8") as f:
33 | tree = ast.parse(f.read())
34 | return tree
35 |
36 |
37 | def extract_functions_and_imports(tree):
38 | functions = {}
39 | imports = set()
40 | for node in ast.walk(tree):
41 | if isinstance(node, ast.FunctionDef):
42 | functions[node.name] = {"calls": [], "line": node.lineno, "file": None}
43 | elif isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):
44 | for alias in node.names:
45 | imports.add(alias.name.split(".")[0]) # Add imported module names
46 | return functions, imports
47 |
48 |
49 | def analyze_function_calls(tree, functions):
50 | for node in ast.walk(tree):
51 | if isinstance(node, ast.Call):
52 | caller = None
53 | for parent in ast.walk(tree):
54 | if isinstance(parent, ast.FunctionDef) and node in ast.walk(parent):
55 | caller = parent.name
56 | break
57 | if caller and caller in functions:
58 | if isinstance(node.func, ast.Name):
59 | called_func = node.func.id
60 | functions[caller]["calls"].append(called_func)
61 | elif isinstance(node.func, ast.Attribute):
62 | called_func = node.func.attr
63 | if isinstance(node.func.value, ast.Name):
64 | object_name = node.func.value.id
65 | functions[caller]["calls"].append(
66 | f"{object_name}.{called_func}"
67 | )
68 | else:
69 | functions[caller]["calls"].append(called_func)
70 | else:
71 | if hasattr(node.func, "id"):
72 | functions[caller]["calls"].append(node.func.id)
73 | elif hasattr(node.func, "attr"):
74 | functions[caller]["calls"].append(node.func.attr)
75 |
76 |
77 | def create_graph_with_directory_structure(functions, imports, file_paths):
78 | G = nx.DiGraph()
79 |
80 | directory_nodes = {}
81 |
82 | for file_path in file_paths:
83 | directory = os.path.dirname(file_path)
84 | module_name = os.path.basename(file_path).replace(".py", "")
85 |
86 | # Add directory node
87 | if directory not in directory_nodes:
88 | G.add_node(directory, label=directory, shape="box", color="lightblue")
89 | directory_nodes[directory] = True
90 |
91 | # Add file node
92 | G.add_node(file_path, label=module_name, shape="ellipse", color="lightgreen")
93 | G.add_edge(directory, file_path)
94 |
95 | for func, data in functions.items():
96 | if data["file"] == file_path:
97 | G.add_node(func, module=module_name)
98 | G.add_edge(file_path, func)
99 | for call in data["calls"]:
100 | if call in functions:
101 | G.add_edge(func, call)
102 |
103 | for module in imports:
104 | G.add_node(module, module="import")
105 |
106 | return G
107 |
108 |
109 | @app.route("/")
110 | def index():
111 | return render_template_string(
112 | """
113 |
114 |
115 |
116 | Function Call Graph
117 |
118 |
125 |
126 |
127 |
128 |
171 |
172 |
173 | """
174 | )
175 |
176 |
177 | @app.route("/graph_data")
178 | def graph_data():
179 | return jsonify(network_to_visjs(G))
180 |
181 |
182 | def run_flask_app():
183 | print("Starting the web server.")
184 | print(
185 | "Please open a web browser and go to http://127.0.0.1:5000/ to view the graph."
186 | )
187 | app.run(debug=True)
188 |
189 |
190 | def create_graph_from_directory(directory_path, omit_dirs):
191 | global G
192 | python_files = parse_directory(directory_path, omit_dirs)
193 |
194 | functions = {}
195 | imports = set()
196 |
197 | for i, file_path in enumerate(python_files):
198 | tree = parse_file(file_path)
199 | file_functions, file_imports = extract_functions_and_imports(tree)
200 |
201 | for func_name, func_data in file_functions.items():
202 | func_data["file"] = file_path
203 |
204 | functions.update(file_functions)
205 | imports.update(file_imports)
206 | analyze_function_calls(tree, functions)
207 |
208 | G = create_graph_with_directory_structure(
209 | functions, imports, python_files[: i + 1]
210 | )
211 |
212 | print(
213 | f"Processing file {i+1}/{len(python_files)}: {os.path.basename(file_path)}"
214 | )
215 |
216 | print("Graph creation completed.")
217 |
218 |
219 | def main():
220 | directory_path = input("Enter the path to the directory: ")
221 | print(f"The input directory is: {directory_path}")
222 | omit_dirs = input("Enter the directories to omit (comma-separated): ").split(",")
223 | omit_list = [func.strip() for func in omit_dirs]
224 | create_graph_from_directory(directory_path, omit_list)
225 | run_flask_app()
226 |
227 |
228 | if __name__ == "__main__":
229 | main()
230 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import ast
3 | import flask
4 | import networkx as nx
5 | from flask import Flask, render_template_string, jsonify, request
6 | from transformers import pipeline
7 |
8 | app = Flask(__name__)
9 |
10 | G = None
11 | code_contents = {}
12 |
13 | # Initialize the code explanation model
14 | explainer = pipeline("text2text-generation", model="facebook/bart-large-cnn")
15 |
16 |
17 | def network_to_visjs(G: nx.DiGraph):
18 | """
19 | Convert a NetworkX graph to a dictionary format that can be used by vis.js.
20 | """
21 | nodes = [
22 | {
23 | "id": node,
24 | "label": G.nodes[node].get("label", node),
25 | "color": G.nodes[node].get("color", "#FFFFFF"),
26 | "shape": G.nodes[node].get("shape", "dot"),
27 | "size": G.nodes[node].get("size", 10),
28 | }
29 | for node in G.nodes()
30 | ]
31 | edges = [
32 | {"from": source, "to": target, "color": "#FFFFFF"}
33 | for source, target in G.edges()
34 | ]
35 | return {"nodes": nodes, "edges": edges}
36 |
37 |
38 | def parse_directory(directory_path: str, omit_dirs: list):
39 | """
40 | Parse a directory and return a list of Python files in the directory.
41 | """
42 | python_files = []
43 | for root, dirs, files in os.walk(directory_path):
44 | dirs[:] = [d for d in dirs if d not in omit_dirs]
45 | for file in files:
46 | if file.endswith(".py"):
47 | python_files.append(os.path.join(root, file))
48 | return python_files
49 |
50 |
51 | def parse_file(file_path: str):
52 | """
53 | Parse a Python file and return the AST (Abstract Syntax Tree) representation of the code.
54 | """
55 | with open(file_path, "r", encoding="utf-8") as f:
56 | content = f.read()
57 | code_contents[file_path] = content
58 | tree = ast.parse(content)
59 | return tree
60 |
61 |
62 | def extract_functions_and_imports(tree: ast.AST):
63 | """
64 | Extract function definitions and imports from the AST of a Python file.
65 | Also track function calls for execution path visualization.
66 | """
67 | functions = {}
68 | imports = set()
69 | function_stack = []
70 | current_func = None
71 |
72 | for node in ast.walk(tree):
73 | if isinstance(node, ast.FunctionDef):
74 | current_func = node.name
75 | functions[node.name] = {"calls": [], "line": node.lineno, "file": None}
76 | function_stack.append(current_func)
77 |
78 | elif isinstance(node, ast.Call) and current_func:
79 | if isinstance(node.func, ast.Name):
80 | functions[current_func]["calls"].append(node.func.id)
81 |
82 | elif isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):
83 | for alias in node.names:
84 | imports.add(alias.name.split(".")[0])
85 |
86 | elif isinstance(node, ast.Return):
87 | if function_stack:
88 | function_stack.pop()
89 | current_func = function_stack[-1] if function_stack else None
90 |
91 | return functions, imports
92 |
93 |
94 | def create_graph_with_directory_structure(
95 | functions: dict, imports: set, file_paths: list
96 | ):
97 | """
98 | Create a directed graph representing the directory structure of Python files, function calls, and imports.
99 | """
100 | G = nx.DiGraph()
101 |
102 | for file_path in file_paths:
103 | module_name = os.path.basename(file_path).replace(".py", "")
104 | G.add_node(file_path, label=module_name, color="#FF6B6B", shape="dot", size=15)
105 |
106 | for module in imports:
107 | G.add_node(module, label=module, color="#4ECDC4", shape="dot", size=10)
108 |
109 | for func_name, func_data in functions.items():
110 | G.add_node(func_name, label=func_name, color="#FFFFFF", shape="dot", size=7)
111 | if func_data["file"]:
112 | G.add_edge(func_data["file"], func_name)
113 |
114 | for called_func in func_data["calls"]:
115 | if called_func in functions:
116 | G.add_edge(func_name, called_func)
117 |
118 | return G
119 |
120 |
121 | @app.route("/")
122 | def index():
123 | """
124 | A web page displaying the graph with search and code execution path visualization.
125 | """
126 | return render_template_string(
127 | """
128 |
129 |
130 |
131 | Graph Visualization
132 |
133 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
286 |
287 |
288 | """
289 | )
290 |
291 |
292 | @app.route("/graph_data")
293 | def graph_data():
294 | """
295 | Serve the graph data for visualization.
296 | """
297 | visjs_data = network_to_visjs(G)
298 | return jsonify(visjs_data)
299 |
300 |
301 | @app.route("/get_code")
302 | def get_code():
303 | """
304 | Serve the code for a clicked node.
305 | """
306 | node = request.args.get("node")
307 | return jsonify({"code": code_contents.get(node, "Code not found.")})
308 |
309 |
310 | @app.route("/explain_code", methods=["POST"])
311 | def explain_code():
312 | """
313 | Explain the code using AI when the user clicks the 'Explain' button.
314 | """
315 | code = request.json.get("code")
316 | explanation = explainer(code)[0]["summary_text"]
317 | return jsonify({"explanation": explanation})
318 |
319 |
320 | if __name__ == "__main__":
321 | # Sample directory to parse (replace with your directory)
322 | directory_path = input("Enter the path to the directory to parse: ")
323 | print(f"Parsing directory: {directory_path}")
324 |
325 | omit_dirs = input("Enter the directories to omit (comma-separated): ").split(",")
326 | print(f"Omitting directories: {omit_dirs}")
327 |
328 | python_files = parse_directory(directory_path, omit_dirs)
329 |
330 | # Parse files and extract functions and imports
331 | all_functions = {}
332 | all_imports = set()
333 | for file_path in python_files:
334 | tree = parse_file(file_path)
335 | functions, imports = extract_functions_and_imports(tree)
336 | for func_name, func_data in functions.items():
337 | func_data["file"] = file_path
338 | all_functions[func_name] = func_data
339 | all_imports.update(imports)
340 |
341 | # Create the graph
342 | G = create_graph_with_directory_structure(all_functions, all_imports, python_files)
343 |
344 | # Run the Flask app
345 | app.run(debug=True)
346 |
--------------------------------------------------------------------------------
/playground/playground.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Purpose of this file:\n",
8 | "\n",
9 | "The file is just used for debugging purposes. It is used to check if the code is working as expected."
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "# importing modules\n",
19 | "import ast\n",
20 | "import networkx as nx\n",
21 | "import matplotlib.pyplot as plt"
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 2,
27 | "metadata": {},
28 | "outputs": [],
29 | "source": [
30 | "def parse_file(file_path: str):\n",
31 | " \"\"\"\n",
32 | " Parse the file and return the abstract syntax tree\n",
33 | "\n",
34 | " Args:\n",
35 | " file_path: The path to the file to be parsed\n",
36 | "\n",
37 | " Returns:\n",
38 | " The abstract syntax tree of the file\n",
39 | " \"\"\"\n",
40 | " with open(file_path, 'r') as f:\n",
41 | " tree = ast.parse(f.read())\n",
42 | " return tree"
43 | ]
44 | },
45 | {
46 | "cell_type": "code",
47 | "execution_count": 4,
48 | "metadata": {},
49 | "outputs": [],
50 | "source": [
51 | "def extract_functions(tree):\n",
52 | " \"\"\" \n",
53 | " Extract all the functions from the abstract syntax tree\n",
54 | "\n",
55 | " Args:\n",
56 | " tree: The abstract syntax tree of the file\n",
57 | "\n",
58 | " Returns:\n",
59 | " A dictionary of functions with the function name as the key and the function's\n",
60 | " \"\"\"\n",
61 | " functions = {}\n",
62 | " for node in ast.walk(tree):\n",
63 | " if isinstance(node, ast.FunctionDef):\n",
64 | " functions[node.name] = {\n",
65 | " \"calls\" : [],\n",
66 | " 'line' : node.lineno\n",
67 | " }\n",
68 | " return functions"
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "execution_count": 8,
74 | "metadata": {},
75 | "outputs": [],
76 | "source": [
77 | "def analyze_function_calls(tree, functions):\n",
78 | " \"\"\" \n",
79 | " Analyze the function calls in the abstract syntax tree and update the functions dictionary\n",
80 | "\n",
81 | " Args:\n",
82 | " tree: The abstract syntax tree of the file\n",
83 | " functions: The dictionary of functions with the function name as the key and the function's\n",
84 | "\n",
85 | " Returns:\n",
86 | " None\n",
87 | " \"\"\"\n",
88 | " for node in ast.walk(tree):\n",
89 | " if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):\n",
90 | " caller = None\n",
91 | " for parent in ast.walk(tree):\n",
92 | " if isinstance(parent, ast.FunctionDef) and node in ast.walk(parent):\n",
93 | " caller = parent.name\n",
94 | " break\n",
95 | " if caller and node.func.id in functions:\n",
96 | " functions[caller]['calls'].append(node.func.id)"
97 | ]
98 | },
99 | {
100 | "cell_type": "code",
101 | "execution_count": 9,
102 | "metadata": {},
103 | "outputs": [],
104 | "source": [
105 | "def create_graph(functions):\n",
106 | " \"\"\" \n",
107 | " Create a directed graph of the functions and their calls\n",
108 | "\n",
109 | " Args:\n",
110 | " functions: The dictionary of functions with the function name as the key and the function's\n",
111 | "\n",
112 | " Returns:\n",
113 | " A directed graph of the functions and their calls\n",
114 | " \"\"\"\n",
115 | " G = nx.DiGraph()\n",
116 | " for func, data in functions.items():\n",
117 | " G.add_node(func)\n",
118 | " for call in data['calls']:\n",
119 | " G.add_edge(func, call)\n",
120 | " return G"
121 | ]
122 | },
123 | {
124 | "cell_type": "code",
125 | "execution_count": 10,
126 | "metadata": {},
127 | "outputs": [],
128 | "source": [
129 | "def visualize_graph(G):\n",
130 | " \"\"\" \n",
131 | " Visualize the directed graph of the functions and their calls\n",
132 | "\n",
133 | " Args:\n",
134 | " G: A directed graph of the functions and their calls\n",
135 | "\n",
136 | " Returns:\n",
137 | " None\n",
138 | " \"\"\"\n",
139 | " plt.figure(figsize=(15, 10)) # Increase figure size\n",
140 | " pos = nx.spring_layout(G, k=0.9, iterations=50) # Adjust layout for more spacing\n",
141 | " \n",
142 | " # Draw nodes\n",
143 | " nx.draw_networkx_nodes(G, pos, node_color='lightblue', node_size=3000, alpha=0.8)\n",
144 | " nx.draw_networkx_labels(G, pos, font_size=10, font_weight=\"bold\")\n",
145 | " \n",
146 | " # Draw edges\n",
147 | " nx.draw_networkx_edges(G, pos, edge_color='gray', arrows=True, arrowsize=20)\n",
148 | " \n",
149 | " # Add edge labels (function names)\n",
150 | " edge_labels = {(u, v): u for (u, v) in G.edges()}\n",
151 | " nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=8)\n",
152 | " \n",
153 | " plt.title(\"Function Call Graph\", fontsize=16)\n",
154 | " plt.axis('off')\n",
155 | " plt.tight_layout()\n",
156 | " plt.show()"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": 11,
162 | "metadata": {},
163 | "outputs": [
164 | {
165 | "data": {
166 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABdEAAAPdCAYAAABlRyFLAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3yV9fn/8fd9dvZghRXCJiAIEQUHikURR0XFgdY966j60zrqbq2zfnFUq7VaW2tttVj3RAUFBVH2CCNsCCFwTvY4477v3x/hpAQSZpKT8Xo+Sg3n3OO6D3k8zjnvc53rY9i2bQsAAAAAAAAAAOzBEesCAAAAAAAAAABoqQjRAQAAAAAAAABoACE6AAAAAAAAAAANIEQHAAAAAAAAAKABhOgAAAAAAAAAADSAEB0AAAAAAAAAgAYQogMAAAAAAAAA0ABCdAAAAAAAAAAAGkCIDgAAAAAAAABAAwjRAQAA2omsrCwZhrHXP88880ysy2w069evl2EYysrKinUp+8W2bU2dOlUXXnihevfurYSEBPl8PvXs2VNnnHGGXn75ZZWVlTXKuaK/C+vXr69z++WXXy7DMPS3v/3toI5bVVWlF198UT//+c/Vs2dPxcfHKy4uTj169NApp5yixx9/XGvXrj30C2gGre33BwAAAE3HFesCAAAA0LyOPfZY9evXr977Bg8e3MzVHLysrCxt2LBB69ata/VB59q1a3XuuedqwYIFkqTs7GyNHz9eXq9XW7Zs0bRp0/Txxx/r3nvv1U8//aRevXrFuOI9TZs2TZdccom2bdsmh8Oh4cOH66ijjpLH41FBQYG+++47ffHFF7rvvvv05JNP6rbbbot1yQAAAMB+IUQHAABoZ66++mpdfvnlsS6jyXXv3l25ublyu92xLmWvNm7cqKOPPlqFhYU6+uij9dJLL2nYsGF1tikrK9OLL76oRx55REVFRS0uRP/oo4901llnyTRNXXHFFfr973+vbt261dkmHA7rgw8+0KOPPqpVq1bFqFIAAADgwBGiAwAAoE1yu90aNGhQrMvYp4svvliFhYU66qij9PXXX8vn8+2xTVJSku68806dc845SkhIiEGVDfP7/br44otlmqb+3//7f5oyZUq927ndbk2aNElnnXWWFi5c2LxFAgAAAIeAmegAAADYw75mY//tb3+TYRh7dLTventFRYV+85vfqF+/fvJ6vcrIyNBll12mLVu2NHjeLVu26I477tDQoUOVlJSkhIQEDRgwQJdffrm+//77OufYsGGDJKl379515rrPmDFD0r5nWm/evFm/+tWv1L9/f/l8PqWkpOjYY4/Vn//8Z5mmuddrPphrq88333yjmTNnSpJeeumlegP0XfXr109du3at/fv27dv13HPP6bTTTlPv3r0VFxen5ORkjRw5Uk888YSqq6sPqJ6D8cc//lElJSXKyMjQ448/vs/tnU6njjjiiDq37fpvZZqmpkyZohEjRigxMVGGYdRut3z5cj344IM69thj1b17d3k8HnXo0EEnnXSS3n777XrPN2PGDBmGobFjx6qyslL33HOP+vXrJ5/Pp27duumqq67a57+bbdt6+eWXdcQRRyghIUEpKSkaP368Zs+evR+PEAAAAFo7OtEBAADQ6EpKSnTMMcdo48aNGjNmjA477DDNnj1br7/+ur755hstWrRIKSkpdfb56quvdO6556q4uFidO3fWuHHj5PF4tH79er355puSpGOOOUb9+vXTZZddpqlTp6qiokKTJk1SYmJi7XEyMjL2Wd+PP/6oCRMmKBAIKDMzU2eddZZKSko0Y8YMff/993r33Xf1wQcfyOPxNMq1NeT999+XJA0dOlQjRozYr3129fnnn+uWW25R9+7d1a9fP40ePVrbt2/XDz/8oLvvvlvvv/++pk+fLq/Xe8DH3l/Razj//PPrfbwOhG3bOuecc/TZZ59pzJgxys7O1rJly2rvnzJlil599VUNGjRIQ4cOVWpqqjZu3Kjp06frq6++0pw5cxrshA+FQho3bpwWL16ssWPHKicnR7NmzdJf//pXffLJJ/r222/Vv3//eve94oor9Oabb2rMmDE644wztHDhQk2bNk3ffvutvvnmG40aNeqQrhsAAAAtGyE6AAAAGt17772nU045RTNnzlRycrIkqaioSD/72c+0cOFC/elPf9JvfvOb2u03bdqkSZMmqaSkRHfffbd++9vf1glkCwsLa+doH3fccTruuOM0Y8YMVVRU6KmnnjqghUWDwaDOO+88BQIB/fKXv9Rzzz1XOzd97dq1GjdunD7//HP99re/1SOPPHLI17Y3P/30kyTpyCOP3O/6d3XEEUdo9uzZGj16dJ3bi4qKNHnyZH3xxRd67rnndMcddxzU8fclEolo8eLFkg7+Gna1ceNGWZalJUuWaMCAAXvcf8kll+iee+5Rnz596ty+cuVKnXTSSXr66ac1efJkHXXUUXvsO3v2bPXr10+5ubnKzMyUJFVXV+viiy/WO++8o0svvbTezvINGzZoxowZWrp0aW1Npmnq2muv1V//+lc98MAD+vzzzw/52gEAANByMc4FAACgnbniiivqjD+J/hk7dmyjnSMhIUGvvfZabcgsSWlpabr77rslSV9++WWd7adMmaKSkhL9/Oc/12OPPbZHR3Pnzp113HHHNUpt//nPf7RhwwZ169ZNzzzzTJ2FR/v06aOnnnpKUs2YkvrGoRzote3N9u3bJdVc38HIzs7eI0CP1vPHP/5RUs31NpVAICDLsiRJnTp1qnebF154QZdffvkefxry6KOP1hugS9IJJ5ywR4AuSQMHDtT9998vSZo6dWqDx37qqadqA3RJ8vl8+tOf/qT4+HjNmTOndmTQ7v74xz/WqcnpdNZ+wPLNN98oHA43eE4AAAC0fnSiAwAAtDPHHnus+vXrt8ftjbkI58iRI+vM7o7Kzs6WpD1mUH/22WeSpGuvvbbRamhIdGb65MmT6x1zcs455ygtLU1FRUWaN2+ejj322Dr3H+i1NTXTNGvH0GzdulVVVVWybVu2bUuq6dKOpenTp+udd97Z4/aG5u1PmjRpr8crLy/Xp59+qgULFmjHjh0KhUKSpK1bt0pq+HpTU1N15pln7nF7586dNWHCBP33v//VjBkzdMwxx9S53+VyacKECXvsl5GRUft74vf792uMEAAAAFonQnQAAIB25uqrr95rJ3Bj2LXbd1fR7u3dO7yji4Q2ZpDfkGjI3bt373rvNwxDvXv3VlFRUb2B+IFe29506tRJK1asUGFh4X7vs6vVq1fr7LPPrjM3fHelpaUHdez9kZ6eLsMwZNt2bVf97nbtDN+8ebN69uzZ4PE6d+6s+Pj4Bu//8MMPdcUVV8jv9ze4TUPXm5WVVWeR0l1Ffxc2b968x31du3at822FXSUnJ6uoqKhZFnAFAABA7DDOBQAAAAcsOsKjIQ5H232Z2ZjXdsQRR0iqWej0YJx77rlatmyZzjjjDH377be1ndm2bSsYDDZanQ1xuVwaNmyYpP/Ndz8UcXFxDd63ZcsWXXDBBfL7/brzzju1aNEilZSUyDRN2bZdO5c82oF/MOrbty3/LgMAAGD/8IoQAAAAe4jOJC8rK6v3/mjneGOJdnevWLGiUY9bn+7du0uqWUS0IevWrauzbVOZOHGiJGnJkiVasGDBAe27YsUKLV68WJ07d9a7776rMWPGqEOHDrVd06tXr270eusTHZHy9ttvN+ls8A8//FBVVVU6++yz9cQTT2jYsGFKTk6uDbn3db3r16/f5309evRorHIBAADQhhCiAwAAYA/R8Dg3N3eP+2zb1qefftqo54vOnP7LX/6y3/tEg/5IJHJA54ouoPrWW2/VO4bj3XffVVFRkZKSkmo7xZvK2LFja2euX3/99fvsHl+zZk3t7O9AICBJ6tatm1yuPac0vvHGG41cbf1uvvlmJScna+vWrbr33nub7DzR6+3Vq9ce99m2rTfffHOv+xcXF+vDDz/c4/bt27fXzuRvzMV1AQAA0HYQogMAAGAPJ510kiTpH//4h5YvX157ezgc1l133XXQ40cacttttykpKUkffPCB7rvvvj06mgsLCzVr1qw6t0W7hvc2D7w+5513njIzM5Wfn6/bbrutTgi/bt063X777ZKkX/3qV/L5fAdzOQfkjTfeUMeOHfXDDz/oZz/7mZYsWbLHNhUVFZoyZYqOOOIIbdu2TZI0YMAAOZ1OLVmypHax1KgPP/xQTz/9dJPXLkkdO3bU66+/LofDoT/84Q+65ppraoP+Xdm2re++++6gzxNduHXq1Kl1jm+aph544AF9//33+zzG7bffXmfueTAY1I033qiKigodddRReywiCwAAAEgsLAoAAIB6HHvssZo4caLef/99jRw5Uscdd5zi4uI0f/58lZaW6pZbbtGzzz7baOfLzMzU1KlTde655+qRRx7RK6+8oqOPPlput1sbNmzQggULdNFFF+m4446r3WfSpEmaPn26Lr74Yo0fP15paWmSpDvuuEMDBw5s8Fxer1dTp07VhAkT9OKLL+qTTz7R6NGjVVZWpq+//lrV1dU65ZRT9OCDDzba9e1NVlaWZs+erUmTJun777/XsGHDNHjwYA0aNEgej0dbtmzR3LlzFQwG1aVLF6Wnp0uqCa9vuukmPfvssxo3bpzGjBmjbt26aeXKlZo/f77uu+8+/f73v2+Wa5g4caI+/vhjXXrppXrllVf02muvafjw4crKylJcXJz8fr8WLFiggoICORwOXXzxxQd8jp///Oc64ogjNG/ePA0YMEAnnHCCEhIS9MMPPyg/P1933XWXnnjiiQb3P/roo2VZlgYOHKif/exnio+P16xZs5Sfn6/OnTvr9ddfP5SHAAAAAG0YnegAAACo11tvvaX77rtPXbt21YwZMzRnzhyNGTNG8+fP1/Dhwxv9fOPHj9fSpUt1yy23KDU1VZ999pk+/fRTFRcX65JLLtEvf/nLOttff/31euyxx9SrVy998sknevXVV/Xqq6/W2wW9uyOPPFILFy7UjTfeKKfTqXfffVczZ87UiBEj9OKLL+qjjz6qHRfTHPr166cFCxborbfe0vnnn6+Kigp9+umnevfdd7Vu3TqdfPLJ+stf/qK1a9fWzo+XpKefflqvvvqqRowYoXnz5umTTz5RfHy8/v3vf+vhhx9utvqlmpE869at0/PPP69TTjlFBQUF+vjjj/Wf//xHixYt0mGHHaaHH35Yq1ev1t///vcDPr7L5dKMGTN0zz33qHv37vrqq680Y8YMjRgxQrNnz64dCdQQj8ejr776SjfeeKOWLVum9957T6Zp6vLLL9dPP/201w9eAAAA0L4Z9qEsXw8AAAAALdiMGTN04okn6oQTTthj7A0AAACwP+hEBwAAAAAAAACgAYToAAAAAAAAAAA0gBAdAAAAAAAAAIAGMBMdAAAAAAAAAIAG0IkOAAAAAAAAAEADCNEBAAAAAAAAAGgAIToAAAAAAAAAAA0gRAcAAAAAAAAAoAGE6AAAAAAAAAAANIAQHQAAAAAAAACABhCiAwAAAAAAAADQAEJ0AAAAAAAAAAAaQIgOAAAAAAAAAEADCNEBAAAAAAAAAGgAIToAAAAAAAAAAA0gRAcAAAAAAAAAoAGE6AAAAAAAAAAANIAQHQAAAAAAAACABhCiAwAAAAAAAADQAEJ0AAAAAAAAAAAaQIgOAAAAAAAAAEADCNEBAAAAAAAAAGgAIToAAAAAAAAAAA0gRAcAAAAAAAAAoAGE6AAAAAAAAAAANIAQHQAAAAAAAACABhCiAwAAAAAAAADQAEJ0AAAAAAAAAAAaQIgOAAAAAAAAAEADCNEBAAAAAAAAAGgAIToAAAAAAAAAAA0gRAcAAAAAAAAAoAGE6AAAAAAAAAAANIAQHQAAAAAAAACABhCiAwAAAAAAAADQAEJ0AAAAAAAAAAAaQIgOAAAAAAAAAEADCNEBAAAAAAAAAGgAIToAAAAAAAAAAA0gRAcAAAAAAAAAoAGE6AAAAAAAAAAANIAQHQAAAAAAAACABhCiAwAAAAAAAADQAEJ0AAAAAAAAAAAaQIgOAAAAAAAAAEADCNEBAAAAAAAAAGgAIToAAAAAAAAAAA0gRAcAAAAAAAAAoAGE6AAAAAAAAAAANMAV6wIAAAAAAEDshE1LEcuWZdsybVu2LRmG5DQMOQxDLocht5MePABA+0WIDgAAAABAOxEyLZWFIioLRVQaDKukOqLKiClbkmzJrvlJkmTI0M7/Kd7lVKrPrSSvS0memj8egnUAQDth2LZt73szAAAAAADQ2ti2re2VIW2rCKq4OqzKiFnbbS7VzHh1OAwZ2hmaSzWp+c777Z2xumXZsnYeM9qlHg3WuyR41SneI8MwmvXaAABoLoToAAAAAAC0McGIqfzyoDaVVqo8bMq2/xeYO42doflBhN62XROqm7ZdG6wbhpTodqlncpy6JfrkddGhDgBoWwjRAQAAAABoA2zbVnEwos2lVdpaXq2wZcuQ5HY45HQ0XZe4adkKW5ZsSW6Hoa6JPvVIjlOq10V3OgCgTSBEBwAAAACglSuqDmuFv0zF1RFZti2nYcjtMJo1xLZtW2GrZnFSh2Eo1efSoA5JSvO5m60GAACaAiE6AAAAAACtlGnZWlNUoXUllYpYttzRcS0x7AC37ZogPWzZcjkM9U6NV9/UhCbthgcAoCkRogMAAAAA0AoVVYe1bHupSoKRmHSe78uunekpXpeGdEqmKx0A0CoRogMAAAAA0Irs3n3udTrkaEHh+e4s21bQtOhKBwC0WoToAAAAAAC0EmWhiBZtK2mx3ecN2b0r/fAuKUryuGJdFgAA+4UQHQAAAACAVqC4Oqz5BcWqilgtvvu8IdGu9DiXQzkZqUplvAsAoBUgRAcAAAAAoIXzV4W0oKBEQdOSz+loFd3nDbFtW9VmzQcBIzJS1CHOE+uSAADYK0esCwAAAAAAAA3zV4U0v6C4TQTokmQYhnxOh4KmpfkFxfJXhWJdEgAAe0WIDgAAAABAC1VcHdaCghKFTLtNBOhR0SA9ZNpaUFCi4upwrEsCAKBBhOgAAAAAALRAZaFIm+pA393uHelloUisSwIAoF6E6AAAAAAAtDCmZWvRthJVRdpmgB4VDdKrIpYWbSuRabFsGwCg5SFEBwAAAACghVlTVKGSYETeNhygRxmGIa/ToZJgRGuKK2JdDgAAeyBEBwAAAACgBSmqDmtdSaWchiFHGw/QoxyGIadhaF1xpYqYjw4AaGEI0QEAAAAAaCFMy9ay7aWKWLbcjvYRoEe5HYYiO6+fsS4AgJaEEB0AAAAAgBaiPY1x2R1jXQAALRUhOgAAAAAALUB7HOOyO8a6AABaIkJ0AAAAAABizLZtrfCXtcsxLruLjnVZ4S+TbTPWBQAQe4ToAAAAAADEWHEwouLqiNwOo92NcdmdYRhyOwwVV0dUHIzEuhwAAAjRAQAAAACItc2lVbJsW852HqBHOQ1Dlm1rS2lVrEsBAIAQHQAAAACAWApGTG0tr5bToAs9ytg5Gz2/vFrBiBXrcgAA7RwhOgAAAAAAMZRfHlSYWeh7cDsMhS1b+eXVsS4FANDOEaIDAAAAABAjlm1rU2mlDIku9N0YhiFD0qbSKhYYBQDEFCE6AAAAAAAxsqMypPKwKbeDt+f1cTscKg9HtKMqFOtSAADtGM/SAAAAAADEyLaKoGxbcjLKpV5OhyHblgrKg7EuBQDQjhGiAwAAAAAQI8XVYd6Y74MhqTgYjnUZAIB2jOdqAAAAAABiIGRaqoyYctCFvldOh6HKsKmwacW6FABAO0WIDgAAAABADJSFIjJtW04WFN0rp2HIsm2VhSKxLgUA0E4RogMAAAAAEANloYhsu2ZcCRpmSLJsqZQQHQAQI4ToAAAAAAA0o/Xr18swDPVOTdDiH76T0Yid6J9N/ZfG9e6kcb07NdoxYy36+JQFDz5EHzt2rAzD0OWXX95IVQEA2hNCdAAAAAAAYqQlvSmPhu+fTf1Xox/7ouNyNK53J/39mScPav+n77xZw7qkaOzYsY1bGAAA+6ElPV8DAAAAANCuNGYXelsWfZxsO8aFAADaJUJ0AAAAAAAOgG3b+tOf/qQRI0YoLi5OSUlJOuqoo7Rw4UJNmzZNY8aMUefOneXxeJScnKwxY8bo008/rfdYu0boKxcv1P3XXKKzRgzQhIHddfHxI/X2X/4kSVo457vaTvGCzRtr99mf7vEv35uqGyaO19k5AzW+f1dNPLyf7rr0PK1YOL/OsaP+cMfNGte7ky46Lqf2th9mfKn/d8GZOuOwLJ06qKduOe8MLZg9a5+PVcHmjRrXu5O2bdkkSXr92T/sMW5myY9zdNel5+nMYX00YWB3XXHSMXrrz8/LNE1JNV3sX/73LUnSt99+I8MwZBiGZsyYoaqqKp111lnq3bu3EhIS5PV61b9/fz3wwAMKhUL7rA8AgP1BiA4AAAAAwAG4+eabdeONN2rhwoVKSEhQr169tGjRIq1fv17Lli3TDz/8oKSkJB122GGybVuzZs3SmWeeqUWLFu1xLGNnjL5s3lzdct7p+v7Lz1RdWaHuWX1UUV6mJT/OOeR6Vy5eoHUrc5Wcmqas/gMVrK7WTzNn6I5LJimwfZviExOVPfyI2u27ZmYpe/gR6jdkqCRp+kfv6t4rL9LiubOVnJquDp27aOlPP+jOS87dZ5Du9niUPfwIuT0eSVLHjK7KHn5E7fkWzvlOt190tn6aOUMOh1Odu/XQxjWr9fLjv9Uz9/5aktRvyFClpHeQJCUlJWnUqFEaNWqUkpOTFQwG9f7776uqqkoDBgxQ586dlZeXp4cfflj33nvvIT92AABIhOgAAAAAAOy39evX64UXXpAknX322crPz9fSpUu1efNmjRw5UmeffbYKCwu1Zs0azZ8/Xxs3blRSUpIikYimTp3a4HH/+n+PKRwKKTE5RX/59Fu9+vlMvfNTri6/9c5DrnniJVfq3QUr9fev5+jlT2bo1c+/lSRVlpdrztfTNOCww/X8u5/Vbn/xr27T8+9+pt/9+e+SpFee+L1s29aE8y/SP2fO0z+++VHHnXK6LNPU36Y8vtdzd+icoeff/UzpnbpIkk674GI9/+5ntef7+9NPyIxE1KV7T73x7U96ffoPOueKayVJn779T+VvXK/f/fnvOmrsSZKkw4eP0Jw5czRnzhzl5OQoISFBy5YtU0FBgRYsWKBNmzbp4osvliT9+9//PuTHDgAASXLFugAAAAAAAFqLH3/8UfbOwdy33367PDs7rDt1qhlPsmrVKl1++eX6/vvv5ff7ZVlW7b75+fl7HnDnPJfoaJXjT/25evbpK0lyOBzqO/iwQ665vKREz95/l1YvXaTy0pLa+iXJv23bXvct9u+oHR/z2dtv6rO336xz/4pF8w+ptpWLF0qSRp14khKTUyRJ486cpP++9rJs29bqJYvULTOr9nHafSS6w+HQG2+8oalTp2rDhg11RrjU+3gDAHAQCNEBAAAAAGgkp59+uvLy8uRyuTR06FD5fD4tWLBAoVCodsZ3Hfu5UOaus9OtnccpLy3d535VFeW667LzVV5aIo/Xp35Dhsrlcit34byaY1n11NSArplZSt05VmVX4VCodlxLk9n5OO2+DOvjjz+uxx57TJLUq1cvZWRkaPPmzdqyZUudDzAAADgUjHMBAAAAAGA/HXnkkTKMmij3mWeeqe189vv92rBhg/Ly8iRJv/vd77Rw4UL9+9//rt1+bwYNr1nEc+ZnH2nL+rWSahYwXZO7TJKU2vF/C3FuWrdGkvTNJ+/v87ib1q5ReWmJJOmOJ5/VSx9+pRse+H2923p9cZKk6srK2ttSO3RUl+49JUn9hwzVs//5qHYcy13/94Iuv+3u/QrQvXF7HluSBg4bLkn6YfqXtXV+/eF/JUmGYaj/0MPr7F9ZWVFn/zlzambGDxgwQOvXr9d3332nww8/fJ/1AABwIAjRAQAAAADYT1lZWbrxxhslSVOnTlX37t01dOhQde/eXfPnz1ePHj0kSQ8++KCGDh2qnJwcuVwNfwnc3tlifeXtv5Hb41FZSbGuOmWMrp5wvCaNzNbfnn5CktQjq486d6s59qO3/FK3XXiW/vjg3fust2tmL/ni4yVJT911q66ecIIeuPbSerft2befJOmVJx/WDRPH65U/1ITtV91Rs0Dnt59+qPNHD9V1p5+oc48crMvHjdZX7zc8531XmX37S5Le/ftfdMPEk/XkHb+SJF32/+6S0+XSti2bdPHxI3XpiaP0zl//LEk69fxf1IxykdSzT01t8+fN09ChQzV69GhVVVVp2LBhkmrG6PTu3Vu9evWqDdYBAGgshOgAAAAAAByA5557Ti+88IKGDx+u8vJyrVu3TsOGDVPv3r31zjvv6Mgjj5TT6ZRpmvrnP/+pjh07Nnis6DSXIUccpWf/87GOHneKfPEJ2rQ2T3HxCRo6cpQkyely6f7n/6J+Q4YqFAyqrLhYv33pb/usNSklVQ+88Kp69R8oy7Lk9rj1+1f+We+2Nz34qHoPHKxIOKyVixdo89qajvdxEyfpkVf/qcNHHaNgdZU2rV2j+MREnXzO+Trtgov36zG74vbfKHvESBmGQysXL9S6lbmSpOGjj9X/vfmujjhurCzL1LYtm5TZt7+uuesB3frIU7X7jz/vIh034QylpKRo6dKl+uGHH2Sapu655x5ddtllSk1NVWlpqSZPnqwbbrhhv2oCAGB/GfauK4oAAAAAAIBmMXOjX+WhiLwuZ6xLafGqI6aSPC6NydxzJjsAAE2NhUUBAAAAAIiBVJ9bpaFIrMs4ZKuWLtJz999V7339DxumWx5+8pDPYavm8QIAIBYI0QEAAAAAiIEkb81bctu292vx0ZaqsrxcuQvn1Xufx+s95ONHv0AffbwAAGhujHMBAAAAACAG/FUh/ZBfJI/DIUcrDtGbmmXbCluWRnVLU3qcJ9blAADaIRYWBQAAAAAgBpI8LjkNQya9bXtl2rYchqEkD53oAIDYIEQHAAAAACAGPE6H4l1OWRYh+t6Ylq14t1NuJxEGACA2eAYCAAAAACBGUn1uWbEuooWzJaV6WVQUABA7hOgAAAAAAMRIlwSvDKOm27olsmxLO/w7FDEjMTm/adkyDCkj8dAXKAUA4GARogMAAAAAECOd4j1KdDsVtmLXj26apgq2FSgYrN7jvlAopFAopB3btysSaf4gPWxZSnS71JEFRQEAMUSIDgAAAABAjBiGoZ7J8bIl2TFZYNRWcXGRLMtSZWXlnvfurMmybe3YsV2hcKj5KrNt2ZJ6JsfJMIxmOy8AALsjRAcAAAAAIIa6JXrldhgKx2CkS2VllYKhmmC85r91a7BMs/Zn27bl3+Gvt2O9KYQtW26HoW6JvmY5HwAADSFEBwAAAAAghrwup7om+mTadrN2o5tmRCUlJbV/tyxLoVDdTnPLshTtAbcl2bIVCARUVbVn13pjsm1bpm2rW6JPXhfRBQAgtngmAgAAAAAgxnokx8lhGDKbLUS3VVRUpF07zw1J1dV1u8xNc89Z7bakouJilVeUN1l1pm3LYRjqnhzXZOcAAGB/EaIDAAAAABBjqV6XUn0uha3m6UYvLy9XKByuM7zFllRVVaVdg3XLMtVQNaWlpSotLdHuI2AOlW3bClu2Un0upXpdjXpsAAAOBiE6AAAAAAAxZhiGBnVIkqsZZqOHw2GVlZXVe59pWQqFw//7ez2d6Lsqr6hQcXGx7EYM0sOWLZej5vFgQVEAQEtAiA4AAAAAQAuQ5nOrd0q8TNuW1UTd6LZtq6go0OD9hqTqqqrav1uW2eC2UZVVVQoEAo3SQW/tnIXeOzVeaT73IR8PAIDGQIgOAAAAAEAL0TctQSlel4Km1SRjXcrKSmWaDY9oqTvSxZZl7b0TXaoJ3oPBoELh0D633RvbthU0LaV6XeqbmnBIxwIAoDERogMAAAAA0EI4HYaGdEpukrEuwVBQ5RUV+xy8Eh3pYlkND2kxav9rKC4+Xh07dpTX4z2k+qJjXAZ3SpbTwRgXAEDLwQodAAAAAAC0INGxLquLKmTZthyNMBfclq3ioqL92jY60iU+Pr7e+2xJTqdTiYmJiouLk2Ecen9edIxL/7QExrgAAFocOtEBAAAAAGhhGn2siy253R45HfuOAaIjXcydo1yiEb7DMJSQkCC3yyWXy6X4+IRGCdAZ4wIAaOnoRAcAAAAAoIVxOgwd3iVFP+YXqSpiyed0yDiEjnTDMJSeni6pJrQ2zYgikYhKSktlSHI4nYpEIrUz0E3Lqv3Z4/EqPiFePp9PhgxVVlaopKREpmXK6XAe0nXatq1q01Kcy6FhXVIY4wIAaJEMuylWKgEAAAAAAIesuDqsn7YWK2geepBen4JtBUpMSFBiYpIkybYtRUxTtmXJ4/HIVs3c813ZtqWCbduUlJhYu9/BiAboXpdDIzNSlcoYFwBAC8U4FwAAAAAAWqhUn1sjMlLkcRqqbqzRLjtZdk23udP1vy+pG4ZDbpdbHo9XNfH5nqG9YTgU54tTZWWltM9lSusXDdA9TodyuqQQoAMAWjRCdAAAAAAAWrAOcR7lZKTK63Q0apAeiUQkSS7ngU96jY+PU8Q0FQyFDnjfXTvQczJSlB7nOeBjAADQnAjRAQAAAABo4TrEeTSya6riXDVButUIQboZDdFdBz7X3OPxyOVy7exG33/WLjPQj8xIVQcCdABAK0CIDgAAAABAK5Dqc+vIbmlK8boUNC2FDrErPRKJyOlwyDAOJhowFB8fr+qqqtoFSPfGtm2FTEtB01KK11VzHYxwAQC0EoToAAAAAAC0Ekkel47unq7+6QkyDB1SV3rENOvMQz9Q8XFxkqSqqr13o0e7zw1D6p+eoKO7pyvJc/DnBQCgufGsBQAAAABAK+J0GBqQnqhO8V4t216qkmBETsOQ22HIMPZcCLQhkUhEbvfBd4M7HE75fD5VVlYqISFB2m0RUtu2FbZsmbatFK9LQzolK43ucwBAK0QnOgAAAAAArVCaz71HV3rE2t8RL7bMSEQu54HPQ99VfHy8wpGIwuHw/45s24pY1h7d5wToAIDWik50AAAAAABaqV270lf4y1RcHVHYsvbZmW5ZNWNgXIcwzkWSvF6vnE6nKisrlZzsru08dxiG0uPcGtQhifAcANDqEaIDAAAAANDKpfncGt0tTcXBiLaUVim/vLqmE1yS2+GQ01E3TI9EIpJ0SDPRaxiKi4tX0DRVbZpyOxzqkRSn7slxSvW6Dmi8DAAALRUhOgAAAAAAbYBhGErzuZXmc6t/eqLyy6u1qbRK5eGIQpGaieVOhyGnYSgcMSVJLueBxQK2bcuWZNq2TKvmZ7fPp9Kt+erqNDUqu7+8LibHAgDaFkJ0AAAAAADaGK/Lod6p8cpKidOOqpAKyoMqDoZVGTYVtixFJHniExU0LTkdhgxJRnRhUEPSzrHqtnaG5jsDc0lyGJLDMJTkdSnV61ZGolefzflSeXlhHT90YLNfKwAATY0QHQAAAACANsowDHWK96pTvFeSFDItlYci+vq72bKcHiWlDVBlxJQlSTu7zGXbqo3UjZpMPcnjUqrPrSSvS8kel5I8Lrmd/+s4z8nJ0dSpU7Vjxw517NixuS8TAIAmRYgOAAAAAEA74XE6lB7n0Y68XPXo0UNjMjsobFqK2LYsy5ZlS9bOhUEdhuRwGHIZRp3AvD4DBw5UXFyc5s+fr/HjxzfT1QAA0DwYVAYAAAAAQDti27YCgYDS09MlSW6nQ3EupxI8LiV5XUrZ2XGe4HEpzuXcZ4AuSS6XS8OGDdOiRYtkmmZTXwIAAM2KEB0AAAAAgHakrKxM4XBYHTp0aNTj5uTkqLKyUqtWrWrU4wIAEGuE6AAAAAAAtCOBQECSGj1E79y5s7p376758+c36nEBAIg1QnQAAAAAANoRv98vwzCUlpbW6MfOyclRXl6eSkpKGv3YAADECiE6AAAAAADtSCAQUEpKipxOZ6Mfe8iQIXK73Vq4cGGjHxsAgFghRAcAAAAAoB0JBAKNPsolyuv1asiQIVqwYIFs226ScwAA0NwI0QEAAAAAaEf8fr/S09Ob7Pg5OTkqKSnR2rVrm+wcAAA0J0J0AAAAAADaCdu2m7QTXZJ69OihTp06acGCBU12DgAAmhMhOgAAAAAA7URJSYlM02zSTnTDMDRixAitWLFClZWVTXYeAACaCyE6AAAAAADtRCAQkKQm7USXpGHDhsm2bS1evLhJzwMAQHMgRAcAAAAAoJ3w+/1yOBxKTU1t0vMkJCRo0KBBLDAKAGgTCNEBAAAAAGgn/H6/UlNT5XA0fRyQk5OjwsJCbdmypcnPBQBAUyJEBwAAAACgnWjqRUV31adPH6WkpGj+/PnNcj4AAJoKIToAAAAAAO1EIBBo0kVFd2UYhoYPH65ly5YpFAo1yzkBAGgKhOgAAAAAALQDlmWpqKio2TrRJWnEiBEKhUJatmxZs50TAIDGRogOAAAAAEA7UFxcLMuymq0TXZJSUlLUt29fRroAAFo1QnQAAAAAANoBv98vSc3aiS7VLDC6efNmbd++vVnPCwBAYyFEBwAAAACgHQgEAnI6nUpJSWnW8w4cOFDx8fF0owMAWi1CdAAAAAAA2gG/36/09HQZhtGs53U6nRo2bJgWL14s0zSb9dwAADQGQnQAAAAAANqBQCDQrPPQd5WTk6PKykqtXLkyJucHAOBQEKIDAAAAANAORDvRY6FTp07q2bMnI10AAK0SIToAAAAAAG2caZoqKSlp9kVFdzVixAitWbNGxcXFMasBAICDQYgOAAAAAEAbV1RUJNu2YxqiDxkyRB6PRwsXLoxZDQAAHAxCdAAAAAAA2ji/3y9JMRvnIkkej0eHHXaYFi5cKMuyYlYHAAAHihAdAAAAAIA2LhAIyO12KykpKaZ1jBgxQiUlJVq7dm1M6wAA4EAQogMAAAAA0MZFFxU1DCOmdXTv3l2dO3fWggULYloHAAAHghAdAAAAAIA2LhAIxHQeepRhGBoxYoRWrFihioqKWJcDAMB+IUQHAAAAAKCNi3aitwTDhg2TYRhavHhxrEsBAGC/EKIDAAAAANCGhcNhlZaWtpgQPT4+XoMGDdL8+fNl23asywEAYJ8I0QEAAAAAaMOKiookqUWMc4nKycnRjh07tHnz5liXAgDAPhGiAwAAAADQhvn9fklqMZ3oktS7d2+lpqZq/vz5sS4FAIB9IkQHAAAAAKAN8/v98nq9SkhIiHUptQzD0PDhw7Vs2TIFg8FYlwMAwF4RogMAAAAA0IYFAgGlp6fLMIxYl1LH8OHDFYlEtGzZsliXAgDAXhGiAwAAAADQhgUCgRY1Dz0qJSVFffv2ZaQLAKDFI0QHAAAAAKAN8/v9LWoe+q5ycnK0ZcsWFRYWxroUAAAaRIgOAAAAAEAbFQwGVV5e3mJD9AEDBighIYFudABAi0aIDgAAAABAGxUIBCSpRY5zkSSn06lhw4Zp8eLFikQisS4HAIB6EaIDAAAAANBGtfQQXaoZ6VJVVaUVK1bEuhQAAOpFiA4AAAAAQBvl9/sVFxenuLi4WJfSoI4dOyozM1MLFiyIdSkAANSLEB0AAAAAgDYqEAi02HnouxoxYoTWrl2roqKiWJcCAMAeCNEBAAAAAGij/H5/ix7lEjV48GB5PB4tXLgw1qUAALAHQnQAAAAAANqo1tKJ7vF4NHToUC1cuFCWZcW6HAAA6iBEBwAAAACgDaqurlZlZWWr6ESXaka6lJaWas2aNbEuBQCAOgjRAQAAAABog/x+vyS1ik50SerWrZu6dOnCAqMAgBaHEB0AAAAAgDYoEAhIUqvpRDcMQyNGjNDKlStVUVER63IAAKhFiA4AAAAAQBvk9/uVkJAgr9cb61L227Bhw2QYhhYtWhTrUgAAqEWIDgAAAABAGxQIBFpNF3pUXFycsrOzNX/+fNm2HetyAACQRIgOAAAAAECb5Pf7W8089F3l5OTI7/dr06ZNsS4FAABJhOgAAAAAALQ5tm0rEAi0yhA9KytLaWlpLDAKAGgxCNEBAAAAAGhjqqqqVF1d3erGuUg1C4wOHz5cy5YtUzAYjHU5AAAQogMAAAAA0Nb4/X5JapWd6JI0fPhwRSIRLV26NNalAABAiA4AAAAAQFvT2kP05ORk9e/fX/Pnz491KQAAEKIDAAAAANDWBAIBJSUlyePxxLqUgzZixAjl5+dr27ZtsS4FANDOEaIDAAAAANDGBAKBVjkPfVf9+/dXQkIC3egAgJgjRAcAAAAAoI3x+/2tdpRLlNPp1PDhw7V48WJFIpFYlwMAaMcI0QEAAAAAaENs224TIbpUM9Klurpaubm5sS4FANCOEaIDAAAAANCGlJeXKxwOt/pxLpLUoUMH9erVSwsWLIh1KQCAdowQHQAAAACANiQQCEhSmwjRpZpu9HXr1qmoqCjWpQAA2ilCdAAAAAAA2hC/3y9JSktLi3EljWPw4MHyer10owMAYoYQHQAAAACANiQQCCglJUUulyvWpTQKt9utoUOHauHChbIsK9blAADaIUJ0AAAAAADaEL/f32ZGuUTl5OSorKxMeXl5sS4FANAOEaIDAAAAANCGBAIBpaenx7qMRtW1a1dlZGQw0gUAEBOE6AAAAAAAtBG2bSsQCLS5TnSpZoHRlStXqry8PNalAADaGUJ0AAAAAADaiNLSUkUikTbXiS5JQ4cOldPp1KJFi2JdCgCgnSFEBwAAAACgjQgEApLUJjvR4+LilJ2drfnz58u27ViXAwBoRwjRAQAAAABoI/x+vwzDUGpqaqxLaRI5OTkKBALauHFjrEsBALQjhOgAAAAAALQRfr9faWlpcjqdsS6lSfTq1Uvp6eksMAoAaFaE6AAAAAAAtBGBQKBNzkOPMgxDw4cP17Jly1RdXR3rcgAA7QQhOgAAAAAAbURbD9Elafjw4TJNU0uWLIl1KQCAdoIQHQAAAACANsCyLAUCgTa5qOiukpKSNGDAAEa6AACaDSE6AAAAAABtQElJiSzLavOd6JI0YsQIbd26VVu3bo11KQCAdoAQHQAAAACANsDv90tSm+9El6T+/fsrMTGRbnQAQLMgRAcAAAAAoA0IBAJyOp1KSUmJdSlNzuFwaPjw4VqyZInC4XCsywEAtHGE6AAAAAAAtAF+v19paWlyONrHW/0RI0aourpaubm5sS4FANDGtY9nVgAAAAAA2rhAINAu5qFHpaenKysri5EuAIAmR4gOAAAAAEAb4Pf721WILtV0o69fv16BQCDWpQAA2jBCdAAAAAAAWjnTNFVcXNwuFhXdVXZ2tnw+H93oAIAmRYgOAAAAAEArV1xcLNu2212I7na7NXToUC1cuFCWZcW6HABAG0WIDgAAAABAK+f3+yWp3Y1zkaScnByVl5dr9erVsS4FANBGEaIDAAAAANDKBQIBuVwuJScnx7qUZpeRkaGuXbsy0gUA0GQI0QEAAAAAaOWii4oahhHrUmJixIgRWrVqlcrKymJdCgCgDSJEBwAAAACglQsEAu1uHvquhg4dKqfTqUWLFsW6FABAG0SIDgAAAABAKxftRG+vfD6fhgwZovnz58u27ViXAwBoYwjRAQAAAABoxSKRiEpKStp1iC7VjHQpKirShg0bYl0KAKCNIUQHAAAAAKAVKyoqkqR2Pc5FkjIzM5Wens4CowCARkeIDgAAAABAK+b3+yWp3XeiG4ahnJwcLV++XFVVVbEuBwDQhrhiXQAAAAAAADh4fr9fHo9HiYmJsS4l5oYPH65wOCyn0xnrUgAAbQghOgAAAAAArVggEFB6eroMw4h1KTGXkJCg448/nscCANCoCNEBAAAAADhIYdNSxLJl2bZM25ZtS4YhOQ1DDsOQy2HI7WzaSaqBQKDdz0PflcPB5FoAQOMiRAcAAAAAYD+ETEtloYjKQhGVBsMqqY6oMmLKliRbsmt+kiQZMrTzf4p3OZXqcyvJ61KSp+aPpxGDdb/fr549ezba8QAAQF2E6AAAAAAA1MO2bW2vDGlbRVDF1WFVRszabnNJckhyOAw5pJ3jQ3am5jvvt3fG6uWhiEpDEUn/61KPButdErzqFO856PEjoVBIZWVl7X5RUQAAmhIhOgAAAAAAuwhGTOWXB7WptFLlYVO2/b/A3ONwyJD2Hnobu/2ws+nctmtCddO2a4P1TWVVSnS71DM5Tt0SffK6DqxDPRAISBLjXBpg27Zs22bECwDgkBCiAwAAAADaPdu2VRyMaHNplbaWVyts2TIkuR0OOZ2Ns0ilYRgyJDkMozZYN62aQH35jjKtDpSra6JPPZLjlOp17Vd3OiH63r3++uv67rvv9P333+u+++7TxIkTFRcXJ9u2WXwUALDfCNEBAAAAAO1aUXVYK/xlKq6OyLJtOQ1DPqejWUJWp8OQ0+GUbdsKW7Y2llZpc1m1Un0uDeqQpDSfe6/7+/1++Xw+xcXFNXmtrYllWbrooouUl5enCy64QKeeeqrefvttbdq0SXfccYcsy5LT6Yx1mQCAVoIQHQAAAADQLpmWrTVFFVpXUqmIZcsdHdcSgw5lwzDkcRqybVumbStQFdbc/CL1To1X39QEOR311xQIBJSenk5X9W7WrFkjSfr444/VpUsXSVKvXr101VVX6Y477iBABwAcEIaCAQAAAADanaLqsGZvCWh1UYVsW/I5HXLFKEDflWEYcjkc8jkdsm1pdaBCs7cEVFQdrnd7v9/PKJd6hEIh5eXlqUuXLjJNU6FQSDk5ORo9erQ2b94c6/IAAK0MIToAAAAAoN0wLVur/OWam1+kkmBEXqdDnmYa3XIgajrTHfI6HSoJRjQ3v0irAuUyLbvOdtFOdNQ1ZMgQud1uff3113I6nfJ4PJKkK6+8UosWLZJUM/IFAID9QYgOAAAAAGgXykKRPbrPHS0sPN+dY+d89l270stCEUlSMBhURUUFnei7MU1TkvTAAw+osLBQ//3vf/XQQw9p/vz5yszM1PPPP6+qqio5HEQiAID9wzMGAAAAAKDNK64O68cW3n3ekN270n/ML1JxdVh+v1+S6ETfTXTe+YQJExQIBHTbbbdpwYIFuueee1RRUaGhQ4fqtddek/S/wB0AgL0hRAcAAAAAtGn+qpB+2lqsqojVKrrPGxLtSq+KWPppa7G2FJVKEp3o9bBtW4ZhaM2aNbr22mv1/vvv65RTTtGzzz6r008/Xe+//74kscAoAGC/EKIDAAAAANosf1VI8wuKFTRrAvTW0n3eEGNnkB40LeXbPqV1z5TP54t1WS2ObdfMjj/jjDP0+eefq7S0VNdcc42+/PJLvfXWW7rkkkskSeFw/Qu2AgCwK1esCwAAAAAAoCkUV4e1oKBEIdNuEwF6VDRIL5GhrjnHqLg6rFSfO9ZltSjReecnnnii8vLydNJJJ8nj8WjLli0qLi7W0UcfLUlyu3ncAAD7Ric6AAAAAKDNKQtF2lQH+u4Mw1CkulJOr0/zC4prFxvF/0S70cPhsFasWKGTTz5ZS5Ys0Ztvvqm+fftKkt58800NGTJEW7ZsiWWpAIAWzrCjzyoAAAAAALQBpmVr9paASoKRNhmgRxVsK1BCQoJcvnileF06unu6nI62ea0HIzoXPRKJyOX63xfxlyxZoieeeELvvPOOunXrpvPPP18PPPCAfD5fm/1dAQAcGjrRAQAAAABtypqiCpUEI/K24QDdsixZliWXyyWv06GSYERriitiXVaLEv23j/730Ucf1cCBAzVy5EhVVlbqiy++0Jo1a/TYY48pLi6uzf6uAAAOHTPRAQAAAABtRlF1WOtKKuU0DDnacCgaMWvGt7icLjkMQ07D0LriSnWK9yqN+eh1OJ1OffHFF/q///s/PfTQQ7r66qsVFxcnqebDiOj8dAAAGsI4FwAAAABAm9BexrhIUlVVpYqKi9U1I0OG4ZBt26o2Lca67IetW7fq1Vdf1aeffqqTTz5Z559/vgYPHizTNOV0OmNdHgCgBeLjVgAAAABAm9AexrhERSIROR0OGUbN23rDMBjrsh9mzZqlkSNH6rvvvtPkyZOVkJCga6+9VpII0AEADWKcCwAAAACg1WsvY1yiIqZZZ7FMSYx12Q/ff/+9br31Vt1xxx21t3311Vf64IMPdOaZZzLeBQBQL54ZAAAAAACtmm3bWuEvU8Sy5W4nY0wikYicrj374twOQxGr5vFgeuue5s6dq27dukmSSkpKJEkXX3yx5s2bJ0kE6ACAevHsAAAAAABo1YqDERVXR+R2GG1+jEsNW2YkIlc940cMw5DbYai4OqLiYCQGtbVMpmlKkiZNmqS33npLkpSQkCDbtjVx4kTdcsstsSwPANDCEaIDAAAAAFq1zaVVsmxbznYRoEuWZcmy7T3GuUQ5DUOWbWtLaVUzV9ZyReedX3jhhcrMzNT69evlcrlkGIZcLpc+/fRTffjhh5JqHl8AAHbFTHQAAAAAQKsVjJjaWl4tp9FeutBrRrlIajBEN3bORs8vr1b/9ER5XfTPSTVjfwzD0P33368uXbpoyZIleuONNzRv3jwZhqEzzzxTEiNdAAB7IkQHAAAAALRa+eVBhS1bPmf7CT4jkZrRJE5nw2/p3Q5D1aal/PJq9U6Nb67SWrTohyxdunRRfn6+fvvb36pz5866+uqrNXToUHXt2jXGFQIAWipCdAAAAABAq2TZtjaVVsqQ2k0XuiSZZkROp3Ov12wYhgxJm0qrlJUS164en/3x9NNPKz4+Xvfff7/S0tLk8/nq3B/tWgcAQGImOgAAAACgldpRGVJ52JS7nY3fiEQicu2lCz3K7XCoPBzRjqpQM1TVOkQXGO3Xr5+cTqe6du0qn8+ngoICvfrqq7r88stVXV1NgA4AqINOdAAAAABAq7StIijblpzO9hV4RiKmPB73PrdzOgyFIlJBeVCd4r3NUFnLF11g9IorrtA333yjBx98UNu2bVNhYaESExPVo0cPlZaW7tGZDgBo3wjRAQAAAACtUnF1uB1+vdpWxIwo3hW3X1sbkoqD4aYtqZWxLEsej0ejRo3SM888oxNPPFHnnnuujjnmGGVlZamqqkrvvfeefvzxRz3yyCOxLhcA0AIQogMAAAAAWp2QaakyYsrhaF9d6KZlybZtOV3793be6TBUGTYVNi2529Hiq3sTHdUyefJkjRgxQscdd5wcDodWrlyp5557Tj/++KMkKTExURs3blRmZmYsywUAtACE6AAAAACAVqcsFJFp2/K0s3noZiQiSfs1E12SnIahsGWpLBRRepynKUtrNaIhepcuXZSQkKD//ve/+u6777Rp0yalp6crJydHOTk5GjBggLp27RrjagEALQEhOgAAAACg1SkLRWTbNeNK2pNIJCJDktPl3K/tDUmWLZUSotfrm2++0csvv6wjjzxSv/jFLzRo0CANGDCgdnY6AAASIToAAAAAoBUqC9Z0ZEe7iluq2yZP1KIfvtfho47RlH+/f8jHi0QicjqdMvbz44Po4xN9vFDXySefrLS0NB1zzDEqLy+Xz+eTw+HQf//7X6WkpGjcuHEyTZNQHQDaufb1vTcAAAAAQJvQlIuKLpzzncb17qRxvTupYPPGJjrLwdUQMc39noceZajm8cKePB6PjjnmGL300ks67LDDdOONN+rjjz9W9+7d9fjjj0uSHO1sZBAAYE90ogMAAAAAWpVwO11UVKqZie7xeA9oH6fDUGWExUUbsm3bNn3wwQd68cUXVVZWpvvvv18LFixQcXGxVq1apQEDBsi27Rb/rQcAQNPh2RMAAAAA0KpELFu29pyHXlZSrIdvulqnZWfqwmOH64M3XtNtkydqXO9Oum3yRElSKBjU355+QpeeeJROGdBNk0Zm6w933qySgF+S9PdnntTtF55Ve8xfjDlC43p30hO/vmmfdZWVFOt3N15Ve/4P//m3erf7yxO/05Xjj9OZw/pqfP+uOn/UYXr89hvlLyzYZw2RSEQfv/k3XXvaWJ01vL/G9++qc44YpAd/ebk2rV1T7/kMSbakiG3v8xraoy5dumjlypXq0aOHzj//fB1xxBF65513dOSRR2rjxppvARCgA0D7Ric6AAAAAKBVsWxbsvcMNv/v7ls187OPJUleX5z+/NhDe+z70PWX64fpX8rhdCqr/yBt27JRn/3nX8pdOF8vfjBNHTO6KrPfAG3MWyVJ6jf4MLk9XnXL7L3PunY//0uPPljvdj9+87V2FGxV527dZUYi2rQ2T9P++7Y25q3Wn97/osEaMnpmypa0bN5cbdmwTp279VDHjK7akLdKsz7/WCsXL9Dr03+Qx+urcz5DhmTbsixC9N1F553/+te/1n/+8x+Vl5crFApp8uTJOu2003T00UfHukQAQAtg2DYfRQMAAAAAWo/SYFjfbQ7IZTjk3DnSJX/DOl0y9ihJ0vnX3Kjr7nlIG9es1tUTjpcZiejwUcfoslvv1G07O7yf/vf7GjbqGPkLC3TJCUcpWF2l2x9/WqddcLEWzvmuthP8nzPnKaNH5j5r2vX8k3/5K11z1wPatCZPV00YU3v+6MKia1csV9aAQbWztj/+9z805Te3SZL+MWOuuvXqXW8NwWC1/IGAqkqK1KvvALncbknSvFnf6M5LzpUk/eGNd5Rz7PF1ajMtWxHb1nE90pXkpZeuPn6/X+PGjdOKFSt0+umn6/TTT9eVV16piooKVVZWKhwOy+12q1OnTrEuFQAQAzx7AgAAAABaldpWsF0a0devWln78wmn14xuyezbX30GDdbqpYslSSsWLajd5v/tHO+yq9wF83TaBRcfVE27nn/MhJ9Lknr27Vfn/FFrli/Vk3f8SpvW5qm6srLOfTu2Fahbr/q73iOmKUPSjoKteu7+O7V2xXJVVVRo1944/7aCPXc0VNOJTg9dvWzbVocOHXT33XcrLS1Nxx9/vOLi4lRZWalnn31W//jHP3TSSSfp/PPPJ0QHgHaKEB0AAAAA0KrUTnGpbzD6fsoefsQet6V36nzQNe2vJT/O0RO/vkm2bSs5LV29+g1UVWVF7egWy7Ia3NeMRLRj21Y9eN1lCodCik9M1IChh8uMRJS3fGnNNpa55462JBlyMNe7XtGxQJMmTZLb7daCBQv0+eefa+nSpbJtW4FAQNnZ2Ro6dCgLjAJAO0WIDgAAAABoVZyGUTPnexdZAwfV/jzri4816PAR2rhmtdauWF57+8DDR9T+fOH1t+jY8adKqgmn5333jTL79pck+Xxxtdvt3inekF79B+xx/k1r19Q5vyTlLpxf2zn+ymffqEPnDP3rxWf1ypO/r7NdfTVEIhFtWr1S4VBIkvT439/WkJwj9fWH7+qRm6/da32GJAfZ71653W7l5eXpueeeU3x8vI466iiddNJJ8nq9CgaDSk1NjXWJAIAYIUQHAAAAALQqDsOQDMnepRW9W2aWxkw4XTM/+1j/+tOz+u7zT1S4dYvcbo/MSESSNHz0sTry+BP147fT9cB1l6pnn35yOJ3atmWTqisr9X//ek8ZPTLVtVeWXG63IuGw7rh4krp076nzrrlBJ5x2ZoM1dc/qo2PHn6bvvvikzvkdDqdMRWq36zNocO3PV50yRslpHVRa5N/jePXVcMr5v1DfwUPkcDplmaZ+c/kF6tythwLbC/f6eNmyJUNykKLv03vvvadNmzbp7bffVlxcnOLi4vToo49qxowZsS4NABBDjlgXAAAAAADAgXA5avrQd5/wffvjz+iE086U1xenyopyXXPn/bUd4h6fT5L0u5df1yU3/1rds/po66YNCmwvVK9+A3TxTbep94CabvaUtHTd9OCj6tytu4p2bFfuwnkq2kdQLUm/fuIZjZlwhjxenyrKSnX5/7tbg0fUHRszcsxYXXPXA+rQJUOh6qC6ZvbSZbffs9uR7HprqK4sV//BQ3XHE8+qa89eCofCSk5L173P/nmvdUU/anAxhqRB0TE6p512mpxOp9LT0xUXF6ctW7bINE1NmjQpxhUCAGLJsG1WFgEAAAAAtC4zN/pVHorI63LW3laYv0WpHTrI460JzPM3rNNVpxyvULBaF15/s66+8/5YlbsXtoKhkJxOp1xOp/Y+5L2eFVX3Q3XEVJLHpTGZHQ62yHblo48+0vHHH6+PPvpIH3zwgbZt26YjjjhCo0aN0nnnnSfLsuRw0JMIAO0J41wAAAAAAK1Oqs+t0lCkzm0zP/tQbzz/tAYcNkyGYWjJTz8oFKxWWsdOOuuyaxQKhxQKhWRbtmx79z+WrOjPliXbtmvD0i5dMiRJN509ocF6nn/3s4O8EkNej3e/tz0YtmoeL+yfM844Q3PnztWTTz6piRMnau7cuXr11Vc1adIkTZgwQUlJSbEuEQDQzAjRUa+waSli2bJsW6Zty7Ylw6hZwMdhGHI5DLmdfPIOAAAAIDaSvDVvZ23blrFzTEnvgYPVLTOrZvRJVZXSO3XW2NMn6tKb71DHLhny+3coGArtEUXv7evZLvf/wufchfMa+SqaXvTL59HHC/vnk08+0eWXX65bb71V33//vQzD0Mknn6zXXntNN998M93oANDO8CwKhUxLZaGIykIRlQbDKqmOqDJi1ryQtKOL9dQwVLOAjyEp3uVUqs+tJK9LSZ6aPx6CdQAAAADNIMnjkmFol6VFpZxjj1fOscc3uE9iYqKCgcBeQ/NduZxOpael1/79q3XbD7reWLElOQwp2cPb//0RDce3bNlS23F+zjnn6Mknn9Rxxx2n7dtrfgcI0AGgfWEmejtk27a2V4a0rSKo4uqwKiNmbbe5VLParGPnQj1G9OXoLqv22DtjdcuyZe08ZrRLPRqsd0nwqlO8p7YjBAAAAAAaU8i0NH3DDkmSe78DTVt+v79mpMs+tjQkdezYUW6351DKbGb2zg8V/vc+LLxzwcyf9erIt4n3QzREnzt3rm6++WbNmTNHwWBQnTp1Ulpamr755htlZWXFukwAQDPjo+h2JBgxlV8e1KbSSpWHTdn2/wJzj8NRE5rvLfQ2dvth5+sv2655oWbatspDEZWGItpUVqVEt0s9k+PULdEnr4sXawAAAAAaj8fpULzLqfJQpPa9yb4ZSk5Jqe0m3pvExMQWGqDvfXHR0tJSmRFTvjiffD6fTMtWktdFgL6foh3mRx11lLp27ao333xTF110kT766CMddthhSk9P38cRAABtEZ3obZxt2yoORrS5tEpby6sVtmwZqunUcDqarkvctGyFLUu2JLfDUNdEn3okxynV66I7HQAAAECjWFJYqo2lVYpzOQ9ov0BRQNXV1fXeZ0hyuVzq2KlTnY7uWIlEwnI4nXIY+xeCV1dXqbyiQqGds9+9iclKUUjH9OmuhISEpi22jcnLy1NycrI6d+5cexuz0AGgfSJEb8OKqsNa4S9TcXVElm3LaRhyO4xmDbFt21bYqlmc1GEYSvW5NKhDktJYGR4AAADAISqsCOqngmK5jf1rErJsS+VlZaqoqGhwnIshqVOnTnK5Yv2epWYwy+bNm9ShY0fF+eJUuL1QxcXF6tatmxITEve6t2mZqqquVihiacP3X6qicKsyMzOVnZ2t7OxsJScnN89ltDK2bWvJkiUaNmxYrEsBALQghOhtkGnZWlNUoXUllYpYttwOQ06jecPz3dl2TZAetmy5HIZ6p8arb2pCk3bDAwAAAGjbbNvWzE1+lYdM+fbSjW7LVmVFhcrKymSrZlSLbVn1hunJycn7DKib09JlS3XYkCGqrKzUpk2blJqWpsqKCvXKytpnd3p1xFSix6UjOvi0cuVK5ebmau3atbIsSz169FB2drYGDx6s1NTU5rmYVuLWW2/Vddddp+zsbJmmKafzwL7pAABoewjR25ii6rCWbS9VSTASk87zfdm1Mz3F69KQTsl0pQMAAAA4aOuKK7V8R5l8Tkc9731sVVVXq6y0VKZpKj4+XklJSXI4nLJtS9u2bZO18y2xIcnt8ahjhw5qaN54c4tEwlq1apWys7O1ZcsW+eLilJ6WptwVKzRk8JC97mvbtqpNS4M7Jql3anzt7dXV1bWBel5enkzTVNeuXWsD9Q4dOjT1ZbV406dP14cffqgpU6Y0GKLbtt2i3msDAJoWIXobsXv3udfpkKMFP6Fbtq2gadGVDgAAAOCQBCOmvtnol2XXLDYaFQqHVFpSqlA4JJ/Xq+Tk5D1GtFRUVqikpESSZMhQ586d5HS6mrX+vQmFQ9qyeYs8HrfKy8s1cOAgBYPVWrdunQYNylZ05Eu9+5qWHIZ0QmZHeV31d6wHg0GtXr1aubm5Wr16tcLhsDp37lwbqHfq1KldBsWmaWr06NH68ccf97idrnQAaJ8I0duAslBEi7aVtNju84bs3pV+eJcUJXlazgtWAAAAAK1DdIFRn9Mh0zJVVlqqqupqud1uJScny+vx1rufLVvbCwsVMU2lpqQoPr5lLbxp25ZKSkpVWlqiDh06KCEhUX7/DlVVValHj56yZde7+Gm0C71XcpwO67x/s8/D4bDy8vKUm5urVatWKRgMqkOHDrWBekZGRqt4n9lYHn74YQ0cOFDnn3++IpGIXK7/vVe1bVuFhYV65513dMMNN8SwSgBAcyFEb+WKq8OaX1CsqojV4rvPGxLtSo9zOZSTkapUxrsAAAAAOABF1WHN3uxXsKpKleVlcjidSk5KUlxcnPY1miUUDikYDCopMXGf2zafmg7zQMAvn8+3M9yvua2yskKGYSguLl4NdaJHLEumLY3unnZQ4zMjkYjWrVun5cuXa+XKlaqqqlJqamrtoqQ9evRo84H6pk2b9Ktf/UrvvfeeJCkUCumee+7Rv/71L91xxx264oordOutt+rnP/+5zjnnHFmWJYdj7zPqAQCtFyF6K+avCmlBQYmCptXA/L/WI9op4XU6NCIjRR3iPLEuCQAAAEArEIlENOeHH7Qm5FJcekd5nQ4lJiS26vdHphmRw+HU6rzV6tiho9LT02XblgzDoa1b85WYlKSkxKR6942+t0qPc2t0t7RDfhxM09SGDRu0fPlyrVixQhUVFUpKSqoN1DMzM9tsePztt9/q2GOPldPp1Mcff6zHHntMd911lz799FNlZWVpzJgxevTRR/Xhhx8SogNAG8fsjFbKXxXS/IJihUy71QfokmQYhnxOh6pNS/MLipWTkUqQDgAAAKBBtm1r6dKl+uqrr1RaWqqcY8bImZAgw2j974/KystVXFSkyooKlft8smxLLqdTbrdbO3bsUHJydETLnp3oYcuWy2FoUIekRnkcnE6n+vTpoz59+ui0007Tpk2bagP1uXPnKiEhQYMGDVJ2draysrLa1Mzw448/vvbnqqoqSdLPf/5zDR8+XBdeeKEuueQSVVVVqby8XImJibEqEwDQDOhEb4WKq8P6aWtxm+hA392uHekjuzLaBQAAAMCe1q9fr2nTpik/P1+DBg3SuHHj1LFjR63yl2t1UUWrHXUZFY6EVV5WrsLthfJ5fYpEwjJNUzIMJSYmqmtGhgxjz67n6KjM/ukJGpDetKGubdvasmWLli9frtzcXBUXFysuLk4DBw5Udna2+vTpU2eOeFtw4YUX6oILLtCpp56qI488UoWFhbr99tt1xx13xLo0AEATI0RvZcpCEf2YX6SqSNsL0KOiQXqcy6Eju6Wx2CgAAAAASdKOHTv05ZdfauXKlerWrZvGjx+vXr161d5vWrZmbwmoJBhpxe+X7J395Yaqq6vk88XV3hOJROR0OuoN0KPvo1K9Lo3uni6no/mu3bZtFRQU1Abqfr9fXq9XAwYMUHZ2tvr16ye3u/U2SNm2LcMw9Nlnn+nss8+WbdvKysrS7bffrmuuuUZ+v18dOnSIdZkAgCZEiN6KtI0XhPsn+gIwxevS0c38AhAAAABAy1JRUaEZM2Zo3rx5SklJ0bhx4zRkyJB63xMVVYc1N79Iti15nK1vRnVFRbnWrl2r+IQE+bxeud1ueb0+eb0eudxuOR31h+gh05JhSEd1O7jFRBuLbdvavn27cnNzlZubq23btsntdqt///7Kzs5W//795fV6Y1bfwYiG6Hl5ebr//vt15513asSIEbX333nnnbrssss0ZMiQ2m0BAG0LIXor0la+mri/mvOriAAAAABannA4rDlz5mjWrFlyOBwaM2aMjjrqqH2OCWnN751My1RZaamCoZCqqqoUCgYVDodl27ZM01THjp3UvXt37ToPvSW/d/L7/bWBen5+vpxOp/r166fs7GwNGDBAcXFx+z5IC7VkyRLdeuut8vv9ev311zVs2LBYlwQAaCKE6K1Ea++mOFgtpZsCAAAAQPOxLEuLFy/W119/rYqKCh111FEaM2aM4uPj92v/tvgtXtu2VF0dlOEw5PP6FA3RYznG5UAVFxfXBuqbNm2Sw+FQ7969lZ2drUGDBikhISHWJe43v9+ve+65R507d9bDDz8c63IAAE2MEL0VaIsvAPcXY10AAACA9mXt2rWaNm2aCgoKNHjwYI0bN07p6ekHfJzWup6ULVuGDG3dmi/TNBUfnyCvzyuv1yuX01W71a4BemtcT6qsrKw2UN+wYYMkqVevXsrOzlZ2draSkpJiXGHD5s6dq1/+8pcaOXKknnnmGXm9Xjmdztr7GekCAG0PIXor0Jq/itgYWvJXEwEAAAA0jsLCQk2bNk15eXnq2bOnTj75ZPXs2fOQjllcHdZPW4sVNFtXkC5JBdsKVF5WplAorHA4JNO05HQ6lJ2dLY/HWxuge10OjcxIVWor/uZuRUWFVqxYodzcXK1bt06WZalnz561gXpqamqsS6zjjjvu0CuvvKInnnhCixcvVseOHWVZlvLz8/XKK6/EujwAQBMgRG/h2usYl90x1gUAAABom8rKyjR9+nQtXLhQaWlpGjdunLKzsxst8PZXhTS/oFgh0251Qfqu/AG/ysvKlJmZKclQtWnJ43ToiIwUpcd5Yl1eo6mqqtLKlSuVm5urNWvWyDRNdevWTdnZ2Ro8ePBBfSuhsViWJYfDoby8PL3//vvKy8tTenq6OnfurDVr1qhLly667bbbWvWcdwBA/QjRWzDbtjUnv0iBqnCrfrHXGKJdFulxbo3ultauHwsAAACgLQiFQvr+++/1/fffy+Vy6YQTTtDIkSPrjMVoLP6qkBYUlLTKjvQo0zS1bv069e3Tt7YDfUSXFHVoQwH67oLBoFatWqXc3FytXr1akUhEXbp0qQ3UO3XqFOsSAQDtBCF6C1ZUHdacLUVyGpLL0X670KMiliXTlkZ3pxsdAAAAaK0sy9LChQs1ffp0VVVVadSoURozZox8Pl+Tnre4Oqz5BcWqilgteFRmzazzysoKbS0oUHJSknxxcfJ6PCouKVFRUbEy+/RVnMuhIzJSldKO3heFw2Hl5eVp+fLlWrVqlUKhkDp27Fg78iUjIyMmH47k5+frtdde0/r165WSkqITTzxRp512Wqv8oAYA0DBC9BZsSWGpNpZWtdpOicYW7UbvlRynwzonx7ocAAAAAAfAtm3l5eVp2rRp2r59u4YOHaqf/exnzTrvuiwU0aJtJSoJRuQ0DLkdRot8r1VVVakt+fmKhMMKBoMyLUudumQoJTVNHZPiNaxTkpJ9bbcDfV8ikYjWrl2r3NxcrVixQtXV1UpLS6sN1Lt3795s/6533323CgsL9eOPP+qUU05RMBjU8OHDddVVV8k0zSb5ZgUAoPkRordQwYipbzb6ZbXzWei7C5mWHIZ0QmZHeV08LgAAAEBrUFBQoGnTpmnt2rXq1auXxo8fr27dusWkFtOytaa4QuuKKxWx7BbclV7Dsm0FTUtOQ+qTlqC+qQlyOlpuvc3NNE2tX79ey5cv14oVK1RZWank5GQNGjRIgwcPVs+ePeVoom92r169Wtdff73+/Oc/66OPPlJZWZkmT56sG264QV988YVs226RH9IAAA6cK9YFoH755UGFrZqFb/A/bkfNAjr55dXqnRof63IAAAAA7EVpaam+/vprLVq0SB06dNDkyZM1YMCAmAaLToehAemJ6hTv1bLtpS2sK71mnMvWgq1KTk6W2xunqmBQlYHtyuneUQPSu8S4vpbH6XSqb9++6tu3r04//XRt3LhRy5cvV25urubOnauEhITaQD0rK6tRA/UdO3YoGAyqb9++uvTSSzVhwgRdeeWVcjqd2rFjhzp27Nho5wIAxBYhegtk2bY2lVbKkFrAi7iWxTAMGZI2lVYpKyWOxwcAAABogYLBoGbNmqU5c+bI4/HotNNOU05OTosabZHmc+vo7um1XenVpiW3w5DTiG2Ybtu2yioqlJiWLssy9dk//6rC3MX62OfV888/r/T09JjV1tI5HA5lZWUpKytLp556qjZv3qzc3FwtX75c8+bNU1xcnAYOHKjBgwerT58+h/z7ePTRRysSiWjJkiUaOnSo+vTpo+zsbP36178mQAeANoZxLi1QYUVQPxUUy204+JpePUzLVti2dGTXVHWK98a6HAAAAAA7maap+fPna8aMGQqFQjr66KN17LHHyutt2a/bi6rDWuEvU3F1RJZtx6Qz3bZthS1bpm2pYOtWDe7TS3M+mCpHqEq33HKLRowYodmzZzf5AqxtkW3b2rp1a22gHggE5PV6NXDgQGVnZ6tv375yuw9skdbovPNHHnlEGzZs0Msvv6zc3Fx98cUXuv7661VZWdms8/4BAE2LEL0Fii4oGudqOV0aLU1VxFRmcpyGssAoAAAAEHO2bWvVqlWaNm2a/H6/Dj/8cP3sZz9TcnLreb1u27aKgxFtKa1Sfnm1wpYtQ5Lb0bTNTaZlK2xZslUzvjLNZeuZ3z2gPl0769tvv9Xrr7+upKQkjR8/Xj/99FOT1dFe2LatwsJC5ebmKjc3V4WFhXK73erfv78GDx6s/v37y+PZ96Kt0XnnpaWlmj17tsaNG1fzLYKyMi1dulTvv/++LrvsMg0bNkyWZTXZXHYAQPNgnEsLVFwdFk+ve2dIKg6GY10GAAAA0O5t2bJF06ZN04YNG9SnTx+de+65ysjIiHVZB8wwDKX53ErzudU/PVH55dXaVFql8nBEoUjNexBndNyLDm70pm3bsiWZti3TqvnZMKREj0s9k+PULdEnl2HrorPP1N///nddeOGF6tWrl957773aMS4EsofGMAx16dJFXbp00dixY7Vjx47aQH3q1KlyuVzq27evsrOzNXDgwAY7/6P//snJyRo3bpzmzZunxYsXa+7cuZo5c6YKCwvl8Xg0bNgwxpACQBtAJ3oLEzItTd+wQ1JNxwPqF7YsSdLPenWUm8VXAQAAgGZXXFysr7/+WkuWLFGnTp00fvx49e3bt00FhrZta0dVSAXlQRUHw6oMm7JsW9bOd9HRYN2QVPP/O2/ceb+tnaH5zsBckhyG5DAMxbudSvW6lZHoVcc4jwzDqO1ulqT169ere/fuMgxDfr9f5eXl6tu3b51t0LiKiopqA/XNmzfL4XCoT58+Ovzww3XYYYc1uF9ubq6uv/56dezYUTk5OTrllFPUvXt3TZo0SW+99ZZ69OjRjFcBAGgKhOgtjL8qpB/yi+RxOOTghVGDLLvmK4+juqUpPW7fX7UDAAAA0Diqq6s1c+ZM/fDDD4qLi9OJJ56o4cOHt4vu6JBpqTwUUWkoorJgRMXVYVVGzJqA3I5m57ZqI3WjJlOPdzmV6nMryetSsselJI9rj2agaIf5999/r08//VQffPCBHnnkEZ1xxhmaOXOmBg8erA4dOjTvBbdjpaWltYH6xo0bdemllyozM7PB3/NPP/1UY8eOVVxcXO1tL730kkaMGKFRo0Y1V9kAgCbCOJcWpiwUkW1LxOd7Z0iybKk0FCFEBwAAAJqBaZr68ccf9e233yoSiei4447TMcccs1/zo9sKj9Oh9DhPnfcgYdNSxLZlWTUd6pZty2EYNR3nDkMuwzigb88+9dRTOv300+X1epWYmChJeuaZZ/SrX/1KY8eOpRO9mSQnJ2vUqFEaNWqUysvLVVhYuNcPik499dQ9brvgggs0d+7cpiwTANBMCNFbmLJgRNLBzddrTQo2b9QvxhwhSbrjD89pwrkXHtD+0ccn+ngBAAAAaBq2bSs3N1dffvmliouLNWLECI0dO1ZJSUmxLq1FcDsdcjfCcaLvcTZs2KCrrrpKb731ljIzMyVJ+fn56t69e53t0HwSExNrP9DYlwULFuiVV17R2WefrVGjRundd9+Vy+XSuHHjmGcPAK0YIXoLw6Ki+/bEr2/SF++8paFHHa0X/vNhrMsBAAAA2qxNmzZp2rRp2rRpk/r166fJkyerc+fOsS6rTTIMQ5FIRB07dtSKFStUXFysPn36KBgMqry8XFlZWbEuEfuwePFiXXDBBcrKytJrr72mjRs3atKkSfrLX/6icePGxbo8AMAhIERvQcKmpcqIKTMSllzOWJfT8hmGKiOmwqbF4qIAAABAIwoEAvrqq6+0fPlyZWRk6JJLLlGfPn1iXVab53K5dP/99+t3v/udtm3bpnfeeUdvvvmmxo8fL7e7Mfrd0RSiI3bWrVunzMxMffHFF1q4cKFuvPFGffXVV7rttttUXl6+393sAICWh+SxCWVlZckwDN1999266aablJ6erpSUFN1www0KBoOSaroNDMPQk08+qXMnTdJZQ3vruXt/LUkqLS7Ss/ffqcnHHK7x/btq0sjBevTW67Vty+Y651m5eKHuv+YSnTVigCYM7K6Ljx+pt//yp9r7d2wr0B/uvFnnjzpMpwzopouPH6l/PPd/MiP/G4WyfMFP+vUvztl5jB666Lgc3X/tpcrfsE6SFNi+TY/e+kudd9QQTRjYXeceOVi3X3S2fpg+bb8eiwWzZ+mqU8ZowsAeuuW807Vh9co9ttm+NV+/uWKyJh9zuE4d1FOnDuqpq04Zo3f++pKi699edFyOvnjnLUnSkh++14S+XeRxOTVjxgxVVVXprLPOUu/evZWQkCCv16v+/fvrgQceUCgU2t9/NgAAAKDdqqys1GeffaYXXnhBmzZt0llnnaVrr72WAL2Z5OXlqaSkRCeddJJycnL01FNPady4cfrDH/4Q69KwF9ERO2eccYZ27NihpUuXavjw4UpLS9NFF12k008/vc6CowCA1odO9GbwzDPPKDExUampqVq3bp1efPFF+Xw+TZkypXab+++/Xz6fTxk9MuVyexQKVuu2yRO1bmWunC6XevTuq60bN+ir96dq4ZxZevnj6Urt0FHL5s3V7RedrXAoJLfHo+5ZfRTYXqglP87R+dfcoJKigH51zgQV5m9RfGKiMvsO0Ia8lfrb04+rYPMG3fHkc7IsS/de9QuVFgWU1rGTevXrrx3bCvT9tE816crr1K1Xbz17/12a9fnHiktIUNaAQSoJ+LVozncadtTRGnXiyXu9/sD2bbrv6l+ourJSvrh4lRYV6Xc3Xb3HdiVFfs2d8ZU6de2mzH79taOgQOtXrdCfHr5fTpdbZ116lfoNGarqqkqVBPyKT0xUz74DlOx1KTk5WcFgUO+//766dOmiAQMGaMeOHcrLy9PDDz+sqqoqXngCAAAADYhEIpo7d65mzpwpy7I0duxYjR49mu7nZhKdlf3ee+/JsizdeeeduvLKK2NdFg6AZVlyOp2aMmWKbr31Vvn9fi1atEgnn3yyJk6cKKez/m+bs1AsALQOhOjNIDMzU/PmzVNSUpIuuugi/etf/9ILL7ygBx98sHabPn366LPp32h5hS3DsvX1e29r3cpcSdIDL7yq48afplVLF+nGiePl31ag915/VZf/v7v01/97TOFQSInJKXr+3c/Vs09fWZaldSuWS5Lef/1VFeZvUVrHTnrls2+V2qGjvvviUz1w3aX6fOq/ddENtyoxJVWlRQFJ0osffqVOGV0lSetXrVBKegdJ0pb1ayVJt/7+KZ101rmSJH9hgSrKyvZ5/e+//ldVV1bK4XTqhfc+V9aAQXrt/x7TG89PqbNdRo9e+ufMecroUbN4jmVZuv3Cs7R47mxN//BdnXXpVfrdn/9eOxO935Bhevyf7+q4HulK8roUDoe1bNkyDR48uPaYl1xyid544w39+9//JkQHAAAAdmPbtpYuXaqvv/5aJSUlOuKIIzR27FglJCTEurR2JRqiZmVlKT8/P8bV4GBEFwzt0KGDvv32W91yyy16++231b9//73uZxiG5s2bp/T0dPXq1YuFRwGghSJEbwZnnHFG7cr1kydP1r/+9S+FQiGtWrWqdpvLLrtMqalpUkVATpdTKxcvlCT54uJ13PjTJEkDDjtcPfr008a8VVq1pOb+FQvnS5KOP/Xn6tmnr6SaJ+++gw+ruX9Rzf1FO7Zr0sjsOnXZtq3chfN10lnnanDOkVo+/0ddOvYodc/qrawBgzTqxJM1buIkSdLoceO1bmWunvj1Tfr7M0+oZ9/+OvyoY3TGRZft8/rX7xzd0rNPP2UNGCRJOuH0iXuE6E6XU2/9+XnN+Xqa/IUFdcbN+Au3NXB0W9bOUS8Oh0NvvPGGpk6dqg0bNtQZ4cILUQAAAKCuDRs26IsvvlB+fr4GDhyoX/ziF+rYsWOsy2qXol3Mzz//vGbOnKk5c+Zo/PjxGjx4sPr06cO/Syth27YOP/zw2veitm3r9ddf17vvvquePXvq8ssvV05OjkzTrO1MtyxLHTt21N/+9jfFx8dr4MCBGjx4sHr37t1g9zoAoPkRorcQXbp0Ue03uOzGP358YqJ69Ru4x+2+nXPZnvrnO/rq/Xe0bN5cbVi9St9++qGmf/iuAoXbdMF1N+mqX9+rw444Sj99O13rVq3Qkrmz9cPX07Toh+/06F//1Sg1/ul39+mTt96QJHXP6qPk1DTlb1yvkoBflmk2sJchx84H7vHHH9djjz0mSerVq5cyMjK0efNmbdmyRZZlNUqNAAAAQGu3Y8cOffXVV1qxYoW6deumyy67TFlZWbEuq12LhqW//e1vNX/+fP3444+aMmWKtmzZoqKiIq1fv16ZmZl1wle0PLuOZVm6dKkmTZqkpKQkjRs3Tj179tR5552n3NxceTye2u0cDocyMzN13XXXaenSpcrNzdWCBQvk9Xo1cOBAZWdnq2/fvoxWAoAYI0RvBh9//LF+97vfKTExUW+//bYkyePxaMCAAbXbGIYhp2HIUM2T7sBhwyVJ1VWVmvXFJ7XjXDavzZMkDRhac/+g4TlaOHuWZn72kSb/8lfqntVHtm1r7Yrl6ps9RAOHjdAP07+U0+nSfX98uXZUSmV5uWZ9/rGOO+V02batZfN+1CnnXqjTLrhYkvT0vb/WR2/+XYvnztYF192kpT/9oMNHHaPRPxsvSfr6w3f1yM3XavHc2fu8/qz+AzXr84+1aW2eNuStUq9+A/Ttpx/usV3uwnmSpJFjxuqJ1/+jULBaN509QSUBf53tfHHxNY9NZaUMSY6dr1PmzJlT89gMGKCVK1fKNE2deeaZ2rJlyz5rBAAAANq6iooKffPNN/rpp5+UnJysc845R4cddhjzmFuQE044QSeccEKD9xOgt2yWZWnp0qUaOHCgvvrqK51zzjm1jV6SNH/+fH366aeaOHFi7Rx8qSYPyMjIUEZGhsaNG6fCwkItX75cubm5Wrx4sTwej/r376/s7Gz179+/TggPAGgehOjNYMuWLerdu7eSk5O1dm3NbPHrr79eKSkpdbZzGIZkSLZs/ezMczT11Ze0bmWufnfjVbULi1qWpQ5dMnTWpVdJkq68/Te6/aKzVVZSrKtOGaMevfsqsL1QQ444Sg+//LomXnKlPnnrDe0o2KrLxx2tzL79VVlRoe1btygSDmv8pAtkmabuuHiS4hMT1alrdzkcDm3YOYKlz6Ca+eKvPPmwVi5eqE5duykhKVkb81bXuX9vzrzkCk199SVVV1XqhjNPVudu3VWwedMe2/UZNFjrVubqp5kzdNnPRquspLjeDvKeffpJklYtWajrTztBnVKT9c2MGRo2bJg++ugjrVq1Sr1791Y4HFZVVdV+/isBAAAAbVM4HNacOXM0a9YsGYahk046SUcddZRcLt4OtjSWZcm2bdm7jKyMBq0lJSV64403dOONN8ayROyFw+HQSy+9pJtuukmrV69Wjx496tw/cOBATZs2TRMnTmzwwyvDMNSlSxd16dJFJ554onbs2FEbqE+dOlUul0v9+vVTdna2BgwYIJ/Pt9eaor9TfAADAIeGFSuawS233KKLL75YRUVFSkpK0nXXXafHH398j+1cjpo+dFuSx+vTlH+/rzMvvkLpnTpr87o1ik9M1LiJ5+qP73yq1A41M/GGHHGUnv3Pxzp63CnyxSdo09o8xcUnaOjIUZKk1A4d9fx/P9OE8y5Ucmqa1q9eqVB1lYYeOVo33P+wJMnhdOrnv7hcGT16aUfBVm1Zv05demTq/Gtu1CU3/1qSNPb0szRg6OGqLC/XupW5SkxO1ok/P1v3PvvyPq+/Q+cMPfyXf6hX/4EyzYjiEhJ1zzMv7rHdL+/9nY45+VTFJSSoqqJc519zo44eN36P7U49/yKNmXCGEpKStX7VCv04d65M09Q999yzc7Z8qkpLSzV58mTdcMMN+/vPBAAAALQptm1r0aJFev755zVjxgyNGDFCN998s4455hgC9BbK4XDI6XTK5XLJ5XLJ4XDUBupLlizR0qVLY1wh9iU7O1uvvPKKbrvtNq1cuVLr16/XrFmzdOmll+ree+9VXl6eSkpK9vsbIB07dtTxxx+v6667TjfffLPGjh2rsrIyvfvuu3rqqaf0zTff7HX/6O+UJJkNjkkFAOyLYUefkdHosrKytGHDBj344IN66KGH9mufmRv9Kg9F5HW13k+JQ6FgzQuCneNpDEM7f1bd2yRJB//V0eqIqSSPS2MyOxx60QAAAEAbsnbtWk2bNk0FBQUaPHiwxo0bp/T09FiXhYMQHfvx97//XS6XS7/4xS9iXRL2oqqqSiNGjNCjjz6q5557TvPmzVOHDh10yimnaOLEiRo5cqRSUlLk9XoP6TwlJSXKzc1Vhw4d1KdPnz06zWfNmqWpU6dq+fLluvPOO3XCCSfUmatOhzoAHBjaD1qYVJ9bpaFIrMs4IHO+/kJv/HGKpJpRNOFwuPa+4ceM0VlXXNfgvtFgPSkpSYkJiQd0Xls1jxcAAACAGoWFhfryyy9rR0lceeWV6tmzZ6zLwn6ybVuWZdUJNqN9bytXrtTZZ58dq9Kwn+Li4vSXv/xFr7zyirp166ZLL71UJ554onr37i1JWrdunTp37nzI50lJSdHo0aPrvW/Tpk264IIL9NBDD+nII4/U9OnTdeONN+q+++7TJZdcokgkUufbKLZtyzAMFq4FgL0gRG9hkrw1/yTRJ7HWoDjgr10UdHdde/Xe6762JNm2HMaBTRaKvpCMPl4AAABAe1ZeXq7p06drwYIFSk1N1Xnnnafs7OxW854C/3sP2FCIuXr1aj4QaSXGjBmjMWPG1P69qqpK9913n9566y15vV5deeWVGjVqlI499tg6C4w2BsuyNHXqVB1//PG65pprJEnTp0/XY489piFDhujLL7/U22+/re3bt+ukk07SFVdcIY/HI5fLpXfeeUeJiYk67bTTGq0eAGgrSCCb0Pr16w94nySPS4ZREy63lpe7E869UBPOvbD277Zs7di+XZFIRPuaFWSoZoX5+Pi4AzqnLclhSMkefoUBAADQfoVCIc2ePVvfffedXC6Xxo8fryOPPJJu0lbIMAy9+eabikQi+sUvfiHTNOVyuerMs2YkT+sS7eyeMmWKvv32W40dO1Yul0vDhg3TlClTdOyxxzb6B10Oh0Pz589XdnZ27W3hcFgDBgyQaZq65JJLNG/ePG3fvl1//etf9dxzz+nuu+/WvHnzdO211+qDDz5o1HoAoK1gYdEWJsnjktMwZLbiUfWGDKWlpe3Xtrak5ORkHehHBqZty2EYSiJEBwAAQDtkWZbmz5+vP/7xj5o5c6ZGjhypX/3qVxo9ejQBeitUXV2t2267TZ9//rmeeuopOZ1O5eXl6W9/+1vtNg899JA8Hk/sisQBczqdKigo0E8//aSXXnpJL7zwgubNm6eTTjpJ69ev16ZNm5rs2yKpqam1Pz/55JM677zz9MknnygUCumCCy7QBx98oMzMTH3wwQeqrq7Wm2++qfLycj388MN69tlnZVlWk9QFAK0VIXoL43E6FO9yyrJab4guSS6XW8nJKXvdxpDkdrvl8/kO+PimZSve7ZTbya8wAAAA2pe8vDz9+c9/1ocffqisrCzdeOONGj9+vOLiDuzbnYi9Xeedr1ixQtdee21t+Gnbtl5++eXabYcNGxaLEnGIMjIytGnTJqWmpsrj8SgjI0N/+MMfNGTIEG3evLlJznnvvffqpZde0qmnnqrf//73+vrrr3XOOefo7bff1rRp0zRt2jQlJCToyy+/VGZmpnw+n9LS0nTSSSfp0UcflWEY+xwxY5omQTuAdoUEsgVK9bnVFp6KEhLi5fN6G+wxtyW5nC5ZB9F1b0tK9bKoKAAAANqPgoIC/eMf/9A///lPxcXF6eqrr9akSZP2+1ugaHmiIfqKFSt0+OGHq1u3burYsaMkKT8/X926dZNUE1jarfjbyu2VaZqSpJNPPllPPfWUJOnGG2/UCy+8oEGDBunoo49u9HOuXr1aFRUVWr58uaZMmaKtW7dqyJAhGjp0qMaOHatZs2bJ5/Pptttu06effqrXXntNkvTKK6/o8ssv15FHHqmbb755n+dxOp1yOBwKBAK66qqrVFVV1ejXAgAtCbMwWqAuCV5tKquSadlyOlrLZPT6GEpNTVXh9u2SZdWZj25Icjidqg5WK7itWomJiUpISNyvr7KZli3DkDISvU1WOQAAANBSlJaWavr06Vq4cKE6dOigCy64QAMHDmTR0DYg+m8YFxcnt9utKVOm6LDDDpMkffXVV+rXr98e26L1iHZzX3311br++uuVn5+vU045RY899piOOeaYJjlndXW1Hn/8ca1evVqDBw9WJBLRddddJ5fLpSuvvFK33HKL3n//fY0aNUrjx4/X2LFjtW7dOm3evFlnnXWWQqFQvWODogvfzps3T2+99ZYqKir02GOP6e2339YPP/xQ+02YaHd6Yy6WCgAtgWHzcXaLY9u2Zm7yqzxkyudq/fMMg8Fq+QOBPW7v1LGjnE6nysrKVVlZIYfDocSkJMXHx8vYy4z06oipRI9LY3qm80ISAAAAbVYwGNR3332n2bNny+PxaOzYscrJyWHmeRsTDSdfffVVPf300+rVq5dSUlLkdrt11113afDgwbXboPVat26dUlJSmm1xWL/fr88++0zHHHOMsrKy6vz+zJo1S2+//bZGjBihK664Qv/+97/14osv6ptvvtnrMVevXq2jjz5aDz30kPLz81VdXa0PP/xQt9xyi2666aY9tuf3FkBbQojeQq0rrtTyHWXyOR1t4kmntLREFRUVslXThe71+ZSe9r8XD6YZUVlZmSqrquRyOpWUlLTzk+y6127btqpNS4M7Jql3anyzXgMAAADQHKKLhs6YMUPBYFCjR4/Wsccee1BrCaH1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ALfffnuAvwMR+aaysjIAzUSXM8owDNLS0liwYAFnn302Tqcz0CWJABBstxHmsFPj8YHt+Nt3VH7TItLpIMiuJ6m10DgXEWm16uvrWbBgAUuWLCEoKIhJkyaRnp5OUJAW1hARkfapoaGBP/3pTzgcDuLi4ujduzcXXHABK1euJDU1FYC7776bXbt28fnnn7Nt2zY+++wzrr32WgV0Iq3UwoULKSgo4Ne//nWbnP8rbVdlZSXPPvss559/vkYJSauy+kAVO6vqCXXYj79xB1Xv89MrKpTUhKhAlyKHKUQXkVavurqaOXPmUFRURHh4OFOnTiUtLe1bi6yJiIi0daZpEh0dza233sqzzz4LNIbma9euZe7cuQDs3buXxMREli9frlBEpA347LPP2LNnD3feeWegS5EO6N1336W+vp7bbrst0KWINDtQ62b5vgqCDBt2m04ufpPftPBaJundYogP01UkrYUSKBFp9SIjIznvvPO455576N27N59//jkvvvgia9euRecBRUSkPWh6P7PZbHz00UfNgTnAU089RXFxMV999RUA3bp1Y/v27QrQRdqIsrIyzUOXgElLS2P37t0cOHAg0KWINIsPCyYiyI7XNANdSqvkNU0ighx01oKirYpCdBFpM+Li4rj00ku588476dSpEzNnzuTVV19l8+bNCtNFRKTNcrlcR/192rRpVFRU8OmnnwIQFhbGPffcw6OPPtq8Ta9evc5ojSJy6hSiSyA1rZ9RWFgY6FJEmhmGQc+oMCzQsfw3WJaFBfSMCtUIsFZGIbqItDldu3blmmuu4aabbiIoKIh3332Xt956i127dgW6NBERkRN24MAB3n33XV5++WVqa2uPOoj89NNPue+++5r//qc//Yn58+cHokwR+QG8Xi9VVVVas0ACxm63M3z4cFatWoXP5wt0OSLNukc4CbIZeE2F6EfymhZBNoPuESGBLkW+QSG6iLRZvXv35uabb+bqq6+moaGBv/3tb7z33nu6VFFERFq16upqPvvsM/7yl7/gcrm45JJLCA8PP6rbaOjQofTs2ZN58+YFsFIR+aHKysoAFKJLQKWlpVFfX8+GDRsCXYpIM6fDTreIEPyWpW70wyzLwm9ZdI8IwelQZNvaOAJdgIjID2EYBklJSQwcOJA1a9aQn5/Pyy+/zLBhw8jIyCA2NjbQJYqIiADg8XhYuHAhCxcuxOFwcNZZZzF69Gjsdvsxt58zZ8533iYibUPTuCaNc5FAio+Pp2fPnhQWFjJkyJBAlyPSrEdUKKXVDfgtC4dGl+C3LGyGQWJUaKBLkWNQiC4i7YJhGKSmpjJ48GAKCwuZO3cua9asYdSoUUyZMoWIiIhAlygiIh2UaZoUFxeTn59PfX09Y8eOZfLkyYSEfP9lugrQRdq+srIynE4nYWFhgS5FOri0tDQ+/fRTKioqiImJCXQ5IgDEOB3EhDgoq/diN6wOPQPcsiy8pkVcaBAxTsW1rZF+KiLSrtjtdtLT0xk+fDhLly5lwYIFFBcXM27cOCZMmHDcwEJEROR0sSyLzZs3M3v2bA4cOEBqaipZWVkKL0Q6EJfLRadOnTp0MCStw5AhQ/jqq68oKioiMzMz0OWIAI3NcMmdIlm6pxyvaRFs77ivlV7TwmFrfD70ntE6KUQXkXYpODiYSZMmMWrUKBYsWMCiRYtYtmwZt9xyC507dz7mm5Lf71fXn4iInBb79u0jJyeHrVu30rt3b26//Xa6d+8e6LJE5AwrKyvTKBdpFYKDgxk6dCjFxcVMnToVm03zlqV1iA0Jom90GJvKazEPjzPpaMzDs9AHxoYTGxIU6HLkOyhEF5F2LTQ0lGnTpjF27FiKi4uJj48/5nZutxun0wk0huk2m01nf0VE5KRVVVWRl5fHypUr6dSpE1dddRVJSUl6TxHpoFwuF3379g10GSIAjBw5ksLCQrZs2cLAgQMDXY5Is/6x4Ryoc1Pp9hFi71jH4pZl4fabxDgd9I8JD3Q58j0UootIhxAZGcnkyZOxrG/PWfP5fERHR/PZZ58xadIkQkO1iIeIiJwct9vdfOVTcHAwP/rRjxg5cqSucBLpwNxuN7W1tepEl1aje/fuJCQkUFRUpBBdWhW7zWBIfFSHHOvSNMZlcHwUdlvH+b7bIl2/IyIdyrHOaL/yyivEx8ezdu1ahgwZwvPPP3/U7X6//0yVJyIibYzf72fZsmU899xzLFq0iPHjx3P//feTnp6uAF2kgysrKwOgU6dOAa5EpJFhGIwcOZINGzZQW1sb6HJEjtI01sVvWZiWFehyzoimMS59Y8I0xqUNUCe6iHRoDQ0N/PSnP2Xp0qUMHz6ctLQ0Xn75ZVJTU6mvr+ecc85RCCIiIt9iWRYbN25k9uzZHDp0iOHDh5OVlUVUVFSgSxORVsLlcgGoE11aldTUVHJycli5ciUTJkwIdDkiR+lIY100xqXtUSe6iHRojz76KHfccQfDhw8HGke7fPDBByxbtowPP/yQpKQk1q9ff9R9TNMMRKkiItJK7Nmzh7feeov33nuPyMhI7rzzTi666CIF6CJyFJfLRWhoqEYFSqsSFhZGSkoKRUVFWB2k21faDrvNYHiXaEIdNhr8Zrv9HbUsiwa/SajDxrAu0Rrj0kaoE11EOqyqqioee+wxqqqqmr/2y1/+kl/96lf84he/AODOO++kuLiY5OTk5m2aVrI3TVOr2ouIdCAVFRXk5eWxevVq4uPjueaaaxgwYEC77pISkVNXVlamUS7SKqWlpfH3v/+dXbt20atXr0CXI3KUyGAHI7vGsHxvBQ1+s911pDcF6E6HjZFdY4gMVjTbVij9EZEOy+1289577xEREQHAZ599xrZt2/jTn/4ENIbkhYWFzfMsly1bxoUXXsicOXMAFKCLiHQQDQ0N5OTk8MILL7Bt2zbOP/987rrrLgYOHNiuDupE5PRSiC6tVd++fYmJiaGoqCjQpYgcU0xIEGldowm2G+2qI70pQA+22xjZJZoYzUFvU5QAiUiHFR8fzxVXXNH891tuuYUHHnig+e/vv/8+e/bs4cc//jEAgwYN4sc//jGPPfYY11xzTfOcS4DVq1cza9asM1a7iIi0PL/fz5IlS3juuedYtmwZkyZN4r777mPkyJE6kSoix+VyuTQPXVolwzBIS0tj7dq1uN3uQJcjckydQoMZ2TUGp719jHY5ugM9mrjQ4ECXJCdJn/5FRA77/PPP+f3vfw+A1+vlj3/8I//v//0/AN544w0efPBBduzYwX/+8x9CQkIoLS1tvm+XLl3YvHlzQOoWEZHTy7Is1q1bx0svvcTXX39NcnIy9913HxkZGQQH64BHRI6vvr6e+vp6hejSao0YMQKfz8eaNWtO+D5ev0m910+tx0eV20tlg5cqt5daj496rx+vX2tHyenVKTSY0d1immekm200SDePmIGe3jWGTgrQ2yQN3hEROWzs2LHNf/7444/ZsWMHN910Ey+++CJvvvkmDz74IHPmzOHpp58mOjqaTZs2MXz4cHJycli/fj333Xdf8/39fj92uz0Q34aIiPwApaWlzJo1i127djFgwACuvPJKEhISAl2WiLQxTVcs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tD0K0UVE5LSIj4/niiuuYPfu3eTl5fH++++TmJhIdnY2ffv2DXR5InIEj8fDokWLWLhwITabjenTp5Oenq5xTCIip8DlcpGamhroMiSAzj33XDZv3ozD4SA1NZWQkBCKiorweDzNM71PxZEntU1f435qqqqOe7/62hp+deMV1FRVEuwMYcCQVByOoObRLaZ54jU1jXn5Jq/HQ9D3LNg5++OZvPLYHwDolNCF+G6DqSwvY+/O7UfVMHT0WBL79GX39m0UfP4Jc774FIAZl155UrUcKaZTPLYjnrvHH3+cP/3pTwD07t2brl27Ulpayu7du3/QFbQjRozAeTisb9K7d+9T3p+ItG46UhIRkdMqMTGR66+/nq1bt5Kbm8vbb79N//79ycrKonv37oEuT6RDM02TlStXkp+fT11dHWPGjGHy5MmEhoYGujQRkTbJ6/VSVVWl8VftXHp6OoZhYFkWzz77LOnp6QQHB+NyuaipqWHz5s0APPLII/z6179m+/btJCcnH3e/Y8eOJT8/nw8//JBf/epXDBgwAMuyWL16NcOGDTtqtnbptq307NuPOf/55Lj73bV1CzVVlQD84ok/k3XBJawrWs59l5zzrW2dIaG4G+ppqKtr/lpMp850SezJ/t27GDgkld899yr2wyfad23dwv7du743QAcoKVoOQFhEBO/MXUGw08mzv/sFn7375re2nX7xlbz5zOP88+U/U3bwAEHBTrIuuOSUa7EZBrYjOvebusOTkpLYsGEDfr+fCy64gN27dzdvM2DAAEJCQmhoaODjjz/m8ssv5+DBg+Tn5x+171GjRjX/Ltx000385Cc/ARoXnp0/fz7R0dHf+7yISNulmegiItIi+vXrx2233cYVV1xBZWUlr732Gv/61784dOhQoEsT6ZC2bNnCq6++yqeffkqvXr245557mDFjhgJ0EZEfoLy8HEAhejvXp08f7rnnHgBmzpxJYmIiqampJCYmUlhYSI8ePQD4wx/+QGpqKiNHjjyhq7seffRRgoODKS8vZ8iQIaSmppKQkMDvf/97AAYOHEjPXr0AePzBu/jp1Rfx/B/+57j7jY1PICQ0DID/+9VPuPXsKfz+jhuOuW3P/gMAeP2JP/LjC2fw+pOPAnDrL34LwNwvP+OKcanceW4ml6UP5qbsceR+8t1z3pv0Sx4CNM5gv27qaK6bMpqC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Tz31lNatW6ennnpKZWVlKikpkSRt2rRJ77//vj755BP97W9/06BBgy7ofgEAAAAAAAC0T5ToLWzHjh2Nb0+fPl2SdPXVV+u666771OvdddddkupL9D59+uiOO+7Q7576L2V1ztUZg+gaM3maLMtScmqabhp3uyTpo907m7ztcDisXz34D5o+fKAmXNlVd3/mKtVWV0uSTnxyTJJ0x4xZ8geSdeLYUW1c9abWLn9djuOox+V9NXj4jc3++v2BZE2afb+k+pU1lWWlOnbogCRp2bPzNf6KLhp/RRet+curkqRdWzdLkm64dYx8SUnavPZt3TNsgL597yT9z/99RP7k5Gbfd/3jdGaN3rScnByNHDlSktSvXz9de+21mj17tt5//3117ty5+fcLAAAAAAAAoN3iYNE48ZWvfEUDBgzQSy+9pO3bt2vTpk1avny5+ix6Vr9ftvqSbvuhL87W4aKP5PF61ffqgUryB7T3g+2KhMNyTh7+mZ6ZpTF33a1lixdo2eIFqq2ukiRNmHbfBd1XZnaObPvcz81c1vtyZWXnnPXxSDisvlcP1B//slorXnpBe3ds1/6dO/S3jb/X64vm6X/fWKuuPXrKsuqfTWjILEk1VVV/vyEjnfWMw3msWLFC8+fP19q1a/XBBx/oueee08KFC3X06FF9//vfv6DbAgAAAAAAAND+UKK3sFPXgLz44ou64YYbtHv3bm3btu1Tr/fee+/pmmuu0a233iqp/sDLkSNH6uM9H6qyrPS0y658dak+O2GigrU1Wv/mG5Kkvv0HnvN2K8pKdbjoI0nSA9/5oeZ84x917NABPTDus2dd9q65n9eyxQv07oq/yBgjy7I04Z57m//FS41Fd4OsnM7q2qOXjh8+qKuuuVb//OT/yOOt/213cP8+HT98UL6kJB36aJ9s29b933pQUn2xPn34ANVUVenDbe+ra4+eysrprGOHDjQeflpRWqKt69aefv/nyJSSktL4dk1NTePbxhi98847euCBB/TFL35RkvS1r31Nv/vd77Rq1SpKdAAAAAAAAACU6C2tX79+uvvuu7VkyRL967/+q1588UUdPHhQHo9H0Wi0yes9+eSTWrRokXr27Kns7Gzt3btXkpTT7TKlZWUpFPx7+bv2jdeUd+twBWtrVF5yQpI06+vfOuftZmR1Uu5l3VV89Ij+/MRjevOlF3Ti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",
167 | "text/plain": [
168 | ""
169 | ]
170 | },
171 | "metadata": {},
172 | "output_type": "display_data"
173 | }
174 | ],
175 | "source": [
176 | "def main():\n",
177 | " \"\"\" \n",
178 | " Main function to run the program\n",
179 | " \"\"\"\n",
180 | " file_path = input(\"Enter the path to the Python file: \")\n",
181 | " tree = parse_file(file_path)\n",
182 | " functions = extract_functions(tree)\n",
183 | " analyze_function_calls(tree, functions)\n",
184 | " G = create_graph(functions)\n",
185 | " visualize_graph(G)\n",
186 | "\n",
187 | "if __name__ == \"__main__\":\n",
188 | " main()"
189 | ]
190 | },
191 | {
192 | "cell_type": "markdown",
193 | "metadata": {},
194 | "source": [
195 | "## For the whole directory"
196 | ]
197 | },
198 | {
199 | "cell_type": "code",
200 | "execution_count": 10,
201 | "metadata": {},
202 | "outputs": [],
203 | "source": [
204 | "# importing modules\n",
205 | "import os\n",
206 | "import ast\n",
207 | "import time\n",
208 | "import flask\n",
209 | "import numpy as np\n",
210 | "import igraph as ig\n",
211 | "import networkx as nx\n",
212 | "from dash import Dash, html, dcc\n",
213 | "import plotly.graph_objects as go\n",
214 | "from dash.dependencies import Input, Output"
215 | ]
216 | },
217 | {
218 | "cell_type": "code",
219 | "execution_count": 11,
220 | "metadata": {},
221 | "outputs": [],
222 | "source": [
223 | "def parse_directory(directory_path: str):\n",
224 | " \"\"\" \n",
225 | " Parse the directory and return all the python files in that directory\n",
226 | "\n",
227 | " Args:\n",
228 | " directory_path: The path to the directory\n",
229 | "\n",
230 | " Returns:\n",
231 | " A list of all the python files in the directory\n",
232 | " \"\"\"\n",
233 | " python_files = []\n",
234 | " for root, dirs, files in os.walk(directory_path):\n",
235 | " for file in files:\n",
236 | " if file.endswith(\".py\"):\n",
237 | " python_files.append(os.path.join(root, file))\n",
238 | " return python_files"
239 | ]
240 | },
241 | {
242 | "cell_type": "code",
243 | "execution_count": 12,
244 | "metadata": {},
245 | "outputs": [],
246 | "source": [
247 | "def parse_file(file_path: str):\n",
248 | " \"\"\"\n",
249 | " Parse the file and return the abstract syntax tree\n",
250 | "\n",
251 | " Args:\n",
252 | " file_path: The path to the file to be parsed\n",
253 | "\n",
254 | " Returns:\n",
255 | " The abstract syntax tree of the file\n",
256 | " \"\"\"\n",
257 | " with open(file_path, 'r', encoding='utf-8') as f:\n",
258 | " tree = ast.parse(f.read())\n",
259 | " return tree"
260 | ]
261 | },
262 | {
263 | "cell_type": "code",
264 | "execution_count": 13,
265 | "metadata": {},
266 | "outputs": [],
267 | "source": [
268 | "def extract_functions(tree):\n",
269 | " \"\"\" \n",
270 | " Extract all the functions from the abstract syntax tree\n",
271 | "\n",
272 | " Args:\n",
273 | " tree: The abstract syntax tree of the file\n",
274 | "\n",
275 | " Returns:\n",
276 | " A dictionary of functions with the function name as the key and the function's\n",
277 | " \"\"\"\n",
278 | " functions = {}\n",
279 | " for node in ast.walk(tree):\n",
280 | " if isinstance(node, ast.FunctionDef):\n",
281 | " functions[node.name] = {\n",
282 | " \"calls\" : [],\n",
283 | " 'line' : node.lineno,\n",
284 | " 'file': None\n",
285 | " }\n",
286 | " return functions"
287 | ]
288 | },
289 | {
290 | "cell_type": "code",
291 | "execution_count": 14,
292 | "metadata": {},
293 | "outputs": [],
294 | "source": [
295 | "def extract_functions_and_imports(tree):\n",
296 | " \"\"\" \n",
297 | " Extract all the functions and imported modules from the abstract syntax tree\n",
298 | "\n",
299 | " Args:\n",
300 | " tree: The abstract syntax tree of the file\n",
301 | "\n",
302 | " Returns:\n",
303 | " A dictionary of functions and imports with the function name as the key and the function's data\n",
304 | " \"\"\"\n",
305 | " functions = {}\n",
306 | " imports = set()\n",
307 | " for node in ast.walk(tree):\n",
308 | " if isinstance(node, ast.FunctionDef):\n",
309 | " functions[node.name] = {\n",
310 | " \"calls\": [],\n",
311 | " 'line': node.lineno,\n",
312 | " 'file': None\n",
313 | " }\n",
314 | " elif isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):\n",
315 | " for alias in node.names:\n",
316 | " imports.add(alias.name.split('.')[0]) # Add imported module names\n",
317 | " return functions, imports"
318 | ]
319 | },
320 | {
321 | "cell_type": "code",
322 | "execution_count": 15,
323 | "metadata": {},
324 | "outputs": [],
325 | "source": [
326 | "def analyze_function_calls(tree, functions, omit_list):\n",
327 | " \"\"\" \n",
328 | " Analyze the function calls in the abstract syntax tree and update the functions dictionary\n",
329 | "\n",
330 | " Args:\n",
331 | " tree: The abstract syntax tree of the file\n",
332 | " functions: The dictionary of functions with the function name as the key and the function's\n",
333 | " omit_list: A list of functions to omit from the analysis\n",
334 | "\n",
335 | " Returns:\n",
336 | " None\n",
337 | " \"\"\"\n",
338 | " for node in ast.walk(tree):\n",
339 | " if isinstance(node, ast.Call):\n",
340 | " caller = None\n",
341 | " for parent in ast.walk(tree):\n",
342 | " if isinstance(parent, ast.FunctionDef) and node in ast.walk(parent):\n",
343 | " caller = parent.name\n",
344 | " break\n",
345 | " if caller and caller in functions and caller not in omit_list:\n",
346 | " if isinstance(node.func, ast.Name):\n",
347 | " called_func = node.func.id\n",
348 | " if called_func not in omit_list:\n",
349 | " functions[caller]['calls'].append(called_func)\n",
350 | " elif isinstance(node.func, ast.Attribute):\n",
351 | " called_func = node.func.attr\n",
352 | " if isinstance(node.func.value, ast.Name):\n",
353 | " object_name = node.func.value.id\n",
354 | " if called_func not in omit_list:\n",
355 | " # Append the method call (e.g., object.method)\n",
356 | " functions[caller]['calls'].append(f\"{object_name}.{called_func}\")\n",
357 | " else:\n",
358 | " if called_func not in omit_list:\n",
359 | " functions[caller]['calls'].append(called_func)\n",
360 | " else:\n",
361 | " if hasattr(node.func, 'id') and node.func.id not in omit_list:\n",
362 | " functions[caller]['calls'].append(node.func.id)\n",
363 | " elif hasattr(node.func, 'attr') and node.func.attr not in omit_list:\n",
364 | " functions[caller]['calls'].append(node.func.attr)"
365 | ]
366 | },
367 | {
368 | "cell_type": "code",
369 | "execution_count": 17,
370 | "metadata": {},
371 | "outputs": [],
372 | "source": [
373 | "def create_graph(functions, imports, file_paths, omit_list):\n",
374 | " \"\"\" \n",
375 | " Create a directed graph of the functions, their calls, and imports\n",
376 | "\n",
377 | " Args:\n",
378 | " functions: The dictionary of functions with the function name as the key and the function's data\n",
379 | " imports: The set of imported modules\n",
380 | " file_paths: A list of file paths\n",
381 | " omit_list: A list of functions to omit from the analysis\n",
382 | "\n",
383 | " Returns:\n",
384 | " A directed graph of the functions, their calls, and imports\n",
385 | " \"\"\"\n",
386 | " G = nx.DiGraph()\n",
387 | " \n",
388 | " for file_path in file_paths:\n",
389 | " module_name = os.path.basename(file_path).replace('.py', '')\n",
390 | " for func, data in functions.items():\n",
391 | " if data['file'] == file_path and func not in omit_list:\n",
392 | " G.add_node(func, module=module_name)\n",
393 | " for call in data['calls']:\n",
394 | " if call in functions and call not in omit_list:\n",
395 | " G.add_edge(func, call)\n",
396 | "\n",
397 | " # Add imported modules as isolated nodes\n",
398 | " for module in imports:\n",
399 | " G.add_node(module, module='import')\n",
400 | " \n",
401 | " return G"
402 | ]
403 | },
404 | {
405 | "cell_type": "code",
406 | "execution_count": 8,
407 | "metadata": {},
408 | "outputs": [],
409 | "source": [
410 | "def visualize_graph_3d(G):\n",
411 | " \"\"\"\n",
412 | " Create a 3D directed graph of the functions, their calls, and imports\n",
413 | " \n",
414 | " Args:\n",
415 | " G: A directed graph of the functions, their calls, and imports\n",
416 | " \n",
417 | " Returns:\n",
418 | " A Plotly Figure object\n",
419 | " \"\"\"\n",
420 | " # Convert NetworkX graph to igraph\n",
421 | " ig_graph = ig.Graph.from_networkx(G)\n",
422 | "\n",
423 | " # Get the layout\n",
424 | " layt = ig_graph.layout_fruchterman_reingold(dim=3)\n",
425 | "\n",
426 | " # Extract node positions\n",
427 | " node_x, node_y, node_z = zip(*layt)\n",
428 | "\n",
429 | " # Create node trace\n",
430 | " node_trace = go.Scatter3d(\n",
431 | " x=node_x, y=node_y, z=node_z,\n",
432 | " mode='markers+text',\n",
433 | " text=list(G.nodes()),\n",
434 | " textposition=\"top center\",\n",
435 | " textfont=dict(size=10, color='black'),\n",
436 | " hoverinfo='text',\n",
437 | " marker=dict(\n",
438 | " showscale=True,\n",
439 | " colorscale='YlGnBu',\n",
440 | " reversescale=True,\n",
441 | " color=[],\n",
442 | " size=10,\n",
443 | " colorbar=dict(\n",
444 | " thickness=15,\n",
445 | " title='Node Connections',\n",
446 | " xanchor='left',\n",
447 | " titleside='right'\n",
448 | " ),\n",
449 | " line_width=2))\n",
450 | "\n",
451 | " # Color node points by the number of connections\n",
452 | " node_adjacencies = []\n",
453 | " node_text = []\n",
454 | " for node, adjacencies in G.adjacency():\n",
455 | " node_adjacencies.append(len(adjacencies))\n",
456 | " node_text.append(f\"Function: {node}
# of connections: {len(adjacencies)}\")\n",
457 | "\n",
458 | " node_trace.marker.color = node_adjacencies\n",
459 | " node_trace.hovertext = node_text\n",
460 | "\n",
461 | " # Create edge traces with arrows\n",
462 | " edge_traces = []\n",
463 | " for edge in G.edges():\n",
464 | " start = layt[list(G.nodes()).index(edge[0])]\n",
465 | " end = layt[list(G.nodes()).index(edge[1])]\n",
466 | " x0, y0, z0 = start\n",
467 | " x1, y1, z1 = end\n",
468 | " \n",
469 | " # Calculate the direction vector\n",
470 | " dx, dy, dz = x1 - x0, y1 - y0, z1 - z0\n",
471 | " \n",
472 | " # Normalize the direction vector\n",
473 | " length = np.sqrt(dx**2 + dy**2 + dz**2)\n",
474 | " ux, uy, uz = dx/length, dy/length, dz/length\n",
475 | " \n",
476 | " # Calculate the midpoint\n",
477 | " mx, my, mz = (x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2\n",
478 | " \n",
479 | " # Create the line trace\n",
480 | " line_trace = go.Scatter3d(\n",
481 | " x=[x0, x1],\n",
482 | " y=[y0, y1],\n",
483 | " z=[z0, z1],\n",
484 | " mode='lines',\n",
485 | " line=dict(color='#888', width=2),\n",
486 | " hoverinfo='none'\n",
487 | " )\n",
488 | " \n",
489 | " # Create the arrow trace\n",
490 | " arrow_trace = go.Cone(\n",
491 | " x=[mx], y=[my], z=[mz],\n",
492 | " u=[ux], v=[uy], w=[uz],\n",
493 | " sizemode=\"absolute\",\n",
494 | " sizeref=0.15,\n",
495 | " showscale=False,\n",
496 | " colorscale=[[0, '#888'], [1, '#888']],\n",
497 | " anchor=\"tip\"\n",
498 | " )\n",
499 | " \n",
500 | " edge_traces.extend([line_trace, arrow_trace])\n",
501 | "\n",
502 | " # Create the figure\n",
503 | " fig = go.Figure(data=[*edge_traces, node_trace],\n",
504 | " layout=go.Layout(\n",
505 | " title='3D Function Call Graph',\n",
506 | " showlegend=False,\n",
507 | " hovermode='closest',\n",
508 | " margin=dict(b=0,l=0,r=0,t=0),\n",
509 | " scene=dict(\n",
510 | " xaxis=dict(showbackground=False, showline=False, zeroline=False, showgrid=False, showticklabels=False, title=''),\n",
511 | " yaxis=dict(showbackground=False, showline=False, zeroline=False, showgrid=False, showticklabels=False, title=''),\n",
512 | " zaxis=dict(showbackground=False, showline=False, zeroline=False, showgrid=False, showticklabels=False, title=''),\n",
513 | " ),\n",
514 | " annotations=[\n",
515 | " dict(\n",
516 | " showarrow=False,\n",
517 | " text=\"\",\n",
518 | " xref=\"paper\",\n",
519 | " yref=\"paper\",\n",
520 | " x=0,\n",
521 | " y=0.1,\n",
522 | " xanchor=\"left\",\n",
523 | " yanchor=\"bottom\",\n",
524 | " font=dict(size=14)\n",
525 | " )\n",
526 | " ]\n",
527 | " )\n",
528 | " )\n",
529 | "\n",
530 | " return fig"
531 | ]
532 | },
533 | {
534 | "cell_type": "code",
535 | "execution_count": 18,
536 | "metadata": {},
537 | "outputs": [],
538 | "source": [
539 | "def create_dash_app(G):\n",
540 | " \"\"\"\n",
541 | " Create a Dash app to serve the 3D graph visualization\n",
542 | " \n",
543 | " Args:\n",
544 | " G: A directed graph of the functions, their calls, and imports\n",
545 | " \n",
546 | " Returns:\n",
547 | " A Dash app object\n",
548 | " \"\"\"\n",
549 | " app = Dash(__name__)\n",
550 | " \n",
551 | " app.layout = html.Div([\n",
552 | " html.H1(\"3D Function Call Graph\"),\n",
553 | " dcc.Graph(id='3d-graph', figure=visualize_graph_3d(G)),\n",
554 | " ])\n",
555 | " \n",
556 | " return app"
557 | ]
558 | },
559 | {
560 | "cell_type": "code",
561 | "execution_count": 19,
562 | "metadata": {},
563 | "outputs": [
564 | {
565 | "name": "stdout",
566 | "output_type": "stream",
567 | "text": [
568 | "The input directory is: C:\\Users\\Vishal\\Github\\CodeFlowMapper\\testing-directories\n",
569 | "The functions to omit are: ['']\n",
570 | "Processing file 1/4: analyzer.py\n",
571 | "Processing file 2/4: data_processor.py\n",
572 | "Processing file 3/4: main.py\n",
573 | "Processing file 4/4: utils.py\n",
574 | "Starting the web server. Please open a web browser and go to http://127.0.0.1:8050/ to view the graph.\n"
575 | ]
576 | },
577 | {
578 | "data": {
579 | "text/html": [
580 | "\n",
581 | " \n",
589 | " "
590 | ],
591 | "text/plain": [
592 | ""
593 | ]
594 | },
595 | "metadata": {},
596 | "output_type": "display_data"
597 | }
598 | ],
599 | "source": [
600 | "def main():\n",
601 | " directory_path = input(\"Enter the path to the directory: \")\n",
602 | " print(f\"The input directory is: {directory_path}\")\n",
603 | " omit_list = input(\"Enter the functions to omit (comma-separated): \").split(',')\n",
604 | " print(f\"The functions to omit are: {omit_list}\")\n",
605 | "\n",
606 | " omit_list = [func.strip() for func in omit_list]\n",
607 | "\n",
608 | " python_files = parse_directory(directory_path)\n",
609 | "\n",
610 | " functions = {}\n",
611 | " imports = set()\n",
612 | " G = nx.DiGraph()\n",
613 | "\n",
614 | " for i, file_path in enumerate(python_files):\n",
615 | " tree = parse_file(file_path)\n",
616 | " file_functions, file_imports = extract_functions_and_imports(tree)\n",
617 | " \n",
618 | " for func_name, func_data in file_functions.items():\n",
619 | " func_data['file'] = file_path\n",
620 | " \n",
621 | " functions.update(file_functions)\n",
622 | " imports.update(file_imports)\n",
623 | " analyze_function_calls(tree, functions, omit_list)\n",
624 | "\n",
625 | " G = create_graph(functions, imports, python_files[:i+1], omit_list)\n",
626 | " \n",
627 | " print(f\"Processing file {i+1}/{len(python_files)}: {os.path.basename(file_path)}\")\n",
628 | "\n",
629 | " # Pause to simulate processing time (optional)\n",
630 | " time.sleep(0.5)\n",
631 | "\n",
632 | " # Create and run the Dash app\n",
633 | " app = create_dash_app(G)\n",
634 | " print(\"Starting the web server. Please open a web browser and go to http://127.0.0.1:8050/ to view the graph.\")\n",
635 | " app.run_server(debug=True)\n",
636 | "\n",
637 | "if __name__ == \"__main__\":\n",
638 | " main()"
639 | ]
640 | },
641 | {
642 | "cell_type": "markdown",
643 | "metadata": {},
644 | "source": [
645 | "# Visualizing the graph on the web"
646 | ]
647 | },
648 | {
649 | "cell_type": "code",
650 | "execution_count": 20,
651 | "metadata": {},
652 | "outputs": [],
653 | "source": [
654 | "import os\n",
655 | "import ast\n",
656 | "import time\n",
657 | "import flask\n",
658 | "import networkx as nx\n",
659 | "from flask import Flask, render_template_string, jsonify"
660 | ]
661 | },
662 | {
663 | "cell_type": "code",
664 | "execution_count": 21,
665 | "metadata": {},
666 | "outputs": [],
667 | "source": [
668 | "app = Flask(__name__)"
669 | ]
670 | },
671 | {
672 | "cell_type": "code",
673 | "execution_count": 22,
674 | "metadata": {},
675 | "outputs": [],
676 | "source": [
677 | "def network_to_visjs(G):\n",
678 | " nodes = [{\"id\": node, \"label\": node} for node in G.nodes()]\n",
679 | " edges = [{\"from\": source, \"to\": target} for source, target in G.edges()]\n",
680 | " return {\"nodes\": nodes, \"edges\": edges}"
681 | ]
682 | },
683 | {
684 | "cell_type": "code",
685 | "execution_count": 23,
686 | "metadata": {},
687 | "outputs": [],
688 | "source": [
689 | "def parse_directory(directory_path: str):\n",
690 | " \"\"\" \n",
691 | " Parse the directory and return all the python files in that directory\n",
692 | "\n",
693 | " Args:\n",
694 | " directory_path: The path to the directory\n",
695 | "\n",
696 | " Returns:\n",
697 | " A list of all the python files in the directory\n",
698 | " \"\"\"\n",
699 | " python_files = []\n",
700 | " for root, dirs, files in os.walk(directory_path):\n",
701 | " for file in files:\n",
702 | " if file.endswith(\".py\"):\n",
703 | " python_files.append(os.path.join(root, file))\n",
704 | " return python_files\n"
705 | ]
706 | },
707 | {
708 | "cell_type": "code",
709 | "execution_count": 24,
710 | "metadata": {},
711 | "outputs": [],
712 | "source": [
713 | "def parse_file(file_path: str):\n",
714 | " \"\"\"\n",
715 | " Parse the file and return the abstract syntax tree\n",
716 | "\n",
717 | " Args:\n",
718 | " file_path: The path to the file to be parsed\n",
719 | "\n",
720 | " Returns:\n",
721 | " The abstract syntax tree of the file\n",
722 | " \"\"\"\n",
723 | " with open(file_path, 'r', encoding='utf-8') as f:\n",
724 | " tree = ast.parse(f.read())\n",
725 | " return tree"
726 | ]
727 | },
728 | {
729 | "cell_type": "code",
730 | "execution_count": 25,
731 | "metadata": {},
732 | "outputs": [],
733 | "source": [
734 | "def extract_functions_and_imports(tree):\n",
735 | " \"\"\" \n",
736 | " Extract all the functions and imported modules from the abstract syntax tree\n",
737 | "\n",
738 | " Args:\n",
739 | " tree: The abstract syntax tree of the file\n",
740 | "\n",
741 | " Returns:\n",
742 | " A dictionary of functions and imports with the function name as the key and the function's data\n",
743 | " \"\"\"\n",
744 | " functions = {}\n",
745 | " imports = set()\n",
746 | " for node in ast.walk(tree):\n",
747 | " if isinstance(node, ast.FunctionDef):\n",
748 | " functions[node.name] = {\n",
749 | " \"calls\": [],\n",
750 | " 'line': node.lineno,\n",
751 | " 'file': None\n",
752 | " }\n",
753 | " elif isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):\n",
754 | " for alias in node.names:\n",
755 | " imports.add(alias.name.split('.')[0]) # Add imported module names\n",
756 | " return functions, imports"
757 | ]
758 | },
759 | {
760 | "cell_type": "code",
761 | "execution_count": 26,
762 | "metadata": {},
763 | "outputs": [],
764 | "source": [
765 | "def analyze_function_calls(tree, functions, omit_list):\n",
766 | " \"\"\" \n",
767 | " Analyze the function calls in the abstract syntax tree and update the functions dictionary\n",
768 | "\n",
769 | " Args:\n",
770 | " tree: The abstract syntax tree of the file\n",
771 | " functions: The dictionary of functions with the function name as the key and the function's\n",
772 | " omit_list: A list of functions to omit from the analysis\n",
773 | "\n",
774 | " Returns:\n",
775 | " None\n",
776 | " \"\"\"\n",
777 | " for node in ast.walk(tree):\n",
778 | " if isinstance(node, ast.Call):\n",
779 | " caller = None\n",
780 | " for parent in ast.walk(tree):\n",
781 | " if isinstance(parent, ast.FunctionDef) and node in ast.walk(parent):\n",
782 | " caller = parent.name\n",
783 | " break\n",
784 | " if caller and caller in functions and caller not in omit_list:\n",
785 | " if isinstance(node.func, ast.Name):\n",
786 | " called_func = node.func.id\n",
787 | " if called_func not in omit_list:\n",
788 | " functions[caller]['calls'].append(called_func)\n",
789 | " elif isinstance(node.func, ast.Attribute):\n",
790 | " called_func = node.func.attr\n",
791 | " if isinstance(node.func.value, ast.Name):\n",
792 | " object_name = node.func.value.id\n",
793 | " if called_func not in omit_list:\n",
794 | " # Append the method call (e.g., object.method)\n",
795 | " functions[caller]['calls'].append(f\"{object_name}.{called_func}\")\n",
796 | " else:\n",
797 | " if called_func not in omit_list:\n",
798 | " functions[caller]['calls'].append(called_func)\n",
799 | " else:\n",
800 | " if hasattr(node.func, 'id') and node.func.id not in omit_list:\n",
801 | " functions[caller]['calls'].append(node.func.id)\n",
802 | " elif hasattr(node.func, 'attr') and node.func.attr not in omit_list:\n",
803 | " functions[caller]['calls'].append(node.func.attr)"
804 | ]
805 | },
806 | {
807 | "cell_type": "code",
808 | "execution_count": 27,
809 | "metadata": {},
810 | "outputs": [],
811 | "source": [
812 | "def create_graph(functions, imports, file_paths, omit_list):\n",
813 | " \"\"\" \n",
814 | " Create a directed graph of the functions, their calls, and imports\n",
815 | "\n",
816 | " Args:\n",
817 | " functions: The dictionary of functions with the function name as the key and the function's data\n",
818 | " imports: The set of imported modules\n",
819 | " file_paths: A list of file paths\n",
820 | " omit_list: A list of functions to omit from the analysis\n",
821 | "\n",
822 | " Returns:\n",
823 | " A directed graph of the functions, their calls, and imports\n",
824 | " \"\"\"\n",
825 | " G = nx.DiGraph()\n",
826 | " \n",
827 | " for file_path in file_paths:\n",
828 | " module_name = os.path.basename(file_path).replace('.py', '')\n",
829 | " for func, data in functions.items():\n",
830 | " if data['file'] == file_path and func not in omit_list:\n",
831 | " G.add_node(func, module=module_name)\n",
832 | " for call in data['calls']:\n",
833 | " if call in functions and call not in omit_list:\n",
834 | " G.add_edge(func, call)\n",
835 | "\n",
836 | " # Add imported modules as isolated nodes\n",
837 | " for module in imports:\n",
838 | " G.add_node(module, module='import')\n",
839 | " \n",
840 | " return G"
841 | ]
842 | },
843 | {
844 | "cell_type": "code",
845 | "execution_count": 29,
846 | "metadata": {},
847 | "outputs": [],
848 | "source": [
849 | "@app.route('/')\n",
850 | "def index():\n",
851 | " return render_template_string('''\n",
852 | " \n",
853 | " \n",
854 | " \n",
855 | " Function Call Graph\n",
856 | " \n",
857 | " \n",
864 | " \n",
865 | " \n",
866 | " \n",
867 | " \n",
904 | " \n",
905 | " \n",
906 | " ''')"
907 | ]
908 | },
909 | {
910 | "cell_type": "code",
911 | "execution_count": 30,
912 | "metadata": {},
913 | "outputs": [],
914 | "source": [
915 | "@app.route('/graph_data')\n",
916 | "def graph_data():\n",
917 | " return jsonify(network_to_visjs(G))"
918 | ]
919 | },
920 | {
921 | "cell_type": "code",
922 | "execution_count": 32,
923 | "metadata": {},
924 | "outputs": [],
925 | "source": [
926 | "def create_graph_from_directory(directory_path, omit_list):\n",
927 | " global G\n",
928 | " python_files = parse_directory(directory_path)\n",
929 | "\n",
930 | " functions = {}\n",
931 | " imports = set()\n",
932 | "\n",
933 | " for i, file_path in enumerate(python_files):\n",
934 | " tree = parse_file(file_path)\n",
935 | " file_functions, file_imports = extract_functions_and_imports(tree)\n",
936 | " \n",
937 | " for func_name, func_data in file_functions.items():\n",
938 | " func_data['file'] = file_path\n",
939 | " \n",
940 | " functions.update(file_functions)\n",
941 | " imports.update(file_imports)\n",
942 | " analyze_function_calls(tree, functions, omit_list)\n",
943 | "\n",
944 | " G = create_graph(functions, imports, python_files[:i+1], omit_list)\n",
945 | " \n",
946 | " print(f\"Processing file {i+1}/{len(python_files)}: {os.path.basename(file_path)}\")\n",
947 | "\n",
948 | " print(\"Graph creation completed.\")"
949 | ]
950 | },
951 | {
952 | "cell_type": "code",
953 | "execution_count": 33,
954 | "metadata": {},
955 | "outputs": [],
956 | "source": [
957 | "def run_flask_app():\n",
958 | " print(\"Starting the web server.\")\n",
959 | " print(\"Please open a web browser and go to http://127.0.0.1:5000/ to view the graph.\")\n",
960 | " app.run(debug=True)"
961 | ]
962 | },
963 | {
964 | "cell_type": "code",
965 | "execution_count": 34,
966 | "metadata": {},
967 | "outputs": [
968 | {
969 | "name": "stdout",
970 | "output_type": "stream",
971 | "text": [
972 | "The input directory is: C:\\Users\\Vishal\\Github\\CodeFlowMapper\\testing-directories\n",
973 | "The functions to omit are: ['']\n",
974 | "Processing file 1/4: analyzer.py\n",
975 | "Processing file 2/4: data_processor.py\n",
976 | "Processing file 3/4: main.py\n",
977 | "Processing file 4/4: utils.py\n",
978 | "Graph creation completed.\n",
979 | "Starting the web server.\n",
980 | "Please open a web browser and go to http://127.0.0.1:5000/ to view the graph.\n",
981 | " * Serving Flask app '__main__'\n",
982 | " * Debug mode: on\n"
983 | ]
984 | },
985 | {
986 | "ename": "SystemExit",
987 | "evalue": "1",
988 | "output_type": "error",
989 | "traceback": [
990 | "An exception has occurred, use %tb to see the full traceback.\n",
991 | "\u001b[1;31mSystemExit\u001b[0m\u001b[1;31m:\u001b[0m 1\n"
992 | ]
993 | }
994 | ],
995 | "source": [
996 | "if __name__ == \"__main__\":\n",
997 | " directory_path = input(\"Enter the path to the directory: \")\n",
998 | " print(f\"The input directory is: {directory_path}\")\n",
999 | " omit_list = input(\"Enter the functions to omit (comma-separated): \").split(',')\n",
1000 | " print(f\"The functions to omit are: {omit_list}\")\n",
1001 | "\n",
1002 | " omit_list = [func.strip() for func in omit_list]\n",
1003 | "\n",
1004 | " create_graph_from_directory(directory_path, omit_list)\n",
1005 | " run_flask_app()"
1006 | ]
1007 | },
1008 | {
1009 | "cell_type": "code",
1010 | "execution_count": null,
1011 | "metadata": {},
1012 | "outputs": [],
1013 | "source": []
1014 | }
1015 | ],
1016 | "metadata": {
1017 | "kernelspec": {
1018 | "display_name": "venv",
1019 | "language": "python",
1020 | "name": "python3"
1021 | },
1022 | "language_info": {
1023 | "codemirror_mode": {
1024 | "name": "ipython",
1025 | "version": 3
1026 | },
1027 | "file_extension": ".py",
1028 | "mimetype": "text/x-python",
1029 | "name": "python",
1030 | "nbconvert_exporter": "python",
1031 | "pygments_lexer": "ipython3",
1032 | "version": "3.11.9"
1033 | }
1034 | },
1035 | "nbformat": 4,
1036 | "nbformat_minor": 2
1037 | }
1038 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | asttokens==2.4.1
2 | attrs==24.2.0
3 | blinker==1.8.2
4 | certifi==2024.8.30
5 | charset-normalizer==3.3.2
6 | click==8.1.7
7 | colorama==0.4.6
8 | comm==0.2.2
9 | contourpy==1.2.1
10 | cycler==0.12.1
11 | dash==2.17.1
12 | dash-core-components==2.0.0
13 | dash-html-components==2.0.0
14 | dash-table==5.0.0
15 | debugpy==1.8.5
16 | decorator==5.1.1
17 | executing==2.0.1
18 | fastjsonschema==2.20.0
19 | filelock==3.15.4
20 | Flask==3.0.3
21 | fonttools==4.53.1
22 | fsspec==2024.6.1
23 | huggingface-hub==0.24.6
24 | idna==3.8
25 | igraph==0.11.6
26 | importlib_metadata==8.4.0
27 | ipykernel==6.29.5
28 | ipython==8.26.0
29 | itsdangerous==2.2.0
30 | jedi==0.19.1
31 | Jinja2==3.1.4
32 | jsonschema==4.23.0
33 | jsonschema-specifications==2023.12.1
34 | jupyter_client==8.6.2
35 | jupyter_core==5.7.2
36 | kiwisolver==1.4.5
37 | MarkupSafe==2.1.5
38 | matplotlib==3.9.2
39 | matplotlib-inline==0.1.7
40 | mpmath==1.3.0
41 | nbformat==5.10.4
42 | nest-asyncio==1.6.0
43 | networkx==3.3
44 | numpy==1.26.4
45 | packaging==24.1
46 | pandas==2.2.2
47 | parso==0.8.4
48 | pillow==10.4.0
49 | platformdirs==4.2.2
50 | plotly==5.23.0
51 | prompt_toolkit==3.0.47
52 | psutil==6.0.0
53 | pure_eval==0.2.3
54 | Pygments==2.18.0
55 | pyparsing==3.1.2
56 | python-dateutil==2.9.0.post0
57 | pytz==2024.1
58 | pywin32==306
59 | PyYAML==6.0.2
60 | pyzmq==26.1.0
61 | referencing==0.35.1
62 | regex==2024.7.24
63 | requests==2.32.3
64 | retrying==1.3.4
65 | rpds-py==0.20.0
66 | safetensors==0.4.4
67 | scipy==1.14.0
68 | six==1.16.0
69 | stack-data==0.6.3
70 | sympy==1.13.2
71 | tenacity==9.0.0
72 | texttable==1.7.0
73 | tokenizers==0.19.1
74 | torch==2.4.0
75 | torchaudio==2.4.0
76 | torchvision==0.19.0
77 | tornado==6.4.1
78 | tqdm==4.66.5
79 | traitlets==5.14.3
80 | transformers==4.44.2
81 | typing_extensions==4.12.2
82 | tzdata==2024.1
83 | urllib3==2.2.2
84 | wcwidth==0.2.13
85 | Werkzeug==3.0.4
86 | zipp==3.20.1
87 |
--------------------------------------------------------------------------------
/testing-directories/analyzer.py:
--------------------------------------------------------------------------------
1 | from .utils import log_message
2 | from .data_processor import preprocess_data
3 |
4 |
5 | def analyze_results(data):
6 | log_message("Analyzing results")
7 | preprocessed = preprocess_data(data)
8 | total = sum(preprocessed)
9 | average = total / len(preprocessed)
10 | return {"total": total, "average": average}
11 |
12 |
13 | def generate_report(results):
14 | log_message("Generating report")
15 | return f"Report: Total = {results['total']}, Average = {results['average']}"
16 |
--------------------------------------------------------------------------------
/testing-directories/data_processor.py:
--------------------------------------------------------------------------------
1 | from .utils import log_message, validate_data
2 |
3 | def process_data(data):
4 | log_message("Processing data")
5 | validate_data(data)
6 | return [x * 2 for x in data]
7 |
8 | def preprocess_data(data):
9 | log_message("Preprocessing data")
10 | return [x + 1 for x in data]
--------------------------------------------------------------------------------
/testing-directories/main.py:
--------------------------------------------------------------------------------
1 | from .data_processor import process_data
2 | from .analyzer import analyze_results
3 | from .utils import log_message
4 | from .analyzer import generate_report
5 |
6 |
7 | def main():
8 | log_message("Starting main process")
9 | data = [1, 2, 3, 4, 5]
10 | processed_data = process_data(data)
11 | results = analyze_results(processed_data)
12 | log_message(f"Analysis results: {results}")
13 | report = generate_report(results)
14 | log_message(f"Report: {report}")
15 |
16 |
17 | if __name__ == "__main__":
18 | main()
19 |
--------------------------------------------------------------------------------
/testing-directories/utils.py:
--------------------------------------------------------------------------------
1 | def log_message(message):
2 | print(f"[LOG] {message}")
3 |
4 |
5 | def validate_data(data):
6 | if not isinstance(data, list):
7 | raise ValueError("Data must be a list")
8 | if not all(isinstance(x, (int, float)) for x in data):
9 | raise ValueError("All elements must be numbers")
10 |
--------------------------------------------------------------------------------
/testing-files/basic_python.py:
--------------------------------------------------------------------------------
1 | def main():
2 | print("Starting the program...")
3 | data = get_data()
4 | processed_data = process_data(data)
5 | result = analyze_results(processed_data)
6 | display_results(result)
7 | print("Program completed.")
8 |
9 |
10 | def get_data():
11 | print("Fetching data...")
12 | data = [1, 2, 3, 4, 5]
13 | validate_data(data)
14 | return data
15 |
16 |
17 | def validate_data(data):
18 | print("Validating data...")
19 | if not data:
20 | raise ValueError("Data is empty")
21 | return True
22 |
23 |
24 | def process_data(data):
25 | print("Processing data...")
26 | return [x * 2 for x in data]
27 |
28 |
29 | def analyze_results(data):
30 | print("Analyzing results...")
31 | total = calculate_total(data)
32 | average = calculate_average(data)
33 | return {"total": total, "average": average}
34 |
35 |
36 | def calculate_total(data):
37 | return sum(data)
38 |
39 |
40 | def calculate_average(data):
41 | total = calculate_total(data)
42 | return total / len(data)
43 |
44 |
45 | def display_results(results):
46 | print("Displaying results...")
47 | print(f"Total: {results['total']}")
48 | print(f"Average: {results['average']}")
49 |
50 |
51 | if __name__ == "__main__":
52 | main()
53 |
--------------------------------------------------------------------------------