
ssh-chat بلغة C الحديثة

برنامج BBS عام
بدأ SSH-Chatter كإعادة تنفيذ بلغة C لخادم ssh-chat المكتوب بـ Go. إنه يعكس/يوسع السلوك الأصلي مع استخدام أنماط C الحديثة ونواة صغيرة قابلة للاختبار. يستمع الخادم إلى اتصالات SSH/TELNET ويضع كل مستخدم مصادق عليه في غرفة دردشة مشتركة تعرض نفس سطح الأوامر مثل التنفيذ المرجعي في Go.
هل تعلم لماذا يستغرق فهم C وقتًا طويلاً؟ لأنه غريزة.
/rss list، /rss read <tag>، بالإضافة إلى /rss add <url> <tag> و /rss del <tag> (للمشغلين فقط) حتى تتمكن الغرفة من تصفح العناوين معًا./delete-msg لتنظيف تاريخ الدردشة المستهدف./bbs يفتح نظام لوحة إعلانات قديم غامر مع علامات، تعليقات، bumping، ومحرر متعدد الأسطر.
bumped (النشاط الأخير)، hot (الرائجة حسب النقاط والتعليقات)، top (أعلى نتيجة صافية للتصويتات الإيجابية)، أو new (تاريخ الإنشاء) باستخدام list [hot|top|new|bumped|all].search <query>.▲ 12 💬 5) مباشرة في القوائم./bbs داخل وضع BBS./asciiart المباشر بحد 640 سطرًا، وفترة تبريد لمدة عشر دقائق لكل عنوان IP، وإخراج متعدد الأسطر، واختصارات لوحة المفاتيح للإلغاء بـ Ctrl+A والإرسال بـ Ctrl+S أو >/__ARTWORK_END> الافتراضي المدرك للغة المنطقة./birthday، و /grant <ip> حتى يتمكن مشغلو الشبكة المحلية من تفويض الصلاحيات حسب العنوان، و /revoke <ip> حتى يتمكن كبار مسؤولي الشبكة المحلية من استعادتها./ban التي تقبل عناوين IP الخام إلى جانب أسماء المستخدمين./weather <city> لتوقعات عالمية سريعة.


