https://github.com/nytroxdev/veltix
The networking library you always wanted
https://github.com/nytroxdev/veltix
networking protocol python tcp zero-dependencies
Last synced: 3 months ago
JSON representation
The networking library you always wanted
- Host: GitHub
- URL: https://github.com/nytroxdev/veltix
- Owner: NytroxDev
- License: mit
- Created: 2026-02-06T08:46:17.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-02-07T23:28:11.000Z (4 months ago)
- Last Synced: 2026-02-08T04:57:39.543Z (4 months ago)
- Topics: networking, protocol, python, tcp, zero-dependencies
- Language: Python
- Homepage:
- Size: 51.8 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# Veltix
A modern, lightweight TCP networking library for Python — simple enough for beginners, solid enough for production.
[](https://pypi.org/project/veltix/)
[](https://pypi.org/project/veltix/)
[](https://github.com/NytroxDev/Veltix/blob/main/LICENSE)
[](https://pepy.tech/projects/veltix)
[](SECURITY.md)
Veltix provides a clean abstraction layer over TCP sockets, handling the low-level complexity so you can focus on your
application logic. It ships with message integrity verification, a structured binary protocol, request/response
correlation, automatic connection handshake, decorator-based message routing, auto-reconnect, and production-ready
logging — all with zero external dependencies.
**Performance highlights:** 55k+ msg/s throughput • 0.011ms average latency • 84KB idle memory • 100% success rate
---
## Table of Contents
- [Why Veltix](#why-veltix)
- [Features](#features)
- [Performance](#performance)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Integrated Logger](#integrated-logger)
- [Request/Response Pattern](#requestresponse-pattern)
- [Built-in Ping/Pong](#built-in-pingpong)
- [Advanced Features](#advanced-features)
- [Comparison](#comparison)
- [Roadmap](#roadmap)
- [Migration Guide](#migration-guide)
- [Examples](#examples)
- [Security](#security)
- [Contributing](#contributing)
- [License](#license)
---
## Why Veltix
Working directly with Python's `socket` module or `asyncio` forces you to manage framing, concurrency, error handling,
and protocol design from scratch. Heavier frameworks like Twisted introduce steep learning curves and large dependency
trees.
Veltix sits in between: a focused library that handles the hard parts — connection management, message integrity,
threading, handshake, routing, and request correlation — while keeping the API surface small and the codebase readable.
**Designed for:**
- Developers who want structured TCP communication without dealing with `asyncio` internals
- Teams that need a maintainable, dependency-free networking layer in production
- Real-time applications and simulations
- Rapid prototyping of client/server applications
- Custom protocol experimentation
---
## Features
- **Simple API** — Get a working client/server in under 30 lines
- **High Performance** — 55k+ messages/second, 0.011ms latency
- **Message integrity** — Built-in SHA-256 payload verification
- **Custom binary protocol** — Lightweight framing with TCP stream handling
- **Zero dependencies** — Pure Python standard library only
- **Multi-threaded** — Concurrent client handling out of the box
- **Automatic handshake** — HELLO/HELLO_ACK with version compatibility check on every connection
- **Thread-safe callbacks** — All callbacks run in a thread pool, slow handlers never block reception
- **Message routing** — `@server.route(MY_TYPE)` / `@client.route(MY_TYPE)` decorators for per-type handlers
- **Auto-reconnect** — Configurable retry with `DisconnectState` callbacks
- **Request/Response pattern** — `send_and_wait()` with configurable timeout
- **Built-in ping/pong** — Bidirectional latency measurement
- **Integrated logger** — Colorized, file-rotating, thread-safe logging
- **Performance modes** — `LOW` / `BALANCED` / `HIGH` presets for CPU/reactivity trade-off
- **Socket abstraction** — Swappable socket backends via `SocketCore` (Threading now, Selectors and Rust coming)
- **Client tags** — Attach arbitrary metadata to connected clients
- **Extensible** — Custom message types and event callbacks
- **Defensive design** — Strict validation and controlled failure handling
---
## Performance
> Benchmarked on Python 3.14.3 — 12-core CPU, 30.5 GB RAM, Linux. All tests run locally (loopback).
```
┌─────────────────────────────────────────────────────────────────────┐
│ VELTIX PERFORMANCE RESULTS │
├─────────────────────┬───────────────────────────────────────────────┤
│ MEMORY │ │
│ Idle server │ 84 KB │
│ Per client │ 78 KB │
│ 50 clients total │ 28.89 MB │
├─────────────────────┼───────────────────────────────────────────────┤
│ LATENCY (local) │ │
│ Average │ 0.011 ms │
│ P95 │ 0.000 ms │
│ P99 │ 1.000 ms │
│ Max │ 1.000 ms │
├─────────────────────┼───────────────────────────────────────────────┤
│ FPS SIMULATION │ │
│ 64 players @64Hz │ 4,490 msg/s – 100% success │
│ 128 players @20Hz │ 2,813 msg/s – 100% success │
├─────────────────────┼───────────────────────────────────────────────┤
│ BURST THROUGHPUT │ │
│ Send │ 55,606 msg/s │
│ Receive │ 43,497 msg/s │
│ Data │ 2.65 MB/s │
├─────────────────────┼───────────────────────────────────────────────┤
│ CONCURRENT STRESS │ │
│ 100 clients │ 33,482 msg/s – 100% success │
└─────────────────────┴───────────────────────────────────────────────┘
```
**Ping/Pong** — 2,000 iterations, 100% success rate, 23,181 ping/s throughput.
**FPS simulation** — Veltix sustains a full 64-player game server at 64 tick/s and a 128-player server at 20 tick/s with
zero message loss.
**Burst throughput** — 10,000 × 64-byte messages processed in 0.230s.
**Concurrent stress** — 100 simultaneous clients each firing 100 messages; all 10,000 delivered with 100% success in
0.299s.
To run the benchmark suite yourself:
```bash
python benchmark.py
# Save results to JSON for sharing
python benchmark.py --save results.json
```
---
## Installation
```bash
pip install veltix
```
**Requirements:** Python 3.10+, no additional dependencies.
---
## Quick Start
The following example implements a basic echo server and client.
**Server (`server.py`):**
```python
from veltix import Server, ClientInfo, ServerConfig, Response, MessageType, Request, Events
CHAT = MessageType(code=200, name="chat")
config = ServerConfig(host="0.0.0.0", port=8080)
server = Server(config)
sender = server.get_sender()
def on_message(client: ClientInfo, response: Response):
print(f"[{client.addr[0]}] {response.content.decode()}")
reply = Request(CHAT, f"Echo: {response.content.decode()}".encode())
sender.broadcast(reply, server.get_all_clients_sockets())
server.set_callback(Events.ON_RECV, on_message)
server.start()
input("Press Enter to stop...")
server.close_all()
```
**Client (`client.py`):**
```python
from veltix import Client, Response, ClientConfig, MessageType, Request, Events
CHAT = MessageType(code=200, name="chat")
config = ClientConfig(server_addr="127.0.0.1", port=8080)
client = Client(config)
sender = client.get_sender()
def on_message(response: Response):
print(f"Server: {response.content.decode()}")
client.set_callback(Events.ON_RECV, on_message)
client.connect() # Blocks until handshake is complete — safe to send immediately
msg = Request(CHAT, b"Hello Server!")
sender.send(msg)
input("Press Enter to disconnect...")
client.disconnect()
```
```bash
python server.py
python client.py # In a separate terminal
```
---
## Integrated Logger
Veltix includes a production-ready logging system with colorized output, automatic file rotation, and thread safety. It
follows a singleton pattern so the same instance is shared across your application.
### Basic Usage
```python
from veltix import Logger, LogLevel
logger = Logger.get_instance()
logger.trace("Detailed trace information")
logger.debug("Debug information")
logger.info("General information")
logger.success("Operation successful")
logger.warning("Warning message")
logger.error("Error occurred")
logger.critical("Critical failure")
```
### Configuration
```python
from veltix import Logger, LoggerConfig, LogLevel
from pathlib import Path
config = LoggerConfig(
level=LogLevel.DEBUG,
enabled=True,
use_colors=True,
show_timestamp=True,
show_caller=True,
show_level=True,
file_path=Path("logs/veltix.log"),
file_rotation_size=10 * 1024 * 1024, # 10 MB
file_backup_count=5,
async_write=False,
buffer_size=100,
)
logger = Logger.get_instance(config)
```
### Output Format
```
[14:23:45.123] INFO [server.py:45] Server listening on 0.0.0.0:8080
[14:23:46.456] OK [client.py:78] Successfully connected to server
[14:23:47.789] DEBUG [sender.py:92] Sent 156 bytes via client (request_id: a3f2...)
[14:23:48.012] WARN [network.py:34] Connection issue: ConnectionResetError
[14:23:49.345] ERROR [request.py:89] Parse error: Hash mismatch — corrupted data
```
### Available Log Levels
| Level | Severity |
|------------|----------|
| `TRACE` | 5 |
| `DEBUG` | 10 |
| `INFO` | 20 |
| `SUCCESS` | 25 |
| `WARNING` | 30 |
| `ERROR` | 40 |
| `CRITICAL` | 50 |
```python
# Change level at runtime
logger.set_level(LogLevel.WARNING)
```
---
## Request/Response Pattern
`send_and_wait()` enables synchronous request/response communication over TCP. The client blocks until the server
replies with a matching `request_id`, or the timeout elapses.
**Client:**
```python
from veltix import Client, ClientConfig, MessageType, Request
ECHO = MessageType(code=201, name="echo")
client = Client(ClientConfig(server_addr="127.0.0.1", port=8080))
client.connect()
request = Request(ECHO, b"Hello Server!")
response = client.send_and_wait(request, timeout=5.0)
if response:
print(f"Response: {response.content.decode()}")
print(f"Latency: {response.latency}ms")
else:
print("Request timed out")
client.disconnect()
```
**Server:**
```python
from veltix import Server, ServerConfig, MessageType, Request, Events
ECHO = MessageType(code=201, name="echo")
server = Server(ServerConfig(host="0.0.0.0", port=8080))
def on_message(client, response):
reply = Request(response.type, response.content, request_id=response.request_id)
server.get_sender().send(reply, client=client.conn)
server.set_callback(Events.ON_RECV, on_message)
server.start()
input("Press Enter to stop...")
server.close_all()
```
---
## Built-in Ping/Pong
Veltix handles PING/PONG internally. No manual implementation required.
**Client pinging the server:**
```python
from veltix import Client, ClientConfig
client = Client(ClientConfig(server_addr="127.0.0.1", port=8080))
client.connect()
latency = client.ping_server(timeout=2.0)
print(f"Latency: {latency}ms" if latency else "Ping timed out")
client.disconnect()
```
**Server pinging a client:**
```python
from veltix import Server, ServerConfig, Events
server = Server(ServerConfig(host="0.0.0.0", port=8080))
def on_connect(client):
latency = server.ping_client(client, timeout=2.0)
if latency:
print(f"Client {client.addr} latency: {latency}ms")
server.set_callback(Events.ON_CONNECT, on_connect)
server.start()
input("Press Enter to stop...")
server.close_all()
```
---
## Advanced Features
### Message Routing
Use `@server.route()` and `@client.route()` to handle specific message types directly, without a global `on_recv`.
Routes take priority over `on_recv` and run in the thread pool.
```python
from veltix import Server, ServerConfig, MessageType, Response
from veltix.server.client_info import ClientInfo
CHAT = MessageType(code=200, name="chat")
STATUS = MessageType(code=201, name="status")
server = Server(ServerConfig(host="0.0.0.0", port=8080))
@server.route(CHAT)
def on_chat(response: Response, client: ClientInfo):
print(f"[{client.addr[0]}] {response.content.decode()}")
@server.route(STATUS)
def on_status(response: Response, client: ClientInfo):
print(f"Status from {client.addr[0]}: {response.content.decode()}")
server.start()
```
```python
from veltix import Client, ClientConfig, MessageType, Response
CHAT = MessageType(code=200, name="chat")
client = Client(ClientConfig(server_addr="127.0.0.1", port=8080))
@client.route(CHAT)
def on_chat(response: Response, client=None):
print(f"Server: {response.content.decode()}")
client.connect()
```
Routes can also be registered programmatically:
```python
server.request_handler.register_route(CHAT, on_chat)
server.request_handler.unregister_route(CHAT)
```
### Client Tags
Attach arbitrary metadata to connected clients for tracking, filtering, or access control.
```python
from veltix import Server, ServerConfig, ClientInfo, Events
server = Server(ServerConfig(host="0.0.0.0", port=8080))
def on_connect(client: ClientInfo):
client.add_tag("guest")
def on_message(client: ClientInfo, response):
if client.has_tag("guest"):
# Authenticate and upgrade
client.remove_tag("guest")
client.add_tag("authenticated", value="admin")
if client.has_all_tags(["authenticated", "admin"]):
print(f"Admin message from {client.addr[0]}")
server.set_callback(Events.ON_CONNECT, on_connect)
server.set_callback(Events.ON_RECV, on_message)
server.start()
```
Available tag methods on `ClientInfo`:
```python
client.add_tag("authenticated") # Add a tag (returns False if already exists)
client.add_tag("role", value="admin") # Add a tag with a value
client.has_tag("authenticated") # Check for a single tag
client.has_all_tags(["auth", "admin"]) # Check all tags are present (AND)
client.has_any_tags(["admin", "mod"]) # Check at least one tag is present (OR)
client.get_tag("role") # Retrieve a tag value
client.remove_tag("guest") # Remove a tag
client.clear_tags() # Remove all tags
```
### Socket Backend
Veltix abstracts the socket layer behind a `SocketCore` enum. The default is `THREADING` — future versions will add
`ASYNC` (selectors-based, v1.7.0) and `RUST` (Tokio via PyO3, v3.0.0).
```python
from veltix import ServerConfig, ClientConfig, SocketCore
# Default — one thread per client
server = Server(ServerConfig(host="0.0.0.0", port=8080, socket_core=SocketCore.THREADING))
# Coming in v1.7.0 — selectors-based, same API
# server = Server(ServerConfig(host="0.0.0.0", port=8080, socket_core=SocketCore.ASYNC))
```
Switching backends requires no changes to application code.
### Auto-Reconnect
Enable automatic reconnection by setting `retry` in `ClientConfig`. The `on_disconnect` callback receives a
`DisconnectState` with full context at every attempt.
```python
from veltix import Client, ClientConfig, Events
from veltix.client.client import DisconnectState
client = Client(ClientConfig(
server_addr="127.0.0.1",
port=8080,
retry=5, # number of reconnection attempts
retry_delay=1.0, # seconds between attempts
))
def on_disconnect(state: DisconnectState):
if state.permanent:
print(f"Permanently disconnected — reason: {state.reason.name}")
else:
print(f"Retrying... attempt {state.attempt}/{state.retry_max}")
client.set_callback(Events.ON_DISCONNECT, on_disconnect)
client.connect()
# Cancel retries at any time
client.stop_retry()
# Force a new attempt, optionally overriding retry_max
client.retry(max_=10)
```
### Performance Mode
```python
from veltix import ServerConfig, ClientConfig, PerformanceMode
# LOW — socket timeout 1.0s, minimal CPU
# BALANCED — socket timeout 0.5s, default
# HIGH — socket timeout 0.1s, fast disconnection detection
server = Server(ServerConfig(host="0.0.0.0", port=8080, performance_mode=PerformanceMode.HIGH))
client = Client(ClientConfig(server_addr="127.0.0.1", port=8080, performance_mode=PerformanceMode.HIGH))
```
### Buffer Size
```python
from veltix import ServerConfig, ClientConfig, BufferSize
# SMALL — 1KB (default)
# MEDIUM — 8KB
# LARGE — 64KB
# HUGE — 1MB
server = Server(ServerConfig(host="0.0.0.0", port=8080, buffer_size=BufferSize.LARGE))
```
### Custom Message Types
Message type codes are divided into ranges by convention:
```python
from veltix import MessageType
# System messages (0–199)
PING = MessageType(0, "ping", "System ping")
# Application messages (200–499)
CHAT = MessageType(200, "chat", "Chat message")
FILE_TRANSFER = MessageType(201, "file", "File transfer")
# Plugin messages (500+)
CUSTOM = MessageType(500, "plugin", "Custom plugin message")
```
### Event Callbacks
```python
from veltix import Server, Events
server = Server(config)
server.set_callback(Events.ON_CONNECT, lambda client: print(f"Connected: {client.addr}"))
server.set_callback(Events.ON_RECV, lambda client, msg: print(f"Message from {client.addr}"))
server.set_callback(Events.ON_DISCONNECT, lambda client: print(f"Disconnected: {client.addr}"))
```
### Client Callbacks
```python
from veltix import Client, ClientConfig, Events
from veltix.client.client import DisconnectState
client = Client(ClientConfig(server_addr="127.0.0.1", port=8080))
client.set_callback(Events.ON_CONNECT, lambda: print("Connected and handshake complete!"))
client.set_callback(Events.ON_RECV, lambda response: print(response.content.decode()))
client.set_callback(Events.ON_DISCONNECT, lambda state: print(f"Disconnected — permanent={state.permanent}"))
client.connect()
```
### Configuring the Thread Pool
```python
from veltix import ServerConfig, ClientConfig
# Increase workers for high-concurrency workloads with slow callbacks
server_config = ServerConfig(host="0.0.0.0", port=8080, max_workers=8)
client_config = ClientConfig(server_addr="127.0.0.1", port=8080, max_workers=8)
```
### Broadcasting
```python
# Broadcast to all connected clients
message = Request(CHAT, b"Server announcement")
sender.broadcast(message, server.get_all_clients_sockets())
# Broadcast with exclusion
sender.broadcast(message, server.get_all_clients_sockets(), except_clients=[client.conn])
```
### Utilities
```python
from veltix import format_bytes, encode_json, decode_json, encode_utf8, decode_utf8
# Human-readable byte formatting
format_bytes(148_000) # "144.5 KB"
format_bytes(3_000_000) # "2.86 MB"
# JSON helpers
data = encode_json({"key": "value"}) # bytes
obj = decode_json(data) # dict
# UTF-8 helpers
raw = encode_utf8("hello") # bytes
text = decode_utf8(raw) # str
```
---
## Comparison
| Feature | Veltix | `socket` | `asyncio` | Twisted |
|------------------------|:------:|:--------:|:---------:|:-------:|
| Simple API | ✓ | ✗ | ~ | ✗ |
| High Performance | ✓ | ~ | ✓ | ~ |
| Zero dependencies | ✓ | ✓ | ✓ | ✗ |
| Custom protocol | ✓ | ✗ | ✗ | ~ |
| Message integrity | ✓ | ✗ | ✗ | ✗ |
| Multi-threading | ✓ | ✗ | ✗ | ✓ |
| Request/Response | ✓ | ✗ | ~ | ✓ |
| Built-in ping/pong | ✓ | ✗ | ✗ | ✗ |
| Automatic handshake | ✓ | ✗ | ✗ | ✗ |
| Message routing | ✓ | ✗ | ✗ | ~ |
| Auto-reconnect | ✓ | ✗ | ~ | ✓ |
| Non-blocking callbacks | ✓ | ✗ | ✓ | ✓ |
| Integrated logger | ✓ | ✗ | ~ | ✓ |
| Client tags | ✓ | ✗ | ✗ | ✗ |
| Swappable socket core | ✓ | ✗ | ✗ | ✗ |
---
## Roadmap
### v1.4.0 — Handshake & Callbacks ✓ *(Released March 2026)*
- HELLO/HELLO_ACK handshake with version compatibility check
- Thread pool for non-blocking callback execution (`CallbackExecutor`)
- Blocking `connect()` — safe to send immediately after connecting
- `on_connect` / `on_disconnect` callbacks on Client
### v1.5.0 — Routing & Reconnect ✓ *(Released March 2026)*
- Decorator-based message routing (`@server.route(MY_TYPE)`, `@client.route(MY_TYPE)`)
- Auto-reconnect with configurable retry and `DisconnectState` callbacks
- `PerformanceMode` presets for CPU/reactivity trade-off
- `BufferSize` presets for common buffer configurations
### v1.6.0 — Socket Abstraction & Tags ✓ *(Released March 2026)*
- `BaseSocket` Protocol — universal socket interface
- `ThreadingSocket` — current implementation behind clean abstraction
- `SocketCore` enum — swappable socket backends with zero API changes
- `ClientInfo` tags — arbitrary metadata on connected clients
- `veltix.utils` — encoding helpers and `format_bytes`
- `max_connection = -1` — unlimited connections by default
- Benchmark suite with JSON export for community sharing
### v1.7.0 — Selectors *(June 2026)*
- `AsyncSocket` — selectors-based I/O, replaces one-thread-per-client
- Same API, 4–8× throughput improvement expected
- Switch via `SocketCore.ASYNC`
### v1.8.0 — Plugin System *(August 2026)*
- `VeltixBasePlugin` — extensible plugin architecture
- Permission system for plugin event access
- `server.register_plugin()` / `client.register_plugin()`
- `server.attach(TYPE, plugin, mode)` — route message types to plugins
### v2.0.0 — Encryption *(September 2026)*
- End-to-end encryption: ChaCha20 + X25519 + Ed25519
- Automatic key exchange and perfect forward secrecy
### v3.0.0 — Rust Core *(2027)*
- PyO3 bindings
- 10–100× throughput improvement
- `SocketCore.RUST`
---
## Migration Guide
### v1.5.0 → v1.6.0
No breaking changes to public API.
- `ClientInfo` now has tag methods: `add_tag()`, `has_tag()`, `has_all_tags()`, `has_any_tags()`, `get_tag()`,
`remove_tag()`, `clear_tags()`
- `ServerConfig.max_connection` default changed from `2` to `-1` (unlimited)
- New `ServerConfig` / `ClientConfig` field: `socket_core` (default: `SocketCore.THREADING`)
- `veltix.utils` now exports encoding helpers and `format_bytes`
- Benchmark suite now supports `--save results.json`
### v1.4.0 → v1.5.0
**Breaking change:** `on_disconnect` on the client now receives a `DisconnectState` argument.
```python
# Before (v1.4.0)
client.set_callback(Events.ON_DISCONNECT, lambda: print("Disconnected"))
# After (v1.5.0)
client.set_callback(Events.ON_DISCONNECT, lambda state: print(f"Disconnected — permanent={state.permanent}"))
```
New optional fields in `ClientConfig`: `retry`, `retry_delay`, `performance_mode`, `buffer_size`.
New optional fields in `ServerConfig`: `performance_mode`, `buffer_size`.
### v1.3.0 → v1.4.0
No breaking changes to public API.
- `on_connect` (server-side) now fires after the handshake is complete — `client.handshake_done` is always `True` when
it fires.
- `connect()` (client-side) now blocks until the handshake is done. It is safe to send messages immediately after it
returns.
- New `ClientConfig` fields: `handshake_timeout` (default: `5.0`), `max_workers` (default: `4`)
- New `ServerConfig` fields: `handshake_timeout` (default: `5.0`), `max_workers` (default: `4`)
### v1.2.x → v1.3.0
No breaking changes to public API.
### v1.1.x → v1.2.0
```python
# Before
from veltix import Bindings
server.bind(Bindings.ON_RECV, callback)
# After
from veltix import Events
server.set_callback(Events.ON_RECV, callback)
```
---
## Examples
Full examples are available in the [`examples/`](examples/) directory:
- **Echo Server** — `send_and_wait()` with request correlation
- **Chat Server** — Broadcast messaging in under 80 lines
- **Ping Example** — Bidirectional latency measurement
---
## Security
Message integrity is enforced via SHA-256 payload verification on every message. If you discover a vulnerability, please
report it responsibly through our [Security Policy](SECURITY.md).
---
## Contributing
Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before submitting a pull request.
- **Bug reports:** [Open an issue](https://github.com/NytroxDev/Veltix/issues)
- **Discussions:** [Join the Discord](https://discord.gg/NrEjSHtfMp)
- **Pull requests:** Follow the contribution guide
### Core Team
- **Nytrox** — Creator & Lead Developer
---
## License
MIT License — see [LICENSE](LICENSE) for details.
---
## Links
- **GitHub:** [NytroxDev/Veltix](https://github.com/NytroxDev/Veltix)
- **PyPI:** [pypi.org/project/veltix](https://pypi.org/project/veltix)
- **Documentation:** https://nytroxdev.github.io/Veltix/
- **Discord:** [discord.gg/NrEjSHtfMp](https://discord.gg/NrEjSHtfMp)