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

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

  1. عبدالباسط ابراهيم

    • نقاط

      6

    • المساهمات

      4894


  2. Mustafa Suleiman

    Mustafa Suleiman

    الأعضاء


    • نقاط

      5

    • المساهمات

      13209


  3. مازن الضيفي

    مازن الضيفي

    الأعضاء


    • نقاط

      2

    • المساهمات

      23


  4. أبو مهيب

    أبو مهيب

    الأعضاء


    • نقاط

      2

    • المساهمات

      22


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

المحتوى الأعلى تقييمًا في 07/11/23 في كل الموقع

  1. السلام عليكم ورحمة الله وبركاته لدي كود جافا سكربت يقوم بفتح الميكرفون والتسجيل الصوتي ولكن يقوم بعمل رابط لتحميل الصوت المسجل. أنا اريد تعديل ذلك الكود ليقوم برفع وارسال الصوت الى السيرفر لاقوم بعد ذلك بتخزينه في قاعدة البيانات والتحكم فيه الكود <html> <body> <button onclick="samah();">تسجيل صوتي</button> <button onclick="stops();">stop</button> <a id="a"></a> <script> var audioChunks = []; // بيانات الصوت var mediaRecorder = null; var audioBlob = null; var audioUrl = null; var mainStream = null; function samah() { navigator.mediaDevices.getUserMedia({audio: true}) .then(stream => { mainStream = stream; mediaRecorder = new MediaRecorder(stream); mediaRecorder.start(); // بدء التسجيل mediaRecorder.addEventListener("dataavailable", event => { audioChunks.push(event.data); }); }); } function stops() { mediaRecorder.addEventListener("stop", () => { audioBlob = new Blob(audioChunks, {type: mediaRecorder.mimeType}); audioUrl = URL.createObjectURL(audioBlob); mainStream.getTracks() // get all tracks from the MediaStream .forEach(track => track.stop()); // stop each of them // تحميل ملف الصوت let a = document.getElementById("a"); a.href = audioUrl; a.download = "recording.webm"; a.innerText = 'click me to save file'; //document.body.appendChild(a); //a.click(); }); mediaRecorder.stop(); } </script> </body> </html>
    2 نقاط
  2. مرحبا من فضلكم ممكن شرح مفصل للأمر this وما هو عملها وما هي فائدتها في لغة جافا سكريبت
    2 نقاط
  3. السلام عليكم هل شرط أساسي عند كتابة display flex أن يتبعها خاصية justify-content وماهي الصلة بينهم ؟
    2 نقاط
  4. السلام عليكم اواجه مشكلة في اعدادات visual studio code لدي , حاولت تفعيل auto formatting لكنها لا تعمل مع اني قمت بتحميل الاضافة Prettier وجربت العديد من الطرق
    2 نقاط
  5. عندي مشكلة في برنامج visual studio code يستطيع المستخدم إعادة مرات الادخال مرات لا نهائية
    1 نقطة
  6. ماهي آلية عمل التصنيفات التي تكون علاقتها Many To Many مثلاً لدي بوستات والبوستات تنتمي الى تصنيف الرياضة وتصنيف الصحة كيف تعمل هذي في الفرونت والباك اند ؟
    1 نقطة
  7. السلام عليكم ورحمة الله وبركاته لدي مشروع فلاتر واحتاج استخراج تطبيق يعمل على ANDROID ماهي الادوات التي علي استخدامها لاستخراج هذا التطبيق وكذلك في مرحلة اخرى احتاج اصدر نسخة من نفس المشروع للعمل على بيئة IOS شكرا لاتاحة الفرصة
    1 نقطة
  8. بعد الانتهاء من بناء التطبيق باستخدام Flutter وتهيئته، يمكنك تجربته على المحاكي الخاص ب Android و iOS أو على جهاز Android و iOS الفعلي. لتجربة التطبيق على المحاكي الخاص ب Android، يجب إطلاق المحاكي الخاص ب Android وتشغيل التطبيق عليه. يمكنك تحديد محاكي الجهاز الذي تريد استخدامه، مثل Pixel أو Nexus أو غيرها. لتجربة التطبيق على المحاكي الخاص ب iOS، يجب إطلاق المحاكي الخاص ب iOS وتشغيل التطبيق عليه. يمكنك تحديد محاكي الجهاز الذي تريد استخدامه، مثل iPhone أو iPad أو غيرها. يمكن أيضًا تجربة التطبيق على جهاز Android و iOS الفعلي، وذلك بتوصيل الجهاز بالكمبيوتر وتشغيل التطبيق عليه. إنشاء Build بعد التأكد من عمل التطبيق بشكل جيد وتجربته، يمكنك إنشاء Build للتطبيق على Android و iOS باستخدام Android Studio و Xcode. لإنشاء Build للتطبيق على Android، يجب تحديد Build Variant المناسب والضغط على زر "Generate Signed Bundle/APK". يتم إنشاء ملف APK الذي يمكن تثبيته على أي جهاز Android. لإنشاء Build للتطبيق على iOS، يجب تحديد Target المناسب والضغط على زر "Archive". يتم إنشاء ملف IPA الذي يمكن تثبيته على جهاز iOS باستخدام Xcode أو إرساله إلى متجر التطبيقات للنشر.
    1 نقطة
  9. وعليكم السلام لا، ليس شرطاً أساسياً أن يتبع استخدام خاصية display: flex بخاصية justify-content. الخاصية display: flex تُستخدم لتعريف عنصر واحد كعنصرٍ مرن (flex container) ولجعل العناصر الفرعية (flex items). تُستخدم خاصية justify-content لتحديد توزيع العناصر الفرعية في الاتجاه الأفقي (المحور الرئيسي) داخل العنصر الأب الذي له الخاصية flex . هذه الخاصية تحدد كيفية توزيع الفراغ الأفقي بين العناصر وموضعها داخل العنصر الأب. بمعنى آخر، الخاصية justify-content تحدد كيف يتم توزيع العناصر أفقيًا داخل العنصر المرن، بينما display: flex تعرف العنصر كعنصر مرن. يمكنك استخدام display: flex بدون justify-content إذا كنت ترغب في ترتيب العناصر الفرعية بطريقة أخرى دون تحديد توزيع أفقي محدد. بالطبع، يمكنك استخدام خاصية justify-content إذا كنت ترغب في تحديد توزيع العناصر الفرعية بشكل محدد. وهناك قيم مختلفة يمكنك استخدامها مع justify-content مثل flex-start (التوزيع من البداية)، center (التوسيط)، flex-end (التوزيع من النهاية)، space-between (توزيع متساوٍ بين العناصر) وغيرها. للإطلاع أكثر حول الخاصية display و justify-content
    1 نقطة
  10. لا ليس شرطاً، فالـ `display: flex` يستخدم لتحديد عنصر كحاوية مرنة وتمكين تخطيط Flexbox لمحتوياتها. بينما `justify-content` يستخدم لمحاذاة العناصر المرنة على المحور الرئيسي (أفقيًا) عندما لا تستخدم العناصر كل المساحة المتاحة . وهذه كل الاحتمالات التي تقبلها justify-content : وهذا مثال على استخدامهما : <!DOCTYPE html> <html> <head> <style> .container { display: flex; justify-content: center; } .item { width: 50px; height: 50px; } </style> </head> <body> <div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> </body> </html>
    1 نقطة
  11. ببساطة وبدون تعقيد في JavaScript، يستخدم مصطلح "دالة callback" للإشارة إلى دالة يتم تمريرها كوسيط إلى دالة أخرى، وعندما تكون الدالة الأصلية قادرة على الانتهاء من تنفيذ مهمتها الرئيسية، تستدعى الدالة callback لتنفيذ بعض الإجراءات الإضافية. والأمر يتم من خلال المترجم (Compiler) أو محرك JavaScript وهو لا يتعرف بشكل مباشر على الدالة الممررة كـ callback function، لكنه يعتمد تحديد الدالة كـ callback function على كيفية استخدامها في سياق معين في الكود. ويوجد مفهوم الـ callback queue (طابور الاستدعاءات) والذي يتعلق بنظام المحدثات (event loop) في محرك JavaScript، وهو جزء من عمل المحرك نفسه. وعند تمرير دالة callback إلى دالة معينة، مثلما هو الحال في مثالك app.listen، يتم تسجيل تلك الدالة في callback queue، والcallback queue هو عبارة عن هيكل بيانات يحتوي على مجموعة من الدوال الممررة كـ callbacks، وتكون تلك الدوال جاهزة للاستدعاء عند حدوث حدث معين. وسأوضح الأمر على المثال الذي طرحته: تُستخدم دالة callback في دالة app.listen، وتعمل على استماع التطبيق على منفذ محدد (port) للطلبات الواردة من المتصفح، وتحتوي على معاملين، الأول هو رقم المنفذ (port) الذي ترغب في استخدامه، والثاني هو الدالة callback التي ستتم استدعاؤها عندما يكون التطبيق جاهزًا للاستماع وتلقي الطلبات. وتمرر دالة callback بواسطة السهم البسيط () => {} بعد معامل المنفذ (port)، ويتم تنفيذ تلك الدالة callback عندما يبدأ التطبيق في الاستماع على المنفذ المحدد، أي يتم رسالة في وحدة التحكم تقول "Example app listening on port" تليها قيمة المنفذ الذي تم تمريره. بمعنى آخر، عند تشغيل التطبيق ويب، سيبدأ في الاستماع على المنفذ المحدد، وعندما يكون جاهزًا، ستستدعى الدالة callback المحددة وطباعة رسالة توضح أن التطبيق جاهز للاستخدام على المنفذ المحدد.
    1 نقطة
  12. ستحتاج إلى تعديل الكود كالتالي: <html> <body> <button onclick="samah();">تسجيل صوتي</button> <button onclick="stops();">stop</button> <a id="a"></a> <script> let audioChunks = []; let mediaRecorder = null; let audioBlob = null; let mainStream = null; function samah() { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { mainStream = stream; mediaRecorder = new MediaRecorder(stream); mediaRecorder.start(); mediaRecorder.addEventListener("dataavailable", event => { audioChunks.push(event.data); }); }); } async function stops() { mediaRecorder.addEventListener("stop", async () => { audioBlob = new Blob(audioChunks, { type: mediaRecorder.mimeType }); mainStream.getTracks().forEach(track => track.stop()); // إنشاء كائن FormData لإرسال البيانات إلى السيرفر const formData = new FormData(); formData.append("audio", audioBlob, "recording.webm"); try { // إرسال البيانات إلى السيرفر باستخدام Fetch API و async/await const response = await fetch("URL_TO_SERVER_ENDPOINT", { method: "POST", body: formData }); const data = await response.json(); console.log("تم رفع التسجيل الصوتي بنجاح!", data); // هنا يمكنك التحكم في البيانات المرتدة من السيرفر } catch (error) { console.error("حدث خطأ أثناء رفع التسجيل الصوتي:", error); } }); mediaRecorder.addEventListener("stop", stops); mediaRecorder.stop(); } </script> </body> </html> وآلية عمل الكود هي: عند النقر على زر "تسجيل صوتي"، تستدعى الدالة samah(). تتم مطالبة المستخدم بالإذن للوصول إلى الميكروفون باستخدام navigator.mediaDevices.getUserMedia(). بمجرد الحصول على الإذن، يتم تشغيل التسجيل باستخدام MediaRecorder، وتبدأ المكونات الصوتية في الاحتفاظ بالبيانات المسجلة في المصفوفة audioChunks. عند النقر على زر "stop"، يتم استدعاء الدالة stops(). استدعاء حدث "stop" على mediaRecorder باستخدام mediaRecorder.addEventListener("stop", stops) للتأكد من استدعاء الدالة عند إيقاف التسجيل. إنشاء كائن Blob من المكونات الصوتية المسجلة. يتم إيقاف جميع المسارات في mainStream باستخدام mainStream.getTracks().forEach(track => track.stop()). إنشاء كائن FormData لتكوين بيانات الصوت المراد إرسالها إلى السيرفر. استخدام fetch لإرسال بيانات الصوت إلى السيرفر بطريقة غير متزامنة باستخدام طريقة POST. التعامل مع الاستجابة من السيرفر باستخدام response.json() ومن ثم استخدام البيانات المرتجعة كما تحتاج.
    1 نقطة
  13. بما أنك تقوم بتجاوز عنصر audioBlob، فما عليك إلا ارسال الـ Blob الخاص بملف الأوديو وسيتم التعامل معه بشكل اعتيادي جدا، لنقم مثلا بإنشاء وظيفة جديدة هي وظيفة uploadAudio بحيث تقوم بـ: إنشاء formData نقوم بإضافة عنصر الأوديو إليه. ارسال ملف الصورة إلى الخادم. function uploadAudio() { // إرسال الصوت إلى الخادم هنا var formData = new FormData(); formData.append("audio", audioBlob, "recording.webm"); fetch("URL_TO_SERVER_ENDPOINT", { method: "POST", body: formData }) .then(response => response.json()) .then(data => { console.log("تم رفع الصوت بنجاح!", data); // استجابة من الخادم تحتوي على معلومات الصوت المرفوع ومعالجتها وتخزينها في قاعدة البيانات هنا }) .catch(error => { console.error("حدث خطأ أثناء رفع الصوت", error); }); } بعد هذا سيمكنك التعامل مع الملف من خلال الباك اند بشكل عادي جدا.
    1 نقطة
  14. لا اعلم ما سبب عدم القدرة على تفعيل الروابط في الصفحه الرئيسية عند الضغط على التسجيل كموظف يتم الانتقال الى صفحه الموظف وعند الضغط على التسجيل كشركه يتم الانتقال ايضا الى صفحة الموظف وانا اريد الانتقال الى صفحة الشركه ما السبب في عدم القدرة على ذلك وهل طريقة الربط بين الصفحات صحيحه ؟؟ Desktop.rar
    1 نقطة
  15. السلام عليكم ورحمة الله و بركاته, ما الفرق بين Next.js و Nuxt.js و ما الفائدة منهم ؟ وشكرا لكم
    1 نقطة
  16. ما الفرق بين Next.js و Nuxt.js و ما الفائدة منهم ؟ Next.js و Nuxt.js هما إطاري عمل حديثين للجافاسكربت يمكن استخدامهما لبناء تطبيقات الويب الحديثة، ولكن، هناك بعض الاختلافات الرئيسية بين الإطارين. Next.js هو إطار عمل مبني على React ويعتمد على Node.js، يوفر مجموعة من الميزات التي يمكن أن تساعد في تحسين أداء وتحسين محركات البحث لتطبيق الويب الخاص بك، مثل تقديم الخادم (SSR) وتوليد المواقع الثابتة (SSG)، وهو أيضًا خيار شائع لبناء تطبيقات full-stack، حيث يمكن استخدامه لإنشاء الكود الأمامي والخلفي للتطبيق. أما Nuxt.js هو إطار عمل يعتمد على Vue ويعتمد أيضًا على Node.js، ويوفر مجموعة من الميزات المشابهة لـ Next.js، مثل SSR وSSG، ويحتوي Nuxt.js أيضًا على عدد من الميزات الإضافية، مثل نظام التوجيه المدمج ونظام الوحدات، مما يجعل Nuxt.js خيارًا جيدًا لبناء تطبيقات الويب المعقدة والقابلة للتوسع. فوائد Next.js: يستخدم Next.js SSR لتوليد HTML لصفحاتك على الخادم قبل إرسالها إلى العميل، وبالتالي يحسن ذلك الأداء لتطبيق الويب، خاصةً للصفحات التي لا تُحدَّث بشكل متكرر. يولِّد Next.js أيضًا صفحات ثابتة لتطبيق الويب، مما يُحسِّن من ترتيب الموقع في جولج، حيث يمكن لمحركات البحث فهرستة صفحاتك وزيارتها بسهولة أكبر. تستطيع استخدام Next.js لتوليد الكود الأمامي والخلفي لتطبيق الويب الخاص بك. فوائد Nuxt.js: خيار جيد لبناء تطبيقات الويب المعقدة والقابلة للتوسع، ونظام التوجيه المدمج ونظام الوحدات يجعل من السهل تنظيم الكود الخاص بك والحفاظ على قابلية صيانة تطبيق الويب. قابل للتخصيص بشكل كبير، وباستطاعتك استخدام الوحدات المدمجة لإضافة ميزات إلى تطبيق الويب، أو يمكنك كتابة وحدات خاصة بك.
    1 نقطة
  17. Next.js و Nuxt.js هما إطارات عمل (Frameworks) لتطوير تطبيقات ويب يستندان إلى React.js و Vue.js على التوالي. والفائدة الرئيسية منهم هي تسريع عملية تطوير تطبيقات الويب، وتحسين أداء التطبيقات، وتسهيل إدارتها. الفرق الرئيسي بين Next.js و Nuxt.js هو أن Next.js يستخدم React.js ، في حين أن Nuxt.js يستخدم Vue.js وبشكل عام، فإن Next.js و Nuxt.js يوفران العديد من الميزات والفوائد التالية: يسمحون بتطوير تطبيقات الويب بشكل أسرع وأكثر كفاءة وبأداء أفضل. يوفرون دعمًا متقدمًا للجانب الخادم والجانب العميل. يسمحون بإنشاء تجربة المستخدم الأفضل والأكثر تفاعلية. يوفرون ميزات مثل تحميل ديناميكي للصفحات، والتحكم في التوجيه، والتحكم في الحالة العالمية (Global State)، وإدارة البيانات وغيرها من الميزات الأخرى. وبالإضافة إلى ذلك، فإن Next.js و Nuxt.js يوفران مجتمعات تطوير نشطة ودعمًا كبيرًا من المطورين، مما يجعلهما خيارًا شائعًا لتطوير تطبيقات الويب المتطورة. وللمزيد من التفاصيل يفضل قراءة الإجابات التالية بدلاً من التكرار
    1 نقطة
  18. كل منهما إطار عمل جاء لخدمة أفكار من مثل التصيير على الخادم server side rendering وتوليد المواقع الثابتة statis site generation، عدا أن الأول (NextJS) قائم على ReactJS في حين أن الثاني (NuxtJS) والمستوحى أصلا من الأول قائم على VueJS. عند استعمال React أو Vue مباشرة قد يكون هنالك الكثير من الأشياء المكررة والعمليات الروتينية التي يتوفر عليها اطارا العمل بشكل مدمج مسبقا built-in. هذا بجانب أن مكتبة React و Vue كانتا تفتقران لمفهوم الـ SSR قبل ذلك، فالمكونات والصفحات التي يقومان بتوليدها كانت تتم على جزء العميل، ولذلك فإن فهرسة محركات البحث لم تعد تشملها. فمحركات البحث تطلب الصفحات والمعلومات الوصفية وما الى ذلك من الخادم وليس من العميل. ولذلك فإنه هاته الفكرة بالأساس دعت الى انشاء اطر عمل مثل NextJS و NuxtJS، اللذان يتجاوزان هاته الفكرة ويقومان -اختيارا طبعا- بتوليد هاته الصفحات والمكونات على جزء الخادم على خادم Node-based لتتم أرشفتها وفهرستها على محركات البحث.
    1 نقطة
  19. edabit موقع رائع لتمارين البرمجة، يحتوي على العديد من التمارين الجيدة للمبتدئين والمتقدمين على جميع مستويات البرمجة. أوصي به بشدة للمساعدة في تعلم جافاسكريبت وتحسين المهارات البرمجية. وبشكل أكثر تحديدًا: لكل تمرين، يوفر توضيح واضح للشرح والحلول الممكنة لمساعدتك في تعلم المهارة. هناك العديد من المستويات لكل تمرين، مما يساعد على تتبع تقدمك كمتدرب. يوفر إحصائيات وردود فعل الآخرين على حلولك لتحسينها بناءً على هذه التعليقات. يمكن الوصول إلى التمارين بسهولة من خلال فلتر المهارة أو اللغة. فيما يخص ال Loops ، يحتوي edabit على أكثر من 100 تمرينًا على الـ While Loops والـ For loops في جافاسكريبت ، وكلها مصنفة بناءً على المستوى من البسيط إلى المتقدم. يمكنك الذهاب للموقع من هذا الرابط وستجد جميع التمارين الخاصة بال loops بواسطة javascript
    1 نقطة
  20. صحيح، فعند كتابة الكود في ملف ثم الضغط على علامة تشغيل الكود كما بالصورة يتم السؤال عن إدخال رقم مرة واحدة وينتهي الكود، أرجو منك إغلاق محرر الأكواد vscode تمامًا ثم التجربة مرة أخرى:
    1 نقطة
  21. مثل هذا الكود int(input("enter the num: ")) من المفترض انو مرا واحدة فقط يكتب المستخدم صح ؟؟؟؟
    1 نقطة
  22. A company hired 10 temporary workers who are paid hourly and you are given a data file that contains the last name of the employees, the number of hours each employee worked in a week, and the hourly pay rate of each employee. You are asked to write a program that computes each employ- ee’s weekly pay and the average salary of all the workers. The program then outputs the weekly pay of each employee, the average weekly pay, and the names of all the employees whose pay is greater than or equal to the average pay. If the number of hours worked in a week is more than 40, then the pay rate for the hours over 40 is 1.5 times the regular hourly rate. Use two parallel arrays: a one-dimensional array to store the names of all the employees, and a two-dimensional array of 10 rows and 3 columns to store the number of hours an employee worked in a week, the hourly pay rate, and the weekly pay. Your program must contain at least the follow- ing functions—a function to read the data from the file into the arrays, a function to determine the weekly pay, a function to output the names of all the employees whose pay is greater than or equal to the average weekly pay, and a function to output each employee’s data.
    1 نقطة
  23. بشكل عام نستعمل lambda عندما نريد تابع بسيط يقوم بعملية بسيطة و نريد تمريره إلى تابع ما. في بايثون خصوصاً دالة lambda لا يمكن أن تكون معقدة، و بالتالي في حال أردت القيام بعملية معقدة عليك إنشاء تابع عادي لها. أيضاً في حال كنت تريد استعمال هذه العملية كثيراً فمن غير الجيد في كل مرة أن نقوم بتعريف lambda بل من الأفضل تعريف تابع واحد يتم استدعاءه في مختلف الأماكن في الكود، و بالتالي نستعمل lambda غالباً للتوابع التي لن نستعملها كثيراً أو في أكثر من مكان في الكود. أما بالنسبة لسؤالك ف key هو معطى تتوقع الدالة أن تعطيها إياه، و لذلك لا يمكنك تغييره، و لكنك بالطبع يمكنك إنشاء متغير خارجي قيمته تساوي ال lambda و لكن بشكل عام هذا الأمر غير منصوح به، فأنت كأنك تعطي اسم لهذه الدالة، و في تلك الحالة من الأفضل كتابة تابع عادي.
    1 نقطة
  24. وظيفة الدوال اللامدا (Lambda) هي إنشاء وتعريف دوال صغيرة بدون اسم في برمجة البايثون، وتُستخدم بشكل شائع في الأماكن التي يتطلب فيها استخدام دالة بسيطة وغير معقدة ولا تحتاج إلى إعادة استخدامها في أماكن أخرى. وفي الكود الخاص بك، تستخدم دالة Lambda في وضعها كمعامل لمتغير key في دالة sort()، مما يعني أن الدالة اللامدا تُعين كمعيار (key) لتحديد كيفية ترتيب العناصر في القائمة. تفسير الدالة lambda : lambda x: int(x[2:]) lambda: الكلمة المفتاحية لإنشاء الدالة اللامبدا. x: هو المعامل المستخدم في الدالة. int(x[2:]): تحويل جزء من السلسلة x إلى عدد صحيح (integer)، حيث يتم استخراج الجزء من المؤشر 2 وما بعده. وباستخدام تلك الدالة، يتم تحويل قيمة العنصر في القائمة إلى عدد صحيح، ومن ثم يتم استخدامها كمعيار لترتيب العناصر في القائمة. وتستطيع الإعتماد على دالة print() بشكل مباشر دون استخدام الدالة اللامبدا في هذا السياق، ولكن في حالة الدالة sort()، تحتاج إلى تحديد المعيار الذي يتم استخدامه في الترتيب، وهو السبب في استخدام الدالة اللامدا كمعامل لمتغير key. تعابير lambda في بايثون
    1 نقطة
  25. يتم استخدام الدالة الموجودة في متغير key كدالة تحويل (transform function)، والتي تستخدم لتحويل كل عنصر في القائمة قبل الفرز. في حالتنا، تحويل العناصر يتم بإزالة الحرفين الأولين من كل عنصر في القائمة، ثم تحويل النتيجة إلى قيمة صحيحة (integer) باستخدام دالة int()، وهذا يتم بإستخدام التعبير اللامبدا (lambda expression). يمكن تغيير اسم المتغير key إلى اسم آخر، لكن يجب الاحتفاظ بالمعنى الذي يحمله، والذي يعني "الدالة التي تستخدم لتحويل العناصر قبل الفرز". ويمكن استخدام دالة مخصصة بدلاً من التعبير اللامبدا في المتغير key، وستعمل بنفس الطريقة، أي تحويل العناصر قبل الفرز. يتم استخدام الدالة print() لإظهار قائمة العناصر المرتبة بعد الفرز، وليست لتحويل العناصر قبل الفرز. لذلك، يجب تحديد دالة تحويل (transform function) مخصصة باستخدام المتغير key لتحويل العناصر قبل الفرز، ولا يمكن استخدام دالة print() لهذا الغرض. مثال آخر على الشرح لنفترض أن لدينا قائمة من الأسماء ونريد ترتيبها بحسب طول كل اسم. يمكن استخدام المتغير key لتحديد دالة تحويل (transform function) تستخدم لتحويل كل عنصر في القائمة قبل الفرز. في هذه الحالة، يمكن استخدام دالة len() لتحويل كل عنصر في القائمة إلى طوله قبل الفرز. يمكن استخدام المتغير key لتحديد دالة التحويل كالتالي: my_list = ['John', 'Bob', 'Alice', 'Mike', 'David'] my_list.sort(key=lambda x: len(x)) print(my_list) في هذا المثال، تم استخدام التعبير اللامبدا (lambda expression) في المتغير key لإنشاء دالة تحويل مخصصة. تستخدم هذه الدالة دالة len() لتحويل كل عنصر في القائمة إلى طوله، ثم يتم فرز القائمة وفقًا لطول كل عنصر فيها. سيتم طباعة النتيجة كالتالي: ['Bob', 'John', 'Mike', 'Alice', 'David'] ويمكن ملاحظة أن الأسماء مرتبة حسب طولها بدءًا من الأصغر إلى الأكبر. إذا كان السؤال خاص بدورة ما في الأكاديمية يفضل السؤال أسفل الفيديو وسيتم الإجابة بأسرع وقت
    1 نقطة
  26. في الكود الذي قمت بتقديمه، يتم استخدام دالة مساعدة (lambda function) كمتغير key في دالة sort(). دعنا نلقي نظرة على السبب وراء ذلك: دالة sort() في لغة Python تستخدم لترتيب قائمة وفقًا لمعيار معين. المعيار المستخدم لترتيب العناصر في القائمة يمكن تخصيصه باستخدام متغير key. في الكود الخاص بك، تم استخدام key = lambda x: int(x[2:]) لتحديد المعيار الذي سيتم استخدامه في ترتيب العناصر في القائمة. تقوم الدالة lambda بتحويل العناصر في القائمة إلى أعداد صحيحة بدءًا من المؤشر 2 ومن ثم يتم استخدام هذه الأعداد لترتيب العناصر. السبب في استخدام دالة مساعدة (lambda function) بدلاً من كتابة الدالة مباشرة في دالة sort() هو القدرة على تخصيص المعيار بسهولة. باستخدام دالة lambda، يمكنك تعريف معيار ترتيب مخصص بشكل سريع ومباشر واستخدامه في دالة sort() دون الحاجة إلى تعريف دالة منفصلة. بالنسبة للتسمية، يمكنك تغيير اسم المتغير key إلى أي اسم تريده. يعتمد ذلك على تفضيلاتك الشخصية وقراءة الكود الأكثر وضوحًا وفهمًا. لمزيد من الوضوح والقراءة السلسة للكود، يمكنك استخدام الدالة lambda بشكل منفصل وتعريفها قبل استخدامها في دالة sort() كما يلي: my_list = ['id1', 'id22', 'id3', 'id100', 'id40'] custom_key = lambda x: int(x[2:]) my_list.sort(key=custom_key) print(my_list) بهذه الطريقة، يمكنك تعريف الدالة المساعدة بشكل مستقل وإعادة استخدامها في حالة الحاجة.
    1 نقطة
  27. عندما تقوم باستخدام ال rem في موقعك فإنك تقوم بتعديل ال font-size لل html حتى يتم تعديل المقاسات للعناصر التي تستخدم ال rem تجاوبياً ولكن في بعض الأحيان هناك بعض العناصر التي لا تريد أن تتفاعل تجاوبياً مع حجم الشاشة لذلك نستخدم معها ال px نستخدم ال px أيضاً عند التعامل مع ال border مثلاً حيث نتعامل مع حجم صغير جداً فمثلاً بدلاً من كتابة القيمة بالشكل التالي border-radius: .18rem; نستخدم ال px لهذه القيم الصغيرة كالتالي border-radius: 3px; هناك العديد من الحالات التي يمكنك الإطلاع عليها من خلال النقاشات التالية بدلاً من التكرار
    1 نقطة
  28. يمثل المخزن المؤقت buffer مساحة ما في الذاكرة RAM تحتوي على البيانات بالصيغة الثنائية binary، ويمكن لنود Node.js أن تتعامل مع هذه الذاكرة باستخدام الصنف ‎Buffer‎، حيث يمثل البيانات كسلسلة من الأعداد بطريقة مشابهة لعمل المصفوفات في جافاسكربت، إلا أن الفرق أن هذه البيانات لا يمكن التعديل على حجمها بعد إنشاء المخزن، وكثيرًا ما نتعامل مع المخازن المؤقتة عند تطوير البرامج ضمن بيئة نود دون أن نشعر، فمثلًا عند قراءة ملف ما باستخدام التابع ‎fs.readFile()‎ فسيمرر كائن من نوع مخزن مؤقت يحوي بيانات الملف الذي نحاول قراءته إلى تابع رد النداء callback أو كنتيجة للوعد Promise، وحتى عند إنشاء طلبات HTTP فالنتيجة هي مجرى stream من البيانات المخزنة مؤقتًا في مخزن مؤقت داخلي يساعد المستخدم على معالجة بيانات جواب الطلب على دفعات بدلًا من دفعة واحدة. ونستفيد من المخازن المؤقتة أيضًا عند التعامل مع البيانات الثنائية عند كتابة البرامج منخفضة المستوى مثل التي تتعامل مع إرسال واستقبال البيانات عبر الشبكة، كما توفر القدرة على التعامل مع البيانات على أخفض مستوى ممكن والتعديل عليها في الحالات التي نحتاج بها لذلك. سنتعرف في هذا الفصل على المخازن المؤقتة وطريقة إنشائها والقراءة والنسخ منها والكتابة إليها، وحتى تحويل البيانات الثنائية ضمنها إلى صيغ ترميز أخرى. المستلزمات هذا الفصل جزء من سلسلة دليل تعلم Node.js لذا يجب قبل قراءته: تثبيت بيئة Node.js على الجهاز، حيث استخدمنا في هذا المقال الإصدار رقم 10.19.0. معرفة التعامل مع حلقة REPL في نود، يمكنك الاطلاع على المقال الثاني من هذه السلسلة للتعرف أكثر على طريقة استخدام هذا الوضع. معرفة بأساسيات جافاسكربت وأنواع البيانات المتوفرة ضمن اللغة. إنشاء المخزن المؤقت سنتعرف في هذه الفقرة على طريقتين لإنشاء كائن التخزين المؤقت في نود، حيث يجب يجب أن نسأل أنفسنا دومًا في ما إذا كنا نريد إنشاء مخزن مؤقت جديد، أو استخراج مخزن مؤقت من بيانات موجودة مسبقًا، وعلى أساس ذلك سنحدد الطريقة المستخدمة لإنشائه، ففي حال أردنا تخزين بيانات غير موجودة ونتوقع أن تصل لاحقًا ففي تلك الحالة يجب إنشاء مخزن مؤقت جديد باستدعاء بالتابع ‎alloc()‎ من الصنف ‎Buffer‎، ولنوضح هذه الطريقة نبدأ بفتح جلسة جديدة من وضع حلقة REPL بتنفيذ الأمر ‎node‎ في سطر الأوامر كالتالي: $ node يظهر الرمز ‎>‎ في بداية السطر، ما يدل على استعداد هذا الوضع لتلقي التعليمات البرمجية وتنفيذها، حيث يقبل التابع ‎alloc()‎ تمرير عدد كمعامل أول إجباري يشير إلى حجم المخزن المؤقت الذي نود إنشاءه، أي يمثل هذا المعامل عدد البايتات التي ستُحجز في الذاكرة للمخزن المؤقت الجديد، فمثلًا لإنشاء مخزن مؤقت بسعة 1 كيلوبايت أي ما يعادل 1024 بايت يمكننا استخدام التابع السابق كالتالي: > const firstBuf = Buffer.alloc(1024); نلاحظ أن الصنف ‎Buffer‎ متاح بشكل عام في بيئة نود، ومنه يمكننا الوصول مباشرة إلى التابع ‎alloc()‎ لاستخدامه، ونلاحظ كيف مررنا القيمة ‎1024‎ كمعامل أول له لينتج لدينا مخزن مؤقت بسعة 1 كيلوبايت، حيث ستحوي المساحة المحجوزة للمخزن المؤقت الجديد مؤقتًا على أصفار افتراضيًا، وذلك ريثما نكتب البيانات ضمنه لاحقًا، وبإمكاننا تخصيص ذلك فإذا أردنا أن تحتوي تلك المساحة على واحدات بدلًا من الأصفار يمكننا تمرير هذه القيمة كمعامل ثاني للتابع ‎alloc()‎ كالتالي: > const filledBuf = Buffer.alloc(1024, 1); ينتج لدينا مخزنًا مؤقتًا بمساحة 1 كيلوبايت من الذاكرة المملوءة بالواحدات، ويجب التأكيد أن البيانات التي يمثلها المخزن المؤقت ستكون بيانات ثنائية binary مهما كانت القيمة التي نحددها له كقيمة أولية، حيث يمكن تمثيل العديد من صيغ البيانات بواسطة البيانات الثنائية، فمثلًا البيانات الثنائية التالية تمثل حجم 1 بايت: ‎01110110‎، ويمكن تفسيرها كنص بترميز ASCII باللغة الإنكليزية وبالتالي ستُعبّر عن الحرف ‎v‎، ويمكن أيضًا تفسير هذه البيانات بسياق آخر وترميز مختلف على أنها لون لبكسل واحد من صورة ما، حيث يمكن للحاسوب التعامل مع هذه البيانات ومعالجتها بعد معرفة صيغة ترميزها. ويستخدم المخزن المؤقت في نود افتراضيًا ترميز UTF-8 في حال كانت القيمة الأولية المخزنة ضمنه عند إنشاءه هي سلسلة نصية، حيث يمكن للبايت الواحد في ترميز UTF-8 أن يمثل حرفًا من أي لغة أو عددًا أو رمزًا ما، ويعتبر هذا الترميز توسعة لمعيار الترميز الأمريكي لتبادل البيانات أو ASCII والذي يقتصر على ترميز الأحرف الإنكليزية الكبيرة والصغيرة والأعداد وبعض الرموز القليلة الأخرى فقط، كعلامة التعجب "!" وعلامة الضم "&"، ويمكننا تحديد الترميز المستخدم من قبل المخزن المؤقت عبر تمريره كمعامل ثالث للتابع ‎alloc()‎، فمثلًا لو اقتصرت حاجة برنامج ما على التعامل مع محارف بترميز ASCII يمكننا تحديده كترميز للبيانات ضمن المخزن المؤقت كالتالي: > const asciiBuf = Buffer.alloc(5, 'a', 'ascii'); نلاحظ تمرير المحرف ‎a‎ كمعامل ثانِ وبذلك سيتم تخزينه ضمن المساحة الأولية التي ستُحجز للمخزن المؤقت الجديد، ويدعم نود افتراضيًا صيغ ترميز المحارف التالية: ترميز ASCII ويُمثّل بالسلسلة النصية ‎ascii‎. ترميز UTF-8 ويُمثّل بالسلسلة النصية ‎utf-8‎ أو ‎utf8‎. ترميز UTF-16 ويُمثّل بالسلسلة النصية ‎utf-16le‎ أو ‎utf16le‎. ترميز UCS-2 ويُمثّل بالسلسلة النصية ‎ucs-2‎ أو ‎ucs2‎. ترميز Base64 ويُمثّل بالسلسلة النصية ‎base64‎. الترميز الست عشري Hexadecimal ويُمثّل بالسلسلة النصية ‎hex‎. الترميز ISO/IEC 8859-1 ويُمثّل بالسلسلة النصية ‎latin1‎ أو ‎binary‎. حيث يمكن استخدام أي من أنواع الترميز السابقة مع أي تابع من الصنف ‎Buffer‎ يقبل ضمن معاملاته معاملًا بالاسم ‎encoding‎ لتحديد صيغة الترميز، ومن ضمنها التابع ‎alloc()‎ الذي تعرفنا عليه. قد نحتاج أحيانًا لإنشاء مخزن مؤقت يُعبر عن بيانات جاهزة موجودة مسبقًا، كقيمة متغير أو سلسلة نصية أو مصفوفة، حيث يمكننا ذلك باستخدام التابع ‎from()‎ الذي يدعم إنشاء مخزن مؤقت جديد من عدة أنواع من البيانات وهي: مصفوفة من الأعداد التي تتراوح قيمها بين ‎0‎ و ‎255‎،حيث يمثل كل عدد منها قيمة بايت واحد. كائن من نوع ‎ArrayBuffer‎ والذي يخزن داخله حجمًا ثابتًا من البايتات. سلسلة نصية. مخزن مؤقت آخر. أي كائن جافاسكربت يملك الخاصية ‎Symbol.toPrimitive‎ التي تُعبر عن طريقة تحويل هذا الكائن إلى بيانات أولية، مثل القيم المنطقية ‎boolean‎ أو ‎null‎ أو ‎undefined‎ أو الأعداد ‎number‎ أو السلاسل النصية ‎string‎ أو الرموز ‎symbol‎. لنختبر الآن طريقة إنشاء مخزن مؤقت جديد من سلسلة نصية باستخدام التابع from كالتالي: > const stringBuf = Buffer.from('My name is Hassan'); ينتج بذلك لدينا كائن مخزن مؤقت جديد يحتوي على قيمة السلسلة النصية ‎My name is Hassan‎، ويمكننا كما ذكرنا إنشاء مخزن مؤقت جديد من مخزن مؤقت آخر مثلًا كالتالي: > const asciiCopy = Buffer.from(asciiBuf); ينتج بذلك لدينا المخزن المؤقت ‎asciiCopy‎ والذي هو نسخة مطابقة من المخزن الأول ‎asciiBuf‎، وبذلك نكون قد تعرفنا على طرق إنشاء المخازن المؤقتة، وفي الفقرة التالية سنتعلم طرق قراءة البيانات منها. القراءة من المخزن المؤقت يوجد عدة طرق تمكننا من قراءة بيانات المخزن المؤقت، حيث يمكنن قراءة بايت واحد محدد فقط منه إذا أردنا، أو قراءة كل البيانات دفعة واحدة، ولقراءة بايت واحد فقط يمكن الوصول إليه عبر رقم ترتيب مكان هذا البايت ضمن المخزن المؤقت، حيث تُخزِّن المخازن المؤقتة البيانات بترتيب متتابع تمامًا كالمصفوفات، ويبدأ ترتيب أول مكان للبيانات داخلها من الصفر ‎0‎ تمامًا كالمصفوفات، ويمكن استخدام نفس صيغة الوصول إلى عناصر المصفوفة لقراءة البايتات بشكل مفرد من المخزن مؤقت. لنختبر ذلك نبدأ بإنشاء مخزن مؤقت جديد من سلسلة نصية كالتالي: > const hiBuf = Buffer.from('Hi!'); ونحاول قراءة أول بايت من هذا المخزن كالتالي: > hiBuf[0]; بعد الضغط على زر الإدخال ‎ENTER‎ وتنفيذ التعليمة السابقة سيظهر لنا النتيجة التالية: 72 حيث يرمز العدد ‎72‎ ضمن ترميز UTF-8 للحرف ‎H‎ وهو أول حرف من السلسلة النصية المُخزنة، حيث تقع قيمة أي بايت ضمن المجال من صفر ‎0‎ إلى ‎255‎، وذلك لأن البايت يتألف من 8 بتات أو bits، وكل بت بدوره يمثل إما صفر ‎0‎ أو واحد ‎1‎، فأقصى قيمة يمكن تمثيلها بسلسلة من ثمانية بتات تساوي 2⁸ وهو الحجم الأقصى للبايت الواحد، أي يمكن للبايت تمثيل قيمة من 256 قيمة ممكنة، وبما أن أول قيمة هي الصفر فأكبر عدد يمكن تمثيله في البايت الواحد هو 255، والآن لنحاول قراءة قيمة البايت الثاني ضمن المخزن كالتالي: > hiBuf[1]; سنلاحظ ظهور القيمة ‎105‎ والتي ترمز للحرف الصغير ‎i‎، والآن نحاول قراءة آخر بايت من هذا المخزن كالتالي: > hiBuf[2]; نلاحظ ظهور القيمة ‎33‎ والتي ترمز إلى إشارة التعجب ‎!‎، ولكن ماذا سيحدث لو حاولنا قراءة بايت غير موجود بتمرير قيمة لمكان خاطئ ضمن المخزن كالتالي: > hiBuf[3]; سنلاحظ ظهور القيمة التالية: undefined وهو نفس ما سيحدث لو حاولنا الوصول إلى عنصر غير موجود ضمن مصفوفة ما. والآن بعد أن تعرفنا على طريقة قراءة بايت واحد من البيانات ضمن المخزن مؤقت، سنتعرف على طريقة لقراءة كل البيانات المخزنة ضمنه دفعة واحدة. يوفر كائن المخزن مؤقت التابعين ‎toString()‎ و ‎toJSON()‎ والذي يعيد كل منهما البيانات الموجودة ضمن المخزن دفعة واحدة كل منهما بصيغة مختلفة، ونبدأ بالتابع ‎toString()‎ والذي يحول البايتات ضمن المخزن المؤقت إلى قيمة سلسلة نصية ويعيدها، لنختبر ذلك باستدعائه على المخزن المؤقت السابق ‎hiBuf‎ كالتالي: > hiBuf.toString(); سنلاحظ ظهور القيمة التالية: 'Hi!' وهي قيمة السلسلة النصية التي خزناها ضمن المخزن المؤقت عند إنشاءه، ولكن ماذا سيحدث لو استدعينا التابع ‎toString()‎ على مخزن مؤقت تم إنشاءه من بيانات من نوع مختلف؟ لنختبر ذلك بإنشاء مخزن مؤقت جديد فارغ بحجم ‎10‎ بايت كالتالي: > const tenZeroes = Buffer.alloc(10); ونستدعي التابع ‎toString()‎ ونلاحظ النتيجة: > tenZeroes.toString(); سيظهر ما يلي: '\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000' حيث تقابل السلسلة النصية ‎\u0000‎ المحرف في ترميز Unicode المقابل للقيمة ‎NULL‎، وهو ما يقابل قيمة الصفر ‎0‎، حيث يعيد التابع ‎toString()‎ ترميز UTF-8 للبايتات المخزنة في حال كانت البيانات ضمن المخزن المؤقت ليست من نوع سلسلة نصية، ويقبل التابع ‎toString()‎ معامل اختياري بالاسم ‎encoding‎ لتحديد ترميز البيانات المطلوب، حيث يمكن باستخدامه تعديل ترميز قيمة السلسلة النصية التي يعيدها التابع، فيمكن مثلًا قراءة نفس البيانات للمخزن ‎hiBuf‎ السابق لكن بالترميز الست عشري كالتالي: > hiBuf.toString('hex'); سنلاحظ ظهور النتيجة التالية: '486921' حيث تُعبر تلك القيمة عن الترميز الست عشري للبايتات التي تتألف منها السلسلة النصية ‎Hi!‎. ويُستفاد في نود من تلك الطريقة لتحويل ترميز بيانات ما من شكل لآخر، بإنشاء مخزن مؤقت جديد يحوي قيمة السلسلة النصية المراد تحويلها ثم استدعاء التابع ‎toString()‎ مع تمرير الترميز الجديد المرغوب به. أما وفي المقابل يعيد التابع ‎toJSON()‎ البيانات ضمن المخزن المؤقت كأعداد تمثل قيم البايتات المخزنة مهما كان نوعها، والآن لنختبر ذلك على كل من المخزنين السابقين ‎hiBuf‎ و ‎tenZeroes‎ ونبدأ بإدخال التعلمية التالية: > hiBuf.toJSON(); سنلاحظ ظهور القيمة التالية: { type: 'Buffer', data: [ 72, 105, 33 ] } يحوي الكائن الناتج من استدعاء التابع ‎toJSON()‎ على خاصية النوع ‎type‎ بالقيمة نفسها دومًا وهي ‎Buffer‎، حيث يُستفاد من هذه القيمة لتمييز نوع كائن JSON هذا عن الكائنات الأخرى، ويحتوي على خاصية البيانات ‎data‎ وهي مصفوفة من الأعداد التي تمثل البايتات المخزنة، ونلاحظ أنها تحتوي على القيم ‎72‎ و ‎105‎ و ‎33‎ بالترتيب وهي نفس القيم التي ظهرت لنا سابقًا عند محاولة قراءة البايتات المخزنة بشكل مفرد. والآن لنختبر استدعاء التابع ‎toJSON()‎ على المخزن الفارغ ‎tenZeroes‎: > tenZeroes.toJSON(); سنلاحظ ظهور النتيجة التالية: { type: 'Buffer', data: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] } الخاصية ‎type‎ تحوي نفس القيمة السابقة، بينما البيانات في المصفوفة هي عشرة أصفار تمثل البايتات العشرة الفارغة التي يحويها المخزن المؤقت، وبذلك نكون قد تعلمنا طرق قراءة البيانات من المخازن المؤقتة، وفي الفقرة التالية سنتعلم طريقة التعديل على تلك البيانات ضمن المخزن المؤقت. التعديل على المخزن المؤقت يوجد عدة طرق للتعديل على البيانات ضمن المخزن المؤقت، وهي مشابهة لطريقة قراءة البيانات حيث يمكن إما تعديل قيمة بايت واحد مباشرة باستخدام نفس صيغة الوصول لعناصر المصفوفات، أو كتابة محتوى جديد وتبديل المحتوى المخزن مسبقًا. ولنبدأ بالتعرف على الطريقة الأولى لذلك سنستخدم المخزن السابق ‎hiBuf‎ الذي يحتوي على قيمة السلسلة النصية ‎Hi!‎ داخله، ولنحاول تعديل محتوى كل بايت منه على حدى إلى أن تصبح القيمة الجديدة هي ‎Hey‎، حيث نبدأ بتعديل الحرف الثاني من المخزن ‎hiBuf‎ إلى الحرف ‎e‎ كالتالي: > hiBuf[1] = 'e'; نتأكد من صحة التعديل السابق بقراءة محتوى المخزن المؤقت الجديد باستدعاء التابع ‎toString()‎ كالتالي: > hiBuf.toString(); نلاحظ ظهور القيمة التالية: 'H\u0000!' القيمة الغريبة التي ظهرت تدل على أن المخزن مؤقت يقبل فقط القيم العددية عند تخزينها داخله، لذا لا يمكن تمرير الحرف ‎e‎ كسلسلة نصية مباشرةً، بل يجب تمرير القيمة الثنائية المقابلة له كالتالي: > hiBuf[1] = 101; الآن يمكننا معاينة القيمة الجديدة والتأكد: > hiBuf.toString(); نحصل على القيمة التالية: 'He!' نعدل الحرف الأخير من هذه القيمة وهو العنصر الثالث ونضع القيمة الثنائية المقابلة للحرف ‎y‎ كالتالي: > hiBuf[2] = 121; نتأكد من المحتوى بعد التعديل: > hiBuf.toString(); نحصل على القيمة: 'Hey' ماذا سيحدث لو حاولنا تعديل قيمة بايت يقع خارج مجال بيانات المخزن المؤقت؟ سنلاحظ تجاهل المخزن لتلك العملية وتبقى القيمة المخزنة ضمنه كما هي، لنختبر ذلك بكتابة الحرف ‎o‎ إلى المحرف الرابع الغير موجود ضمن المخزن السابق كالتالي: > hiBuf[3] = 111; نعاين قيمة المخزن بعد ذلك التعديل: > hiBuf.toString(); ونلاحظ أن القيمة بقيت كما هي دون تعديل: 'Hey' الطريقة الأخرى للتعديل على محتوى المخزن تكون بكتابة عدة بايتات معًا باستخدام التابع ‎write()‎ الذي يقبل سلسلة نصية كمعامل له تعبر عن المحتوى الجديد للبيانات، لنختبر ذلك عبر تعديل محتوى المخزن ‎hiBuf‎ إلى محتواه السابق ‎Hi!‎ كالتالي: > hiBuf.write('Hi!'); نلاحظ أن تنفيذ التعليمة السابقة يعيد القيمة ‎3‎ وهي عدد البايتات التي تم تعديلها ضمن المخزن في تلك العملية، حيث يعبر كل بايت عن محرف واحد لأننا نستخدم الترميز UTF-8، وفي حال كان المخزن يستخدم ترميز آخر مثل UTF-16 ففيه يُمثَّل كل محرف على 2 بايت، عندها سيعيد تنفيذ تابع الكتابة ‎write()‎ بنفس الطريقة القيمة ‎6‎ للدلالة على عدد البايتات التي تمثل المحارف الثلاث المكتوبة. والآن لنتأكد من المحتوى الجديد بعد التعديل نستدعي‎toString()‎ كالتالي: > hiBuf.toString(); نحصل على القيمة: 'Hi!' هذه الطريقة أسرع من طريقة تعديل كل بايت على حدى، ولكن ماذا سيحدث لو كتبنا بيانات بحجم أكبر من حجم المخزن الكلي؟ سيقبل المخزن البيانات المقابلة لحجمه فقط ويهمل البقية، لنختبر ذلك بإنشاء مخزن مؤقت بحجم 3 بايت كالتالي: > const petBuf = Buffer.alloc(3); ونحاول كتابة سلسلة نصية بأربعة محارف مثلًا ‎Cats‎ كالتالي: > petBuf.write('Cats'); نلاحظ أن ناتج التعليمة السابقة هي القيمة ‎3‎ أي تم تعديل قيمة ثلاث بايتات فقط وتجاهل باقي القيمة المُمررة، لنتأكد من القيمة الجديدة كالتالي: > petBuf.toString(); نلاحظ القيمة الجديدة: 'Cat' حيث يُعدل التابع ‎write()‎ البايتات بالترتيب فعدّل أول ثلاث بايتات فقط ضمن المخزن وتجاهل البقية. والآن لنختبر ماذا سيحدث لو كتبنا قيمة بحجم أقل من حجم المخزن الكلي، لهذا نُنشئ مخزن مؤقت جديد بحجم 4 بايت كالتالي: > const petBuf2 = Buffer.alloc(4); ونكتب القيمة الأولية داخله كالتالي: > petBuf2.write('Cats'); ثم نكتب قيمة جديدة حجمها أقل من حجم المخزن الكلي كالتالي: > petBuf2.write('Hi'); وبما أن البيانات ستكتب بالترتيب بدئًا من أول بايت سنلاحظ نتيجة ذلك عند معاينة القيمة الجديدة للمخزن: > petBuf2.toString(); ليظهر القيمة التالية: 'Hits' تم تعديل قيمة أول بايتين فقط، وبقيت البايتات الأخرى كما هي دون تعديل. تكون البيانات التي نود كتابتها موجودة أحيانًا ضمن مخزن مؤقت آخر، حيث يمكننا في تلك الحالة نسخ محتوى ذلك المخزن باستدعاء التابع ‎copy()‎، لنختبر ذلك بداية بإنشاء مخزنين جديدين كالتالي: > const wordsBuf = Buffer.from('Banana Nananana'); > const catchphraseBuf = Buffer.from('Not sure Turtle!'); يحوي كل من المخزنين ‎wordsBuf‎ و ‎catchphraseBuf‎ على بيانات من نوع سلسلة نصية، فإذا أردنا تعديل قيمة المخزن ‎catchphraseBuf‎ ليحوي على القيمة ‎Nananana Turtle!‎ بدلًا من ‎Not sure Turtle!‎ يمكننا استدعاء تابع النسخ ‎copy()‎ لنسخ القيمة ‎Nananana‎ من المخزن ‎wordsBuf‎ إلى ‎catchphraseBuf‎، حيث نستدعي التابع ‎copy()‎ على المخزن الحاوي على المعلومات المصدر لنسخها إلى مخزن آخر، ففي مثالنا النص الذي نريد نسخه موجود ضمن المخزن ‎wordsBuf‎، لذا نستدعي تابع النسخ منه كالتالي: > wordsBuf.copy(catchphraseBuf); حيث يُعبّر معامل الوجهة ‎target‎ المُمرر له عن المخزن المؤقت الذي ستُنسخ البيانات إليه، ونلاحظ ظهور القيمة ‎15‎ كنتيجة لتنفيذ التعليمة السابقة وهي تعبر عن عدد البايتات التي تم كتابتها، ولكن بما أن النص ‎Nananana‎ مكوّن من ثمانية محارف فقط فهذا يدل على عمل مختلف نفذه تابع النسخ، لنحاول معرفة ماذا حدث ونعاين القيمة الجديدة باستخدام التابع ‎toString()‎ ونلاحظ النتيجة: > catchphraseBuf.toString(); نلاحظ القيمة الجديدة: 'Banana Nananana!' نلاحظ أن تابع النسخ ‎copy()‎ قد نسخ كامل المحتوى من المخزن ‎wordsBuf‎ وخزنه ضمن ‎catchphraseBuf‎، ولكن ما نريده هو نسخ قسم من تلك البيانات فقط وهي القيمة ‎Nananana‎، لنعيد القيمة السابقة للمخزن ‎catchphraseBuf‎ أولًا ثم نحاول تنفيذ المطلوب كالتالي: > catchphraseBuf.write('Not sure Turtle!'); يقبل التابع ‎copy()‎ عدة معاملات تمكننا من تحديد البيانات التي نرغب بنسخها إلى المخزن المؤقت الوجهة وهي: الوجهة ‎target‎ وهو المعامل الإجباري الوحيد، ويعبر عن المخزن المؤقت الوجهة لنسخ البيانات. ‎targetStart‎ وهو ترتيب أول بايت ستبدأ كتابة البيانات إليه ضمن المخزن الوجهة، وقيمته الافتراضية هي الصفر ‎0‎، أي بدء عملية الكتابة من أول بايت ضمن المخزن الوجهة. ‎sourceStart‎ وهو ترتيب أول بايت من البيانات التي نرغب بنسخها من المخزن المصدر. ‎sourceEnd‎ وهو ترتيب آخر بايت من البيانات الذي ستتوقف عملية النسخ عنده في المخزن المصدر، وقيمته الافتراضية هي الطول الكلي للبيانات ضمن المخزن المصدر. باستخدام تلك المعاملات يمكننا تحديد الجزء ‎Nananana‎ من المخزن ‎wordsBuf‎ ليُنسخ إلى المخزن ‎catchphraseBuf‎، حيث نمرر المخزن ‎catchphraseBuf‎ كمعامل الوجهة ‎target‎ كما فعلنا سابقًا، ونمرر القيمة ‎0‎ للمعامل ‎targetStart‎ لكتابة القيمة ‎Nananana‎ في بداية المخزن ‎catchphraseBuf‎، أما للقيمة ‎sourceStart‎ سنمرر ‎7‎ وهو ترتيب بداية أول محرف من القيمة ‎Nananana‎ ضمن المخزن ‎wordsBuf‎، وللقيمة ‎sourceEnd‎ نمرر الحجم الكلي للمخزن المصدر، ليكون الشكل النهائي لاستدعاء تابع النسخ بعد تخصيص المعاملات السابقة كالتالي: > wordsBuf.copy(catchphraseBuf, 0, 7, wordsBuf.length); سيظهر هذه المرة القيمة ‎8‎ كنتيجة لتلك العملية ما يعني أن القيمة التي حددناها فقط هي ما تم نسخه، ونلاحظ كيف استخدمنا الخاصية ‎wordsBuf.length‎ لتمرير حجم المخزن كقيمة للمعامل ‎sourceEnd‎، وهي نفس الخاصية ‎length‎ الموجودة ضمن المصفوفات، والآن لنعاين القيمة الجديدة للمخزن ‎catchphraseBuf‎ ونتأكد من النتيجة: > catchphraseBuf.toString(); نلاحظ القيمة الجديدة: 'Nananana Turtle!' بذلك نكون قد عدلنا البيانات ضمن المخزن ‎catchphraseBuf‎ عن طريق نسخ جزء محدد من بيانات المخزن ‎wordsBuf‎ إليه. والآن بعد أن انتهينا من تنفيذ الأمثلة في هذا الفصل يمكنك الخروج من جلسة REPL حيث ستُحذف كل المتغيرات السابقة التي عرفناها بعد عملية الخروج هذه، ولذلك ننفذ أمر الخروج كالتالي: > .exit ختامًا تعرفنا في هذا المقال على المخازن المؤقتة والتي تمثل مساحة محددة من الذاكرة محجوزة لتخزين البيانات بالصيغة الثنائية، وتعلمنا طرق إنشاء المخازن المؤقتة، سواء الجديدة أو التي تحتوي على بيانات موجودة مسبقًا، وتعرفنا بعدها على طرق قراءة تلك البيانات من المخزن سواء بقراءة كل بايت منه على حدى أو قراءة المحتوى كاملًا باستخدام التابعين ‎toString()‎ و ‎toJSON()‎، ثم تعرفنا على طرق الكتابة إلى المخازن لتعديل البيانات المخزنة ضمنها، سواء بكتابة كل بايت على حدى أو باستخدام التابعين ‎write()‎ و ‎copy()‎. يفتح التعامل مع المخازن المؤقتة في نود Node.js الباب للتعامل مع البيانات الثنائية مباشرة، فيمكن مثلًا دراسة تأثير صيغ الترميز المختلفة للمحارف على البيانات المخزنة، كمقارنة صيغ الترميز المختلفة مع الصيغتين UTF-8 و ASCII وملاحظة فرق الحجم بينها، كما يمكن مثلًا تحويل البيانات المخزنة من صيغة UTF-8 إلى صيغ الترميز الأخرى، ويمكنك الرجوع إلى التوثيق الرسمي العربي من نود للكائن ‎Buffer‎ للتعرف عليه أكثر. ترجمة -وبتصرف- للمقال Using Buffers in Node.js لصاحبه Stack Abuse. اقرأ أيضًا المقال السابق: إنشاء خادم ويب في Node.js باستخدام الوحدة HTTP مقدمة إلى Node.js أساسيات التخزين المؤقت للويب Web Caching: المصطلحات الأساسية أساسيات التخزين المؤقت للويب Web Caching: ترويسات HTTP واستراتيجيات التخزين المؤقت
    1 نقطة
  29. مرحباً @Kakao Adado نقوم أولاً بإنشاء 3 مصفوفات واحدة من نوع رقم والباقي نص , الأولى ستكون لتخزين ال id أو الرقم الذاتي والأخرى للإسم والتالية للراتب ونضع حجمها فليكن 10 عناصر , وأخيراً نقوم أيضاً بإنشاء مصفوفة ستحمل جميع بيانات المصفوفات الأخرى فلنسمها userinfo أي هكذا int[] number = new int[10]; string[] name = new string[10]; string[] salary = new string[10]; ArrayList userinfo = new ArrayList(); والأن لإضافة عامل للسجل نقوم بطباعة القيمة التي نريدها من المستخدم إدخالها متل الإسم والراتب والمعرف الذاتي وبعد ذلك نقوم بتمرير تلك البيانات بعد تخزين كل منها في مصفوفته إلى المصفوفة الرئيسية وهي userinfo أي برمجياً هكذا for (int i = 0; i < name.Length;) { Console.Write("name : "); name[i] = Console.ReadLine(); Console.Write("number : "); number[i] = Convert.ToInt32(Console.ReadLine()); Console.Write("salary : "); salary[i] = Console.ReadLine(); //هنا نقوم بإرسال البيانات أعلاه إلى المصفوفة الرئيسية userinfo.Insert(i, name[i]); userinfo.Insert(i, Convert.ToString(number[i])); userinfo.Insert(i, salary[i]); i++; //هنا قمنا بعمل ميثود ستقوم بعرض عناصر المصفوفة userinfo بعد تخزينها ShowuserData(userinfo); break; } والأن لحذف عامل أو سجل عامل من خلال المعرف الذاتي الخاص به نقوم بأخذ مدخل المستخدم وسيكون رقم وهو عبارة عن ترتيب المصفوفة على حسب البيانات الدخلة من دالة الإدخال ومن ثم نمرره للدالة RemoveAt على المصفوفة userinfo وبالتالي سنحذف بيانات ذلك المستخدم من خلال المعرف الخاص به أي هكذا Console.Write("enter the id: "); int item = Convert.ToInt32(Console.ReadLine()); itsTrue = false; userinfo.RemoveAt(item); Console.WriteLine("deleted: {0}", item); ShowuserData(userinfo); وأيضاً أضفت قائمة لإختيار ماذا تريد أن تفعل من خلال إختيار رقم الوظيفة متل بحث,حذف,إدخال ,وبعض الأمور الأخرى البسيطة اتركك تتطلع عليه ويمكن إضافة ما تريد بالتمعن في الأكواد التي كتبتها لك ,وأيضاً تجربة البرنامج using System; using System.Collections; public class Program { public static void Main(string[] args) { int[] number = new int[10]; string[] name = new string[10]; string[] salary = new string[10]; ArrayList userinfo = new ArrayList(); bool itsTrue; string help = @" #enter 1 to add Employee. #enter 2 to exit.0 #enter 3 to delete Employee #enter 4 to search"; Console.WriteLine(help); while (true) { Console.Write("==================================Employees Managment=============="); int input = Convert.ToInt32(Console.ReadLine()); if (input == 1) { for (int i = 0; i < name.Length;) { Console.Write("name : "); name[i] = Console.ReadLine(); Console.Write("number : "); number[i] = Convert.ToInt32(Console.ReadLine()); Console.Write("salary : "); salary[i] = Console.ReadLine(); userinfo.Insert(i, name[i]); userinfo.Insert(i, Convert.ToString(number[i])); userinfo.Insert(i, salary[i]); i++; ShowuserData(userinfo); break; } } else if (input == 2) { Console.Write("Hit y to Exit and n to cancel: "); string exit = Console.ReadLine().ToUpper(); if (exit == "Y") { break; } else if (exit == "N") { continue; } } else if (input == 3) { Console.Write("enter the id: "); int item = Convert.ToInt32(Console.ReadLine()); itsTrue = false; userinfo.RemoveAt(item); Console.WriteLine("deleted: {0}", item); ShowuserData(userinfo); itsTrue = true; break; } else if (input == 4) { Console.Write("enter the id: "); int search = Convert.ToInt32(Console.ReadLine()); itsTrue = false; for (int j = 0; j < name.Length; j++) { if (search == number[j]) { Console.WriteLine("name: {0}", name[j]); Console.WriteLine("number:{0}", number[j]); Console.WriteLine("salary:{0}", salary[j]); itsTrue = true; break; } } } else if (input == 5) { itsTrue = false; ShowuserData(userinfo); itsTrue = true; break; } else { Console.WriteLine("content not found."); } } } private static void ShowuserData(ArrayList users) { foreach (string item in users) { Console.WriteLine(item); } } }
    1 نقطة
  30. بدايةً React هو الأساس وهو قبل المكتبتين الآخريين اما Next.js و Gatsby فهما أطر عمل Framework لمكتبة React لديهما ميزات أضافية ليست موجودة في React ف Gatsby هو عبارة عن Static Site Generator مولد مواقع ثابتة مبني فوق مكتبة React اما Next.js فلديه العديد من الميزات مثل 1- Static Site Generating 2- Static Site Rendering والميزة الجديدة هي 3- Incremental Static Generating إذا كنت تشتغل Front end مطور واجهات فقط فيفضل استخدام React وإذا كنت تهتم بال SEO وتريد بناء تطبيق React كامل Full Stack React App فيستحسن استخدام Next.js
    1 نقطة
  31. أولاً ال gatsby و ال next يستخدمان ال react لذلك ما هما إلا تطوير لل react ولكن ما هو التطوير الذي سأستفيد منه باستخدام أياً منهما NEXT يقوم بتسهيل العمل بال react مثل إختصار كتابة ال routes وإستبدالها ب routes ذاتياً إعتماداً على مجلدات وملفات المشروع والوظيفة الأكثر أهمية هي ال server side rendering مما تساعد بشكل كبير على تحسين ال SEO للموقع gatsby يعتبر static site generator وهو مفهوم جديد للمواقع الديناميكية بحيث يتم فيه الإستغناء عن استخدام قواعد البيانات وبالتالي اتخدام ال backend فمثلاً يمكنك بناء مدونة وإضافة محتوى جديد بدون أي cms ويمكنك أيضاً استخدام ال NEXT ك static site generator لذلك يمكنك استخدام التقنية التي تخدم الأهداف المطلوبة للمشروع
    1 نقطة
  32. في تطوير المواقع يوجد جانبين: الجانب الأول هو جانب المستخدم، وهو كل ما يتعلق بالواجهات والعناصر التي يرها المستخدم على المتصفح ويتفاعل معاها من نصوص وأزرار وصور وفيديوهات وغيرها من العناصر وهذه الواجهات تعتمد بالأساس على اللغتين HTML وCSS بالإضافة للغة جافاسكربت، ونسمى هذا الجانب Front end، والمطور الذي يطور هذا الجانب ب front end developer. الجانب الثاني هو جانب الخادم، وهو يتعلق بالأشياء التي لا تحصل في المتصفح بل تحصل في جزء آخر، هذا الجانب يكون به أكواد نستطيع من خلالها القيام بالعديد من الأشياء، مثلًا الإتصال بقواعد البيانات وإستخراج وإدخال معلومات جديدة لها، معالجة البيانات، تسجيل الصور أو إنشائها والعديد من الأشياء الأخرى، ونسمى هذا الجانب Back end، والمطور الذي يطور هذا الجانب ب back end developer. أما full stack developer فهو مبرمج قادر على تطوير برمجيات في كلا الجانبين، أي Front end و back end في نفس الوقت. الخادم أو السرفر هو حاسوب يحتوي على نفس مكونات الحاسب العادي، لكن غالبًا ما يحتوي هذا الحاسوب على إمكانيات أقوى من إمكانيات الأجهزة العادية إطار العمل هو مجموعة من المكتبات الجاهزة لمساعدة المطور على أداء عمله بسهولة وسرعة، وتوفر عليه بناء التطبيق من الصفر ليركز فقط على ما يميز تطبيقه ويبدأ من نقطة متقدمة، كما أنها تساعده على تنظيم الكود الخاص به. المكتبات هي مجموعة من الأكواد تقوم بعمل شيء ما، مثلًا: يوجد مكتبات للعمليات الحسابية، تحتوي هذه المكتبات على دوال رياضية لمختلف العمليات. يوجد مكتبات لإضافة تنسيقات لكود الصفحة، تحتوي هذه المكتبات على دوال أو تنسيقات جاهزة يمكنك إدراجها لمشروعك يوجد مكتبات لإضافة animation للصفحة. وغيرها ... نعم، يمكن للمطور تعلم العديد من الأشياء في نفس الوقت، لكن كلما تخصص المبرمج كان له مهارات أكبر في المجال الذي تخصص به. ستحتاج بإستمرار للذهاب لتوثيق المكتبات وأطر العمل للبحث عن شيء ما، أو عندما ستحصل معك مشكلة يمكن أن تبحث عن حل لها في جوجل وهكذا .. هناك العديد من التخصصات البرمجية، لا يجب عليك معرفتها جميعًا أو معرفة محتواها كلها. أود إخبارك أن أغلب هذه التخصصات تتقاطع في أجزاء كثيرة مع بعض البعض وفيها بعض الإختلافات التي تميز كل تخصص عن غيره.
    1 نقطة
  33. بعد أن تعلّمنا في الدّرس السّابق كيفيّة التعامل مع كل من الصفوف، المجموعات والقواميس في لغة بايثون ، سنكمل مشوار تعلّم هذه اللغة الجميلة. سنتعلّم في هذا الدّرس كيفيّة التّعامل مع التّعابير الشّرطية، و كيفيّة استعمال الجمل الشّرطية في برامجنا وكيفّية القيّام بإزاحة مناسبة عند التّعامل مع أجزاء متعدّدة من الشّيفرة، وسنكمل هذا الدّرس بمثال تطبيقي يتجلى في برنامج تسجيل حساب والولوج إليه. مع التذكير بأنّ جميع الشّيفرات التّي تبدأ بعلامة <<< يجب أن تنفّذ على مفسر بايثون. التعابير الشرطية Conditional Expressions توفّر لنا لغة بايثون عدّة مُعاملات لمُقارنة القيّم، ونتيجة المُقارنة تكون قيمة منطقيّة Boolean إمّا True أو False. >>> 2 < 3 False >>> 2 > 3 True إليك قائمة بالمُعاملات المُتوفّرة في لغة بايثون. == يُساوي =! لا يُساوي > أصغر من < أكبر من => أصغر من أو تُساوي =< أكبر من أو تُساوي ويُمكن استعمال هذه المُعاملات أكثر من مرّة في السّطر الواحد: >>> x = 5 >>> 2 < x < 10 True >>> 2 < 3 < 4 < 5 < 6 True وتعمل المعاملات على السّلاسل النّصية كذلك (التّرتيب يكون بشكل معجمي، أي حسب ترتيب الكلمات في المُعجم). >>> "python" > "perl" True >>> "python" > "java" True يُمكن الجمع بين القيّم المنطقيّة بمعاملات منطقيّة: a and b: صحيح فقط إذا كان كل من a و b يحملان القيمة True. a or b: صحيح إذا كانت إحدى القيمتين صحيحة. not a: صحيح فقط إذا كان a يحمل القيمة False. وإليك مثالا على المُعاملات المنطقيّة: >>> True and True True >>> True and False False >>> 2 < 3 and 5 < 4 False >>> 2 < 3 or 5 < 4 True الجملة الشرطية If تُستعمل الجملة الشّرطيّة If (إذا كان) لتنفيذ جزء من الشّيفرة إذا كان الشّرط مُحقّقا: >>> if x % 2 == 0: ... print 'even' ... even >>> في المثال أعلاه طُبعَت الكلمة even لأنّ باقي قسمة 42 على 2 يُساوي صفرا (x % 2 == 0)، وبالتّالي فقد تحقّق الشّرط، فلو أنّ الشّرط لم يتحقّق لما أرجع المُفسّر أي نتيجة. يُمكن استخدام If كشرط لتنفيذ جزء منفصل من الشيفرة بالإزاحة (انظر فصل الإزاحة والمساحات أسفله)، ويكون هذا الأمر مُفيدا عندما يحتوي برنامجك على الكثير من الجمل. لاحظ بأنّ الجمل التّابعة للسّطر if x % 2 == 0 مُزاحةٌ بأربع مسافات بيضاء. الجملة else يُمكن أن تزيد على جملة If بند else وترجمته (وإلّا / إذا لم يكن ذلك صحيحًا)، والتي تنفّذ الشيفرة التّي من بعدها إذا كان الشّرط الأول خاطئا. >>> x = 3 >>> if x % 2 == 0: ... print 'even' ... else: ... print 'odd' ... odd >>> في المثال أعلاه، كان الشّرط الأول خاطئا لأن باقي قسمة 3 على 2 لا يُساوي صفرًا، ولذلك انتقل البرنامج لتنفيذ الشّيفرة بعد جملة else وقام بطباعة كلمة odd. الجملة elif يُمكن كذلك أن تزيد جملة elif وهي اختصار لـ else if والتّي تعني "إذا لم يتحقّق الشرط فانظر الشّرط التّالي": >>> x = 42 >>> if x < 10: ... print 'one digit number' ... elif x < 100: ... print 'two digit number' ... else: ... print 'big number' ... two digit number >>> في المثال أعلاه، هناك شرطان مختلفان، أولا عند تحقّق شرط كون قيمة المتغيّر x أصغر من العدد 10 فسيطبع البرنامج الجملة التي تقول بأنّ قيمة المتغير x عبارة عن رقم واحد، إذا لم يتحقّق الشّرط السّابق فسينتقل البرنامج إلى الشّرط الذي يليه وهو ما يتبع الجملة elif أي إذا كانت قيمة المتغيّر x أصغر من 100 فسيطبع البرنامج الجملة التي تفيد بأنّ قيمة المتغير x عبارة عن رقمين والجملة else تنفَّذُ إذا لم يتحقّق أي شرط وتفيد بأنّ قيمة المتغيّر x عبارة عن عدد كبير (لأنّه يتكون من 3 أرقام فأكثر). المساحة والمسافات والإزاحة المساحات التّي تسبق الشّيفرات في بايثون مُهمّة جدّا لترتيب شيفرة البرنامج ولتسهيل قراءته، كما أنّها تكون ضروريّة في بايثون، فإن لم تتّبع قوانين الإزاحة فلن يعمل البرنامج، وتُستعمل هذه الطّريقة لفصل الشّيفرات التّابعة لجزء معيّن من البرنامج، والإزاحة تكون بكتابة الشّيفرة بعد عدد معيّن من المسافات، ومن المُفضّل أن تكون أربع مسافات بيضاء، انظر المثال: هل الشّرط محقّق؟ .... نعم الشّرط محقّق .... لا الشرط غير محقق انتهى البرنامج في المثال أعلاه، الجملتان "نعم الشّرط محقّق" و "لا الشّرط غير محقّق" تابعتان للجملة "هل الشّرط محقّق؟" أمّا الجملة "انتهى البرنامج" فتابعة للبرنامج عامّة. وقد اعتمدت على النّقاط لتوضيح فكرة الإزاحة فقط وعليك أن تستبدل النّقاط بالمسافات في ملفّات بايثون. يُمكن كذلك أن تكون الشّيفرة تابعة لجملة ما، والتّي بدورها تابعة لجملة أخرى، لتتّضحك الأمور أكثر، فكّر في شجرة عائلة تتكوّن من الآباء والأولاد: جدّ ....أب 1 ........ابن 1.1 ........ابن 1.2 ....أب 2 ........ابن 2.1 ........ابن 2.2 للجد ابنان، ولكل ابن ابنان، نستنتج من هذا أنّ كلّ ابن تابع لأبيه بإزاحة أربع مسافات، أمّا الحفيد فتابع للجدّ بثماني مسافات. وإلى الآن تعرّفنا على موضع واحد تكون فيه الإزاحة إجباريّة وهي الجمل الشّرطيّة، فمثلا البرنامج التّالي: x = 42 if x % 2 == 0: print 'even' print 'Hello World' في المثال أعلاه جميع السّطور المزاحة بأربع مسافات (أي الجملة التي تطبع كلمة even) تُنفّذ عند تحقّق الشّرط فقط، أي أنّها جزء مرتبط بالشّرط في البرنامج، أمّا الشيفرة التي لم تُسبق بمسافات فتنفّذ بشكل طبيعي وتعتبر ضمن البرنامج عامّة. أمّا إذا أردنا أن نطبع جملة بعد التّحقّق من شرطين فسيكون البرنامج كالتّالي: الشّرط الأول محقّق، إذن انتقل إلى الشّرط الثّاني. الشّرط الأول غير محقّق، إذن لا تنتقل إلى الشّرط الثّاني. إليك تطبيقا للأمر في لغة بايثون: # البرنامج x = 42 if x % 2 == 0: print 'even' if x / 2 == 21: print '42/2 = 21 Is true' print 'Hello World' # المُخرج even 42/2 = 21 Is true Hello World في المثال أعلاه، قمنا بالتّحقّق من أنّ باقي قسمة العدد 42/2 يساوي 0، وبما أنّ الشّرط مُحقّق فقد طبعت الكلمة even وانتقل المُفسّر إلى الشّرط التّالي وهو التّحقّق من أن 42/2 يُساوي 21 وبما أنّه بدوره شرط مُحقّق أيضا فقد قام البرنامج طباعة الجملة 42/2 = 21 Is true وبعدها قام بطباعة الجملة Hello World لأنّها غير مُرتبطة بأي شرط. وبطبيعة الحال إذا لم يكن الشّرط الأول محقّقا، فلن ينتقل المُفسّر للشّرط التّالي ولن يقوم بأي شيء حتّى ولو كان الشّرط مُحقّقا. الحصول على قيم من مستخدم البرنامج يُمكن أن تطلب من المُستخدم أن يُدخل قيمة معيّنة، ثمّ تسند هذه القيمة إلى مُتغيّر في البرنامج، فمثلا لنقل بأنّك ترغب بالتّرحيب بالمُستخدم، أولا يجب أن تطلب منه أن يُدخل اسمه، بعدها تقوم بطباعة الجملة "Hello, Person"، بحيث تستبدل Person بالقيمة التّي أدخلها المُستخدم، انظر المثال: >>> person = raw_input('Enter your name: ') >>> 'Hello ', person إذا نفّذت البرنامج فسيكون المُخرج كالتّالي: Enter your name: وبعد إدخال اسمي والضّغط على مفتاح ENTER، فإنّ المُخرج سيكون كالتّالي: Hello Abdelhadi ما يحدث هو أن البرنامج يأخذ القيمة المُدخلة ويُسندها للمُتغيّر person وبعدها تستطيع أنت أن تطبع المُتغيّر للمُستخدم. تطبيق لنطبّق ما تعلّمناه ولننشئ برنامجا بسيطًا لجدولة مُقابلات العمل: سنطلب من المُستخدم توفير المعلومات التّاليّة: اسم المُتقدّم اسم المسؤول عن المُقابلة وقتُ المُقابلة وبعدها سنطبع جملة تحتوي على جميع المعلومات التّي قدّمها المُستخدم، افتح ملفّا باسم interview.py واكتب فيه التّالي: applicant = raw_input('Enter the applicant name: ') interviewer = raw_input('Enter the interviewer name: ') time = raw_input('Enter the appointment time: ') print interviewer, "will interview", applicant, "at", time في المثال أعلاه نطلب أولا من مُستخدم البرنامج أن يُدخل اسم المُتقدّم ثمّ تُسندُ القيمة إلى المتغيّر applicant، بعد ذلك يُطلب اسم المسؤول عن المُقابلة وتُسند قيمته إلى المُتغيّر interviewer وبعد ذلك نحصل على وقتُ المُقابلة من المُستخدم ونُسند القيمة إلى المُتغيّر time، وفي النّهاية نطبع الجملة الجامعة لكل المعلومات وتقديمها بشكل أسهل. جرّب الأمر بنفسك، وأسند القيّم التّي تريد، وانظر إلى النّتيجة، العب بالشّيفرة، أضف مميّزات أخرى كالتّحقّق من أن عُمر المُتقدّم أكبر من 18 عاما مثلا، وتذكّر بأنّ التعلّم بالتّطبيق أفضل من أي طريقة أخرى. تطبيق عملي: إنشاء برنامج تسجيل دخول بسيط الآن حان الوقت لنطبّق ما تعلّمناه، ولنقم بكتابة برنامج تسجيل دخول بسيط، ومبدأه كالتّالي: يُرحب البرنامج بالمُستخدم. يطلبُ منه معلومات التّسجيل. يفيد البرنامج المُستخدم بأنّ التّسجيل قد تم بنجاح أو بعكس ذلك. يطلب البرنامج معلومات الدّخول. يتحقّق البرنامج من أنّ المعلومات التّي أدخلها صحيحة. إذا كانت صحيحة، يطبع البرنامج رسالة نجاح. إذا كانت خاطئة، يطبع البرنامج رسالة فشل. المُتغيّرات التّي سنعتمد عليها: username: اسم المُستخدم password: كلمة المرور password_verification: تأكيد كلمة المرور (فقط للتّأكد من أنّ المُستخدم أدخل نفس كلمة المرور وأنّه يتذكّرها دون مشاكل). أولا جملة التّرحيب: print 'Hello User, this is a basic sign up/login Program' ثانيّا لنطلب من المُستخدم توفير قيّم المتغيرّات (username: اسم المُستخدم، password: كلمة المرور، password_verification: تأكيد كلمة المرور): username = raw_input('Enter your username please: ') password = raw_input('Enter the your password please: ') password_verification = raw_input('Verify password: ') الآن لنتحقق من أنّ كلمة المرور التّي أدخلها المستخدم في البداية هي نفسها التّي أدخلها عند تأكيد كلمة المرور وذلك بمقارنة المتغيّرين password و password_verification فإذا كانا يحملان نفس القيمة فهذا يعني بأنّ التّسجيل ناجح وسنطبع للمُستخدم جملة تفيد بأنّ عملية التّسجيل قد نجحت. أما إذا لم تكن القيم متساوية سنطبع جملة تفيد المستخدم بأنّ كلمة المرور وتأكيدها لا يتوافقان، ويمكن القيام بالأمر بالأسطر الآتية: if password == password_verification: print 'You have been successfully signed up!' else: print 'The password and the password verification don't match! Please try again' لقد انتهينا الآن من برمجة نظام التّسجيل، ويجب علينا الانتقال إلى الخطوة التّالية وهي مرحلة تسجيل الدّخول. بعد طباعة الجملة التّي تفيد بأنّ المستخدم قام بالتّسجيل بنجاح (انظر الشّيفرة أعلاه) سنطلب منه معلومات الولوج وذلك بإدخال اسم مُستخدمه وكلمة المرور، سنعيّن هذه القيم المدخلة حديثا إلى متغيّرين جديدين، وذلك لمقارنتهما مع قيم المتغيّرين القديمين، إذا كانت القيم توافق ما أدخله قبل قليل فسنطبع جملة تفيد بأنّ عمليّة الولوج قد نجحت، إذا لم يكن الأمر كذلك سنطبع جملة تفيد المستخدم بأنّ القيم التّي أدخلها خاطئة ثمّ يتوقّف البرنامج. الآن، لنطوّر الشّيفرة أعلاه وندخل عليها التّعديلات المطلوبة لإجراء عمليّة الولوج: if password == password_verification: print 'You have Successfully Signed up! \n' username_sign_in = raw_input('Enter your username please: ') password_sign_in = raw_input('Enter your password please: ') if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' else: print 'The password and the password verification do not match! Please try again' لاحظ استخدام المعامل المنطقي and عند التّحقّق من أنّ اسم المستخدم وكلمة المرور المدخلتان (المخزّنة في المتغيّرين username_sign_in و password_sign_in) توافقان ما تم إدخاله من قبل. العامل and يحرص على أنّ كلا الشّرطين محققان. وبهذا نكون قد انتهينا من البرمجية الصغيرة والبسيطة، وهذه هي الشّيفرة الكاملة: print 'Hello User, this is a basic sign up/login Program' username = raw_input('Enter your username please: ') password = raw_input('Enter the your password please: ') password_verification = raw_input('Verify password: ') if password == password_verification: print 'You have Successfully Signed up! \n' username_sign_in = raw_input('Enter your username please: ') password_sign_in = raw_input('Enter your password please: ') if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' else: print 'The password and the password verification do not match! Please try again' تمارين تمرين 1 ما مُخرجات البرنامج التّالي: print 2 < 3 and 3 > 1 print 2 < 3 or 3 > 1 print 2 < 3 or not 3 > 1 print 2 < 3 and not 3 > 1 تمرين 2 ما مُخرجات البرنامج التّالي: x = 4 y = 5 p = x < y or x < z print p تمرين 3 ما مُخرجات البرنامج التّالي: x = 4 y = 5 p = x < y or x < z print p تمرين 4 ماذا سيحدث بعد تنفيذ الشّيفرة التّالية، هل ستحدث أي أخطاء؟ علّل جوابك. x = 2 if x == 2: print x else: print y تمرين 5 ماذا سيحدث بعد تنفيذ الشّيفرة التّالية، هل ستحدث أي أخطاء؟ علّل جوابك. x = 2 if x == 2: print x else: x + تمرين 6 هل الإزاحة في البرنامج التّالي صحيحة؟ إذا لم يكن الأمر كذلك، فأصلح الخطأ. x = 2 if x == 2: print x if x+1 == 3: print 'x+1 = 3' else: print x + 2 مصادر درس Input and Output للكاتب Dr. Andrew N. Harrington. كتاب Python Practice Book لكاتبه Anand Chitipothu.
    1 نقطة
  34. مقالة ممتازة.. الجدير بالذكر أنه في الإصدارات القديمة لبايثون (بايثون<2.4) كان يوجد إضافة لـلمعامل =! المعامل: <> الذي يقوم بنفس العمل. وفي بايثون 3 ألغيت الدالة raw_input() وأبقي على الدالة input() التي أصبحت تقوم بنفس عمل الدالة raw_input().
    1 نقطة
  35. مقالة ممتازة.. الجدير بالذكر أنه في الإصدارات القديمة لبايثون (بايثون<2.4) كان يوجد إضافة لـلمعامل =! المعامل: <> الذي يقوم بنفس العمل. وفي بايثون 3 ألغيت الدالة raw_input() وأبقي على الدالة input() التي أصبحت تقوم بنفس عمل الدالة raw_input().
    1 نقطة
×
×
  • أضف...