mainيتفرع فرع work بانتظام عن التطوير الرئيسي (upstream) حتى تتمكن الميزات الأكبر من التطور دون مقاطعة حركة المرور الإنتاجية. عندما يحين وقت المزامنة مع main، اسحب أحدث شجرة وادمجها محليًا قبل فتح طلب سحب (pull request):```bash
git fetch origin main
git checkout work
git merge --no-ff origin/main
حل أي تعارضات في مكانها (إجراءات المساعدة `src/host_aggregate.c` تعكس بالفعل التخطيط المستخدم في `main`، لذا عادة ما تكون عمليات الدمج مباشرة) وقم بتشغيل `make` لتأكيد نجاح البناء قبل دفع النتيجة.
## خطافات الأتمتة
- يعرض `host_snapshot_last_captcha` أحدث كابتشا تم إنشاؤها مع الطلب والإجابة بالإضافة إلى طابع زمني لتمكين العملاء الخارجيين من تمرير التحديات نيابة عن الأتمتة غير المراقبة.
## تعزيز الأمان
- يقوم `scripts/safe_permission.sh` بتشديد الملكية والصلاحيات على ملفات بيانات وقت التشغيل (حالة BBS، حالة التصويت، لقطات التبريد، وحالة الدردشة العامة). قم بتشغيله بعد النشر لحصر دليل البيانات في `ssh-chatter` وضمان تعيين كل ملف إلى `0600`. يمكن تجاوز الأهداف بتمرير مسارات صريحة أو بتصدير متغيرات البيئة `STATE_ROOT` أو `CHATTER_*_FILE` قبل التنفيذ.
- يقوم مراقب BBS خلفي بتغذية المنشورات والتعليقات بشكل دوري عبر خط أنابيب الإشراف بالذكاء الاصطناعي (Gemini أساسي مع Ollama احتياطي). يتم إزالة المنشورات المميزة تلقائيًا ويتم بث إشعار إلى الغرفة.
- تمر رسائل الدردشة وفن ASCII ومنشورات / تعليقات BBS عبر خط أنابيب الإشراف بالذكاء الاصطناعي. قم بتمكينه باستخدام `CHATTER_SECURITY_AI=on` (عين `GEMINI_API_KEY` لـ Gemini؛ يعود الخفي تلقائيًا إلى نقطة نهاية Ollama المحلية عند `http://127.0.0.1:11434`). قم بتعطيل كل شيء باستخدام `CHATTER_SECURITY_FILTER=off`. إذا فشل كل مزود، يقوم الفلتر بتعطيل نفسه تلقائيًا للحفاظ على تدفق المحادثات بدلاً من إسقاط المحتوى بصمت.
- تم تثبيت نقل SSH على تبادلات مفاتيح وتشفير و MACs حديثة، ويتم تغليف كل حمولة جسر في طبقة ثلاثية من AES-256-GCM بحيث ترى المرحلات نصًا مشفرًا فقط.
- يتم الآن تتبع الإرسالات المشبوهة التي تؤدي إلى تشغيل الفلتر متعدد الطبقات لكل IP؛ تؤدي الضربات المتكررة إلى طرد وحظر تلقائيين عند التمكين، بينما يسمح كاشف إعادة الاتصال السريع بنوافذ استرداد أطول حتى تتمكن الجلسات الشبكية غير المستقرة من الانضمام مرة أخرى دون عقاب. إدخالات الحظر التلقائي **مغلقة افتراضيًا**؛ عيّن `CHATTER_AUTO_BAN=on` (أو `true`/`1`) لتمكينها، أو اترك المتغير غير معين للإبقاء على التحذيرات والتقييد دون كتابة إدخالات حظر تلقائي.
- يمكن للمشغلين تحديد نقاط الدخول الموثوقة (مخارج VPN، عكس الوكلاء، المضيف المحلي) باستخدام `CHATTER_PROTECTED_IPS` (مفصولة بفواصل، افتراضيًا `127.0.0.1,::1,192.168.0.1`) بحيث لا تؤدي عمليات الحظر الطارئة إلى قفل الخفي خارج مستوى التحكم الخاص به.
## تخزين الملفات ونقلها
- توجد جميع ملفات المستخدم المُدارة الآن تحت `/etc/ssh-chatter/user-files` (يمكن تجاوزها بـ `CHATTER_FILESTORE_PATH`، احتياطي قديم: `CHATTER_FILE_STORAGE_ROOT`). يقوم الخفي بإنشاء الدليل إذا لزم الأمر ويبقي التحميلات محصورة فيه.
- يستخدم عملاء SSH الـ `scp` القياسي دون أي غلاف مخصص. تعامل مع `/name.ext` كجذر شجرة التخزين: يكتب `scp my.zip user@host:/demos/my.zip` إلى `/etc/ssh-chatter/user-files/demos/my.zip` بينما يقوم `scp user@host:/readme.txt ./` بتنزيل `/etc/ssh-chatter/user-files/readme.txt`.
- يستخدم عملاء TELNET أوامر `/filestore` الجديدة. يسرد `/filestore` الملفات المتاحة، ويبدأ `/filestore-upload` جلسة `rz`، ويبدأ `/filestore-download <name>` جلسة `sz`. قم بتثبيت `lrzsz` (أو أي حزمة توفر `rz`/`sz`) على الخادم حتى يتمكن الخلفية ZMODEM من تشغيل هذه المساعدات.
- يقبل `/filestore-upload` وجهة اختيارية (على سبيل المثال `/filestore-upload /kitten/meow.png`). يقوم SSH-Chatter بإنشاء الدليل `/kitten` تلقائيًا ويضع الملف المرفوع هناك، مما يعكس كيفية استخدام SCP للمسارات مثل `user@host:/kitten/meow.png`.
- يمكن لكلا النقلين المزج والمطابقة: SSH لنقل النصوص البرمجية غير المراقب، TELNET لعملاء BBS الحنينين بأدوات ZMODEM المدمجة.
## مرحل مورس
يدعم SSH-Chatter مرحل راديو الهواة.
يعرض هذا إشارات مورس العالمية.
`/morse on` لرؤيتها، `/morse-reply` للإرسال.
### تفاصيل البروتوكول
يتبع التنفيذ مواصفات بروتوكول Binkp:
- هيكل إطار Binkp قياسي مع رؤوس بحجم 2 بايت
- مصادقة كلمة مرور الجلسة (CMD\_PWD/CMD\_OK)
- آلية البقاء على قيد الحياة (CMD\_NUL) كل 60 ثانية
- أمر CHAT مخصص (CMD\_CHAT، امتداد) لمزامنة الرسائل
## المتطلبات الأساسية
يتطلب بناء المشروع بيئة POSIX مع:
- مترجم متوافق مع C23 (مثل `gcc` أو `clang`)
- `make`
- رؤوس التطوير ومكتبة `libssh` (`libssh-dev` على Debian/Ubuntu)
- رؤوس التطوير ومكتبة `libcurl` (`libcurl4-openssl-dev` على Debian/Ubuntu)
- رؤوس التطوير ومكتبة `uchardet` (`libuchardet-dev` على Debian/Ubuntu)
- رؤوس التطوير ومكتبة `icu` (المكونات الدولية لـ Unicode) (`libicu-dev` على Debian/Ubuntu)
- مكتبة ضغط `lz4` ورؤوس التطوير (`liblz4-dev` على Debian/Ubuntu)
- خيوط POSIX (عادةً ما يوفرها النظام `libpthread`)
- `python3-pygments` (يوفر أداة التظليل `pygmentize` لشاشة تمويه Tetris)
على Debian/Ubuntu يمكن تثبيت التبعيات باستخدام:```bash
sudo apt-get update
sudo apt-get install build-essential libssh-dev libcurl4-openssl-dev libuchardet-dev libicu-dev liblz4-dev
استنسخ المستودع واستخدم ملف Makefile المقدم:```bash
make
يؤدي هذا إلى إنشاء ثنائي `ssh-chatter` في جذر المستودع وكائن مشترك `libssh_chatter_backend.so` يكشف عن مساعدات الترجمة لإعادة الاستخدام في التطبيقات الأخرى. نظف القطع الأثرية الوسيطة باستخدام `make clean`.
### استخدام الواجهة الخلفية للترجمة المشتركة
الكائن المشترك يعيد استخدام خط أنابيب الترجمة بلغة C للخادم (بما في ذلك الحفاظ على العناصر النائبة لـ ANSI) حتى تتمكن العمليات الأخرى من الحصول على الترجمات دون تشغيل مضيف SSH بالكامل. اربط مع `libssh_chatter_backend.so` وقم بتضمين `include/ssh_chatter/ssh_chatter_backend.h`:```c
#include "ssh_chatter/ssh_chatter_backend.h"
int main(void) {
char translated[4096];
char detected[64];
if (ssh_chatter_backend_translate_line("Hello, world!", "ko", translated, sizeof(translated), detected, sizeof(detected))) {
printf("Detected %s -> %s\n", detected, translated);
}
}
اضبط GEMINI_API_KEY (واختيارياً GEMINI_API_BASE أو GEMINI_MODEL) في البيئة ليتمكن المساعد من الوصول إلى Google Generative Language API، وذلك لعكس متطلبات وقت التشغيل للبرنامج الخلفي الرئيسي. يمكنك تشغيل ./scripts/test_gemini_connection.sh قبل بدء تشغيل خادم الدردشة للتحقق من أن بيانات الاعتماد تسمح بإجراء المكالمات الصادرة؛ يطبع النص البرمجي استجابة Gemini الخام حتى تتمكن من رؤية ما إذا كان الطلب ناجحاً.
الخادم يستمع افتراضياً على 0.0.0.0:2222. يمكنك تعديل معاملات وقت التشغيل باستخدام العلامات المتاحة:```
Usage: ./ssh-chatter [-a address] [-p port] [-m motd_file] [-k host_key_dir] [-T telnet_port|off] [-J json_port|off]
./ssh-chatter [-h]
./ssh-chatter [-V]
عند توفيره، يقرأ `-m` رسالة اليوم من مسار الملف المحدد.
أمثلة شائعة:```bash
# Start the chat server on port 2022, loading host keys from /etc/ssh
./ssh-chatter -p 2022 -k /etc/ssh
# Enable telnet access on 0.0.0.0:4242 alongside SSH
./ssh-chatter -T 0.0.0.0:4242
# Serve a custom MOTD from a file and bind to localhost
./ssh-chatter -a 127.0.0.1 -m /etc/ssh-chatter/motd
يجب أن يحتوي دليل مفتاح المضيف على ملف ssh_host_rsa_key (و.pub اختياري). قم بإنشاء واحد باستخدام ssh-keygen -t rsa -b 4096 -f /path/to/dir/ssh_host_rsa_key إذا كنت لا ترغب في إعادة استخدام مفاتيح مضيف SSH الخاصة بنظامك. يتم تحميل مفاتيح المضيف الإضافية المسماة ssh_host_ed25519_key و ssh_host_ecdsa_key تلقائيًا عند وجودها حتى يتمكن الخادم من تقديم خوارزميات حديثة أثناء تبادل المفاتيح.
بمجرد التشغيل، قم بالاتصال باستخدام أي عميل SSH:```bash ssh -p 2222 user@server-address
الخادم العام متاح على `bbs.chatter.pw` على منفذ SSH الافتراضي:```bash
ssh -p 2222 [email protected]
أسماء المستخدمين المقدمة في موجه SSH تُستخدم كلقب للدردشة.
يمكن لعملاء Telnet الانضمام بنفس مجموعة الميزات. تم تمكين الاستماع عبر Telnet افتراضيًا على المنفذ 2323 ويمكن تعديله أو تعطيله باستخدام العلم -T. قدّم -T address:port لتجاوز عنوان الربط (يرث ربط SSH عند الحذف؛ استخدم مضيفًا فارغًا مثل -T :4242 للاستماع على جميع الواجهات). على سبيل المثال، للانضمام عبر Telnet من محطة طرفية قديمة:```bash
telnet server-address 2323
مرر `-T off` (أو `-T disable`) لإيقاف مستمع telnet تمامًا.
### JSON line API
يعرض الخادم أيضًا بروتوكول JSON line عبر TCP للأتمتة والتكاملات الخارجية. يستمع على المنفذ `34567` افتراضيًا ويمكن تعطيله أو إعادة تكوينه باستخدام `-J`:```bash
# Disable the JSON API
./ssh-chatter -J off
# Bind JSON API on a custom port
./ssh-chatter -J 0.0.0.0:45678
كل طلب هو كائن JSON واحد منتهي بـ \n. الاستجابات وأحداث الدردشة هي كائنات JSON، محددة أيضًا بفواصل الأسطر الجديدة. تدعم واجهة البرمجة الدردشة العامة وتدفقات /poll و/vote و/image و/video و/audio و/files و/asciiart.
حمولات الأحداث (server → client)```json {"type":"event","event":"message","payload":{"id":123,"username":"alice","message":"hello","created_at":1710000000,"system":false,"preserve_whitespace":false,"attachment":{"type":"none","target":"","caption":""}}}
**أمثلة الطلب (client → server)**```json
{"type":"chat","id":1,"username":"alice","message":"안녕하세요"}
{"type":"image","id":2,"username":"alice","url":"https://example.com/cat.png","caption":"cat"}
{"type":"asciiart","id":3,"username":"alice","message":" /\\_/\\\\n( o.o )\\\\n > ^ <"}
{"type":"poll","id":4,"username":"op","is_operator":true,"question":"Favorite color?","options":["red","blue","green"]}
{"type":"poll","id":5,"username":"bob","action":"vote","choice":2}
{"type":"vote","id":6,"username":"op","label":"weekend","question":"Plan?","options":["hike","rest"],"allow_multiple":true}
{"type":"vote","id":7,"username":"bob","label":"weekend","action":"vote","choice":1}
تحتوي الردود على id وتتضمن status و message وكائنات result اختيارية:```json
{"type":"response","id":4,"status":"ok","message":"poll started","result":{"poll":{"active":true,"allow_multiple":false,"id":10,"question":"Favorite color?","options":[{"index":1,"text":"red","votes":0},{"index":2,"text":"blue","votes":0}]}}}
للحصول على مثال قابل للتشغيل، راجع `scripts/json_api_example.py`:```bash
python3 scripts/json_api_example.py --url tcp://127.0.0.1:34567 --save /tmp/json_api_output.txt
يتم توفير سكريبت مساعد لأتمتة التثبيت على الأنظمة التي تستخدم systemd:```bash
sudo ./scripts/install_chatter_service.sh
ما الذي يفعله السكريبت:
1. يقوم بتجميع المشروع (`make`).
2. يقوم بتثبيت الملف الثنائي الناتج إلى `/usr/local/bin/ssh-chatter`.
3. يقوم بإنشاء مستخدم ومجموعة نظام مخصصين `ssh-chatter` (إذا لم يكونا موجودين بالفعل).
4. يقوم بإنشاء `/var/lib/ssh-chatter` لحالة وقت التشغيل (بما في ذلك مفتاح مضيف SSH) و `/etc/ssh-chatter` لملفات التكوين.
5. يقوم بإنشاء مفتاح مضيف RSA افتراضي تحت `/var/lib/ssh-chatter/ssh_host_rsa_key` عند فقدانه.
6. يقوم بإنشاء MOTD افتراضي في `/etc/ssh-chatter/motd` وملف تجاوز `/etc/ssh-chatter/chatter.env` للضبط القائم على البيئة.
7. يكتب `/etc/systemd/system/chatter.service`، ويعيد تحميل `systemd`، ويمكّن الخدمة، ويبدأها فوراً.
وحدة `chatter.service` الناتجة تبدأ الخادم بإعدادات افتراضية معقولة وتمنح capability `CAP_NET_BIND_SERVICE` بحيث يمكن لحساب الخدمة غير الجذر ربط المنافذ المميزة إذا لزم الأمر.
### تخصيص الخدمة
يمكنك تعديل الإعدادات الافتراضية عن طريق تحرير `/etc/ssh-chatter/chatter.env` وإعادة تشغيل الخدمة:```bash
sudo systemctl edit chatter.service # or edit the environment file directly
sudo systemctl restart chatter.service
تشمل متغيرات البيئة المدعومة ما يلي:
CHATTER_BIND_ADDRESS – عنوان IP للربط (الافتراضي 0.0.0.0).CHATTER_PORT – منفذ TCP المعرض للعملاء (الافتراضي 2222).CHATTER_MOTD_FILE – المسار إلى ملف رسالة اليوم (الافتراضي /etc/ssh-chatter/motd).CHATTER_HOST_KEY_DIR – الدليل الذي يحتوي على ssh_host_rsa_key (الافتراضي /var/lib/ssh-chatter).CHATTER_EXTRA_ARGS – وسائط إضافية تُلحق باستدعاء ssh-chatter.CHATTER_VOTE_FILE – المسار إلى ملف حالة التصويت (الافتراضي vote_state.dat).مقتطفات شيفرة التمويه:
بالنسبة لميزة تمويه Tetris، يتوقع وقت التشغيل وجود ملفات مقتطفات شيفرة في /var/lib/ssh-chatter/.
يتضمن هذا المستودع الآن أمثلة جاهزة للاستخدام تحت ./camouflage/ (c.txt، cpp.txt، java.txt، go.txt، js.txt، ts.txt، rust.txt).
انسخها إلى دليل وقت التشغيل مرة واحدة أثناء الإعداد:```bash
sudo install -d /var/lib/ssh-chatter
sudo cp camouflage/*.txt /var/lib/ssh-chatter/
يمكنك تعديل أي ملف منسوخ لتخصيص ما يظهر عندما تكون شاشة التمويه نشطة.
يعتمد دعم الترجمة الآن على Google Gemini API. قم بتعيين التالي في `chatter.env` (أو البيئة) لتفعيله:
- `GEMINI_API_KEY` – مفتاح API سري يُستخدم لمصادقة طلبات الترجمة.
- `GEMINI_API_BASE` – تجاوز اختياري لعنوان URL الأساسي للـ API (القيمة الافتراضية `https://generativelanguage.googleapis.com/v1beta`).
- `GEMINI_MODEL` – تجاوز اختياري لاسم نموذج Gemini (القيمة الافتراضية `gemini-2.5-flash`).
عندما يكون الترجمة نشطًا، يقوم الشات بتسليم كل رسالة فورًا بلغتها الأصلية ويتبعها بتعليق مُسَنَّد يحتوي على النص المترجم بمجرد وصول رد Gemini. تستخدم ملخصات التفاعلات نفس تنسيق التعليق بحيث تظهر التحديثات مباشرة أسفل الرسالة التي تشير إليها.
إذا شعرت أن إدراج التعليقات المضمنة مزعج، يمكنك حجز مساحة صغيرة من الأسطر الفارغة مسبقًا باستخدام `/chat-spacing <0-5>`. يؤثر هذا الإعداد فقط على محادثات الشات المباشرة—تستمر محتويات لوحة الإعلانات في الترجمة بدون حجز—حتى تتمكن من ضبط التباعد لجلسة خاصة بك دون التأثير على المنشورات الطويلة.
يتم حفظ مفتاح الترجمة وخيارات اللغة الخاصة بك في `chatter_state.dat`، لذا ستستعيد الجلسات المستقبلية نفس التكوين تلقائيًا بمجرد إعادة الاتصال.
إذا كنت تفضل التثبيت دون بدء الخدمة فورًا، قم بتشغيل السكريبت مع `SKIP_START=1`.
أوامر إدارة الخدمة:```bash
sudo systemctl status chatter.service
sudo systemctl restart chatter.service
sudo systemctl disable --now chatter.service
-m أو ملف إعدادات مُدار من الخدمة./help للعملاء المتصلين./ban, /poke)./weather/vote واستطلاعات ذات خيار واحد /vote-single، بما في ذلك /elect <label> <choice> كاختصار تصويت نصي سهل./bbs مع وسم وتعليقات ورفع ومحرر تفاعلي ينتهي بفاصل مراعي للمنطقة (افتراضيًا >/__BBS_END>).نرحب بالمشكلات وطلبات السحب (pull requests). يرجى تضمين خطوات إعادة إنتاج الأخطاء والتأكد من نجاح الأمر make قبل تقديم التغييرات.
| المسار | الوصف |
|---|
src/main.c | تحليل سطر الأوامر وبدء التشغيل (عنوان الربط، المنفذ، رسالة اليوم MOTD، دليل مفتاح المضيف). |
src/host_aggregate.c, include/ssh_chatter/host.h | تطبيق مضيف الدردشة – دورة حياة الجلسة، معالجة رسالة اليوم (MOTD)، وخطافات لمنطق بث الرسائل في المستقبل. |
src/host | أنظمة مضيف فرعية معيارية يتم تجميعها في وحدة ترجمة واحدة عبر src/host_aggregate.c. |
include/ssh_chatter | رؤوس مشتركة للخفي (daemon)، أدوات الإجهاد، وخلفية الترجمة. |
include/ssh_chatter/contexts | تعريفات لـ session_ctx_t والهياكل ذات الصلة التي تغلف حالة كل اتصال. |
data/banner/banner | لافتة ترحيبية نموذجية يمكن الإشارة إليها باستخدام CHATTER_WELCOME_BANNER. |
scripts/install_chatter_service.sh | مثبت ملائم يقوم ببناء الثنائي، تثبيته تحت /usr/local/bin، وربط وحدة systemd (chatter.service). |
scripts/install_dependencies.sh | مثبت حزم أدنى للمتطلبات الأساسية للبناء على أنظمة Debian/Ubuntu. |
CHATTER_GEMINI_COOLDOWN_FILE – المسار إلى ملف حالة التباطؤ لـ Gemini (الافتراضي gemini_cooldown.dat).CHATTER_SECURITY_FILTER – قم بتعيينه إلى off/false/0 لتعطيل مرشح الأمان الطبقي (مفعل افتراضيًا).CHATTER_SECURITY_AI – قم بتعيينه إلى on/true/1 لتفعيل الوساطة بالذكاء الاصطناعي (معطل افتراضيًا).CHATTER_FILESTORE_PATH – تجاوز مسار تخزين الملفات المُدارة (الافتراضي /etc/ssh-chatter/user-files).CHATTER_FILE_STORAGE_ROOT – احتياطي قديم لمسار تخزين الملفات المُدارة.CHATTER_MAX_ALLOC_BYTES – الحد الأعلى لمحاولة تخصيص متجاورة واحدة في مدير الذاكرة الداخلي. افتراضيًا لا يوجد حد (SIZE_MAX). قم بتعيين هذا فقط إذا كنت تريد فرض حد صارم على تخصيص واحد. قم بتعيينه إلى 0 أو unlimited أو inf أو infinity لإزالة أي حد بشكل صريح./asciiart/game الذي يضم tetris المدمجة (منقولة من تطبيق C السوفيتي الأصلي) وliargame، وكلاهما قابل للإيقاف المؤقت عبر /suspend! أو Ctrl+Z.