hyperping 1.4.0__tar.gz → 1.4.1__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.
- {hyperping-1.4.0 → hyperping-1.4.1}/CHANGELOG.md +88 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/PKG-INFO +38 -1
- {hyperping-1.4.0 → hyperping-1.4.1}/README.md +37 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/pyproject.toml +1 -1
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/__init__.py +1 -1
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_mcp_transport.py +4 -3
- hyperping-1.4.1/src/hyperping/_version.py +1 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/mcp_client.py +2 -1
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_mcp_transport.py +11 -0
- hyperping-1.4.0/src/hyperping/_version.py +0 -1
- {hyperping-1.4.0 → hyperping-1.4.1}/.gitignore +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/CONTRIBUTING.md +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/LICENSE +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/scripts/verify_endpoints.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_async_client.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_async_healthchecks_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_async_incidents_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_async_maintenance_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_async_monitors_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_async_outages_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_async_statuspages_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_circuit_breaker.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_healthchecks_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_incidents_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_internals.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_maintenance_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_monitor_constants.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_monitors_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_outages_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_protocols.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_statuspages_mixin.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/_utils.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/client.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/endpoints.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/exceptions.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/__init__.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_healthcheck_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_incident_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_integration_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_maintenance_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_monitor_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_observability_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_oncall_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_outage_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_reporting_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/models/_statuspage_models.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/src/hyperping/py.typed +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/__init__.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/__init__.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/conftest.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_async_client.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_async_preexisting.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_healthchecks.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_incidents.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_maintenance.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_mcp_client.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_monitors.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_outages.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_pagination.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_sdk_surface.py +0 -0
- {hyperping-1.4.0 → hyperping-1.4.1}/tests/unit/test_statuspages.py +0 -0
|
@@ -5,6 +5,87 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.4.1] - 2026-04-20
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- HTTP 403 from MCP server now correctly raises `HyperpingAuthError` (was
|
|
13
|
+
`HyperpingAPIError`). The Hyperping MCP server returns 403 for invalid API keys;
|
|
14
|
+
the transport only handled 401. Now matches REST client behavior.
|
|
15
|
+
- `MCP_URL` defined in single location (`endpoints.py`); removed duplicate in
|
|
16
|
+
`_mcp_transport.py`.
|
|
17
|
+
- MCP handshake version string uses `__version__` instead of hardcoded `"1.4.0"`.
|
|
18
|
+
|
|
19
|
+
## [1.4.0] - 2026-04-19
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **`HyperpingMcpClient`** -- new client for Hyperping MCP server features not available
|
|
24
|
+
via the REST API. Uses JSON-RPC 2.0 over HTTP at `/v1/mcp` with the same Bearer token
|
|
25
|
+
API key. Provides 16 typed methods: `get_status_summary`, `get_monitor_response_time`,
|
|
26
|
+
`get_monitor_mtta`, `get_monitor_mttr`, `get_monitor_anomalies`, `get_monitor_http_logs`,
|
|
27
|
+
`list_recent_alerts`, `list_on_call_schedules`, `get_on_call_schedule`,
|
|
28
|
+
`list_escalation_policies`, `get_escalation_policy`, `list_team_members`,
|
|
29
|
+
`list_integrations`, `get_integration`, `get_outage_timeline`, `search_monitors_by_name`.
|
|
30
|
+
- **`McpTransport`** -- low-level JSON-RPC 2.0 transport with auto-initialization handshake,
|
|
31
|
+
double-parse response extraction, and error mapping to existing SDK exception types.
|
|
32
|
+
- **`MCP_URL`** constant exported from `hyperping` top-level.
|
|
33
|
+
- **Sync outage methods** -- `create_outage`, `delete_outage`, `get_outage`,
|
|
34
|
+
`unacknowledge_outage` added to `OutagesMixin` (were only in async client).
|
|
35
|
+
- **Verification script** -- `scripts/verify_endpoints.py` for testing endpoints against
|
|
36
|
+
the live API.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **Maintenance update** uses `model_dump(include=...)` instead of hard-coded field list.
|
|
41
|
+
- **Incident update error handling** -- `add_incident_update` now provides context when
|
|
42
|
+
the POST succeeds but the follow-up GET fails.
|
|
43
|
+
|
|
44
|
+
### Removed
|
|
45
|
+
|
|
46
|
+
- **Speculative REST methods** -- 12 methods that called nonexistent REST endpoints
|
|
47
|
+
(on-call, alerts, anomalies, integrations, probe logs, response time, MTTA, status
|
|
48
|
+
summary, outage timeline, monitor search) removed from `HyperpingClient` and
|
|
49
|
+
`AsyncHyperpingClient`. These features are MCP-only; use `HyperpingMcpClient` instead.
|
|
50
|
+
- **8 speculative mixin files** (sync + async) deleted.
|
|
51
|
+
- **8 speculative Endpoint enum entries** removed from `endpoints.py`.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- HTTP 403 from MCP server now correctly raises `HyperpingAuthError` (was
|
|
56
|
+
`HyperpingAPIError`). Matches REST client behavior.
|
|
57
|
+
- `MCP_URL` defined in single location (`endpoints.py`), not duplicated.
|
|
58
|
+
- MCP handshake version uses `__version__` instead of hardcoded string.
|
|
59
|
+
- `pytest` bumped to 9.0.3 (CVE-2025-71176).
|
|
60
|
+
|
|
61
|
+
## [1.3.0] - 2026-04-18 [YANKED]
|
|
62
|
+
|
|
63
|
+
v1.3.0 added 18 speculative REST methods for MCP-discovered features (reporting,
|
|
64
|
+
observability, on-call, integrations). All 12 endpoint paths were guessed from MCP
|
|
65
|
+
tool names and **none of them work via the REST API** (verified: 10x 404, 2x 401).
|
|
66
|
+
These features are only accessible through the MCP server (JSON-RPC 2.0). Superseded
|
|
67
|
+
by v1.4.0 which replaces the broken REST methods with a proper `HyperpingMcpClient`.
|
|
68
|
+
|
|
69
|
+
## [1.2.1] - 2026-04-17
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- Bump `pytest` to 9.0.3 (CVE-2025-71176).
|
|
74
|
+
|
|
75
|
+
## [1.2.0] - 2026-04-17
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- **Sync outage methods** -- `create_outage`, `delete_outage`, `get_outage`,
|
|
80
|
+
`unacknowledge_outage` added to `OutagesMixin` for feature parity with async client.
|
|
81
|
+
|
|
82
|
+
### Changed
|
|
83
|
+
|
|
84
|
+
- **Maintenance update** uses `model_dump(include=...)` instead of hard-coded field
|
|
85
|
+
enumeration for robustness.
|
|
86
|
+
- **Incident update error handling** -- `add_incident_update` now provides context when
|
|
87
|
+
the POST succeeds but the follow-up GET fails.
|
|
88
|
+
|
|
8
89
|
## [1.1.0] - 2026-04-09
|
|
9
90
|
|
|
10
91
|
### Added
|
|
@@ -30,6 +111,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
30
111
|
- **`collect_all_pages` / `collect_all_pages_async`** helpers in `_utils.py` for
|
|
31
112
|
transparent multi-page result aggregation.
|
|
32
113
|
|
|
114
|
+
## [1.0.1] - 2026-04-05
|
|
115
|
+
|
|
116
|
+
### Fixed
|
|
117
|
+
|
|
118
|
+
- Fix version string in `pyproject.toml` (was out of sync with `_version.py`).
|
|
119
|
+
- Fix package metadata: incorrect email address in project config.
|
|
120
|
+
|
|
33
121
|
## [1.0.0] - 2026-04-05
|
|
34
122
|
|
|
35
123
|
First stable release. The public API is production-ready and covered by semver
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperping
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: Python SDK for the Hyperping uptime monitoring and incident management API
|
|
5
5
|
Project-URL: Homepage, https://github.com/develeap/hyperping-python
|
|
6
6
|
Project-URL: Documentation, https://github.com/develeap/hyperping-python#readme
|
|
@@ -181,6 +181,43 @@ sub = client.add_subscriber("sp_uuid", "user@example.com")
|
|
|
181
181
|
client.remove_subscriber("sp_uuid", sub.id)
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
+
### MCP Client (on-call, alerts, anomalies, integrations)
|
|
185
|
+
|
|
186
|
+
Some Hyperping features are only available via the MCP server (JSON-RPC 2.0),
|
|
187
|
+
not the REST API. Use `HyperpingMcpClient` for these:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from hyperping import HyperpingMcpClient
|
|
191
|
+
|
|
192
|
+
with HyperpingMcpClient(api_key="sk_...") as mcp:
|
|
193
|
+
# Status & reporting
|
|
194
|
+
summary = mcp.get_status_summary()
|
|
195
|
+
mtta = mcp.get_monitor_mtta("mon_uuid")
|
|
196
|
+
mttr = mcp.get_monitor_mttr("mon_uuid")
|
|
197
|
+
response_time = mcp.get_monitor_response_time("mon_uuid")
|
|
198
|
+
|
|
199
|
+
# On-call & escalation
|
|
200
|
+
schedules = mcp.list_on_call_schedules()
|
|
201
|
+
policies = mcp.list_escalation_policies()
|
|
202
|
+
members = mcp.list_team_members()
|
|
203
|
+
|
|
204
|
+
# Observability
|
|
205
|
+
anomalies = mcp.get_monitor_anomalies("mon_uuid")
|
|
206
|
+
logs = mcp.get_monitor_http_logs("mon_uuid")
|
|
207
|
+
alerts = mcp.list_recent_alerts()
|
|
208
|
+
|
|
209
|
+
# Integrations
|
|
210
|
+
integrations = mcp.list_integrations()
|
|
211
|
+
|
|
212
|
+
# Outage timeline & monitor search
|
|
213
|
+
timeline = mcp.get_outage_timeline("out_uuid")
|
|
214
|
+
results = mcp.search_monitors_by_name("api")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The MCP client uses the same API key as `HyperpingClient`. All methods return
|
|
218
|
+
plain dicts/lists; use the exported Pydantic models (e.g., `OnCallSchedule`,
|
|
219
|
+
`EscalationPolicy`) for validation if needed.
|
|
220
|
+
|
|
184
221
|
### Healthchecks
|
|
185
222
|
|
|
186
223
|
```python
|
|
@@ -144,6 +144,43 @@ sub = client.add_subscriber("sp_uuid", "user@example.com")
|
|
|
144
144
|
client.remove_subscriber("sp_uuid", sub.id)
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
+
### MCP Client (on-call, alerts, anomalies, integrations)
|
|
148
|
+
|
|
149
|
+
Some Hyperping features are only available via the MCP server (JSON-RPC 2.0),
|
|
150
|
+
not the REST API. Use `HyperpingMcpClient` for these:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from hyperping import HyperpingMcpClient
|
|
154
|
+
|
|
155
|
+
with HyperpingMcpClient(api_key="sk_...") as mcp:
|
|
156
|
+
# Status & reporting
|
|
157
|
+
summary = mcp.get_status_summary()
|
|
158
|
+
mtta = mcp.get_monitor_mtta("mon_uuid")
|
|
159
|
+
mttr = mcp.get_monitor_mttr("mon_uuid")
|
|
160
|
+
response_time = mcp.get_monitor_response_time("mon_uuid")
|
|
161
|
+
|
|
162
|
+
# On-call & escalation
|
|
163
|
+
schedules = mcp.list_on_call_schedules()
|
|
164
|
+
policies = mcp.list_escalation_policies()
|
|
165
|
+
members = mcp.list_team_members()
|
|
166
|
+
|
|
167
|
+
# Observability
|
|
168
|
+
anomalies = mcp.get_monitor_anomalies("mon_uuid")
|
|
169
|
+
logs = mcp.get_monitor_http_logs("mon_uuid")
|
|
170
|
+
alerts = mcp.list_recent_alerts()
|
|
171
|
+
|
|
172
|
+
# Integrations
|
|
173
|
+
integrations = mcp.list_integrations()
|
|
174
|
+
|
|
175
|
+
# Outage timeline & monitor search
|
|
176
|
+
timeline = mcp.get_outage_timeline("out_uuid")
|
|
177
|
+
results = mcp.search_monitors_by_name("api")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The MCP client uses the same API key as `HyperpingClient`. All methods return
|
|
181
|
+
plain dicts/lists; use the exported Pydantic models (e.g., `OnCallSchedule`,
|
|
182
|
+
`EscalationPolicy`) for validation if needed.
|
|
183
|
+
|
|
147
184
|
### Healthchecks
|
|
148
185
|
|
|
149
186
|
```python
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hyperping"
|
|
7
|
-
version = "1.4.
|
|
7
|
+
version = "1.4.1"
|
|
8
8
|
description = "Python SDK for the Hyperping uptime monitoring and incident management API"
|
|
9
9
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -15,7 +15,6 @@ Quick start::
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
from hyperping._async_client import AsyncHyperpingClient
|
|
18
|
-
from hyperping._mcp_transport import MCP_URL
|
|
19
18
|
from hyperping._version import __version__
|
|
20
19
|
from hyperping.client import (
|
|
21
20
|
CircuitBreaker,
|
|
@@ -26,6 +25,7 @@ from hyperping.client import (
|
|
|
26
25
|
)
|
|
27
26
|
from hyperping.endpoints import (
|
|
28
27
|
API_BASE,
|
|
28
|
+
MCP_URL,
|
|
29
29
|
APIVersion,
|
|
30
30
|
Endpoint,
|
|
31
31
|
)
|
|
@@ -8,9 +8,10 @@ from typing import Any
|
|
|
8
8
|
import httpx
|
|
9
9
|
from pydantic import SecretStr
|
|
10
10
|
|
|
11
|
+
from hyperping._version import __version__
|
|
12
|
+
from hyperping.endpoints import MCP_URL
|
|
11
13
|
from hyperping.exceptions import HyperpingAPIError, HyperpingAuthError
|
|
12
14
|
|
|
13
|
-
MCP_URL = "https://api.hyperping.io/v1/mcp"
|
|
14
15
|
_PROTOCOL_VERSION = "2025-03-26"
|
|
15
16
|
|
|
16
17
|
|
|
@@ -61,7 +62,7 @@ class McpTransport:
|
|
|
61
62
|
|
|
62
63
|
resp = self._client.post(self._url, content=json.dumps(payload))
|
|
63
64
|
|
|
64
|
-
if resp.status_code
|
|
65
|
+
if resp.status_code in (401, 403):
|
|
65
66
|
raise HyperpingAuthError("Invalid or expired API key")
|
|
66
67
|
if resp.status_code == 202:
|
|
67
68
|
return None # Notification accepted
|
|
@@ -91,7 +92,7 @@ class McpTransport:
|
|
|
91
92
|
{
|
|
92
93
|
"protocolVersion": _PROTOCOL_VERSION,
|
|
93
94
|
"capabilities": {},
|
|
94
|
-
"clientInfo": {"name": "hyperping-python", "version":
|
|
95
|
+
"clientInfo": {"name": "hyperping-python", "version": __version__},
|
|
95
96
|
},
|
|
96
97
|
)
|
|
97
98
|
self._send_rpc("notifications/initialized", is_notification=True)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.4.1"
|
|
@@ -76,6 +76,17 @@ def test_call_tool_http_401():
|
|
|
76
76
|
transport.close()
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
@respx.mock
|
|
80
|
+
def test_call_tool_http_403():
|
|
81
|
+
"""MCP server returns 403 (not 401) for invalid API keys."""
|
|
82
|
+
respx.post(MCP_URL).mock(return_value=httpx.Response(403, text="Forbidden"))
|
|
83
|
+
transport = McpTransport(api_key="sk_bad", base_url=MCP_URL)
|
|
84
|
+
transport._initialized = True
|
|
85
|
+
with pytest.raises(HyperpingAuthError):
|
|
86
|
+
transport.call_tool("list_team_members")
|
|
87
|
+
transport.close()
|
|
88
|
+
|
|
89
|
+
|
|
79
90
|
@respx.mock
|
|
80
91
|
def test_call_tool_jsonrpc_error():
|
|
81
92
|
respx.post(MCP_URL).mock(
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.4.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|