يوم يتصرف كعنبر حقيقي
المحاكاة مكتوبة لتروي فترة ما بعد الظهر في عنبر: حالات الخروج تتجمع في أواخر الصباح وحالات الدخول تصل طوال المساء، فتبقى الأسرّة متسخة، ثم قيد التنظيف، ثم جاهزة ومنتظرة. وتسخن الغرف بأعطال التكييف، ويثقل الهواء في استراحة العائلات في ساعات الزيارة، وتضعف بطاريات المضخات حتى يوصلها أحد بالكهرباء، وتنتظر أجراس الاستدعاء أطول عند تبديل النوبات. كل جناح من الأجنحة الستة والثلاثين يعمل من بذرته الخاصة، فكل زائر يعيد عرض اليوم نفسه، ولا يغيّر يوم جناح يوم جناح آخر، والجناح 4A، حيث يبدأ العرض، يحتفظ بقصة مكتوبة فوق ذلك. ويعمل كل هذا في Web Worker، ويصل الجناح المعروض أولًا في أقل من 30 ملي ثانية، وبقية المستشفى بعده بأقل من ثانية.
من جناح واحد إلى المستشفى كله
يعمل النموذج على ثلاثة مقاييس. الجناح عنبران ووحدة عناية مركزة، قريب بما يكفي لقراءة سرير. والطابق يضع أجنحته الستة على صفيحة واحدة، تصل بينها ممرات زجاجية. و«كل الطوابق» يرسم الطوابق الستة متباعدة، كمقطع مفكك للمبنى، وكل منها ملون بالطبقة نفسها، فتظهر الغرفة الساخنة من الطرف الآخر للمستشفى. وبجانب النموذج خريطة للمبنى، كل جناح فيها مظلل حسب امتلائه ومعلّم حيث يوجد أمر حرج مفتوح، والنقر على جناح يطير إليه، ومسار فوق اللوحة يعيدك إلى الأعلى. والكاميرا تضبط كل مقياس بإسقاط زواياه عبر كاميرا تجريبية، فيبقى النموذج دائمًا بعيدًا عن العناصر المعروضة فوقه، وشريط العنوان يحفظ المقياس والعرض والطبقة والوقت والاختيار، فكل عرض رابط.
الرسم والنموذج مشهد واحد
عرض المسقط لا يستبدل النموذج بخريطة مسطحة. كل جدار ينخفض إلى مقطع على ارتفاع 15 سم فوق الأرضية ويغمق حتى لون الحبر، فيتحول النموذج إلى رسم المعماري ثم يعود، لجناح أو لطابق كامل، والتحميل الأول يؤدي الحركة نفسها بالعكس: يرتفع المسقط ليصير المبنى. وعرض القائمة يحمل البيانات نفسها في جدول، للوحة المفاتيح وقارئات الشاشة ولكل من يريد أن يمر عليها بسرعة.
مبنى حقيقي من نموذج BIM الخاص به
كل أجنحة المستشفى التجريبي مبنية على مخطط واحد، ولا يوجد مبنى حقيقي هكذا. لذلك صار التوأم يقرأ مبنى حقيقيًا أيضًا: عيادة Medical-Dental من buildingSMART، وهي عيادة حقيقية من طابقين منشورة للاختبار في ملف IFC بحجم 13 MB. يُقرأ الملف في Node وقت البناء، ويُقتطع حدّ كل غرفة من شبكتها نفسها، مع اسمها وتصنيفها والمساحة التي يذكرها النموذج؛ وتحمّل الصفحة 34 kB من الحدود والجدران والأبواب، ولا تحمّل أداة القراءة أبدًا. والمرجع أرقام النموذج نفسه: النموذج يقيس الغرفة إلى منتصف جدرانها، وبعد احتساب نصف الجدار تقع 258 غرفة من 259 في حدود 5% من المساحة المذكورة. وتُفتح العيادة من رابط بالطبقات والعروض والتنبيهات واللغتين نفسها، مع يوم مُحاكى على غرفها هي، يُعاد عرضه أو يصل مباشرة: يخدمها خادم التكامل مبنى قائمًا بذاته، بمواضيعه وقواعده وبثه الخاص.
أقرب مضخة متاحة، والطريق إليها
من أي سرير، يجد «أقرب جهاز متاح» مضخة المحاليل أو الكرسي المتحرك أو جهاز مسح المثانة، أو جهاز التنفس من سرير العناية المركزة، الأسرع وصولًا سيرًا في أي مكان في المستشفى. والطريق يُحسب على شبكة للمبنى من 4,296 نقطة: كل غرفة وبابها، وممرا كل جناح، والعبور عبر قلب المبنى، والممرات الزجاجية، والمصاعد. والكلفة بالثواني، 1.2 م/ث سيرًا، والمصعد انتظار تُضاف إليه ثوانٍ قليلة لكل طابق. للسؤال إجابات ممكنة كثيرة، فبحث Dijkstra واحد من الغرفة يصل إليها كلها، بينما يحتاج A* إلى بحث لكل مضخة، ويستغرق البحث بين 2 و11 ملي ثانية. والطريق يُرسم فوق الجدران، ويتسع العرض إلى الطابق أو المبنى ليحتويه، ولا يُحمَّل البحث إلا عندما يسأل أحد أول مرة، كملف مستقل حجمه 1.4 kB.
تنبيهات لا تعرف إلا الحاضر
التنبيه لا يحتفظ إلا بما كان معروفًا عند فتحه، وصياغته بحسب الدقيقة على الخط الزمني: ضُغط في 14:21، وتسع دقائق بلا استجابة. اسحب إلى أي وقت، ولن يكشف شيء ما سيحدث بعد ذلك. والخطورة تُقرأ في تلك الدقيقة أيضًا، فلا تصبح الغرفة الدافئة حرجة إلا بعد أن تتجاوز 26.5 °م.
تنبيهات يمكن الرد عليها
يستلم الموظف التنبيه ثم يرسله إلى الفريق المسؤول عنه: الصيانة للغرفة الساخنة، والتمريض لجرس استدعاء بلا رد، وخدمات النظافة لسرير بانتظار التنظيف، وإدارة الأسرّة لسرير نظيف بلا مريض. ولا ينتهي التنبيه إلا حين تنتهي حالته. ففي إدارة الإنذارات الاستلام للموظف والإنهاء للعملية نفسها، فلا يدّعي زرٌّ أنه يبرّد غرفة. وكل إجراء ينضم إلى اليوم بدقيقته: اسحب الوقت إلى ما قبل الاستلام فيعود التنبيه جديدًا، وكل غرفة تحتفظ بسجل يقول متى انتهى تنبيه قبل أن يستلمه أحد. وفي الوضع المباشر يذهب الإجراء إلى الخادم ويعود إلى كل الشاشات حدثًا. وما يُتخذ والخادم متوقف ينتظر في صندوق صادر حتى يعود الاتصال، ويُسجَّل مرة واحدة مهما أُرسل، ويتحقق من ذلك اختبار متصفح عبر انقطاع العرض نفسه.
أسرّة العنابر في الساعات الأربع القادمة
كل نظرة عامة تتوقع عدد أسرّة العنابر التي ستكون فارغة في الساعات الأربع القادمة، بعد طرح المرضى المنتظرين: رقمًا مرجّحًا، ومدى يُفترض أن يصيب أربع مرات من كل خمس، مرسومًا بجانب الساعات الأربع الماضية. ولا يُبنى إلا مما هو معروف في تلك الدقيقة: الأسرّة الجاري تنظيفها، وحالات الخروج التي خططت لها جولة الصباح، والوتيرة المعتادة للدخول، ويتحقق منه اختبار: التوقع المبني من البث المباشر حتى دقيقة ما، والمبني من التسجيل كله، يجب أن يتطابقا. واختبار رجعي يصنع التوقع كل نصف ساعة في كل جناح ويقارنه بما فعله اليوم بعد ذلك. بدت النسخة الأولى سليمة على الشاشة، وكان مداها يصيب نصف المرات فقط، فكشف الاختبار الرجعي الخطأين وراء ذلك.
بالإنجليزية أو بالعربية
مفتاح في الشريط العلوي يحوّل الواجهة كلها إلى العربية، من اليمين إلى اليسار، ويمكن لرابط أن يفتحها كذلك. ينعكس التخطيط، فتنتقل اللوحة إلى يسار النموذج وتتبادل العناصر العائمة أماكنها، بينما يبقى الوقت والمقاييس من اليسار إلى اليمين، كما في مشغّل الوسائط: الخط الزمني، والرسوم البيانية، وتدرجات الألوان، وخريطة المبنى. والتنبيهات مصاغة بالعربية بصيغ الجمع الست فيها، وأسماء الغرف مكتوبة بالعربية على الأرضيات. اخترت Vazirmatn بعد أن وضعت نصوص الواجهة نفسها في ستة خطوط عربية بجانب Schibsted Grotesk. ولا يُحمَّل هو ولا الفهرس العربي إلا في زيارة بالعربية، واختبار يقرأ الكود المصدري يفشل إذا فات الفهرس نص تعرضه الواجهة.
مباشرة، من سيل من الأحداث
الوضع المباشر يبني المستشفى من الأحداث عند وصولها بدلًا من يوم مسجل. خادم تجريبي في Web Worker يشغّل اليوم عبر بروتوكول JSON الذي سيستخدمه خادم تكامل حقيقي، بمعدل دقيقة مُحاكاة كل ثانية، والصفحة تضم كل حدث إلى اليوم نفسه الذي تقرؤه العروض أصلًا، فلم يحتج أي منها إلى تغيير. وأرقام التسلسل تحفظ السيل كاملًا: عند انقطاع الاتصال تقول الصفحة إن الطابق قديم، وتنتظر أطول قبل كل محاولة، ولا تطلب إلا الأحداث التي فاتتها، من آخر 2,000 حدث يحتفظ بها الخادم. واختبار يعيد تشغيل اليوم كله كأحداث ويتحقق أنه يُقرأ تمامًا كالتسجيل عند كل قراءة كل خمس دقائق.
من أنظمة المستشفى نفسها
أنظمة المستشفى لا تتكلم بلغة بث التوأم: حساسات المبنى وحالة الأسرّة ونداء التمريض وأوسمة التتبع، لكلٍّ منها بروتوكوله، ومعظمها يصل إلى MQTT عبر بوابة. لذلك يقف بينها وبين التوأم خادم تكامل: يشترك في موضوع لكل غرفة وجهاز وتدفق، ويفحص كل رسالة، ويجمع القراءات في إطار واحد كل خمس دقائق، ويستنتج كل تنبيه بنفسه بالحدود نفسها التي تستخدمها المحاكاة، ثم يقدّم البث الذي تقرؤه الصفحة أصلًا. وأمر واحد يشغّل مستشفى مُحاكى كاملًا على جهاز واحد، والعيادة بجانبه: الوسيط، والأنظمة وهي تنشر اليوم رسائل خامًا، وخادمًا لكل مبنى، والتوأم. ويرسل اختبارٌ اليومَ كله، 1,005,153 رسالة، ويجب أن يحوّلها الخادم إلى سجل الأحداث المسجَّل نفسه، 21,904 حدثًا ومعها التنبيهات الـ881 كلها، دون أن يُعطى أيًّا منها.
داخل لوحة تحكم أخرى
نادرًا ما يحظى التوأم بالشاشة وحده، لذا يمكن لأي صفحة أن تضمّنه: سكربت واحد حجمه 1 kB ووسم واحد، <cutaway-twin at="level-4">. وتخاطب الصفحة التوأم بالكلمات التي يستخدمها الرابط أصلًا. تفتح غرفة أو طبقة أو دقيقة وتشغّل اليوم، وتسمع ما يختاره المستخدم، والتنبيهات المفتوحة، وكل تنبيه لحظة فتحه، بلغة التوأم. ويعمل التوأم داخل iframe، فلا يلتقي React وthree.js وWebGL الخاصة به أبدًا بإطار عمل الصفحة المضيفة ولا بأنماطها، وبعد المصافحة يقبل الأوامر من ذلك المصدر وحده ولا يرسل تقاريره إلا إليه. وكل أمر تفحصه الدالة نفسها التي تقرأ الرابط، والأمر الذي لا يمكن تنفيذه يعود خطأً باسمه. وصفحة عمليات تجريبية تعرضه وهو يعمل، واختبار متصفح يضمّن التوأم في صفحة من مصدر آخر، ويحركه ويستمع إليه.
بلوحة المفاتيح وقارئ الشاشة
النموذج محطة واحدة في ترتيب التنقل بلوحة المفاتيح. ومفاتيح الأسهم تنتقل بين الغرف، أو بين الأجنحة في طابق أو في المستشفى كله، حسب ما يقع في ذلك الاتجاه على الشاشة، فتعني ما تراه العين أيًّا كان دوران الكاميرا، وEnter يفتح وEscape يعود خطوة إلى الخارج. والمؤشر يضيء الأرضية ويعرض الوسم نفسه الذي يظهر عند المرور بالماوس، وكل انتقال يُنطق بصوت مسموع، باسم الغرفة وحالتها. والتنبيهات التي تُفتح أثناء تشغيل اليوم أو بثه مباشرة تُنطق أيضًا، مجمّعة كل بضع ثوانٍ حتى لا يغرق المستمع في إعادة عرض سريعة. وعرض القائمة يحمل الطابق نفسه في جدول. ومع كل رفع للكود يفحص axe-core ثمانية عروض يمكن لرابط أن يفتحها، وفق WCAG 2.2 بمستويي A وAA، بمقاسي الحاسوب والهاتف. وجد في أول تشغيل مخالفة واحدة تكررت في كل عرض، وأُصلحت.
سريع لأنه يرسم أقل
اللوحة لا يُعاد رسمها إلا عندما يتغير شيء، فالمستشفى الساكن لا يكلف معالج الرسوميات شيئًا. وكل جناح مبني على مخطط واحد، فكل جزء من الهيكل instanced mesh واحدة لكل الأجنحة الستة والثلاثين، وأرضيات الغرف، وعددها 1,368، واحدة أخرى، وهي أيضًا هدف النقر. ولا يُحزم فيما يرسمه المعالج إلا ما يظهر في العرض: أول بناء للمستشفى كان يخفي الأجنحة الأخرى لكنه يرسلها إلى المعالج، 207,000 مثلث لجناح واحد، والحزم أعادها إلى 15,000. والأسرّة والمرضى وأثاث جانب السرير والأجهزة نماذج glTF، فيها 17,208 مثلثات مضغوطة إلى 129 KB، تُرسم كنسخ مكررة عبر shader لا يلوّن إلا الأجزاء التي تحمل حالة، مثل البطانية أو غلاف المضخة. وكل منها يتحول إلى بديل مبسط حسب بعده عن المكان الذي تنظر إليه الكاميرا، وإلى صندوق في عرض المستشفى كله، الذي يُرسم في 33 أمر رسم، أقل مما يحتاجه جناح واحد عن قرب. وحرارة الممرات وهواؤها تُقدَّر في fragment shader، من أبواب كل جناح، وهي 38 بابًا، موزونة بعرضها، وتُرسم خطوط التساوي وحد التنبيه من مشتقات فضاء الشاشة، وتفعيل تلك الطبقة يكلف إطارًا أو إطارين في الثانية.
يتكيف ويتعافى ومُختبر
الجودة تتكيف مع الجهاز: أربعة مستويات، من الإظلال المحيطي مع SMAA نزولًا إلى رسم بسيط بكثافة بكسلات أقل، تتدرج حسب معدل الإطارات المقاس أثناء حركة المشهد. وإن أُعيد تشغيل تعريف الرسوميات، يقول العرض إنه توقف مؤقتًا ويعيد بناء نفسه، وقد اختُبر ذلك والتأثيرات تعمل قبل الانقطاع، وهي تصل بعده، وهو تسابق كشفته الاختبارات الآلية. وكل رفع للكود يشغّل 113 اختبار وحدة، و30 اختبار متصفح مع WebGL حقيقي بمقاسي الحاسوب والهاتف، وفحوص إمكانية الوصول لاثني عشر عرضًا، وفحص جودة الكود، وفحص الأنواع، وحدًا لحجم كل حزمة، وأي فشل يوقف النشر.