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

Mustafa Suleiman

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

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

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

  • عدد الأيام التي تصدر بها

    305

أجوبة بواسطة Mustafa Suleiman

  1. المشكلة الأولى (CS5001)  سببها أنه لا يتم العثور على طريقة Main الثابتة في البرنامج، وطريقة Main هي نقطة البداية الرئيسية لتنفيذ البرنامج، أي يجب أن تقوم بإضافة طريقة Main إلى الكود كالتالي:

    public static void Main(string[] args)
    {
        // الكود هنا
    }

    ولاحظ أنك قمت بكتابة Main بحرف m صغير وليس كبير.

    أما بالنسبة للمشكلة الثانية (CS8600)، فتحدث عندما تحاول تحويل قيمة قد تكون قيمة فارغة (null) إلى نوع غير قابل للاشتقاق مما يعني أنه تم استخدام قيمة قد تكون فارغة (null) في مكان لا يقبل القيم الفارغة.

    والصحيح هو استخدام Convert.ToInt32 لتحويل الإدخال المقروء من Console.ReadLine إلى قيمة صحيحة وتخزينها في المتغير age.

    ففي السطر name = Console.ReadLine(), إذا قام المستخدم بترك الإدخال فارغًا، فإن Console.ReadLine() ستعيد قيمة فارغة (null)، إذا كانت name معرفة كنوع غير قابل للاشتقاق (non-nullable type)، فسيحدث خطأ CS8600، وتستطيع يمكنك استخدام نوع قابل للاشتقاق لـ name من خلال استخدام string? بدلاً من string.

    وفي السطر age = Convert.ToInt32(Console.ReadLine()), إذا قام المستخدم بإدخال قيمة غير صحيحة أو ترك الإدخال فارغًا، فإن Console.ReadLine() قد تعيد قيمة فارغة (null).

    وبما أن age هو من نوع int (نوع غير قابل للاشتقاق)، فسيحدث خطأ CS8600، لذا عليك استخدام int? بدلاً من int لتجنب خطأ CS8600 وللسماح بتخزين القيمة الفارغة (null) في حالة إدخال غير صحيح.

    ولكن سيظهر لديك تنبيه آخر وهو CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

    حيث أنه في لغة C# 8.0 وما بعدها، يمكن استخدام تعليقات Nullable Reference Types لتوضيح قابلية القيم الفارغة (nullability) للمراجعات، ويتم استخدامها لتوضيح ما إذا كانت المراجعات قد يتم تعيينها بقيمة فارغة (null) أم لا، ولكن، يجب تعيين السياق الخاص بتعليقات Nullable Reference Types باستخدام تعليمة '#nullable enable' في بداية الملف الذي يستخدم تلك التعليقات أي وضع السطر التالي:

    #nullable enable

    وبعد التعديلات السابقة يصبح الكود كالتالي:

    #nullable enable
    
    using System;
    
    namespace pl
    {
        class Program
        {
            static void Main(string[] args)
            {
                string? name;
    
                Console.WriteLine("enter your name");
                name = Console.ReadLine();
    
                Console.WriteLine("enter your age");
                string? ageInput = Console.ReadLine();
    
                int? age = !string.IsNullOrEmpty(ageInput) ? Convert.ToInt32(ageInput) : null;
    
                if (age > 20 && name != null)
                {
                    Console.WriteLine($"welcome MR{name}");
                }
                else if (name != null)
                {
                    Console.WriteLine($"welcome {name}");
                }
            }
        }
    }
  2. بخصوص مشكلة التعليق، أرجو منك غلق المتصفح بالكامل ثم إعادة فتحه وتجربة كتابة التعليق، وإذا استمرت المشكلة حاول تفقد هل هناك إضافة تسبب تلك المشكلة حاول تعطيل كل إضافة على حدى ثم التجربة، أو تجربة استخدام متصفح آخر.

    وربما قد يفيدك أيضًا حذف ملفات التخزين المؤقتة للمتصفح، عن طريق الضغط على CTRL + SHIFT + DELETE وستظهر لك نافذة تستطيع منها حذف كل البيانات من خلال الإختيار والضغط على clear data، ولكن لا أنصحك بحذف الكوكيز حتى لا يتم تسجيل خروجك من كل الحسابات في المواقع التي سجلت الدخول بها وستضطر إلى إعادة تسجيل الدخول.

    وبخصوص فهم الفرق بين block و inline-block فالأفضل شرح الفرق بين block و inline و inline-block:

    أولاً العناصر block تبدأ في سطر جديد وتأخذ عرضًا كاملاً في حاويتها، ويمكن أن تحتوي على هوامش (margins) وحشو (padding) وإطار (border) على جميع الجوانب، وأمثلة على العناصر block تشمل <div>، <p>، و <ul>.

    العناصر inline لا تبدأ في سطر جديد وتأخذ فقط العرض الذي تحتاجه، وبإمكانها أن تحتوي فقط على هوامش وحشو وإطار من الجانب الأيمن والأيسر فقط أي لا تستطيع تحديد طول وعرض لها، وأمثلة على العناصر inline تشمل <span>، <a>، و <img>.

    وهناك أمر هام يجب الإنتباه إلى إليه أنه في حالة استخدام التنسيق التالي على عنصر inline مثل span:

    span {
        padding: 12px;
        border: 14px solid red;
    }

    ستجد أنه يظهر إطار من الأعلى والأسفل وأيضًا حشو من الأعلى والأسفل، لكن كيف ذلك! ببساطة الحشو أو الإطار من الأعلى والأسفل لن يؤثر على طول العنصر وإذا قمت بزيادة القيمة ستجد أنه يتم الزيادة من الجانب الأيسر والأيمن بينما الأعلى والأسفل ستجد أنه  يتم إنشاء منطقة إضافية حول النص تعتبر "منطقة تجاوز" (overflowing area) والتي لن تكون مرئية إلا إذا تم تعيين خلفية للعنصر كما في الإطار.

    بينما النص داخل الـ span ظل كما هو على نفس السطر ولم يرتفع أو ينخفض لأسفل.

    بمعنى أن الحشو (padding) أو margin أو الإطار للعناصر inline لا يؤثر على المسافة أعلى وأسفل العنصر - أي أن الخط (أو الخط الأساسي للنص) يكون في نفس الوضع الرأسي حيث سيكون (أو بالأحرى: هو) بدون الحشو، والحشو هنا ينشئ منطقة تتجاوز خلالها العناصر القائمة فقط إذا تم تحديد خلفية لها.

    2023-07-07_15-57-22.png.722cb64125e1124d46d5eefedc724acd.png

    أما عناصر inline-block هي عناصر متوسطة بين العناصر block و inline.

    ولا تبدأ في سطر جديد، ولكن يمكن أن تحتوي على هوامش وحشو وإطار، مما  يجعلها خيارًا جيدًا للعناصر التي ترغب في التحكم في عرضها وارتفاعها، ولكنك لا ترغب في أن تبدأ في سطر جديد، وأمثلة على العناصر inline-block تشمل <input>، <select>، و <button>.

    8-block-vs-inline.jpg_gz.jpg.11f455b3890f0e338d88c44342eec97a.jpg

    شرح خـاصيه الـ Display بالقيم الخاصه بهاا بالتفصـيل معها أمثله

    • شكرًا 1
  3. لتفهم سبب شهرته، أولاً هو إطار مفتوح المصدر تم تطويره من قبل مايكروسوفت، وتستطيع من خلاله بناء تطبيقات ويب تعمل على أي نظام، وأيضًا تطبيقات هاتف من خلال Xamarin.

    أيضًا C# هي لغة برمجة تم تطويرها بواسطة شركة Microsoft وتم إطلاقها لأول مرة في عام 2000 كجزء من منصة Microsoft .NET Framework، ومنذ ذلك الحين، أصبحت C# لغة برمجة رئيسية ومشهورة في تطوير تطبيقات الويندوز وتطبيقات الويب باستخدام ASP.NET وتطبيقات الأجهزة الذكية باستخدام منصة Xamarin.

    وقامت مايكروسوفت بدفع الكثير من المال وإجراء إتفاقيات من أجل دعم استخدام  ASP.NET في المؤسسات الكبيرة الحكومية وإنشاء دورات تدريبية من أجل توفير مطوري ASP.NET في سوق العمل، أيضًا هناك تبرعات تقوم بها مايكروسوفت لدول العالم الثالث! كل سنة.

    ولذلك ستجد أنه يتم تدريس واستخدام لغات وتقنيات تابعة لمايكروسوفت حصرًا.

    وانتبه إلى أن ASP.NET هو إطار عمل لتطوير تطبيقات الويب على الجانب الخادم (الواجهة الخلفية، أي نستخدمه لبناء وتشغيل خادم الويب الذي يتعامل مع الطلبات من المتصفحات ويُنشئ الاستجابات الملائمة للعملاء.

    ويعمل ASP.NET على معالجة المنطق والتفاعل مع قواعد البيانات وتنسيق البيانات وإدارة الحالة والمزيد من الوظائف التي تتطلبها تطبيقات الويب.

    وASP.NET Core هو إطار عمل حديث يدعم أحدث تقنيات تطوير الويب، مثل Razor Pages و Blazor."

    حيث أن Razor Pages  وهي نموذج بناء الصفحات في ASP.NET Core. تمكن المطورين من بناء صفحات الويب بناءًا على بنية بسيطة، حيث يتم دمج ترميز HTML وكود C# الخادمي في ملف واحد، وبالتالي تساعد تلك الطريقة على إنتاج كود نظيف وقابل للصيانة، مما يجعل عملية تطوير وصيانة تطبيقات الويب أسهل.

    أما Blazor هو إطار عمل ويب مبتكر يتيح للمطورين بناء تطبيقات ويب تفاعلية عميلية باستخدام لغة C# بدلاً من JavaScript، وباستخدام Blazor، يمكن للمبرمجين كتابة الكود على الجانب العميل والجانب الخادم بلغة C#، مما يوفر لغة برمجة موحدة في جميع أجزاء التطبيق. وبذلك، يتم الاستغناء عن الحاجة إلى التبديل بين لغات برمجة مختلفة ويتم تبسيط عملية التطوير.

  4. سبب المشكلة هو أنك كتبت دالة setTimeout بشكل غير صحيح، ففي جافاسكريبت يتم إعتماد طريقة camel Case في الأسماء أي أن كل كلمة بعد الأولى تبدأ بحرف كبير، لاحظ أنك كتبت settimeout بينما الصحيح هو setTimeout لاحظ حرف t كبير وليس صغير.

  5. أرجو منك التعليق أسفل فيديو الدورة الخاص بالسؤال حيث ستجد قسم خاص بالتعليقات، وطرح الأسئلة العامة هنا في قسم أسئلة البرمجة.

    والكود الذي وضحته وهو التالي لا يوجد به مشكلة حيث سيتم طباعة hello بعد فترة 3 ثواني:

    const wait = time => new Promise(
        (resolve, reject) => setTimeout(resolve, time)
    )
    
    wait(3000).then(() => console.log('hello'))

    فما هو الخطأ الذي يظهر لك في الكونسول؟

    وإليك تفسير الكود:

    نستخدم الوظيفة wait لإنشاء وعد (Promise) يتأخر لفترة محددة من الوقت المحدد كمعامل (time)، ثم حل الوعد (resolve) بعد انتهاء الفترة المحددة وهي لمدة 3000 ميلي ثانية (3 ثوانٍ)، ثم يتم طباعة "hello" عندما يتم حل الوعد.

  6. إذا كنت تواجه مشكلة أو تريد المزيد من الإيضاح لبعض الأمور في الدورة تستطيع طرح ذلك وسيتم مساعدتك.

    أما بخصوص تغيير الدورة إلى دورة أخرى، فأرجو منك التحدث إلى مركز المساعدة الخاصة بأكاديمية حسوب وسيتم سؤالك عن البريد الإلكتروني فأدخل البريد الخاص بالحساب الذي اشتركت به في الدورة، ثم سيصلك كود تفعيل أدخله وستظهر لك نافذة المحادثة أخبرهم بما تريد، وسيتم الرد عليك خلال 24 إلى 48 ساعة ولا تقلق بشأن الرد فسيتم مساعدتك بلا شك، لكن أحيانًا يكون هناك ضغط.

  7. المشكلة بسبب استخدام دالة useReducer في TypeScript بشكل غير صحيح، حيث يجب أن تحدد نوع الـ reducer الخاص بك بشكل صحيح، وتتوقع useReducer أن تمرر reducer يستقبل حالة وإجراء ويعيد الحالة الجديدة، ووفقًا للواجهة التي قمت بتعريفها، الدالة reducerFunction من المفترض أن تعيد حالة جديدة من نوع state وليس void.

    وتستطيع تحديد النوع العام للـ reducer كالتالي:

    function reducerFunction(state: state, action: action): state {
      // ...
    }

    وبذلك تحدد أن الدالة reducerFunction ستعيد حالة جديدة من نوع state وليس void، وبالتالي يتوافق مع متطلبات useReducer.

    وبعد تحديد النوع العام للـ reducer، بإمكانك استخدامه في useReducer كما هو:

    let [state, dispatch] = useReducer(reducerFunction, {
      b_count: 0,
      a_count: 0,
    });

     

  8. بدون أدوات خارجية سيتعين عليك التالي:

    1.  استخدم توازن الحمل load balancer لتوزيع حركة المرور الواردة على عدة نسخ من التطبيق الخاص بك، وذلك يضمن وجود نسخة واحدة على الأقل تخدم الطلبات أثناء عملية النشر.
    2. إذا تضمنت عملية النشر تغييرات في هيكل قاعدة البيانات، استخدم ميزة ترحيل قاعدة البيانات في Laravel، حيث تتيح لك الترحيلات تطبيق التغييرات على هيكل قاعدة البيانات مع استمرار تشغيل التطبيق، ويتعامل Laravel مع ذلك من خلال تطبيق الترحيلات في عملية انتقالية، لذا إذا فشلت عملية الترحيل، سيقوم Laravel تلقائيًا بإلغاء التغييرات.
    3. إعداد بيئة منفصلة للنشر مثل بيئة التجريب أو الاختبار ، ويجب أن تكون تلك البيئة مطابقة لبيئة الإنتاج الحية قدر الإمكان، وذلك بإختبار عملية النشر بدقة في هذه البيئة قبل تطبيقها على بيئة الإنتاج الحية.
    4.  استخدام نظام التحكم في الإصدار مثل Git لإدارة الكود مما يسمح لك بتتبع التغييرات وإعادة التراجع إذا لزم الأمر. 
    5. بدلاً من نشر جميع نسخ التطبيق الخاصة بك دفعة واحدة، تستطيع اعتماداستراتيجية النشر التدريجي، وينطوي ذلك على نشر النسخ الجديدة تدريجيًا واحدة تلو الأخرى، بينما تستمر النسخ الحالية في تلبية الطلبات، مما يقلل من تأثير النشر على المستخدمين ويضمن استمرارية الخدمة.
    6. تنفيذ فحوصات الحالة لمراقبة حالة نسخ التطبيق الخاصة بك، للتحقق مما إذا كانت النسخة جاهزة لتلقي الطلبات، وتكوين توازن الحمل لتنفيذ فحوصات الحالة وتوجيه المرور إلى النسخ المناسبة والسليمة فقط.

    بينما من الأسهل لك هو أتمتة عملية النشر وهي تضمن توحيد الأسلوب وتقليل الأخطاء وذلك باستخدم أدوات النشر مثل Jenkins أو GitLab CI/CD أو Laravel Envoyer لأتمتة عملية النشر، وذلك لجلب أحدث كود، وتشغيل الاختبارات، وتنفيذ الترحيلات، وتنفيذ خطوات النشر بشكل تلقائي.

    وهناك العديد من الأدوات المفيدة التي يمكن استخدامها لتحقيق نشر تطبيق Laravel بدون توقف، وفيما يلي بعض الأدوات الشائعة:

    • Envoyer by Laravel
    • Deployer
    • Jenkins
    • GitLab CI/CD
    • Laravel Vapor
  9. كلام صحيح، وذلك هو الغرض من دورة خاصة بتعلم أساسيات علوم الحاسب ومخصصة لمن لا يمتلك أي دراية بالبرمجة أو علوم الحاسب، لذلك لا يتم التعمق بشكل كبير في كتابة الكود بل التدريب على التفكير المنطقي والتعرف على علوم الحاسب ومجالات البرمجة وآلية عمل الويب والسيرفرات وقواعد البيانات وخلافه.

    الأمر الذي يؤهلك لإختيار مجال البرمجة الذي تريده على دراية ووعي، أيضًا يجنبك الإحباط عند التعمق ودراسة لغة البرمجة الأولى لك، مثل دورة بايثون أو دورة جافاسكريبت.

    وتستطيع الاستزادة وتعلم ما تريد من خلال المسار الأول في دورة تطوير واجهات المستخدم في مسار أساسيات تطوير الويب، وأيضًا المسار الأول دورة تطوير التطبيقات باستخدام JavaScript وهو  أساسيات لغة JavaScript، وكل المسارات الأولى من الدورات الأخرى متاحة لك بشكل مجاني.

    وبإمكانك أيضًا البحث على يوتيوب عن مشاريع جافاسكريبت أو بايثون للمبتدئين وستجد الكثير من أجل التطبيق على ما تعلمته، وأيضًا تستطيع البحث عما تريد فهمه، ويوجد شرح كامل لجافاسكريبت وبايثون في أكاديمية حسوب وموسوعة حسوب:

     

  10. يوجد عدة أخطاء في الكود وهي كالتالي:

    1. تم استيراد React مرتين واستخدام useReact مرتين أيضًا، وعليك  باستيراد React مرة واحدة فقط واستخدام useState مرة واحدة.
    2. هناك خطأ في كتابة "useState"، اعتمد على useState وليس usestate.
    3. هناك خطأ في كتابة "useNavigate"، نستخدم useNavigate وليس usenavigate.
    4. الكود يحتوي على ترقيم غير صحيح في الكود الخاص بـ yup.object. يجب أن يكون yup.object() بدلاً من yup object().
    5. في جزء cpassword, يوجد غلق قوس مفقود بعد [yup.ref('password')].
    6. يوجد أخطاء في كتابة الدوال داخل الكود، استخدم useFormik و useState بدلاً من useformik و usestate على التوالي، ويجب أن يكون onSubmit بدلاً من onsubmit.
    7. في دالة register, هناك غلق قوس مفقود بعد if data.message == "succuess".
    8. هناك خطأ في كتابة Console.log، والصحيح هو console.log.

    وإليك الكود بعد تصحيح ما سبق.

    import React, { useState } from 'react';
    import axios from 'axios';
    import { useFormik } from 'formik';
    import { useNavigate } from 'react-router-dom';
    import * as yup from 'yup';
    
    const Register = () => {
      const [errors, setErrors] = useState([]);
      const navigate = useNavigate();
      const [statusErrors, setStatusErrors] = useState('');
    
      const schema = yup.object({
        name: yup.string().required('name is required').min(3, 'min is 3 char').max(10, 'max is 10 char'),
        email: yup.string().required('email is required').email('not valid email'),
        password: yup.string().required('password is required').matches(/^[A-Z][a-z0-9]{4,8}$/, 'not valid password'),
        cpassword: yup.string().required('confirm password is required').oneOf([yup.ref('password')], 'passwords do not match'),
      });
    
      const formik = useFormik({
        initialValues: {
          email: '',
          name: '',
          password: '',
          cpassword: '',
        },
        validationSchema: schema,
        onSubmit: register,
      });
    
      async function register(values) {
        try {
          const { data } = await axios.post('https://lazy-blue-sockeye-gear.cyclic.app/api/v1/auth/signup', values);
          console.log(data);
          if (data.message === "success") {
            console.log("registered");
          }
        } catch (error) {
          console.log(error);
        }
      }
    
      return (
        <div className="container mt-5 pt-5">
          <form className="w-50 m-auto text-center" onSubmit={formik.handleSubmit}>
            <div className="mb-3">
              <label htmlFor="exampleInputEmail1" className="form-label">Email address</label>
              <input
                type="email"
                className="form-control"
                id="exampleInputEmail1"
                value={formik.values.email}
                onChange={formik.handleChange}
                name="email"
                aria-describedby="emailhelp"
              />
            </div>
    
            <div className="mb-3">
              <label htmlFor="exampleInputName" className="form-label">Name</label>
              <input
                type="text"
                className="form-control"
                id="exampleInputName"
                value={formik.values.name}
                onChange={formik.handleChange}
                name="name"
              />
            </div>
    
            <div className="mb-3">
              <label htmlFor="exampleInputPassword1" className="form-label">Password</label>
              <input
                type="password"
                className="form-control"
                id="exampleInputPassword1"
                value={formik.values.password}
                onChange={formik.handleChange}
                name="password"
              />
            </div>
    
            <div className="mb-3">
              <label htmlFor="exampleInputPassword2" className="form-label">Confirm Password</label>
              <input
                type="password"
                className="form-control"
                id="exampleInputPassword2"
                value={formik.values.cpassword}
                onChange={formik.handleChange}
                name="cpassword"
              />
            </div>
    
            <button type="submit" className="btn btn-primary">Submit</button>
          </form>
        </div>
      );
    };
    
    export default Register;

     

  11. تلك مشكلة أخرى في صيغة استعلام SQL الذي يتم تكوينه، وتكمن في طريقة تكوين الجملة WHERE في الاستعلام.

    جرب تعديل السطر التالي:

    cur.execute("SELECT * FROM employee WHERE " + self.se_by.get() + " like '%" + self.se_var.get() + "%'")

    إلى:

    cur.execute("SELECT * FROM employee WHERE {} LIKE '%{}%'".format(self.se_by.get(), self.se_var.get()))

    وذلك لاستخدام التنسيق النصي {} لتضمين قيم المتغيرات في الاستعلام مما يساعد في تجنب أخطاء صيغة SQL ويجعل التعبير أكثر وضوحًا، وتأكد أيضًا من أن أسماء الأعمدة والجداول مكتوبة بشكل صحيح وتطابق قاعدة البيانات لديك.

  12. المشكلة  هي استخدام دالة str() للتحويل إلى سلسلة نصية في الجزء التالي:

    str(self.se_by.get())+" like'% "+str(self.se_var.get())+"%'"

    ويفترض أن self.se_by.get() و self.se_var.get() تعيدان قيمة عددية أو سلسلة نصية، وإذا كانت تلك القيم تعود بالفعل كسلاسل نصية، فلن تحتاج إلى استخدام str() مرة أخرى.

    لذا، عليك بتعديل السطر التالي:

    cur.execute("SELECT * FROM employee WHERE " + str(self.se_by.get()) + " like '% " + str(self.se_var.get()) + "%'")

    إلى:

    cur.execute("SELECT * FROM employee WHERE " + self.se_by.get() + " like '%" + self.se_var.get() + "%'")

    وبالتالي لن يتم تحويل القيم إلى سلاسل نصية مرتين، ويتم تكوين استعلام SQL بشكل صحيح.

    • أعجبني 1
  13. كل من WebRTC و Amazon Kinesis Video Streams هي خيارات جيدة، ولكن تقنية WebRTC هي تقنية مجانية ومفتوحة المصدر تسمح بالاتصال في الوقت الحقيقي بين جهازين أو أكثر، وقابلة للتوسع بشكل كبير، لكن يمكن أن تكون معقدة في إعدادها وصيانتها.

    بالمقابل، Amazon Kinesis Video Streams هي خدمة تديرها Amazon تجعل من السهل بث وتخزين بيانات الفيديو، أيضًا قابلة للتوسع، لكنها قد تكون أكثر تكلفة من WebRTC تبعًا لطريقة الإعداد والاستخدام.

    تعتمد تكلفة Amazon Kinesis Video Streams على كمية البيانات التي ستسخدمها، وكما ذكرت أنت التكلفة لـ 1000 طالب، تترواح ما بين 100 إلى 200 دولار في الشهر، وقد تزيد التكلفة إذا تم تدفق المزيد من البيانات أو إذا كنت بحاجة إلى تخزين البيانات لفترات أطول.

    وفيما يلي بعض العوامل التي يجب مراعاتها عند اختيار بين WebRTC و Amazon Kinesis Video Streams:

    التوسع

    كلا من WebRTC و Amazon Kinesis Video Streams قابلة للتوسع، لكن WebRTC يمكن أن تكون أكثر صعوبة في التوسع لعدد كبير من المستخدمين.

    التكلفة

    Amazon Kinesis Video Streams أكثر تكلفة من WebRTC، لكنها أيضًا أسهل في الإعداد والصيانة.

    الميزات

    WebRTC يوفر مجموعة أوسع من الميزات من Amazon Kinesis Video Streams، مثل إمكانية مشاركة الشاشة واستخدام اتصالات ند لند.

    وفي حال كنت قلقًا بشأن قابلية التوسع والتكلفة، فإن Amazon Kinesis Video Streams خيار جيد، وبالرغم من ذلك، إذا كنت بحاجة إلى مجموعة أوسع من الميزات، فعليك بالنظر إلى استخدام WebRTC.

    وإليك بعضالحلول البديلة الأخرى التي قد ترغب بأخذها في الإعتبار:

    • Zoom
    • Google Meet
    • Microsoft Teams
    • أعجبني 1
  14. أولاً عليك بنشاء ملف تحكم (Controller) أو ملف خدمة (Service) في مجلد pages/api بمشروع Next.js واسمه يمكن أن يكون likes.ts.

    ثم كتابة دالتين للطلبات POST واحدة لإضافة الـ "like" والأخرى لإزالته، وإليك المثال التالي لملف likes.ts:

    import { NextApiRequest, NextApiResponse } from 'next';
    
    export default function handler(req: NextApiRequest, res: NextApiResponse) {
      if (req.method === 'POST') {
        const { like } = req.body;
    
        if (like) {
          // إضافة "like" بناءً على قيمة `like`
          // انفذ الكود الخاص بإضافة "like" هنا
          res.status(200).json({ message: 'تمت إضافة الـ "like" بنجاح' });
        } else {
          // إزالة "like" بناءً على قيمة `like`
          // انفذ الكود الخاص بإزالة "like" هنا
          res.status(200).json({ message: 'تمت إزالة الـ "like" بنجاح' });
        }
      } else {
        res.status(405).json({ message: 'الطلب غير مدعوم' });
      }
    }

    وفي صفحتك التي تحتوي على زر الـ "like"، قم بإضافة حالة لتتبع حالة الـ "like" وإجراء طلب POST بناءً على الحالة.

    مثال:

    import { useState } from 'react';
    
    export default function LikeButton() {
      const [liked, setLiked] = useState(false);
    
      const handleLike = () => {
        fetch('/api/likes', {
          method: 'POST',
          body: JSON.stringify({ like: !liked }),
          headers: {
            'Content-Type': 'application/json',
          },
        })
          .then((response) => response.json())
          .then((data) => {
            console.log(data.message);
            setLiked(!liked);
          })
          .catch((error) => {
            console.error('حدث خطأ:', error);
          });
      };
    
      return (
        <button onClick={handleLike}>
          {liked ? 'إزالة الـ "like"' : 'إضافة الـ "like"'}
        </button>
      );
    }

    ثم تحديث ملفات الطرق (routes) في مشروع Next.js (مثل pages/index.tsx) لتضمين الزر الخاص بالـ "like" في الصفحة:

    import LikeButton from '../components/LikeButton';
    
    export default function HomePage() {
      return (
        <div>
          <h1>صفحة الموقع</h1>
          <LikeButton />
        </div>
      );
    }
  15.  بإمكانك الإعتماد على الدوال المتوفرة في لغة PHP للاتصال بقاعدة البيانات واستعلامها وإليك مثال بسيط يستخدم لغة PHP وMySQL:

    <?php
    // اتصال بقاعدة البيانات
    $servername = "اسم_خادم_قاعدة_البيانات";
    $username = "اسم_مستخدم_قاعدة_البيانات";
    $password = "كلمة_مرور_قاعدة_البيانات";
    $dbname = "اسم_قاعدة_البيانات";
    
    $conn = new mysqli($servername, $username, $password, $dbname);
    
    // التحقق من اتصال قاعدة البيانات
    if ($conn->connect_error) {
        die("فشل الاتصال بقاعدة البيانات: " . $conn->connect_error);
    }
    
    // إدراج السجل في قاعدة البيانات
    $sql = "INSERT INTO اسم_الجدول (حقل1, حقل2, حقل3) VALUES ('قيمة1', 'قيمة2', 'قيمة3')";
    
    if ($conn->query($sql) === TRUE) {
        // الاستعلام الناجح
    
        // استعراض آخر معرف ID تم إدراجه
        $last_inserted_id = $conn->insert_id;
        echo "تم إدراج السجل بنجاح. العنصر الأخير المُدرَج له ID: " . $last_inserted_id;
    } else {
        echo "خطأ في الإدراج: " . $conn->error;
    }
    
    // إغلاق اتصال قاعدة البيانات
    $conn->close();
    ?>

    قمت بإنشاء اتصال بقاعدة البيانات، ثم يتم إجراء استعلام INSERT لإدراج السجل في الجدول، وإذا تم الإدراج بنجاح، واستخدام الدالة $conn->insert_id لاستعراض آخر معرف ID تم إدراجه، ومن ثم عرضه في الصفحة.

    استبدلي "اسم_خادم_قاعدة_البيانات" و"اسم_مستخدم_قاعدة_البيانات" و"كلمة_مرور_قاعدة_البيانات" و"اسم_قاعدة_البيانات" بالقيم الصحيحة لخادم قاعدة البيانات الذي تستخدمه ومعلومات اعتماد الوصول لديك، وأيضًا استبدال "اسم_الجدول" و "حقل1" و "حقل2" و "حقل3" بالأسماء الصحيحة للجدول والحقول المراد إدراج البيانات فيها.

  16. سببه أنك تحاولين إضافة أو تحديث صف مرتبط بقيد أب (foreign key) ولكن القيد الأب غير موجود في الجدول المرجع (referenced table) أو عندما يتعارض العمل بتحديث القيد الأب مع قيد الابن (child key) المرتبط به

    ورسالة الخطأ تعني إلى أنه لا يمكنك إضافة أو تحديث صف في جدول doctor لأنه يتضمن قيد أب مرتبط بجدول employes والقيد الأب (user_id) المحدد غير موجود في جدول employes.

    وربما تكون قيمة user_id التي تحاولين إضافتها غير موجودة في جدول employes، أو تحاولين تحديث قيمة user_id التي تشير إلى قيد غير موجود في جدول employes.

    لذلك تحققي من وجود قيمة user_id في جدول employes المشار إليه في الخطأ، وتأكدي من أن القيد الأب المحدد موجود بالفعل في الجدول المرجع.

    وفي حال كانت القيمة موجودة في جدول employes، تحققي من نوع البيانات لحقل user_id في جدول doctor ومن أنه يتوافق مع نوع البيانات في حقل U_id في جدول employes، حيث يجب أن يكون نوع البيانات والطول والتنسيق متطابقين.

    أيضًا التأكد من أن لديك الصلاحيات الكافية لإضافة أو تحديث الصفوف في جدول doctor وجدول employes.

    وربما السبب هو أنه هناك تعارض في العلاقة بين الجدولين، فتحققي من القيود (constraints) الموجودة على العلاقة بين الجدولين وتأكد من أنها معرفة بشكل صحيح وتتوافق مع البيانات الموجودة.

  17. بتاريخ الآن قال Hadi255:

    نفس الخطأ لم يتغير شيء

    من الأفضل قراءة المستند الرسمي وتطبيق الشرح على مشروعك:

    https://vuejs.org/guide/reusability/custom-directives.html

    وأيضًا هناك دليل عن كيفية الإنتقال من vue 2 إلى vue 3 :

  18. بتاريخ الآن قال Hadi255:

    شكرا لك على الإجابة ، لكنه لم يعمل و ظهر لي خطأ لم أستطع فهمه واختفت الصفحة بسبب الخطأ :

    runtime-dom.esm-bundler.js:13 Uncaught TypeError: Cannot read properties of null (reading 'parentNode')
        at remove (runtime-dom.esm-bundler.js:13:26)
        at performRemove (runtime-core.esm-bundler.js:6257:7)
        at remove2 (runtime-core.esm-bundler.js:6271:7)
        at unmount (runtime-core.esm-bundler.js:6226:9)
        at Object.remove (runtime-core.esm-bundler.js:6592:11)
        at unmount (runtime-core.esm-bundler.js:6205:20)
        at unmountChildren (runtime-core.esm-bundler.js:6314:7)
        at unmount (runtime-core.esm-bundler.js:6215:9)
        at unmountComponent (runtime-core.esm-bundler.js:6294:7)
        at unmount (runtime-core.esm-bundler.js:6195:7)
    remove @ runtime-dom.esm-bundler.js:13
    performRemove @ runtime-core.esm-bundler.js:6257
    remove2 @ runtime-core.esm-bundler.js:6271
    unmount @ runtime-core.esm-bundler.js:6226
    remove @ runtime-core.esm-bundler.js:6592
    unmount @ runtime-core.esm-bundler.js:6205
    unmountChildren @ runtime-core.esm-bundler.js:6314
    unmount @ runtime-core.esm-bundler.js:6215
    unmountComponent @ runtime-core.esm-bundler.js:6294
    unmount @ runtime-core.esm-bundler.js:6195
    unmountChildren @ runtime-core.esm-bundler.js:6314
    unmount @ runtime-core.esm-bundler.js:6215
    unmountChildren @ runtime-core.esm-bundler.js:6314
    unmount @ runtime-core.esm-bundler.js:6215
    unmountComponent @ runtime-core.esm-bundler.js:6294
    unmount @ runtime-core.esm-bundler.js:6195
    patch @ runtime-core.esm-bundler.js:4991
    render2 @ runtime-core.esm-bundler.js:6332
    mount @ runtime-core.esm-bundler.js:3824
    app.mount @ runtime-dom.esm-bundler.js:1431
    (anonymous) @ main.js?t=1688563145513:50
    Show 20 more frames

    هل يمكنك تجريب ذلك و ينجح معك

    هناك مشكلة تحدث عند إزالة العنصر من DOM، جرب تعديل الكود في ملف directives.js واستخدام الخاصية beforeUnmount بدلاً من unmounted في كود الـ custom directive.

    أي في ملف directives.js، قم بتعديل الكود ليصبح كالتالي:

    // directives.js
    
    import { createApp } from 'vue'
    import App from './App.vue'
    
    const app = createApp(App)
    
    // global Custom Directive 
    app.directive('globalexternal', {
      beforeUnmount: function (el) {
        el.placeholder = ''
      },
      mounted: function (el) {
        el.placeholder = 'Global Custom Directive from external file'
      }
    })
    
    console.log('Global Custom Directive from external file')
    
    export default app

     

  19. يجب تحويل قيمة الـ prompt إلى رقم حيث أن القيمة العائدة منه هي نص، وهناك أكثر من طريقة لفعل ذلك، الأولى هي بوضع علامة + بجانب prompt أي كالتالي:

    let x = +prompt('أدخل رقم من المصفوفة')

    وسيتم تحويل القيمة المدخلة إلى رقم.

    والطريقة الثانية هي باستخدام دالة parseInt كالتالي:

    let x = parseInt(prompt('أدخل رقم من المصفوفة'));

    والطريقة الثالثة هي باستخدام دالة Number وانتبه إلى أن حرف الـ N كبير لكونها constructor أي دالة بانية  ولكننا نستخدمها كدالة هنا لتحويل النص إلى الرقم كالتالي:

    let x = Number(prompt('أدخل رقم من المصفوفة'));
  20. في Vue 3، هناك بعض التغييرات في استخدام custom directives مقارنةً بـ Vue 2، وتستطيع تحقيق ما تريده عن طريق التالي:

    في ملف directives.js، يجب تصدير الـ custom directive مباشرة بدون استخدام دالة glob()، وذلك لأنك ستقوم بتصدير الـ directive ذاتها، وليس دالة لتسجيل الـ directive:

    // directives.js
    
    import { createApp } from 'vue'
    import App from './App.vue'
    
    const app = createApp(App)
    
    // global Custom Directive 
    app.directive('globalexternal', {
      mounted: function (el) {
        el.placeholder = 'Global Custom Directive from external file'
      }
    })
    
    console.log('Global Custom Directive from external file')
    
    export default app

    وفي ملف main.js، قم بتصدير ما يتم استيراده من ملف directives.js ثم تشغيل التطبيق:

    // main.js
    
    import { createApp } from 'vue'
    import App from './App.vue'
    import directivesApp from './directives'
    
    const app = createApp(App)
    
    directivesApp.mount('#app')
    app.mount('#app')

    وفي ملف App.vue، قم بتطبيق الـ custom directive المستورد باستخدام v-globalexternal:

    <!-- App.vue -->
    
    <template>
      <input v-globalexternal style="width: 370px" />
    </template>
    
    <script>
    export default {
      // ...
    }
    </script>

    ومن المفترض أن يعمل الـ custom directive بشكل صحيح في تطبيق Vue 3 لديك، وانتبه إلى أنه في Vue 3 لم يعد هناك حاجة لاستدعاء الـ custom directive في الملف main.js مثلما كان في Vue 2، بل تستطيع تسجيلها مباشرة في الملف directives.js.

  21. أولاً أنت لم  تستخدم دالة isNaN بشكل صحيح وأيضًا لديك مشكلة أخرى هي عدم تحديث قيمة المتغير total بشكل صحيح.

    بالإضافة إلى أنك استخدمت علامة التنصيص العادية ' ' ونضع بداخلها نص فقط، أما إذا أردت استخدام متغير فأرجو منك استخدام Template literals أو قوالب النصوص وهي علامة التنصيص المائلة ` ` وتصل إليها من حرف ذ في الكيبورد لكن يجب أن تكون لوحة المفاتيح باللغة الإنجليزية وليس العربية، وإليك شرح لقوالب النصوص:

    أرجو منك كتابة الكود كالتالي:

    let total = 0;
    
    while (true) {
        let value = +prompt('Enter a number');
        if (value == 0) break;
        if (isNaN(value)) continue;
        total += value;
    }
    
    alert(`Your total number is: ${total}`);
    • قمت بإصلاح استخدام دالة isNaN عن طريق إضافة قوسين بعد اسم الدالة وإضافة قيمة value.
    • ثم تحديث المتغير total عندما يتم إدخال رقم صالح عن طريق إضافة القيمة value إليه.
    • استخدام قالب النص بدلاً من علامة التنصيص العادية

    وسيتم سؤالك عن إدخال رقم بشكل لا نهائي لأننا وضعنا شرط true في while، وإذا ضغط على cancel أثناء إدخال الرقم سيتم عرض مجموع ما قمت بإدخاله سابقًا.

    • شكرًا 1
  22. بخصوص odoo ستجد ما تريده في المحتوى الأجنبي أرشح لك قناتي odoo mates  و Odoo Discussions وأيضًا يوجد قائمة مفيدة باسم Odoo Website & E-Commerce في قناة Concept Solutions.

    أيضًا قناة odoo الرسمية بها شروحات مفيدة، ابحث مثلاً عن Build an ecommerce website with Odoo.

    أيضًا يوجد المستند الرسمي:

    وتستطيع البحث في جوجل عن المزيد.

    • شكرًا 1
  23. هل تواجه مشكلة أو صعوبة في أمرًا ما، تستطيع طرح المشكلة ليتم مساعدتك.

    وبخصوص الأمور المالية أو تغيير الدورة أو الاسترجاع، فعليك بالتحديث إلى مركز المساعدة الخاص بأكاديمية حسوب من خلال الرابط التالي:

    ثم أدخل البريد الخاص بحسابك الذي اشتركت من خلاله بالدورة، وسيصلك كود تفعيل على البريد أرجو منك إدخاله وستظهر لك نافذة المحادثة، اشرح بها ما تريد وسيتم الرد عليك خلال 24 إلى 48 ساعة حيث أنه في بعض الأحيان يوجد ضغط، ولا تقلق بشأن الرد.

  24. أولاً، يجب أن تقوم بتنصيب حزمة إعلانات المكافأة المناسبة من خلال ملف "pubspec.yaml" الخاص بتطبيقك بإضافة حزمة مثل firebase_admob أو admob_flutter وتثبيتها باستخدام أمر flutter pub get.

    ثانيًا، بعد تنصيب الحزمة، عليك أن تنشئ وتكوّن وحدة الإعلانات المكافأة في حسابك على منصة AdMob، حيث ستحتاج إلى استخدام معرف الوحدة الإعلانية الخاصة بالإعلانات المكافأة في تطبيقك.

    ثالثًا، قم بإنشاء عنصر واجهة المستخدم في تطبيقك حيث ترغب في عرض الإعلان المكافأة باستخدام واجهة المستخدم المخصصة لحزمة الإعلانات التي قمت بتنصيبها لإظهار الإعلان، وفي الغالب يكون هناك زر أو تفاعل مستخدم يمكنه استدعاء الإعلان المكافأة.

    أخيرًا، يجب أن تنشيء الإعلان المكافأة في تطبيقك بالإعتماد على وحدة الإعلانات المكافأة لتحديد الإعدادات المرتبطة بالإعلان، مثل الجوائز المحتملة ومدة الفيديو المطلوبة وما إلى ذلك.

    وتأكد من قراءة وثائق الحزمة التي استخدمتها والتعليمات المقدمة بواجهة برمجة التطبيقات (API) الخاصة بمزود الإعلانات الذي تستخدمه، وستحتاج أيضًا إلى اختبار التطبيق للتأكد من عرض الإعلانات بشكل صحيح والتأكد من أن كل شيء يعمل بشكل صحيح.

  25. في البداية يجب إنشاء اتصال بقاعدة البيانات باستخدام مكتبة PDO وتوفير معلومات الاتصال بقاعدة البيانات مثل اسم المستخدم وكلمة المرور واسم قاعدة البيانات ومضيف قاعدة البيانات.

    $servername = "اسم_الخادم";
    $username = "اسم_المستخدم";
    $password = "كلمة_المرور";
    $dbname = "اسم_قاعدة_البيانات";
    
    try {
        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        echo "تم الاتصال بنجاح";
    } catch(PDOException $e) {
        echo "فشل الاتصال: " . $e->getMessage();
    }

    ثم تحديد الجداول التي تحتاج إلى إجراء الإضافة إليها، ولنفترض وجود جدولين: "users" و "doctors".

    ثم استعادة البيانات التي ترغبين في إضافتها إلى جداول المستخدمين والأطباء باستخدام المتغيرات لتخزين القيم المستلمة من الصفحة الخاصة بالمشرف كالتالي:

    $username = $_POST['اسم_المستخدم'];
    $password = $_POST['كلمة_المرور'];
    $role = $_POST['الدور'];

    الآن لنجري عملية الإدخال في كل جدول بالإعتماد على الاستعلامات المعدة مسبقًا (Prepared Statements) لتأمين قاعدة البيانات من هجمات SQL Injection وتسهيل عملية الإدخال.

    try {
        // إضافة إلى جدول المستخدمين
        $stmt = $conn->prepare("INSERT INTO users (username, password) VALUES (:username, :password)");
        $stmt->bindParam(':username', $username);
        $stmt->bindParam(':password', $password);
        $stmt->execute();
    
        // إضافة إلى جدول الأطباء إذا كان الدور طبيبًا
        if ($role == 'طبيب') {
            $stmt = $conn->prepare("INSERT INTO doctors (username) VALUES (:username)");
            $stmt->bindParam(':username', $username);
            $stmt->execute();
        }
    
        echo "تمت الإضافة بنجاح";
    } catch(PDOException $e) {
        echo "حدث خطأ أثناء الإضافة: " . $e->getMessage();
    }

    ولا تنسي إغلاق الإتصال بقاعدة البيانات بعد الانتهاء من العمليات.

    $conn = null; // إغلاق الاتصال بقاعدة البيانات

     

×
×
  • أضف...