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

مصطفى القباني

الأعضاء
  • المساهمات

    89
  • تاريخ الانضمام

  • تاريخ آخر زيارة

إجابات الأسئلة

  1. إجابة مصطفى القباني سؤال في سؤال في الرياضيات والإحصاء كانت الإجابة المقبولة   
    العفو شكراً جدا على ذوق حضرتك.
    ليس بالظبط، فهذا يتوقف على المقصود ب"أفضل".
    للحصول على أفضل نتيجة في التدريب، فبوضع c1 وc2  ب صفر سيعطي أفضل نتيجة خلال التدريب، بسبب الoverfitting.
    لكن أفضل نتيجة على بيانات الإختبار والcross validation يتم الحصول عليها تجريبياً، بتجربة قيم مختلفة لc1 وc2 في search space أو  param space معينة.
    وتحديد التوزيع الإحصائي الذي يتم سحب منه القيم يكون عن طريق معرفة مجال القيم المنطقية، فمثلا في حالتنا القيم السالبة مستبعدة، لأننا نريد إضافة عقوبة موجبة إلى دالة الخطأ، وأيضاً القيمة يجب أن تكون أقل من واحد في الحالتين، لأننا لن نقوم بإضافة عقوبة على متغيرات المودل بقيمة أكبر من المتغيرات نفسها. (إذا إستخدمنا قيمة اكبر من 1 كمعامل، سيتم إضافة عقوبة حجمها أكبر من مجموع المعاملات أو مجموع مربعات المعاملات).
    بالتالي بمعرفتنا تلك المعلومات قمنا بحصر الsearch space بين الصفر والواحد، ويتبقى فقط تحديد توزيع إحصائي يعطي قيم في هذا المجال.
    يمكن مثلاً إستخدام توزيع uniform بين 0 و 1 أو exponential distribution كما في الكود الخاص بك، لكن تأكد من أن الscale المعطى للدالة expon يعطي قيم في المجال المرغوب.
  2. إجابة مصطفى القباني سؤال في التأكد من نوع المتغير في بايثون كانت الإجابة المقبولة   
    يمكنك الكشف على نوع المتغير عن طريق الدالة type.
    مثلا:
    x = 1 print(type(x)) y = 'hello' print(type(y)) if type(x) is int: print('the type is int') كما أن بايثون أيضاً تفضل إستخدام ما يسمى بالduck typing، وهو أن تتعامل مع المتغير الذي لديك على أنه نوع معين، وأن تتعامل مع الخطأ إن حدث. مثلاً:
    x = 1 try: y = x[:1] # أفترضنا أن المتغير إكس عبارة عن مصفوفة أو سترينج except: print("x is not a string or a list, can't be sliced") يمكنك القراءة أكثر عن الduck typing من هنا أو هنا.
    بالتوفيق
  3. إجابة مصطفى القباني سؤال في حقل الإدخال يأخذ أكثر من 5 حروف رغم أنني حددت له الخاصية max ب خمسة HTML كانت الإجابة المقبولة   
    تحياتي
    الخطأ في كود حضرتك بسيط وهو أن الattribute اسمه maxlength وليس max .
    لذلك يجب تعديل الكود ليصبح كالآتي:
    <input type="text" maxlength="5" required="required" placeholder="enter first name"/> لاحظ أن maxlength تستخدم مع النوع text بينما max تستخدم مع: number, range, date, datetime-local, month, time and week.
    بالتوفيق
  4. إجابة مصطفى القباني سؤال في ممكن شرح هذا الكود .. ريأكت كانت الإجابة المقبولة   
    تحياتي
    في السطر الأول:
    function AppFormField({name, ...otherProps}){ تم تعريف functional component وهو أحد نوعين من الcomponents في ريأكت، ويستخدم الfunctional component إذا لن يحتوي الcomponent  على state.
    ويتم إنشاء الcomponent بتمرير الخواص name و otherProps مع إستخدام الspread operator.
    في السطر التالي:
    const { setFieldTouched, handleChange, errors, touched} = useFormikContext()  تم إستدعاء الدالة useFormikContext() (هي في الواقع hook) وتم عمل object destructuring للobject الذي تم إرجاعه من هذا الfunction.
    لفهم الobject destructuring ، إذا كان لديك الobject الآتي:
    let x ={ a: 1, b :2, c :'hello', }  
    فيمكن إستقبال ما تم تعريفه داخل الobject هكذا:
    let {a,b,c} = x وهو ما تم عمله في الكود الخاص بحضرتك.
    بعد ذلك:
    return ( <> <AppTextInput onBlur={() => setFieldTouched(name)} onChangeText={handleChange(name)} {...otherProps} /> <ErrorMessage error={errors[name]} visible={touched[name]} /> </> ); export default AppFormField; بعد ذلك تم تعريف دالة الrender، وتقوم بإرجاع :
    AppTextInput و ErrorMessage وتم إحطاتهم بreact fragment.
     الcomponent الأول تم إنشائه بالprops onBlur وonChangeText وهما ما إستقبالهم بعمل object destructuring بالأعلى.
    بعد ذلك تم عمل export للcomponent ليمكن إستدعائه في الملفات الأخرى.
    بالتوفيق.
  5. إجابة مصطفى القباني سؤال في كيفية ارسال بيانات ( التاريخ والساعه ) بواسطة البايثون كانت الإجابة المقبولة   
    بالفعل السبب هو أن الelement المطلوب موجود بداخل iframe، والذي بدوره موجود بداخل iframe آخر، والذي بدوره بداخل iframe آخر. لذلك يجب عمل switching ثلاث مرات.
    يمكن عمل التالي كالآتي:
    #اختصار الاسم الطويل للفانكشن q = driver.find_elements_by_css_selector #إيجاد أول فريم وعمل سويتش إليه frames = q('iframe')[1] a = driver.switch_to_frame(q('iframe')[1]) inside_frame = q('*') #إيجاالفريم بداخل الفريم وعمل سويتش إليه inception_frame = inside_frame[-2] driver.switch_to_frame(inception_frame) #إيجاالفريم بداخل الفريم بداخل الفريم وعمل سويتش إليه double_inception_frame = q("*")[-2] driver.switch_to_frame(double_inception_frame) بعد ذلك لإضافة التاريخ إلى الinput:
    from selenium.webdriver.common.keys import Keys #الآن يمكننا الوصول للعنصر لأننا بداخل الفريم الحاوي له inp = q('#stop-datetime')[0] our_time = '11/23/2021 11:14 AM' inp.send_keys('11') inp.send_keys('23') inp.send_keys('2021') inp.send_keys(Keys.TAB) inp.send_keys('11') inp.send_keys('14') inp.send_keys('AM') بعد ذلك إن أردت العودة إلى الصفحة خارج جميع الframes:
    driver.switch_to_default_content() بالتوفيق.
  6. إجابة مصطفى القباني سؤال في كيف أحسب نسبة التغير من أكثر من قيمة رقمية؟ كانت الإجابة المقبولة   
    ممتاز جدا هذه هي النتيجة الصحيحة.
  7. إجابة مصطفى القباني سؤال في سؤال حول استعمال diff و regex كانت الإجابة المقبولة   
    تحياتي
    بالنسبة لdiff هي أداة لتوضيح الفرق بين ملفين، ويتم إستدعائها كالآتي:
     
    diff filename1 filename2 ويمكن إضافة -u عند إستدعائها كالآتي:
     
    diff -u filename1 filename2 في كلا الحالتين يتم توضيح الإختلاف بين الملفين، ولكن يكون التنسيق مختلف، فعند إضافة ال-u يتم طباعة الإختلاف بشكل يسمى بالunified format وهي فقط طريقة مختلفة لتوضيح الإختلاف بين الملفين.

    مثال توضيحي، إذا كان لدينا ملفين first_file.txt ومحتوياته هي:
    first line second line third line وملف آخر اسمه second_file.txt ومحتوياته هي:
    first line second line عند إستخدام diff first_file.txt second_file.txt يكون الناتج هو:

    وعند إستخدام diff -u first_file.txt second_file.txt يكون الناتج هو:

    بالنسبة لvimdiff، فإن vim هو text editor، يوفر الكثير من الأدوات التي تسهل على المبرمجين، إحدى هذه الأدوات هي أداة vimdiff وهي تستخدم أيضاً لتوضيح الإختلاف بين الملفات.
    يتم إستدعائها كالآتي:
     
    vimdiff first_file.txt second_file.txt ويكون المخرجات هي:

    بالنسبة لإشارة < و  إشارة > ، يتم إستخدامهم لإعادة توجيه المخرجات والمدخلات. مثلا عند إستخدام الأمر الآتي مع diff:
    diff first_file.txt second_file.txt > diff.txt يتم إعادة توجيه المخرجات إلى الملف diff.txt
    يمكنك القراءة عن إعادة التوجيه في موسوعة حسوب من هنا.

    بالنسبة للregex في المثال:
    re.search(r"^[a-zA-Z] ", "this is a sentence with spaces.")  الregex string المطلوب البحث عنه أوله ^ أي أن يجب أن يطابق الحرف التالي البداية، ثم حرف واحد من الأبجدية a-zA-Z ثم مسافة.
    ستكون نتيجة البحث السابق فارغة، لأن الجملة التي يتم البحث فيها أولها ليس حرف متبوع بمسافة.
     
    بالنسبة ل:
    re.search(r"py[a-z] *n", "Python Porgramming."): يتم البحث عن الحرفين py متبوعين بحرف من الأبجدية من a-z متبوعة بمسافة إختيارية أو أكثر متبوعة بحرف n.
    أيضاً ستكون نتيجة البحيث فارغة لأن ما يتم البحث عنه غير موجود بالstring.
    ربما كان القصد هو الآتي:
    re.search(r"Py[a-z]*n", "Python Porgramming.") وقتها ستكون نتيجة البحث هي Python لأن بالفعل Py جائت متبوعة بحروف من الأبجدية بعدد صفر أو أكثر من مرة، متبوعة بحرف n.

    بالنسبة ل:
     re.search(r"o+L+", "goldfish.") يتم البحث عن الحرف o مرة واحدة أو أكثر متبوع بحرف L كابيتال مرة واحدة أو أكثر، وستكون نتيجة البحث فارغة لأنه لا يوجد مطابقة.
    لكن إذا تم تغيير حرف الL إلى l ستتم المطابقة لol
     
    بالنسبة ل:
     re.findall(r"[a-zA-Z]{5} ", "a scary ghost appeared")    يتم البحث عن عدد 5 حروف من حروف الأبجدية سواء الكابيتال أو السمول متبوعة بمسافة، بالتالي يتم إرجاع ghost و scary.
    بالتوفيق.
  8. إجابة مصطفى القباني سؤال في شرح كود bash كانت الإجابة المقبولة   
    تحياتي
    السطر الأول:
    #!/bin/bash تعرف العلامة #! باسم ال'shabang' وتستخدم في أنظمة التشغيل linux لتحديد البرنامج الذي سيقوم بتشغيل الscript، ويتم تمرير الscript كمدخلات إلى هذا البرنامج.
    في هذه الحالة عند تشغيل الملف الذي لدينا، سيقوم نظام التشغيل بإستخدام /bin/bash وإعطاء الكود الموجود في الscript كinput لهذا البرنامج.
    ومثلاً إذا كان الshabang متبوعاً ب/bin/python سيقوم نظام التشغيل بتشغيل الscript داخل بايثون.
    n=0 تم تعريف متغير n ومساوته بالصفر.
    command=$1 يعرف $1 باسم الpositional parameters وهو ما تم تمريره إلى السكريبت، وهو مشابه لsys.argv في بايثون.
    على سبيل المثال إذا كان لديك script بهذا الشكل واسمها script.sh:
    command=$1 command2=$2 echo $command echo $command2 وقمت بإستدعاءها كالآتي:
    script.sh arg1 arg2 سيتم طباعة arg1 arg2 وهو ما تم تمريرهم إلى الscript.
    بالتالي في الكود الخاص بك قمنا بوضع أول قيمة تم تمريرها عند إستدعاء الscript في المتغير command.
     
    while ! $command && [ $n -le 5 ]; do يتم عمل loop تقوم بالإستمرار في حالتين، لفهم الحالتين يجب توضيح الآتي:
    ! $command عند كتابة ! متبوعاً بأمر، يتم تنفيذ آخر أمر تم تنفيذه من الhistory. مثلا:
    !ls سيقوم بتنفيذ آخر أمر ls موجود بالhistory.
    أيضاً هناك نقطة هامة لفهم عمل الloop، وهو في نظام تشغيل لينكس، الأمر الناجح يقوم بإرجاع القيمة 0 ، بينما الأمر الغير ناجح يرجع قيمة لا تساوي الصفر. لذلك عند إستخدام أمر ما كشرط في الloop، فإن الloop يتم الخروج منها عند تنفيذ الأمر بنجاح، بينما تستمر الloop إذا كان الأمر غير ناجح.
     
    [ $n -le 5 ] هنا le تعني less than or equal، أي أن الشرط هنا أن تكون n أقل من أو تساوي 5.
     
    sleep $n ((n=n+1)) echo "Retry #$n" done; الأمر sleep يقوم بعمل إنتظار لعدد معين من الثواني.
    إذا الكود ككل يقوم بعمل الآتي:
    يتم تمرير أمر ما إلى الscript، ويتم تخزين هذا الأمر في متغير يدعى command، ويتم تعريف متغير n ومساوته بالصفر.
    ثم يتم عمل loop يتم الخروج منها إذا تم تنفيذ الأمر بنجاح، ويتم الإستمرار فيها بينما الأمر به خطأ وn أقل من أول تساوي 5. وفي اللوب يتم التأخير بعدد n من الثواني ، ثم زيادة n، وطباعة الجملة Retry.
  9. إجابة مصطفى القباني سؤال في تعريف methods للصنف Line بلغة ال++c كانت الإجابة المقبولة   
    تحياتي
    المطلوب هو تعريف الmethods للصنف Line.
    يمكن عمل المطلوب بوضع التالي في ملف Line.cpp :
    #include <cmath> #include "Line.h" Line::Line(double x1, double y1, double x2, double y2) { Line::x1 = x1; Line::x2 = x2; Line::y1 = y1; Line::y2 = y2; } double Line::getStartX() { return x1; } double Line::getStartY() { return y1; } double Line::getEndX() { return x2; } double Line::getEndY() { return y2; } double Line::getSlope() { return (y2 - y1) / (x2 - x1); } bool Line::isVertical() { return ((x2 - x1) == 0); } bool Line::isHorizontal() { return ((y2 - y1) == 0); } bool Line::isThroughOrigin() { return (x1 * (y2 - y1) == y1 * (x2 - x1)); } void Line::mirror(int axis) { double slope = getSlope(); double new_slope = -slope; if (isVertical() && axis >= 0) y2 = y1 - (y2 - y1); else if (isHorizontal() && axis < 0) x2 = x1 - (x2 - x1); else { if (axis >= 0) y2 = y1 + new_slope * (x2 - x1); else x2 = x1 + ((y2 - y1) / new_slope); } } شرح الدوال:
    بالنسبة للLine::Line هو الconstructor ويأخذ x1 و y1 وx2 وy2.
    بالنسبة ل getStartX getStartY getEndX getEndY يقومو بإرجاع النقاط الأربعة x1 y1 x2 y2 بالترتيب.
    بالنسبة لgetSlope تقوم بإرجاع ميل الخط المستقيم، ويتم حسابه من معادلة الميل:
    بالنسبة ل isVertical isHorizontal تقوم بالتحقق إذا كان الخط أفقي أو رأسي.
    ويتم التحقق من ذلك من خلال الكشف إذا كان x2 -x1 مساوي للصفر في حالة الكشف عن إذا كان الخط رأسي، وإذا كان y2 - y1 مساوي للصفر في حالة إذا كان الخط أفقي.
    بالنسبة ل isThroughOrigin تقوم بالتحقق إذا كان الخط يمر بنقطة الأصل (0،0)، ويتم ذلك عن طريق التحقق إذا كان (x1 * (y2 - y1) == y1 * (x2 - x1)) .
     
    بالنسبة ل mirror تأخذ متغير axis وتقوم بعمل إنعكاس للخط حول المحور الأفقي إذا كانت axis أكبر من أو تساوي للصفر، أو المحور الرأسي إذا كانت axis أقل من الصفر.
    وحسب المطلوب فإن الإنعكاس لا يغير نقطة البداية x1 y1 ولكن يغير نقطة النهاية فقط، مع ملاحظة أن إذا كان الإنعكاس حول المحور الأفقي فإن x1 y1 x2 لا يتغيروا، ويتغير فقط y2.
    وبالمثل إذا كان الإنعكاس حول المحور الرأسي فإن x1 y1 y2 لا يتغيروا، ويتغير فقط x2.
    ولاحظ أيضاً أنه عند عمل الإنعكاس، فإن الميل للخط المستقيم يتغير للسالب، مثلاً إذا كان ميل الخط 5 يصبح -5 وهكذا.
    وبالتالي يمكن معرفة النقطة الناقصة بالتعويض في معادلة الميل مع إضافة إشارة سالبة للميل
    وبالمثل لحساب x2.
    هناك نقطتين أخرتين يجب مراعاتهم في هذه الدالة، وهي أن التعويض في معادلة الميل سيعطي خطأ في حالة أن الخط أفقي أو رأسي، بسبب أن ميل الخط الأفقي = 0 ، والرأسي ميله لا نهاية، بالتالي يتم حساب نقطة النهاية بدون التعويض في القانون ولكن بإستخدام :
    y2 = y1 - (y2 - y1); في حالة الخط الرأسي.
    و باستخدام:
     x2 = x1 - (x2 - x1); في حالة الخط الافقي.
    بالتوفيق.
  10. إجابة مصطفى القباني سؤال في ممكن حل لهذا السؤال بلغة ال++c وشكرا كانت الإجابة المقبولة   
    يمكن عمل المطلوب كالآتي:
    #include <iostream> using namespace std; void Multiply(const int[], const int[][3], int[], int); int main(){ int n; cin >> n; int v_array[n]; int m_array[n][3]; int o_array[3]; for (int i=0; i<n; i++) cin >> v_array[i]; for (int i=0; i<n; i++) for(int j=0; j<3; j++) cin >> m_array[i][j]; Multiply(v_array,m_array,o_array,n); for(int j=0; j<3; j++) cout<<o_array[j]<<" "; return 0; } void Multiply(const int v_arr[], const int m_arr[][3], int o_arr[], int size){ int current_sum; for (int i=0; i<3; i++){ current_sum = 0; for(int j=0;j<size;j++){ current_sum += v_arr[j] * m_arr[j][i]; } o_arr[i] = current_sum; } } المطلوب هو تعريف دالة Multiply  والتي تقوم بضرب متجه من الحجم 1 * ن في مصفوفة من الحجم ن * 3.
    شرط الضرب للمصفوفات في هذه الحالة دائماً متحقق، وشرط الضرب هو أن عدد أعمدة المصفوفة الأولى تساوي عدد صفوف المصفوفة الثانية. وهو دائماً متحقق لأن حجم المتجه هو 1 * ن أي أن عدد أعمدته تساوي ن ، وحجم المصفوفة هو ن*3 ، أي أن عدد الصفوف تساوي ن. بالتالي عدد أعمدة المتجه الأول مساوي لعدد صفوف المصفوفة، بالتالي يمكن ضربهم.
    تتم عملية الضرب في loop التالية بضرب المتجه في كل عمود للمصفوفة، وينتج عن عملية الضرب العنصر المناظر في المتجه الناتج.
    int current_sum; for (int i=0; i<3; i++){ current_sum = 0; for(int j=0;j<size;j++){ current_sum += v_arr[j] * m_arr[j][i]; } o_arr[i] = current_sum; } يمكنك تجربة الكود كامل من هنا.
  11. إجابة مصطفى القباني سؤال في ممكن حل لهذا السؤال بلغة ال ++c كانت الإجابة المقبولة   
    يمكن عمل المطلوب كالآتي:
     
    #include <iostream> using namespace std; int minimumNumberOfSteps(int n, int count){ if (n==1){ return count; } else if(n%3 == 0){ return minimumNumberOfSteps(n/3, count+1); } else if(n%2 == 0){ return minimumNumberOfSteps(n/2, count+1); } else{ return minimumNumberOfSteps(n-1, count+1); } } int main() { int n; cout<<"Please enter n"; cin >> n; int answer = minimumNumberOfSteps(n,0); cout<< answer << endl; return 0; } في الدالة المعرفة تستخدم الrecursion مثل المطلوب وتأخذ متغيرين هما العدد n، وعدد الخطوات التي تم عملها count حتى الآن، وتطبق الأربع حالات المعطاه وهي:
    إذا كانت قيمة n مساوية للواحد نقوم بإرجاع عدد الخطوات التي تم عملها للوصول.
    إذا كانت n تقبل القسمة على ثلاثة، نقوم بإستدعاء الدالة مع إستبدال n بn/3 وإضافة واحد لعدد الخطوات count.
    إذا كانت n تقبل القسمة على اثنان أي انها عدد زوجي، نقوم بإستدعاء الدالة مع إستبدال n بn/2 وإضافة واحد لعدد الخطوات count.
    إذا كانت n لا تقبل القسمة على 2 أو ثلاثة، نقوم بإستدعاء الدالة مع إستبدال n بn-1 وزيادة واحد لعدد الخطوات count.
    يمكنك تجربة الكود من هنا.
  12. إجابة مصطفى القباني سؤال في ماهي sys.argv في لغة بايثون كانت الإجابة المقبولة   
    بالنسبة لsys.argv هي الطريقة التي يتم الوصول إلى الarguments المعطاة للبايثون script.
    على سبيل المثال إذا كان لديك script به الكود الآتي وقمت بحفظه في ملف script.py:
    import sys for arg in sys.argv: print(arg) وقمت بإستدعاءه عن طريق الcommand line كالآتي:
    python script.py arg1 arg2 arg3 سيكون المخرج هو:
    script.py arg1 arg2 arg3 وهو ما تم تمريره في الcommand line.
    أما بالنسبة ل:
    if __name__ == '__main__': تستخدم في الملفات التي يراد إستخدامها بطريقتين، الأولى هي كبرنامج مستقل، والثانية إستدعائها في ملف آخر.
    مثلاً إذا كان لديك الملف example.py وبه الآتي:
    if __name__=='__main__': print('im running as the main program') def helper(a): return 2*a هذا الملف إذا تم تشغيله من خلال الcommand line سيقوم بطباعة 'im running as the main program'، أما إذا تم إستدعاءه داخل ملف آخر مثلا:
    import example print(example.helper(2)) فلن يتم طباعة الجملة، ولكن يمكن إستخدام الدوال والمتغيرات المعرفة بداخله، وبهذه الطريقة يمكن إستخدام الملف بطريقتين، بكونه البرنامج الرئيسي، أو إستخدامه كملف يتم إستدعاءه وإستخدام المتغيرات المعرفة بداخله. وهذه التفرقة تتم عن طريق الكشف على المتغير __name__ إذا كان مساوي ل'__main__' أم لا.
  13. إجابة مصطفى القباني سؤال في شرح مفاهيم أساليب يتم إستخدامها للتأكد من سلامة البرامج المكتوبة من الأخطاء كانت الإجابة المقبولة   
    تحياتي،
    هذه المصطلحات تخص إختبار البرمجيات، وهي أساليب يتم إستخدامها للتأكد من سلامة البرامج المكتوبة من الأخطاء بشتى أنواعها، والتأكد من تأديتها للوظائف المرغوبة.
    manual testing:
    الإختبار اليدوي، وهي القيام بإختبار وظائف البرنامج أو الموقع أو التطبيق بطريقة يدوية.
    automated testing:
    هو عمل الإختبارات بصورة برمجية، بحيث لا يتم إجراء الإختبار بصورة يدوية، ولكن عن طريق برنامج يكون لديه المخرج المتوقع، وإذا حاد البرنامج عن هذا المخرج يعتبر ان البرنامج فشل في الإختبار.
    test case:
    هي حالات الإختبار، ويتم تقسيم الإختبارات سواء اليدوية أو الautomated إلى حالات إختبار، يتم فحص كل وظيفة فيها على حدى.
    unit tests:
    إختبارات الوحدات، والوحدة هي أصغر جزء يمكن إختباره من البرنامج.
    edge cases:
    الحالات الطرفية, وهي الحالات التي تحدث في الحالات القصوى، مثل إختبار المدخلات الضخمة، أو متناهية الصغر.
    test suite:
    وهي حزمة من الإختبارات، يتم إجراءها معاً للتأكد من مطابقة البرنامج لمجموعة من المواصفات.
    black box :
    ويتم فيها إجراء الإختبار بدون النظر إلى مكونات البرنامج، ولكن عن طريق المدخلات والمخرجات فقط.
    white box:
    ويتم فيها فحص مكونات البرنامج من الداخل.
    integration test:
    وهي إختبارات يتم فيها التأكد من عمل أجزاء البرنامج المختلفة بصورة متوافقة، وهي قد تظهر أخطاء لا يظهرها إختبارات الوحدة unit tests.
    regression tests:
    إختبارات الإنحدار، وهي إختبارات غرضها التأكد من أن الخاصية الجديدة المضافة للبرنامج لم تتسبب في كسر بعض الخواص الموجودة في البرنامج.
    smoke test:
    وهي إختبارات تسأل أسئلة بسيطة، وفشلها يؤدي لرفض البرنامج. مثل: هل البرنامج يقوم بالفتح؟ هل الضغط على الزر يعمل؟
    load tests:
    وهي إختبارات تقوم بعمل ضغط على النظام لدراسته تحت هذا الضغط، مثلاً إرسال عدد كبير جداً من الطلبات إلى موقع ما، ودراسة متى يتوقف عن العمل.
    test driven developments
    وهي أسلوب من البرمجة يتم فيه كتابة حالات الإختبار قبل البدء في كتابة الكود، وثم كتابة الكود بغرض المرور من هذه الإختبارات.
    assertion error
    يحدث عند عدم تطابق نوع من المتغيرات مع النوع المتوقع، مثلاً دالة تتوقع أن تستقبل متغير من النوع integer ولكنها استقبلت string
    isalnum()
    دالة في لغة الc، والكلمة إختصار ل is alpha numeric وهي دالة تكشف إذا كان المعطى لها هو من الأرقام او من الحروف الأبجدية.
    raising errors
    وهي المصطلح البرمجي المستخدم لحدوث الأخطاء.
  14. إجابة مصطفى القباني سؤال في مشكلة في إغلاق ثغرة sql injection من خلال الprepared statement كانت الإجابة المقبولة   
    تحياتي أستاذ مروان
    في الكود يوجد جملة SQL وحيدة وهي عرضة للSQL injection وهي:
    $sql = "SELECT * FROM user WHERE phone='$phone' AND password='$password' "; وهي عرضة للSQL injection بسبب المتغيرات $password و $phone.
    لذلك عليك تجهيز هذه الجملة أولا عن طريق الprepared statements.
    نقوم بتجهيز الجملة بوضع علامة إستفهام مكان المتغيرات كالآتي:
    $stmt = $mysqli->prepare("SELECT * FROM user WHERE phone=? AND password=?"); وبعد ذلك نقوم بربط علامات الإستفهام بالمتغيرات التي نريد تمريرها إلى الجملة كالآتي:
    $stmt->bind_param("ss", $phone, $password); إذا كان المتغير phone$ من النوع int يجب تغيير الparameter الأول إلى "is" وتصبح الجملة كالآتي:
    $stmt->bind_param("is", $phone, $password); بالتالي يكون الكود الكامل لتجهيز الجملة وتنفيذها هو:
    $stmt = $mysqli->prepare("SELECT * FROM user WHERE phone=? AND password=?"); $stmt->bind_param("ss", $phone, $password); $result $stmt->execute(); ويمكنك التعامل مع الresult المرجعة.
  15. إجابة مصطفى القباني سؤال في كيف احمي ملفات php من ثغرة SQL Injections كانت الإجابة المقبولة   
    تحياتي أستاذ مروان
    في النموذج الأول، لنفرض أن المتغير $studentid قيمته تساوي الstring التالي:
    "1; DROP TABLE student;"
    وعند ترجمة الطلب الآتي: 
     $CheckSQL = "SELECT * FROM student WHERE studentid='$studentid'"; يصبح:
    SELECT * FROM student WHERE studentid=1; DROP TABLE student; لذلك الكود به ثغرة sql injection.
    لتجنب ذلك لابد من إستخدام الprepared statements و parameterized queries.
    تنفيذ الprepared statement يكون على خطوتين، الأولى التجهيز prepare ثم التنفيذ execute.بما أنك تستخدم MySQLi يمكنك عمل ذلك عن طريق الآتي:
    $stmt = $mysqli->prepare("SELECT * FROM student WHERE studentid = ?") $stmt->bind_param('s', $studentid); $stmt->execute(); $result = $stmt->get_result(); في السطر الثاني ال's' تشير إلى أن نوع المتغير هو string، إذا كان studentid هو int عليك تغييره إلى 'i'.
    بهذه الطريقة تصبح العبارة آمنة، بسبب أن جزء الأمر مفصول عن جزء الداتا، والسبب في أي sql injection هو خلط البيانات بالأوامر، حيث يمكن تمرير أمر إلى الداتابيز في شكل داتا.
    أي أمر ترسله إلى الداتابيز سواء إضافة أو قراءة، ويكون في هذا الأمر parameter، يجب تجهيزه بهذه الطريقة.
    بالتوفيق
  16. إجابة مصطفى القباني سؤال في تحويل الكود إلى دوال ++C كانت الإجابة المقبولة   
    تحياتي أستاذ عباس.
    الكود المكتوب به أخطاء، ولكن يبدو أن ما يجب أن يقوم بعمله هو حساب المجموع والمتوسط لأول n من الأعداد، والمطلوب تحويله إلى مجموعة من الدوال.
    يمكن عمل الآتي كالتالي:
    أولا عمل دالة تقوم بحساب مجموع أول n من الأعداد:
    int get_sum(int n){ int sum =0; for(int j=1; j<=n; j++) { sum = sum + j; } return sum; } وفيها نقوم بعمل loop ونقوم بجمع عداد الloop كل مرة وأضافته على المجموع، وبإنتهاء الloop نكون قد حصلنا على المجموع.
    ثانياً عمل دالة تقوم بحساب المتوسط لأول n من الأعداد، وتقوم بداخلها بإستخدام الدالة sum كالآتي:
    float get_avg(int n){ int sum; float avg; avg = (float)get_sum(n)/n; return avg; } وفيها قمنا بحساب المتوسط لأول n من الأعداد وهو حسب التعريف المجموع مقسوم على العدد، بالتالي قمنا بإستخدام دالة حساب المجموع، وقمنا بالقسمة على n، مع مراعاة عمل casting إلى النوع float عند قسمة integer على integer  لنحتفظ بالأجزاء العشرية.
    ويمكن إستخدامهم من الدالة main كالآتي:
    int main() { int n; float avg; cout<<" Enter N : "; cin>>n; cout<<" The sum= "<<get_sum(n)<<endl; cout<<" The average= "<<get_avg(n)<<endl; return 0; } وفيها قمنا بطلب إدخال عدد من المستخدم، وبعد إدخال العدد قمنا بإستخدام الدالتين الذي قمنا بتعريفهم لحساب المجموع وحساب المتوسط، وطباعة النتيجتين.
    الكود بالكامل موجود هنا.
    بالتوفيق.
  17. إجابة مصطفى القباني سؤال في كيفية كتابة برنامج بلغة ++c يدخل رقم n ويخرج n! كانت الإجابة المقبولة   
    تحياتي
    الكود المطلوب:
    #include <iostream> using namespace std; int main() { int i,fact=1,number; cout<<"Enter any Number: "; cin>>number; for(i=1;i<=number;i++){ fact=fact*i; } cout<<"Factorial of " <<number<<" is: "<<fact<<endl; return 0; } قمنا بتعريف المتغيرات i,fact, number.
    المتغير i سنقوم بإستخدامه كعداد الloop.
    المتغير fact سنقوم بتخزين القيمة المحسوبة فيه، والمتغير number لوضع الرقم المدخل من المستخدم.
    بعد ذلك قمنا بعمل loop تقوم بضرب الرقم بداية من 1 إلى الرقم المدخل، وهو التعريف لعملية الfactorial.
    يمكنك تجربة الكود من هنا.
    بالتوفيق
×
×
  • أضف...