Spaces:
Running on Zero
Running on Zero
atakan commited on
Commit ·
2d71e4f
1
Parent(s): 30f040e
chore: Streamline repository to focused 2-step local launcher and clean up disk
Browse files- ControlAI_Colab_Demo.ipynb +0 -103
- Modelfile +0 -19
- README.md +27 -57
- scripts/fuse_model.py +0 -60
ControlAI_Colab_Demo.ipynb
DELETED
|
@@ -1,103 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"cells": [
|
| 3 |
-
{
|
| 4 |
-
"cell_type": "markdown",
|
| 5 |
-
"metadata": {},
|
| 6 |
-
"source": [
|
| 7 |
-
"# ControlAI: Open-Source AI Agent for Control Systems Engineering\n",
|
| 8 |
-
"\n",
|
| 9 |
-
"[](https://github.com/atakankahya/controlai-agent)\n",
|
| 10 |
-
"[](https://huggingface.co/atakankahya/ControlAI-Agent)\n",
|
| 11 |
-
"[](https://opensource.org/licenses/MIT)\n",
|
| 12 |
-
"\n",
|
| 13 |
-
"Welcome to the official **ControlAI** interactive notebook! You can test control engineering problems, LQR synthesis, Bode plots, and ODE simulations directly in Google Colab.\n",
|
| 14 |
-
"\n",
|
| 15 |
-
"---"
|
| 16 |
-
]
|
| 17 |
-
},
|
| 18 |
-
{
|
| 19 |
-
"cell_type": "markdown",
|
| 20 |
-
"metadata": {},
|
| 21 |
-
"source": [
|
| 22 |
-
"### Step 1: Install Dependencies"
|
| 23 |
-
]
|
| 24 |
-
},
|
| 25 |
-
{
|
| 26 |
-
"cell_type": "code",
|
| 27 |
-
"execution_count": null,
|
| 28 |
-
"metadata": {},
|
| 29 |
-
"outputs": [],
|
| 30 |
-
"source": [
|
| 31 |
-
"# Clone repo & install all required dependencies\n",
|
| 32 |
-
"!git clone https://github.com/atakankahya/controlai-agent.git\n",
|
| 33 |
-
"%cd controlai-agent\n",
|
| 34 |
-
"!pip install -q -r requirements.txt pypdf\n",
|
| 35 |
-
"print(\"Dependencies installed successfully!\")"
|
| 36 |
-
]
|
| 37 |
-
},
|
| 38 |
-
{
|
| 39 |
-
"cell_type": "markdown",
|
| 40 |
-
"metadata": {},
|
| 41 |
-
"source": [
|
| 42 |
-
"### Step 2: Initialize the ControlAI Agent"
|
| 43 |
-
]
|
| 44 |
-
},
|
| 45 |
-
{
|
| 46 |
-
"cell_type": "code",
|
| 47 |
-
"execution_count": null,
|
| 48 |
-
"metadata": {},
|
| 49 |
-
"outputs": [],
|
| 50 |
-
"source": [
|
| 51 |
-
"import sys\n",
|
| 52 |
-
"from pathlib import Path\n",
|
| 53 |
-
"from IPython.display import display, Markdown, Image\n",
|
| 54 |
-
"import matplotlib.pyplot as plt\n",
|
| 55 |
-
"\n",
|
| 56 |
-
"from controlai_agent.orchestrator import ControlAIAgent\n",
|
| 57 |
-
"\n",
|
| 58 |
-
"print(\"Loading ControlAI Engine with Qwen 3B...\")\n",
|
| 59 |
-
"agent = ControlAIAgent(model_path=\"Qwen/Qwen2.5-3B-Instruct\")\n",
|
| 60 |
-
"print(\"ControlAI Engine ready!\")"
|
| 61 |
-
]
|
| 62 |
-
},
|
| 63 |
-
{
|
| 64 |
-
"cell_type": "markdown",
|
| 65 |
-
"metadata": {},
|
| 66 |
-
"source": [
|
| 67 |
-
"### Step 3: Ask Any Control Engineering Question\n",
|
| 68 |
-
"You can edit the prompt below to test your own dynamical systems, transfer functions, or optimal control problems."
|
| 69 |
-
]
|
| 70 |
-
},
|
| 71 |
-
{
|
| 72 |
-
"cell_type": "code",
|
| 73 |
-
"execution_count": null,
|
| 74 |
-
"metadata": {},
|
| 75 |
-
"outputs": [],
|
| 76 |
-
"source": [
|
| 77 |
-
"# Enter your engineering query here:\n",
|
| 78 |
-
"prompt = \"Design an LQR controller for A=[[0, 1], [-2, -3]], B=[[0], [1]], Q=diag([10, 1]), R=1 and simulate the step response.\"\n",
|
| 79 |
-
"\n",
|
| 80 |
-
"print(f\"User Query: {prompt}\\n\")\n",
|
| 81 |
-
"result = agent.run(prompt)\n",
|
| 82 |
-
"\n",
|
| 83 |
-
"# Display formatted response\n",
|
| 84 |
-
"display(Markdown(result.final_response))\n",
|
| 85 |
-
"\n",
|
| 86 |
-
"# Display any generated simulation plots\n",
|
| 87 |
-
"for plot_path_rel in result.plots:\n",
|
| 88 |
-
" clean_name = Path(plot_path_rel).name\n",
|
| 89 |
-
" local_path = Path(\"outputs/plots\") / clean_name\n",
|
| 90 |
-
" if local_path.exists():\n",
|
| 91 |
-
" print(f\"\\nGenerated Simulation Plot: {clean_name}\")\n",
|
| 92 |
-
" display(Image(filename=str(local_path)))"
|
| 93 |
-
]
|
| 94 |
-
}
|
| 95 |
-
],
|
| 96 |
-
"metadata": {
|
| 97 |
-
"language_info": {
|
| 98 |
-
"name": "python"
|
| 99 |
-
}
|
| 100 |
-
},
|
| 101 |
-
"nbformat": 4,
|
| 102 |
-
"nbformat_minor": 2
|
| 103 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Modelfile
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
# ControlAI Ollama Model Template
|
| 2 |
-
FROM qwen2.5:3b
|
| 3 |
-
|
| 4 |
-
# Set deterministic temperature for control engineering & exact math
|
| 5 |
-
PARAMETER temperature 0.2
|
| 6 |
-
PARAMETER top_p 0.95
|
| 7 |
-
PARAMETER stop "<|im_end|>"
|
| 8 |
-
PARAMETER stop "<|endoftext|>"
|
| 9 |
-
|
| 10 |
-
# Set the safety-critical system prompt
|
| 11 |
-
SYSTEM """You are ControlAI, a premier AI research scientist and expert engineering agent specialized in control systems engineering, applied mathematics, robotics, and dynamical systems.
|
| 12 |
-
|
| 13 |
-
### 4-Stage Mathematical Reasoning & Proof Standard:
|
| 14 |
-
When answering theoretical principles, derivations, proofs, comparisons, or limitation questions:
|
| 15 |
-
1. State the state-space equations, signal spaces, and underlying assumptions.
|
| 16 |
-
2. State the governing theorem with exact mathematical rigor (PBH rank test, Doyle 1978 LQG robustness counterexample, Lyapunov Invariance).
|
| 17 |
-
3. Provide the full closed-form relationships in pure LaTeX.
|
| 18 |
-
4. Explicitly state engineering breakdown conditions and conservation trade-offs (Bode sensitivity integral).
|
| 19 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -1,18 +1,37 @@
|
|
| 1 |
# ControlAI: Open-Source Safety-Critical AI Agent for Control Systems Engineering
|
| 2 |
|
| 3 |
-
[](https://colab.research.google.com/github/atakankahya/controlai-agent/blob/main/ControlAI_Colab_Demo.ipynb)
|
| 4 |
[](https://github.com/atakankahya/controlai-agent)
|
| 5 |
[](https://huggingface.co/atakankahya/ControlAI-Agent)
|
| 6 |
[](https://opensource.org/licenses/MIT)
|
| 7 |
[](https://www.python.org/downloads/)
|
| 8 |
|
| 9 |
-
**ControlAI** is an open-source, domain-specific AI
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
---
|
| 12 |
|
| 13 |
## Motivation: Safety-Critical Verification in Control Engineering
|
| 14 |
|
| 15 |
-
Standard large language models (LLMs) operate probabilistically without deterministic verification. When applied to physical systems—such as autonomous aerial vehicles, industrial manipulators, or power
|
| 16 |
* **Numerical Hallucinations:** Estimating eigenvalues without characteristic polynomial evaluation, inverting singular matrices, or generating unstable feedback gains.
|
| 17 |
* **Lack of Formal Proof Structure:** Omitting boundary conditions, PBH rank tests, or domain-specific stability limits.
|
| 18 |
* **Physical Safety Violations:** A sign error in a state feedback gain leads directly to closed-loop instability in hardware.
|
|
@@ -20,22 +39,11 @@ Standard large language models (LLMs) operate probabilistically without determin
|
|
| 20 |
**ControlAI addresses these limitations through a hybrid architecture:**
|
| 21 |
1. **Deterministic Scientific Sandbox:** Computes continuous/discrete algebraic Riccati equations (CARE/DARE), matrix exponentials, and Bode diagrams using LAPACK, SciPy, and CVXPY.
|
| 22 |
2. **4-Stage Mathematical Proof Standard:** Formulates system class, analytical theorems, closed-form derivations, and engineering breakdown limits.
|
| 23 |
-
3. **Dynamic Simulation & Plotting:** Solves nonlinear differential equations and renders verified trajectories.
|
| 24 |
4. **Offline RAG Knowledge Engine:** Grounded with 68,000+ chunks indexed across classical and modern control engineering literature.
|
| 25 |
|
| 26 |
---
|
| 27 |
|
| 28 |
-
## Live Demo and Access
|
| 29 |
-
|
| 30 |
-
* **Interactive Google Colab Demo:**
|
| 31 |
-
Run ControlAI in a cloud environment with zero local setup:
|
| 32 |
-
[](https://colab.research.google.com/github/atakankahya/controlai-agent/blob/main/ControlAI_Colab_Demo.ipynb)
|
| 33 |
-
|
| 34 |
-
* **Hugging Face Model Repository:**
|
| 35 |
-
Access model weights and fine-tuning configurations: [atakankahya/ControlAI-Agent](https://huggingface.co/atakankahya/ControlAI-Agent)
|
| 36 |
-
|
| 37 |
-
---
|
| 38 |
-
|
| 39 |
## Architecture Overview
|
| 40 |
|
| 41 |
```mermaid
|
|
@@ -68,9 +76,9 @@ graph TD
|
|
| 68 |
|
| 69 |
## Key Capabilities
|
| 70 |
|
| 71 |
-
### 1. Web Console (`web/`)
|
| 72 |
-
* **Real-Time Token Streaming (SSE):**
|
| 73 |
-
* **LaTeX Formula Rendering:** KaTeX integration with math delimiter protection and
|
| 74 |
* **Engineering Toolbar:** One-click insertion of state matrices, transfer functions, and control parameters ($\zeta, \omega_n$).
|
| 75 |
|
| 76 |
### 2. Deterministic Mathematical Tool Suite (`controlai_agent/tools/`)
|
|
@@ -83,7 +91,7 @@ graph TD
|
|
| 83 |
|
| 84 |
### 3. Live Python Execution Sandbox (`python_executor.py`)
|
| 85 |
* Executes scientific Python routines using `numpy`, `scipy.signal`, `scipy.linalg`, `control`, and `matplotlib`.
|
| 86 |
-
* Automatically isolates and captures generated simulation plots to `outputs/plots/`.
|
| 87 |
|
| 88 |
---
|
| 89 |
|
|
@@ -102,44 +110,6 @@ Evaluated across **50 multi-pillar benchmark problems**:
|
|
| 102 |
|
| 103 |
---
|
| 104 |
|
| 105 |
-
## Local Installation and Usage
|
| 106 |
-
|
| 107 |
-
### 1. Clone and Set Up Environment
|
| 108 |
-
|
| 109 |
-
```bash
|
| 110 |
-
# Clone the repository
|
| 111 |
-
git clone https://github.com/atakankahya/controlai-agent.git
|
| 112 |
-
cd controlai-agent
|
| 113 |
-
|
| 114 |
-
# Create and activate virtual environment
|
| 115 |
-
python3 -m venv .venv
|
| 116 |
-
source .venv/bin/activate
|
| 117 |
-
|
| 118 |
-
# Install dependencies
|
| 119 |
-
pip install -r requirements-corpus.txt
|
| 120 |
-
pip install -r requirements-training.txt
|
| 121 |
-
pip install rich
|
| 122 |
-
```
|
| 123 |
-
|
| 124 |
-
### 2. Launch Universal Assistant (Web & Browser Auto-Open)
|
| 125 |
-
|
| 126 |
-
```bash
|
| 127 |
-
./run.sh
|
| 128 |
-
```
|
| 129 |
-
* Starts the backend server and opens the browser interface at `http://127.0.0.1:8000`.
|
| 130 |
-
|
| 131 |
-
### 3. Interactive Terminal CLI
|
| 132 |
-
|
| 133 |
-
```bash
|
| 134 |
-
# Launch interactive terminal session
|
| 135 |
-
./run.sh --cli
|
| 136 |
-
|
| 137 |
-
# Or execute a single query directly
|
| 138 |
-
python cli.py "Design an LQR controller for A=[[0, 1], [-2, -3]], B=[[0], [1]], Q=diag([10, 1]), R=1"
|
| 139 |
-
```
|
| 140 |
-
|
| 141 |
-
---
|
| 142 |
-
|
| 143 |
## Open-Source and Community Support
|
| 144 |
|
| 145 |
ControlAI is an **open-source project** developed for control engineering researchers, robotics practitioners, and applied mathematicians.
|
|
|
|
| 1 |
# ControlAI: Open-Source Safety-Critical AI Agent for Control Systems Engineering
|
| 2 |
|
|
|
|
| 3 |
[](https://github.com/atakankahya/controlai-agent)
|
| 4 |
[](https://huggingface.co/atakankahya/ControlAI-Agent)
|
| 5 |
[](https://opensource.org/licenses/MIT)
|
| 6 |
[](https://www.python.org/downloads/)
|
| 7 |
|
| 8 |
+
**ControlAI** is an open-source, domain-specific AI assistant engineered specifically for **Control Systems Engineering, Dynamical Systems, Robotics, and Applied Mathematics**.
|
| 9 |
+
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
## Quickstart: Run Locally in 2 Steps
|
| 13 |
+
|
| 14 |
+
ControlAI runs locally on your workstation without cloud dependencies:
|
| 15 |
+
|
| 16 |
+
```bash
|
| 17 |
+
# 1. Clone the repository
|
| 18 |
+
git clone https://github.com/atakankahya/controlai-agent.git
|
| 19 |
+
cd controlai-agent
|
| 20 |
+
|
| 21 |
+
# 2. Launch the application (Automatically opens browser at http://127.0.0.1:8000)
|
| 22 |
+
./run.sh
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
To run in interactive terminal CLI mode instead:
|
| 26 |
+
```bash
|
| 27 |
+
./run.sh --cli
|
| 28 |
+
```
|
| 29 |
|
| 30 |
---
|
| 31 |
|
| 32 |
## Motivation: Safety-Critical Verification in Control Engineering
|
| 33 |
|
| 34 |
+
Standard large language models (LLMs) operate probabilistically without deterministic verification. When applied to physical systems—such as autonomous aerial vehicles, industrial manipulators, or power grids—general-purpose models present severe reliability challenges:
|
| 35 |
* **Numerical Hallucinations:** Estimating eigenvalues without characteristic polynomial evaluation, inverting singular matrices, or generating unstable feedback gains.
|
| 36 |
* **Lack of Formal Proof Structure:** Omitting boundary conditions, PBH rank tests, or domain-specific stability limits.
|
| 37 |
* **Physical Safety Violations:** A sign error in a state feedback gain leads directly to closed-loop instability in hardware.
|
|
|
|
| 39 |
**ControlAI addresses these limitations through a hybrid architecture:**
|
| 40 |
1. **Deterministic Scientific Sandbox:** Computes continuous/discrete algebraic Riccati equations (CARE/DARE), matrix exponentials, and Bode diagrams using LAPACK, SciPy, and CVXPY.
|
| 41 |
2. **4-Stage Mathematical Proof Standard:** Formulates system class, analytical theorems, closed-form derivations, and engineering breakdown limits.
|
| 42 |
+
3. **Dynamic Simulation & Plotting:** Solves nonlinear differential equations and renders verified trajectories directly in the interface.
|
| 43 |
4. **Offline RAG Knowledge Engine:** Grounded with 68,000+ chunks indexed across classical and modern control engineering literature.
|
| 44 |
|
| 45 |
---
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
## Architecture Overview
|
| 48 |
|
| 49 |
```mermaid
|
|
|
|
| 76 |
|
| 77 |
## Key Capabilities
|
| 78 |
|
| 79 |
+
### 1. Modern Interactive Web Console (`web/`)
|
| 80 |
+
* **Real-Time Token Streaming (SSE):** Token-by-token fluid rendering with smart scroll retention.
|
| 81 |
+
* **LaTeX Formula Rendering:** KaTeX integration with math delimiter protection and syntax-highlighted code blocks.
|
| 82 |
* **Engineering Toolbar:** One-click insertion of state matrices, transfer functions, and control parameters ($\zeta, \omega_n$).
|
| 83 |
|
| 84 |
### 2. Deterministic Mathematical Tool Suite (`controlai_agent/tools/`)
|
|
|
|
| 91 |
|
| 92 |
### 3. Live Python Execution Sandbox (`python_executor.py`)
|
| 93 |
* Executes scientific Python routines using `numpy`, `scipy.signal`, `scipy.linalg`, `control`, and `matplotlib`.
|
| 94 |
+
* Automatically isolates and captures generated simulation plots to `outputs/plots/` and renders them in chat.
|
| 95 |
|
| 96 |
---
|
| 97 |
|
|
|
|
| 110 |
|
| 111 |
---
|
| 112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
## Open-Source and Community Support
|
| 114 |
|
| 115 |
ControlAI is an **open-source project** developed for control engineering researchers, robotics practitioners, and applied mathematicians.
|
scripts/fuse_model.py
DELETED
|
@@ -1,60 +0,0 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
-
"""Merge/Fuse ControlAI LoRA fine-tuned adapter into base model to produce a standalone model."""
|
| 3 |
-
|
| 4 |
-
from __future__ import annotations
|
| 5 |
-
|
| 6 |
-
import argparse
|
| 7 |
-
import subprocess
|
| 8 |
-
import sys
|
| 9 |
-
from pathlib import Path
|
| 10 |
-
|
| 11 |
-
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
def main() -> None:
|
| 15 |
-
parser = argparse.ArgumentParser(description="Fuse ControlAI LoRA adapter into base model")
|
| 16 |
-
parser.add_argument(
|
| 17 |
-
"--model",
|
| 18 |
-
type=str,
|
| 19 |
-
default="mlx-community/Qwen3-4B-Instruct-2507-4bit",
|
| 20 |
-
help="Base model path or Hugging Face repo ID",
|
| 21 |
-
)
|
| 22 |
-
parser.add_argument(
|
| 23 |
-
"--adapter-path",
|
| 24 |
-
type=str,
|
| 25 |
-
default="adapters/controlai_qwen3_4b_sft_v2",
|
| 26 |
-
help="Path to trained LoRA adapter",
|
| 27 |
-
)
|
| 28 |
-
parser.add_argument(
|
| 29 |
-
"--save-path",
|
| 30 |
-
type=str,
|
| 31 |
-
default="models/controlai_fused",
|
| 32 |
-
help="Target folder for standalone merged model",
|
| 33 |
-
)
|
| 34 |
-
|
| 35 |
-
args = parser.parse_args()
|
| 36 |
-
|
| 37 |
-
print(f"Fusing LoRA adapter from {args.adapter_path} into {args.model}...")
|
| 38 |
-
cmd = [
|
| 39 |
-
sys.executable,
|
| 40 |
-
"-m",
|
| 41 |
-
"mlx_lm",
|
| 42 |
-
"fuse",
|
| 43 |
-
"--model",
|
| 44 |
-
args.model,
|
| 45 |
-
"--adapter-path",
|
| 46 |
-
args.adapter_path,
|
| 47 |
-
"--save-path",
|
| 48 |
-
args.save_path,
|
| 49 |
-
]
|
| 50 |
-
|
| 51 |
-
res = subprocess.run(cmd, cwd=PROJECT_ROOT)
|
| 52 |
-
if res.returncode == 0:
|
| 53 |
-
print(f"\nModel successfully fused into standalone checkpoint at: {args.save_path}")
|
| 54 |
-
else:
|
| 55 |
-
print(f"\nError during fusion (exit code {res.returncode})")
|
| 56 |
-
sys.exit(res.returncode)
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
if __name__ == "__main__":
|
| 60 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|