لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 07/26/20 في كل الموقع
-
يبدو العمل المستقل من المنزل حلمًا يتحقق لهؤلاء العالقين في دوامة الدوام الكامل، إلا أنه بدوره يحمل في طياته مشاكله الخاصة، الجسدية والنفسية، والتي لا تكون واضحة في البداية، وقد يشكل التعامل معها أكبر تحدٍ يواجهك كمستقل، إلا أنه يمكن الفوز به، إذا كنت ترحب ببعض التغييرات في أسلوب حياتك. بالنسبة لكاتب المقال وربما بالنسبة لك أيضًا، أكبر تحديات هي: العزلة، ونقص التمارين، والإجهاد العقلي، سيتحدث المقال عنها على حدى، وكيف يمكن التعامل معها. سلبية العمل من المنزل يخبرنا كاتب المقال عن مدى شعوره بأنه محظوظ في أول يوم بعد أن استقال من آخر عمل مكتبي له ليبدأ مسيرته كمستقل متفرغ، إذ يستيقظ المرء الساعة التاسعة صباحًا ويحضر فطورًا معدًا من القلب، ويتلذّذ بأول كوب قهوة قبل الشروع في العمل، ولا تبدأ صعوبات أسلوب الحياة الجديد هذا بالظهور إلا بعد الأسابيع الأولى القليلة. العزلة لا تشعر بقيمة القدرة على الانخراط الاجتماعي السهل أثناء قيامك بأي عمل عادي إلا عندما تبدأ العمل كمستقل، فحينما عمل صديقنا في مطبخ، كان زملاؤه يمازحون بعضهم البعض طوال اليوم، وعمل آخر جعله يجلس في مهجع محاطًا بكثير من الأشخاص الذين كان يعرفهم، إذ لا يمكنك تجنب الانخراط الاجتماعي إذا كانت حياتك تعتمد عليه. عندما بدأ صاحبنا مسيرته كمستقل، كان يمكن أن تمر أيام كاملة دون أن يحادث أحدًا إلا بالرسائل النصية أو البريد الإلكتروني أو الاتصالات الهاتفية، ومن المؤكد أن العديد منكم مر بهذا، ويمكن لهذا أن يؤثر عميقًا، ويسبب لك القلق خصوصًا إذا كنت مستقلًا يعيش وحده. يمكن لعمل كهذا أن يتسبب بجداول عمل غريبة ويوتر علاقاتنا الاجتماعية الهشة أساسًا، وقبل أن تدرك ذلك ستجد نفسك ذلك الشخص ذا اللحية الشعثاء الذي يبتاع البسكويت في منتصف الليل مرتديًا خفّين. نقص التمرن ينتج عن الجداول اليومية الغريبة عادة سيئة أخرى، نقص التمرن، حيث يمكن أن يكون جسدك رشيقًا طوال حياتك لكن تفسد ساعات الجلوس الطويلة أمام الحاسوب ذلك في سنة أو سنتين، فيمكن أن يسبب هذا مشاكل قلبية، فتجد نفسك تتعرّق أكثر من الإنسان العادي بعد الجلوس من مشية خفيفة لمدة خمس دقايق، فتكون قد عوّدت جسدك على عدم التمرن والحركة. والمعلومة الصادمة هي أن هذا شائع بين المستقلين، الذي قد يعرضون أنفسهم لخطر أكبر من أمراض القلب والأوعية الدموية إذا ظلوا ملتصقين بالحاسوب، أغلبنا غير معتاد على التمرن في المنزل، بل يرونه نشاطًا غير منزلي، فيتهمون العمل المكتبي بتسبيب المشاكل الصحية بساعات عمله الطويلة، بينما يرتكبون نفس الخطأ في عملهم المستقل. الإجهاد النفسي هذه مشكلة أقل شيوعًا بين المستقلين إلا أن هذا ليس مؤشرًا إيجابيًا، فالسبب هو بيئة العمل الغريبة التي تسمح لك باستخدام فيس بوك أو Reddit أو أي مصدر تشتيت تختاره وتضيع وقتك به بعيدًا عن الضغط، فكأننا نستبدل مشكلة بأخرى. لكن تجنب الإجهاد العقلي أو الإنهاك أكثر من مسألة مصادر تشتيت، فيمكن للبعض قضاء أيام على مشروع واحد دفعة واحدة باستثناء بعض الاستراحات القصيرة، والبقاء مستيقظين طيلة بعض الليالي، مؤدين بأنفسهم إلى كارثة. للمشكلة عدة تجليات، فصاحبنا مثلًا يعاني من قلة الإنتباه للتفاصيل، قد تعاني أنت من نسيان مواعيدك النهائية، أو شيء مشابه، والفظيع في الإجهاد العقلي هو استمراره لفترة دون أن يُلاحَظ إلا عندما يكون قد نال من أدائنا. يقود هذا إلى نقطة سيتم تكرارها في أقسام المقال التالية: أفضل وسيلة للتعامل مع هذه المشاكل هي الإجراءات الوقائية منها، وسنتحدث الآن عن كيفية تطبيقها. كيفية التعامل مع هذه المشاكل التعامل مع العزلة كمستقلين، فإن أبسط طريقة للتخلص من العزلة هي إيجاد محيط عمل تعاوني، من المحتمل أن هذا الاقتراح قد خطر لك إذا كنت تعمل كمستقل منذ مدة، لنناقش إذًا بعض الحلول الأخرى. تزويد جدول عملك بالمكافآت لنفسك فكرة جيدة، يمكنك وضع موعد محدد لك لأخذ راحة وقضاء بعض الوقت مع أصدقائك بعد أن تنجز قدرًا جيدًا من مشروعك، هل أنهيت مشروعك خلال المدة المطلوبة، لم لا تتناول العشاء مع أصدقائك إذًا؟ قد يبدو نهجًا آليًا، لكن قد تكافئ نفسك بطريقة مختلفة، كالانضمام إلى دورة لليوغا أو دروس رقص، ما يقودنا إلى القسم التالي. التعامل مع نقص التمرن يمكنك تبني حلول في غاية الفعالية حيث تحل مشكلتين في النفس الوقت، كالانضمام إلى تمارين جماعية حيث يحل لك مشكلتين سبق لنا ذكرهما: العزلة، والنقص التمرن. في حالة صديقنا الكاتب، فإنه يأخذ دروسًا في الرقص، لذا علاوة على مقابلته لأشخاص جدد وإعادة جسمه لرشاقته، فإنه يكسب مهارة جديدة، أليس انتصارًا ساحقًا؟ النادي الرياضي خيار وارد، لكن إذا لم تكن من محبيه فهناك العديد من التمارين اليومية التي يمكنك القيام بها في المنزل بقليل من الاستثمار للبدء، مثل P90X، أو Insanity، أو DDP Yoga. التعامل مع الإجهاد العقلي وها قد وصلنا إلى مشكلتنا الأخيرة، الإجهاد العقلي، والمقال سيختصرها عليك ليتجنب إجهادك ولا يتسبب بها. أفضل وسيلة للتعامل مع هذه المشكلة هو التقليل من حدوثها قدر الإمكان، ستواجه دومًا كمستقل مواعيد نهائية مباغتة تستنزف قواك العقلية، لكن يمكن احتواء الضغط الناتج بتنظيم عبء العمل، وهذه بعض النصائح لمجابهة الإجهاد: حاول الالتزام بجدول حتى لو كان غير رسمي، إذ سيساعدك في تقدير مدة التي تلزم كل مشروع. ارفض المواعيد النهائية اللامعقولة، فلن يستفيد أحد من ضغطك على نفسك بالعمل بلا مغزى. نفّس عن نفسك بطريقتك المفضلة سواء كانت الطبخ، أو تناول الطعام في الخارج، أو الخروج مع الأصدقاء، أو لعب لعبة فيديو جديدة. خاتمة المشاكل السابق ذكرها من عزلة ونقص التمرّن والإجهاد العقلي ليس مما يجب التغاضي عنه، وإلا انحرفت بحياتك عن الطريق السوي وضرّت صحتك على المدى البعيد. الوقاية هي النهج الأساسي لمجابهة هذه المشاكل والتخلص منها إلى الأبد، لنراجع إذًا معًا خلاصة الحلول لها: كرّس وقتًا لأصدقائك وقابل أناسًا جدد. اجعل أسلوب حياتك أكثر حيوية واختر أي تمرين تفضله، طالما أنه يبعدك عن الكرسي. ابقِ حياتك الوظيفية مرتبة ومارس هواياتك المفضلة. ما المشكلة التي تعتبرها الأكبر حول العمل في المنزل؟ شاركنا تجربتك في تعليق في الأسفل! ترجمة -وبتصرف- للمقال How to Work From Home (And Stay Physically and Mentally Healthy) لصاحبه Alexander Cordova1 نقطة
-
1 نقطة
-
1 نقطة
-
1 نقطة
-
نعم يمكنك إضافتها إلى ملف الhtml قبل غلق الbody، أو يمكنك إضافتها في ملف منفصل. الكود بعد التنسيق: <!DOCTYPE html> <html dir="rtl" lang="ar"> <head> <meta charset="UTF-8"> <meta name="description" content="تجربة"> <meta name="keywords" content="HTML, CSS, JavaScript"> <meta name="author" content="تجربة"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>درس 1</title> <link rel="stylesheet" type="text/css" href="css/bootstrap.css" /> </head> <body> <center> <img src="/images/logo.jpg" alt="centered image" /> </center> <div class="container"> <div class="row col-md-6 col-md-offset-3"> <div class="panel panel-primary"> <div class="panel-heading text-center"> <label for="start">Start date:</label> <input type="date" id="start" name="trip-start" value="2018-07-22" min="2018-01-01" max="2018-12-31"> <input type="submit" class="btn btn-primary text-right" /> </div> <div class="panel-footer text-right"> <small>شكرا لكم</small> </div> </div> </div> </div> <script> var inputElement = document.querySelector('input[type="date"]'); var getCurrentDate = function (monthOffset) { today = new Date(); var dd = today.getDate(); var mm = today.getMonth() + 1; //As January is 0. if (monthOffset) { mm = mm + monthOffset; } var yyyy = today.getFullYear(); if (dd < 10) dd = '0' + dd; if (mm < 10) mm = '0' + mm; return (yyyy + '-' + mm + '-' + dd); }; var currentDate = getCurrentDate(); var maxDate = getCurrentDate(3); inputElement.value = currentDate; inputElement.min = currentDate; inputElement.max = maxDate; </script> </body> </html>1 نقطة
-
أهلاً بك @Ahmed Sawy تفسير الخطاً :- إنك تحاول الوصول الى عنصر غير موجود في المصفوفة من الأساس و هذا بسبب أن عدد العناصر في المصفوفة يبدأ من 0 , و ليس من 1 لنفرض أن لديك مصفوفة حجمها 4، ترتيب العناصر سيكون كالتالي 0 1 2 3 . و إذا أردت الوصول الى العنصر 4 سوف يظهر لك رسالة خطأ كالتي ظهرت لك الآن . حلول للمشكلة :- قم بتعديل الكود الخاص بك و استعمل length بدل size ليصبح بالشكل التالي:- for(int 1 = 0; i < list.length() ; i++){ //code } في حال لم ينجح الأمر ، قم بتعديل الكود الخاص بك بإنقاص 1 من حجم المصفوفة ليصبح كالتالي :- for(int i =0 ; i < list.size()-1 ; i++){ //code } في حالة نجح الأمر معك أرجو أن تخبرنا . شكراً لك1 نقطة
-
يمكنك عمل الآتي عن طريق الjavascript كالتالي: <script> var inputElement = document.querySelector('input[type="date"]'); var getCurrentDate = function (monthOffset) { today = new Date(); var dd = today.getDate(); var mm = today.getMonth() + 1; //As January is 0. if (monthOffset) { mm = mm + monthOffset; } var yyyy = today.getFullYear(); if (dd < 10) dd = '0' + dd; if (mm < 10) mm = '0' + mm; return (yyyy + '-' + mm + '-' + dd); }; var currentDate = getCurrentDate(); var maxDate = getCurrentDate(3); inputElement.value = currentDate; inputElement.min = currentDate; inputElement.max = maxDate; </script> قم بإضافة هذا الوسم بعد وسم الinput وقبل نهاية وسم الbody، وسيقوم بجعل الcurrent والmin بالتاريخ الحالي، والmax بعد ثلاثة أشهر. شرح الكود: var inputElement = document.querySelector('input[type="date"]'); قمنا بإختيار الوسم input الذي نوعه date ووضعه داخل المتغير inputElement، وسنقوم بالتعديل على خواصه. var getCurrentDate = function (monthOffset) { today = new Date(); var dd = today.getDate(); var mm = today.getMonth() + 1; //As January is 0. if (monthOffset) { mm = mm + monthOffset; } var yyyy = today.getFullYear(); if (dd < 10) dd = '0' + dd; if (mm < 10) mm = '0' + mm; return (yyyy + '-' + mm + '-' + dd); }; قمنا بتعريف دالة وظيفتها أن ترجع لنا التاريخ الحالي، نقوم بالحصول على التاريخ الحالي عن طريق new Date() وهو يرجع لنا تاريخ اليوم، وقمنا بوضعه داخل المتغير today. قمنا بإستخدام getDate و getMonth و getFullYear للحصول على اليوم والشهر والسنة، وقمنا بإرجاع التاريخ في الشكل المطلوب وهو على الشكل yyy-mm-dd. var currentDate = getCurrentDate(); var maxDate = getCurrentDate(3); inputElement.value = currentDate; inputElement.min = currentDate; inputElement.max = maxDate; وفي النهاية قمنا بإستخدام هذه الدالة للحصول على التاريخ الحالي، والتاريخ الحالي مضاف إليه ثلاثة أشهر، وقمنا بتعديل الخواص value و min و max للوسم.1 نقطة
-
تطبيق يعتمد على وجود المدن والاحياء بشكل كامل كيف يمكن ادراج المدن والاحياء باسمائها بشكل تلقائي دون الاضافة اليدوية عبر لوحة التحكم الباك ايند nod.js ، mangoDB1 نقطة
-
أنت لاتحتاج لتخزينها لأن هذا سيكلفك الكثير , وخاصة أن هذه الخدمة توفرها غوغل عبر خدمة Google Maps API بالتأكيد فإن هذه الخدمة توفرها غوغل وهذه مجموعة من المصادر التي تساعدك في استخدامها : يمكنك الإطلاع على كيفية إستخدام التقنية الخاصة بغوغل مابس من هنا هذا رابط الموقع الرسمي لمطوري غوغل لاستخدام google maps api with javascript من هنا هذا مقال بالعربية من أكاديمية حسوب عن استخدام التقنية مع صفحة ويب في تطبيقك من هنا1 نقطة
-
السلام عليكم أخي @محمد الثبيتي يمكنك القيام بذلك من خلال تخزين المدن والأحياء الخاصة بها في قاعدة بيانات محلية مثل Sqllite في نفس التطبيق وعرض تلك البيانات داخل التطبيق1 نقطة
-
أهلا بك محمد هل تقصد إسخدام API ك google maps أو ماذا تقصد بالشكل التلقائي أرجو توضيح من فضلك1 نقطة
-
في الحقيقة إمكانية الإستفادة ضعيفة وذلك في النقاط التالية : إذا كان منافسك مثلا هو example.com فهذا يعني أن محركات البحث قد تعرفت عليه من قبل و ذلك لمدى تعامل الخوارزميات الخاصة ب SEO وعرضها في الصفحات الأولى فعند البحث ب example ستكون لديه الأولية وإلا فلابد من كتابة الرابط كما هو example.net وهذا شيئ صعب الوصول إليه لأن أكثر من 90% من الزيارات تأتي من محركات البحث كغوغل وبينغ وياهو. أما من ناحية البراند أو اسم الشركة فلن تربح شيء لأنك في غالب الأمر تروج لمنافسك بنفس إسم النطاق فالعميل هنا سيظن أن النطاق example.net تابع لل example.com وبهذا ستخسر الترويج الذي خصصته للتسويق في حين أن العميل هنا لن يتذكر إمتداد النطاق بقدر ما يتذكر إسم النطاق وعند العودة للبحث باسم النطاق example ستكون الحالة الأولى التي ذكرناها سابقا . من الأحسن أن تكون المنافسة في الفكرة وليس في الإسم أو بالتنافس في العروض وكسب عملاء حتى من منافسيك. بالتوفيق1 نقطة
-
شكراً لك على ردك الكريم م. نزار ماضي لكن ألا ترى أن الأنظمة التي توفرها الموقع التصميم لا توفر فقط قوالب جاهزة فأنت تستطيع بناء قوالب من الصفر بدون استخدام قوالب جاهزة.. تماماً كاستخدام برامج التصميم مثل الفوتشوب وغيرها متى ما عرفت استخدام الأدوات بالشكل الصحيح.. فانت تمتلك نفس القدرة التي توفرها لك لغات البرمجة التي تعمل كـ(Front end) مثل (HTML - CSS) .. نعم قد تكون بحاجة إلى لغات برمجة أخرى التي تعمل كـ(Back end). ألا تتفق معي أنه ربما في المستقبل قد لا يكون هناك حاجة لاستخدام لغات مثل (HTML - CSS) وشكرا لك1 نقطة
-
I have used tons of Android Emulators but the best one is BlueStacks but in order to get more out it and best results you will need a high end system. However, you can also use Andy and KO Player as a alternative to BlueStacks and NOX.1 نقطة
-
إذا لم تسمع بعد عن WebAssembly، فستسمع عنه قريبًا على رغم من وجوده في كل مكان، فهو مدعوم من أغلب المتصفحات (وسيدعم الخادم قريبًا) وهو سريع ويُستخدم في الألعاب، وهو معيار مفتوح من اتحاد شبكة الويب العالميّة (W3C)، والتي هي المنظمة الدولية للمعايير الرئيسيّة لشبكة الإنترنت. ستندهش على الأغلب من ذلك، وسترغب في تعلم البرمجة به، لكن هذا ليس صحيح تمامًا، فأنت لا تكتب شيفرات باستخدام WebAssembly، لنأخذ بعض الوقت ونتعلم حول هذه التكنولوجيات التي تختصر في العادة إلى "Wasm". من أين أتت؟ إذا عدنا لعشرة سنوات إلى الوراء، سنجد أن جافاسكربت لم يكن سريعًا كفاية للكثير من الأشياء، فلغة الجافاسكربت كانت بلا شك ناجحة ومناسبة، فهي تعمل على أي متصفّح وتضيف للصفحات الحيويّة التي نعتبرها أمرًا عاديًا الآن، لكنه كان لغة عاليّة المستوى وهي غير مصمّمة للعمل على أعمال تستهلك الكثير من الحسابات. ومع ذلك، على الرغم من أن المهندسين المسؤولين عن متصفحات الويب الشهيرة كانوا متفقين بشكل عام على مشكلة الأداء، فلم يتفقوا حول حل لها. فلقد ظهر معسكران، بدأت جوجل مشروع عميل Native وبعد ذلك نسخة محمولة منه للتركيز على السماح للألعاب وبقيّة البرامج المكتوبة بلغة C و C++ للعمل في مكان آمن في كروم Chrome. وفي نفس الوقت، حصلت Mozilla على دعم Microsoft لـ asm.js، وهو أسلوب لتحديث المتصفح للعمل على مجموعة فرعية من تعليمات جافا سكربت منخفضة المستوى بسرعة كبيرة (ظهر مشروع آخر مكّن من تحويل شيفرات C و C++ إلى هذه التعليمات). لم يحصل أي معسكر على تبني واسع، لذلك اتفقوا جميعًا على التعاون في 2015 حول معيار جديد يدعى WebAssembly مبني على نهج بسيط مأخوذ من asm.js، وكما كتب Stephen Shankland في CNET: أعلنت موزيلا في 2017 عن منتج الحد الأدنى (Minimum viable product) للتجربة، وجميع المتصفحات تبنته في نهاية ذلك العام، وفي ديسمبر 2019، أطلقت مجموعة عمل WebAssembly مواصفات WebAssembly الثلاثة كتوصيات W3C. يعرّف WebAssembly صيغة شيفرة بصيغة ثنائية (binary code) محمولة للبرامج التنفيذيّة، و مقابلها بلغة التجميع، وواجهات لتسهيل التفاعل بين هذه البرامج والبيئة المستضيفة. تعمل شيفرة البرمجية لـ WebAssembly في آلات افتراضية ذات مستوى منخفض الذي يحاكي وظائف العديد من المعالجات الدقيقة التي يمكن تشغيلها عن طريق ترجمة فوريّة - Just-In-Time (JIT) - أو تفسير - interpretation -، يمكن لمحرّك WebAssembly العمل بنفس السرعة تقريبًا للترجمة في منصة Native. لماذا الاهتمام الآن؟ يأتي بعض من الإهتمام الأخير بـ WebAssembly من الرغبة في تشغيل شيفرات تستهلك الكثير من الحسابات في المتصفحات، فمستخدمي الحاسوب المحمول على وجه الخصوص، يقضون أغلب أوقاتهم في المتصفح (أو في حالة Chromebooks، كامل وقتهم)، لذلك خلق هذا الاتجاه إلحاحا حول إزالة الحواجز التي تحول دون تشغيل مجموعة كبيرة من التطبيقات في المتصفح، وواحدة من هذه الحواجز هي الأداء، والتي صمم WebAssembly في الأصل لمعالجتها. ومع ذلك، فإن WebAssembly ليس للمتصفحات فقط، ففي عام 2019، أعلنت موزيلا عن مشروع يدعى WASI اختصارًا للعبارة WebAssembly System Interface أي واجهة نظام WebAssembly لوضع معيار لكيفية تعامل شيفرة WebAssembly مع نظام التشغيل خارج سياق المتصفح، وبالجمع ما بين دعم المتصفح لـ WebAssembly و WASI ستتمكن من تشغيل ملفات الثنائيّة المترجمة في داخل وخارج المتصفحات، عن طريق مختلف الأجهزة وأنظمة التشغيل، بسرعة الآلة (Native) تقريبًا. بسبب أعباء WebAssembly المنخفضة سيكون من العملي استخدامه خارج المتصفحات، لكن هنالك العديد من الطرق الأخرى التي يمكننا من خلالها تشغيل تطبيقات بنفس الكفائة، فلماذا نستخدم WebAssembly تحديدًا؟ أهم سبب لهذا هو المحمولية، فاللغات المترجمة المستخدمة اليوم مثل C++ و Rust هي الأكثر ارتباطًا بـ WebAssembly اليوم. ومع ذلك، العديد من اللغات الأخرى تترجم إلى أو تملك آلاتها الافتراضيّة في WebAssembly، وعلاوة على ذلك، على الرغم من افتراض WebAssembly لبعض الشروط المسبقة لبيئات التنفيذ، فإنه مصمم للعمل بكفاءة على مجموعة واسعة من أنظمة التشغيل والبنيات، لذلك يمكن كتابة شيفرة WebAssembly باستخدام مجموعة واسعة من اللغات على نطاق واسع من أنظمة التشغيل وأنواع المعالجات. تنبع ميّزة WebAssembly أخرى، من حقيقة أن الشيفرة البرمجية تعمل في آلة افتراضيّة، ونتيجة لذلك، كل وحدة WebAssembly تنفذ في بيئة منعزلة عن وقت تنفيذ المضيف باستخدام تقنية عزل الخطأ (fault isolation). ويتضمن هذا من الأشياء الأخرى، أن تنفّذ التطبيقات في منعزل عن بقيّة بيئة المضيف ولا يمكنها الهروب من البيئة المنعزلة دون المرور عن طريق API. أمثلة عمليّة WebAssembly مثال على WebAssembly هو Enarx. يوفّر مشروع Enarx استقلاليّة الأجهزة لتأمين التطبيقات باستخدام بيئات التنفيذ الموثوق (Trusted Execution Environments)، فيسمح لك هذا الأخير بتسليم تطبيق مترجم إلى WebAssembly بشكل آمن إلى مزود السحابي (cloud) وتشغيله عن بعد، وكما يقول مهندس الأمن في Red Hat المهندس Nathaniel McCallum: ومثال آخر لذلك هو OPA أي عميل السياسة المفتوحة (Open Policy Agent)، والذي أعلن في نوفمبر 2019 أنه يمكنك ترجمة لغة تعريف السياسة الخاصة بهم Rego إلى WebAssembly، يسمح لك Rego بكتابة المنطق للبحث والجمع بين بيانات JSON/YAML من مختلف المصادر لسؤال عن أسئلة مثل "هل API هذا متاح؟". أستخدمت OPA لتطبيقات تفعيل السياسة (policy-enable software) والتي من بينها Kubernetes، ويُعتبر تبسيط السياسة باستخدام أدوات مثل OPA خطوة مهمة لتأمين نشر Kubernetes بشكل جيّد بين البيئات المختلفة، فمحمولية وميزات الأمن المدمجة في WebAssembly تعتبر أسلحة ممتازة لهذه الأدوات. آخر مثال على ذلك هو Unity، لقد ذكرنا في بداية المقال عن أنه WebAssembly يُستخدم في الألعاب، فيعتبر يونتي Unity والذي هو محرّك ألعاب متعدّد المنصات من أوائل المتبنين للـ WebAssembly، حيث وفروا أول نسخة تجريبيّة لـ Wasm في المتصفحات، ومنذ الشهر الثامن من سنة 2018، تُستخدم WebAssembly كهدف للمخرجات لهدف بناء Unity WebGL. نظرة أعمق على WebAssembly إن WebAssembly هو ملف ثنائي يمكن تشغيله من قبل جميع المتصفحات (باستثناء IE 11) عبر الأجهزتها الافتراضيّة، ولديه القدرة على البدء والعمل بشكل أسرع من جافا سكربت لأن الملف الثنائي يمكن فهمه بسهولة من قبل المتصفحات وسيعمل بطريقة مثاليّة، وإذا كنت مهتم بالتفاصيل التقنيّة التي تجعل من WebAssembly مميّز، فأنصحك بهذا المقال. وعلى الرغم من أنني بدأت بالبحث في WebAssembly عند بحثي عن طريقة كتابة Rust في بيئات أخرى (على سبيل المثال المتصفّح)، لكن ليس هذا ما يجعل WebAssembly مميّز، فأنا أستمتع بكتابة جافا سكربت (TypeScript على وجه الخصوص)، وبيئة تطوير الويب المبنيّة على جافا سكربت كبيرة للغاية ولا يمكن إلغاؤها، فيمكنك اعتبار WebAssembly كإضافة إلى جافا سكربت حيث يمكنك استخدامه في المهام التي يكون أداء جافا سكربت ضعيف. يمكن استخدام WebAssembly لكتابة تطبيقات ويب كاملة أو استبدال أجزاء من تطبيقات يكون أدائها غير جيّد كفاية ببديل يعمل بسرعة أكبر، وبالإضافة إلى ذلك، بما أن WebAssembly ملف تجميع مشابه للغة الآلة، فيمكن استخدام العديد من اللغات للترجمة إليه، أي مشاركة الشيفرة البرمجية مع المنصات الأخرى والويب أصبح الآن أكثر عملية. لغات تدعم WebAssembly يمكن استخدام العديد من اللغات للترجمة إلى WebAssembly، بما في ذلك C# وGo، فلماذا لا نستخدمهم بدلًا من Rust؟ على الرغم من أن استخدام لغات البرمجة هو أمر شخصي يختلف حسب تفضيلات الشخص، إلا أن هنالك العديد من الأسباب التي تجعل من Rust أفضل أداة لهذا العمل، فهذه اللغات تملك وقت تشغيل كبير يجب وضعه في ملف الثنائي لـ WebAssembly، لذلك فهي مناسبة فقط للمشاريع الجديدة غير المبنيّة على مشاريع أخرى (على سبيل المثال، فهي مناسبة كبديل لجافا سكربت)، هذا المقال ستجد في قسم Wasm في ويكي لغة GO يقول أن أصغر حجم ملف ثنائي غير مضغوط يمكن عمله هو 2 ميغابايت، بالنسبة للغة Rust، والتي تملك أجزاء وقت التشغيل صغيرة للغاية (مجرّد allocator)، فمثال "أهلا بالعالم" يُترجم إلى ملف بحجم 1.6 كيلوبايت على حاسوبي بدون تحسينات لخفض الحجم (والتي يمكنها تصغيره أكثر). أنا لا أقول أن للغات Go وC# مستقبل سيء بالنسبة لتطبيقات الويب، فأنا متشوّق حول جديدها، لكنني أعتقد أنها ستكون مناسبة للمشاريع الجديدة غير مبنيّة على مشاريع أخرى. على الرغم من أن لغات C و C++ تملك وقت تشغيل صغير للغاية مثل Rust وهي مناسبة لوضعها داخل التطبيقات والمكتبات الموجودة بالفعل، فإن Rust ستجعل من إنشاء ملفات WebAssembly ثنائيّة التي تستخدم واجهات جافا سكربت اصطلاحيّة إلى حد ما باستخدام الأدوات التي سنكتشفها في المقالات هذه السلسلة، في حين أن المعالجة في لغات C و C++ أكثر يدويّة. إن استخدام الأدوات في لغة Rust جميل للغاية وأعتقد أنها تجعل كامل التجربة ممتعة بشكل أكبر، وتمتاز لغة Rust بأنها لغة آمنة للذاكرة لذا فإن هذا الصنف من الأخطاء الموجودة في لغات C و C++ يستحيل وجوده في Rust، وإذا استخدمت لغات تملك ذاكرة آمنة مثل جافا سكربت وجافا وC# (وحتى إذا لم تستخدمها) سترغب باستخدام لغة Rust. لنسمي لغات C و C++ و Rust بلغات النظام، لأن هدفهم برمجة الأنظمة وتطبيقات عاليّة الأداء. تتشارك هذه اللغات بمميزات تجعلهم منسابين للترجمة إلى WebAssembly، سنتعرف في القسم القادم على المزيد من التفاصيل وسنعد أمثلة لشيفرات برمجية كاملة بلغات C و TypeScript مع عينات من لغة صيغة نص WebAssembly. أنواع البيانات الصريحة وجامع القمامة تتطلّب لغات الأنظمة أنواع بيانات صريحة مثل int وdouble للتصريح عن متغيرات القيم المرجعة من الدوال، فعلى سبيل المثال، توضح هذه الشيفرة البرمجية عملية جمع 64 بت في لغة السي: long n1 = random(); long n2 = random(); long sum = n1 + n2; دوال المكتبة random تعرّف نوع long للإرجاع: long random(); /* returns a long */ في أثناء الترجمة، تتحول الشيفرة المكتوبة بلغة C إلى لغة التجميع (أسمبلي) ومن ثم إلى لغة الآلة، تتحول الشيفرة البرمجيّة السابقة في لغة التجميع لـ Intel (نوع AT&T)، إلى ما يشبه هذا (حيث أن ## هي التعليقات): addq %rax, %rdx ## %rax = %rax + %rdx (64-bit addition) إن %rax و %rdx هي سجلات 64 بت، وتعليمة addq تعني أجمع quadwords، حيث أن quadwords هي 64 بت، والذي هو المعيار لنوع long في لغة سي، تترجم لغة التجميع التعليمات السابقة إلى لغة الآلة بما في ذلك الأنواع، حيث أن في العادة يقدم النوع من خلال خليط بين التعليمات والمعاملات، وفي هذه الحالة، تعليمة add هي addq (عملية جمع 64 بت)، وهنالك أيضًا addl والتي تجمع قيم 32 بت، أي نوع int في لغة السي. السجلات هي من نوع 64 بت (حرف r في %rax و %rdx) بدلًا من قطع 32 بت منه (على سبيل المثال %eax هو النسخة المنخفضة من 32بت من %rax و %edx هي النسخة 32بت المنخفضة من %rdx). تنفّذ عملية الجمع في لغة التجميع بأداء عالي لأن المعاملات مخزنة في سجلات CPU، ومترجم لغة C العادي (حتى لو استخدم تحسينات الوضع الافتراضي) سينتج شيفرة برمجيّة بلغة أسمبلي مشابهة للسابق. تعتبر لغات الأنظمة الثلاثة هي خيارات جيّدة للترجمة إلى WebAssembly بسبب تركيزها على أنواع صريحة كما في WebAssembly: i32 لقيمة عدد صحيح 32 بت و f64 لقيمة الفاصلة العائمة، وهكذا… تشجع أنواع البيانات الصريحة تحسين استدعاءات الدالة، فتملك الدالة مع نوع بيانات صريح توقيع يحدد أنواع البيانات للمعاملات والقيمة التي ستعود من الدالة (إذا كانت موجودة)، وفي الأسفل توقيع لدالة WebAssembly تسمى $add، وهي مكتوبة بشكل نص لغة WebAssembly كما سنتحدث عليها لاحقًا، تأخذ الدالة عددين صحيحين 32 بت كمعاملات وترجع عدد صحيح 64 بت: (func $add (param $lhs i32) (param $rhs i32) (result i64)) يجب أن يملك مترجم JIT للمتصفح على معاملات أعداد صحيحة 32 بت ويرجع قيمة 64 بت مخزنة في سجلات بالحجم المناسب. عندما نتحدث عن شيفرة برمجيّة عالية الأداء فإن WebAssembly تتربع على عرش ذلك، فعلى سبيل المثال asm.js هي لغة برمجة مشابهة لجافا سكربت لزيادة الأداء وجعلها مقاربة لسرعة الآلة، فتدعو هذه اللغة إلى تحسين الشيفرة البرمجيّة لتحاكي أنواع البيانات الصريحة الموجودة في لغات النظام، هذا المثال بلغة C وآخر بلغة asm.js، فعينة الدالة في لغة C هي: int f(int n) { /** C **/ return n + 1; } فكل من معامل n و نوع الإرجاع من نوع int بصراحة، والدالة المقابلة لذلك في asm.js ستكون هذه : function f(n) { /** asm.js **/ n = n | 0; return (n + 1) | 0; } فلغة جافا سكربت لا تعلن صراحة عن أنواع البيانات، لكن عملية OR بتيّة في جافا سكربت ترجع عدد صحيح، هذا مثال لعملية OR البتيّة عديمة الجدوى: n = n | 0; /* bitwise-OR of n and zero */ عمليّة OR البتيّة بين n و صفر تساوي n، لكن هدفنا هنا أن n يحتوي على عدد صحيح، فتعليمة return تخدعك عن طريق التحسين. يتميّز TypeScript بين أنواع جافا سكربت بتبني أنواع البيانات الصريحة، والتي ستجعل من هذه اللغة جذابة للترجمة إلى لغة WebAssembly (ستجد شيفرة برمجية تفسر هذا في الأسفل). الميّزة المشتركة الثانية بين أنظمة اللغات الثلاثة أنها تنفّذ دون جامع القمامة garbage collector (GC)، فمترجم لغة Rust لتخصيص الذاكرة بشكل حيوي يكتب شيفرات البرمجيّة الخاصة بالتخصيص وإلغاء التخصيص (allocation/deallocation) وبالنسبة لبقية اللغات، يقع هذا العمل على المبرمج حيث أن من مهامه تخصيص وإلغاء التخصيص بشكل صريح في هذه الذاكرة، لذلك فلغات الأنظمة تتجنّب تعقيدات جامع القمامة التلقائي. يمكن تلخيص ما عرفناه على WebAssembly في أن أي مقال على لغة WebAssembly تقريبًا يذكر سرعته القريبة من سرعة الآلة كأهم ميزة فيه، لذلك فإن هذه اللغات الثلاثة كانوا أول مشرحين للترجمة إلى WebAssembly. فصل المخاوف بين جافا سكربت و WebAssembly على عكس جميع الإشاعات، فلقد صممت لغة WebAssembly لدعم جافا سكربت وليس لاستبداله عن طريق توفير أداء أفضل في المهام الصعب، ولهذه اللغة أفضلية عند التنزيل، فالمتصفح يحصل على وحدة جافا سكربت كنص، وفي WebAssembly يحصل على صيغة ثنائيّة مضغوطة لتسريع التنزيل. من المهم معرفة كيف جافا سكربت وWebAssembly يعملان معًا، فجافاسكربت مصمم لقراءة وكتابة نموذج كائن المستند (Document Object Model - DOM)، الشجرة التي تمثل صفحة الويب، وعلى نقيض ذلك، لا يأتي WebAssembly على أي وظائف مدمجة لـ DOM، لكن يمكن لـ WebAssembly استيراد الدوال من جافا سكربت واستدعاءها حسب الحاجة، يفسر هذا كيفية عمل ذلك: DOM<----->JS<----->WebAssembly سيبقى جافا سكربت في أي نوع من أنواعه يدير DOM، لكن يمكنه استخدام وظائف الأغراض العامة من وحدات WebAssembly، كما في الشيفرة البرمجية السابقة. تسلسل Hailstone وتخمين Collatz هنالك أمثلة عديدة لشيفرة WebAssembly في وضع الإنتاج عند عملها بأداء عالي، مثل إنشاء أزواج مفاتيح تشفير كبيرة أو استخدام هذه المفاتيح للتشفير وفك تشفير، ومثال على ذلك يمكن اتباعه بسهول، هنالك عملية صعبة بأعداد كبيرة ويمكن لجافا سكربت التعامل معها بسهولة. هذه دالة hstone (اختصار لـ Hailstone)، تأخذ عدد صحيح كمعامل. تعريف هذه الدالة كالتالي: 3N + 1 إذا كان N عدد فردي hstone(N) = N/2 إذا كان N عدد زوجي على سبيل المثال، hstone(12) ترجع 6 في حين hstone(11) ترجع 34، إذا كان N عدد فردي، فإن 3N+1 هو عدد زوجي، وإذا كان N عدد زوجي، فإن N/2 إما عدد زوجي (مثال 4/2=2) أو فردي (مثال 6/2=3). يمكن استخدام دالة hstone بطريقة عودية عن طريق تمرير قيمة العودة كالمعامل التالي، وستكون النتيجة هي تسلسل hailstone مثل هذه، والتي تبدأ برقم 24 كمعامل أول، وترجع القيمة 12 كمعامل التالي وهكذا: 24,12,6,3,10,5,16,8,4,2,1,4,2,1,... يتطلب الأمر 10 استدعاءات للدالة حتى تستقر على الرقم واحد، وسيبقى التسلسل 4,2,1 يتكرر إلى ما لا نهاية لأن (3x1)+1 هو 4، لذلك يقسم على 2 ليعود 2، والذي يقسم على 2 ليكون 1 وهكذا دواليك، ولمزيد من المعلومات يمكنك الإطلاع على تفسير مجلة Plus حول لماذا اسم hailstone هو الاسم المناسب لهذا التسلسل. لاحظ أن أس 2 تتلاقى بسرعة كبيرة، حيث أنها تتطلّب N تقسيمات على 2 للوصول إلى 1، فعلى سبيل المثال 32 = 25 لديها طول تقارب 5 و 64 = 26 لديها طول تقارب 6 ، نهتم هنا بطول التسلسل من المعامل الأول إلى أول ظهور لرقم 1، فشيفرتي البرمجية بلغة C و TypeScript تحسب طول تسلسل hailstone. تخمين Collatz هو تسلسل hailstone يتقارب إلى 1 مهما كان المعامل N>0، فلم يستطع أحد تفنيد تخمين Collatz ولم يتمكن أي أحد الحصول على إثبات لجعل التخمين نظرية، فالتخمين، على الرغم من سهولة تجربته ببرنامج، يبقى مشكلة صعبة في الرياضيات. من C إلى WebAssembly في خطوة واحدة برنامج hstoneCL أسفله هو تطبيق ليس ويب يمكن ترجمته باستخدام مترجم Cعادي (على سبيل المثال GNU أو Clang)، يولّد هذا البرنامج عدد صحيح عشوائي قيمته N>0 ثمانية مرات ويحسب طول تسلسل hailstone بداية من N، دالتين مهمتين وهما main وhstone عند ترجمة التطبيق إلى WebAssembly. المثال 1 - دالة hstone في لغة السي #include <stdio.h> #include <stdlib.h> #include <time.h> int hstone(int n) { int len = 0; while (1) { if (1 == n) break; /* halt on 1 */ if (0 == (n & 1)) n = n / 2; /* if n is even */ else n = (3 * n) + 1; /* if n is odd */ len++; /* increment counter */ } return len; } #define HowMany 8 int main() { srand(time(NULL)); /* seed random number generator */ int i; puts(" Num Steps to 1"); for (i = 0; i < HowMany; i++) { int num = rand() % 100 + 1; /* + 1 to avoid zero */ printf("%4i %7i\n", num, hstone(num)); } return 0; } يمكن ترجمة الشيفرة البرمجية وتشغيلها من سطر الأوامر (حيث أن % موجه لسطر الأوامر) على أي نظام مشابه ليونكس: % gcc -o hstoneCL hstoneCL.c ## compile into executable hstoneCL % ./hstoneCL ## execute هذا مثال لمخرجات عند التشغيل: Num Steps to 1 88 17 1 0 20 7 41 109 80 9 84 9 94 105 34 13 تتطلّب لغات الأنظمة (بما في ذلك لغة السي) أداة مخصصّة لترجمة الشيفرة البرمجية إلى وحدة WebAssembly، بالنسبة للغات C وC++، يعتبر Emscripten هو الخيار الأكثر الانتشارًا مبني على بنية مترجم LLVM (Low-Level Virtual Machine)، استخدمت في امثلتي بلغة C على EmScripten، والذي يمكنك تثبيته بمساعدة هذا الدليل. يمكن جعل برنامج hstoneCL يعمل على الويب باستخدام Emscription لترجمة الشيفرة البرمجيّة - دون تغيير - إلى وحدة WebAssembly، تُنشئ أداة Emscription صفحة HTML مع جافا سكربت (في asm.js) الذي يتوسط بين DOM ووحدة WebAssembly التي تحسب دالة hstone، وهذه هي الخطوات: 1- ترجمة برنامج hstoneCL الذي لا يعمل على الويب إلى WebAssembly: % emcc hstoneCL.c -o hstone.html ## generates hstone.js and hstone.wasm as well يحتوي ملف hstoneCL.c على الشيفرة البرمجيّة الموجودة في الأعلى، و معامل -o لراية المخرجات والتي ستحدد اسم ملف HTML وسيحمل كل من شيفرة جافا سكربت المولّدة وملف ثنائي WebAssembly نفس الاسم (في هذه الحالة، hstone.js و hstone.wasm على التوالي)، النسخ الأقدم من Emscription (قبل الاصدار 13)، قد يتطلّب تضمين راية -s WASM=1 في أمر الترجمة. 2- استخدم خادم ويب Emscription (أو ما يعادله) لاستضافة تطبيق الويب: % emrun --no_browser --port 9876 . ## . is current working directory, any port number you like لتجاوز رسائل التحذيريّة، يمكنك تضمين راية --no_emrun_detect. يشغّل هذا الأمر خادم الويب، والذي يستضيف جميع الموارد في مجلد العمل الحالي، على وجه الخصوص hstone.html و hstone.js و hstone.wasm. 3- افتح المتصفح مع تفعيل WebAssembly (على سبيل المثال Chrome أو Firefox) وانتقل إلى العنوان : http://localhost:9876/hstone.html. تظهر هذه الصورة المخرجات من حاسوبي باستخدام متصفح Firefox: النتيجة رائعة خاصة أنك كتبت سطر واحد فقط دون أي تغييرات على برنامج C الأصلي. تحسين برنامج hstone للويب تترجم أداة Emscription برنامج C إلى وحدة WebAssembly وتولّد جافا سكربت المطلوب، لكن هذه الأداة مناسبة لشيفرة برمجيّة ولّدتها اللآلة، على سبيل المثال، ينتج asm.js ملف بحجم 100 كيلوبايت تقريبًا، تتعامل شيفرة البرمجيّة للجافا سكربت عدة سيناريوهات ولا تستخدم API الأخير الخاص بـ WebAssembly. نسخة مصغّرة من برنامج hstone للويب ستجعل من السهل التركيز على كيف تتعامل وحدة WebAssembly (الموجودة في ملف hstone.wasm) مع جافا سكربت (الموجود في ملف hstone.js). هنالك مشكلة أخرى: الشيفرة البرمجيّة لـ WebAssembly لا تملك حدود دالية في مصدر البرنامج كما في لغة السي، فعلى سبيل المثال، يملك برنامج ChstoneCL دالتين معرفتين من قبل المستخدم وهما main و hstone، ستكون النتيجة تصدير وحدة WebAssembly دالة تسمى _main لكنها لا تصدر دالة اسمها _hstone (حيث أن دالة main هي نقطة الدخول في برنامج سي). جسم دالة Chstone سيكون في دالة غير مصدّرة أي ملفوفة بـ _main، دوال WebAssembly المصدّرة هي نفسها التي يمكن لجافا سكربت استدعاؤها باسمها، وعلى الرغم من ذلك، من الأفضل تحديد أي دوال لغة المصدر يجب تصديرها بالاسم في شيفرة البرمجيّة لـ WebAssembly. المثال الثاني - برنامج hstone المنقح #include <stdio.h> #include <stdlib.h> #include <time.h> #include <emscripten/emscripten.h> int EMSCRIPTEN_KEEPALIVE hstone(int n) { int len = 0; while (1) { if (1 == n) break; /* halt on 1 */ if (0 == (n & 1)) n = n / 2; /* if n is even */ else n = (3 * n) + 1; /* if n is odd */ len++; /* increment counter */ } return len; } برنامج hstoneWA المنقح المعروض أعلاه، لا يملك دالة main، فلا حاجة له، لأن البرنامج ليس مصمم للعمل كبرنامج مستقل بل مخصص لوحدة WebAssembly مع دالة تصدير واحدة. يشير توجيه EMSCRIPTEN_KEEPALIVE (المعرّف في الملف الرأCemscripten.h) إلى المترجم لتصدير دالة _hstone في وحدة WebAssembly، إتفاقية الاسم واضحة للغاية: يبقى اسم دالة Cمثل hstone، لكن مع شرطة السفليّة كحرف أول في WebAssembly (أي _hstone في هذه الحالة)، وتتبع مترجمات WebAssembly أخرى اتفاقيات أسماء مختلفة. للتأكد من عمل ذلك، يمكنك اختصار خطوة الترجمة إلى إنتاج وحدة WebAssembly و جافا سكربت، لكن بدون HTML: % emcc hstoneWA.c -o hstone2.js ## we'll provide our own HTML file يمكن اختصار الملف HTML إلى هذا: <!doctype html> <html> <head> <meta charset="utf-8"/> <script src="hstone2.js"></script> </head> <body/> </html> يحمل ملف HTML ملف جافا سكربت، والذي يقوم بجلب وتحميل ملف WebAssembly الثنائي الذي يسمى hstone2.wasm، وبالمناسبة ملف WASM الجديد بنصف حجم الملف الأصلي تقريبًا. يمكن ترجمة الشيفرة البرمجية للتطبيق كالسابق ومن ثم تشغيله مع خادم الويب المدمج: % emrun --no_browser --port 7777 . ## new port number for emphasis بعد طلب وزيارة ملف HTML في المتصفح (في هذه الحالة Chrome)، يمكن استخدام كونسول ويب للتأكّد من تصدير دالة hstone على أنها _hstone. هذا مقتطف من جلستي في كونسول الويب، مع ## للتعليقات: > _hstone(27) ## invoke _hstone by name < 111 ## output > _hstone(7) ## again < 16 ## output يعتبر استخدام موجه EMSCRIPTEN_KEEPALIVE هو طريقة واضحة لجعل مترجم Emscripten وحدة WebAssembly تصدّر أي دالة إلى جافا سكربت، وهذا ما يقوم به هذا المترجم، وأي مستند HTML مخصّص مع جافا سكربت يدوي مناسب يمكنه استدعاء دوال من وحدة WebAssembly وذلك بفضل Emscripten. ترجمة TypeScript إلى WebAssembly مثال شيفرة البرمجيّة التالية بلغة TypeScript، والتي هي جافا سكربت مع أنواع بيانات صريحة، ويتطلب هذا Node.js مع مدير الحزم الخاص به npm، يثبت أمر npm التالي AssemblyScript والذي هو مترجم WebAssembly لشيفرة برمجية TypeScript: % npm install -g assemblyscript ## install the AssemblyScript compiler يتكون برنامج TypeScript hstone.ts من دالة واحدة، والتي تسمى hstone أيضًا، وسيسبق نوع البيانات i32 (عدد صحيح 32 بت) المعاملات وأسماء المتغيرات المحليّة (في هذه الحالة، n و len على التوالي): export function hstone(n: i32): i32 { // will be exported in WebAssembly let len: i32 = 0; while (true) { if (1 == n) break; // halt on 1 if (0 == (n & 1)) n = n / 2; // if n is even else n = (3 * n) + 1; // if n is odd len++; // increment counter } return len; } تأخذ دالة hsotne معامل واحد من نوع i32 وترجع قيمة من نفس النوع، ويشبه جسم الدالة ذلك الموجود في مثال لغة سي، ويمكن ترجمة الشيفرة المصدريّة إلى WebAssembly كالتالي: % asc hstone.ts -o hstone.wasm ## compile a TypeScript file into WebAssembly حجم ملف WASM hstone.wasm حوالي 14 كيلوبايت. لإيضاح كيف تحمّل وحدة WebAssembly، يتضمن ملف HTML في الأسفل (index.html في موقعي) سكربت جلب وتحميل وحدة WebAssembly hstone.wasm ومن ثم إنشاء مثيل لهذه الوحدة حتى يمكن استدعاء دالة hstone في كونسول المتصفح. المثال 3 - صفحة HTML لشيفرة TypeScript <!doctype html> <html> <head> <meta charset="utf-8"/> <script> fetch('hstone.wasm').then(response => <!-- Line 1 --> response.arrayBuffer() <!-- Line 2 --> ).then(bytes => <!-- Line 3 --> WebAssembly.instantiate(bytes, {imports: {}}) <!-- Line 4 --> ).then(results => { <!-- Line 5 --> window.hstone = results.instance.exports.hstone; <!-- Line 6 --> }); </script> </head> <body/> </html> يمكن تفسير عنصر script في HTML السابق سطرً سطرًا، فيستخدم استدعاء fetch في السطر الأول وحدة fetch للحصول على وحدة WebAssembly من خادم الويب الذي يستضيف صفحة HTML، وعند وصول إجابة HTTP، ستعمل وحدة WebAssembly كتسلسل من البيتات، والتي ستكون مخزّنة في arrayBuffer من السكربت في السطر 2، تتكوّن هذه البايتات من وحدة WebAssembly، والتي هي كامل الشيفرة البرمجيّة مترجمة من ملف TypeScript، هذه الوحدة لا تملك أي استدعاءات، كما هو مبيّن في نهاية السطر 4. في بداية السطر الرابع، سينشئ مثيل وحدة WebAssembly وتشبه هذه الوحدة لصنف غير ثابت مع أعضاء غير ثابتين في لغة كائنيّة التوجه مثل جافا. تحتوي الوحدة من متغيرات، دوال، وأدوات دعم مختلفة (artifacts)، لكن يجب إنشاء مثيل للوحدة قبل استخدامها كما في الصنف غير ثابت، وفي هذه الحالة في كونسول الويب، لكن بصفة عامة في شيفرة جافاسكربت مناسبة. يصدّر السطر السادس من السكربت دالة hstone من TypeScript الأصليّة بنفس الاسم، وستكون دالة WebAssembly متاحة لأي شيفرة جافا سكربت، كما ستؤكد جلسة أخرى في كونسول المتصفح. يملك WebAssembly API أكثر إيجازًا لجلب وإنشاء مثيل وحدة، يقلل API الجديد السكربت السابق لعمليتي جلب وإنشاء مثيل، بالنسبة إلى النسخة التي عرضناها هنا لإيضاح فائدة التفاصيل، وبشكل خاص، عرض وحدة WebAssembly كمصفوفة بايت التي ينشئ مثيلها ككائن مع دوال المصدّر. الهدف هو الحصول على صفحة ويب تحمّل وحدة WebAssembly بنفس طريقة وحدة JS ES2015: <script type='module'>...</script> سيعمل جافا سكربت على جلب وترجمة ومعالجة وحدة WebAssembly كما لو كانت مجرّد واحدة JS أخرى. لغة صيغة النص (text format language) يمكن ترجمة الشيفرة الثنائيّة لـ WebAssembly من وإلى مرادفها بصيغة النص، فالشيفرة الثنائيّة تكون موجودة في ملفات بصيغة WASM، في حين أن نصوص قابلة للقراءة من قبل المبرمجين تكون موجودة بملفات بصيغة WAT. إن WABT هي مجموعة من عشرات الأدوات للتعامل مع WebAssembly، بما في ذلك للترجمة من وإلى صيغ مثل WASM و WARK ومن بين أدوات التحويل wasm2wat و wasm2c و wat2wasm. تتبنى لغة صيغة النص صياغة S-expression (S تعني رمزي symbolic) الشائعة في Lisp، تمثل S-expression واختصارها sexpr شجرة كقائمة مع العديد من القوائم الفرعية بشكل اعتباطي، فعلى سبيل المثال، يحدث هذا sexpr بالقرب من نهاية ملف WAT لمثال TypeScript: (export "hstone" (func $hstone)) ## export function $hstone by the name "hstone" الشجرة التي تمثله هي التاليّة: export ## root | +----+----+ | | "hstone" func ## left and right children | $hstone ## single child في الصيغة النصيّة، وحدة WebAssembly هي sexpr حيث أن الجزء الأول هي الوحدة module والتي هي جذر الشجرة. هذا مثال ثاني لوحدة معرّفة ومصدّرة كدالة فرديّة، والتي لا تأخذ أي معامل لكنها ترجع ثابت 9876: (module (func (result i32) (i32.const 9876) ) (export "simpleFunc" (func 0)) // 0 is the unnamed function's index ) تعرّف هذه الدالة دون اسم (كما في lambda) وتصدّر بالإشارة إلى مؤشر 0، والذي هو مؤشر أول sexpr متداخل في الوحدة، وإن اسم دالة التصدير هي السلسلة النصيّة "simpleFunc". الدوال في صيغة النص تملك نمط قياسي، والذي يمكن تفسيره على النحو التالي: (func <signature> <local vars> <body>) يحدّد التوقيع المعاملات (إذا كانت موجودة) ويرجع قيمة العودة (إذا كانت موجودة)، فعلى سبيل المثال، هذا توقيع لدالة لا تملك اسم تأخذ معاملين من نوع عدد صحيح 32 بت وتعيد قيمة عدد صحيح 64 بت: (func (param i32) (param i32) (result i64)...) يمكن إعطاء الأسماء إلى الدوال والمعاملات والمتغيرات المحليّة، حيث يبدأ الأسم بعلامة دولار: (func $foo (param $a1 i32) (param $a2 f32) (local $n1 f64)...) يعكس جسد دالة WebAssembly بنية الآلة الأساسية لهذه اللغة، فتخزين المكدس هو الأساس، ومثال ذلك دالة تضاعف معامل عددها الصحيح وتعيد القيمة الجديدة: (func $doubleit (param $p i32) (result i32) get_local $p get_local $p i32.add) تدفع كل واحدة من عمليات get_local، والتي تعمل على المتغيرات المحلية والمعاملات المشابهة، معامل 32 بت إلى المكدس، وستخرج عملية i32.add أعلى قيمتين (والتي هي في هذه الحالة، القيم الوحيدة) من المكدس بجمعهم، وستكون النتيجة هي القيمة الوحيدة الموجودة في المكدّس وبالتالي سترجع من دالة $doubleit. عند ترجمة شيفرة WebAssembly إلى لغة الآلة، يجب استبدال أساس مكدس WebAssembly عند الإمكان بسجلات الأغراض العامة، وهذه مهمة مترجم JIT، والتي تترجم شيفرة آلة المكدس الافتراضية لـ WebAssembly إلى شيفرة آلة حقيقيّة. لا يفضل مبرمجو الويب كتابة WebAssembly بصيغة النص، حيث أن الترجمة من لغة عالية المستوى يعتبر خيار أفضل لهم على عكس كتّاب المترجم، حيث سيجدون من المفيد العمل عليها. الخاتمة على الرغم من إحراز الكثير من هدف WebAssembly للوصول إلى سرعة مقاربة لآلة (Native)، لكن لايزال مترجم JIT لجافا سكربت يتحسن مع ظهور أنواع مناسبة للتحسين (مثل TypeScript) تقترب من سرعة الآلة (native)، فهل هذا يعني أن WebAssembly هو مضيعة للوقت؟ لا أعتقد ذلك. يعالج WebAssembly هدفًا تقليديًا آخر في الحوسبة: إعادة استخدام الشيفرة البرمجية ذات معنى، كما توضح الأمثلة المختصرة في هذا المقال، فإن الشيفرة البرمجيّة بلغة C أو TypeScript، تترجم بسهولة إلى وحدة WebAssembly والتي تعمل بشكل جيّد مع شيفرة برمجيّة خاصة بجافا سكربت وهو الرابط بين التقنيات المستخدمة في الويب، وبالتالي يدعو WebAssembly إلى إعادة استخدام الشيفرة البرمجيّة وتوسيع استخدام التعليمات الجديدة، على سبيل المثال، قد يكون برنامج عالي الأداء لمعالجة الصور مكتوب كتطبيق سطح المكتب مفيدًا أيضا في تطبيق ويب، لذلك سيكون من الأفضل استخدام WebAssembly (بالنسبة لوحدات الويب الجديدة ذات صلة بالحسابات، سيكون WebAssembly هو خيار جيّد). وحدسي يقول أن WebAssembly ستزدهر بنفس القدر لإعادة استخدام للأداء. ترجمة -وبتصرف- للمقالات: WebAssembly for speed and code reuse لصاحبه Marty Kalin Why everyone is talking about WebAssembly لصاحبيه Gordon Haff وMike Bursell Why should you use Rust in WebAssembly? لصاحبه Ryan Levick1 نقطة