
تحليل CVE-2026-5281 (Chrome Dawn WebGPU UAF)، أدوات تحقق مخبرية، وبيئة قابلة لإعادة الإنتاج للبنيات المعرضة للثغرة مقابل البنيات المُصححة.
هذه الثغرة أثرت على أحد العملاء الذين نقدم لهم الخدمات. هذا المستودع هو مساهمتنا في البحث الأصلي: نقطة انطلاق مركزية للفريق، بحيث إذا ظهرت ثغرة مشابهة تؤثر على هذا المكون مرة أخرى، يكون لدينا الأساس جاهزًا. يجمع المستودع النظرية وراء الخلل، وملخصًا موثقًا لنتائج الباحث الأصلي، ومجموعة من الأدوات العملية للتحقق من التعرض في بيئة مختبرية.
ملاحظة: كنت أرغب في مشاركة المزيد من هذا البحث، لكن بسبب قيود الشركة لا يمكنني الكشف عنه أكثر. كل ما هو مدرج هنا قد تمت مراجعته ولا ينتهك أي اتفاقيات أنا ملزم بها. لذلك تم أرشفة المستودع في حالته الحالية.
في الأول من أبريل 2026، أصدرت Google تحديثًا أمنيًا لـ Chrome يعالج 21 ثغرة، إحداها CVE-2026-5281، والتي كانت تُستغل بنشاط في النسخة المتداولة وقت الإفصاح. بعد ثلاثة أيام، أضافتها CISA إلى فهرس الثغرات المعروفة والمستغلة وأصدرت توجيهًا تشغيليًا ملزمًا يطالب الوكالات الفيدرالية بتطبيق التصحيح. بحلول ذلك الوقت، كانت قد أثرت علينا بالفعل.
هذا المستودع موجود لسبب واحد: حتى في المرة القادمة التي يحدث فيها شيء كهذا، يكون لدينا نقطة انطلاق بدلاً من البدء من الصفر. يجمع المستودع بين:
عندما تريد فهم سبب وجود ثغرة معينة، تبدأ بما صُمم النظام لفعله والافتراضات التي بني عليها.
يقدم WebGPU واجهة برمجة تطبيقات (API) لتنفيذ عمليات، مثل التصيير والحساب، على وحدة معالجة الرسومات (GPU). WebGPU ليس محاولة لتقديم OpenGL أو OpenGL ES (الأنظمة المضمنة). إنها واجهة برمجة تطبيقات جديدة مبنية على أفكار واجهات برمجة التطبيقات الحديثة مثل Direct3D 12 و Metal و Vulkan.
WebGPU هو البديل الحديث لـ WebGL، واجهة برمجة تطبيقات GPU القديمة التي استخدمتها المتصفحات لسنوات. الفرق الرئيسي هو أن WebGPU صُمم من البداية ليكون آمنًا وذا إدارة واضحة للموارد. أنت تعلن عن دورة حياة كل مخزن مؤقت (buffer) ونسيج (texture) وخط أنابيب (pipeline) بنفسك. يعمل المتصفح كطبقة تحقق بين JavaScript والعتاد GPU.
الكائنات التي تقع في مركز هذه الثغرة، حسب ترتيب الإنشاء:``` GPUAdapter ← represents a physical GPU or software fallback └─ GPUDevice ← your logical connection to the adapter; owns everything ├─ GPUBuffer ← a chunk of GPU-accessible memory ├─ GPUShaderModule ← a compiled WGSL shader program ├─ GPUComputePipeline ← a shader wired to a pipeline layout ├─ GPUBindGroup ← binds buffers as inputs to a pipeline ├─ GPUCommandEncoder ← records a sequence of GPU commands └─ GPUQueue ← submits recorded commands to hardware
القاعدة المهمة هنا: كل كائن مملوك لـ GPUDevice. إتلاف المخزن المؤقت بينما لا يزال الجهاز يحتوي على أوامر قيد التنفيذ تشير إليه هو أمر غير قانوني صراحةً بموجب المواصفات. من المفترض أن يكتشف تطبيق Dawn ذلك ويرفضه. CVE-2026-5281 هو حالة لم يفعل فيها ذلك.
---
---
---
<div id='whatisdawn'/>
## ***⚙️ ما هو Dawn؟***
- **[Dawn - تنفيذ WebGPU مفتوح المصدر](https://dawn.googlesource.com/dawn)**
> Dawn هو تنفيذ مفتوح المصدر ومتعدد المنصات لمعيار WebGPU قيد التطوير. يعرض واجهة برمجة تطبيقات C++ أصلية تعكس WebGPU IDL مع بعض الامتدادات.
Dawn هي مكتبة C++ داخل Chrome تترجم استدعاءات JavaScript الخاصة بـ WebGPU إلى أوامر GPU أصلية للمنصة. على Windows تستهدف D3D12، على macOS تستهدف Metal، وعلى Linux تستهدف Vulkan. تقع بين محرك JavaScript في Chrome وبرنامج تشغيل الأجهزة، وهي مسؤولة عن أربعة أشياء: التحقق من صحة استدعاءات API، تسلسل الأوامر، تتبع عمر الكائنات، وإظهار الأخطاء إلى JavaScript.
يقع CVE-2026-5281 في جزء تتبع العمر. تحديدًا، في المدة التي يحتفظ فيها Dawn بكائنات المخزن المؤقت لل GPU حية بينما لا تزال الأوامر التي تشير إليها معلقة للتنفيذ على قائمة انتظار الأجهزة.```
JavaScript (V8)
│ WebGPU API calls
▼
Dawn (C++) - validates, serializes, tracks lifetimes, reports errors
│
▼
D3D12 (Windows) - Metal (macOS) - Vulkan (Linux)
│
▼
GPU hardware driver
│
▼
Physical GPU - shader cores, VRAM
تحتاج إلى نموذج ذهني واضح لمكان وجود الأشياء في الذاكرة قبل أن يصبح Use-After-Free بديهيًا.``` High addresses ┌────────────────────────────────────┐ │ Kernel space │ The OS and drivers live here. │ │ User-mode code cannot touch it. ├────────────────────────────────────┤ │ Stack │ Function call frames. Fast. │ (grows downward) │ Freed automatically when the │ │ function returns. ├────────────────────────────────────┤ │ Heap │ Dynamic allocations - malloc, new, │ (grows upward) │ smart pointers like Ref. │ │ Freed only when you say so. ├────────────────────────────────────┤ │ BSS / Data / Text │ Globals, constants, compiled code. └────────────────────────────────────┘ Low addresses
كائنات C++ الخاصة بـ Dawn، مثل الكائن الداخلي الذي يدعم GPUBuffer، تعيش على الـ heap. ويتم عدّها بالمراجع: يحتفظ مؤشر ذكي بعدد الأشياء التي تحتفظ بمرجع للكائن. عندما يصل هذا العدد إلى الصفر، يتم تشغيل المدمر وتُعاد الذاكرة إلى المخصص.
يمتلك GPUBuffer تمثيلين في نفس الوقت، واحد على جانب CPU وواحد على جانب GPU:```
CPU side (Dawn, system RAM)
└─ C++ object - metadata, state flags, and a hardware handle
│
│ handle: ID3D12Resource* (D3D12) - MTLBuffer (Metal) - VkBuffer (Vulkan)
▼
GPU side (driver, VRAM)
└─ Actual memory allocation on the graphics card
عندما تستدعي JavaScript buffer.destroy()، يكون السلوك المقصود هو: وضع علامة على الكائن على أنه مدمر، تقليل عدد المراجع، تحرير مقبض الجهاز، وتحرير ذاكرة VRAM. يؤدي الخلل في CVE-2026-5281 إلى تحرير ذاكرة VRAM بينما لا يزال قائمة أوامر GPU تحتوي على مرجع إلى ذلك المقبض، مما يعني أن GPU يقرأ أو يكتب بنشاط في ذاكرة لم تعد مملوكة له.
CWE-416: الاستخدام بعد التحرير (MITRE)
الإشارة إلى الذاكرة بعد تحريرها يمكن أن تتسبب في تعطل البرنامج، أو استخدام قيم غير متوقعة، أو تنفيذ تعليمات برمجية. يمكن أن يؤدي استخدام الذاكرة التي تم تحريرها مسبقًا إلى أي عدد من العواقب السلبية، بدءًا من تلف البيانات الصحيحة إلى تنفيذ تعليمات برمجية عشوائية.
يتبع الاستخدام بعد التحرير نمطًا ثابتًا من ثلاث خطوات وهو أحد أكثر أنواع ثغرات أمان الذاكرة استغلالًا باستمرار في أمان المتصفحات:```
After step 2, the allocator can hand that same memory region to a completely different allocation. If an attacker can control what gets placed into that freed region, a technique called heap grooming, they can control what the stale pointer reads back. That is how a memory safety bug becomes code execution.
GPU-side UAF is harder to observe than CPU-side UAF, because:
- The "allocator" is the GPU driver's VRAM allocator, not the system malloc.
- The "stale pointer" is a hardware handle still referenced by the command queue.
- The GPU executes commands asynchronously, the CPU has moved on long before the crash happens.
---
---
---
<div id='thevulnerability'/>
## ***🕳️ الثغرة***
---
<div id='thevulnerability-whatweknow'/>
### ***📋 ما نعرفه من المصادر العامة***
التالي مبني بالكامل على ما تم تأكيده علنًا.
- **[NVD: CVE-2026-5281](https://nvd.nist.gov/vuln/detail/CVE-2026-5281)**
> ثغرة Use-after-free في Dawn في Google Chrome قبل الإصدار 146.0.7680.178 سمحت لمهاجم عن بُعد قام باختراق عملية العرض بتنفيذ تعليمات برمجية عشوائية عبر صفحة HTML مصمَّمة خصيصًا.
- **[The Hacker News: 1 أبريل 2026](https://thehackernews.com/2026/04/new-chrome-zero-day-cve-2026-5281-under.html)**
> تدرك Google أن استغلالًا لـ CVE-2026-5281 موجود في البرية.
- **[Help Net Security: 1 أبريل 2026](https://www.helpnetsecurity.com/2026/04/01/google-chrome-zero-day-cve-2026-5281/)**
> تم الإبلاغ عن CVE-2026-5281 من قبل صائد أخطاء باسم مستعار (86ac1f1587b71893ed2ad792cd7dde32)، والذي أبلغ سابقًا عن ثغرتين تم إصلاحهما في تحديث Chrome الصادر في 23 مارس 2026: تجاوز سعة مخزن مؤقت في WebGL (CVE-2026-4675) وثغرة Use-after-free أخرى في Dawn (CVE-2026-4676). كما أبلغ صائد الأخطاء عن ثغرة ثالثة Use-after-free في Dawn (CVE-2026-5284) تم إصلاحها هذه المرة.
---
<div id='thevulnerability-executionlayers'/>
### ***🔗 من JavaScript إلى العتاد***
لفهم مصدر ثغرة UAF في Dawn، من المفيد رؤية كيفية انتقال استدعاء WebGPU من سطر من JavaScript وصولاً إلى العتاد المادي:```
JavaScript
↓ navigator.gpu → adapter → device → buffer / pipeline / encoder
↓ queue.submit([commandBuffer]) ← validation happens here
↓ buffer.destroy() ← if this races GPU execution, UAF
Dawn (C++) - validates API calls, serializes commands, tracks lifetimes
↓ translates WebGPU calls to platform-native API calls
D3D12 (Windows)
↓ ID3D12CommandQueue::ExecuteCommandLists()
↓ hardware handle for the buffer passed to the driver
GPU hardware
↓ shader cores execute the queued commands
↓ if the buffer was freed prematurely → they access freed VRAM ← UAF
التوتر الأساسي هو أن كلاً من queue.submit() و buffer.destroy() هما استدعاءان لواجهة برمجة تطبيقات جافا سكريبت يعودان فوراً، لكن وحدة معالجة الرسومات (GPU) تنفذ الأوامر المُرسلة بشكل غير متزامن، وربما بعد فترة طويلة من عودة كلا الاستدعاءين. تحتاج Dawn إلى إبقاء كائنات المخزن المؤقت (buffer objects) حية طوال مدة تنفيذ وحدة معالجة الرسومات، وليس فقط حتى عودة استدعاء جافا سكريبت.
عندما يتم تشغيل UAF، تصطدم وحدة معالجة الرسومات بما تسميه D3D12 حدث "الجهاز المُزال" (Device Removed). التسلسل هو:```
هذا أيضًا ما يكتشفه عداء الاختبار الآلي في هذا المستودع: فهو يراقب تلك الإشارات الدقيقة لوحدة التحكم لتحديد ما إذا كان الثغرة الأمنية قابلة للتفعيل في إصدار معين من كروم.
---
<div id='thevulnerability-impact'/>
### ***💥 التأثير ومتطلبات الاستغلال***
وصف NVD محدد بشأن قيد مهم واحد: يتطلب الاستغلال أن يكون المهاجم قد اخترق بالفعل عملية العرض. هذا يعني أن CVE-2026-5281 ليس RCE مستقلًا بنقرة واحدة من بداية باردة، بل هو هروب من الصندوق الرملي يصبح جزءًا من سلسلة.
عمليًا، ستبدو سلسلة الهجوم الكاملة كما يلي:```
Initial access ← some other vulnerability gets code running in the renderer
↓
CVE-2026-5281 ← UAF in Dawn used to escape the renderer sandbox
↓
Arbitrary code ← execution in a higher-privilege Chrome process or OS context
هذا هو نموذج الاستغلال الذي يجعل ثغرات وحدة معالجة الرسومات في المتصفح ذات قيمة عالية: بمجرد دخولك إلى عارض المحتوى، تصبح Dawn أحد الأهداف الطبيعية التالية لأنها تتعامل مع الذاكرة على مستوى الأجهزة بنوع من التعقيد غير المتزامن الذي ينتج نوافذ التوقيت هذه.
التأثير المؤكد وقت الإفصاح كان تنفيذ تعليمات برمجية عشوائية، ويسجل قاعدة بيانات Vulners تلف البيانات وتعطل المتصفح كتأثيرات إضافية ملحوظة.
لم يظهر CVE-2026-5281 بمعزل عن الآخرين. كانت رابع ثغرة يوم-صفر في Chrome لعام 2026، وهو العام الذي كان بالفعل في طريقه لتجاوز العدد الإجمالي لثغرات اليوم-الصفر لعام 2025 والبالغ ثمانية قبل نهاية الربع الأول.
| التاريخ | الحدث |
|---|---|
| فبراير 2026 | تم تصحيح CVE-2026-2441، UAF في مكون CSS في Chrome، تم استغلاله بنشاط |
| 10 مارس 2026 | تم تصحيح CVE-2026-3909 و CVE-2026-3910، وكلاهما ثغرات يوم-صفر تم استغلالها بنشاط |
| 23 مارس 2026 | تم تصحيح CVE-2026-4675 (تجاوز سعة المخزن المؤقت في WebGL) و CVE-2026-4676 (UAF في Dawn)، نفس المبلغ عن CVE-2026-5281 |
| 1 أبريل 2026 | أصدرت Google Chrome 146.0.7680.177/178، تم تصحيح 21 ثغرة، تم تأكيد استغلال CVE-2026-5281 في البرية |
| 1 أبريل 2026 | أضافت CISA CVE-2026-5281 إلى كتالوج الثغرات المستغلة المعروفة |
| 3 أبريل 2026 | أقرت Google باستغلال نشط ضد 3.5 مليار مستخدم لـ Chrome |
نفس الباحث المجهول الذي أبلغ عن CVE-2026-5281 أبلغ أيضًا عن ثلاث ثغرات أخرى في الإطار الزمني المحيط (CVE-2026-4675 و CVE-2026-4676 و CVE-2026-5284، وآخر اثنتين هما أيضًا UAF في Dawn). يشير هذا إلى جهد بحثي مركز ومستمر يستهدف على وجه التحديد إدارة الذاكرة في Dawn.
تم بناء مجموعة الأدوات في هذا المستودع على بحث أمني أصلي يوثق سلوك الثغرة في بيئة معملية. ما يلي هو ملخص لذلك البحث، والاستراتيجية المستخدمة لتفعيل UAF والنتائج التي لوحظت.
تم تصميم نهج الباحث لتفعيل UAF بحيث يلبي في الوقت نفسه الشروط الثلاثة التي تجعل نافذة السباق قابلة للوصول: ضغط كافٍ على قائمة انتظار وحدة معالجة الرسومات لتأخير التنفيذ، وتوقيت ضيق بما يكفي بين الإتلاف والإرسال، وإعادة تخصيص مخزن مؤقت بنفس الحجم لتعظيم فرصة التلف الملحوظ.
تنقسم الاستراتيجية إلى خمس خطوات:
الخطوة 1 - الحجم والضغط: تخصيص 200 مخزن مؤقت مؤقت لتخزين WebGPU بأحجام عشوائية (جميعها مضاعفات 4 بايت كما هو مطلوب في مواصفات WebGPU). لا يتعلق الأمر بملء VRAM، بل بإنشاء قدر كافٍ من العمل المعلق بحيث لا تستطيع وحدة معالجة الرسومات تنفيذ الأوامر فورًا.
الخطوة 2 - تشبع خيوط الحوسبة: وضع 32 خط أنابيب حوسبة متوازي في قائمة الانتظار بأعباء عمل ثقيلة، وحلقات داخلية تعمل 1000 تكرار وأحجام إرسال 4096 مجموعة عمل. الهدف هو إبقاء قائمة انتظار وحدة معالجة الرسومات متخلفة بشدة بحيث تظل النافذة بين الإرسال والتنفيذ مفتوحة لفترة كافية للسباق.
الخطوة 3 - المصيدة: فور إرسال جميع مخازن الأوامر المؤقتة، يتم استدعاء destroy() على جميع المخازن البالغ عددها 200. في هذه المرحلة، تلقت وحدة معالجة الرسومات الأوامر ولكنها لم تنفذها بعد. لقد تجاوزت Dawn بالفعل التحقق من صحة وقت الإرسال. يتم تحرير VRAM.
الخطوة 4 - المشغل: 32 تخصيصًا جديدًا للمخازن المؤقتة باستخدام نفس الأحجام تمامًا مثل المخازن التي تم تحريرها للتو. إذا قام مُخصِّص VRAM بإرجاع نفس العناوين الفعلية، وهو ما سيفعله غالبًا نظرًا لتطابق الأحجام، فإن الأوامر المعلقة لوحدة معالجة الرسومات لديها الآن مقبض أجهزة يشير إلى ذاكرة تنتمي إلى تخصيص مختلف ونشط.
الخطوة 5 - إرسال أوامر إعادة الاستخدام: جولة أخرى من إرسال مخازن الأوامر المؤقتة باستخدام المخازن المخصصة حديثًا. في هذه المرحلة، هناك مجموعتان من الأوامر في قائمة الانتظار تشيران إلى ما كان في يوم من الأيام نفس الذاكرة، مع استمرار وحدة معالجة الرسومات في العمل على المجموعة الأولى.
النتيجة هي UAF كلاسيكي في طبقة VRAM: ذاكرة مُحررة تُقرأ بنشاط بواسطة تنفيذ التظليل الجاري.
قام الباحث بتشغيل الإثبات على كل من تثبيت Chrome الضعيف والمصحح ولاحظ انقسامًا سلوكيًا واضحًا:
تشغيل النسخة الضعيفة (Chrome < 146.0.7680.178):``` [INFO] CVE-2026-5281 AGGRESSIVE PoC Loaded [INFO] Initializing WebGPU context... [INFO] WebGPU device initialized [INFO] Starting aggressive UAF attacks... [ERROR] UNCAUGHT GPU ERROR: device lost due to internal error [CRASH] GPU DEVICE LOST: destroyed [CRASH] [!!!] CRASH DETECTED! Check console for details.
توقفت عملية Chrome المستهدفة عن العرض تمامًا. شهد نظام التشغيل تجميدًا بصريًا قصيرًا، وهو ما يتوافق مع اضطرار برنامج تشغيل العرض إلى إعادة التعيين أو إيقاف المعالجة بعد خطأ وحدة معالجة الرسومات. تم تعيين حدث فقدان الجهاز إلى خطأ فادح في وحدة معالجة الرسومات بدلاً من خطأ التحقق من صحة واجهة برمجة تطبيقات WebGPU القياسي، مما يؤكد أن تخطيط الذاكرة التالف وصل إلى طبقة الأجهزة دون أن يتم اكتشافه بواسطة وضع الحماية من جانب JavaScript في Chrome.
**تشغيل مصحح (Chrome >= 146.0.7680.178):**```
[INFO] CVE-2026-5281 AGGRESSIVE PoC Loaded
[INFO] Initializing WebGPU context...
[INFO] WebGPU device initialized
[INFO] Starting aggressive UAF attacks...
[INFO] Max attempts reached without crash
[INFO] Either browser is patched or target build not affected
لا يوجد تعطل، ولا فقدان للجهاز، ولا إشارات GPU قاتلة عبر جميع المحاولات. الإصلاح صامد.
تم التقاط اللقطات التالية أثناء اختبار مجموعة الأدوات في المختبر ضد كل من إصدار Chrome الضعيف وإصدار Chrome المُصحَّح للاختبار على جهاز ويندوز مزود ببطاقة رسومات مدمجة Intel gen-12lp. تم تشغيل كل أداة ضد كلا الهدفين للتحقق من الفرق السلوكي.
01 - كاشف الإصدار
| ضعيف (< 146.0.7680.178) | مُصحَّح (>= 146.0.7680.178) |
|---|---|
![]() | ![]() |
02 - فاحص الثغرات
| ضعيف | مُصحَّح |
|---|
![]() | ![]() |
03 - الماسح المحلي
| ضعيف | مُصحَّح |
|---|---|
![]() | ![]() |
04 - ماسح الأسطول
| ضعيف | مُصحَّح |
|---|---|
![]() | ![]() |
05 - مشغل UAF
| Chrome | Firefox |
|---|---|
![]() | ![]() |
تم تضمين Firefox للمقارنة. يستخدم Firefox تطبيقه الخاص لـ WebGPU ولا يتأثر بهذه الثغرة. يكمل جميع المحاولات دون أي إشارة تعطل بغض النظر عن الإصدار، وهو السلوك المتوقع.
06 - مشغل UAF + المُشغِّل الآلي
| فقدان جهاز GPU |
|---|
![]() |
ليس من السهل دائمًا الحصول على إشارة تعطل مرئية. اعتمادًا على العتاد والبيئة، قد يتطلب المشغل بعض الضبط لإنتاج نتائج قابلة للملاحظة. في حالتنا، كان السلوك قابلاً للتكرار، لكنه لم يكن مكشوفًا باستمرار دون تعديل حجم العمل.
قمنا بنجاح بإعادة إنتاج هجوم رفض الخدمة ضد تثبيت Chrome ضعيف في بيئة مختبرية محكومة. يتسبب مشغل UAF في تشبع GPU بنسبة 100% حيث يمنع قائمة الأوامر المكدسة بشدة برنامج التشغيل من خدمة طلبات إدارة الذاكرة الجديدة. خلال بعض عمليات التشغيل، دخلت عملية GPU في حالة خطأ غير قابلة للاسترداد، مما أنتج التأثيرات القابلة للملاحظة التالية:
يؤكد تشبع GPU والاستثناء العرضي أن تلف الذاكرة يصل إلى طبقة العتاد: يتم الوصول إلى مقبض المخزن المؤقت المُحرَّر بواسطة تنفيذ التظليل الجاري، يتعطل GPU، وتظهر آلية TDR الخاصة بـ D3D12 كحدث إزالة جهاز. أكمل الإصدار المُصحَّح نفس حجم العمل بشكل نظيف دون أي إشارة تعطل من أي نوع.
يؤكد إعادة إنتاج DoS وجود الثغرة. يتركز العمل الجاري على تحليل التصحيح على المستوى الثنائي، وتحديدًا مقارنة مسار إرسال أوامر Dawn بين آخر بناء ضعيف و 146.0.7680.178 لفهم أين وكيف تم تطبيق إصلاح احتساب المرجع بالضبط.
بخصوص المُشغِّل الآلي: نشر الباحث الأصلي سكريبت مشغل إلى جانب إثبات المفهوم الخاص به. تطلبت نسختنا تعديلات لتعمل بشكل موثوق في سياق المختبر المحلي، وتحديدًا التبديل إلى الوضع بدون رأس الجديد لـ Chrome وإضافة خيار للسماح بإشارات تعطل GPU بالانتشار من عملية GPU إلى المُقدِّم. بدون هذين العلمين، يمتص Chrome بصمت أعطال عملية GPU ولا يمكن ملاحظة الفرق السلوكي بين البناء الضعيف والمُصحَّح من JavaScript.
بينما لا يزال العمل على الهندسة العكسية والمقارنة الثنائية قيد التقدم، لم يتم نشر المُشغِّل الآلي في هذا المستودع. سيتم تضمينه في تحديث لاحق بمجرد اكتمال تحليل التصحيح.