Trong bài viết này, tôi sẽ chia sẻ kinh nghiệm thực chiến khi triển khai HolySheep MCP Agent Gateway — một giải pháp gateway tập trung giúp quản lý rate limit, retry mechanism, quota allocation và observability cho hệ thống multi-agent. Sau 3 tháng vận hành production với hơn 2 triệu tool calls mỗi ngày, tôi sẽ cung cấp đánh giá chi tiết về độ trễ, tỷ lệ thành công, và ROI thực tế.
Mục Lục
- Tổng Quan HolySheep MCP Gateway
- Kiến Trúc Hệ Thống
- Rate Limiting — Giới Hạn Tốc Độ Tool Calls
- Failure Retry — Chiến Lược Thử Lại Thông Minh
- Quota Governance — Quản Lý Phân Bổ Tài Nguyên
- Call Chain Monitoring — Giám Sát Chuỗi Gọi
- Giá và ROI
- Phù Hợp / Không Phù Hợp Với Ai
- Lỗi Thường Gặp Và Cách Khắc Phục
- Vì Sao Chọn HolySheep
Tổng Quan HolySheep MCP Agent Gateway
HolySheep MCP Gateway là unified gateway cho phép các agent giao tiếp với external tools thông qua standardized interface. Điểm nổi bật của giải pháp này là khả năng centralized rate limiting, intelligent retry, và fine-grained quota management — tất cả đều có dashboard trực quan với độ trễ trung bình chỉ <50ms.
Tính Năng Chính
- Tool Registry: Đăng ký và quản lý tools tập trung
- Rate Limiting: Per-agent, per-tool, per-endpoint limits
- Retry Engine: Exponential backoff với jitter thông minh
- Quota Management: Budget allocation theo team/project
- Call Chain Tracing: Distributed tracing cho toàn bộ flow
- Cost Attribution: Track chi phí theo user, session, tool
Bảng So Sánh Tính Năng Gateway
| Tiêu Chí | HolySheep MCP | Self-Hosted Gateway | API Gateway Cloud |
|---|---|---|---|
| Độ trễ trung bình | <50ms | 20-80ms | 80-200ms |
| Rate Limiting | ✅ Native | ⚠️ Cần config | ✅ Có giới hạn |
| Retry Logic | ✅ Smart retry | ⚠️ Tự implement | ❌ Không có |
| Quota Governance | ✅ Chi tiết | ⚠️ Phức tạp | ⚠️ Cơ bản |
| Monitoring | ✅ Dashboard | ⚠️ Cần setup | ✅ Có limits |
| Chi phí vận hành | $0.02/1K calls | $200-500/tháng | $0.05-0.10/1K |
Kiến Trúc Hệ Thống
Architecture của HolySheep MCP Gateway sử dụng microservices pattern với các components chính:
┌─────────────────────────────────────────────────────────────┐
│ HolySheep MCP Gateway │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │
│ │ Rate │ │ Retry │ │ Quota │ │ Monitoring │ │
│ │ Limiter │ │ Engine │ │ Manager │ │ & Tracing │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────────┬────────┘ │
│ │ │ │ │ │
│ ┌────▼────────────▼────────────▼─────────────────▼────────┐ │
│ │ Internal Message Queue (Redis) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼─────────────────────────────┐ │
│ │ Tool Adapters Layer │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │Browser │ │Code │ │Search │ │Custom │ │ │
│ │ │Tool │ │Executor │ │Tool │ │Tools │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Rate Limiting — Giới Hạn Tốc Độ Tool Calls
Rate limiting là tính năng quan trọng nhất của bất kỳ gateway nào. HolySheep cung cấp multi-level rate limiting với độ chính xác cao.
Cấu Hình Rate Limit
# config.yaml - HolySheep MCP Gateway Configuration
gateway:
base_url: "https://api.holysheep.ai/v1"
api_key: "YOUR_HOLYSHEEP_API_KEY"
Rate Limiting Configuration
rate_limits:
# Global limit cho toàn bộ system
global:
requests_per_minute: 10000
burst_size: 500
# Per-agent limits
agent_limits:
research_agent:
requests_per_minute: 1000
requests_per_hour: 50000
concurrent_calls: 50
data_agent:
requests_per_minute: 500
requests_per_hour: 20000
concurrent_calls: 20
# Per-tool limits
tool_limits:
web_search:
requests_per_minute: 200
requests_per_day: 10000
database_query:
requests_per_minute: 1000
requests_per_second: 100
Quota Configuration
quotas:
default_budget_usd: 100.00 # Budget mặc định cho mỗi agent
alert_threshold: 0.80 # Alert khi sử dụng 80% budget
Implementation Rate Limit Trong Agent Code
import requests
import time
from collections import deque
from threading import Lock
class HolySheepMCPGateway:
"""
HolySheep MCP Gateway Client với built-in rate limiting
"""
def __init__(self, api_key: str):
self.base_url = "https://api.holysheep.ai/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
self.rate_limit_window = 60 # 60 giây
self.max_requests = 1000 # requests per minute
# Token bucket algorithm
self.tokens = self.max_requests
self.last_refill = time.time()
self.lock = Lock()
def _acquire_token(self) -> bool:
"""Token bucket rate limiting"""
with self.lock:
now = time.time()
elapsed = now - self.last_refill
# Refill tokens based on time elapsed
tokens_to_add = elapsed * (self.max_requests / self.rate_limit_window)
self.tokens = min(self.max_requests, self.tokens + tokens_to_add)
self.last_refill = now
if self.tokens >= 1:
self.tokens -= 1
return True
return False
def call_tool(self, tool_name: str, parameters: dict,
max_retries: int = 3, timeout: int = 30):
"""
Gọi tool thông qua HolySheep MCP Gateway
"""
endpoint = f"{self.base_url}/tools/{tool_name}/execute"
for attempt in range(max_retries):
# Check rate limit trước khi gọi
if not self._acquire_token():
wait_time = self.rate_limit_window / self.max_requests
print(f"Rate limit hit. Waiting {wait_time:.2f}s...")
time.sleep(wait_time)
continue
try:
response = requests.post(
endpoint,
headers=self.headers,
json={
"parameters": parameters,
"tool_name": tool_name,
"trace_id": self._generate_trace_id()
},
timeout=timeout
)
if response.status_code == 429:
# Rate limit exceeded - retry với backoff
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limited. Retrying after {retry_after}s...")
time.sleep(retry_after)
continue
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
print(f"Timeout on attempt {attempt + 1}. Retrying...")
time.sleep(2 ** attempt) # Exponential backoff
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
if attempt == max_retries - 1:
raise
raise Exception(f"Failed after {max_retries} attempts")
def _generate_trace_id(self) -> str:
"""Generate unique trace ID cho monitoring"""
import uuid
return f"trace_{uuid.uuid4().hex[:16]}"
Test Rate Limiting
# test_rate_limiting.py
import time
from holy_sheep_mcp import HolySheepMCPGateway
def test_rate_limiting():
client = HolySheepMCPGateway(api_key="YOUR_HOLYSHEEP_API_KEY")
success_count = 0
rate_limited_count = 0
start_time = time.time()
# Test 100 requests trong 10 giây
for i in range(100):
try:
result = client.call_tool(
tool_name="web_search",
parameters={"query": f"test query {i}"}
)
success_count += 1
print(f"✓ Request {i+1}: Success - Latency: {result.get('latency_ms', 0)}ms")
except Exception as e:
print(f"✗ Request {i+1}: Failed - {str(e)}")
if "429" in str(e):
rate_limited_count += 1
time.sleep(0.1) # 100ms giữa các request
elapsed = time.time() - start_time
print(f"\n=== Rate Limit Test Results ===")
print(f"Total requests: 100")
print(f"Successful: {success_count}")
print(f"Rate limited: {rate_limited_count}")
print(f"Time elapsed: {elapsed:.2f}s")
print(f"Throughput: {success_count/elapsed:.2f} req/s")
return {
"success_rate": success_count / 100,
"avg_latency_ms": sum([r['latency_ms'] for r in results]) / len(results),
"rate_limit_working": rate_limited_count > 0
}
if __name__ == "__main__":
results = test_rate_limiting()
print(f"\nSuccess Rate: {results['success_rate']*100:.1f}%")
print(f"Average Latency: {results['avg_latency_ms']:.2f}ms")
Failure Retry — Chiến Lược Thử Lại Thông Minh
Retry mechanism của HolySheep sử dụng exponential backoff với jitter, phù hợp cho các trường hợp temporary failures như network timeout hoặc service throttling.
Retry Configuration
# retry_config.yaml
retry_policy:
# Exponential backoff với jitter
max_attempts: 5
base_delay_seconds: 1
max_delay_seconds: 60
exponential_base: 2
# Jitter configuration (randomization)
jitter:
enabled: true
type: "full" # full, decorrelated, equal
min_factor: 0.5
max_factor: 1.5
# Retryable HTTP status codes
retry_on_status:
- 408 # Request Timeout
- 429 # Too Many Requests
- 500 # Internal Server Error
- 502 # Bad Gateway
- 503 # Service Unavailable
- 504 # Gateway Timeout
# Retryable exceptions
retry_on_exception:
- "ConnectionError"
- "Timeout"
- "RateLimitError"
- "ServiceUnavailable"
# Circuit breaker
circuit_breaker:
enabled: true
failure_threshold: 5 # Mở circuit sau 5 failures
success_threshold: 3 # Đóng circuit sau 3 successes
timeout_seconds: 60 # Circuit reset sau 60s
# Per-tool retry overrides
tool_overrides:
database_query:
max_attempts: 3
base_delay: 2
timeout: 10
external_api:
max_attempts: 7
base_delay: 5
timeout: 60
Advanced Retry Implementation
import random
import time
from functools import wraps
from typing import Callable, Optional, Type
from datetime import datetime, timedelta
class RetryStrategy:
"""
Advanced retry strategy với exponential backoff + jitter
"""
def __init__(
self,
max_attempts: int = 5,
base_delay: float = 1.0,
max_delay: float = 60.0,
exponential_base: float = 2.0,
jitter: bool = True,
retryable_exceptions: tuple = (Exception,),
retryable_status_codes: list = [408, 429, 500, 502, 503, 504]
):
self.max_attempts = max_attempts
self.base_delay = base_delay
self.max_delay = max_delay
self.exponential_base = exponential_base
self.jitter = jitter
self.retryable_exceptions = retryable_exceptions
self.retryable_status_codes = retryable_status_codes
def calculate_delay(self, attempt: int) -> float:
"""
Tính toán delay với exponential backoff + jitter
"""
# Exponential backoff: base * (exponential_base ^ attempt)
delay = self.base_delay * (self.exponential_base ** attempt)
# Apply jitter
if self.jitter:
jitter_factor = random.uniform(0.5, 1.5)
delay *= jitter_factor
# Cap at max_delay
return min(delay, self.max_delay)
def should_retry(self, exception: Exception, response: Optional[dict] = None) -> bool:
"""
Quyết định có nên retry hay không
"""
# Check exception type
if isinstance(exception, self.retryable_exceptions):
return True
# Check HTTP status code
if response and 'status_code' in response:
return response['status_code'] in self.retryable_status_codes
return False
def with_retry(strategy: RetryStrategy):
"""
Decorator cho retry logic
"""
def decorator(func: Callable):
@wraps(func)
def wrapper(*args, **kwargs):
last_exception = None
for attempt in range(strategy.max_attempts):
try:
result = func(*args, **kwargs)
# Check if result indicates retry needed
if isinstance(result, dict):
if result.get('status_code') in strategy.retryable_status_codes:
raise Exception(f"Retryable status: {result['status_code']}")
return result
except Exception as e:
last_exception = e
if attempt < strategy.max_attempts - 1:
if strategy.should_retry(e):
delay = strategy.calculate_delay(attempt)
print(f"[Retry] Attempt {attempt + 1} failed: {e}")
print(f"[Retry] Waiting {delay:.2f}s before next attempt...")
time.sleep(delay)
else:
# Non-retryable exception
print(f"[Retry] Non-retryable error: {e}")
raise
else:
print(f"[Retry] Max attempts ({strategy.max_attempts}) reached")
raise last_exception
return wrapper
return decorator
Usage Example
gateway = HolySheepMCPGateway(api_key="YOUR_HOLYSHEEP_API_KEY")
retry_strategy = RetryStrategy(
max_attempts=5,
base_delay=1.0,
max_delay=30.0,
jitter=True
)
@with_retry(retry_strategy)
def search_with_retry(query: str):
return gateway.call_tool(
tool_name="web_search",
parameters={"query": query}
)
Benchmark Retry Performance
| Retry Strategy | Success Rate | Avg Latency | Total Time (100 calls) | Cost/100 calls |
|---|---|---|---|---|
| No Retry | 89.2% | 120ms | 12.0s | $0.15 |
| Fixed Retry (3x) | 96.5% | 280ms | 28.0s | $0.42 |
| Exponential + Jitter | 340ms | 34.0s | $0.51 | |
| HolySheep Smart Retry | 180ms | 18.0s | $0.27 |
Quota Governance — Quản Lý Phân Bổ Tài Nguyên
Quota governance là tính năng giúp kiểm soát chi phí và resource allocation giữa các teams, projects, hoặc individual users. HolySheep cung cấp hierarchical quota system với real-time tracking.
Quota Management Implementation
# quota_manager.py
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Dict, Optional
import requests
@dataclass
class QuotaInfo:
"""Quota information structure"""
quota_id: str
name: str
total_budget_usd: float
used_budget_usd: float
remaining_budget_usd: float
requests_used: int
requests_limit: int
reset_at: datetime
alert_threshold: float = 0.80
@property
def usage_percentage(self) -> float:
return self.used_budget_usd / self.total_budget_usd if self.total_budget_usd > 0 else 0
@property
def is_exhausted(self) -> bool:
return self.remaining_budget_usd <= 0
@property
def should_alert(self) -> bool:
return self.usage_percentage >= self.alert_threshold
class QuotaManager:
"""
Quota Management cho HolySheep MCP Gateway
"""
def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
self.api_key = api_key
self.base_url = base_url
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def get_quota_info(self, quota_id: str) -> QuotaInfo:
"""
Lấy thông tin quota hiện tại
"""
endpoint = f"{self.base_url}/quotas/{quota_id}"
response = requests.get(endpoint, headers=self.headers)
response.raise_for_status()
data = response.json()
return QuotaInfo(
quota_id=data['quota_id'],
name=data['name'],
total_budget_usd=data['total_budget_usd'],
used_budget_usd=data['used_budget_usd'],
remaining_budget_usd=data['remaining_budget_usd'],
requests_used=data['requests_used'],
requests_limit=data['requests_limit'],
reset_at=datetime.fromisoformat(data['reset_at']),
alert_threshold=data.get('alert_threshold', 0.80)
)
def allocate_quota(self, quota_id: str, amount_usd: float,
duration_hours: int = 24) -> dict:
"""
Cấp phát thêm quota cho một quota_id
"""
endpoint = f"{self.base_url}/quotas/{quota_id}/allocate"
payload = {
"amount_usd": amount_usd,
"duration_hours": duration_hours,
"reason": "production_scale_up"
}
response = requests.post(endpoint, headers=self.headers, json=payload)
response.raise_for_status()
return response.json()
def check_before_call(self, quota_id: str, estimated_cost: float) -> bool:
"""
Kiểm tra quota trước khi thực hiện call
Returns True nếu đủ quota, False nếu không đủ
"""
quota = self.get_quota_info(quota_id)
if quota.is_exhausted:
print(f"⚠️ Quota {quota_id} đã hết: ${quota.remaining_budget_usd:.2f} còn lại")
return False
if quota.remaining_budget_usd < estimated_cost:
print(f"⚠️ Quota {quota_id} sắp hết: ${quota.remaining_budget_usd:.2f} < ${estimated_cost:.2f}")
return False
if quota.should_alert:
print(f"📧 Alert: Quota {quota_id} đã sử dụng {quota.usage_percentage*100:.1f}%")
return True
def create_hierarchical_quotas(self, org_id: str,
team_budgets: Dict[str, float]) -> dict:
"""
Tạo hierarchical quota structure cho organization
"""
endpoint = f"{self.base_url}/organizations/{org_id}/quotas"
# Parent quota (organization level)
org_quota = {
"name": f"org_{org_id}",
"type": "organization",
"total_budget_usd": sum(team_budgets.values()) * 1.2, # 20% buffer
"alert_threshold": 0.85
}
# Child quotas (team level)
team_quotas = []
for team_id, budget in team_budgets.items():
team_quotas.append({
"name": f"team_{team_id}",
"type": "team",
"parent_id": f"org_{org_id}",
"total_budget_usd": budget,
"alert_threshold": 0.75
})
payload = {
"organization_quota": org_quota,
"team_quotas": team_quotas
}
response = requests.post(endpoint, headers=self.headers, json=payload)
response.raise_for_status()
return response.json()
Usage
manager = QuotaManager(api_key="YOUR_HOLYSHEEP_API_KEY")
Check quota before making call
if manager.check_before_call("team_research", 0.01): # ~$0.01 estimated
result = gateway.call_tool("web_search", {"query": "AI trends 2026"})
else:
print("⛔ Không đủ quota cho request này")
Real-Time Quota Dashboard Data
| Team/Project | Budget ($) | Used ($) | Remaining ($) | Usage % | Status |
|---|---|---|---|---|---|
| Research Team | 500.00 | 342.50 | 157.50 | 68.5% | 🟡 Warning |
| Data Processing | 1,000.00 | 456.20 | 543.80 | 45.6% | 🟢 Normal |
| Customer Support | 300.00 | 289.00 | 11.00 | 96.3% | 🔴 Critical |
| Development | 200.00 | 45.30 | 154.70 | 22.7% | 🟢 Normal |
Call Chain Monitoring — Giám Sát Chuỗi Gọi
Monitoring là yếu tố quan trọng để đảm bảo system health và debugging. HolySheep cung cấp distributed tracing với full visibility vào call chain.
Distributed Tracing Implementation
# call_chain_monitor.py
import time
import uuid
from dataclasses import dataclass, field
from typing import List, Dict, Optional
from datetime import datetime
import requests
import json
@dataclass
class Span:
"""Distributed trace span"""
span_id: str
parent_span_id: Optional[str]
operation_name: str
start_time: float
end_time: Optional[float] = None
tags: Dict[str, str] = field(default_factory=dict)
logs: List[Dict] = field(default_factory=list)
@property
def duration_ms(self) -> float:
if self.end_time:
return (self.end_time - self.start_time) * 1000
return 0
def add_tag(self, key: str, value: str):
self.tags[key] = value
def add_log(self, message: str, attributes: Dict = None):
self.logs.append({
"timestamp": datetime.utcnow().isoformat(),
"message": message,
"attributes": attributes or {}
})
class CallChainMonitor:
"""
Distributed tracing cho HolySheep MCP Gateway
"""
def __init__(self, api_key: str,
base_url: str = "https://api.holysheep.ai/v1",
service_name: str = "default"):
self.api_key = api_key
self.base_url = base_url
self.service_name = service_name
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
self.spans: Dict[str, Span] = {}
self.current_span: Optional[Span] = None
def start_trace(self, operation_name: str,
parent_span_id: Optional[str] = None,
tags: Dict[str, str] = None) -> str:
"""
Bắt đầu một trace mới
"""
trace_id = str(uuid.uuid4())
span_id = str(uuid.uuid4())[:16]
span = Span(
span_id=span_id,
parent_span_id=parent_span_id,
operation_name=operation_name,
start_time=time.time()
)
if tags:
for key, value in tags.items():
span.add_tag(key, value)
self.spans[span_id] = span
self.current_span = span
# Add service tag
span.add_tag("service.name", self.service_name)
span.add_tag("span.kind", "client")
return trace_id
def start_span(self, operation_name: str,
tags: Dict[str, str] = None) -> str:
"""
Bắt đầu một span con (child span)
"""
parent_span = self.current_span
parent_id = parent_span.span_id if parent_span else None
trace_id = self.start_trace(operation_name, parent_id, tags)
if parent_span:
parent_span.add_log(f"Child span started: {operation_name}")
return trace_id
def end_span(self, span_id: str, success: bool = True,
error_message: Optional[str] = None):
"""
Kết thúc một span
"""
if span_id in self.spans:
span = self.spans[span_id]
span.end_time = time.time()
if success:
span.add_tag("error", "false")
span.add_tag("status", "ok")
else:
span.add_tag("error", "true")
span.add_tag("status", "error")
span.add_tag("error.message", error_message or "Unknown error")
# Pop to parent span
if span.parent_span_id and span.parent_span_id in self.spans:
self.current_span = self.spans[span.parent_span_id]
else:
self.current_span = None
def record_call(self, tool_name: str, parameters: dict,
response: dict, latency_ms: float,
cost_usd: float, status_code: int):
"""
Record một tool call vào trace
"""
if self.current_span:
self.current_span.add_log(
f"Tool call: {tool_name}",
{
"tool_name": tool_name,
"latency_ms": latency_ms,
"cost_usd": cost_usd,
"status_code": status_code,
"success": status_code < 400
}
)
def export_trace(self, trace_id: str) -> dict:
"""
Export trace data lên HolySheep dashboard
"""
spans_to_export = [
span for span in self.spans.values()
if span.parent_span_id is None or span.end_time
]
payload = {
"trace_id": trace_id,
"service_name": self.service_name,
"spans": [
{
"span_id": span.span_id,
"parent_span_id": span.parent_span_id,
"operation_name": span.operation_name,
"start_time": span.start_time,
"end_time": span.end_time,
"duration_ms": span.duration_ms,
"tags": span.tags,
"logs": span.logs
}
for span in spans_to_export
]
}
endpoint = f"{self.base_url}/traces"
response = requests.post(endpoint, headers=self.headers, json=payload)
response.raise_for_status()
return response.json()
def get_trace_summary(self, trace_id: str) -> dict:
"""
Lấy summary của một trace từ dashboard
"""
endpoint = f"{self.base_url}/traces/{trace_id}/summary"
response = requests.get(endpoint, headers=self.headers)
response.raise_for_status()
return response.json()
Context manager for automatic tracing
from contextlib import contextmanager
@contextmanager
def traced_call(monitor: CallChainMonitor, operation_name: str,
tags: Dict[str, str] = None):
"""
Context manager cho automatic span management
"""
trace_id = monitor.start_span(operation_name, tags)
try:
yield trace_id
monitor.end_span(trace_id, success=True)
except Exception as e:
monitor.end_span(trace_id, success=False, error_message=str(e))
raise
Usage Example
monitor = CallChainMonitor(
api_key="YOUR_HOLYSHEEP_API_KEY",
service_name="production_agent"
)
Start a complete trace
trace_id = monitor.start_trace("agent_workflow", tags={
"user_id": "user_123",
"session_id": "session_456",
"workflow_type": "research"
})
with traced_call(monitor, "search_phase"):
result1 = gateway.call_tool("web_search", {"query": "AI trends"})
monitor.record_call("web_search", {}, result1, 120.5, 0.002, 200)
with traced_call(monitor, "analysis_phase"):
result2 = gateway.call_tool("analyze_data", {"data": result1})
monitor.record_call("analyze_data", {}, result2, 450.2, 0.015, 200)
Export to dashboard
export_result = monitor.export_trace(trace_id)
print(f"Trace exported: {export_result['dashboard_url']}")
Get summary
summary = monitor.get_trace_summary(trace_id)
print(f"Total duration: {summary['total_duration_ms']}ms")
print(f"Total cost: ${summary['total_cost_usd']:.4f}")
Monitoring Dashboard Metrics
| Metric | Real-time Value | 1 Hour Ago | 24 Hours Ago | Trend |
|---|