1- مقدمة
ما هو جهاز توجيه حد سلاسل المحادثات؟
إنّ سلسلة المحادثات عبارة عن بروتوكول شبكات لاسلكية لاسلكية منخفض الطاقة مستند إلى عنوان IP، ويتيح اتصالات آمنة بين الجهازين وبين الجهاز وبين السحابة الإلكترونية. يمكن أن تتكيّف شبكات سلاسل المحادثات مع التغييرات في علم المخطط لتجنُّب أي نقطة من نقاط الإخفاق.
يعمل جهاز توجيه حد سلسلة المحادثات على توصيل شبكة سلاسل محادثات بشبكات أخرى مستندة إلى عنوان IP، مثل Wi-Fi أو إيثرنت. تتطلب شبكة سلاسل المحادثات جهاز توجيه الحدود للاتصال بشبكات أخرى. يتوافق جهاز توجيه حد سلسلة المحادثات مع الحد الأدنى من الوظائف التالية:
- اتصال IP ثنائي الاتجاه بين سلاسل المحادثات وشبكات Wi-Fi/إيثرنت.
- اكتشاف الخدمة ثنائية الاتجاه عبر mDNS (عبر رابط Wi-Fi/Ethernet) وSRP (على شبكة سلسلة محادثات).
- البنية الأساسية التي تتضمن سلسلة محادثات والتي تدمج أقسام سلاسل المحادثات عبر الروابط المستندة إلى عنوان IP.
- إنشاء سلسلة محادثات خارجية (على سبيل المثال، هاتف جوّال) لمصادقة جهاز سلسلة المحادثات والانضمام إليها إلى شبكة سلاسل المحادثات.
جهاز توجيه حدود سلسلة OpenOpen (OTBR) الذي أصدرته Google هو تطبيق مفتوح المصدر لبرنامج توجيه سلاسل المحادثات.
المهام التي ستنفِّذها
في هذا الدرس التطبيقي، ستُجري عملية إعداد جهاز توجيه حد للسلسلة وتربط هاتفك الجوّال بجهاز نهاية سلسلة المحادثات عبر جهاز توجيه الحدود.
ما ستتعرَّف عليه
- كيفية إعداد OTBR
- طريقة إنشاء شبكة سلاسل محادثات باستخدام بروتوكول OTBR
- كيفية إنشاء جهاز Openسلسلة سطر الأوامر (CLI) باستخدام ميزة SRP
- كيفية تسجيل خدمة في SRP
- كيفية اكتشاف جهاز نهاية سلسلة المحادثات والوصول إليه.
المتطلبات
- جهاز Raspberry Pi 3/4 وبطاقة SD بسعة 8 غيغابايت على الأقل.
- لوحتان للتطوير شبه الشمالي nRF52840
- تم تفعيل نقطة وصول Wi-Fi بدون IPv6 Router Advertisingment Guard على جهاز التوجيه.
- هاتف iOS يعمل بنظام التشغيل iOS 14 أو Android على الأقل يعمل بالإصدار 8.1 على الأقل من نظام التشغيل Android.
2- إعداد OTBR
إعداد Raspberry Pi
من السهل إعداد جهاز Raspberry Pi جديد باستخدام الأداة rpi-imager
عن طريق اتّباع التعليمات الواردة على rapberrypi.org (بدلاً من استخدام أحدث إصدار من نظام Raspberry Pi OS في الأداة، يُرجى تنزيل 2021-05-07-raspios-buster-armhf-lite بنفسك). لإكمال خطوات الهاتف الجوّال في هذا الدرس التطبيقي، عليك ربط تطبيق Raspberry Pi بنقطة اتصال Wi-Fi. اتّبِع هذا الدليل لإعداد الاتصال اللاسلكي. من السهل تسجيل الدخول إلى Raspberry Pi باستخدام SSH، يمكنك العثور على التعليمات هنا.
الحصول على رمز OTBR
سجّل الدخول إلى Raspberry Pi واستنساخ ot-br-posix
من GitHub:
$ git clone https://github.com/openthread/ot-br-posix.git --depth 1
إنشاء OTBR وتثبيتها
يقدّم OTBR نصين برمجيين يعملان على تشغيل وتم إعداد جهاز توجيه حد سلسلة المحادثات:
$ cd ot-br-posix $ ./script/bootstrap $ INFRA_IF_NAME=wlan0 ./script/setup
يعمل OTBR على كل من واجهة سلسلة المحادثات وواجهة الشبكة الأساسية (مثل Wi-Fi/Ethernet) والتي يتم تحديدها مع INFRA_IF_NAME
. يتم إنشاء واجهة سلسلة المحادثات من خلال OTBR نفسها وتسميتها.wpan0
بشكل تلقائي، وتتضمن الواجهة الأساسية قيمة تلقائيةwlan0
إِذَاINFRA_IF_NAME
غير محدد بشكل صريح. إذا كان كابل Raspberry Pi متصلاً بكابل إيثرنت، حدِّد اسم واجهة إيثرنت (مثل eth0
):
$ INFRA_IF_NAME=eth0 ./script/setup
تحقّق مما إذا تم تثبيت OTBR بنجاح:
$ sudo service otbr-agent status ● otbr-agent.service - Border Router Agent Loaded: loaded (/lib/systemd/system/otbr-agent.service; enabled; vendor preset: enabled) Active: activating (auto-restart) (Result: exit-code) since Mon 2021-03-01 05:43:38 GMT; 2s ago Process: 2444 ExecStart=/usr/sbin/otbr-agent $OTBR_AGENT_OPTS (code=exited, status=2) Main PID: 2444 (code=exited, status=2)
من المتوقع أن خدمة otbr-agent
غير نشطة، لأنها تتطلب شريحة RCP
لتشغيلها.
أعِد تشغيل Raspberry Pi لتصبح التغييرات سارية المفعول.
إنشاء برامج RCP الثابتة وفلاشها
يتوافق OTBR مع شريحة راديو 15.4 في وضع المعالج المشترك للراديو (RCP). في هذا الوضع، تعمل حزمة OpenThread على الجانب المضيف وتنقل/تتلقّى الإطارات عبر جهاز إرسال واستقبال IEEE802.15.4.
اتّبِع الخطوة 4 من إنشاء شبكة سلاسل محادثات باستخدام nRF52840 لوحات وOpenthread حول الترميز لإنشاء جهاز nRF52840 RCP ووميضه:
$ script/build nrf52840 USB_trans
بدء OTBR والتحقق من الحالة
اربط لوحة nRF52840 بجهاز Raspberry Pi وبدء خدمة otbr-agent
:
$ sudo service otbr-agent restart
تحقَّق من أن خدمة otbr-agent
نشطة:
$ sudo service otbr-agent status ● otbr-agent.service - Border Router Agent Loaded: loaded (/lib/systemd/system/otbr-agent.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2021-03-01 05:46:26 GMT; 2s ago Main PID: 2997 (otbr-agent) Tasks: 1 (limit: 4915) CGroup: /system.slice/otbr-agent.service └─2997 /usr/sbin/otbr-agent -I wpan0 -B wlan0 spinel+hdlc+uart:///dev/ttyACM0 Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Stop publishing service Mar 01 05:46:26 raspberrypi otbr-agent[2997]: [adproxy] Stopped Mar 01 05:46:26 raspberrypi otbr-agent[2997]: PSKc is not initialized Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Check if PSKc is initialized: OK Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Initialize OpenThread Border Router Agent: OK Mar 01 05:46:26 raspberrypi otbr-agent[2997]: Border router agent started. Mar 01 05:46:26 raspberrypi otbr-agent[2997]: [INFO]-CORE----: Notifier: StateChanged (0x00038200) [NetData PanId NetName ExtPanId] Mar 01 05:46:26 raspberrypi otbr-agent[2997]: [INFO]-PLAT----: Host netif is down
3. إعداد شبكة سلسلة محادثات
يتوفّر أمر ot-ctl
يمكن استخدامه للتحكُّم في خدمة otbr-agent
. تقبل ot-ctl
جميع أوامر OpenCL CLI، وللحصول على مزيد من التفاصيل في دليل CLI المفتوح.
إنشاء شبكة سلسلة محادثات باستخدام OTBR:
$ sudo ot-ctl dataset init new Done $ sudo ot-ctl dataset commit active Done $ sudo ot-ctl ifconfig up Done $ sudo ot-ctl thread start Done
انتظِر بضع ثوانٍ، من المفترض أن نرى أن OTBR تعمل كسلسلة محادثات leader
وهناك بادئة off-mesh-routable
(OMR) في بيانات شبكة سلاسل المحادثات:
$ sudo ot-ctl state leader Done $ sudo ot-ctl netdata show Prefixes: Prefixes: fd76:a5d1:fcb0:1707::/64 paos med 4000 Routes: fd49:7770:7fc5:0::/64 s med 4000 Services: 44970 5d c000 s 4000 44970 01 9a04b000000e10 s 4000 Done $ sudo ot-ctl ipaddr fda8:5ce9:df1e:6620:0:ff:fe00:fc11 fda8:5ce9:df1e:6620:0:0:0:fc38 fda8:5ce9:df1e:6620:0:ff:fe00:fc10 fd76:a5d1:fcb0:1707:f3c7:d88c:efd1:24a9 fda8:5ce9:df1e:6620:0:ff:fe00:fc00 fda8:5ce9:df1e:6620:0:ff:fe00:4000 fda8:5ce9:df1e:6620:3593:acfc:10db:1a8d fe80:0:0:0:a6:301c:3e9f:2f5b Done
4. إعداد جهاز العميل النهائي SRP
إنشاء سطر الأوامر والمضي قدمًا في سطر الأوامر
اتّبِع الخطوة 5 من عملية إنشاء شبكة سلسلة محادثات باستخدام لوحات nRF52840 وOpenThread لإنشاء جهاز نهاية nRF52840 CLI ووميضه.
ولكن بدلاً من تفعيل OT_COMMISSIONER
وOT_JOINER
، تتطلب عُقدة سطر الأوامر (CLI) ميزتَين OT_SRP_CLIENT
وOT_ECDSA
.
لذا، يجب أن يظهر استدعاء البنية بالكامل على النحو التالي:
$ script/build nrf52840 USB_trans -DOT_SRP_CLIENT=ON -DOT_ECDSA=ON
الانضمام إلى شبكة OTBR
للانضمام إلى شبكة سلاسل المحادثات التي أنشأتها خدمة otbr-agent
، نحتاج إلى الحصول على مجموعة بيانات التشغيل النشط من جهاز OTBR. سنعود إلى سطر الأوامر otbr-agent
ونحصل على مجموعة البيانات النشطة:
$ sudo ot-ctl dataset active -x 0e080000000000010000000300001235060004001fffe002083d3818dc1c8db63f0708fda85ce9df1e662005101d81689e4c0a32f3b4aa112994d29692030f4f70656e5468726561642d35326532010252e204103f23f6b8875d4b05541eeb4f9718d2f40c0302a0ff Done
ارجع إلى جلسة شاشة عقدة عميل SRP واضبط مجموعة البيانات النشطة:
> dataset set active 0e080000000000010000000300001235060004001fffe002083d3818dc1c8db63f0708fda85ce9df1e662005101d81689e4c0a32f3b4aa112994d29692030f4f70656e5468726561642d35326532010252e204103f23f6b8875d4b05541eeb4f9718d2f40c0302a0ff Done
بعد ذلك، ابدأ واجهة "سلسلة المحادثات":
> ifconfig up Done > thread start Done
انتظر لبضع ثوانٍ وتحقق من نجاح الانضمام إلى شبكة سلاسل المحادثات:
> state child Done > netdata show Prefixes: fd76:a5d1:fcb0:1707::/64 paos med 4000 Routes: fd49:7770:7fc5:0::/64 s med 4000 Services: 44970 5d c000 s 4000 44970 01 9a04b000000e10 s 4000 Done > ipaddr fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 fda8:5ce9:df1e:6620:0:ff:fe00:4001 fda8:5ce9:df1e:6620:ed74:123:cc5d:74ba fe80:0:0:0:d4a9:39a0:abce:b02e Done
تأكد من تطابق بيانات الشبكة مع البيانات المطبوعة على OTBR. يمكننا الآن فحص عنوان OMR الخاص بـ OTBR:
> ping fd76:a5d1:fcb0:1707:f3c7:d88c:efd1:24a9 Done > 16 bytes from fd76:a5d1:fcb0:1707:f3c7:d88c:efd1:24a9: icmp_seq=1 hlim=64 time=49ms
5. نشر الخدمة على الجهاز النهائي
تم استخدام mDNS على نطاق واسع لنشر خدمة DNS-SD على رابط محلي. ولكن رسائل البث المتعدد تستهلك معدل نقل بيانات كبيرًا جدًا وسيتم استهلاك البطارية للأجهزة التي تعمل بالطاقة المنخفضة بسرعة. تستخدم سلسلة المحادثات بروتوكول SRP بلغة unicast لتسجيل خدماتها لدى جهاز توجيه الحدود وتعتمد على جهاز توجيه الحدود للإعلان عن الخدمات على رابط Wi-Fi أو رابط إيثرنت.
يمكننا تسجيل خدمة باستخدام الأمر srp client
.
انتقل إلى جلسة شاشة عقدة عميل SRP وابدأ تشغيل برنامج SRP تلقائيًا:
> srp client autostart enable Done
حدِّد اسم المضيف الذي سيتم الإعلان عنه على رابط Wi-Fi/إيثرنت:
> srp client host name ot-host Done
بالنسبة إلى جهاز على رابط Wi-Fi/إيثرنت للوصول إلى جهاز نهاية سلسلة محادثات، يجب الإعلان عن عنوان OMR للجهاز النهائي:
> srp client host address fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 Done
في النهاية، سجِّل خدمة _ipps._tcp
مزيّفة:
> srp client service add ot-service _ipps._tcp 12345 Done
يُرجى الانتظار بضع ثوانٍ ومن المفترض أن نتمكّن من تسجيل الخدمة:
> srp client service instance:"ot-service", name:"_ipps._tcp", state:Registered, port:12345, priority:0, weight:0 Done
لقد أكملنا جميع أعمال الإعداد وكان من المفترض أن يتم الإعلان عن خدمة _ipps._tcp
على رابط Wi-Fi/إيثرنت. حان الوقت لاكتشاف الجهاز النهائي والوصول إليه الآن.
6. تعرّف على الخدمة
اكتشاف الخدمة باستخدام هاتف جوّال
نستخدم تطبيق Service Server (متصفّح الخدمة) للتعرّف على خدمات mDNS في هاتف Android، ويمكن أيضًا العثور على تطبيق مكافئ للأجهزة الجوّالة التي تعمل بنظام التشغيل iOS. افتح التطبيق وستظهر الخدمة _ipps._tcp
.
اكتشاف الخدمة من خلال مضيف نظام التشغيل Linux
إذا كنت تريد استكشاف الخدمة من مضيف Linux آخر، يمكنك استخدام الأمر avahi-browse
.
تثبيت avahi-daemon
وavahi-utils
:
$ sudo apt-get install -y avahi-daemon avahi-utils
حل الخدمة:
$ sudo service avahi-daemon start # Ensure the avahi daemon is started. $ avahi-browse -r _ipps._tcp + wlan0 IPv6 ot-service Secure Internet Printer local = wlan0 IPv6 ot-service Secure Internet Printer local hostname = [ot-host.local] address = [fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927] port = [12345] txt = [] ...
اكتشاف الخدمة من خلال مضيف نظام التشغيل macOS
يمكنك استخدام dns-sd
على نظام التشغيل macOS لحل الخدمة:
$ dns-sd -Z _ipps._tcp local. Browsing for _ipps._tcp.local. DATE: ---Sun 14 Mar 2021--- 21:31:42.125 ...STARTING... ; To direct clients to browse a different domain, substitute that domain in place of '@' lb._dns-sd._udp PTR @ ; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names. ; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local ; names with the correct fully-qualified (unicast) domain name of the target host offering the service. _ipps._tcp PTR ot-service._ipps._tcp ot-service._ipps._tcp SRV 0 0 12345 ot-host.local. ; Replace with unicast FQDN of target host ot-service._ipps._tcp TXT "" ...
7- فحص الاتصال للجهاز النهائي
إشعار من هاتف جوّال
كمثال على هاتف Pixel، يمكننا العثور على عنوان OMR الخاص بالخدمة المُسجَّلة سابقًا "ot-service" في صفحة تفاصيل النسخة الافتراضية من الخدمة في تطبيق Browser Service.
يمكننا الآن فحص عنوان OMR باستخدام تطبيق Network Analyzer آخر.
عذرًا، لا يتوافق إصدار Android من تطبيق Network Analyzer مع طلبات بحث mDNS لأداة فحص الاتصال ولا يمكننا فحص اتصال اسم المضيف ot-host.local
مباشرة (يمكننا فحص اتصال اسم المضيف باستخدام إصدار iOS من التطبيق).
فحص الاتصال من مضيف Linux/macOS
يرسل جهاز توجيه حد سلسلة المحادثات ICMPv6 Router Ads (RA) للإعلان عن البادئات (عبر خيار معلومات البادئة) والمسارات (عبر خيار "معلومات المسار") على رابط Wi-Fi/إيثرنت.
إعداد مضيف Linux
من المهم التأكُّد من تفعيل RA وRIO على مضيفك:
- يجب أن تكون القيمة
net.ipv6.conf.wlan0.accept_ra
1
على الأقل في حال عدم تفعيل إعادة توجيه عنوان IP، و2
في حال عدم تفعيلها. - يجب ألا يقل
net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen
عن64
.
يتم ضبط accept_ra
تلقائيًا على 1
لمعظم التوزيعات. ولكن قد تكون هناك برامج أخرى غير متوفرة على الشبكة ستلغي هذا الخيار (على سبيل المثال، سيلغي dhcpcd
على Raspberry Pi الإعداد accept_ra
إلى 0
). يمكنك التحقّق من قيمة accept_ra
باستخدام:
$ sudo sysctl -n net.ipv6.conf.wlan0.accept_ra 0
ويمكنك ضبط القيمة على 1
(أو 2
في حال تفعيل إعادة توجيه عنوان IP) باستخدام:
$ sudo sysctl -w net.ipv6.conf.wlan0.accept_ra=1 Net.ipv6.conf.wlan0.accept_ra = 1
خيار accept_ra_rt_info_max_plen
في معظم توزيعات Linux هو الإعداد التلقائي إلى 0
، ويتم ضبطه على 64
باستخدام:
$ sudo sysctl -w net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen=64 net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen = 64
سيتم فقدان التغيير بعد إعادة تشغيل المضيف. على سبيل المثال، يمكنك إلحاق الأوامر أدناه بـ/etc/sysctl.conf
لتفعيل RIO بشكل دائم:
$ net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen = 64
قد يكون الوقت متأخرًا جدًا لتغيير عمليات الضبط هذه لأن OTBR كان يرسل رسائل RA بالفعل وقد يكون الفاصل بين رسالتَي RA غير مرغوب فيهما عدة مئات من الثواني. تتمثل إحدى الطُرق في قطع الاتصال بنقطة اتصال Wi-Fi وإعادة الاتصال بها لإرسال رسائل طلب جهاز التوجيه، وذلك حتى يستجيب نظام OTBR عند طلب RAS. هناك خيار آخر وهو إعادة تشغيل وظيفة توجيه الحدود على جهاز توجيه الحدود:
$ sudo ot-ctl br disable Done $ sudo ot-ctl br enable Done
إذا كنت تحاول إعادة الاتصال بشبكة Wi-Fi أو إعادة تشغيل واجهة إيثرنت، تأكَّد من أنّ الخيار dhcpcd لا يُستخدَم في إدارة شبكة Wi-Fi/إيثرنت Ethernet6. لأن dhcpcd يلغي دائمًا خيار accept_ra
في كل مرة تتم فيها إعادة تشغيل الواجهة، وسيتم فقدان إعداد accept_ra
. ألحق الأسطر التالية بملف إعداد dhcpcd (مثل /etc/dhcpcd.conf
) لإيقاف IPv6 صراحة في dhcpcd:
noipv6 noipv6rs
يجب إعادة التشغيل ليتم تفعيل التغيير.
إعداد مضيف نظام التشغيل macOS
يتم تفعيل كلا الخيارين accept_ra*
تلقائيًا، ولكن تحتاج إلى ترقية نظامك إلى نظام التشغيل macOS Big Sur على الأقل.
فحص اسم المضيف أو عنوان IPv6
يمكننا الآن فحص اتصال اسم المضيف ot-host.local
باستخدام الأمر ping -6
(ping6
لنظام التشغيل macOS):
$ ping -6 ot-host.local. PING ot-host.local.(fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927)) 56 data bytes 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=1 ttl=63 time=170 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=2 ttl=63 time=64.2 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=3 ttl=63 time=22.8 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=4 ttl=63 time=37.7 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 (fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927): icmp_seq=5 ttl=63 time=28.7 ms ...
قد يتعذّر تنفيذ هذا الأمر على مضيفات Linux التي تظهر فيها رسالة الخطأ "Name or service not known"
. وذلك لأن الأمر ping
لا يحل اسم ot-host.local.
مع طلبات بحث mDNS. افتح /etc/nsswitch.conf
وأضِف mdns6_minimal
إلى السطر الذي يبدأ بـ hosts
:
hosts: files mdns4_minimal mdns6_minimal dns
وبالطبع، يمكنك دائمًا فحص عنوان IPv6 مباشرةً:
$ ping -6 fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927 PING fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927(fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927) 56 data bytes 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=1 ttl=63 time=32.9 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=2 ttl=63 time=27.8 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=3 ttl=63 time=29.9 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=4 ttl=63 time=73.5 ms 64 bytes from fd76:a5d1:fcb0:1707:d3dc:26d3:f70b:b927: icmp_seq=5 ttl=63 time=26.4 ms ...
8. إلغاء نشر الخدمة للجهاز
لإزالة العنوان والخدمة المسجَّلين من عقدة عميل SRP:
> srp client host remove Done
يجب ألا تتمكّن من اكتشاف خدمة _ipps._tcp
الآن.
9. تهانينا
تهانينا، لقد نجحت في إعداد OTBR كجهاز توجيه حد سلسلة المحادثات لتوفير اتصال IP ثنائي الاتجاه واكتشاف الخدمة لأجهزة سلسلة المحادثات النهائية.
ما هي الخطوة التالية؟
اطّلِع على بعض هذه الدروس التطبيقية حول الترميز...