mcp-sqlite-memory-bank 1.5.1__tar.gz → 1.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mcp_sqlite_memory_bank-1.5.1/src/mcp_sqlite_memory_bank.egg-info → mcp_sqlite_memory_bank-1.6.2}/PKG-INFO +54 -6
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/README.md +51 -3
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/pyproject.toml +18 -3
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/__init__.py +3 -3
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/__main__.py +8 -7
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/database.py +166 -48
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/prompts.py +64 -48
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/resources.py +218 -144
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/semantic.py +25 -13
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/server.py +174 -32
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/tools/__init__.py +26 -29
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/tools/analytics.py +179 -130
- mcp_sqlite_memory_bank-1.6.2/src/mcp_sqlite_memory_bank/tools/basic.py +525 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/tools/discovery.py +549 -360
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/tools/search.py +147 -71
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/types.py +6 -1
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/utils.py +154 -105
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2/src/mcp_sqlite_memory_bank.egg-info}/PKG-INFO +54 -6
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank.egg-info/requires.txt +1 -1
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/conftest.py +91 -81
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/test_api.py +1103 -984
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/test_discovery_tools.py +296 -262
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/test_edge_cases.py +105 -93
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/test_mocks.py +43 -69
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/test_performance.py +95 -75
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/test_server.py +185 -179
- mcp_sqlite_memory_bank-1.5.1/src/mcp_sqlite_memory_bank/tools/basic.py +0 -112
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/LICENSE +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/MANIFEST.in +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/setup.cfg +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/py.typed +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank.egg-info/SOURCES.txt +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank.egg-info/dependency_links.txt +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank.egg-info/entry_points.txt +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank.egg-info/top_level.txt +0 -0
- {mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/tests/README.md +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp_sqlite_memory_bank
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.6.2
|
4
4
|
Summary: A dynamic, agent/LLM-friendly SQLite memory bank for MCP servers with semantic search capabilities.
|
5
5
|
Author-email: Robert Meisner <robert@catchit.pl>
|
6
6
|
License-Expression: MIT
|
@@ -9,13 +9,13 @@ Project-URL: Source, https://github.com/robertmeisner/mcp_sqlite_memory_bank
|
|
9
9
|
Project-URL: Issues, https://github.com/robertmeisner/mcp_sqlite_memory_bank/issues
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
11
11
|
Classifier: Operating System :: OS Independent
|
12
|
-
Requires-Python: >=3.
|
12
|
+
Requires-Python: >=3.10
|
13
13
|
Description-Content-Type: text/markdown
|
14
14
|
License-File: LICENSE
|
15
15
|
Requires-Dist: fastapi>=0.100.0
|
16
16
|
Requires-Dist: uvicorn>=0.22.0
|
17
17
|
Requires-Dist: pydantic>=1.10.0
|
18
|
-
Requires-Dist: fastmcp
|
18
|
+
Requires-Dist: fastmcp>=2.9.0
|
19
19
|
Requires-Dist: sqlalchemy>=2.0.0
|
20
20
|
Requires-Dist: sentence-transformers>=2.2.0
|
21
21
|
Requires-Dist: torch>=1.9.0
|
@@ -126,10 +126,10 @@ Restart your IDE and try asking your AI assistant:
|
|
126
126
|
|
127
127
|
SQLite Memory Bank v1.4.0+ provides full Model Context Protocol (MCP) compliance with advanced features for enhanced LLM and agent integration:
|
128
128
|
|
129
|
-
### 🔧 MCP Tools (
|
129
|
+
### 🔧 MCP Tools (23 Available)
|
130
130
|
Organized into logical categories for easy discovery:
|
131
131
|
- **Schema Management** (6 tools): Table creation, modification, and inspection
|
132
|
-
- **Data Operations** (
|
132
|
+
- **Data Operations** (8 tools): CRUD operations with validation and batch processing
|
133
133
|
- **Search & Discovery** (2 tools): Content search and exploration
|
134
134
|
- **Semantic Search** (5 tools): AI-powered natural language content discovery
|
135
135
|
- **Analytics** (2 tools): Memory bank insights and statistics
|
@@ -175,7 +175,7 @@ All tools are designed for explicit, discoverable use by LLMs, agents, and devel
|
|
175
175
|
| `describe_table` | Get schema details | `table_name` (str) | None |
|
176
176
|
| `list_all_columns` | List all columns for all tables | None | None |
|
177
177
|
|
178
|
-
### Data Operations Tools (
|
178
|
+
### Data Operations Tools (8 tools)
|
179
179
|
|
180
180
|
| Tool | Description | Required Parameters | Optional Parameters |
|
181
181
|
|------|-------------|---------------------|---------------------|
|
@@ -184,6 +184,9 @@ All tools are designed for explicit, discoverable use by LLMs, agents, and devel
|
|
184
184
|
| `update_rows` | Update existing rows | `table_name` (str), `data` (dict), `where` (dict) | None |
|
185
185
|
| `delete_rows` | Delete rows from table | `table_name` (str), `where` (dict) | None |
|
186
186
|
| `run_select_query` | Run safe SELECT query | `table_name` (str) | `columns` (list[str]), `where` (dict), `limit` (int) |
|
187
|
+
| `upsert_memory` | Smart update or create memory record | `table_name` (str), `data` (dict), `match_columns` (list[str]) | None |
|
188
|
+
| `batch_create_memories` | Efficiently create multiple memory records | `table_name` (str), `data_list` (list[dict]) | `match_columns` (list[str]), `use_upsert` (bool) |
|
189
|
+
| `batch_delete_memories` | Delete multiple memory records efficiently | `table_name` (str), `conditions_list` (list[dict]) | `match_mode` (str) |
|
187
190
|
|
188
191
|
### Search & Discovery Tools (2 tools)
|
189
192
|
|
@@ -211,6 +214,51 @@ All tools are designed for explicit, discoverable use by LLMs, agents, and devel
|
|
211
214
|
|
212
215
|
Each tool validates inputs and returns consistent response formats with success/error indicators and appropriate data payloads.
|
213
216
|
|
217
|
+
## 🚀 Batch Operations & Smart Memory Management
|
218
|
+
|
219
|
+
SQLite Memory Bank provides powerful batch operations for efficient memory management:
|
220
|
+
|
221
|
+
### Smart Memory Updates
|
222
|
+
- **`upsert_memory`**: Intelligent update-or-create for preventing duplicates
|
223
|
+
- **Duplicate Prevention**: Uses match columns to find existing records
|
224
|
+
- **Flexible Matching**: Specify which columns to match for finding existing records
|
225
|
+
|
226
|
+
### Efficient Batch Processing
|
227
|
+
- **`batch_create_memories`**: Create multiple records in a single operation
|
228
|
+
- **Smart vs Fast Modes**: Choose between upsert logic (prevents duplicates) or fast insertion
|
229
|
+
- **Partial Success Handling**: Continues processing even if some records fail
|
230
|
+
- **Detailed Feedback**: Returns counts for created, updated, and failed records
|
231
|
+
|
232
|
+
### Flexible Batch Deletion
|
233
|
+
- **`batch_delete_memories`**: Delete multiple records with complex conditions
|
234
|
+
- **Flexible Matching**: Support for OR (match_any) and AND (match_all) logic
|
235
|
+
- **Condition Lists**: Delete based on multiple different criteria
|
236
|
+
- **Safe Operations**: Validates conditions before deletion
|
237
|
+
|
238
|
+
### Usage Examples
|
239
|
+
|
240
|
+
```python
|
241
|
+
# Smart memory upsert - prevents duplicates
|
242
|
+
upsert_memory('technical_decisions', {
|
243
|
+
'decision_name': 'API Design',
|
244
|
+
'chosen_approach': 'REST APIs',
|
245
|
+
'rationale': 'Better discoverability for LLMs'
|
246
|
+
}, match_columns=['decision_name'])
|
247
|
+
|
248
|
+
# Batch create with duplicate prevention
|
249
|
+
batch_create_memories('project_insights', [
|
250
|
+
{'category': 'performance', 'insight': 'Database indexing'},
|
251
|
+
{'category': 'security', 'insight': 'Input validation'},
|
252
|
+
{'category': 'architecture', 'insight': 'Microservice patterns'}
|
253
|
+
], match_columns=['category', 'insight'], use_upsert=True)
|
254
|
+
|
255
|
+
# Batch delete with flexible conditions
|
256
|
+
batch_delete_memories('old_notes', [
|
257
|
+
{'status': 'archived'},
|
258
|
+
{'created_date': '2023-01-01', 'priority': 'low'}
|
259
|
+
], match_mode='match_any') # Delete if ANY condition matches
|
260
|
+
```
|
261
|
+
|
214
262
|
---
|
215
263
|
|
216
264
|
## Transport Modes
|
@@ -100,10 +100,10 @@ Restart your IDE and try asking your AI assistant:
|
|
100
100
|
|
101
101
|
SQLite Memory Bank v1.4.0+ provides full Model Context Protocol (MCP) compliance with advanced features for enhanced LLM and agent integration:
|
102
102
|
|
103
|
-
### 🔧 MCP Tools (
|
103
|
+
### 🔧 MCP Tools (23 Available)
|
104
104
|
Organized into logical categories for easy discovery:
|
105
105
|
- **Schema Management** (6 tools): Table creation, modification, and inspection
|
106
|
-
- **Data Operations** (
|
106
|
+
- **Data Operations** (8 tools): CRUD operations with validation and batch processing
|
107
107
|
- **Search & Discovery** (2 tools): Content search and exploration
|
108
108
|
- **Semantic Search** (5 tools): AI-powered natural language content discovery
|
109
109
|
- **Analytics** (2 tools): Memory bank insights and statistics
|
@@ -149,7 +149,7 @@ All tools are designed for explicit, discoverable use by LLMs, agents, and devel
|
|
149
149
|
| `describe_table` | Get schema details | `table_name` (str) | None |
|
150
150
|
| `list_all_columns` | List all columns for all tables | None | None |
|
151
151
|
|
152
|
-
### Data Operations Tools (
|
152
|
+
### Data Operations Tools (8 tools)
|
153
153
|
|
154
154
|
| Tool | Description | Required Parameters | Optional Parameters |
|
155
155
|
|------|-------------|---------------------|---------------------|
|
@@ -158,6 +158,9 @@ All tools are designed for explicit, discoverable use by LLMs, agents, and devel
|
|
158
158
|
| `update_rows` | Update existing rows | `table_name` (str), `data` (dict), `where` (dict) | None |
|
159
159
|
| `delete_rows` | Delete rows from table | `table_name` (str), `where` (dict) | None |
|
160
160
|
| `run_select_query` | Run safe SELECT query | `table_name` (str) | `columns` (list[str]), `where` (dict), `limit` (int) |
|
161
|
+
| `upsert_memory` | Smart update or create memory record | `table_name` (str), `data` (dict), `match_columns` (list[str]) | None |
|
162
|
+
| `batch_create_memories` | Efficiently create multiple memory records | `table_name` (str), `data_list` (list[dict]) | `match_columns` (list[str]), `use_upsert` (bool) |
|
163
|
+
| `batch_delete_memories` | Delete multiple memory records efficiently | `table_name` (str), `conditions_list` (list[dict]) | `match_mode` (str) |
|
161
164
|
|
162
165
|
### Search & Discovery Tools (2 tools)
|
163
166
|
|
@@ -185,6 +188,51 @@ All tools are designed for explicit, discoverable use by LLMs, agents, and devel
|
|
185
188
|
|
186
189
|
Each tool validates inputs and returns consistent response formats with success/error indicators and appropriate data payloads.
|
187
190
|
|
191
|
+
## 🚀 Batch Operations & Smart Memory Management
|
192
|
+
|
193
|
+
SQLite Memory Bank provides powerful batch operations for efficient memory management:
|
194
|
+
|
195
|
+
### Smart Memory Updates
|
196
|
+
- **`upsert_memory`**: Intelligent update-or-create for preventing duplicates
|
197
|
+
- **Duplicate Prevention**: Uses match columns to find existing records
|
198
|
+
- **Flexible Matching**: Specify which columns to match for finding existing records
|
199
|
+
|
200
|
+
### Efficient Batch Processing
|
201
|
+
- **`batch_create_memories`**: Create multiple records in a single operation
|
202
|
+
- **Smart vs Fast Modes**: Choose between upsert logic (prevents duplicates) or fast insertion
|
203
|
+
- **Partial Success Handling**: Continues processing even if some records fail
|
204
|
+
- **Detailed Feedback**: Returns counts for created, updated, and failed records
|
205
|
+
|
206
|
+
### Flexible Batch Deletion
|
207
|
+
- **`batch_delete_memories`**: Delete multiple records with complex conditions
|
208
|
+
- **Flexible Matching**: Support for OR (match_any) and AND (match_all) logic
|
209
|
+
- **Condition Lists**: Delete based on multiple different criteria
|
210
|
+
- **Safe Operations**: Validates conditions before deletion
|
211
|
+
|
212
|
+
### Usage Examples
|
213
|
+
|
214
|
+
```python
|
215
|
+
# Smart memory upsert - prevents duplicates
|
216
|
+
upsert_memory('technical_decisions', {
|
217
|
+
'decision_name': 'API Design',
|
218
|
+
'chosen_approach': 'REST APIs',
|
219
|
+
'rationale': 'Better discoverability for LLMs'
|
220
|
+
}, match_columns=['decision_name'])
|
221
|
+
|
222
|
+
# Batch create with duplicate prevention
|
223
|
+
batch_create_memories('project_insights', [
|
224
|
+
{'category': 'performance', 'insight': 'Database indexing'},
|
225
|
+
{'category': 'security', 'insight': 'Input validation'},
|
226
|
+
{'category': 'architecture', 'insight': 'Microservice patterns'}
|
227
|
+
], match_columns=['category', 'insight'], use_upsert=True)
|
228
|
+
|
229
|
+
# Batch delete with flexible conditions
|
230
|
+
batch_delete_memories('old_notes', [
|
231
|
+
{'status': 'archived'},
|
232
|
+
{'created_date': '2023-01-01', 'priority': 'low'}
|
233
|
+
], match_mode='match_any') # Delete if ANY condition matches
|
234
|
+
```
|
235
|
+
|
188
236
|
---
|
189
237
|
|
190
238
|
## Transport Modes
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "mcp_sqlite_memory_bank"
|
7
|
-
version = "1.
|
7
|
+
version = "1.6.2"
|
8
8
|
description = "A dynamic, agent/LLM-friendly SQLite memory bank for MCP servers with semantic search capabilities."
|
9
9
|
authors = [
|
10
10
|
{ name="Robert Meisner", email="robert@catchit.pl" }
|
@@ -12,7 +12,7 @@ authors = [
|
|
12
12
|
license = "MIT"
|
13
13
|
license-files = ["LICENSE"]
|
14
14
|
readme = "README.md"
|
15
|
-
requires-python = ">=3.
|
15
|
+
requires-python = ">=3.10"
|
16
16
|
classifiers = [
|
17
17
|
"Programming Language :: Python :: 3",
|
18
18
|
"Operating System :: OS Independent",
|
@@ -21,7 +21,7 @@ dependencies = [
|
|
21
21
|
"fastapi>=0.100.0",
|
22
22
|
"uvicorn>=0.22.0",
|
23
23
|
"pydantic>=1.10.0",
|
24
|
-
"fastmcp",
|
24
|
+
"fastmcp>=2.9.0",
|
25
25
|
"sqlalchemy>=2.0.0",
|
26
26
|
"sentence-transformers>=2.2.0",
|
27
27
|
"torch>=1.9.0",
|
@@ -43,3 +43,18 @@ test = ["pytest"]
|
|
43
43
|
[tool.setuptools.packages.find]
|
44
44
|
where = ["src"]
|
45
45
|
exclude = ["*__pycache__*", "*.pyc", "*.pyo"]
|
46
|
+
|
47
|
+
[tool.mypy]
|
48
|
+
python_version = "3.10"
|
49
|
+
strict = true
|
50
|
+
warn_return_any = true
|
51
|
+
warn_unused_configs = true
|
52
|
+
disallow_untyped_defs = true
|
53
|
+
|
54
|
+
# Temporarily exclude files with type issues until separate type safety PR
|
55
|
+
[[tool.mypy.overrides]]
|
56
|
+
module = [
|
57
|
+
"mcp_sqlite_memory_bank.tools.discovery",
|
58
|
+
"mcp_sqlite_memory_bank.tools.analytics"
|
59
|
+
]
|
60
|
+
ignore_errors = true
|
{mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/__init__.py
RENAMED
@@ -8,7 +8,7 @@ Cursor, and other LLM-powered tools to interact with structured data in a
|
|
8
8
|
safe, explicit, and extensible way.
|
9
9
|
|
10
10
|
Author: Robert Meisner
|
11
|
-
Version:
|
11
|
+
Version: 1.6.2
|
12
12
|
License: MIT
|
13
13
|
"""
|
14
14
|
|
@@ -73,7 +73,7 @@ from .types import (
|
|
73
73
|
)
|
74
74
|
|
75
75
|
# Package metadata
|
76
|
-
__version__ = "
|
76
|
+
__version__ = "1.6.2"
|
77
77
|
__author__ = "Robert Meisner"
|
78
78
|
__all__ = [
|
79
79
|
# Core tools
|
@@ -93,7 +93,7 @@ __all__ = [
|
|
93
93
|
"explore_tables",
|
94
94
|
"add_embeddings",
|
95
95
|
"semantic_search",
|
96
|
-
"find_related",
|
96
|
+
"find_related",
|
97
97
|
"smart_search",
|
98
98
|
"embedding_stats",
|
99
99
|
"auto_semantic_search",
|
{mcp_sqlite_memory_bank-1.5.1 → mcp_sqlite_memory_bank-1.6.2}/src/mcp_sqlite_memory_bank/__main__.py
RENAMED
@@ -17,16 +17,16 @@ if project_root not in sys.path:
|
|
17
17
|
|
18
18
|
# Configure logging before any other imports
|
19
19
|
logging.basicConfig(
|
20
|
-
level=logging.INFO,
|
21
|
-
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
20
|
+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
22
21
|
)
|
23
22
|
|
24
|
-
|
23
|
+
|
24
|
+
def main() -> None:
|
25
25
|
"""Main entry point for the MCP server."""
|
26
26
|
try:
|
27
27
|
# Import here to avoid circular import issues
|
28
28
|
from .server import app, DB_PATH
|
29
|
-
|
29
|
+
|
30
30
|
# Handle help argument
|
31
31
|
if "--help" in sys.argv or "-h" in sys.argv:
|
32
32
|
print("SQLite Memory Bank MCP Server")
|
@@ -41,13 +41,13 @@ def main():
|
|
41
41
|
print("Environment variables:")
|
42
42
|
print(" DB_PATH: Override the default database path")
|
43
43
|
return
|
44
|
-
|
44
|
+
|
45
45
|
# Log startup information
|
46
46
|
logging.info(f"Starting SQLite Memory Bank MCP server with database at {DB_PATH}")
|
47
|
-
|
47
|
+
|
48
48
|
# Run the FastMCP app in stdio mode for MCP clients
|
49
49
|
app.run(transport="stdio")
|
50
|
-
|
50
|
+
|
51
51
|
except KeyboardInterrupt:
|
52
52
|
logging.info("Server stopped by user")
|
53
53
|
sys.exit(0)
|
@@ -55,5 +55,6 @@ def main():
|
|
55
55
|
logging.error(f"Failed to start MCP server: {e}")
|
56
56
|
sys.exit(1)
|
57
57
|
|
58
|
+
|
58
59
|
if __name__ == "__main__":
|
59
60
|
main()
|