اذهب إلى المحتوى

لوحة المتصدرين

  1. Amer Abdallah

    Amer Abdallah

    الأعضاء


    • نقاط

      8

    • المساهمات

      150


  2. بلال زيادة

    بلال زيادة

    الأعضاء


    • نقاط

      4

    • المساهمات

      4376


  3. Moatasm Elshahry

    Moatasm Elshahry

    الأعضاء


    • نقاط

      4

    • المساهمات

      15


  4. Khaled Mohammed7

    Khaled Mohammed7

    الأعضاء


    • نقاط

      3

    • المساهمات

      24


المحتوى الأكثر حصولًا على سمعة جيدة

المحتوى الأعلى تقييمًا في 08/16/21 في كل الموقع

  1. لنفترض أن لدي مصفوفة بسيطة كالتالي: >>> import numpy as np >>> lst = [np.array([1, 2, 3]), np.array([[4, 5, 6],[7, 8, 9]])] ما أحاول فعله هو تحويل القائمة السابقة إلى مصفوفة Numpy واحدة كالتالي: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) أنا أقوم بحلها عن طريق التكرار على vstack في الوقت الحالي ولكنها يبدو أن هذه العملية بطيئة حقًا خصوصًا عند إستعمال قائمة كبيرة. ما هي أفضل طريقة فعالة للقيام بعملية التحويل هذه؟
    2 نقاط
  2. لدي مشروع في material-ui ، nextjs. أحاول جعل شريط التنقل الخاص بي يعمل مع nextjs: import * as React from 'react'; import AppBar from '@material-ui/core/AppBar'; import Link from "next/link"; import {Tab, Tabs} from "@material-ui/core"; export default function NavBar() { return ( <AppBar position="static"> <Tabs> <Tab label="Timer"><Link href="timer" /> </Tab> <Tab label="Home" to="/" component={Link} /> </Tabs> </AppBar> ); } لكنه يتسبب في فشل البناء. هل هناك شيء مفقود؟
    2 نقاط
  3. كيفية تحويل مصفوفة من النصوص: ["1.1", "2.2", "3.3"] إلى مصفوفة من نوع float: [1.1, 2.2, 3.2] في مكتبة Numpy؟
    2 نقاط
  4. الإصدار 1.0.0

    47114 تنزيل

    يضع هذا الكتاب المُوجز القارئ على أعتاب عالم تصميم تجربة المُستخدمين UX، وهو علم له قواعده وأصوله وأدواته، ويهدف إلى تعريف القارئ المُبتدئ بأساس هذا العلم وكيف يُطبّق على المُنتجات الرّقمية من مواقع ويب خدميّة وتطبيقات على الأجهزة الذّكية وصولًا إلى التّصميم الأمثل الّذي يُوفِّق بين هدف المُستخدم أوّلًا وهدف الخدمة التّجاريّ، الأمر الّذي يعني منتجًا ناجحًا. يبدأ الكتاب بشرح مفاهيم عامة عن تجربة المستخدم ليواصِل مع شرح كيفية إجراء مختلف الدراسات التي يحتاج المصمِّم للقيام بها، ومتطلباتها، ثم الأمور الواجب أخذها بالحسبان عند التصميم لضمان تجربة استخدام مريحة وممتازة، ليختتم في النهاية بالإشارة إلى أهمية الإحصائيات وضرورة الاعتماد عليها، حيث خُصّصت عدة أقسام لهذه النقطة، لتشير إلى مدى أهمية اعتماد بيانات وإحصائيات المستخدمين مثل أساس للتصميم، وكذا أبرز الإحصائيات الممكن التحصل عليها من خلال عدة اختبارات. يمكنك قراءة فصول هذا الكتاب مباشرةً على شكل مقالات، وإليك العناوين: مدخل إلى تجربة المستخدم User Experience فهم ودراسة المستخدمين في مجال تجربة المستخدم دراسة الشريحة المستهدفة في مجال تجربة المستخدم كيفية التصميم للأجهزة المختلفة هندسة المعلومات في تجربة المستخدم تعرف على أنماط التصميم في مجال تجربة المستخدم أشياء لا يمكن اعتبارها رسوما تخطيطية (Wireframes) في مجال تجربة المستخدم تعرف على الرسوم التخطيطية (Wireframes) في مجال تجربة المستخدم مفهوم الثقل المرئي (Visual Weight) والألوان في مجال تجربة المستخدم التكرار ومخالفة الأنماط في مجال تجربة المستخدم المحاذاة والقرب في مجال تجربة المستخدم تعرف على أساليب مسح الواجهة والتراتب المرئي في مجال تجربة المستخدم أساليب الإطلاع في مجال تجربة المستخدم: التصفح، البحث والاكتشاف تصميم هيكل صفحة الويب والعناصر الأساسية في مجال تجربة المستخدم الأزرار، النماذج والدعوات إلى الإجراء في مجال تجربة المستخدم استخدام علم النفس في مجال تجربة المستخدم لتكييف المستخدم وإقناعه كيف تغير الخبرة من تجربة المستخدم؟ تصميم تجربة المستخدم من خلال بيانات وإحصائيات المستخدمين تعرف على أنواع المخططات الإحصائية في مجال تجربة المستخدم اختبارات أ/ب (A/B Test) في مجال تجربة المستخدم
    1 نقطة
  5. لدي مصفوفة على الشكل : months=['January','February','March','April','May','June','July','August','September','October','November','December'] واريد تحويلها لتظهر على الشكل : months = {1:'January', 2:'February',....} قمت باستخدام enumerate() لكنها لم تفلح معي رغم اني اعرف انها يمكنها ان تفعل هذا فما الحل؟
    1 نقطة
  6. هل توجد طريقة في بايثون لاضافة key جديد على قاموس تم انشاؤه بالفعل؟ لقد بحثت كثيرا لكن لم اصل لاجابة.
    1 نقطة
  7. أريد ان اعرف كيف يمكنني ترتيب القيم داخل القاموس بالقيمة value، كترتيب ال value بشكل تصاعدي او تنازلي علي سبيل المثال.
    1 نقطة
  8. أنا أبحث عن أسرع طريقة للتحقق من وجود NaN (np.nan) في مصفوفة NumPy ، لكن إستعمال دالة isnan غير وارد ، لأنها تنشئ مصفوفة منطقية boolean من الشكل arr.shape ، والتي من المحتمل أن تكون عملاقة (حسب حجم المصفوفة arr). لقد جربت np.nan كالتالي: np.nan in arr لكن يبدو أن هذه الطريقة لا تعمل لأن: np.nan != np.nan # True لا أفهم لماذا الشرط السابق يتحقق True، لكن يبدو أن إستعمال np.nan غير وارد بسبب الشرط السابق. هل هناك طريقة سريعة وفعالة للقيام بذلك في Numpy؟
    1 نقطة
  9. حاولت فهم وظيفة الدالة forEach في js ولكن لم أفهم هل هي مثلا تمثل عنصر ما أو parameter ما array
    1 نقطة
  10. اذا كنت تفهم وظيفة الدالة for فيمكنك فهم وظيفة foreach لأنهما متقاربتان من بعضهما البعض ولديهما نفس الهدف, وهو القيام بحلقة تكرار على مصفوفة , لنحاول شرحها باستخدام كود, لاحظ الكود التالي const myArray = ['a', 'b', 'c']; myArray.forEach(element => console.log(element)); لدينا مصفوفة وتحتوي على ثلاثة عناصر كما تلاحظ, أريد ان أطبع هذه العناصر الثلاثة, يمكننا فعل ذلك عن طريق عمل حلقة تكرار على المصفوفة هذه, يمكننا استخدام for او foreach , استخدمت في هذا الكود foreach, فكرة عملها بسيطة جدا, تقوم الدالة باستقبال عنصر واحد في كل حلقة, هذا العنصر بالتأكيد ينتمي للمصفوفة التي اجريت عليها حلقة التكرار, في البداية تستقبل العنصر الاول, ثم الثاني , وهكذا الى أن تصل للعنصر الأخير, يتم استقبال العنصر وتخزينه في المتغير element, وبالطبع يمكنك تسميته كما تريد فمثلا سوف أسميه data myArray.forEach(data => console.log(data)); بعد تخزين العنصر في المتغير data نستطيع أن نجري عليه العمليات التي نريد, في المثال قمت بطباعته فقط
    1 نقطة
  11. لدي مصفوفتين كالتالي: >>> import numpy as np >>> x = np.matrix([[1, 2], [5, 6]]) >>> y = np.matrix([[3, 4], [7, 8]]) وأريد حساب ناتج ضرب هادامار Hadamard Product (يعرف أيضًا بـ element-wise product)، والذي يتم عبر ضرب المصفوفتين بالشكل التالي: [ [1*3, 2*4], [5*7, 6*8] ] # أو ما يساوي [ [3, 8], [35, 48] ] حاولت أن أستعمل دالة dot و ضرب المصفوفتين مباشرة: print(np.dot(x, y)) print(x * y) ولكن كلا الطريقتين أخرجت النتيجة التالي: [[17 20] [57 68]] وهو حاصل ضرب المصفوفة، وليس ناتج ضرب هادامار. كيف يمكنني الحصول على element-wise product (المعروف أيضًا باسم Hadamard product) باستخدام مكتبة Numpy؟
    1 نقطة
  12. السلام عليكم ورحمة الله بدون قصد لم اطبق الشرط الثالث من شروط التقدم للامتحان لانني لم اقرءه او لم انتبه له سابقا و هاقد اتممت 3 مسارات من الدورة فهل هذا ياثر على حصولي على الشهادة !! وكيف يمكنني مشاركة المسارات المتبقية لي مع الاكدمية على GitHub ,اريد بعض التوضيح لاوفي القيام بهذا الشرط وشكرا لكم
    1 نقطة
  13. لدي رقم يتكون من عدة خانات كل خانة بها ٤ ارقام اريد جلب اول رقم من كل خانة $number = "21 1 10 0,22 0 0 0,23 0 0 0,24 0 0 0,25 0 0 0,26 0 0 0,27 0 0 0,28 0 0 0"; اريد النتيجة تكون 21,22,23,24,25,26,27,28 طبعا استخدم لغة php
    1 نقطة
  14. أتتبع دورة تعليمية، في كيراس، لكن عند محاولتي تطبيق ذلك ظهر لي الخطأ التالي: from keras.layers import Conv2D, MaxPooling2D,Dense, Dropout, Activation, Flatten from keras.models import Sequential from keras.preprocessing.image import ImageDataGenerator --------------------------------------------------------------------------- ImportError Traceback (most recent call last) <ipython-input-13-3a12c6f32fcf> in <module>() ----> 1 from keras.layers import Conv2D, MaxPooling2D,Dense, Dropout, Activation, Flatten ImportError: cannot import name Conv2D
    1 نقطة
  15. لمعرفة الاحداثيات عند مكان ضغط المستخدم يمكنك الاستفادة من التابع onPress كما يلي <MapView style={{flex: 1}} onPress={({ coordinate, position}) => { const {latitude, longitude} = coordinate // الان اصبح لديك الاحداثيات التي تم الضغط عليها }}> </MapView> لمعرفة وجود مكان مميز عند تلك الاحداثيات، يجب الاستعلام عن ذلك من مزود معلومات الاماكن المميزة حسب تطبيقك : اما من بيانات الاماكن المميزة التي يوفرها تطبيقك (في قاعدة البيانات لديك مثلا) أو الاستفادة بالاشتراك بمزود معلومات خرائط طرف ثالث مثل Google Maps
    1 نقطة
  16. تحديد المسافة بين موقعين باستخدام php فلدي قيمة x , y الخاصة بي و لدي قيمة x, y للموقع الذي اريد تحديد المسافة بيني و بينه
    1 نقطة
  17. يمكن ايجاد المسافة باستخدام التابع التالي function distance($x1, $y1, $x2, $y2) { return sqrt(pow(abs($x1 - $x2), 2) + pow(abs($y1 - $y2), 2)); } أو استعمال التابع hypot في PHP كما يلي $distance = hypot($x1 - $x2, $y1 - $y2); كلا الطريقتين تعتمدان مبدأ معادلة حساب الوتر المتشكل بين النقطتين
    1 نقطة
  18. عند عمل مشروع بالووردبريس عن طريق MAMP و اختيار مجلد المشروع ف ان الاتصال بال Apache و MySQL ينجح و عند الضغط على open WebStart يفتح صفحة http://localhost/MAMP/ و هية تعمل بشكل جيد لكن عند الذهاب الى My WebSite يظهر لي الخطئ localhost is currently unable to handle this request. HTTP ERROR 500 قمت بحذف البرنامج و اعادة تثبيته و نفس المشكلة
    1 نقطة
  19. كيف اجعل الخريطة تظهر باللغة العربية ليست الانجليزية فى الوقت الدى فيه ال simulator لغته english وليست عربى فى React Native <MapView style={{flex: 1}} region={region}> {ads.map((item, index) => ( <Marker title={item.title} description={item.description} key={index} coordinate={item.region}> <Image style={{width: 26, height: 28}} resizeMode="contain" source={require('../../assets/map/marker.png')} /> </Marker> ))} </MapView>
    1 نقطة
  20. لماذا يعطي Numpy هذه النتيجة: >>> import numpy as np >>> arr = np.array([5.51,0.0,8.7,5.4]) >>> arr.argsort() # Output: [1, 3, 0, 2] كنت أتوقع أن تكون النتيجة كالتالي: [3, 1, 2, 0] لكن من الواضح أن هناك شيء مازلت أجهله بشأن هذه الدالة، هل يمكن لأحد أن يشرح لي فائدة argsort وكيفية عملها؟
    1 نقطة
  21. ربما استطيع مساعدتك في برمجة دالة تحدد المسافة , فلنقم بصنع دالة وليكن اسمها getDistance function getDistance(){ } و لنمرر لها المتغيرات الأتية و هي $lat1, $lon1, $lat2, $lon2, $radius بحيث $lat1, $lon1 هي أحداثيات الموقع الخاص بك و $lat2, $lon2 هي أحداثيات الموقع الذي تريد جلب المسافة بينك وبينه و $radius هو نصف قطر بين كل أحداثيين فتكون الدالة بهذا الشكل function getDistance( $lat1, $lon1, $lat2, $lon2, $radius ) { } ثم نقوم بجلب الزاوية باستخدام متغير $radius $angle = $radius / 180; ثم نقسم كل أحداثية على هذه الزاوية $lat1 /= $angle; $lon1 /= $angle; $lat2 /= $angle; $lon2 /= $angle; ثم نستخدم rad2deg لتحويل الرقم الدائري إلى رقم مكافئ بالدرجات ثم نمرر لها دالة acos لجيب تمام القوسي للرقم ثم نمرر المتغيرات الأربعة داخل دالة sin لإرجاع جيب الرقم بهذا الشكل return rad2deg( acos( sin( deg2rad( $lat1 ) ) * sin( deg2rad( $lat2 ) ) + cos( deg2rad( $lat1 ) ) * cos( deg2rad( $lat2 ) ) * cos( deg2rad( $lon1 - $lon2 ) ) ) ) * $angle; ثم نضرب الرقم الناتج بالزاوية حتى نحصل على المسافة فتكون الدالة بهذا الشكل function getDistance( $lat1, $lon1, $lat2, $lon2, $radius ) { $angle = $radius / 180; $lat1 /= $angle; $lon1 /= $angle; $lat2 /= $angle; $lon2 /= $angle; return rad2deg( acos( sin( deg2rad( $lat1 ) ) * sin( deg2rad( $lat2 ) ) + cos( deg2rad( $lat1 ) ) * cos( deg2rad( $lat2 ) ) * cos( deg2rad( $lon1 - $lon2 ) ) ) ) * $angle; } يرجى تطبيق الحل و أخباري بالنتيجة , فهذا الحل ربما يفيدك و أتمنى أن أكون أجبت على سؤالك بشكلٍ جيد, الأمر قد يكون معقد نوعاً ما و لكن بعد مراجعة الدوال المستخدمة ستوضح لك الأمور كاملة بإذن الله
    1 نقطة
  22. هل يمكنك إرفاق الأحداثيات لموقعك و الموقع الأخر , أي كيف تكون شكل الأحداثيات ؟
    1 نقطة
  23. السلام عليكم لدي api بها مجموعة من الراوتس يتعين على المستخدم تسجيل الدخول من قبل الموقع والحصول على access token و refresh token مدة access token 10s ويتجدد من خلال refresh معلوم انه بوجود هذا التوكن يستطيع المستخدم تصفح الموقع والاستعلام عن البيانات والسؤال هو لاشك انه يوجد بعض الراوتز محجوبة عن المستخدم العادي في front end وهي مخصصة للمدراء وغيرهم، يتم هذا الحجب من خلال الفرونت اند وذلك بحجب هذه الصفحات عنه ولكن في حال اراد الاستعلام عن طريق برنامج مثلاً postman يستطيع تصفح تلك الراوتز ! كيف يمكن منعه من ذلك ؟ اول ما خطر في بالي هو وضع حقل في جدول المستخدم للاستعلام عن هذه الراوتز هل هذه الطريقة صحيحة ؟ وان كان يوجد افضل منها فياليت احد يزودني بها مع الشكر.
    1 نقطة
  24. اريد تحويل الثواني الي فورمات الساعة في PHP مثل لدي رقم اقوم بجلبه عن طريق timestamp و اريد تحويله هكذا 00:00:00 يعني ثواني و ساعات و دقايق
    1 نقطة
  25. ربما تقصد أنه لديك وقت ما يكون بصيغة timestamp بهذا الشكل 86400 لاحظ ان الرقم السابق هو عدد الثواني في 24 ساعة ,فيمكنك برمجة دالة تقوم بهذا الأمر , لأن الدالة ستسمح لك باستخدامها في أي مكان في مشروعك فنقوم بإنشاء دالة وليكن اسمها secondsToString بهذا الشكل function secondsToString( $seconds ){ } لاحظ أننا مررنا لها رقم الثواني , الأن يمكننا الاستفادة من رقم الثواني هذا في تحويله إلى ثواني و دقائق و ساعات , نقوم باستخدام دالة intval لنحصل على القيمة الصحيحة للرقم $seconds = intval( $seconds ); ثم نقوم باستخراج الساعة عن طريق تمرير عدد الثواني مقسوم على 3600 و هو عدد الثواني في الساعة الواحدة $h = floor( $seconds / 3600 ); ثم نقوم باستخراج عدد الدقائق من خلال جلب باقي قسمة الثواني على 3600 ثم قسمة الرقم الناتج على 60 $m = floor( $seconds % 3600 / 60 ); ثم عدد الثواني من خلال جلب باقي قسمة الثواني على 60 $s = floor( $seconds % 60 ); ثم نقوم بإرجاع القيم هذه من خلال دالة return و نضع بين المتغيرات النص ":" بهذه الطريقة return $h.":".( $m < 10 ? "0" : "" ).$m.":".( $s < 10 ? "0" : "" ).$s; فسيكون الناتج بهذا الشكل 23:59:59 فتكون كامل الدالة function secondsToString( $seconds ){ $seconds = intval( $seconds ); $h = floor( $seconds / 3600 ); $m = floor( $seconds % 3600 / 60 ); $s = floor( $seconds % 60 ); return $h.":".( $m < 10 ? "0" : "" ).$m.":".( $s < 10 ? "0" : "" ).$s; }
    1 نقطة
  26. @Salah Eddin Berriani يعني اخي صلاح الطريقة المعمول فيها هي بتوفير داتا في قاعدة البيانات تبين صلاحيات المستخدم بالنسبة لدخول اي راوت ؟ لان الصلاحيات ليست مدير وفقط ولكن صلاحيات كثيرة، لا يوجد سوى حفظها في قاعدة البيانات هل هذا صحيح ؟ @بلال زيادةاخ بلال انا لا اتكلم عن عملية تسجيل الدخول وانما عن ما هو بعدها من صلاحيات للصفحات، وبخصوص عملية تسجيل الدخول تكون عن طريق تضمين التوكن في كوكيز اليس هذا افضل ؟
    1 نقطة
  27. أنا أعمل على مشروع NextJS وأريد استخدام خطاف ويب GITHUB لنشر برنامج نصي يحتوي على إرشادات النشر. لقد قمت بإعداد خطاف ويب للدفع في GITHUB حاولت إضافة الكود التالي في ملف server.ts الخاص بي واختباره الآن مع ngrok // testing server.post("/webhooks/github", function(req, res) { var sender = req.body.sender; var branch = req.body.ref; if (branch.indexOf("master") > -1 && sender.login === githubUsername) { deploy(res); } }); function deploy(res: any) { childProcess.exec("sh deploy.sh", function(err, stdout, stderr) { if (err) { console.error(err, stderr); return res.send(500); } console.log(stdout); res.send(200); }); } هذا الملف هو ملف NODEالخاص بي لتطبيق JS التالي لكنني أحصل على 502 في سجلات ngrok الخاصة بي أرغب في معرفة المكان الذي يجب أن أضع فيه نقطة نهاية خطاف الويب هذا في تطبيق NextJS الخاص بي لتشغيله
    1 نقطة
  28. قمت بتثبيت بيئة أناكوندا Anaconda 4.4.1 وأحاول تنفيذ نموذج في كيراس على جوبيتر لكن يظهر لي الخطأ التالي عند محاولة استيرادها: import keras ----------------------------------------------------- Traceback (most recent call last): File "<ipython-input-3-c74e2bd4ca71>", line 1, in <module> ImportError: No module named 'keras'
    1 نقطة
  29. لقد لاحظت مؤخرًا أن معامل ضرب المصفوفة الجديد (@) يتصرف أحيانًا بشكل مختلف عن معامل numpy.dot . على سبيل المثال، للمصفوفات ثلاثية الأبعاد: import numpy as np a = np.random.rand(2,3,3) b = np.random.rand(2,3,3) c = a @ b # Python 3.5+ d = np.dot(a, b) يُرجع المعامل @ شكل المصفوفة كالتالي: >>> c.shape (2, 3, 3) بينما الدالة np.dot() تعيد شكل مصفوفة كالتالي: >>> d.shape (2, 3, 2, 3) ما الفرق بين numpy.dot وضرب المصفوفة باستخدام المعامل @؟ وكيف يمكنني إعادة إنتاج نفس النتيجة باستخدام numpy.dot؟
    1 نقطة
  30. داخل keras، هناك بعض النماذج المدربة مسبقا pretrained model مثل النموذج التالي: from keras.applications import VGG16 model = VGG16(weights='imagenet') واريد عمل اعادة تدريب له واضافة طبقات dropout ، مع العلم ان شكل النموذج كالتالي: Layer (type) Output Shape Param # Connected to ==================================================================================================== input_1 (InputLayer) (None, 3, 224, 224) 0 ____________________________________________________________________________________________________ block1_conv1 (Convolution2D) (None, 64, 224, 224) 1792 input_1[0][0] ____________________________________________________________________________________________________ block1_conv2 (Convolution2D) (None, 64, 224, 224) 36928 block1_conv1[0][0] ____________________________________________________________________________________________________ block1_pool (MaxPooling2D) (None, 64, 112, 112) 0 block1_conv2[0][0] ____________________________________________________________________________________________________ block2_conv1 (Convolution2D) (None, 128, 112, 112) 73856 block1_pool[0][0] ____________________________________________________________________________________________________ block2_conv2 (Convolution2D) (None, 128, 112, 112) 147584 block2_conv1[0][0] ____________________________________________________________________________________________________ block2_pool (MaxPooling2D) (None, 128, 56, 56) 0 block2_conv2[0][0] ____________________________________________________________________________________________________ block3_conv1 (Convolution2D) (None, 256, 56, 56) 295168 block2_pool[0][0] ____________________________________________________________________________________________________ block3_conv2 (Convolution2D) (None, 256, 56, 56) 590080 block3_conv1[0][0] ____________________________________________________________________________________________________ block3_conv3 (Convolution2D) (None, 256, 56, 56) 590080 block3_conv2[0][0] ____________________________________________________________________________________________________ block3_pool (MaxPooling2D) (None, 256, 28, 28) 0 block3_conv3[0][0] ____________________________________________________________________________________________________ block4_conv1 (Convolution2D) (None, 512, 28, 28) 1180160 block3_pool[0][0] ____________________________________________________________________________________________________ block4_conv2 (Convolution2D) (None, 512, 28, 28) 2359808 block4_conv1[0][0] ____________________________________________________________________________________________________ block4_conv3 (Convolution2D) (None, 512, 28, 28) 2359808 block4_conv2[0][0] ____________________________________________________________________________________________________ block4_pool (MaxPooling2D) (None, 512, 14, 14) 0 block4_conv3[0][0] ____________________________________________________________________________________________________ block5_conv1 (Convolution2D) (None, 512, 14, 14) 2359808 block4_pool[0][0] ____________________________________________________________________________________________________ block5_conv2 (Convolution2D) (None, 512, 14, 14) 2359808 block5_conv1[0][0] ____________________________________________________________________________________________________ block5_conv3 (Convolution2D) (None, 512, 14, 14) 2359808 block5_conv2[0][0] ____________________________________________________________________________________________________ block5_pool (MaxPooling2D) (None, 512, 7, 7) 0 block5_conv3[0][0] ____________________________________________________________________________________________________ flatten (Flatten) (None, 25088) 0 block5_pool[0][0] ____________________________________________________________________________________________________ fc1 (Dense) (None, 4096) 102764544 flatten[0][0] ____________________________________________________________________________________________________ fc2 (Dense) (None, 4096) 16781312 fc1[0][0] ____________________________________________________________________________________________________ predictions (Dense) (None, 1000) 4097000 fc2[0][0] ==================================================================================================== Total params: 138,357,544 Trainable params: 138,357,544 Non-trainable params: 0 ____________________________________________________________________________________________________ كيف يمكنني فعل هذا؟
    1 نقطة
  31. إن بنية الصفحة لديك، غير مفهومة تماماً، لديك اكثر من select وتريد إظهار بيانات من خلال زر وحيد حيث على هذا الزر أن يعرف اي select تغيرت قيمة التحديد فيه. أفضّل وضع متغير عام يحمل قيمة عنصر select المختار، يتم فيه إسناد هذا الselect من خلال دالة onchange نضعها لكل عناصر select حيث يتم جعل المتحول العام يحمل قيمة this الممرة ل on change مع تغيير اي عنصر select بطريقة مشابهة لما سبق...
    1 نقطة
  32. إذا أردنا وصف البرنامج المثالي، فسيكون ذلك الذي له بنية واضحة مثل الكريستال، ويسهل وصف طريقة عمله، كما يملك كل جزء فيه دورًا محدَّدًا ومعروفًا. لكن هذا لا يكون في الواقع، بل تكون لدينا برامج تنمو نموًا عضويًا، بحيث تضاف إليها المزايا كلما دعت الحاجة إلى ذلك؛ أما الهيكلة البنائية لها والحفاظ على تلك الهيكلية فهي أمر آخر، إذ لا تُرى ثمرتها إلا في المستقبل حين يأتي شخص آخر ليعمل على البرنامج، وعلى ذلك فمن المغري للمبرمج إهمالها الآن لتصبح أجزاء البرنامج متشعبةً ومتداخلةً إلى حد فظيع. يتسبب هذا في مشكلتين حقيقيتَين، أولاهما أنّ فهم مثل هذا النظام صعب جدًا، إذ سيكون من العسير النظر لأيّ جزء فيه نظرة مستقِلة إذا كان كل شيء فيه يتصل بشيء آخر، حيث سنُجبَر على دراسة البرنامج كله من أجل فهم جزء واحد فقط؛ أما الثانية فهي إذا أردنا استخدام أيّ وظيفة من مثل هذا البرنامج في حالة أخرى، فستكون إعادة كتابتها من الصفر أسهل من استخراجها مستقِلةً من شيفرتها لتعمل في مكان آخر. يستخدم مصطلح "كرة الوحل" لمثل تلك البرامج التي لا هيكل لها، والتي يلتصق كل شيء فيها ببعضه، فإذا حاولت استخراج جزء، فستنهار الكرة كلها، ولا ينالك إلا تلطيخ يدك. الوحدات Modules تُعَدّ الوحدات محاولةً لتفادي مثل تلك المشاكل التي وصفناها، فالوحدة هي جزء من برنامج ما يحدِّد بوضوح ما هي الأجزاء الأخرى التي يعتمد عليها، وما هي الوظيفة -أي الواجهة الخاصة به- التي سيوفرها للوحدات الأخرى لتستخدمها. تشترك واجهات الوحدات مع واجهات الكائنات في أمور كثيرة كما رأينا في مقال الحياة السرية للكائنات في جافاسكريبت، إذ تجعل جزءًا من الوحدة متوفرًا للعالم الخارجي وتحافظ على خصوصية الباقي، كما يصبح النظام أشبه بقِطع الليجو LEGO في تقييد الطرق التي تتفاعل الوحدات بها مع بعضها البعض، فتتفاعل الأجزاء المختلفة من خلال وصلات connectors معرَّفة جيدًا، على عكس الوحل الذي يختلط فيه كل شيء. تسمى العلاقات التي بين الوحدات بالاعتماديات dependencies، فإذا احتاجت وحدة إلى جزء من وحدة أخرى، فسيقال أنها تعتمد على تلك الوحدة، وحين توصف تلك الحقيقة بوضوح داخل الوحدة نفسها، فيمكن استخدامها لمعرفة الوحدات الأخرى التي يجب أن تكون موجودةً من أجل استخدام وحدة ما، ولتحميل الاعتماديات تلقائيًا، كما ستحتاج كل واحدة منها إلى مجال خاص private scope إذا أردنا فصل الوحدات بهذه الطريقة. لا يكفي وضع شيفرة جافاسكربت في ملفات مختلفة لتلبية تلك المتطلبات، فلا زالت الملفات تتشارك فضاء الاسم العام global namespace نفسه، كما قد تتداخل عن قصد أو غير قصد مع رابطات بعضها bindings، وهكذا تظل هيكلية الاعتماديات غير واضحة، وسنرى بعد قليل كيف نعالج ذلك. قد يكون التفكير في تصميم وحدة ذات هيكل مناسب لبرنامج ما صعبًا بما أننا في مرحلة البحث عن المشكلة واستكشاف حلول لها، وذلك لنرى أيها يعمل، كما لا نريد شغل بالنا بتنظيم أحد الحلول إلا حين يثبت نجاحه. الحزم نستطيع استخدام نفس الجزء في برامج أخرى مختلفة، وهي إحدى المزايا التي نحصل عليها عند بناء برنامج من أجزاء منفصلة تستطيع العمل مستقِلة عن بعضها البعض. لكن كيف نُعِدّ هذا؟ لنقل أننا نريد استخدام الدالة parseINI من المقال السابق في برنامج آخر، فإذا كان ما تعتمد عليه الدالة واضحًا -لا تعتمد الدالة على شيء في هذه الحالة-، فلن نفعل أكثر من نسخ شيفرتها إلى المشروع الجديد واستخدامها؛ أما إذا رأينا خطأً في تلك الشيفرة، فسنصلحه في ذلك المشروع الجديد وننسى إصلاحه في البرنامج الأول الذي أخذنا منه الشيفرة، وبهذا نهدر الوقت والجهد في نسخ الشيفرات من هنا إلى هناك والحفاظ عليها محدَّثة. وهنا يأتي دور الحِزم packages، فهي قطعة من شيفرة يمكن نشرها وتوزيعها -أي نسخها وتثبيتها-، وقد تحتوي على وحدة واحدة أو أكثر، كما فيها معلومات عن الحِزم الأخرى التي تعتمد عليها، وتأتي مع توثيق يشرح وظيفتها كي يستطيع الناس استخدامها، فلا تكون مقتصرةً على من كتبها فقط. تُحدَّث حزمة ما إذا وُجدت مشكلة فيها أو أضيفت إليها ميزة جديدة، وعليه تكون البرامج التي تعتمد عليها -والتي قد تكون حِزمًا أيضًا- يمكنها الترقية إلى تلك النسخة الجديدة. يتطلب العمل بهذه الطريقة بنيةً تحتيةً، وذلك لحاجتنا إلى مكان لتخزين تلك الحِزم والبحث فيها، وإلى طريقة سهلة لتثبيتها وترقيتها كذلك، كما تُوفَّر هذه البنية التحتية في عالم جافاسكربت من قِبَل NPM وهي اختصار لـ Node Package Manager، التي تعني مدير الحِزم. يتكون مدير الحِزم NPM من شيئين، أولهما تقدِّم خدمة تنزيل ورفع الحزم عبر الإنترنت -أي أونلاين online-، وبرنامج -مضمَّن مع Node.js- يساعدك على تثبيت تلك الحزم وإدارتها، كما توجد أكثر من نصف مليون حزمة متاحة على NPM وقت كتابة هذه الكلمات (بنسختها الأجنبية)، وأكثرها لا فائدة منه، لكن الحزم المفيدة المتاحة للعامة موجودة هناك أيضًا. سنجد محلل ملفات INI مثلًا الذي يشبه ما بنيناه في المقال السابق في هيئة حزمة اسمها ini، كما سنرى في مقال لاحق كيف نُثبِّت مثل تلك الحزم محليًا باستخدام أمر npm في الطرفية. إتاحية مثل تلك الحزم عالية الجودة للتحميل مفيد جدًا، فهو يعني استطاعتنا تجنب إعادة اختراع برنامج كتبه مائة إنسان قبلنا، كما نتجاوز ذلك إلى استخدام حزمة مجرَّبة ومختبَرة جيدًا ببضع ضغطات على لوحة المفاتيح، ومن بداهة القول أنّ البرامج لا تكلف شيئًا في نَسخها، لكن كتابة البرامج أول مرة هي العمل الذي يكلف الجهد والوقت والمهارة، كما يماثلها الاستجابة لمن يجد مشاكل في الشيفرة، أو الاستجابة لمن يريد إدخال ميزات جديدة في البرنامج. مَن يكتب البرنامج يمتلك حقوقه افتراضيًا، ولا يستطيع أحد استخدامه إلا برخصة من المبرمج، لكن بما أنّ بعض البشر ذوو قلوب طيبة، ولأنّ نشر البرامج الجيدة سيبني لك سُمعة وسط المبرمجين، فستسمح صراحةً كثير من الحِزم تحت رخصة ما باستخدامها من أيّ كان. ترخَّص أغلب الشيفرات الموجودة في NPM بتلك الطريقة، في حين قد تشترط بعض الرخص نشر الشيفرة التي تبنيها على قمة الحزمة التي استخدمتها تحت رخصة الحزمة نفسها، وأخرى لا تريد أكثر من استخدام رخصة الحزمة نفسها حين تنشر برنامجك، وهي الرخصة التي يستخدمها أغلب مجتمع جافاسكربت، وبالتالي تأكد حين تستخدِم حِزمًا كتبها غيرك من قراءة الرخصة التي تأتي بها الحزمة. الوحدات المرتجلة Improvised modules لم يكن في جافاسكربت نظام وحدات مضمَّن حتى عام 2015، إذ لم يمنع ذلك الناس من بناء نظمًا كبيرة في جافاسكربت طيلة أكثر من عشر سنين، كما كانوا في أمسّ الحاجة إلى وحدات لهذا، وعليه فقد صمموا نظم وحداتهم الخاصة بهم فوق اللغة نفسها، حيث نستطيع استخدام دوال جافاسكربت لإنشاء نطاقات محلية local scopes وكائنات لتمثل واجهات الوحدات. لدينا فيما يلي وحدةً للانتقال بين أسماء الأيام وأرقامها -وذلك من إعادة التابع getDay الخاص بـ Date-، إذ تتكون واجهتها من weekDay.name وweekDay.number، كما تخفي رابطتها names المحلية داخل نطاق تعبير الدالة الذي يُستدعى فورًا. const weekDay = function() { const names = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; return { name(number) { return names[number]; }, number(name) { return names.indexOf(name); } }; }(); console.log(weekDay.name(weekDay.number("Sunday"))); // → Sunday يوفِّر هذا النسق من الوحدات عزلًا إلى حد ما، لكنه لا يصرح عن الاعتماديات، كما يضع واجهته في النطاق العام global scope، ويَتوقع اعتمادياتها إذا وُجدت أن تحذو حذوه، في حين كان ذلك هو الأسلوب المتَّبع في برمجة الويب لمدة طويلة، لكنه صار مهجورًا الآن وقلّما يُستخدَم. إذا أردنا جعل علاقات الاعتماديات جزءًا من الشيفرة، فيجب التحكم في تحميل الاعتماديات، ويتطلب ذلك أن نستطيع تنفيذ السلاسل النصية على أساس شيفرات، إذ تستطيع جافاسكربت فعل ذلك لحسن الحظ. تقييم البيانات على أساس شيفرات هناك عدة طرق لأخذ البيانات -أي سلسلة نصية من شيفرات برمجية- وتشغيلها على أساس جزء من البرنامج الحالي، وأبسط طريقة هي العامل الخاص eval الذي سينفِّذ السلسلة النصية في النطاق الحالي current scope، لكن هذه فكرة سيئة لا يُنصح بها، إذ تعطِّل بعض الخصائص التي تكون عادةً للمجالات مثل توقعها للرابطة التي يشير إليها اسم ما بسهولة. const x = 1; function evalAndReturnX(code) { eval(code); return x; } console.log(evalAndReturnX("var x = 2")); // → 2 console.log(x); // → 1 يمكن تفسير البيانات على أساس شيفرة بطريقة أبسط باستخدام الباني Function الذي يأخذ وسيطين هما سلسلة نصية تحتوي قائمة من أسماء الوسائط مفصول بينها بفاصلة أجنبية، وسلسلة نصية تحتوي على الدالة نفسها. يغلف الباني الشيفرة داخل قيمة دالة كي تحصل على نطاقها الخاص، ولا تفعل أمورًا غريبة مع النطاقات الأخرى. let plusOne = Function("n", "return n + 1;"); console.log(plusOne(4)); // → 5 هذا هو المطلوب تحديدًا وما نحتاج إليه في نظام الوحدات، إذ نستطيع تغليف شيفرة الوحدة في دالة، ونستخدم نطاق تلك الدالة على أساس نطاق الوحدة. CommonJS لعل أكثر منظور لوحدات جافاسكربت المضافة إليها هو نظام وحدات جافاسكربت المشتركة common Javascript والذي يدعى بالاسم CommonJS، إذ تستخدِمه Node.js الذي هو النظام المستخدَم في أغلب الحِزم على NPM. تدور الفكرة العامة لوحدات CommonJS حول دالة اسمها require، فحين نستدعيها مع اسم وحدة الاعتمادية، فستضمن أن تحميل الوحدة وستعيد واجهتها. تحصل الوحدات على نطاقها المحلي الخاص بها تلقائيًا لأنّ المحمّل يغلف شيفرة الوحدة في دالة، وما عليها إلا استدعاء require كي تصل إلى اعتمادياتها، وتضع واجهاتها في الكائن المقيَّد بـ exports. توفِّر الوحدة المثال التالية دالةً لتنسيق التاريخ، إذ تستخدِم حزمتين من NPM هما ordinal لتحويل الأعداد إلى سلاسل نصية مثل "1st" و"2nd"، وdate-names للحصول على الأسماء الإنجليزية للشهور وأيام الأسبوع، ثم تصدِّر دالةً وحيدةً هي formatDate تأخذ كائن Date وسلسلة قالب template string. قد تحتوي سلسلة القالب على شيفرات توجه التنسيق مثل YYYY للسنة كاملة وDo لترتيب اليوم في الشهر، ومن الممكن إعطاؤها سلسلةً نصيةً مثل "MMMM Do YYYY" للحصول على خرج مثل "November 22nd 2017". const ordinal = require("ordinal"); const {days, months} = require("date-names"); exports.formatDate = function(date, format) { return format.replace(/YYYY|M(MMM)?|Do?|dddd/g, tag => { if (tag == "YYYY") return date.getFullYear(); if (tag == "M") return date.getMonth(); if (tag == "MMMM") return months[date.getMonth()]; if (tag == "D") return date.getDate(); if (tag == "Do") return ordinal(date.getDate()); if (tag == "dddd") return days[date.getDay()]; }); }; تتكون واجهة ordinal من دالة واحدة، بينما تصدِّر date-names كائنًا يحتوي على عدة أشياء، إذ تُعَدّ days وmonths مصفوفات من الأسماء، كما تُعَدّ عملية فك البنية الهيكلية سهلةً جدًا عند إنشاء رابطات للواجهات المستوردة. تضيف الوحدة كذلك دالة واجهتها إلى exports كي تصل إليها الوحدات التي تعتمد عليها، إذ نستطيع استخدام الوحدة كما يلي: const {formatDate} = require("./format-date"); console.log(formatDate(new Date(2017, 9, 13), "dddd the Do")); // → Friday the 13th نستطيع تعريف require في أبسط صورها كما يلي: require.cache = Object.create(null); function require(name) { if (!(name in require.cache)) { let code = readFile(name); let module = {exports: {}}; require.cache[name] = module; let wrapper = Function("require, exports, module", code); wrapper(require, module.exports, module); } return require.cache[name].exports; } تَقرأ الدالة المختلَقة readFile في المثال أعلاه ملفًا وتعيد محتوياته في سلسلة نصية؛ أما جافاسكربت فلا توفِّر مثل تلك الخاصية، لكن توفِّر بيئات جافاسكربت المختلفة مثل المتصفحات وNode.js طرقها الخاصة للوصول إلى الملفات، وقد كان المثال يفترض وجود دالة اسمها readFile. تحتفظ دالة require بذاكرة مؤقتة cache من الوحدات المحمَّلة بالفعل، وذلك لتجنب تحميل الوحدة نفسها عدة مرات، فإذا استُدعيت، فستنظر أولًا إن كانت الوحدة المطلوبة محمَّلة من قبل أم لا، ثم تُحمِّلها إن لم تكن محمَّلة، حيث يتطلب ذلك قراءة شيفرة الوحدة وتغليفها في دالة واستدعاءها. لم تكن واجهة حِزمة ordinal التي رأيناها من قبل كائنًا وإنما دالةً، ومن مزايا CommonJS أنه رغم إنشاء نظام الوحدات لكائن واجهة فارغ مقيَّد بـ exports، يمكننا استبدال أيّ قيمة بذلك الكائن عبر إعادة كتابة module.exports، حيث يتم ذلك بعدة وحدات لتصدير قيمة واحدة بدلًا من كائن واجهة؛ وإذا عرَّفنا require وexports وmodule على أساس معامِلات لدالة التغليف المولَّدة وتمرير القيم المناسبة عند استدعائها، فسيضمن المحمِّل إتاحية تلك الرابطات في نطاق الوحدة. تختلف الطريقة التي تُرجِمت بها السلسلة النصية التي أُعطيت إلى دالة require إلى اسم ملف حقيقي أو عنوان ويب باختلاف الأنظمة، فإذا بدأت بـ ‎"./"‎ أو ‎"../"‎، فستُفسَّر تفسيرًا مرتبطًا باسم ملف الوحدة، وبالتالي سيكون ‎"./format-date"‎ هو الملف المسمى format-date.js في المجلد نفسه؛ أما إذا لم يكن الاسم مرتبطًا بالوحدة، فستبحث Node.js عن حِزمة مثبَّتة تحمل الاسم نفسه، وسنفسر مثل تلك الأسماء التي في شيفرات أمثلة هذا المقال على أنها تشير إلى حِزم NPM، كما سننظر بالتفصيل في كيفية تثبيت واستخدام وحدات NPM لاحقًا في هذه السلسلة. نستطيع استخدام واحد من NPM الآن بدلًا من كتابة محلل ملف INI الخاص بنا. const {parse} = require("ini"); console.log(parse("x = 10\ny = 20")); // → {x: "10", y: "20"} وحدات ESCMAScript تظل وحدات CommonJS حلًا غير دائم وغير احترافي رغم عملها بكفاءة وسماحها لمجتمع جافاسكربت -مع NPM- بتشارك الشيفرات على نطاق واسع، وتُعَدّ صيغتها غريبةً قليلًا، إذ لا تكون الأشياء التي نضيفها إلى exports متاحةً في النطاق المحلي مثلًا، وبما أنّ require هي استدعاء دالة عادية تأخذ أيّ نوع من الوسطاء وليس القيم مصنَّفة النوع فقط، فمن الصعب تحديد اعتماديات الوحدة دون تشغيل شيفرتها. لهذا يُصدِر معيار جافاسكربت نظام وحداته الخاص منذ 2015، كما يطلق عليه غالبًا ES modules، حيث تشير ES إلى ECMAScript، ورغم أنّ المفاهيم الأساسية للاعتماديات والواجهات لا زالت كما هي، إلا أنه يختلف في التفاصيل، فصارت الصيغة الآن مدمجةً في اللغة، كما نستطيع استخدام الكلمة المفتاحية الخاصة import بدلًا من استدعاء دالة للوصول إلى اعتمادية ما. import ordinal from "ordinal"; import {days, months} from "date-names"; export function formatDate(date, format) { /* ... */ } تُستخدم بالمثل كلمة export المفتاحية لتصدير الأشياء، وقد تأتي قبل تعريف دالة أو صنف أو رابطة (let أو const أو var). لا تكون واجهة وحدة ES قيمةً واحدةً، بل مجموعة من الرابطات المسماة، كما تربط الوحدة السابقة formatDate بدالة، فإذا استوردنا من وحدة أخرى، فسنستورد الرابطة وليس القيمة، مما يعني أن الوحدة المصدِّرة قد تغير قيمة الرابطة في أي وقت، وسترى الوحدات المستوردة القيمة الجديدة. إذا وُجدت رابطة اسمها default فستُعامَل على أنها القيمة المصدَّرة الأساسية للوحدة، فإذا استوردنا وحدةً مثل ordinal التي في المثال دون الأقواس التي حول اسم الرابطة، فسنحصل على رابطة default، كما تستطيع مثل تلك الوحدات تصدير رابطات أخرى تحت أسماء مختلفة مع تصدير default الخاص بها. إذا أردنا إنشاء تصدير افتراضي، فسنكتب export default قبل التعبير أو تصريح الدالة أو تصريح الصنف. export default ["Winter", "Spring", "Summer", "Autumn"]; من الممكن إعادة تسمية الرابطات المستورَدة باستخدام الكلمة as. import {days as dayNames} from "date-names"; console.log(dayNames.length); // → 7 من الفروقات المهمة كذلك هو حدوث تصديرات وحدات ES قبل بدء تشغيل سكربت الوحدة، وبالتالي قد لا تظهر تصريحات import داخل الدوال أو الكتل، ويجب أن تكون أسماء الاعتماديات سلاسل نصية مقتَبسة وليست تعبيرات عشوائية. يعكف مجتمع جافاسكربت أثناء كتابة هذه الكلمات على اعتماد وتبني أسلوب الوحدات هذا، لكن يبدو أنها عملية طويلة، فقد استغرقنا بضع سنين بعد الاستقرار على الصياغة كي تدعمها المتصفحات وNode.js، ورغم أنها صارت مدعومةً إلى حد كبير إلا أنّ ذلك الدعم به مشاكل، ولا زال الجدل قائمًا حول الكيفية التي يجب توزيع تلك الوحدات بها في NPM. تُكتب مشاريع عديدة باستخدام وحدات ES، ثم تُحوَّل تلقائيًا إلى صيغة أخرى عند نشرها، فنحن في مرحلة انتقالية يُستخدم فيها نظامَي وحدات جنبًا إلى جنب، ومن المفيد أننا نستطيع قراءة وكتابة شيفرات بكليهما. البناء والتجميع إذا نظرنا إلى مشاريع جافاسكربت فسنجد العديد منها لا يُكتب بجافاسكربت من الأساس -تقنيًا-، فثَمة امتدادات مستَخدَمة على نطاق واسع مثل ذلك الذي تعرضنا له في مقال الزلات البرمجية والأخطاء في جافاسكريبت الذي يتحقق من اللهجة، وقد بدأت الناس باستخدام الامتدادات الجاهزة في اللغة قبل إضافتها إلى المنصات التي تشغِّل جافاسكربت بزمن طويل أصلًا، ولكي يستطيع المبرمج فعل ذلك فإنه يصرِّف compile شيفرته، ثم يترجمها من لهجة جافاسكربت التي استخدمها إلى جافاسكربت عادية، أو إلى نسخة أقدم من جافاسكربت كي تستطيع المتصفحات الأقدم تشغيلها. لكن إدخال برنامج يتكون من وحدات ومن 200 ملف مختلف إلى صفحة ويب له مشاكله، فإذا كان جلب الملف عبر الشبكة يستغرق 50 ميلي ثانية، فسيستغرق تحميل البرنامج كله 10 ثواني، أو نصف تلك المدة إن كان يحمِّل عدة ملفات في الوقت نفسه، وهذا وقت ضائع. بدأ مبرمجو الويب باستخدام أدوات تجمع برامجهم التي قضوا الساعات المضنية في تقسيمها إلى وحدات، ليكون البرنامج ملفًا واحدًا كبيرًا، ثم ينشرونه على الويب، ذلك أن جلب ملف واحد وإن كان كبيرًا عبر الويب سيكون أسرع من جلب الكثير من الملفات الصغيرة، ويطلق على مثل تلك الأدوات اسم المجمِّعات bundlers. يتحكم حجم الملفات في سرعة نقلها عبر الشبكة كذلك، فليس العدد وحده هو المعيار، وعليه فقد اخترع مجتمع جافاسكربت مصغِّرات minifiers، وهي أدوات تأخذ برنامج جافاسكربت وتجعله أصغر عبر حذف التعليقات والمسافات تلقائيًا، كما تعيد تسمية الرابطات bindings، وتستبدل شيفرات أصغر بالشيفرات التي تأخذ حجمًا كبيرًا؛ وهكذا فليس من الغريب إيجاد شيفرة في حزمة NPM أو شيفرة تعمل في صفحة ويب، وتكون قد مرت بعدة مراحل من التحويل من جافاسكربت الحديثة إلى نسخة أقدم، ومن صيغة وحدات ES إلى CommonJS، ثم جُمِّعت وصغِّرت كذلك، كما لن نخوض في تفاصيل تلك الأدوات في هذه السلسلة لأنها مملة وتتغير بسرعة، لكن من المهم معرفة أنّ شيفرة جافاسكربت التي تشغِّلها لا تكون بهيئتها التي كُتبت بها أول مرة. تصميم الوحدة تُعَدّ هيكلة البرامج واحدةً من أدق الأمور في البرمجة، إذ يمكن نمذجة أيّ وظيفة غريبة بعدة طرق، كما يُعَدّ القول بجودة تصميم برنامج ما أمرًا نسبيًا، فهناك حلول وسط دومًا، كما تتدخل التفضيلات الشخصية في الحكم على التصميم، وأفضل ما يمكن فعله لتعلُّم قيمة التصميم الجيد هو القراءة والعمل على برامج كثيرة، وملاحظة ما ينجح وما يفشل، وإذا رأيت شيفرات فوضوية فلا تركن إلى قولك أن هذا هو الواقع ولا مجال لتغييره، بل هناك مساحة لتطوير هيكل أيّ شيء تقريبًا بإعمال الفكر فيه. تُعَدّ سهولة الاستخدام أحد أركان تصميم الوحدات، فإذا كنت تصمم شيئًا ليستخدمه أشخاص عدة -أو حتى نفسك فقط-، فيُستحسن أن تكون واجهتك بسيطةً وسهلة الفهم والتوقع حين تنظر إليها بعد ثلاثة أشهر حين تنسى تفاصيل ما كتبته وما عملته، وقد يعني ذلك اتباع سلوكيات موجودة سلفًا، كما تُعَدّ حزمة ini مثالًا على ذلك، إذ تحاكي كائن JSON القياسي من خلال توفير دوال parse وstringify -لكتابة ملف INI-، كما تحوِّل بين السلاسل النصية والكائنات المجردة مثل JSON، وهكذا فإنّ الواجهة صغيرة ومألوفة، وستذكر كيف استخدمتها لمجرد عملك معها مرةً واحدةً. حتى لو لم تكن ثمة دالة قياسية أو حِزمة مستخدَمة على نطاق كبير لمحاكاتها، فستستطيع إبقاء وحداتك مألوفةً وسهلة التوقع باستخدام هياكل بيانات بسيطة تفعل أمرًا واحدًا فقط، كما توجد على NPM مثلًا وحدات عديدة لتحليل ملف-INI، إذ تحتوي على دالة تقرأ مثل هذا الملف من القرص الصلب مباشرة وتُحلله، ويجعل ذلك من المستحيل استخدام مثل تلك الوحدات في المتصفح، حيث لا يكون لنا وصولًا مباشرًا إلى نظام الملفات، كما يضيف تعقيدًا كان يمكن معالجته بأسلوب أفضل عبر تزويد composing الوحدة بدالة قارئة للملفات file-reading. يشير ذلك إلى منظور آخر مفيد في تصميم الوحدات، وهو سهولة تطعيم شيء ما بشيفرة خارجية، إذ تكون الوحدات المركزة التي تحسب قيمًا قابلةً للتطبيق في طيف واسع من البرامج، على عكس الوحدات الأكبر التي تنفِّذ إجراءات معقدة لها آثار جانبية، وقارئ ملف INI الذي يركز على قراءة الملف من القرص الصلب ليس له فائدة في سيناريو يكون فيه محتوى الملف من مصدر خارجي، وبالمثل فإنّ الكائنات الحالة stateful objects مفيدة أحيانًا، بل قد تكون ضرورية؛ لكن إذا كان يمكن تنفيذ أمر ما بدالة فمن الأفضل استخدام الدالة. توفِّر العديد من قارئات ملفات INI على NPM نمط واجهة interface style، إذ يحتاج منك إنشاء كائن أولً، ثم تحمِّل الملف إلى الكائن، وبعد ذلك تستخدِم توابع مخصصة للحصول على النتائج، وذلك الأمر شائع في البرمجة كائنية التوجه، كما هو أمر مرهق وخاطئ. علينا تنفيذ طقوس نقل الكائن خلال عدة مراحل بدلًا من تنفيذ استدعاء واحد لدالة، وبما أن البيانات مغلفة الآن في نوع كائن مخصص، فيجب على كل الشيفرات التي تتفاعل معها معرفة ذلك النوع، مما يجعل لدينا اعتماديات غير ضرورية. قد تكون لدينا حالات لا يمكن تجنب تعريف هياكل بيانات جديدة فيها، حيث لا توفر اللغة إلا بعض الهياكل البسيطة، كما ستكون العديد من أنواع البيانات معقدةً أكثر من مجرد مصفوفة أو خارطة map، لكن إذا كانت المصفوفة تكفي، فسنستخدِم المصفوفة. يمكن النظر إلى مثال المخطط الذي تعرضنا له في مقال مشروع تطبيقي لبناء رجل آلي (روبوت) عبر جافاسكريبت على أساس مثال على هيكل بيانات معقد، إذ لا توجد طريقة واضحة لتمثيل المخطط في جافاسكربت، وقد استخدمنا في ذلك المقال كائنًا تحمل خصائصه مصفوفات من السلاسل النصية، وهي العقد الأخرى التي يمكن الوصول إليها من تلك العقدة. توجد العديد من حِزم إيجاد المسار في NPM، لكن لا تستخدِم أيّ منها صيغة المخطط تلك، فهي تسمح عادةً لحدود المخطط أن يكون لها وزن يكون التكلفة أو المسافة المرتبطة به، ولم يكن ذلك ممكنًا في تمثيلنا. هناك حِزمة dijkstrajs مثلًا التي تستخدِم منظورًا شائعًا جدًا لإيجاد المسارات والذي يُسمى بخوارزمية ديكسترا Dijkstra's algorithm، إذ سُمي باسم إدزجر ديكسترا Edsger Dijkstra الذي كتبه، وهو مشابه لدالة findRoute الخاصة بنا، ومن الشائع أن تضاف اللاحقة js إلى اسم الحِزمة لتوضيح أنها مكتوبة بجافاسكربت. تستخدِم حزمة dijkstrajs صيغة مخطط تشبه صيغتنا، لكنها تستخدم كائنات تكون قيم خصائصها أعدادًا -أي أوزان الحدود- بدلًا من المصفوفات التي استخدمناها، فإذا أردنا استخدام تلك الحزمة، فسيكون علينا التأكد من تخزين المخطط بالصيغة التي تتوقعها الحزمة، كما يجب أن تحصل جميع الحدود على الوزن نفسه بما أنّ نموذجنا المبسط يعامِل كل طريق على أساس امتلاكه التكلفة نفسها -أي منعطف واحد-. const {find_path} = require("dijkstrajs"); let graph = {}; for (let node of Object.keys(roadGraph)) { let edges = graph[node] = {}; for (let dest of roadGraph[node]) { edges[dest] = 1; } } console.log(find_path(graph, "Post Office", "Cabin")); // → ["Post Office", "Salma’s House", "Cabin"] قد يكون ذلك حاجزًا معيقًا عن التركيب compositing، حيث تستخدِم حِزم عدة هياكل بيانات مختلفة لوصف أشياء متشابهة، فيكون جمعها معًا صعبًا، وبالتالي إذا أردنا تصميم شيء ليكون قابلًا للتركيب، فيجب علينا معرفة هياكل البيانات التي يستخدِمها الأشخاص أولًا، ثم نحذو حذوهم كلما تيسر. خاتمة توفر الوحدات هيكلًا لبرامج أكبر من خلال فصل الشيفرة إلى أجزاء صغيرة لها واجهات واضحة واعتماديات، كما تُعَدّ الواجهة الجزء المرئي من الوحدة للوحدات الأخرى، والاعتماديات هي الوحدات الأخرى التي تستخدِمها. ولأنّ جافاسكربت لم توفر نظامًا للوحدات في البداية، فقد بُني نظام CommonJS عليها، ثم حصلت جافاسكربت بعد مدة على نظام وحدات خاص بها، وهو الآن موجود إلى جانب CommonJS. تُعَدّ الحزمة مجموعة شيفرات يمكن توزيعها مستقِلة بذاتها، كما يُعَدّ NPM مستودعًا لحِزم جافاسكربت، ونستطيع تحميل شتى الحِزم منه سواء مفيدة أو غير مفيدة. تدريبات الروبوت التركيبي فيما يلي الرابطات التي ينشئها المشروع الذي في مقال مشروع تطبيقي لبناء رجل آلي (روبوت) عبر جافاسكريبت الذي أشرنا إليه بالأعلى. roads buildGraph roadGraph VillageState runRobot randomPick randomRobot mailRoute routeRobot findRoute goalOrientedRobot إذا أردت كتابة هذا المشروع على أساس برنامج تركيبي modular، فما الوحدات التي ستنشئها؟ وما الوحدات التي ستعتمد عليها كل وحدة؟ وكيف ستبدو واجهاتها؟ وأيّ الأجزاء ستكون متاحةً ومكتوبةً مسبقًا على NPM؟ وهل ستفضِّل استخدام حِزمة NPM أم تكتبها بنفسك؟ إرشادات للحل إليك ما كنا لنفعله بأنفسنا، لكن مرةً أخرى ليست هناك طريقة صحيحة وحيدة لتصميم وحدة معطاة: توجد الشيفرة المستخدَمة لبناء مخطط الطريق في وحدة graph، ولأننا نُفضِّل استخدام dijkstrajs من NPM بدلًا من شيفرة إيجاد المسار التي كتبناها، فسنجعل هذا المخطط قريبًا من الذي تتوقعه dijkstrajs. تصدِّر هذه الوحدة دالةً واحدةً هي buildGraph، كما سنجعل هذه الدالة تقبل مصفوفةً من مصفوفات ثنائية العناصر بدلًا من سلاسل نصية تحتوي على شخطات -، وذلك من أجل تقليل اعتماد الوحدة على صيغة الإدخال. تحتوي وحدة roads على بيانات الطريق الخام -أي مصفوفة roads- ورابطة roadGraph، كما تعتمد تلك الوحدة على ‎./graph وتصدر مخطط الطريق. يوجد صنف VillageState في وحدة state، حيث يعتمد على وحدة ‎./roads لأنه يحتاج إلى أن يكون قادرًا على التحقق من وجود طريق موجود فعليًا، كما يحتاج إلى randomPick، وبما أنّ هذه دالة من ثلاثة أسطر، فسنضعها في وحدة state على أساس دالة مساعدة داخلية، لكن randomRobot يحتاج إليها كذلك، لذا يجب تكرارها أو وضعها في وحدتها الخاصة، وبما أنّ تلك الدالة موجودة في NPM في حِزمة random-item، فمن الأفضل جعل كلا الوحدتين تعتمدان عليها، كما نستطيع إضافة دالة runRobot إلى تلك الوحدة أيضًا، بما أنها صغيرة ومرتبطة ارتباطًا وثيقًا بإدارة الحالة، في حين تصدِّر الوحدة كلا من الصنف VillageState ودالة runRobot. أخيرًا، يمكن دخول الروبوتات والقيم التي تعتمد عليها مثل mailRoute في وحدة example-robots التي تعتمد على ‎./roads وتصدِّر دوال الروبوت، ولكي يستطيع goalOrientedRobot البحث عن المسار، فستعتمد الوحدة على dijkstrajs أيضًا. صارت الشيفرة أصغر قليلًا من خلال نقل بعض المهام إلى وحدات NPM، حيث تنفِّذ كل وحدة مستقِلة شيئًا بسيطًا ويمكن قراءتها بنفسها، ويقترح تقسيم الشيفرات إلى وحدات على أساس تحسينات أكثر لتصميم البرنامج. يُعد اعتماد الروبوتات وVillageState على مخطط طريق بعينه غريبًا بعض الشيء، فربما يكون من الأفضل جعل المخطط وسيطًا لباني الحالة، ونجعل الروبوتات تقرؤه من كائن الحالة، فنقلل الاعتماديات -وهو أمر جيد-، ونجعل من الممكن إجراء عمليات محاكاة على خرائط مختلفة، وذلك خير وأفضل. هل من الجيد استخدام وحدات NPM لأمور كان يمكن كتابتها بأنفسنا؟ نظريًا، نعم، فمن المرجح أنك ستقع في أخطاء في الأمور المعقَّدة مثل دالة إيجاد المسار وتضيع وقتك في كتابتها بنفسك؛ أما بالنسبة للدوال الصغيرة مثل random-item فتكون كتابتها أمرًا يسيرًا، لكن إضافتها في أيّ مكان تحتاج إليها فيه سيعكر وحداتك. لكن بأي حال، لا تقلل من شأن الجهد المطلوب لإيجاد حِزمة NPM مناسبة، فحتى لو وجدتها فقد لا تعمل جيدًا أو تكون مفتقدةً إلى بعض المزايا التي تحتاجها، وفوق هذا يعني الاعتماد على حِزم NPM التأكد من أنها مثبَّتة، كما ستنشرها مع برنامجك، بل ربما يكون عليك ترقيتها دوريًا، فهذه قد تكون إحدى التبعات التي عليك تحملها، وعلى أيّ حال تستطيع اتخاذ القرار الذي يناسبك وفقًا لمقدار العون الذي تقدمه تلك الحزم لك. وحدة الطرق اكتب وحدة CommonJS بناءً على المثال الذي في مقال مشروع تطبيقي لبناء رجل آلي (روبوت) عبر جافاسكريبت، بحيث تحتوي على مصفوفة من الطرق وتصدِّر هيكل بيانات المخطط الذي يمثلها على أساس roadgraph، كما يجب أن تعتمد على وحدة ‎./graph التي تصدِّر الدالة buildGraph المستخدَمة لبناء المخطط، وتتوقع هذه الدالة مصفوفةً من مصفوفات ثنائية العناصر -أي نقاط البداية والنهاية للطرق-. تستطيع تعديل شيفرة التدريب لكتابة الحل وتشغيلها في طرفية المتصفح إن كنت تقرأ من متصفح، أو بنسخها إلى codepen. // أضف اعتماديات وتصديرات. const roads = [ "Salma's House-Omar's House", "Salma's House-Cabin", "Salma's House-Post Office", "Omar's House-Town Hall", "Sara's House-Mostafa's House", "Sara's House-Town Hall", "Mostafa's House-Sama's House", "Sama's House-Farm", "Sama's House-Shop", "Marketplace-Farm", "Marketplace-Post Office", "Marketplace-Shop", "Marketplace-Town Hall", "Shop-Town Hall" ]; إرشادات للحل بما أنّ هذه وحدة CommonJS، فعليك استخدام require لاستيراد وحدة المخطط، وقد وُصف ذلك على أساس تصدير دالة buildGraph، إذ تستطيع استخراجه من كائن واجهته مع تصريح فك الهيكلة const. أضف خاصيةً إلى كائن exports من أجل تصدير roadGraph، كما يجب أن يكون فصل سلاسل الطريق النصية داخل وحدتك لأن buildGraph تأخذ هيكل بيانات لا يطابق roads بالضبط. الاعتماد المتبادل بين الوحدات تُعَدّ حالة الاعتماد المتبادل بين وحدتين ويدعى circular dependency حالةً تعتمد فيها الوحدة A على الوحدة B -أي يكون الاعتماد على شكل حلقة تبادلية بين وحدتين ولذلك سمي باللغة الإنجليزية circular dependency-، والعكس صحيح مباشرةً أو غير مباشرة، كما تمنع العديد من أنظمة الوحدات ذلك بسبب استطاعتك التأكد من تحميل اعتماديات وحدة قبل تشغيلها، بعض النظر عن الترتيب الذي تختاره لتحميل مثل تلك الوحدات. تسمح وحدات CommonJS بصورة محدودة من الاعتماديات الدورية cyclic dependencies تلك، طالما أنّ الوحدات لا تستبدل كائن exports الافتراضي الخاص بها، ولا يكون لها وصول إلى واجهة غيرها حتى تنتهي من التحميل. تدعم دالة require التي تعرضنا لها سابقًا في هذا المقال مثل ذلك النوع من تبادلية الاعتماديات dependency cycle، فهل يمكنك رؤية كيف تعالج هذه الحالة؟ وما الذي قد يحدث إذا استبدلت وحدة في تعتمد وحدة أخرى عليها (أي داخلة في دورة الاعتمادية)دورة، كائن exports الافتراضي الخاص بها؟ إرشادات للحل تدور الفكرة هنا حول إضافة require وحدات إلى ذاكرتها المؤقتة قبل بدء تحميل الوحدة، وهكذا فإذا حاول أيّ استدعاء require تحميلها أثناء تشغيلها، فسيكون معروفًا وتُعاد الواجهة الحالية بدلًا من تحميل الوحدة مرةً أخرى، وذلك يتسبب في طفحان المكدس؛ أما إذا أعادت وحدة كتابة قيمة module.exports الخاصة بها، فستحصل أيّ وحدة أخرى كانت قد استقبلت قيمة واجهتها قبل أن تنهي التحميل، على كائن الواجهة الافتراضي -الذي سيكون فارغًا على الأرجح- بدلًا من قيمة الواجهة المقصودة. ترجمة -بتصرف- للفصل العاشر من كتاب Elequent Javascript لصاحبه Marijn Haverbeke. اقرأ أيضًا مقدمة إلى الوحدات Modules في جافاسكربت الوحدات Modules والحزم Packages في بايثون الوحدات Modules في AngularJS
    1 نقطة
  33. السلام عليكم و رحمة الله و بركاته ما هو ال Rendering Mode الذي سوف يتبعه المتصفح إذا لم اكتب السطر الخاص بتحديد الإصدار
    1 نقطة
  34. Quirks Mode إذا كنت تستعمل Firefox، يمكنك الذهاب إلى View Page Info من الـ context menu وستجد الـ Render Mode مكتوب.
    1 نقطة
×
×
  • أضف...