لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 12/06/21 في كل الموقع
-
2 نقاط
-
كيف اجعل الخيار select يعرض الارقام من 1 الي 30 في الصورة تظهر في خيار واحد فقط <div class="form-group col-md-6"> <label for="inputState">نسخة البطاقة</label> <select id="inputState" type='text' class="form-control"> <option selected>...أختر</option> <option> @php $num =1; while($num <= 30){ echo $num++; } @endphp </option> </select> </div>2 نقاط
-
هل هناك اضافه بداخل برنامج visual studio code تقوم باضافه المسافات واذا كنت مثلا نسيت قفل div تقوم باضافته تلقائيا .2 نقاط
-
يوجد اضافة اسمها Auto Close Tag تقوم باغلاق الوسوم تلقائيا , هذه هي الصورة الخاصة بالاضافة يمكنك البحث عن اسمها ومن ثم عمل install لها , بالنسبة للمسافات فأنت تحتاج لاضافة تقوم بعمل تنسيق لكامل الملف حسب اللغة الخاصة به , يوجد اضافة اسمها Beautify يمكنها فعل ذلك وهذه صورتها هناك الكثير من الاضافات يمكنك البحث أكثر وتجرب ما تريده بالفعل2 نقاط
-
لاحظ أن لديك بعض الأخطاء البسيطة في الملف tourist.php مثل أن إغلاق حلقة while يجب أن يكون قبل العنصر footer مباشرة، وذلك لأنك تستعمل بعض المتغيرات الخاصة بالبيانات التي يتم إحضارها من قاعدة البيانات، وذلك سيؤدي إلى ظهور العديد من الأخطاء في حالة لم يتم إيجاد أي نتيجة في قاعدة البيانات، كما في الصورة التالية: الأمر الآخر هو أن لديك خطأ في جملة SQL حيث يجب أن تكون بالشكل التالي: $get_news_sql = "SELECT * FROM information WHERE Country LIKE '%{$_GET['search']}%' OR Capital LIKE '%{$_GET['search']}%' "; لاحظ كيف تم إستخدام قيمة المعامل search مباشرة في جملة SQL، ووجود علامة % قبل وبعد المعامل في تعيمتي LIKE. بهذا الشكل سوف يتم البحث عن أي مدينة أو دولة مشابهة للاسم الذي تم البحث عنه. أيضًا قد تجد أن النتيجة عبارة عن علامات إستفهام كما في الصورة التالية: ولحل المشكلة السابقة يجب أن تقوم بإستخدام الدالة mysqli_set_charset بدلًا من الدالة mysqli_query كالتالي: mysqli_set_charset($connection, 'utf8'); // بدلُا من الكود التالي // mysqli_query($connection, "set character_set_server='utf8mb4_general_ci'"); // mysqli_query($connection, "set names 'utf8mb4_general_ci'"); أيضًا يجب التحقق من وجود المعامل search من البداية من خلال الكود التالي: if (!isset($_GET['search'])) { header('Location: index.php'); // العودة إلى صفحة index } يمكنك أن تضع الكود السابق في بداية الملف tourist.php الأمر الأخير هو أنه في حالة وجود أكثر من نتيجة في قاعدة البيانات مسابهة لكلمة البحث فسوف يكون لديك أكثر من صفحة في الكود كما في الصورة التالية: ولحل المشكلة يجب أن تقوم بإضافة LIMIT 1 إلى جملة SQL لتكون بالشكل التالي: $get_news_sql = "SELECT * FROM information WHERE Country LIKE '%{$_GET['search']}%' OR Capital LIKE '%{$_GET['search']}%' LIMIT 1"; هنا ملفات المشروع بعد التعديل: 320.zip2 نقاط
-
عندما أقوم بإستعمال التابع flask.jsonify أو flask.dumps أحصل على نفس النتيجة في المتصفح، from flask import Flask, json, jsonify app = Flask(__name__) @app.route('/api', methods=['GET', 'POST']) def home(): content = { "username": "admin", "email": "admin@localhost", "id": 12 } return jsonify(content) # ما الفرق بين الطريقة السابقة والكود التالي؟ # return json.dumps(content) app.run() لذلك أريد أن أعرف الفرق بين إستخدام الطريقتين، ومتى أستعمل كل واحدة منهما؟1 نقطة
-
أحاول أن أقوم بعمل API وأريد أن أحصل على البيانات المرسلة من العميل على شكل كود JSON في طلب من نوع POST، حاولت أن أستخدم الكود التالي: @app.route('/api/<id>', methods=['GET', 'POST']) def add_message(id): content = request.json() return content ولكن يبدو أن هذه الطريقة لا تعمل بشكل صحيح، كيف أحصل على كود JSON المرسل في طلب POST في Flask؟1 نقطة
-
أريد الحصول على قائمة بجميع معرفات العناصر الموجودة في الصفحة إلى جانب نوع الوسم الموجودة فيه؟ كيف يمكنني القيام بذلك؟1 نقطة
-
أريد تحديد حد أقصى لوقت استجابة تنفيذ الأوامر في Selenium WebDriver، على سبيل المثال أريد شيئاً مثل هذا: driverObj = get_my_driver() # تحديد وقت الاستجابة على 10 ثوان driverObj.set_timeout(10) # الآن عند إرسال طلب للصفحة، أريده أن يتوقف أو أن يرمي استثناء عند تجاوز المدة المحددة وهي 10 ثوان driverObj.get('URL')1 نقطة
-
لدي حوالي 200 رابط من الشكل التالي: <a href="1.html">A1</a> <a href="2.html">A2</a> <a href="3.html">A3</a> <a href="4.html">A4</a> ... <a href="200.html">A200</a> حصلت عليهم من خلال السطر التالي: links=browser.find_elements_by_partial_link_text('A') سؤالي الآن هو كيف يمكنني الحصول على الخاصية href لكل الروابط؟1 نقطة
-
سؤال بخصوص أستدعاء الملفات في لارافيل في فروم . مثلا اذا كان لدي مجموعه من الفورم ولدي ملف واحد به قائمة المدن والدول واريد استدعاء هذا الملف في كل مرة اضيف بها كيف ذلك انا قمت بانشاء مجلد في ملف resourse بداخله ملف يحتوي علي مصفوفة مفتاحية تحتوي علي قائمة المدن . كيف استدعي الملف داخل الفورم انا اعلم انه اذا كان ملف لغه يجب ان استدعيه داخل الفورم {{ ('اسم الملف')__}} انا اقصد كيف استدعيه خارج ملف اللغه . بدون وضع المصفوفه داخل ملف اللغه . والاخر كيف أستدعي القيم بداخل خيار select وجلبها وهي غير مخزنة في قاعدة البيانات بداخل ملف به مصفوفة مفتاحية للقيم countries.php1 نقطة
-
كطريقة منظمة أكثر يمكنك إنشاء صنف مساعد بداخل مجلد تنشئه وليكن Helpers داخل App، يقوم هذا الصنف بتوفير تابع يوفر هاته الخدمة ومن ثم بإستدعاء بسيط سيمكن إستدعاءه و العمل عليه في أي مكان في تطبيقك. ليحتوي الملف الشيفرة التالية: <?php namespace App\Helpers; class CountriesHelper{ public static function get() { $filepath = 'path/to/file'; return file_get_contents($filepath); } } لنقم بتسجيل alias لهذا الصنف في ملف app.php في مصفوفة aliases كالتالي: <?php 'aliases' => [ 'Countries' => App\Helpers\CountriesHelper::class, ] يكون الإستدعاء والإستعمال كالتالي: <?php use Countries; ... public function someMethod() { $countries = Countries::get(); } أو في أحد ملفات العرض لخدمة غرضك مثلا كالتالي: <select name="nationalty" id=""> @foreach(\Countries::get() as $country) <option value="{{$country}}">{{$country}}</option> @endforeach </select>1 نقطة
-
لدي ملف من نوع csv ويحتوي على بعض البيانات الخاصة بالمستخدمين، وأريد أن أعيد هذه البيانات على شكل كود JSON لإستخدامها في عمل API بسيط، حاولت أن أستخدم الكود التالي: @app.route('/', methods=['GET']) def parse_request(): data = [] input_file = csv.DictReader(open("csv.txt")) return input_file ولكن لم ينجح الأمر لأن فلاسك Flask لا يعيد أي بيانات إلا إن كانت من نوع نص أو قاموس, tuple أو Response instance أو WSGI callable. كيف يمكنني أن أقوم بإرسال محتوى الملف csv.txt كـ كود JSON؟1 نقطة
-
يمكنك أن تقوم بهذا الأمر من خلال حلقة for في Laravel كالتالي: <select name="card"> @for($num = 1; $num <= 30; $num++) <option value="">{{$num}}</option> @endfor </select> بهذا الشكل لن تضطر إلى إستعمال أي كوجهات غير الموجهة for فقط1 نقطة
-
الكود الخاص بك به مشكلة صغيرة وهي يجب وضع كل قيمة من while في وسم option كما في الشكل التالي <div class="form-group col-md-6"> <label for="inputState">نسخة البطاقة</label> <select id="inputState" type='text' class="form-control"> <option selected>...أختر</option> @php $num =1; while($num <= 30){ echo '<option>'; echo $num++; echo '</option>'; } @endphp </select> </div>1 نقطة
-
بما أن الملف countries.php يقوم بإرجاع مصفوفة array فيمكنك أن تقوم بإستدعائه وحفظ محتواه في متغير، كالتالي: $categories = include('countries.php'); الآن يحتوي المتغير categories على المصفوفة المرجعة من الملف countries.php ويمكنك أن تستخدمها كما تريد. وبما أن الملف countries.php موجود في مجلد resources فتستطيع الوصول إليه من خلال الدالة resource_path، على النحو التالي: $categories = include(resource_path('countries.php')); وإذا كنت تريد الوصول إلى محتوى الملف من داخل ملف عرض view فيمكنك أن تستخدم الموجهة php التالي: @php $categories = include(resource_path('countries.php')); @endphp ثم يمكنك المرور على كل عنصر في المصفوفة وإستخدام القيمة لعمل عنصر select كالتالي: <select name="nationalty" id=""> @foreach ($categories['nationalty'] as $nationalty => $value) <option value="{{$nationalty}}">{{$value}}</option> @endforeach </select>1 نقطة
-
أريد أن أكون قادرًا على إرسال البيانات إلى تطبيق Flask الخاص بي. لقد حاولت الوصول إلى request.data لكن على ما يبدو أنها نص فارغ. import flask app = flask.Flask(__name__) @app.route('/', methods=['GET']) def parse_request(): data = flask.request.data # نص فارغ b'' print(data) return data app.run() عندما أقوم بطلب عنوان URL التالي: http://127.0.0.1:5000/?page=1 أحصل على نص فارغ، كيف يمكنني أن أصل إلى البيانات الموجودة في عنوان الصفحة؟1 نقطة
-
Activity: هو صنف يوفر كل المزايا المتاحة على إصدار أندرويد المستهدف في مشروعك AppCompatActivity: هو صنف يوفر المزايا المتاحة على إصدار أندرويد المستهدف في مشروعك وأيضا يهتم بتوفير تلك المزايا بطريقة ما على الإصدارات الأقدم (لغاية إصدار قديم معين لا يوفر توافقية قبله) AndroidX: مثل AppCompat يهتم بتوفير التوافقية مع الإصدارات الأقدم من أندويد، واختلافه فقط بتنظيم الأصناف داخله حيث يصبح أسهل على المطور اختيار نسخة من صنف معين داخله واستخدامها يفضل دائما تفضيل استخدام الأصناف التي توفر توافقية مع الاصدارات القديمة، هذا سيؤدي أن تطبيقك النهائي سيدعم شريحة أكبر من الأجهزة، حاول ترتيب أولوية الاختيار بينهم بالترتيب التالي: AndroidX (توافقية أكبر + تنظيم الأصناف داخله أفضل) AppCompat (توافقية أكبر) Android App1 نقطة
-
المشكلة هي في محاولة اندرويد تحسين الأداء وتوفير الطاقة بشكل عام، حيث قد تكون عدة تطبيقات على الهاتف قد عينت BroadcastReciever لنفس الحدث فعند كل تشغيل أو إغلاق للواي فاي سيتم استدعاء مثلا 30 BroadcastReciever معا مما يؤدي لضعف في أداء الهاتف. لذا اندرويد (بدءا من API المستوى 26 وفوق) لا يقوم باستدعاء ال BroadcastReciever الخاص بأي تطبيق إذا كان نائما (في حالة Sleep) فقط عندما يكون التطبيق يعمل سيستقبل الحدث1 نقطة
-
برجاء عمل export لقاعدة البيانات ومن ثم إرفاقها في تعليق حتى أتمكن من معاينتها1 نقطة
-
قمت بعمل ذلك اريد فقط عمل عداد للزوار الخاصين ببلد معين بدون تكرار زائر دخل الموقع اكثر من مرة اما الخطوات السابقة من تخزين الايبي واسم الدولة فهي تخزن بالفعل والكود بالاعلى يظهرالعدد الاجمالي واسماء الدول سوف اضع لك صورة من الموقع للتوضيح بها 23 زائر من دول مختلفة اريد تقسيم ال23 زائر لتظهر بجوار اسم الدولة فكيف يمكن توزيع هذا العدد على الدول1 نقطة
-
جميل جداً أن لديك هدف من تعلم البرمجة ، لكن عليك الوصول لهذه الأهداف وإنشاء جميع التطبيقات التي فكرت بها ، نصيحتي لك هو جدولة الوقت وإعطاء وقت للبرمجة واللغة الإنجليزية والنوم أيضاً والأعمال المهمة والتخلي عن الأعمال الغير ضرورية فهي التي تأخذ كل الوقت ، بعدها سوف تشعر بأن لديك الوقت الكافي للبرمجة واللغة الإنجليزية ، حاول معالجة مشكلة الوقت .1 نقطة
-
1 نقطة
-
إن مصطلح Theming system هو مصطلح عام، ويجب عليك تحديد ما الذي ترغب بتحقيقه في مشروعك. ولكن بشكل عام يمكن إنشاء قوالب أو themes مختلفة ضمن مشروع لارافل ضمن ثلاثة مستويات: على مستوى التنسيقات CSS، أو على مستوى هرمية الملفات Folder Structure أو ضمن مستوى قاعدة البيانات نفسها. بحيث يتم استبدال القطع أو التنسيقات اللازمة لكل ثيم، ويتم اعتماد إحدى هذه المستويات أو جميعها تبعاً لغايتك أثناء بناء المشروع وماهي الخصائص التي ترغب بإجراء التعددية لها. فعلى سبيل المثال أبسط المستويات هي من خلال CSS بحيث يتم اعتماد وحذف التنسيقات اللازمة، أما في حال أردت التخصيص أكثر أو تغيير المكونات بشكل كامل سيتم ذلك على مستويات إضافية مثل المتحكّمات وبنية الملفات، بحيث يتم تقسيم بنية الملفات في مشروعك لكل قالب على حدى وإظهار الشيفرات البرمجية حسب القالب المختار: بفرض لديك: darkTemplate و lightTemplate من الممكن إنشاء مجلدين منفصلين لكل قالب كالتالي: resources/views/layouts/darkTemplate/master.blade.php resources/views/layouts/lightTemplate/master.blade.php أو إنشاء مجلّد واحد والتبديل بين عناصر المقاطع sections ضمن الصفحات. أما من طرف المستخدم، فيجب تخزين القالب المختار بطريقة معيّنة في قاعدة البيانات لديك أو ضمن المتصفح لحفظ هذه الإعدادات للمستخدم وتكرارها في الزيارات المنفصلة. لا يوجد قاعدة معيّنة لذلك فيمكنك تضمين هذه الخصائص بما يتناسب مع مشروعك، وفي حال كنت تستخدم blade أو يتم التعامل مع إطار عمل لواجهة المستخدم. ولكن المبدأ نفسه في أي لغة برمجة أو إطار عمل تعمل عليه.1 نقطة
-
بالرغم من أن cout أبطأ قليلاً وأن iostream أبطأ من cstudio لكن cout تتعرف تلقائياً على نمط المتغير الذي نريد طباعته ولا حاجة لتحديد نمطه ضمن عبارة الطباعة، حيث أن تحديد النمط في cout يأخذ قليلاً من الوقت أثناء عمل البرنامج،ولكنه يحل مشكلة type safety أي لن يحدث خطأ بسبب اختلاف نمط المتغير الذي يكتبه المبرمج عن نمطه الحقيقي مما يمنع الأخطاء. وبإلغاء مزامنة iostream مع المكتبة القياسية تصبح cout سريعة جداً، كيفية تحديد نمط المتغير المراد طباعته في printf1 نقطة
-
بالإضافة لاستخدام باني اللسلسة، يمكننا المرور على المصفوفة المحرفية باستخدام حلقة حيث نتمكن من تحديد المحارف التي نريد إضافتها / تجاهلها مما يعطي تحكم أكبر في عملية التحويل const char* str = "Hsoub Academy"; int s_size = sizeof(str) / sizeof(char); // حجم المصفوفة أو عدد الحروف string s = ""; for (int i = 0; i < s_size; i++) { if (str[i] /* condition */) { // أي شرط s += str[i]; } } return s; // string1 نقطة
-
std::cout جزء من لغة ++C، بينما الدالة printf جزء من لغة C ولكن على الرغم من ذلك فيمكنك أن تستعملها في ++C بدون مشكلة. ولكلٍ منهما مميزات. طريقة الكتابة الدالة printf تستخدم طريقة إستدعاء الدوال العادية، لذلك قد يكون إستعمالها أسهل بكثير من إستعمال std::cout التي تستعمل syntax مختلف كليًا عن الدالة printf، حيث يتم إستعمال المعامل >> ، لذلك قد يكون إستعمال الدالة printf أقصر في الكتابة، لكن هذا الأمر لن يكون ملاحظًا حيث أنه ليس فرق كبير، لكن الفرق يظهر بشكل أكبر عندما تحاول أن تقوم بطباعة أكثر من قيمة في مرة واحدة، حيث أن الدالة printf تسمح لك بتنسيق النص قبل طباعته (إستخدام بعض القيم مثل d% و s% وتمرير متغيرات أو قيم أخرى للتحل مكانها)، اظر مثًلا الكود التالي: printf("Message %d: %s.\n", id, content[id]); std::cout << "Message " << id << ": " << content[id] << "." << std::endl; لاحظ كيف أن الدالة printf أصبحت أقصر بكثير في الكتابة وأن النص يكون أكثر وضوحًا عند إستعمالها. أيضًا سوف يصبح الأمر أكثر تعقيدًا من هذا بكثير عندما تحاول أن تقوم بطباعة متغيرات بقيم محتلفة مثل الأرقام بنظام hex أو octa : #include <iomanip> printf("0x%05x\n", 0x3e3); std::cout << "0x" << std::hex << std::setfill('0') << std::setw(5) << 0x3e3 << std::endl; طباعة الأرقام الصحيحة integers عندما تستعمل std::cout لطباعة أرقام بقيم وأنواع مختلفة فإنه يتم تحويل هذه الأرقام بشكل تلقائي، لكن على الجانب الآخر فيجب عليك أن تستعمل syntax معين للقيام بنفس المهمة بإستخدام printf، فعلى سبيل المثال لطباعة متغير من نوع size_t بإستخدام الدالة printf فعليك أن تستعمل النص zu%، كما أن طباعة النوع int64_t ستحتاج إلى إستعمال "PRId64"% ، بينما std::cout لا تحتاج إلى أي شيء لطباعة هذه الأنواع، حيث يتم تحويلها بشكل تلقائي دون تدخل من المبرمج. الأداء Performance std::cout تستعمل iostream ليتم طباعة البيانات إلى الطرفية، ومن المعروف أن iostream بطيء للغاية مقارنة بإستعمال الدالة printf، بالطبع فرق الأداء لن يكون ملوحظًا عند طباعة نصوص صغيرة أو عند حفظها إلى ملفات، لكن عندما تريد إخراج نصوص كبيرة للغاية وفي أقل وقت ممكن فعليك أن تستعمل الدالة printf1 نقطة
-
يمكنك أن تقوم بإستخدام النوع std::string مباشرة، حيث يحتوي على دالة بانية تقوم بتحويل القيمة المدخله إليها إلى النوع std::string بشكل مباشر، كالتالي: const char* s = "Hsoub"; std::string str(s); std::cout << str; تقوم هذه الدالة البانية بنسخ كل حرف من النص إلى المتغير الجديد str لاحظ أن المتغير s لا يجب أن يكون نوع nullptr وإلا سيتم تنفيذ سلوكم غير معروف undefined behavior كما يمكنك أن تحدد حجم المتغير str أيضًا من خلال تمرير رقم صحيح (عدد الحروف) كمعامل ثاني، على النحو التالي: const char* s = "Hello, World!"; std::string str(s, 5); std::cout << str; // Hello1 نقطة
-
عليك أن تستعمل المعامل scope resolution operator ( :: ) والذي يقوم بتحديد مجال الدالة التي تريد إستدعائها، فعندما تستعدي الدالة execute تقوم بتنفيذ الأمر كالتالي: int main() { // namespcae::function() user::execute(); return 0; } أي أن الجزء الموجود على اليمين هو اسم الدالة والجزء الموجود على يسار المعامل هو اسم المجال namespace، وفي حالة لم يتم تحديد اسم namespace سوف يتم البحث عن الدالة في المجال العام global scope، كالتالي: void print() { std::cout << "hello, world!"; } int main() { ::print(); return 0; } بالطبع إستخدام المعامل scope resolution في الكود السابق غير ضروري ولكن في الكود الخاص بك، عليك أن تستخدمه لتشير إلى الدالة الموجودة في النطاق العام global scope: std::string user_details() { return "global"; } namespace user { std::string user_details() { return "local"; } void execute() { std::cout << ::user_details(); // global } } عند تنفيذ الدالة execute في الكود السابق سوف يتم تنفيذ الدالة الموجودة في المجال العام وسيتم طباعة كلمة global1 نقطة
-
الصداع هو أمر ستواجهه أثناء العمل المكتبي وخصوصًا الذي يحتاج لجلوس لفترات طويلة، سببه الأساسي هو وضعية الجلوس الخاطئة وخاصة احناء الرأس إلى الأمام دون الشعور بذلك لفترات طويلة أنصحك بتعديل وضعية جلوسك وخاصة الانتباه لانحناء الرأس إلى الأمام وتعديلها دوما بحيث يكون مستوى الأذنين فوق الكتفين مباشرة طوال الوقت ما أمكن إلى أن تعتاد على وضعية الجلوس الصحيحة تلك. هناك تمارين خاصة بالعمل المكتبي يجب عليك الاعتياد على تنفيذها مع الوقت ستشعر بالراحة أثناء الجلوس لفترات طويلة. راجع دليل حسوب لوضعية الجلوس الصحيحة، و دليل الإعداد الصحيح لمكان العمل. راحتك الجسدية والنفسية ليست من الكماليات، بل هي أساس عملك المكتبي كمطور، حاول الاهتمام بها قدر الإمكان وسينعكس ذلك على انتاجيتك.1 نقطة
-
بالتأكيد قد تجد صعوبات في تنفيذ الأفكار أو حل المشاكل بشكل عام، وذلك لأنك تحاول أن تكتسب الخبرة مع الوقت ومع حل كل مشكلة، فعلى سبيل المثال: ربما لا تعرف كيفية توليد أرقام عشوائية في JavaScript ولكن لأنك رأيت هذا الأمر في الكود السابق أصبح لديك المعرفة أن الكائن Math يمكن أن يستعمل في توليد أرقام عشوائية، وعليك أن تحاول بتطبيق أفكار بسيطة تستخدم فيها الكائن Math لكي يصبح لديك أيضًا "خبرة" في هذا الكائن بشكل عام وليس مجرد معلومة بأنه يستخدم في توليد أرقام عشوائية. شخصيًا كنت أواجهة مشكلة في إستخدام لغة JavaScript في تعديل كائنات DOM (عناصر الصفحة)، وكلما أردت أن أقوم بتنفيذ فكرة ما لا أعرف من أين أبدأ ولكن مع الوقت ومع تنفيذ أفكار بسيطة واحدًا تلو الآخر أصبجت أكتسب خبرة -ولو بسيطة- من كل مشروع JavaScript أقوم به. وفي الكثير من الأحيان عندما أفشل في معرفة كيفية تنفيذ فكرة معينة أقوم بالبحث عن حلول من خلال سؤال آخرين أو البحث عن مكتبات تساعدني .. إلخ، ومع مرور الوقت أصبحت أستطيع تنفيذ أفكار أكثر تقدمًا وحل مشاكل أكثر صعوبة. لدي بعض النصائح التي قد يساعدك تطبيقها كثيرًا: حاول أن تتعمق في الأكواد التي تعرفها، فعلى سبيل المثال حاول أن تتعمق في كيفية إستخدام الكائن Math لأنك أستخدمته في مشروعك وكذلك الأمر بالنسبة querySelectorAll و التابع forEach و setAttribute وحاول البحث عن توابع أخرى مشابهة وستجد توابع مثل hasAttribute و getAttribute و removeAttribute .. إلخ، أي إن أستخدمت تابع أو كائن جديد فحاول الإطلاع على كل تفاصيله وكذلك الكائنات أو التوابع الأخرى له، وسوف يساعدك إستخدام موسوعة حسوب كثيرًا في هذا الأمر. أقرأ كثيرًا، تحتوي الأكاديمية على مئات المقالات في البرمجة بشكل عام وفي تقنيات الويب مثل JavaScript بشكل خاص، فستجد أكثر من 330 (وقت كتابة هذه الإجابة) خاصة بلغة JavaScript فقط وسوف تستفيد كثيرًا من قراءة المقالات. حاول تنفيذ مشاريع كثيرة، وأنت بالفعل تقوم بهذه الخطوة، لذلك أحسنت العمل أنت في الطريق الصحيح. بعدما تشعر أنك أصبحت متمكنًا من اللغة وتستطيع تطبيق أغلب الأفكار التي لديك بسهولة، حاول أن تقرأ الكود المصدري للمكتبات التي تستعملها مثل lightbox على سبيل المثال، لترى كيف يتم كتابة أكواد إحترافية وكيف يتم تنظيمهما.1 نقطة
-
بالتأكيد يمكنك أن تقوم بهذا الأمر بطريقة تلقائية من خلال JavaScript وهي كالتالي: // تحديد كل العناصر التي لها الصنف gallery const galleries = document.querySelectorAll('.gallery') galleries.forEach(gallery => { // توليد قيمة عشوائية للخاصية data-lightbox const randomText = 'gallery-' + Math.floor(Math.random() * 10000) // إضافة الخاثية data-lightbox بقيمة النص العشوائي السابق const links = gallery.querySelectorAll('a') links.forEach(link => { link.setAttribute('data-lightbox', randomText) }) }) بهذه الطريقة ليس عليك أن تقوم بتحديد قيمة مختلفة، وستقوم JavaScript بتوليد قيم عشوائية لكل مجموعة من الصور.1 نقطة
-
حاول تثبيت مكتبة CV2 و face_recognition من خلال الأمر التالي: pip install opencv-python face-recognition بعد ذلك أعد محاولة تشغيل المشروع مرة أخرى، وإن ظهرت لديك أخطأ أرجو أن تقوم بإرفاقها.1 نقطة
-
عندما يكون لديك أكثر من مجموعة من الصور يجب أن تقوم بتغير قيمة الخاصية data-lightbox، كالتالي: <div id="small-img-roll" class="gallery"> <a href="img/1.png" data-lightbox="gallery1"><img src="img/1.png" class="show-small-img" alt=""></a> <a href="img/2.png" data-lightbox="gallery1"><img src="img/2.png" class="show-small-img" alt=""></a> <a href="img/3.png" data-lightbox="gallery1"><img src="img/3.png" class="show-small-img" alt=""></a> </div> <div id="small-img-roll" class="gallery"> <a href="img/1.png" data-lightbox="gallery2"><img src="img/1.png" class="show-small-img" alt=""></a> <a href="img/2.png" data-lightbox="gallery2"><img src="img/2.png" class="show-small-img" alt=""></a> <a href="img/3.png" data-lightbox="gallery2"><img src="img/3.png" class="show-small-img" alt=""></a> </div> لاحظ أن قيمة الخاصية data-lightbox في المجموعة الأولى تختلف عن المجموعة الثانية، وبالتالي يُمكن لمكتبة LightBox أن تُفرق بين المجموعات.1 نقطة
-
الرامات أو الDRAM إختصاراً ل(Dynamic ram) عبارة عن مجموعة من الخﻻيا الكهربية كل خلية تحتوي على ترانزيستور ومكثف ويتم تخزين القيمة في الخلية عبر شحنها فإما أن يكون جهد المكثف عالي فتصبح القيمة 1 أو منفض فتصبح القيمة بصفر كما في الصورة المُرفقة بالأسفل , ولكن يوجد مشكلة وهي أن المكثف ﻻ يمكنه الإحتفاظ بالطاقة لفترات طويلة حيث يتم فقدان الطاقة في المكثف عبر الزمن مما يؤدي إلى فقدان البيانات من الذاكرة وبالتالي نحتاج لحل تلك المشكلة أن نعيد شحن المكثف كل فترة, عملية الشحن تلك عندما تتم ﻻ يمكن أن يتم معها أي عمليات قراءة او كتابة من الذاكرة مما يسبب تأخراً نسبيا في البيانات ويسبب بطئاً نسبياً على العكس فإن الSRAM (static ram) تصميمها معقد أكثر من السابقة وﻻ تحتاج إلى إعادة شحنها مرة أخرى مما يؤدي إلى فرق في الأداء بينها وبين الرام الديناميكي وهذا من أهم أسباب زيادة سرعة الSRAM مقارنةً بالDRAM لماذا ﻻ نصنع الmemory من الSRAM ببساطة بسبب التصميم المعقد للSRAM وعدد الترانزيستورات (حيث يتم صنع الخلية الواحدة من 6 ترانزيستورات) فهذا يجعل تكلفته عالية جداً حوالي 100 ~ 300 ضعف ثمن الديناميك رام الرامات الإستاتيكية تحتاج لمساحة أكبر نسبياً من الديناميكية ﻻ يمكننا زيادة حجم البيانات بسهولة لأن زيادة حجم البيانات الممكن إستيعابها في الرامات الإستاتيكية يقلل من كفائتها1 نقطة
-
الكاش Cache أو البيانات المؤقتة يتم تخزينها في الذاكرة الوصول العشوائية Random Access Memory (RAM)، وبالتالي لا يمكن المقارنة بينهما، ولكن أعتقد أنك تقصد المسجلات Registers وهي أسرع ذاكرة تخزين في الحاسوب، الحواسيب الحديثة قد تحتوي على ما يصل إلى 10MB من مساحة التخزين كمسجلات Registers وبالتالي نظريًا يمكننا أن نقوم بعمل حاسوب يعمل بالمسجلات فقط، ولكن عمليًا في الحياة الواقعية هذا الأمر غير ممكن، وسأحول أن أوضح هذا الامر بشيء من التفصيل. المسجلات Registers عبارة ذاكرة لتخزين ولنقل البيانات وبعض التعليمات التي تقوم بتنفيذها وحدة المعالجة CPU بشكل مباشرة، ويوجد من المسجلات عدة أنواع ولكل نوع وظيفة معينة، مثل Data register لنقل وتخزين البيانات، Address register تستخدم لتخزين عناوين الذاكرة، Instruction register لتخزين التعليمات التي تقوم وحدة المعالجة بتنفيذها، Input register يقوم تخزين محرف Character معين، ولكل نوع من الأنواع السابقة حجم معين متعارف عليه ويكون ما بين 8bit إلى 16bit فقط. المسجلات Registers سريعة للغاية لأنها متصله بشكل مباشر أو شبه مباشر بالأجزاء العملية بالحاسوب، أيضًا هي مكلفة للغاية مقارنة بأنواع الذاكرة الأخرى مثل الأقراص الصلبة HDD أو ذاكرة الوصول العشوائي RAM .. إلخ. على الجانب الآخر ذاكرة الوصول العشوائي RAM بطيئة مقارنة بالمسجلات ولكنها أرخص منها بكثير، وبالتالي بناء حاسوب بإستخدام المسجلات فقط سيؤدي بالفعل إلى حاسوب أسرع ولكن ستكون تكلفته أكبر بكثير من الحاسوب العادي، لدرجة أن فرق السرعة الذي سنحصل عليه لا يساوي تكلفة الحاسوب، وبالنسبة للشركات فإن تطوير وحدات أسرع (وحدة معالجة أسرع، أو ذاكرة أسرع .. إلخ) أرخص بكثير وسيؤدي إلى نفس النتيجة في النهاية. يوجد سبب آخر لكون الأمر مستحيل عمليًا، وهو التعليمات اللازمة للوصول إلى مسجل Register عمين، حيث أن عدد وحجم المسجلات القليل يجعل من الوصول إليها أمرًا سهلًا، مقارنة بذاكرة الوصول العشاوئية RAM والتي تحتوي على مليارات البتات Bits، فتخيل أنك تريد الذهاب إلى بيت معين من بين مجموعة بيوت موجودة أمامك مقارنة بالذهاب إلى بيت آخر لا تعرف سوى عنوانه في وسط مدينة ضخمةن بالتأكيد سوف تصل إلى البيت في كلتا الحالتين ولكن سوف تستغرق وقت أطول ومجهود أكبر بكثير في الحالة الثانية، وبالتالي إن كان لديك حاسوب يحتوي على أكثر من جيجابايت من المسجلات فيجب أن يكون لهذا الحاسوب طريقة ما للوصول إلى كل مسجل من المسجلات وسيكون الأمر أبطء بطبيعة الحال.1 نقطة
-
الكتاب ممتاز وجميل وقد أعجبني جدًا. الكتاب ليس ترجمة بالكامل بل معظمه تأليف ولهذا تلحظ أنّ أسلوب الكتابة وطريقة التعامل مع المصطلحات سلسان للغاية وكأنّك تقرأ كتاب عربي أصلي. يشرح الكتاب كذلك كلّ ما يحتاجه المرء لبدء استخدام قاعدة PostgreSQL بأسلوب مفصّل وعملي. أعجبني كذلك تصميم الكتاب حيث المحتوى غير محشو بكثرة في كلّ صفحة بل هو مُرتاح والحواشي مرخيّة، وهو ما يجعل عملية القراءة أكثر متعة. في المرّة المقبلة التي يطلب منها أحدٌ منّي مصادر لتعلّم PostgreSQL سأعطيه هذا الكتاب فقط. شكرًا جزيلًا على إخراج الكتاب.1 نقطة
-
بعد أن تعرّفنا على المفاهيم الأساسيّة لتطوير الويب كماهية تطبيق الويب، وإطار العمل، سنُكمل هذه السّلسلة من الدروس وسنتعرّف في هذا الدّرس على كيفيّة تهيئة بيئة التّطوير وتنصيب الأدوات اللازمة، وكذا بعض أساسيّات التّعامل مع إطار العمل Flask. تنصيب لغة بايثون لغة بايثون مُتواجدة بشكل افتراضي على على أنظمة لينكس و OS X، أما بالنّسبة لمستخدمي نظام Windows فيُمكنك تنزيل Python 2 من الموقع الرّسمي، فقط تأكّد من تنزيل آخر نسخة ذات الرّقم x.2.7. تنصيب إطار العمل Flask إنشاء بيئة وهميّة بأداة virtualenv البيئة الوهمية تُوفّر جميع المكتبات والاعتماديات والأدوات التي نقوم بتنصيبها والتي سنحتاج إليها في المشروع في مُجلّد واحد بمعزل عن اعتماديات نظام التّشغيل العامّة، وذلك لتجنّب تصادم بين الاعتماديات، يُمكنك القيام بالتّطوير بعد تشغيل البيئة الوهميّة ولن يكون لذلك تأثير على نظام التّشغيل، وسيبقى كل شيء بداخل مُجلّد واحد، ويُمكنك كذلك إيقاف تشغيل البيئة الوهميّة متى ما تشاء. يُمكن أن تكون أداة Virtualenv مُنصّبة مُسبقا في نظام التّشغيل لديك، يُمكنك التأكد بالأمر التّالي: $ virtualenv --version إذا حصلت على رقم نُسخة فهذا يعني بأنّ الأداة مُنصّبة من قبل. أما إذا لم يكن الأمر كذلك، فيُمكنك تنصيبها بالأمر التّالي في حالة كنت تستعمل توزيعة Ubuntu. $ sudo apt-get install python-virtualenv إذا لم تكن تستعمل نظام Ubuntu فيُمكنك أن تقوم بتنصيبها عبر أداة pip، فقط نفّذ الأمرين التاليين واحدا تلو الآخر: $ pip install -U pip $ pip install virtualenv الأمر الأول معني بتحديث أداة pip والثاني يقوم بتنصيب أداة virtualenv، قد تحتاج إلى إضافة sudo إلى بداية الأمرين إن لم تكن تملك صلاحيات مُدير النّظام (خاص بأنظمة Gnu/Linux و OSX). $ sudo pip install -U pip $ sudo pip install virtualenv تنصيب Flask سنستعمل أداة virtualenv لإنشاء بيئة وهميّة، أولا قم بإنشاء مُجلّد باسم flask_app أو باسم من اختيارك، بعد إنشاء المُجلّد يُمكنك الانتقال إلى مساره بسطر الأوامر وذلك بتنفيذ الأوامر التالية على الطّرفيّة Terminal، بالنّسبة لمُستخدمي Windows فيُمكن تنفيذ هذه الأوامر باستخدام طرفيّة PowerShell: $ mkdir ~/flask_app $ cd ~/flask_app بعدها يُمكنك يُمكنك إنشاء بيئة وهميّة باسم venv (اختصارا فقط) بالأمر التّالي: $ virtualenv venv انتظر لبضع لحظات إلى أن تُلاحظ ما يلي: Installing setuptools, pip, wheel...done. ستلاحظ بأنّ مُجلّدا جديدا باسم venv يحتوي على العديد من الملفّات قد ظهر، وهناك ستبقى الاعتماديات والمكتبات التي سنقوم بتنصيبها بأداة pip. بعد إنشاء البيئة الوهمية تبقى مهمّة تشغيلها، ويُمكن القيام بذلك بالأمر التّالي: $ . venv/bin/activate بعد تنفيذ الأمر أعلاه ستُلاحظ بأنّ سطر الأوامر قد تغيّر، وأضيفت كلمة (venv) إلى بداية السّطر، هذا يعني بأنّ كلّ شيء يعمل مثلما هو مُخطّط له. إذا أردت أن تقوم بإيقاف تشغيل البيئة الوهميّة فيُمكنك تنفيذ الأمر التّالي (لا تقم بذلك الآن): $ deactivate سنقوم الآن بتنصيب إطار العمل Flask، فقط نفّذ الأمر التّالي: $ pip install flask تنبيه نجاح العمليّة سيكون كالآتي: Successfully installed Jinja2-2.8 MarkupSafe-0.23 Werkzeug-0.11.5 flask-0.10.1 itsdangerous-0.24 تطبيقك الأول، مرحبا بالعالم بعد تشغيل البيئة الوهمية، أنشئ ملفا باسم app.py وافتحه بمُحرّرك المُفضّل، وضع به الأسطر التّالية: from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" if __name__ == "__main__": app.run() بعد حفظ الملفّ يكفي تشغيله بتنفيذ الأمر python app.py وستُلاحظ بأنّ الخادوم قد بدأ بالاستماع للطّلبات في المنفذ رقم 3000، ما يعني أنّك تستطيع الوصول إليه من المُتصفّح عبر العنوان http://127.0.0.1:5000 وهذا العنوان خاصّ بجهازك فقط ولا يُمكن لأحد غيرك أن يصل إليه ويُسمى عنوان المُضيف المحلي أو localhost ويُمكنك الوصول إليه من المُتصفّح من العنوان localhost:5000 كذلك. بعد الدّخول إلى العنوان عبر المُتصفّح ستُلاحظ جملة "!Hello World" على الصّفحة، لإيقاف الخادوم يُمكنك الضّغط على تركيبة المفاتيح Ctrl+c. الأسطر أعلاه هي كلّ ما تحتاج إليه لعرض نصّ على المُتصفّح، وإليك شرحا لكلّ جزء من البرنامج: هذا السّطر مسؤول عن استيراد Flask من حزمة flask (لاحظ الفرق بين حالة الحرف f). from flask import Flask نقوم بإنشاء كائن باسم app (يُمكنك تغيير الاسم على شرط أن تُغيّره في بقيّة الشيفرة)، الكائن هو الذي سيُمكننا من الوصول إلى الدوال التي يُوفرها Flask. app = Flask(__name__) السّطر التّالي هو نواة التّطبيق، وفيه تُصاغ الإجابة التي تُقدّم عند طلب الصّفحة من طرف المُتصفّح. @app.route("/") def hello(): return "Hello World!" السّطر الأول عبارة عن مُزخرف يُمكّن من ضبط المُوجّه (أي مسار الجواب) وهو ما يأتي في آخر عنوان التّطبيق http://127.0.0.1:5000 ويُمثّل / المُوجّه الرّئيسي. لتغيير المُوجّه يُمكن ببساطة تغيير قيمة المُعامل، فمثلا تعديله إلى السّطر التّالي سيُمكّننا من الوصول إلى صفحة !Hello World عبر العنوان http://127.0.0.1:5000/hello بدلا من العنوان http://127.0.0.1:5000: @app.route("/hello") بالنّسبة للدالة hello فهي مسؤولة عن تنفيذ الشيفرة التي بداخلها فور طلب الصّفحة وإرجاع قيمة نصيّة. ولإنشاء أكثر من صفحة يكفي تغيير المُوجّه Router، وتغيير اسم الدّالة. @app.route("/") def home(): page = 'Home Page' return page @app.route("/hello") def hello(): return "Hello World!" يُلاحظ أنّ اسم الدالة لا يجب تكراره بين المُوجّهات وإلا فلن يعمل التّطبيق. أما الشيفرة المُتواجدة في السّطرين الأخيرين فتقوم بتشغيل الخادوم ما يُمكّنك من الوصول إلى التّطبيق عن طريق المُتصفّح عبر العنوان http://127.0.0.1:5000. if __name__ == "__main__": app.run() الأمر ()app.run يقوم بتشغيل الخادوم ويُتيح الوصول إليه عبر جهازك فقط، أي أنّك لن تستطيع الوصول إلى التّطبيق إلا من الجهاز الذي قُمت بتشغيله منه، أما إذا كنت ترغب بأن يصل إليه من يتّصل بشبكتك المحليّة (شبكة الـ WiFi مثلا) فعليك إضافة مُعامل host بالقيمة 0.0.0.0 كالتالي: if __name__ == "__main__": app.run(host='0.0.0.0') ستتمكن الآن من الوصول إلى التّطبيق من أي جهاز مُتصل بالشّبكة المحليّة عبر عنوان IP جهازك متبوعا برقم المنفذ (مثلا http://192.168.1.5:5000). ويُمكنك الحصول على عنوان IP جهازك عبر تنفيذ الأمر ifconfig على أنظمة جنو/لينكس وأنظمة OS X والأمر ipconfig خاص بمُستخدمي نظام Windows (ستجد العنوان في السّطر الذي يحتوي على IPv4). للحصول على العنوان وحده في أنظمة جنو/لينكس يُمكن تنفيذ الأمر التّالي من الطّرفيّة: $ ifconfig | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}' لتغيير رقم المنفذ، يُمكن إضافة العامل port مع تعيين رقم منفذ أكبر من 1024 لأنّ كلّ المنافذ ذات الأرقام الصغيرة تتطلّب صلاحيات المُدير، في المثال التالي سنقوم باستعمال الرّقم 1200 كمنفذ للتّطبيق. if __name__ == "__main__": app.run(host='0.0.0.0', port=1200) اللغة العربية عرض اللغة العربية سيحتاج إلى إضافة السطر: # -*- coding:utf8 -*- إلى بداية الملفّ، كما يجب على السّلاسل أن تُسبق بحرف u. @app.route("/hello") def hello(): return u""" <h1 style="direction:rtl"> مرحبا بالعالم! </h1> """ لاحظ بأنّنا أحطنا شيفرات HTML بثلاثة علامات تنصيص لأنّها مُتعدّدة الأسطر. سيُصبح التّطبيق كما يلي: # -*- coding:utf8 -*- from flask import Flask app = Flask(__name__) @app.route("/") def home(): page = 'Home Page' return page @app.route("/hello") def hello(): return u""" <h1 style="direction:rtl"> السّلام عليكم ورحمة الله وبركاته </h1> """ if __name__ == "__main__": app.run() إذا قُمت الآن بزيارة العنوان http://127.0.0.1:5000/hello فستجد صفحة تحتوي على جملة "السّلام عليكم ورحمة الله وبركاته" بخط كبير (بسبب الوسم h1). أما إذا قمت بالدّخول إلى العُنوان http://127.0.0.1:5000 فستجد عبارة Home Page. مع ملاحظة بأن استعمال هذه الطّريقة لتقديم صفحات HTML غير مُجد وغير مرن وقد يجعل التّطوير صعبا في حالة كان التّطبيق مُتعدّد الصفحات، ومن الأفضل فصل ملفّات HTML مع ملفّات لغة Python وذلك لمزيد من التّنسيق وسهولة صيانة التّطبيق، ويُمكن فصلهما بمُحرّك القوالب Jinja2 الذي سنتعرّف عليه في الدّرس القادم. تمرير المتغيرات في عنوان Url الحصول على قيمة من العنوان يُمكن الحصول على قيم مُباشرة من العنوان، ويُمكننا توظيفها في الشيفرة، فمثلا يُمكننا الذهاب إلى العنوان http://127.0.0.1:5000/say_hello/Abdelhadi وسنستطيع الوصول إلى القيمة Abdelhadi كمُعامل بحيث يُمكننا إرجاعها مع جملة ترحيب أو تنفيذ أي عمليّة أخرى. ولنقوم بالأمر سنُضيف أوّلا مُوجّها جديدا باسم say_hello ولكن مع وضع المُعامل داخل علامتي <> وسنُمرّر اسم المُعامل إلى الدّالة كذلك، انظر ما يلي: @app.route("/say_hello/<name>") def say_hello(name): return u"Hello {}".format(name) إذا قُمت الآن بالذهاب إلى العنوان http://127.0.0.1:5000/say_hello/Abdelhadi فستجد عبارة Hello Abdelhadi (جرّب تغيير Abdelhadi إلى اسمك، سواء باللغة العربيّة أو باللغة الانجليزية). بعد هذا الجزء سيُصبح التّطبيق الكامل كالآتي: # -*- coding:utf8 -*- from flask import Flask app = Flask(__name__) @app.route("/") def home(): page = 'Home Page' return page @app.route("/hello") def hello(): return u""" <h1 style="direction:rtl"> السّلام عليكم ورحمة الله وبركاته </h1> """ @app.route("/say_hello/<name>") def say_hello(name): return u"Hello {}".format(name) if __name__ == "__main__": app.run() الحصول على أكثر من قيمة من العنوان الطّريقة السابقة جيّدة في حالة أدرت الحصول على قيمة مُعامل واحد، لكن ماذا لو أردت الحصول على أكثر من مُعامل؟ يُمكننا تحقيق مُرادنا عبر طلبات الـ HTTP من نوع GET، بحيث نُرسل المُعامل وقيمته في العنوان كالتّالي: http://127.0.0.1:5000/first_last?first_name=Abdelhadi&last_name=Dyouri بحيث تُمرّر المفاتيح والقيم التّاليّة: first_name=Abdelhadi last_name=Dyouri لاحظ بأنّنا نفصل بين المُعامل والآخر برمز &. وبالطّبع يُمكنك تمرير مُعامل واحد فقط. http://127.0.0.1:5000/first_last?first_name=Abdelhadi للوصول إلى قيم هذه المُعاملات، سنستخدم الوحدة request التي يُوفّرها إطار Flask وسنستوردها جنبا إلى جنب مع Flask في السّطر الثاني من البرنامج كالتّالي: from flask import Flask, request بعد ذلك سنتمكّن من الوصول إلى قيمة مُعامل كالتّالي: request.args.get('parameter') تطبيق سنُطبّق هذا بإنشاء تطبيق لعرض الاسم الأول للشّخص بأحرف صغيرة مع تكبير الحرف الأول، والاسم الثاني سيكون بأحرف كبيرة، وسنستعمل الدوال upper و capitalize. أولا سننشئ مُوجّها جديدا باسم first_last بعدها سنقوم بالحصول على قيمتي المُعاملين first_name و last_name، ثمّ سنحولّ الاسم الأول باستخدام التّابع capitalize وسنُحوّل الاسم العائلي إلى أحرف كبيرة بالتّابع upper، سنعرضه النتيجة بعد ذلك في وسمي h3 كلّ في سطر. @app.route("/first_last") def first_last(): first_name = request.args.get('first_name').capitalize() last_name = request.args.get('last_name').upper() return "<h3>First Name: {} <br>Last Name: {}</h3>".format(first_name, last_name) يُمكنك تصفّح شيفرة هذا الدّرس وتنزيلها من موقع Github عبر هذا الرّابط تشغيل مصحح الأخطاء Debugger يأتي Flask بمُصحّح أخطاء يعرض مصدر الخطأ مُباشرة على المُتصفّح، ويُنصح باستعماله ليسهل عليك تحديد مصدر الخطأ لإصلاحه. يُمكن تشغيل مُصحّح الأخطاء عبر إضافة مُعامل debug بقيمة True إلى التّابع run. if __name__ == "__main__": app.run(debug=True) وهذه صورة لمُصحّح الخطأ بعد وقوع خطأ في تطبيق Flask. وقع الخطأ لأنّ القيمة الافتراضيّة لمُعامل مُعيّن عند عدم تحديد قيمة له هي None ما يعني بأنّك لا تستطيع تنفيذ التّابع upper الخاص بالسّلاسل النّصية. يُمكنك مُشاهدة هذا الخطأ بالذهاب إلى العنوان http://127.0.0.1:5000/first_last?first_name=abdelhadi لاحظ الجملة الأولى 'AttributeError: 'NoneType' object has no attribute 'upper هذا الخطأ وقع بعد تنفيذ التّابع upper على القيمة None وهذا لأنّنا لم نُوفّر قيمة للمُعامل last_name. خاتمة تعرّفنا إلى الآن على أساسيات التّعامل مع المُوجّهات، وكيفيّة تقديم صفحات HTML للمُتصفّح أو الزّائر، وسنتعرّف في الدّرس القادم بإذن الله على كيفيّة استعمال مُحرّك القوالب Jinja2 لتقديم ملفّات HTML مُستقلّة وكيفيّة استعمال بعض الأساليب البرمجيّة فيه.1 نقطة
-
مخطط الفئات (classes) هو جزءٌ مهمٌ جدًا من لغة النمذجة الموحدة UML، وهو مخطط هيكلي مهمته عرض الفئات بنظامٍ معيّن مع جميع العلاقات التي تربط بينها، وهو -برأيي- أشهر نوع من المخططات في هندسة البرمجيات. يساعدك رسم مخطط الفئات على رؤية المشكلة بأفقٍ أوسع؛ وعندما تكتبها، فستفرِّغ مساحةً في رأسك للأفكار الجديدة. وتُسهِّل أيضًا فهم هيكلية الفئات من الآخرين عندما تناقش المشكلة معهم. الفكرة هي أنني أنسى عادةً بنية المخططات عندما أحاول قراءة أحد المخططات التي رسمها غيري، فلهذا قررت كتابة هذه المقالة لعلها تذكرني بها في المستقبل. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن الفئة – Class المكون الأساسي لهذه المخططات هو مخطط الفئة، التي تَظهَر على شكل عقدة (node) وعادةً كصناديق (boxes)، يمكن أن يُعرَّف لكل صنف دوال (methods) وخاصيات (attributes)، كما هو موضَّح بالشكل أدناه: الوراثة – Inheritance وراثة الفئات -في ما يتعلق بمخططات UML- هي علاقة تعميم (generalization) التي تمثل علاقة "هو" (is a) على مستوى الفئة، المخطط الآتي يُظهِر كيفية رسم التعميم. التطبيق – Realization هنالك علاقة مختلفة في UML للواجهات (interfaces)، فالوراثة من واجهة تسمى "implementation" التي هي علاقة "تطبيق" (realization) في مخططات UML. تمثيلها الشكلي مشابه للوراثة، إلا أنَّ الخط مقطّع (dashed)، ويجب تحديد أنَّ الواجهة هي «مجرَّدة» (abstract) – أي أنَّ اسمها مكتوبٌ بخطٍ مائل؛ كما هو مبيّن في هذا الرسم. الارتباط – Association شكل آخر من أشكال العلاقات في مخططات الفئات هو الارتباط (association)، وهو علاقة على مستوى الكائنات (object-level) أي أنه يحدث بين كائناتٍ لأصنافٍ مرتبطةٍ؛ لذا تُمثَّل كل العلاقة كعائلة من الوصلات (links). هنالك عدة أنواع من الارتباط مُحدَّدة أكثر (التجميع aggregation و التألف composition). التجميع – Aggregation التجميع هو شكل أكثر تحديدًا وتخصيصًا من الارتباط. وهو علاقة "لديه" (has a)؛ التمثيل الرسومي لهذه العلاقة هو الآتي: التألف – Composition شكل أكثر تخصيصًا من التجميع هو التألف (composition) فبدلًا من علاقة "لديه" (has a) تكون العلاقة هي "يملك" (owns a). وهذا ملائمٌ للعلاقات التي لا يمكن أن يتواجد فيها كائن إلا كجزءٍ من كائنٍ آخر. على سبيل المثال، إن كنت هنالك طائرة تملك جناحًا فهذا تألف، فماذا ستفعل بالجناح لوحده؟ لكن إن كانت هنالك بركة فيها بعض البط فهذا تجميع، لأنه يملك للبط أن يعيش دون بركة (وإن لم يكن سعيدًا بذلك)، والبركة ستبقى بركة حتى لو لم يكن فيها بط؛ التمثيل الرسومي لعملية التألف هو مثل التجميع، لكن المُعيَّن مملوء وليس مُفرَّغ. الاعتمادية – Dependency آخر نوع من العلاقات هو "الاعتمادية" (dependency) وهو أضعف من الارتباط (association) ويقول: إن كانت الفئة تستعمل فئةً أخرى، فهي تعمد عليها. يكون من المناسب استعمالها في حالات تكون نسخةٌ من الفئةِ مخزنةً في متغيرٍ محلي في دالة فئة أخرى، أو إذا استعمِلَت دالةٌ ثابتةٌ (static method)؛ لذا لن تكون الفئات مرتبطةً، لكن واحدة تعتمد على الأخرى. خلاصة صممت كل الأمثلة السابقة باستخدام محرر مفتوح المصدر باسم Dia، وأنا أنصح باستخدامه. ولأنه محرر رائع، فهذه صورة شاملة لجميع أنواع العلاقات إن أحببت طباعتها. ترجمة -وبتصرّف- للمقال UML Class Diagram لصاحبه Radek Pazdera.1 نقطة