لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 10/11/21 في كل الموقع
-
لدي مجموعة من البيانات وأريد رسم الهستوغرام لها في Matplotlib فهل هناك دالة أو طريقة للقيام بذلك في هذه المكتبة؟1 نقطة
-
1 نقطة
-
1 نقطة
-
هل حاولتي النقر على ctrl + s لهفظه؟ يمكن أيضا استخدام internet download manager ومحاولة التنزيل إن ظهر أي رسائل خطأ أرجو إرفاقها، وإن كان من غير القانوني حفظ الملف لديكي أرجو عدم عمل ذلك1 نقطة
-
مقدمة من أهم أسباب انتشار ووردبريس وسيطرته على سوق أنظمة إدارة المحتوى هو الكم الهائل من إضافاته المجانية والمدفوعة والتي تقدم العديد من الخصائص والمميزات والتحسينات الإضافية التي لا تتوفر بصورة افتراضية في قلب ووردبريس WordPress Core. في هذا المقال سنتعرف سوّيًا على أساسيات إنشاء إضافة لووردبريس لكن قبل الدخول في لب الموضوع دعنا نجب على سؤال مُهمّ وكذلك تعريف إضافات ووردبريس. لماذا ننشئ إضافات ووردبريس هنالك قاعدة مهمة في تطوير ووردبريس، وهي: إياك أن تلمس الشيفرات Codes الأساسية لووردبريس أي لا تُعدّل على قلب ووردبريس WordPress Core وذلك لأنه عند التحديث سيتمّ استبدال بعض أو كل ملفات ووردبريس الأساسية، وبالتّالي ستفقد التعديلات التي قمت بها، ولهذا السبب نلجأ إلى تطوير إضافات عند الحاجة لإضافة التحسينات والخصائص الجديدة على النّظام. تعريف إضافات ووردبريس إضافة ووردبريس عبارة عن دالة أو مجموعة دوال (حزمة شيفرات code package) مكتوبة بلغة php تقوم بإضافة بعض الخصائص لنظام إدارة المُحتوى. وتندمج شيفرات الإضافة معه من خلال واجهة برمجية API يوفرها له. بالإضافة لملفات php يمكن أن تحتوي الإضافة على ملفات أخرى مثل ملفات JavaScript, CSS وبعض الصور. إنشاء إضافة ووردبريس هذه بعض الخطوات المهمة عند إنشاء أي إضافة ووردبريس وبعض الأمور التي يجب مراعاتها. اختيار اسم الإضافة في البدء عليك أن تقوم باختيار اسم فريد للإضافة التي تود إنشائها بحيث لا يكون الاسم مستخدما من قبل من إحدى إضافات ووردبريس حتى لا يحدث تعارض بين الإضافات مستقبلا. إنشاء مجلد الإضافة بعد اختيار اسم الإضافة تقوم بإنشاء مجلد لها بالاسم الذي اخترناه ويكون هذا المجلد داخل مجلد plugins الخاص بالإضافات والموجود داخل مجلد wp-content كما موضح بالصّورة. يمكنك إنشاء ملف php بنفس الاسم بدلًا عن إنشاء مُجلّد كامل لكن يُفضّل أن تنشئ مُجلّدًا خاصًّا حتى يستوعب بقية ملفات الإضافة، ما لم تكن الإضافة تحتوي على ملف php واحد فقط. إنشاء الملف الأساسي للإضافة بعد إنشائك للمُجلّد في الخطوة أعلاه عليك أن تقوم بإنشاء ملف php له نفس اسم المجلد السابق، وهذا الملف هو الملف الأساسي للإضافة والذي سيستخدمه ووردبريس للتّعرف على بعض الأمور المُتعلّقة بالإضافة مثل اسمها واسم المُبرمج ورخصة الإضافة وغيرها، وهذا يتم من خلال استخدام ترويسة للملف الأساسي للإضافة وهذه هي الصّيغة العامة لها: <?php /** * Plugin Name: هنا تكتب اسم الإضافة والذي يجب أن يكون فريدًا * Plugin URI: هنا تكتب رابط موقع الإضافة * Description: هنا نبذة مختصرة عن الإضافة * Version: رقم نسخة الإضافة، مثلا 1.0.0 * Author: اسم مطور الإضافة * Author URI: رابط موقع مطور الإضافة * License: اسم رخصة الإضافة */ السّطر الإجباري هو سطر اسم الإضافة فقط، ويتمّ استخدام بقية السطور (في حال ورودها) في إنشاء معلومات الإضافة التي تظهر في لوحة تحكم الإضافات عند استعراض الإضافة. برمجة الإضافة قبل أن تبدأ في برمجة الإضافة تحتاج لمعرفة بعض الأمور العامة في برمجة ووردبريس بالإضافة لبعض التسهيلات التي يقدمها ووردبريس للمبرمجين مثل الواجهات البرمجية الجاهزة WordPress API's. الخطافات في ووردبريس WordPress Hooks ( الدخول الى عمق ووردبريس) من أهم المفاهيم في ووردبريس مفهوم الخطافات hooks والتي تنقسم إلى قسمين: الأحداث actions والمُرشّحات filters. 1- الإجراءات في ووردبريس WordPress Actions فلنفترض أنه لدينا دالة معينة نريد أن يتم تنفيذها في لحظة معينة أثناء دورة حياة ووردبريس أو عند حدوث حدث معين، كيف يمكننا إنجاز هذا الأمر؟ أحد الخيارات أن نقوم بمناداة هذه الدالة بالطريقة العادية في المكان الذي نريدها أن تُنفّذ فيه، لكن هذا الأمر يتطلّب التّعديل على ملفات ووردبريس الأساسية. لك القاعدة التي ذكرناها مسبقا: إياك أن تلمس الشيفرات الأساسية لووردبريس تمنعنا من القيام بذلك. الحل الآخر هو أن نستخدم الإجراءات actions وهي عبارة عن آليّة رائعة يوفرها ووردبريس تمكّنك من إضافة الدّوال الخاصّة بك لتُنفّذ في وقت معين أثناء تنفيذ الشيفرات الخاصة بووردبريس إذًا، يمكننا أن نعرف الإجراءات بأنها طريقة تمكننا من إخبار ووردبريس بتنفيذ دالة معينة عند حصول حدث معين وبهذه الطريقة نستطيع الدخول إلى عمق ووردبريس من دون التعديل المباشر على ملفاته الأساسية Core files. يتم هذا كله من خلال ربط الدّوال التي تريدها مع الأحداث الجاهزة التي يوفرها ووردبريس والتي يقوم بتنفيذها أثناء دورة حياته وهذا ما يجعلك قادرا على تنفيذ الدّوال الخاصة بك في أي مكان تريده تقريبا. إذا كنّا نريد مثلا تنفيذ الدّالة my_function عندما ينفذ ووردبريس الحدث my_action علينا ببساطة أن نخبره بذلك من خلال إضافة هذه الدالة إلى هذا الحدث. ويتم ذلك من خلال الدالة add_actions بالطريقة التالية add_action('my_action', 'my_function'); 1-1مثال للإجراءات في ووردبريس فلنأخذ هذا المثال الذي يقوم بإرسال بريد إلى مدير الموقع (الدالة المراد تنفيذها) كلما نشر مقالًا جديدًا (الحدث الذي تنفذ عنده الدالة) add_action('publish_post', 'email_admin'); function email_admin(){ // هنا يتم إرسال البريد الإلكتروني إلى مدير الموقع } 2-المرشحات في ووردبريس WordPress Filters المُرشّحات هي النوع الثاني من الخطّافات التي يوفرها ووردبريس وهي مختصّة أكثر بالبيانات حيث أنها تتيح لنا إمكانية التعديل على قيم المتغيرات (اسم المقال مثلا) قبل حفظها في قاعدة البيانات أو قبل عرضها للمستخدم، وكما هو ظاهر من اسمها فهي تتيح لنا إمكانية ترشيح البيانات، بمعنى إدخالها إلى filter مُعيّن يُعدّل عليها قبل إخراجها من الجانب الآخر من هذا المُرشّح . بطبيعة الأمر وكما هو الحال بالنّسبة للأحداث فإن ووردبريس يُوفّر لك إمكانية إدخال أغلب مُتغيّراته في المُرشّحات التي تريدها من خلال اسم المتغير، ويمكنك الاطّلاع على المُتغيّرات التي يمكنك تمريرها عبر المُرشّحات بزيارة التوثيق الرسمي للمرشحات. يتم إضافة فلتر معين my_filter لبيانات معينة my_data من خلال الدّالة add_filter بالطريقة التالية add_filter( 'my_data', 'my_filter' ); حيث أن my_filter هي الدّالة التي ستقوم بالتعديل على البيانات ويتم تمرير البيانات لها من قبل ووردبريس أي أنها يجب أن تستقبل my_data كمعامل parameter. 2-1مثال للمرشحات في ووردبريس هذا المثال يقوم بتعديل محتوى المقال the_content حيث يقوم بإضافة التّوقيع لمُحتويات كل مقال في الموقع add_filter ( 'the_content', 'add_signiture' ); function add_signiture($the_content){ // هنا نقوم بإضافة الشيفرات التي تضيف التّوقيع لمحتويات المقال return $the_content; // بعد ذلك تقوم الدّالة بإرجاع القيم الجديدة لمحتويات المقال } هذه نظرة سريعة فقط على الخطافات في ووردبريس ولكن ما زال هنالك العديد من الأشياء المتعلقة بهذه الآلية الرّائعة التي يوفرها ووردبريس منها: إمكانية إضافة الـhooks الخاصة بك. تعديل أولوية تنفيذ الدّوال التابعة لنفس الـhook. ويمكنك التعرف على المزيد حول موضوع الخطافات في التّوثيق الرسمي لPlugin API وسوم القالب Template Tags قد تبدو الترجمة الحرفية مُضلّلة نوعًا ما خصوصا إذا علمت أن المقصود من وسوم القالب هو مجموعة من الدّوال الجاهزة التي يوفرها ووردبريس والتي تختصر لك الكثير من العمل، لذلك من الجيد أن تلقي نظرة عليها قبل البدء في برمجة الإضافة الخاصة بك. الجدير بالذّكر أن يتم استخدام كثير من هذه الدّوال داخل الحلقة الخاصّة بجلب المقالات في ووردبريس WordPress Loop والتي تستخدم بكثرة في القوالب، ولعل هذا هو سرّ تسميتها بوسوم القالب. حفظ بيانات/ الإضافة في قاعدة البيانات الكثير من إضافات ووردبريس إن لم يكن معظمها تحتاج لاستقبال بعض البيانات من مدير الموقع (خيارات الإضافة مثلا) وحفظها في قاعدة البيانات لاسترجاعها واستخدامها لاحقا، ولهذا السبب يتيح لنا ووردبريس عدّة طرق لحفظ البيانات في قاعدة بيانات الموقع واختيار الطريقة المناسبة يعتمد على نوع البيانات المراد حفظها. هذه الطرق هي: 1- استخدام آلية "الخيارات options" التي يوفرها ووردبريس وهذه الطريقة مناسبة في حالة كون البيانات المراد حفظها صغيرة نسبيا ولا تتغير كثيرا مثل البيانات التي تتوقع من مدير الموقع إدخالها بعد تنصيب الإضافة مباشرة (خيارات الإضافة) والتي نادرا ما تتغير. في هذه الطريقة يتم حفظ بيانات الإضافة في جدول wp_options والذي يستخدمه ووردبريس لحفظ خياراته الخاصة. 2-استخدام البيانات الوصفية الخاصة بالمقالات Post Meta وهذه الطريقة مناسبة في حالة البيانات المتعلقة بمقال أو صفحة مفردة (مثلا مزاج الكاتب عند كتابة المقال) 3-استخدام الفئات المخصّصة وهذه مناسبة لتصنيف البيانات مثل تصنيف المقالات أو المستخدمين أو التعليقات. 4- إنشاء جدول جديد في قاعدة البيانات هذه الطريقة مناسبة مع البيانات التي لا يصلح معها أي نوع من الأنواع الثلاثة السابقة والتي تتوقع أن تتزايد مع الزمن والتي لا يمكن حصرها في اسم محدد. الاستفادة من الواجهات البرمجية API's التي يوفرها ووردبريس يحتوي ووردبريس على مجموعة ضخمة من الدّوال والأصناف Classes المفيدة التي تمثل بوّابات تربطك بقلب ووردبريس WordPress Core بالإضافة إلى توفيرها لدوال مفيدة في كثيرا من الأمور البرمجية العامة في مجال الويب، وهذه أمثلة لبعض الواجهات البرمجية التي يوفرها ووربريس Plugin API: تتيح لك الدّوال المستخدمة في الاستفادة من ميكانيكية الخطافات وكذلك الدّوال المساعدة لإنشاء الخطافات الخاصة بك. Database API : واجهة برمجية تسهل التعامل مع قاعدة بيانات ووردبريس. Rewrite API: تتيح لك إمكانية تغير صيغة روابط المقالات والموقع عموما والتحكم فيها. Filesystem API: للتعامل مع نظام الملفات في نظام التشغيل. وغيرها الكثير من الواجهات البرمجية ويمكنك الإطلاع عليها من هنا أمور عامة عليك مراعاتها عند برمجة الإضافة 1- الاهتمام بأمن الشيفرة Code Security كما هو الحال عند برمجة أي سكربت من خلال لغة php عليك مراعاة أن يكون خاليا من الثغرات التي قد تعرض الموقع لخطر الاختراق، نفس الأمر ينطبق على إضافات ووردبريس فعليك الاهتمام بإغلاق الثّغرات المعروفة وحماية المدخلات وكذلك ملفات الإضافة بمنع الوصول المباشر لها عن طريق استخدام الشيفرة التالية مثلا defined( 'ABSPATH' ) or die( 'ممنوع الوصول المباشر' ); هنالك أشياء أخرى يجب مراعاتها خصوصا إذا أردت نشر إضافتك في مستودع إضافات ووردبريس، بعض هذه الأمور إجباري وتحتاج لعمله حتى يتم قبول إضافتك ونشرها في المستودع، من هذه الأمور: 2- ملف اقرأني Readme File هو ملف تقوم بتضمينه في مجلد الإضافة باسم readme.txt ويستخدمه مستودع الإضافات لأخذ بعض المعلومات بالإضافة للمعلومات التي تظهر في صفحة الإضافة في المستودع، يمكنك استخدام هذا المُوّلد لإنشائه 3- جعل الإضافة قابلة للترجمة من الأمور الأخرى التي عليك مراعاتها هو جعل الإضافة قابلة للترجمة لعدة لغات localized حيث يمكنك استخدام مكتبة gettext التي يوفرها ووردبريس والتي تجعل من عملية جعل الكلمات قابلة للترجمة أمر سهل، وبعد ذلك يتم إرفاق ملفات اللغة مع الإضافة، ويمكنك قراءة المزيد عن هذا الأمر من هنا 4- استخدام معايير تطوير وودبريس معايير التّطويرCoding Standard هي بعض القواعد العامة التي عليك مراعاتها عند كتابة الشيفرة لتجنب أخطاء التشفير Coding وتسهيل عملية كتابة الشيفرات ومراجعتها وقراءتها خصوصا في حالة تعاون أكثر من شخص في برمجة شيء ما. لووردبريس قواعده الخاصة أيضا والتي يحاول من خلالها المحافظة على قواعد ثابتة في شيفرات ووردبريس وكذلك شيفرات الإضافات والقوالب لذلك يفضل أن تلتزم بهذه القواعد عند كتابة شيفرات الإضافة الخاصة بك. يمكنك قراءة المزيد عن هذه القواعد من هنا. 5- تحديث الإضافة يستخدم مستودع إضافات ووردبريس نظام Subversion لتحديث ولمعرفة آلية القيام بذلك، زر هذه الصّفحة كانت هذه كانت مقدمة سريعة ونبذة مختصرة حاولنا أن نجعلها كمدخل لبرمجة إضافات ووردبريس وما زال هنالك المزيد لمعرفته عن برمجة إضافات ووردبريس في مقالات قادمة.1 نقطة
-
هناك عدة مشاكل و هي أولاً يجب إزالة = من السطر التالي for (let i = 0; i < cart.length; i++) { بحيث متغير i أصغر من عدد عناصر المصفوفة , ومن ثم يجب جمع عناصر المصفوفة , بحيث يجب إضافة اسم المصفوفة المخزنة بها الأعداد كما في السطر التالي total += cart[i]; فيكون كامل الكود هو const cart = [1,3,4,5,6]; let total = 0; for (let i = 0; i < cart.length; i++) { total += cart[i]; } console.log(total); والنتيجة سوف تكون عدد 191 نقطة
-
1 نقطة
-
كيف أحسب المتمم الثنائي بصيغة 16-bit 2’s للعدد 17861 نقطة
-
بقرا في البرمجة عن المصطلحات التالية وأريد شرح عنهم program specifications problem solving implementation testing debuging1 نقطة
-
كيف أستطيع استخدام التابع cv2.warpAffine لتطبيق إزاحة على الصورة في OpenCV؟1 نقطة
-
كيف نقوم بتعديل حجم الصور باستخدام OpenCV حيث أن لدي مجموعة بيانات وأريد استخدامها لاختبار نموذجي لكن أحجام هذه الصور لا تتناسب مع مدخلاته؟1 نقطة
-
هل يمكن عمل الربط بين الجداول باستخدام CASE لتحديد قيمة الحقل عند الربط مكان on في عبارة الدمج؟ أرجو ذكر مثال1 نقطة
-
كيف نقوم برسم مخطط بياني شريطي في بايثون؟ حيث أنه لدي مجموعة بيانات مأخوذة ضمن ظروف محددة وأريد المقارنة بينها من خلال الرسم الشريطي، فهل هناك طريقة للقيام بذلك؟1 نقطة
-
في مكتبة Matplotlib يمكنك استخدام ال bar blot للقيام بكل ما تحتاجه. فكما نعلم أن المخطط الشريطي (Bar chart) هو رسم بياني يمثل فئة البيانات ذات الأشرطة المستطيلة ذات الأطوال والارتفاعات التي تتناسب مع القيم التي تمثلها. ويمكن رسم مخططات الشريط أفقياً أو رأسياً. ويصف المخطط الشريطي المقارنات بين الفئات المنفصلة. حيث تمثل أحد محاور المخطط الفئات المحددة التي تتم مقارنتها، بينما يمثل المحور الآخر القيم المقاسة المقابلة لتلك الفئات. matplotlib.pyplot.bar(x, height, width=0.8, bottom=None, data=None, **kwargs) حيث أن الوسيط الأول يمثل إحداثيات x للأشرطة (قيم المحور الأفقي -الفئات-). أما الوسيط الثاني فيمثل ارتفاع كل فئة (ارتفاع الأشرطة bars). أما الوسيط الثالث فيمثل عرضها، والرابع يمثل أدنى قيمة في المحور العمودي (مثلاً لو وضعت 10 ستبدأ قيم المحور العمودي من ال10) والرابع يأخذ قيمتين إما center أو edge ويحدد محاذاة الشريط bar. وهناك وسطاء يمكنك أن تقوم بإضافتهم مثل اللون color ولون الحدود للأشرطة edgecolor و linewidth لتغيير عرضه و tick_label في حال أردت وضع أسماء محددة للفئات أو القيم. مثال1: فيما يلي مثال بسيط على مخطط شريط Matplotlib. يوضح عدد الطلاب المسجلين في الدورات المختلفة المقدمة من أكاديمية حسوب: import matplotlib.pyplot as plt import numpy as np # الفئات x = np.array(["CS", "UI", "JavaScript", "PHP"]) # ارتفاعها أو تكرارها أو سمها حسب نوع بياناتك y = np.array([307, 466, 674, 539]) # bar تمرير القيم للدالة plt.bar(x,y) # عرض النتائج plt.show() الخرج: مثال2: نفس المثال السابق لكن بشكل احترافي أكثر. import pandas as pd from matplotlib import pyplot as plt # البيانات نفسها name = ["CS", "UI", "JavaScript", "PHP"] freq = [307, 466, 674, 539] # اعديل حجم الشكل fig, ax = plt.subplots(figsize =(10, 9)) # تعريف مخطط شريطي معكوس ax.barh(name, price,color="m") # حذف حدود الشكل for s in ['top', 'bottom', 'left', 'right']: ax.spines[s].set_visible(False) # ticks حذف علامات المحاور ax.xaxis.set_ticks_position('none') ax.yaxis.set_ticks_position('none') # إضافة مسافة بين اسماء الفئات والمحور ax.xaxis.set_tick_params(pad = 5) ax.yaxis.set_tick_params(pad = 10) # إضافة شبكة للخلفية ax.grid(b = True, color ='grey', linestyle ='-.', linewidth = 0.5, alpha = 0.2) # إضافة تعليقات على الأشرطة for i in ax.patches: plt.text(i.get_width()+0.2, i.get_y()+0.5, str(round((i.get_width()), 2)), fontsize = 10, fontweight ='bold', color ='grey') # عنوان المخطط ax.set_title('Classes at Hsoub Academy', loc ='left', ) fig.text(0.9, 0.15, 'Jeeteshgavande30', fontsize = 12, color ='grey', ha ='right', va ='bottom', alpha = 0.7) # عرض الرسم plt.show() الخرج:1 نقطة
-
نعم يمكن الاستعلام من قاعدتي بيانات مختلفتين، الفرق هو وضع اسم قاعدة البيانات التي ينتمي لها الجدول قبل اسمه الشكل العام: SELECT table_1.*, table_2.* FROM [Database_1].[Table_Schema].[Table_Name_1] table_1 JOIN [Database_2].[Table_Schema].[Table_Name_2] table_2 ON table_1.id = table_2.id مثال تقريبي: SELECT t1.*, t2.name -- تحديد الحقول FROM DataBase_A.table1 t1 -- تحديد الجدول الأول من قاعدة البيانات الأولى JOIN DataBase_B.table2 t2 -- تحديد الجدول الثاني من قاعدة البيانات الثانية ON t2.column2 = t1.column1; -- عمل ربط معين لاحظ أن استخدام الاسم المستعار يسهل الوصول للجداول يكون اسم قاعدة البيانات التي ينتمي لها الجدول بادئة prefix للمجال الذي ينتمي منه الجدول مثال فعلي: لنفرض لدينا قاعدة بيانات أولى فيها جدول المستخدمين، وقاعدة بيانات ثانية فيها جدول الرسائل / المحادثات فيمكنا عمل ربط وجلب رسائل أحد المستخدمين بعمل الربط بشكل عادي كالتالي: select * from DataBase_A.dbo.Users u join DataBase_B.dbo.Messages m on u.UserId = m.UserId1 نقطة
-
نعم يمكنك استخدام ال Pie Chart (نسميها الكعكة) وهو المخطط الدائري في Matplotlib وهو مخطط إحصائي دائري يمكنه عرض سلسلة من البيانات. تكون مساحة الرسم البياني هي النسبة المئوية الإجمالية للبيانات المعطاة، وتمثل مساحة شرائح الكعكة "Pie " النسبة المئوية لأجزاء البيانات، وشرائح الكعكة "Pie " تسمى "wedges"، و يتم تحديد مساحتها بطول قوس ال wedge، وتمثل مساحته النسبة المئوية لذلك الجزء بالنسبة للبيانات كاملةً. الشكل العام لهذا التابع: matplotlib.pyplot.pie(data, explode=None, labels=None, colors=None, autopct=None, shadow=False) بحيث أن الوسيط الأول يمثل البيانات الخاصة بك، بينما يمثل الوسيط الثاني قائمة (أو set أو tuble.. لامشكلة) من القيم (float) بحيث تمثل مدى ابتعاد ال wedge (يقابل عينة من data) عن باقي ال wedges (ستفهم أكثر في المثال). أما الوسيط الثالث فهو لوضع أسماء لهذه ال wedges ، والرابع لتحديد اللون، أما الخامس فهو لإضافة نص label يحمل القيمة العددية لل wedge مع إضافة أشياء مثل النسبة المئوية. أما الوسيط الأخير فهو يستخدم لإضافة ظل لل wedges. مثال1: import matplotlib.pyplot as plt import numpy as np # تعريف قائمة تحوي بيانات y = np.array([35, 25, 25, 15]) # تسميتها mylabels = ["Apples", "Bananas", "Cherries", "Dates"] myexplode = [0.2, 0, 0, 0] # إنشاء المخطط plt.pie(y, labels = mylabels,explode = myexplode) # عرضه plt.show() الخرج: مثال2: import numpy as np import matplotlib.pyplot as plt # إنشاء بيانات cars = ['JAGUAR', 'MERCEDES','BMW','AUDI', 'FORD'] data = [22, 100, 42, 30, 25] # مثلاً أريد أن تكون الشريحة الخاصة بسيارات أودي بارزة # وبالتالي سأجعل قيمتها أكبر explode = (0.0, 0.12, 0.2, 0.25, 0.0) # تحديد ألوان مختلفة للشرائح colors = ( "black", "cyan", "red","grey", "yellow") # إضافة بعض الخصائص الخاصة للشرائح wp = { 'linewidth' : 1, 'edgecolor' : "red" } fig, ax = plt.subplots(figsize =(10, 7)) wedges, texts, autotexts = ax.pie(data, autopct = "%1.1f%%", explode = explode, labels = cars, shadow = True, colors = colors, startangle = 90, wedgeprops = wp, textprops = dict(color ="magenta")) # legend إضافة ax.legend(wedges, cars, title ="Cars", loc ="center left", bbox_to_anchor =(1, 0, 0.5, 1)) plt.setp(autotexts, size = 8, weight ="bold") ax.set_title("Customizing pie chart") # عرض البيانات plt.show() الخرج:1 نقطة
-
يمكنك أن تستخدم سطر الأوامر Command Line لإستخراج وإستدعاء قواعد البيانات خصوصًا إن كانت كبيرة الحجم للغاية، ولكي لا تنتظر تحميل الصفحة في phpMyadmin أو خطأ timeout عندما يتم إستخراج قاعدة البيانات يفضل أن تستخدم سطر الأوامر للقيام بهذه المهمة. أيضًا في كثير من الأحيان لا يكون هنا دعم لـ phpMyadmin على الخادم لذلك لا يتوفر سوى إستخدام سطر الأوامر بشكل إفتراضي. تتوفر MySQL على أداة mysqldump التي تسمح لك بإستخراج وإستيراد قواعد البيانات بشكل سهل وسريع، وذلك من خلال تنفيذ الأمر التالي: mysqldump -u YourUser -p YourDatabaseName > wantedsqlfile.sql سوف يتم طلب إدخال كلمة السر الخاصة بسمتخدم قاعدة البيانات YourUser. ثم لإستيراد قاعدة البيانات على خادم آخر، يمكنك أن تقوم بتنفيذ الأمر التالي: mysql -u YourUser -ptmppassword AnotherDatabaseName < wantedsqlfile.sql قم بتغير اسم المستخدم وكلمة السر واسم قاعدة البيانات وسيبدأ عملية إستيراد قاعدة البيانات.1 نقطة
-
شائع عادة إستعمال مدير قواعد البيانات phpMyadmin لذلك . سواء في المستضيف المحلي أو على الإستضافة المشتركة . لنقم بتلخيص الأمر وفق الخطوات التالية : تصدير قواعد البيانات من المستضيف المحلي بصيغة SQL . يمكنك ذلك عن طريق الدخول إلى phpmyadmin من localhost و التوجه إلى export من قائمة التصفح العلوية التي تظهر بعد الضغط على اسم قواعد البيانات الخاصة بك , ثم اختيار صيغة التصدير و التصدير . (يمكنك تجاهل هاته الخطوة ان كنت تمتلك بالفعل ملف بلاحقة sql خاص بقاعدة البيانات التي لديك ) . الدخول إلى لوحة التحكم الخاصة بإستضافتك . الذهاب إلى phpMyadmin في الجزء الخاص بقواعد البيانات . (المثال من لوحة cPanel) قد تحتاج في بعض لوحات التحكم التي تعطي وصولا محدودا في phpMyadmin إلى إنشاء قاعدة بيانات ومستخدم كامل الصلاحيات . بعد الدخول إلى phpMyadmin تأكد أن تقوم بتحديد قاعدة البيانات المنشأة حديثا , أو أن تقوم بإنشاء واحدة جديدة , ان توفرت صلاحية ذلك , عن طريق الضغط على New أعلى القائمة الجانبية أسفل شعار phpmyAdmin . من قائمة التصفح العلوية نقوم بإختيار تضمين أو Import . قم بالتصفح إلى ملف الـ sql. الذي قمت بتصديره و قم بتحديده و تضمينه بعد الضغط على browse files . ربط موقعك بقواعد البيانات المضافة . يكون هذا عادة بملف إعداد للموقع على شاكلة env. أو init.php_ أو غيرها . قد تحتاج كخطوة إضافية في بعض الأحيان محو الملفات المؤقتة الخاصة بإعداد موقعك , و هذا في حالة إستعماله للملفات المؤقتة بالطبع (مثال : تطبيقات اللارافيل تستعمل ذلك) .1 نقطة
-
تحويل أوتسو هو تحويل يستخدم لحساب قيمة العتبة في الصور الثنائية (أبيض أسود) فقط (يمكن استخدامه مع باقي أنواع الصور لكن لن يعطي نتائج جيدة فهو مخصص للتعامل مع حالة الصور الثنائية). في التعتيب_البسيط يتم اختيار عتبة محددة نستنتجها من خلال التجريب أو إذا كنت محترفاً ستستخدم الهيستوغرام الخاص بها لإيجاد العتبة. أما إذا كانت لديك صورة ثنائية (الصورة الثنائية هي الصورة التي تملك قيمتين في هستوغرامها) فسنأخذ قيمة وسطة بين هاتين القيمتين وهذا مايفعله أوتسو. ولتطبيقه نقوم بإضافة "+" الخاصية cv2.THRESH_OTSU إلى الخاصية cv2.THRESH_BINARY مع الدالة cv2.threshold: retValue, thresh=cv2.threshold(source, thresholdValue, maxVal, thresholdingTechnique) # thresholdingTechnique=cv2.THRESH_BINARY + cv2.THRESH_OTSU # maxVal=255 # thresholdValue=0 حيث أننا هنا نقوم بتمرير القيمة 0 إلى الوسيط thresholdValue لكي يقوم أوتسو بإيجاد أفضل قيمة للعتبة (يتم تجاهل هذا الوسيط عموماً). وقيمة العتبة التي يجدها أوتسو هي التي سيتم تطبيقها على الصورة ويتم تخزينها في retValue. في المثال التالي سيكون لدينا صورة تحوي ضجيج سنطبق عليها تعتيب بسيط ثم تعتيب باستخدام أوتسو ثم سنطبق عليها مرشح غاوصي لإزالة الضجيج ثم سنطبق عليها أوتسو مرة أخرى لنرى النتائج: import cv2 from matplotlib import pyplot as plt import numpy as np # قراءة الصورة im = cv2.imread('/content/The-original-Gaussian-noisy-image-The-Gaussian-noise-parameters-are-zero-mean-and.png',0) # global thresholding ret1,th1 = cv2.threshold(im,127,255,cv2.THRESH_BINARY) # Otsu's thresholding ret2,th2 = cv2.threshold(im,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) # Otsu's thresholding + Gaussian filtering blur = cv2.GaussianBlur(im,(3,3),0) ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) # نقوم الآن برسم النتائج + الهيستوغرامات images = [img, 0, th1,img, 0, th2,blur, 0, th3] # لإعطاء تسميات توضيحية للرسوم titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)', 'Original Noisy Image','Histogram',"Otsu's Thresholding", 'Gaussian filtered Image','Histogram',"Otsu's Thresholding"] for i in range(3): plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray') plt.title(titles[i*3]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256) plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray') plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([]) fig =plt.gcf() fig.set_size_inches(20.0, 20.0) plt.show() الخرج:1 نقطة
-
بالإضافة إلى إجابة أستاذ عدنان فإن الview من الممكن أن تقوم بتحسين الأداء, حيث أن الview يوجد منها نوع يُدعى materialized view , هذا النوع على عكس عرض البيانات(view) التقليدي ﻻ يتم تخزين التعريف فقط وإنما يتم تخزين البيانات نفسها وذلك يقوم بتحسين الأداء بناءاً على أكثر من نقطة الفهرسة: بما أن البيانات يتم تخزينها , إذا يمكن أن يتم فهرستها مما يقوم بتقليل الوقت الﻻزم للبحث ويُحسن من الأداء بشكلٍ مباشر تخزين الإستعﻻمات المعقدة : عندما تقوم بتخزين materialized view مبنية على التداخل (join) أو التجميع(aggregation) فإنك ﻻ تحتاج في كل مرة تنفذ فيها الإستعﻻمة أن تقوم قاعدة البيانات بعملية التداخل بين البيانات , إنك فقط تقوم بجلب البيانات من العرض(view) مُحسن الإستعلامات (query optimizer) سيقوم تلقائي بجلب البيانات من العرض إن كان جلبها من هناك أسرع حتى ولو لم تحدد ذلك في الإستعﻻم1 نقطة
-
الـ views أو العروض في SQL هي نوع من الجداول الافتراضية . تحتوي على صفوف وأعمدة مثلها مثل الجداول الحقيقية في SQL . بحيث يمكننا إنشاء العروض عن طريق تحديد حقول معينة من جدول واحد أو أكثر موجود في قاعدة البيانات الخاصة بنا . و لفهمها أكثر لنقم بفهم المثال التالي : ليكن لدينا جدول تفاصيل الطلاب students_details التالي : و ليكن لدينا جدول علامات الطلاب students_marks كالتالي : و لنقل أننا نريد إنشاء طريقة نقوم من خلالها بقراءة علامات الطلبة Mark و عناوينهم Address . واحدة من السبل لذلك هي في إنشاء العروض أو الـ Views .بحيث توفر تلخيصا لذلك في جدول افتراضي و لنقل أنه جدول بإسم students_extra_details . يمكننا إنشاء عرض ما باستخدام التعليمة CREATE VIEW مباشرة .بحيث يمكن إنشاء طريقة عرض إما من جدول واحد أو من عدة جداول بسياق عام كالتالي : CREATE VIEW view_name AS SELECT column1, column2..... FROM table1_name,table2_name , table3_name.... WHERE condition; أي : CREATE VIEW students_extra_details AS SELECT student_details.NAME, student_details.ADDRESS, student_marks.MARKS FROM student_details, student_marks WHERE student_details.NAME = student_marks.NAME; في ذاكرة الـ SQL قد تم إنشاء هاته الـ view كجدول افتراضي , يمكن معاملته كأي جدول SQL اخر . بشكل يبدوا كالتالي : الان لن نحتاج إلا لمعاملتها كجدول عادي تماما , فإستعلام القراءة SELECT مثلا يكون كالتالي : SELECT * FROM students_extra_details; و هكذا .. وراء ما يخفيه هذا الإستعمال المميزات و الفوائد التالية : الأمان و التغليف : بحيث يمكن إتاحة العروض للمستخدمين بينما لا يمكن الوصول إلى الجداول الأساسية بشكل مباشر . مما يعطي المستخدمين البيانات التي يحتاجون إليها فقط ، مع حماية البيانات الأخرى في نفس الجدول , لإستعمالها كشروط أو أغراض أخرى . كما أنها تعتبر طبقة تجريدية أو abstraction layer ، وهي تفعل ما تفعله أي طبقة تجريد جيدة ، بما في ذلك تغليف مخطط قاعدة البيانات وحمايتك من أية عواقب تنتج عن كون هيكلية قواعد البيانات مكشوفة . البساطة و الدلالية: يمكن استخدام العروض لإخفاء الاستعلامات المعقدة مثل إستعلامات الـ JOIN , فما الذي يبدوا أبسط برأيك , إنشاء طريقة عرض شاملة لكامل إستعمالاتك في التطبيق أم كتابة إستعلام JOIN كل مرة تحتاج القراءة من جدولين وفق شرط ما ؟ .. كما يمكن استخدامها لتوفير أسماء مستعارة بسيطة لأسماء الأعمدة لجعلها أكثر قابلية للتذكر أو دلالية ذات مغزى . مساحة تخزين بسيطة : بحيث تأخذ مساحة صغيرة جدًا للتخزين , فقاعدة البيانات تحتوي على تعريف العرض فقط ، وليس نسخة من جميع البيانات التي تقدمها و هذا شيء يقوم بإختصار الكثير . يمكنك القراءة أكثر عن العروض في سلسلة sql للمحترفين - مواضيع متفرقة في SQL .1 نقطة
-
يمكنك استخدام الدالة ()matplotlib.pyplot.axvline لإضافة خطوط عمودية لل plot الخاص بك: matplotlib.pyplot.axvline(x=0, ymin=0, ymax=1, **kwargs) حيث أن الوسيط الأول يستخدم لتحديد الإحداثي x الذي تريد رسم الخط العمودي عنده. أما الوسيط الثاني فيحدد موضع بدء الخط العمودي على المحور y، حيث يأخذ قيم بين 0 و 1، بحيث 0 يكون أسفل المحور ، أما 1 يكون أعلى المحور. أما الوسيط الثالث، فيحدد موضع نهاية الخط العمودي على المحور y ، حيث يأخذ قيم بين 0 و 1، بحيث 0 يكون أسفل المحور ، و 1 يكون أعلى المحور. وأخيراً **kwargs تمثل وسطاء أخرى مثل عرض الخط linewidth واللون color. مثال: import matplotlib.pyplot as plt # تحديد بيانات x =[0, 3, 7, 12, 17] y =[1, 4, 6, 7, 10] # رسم البيانات plt.plot(x, y) # بحيث يبدأ من منتصف المحور العيني x = 3.2 رسم خط عمودي باللون الأحمر عند الإحداثي # وينتهي في نهاية المحور العيني plt.axvline(x = 3.2, ymin = 0.5, ymax = 1, color ='r') plt.show() الخرج: كما يمكنك رسم عدة خطوط عمودية كالتالي: import matplotlib.pyplot as plt # تحديد بيانات x =[0, 3, 7, 12, 17] y =[1, 4, 6, 7, 10] # رسم البيانات plt.plot(x, y) # بحيث يبدأ من منتصف المحور العيني x = 3.2 رسم خط عمودي باللون الأحمر عند الإحداثي # وينتهي في نهاية المحور العيني plt.axvline(x = 3.2, ymin = 0.5, ymax = 1, color ='r') # خط آخر مع تغيير بعض القيم plt.axvline(x = 4.0, ymin = 0.3, ymax = 0.7, color ='black') # خط آخر plt.axvline(x = 5.0, ymin = 0.1, ymax = 0.9, color ='y') plt.show() الخرج: أو من خلال حلقة for: import matplotlib.pyplot as plt # تحديد بيانات x =[0, 3, 7, 12, 17] y =[1, 4, 6, 7, 10] # رسم البيانات plt.plot(x, y) xcoords = [2.22058956, 0.03088437, 4.20589566] for xc in xcoords: plt.axvline(x = xc, ymin = 0.5, ymax = 1, color ='r') plt.show() الخرج:1 نقطة
-
تعتبر أداة FFmpeg حل متعدد المنصات لتسجيل وتحويل وبث الصوت والفيديو و تعديله , و لذلك قد تتغير طريقة الإستعمال أو سياقها بتغير تفاصيل الواجهة الخلفية لموقعك مثلا . فكثير من الإضافات و الملحقات توفر واجهات سهلة للإستعانة بخدمات المكتبة و أدواتها في كثير من اللغات . فعلى سبيل المثال في php , و بإستعمال مكتبة PHP-FFMpeg/PHP-FFMpeg يتم تعديل حجم فيديو كالتالي : $video->filters()->resize($dimension, $mode, $useStandards); // example : $video->filters()->resize(new FFMpeg\Coordinate\Dimension(320, 240)) كما يمكن إضافة علامة مائية كالتالي : $video ->filters() ->watermark($watermarkPath, [ 'position' => 'relative', 'bottom' => 50, 'right' => 50, ]); يمكنك القراءة أكثر عن توثيق المكتبة هنا . كما تتوفر على أداة command Line كاملة , يمكنك الإطلاع على توثيقها مفصلا هنا .1 نقطة
-
في التعتيب_البسيط كنا نستخدم قيمة عامة للعتبة وهذا قد لا يكون مناسباً في بعض الحالات تبعاً لاختلاف شروطا الإضاءة من صورة لأخرى، وهنا يكون من الأفضل استخدام التعتيب المتكيف. وهو عبارة عن خوارزمية حساب عتبة منطقة صغيرة في الصورة، وبالتالي نحصل على عدة عتبات لعدة مناطق في نفس الصورة، وبالتالي الحصول على نتائج أفضل ضمن ظروف الإضاءة المختلفة: cv2.adaptiveThreshold(src, dst, maxValue, adaptiveMethod, thresholdType, blockSize, C) بحيث أن الوسيط الأول يمثل الصورة، أما الثانية فهي المصفوفة التي سنضع الخرج ضمنها، أما المتغير الثالث يمثل القيمة التي سيتم إعطاءها للبكسل في حال كانت قيمته أكبر أو تساوي قيمة العتبة، أما الوسيط الرابع فهو خوارزمية التكييف وهي الطريقة التي سيتم من خلالها حساب قيمة العتبة (أي أن هذا الوسيط ستمثل قيمة خرجه العتبة)، وهناك طريقتان لذلك: cv2.ADAPTIVE_THRESH_MEAN_C: وهنا يتم حساب قيمة العتبة على أساس متوسط مجموع البكسلات المجاورة (مثلاً إذا حددنا ال blockSize على 15 فهذا يعني أن قيمة العتبة ستكون مجموع قيم البكسلات في الجوار 15*15 مقسومة على عددها ومطروحاً منها قيمة الوسيط C) وهكذا من أجل كل بكسل في الصورة. Threshold Value = (Mean of the neighbourhood area values – constant value cv2.ADAPTIVE_THRESH_GAUSSIAN_C: وهنا يتم حساب قيمة العتبة عن طريق حساب المجموع الغاوصي الموزون للبكسلات المتجاورة مطروحاً منه قيمة C: Threshold Value = (Gaussian weighted sum of the neighbourhood values – constant value أما الوسيط الخامس فهو نوع التعتيب المستخدم (تماماً كما في التعتيب البسيط). بينما Block Size فهي كما أشرنا حجم النافذة التي سيتم اعتمادها لحساب العتبة من أجل كل بكسل. و C هي الثابت التي سيتم طرحه. انظر إلى المثال التالي: import cv2 import numpy as np from matplotlib import pyplot as plt # قراءة الصورة img = cv2.imread(r'C:\Users\Windows.10\Desktop\1.jpeg',0) # تطبيق التعتيب البسيط _,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY) # ADAPTIVE_THRESH_MEAN_C تطبيق التعتيب التكيفي مع استخدام th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\ cv2.THRESH_BINARY,11,10) # ADAPTIVE_THRESH_GAUSSIAN_C وسنجرب أيضاً th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\ cv2.THRESH_BINARY,11,10) # إعطاء الصور أسماء توضيحية titles = ['Original Image', 'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding'] images = [img, th1, th2, th3] # عرض النتائج for i in range(4): plt.subplot(2,2,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) fig =plt.gcf() fig.set_size_inches(20.0, 20.0) plt.show() الخرج: لاحظ أن استخدام التعتيب البسيط أدى إلى تشويه الصورة وذلك لأن الصورة ملتقطة في ظروف إضاءة غير متساوية (جزء معتم وجزء آخر أكثر إضاءة). ولكن استخدام التعتيب المتكيف قام بحل المشكلة.1 نقطة
-
يقصد بالتعتيب إنشاء قناع (Mask)، لمجال لوني محدد من الصورة بحيث يظهر هذا المجال اللوني بالأبيض (غالباً) وأي لون خارج هذا المجال سيكون أسود (غالباً) وذلك لإظهاره وتحديده بغاية القيام بعمليات معينة على الصورة. وللقيام بعملية التعتيب نستخدم التابع cv2.threshold حيث يتم مقارنة كل بكسل في الصورة مع قيمة محددة نسميها العتبة (threshold) في حال كانت قيمة البكسل أكبر أو تساوي العتبة يتم استبدال قيمة البكسل ب 255 وإلا تستبدل بالرقم 0 (يمثل اللون الأسود). للقيام بعملية التعتيب نستخدم التابع threshould والذي يأخذ 5 وسطاء، الأول الصورة الأصلية التي نريد تعتيبها مقروءة بالصيغة الرمادية، أما الثاني فهو مصفوفة الخرج(التي نريد وضع الناتج فيها -اختياري-)، أما الثالث فهو قيمة العتبة. ويمثل الرابع القيمة التي يجب تحويل البكسل إليها في حال كانت قيمة البكسل أكبر من العتبة. أما الوسيط الخامس هو نوع العتبة المراد تطبيقها وهناك 6 أنواع مختلفة: cv2.THRESH_BINARY # تعتيب ثنائي الحالة الافتراضية التي نستخدمها cv2.THRESH_BINARY_INV # نفس السابق لكن بشكل معكوس cv2.THRESH_TRUNC # القيم الأعلى من العتبة يتم ضبطها لتصبح مساوية لقيمة العتبة أما باقي البكسلات تبقى كما هي cv2.THRESH_TOZERO # ضبط كثافة البكسل على 0 ، لكل كثافة بكسل ، أقل من الحد الأدنى cv2.THRESH_TOZERO_INV # معكوس السابق والصورة التالية توضح الفروقات بين هذه الأنواع: وهنا المعادلات التي تعتمد عليها هذه الأنواع: ويعيد هذا التابع قيمة على شكل Tuple، بحيث القيمة الأولى تمثل قيمة العتبة التي قمت بتحديدها، في حين القيمة الثانية تمثل المصفوفة الناتجة. cv2.threshold(src, dst, thresh, maxval, type) في المثال التالي سنقوم بتعتيب صورة واستخدام كل أنواع التعتيب البسيط: import cv2 import numpy as np from matplotlib import pyplot as plt # قراءة الصورة بالصيغة الرمادية img = cv2.imread(r'C:\Users\Windows.10\Desktop\Safedrive\images.jpg',0) # THRESH_BINARY تطبيق أول نوع _,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY) # THRESH_BINARY_INV _,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV) # THRESH_TRUNC _,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC) # THRESH_TOZERO _,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO) # THRESH_TOZERO_INV _,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV) # الآن سأعطي عناوين للصور للوضوح titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV'] # نضع الصور ضمن قائمة images = [img, thresh1, thresh2, thresh3, thresh4, thresh5] # نقوم بعرضها for i in range(6): #من مكتببة ماتبلوتليب لرسم أكثر من شكل ضمن نفس النافذة subplot أستخدام التابع plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) fig =plt.gcf() fig.set_size_inches(20.0, 20.0) plt.show() والخرج:1 نقطة
-
111 تعني شبكة 1x1 وأول subplot. بينما 112 تعني شبكة 1x1 وثاني subplot. بينما 232 تعني شبكة 2x3 وثاني subplot. وهكذا.. وهذه الأرقام هي اختصار ل hwi أي الارتفاع والعرض والفهرس (رقم ال plot). حيث أن الدالة subplot تقوم بتشكيل شبكة "Grid" عن طريق تقسيم ال figure إلى عدة أقسام على أساس تقسيم محدد (مثل 111 أو 232 أو 542 ..إلخ) ويتم وضع ال plots ضمن خلايا هذه الشبكة. انظر للصورة التالية: هنا لدينا شبكة 2x2 وقمنا بوضع 4 رسوم بيانية هم 221 و 222 و 223 و 224. والكود الموافق: import matplotlib.pyplot as plt f = plt.figure() #top left f.add_subplot(221) # الأول #top right f.add_subplot(222) # الثاني #bottom left f.add_subplot(223) # الثالث #bottom right f.add_subplot(224) # الرابع plt.show() كذلك بدلاً من كتابة add_subplot(hwi) يمكن كتابة (height,width,index) add_subplot (وهي الصيغة الأساسية) حيث أن hwi هي الصيغة المختصرة (أو المشفرة).1 نقطة
-
يمكنك استخدام التابع cvtColor ولكن هنا بدلاً من تمرير قيمة الصورة للتابع نمرر له القيمة اللونية التي نريدها في BGR (الخطوة الأولى). ثم نقوم بتحديد أعلى وأدنى قيمة لمجال اللون المطلوب عن طريق اتباع القاعدة (الخطوة الثانية): الدنيا: [H-10, 100,100] العليا: [H+10, 255, 255] لكن هذا ليس أفضل خيار دائماً (أقصد القاعدة) لذا لدقة أكبر يفضل أن تختار مجال القيم بشكل يدوي عن طريق تمرير أعلى وأدنى قيمة لعتبة اللون المطلوب في BGR. مثال على ما سبق، مثلاً لو أردنا إيجاد اللون الأحمر في HSV: red = numpy.uint8([[[0,0,255]]]) hsv_red = cv2.cvtColor(red,cv2.COLOR_BGR2HSV) print(hsv_red) # [[[ 0 255 255]]] ثم نطبق القاعدة أعلاه وهذا سيعطينا مجالين: Low: [0, 100,100] High: [10, 255, 255] لكن لو قمت بتجريب ذلك بشكل يدوي سينتج معك أن المجال الأفضل للون الأحمر هو: Low: [0, 100,100] High: [20, 255, 255] مثال آخر لإيجاد اللون الأخضر في HSV: green = np.uint8([[[0,255,0 ]]]) hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV) print (hsv_green) # [[[ 60 255 255]]] ثم ينتج لدينا المجالات المطلوبة حسب القاعدة: Low: [50, 100,100] High: [70, 255, 255]1 نقطة
-
نعم يمكنك استخدام الدالة Scatter في Matplotlib لعرض وتمثيل نقاط البيانات. فيما يلي سأشرح كيف يمكنك استخدامه لتمثيل نقاط البيانات: matplotlib.pyplot.scatter(x_axis_data, y_axis_data, s=None, c=None, marker=None, cmap=None,alpha=None, linewidths=None, edgecolors=None) يتم استخدام الدالة plot من الموديول pyplot لرسم نقاط البيانات. بشكل أساسي تأخذ هذه الدالة وسيطين الأول يمثل المحور الأفقي x-axis والثاني يمثل المحور العمودي y-axis، ويمكن أن تكون قيمهما ممثلة ضمن array أو list أو tuble . على سبيل المثال إذا كانت نقاط المحور الأفقي هي الأعداد ممثلة في القائمة التالية xp ونقاط المحور العمودي هي الأعداد من 15 إلى 22 والممثلة في yp، يمكننا رسم نقاط البيانات هذه بالشكل التالي: import matplotlib.pyplot as plt xp = [3,4,5,2,7,4,3,1] #بحيث تتضمن القيم tuble تعريف مصفوفة أو قائمة أو yp = [15,16,17,18,19,20,21,22] plt.scatter(xp, yp) plt.show() وكذلك يمكنك تمثيل أكثر من plot ضمن نفس ال figure: import matplotlib.pyplot as plt import numpy as np x = np.array([4,5,8,7,2]) y = np.array([22,20,58,33,11]) plt.scatter(x, y) x = np.array([1,3,6,7,15,8,12]) y = np.array([13,66,44,42,36,62,44]) plt.scatter(x, y) plt.show() كذلك يمكنك تغيير حجم نقاط البيانات من خلال الوسيط s (ويمكن أن تمرر له قيمة float لتغيير الحجم أو يمكنك تمرير مصفوفة حجمها بحجم نقاط البيانات لديك في حال أردت أن تجعل نقاط بيانات محددة تظهر بشكل أكبر | أصغر من غيرها). أما الوسيط c فلتحديد لون تسلسل الألوان لنقاط البيانات. أما الوسيط linewidths فلتحديد حجم محيط النقطة، و edgecolor لتحديد لون حدودها. أما alpha لتحديد شفافية النقطة (قيمة بين 0 (شفاف) و 1 (بدون شفافية)). والوسيط marker لتحديد الشكل الذي تظهر به نقطة البيانات وافتراضياً يكون دائرة "o" ويمكنك اختيار أشكل أخرى مثل مثلث "^" أو "+" إلخ.. أما cmap فهي لتحديد خريطة الألوان. أنظر للمثال التالي: import matplotlib.pyplot as plt # مجموعة البيانات الأولى x1 = [89, 43, 36, 36, 95, 10, 66, 34, 38, 20] y1 = [21, 46, 3, 35, 67, 95, 53, 72, 58, 10] plt.scatter(x1, y1, c ="black", # لون النقطة linewidths = 1, # عرض الحدود marker ="*", # شكل النقطة edgecolor ="y", # لون الحدود s = 150) # حجم النقطة # الثانية x2 = [26, 29, 48, 64, 6, 5, 36, 66, 72, 40] y2 = [26, 34, 90, 33, 38, 20, 56, 2, 47, 15] plt.scatter(x2, y2, c ="blue", # لون النقطة linewidths = 3, # عرض الحدود marker ="^", # شكل النقطة edgecolor ="red", # لون الحدود s = 150)#حجمها plt.xlabel("X-axis") plt.ylabel("Y-axis") plt.show() قد ترغب أيضاً في الاطلاع على الدالة plot: وتختلف scatter عن هذه الدالة في أنها تقوم بتمثيل البيانات نقطيَاً أي بدون خطوط تصل بين هذه النقاط وبما أنك تريد رؤية توزع البيانات لديك فأنت تحتاج Scatter.1 نقطة
-
بالنسبة لقياس الأداء فهناك التابع getTickCount الذي يعطينا عدد دورات الساعة CK التي استغرقناها لتنفيذ عملية أو مجموعة عمليات ضمن الكود. وأيضاً التابع getTickFrequency الذي يعطينا تردد دورات الساعة، أو عدد دورات الساعة في الثانية. ولإيجاد زمن تنفيذ المقطع البرمجي الخاص بك بالثواني: import cv2 e1 = cv2.getTickCount() # البداية # الكود الخاص بك يكون هنا e2 = cv2.getTickCount() # النهاية time = (e2 - e1)/ cv2.getTickFrequency() مثال: import cv2 as cv import numpy as np image = cv.imread("im.jpg") t1 = cv.getTickCount() # سنقوم بتجريب فلتر بقيم مختلفة للكيرنل for i in range(3,30,2): img1 = cv.medianBlur(image,i) t2 = cv.getTickCount() time = (t2 - t1)/cv.getTickFrequency() print(time) # 0.432018214 seconds أما بالنسبة لتحسين الأداء فهناك ما يسمى ب "الحل المثالي" حيث يمكنك تشغيل العديد من التوابع في OpenCV في هذا الوضع، لذا إذا كان لديك نظام يدعم خاصية "الحل المثالي" فيمكنك استخدام هذه الخاصية (حالياً جميع المعالجات تدعم ذلك). لتفعيل هذه الخاصية نستخدم cv2.setUseOptimized حيث نمرر له True لتفعيلها و False لإلغاء التفعيل، ولمعرفة فيما إذا كان الكود ينفذ مع المحسَن optimizer أم لا، نقوم باستدعاء التابع cv2.useOptimized حيث يعيد True إذا كانت الخاصية مفعلة وإلا False: cv2.useOptimized() # False # أي أنها معطلة %timeit cv.medianBlur(image,33) # 10 loops, best of 3:66.3 ms per loop # الآن سنقوم بتفعيلها cv2.setUseOptimized(True) cv2.useOptimized() # TRUE %timeit cv.medianBlur(image,33) # 10 loops, best of 3:30.3 ms per loop لاحظ أن الزمن قد تحسن بمقدار الضعف.1 نقطة
-
يمكنك مشاهدة مسار أساسيات جافاسكربت من دورة تطوير التطبيقات باستخدام JavaScript، نحن نعلم أن جافاسكربت أصعب من HTML-CSS وهي لغة برمجية أما اللغتين الباقيتين لغتي توصيف ولا يوجد فيهم منطق أو تفكير.. وهذه الميزة لتوفرها أكاديمية حسوب تتيح للطلاب المسجلين في أي دورة من الوصول للمسار الأول من باقي المسارات. ضمن مسار أساسيات جافاسكربت ستتعلم الأساسيات ما في اللغة من المتغيرات والشروط والحلقات والأغراض ... وستفيدك بالطبع.1 نقطة
-
لنلقي نظرة سريعة على المواضيع التي بدت صعبة في النسخة السابقة من المنهاج قبل أن ننتقل إلى موضوع جديد. التعليمة console.log سيبدو ذلك -رغم المفارقة- صحيحًا على الرغم من أن الهاوي سيحتاج هذه التعليمة أو غيرها من طرق التنقيح أكثر مما يحتاج إليه المحترف. عندما يتوقف تطبيقك عن العمل، لا تحاول أن تخمن مصدر الخطأ فحسب، بل استخدم تعليمة log أو غيرها من وسائل التنقيح. تذكر لا تضم ما تريد إظهاره على الطرفية مستخدمًا إشارة الجمع (+) كأسلوب Java: console.log('props value is' + props) بل افصل الأشياء التي تريد طباعتها بفاصلة (,): console.log('props value is', props) إن استخدمت أسلوب Java فلن تحصل على النتيجة المطلوبة: props value is [Object object] بينما لو استخدمت الفاصلة لتمييز القيم التي تريد إظهارها على الطرفية فستُطبع بشكل قيم نصية منفصلة ومفهومة. لمعرفة المزيد، راجع بعض الأفكار التي تحدثنا عنها بشأن تنقيح تطبيقات React. نصيحة للاحتراف: استخدام مقاطع شيفرة Visual Studio يمكن بسهولة إنشاء مقاطع شيفرة باستخدام Visual studio، حيث تعتبر هذه المقاطع أسطرًا برمجية قابلة لإعادة الاستخدام. وتشابه في عملها أسطر sout في برنامج Netbeans. يمكنك إيجاد المزيد من الإرشادات حول إنشاء واستخدام المقاطع من خلال الإنترنت. كما يمكنك البحث عن مقاطع جاهزة على شكل إضافات لبرنامج Visual Studio مثل الإضافة xabikos.ReactSnippets. يعتبر المقطع الذي ينفذ الأمر ()console.log leg في الشيفرة التالية الأكثر أهمية حيث يوضح الأمرclog: { "console.log": { "prefix": "clog", "body": [ "console.log('$1')", ], "description": "Log output to console" } } مصفوفات JavaScript انطلاقًا من هذه النقطة سنستخدم توابعًا للتعامل مع المصفوفات في JavaScript وفق أسلوب البرمجة بالدوال مثل التوابع find وfilter وmap. تشابه هذه التوابع في مبدأ عملها "المجاري (Streams)" في Java 8 التي اعتُمدت خلال السنوات القليلة الماضية في مقررات قسم علوم الحاسب في جامعة هلسنكي. إن بدا لك غريبًا أسلوب البرمجة بالدوال مع المصفوفات، يمكنك متابعة مقاطع الفيديو الأجنبية التالية: Functional Programming Higher-order functions Map Reduce basics معالجات الأحداث: نظرة ثانية أثبت مفهوم معالجة الأحداث أنه صعب استنادًا إلى تقييمنا لمنهاج العام الفائت. لذا من الأجدى أن تلقي نظرة ثانية على هذا الموضوع الذي ناقشناه في الفصل السابق ضمن فقرة "عودة إلى معالجة الأحداث" إذا أردت إنعاش معلوماتك. كما برزت تساؤلات عدة حول تمرير معالجات الأحداث إلى المكوِّن الابن للمكوِّن الذي أنشأناه سابقًا App، لذلك يفضل مراجعة هذا الموضوع. تصيير مجموعات البيانات سنعمل الآن على الواجهة الأمامية للتطبيقات (frontend) أو ما يعرف بكتابة شيفرة التطبيق من جهة المتصفح. لنبدأ بتطبيق React مشابه للمثال النموذجي الذي رأيناه في مقال أساسيات بناء تطبيقات الويب: import React from 'react' import ReactDOM from 'react-dom' const notes = [ { id: 1, content: 'HTML is easy', date: '2019-05-30T17:30:31.098Z', important: true }, { id: 2, content: 'Browser can execute only Javascript', date: '2019-05-30T18:39:34.091Z', important: false }, { id: 3, content: 'GET and POST are the most important methods of HTTP protocol', date: '2019-05-30T19:20:14.298Z', important: true } ] const App = (props) => { const { notes } = props return ( <div> <h1>Notes</h1> <ul> <li>{notes[0].content}</li> <li>{notes[1].content}</li> <li>{notes[2].content}</li> </ul> </div> ) } ReactDOM.render( <App notes={notes} />, document.getElementById('root') ) تحتوي كل ملاحظة على قيمة نصية وعبارة زمنية وقيمة منطقية (Boolean) تحدد إذا ما كانت الملاحظة هامة أم لا وكذلك قيمة فريدة (unique value) لتمييز الملاحظة تدعى id. يعمل التطبيق السابق على مبدأ وجود ثلاث ملاحظات فقط في المصفوفة، وتصيّر كل ملاحظة باستخدام القيمة id مباشرة: <li>{notes[1].content}</li> لكن من الأفضل أن نظهر المعلومات المستخلصة من المصفوفة على شكل عنصر React باستخدام الدالة map: notes.map(note => <li>{note.content}</li>) ستكون النتيجة مصفوفة من العناصر li: [ <li>HTML is easy</li>, <li>Browser can execute only Javascript</li>, <li>GET and POST are the most important methods of HTTP protocol</li>, ] يمكن إضافتها إلى القائمة ul: const App = (props) => { const { notes } = props return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <li>{note.content}</li>)} </ul> </div> ) } انتبه لضرورة وضع شيفرة JavaScript -الموجودة ضمن قالب JSX- داخل أقواس معقوصة كي يتم تنفيذها. سنجعل الشيفرة أكثر وضوحًا بنشر تصريح الدالة السهمية ليمتد على عدة أسطر: const App = (props) => { const { notes } = props return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <li>{note.content}</li>)} </ul> </div> ) } الصفات المفتاحية key-attribute على الرغم من أن التطبيق سيعمل بشكل طبيعي، إلّا أن تحذيرًا مزعجًا يظهر على الطرفية: تشير التوجيهات في الصفحة المرتبطة برسالة الخطأ، ضرورة امتلاك عناصر القوائم التي أنشأها التابع map قيمًا مفتاحية فريدة وهي صفات تدعى key. لنضف إذا المفاتيح المناسبة: const App = (props) => { const { notes } = props return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <li key={note.id}>{note.content}</li> )} </ul> </div> ) } وهكذا ستختفي رسالة التحذير. تستخدم React الصفات المفتاحية لتقرر الآلية التي تحدّث فيها مظهر التطبيق عندما يعاد تصيير مكوِّن. يمكنك دومًا استخدام وثائق React لمعرفة المزيد. التابع Map إنّ فهمك لآلية عمل التابع map عند التعامل مع المصفوفات أمر حيوي سيلزمك دائمًا. يحتوي التطبيق على مصفوفة تدعى notes: const notes = [ { id: 1, content: 'HTML is easy', date: '2019-05-30T17:30:31.098Z', important: true }, { id: 2, content: 'Browser can execute only Javascript', date: '2019-05-30T18:39:34.091Z', important: false }, { id: 3, content: 'GET and POST are the most important methods of HTTP protocol', date: '2019-05-30T19:20:14.298Z', important: true } ] لنتوقف قليلًا ونرى كيف يعمل map. لنقل أن الشيفرة التالية قد أضيفت إلى نهاية الملف: const result = notes.map(note => note.id) console.log(result) سينشئ التابع map مصفوفة جديدة قيمها [1,2,3] انطلاقًا من عناصر المصفوفة الأصلية. ويستخدم دالة كمُعامل له. ولهذه الدالة الشكل التالي: note => note.id تمثل الشيفرة السابقة الشكل المختصر لدالة سهمية تعطى بشكلها الكامل على النحو: (note) => { return note.id } تقبل الدالة السابقة الكائن note كمُعامل، وتعيد قيمة الحقل id منه. لكن إن غيرنا الشيفرة لتصبح: const result = notes.map(note => note.content) ستكون النتيجة مصفوفة تضم محتوى الملاحظات. هذه الشيفرة قريبة جدًا من شيفرة React التي استخدمناها سابقًا: notes.map(note => <li key={note.id}>{note.content}</li> ) والتي تنشئ عناصر li تضم المحتوى النصي للملاحظات. وطالما أن الدالة مُرّرت كمعامل إلى التابع map لإظهار العناصر، يجب وضع قيم المتغيّرات داخل الأقواس المعقوصة. note => <li key={note.id}>{note.content}</li> حاول أن تعرف ما الذي سيحدث لو أهملت تلك الأقواس. سيزعجك استخدام الأقواس المعقوصة في البداية لكنك ستعتاد على ذلك وستساعدك React بإظهارها مباشرة نتائج شيفرتك. استخدام مصفوفة القرائن كمفاتيح: الأسلوب المعاكس كان بإمكاننا إخفاء رسالة الخطأ السابقة باستخدام مصفوفة القرائن (Array indexes) كمفاتيح، حيث نستخلص هذه القرائن بتمرير معامل آخر إلى دالة الاستدعاء التي استخدمناها كمعامل للتابع map: notes.map((note, i) => ...) عندما نستدعي الدالة بالشكل السابق ستأخذ i قيمة القرينة التي تشير إلى موقع الملاحظة في الكائن note، وبهذا الأسلوب سنعرّف طريقةً لإنشاء المطلوب دون أخطاء: <ul> {notes.map((note, i) => <li key={i}> {note.content} </li> )} </ul> على الرغم من ذلك لا نوصي باتباع هذا الأسلوب نظرًا للمشاكل غير المتوقعة التي يمكن أن تحدث حتى لو بدا أنّ التطبيق يعمل بشكل جيد. يمكنك الاطلاع أكثر بقراءة مقالات تتعلق بالموضوع. إعادة تكوين الوحدات لندعّم الشيفرة التي كتبناها قليلًا. طالما أن اهتمامنا ينحصر في الحقلnotes فقط من خصائص المكوِّن، لنستخلص قيمة الحقل المطلوب مباشرة بطريقة التفكيك: const App = ({ notes }) => { return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <li key={note.id}> {note.content} </li> )} </ul> </div> ) } وإن أردت تذكّر معلوماتك عن موضوع التفكيك راجع فقرة التفكيك في القسم السابق. سنعرف الآن مكوِّنًا جديدًا Note لعرض الملاحظة: const Note = ({ note }) => { return (<li>{note.content}</li> )} const App = ({ notes }) => { return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <Note key={note.id} note={note} /> )} </ul> </div> ) } لاحظ أن الصفة المفتاحية ارتبطت الآن بالمكوِّن Note وليس بالعنصر li. يمكن كتابة تطبيق React بأكمله ضمن ملف واحد. لكن جرت العادة على كتابة كل مكوِّن في ملف خاص على شكل وحدة ES6، على الرغم من أن هذا الأسلوب ليس عمليًا جدًا. لقد استخدمنا الوحدات منذ البداية في شيفرتنا كما فعلنا في أول سطرين من الملف: import React from 'react' import ReactDOM from 'react-dom' فلقد أدرجنا وحدتين لاستخدامهما في الملف. حيث أسندت الوحدة react إلى متغيّر يدعى React وكذلك أسندت الوحدة react-dom إلى المتغيّر ReactDOM. لننقل الآن المكوِّن Note إلى وحدته الخاصة. توضع المكوِّنات عادة في مجلد يدعى components ضمن المجلد src الموجود في المجلد الرئيسي للتطبيق، ويفضل تسمية الملف باسم المكوِّن. دعونا ننفذ ما ذكرناه ونضع المكوِّن Note في ملف جديد يدعى Note.js كالتالي: import React from 'react' const Note = ({ note }) => { return ( <li>{note.content}</li> ) } export default Note لاحظ أننا أدرجنا React في السطر الأول لأن المكوِّن هو مكوِّن React. سيصدّر السطر الأخير الوحدة الجديدة التي عرفناها باسم Note لكي تستخدم في مكان آخر. سندرج الآن الوحدة الجديدة في الملف index.js: import React from 'react' import ReactDOM from 'react-dom' import Note from './components/Note' const App = ({ notes }) => { // ... } وهكذا يمكن استخدام الوحدة الجديدة بإسنادها إلى المتغيّر Note. وتذكر كتابة عنوان الوحدة بطريقة العنوان النسبي عند إدراجها. './components/Note' تشير النقطة (.) في بداية العنوان إلى المسار الحالي وبالتالي فإن الملف Note.js موجود ضمن المجلد الفرعي component والموجود ضمن المسار الحالي (المجلد الذي يحوي التطبيق). ملاحظة: يمكن إغفال كتابة اللاحقة js . لنصرح الآن عن المكوِّن App أيضًا في وحدة خاصة به. وطالما أنه المكوِّن الجذري سنضعه مباشرة في المجلد src: import React from 'react' import Note from './components/Note' const App = ({ notes }) => { return ( <div> <h1>Notes</h1> <ul> {notes.map((note) => <Note key={note.id} note={note} /> )} </ul> </div> ) } export default App ما بقي إذًا في الملف index.js هو التالي: import React from 'react' import ReactDOM from 'react-dom' import App from './App' const notes = [ // ... ] ReactDOM.render( <App notes={notes} />, document.getElementById('root') ) للوحدات استعمالات أخرى عديدة بالإضافة إلى التصريح عن المكوِّنات في ملفاتها الخاصة، سنعود إليها لاحقًا في المنهاج. ستجد شيفرة التطبيق الحالي على موقع GitHub. يحوي المسار الرئيسي للمخزن كما ستلاحظ شيفرات للنسخ التي سنطورها لاحقًا، لكن النسخة الحالية في المسار part2-1. قبل أن تشغّل التطبيق باستعمال الأمر npm start، نفذ أولًا الأمر npm install. عندما ينهار التطبيق سترى في بداياتك البرمجية أو حتى بعد 30 عامًا من كتابة الشيفرات أن التطبيق قد ينهار أحيانًا وبشكل مفاجئ. وسيكون الأمر أسوأ في اللغات التي يمكن كتابة تعليماتها بشكل ديناميكي أثناء التنفيذ مثل JavaScript. فلا يتاح عندها للمتصفح من التحقق مثلًا من نوع البيانات التي يحملها متغيّر أو التي تمرر لدالة. يظهر الشكل التالي مثالًا عن انهيار تطبيق React: سيكون مخرجك الوحيد من المأزق هو الطباعة على الطرفية. إنّ الشيفرة المسؤولة عن الانهيار في حالتنا هي: const Course = ({ course }) => ( <div> <Header course={course} /> </div> ) const App = () => { const course = { // ... } return ( <div> <Course course={course} /> </div> ) } سنقتفي أثر الخطأ بإضافة التعليمة console.log إلى الشيفرة. وطالما أن المكوِّن App سيصيّر أولًا فمن المفيد وضع أول تعليمة طباعة ضمنه: const App = () => { const course = { // ... } console.log('App works...') return ( // .. ) } عليك طبعًا النزول إلى الأسفل مرورًا بقائمة الأخطاء الطويلة حتى ترى نتيجة الطباعة. حالما تتأكد من أن الأمور جيدة حتى نقطة معينة، عليك نقل تعليمة الطباعة إلى نقطة أعمق. وتذكر أن التصريح عن مكوِّن بعبارة واحدة أو عن دالة دون أن تعيد قيمة، سيجعل الطباعة على الطرفية أصعب. const Course = ({ course }) => ( <div> <Header course={course} /> </div> ) لذا غيًر تصريح المكوِّن إلى شكله النموذجي حتى تستطيع الطباعة: const Course = ({ course }) => { console.log(course) return ( <div> <Header course={course} /> </div> ) } قد يكون السبب الأساسي للمشكلة في أحيانٍ كثيرة متعلقًا بالخصائص التي تظهر بأنواع مختلفة عن المتوقع أو التي تستدعى بأسماء مختلفة عن أسمائها الفعلية. وكنتيجة لذلك، ستخفق عملية التفكيك. ويدل على ذلك التخلص من الأخطاء بمجرد إزالة عملية التفكيك، حيث يمكن معرفة المحتوى الفعلي للخصائص. const Course = (props) => { console.log(props) const { course } = props return ( <div> <Header course={course} /> </div> ) } إن لم تُحل المشكلة، لا يمكنك عندها سوى اصطياد الأخطاء بزرع تعليمة الطباعة console.log في أماكن مختلفة من الشيفرة. أضيفت هذه الفقرة لمادة المنهاج بعد أن أخفقت الوحدة التي تمثل حلًا للسؤال التالي بشكل كامل (نظرًا لخطأ في نمط الخصائص) وتوجب علي البحث عن السبب باستخدام تعليمة الطباعة. التمارين 2.1 - 2.5 تسلّم التمارين عبر GitHub ومن ثم يشار إلى إكمالها ضمن منظومة تسليم الملفات. يمكنك أن تضع جميع التمارين في مخزن واحد أو استخدم مخازن مختلفة. إذا وضعت تمارين الأقسام المختلفة في مخزن واحد، احرص على تسمية المجلدات ضمنه بشكل مناسب. تُسلَّم تمارين كل قسم دفعة واحدة، فلا يمكنك تسليم أية تمارين أنجزتها مؤخرًا من قسم ما إذا كنت قد سلمت غيرها من القسم ذاته. يضم هذا القسم تمارين أكثر من القسمين السابقين، لا تسلم أيًا منها حتى تنجزها كلها. تحذير: سيجعل create_react_app المشروع مستودع git إلا إذا أنشأت مشروعك داخل مستودع موجود مسبقًا. لن تريد فعل ذلك على الأغلب، لذا نفذ الأمر rm -rf .git عند جذر مشروعك. 2.1 معلومات عن المنهاج: الخطوة 6 سننهي في هذا التمرين تصيير محتوى المنهاج الذي استعرضناه في التمارين 1.1-1.5. يمكنك البدء من الشيفرة الموجودة في نماذج الأجوبة. ستجد نماذج أجوبة القسم 1 في منظومة تسليم الملفات. انقر على my submissions في الأعلى ثم انقر على show الموجودة ضمن العمود solutions في السطر المخصص للقسم 1. انقر على الملف index.js للاطلاع على حل تمرين "معلومات عن المنهاج course info" تحت عبارة kurssitiedot التي تعني (معلومات عن المنهاج). تنبيه: إذا نسخت مشروعًا من مكان لآخر، سيتوجب عليك حذف المجلد node_modules وإعادة تثبيت ملفات الارتباط (Dependencies) مرة أخرى بتنفيذ الأمر npm install قبل أن تشغل التطبيق. لا يفضل أن تنسخ المحتوى الكامل لتطبيق أو أن تضيف المجلد node_modules إلى منظومة التحكم بالإصدار أو أن تقوم بكلا العملين. لنغيّر الآن المكوِّن App كما يلي: const App = () => { const course = { id: 1, name: 'Half Stack application development', parts: [ { name: 'Fundamentals of React', exercises: 10, id: 1 }, { name: 'Using props to pass data', exercises: 7, id: 2 }, { name: 'State of a component', exercises: 14, id: 3 } ] } return <Course course={course} /> } عّرف مكوِّنًا يدعى Course مسؤولًا عن تنسيق منهاج واحد. يمكن أن يتخذ التطبيق الهيكلية التالية: App Course Header Content Part Part ... سيضم المكوِّن Course كل المكوِّنات التي عرّفناها في القسم السابق والمسؤولة عن تصيير اسم المنهاج وأقسامه. ستبدو الصفحة بعد التصيير على الشكل التالي: ليس عليك جمع عدد التمارين بعد. لكن يجب عليك التأكد من أن التطبيق يعمل بشكل جيد بغض النظر عن عدد الأقسام في المنهاج. أي أنه سيعمل لو أزلت أو أضفت أقسامًا. واحرص على عدم ظهور أخطاء على الطرفية. 2.2 معلومات عن المنهاج: الخطوة 7 أظهر عدد التمارين الكلية في المنهاج. 2.3 معلومات عن المنهاج: الخطوة 8 * إن لم تجد طريقة لحل التمرين السابق، احسب العدد الكلي للتمارين باستخدام التابع reduce الذي يستعمل مع المصفوفات. نصيحة للاحتراف 1: إن بدت شيفرتك بالشكل التالي: const total = parts.reduce((s, p) => someMagicHere) ولم تعمل، يجدر بك استخدام تعليمة الطباعة على الطرفية، والتي تتطلب إعادة كتابة الدالة السهمية بشكلها الكامل: const total = parts.reduce((s, p) => { console.log('what is happening', s, p) return someMagicHere }) نصيحة للاحتراف 2: يمكنك استخدام إضافة للمحرر VS يمكنها تحويل الدالة السهمية المختصرة إلى الكاملة وبالعكس. 2.4: معلومات عن المنهاج: خطوة 9 وسّع التطبيق ليعمل مع أي عدد افتراضي من المناهج: const App = () => { const courses = [ { name: 'Half Stack application development', id: 1, parts: [ { name: 'Fundamentals of React', exercises: 10, id: 1 }, { name: 'Using props to pass data', exercises: 7, id: 2 }, { name: 'State of a component', exercises: 14, id: 3 }, { name: 'Redux', exercises: 11, id: 4 } ] }, { name: 'Node.js', id: 2, parts: [ { name: 'Routing', exercises: 3, id: 1 }, { name: 'Middlewares', exercises: 7, id: 2 } ] } ] return ( <div> // ... </div> ) } يمكن أن يبدو التطبيق بالشكل التالي: 2.5 وحدات منفصلة صرح عن المكوِّن Course في وحدة منفصلة يمكن إدراجها في ملف المكوِّن App. يمكن أن تضع كل المكوِّنات الفرعية للمنهاج ضمن نفس الوحدة. ترجمة -وبتصرف- للفصل Rendering a collection,modules من سلسلة Deep Dive Into Modern Web Development1 نقطة