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

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

  1. Wael Aljamal

    Wael Aljamal

    الأعضاء


    • نقاط

      14

    • المساهمات

      6975


  2. سامح أشرف

    سامح أشرف

    الأعضاء


    • نقاط

      7

    • المساهمات

      2934


  3. Emad Saif

    Emad Saif

    الأعضاء


    • نقاط

      4

    • المساهمات

      205


  4. محمد عاطف17

    محمد عاطف17

    الأعضاء


    • نقاط

      3

    • المساهمات

      3160


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

المحتوى الأعلى تقييمًا في 08/17/22 في كل الموقع

  1. سلام عليكم لقد قمت بتنصيب ال wordpress على جهازي و بعد ذلك نصّبت ال filezilla ماذا أفعل بعد تنصيب ال filezilla .. لم اعرف ماذا ادخل في حقول ال host وusername و password أرجو ألّا تبخلوا عليّ بأي معلومة...شكرا لكم.
    2 نقاط
  2. قمت بعمل إستمارة Form لإضافة أحد المنتجات في متجر مبني بإستخدام لارافيل Laravel، وفي هذه الإستمارة يجب إختيار تصنيف المنتج Category من بين مجموعة من التصنيفات المخزنة في جدول categories في قاعدة البيانات. كيف يمكنني أن أتحقق أن category_id المرسل ضمن الإستمارة موجود بالفعل في جدول categories؟ هل توجد طريقة للتحقق من وجود مفتاح foreign Key في جدول مختلف وعمل validation عليه في لارافيل Laravel؟ حاليًا أقوم بالتحقق من أنه موجود ضمن الطلب request وأنه عبارة عن رقم: $validator = Validator::make($request->all(), [ // ... 'category_id' => 'required|integer', ]); هل توجد طريقة أفضل من الكود السابق؟
    2 نقاط
  3. هذه ليست مشكله وانما استفسار لماذا الكود في الحاله الاولي يعمل , وفي الحاله رقم 2 لا يعمل اريد ان اعرف متي استخدم الحاله الاولي ومتي استخدم الحاله الثانيه لاني بتلخبط بينهم جدا
    2 نقاط
  4. عمري 12 عام ، هل يمكني الحصول علي الشهاده المعتمدة بلغه python بعد اجتياز الامتحان بنجاح
    1 نقطة
  5. السلام عليكم ورحمة الله وبركاته , احتاج الى طريقة لعمل نموذج استمارة او وصفة طبية تحتوي على بيانات ديناميكية ثم طباعتها . مع العلم اني استعمل مكتبة electrion.js
    1 نقطة
  6. ازاي اربط بين صفحتين في react مثال علي ما اقصده : انا عندي صفحة الhome page و عندي صفحة about كيف اربطهم ببعض
    1 نقطة
  7. بصراحة ليس لدي فكرة عن الأنواع ولا الأسعار
    1 نقطة
  8. الموضوع غريب، مما مقاس الشاشة لديك؟ حاول عمل تصغير أكثر
    1 نقطة
  9. هل يوجد حقل مشترك بين الجداول لنعمل ربط بينهم اي join؟ يمكن عمل استعلام لكل جدول وجلب بياناته، ثم من خلال لغة البرمجة نقوم بدمج هذه القيم كسلسلة نصية و نحشرها في قالب HTML
    1 نقطة
  10. الفكره اني عاوز اعمل حقل يكون في مخرج من 5 جداول يظهر كانها المخرج واحد مثال نعتبر ان احمد في جدول محمود في جدول اخر وابراهيم في جدول اخر عنهم اريد ان اضيف في الحقل احمد محمود ابراهيم يتجمع مع بعض
    1 نقطة
  11. السلام عليكم قاعد اتعلم لغة الdart للflutter و واجهة مشكلة عند ضغط run تجيلي هذا الرسالة
    1 نقطة
  12. معك حق، يبدو أنها غير مشروحة عليك بالدرس التالي ملاحظة هامة: عندما تضع سؤالك أرجو بذل بعض الجهد فيه ليفهم المدرب المشكلة ولا يطرح عدة أسئلة ليصل لصلب الموضوع استخدم محرر الشيفرات لوضع الأكواد البرمجية
    1 نقطة
  13. التعليق غير مفيد ولا يشرح المشكلة، عليك ذكر التفاصيل كاملة. المثال السابق لتفهم أنه عليك بناء مكون يعرض الروابط من خلال Link يمكنك وضعه في nav ثم ربط المسارات مع عرض المكونات بالاستعانة ب Route الموضوع مشروح في الدورة، حبذا لو تعيد الدروس لفهم أفضل. شكرا لك
    1 نقطة
  14. أحاول أن أقوم بتعديل قيمة العمود updated_at في جدول users في كل مرة يقوم المستخدم بتسجيل الدخول، وقمت بكتابة الكود التالي: $user = Auth::user(); $user->updated_at = DB::raw('NOW()'); $user->save(); من المفترض الآن أن يتم تعديل قيمة updated_at ولكن ما يحدث هو ظهور الخطأ التالي: InvalidArgumentException A four digit year could not be found Data missing ولا يتم تعديل قيمة updated_at على الإطلاق. ما معنى هذا الخطأ؟ وما المشكلة هنا؟
    1 نقطة
  15. كما تعلم، كل صفحة ويب في React عبارة عن مكون Component ويتم تبديل المكون الذي يتم عرضه في الصفحة من خلال نظام التوجيه Route ومكتبة React Router التي تعتمد على شريط العنوان URL الصفحة الرئيسية App.js تستورد جميع المكونات تقوم بتعريف المسارات import ReactDOM from "react-dom/client"; import { BrowserRouter, Routes, Route } from "react-router-dom"; // تضمين المكونات و الصفحات import Layout from "./pages/Layout"; import Home from "./pages/Home"; import Blogs from "./pages/Blogs"; import Contact from "./pages/Contact"; import NoPage from "./pages/NoPage"; export default function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Layout />}> <Route index element={<Home />} /> <Route path="blogs" element={<Blogs />} /> <Route path="contact" element={<Contact />} /> <Route path="*" element={<NoPage />} /> </Route> </Routes> </BrowserRouter> ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />); ويتم تعريف المسارات ضمن المكون Link ليعبر لنا عن رابط معين مع الاسم الذي سيظهر import { Outlet, Link } from "react-router-dom"; const Layout = () => { return ( <> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/blogs">Blogs</Link> </li> <li> <Link to="/contact">Contact</Link> </li> </ul> </nav> <Outlet /> </> ) }; export default Layout; الآن عند الضغط على الرابط، سيتم تغيير عنوان URL للصفحة، و بالتالي إعادة اختبار أي مكون يجب أن يتم عرضه من بين Routes
    1 نقطة
  16. هل هناك طريقة لإعداد الجلسات sessions بحيث تنتهي صلاحيتها بعد وقت معين. أعتقد أن لارافيل Laravel ينهي الجلسة بعد 30 دقيقة تقريبًا وأريد زيادة هذه المدة لفترة أطول، لكن لا يمكنني العثور على أي أماكن في لارافيل Laravel لضبط مثل هذه القيمة هل يمكن عمل هذا الأمر في لارافيل Laravel؟ أم يجب أن أقوم بعمل نظام إستيثاق بالكامل من الصفر للتحكم في هذا الأمر؟
    1 نقطة
  17. بالتأكيد، لا مشكلة بالنسبة للعمر، عليك فقط أن تنهي مسارات الدورة (أربع مسارات على الأقل) وتقوم بإتمام المشاريع الخاصة بها ورفعها على GitHub لمراجعتها وبعد ذلك يجب أن تخضع لأداء الإمتحان وفي حالة إجتيازه بنجاح ستحصل على شهادة بإسمك على الفور. يمكنك معرفة هذه الأمور وأكثر من خلال مركز المساعدة الخاص بالأكاديمية من هنا.
    1 نقطة
  18. الطريقة تعتمد على الكود الخاص بال HTML فإن التلاعب بعناصر ال DOM تعتمد بشكل أساسي على طريقة كتابة ال HTML فالطريقة الثانية تستخدم إن كان العنصر الذي يتم الضغط عليه هو ما نريد ان نقوم بحذف ال class الخاص به . بينما الطريقة الأولى إن لم يكن نفس العنصر الذي تم الضغط عليه
    1 نقطة
  19. كل واحده من هاتين الطريقتين متي يتم استخدامها و لاني لا اعلم حالات استخدام الطريقه 1 وطريقه2
    1 نقطة
  20. أهلا مجدداً أحمد، الملف معقد وفيه العديد من الحقول والقيم المتفاوتة، لن أتمكن من مساعدتك يمكنك توظيف مختص بملفات إكسيل من موقعي خمسات أو مستقل لإعادة تصميم الجدول لديك و من ثم يصبح عمل تخصيص له و الحسابات أسهل وأفضل والملف بشكل عام أوضح شكرا لك
    1 نقطة
  21. كيف أستطيع تغيير اسم المرسل (كما في الصورة المرفقة)؟
    1 نقطة
  22. عليك أولا تفعيل ميزة Alphanumeric Sender ID بالخطوات: تسجيل الدخول للوحة التحكم www.twilio.com/console. في القائمة اليسرى اختر Programmable SMS. اضغط Settings. تأكد من تفعيل "Alphanumeric Sender ID" is set to Enabled. ثم عليك التأكد من أن الدولة قد تم تفعيل هذه الميزة فيها من هنا ثم يمكنك التعديل على الاستمارة مع وضع الحقل From باسم الشركة لديك / التطبيق curl -XPOST https://api.twilio.com/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json \ -d "Body=Hello there" \ -d "To=+12685551234" \ -d "From=MyCompany" \ -u 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token' هذه الخطوات مذكورة في توثيقهم الرسمي من هنا: personalize-sms-alphanumeric-sender-id
    1 نقطة
  23. - خدمة (Verify - OTP) - وضعت جميع الإعدادات المطلوبة - sid - messaging_service_id - token - from - otp_template ووصلت الرسالة كما في الصورة
    1 نقطة
  24. هل يمكنك إرفاق الملف أو جزء منه لأستطيع محاولة ربط الحقول لديك؟ لأنه يجب أن أعرف كيفية تسجيل عدد ساعات الدوام وحساب الأمور
    1 نقطة
  25. جرب التالي: $result = $query->fetchAll(\PDO::FETCH_ASSOC); لأو while($row = $query->fetch()) { $result[] = [ 'newname' => $row['oldname'], // etc ]; }
    1 نقطة
  26. ما هي البيانات؟ اكتب عدة نتائج متتالية (عدة أسطر) كمثال وليس سطر واحد لأفهم عليك
    1 نقطة
  27. الله يبارك فيك يا أستاذ ويجزيك الخير
    1 نقطة
  28. وعليكم السلام . إن قمت بتنصيب الملفات علي جهازك فإنك لن تحتاج إلي filezilla لأنه يستخدم لمشاركة الملفات بين الخوادم . وبما أن الملفات علي جهازك فأنت تسطيع الوصول إليها دون إستخدام أى برامج . ومن الواضح انك تستخدم برنامج xampp كمضيف لملفاتك فستجد الملفات الخاصة بك في هذا المسار C:\xampp\htdocs أو في المسار الذى قمت بتنصيب البرنامج فيه ثم htdocs .
    1 نقطة
  29. للتواصل مع الخادم يجب أن تمتلك معلومات حساب على لك ذلك الخادم، وهي اسم المستخدم الخاص بك وكلمة المرور لذلك الحساب، ويجب أن تملك عنوان IP للخادم ورقم المنفذ لبروتوكول FTP على ذلك الخادم، بعد جمع تلك المعلومات يمكنك إدخالها كالتالي وتهيئة عملية الاتصال للمباشرة بنقل الملفات من وإلى الخادم: Host عنوان الخادم، إما اسم نطاق Domain name أو عنوان IP Username اسم المستخدم لحسابك على الخادم Password كلمة السر للحساب Port رقم منفذ بروتوكول FTP على الخادم عادة يكون المنفذ رقم 21 يمكنك الاستفادة من قراءة المقالات التالية:
    1 نقطة
  30. السؤال لايفيد في معرفة المشكلة، أرجو إضافة كامل التفاصيل مع مثال لنستطيع إرشادك بصورة صحيحة
    1 نقطة
  31. نجلب البيانات من خلال استعلام نعرف القيم في المصفوفة من كائن نتيجة الاستعلام نحدد نمط إرجاع من FETCH_ASSOC بالتالي ستكون $result لها نفس الهيكلية التي تبحث عنها <?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDBPDO"; try { $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); $stmt = $conn->prepare("SELECT * FROM table"); $stmt->execute(); $result = $stmt->setFetchMode(PDO::FETCH_ASSOC); if ($result->num_rows > 0) { $EN = $result; // أو $EN=[ 'main'=> $result["main"], 'view_reports'=> $result["view_reports"], 'preferred_lang'=> $result["preferred_lang"], 'success'=> $result["success"], ]; } } catch(PDOException $e) { echo "Error: " . $e->getMessage(); } $conn = null; هنا تأكد من اسم الجدول، و شرط الاستعلام
    1 نقطة
  32. بالطبع أغلب المواقع ذات الأمان العالي تقوم بفحص زائر الصفحة هل هو قادم من Script برمجي أم من متصفح تستخدم هذه المواقع حماية عن طريق الإعتماد على نوع المتصفح User-Agent مثال للUser-Agent لمتصفح firefox : USER_AGENT = "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1" فنحن نقوم بالإحتيال على الموقع الذي نريد سحب البيانات منه بإخباره برمجياً أننا قادمون من متصفح للإنترنت فعندها لا يقوم بمنع عملية التصفح وسحب البيانات هذه طريقة للتخطي. هناك اُطر عمل لسحب البيانات تساعد على تخطي فحص ال User-Agent مثل إطار العمل Scrapy.
    1 نقطة
  33. لقد كتبت عنصر الـ html بشكل خاطئ : <input type="time" id= "timeSyart > <!-- والصحيح هو --> <input type="time" id= "timeSyart" > ويمكن اضافة القيمة المضافة لمتغير بالشكل التالي : <input type="time" id="timeSyart" /> <script> // نعرف المتغير let myTime; // input نقوم بجلب الـ const myTimeInput = document.getElementById("timeSyart") //input نضيف وظيفة لتحدث عند تغير قينة ال myTimeInput.addEventListener("change", function (e) { //للمتغير input نقوم بإسناد قيمة الـ myTime = e.target.value console.log(myTime); // سيطبع الوقت الذي يتم اختياره }) </script> ويمكنك المعرفة اكثر عن معالجة الاحداث في جافاسكريبت من هنا
    1 نقطة
  34. يمكنك إستخدام getElementById للحصول علي العنصر . ولإستخدام القيمة المختارة بواسطة العنصر يمكنك إستخدام .value document.getElementById("timeSyart").value ويمكنك إستخدام الأحداث وبهذا تستطيع تنفيذ ما تريد كلما تم إختيار أو تعديل الوقت . document.getElementById("timeSyart").addEventListener("input", (event)=>{ // هنا نقوم بكتابة الكود وسوف يتم تنفيذه كلما تم إختيار الوقت event.target.value // للحصول على قيمة الوقت });
    1 نقطة
  35. لا يزال الجدل قائمًا حول نوعية العمل الملائمة أكثر، فنجد البعض مؤمنًا بأفضلية العمل الحر؛ وعلى النقيض تمامًا، يؤمن بعضهم بأفضلية العمل الوظيفي. وقد شاعت مؤخرًا اعتقادات تصف الوظيفة بالعبودية، وتدعو إلى التوجه نحو العمل الحر. وتكمن بعض الأسباب وراء تلك الاعتقادات في تحكّم بعض رؤساء العمل بالموظفين، ودخل الوظيفة المحدود، وكذلك طول ساعات العمل. فهل حقًا الوظيفة عبودية؟ وما هي محاسن ومساوئ كلٍّ من العمل الوظيفي والعمل الحر؟ دعنا أولًا نتعرف على الفرق ما بين العمل الوظيفي والعمل الحر. الفرق بين العمل الوظيفي والعمل الحر المقصود بالعمل الوظيفي هو أن تعيّن شركةٌ ما شخصًا ما؛ لأداء عدد من المهام، مع الالتزام التام بإنجازها ضمن ساعات عمل محددة، وذلك على النحو الذي يحدده صاحب العمل، ويتقاضى الشخص أجرًا ثابتًا مقابل ذلك؛ أما العمل الحر، فهو أن يعمل الشخص لحسابه الخاص، ولشركات مختلفة على حسب المطلوب، دون الالتزام بساعات عمل محددة. يكمن الفرق الأساسي بين الوظيفة والعمل الحر في أن الشخص في الوظيفة يعمل تحت إشراف شخص آخر ضمن قيود عمل والتزامات محددة، بينما يكون سيّد نفسه في العمل الحر، ويعمل دون أيّة قيود تفرضها عليه مكاتب العمل؛ ناهيك عن الكثير من الفروق الأخرى التي تجعل الكثيرين يفضلون طبيعة العمل المستقل، لأنهم رؤساء أنفسهم، وأحرارٌ في اتخاذ قراراتهم بأنفسهم، ولا أحد يملي أوامره عليهم. محاسن العمل الوظيفي هناك العديد من المزايا التي تجعل من العمل الوظيفي خيارًا مفضلًا للكثيرين. تعزّز تلك المزايا الرضا الوظيفي لدى الموظفين، وبالتالي تزيد من إنتاجيتهم وكفاءة عملهم. سنذكر أهم تلك المزايا في السطور القادمة. 1- الأمن الوظيفي يتمتع الموظف بالاستقرار من الناحية المالية، حيث يحصل على راتب منتظم ومتوقَّع كل شهر، والذي يمكنه الاعتماد عليه في بناء خططه المستقبلية، وبالتالي ليست هناك حاجة للقلق بشأن عدم الحصول على الأجر أو الفصل من العمل. في حال تعرّض الموظف للفصل، فعادةً ما يُنذَر من قبل رئيس العمل قبل ذلك بفترة، ويُعوَّض عن ذلك. لكل وظيفة تشريعاتها التي تحمي مستقبل الموظف من خطر وقوع أية مشاكل محتملة من شأنها أن تهدّد أمنه الوظيفي. 2- الاستقرار يكون نظام العمل في الوظيفة واضحًا وجليًّا منذ البداية، كما توفر الوظيفة للموظف جدول عمل محدد ضمن مساحة عمل محددة، الأمر الذي يخلق لديه شعورًا بالاستقرار. 3- استحقاقات الموظفين توفر الوظيفة لصاحبها عدة مزايا ينتفع بها، مثل: الإجازات مدفوعة الأجر، والإجازات المرضية، وإجازة الأمومة، والتأمين الصحي، وخطة التقاعد، والحصول على معاش بعد التقاعد، والضمان الاجتماعي، وغيرها. هذا ما يجعل الحياة أفضل بكثير للموظف بالنسبة لصحته وأسرته. 4- امتيازات خاصة إلى جانب الانتفاع بالامتيازات الأساسية التي ذُكرَت سابقًا تحت بند استحقاقات الموظفين، ينتفع الموظف بعدد من الامتيازات الخاصة، مثل الاشتراكات المجانية في النوادي الرياضية، والهدايا، والحصول على خصومات تغطي قطاعات محددة، كالمقاهي. ومن تلك الامتيازات أيضًا الحصول على ترقيات، وبعثات دراسية، وحضور تدريبات ودورات تنظّمها الشركة من شأنها تطوير مهارات الموظف. 5- بناء شبكة اجتماعية تتيح طبيعة العمل الوظيفي للموظفين تكوين علاقات اجتماعية مع زملائهم. يأتي هذا من منطلق أنهم يعملون معًا يوميًا في نفس المنشأة، وبالتالي بإمكانهم تكوين صداقات طويلة الأمد مع بعضهم البعض. وتلعب الشركة دورًا كبيرًا في ذلك من خلال تنظيمها لرحلات للموظفين، وجلسات في المناسبات الاجتماعية، وعقدها لدورات وبرامج تدريبية. مساوئ العمل الوظيفي على الرغم من تلك المزايا الرائعة للعمل الوظيفي، إلا أننا نجد له بعض العيوب أيضًا، ومنها: 1- السيطرة والتحكم للموظف رئيسٌ يخبره بما عليه فعله ضمن قواعد محددة، أي أن لديه سيطرةً أقل على عمله، في حين يتمتع المستقل بالسيطرة الكاملة على عمله بما يشمل نواحٍ عديدة، مثل وضع جدول زمني للعمل كما يريد، والحرية المطلقة في قبول تعليمات العمل من رفضها. 2- جبروت رؤساء العمل مع الإشارة إلى أن هذا الوصف لا ينطبق على جميع الوظائف، ولا على جميع الشركات، إلا أن أحد أهم أسباب تشبيه الوظيفة بالعبودية هو جبروت رؤساء العمل، فمنهم مَن يُعامل موظفيه كأنهم عبيد لديه، بحيث ليس من حقهم الاعتراض على أوامره أو مناقشتها، وليس هناك الكثير ممّا يمكنهم تغييره أو تحسينه. أي أن الموظف مقيّد برئيسه، ويعتمد على قرار رئيسه وسياساته في سير العمل. 3- ساعات عمل طويلة قد تزيد عدد ساعات العمل الوظيفي عن 8 ساعات يوميًا في سبيل تحقيق الأهداف المهنية، والحصول على راتب شهري ثابت. ومن هنا نستنتج أن العمل يستهلك معظم الوقت، ما يخلق شعورًا بعدم وجود توازن بين العمل والحياة، فالوقت ثمين، وهو أهم ما يمكن للشخص أن يمتلكه. وتجدر الإشارة هنا إلى أنه كلما زادت عدد ساعات العمل، قلت كفاءة العمل، وقلت قدرة الموظف على الإنتاج. 4- دخل محدود أحد مساوئ العمل الوظيفي هو الدخل الثابت غير القابل للزيادة والرضا بذلك دون ترقية أو أي تغيير يُذكر، ناهيك عن قلة راتب بعض الموظفين في بعض الأقسام الوظيفية، فيجد الموظف نفسه حبيس تلك الوظيفة وذلك الراتب طوال حياته، مع صعوبة تحصيل عمل آخر جانبي من شأنه تحسين دخله. 5- الخوف المستمر من عقوبات العمل كما ذكرنا سابقًا، إن سيطرة وتحكم صاحب العمل بالموظف تجعله مجبرًا على تنفيذ المطلوب دون اعتراض، وهذا لا ينطبق على جميع الشركات ورؤساء الأعمال بالتأكيد، لكنّ المستبدّين منهم يُولّدون خوفًا مستمرًا لدى الموظفين من فرض عقوبات عليهم أو حتى الفصل من العمل ككُل إن لم ينجزوا المهام على الهيئة المطلوبة. هذا ما يهدّد أمن حياتهم بفقدان مصدر رزقهم الوحيد. 6- قد تكون الوظيفة مقبرة للإبداع والطموح عندما يعمل الموظف لصالح مَن لا يُقدّر جهده المبذول؛ فإنه لن يعمل بأفضل ما عنده، ولن يُبدع في عمله. وإذا كانت الوظيفة ضد فطرة الإنسان، ولم تعطِه حق الإبداع، فهي ليست الخيار المناسب له. محاسن العمل الحر بما أن العمل الحر لا يتطلب شهادات علمية؛ فمن السهل على الشخص اختيار المجال الذي يرغبه بناءً على اهتماماته وخبراته. إذًا ما هي فوائد العمل الحر التي من شأنها تشجيع ذلك الشخص على البدء به؟ 1- الحرية الكاملة لمن يرغب في أن يكون رئيسًا لنفسه، وأن يملك الحرية المطلقة في اختيار العمل الذي يريده والعميل الذي يريده، العمل الحر هو الخيار الأفضل، مع إمكانية العمل لدى عدة عملاء في نفس الوقت، فلا قيود أو قوانين ثابتة على المستقل اتباعُها، وبإمكانه اتخاذ جميع القرارات بنفسه، بالتالي تكون لديه كامل السيطرة على العمل. 2- المسؤولية الذاتية من محاسن العمل الحر أن التقييم فيه ذاتي، فالمستقل هو المسؤول عن تقييم نتائج عمله ومشاريعه ودخله، إذ لن تكون لديه أية فرصة للاختباء خلف غيره عندما يتعلق الأمر بالوفاء بالمواعيد النهائية أو جودة العمل. ويحدِّد تقييم العملاء مدى التزام المستقل وخبرته في مجال عمله، حيث تعدّ التقييمات الجيدة في مجال العمل الحر أكثر قيمةً من المال، فهي تجلب للمستقل وظائف وعملاء جدد، وبالتالي مزيدًا من الأرباح. من خلال تلك التقييمات يبني المستقل لنفسه اسمًا وسمعة، فيصل إلى أهدافه المهنية المرجوّة. 3- مرونة متطلبات العمل ليست هناك حاجة لتخصيص مساحة عمل بعينها أو ساعات عمل محددة، فالعمل الحر مرن بطبيعته، ففي الوقت الذي تبدأ فيه بالعمل الحر، تصبح الكرة في ملعبك. يمكن للمستقل العمل من أي مكان، وفي أي وقت تحب، وأخذ قسط من الراحة عندما يستلزم الأمر، بالتالي يستطيع الموازنة بين العمل والحياة؛ ولكن تنبغي الإشارة هنا إلى أهمية ترتيب الأولويات، ومحاولة السيطرة على سير العمل بشكل جيد. مرونة ساعات العمل لا ينبغي لها أن تجعل من المستقل متكاسلًا تاركًا المهام الموكلة إليه إلى الساعة الأخيرة؛ لأن العواقب في النهاية ستكون وخيمة بالتأكيد. 4- مصدر دخل غير محدود إحدى أهم الميزات التي تُشجع المرء على التوجه نحو مجال العمل الحر هي عدم وجود حدٍّ للدخل الممكِن كسبه، فمَن يمتلك مهارات متنوعة، يستطيع العمل على مشاريع متعددة في نفس الوقت، وبالتالي تتعدّد مصادر دخله، وإمكانية التحكّم في أرباحه. 5- توسيع آفاق المعرفة نظرًا إلى أن العمل الحر لا يُقيّد صاحبه بمجال معين، فسيكتسب الفرد مهارات جديدة ومتنوعة مع كل تجربة عمل جديدة بحُكم متطلبات العمل المختلفة، فيجد الفرصة سانحةً أمامه لتعلم شيء جديد في كل مرة، وهذا ما يجعل أداءه أفضل مع مرور الوقت، ويزيد من خبراته. والنصيحة الأهم هنا أن يمارس ما تعلمه شيئًا فشيئًا، وينفذه في أعماله القادمة. كما أن ذلك يُولّد لديه طاقة للخوض والتوسّع في مجالات كان يظنها صعبة عليه في أحد الأيام، لذلك على المستقل ألّا يكتفي بالمهارات التي يمتلكها بالفعل، بل عليه أن يعمل على تطوير نفسه باستمرار، وأن يتعرف على نقاط ضعفه، ويعمل على التغلب عليها. 6- بناء مهارات التواصل مع الآخرين يساعد العمل الحر المرء على صقل مهارات الاتصال والتواصل مع الآخرين بما يخدم حاجته في إدارة وإنجاز المشاريع، وإدارة علاقاته مع العملاء، والتأكد من فهمهم له بالشكل الصحيح. التواصل الفعّال هو أساس نجاح أي عمل، خاصةً إن كان عملًا حرًا، حيث يجعله على قدر كبير من الالتزام، ويكسبه مهارات جيدة في إدارة الوقت. كما ويساعد على مشاركة الأفكار مع الطرف المتلقي، بالتالي إمكانية تحويل العملاء المحتملين إلى عملاء مخلصين، أي دائمين، وذلك عبر ترك انطباع جيد لديهم، وكذلك بناء علاقات قوية تزيد من فرصة الحصول على المزيد من العمل في المستقبل، وتحقيق أقصى استفادة ممكنة على صعيد الحياة المهنية المستقلة على المدى البعيد. مساوئ العمل الحر يتطلب العمل الحر تخطيطًا وإعدادًا دقيقًا؛ لذلك قبل البدء به، على المرء أن يكون على دراية بمساوئه وسلبياته التي سنذكر تاليًا بعضها منها. 1- مصدر دخل غير ثابت قد يظل المستقل فترةً غارقًا في العمل، وأخرى دون أي عمل يُذكر، بالتالي لن يكون دخله مستقرًّا، ولن يتمكّن من وضع خطط مستقبلية. إذًا العمل الحر يصعّب على المستقل أمر تنظيم وإدارة شؤونه المالية، خاصةً إن كان في بداياته، إلّا إذا تعددت مصادر دخله بتعدد العملاء الذين يتعامل معهم؛ فسيكون الأمر مختلفًا حينها. 2- انعدام الأمن الوظيفي يفتقر العمل الحر إلى ميزة الأمن الوظيفي، حيث لا يمكن التنبؤ بمستقبله، فقد يصبح عمل اليوم الذي يعتاش عليه المستقل عملًا عاديًا في المستقبل ويقل الطلب عليه، بالتالي يصبح بلا عمل. ولتفادي ذلك، على المستقل مواكبة الطلب في السوق، وتطوير مهاراته، والانفتاح على مجالات جديدة بتوسيع آفاق معرفته. 3- عدم وجود امتيازات وظيفية لا توجد في العمل الحر امتيازات، كما هو الحال في العمل الوظيفي، حيث لا يحصل المستقل على أي نوع من الإجازات مدفوعة الأجر أو معاش بعد التقاعد أو تأمين صحي، كما أن أي دورة تدريبية قد يرغب بحضورها ستكون على نفقته الخاصة. 4- المنافسة شديدة المنافسة في عالم العمل الحر شديدة، وربما يكون هذا أحد أكبر الأسباب التي تثبّط من معنويات المستقلين، خاصةً المبتدئين منهم؛ وذلك لكثرة عدد مقتنصي الفرص. كذلك، يُعَد الأمر مُحبطًا بالنسبة لذوي الخبرة، حيث يتقدّم عدد كبير من عديمي الخبرة بعروضهم للعمل، وفي ظل ذلك يضطر المستقل المحترف لقبول العمل بسعر منخفض، وإلّا يبقى بلا عمل. 5- الاتصال الدائم بالإنترنت العمل الحر بطبيعته قائم على الإنترنت، فهو وسيلة الاتصال بين المستقل والعميل، ومن دونه من الصعب أن ينجح العمل. هذا ما يفرض على المستقل الارتباط الدائم بالعمل، والبقاء متصلًا بالإنترنت خوفًا من فقدان العملاء الحاليّين أو تفويت أي عملاء جدد. هل الوظيفة عبودية فعلا؟ يستند روّاد هذه الفكرة في رأيهم إلى أن الوظيفة تجعل الموظف تحت رحمة رئيس العمل، وبالتالي تُدخِله في حالة الانقياد ومحاولة الحفاظ على الوضع الحالي والخوف من التغيير، فأي تغيير لن يكون مقبولًا، وسيكون الحل أمامه الاستقالة من العمل، وبالتالي فقدان مصدر رزقه؛ لكن، لا أحد يستطيع أن ينكر الخدمة العظيمة التي تقدمها الوظيفة للمجتمع، ودونها لن نجد معلمًا أو مهندسًا أو طبيبًا أو غيرهم ممّن لهم بصمة كبيرة في حياتنا. من هنا نستنتج أن الوظيفة ليست عبودية طالما وفّرت لصاحبها عيشًا كريمًا ضمن ظروف عمل مناسبة تمكّنه من تطوير ذاته وصقل مهاراته وتحمّل مسؤولياته. في الختام في عالم اليوم، قد يكون من الصعب التمييز بين أنواع التوظيف، فقد يتطور العمل الحر إلى وظيفة رسمية، في حين قد يتمتع العمل الوظيفي بظروف عمل مرنة مقارنةً بالعمل الحر. يكمن مفتاح النجاح في التخطيط المناسب، فلا أحد يأمل في ترك عمله مقابل عمل أقل من المرغوب فيه. وتذكر دائمًا، أيًا كان نوع العمل الذي تختاره، سواء عملًا وظيفيًا أو عملًا حرًا، تأكد من أنه النوع الذي يجعلك سعيدًا وتطلق فيه العنان لإبداعك، فإن حرية القيام بالعمل الذي تستمتع به، والشعور بلذة النجاح هو إنجاز بحد ذاته. إلى هنا تكون قد تعرّفتَ على محاسن ومساوئ كلٍّ من العمل الوظيفي والعمل الحر، وعلمتَ أنه من الصعب إثبات أفضلية أحدهما على الآخر. الخطوة التالية هي أن تحدّد مسارك، وتختار نمط حياة العمل الذي يناسبك ويناسب مستقبلك، بناءً على شخصيتك وما تطمح إليه. اقرأ أيضًا هل العمل الحر مناسب لي؟ 9 أسئلة يجب أن تجيب عنها قبل أن تبدأ العمل الحر ما هو العمل الحر وما هي أهم منصّات العمل للمُستقلّين الجانب المُظلم للعمل الحر ... وكيف تجعله أكثر إشراقًا
    1 نقطة
  36. إذا نظرنا إلى التقنيات والأدوات البرمجية المنتشرة، فسنرى أنّ التقنية أو الأداة المشهورة هي التي تُثبت كفاءتها العملية في مجالها، أو التي تتكامل تكاملًا ممتازًا مع تقنية أخرى مستخدَمة بكثرة، وليس لأنها الأجمل أو الأذكى.إرشادات للحل سنناقش هنا إحدى تلك الأدوات التي تدعى بالتعابير النمطية Regular Expressions، وهي طريقة لوصف الأنماط patterns في بيانات السلاسل النصية، إذ تُكوِّن هذه التعابير لغةً صغيرةً مستقلةً بذاتها، لكنها رغم ذلك تدخل في لغات برمجية أخرى مثل جافاسكربت، كما تدخل في العديد من الأنظمة. قد تكون صيغة التعابير النمطية غريبةً للناظر إليها، كما أنّ الواجهة التي توفرها جافاسكربت للتعامل معها ليست بالمثلى، لكن رغم هذا، فتلك التعابير تُعَد أداةً قويةً لفحص ومعالجة السلاسل النصية، كما سيعينك فهمها على كتابة حلول أكفأ للمشاكل التي تواجهك. إنشاء تعبير نمطي التعبير النمطي هو نوع من أنواع الكائنات؛ فإما يُنشأ باستخدام الباني RegExp، أو يُكتب على أساس قيمة مصنَّفة النوع literal value بتغليف النمط بشرطتين مائلتين أماميتين من النوع /. let re1 = new RegExp("abc"); let re2 = /abc/; يُمثِّل كائنا التعبيرات النمطية في المثال السابق النمط نفسه أي محرف a يتبعه b ثم c، ويُكتب النمط على أساس سلسلة نصية عادية عند استخدام الباني RegExp، لذا تطبَّق القواعد المعتادة للشرطات المائلة الخلفية \، على عكس الحالة الثانية التي نرى فيها النمط بين شرطتين مائلتين، إذ تعامَل الشرطات هنا تعاملًا مختلفًا. نحتاج إلى وضع شرطة خلفية قبل أي شرطة أمامية نريدها جزءًا من النمط نفسه، وذلك لأن الشرطة الأمامية تنهي النمط إذا وُجدت. كذلك فإن الشرطات الخلفية التي لا تكون جزءًا من ترميز خاص لمحرف -مثل ‎\n- لن تُتَجاهل كما نفعل في السلاسل النصية، وعليه ستتسبب في تغيير معنى النمط. تملك بعض المحارف مثل علامات الاستفهام وإشارات الجمع مَعاني خاصة في التعابير النمطية، حيث سنحتاج إلى وضع شرطة مائلة خلفية قبلها إذا أردنا لها تمثيل المحرف نفسه وليس معناه في التعابير النمطية. let eighteenPlus = /eighteen\+/; التحقق من المطابقات تملك كائنات التعابير النمطية توابع عديدة، وأبسط تلك التوابع هو التابع test الذي إن مرَّرنا سلسلةً نصيةً إليه، فسيُعيد قيمةً بوليانيةً تخبرنا هل تحتوي السلسلة على تطابق للنمط الذي في التعبير أم لا. console.log(/abc/.test("abcde")); // → true console.log(/abc/.test("abxde")); // → false يتكون التعبير النمطي من محارف عادية غير خاصة تمثِّل -ببساطة- ذلك التسلسل من المحارف، فإذا وُجد abc في أيّ مكان في السلسلة النصية التي نختبرها -ولا يُشترط وجودها في بدايتها-، فسيُعيد test القيمة true. مجموعات المحارف يمكن التحقق من وجود abc في سلسلة نصية باستدعاء التابع indexof. تسمح لنا التعابير النمطية بالتعبير عن أنماط أكثر تعقيدًا، فمثلًا كل ما علينا فعله لمطابقة عدد ما هو وضع مجموعة من المحارف بين قوسين مربعين لجعل ذلك الجزء من التعبير يطابق أيًا من المحارف الموجودة بين الأقواس. لننظر المثال التالي حيث يطابق التعبيران جميع السلاسل النصية التي تحتوي على رقم ما: console.log(/[0123456789]/.test("in 1992")); // → true console.log(/[0-9]/.test("in 1992")); // → true يمكن الإشارة إلى مجال من المحارف داخل القوسين المربعين باستخدام الشرطة - بين أول محرف فيه وآخر محرف، ويُحدَّد الترتيب في تلك المحارف برمز اليونيكود لكل محرف -كما ترى من المثال أعلاه الذي يشير إلى مجال الأرقام من 0 إلى 9-، وهذه الأرقام تحمل رمز 48 حتى 57 بالترتيب في اليونيكود، وعليه فإنّ المجال [0-9]‎‎ يشملها جميعًا، ويطابق أي رقم. تمتلك مجموعة محارف الأعداد اختصارات خاصة بها كما هو شأن العديد من مجموعات المحارف الشائعة، فإذا أردنا الإشارة إلى المجال من 0 حتى 9، فسنستخدِم الاختصار ‎\d. table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } الاختصار الدلالة ‎\d أيّ محرف رقمي ‎\w محرف أبجدي أو رقمي، أي محرف الكلمة ‎\s أيّ محرف مسافة بيضاء، مثل المسافات الفارغة والجداول والأسطر الجديدة وما شابهها ‎\D محرف غير رقمي ‎\W محرف غير أبجدي وغير رقمي ‎\S محرف مغاير للمسافة البيضاء . أيّ محرف عدا السطر الجديد نستطيع مطابقة تنسيق التاريخ والوقت -كما في 01-30-2003 15:20- باستخدام التعبير التالي: let dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/; console.log(dateTime.test("01-30-2003 15:20")); // → true console.log(dateTime.test("30-jan-2003 15:20")); // → false تعيق الشرطات المائلة الموجودة في المثال أعلاه قراءة النمط الذي نعبر عنه، وسنرى لاحقًا نسخةً أفضل في هذا المقال. يمكن استخدام رموز الشرطات المائلة تلك داخل أقواس مربعة، إذ تعني [‎\d.‎] مثلًا أيّ رقم أو محرف النقطة .، لكن تفقِد النقطة نفسها معناها المميز لها إذا كانت داخل أقواس مربعة، وبالمثل في حالة إشارة الجمع +؛ أما إذا أردنا عكس مجموعة محارف، أي إذا أردنا التعبير عن رغبتنا في مطابقة أيّ محرف عدا تلك المحارف التي في المجموعة، فنستخدم رمز الإقحام ^ بعد قوس الافتتاح. let notBinary = /[^01]/; console.log(notBinary.test("1100100010100110")); // → false console.log(notBinary.test("1100100010200110")); // → true تكرار أجزاء من النمط لقد بتنا الآن نعلم كيف نطابق رقمًا واحدًا، لكن كيف سنفعل ذلك إذا أردنا مطابقة عدد يحتوي على أكثر من رقم؟ إذا وضعنا إشارة الجمع + بعد شيء ما في تعبير نمطي، فستشير إلى أنّ هذا العنصر قد يكرَّر أكثر من مرة، بالتالي تعني ‎/\d+/‎ مطابقة محرف رقم أو أكثر. console.log(/'\d+'/.test("'123'")); // → true console.log(/'\d+'/.test("''")); // → false console.log(/'\d*'/.test("'123'")); // → true console.log(/'\d*'/.test("''")); // → true تحمل إشارة النجمة * معنى قريبًا من ذلك، حيث تسمح للنمط بالمطابقة على أي حال، فإذا لحقت إشارة النجمة بشيء ما، فلن تمنع النمط من مطابقته، إذ ستطابق نُسخًا صفرية zero instances حتى لو لم تجد نصًا مناسبًا لمطابقته؛ أما إذا جاءت علامة الاستفهام بعد محرف في نمط، فستجعل ذلك المحرف اختياريًا optional، أي قد يحدث مرةً واحدةً أو لا يحدث. يُسمح للمحرف u في المثال التالي بالحدوث، ويحقق النمط المطابقة حتى لو لم يكن u موجودًا أيضًا. let neighbor = /neighbou?r/; console.log(neighbor.test("neighbour")); // → true console.log(neighbor.test("neighbor")); // → true نستخدم الأقواس المعقوصة إذا أردنا حدوث النمط عددًا معينًا من المرات، فإذا وضعنا {4} بعد عنصر ما مثلًا، فسيجبره بالحدوث 4 مرات حصرًا، ومن الممكن تحديد المجال الذي يمكن للعنصر حدوثه فيه بكتابة {‎2,4‎} التي تشير إلى وجوب ظهور العنصر مرتين على الأقل، وأربع مرات على الأكثر. لدينا نسخة أخرى من نمط التاريخ والوقت، حيث تسمح بذكر الأيام برقم واحد -أو رقمين-، والأشهر، والساعات، إذ تُعَدّ أسهل قليلًا في قراءتها، وهي المثال الذي قلنا أننا سنعود إليه بنسخة أفضل. let dateTime = /\d{1,2}-\d{1,2}-\d{4} \d{1,2}:\d{2}/; console.log(dateTime.test("1-30-2003 8:45")); // → true نستطيع تحديد مجالات مفتوحة عند استخدام الأقواس بإهمال الرقم الموجود بعد الفاصلة، وبالتالي، تعني {‎5,‎} خمس مرات على الأقل. جمع التعبيرات الفرعية إذا أردنا استخدام عامل مثل *، أو + على أكثر من عنصر في المرة الواحدة، فيجب استخدام الأقواس، وسترى العوامل الجزء الذي داخل الأقواس من التعبير النمطي عنصرًا واحدًا. let cartoonCrying = /boo+(hoo+)+/i; console.log(cartoonCrying.test("Boohoooohoohooo")); // → true تطبَّق إشارتا الجمع الأولى والثانية على o الثانية فقط في boo، وhoo على الترتيب؛ أما علامة الجمع الثالثة فتطبَّق على المجموعة كلها (hoo+‎) مطابِقةً تسلسلًا واحدًا أو أكثر بهذا. يجعل محرف i -الذي في نهاية التعبير- هذا التعبير النمطي غير حساس لحالة المحارف، إذ يسمح بمطابقة المحرف B في سلسلة الدخل النصية رغم تكوّن النمط من محارف صغيرة. التطابقات والمجموعات يُعَدّ التابع test أبسط طريقة لمطابقة تعبير نمطي، إذ لا يخبرك إلا بمطابقة التعبير النمطي من عدمها وفقط، كذلك تملك التعبيرات النمطية تابعًا اسمه exec، حيث يُعيد القيمة null إذا لم يجد مطابقة، كما يُعيد كائنًا مع معلومات عن المطابقة إذا وجد تطابق. let match = /\d+/.exec("one two 100"); console.log(match); // → ["100"] console.log(match.index); // → 8 تكون للكائن المعاد من exec خاصية تدعى index، إذ تخبرنا أين تبدأ المطابقة الناجحة للسلسلة النصية؛ أما خلاف هذا فيبدو الكائن أشبه بمصفوفة من السلاسل النصية -وهو كذلك حقًا-، ويكون أول عنصر في تلك المصفوفة هو السلسلة المطابَقة، كما يكون ذلك هو تسلسل الأرقام الذي كنا نبحث عنه في المثال السابق. تحتوي قيم السلاسل النصية على التابع match الذي له سلوك مشابه: console.log("one two 100".match(/\d+/)); // → ["100"] حين يحتوي التعبير النمطي على تعبيرات فرعية مجمَّعة داخل أقواس، فسيظهر النص الذي يطابق تلك المجموعات في مصفوفة، ويكون العنصر الأول هو التطابق كله دومًا، في حين يكون العنصر التالي هو الجزء المطابَق بواسطة المجموعة الأولى التي يأتي قوس افتتاحها أولًا في التعبير، ثم المجموعة الثانية، وهكذا. let quotedText = /'([^']*)'/; console.log(quotedText.exec("she said 'hello'")); // → ["'hello'", "hello"] إذا لم تطابَق مجموعة ما مطلقًا -كأن تُتبَع بعلامة استفهام-، فسيكون موضعها في مصفوفة الخرج غير معرَّفًا undefined، وبالمثل، فإذا طابقت مجموعةً ما أكثر من مرة، فستكون المطابقة الأخيرة هي التي في المصفوفة فقط. console.log(/bad(ly)?/.exec("bad")); // → ["bad", undefined] console.log(/(\d)+/.exec("123")); // → ["123", "3"] تفيدنا المجموعات في استخراج أجزاء من سلسلة نصية، فإذا أردنا التحقق من احتواء السلسلة النصية على تاريخ، ومن ثم استخراج ذلك التاريخ وبناء كائن يمثله؛ فيمكننا إحاطة الأنماط الرقمية بأقواس، وأخذ التاريخ مباشرةً من نتيجة exec، لكن نحتاج قبل ذلك إلى النظر سريعًا على الطريقة المضمَّنة لتمثيل قيم التاريخ والوقت في جافاسكربت. صنف التاريخ تحتوي جافاسكربت على صنف قياسي لتمثيل البيانات -أو النقاط- في الزمن، ويسمى ذلك الصنف Date، فإذا أنشأنا كائن تاريخ باستخدام new، فسنحصل على التاريخ والوقت الحاليين. console.log(new Date()); // → Mon Nov 13 2017 16:19:11 GMT+0100 (CET) من الممكن إنشاء كائن لوقت محدد: console.log(new Date(2009, 11, 9)); // → Wed Dec 09 2009 00:00:00 GMT+0100 (CET) console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // → Wed Dec 09 2009 12:59:59 GMT+0100 (CET) تستخدِم جافاسكربت تقليدًا تبدأ فيه أعداد الشهور بالصفر -وعليه يكون شهر ديسمبر هو عدد 11-، بينما تبدأ أرقام الأيام بالواحد، وذلك أمر محيِّر وسخيف كذلك لكنه واقع، وإنما ذكرناه للتنبيه. تُعَدّ آخر أربعة وسائط arguments -أي الساعات والدقائق والثواني والميلي ثانية- وسائط اختيارية، وإذا لم تحدد قيمة أيّ منهم فتكون صفرًا افتراضيًا. تُخزَّن العلامات الزمنية Timestamps بعدد من الميلي ثانية منذ العام 1970 في منطقة UTC الزمنية -أي التوقيت العالمي-، ويتبع هذا اصطلاحًا ضُبِط بواسطة توقيت يونكس Unix time الذي اختُرع في تلك الفترة أيضًا، كما يمكن استخدام الأرقام السالبة للتعبير عن الأعوام التي سبقت 1970. إذا استُخدم التابع getTime على كائن تاريخ، فسيُعيد ذلك العدد، وهو عدد كبير كما هو متوقع. console.log(new Date(2013, 11, 19).getTime()); // → 1387407600000 console.log(new Date(1387407600000)); // → Thu Dec 19 2013 00:00:00 GMT+0100 (CET) إذا أعطينا الباني Date وسيطًا واحدًا، فسيعامَل الوسيط على أنه تعداد الميلي ثانية، ويمكن الحصول على القيمة الحالية لتعداد المللي ثانية بإنشاء كائن Date جديد، واستدعاء getTime عليه، أو استدعاء الدالة Date.now. توفِّر كائنات التاريخ توابعًا، مثل getFullYear وgetMonth وgetDate وgetHours وgetMinutes وgetSeconds، من أجل استخراج مكوناتها، كما يعطينا التابع getYear السنة بعد طرح 1900 منها -98، أو 119-، لكن لن نستخدِمه كثيرًا لعدم وجود فائدة حقيقية منه. نستطيع الآن إنشاء كائن تاريخ من سلسلة نصية بما أننا وضعنا أقواسًا حول أجزاء التعبير التي تهمنا، أي كما يلي: function getDate(string) { let [_, month, day, year] = /(\d{1,2})-(\d{1,2})-(\d{4})/.exec(string); return new Date(year, month - 1, day); } console.log(getDate("1-30-2003")); // → Thu Jan 30 2003 00:00:00 GMT+0100 (CET) تُهمَل رابطة الشرطة السفلية _، ولا تُستخدَم إلا لتجاوز عنصر المطابَقة التامة في المصفوفة التي يُعيدها التابع exec. حدود الكلمة والسلسلة النصية يستخرِج التابع getDate التاريخ 00-1-3000 من السلسلة النصية "‎100-1-30000‎"، وهو تاريخ غير منطقي لا شك، حيث تحدث المطابقة في أي موقع في السلسلة النصية، لذا تبدأ في حالتنا عند المحرف الثاني، وتنتهي عند المحرف الثاني من النهاية. نضيف العلامتين ^ و$ لإجبار المطابقة على النظر في السلسلة كلها، إذ تطابِق علامة الإقحام بداية سلسلة الدخل، بينما تطابِق علامة الدولار نهايتها، إذ تطابق ‎/^\d+$/‎ مثلًا سلسلةً مكونةً من رقم واحد أو أكثر، وتطابق ‎/^!/‎ أي سلسلة تبدأ بعلامة تعجب، بينما لا تطابق ‎/x^/‎ أي سلسلة نصية، إذ لا يمكن وجود x قبل بداية السلسلة. نستخدم العلامة ‎\b‎ للتأكد من أنّ التاريخ يبدأ وينتهي عند حدود كلمة، وقد يكون حد الكلمة بداية السلسلة، أو نهايتها، أو أي نقطة فيها تملك محرف كلمة -كما في ‎\w على أحد الجانبين، و محرف غير كلمي على الجانب الآخر. console.log(/cat/.test("concatenate")); // → true console.log(/\bcat\b/.test("concatenate")); // → false لاحظ أنّ علامة الحد لا تطابق محرفًا حقيقيًا، بل تضمن عدم مطابقة التعبير النمطي إلا عند حدوث حالة معينة في الموضع الذي يظهر فيه في النمط. أنماط الاختيار لنقل أننا نريد معرفة هل يحتوي جزء ما من النص على عدد متبوع بإحدى الكلمات التالية: horse، أو cow، أو chicken، أو أي صورة من صور الجمع لها، قد نكتب ثلاثة تعابير نمطية ونختبرها لكن ثَم طريقة أفضل، وذلك بوضع محرف الأنبوب | الذي يشير إلى خيار بين النمط الذي عن يمينه والنمط الذي عن يساره، وعليه نستطيع القول كما يلي: let animalCount = /\b\d+ (horse|cow|chicken)s?\b/; console.log(animalCount.test("15 horses")); // → true console.log(animalCount.test("15 horsechickens")); // → false يمكن استخدام الأقواس لتقييد جزء النمط الذي يطبَّق عليه عامل الأنبوب، ويمكن وضع عدة عوامل مثل هذا بجانب بعضها البعض للتعبير عن اختيار بين أكثر من بديلين اثنين. آلية المطابقة يبحث محرك التعبير نظريًا عند استخدام exec أو test عن تطابق في سلسلتنا النصية، وذلك بمحاولة مطابقة التعبير من بداية السلسلة أولًا، ثم من المحرف الثاني، وهكذا حتى يجد تطابقًا أو يصل إلى نهاية السلسلة، وعندئذ يُعيد أول تطابق وجده، أو يكون قد فشل في إيجاد تطابق أصلًا؛ أما في عملية المطابقة الفعلية، فيعامِل المحرك التعبير النمطي مثل مخطط تدفق flow diagram، وإذا استخدمنا مثالنا السابق عن الحيوانات، فسيبدو مخطط التعبير الخاص بها كما يلي: يكون تعبيرنا مطابقًا إذا استطعنا إيجاد مسار من جانب المخطط الأيسر إلى جانبه الأيمن، حيث نحفظ الموضع الحالي في السلسلة النصية، ونتأكد في كل حركة نتحركها خلال صندوق من أنّ جزء السلسلة التالي لموضعنا الحالي يطابق ذلك الصندوق. إذا كنا نحاول مطابقة "the 3 horses" من الموضع 4، فسيبدو مسار تقدمنا داخل المخطط كما يلي: يمكننا تجاوز الصندوق الأول لوجود حد كلمي word boundary عند الموضع 4. لا زلنا في الموضع 4 ووجدنا رقمًا، لذا نستطيع تجاوز الصندوق الثاني. يتكرر أحد المسارات إلى ما قبل الصندوق الثاني (الرقم) عند الموضع 5، بينما يتحرك الآخر للأمام خلال الصندوق، ويحمل محرف مسافة واحد؛ لذا يجب أخذ المسار الثاني لوجود مسافة وليس رقمًا. نحن الآن في الموضع 6، أي بداية horses وعند التفرع الثلاثي في المخطط، إذ لا نرى cow، ولا chicken هنا، لكن نرى horse، لذا سنأخذ ذلك الفرع. يتخطى أحد المسارات صندوق s عند الموضع 9 بعد التفرع الثلاثي، ويذهب مباشرةً إلى حد الكلمة الأخير، بينما يطابق المسار الآخر s، كما سنمر خلال صندوق s لوجود المحرف s وليس حدًا لكلمة. نحن الآن عند الموضع 10 وهو نهاية السلسلة النصية، ونستطيع مطابقة حد الكلمة فقط، وتُحسب نهاية السلسلة النصية على أنها حد كلمي، لذا سنمر خلال الصندوق الأخير ونكون قد طابقنا تلك السلسلة النصية بنجاح. التعقب الخلفي يطابق التعبير النمطي ‎/\b([01]+b|[\da-f]+h|\d+)\b/‎ عددًا ثنائيًا متبوعًا بـ b، أو عددًا ست عشريًا hexadecimal -وهو نظام رقمي تمثل فيه الأعداد من 10 إلى 15 بالأحرف a حتى f- متبوعًا بـ h، أو عددًا عشريًا عاديًا ليس له محرف لاحق، وفيما يلي المخطط الذي يصف ذلك: سيدخل الفرع العلوي الثنائي عند مطابقة ذلك التعبير حتى لو لم يحوي الدخل على عدد ثنائي، حيث سيصبح من الواضح عند المحرف 3 مثلًا أننا في الفرع الخاطئ عند مطابقة السلسلة "103"، فعلى الرغم تطابق السلسلة للتعبير، إلا أنها لا تطابق الفرع الذي نحن فيه. يبدأ هنا المطابِق matcher بالتعقب الخلفي، فيتذكر موضعه الحالي عند دخول فرع ما -وهو بداية السلسلة في هذه الحالة، بعد صندوق "حد الكلمة" الأول في المخطط-، وذلك ليستطيع العودة والنظر في فرع آخر إذا لم ينجح الفرع الحالي. سيجرب الفرع الخاص بالأرقام الست عشرية في حالة السلسلة النصية "103" إذا وصل إلى المحرف 3، لكنه سيفشل مجددًا لعدم وجود h بعد العدد، وهنا سيحاول في الفرع الخاص بالأعداد العشرية، وتنجح المطابقة، ويُبلَّغ بها. يتوقف المطابِق عندما يجد مطابقةً تامةً، وهذا يعني أنه حتى لو كان لدينا فروع متعددة يمكنها مطابقة سلسلة نصية ما، فهو لن يُستخدَم إلا الفرع الأول الذي ظهر وفقًا لترتيبه في التعبير النمطي. ويحدث التعقب الخلفي أيضًا لعوامل التكرار، مثل + و*، فإذا طابقنا ‎/^.*x/‎ مع "abcxe"، فسيحاول الجزء ‎.*‎ أخذ السلسلة كلها أولًا، لكن سيدرك المحرك أنه يحتاج إلى x كي يطابق النمط، وبما أنه لا توجد x بعد نهاية السلسلة، فسيحاول عامل النجمة المطابقة من غير المحرف الأخير، لكن لا يعثر المطابِق على x بعد abcx، فيعود أدراجه بالتعقب الخلفي ليطابق عامل النجمة مع abc فقط، وهنا يجد x حيث يحتاجها، ويبلِّغ بمطابقة ناجحة من الموضع 0 حتى 4. قد يحدث ونكتب تعبيرًا نمطيًا ينفذ الكثير من عمليات التعقب الخلفي، وهنا تحدث مشكلة حين يستطيع النمط مطابقة جزء من الدخل بطرق عديدة مختلفة، فإذا لم ننتبه عند كتابة تعبير نمطي لعدد ثنائي، فقد نكتب شيئًا مثل ‎/([01]+)+b/‎. عندما يحاول التعبير مطابقة سلسلة طويلة من الأصفار والآحاد التي ليس لها لاحقة b، فسيمر المطابِق على الحلقة الداخلية حتى تنتهي الأرقام، ثم يلاحظ عدم وجود المحرف b، فينفِّذ تعقبًا خلفيًا لموضع واحد فقط، ثم يمر على الحلقة الخارجية مرةً واحدةً قبل أن يستسلم ويعود أدراجه ليتعقب الحلقة الداخلية مرةً أخرى، كما سيظل يحاول جميع الطرق الممكنة عبر هاتين الحلقتين، وهذا يعني مضاعفة مقدار العمل مع كل محرف إضافي، فلو أضفنا بعض العشرات من المحارف، لاستغرقت عملية المطابقة إلى ما لا نهاية. التابع replace تحتوي قيم السلاسل النصية على التابع replace الذي يمكن استخدامه لاستبدال سلسلة نصية بجزء من سلسلة أخرى. console.log("papa".replace("p", "m")); // → mapa يمكن أن يكون الوسيط الأول تعبيرًا نمطيًا، وعندئذ يُستبدل التطابق الأول للتعبير النمطي؛ أما إذا أضيف الخيار g -اختصارًا لـ global- إلى التعبير النمطي، فتُستبدل جميع التطابقات. console.log("Borobudur".replace(/[ou]/, "a")); // → Barobudur console.log("Borobudur".replace(/[ou]/g, "a")); // → Barabadar لو كان لدينا وسيط إضافي للتابع replace بحيث نختار منه استبدال تطابق واحد أو جميع التطابقات، لكان أفضل من الاعتماد على خاصية للتعبير النمطي، بل لو كان من خلال توفير تابع مختلف باسم replaceAll لكان أفضل. ملاحظة: أضيف دعم حديث للغة جافاسكربت يحل النقطة السابقة وأصبحت تدعم التابع replaceAll لتبديل كل التطابقات في النص. يأتي مكمن القوة في استخدام التعابير النمطية مع التابع replace من حقيقة استطاعتنا الإشارة إلى المجموعات المطابَقة في السلسلة النصية البديلة، فمثلًا، لدينا سلسلة كبيرة تحتوي على أسماء أشخاص، بحيث يحتوي كل سطر على اسم واحد، ويبدأ بالاسم الأخير، ثم الاسم الأول، أي بالصورة: Lastname, Firstname إذا أردنا التبديل بين تلك الأسماء وحذف الفاصلة الأجنبية التي بين كل منها لنحصل على الصورة Firstname Lastname، فنستطيع استخدام الشيفرة التالية: console.log( "Mohsin, Samira\nFady, Eslam\nSahl, Hasan" .replace(/(\w+), (\w+)/g, "$2 $1")); // → Samira Mohsin // Eslam Fady // Hasan Sahl يشير كل من ‎$1، و‎$2 في السلسلة البديلة إلى المجموعات المحاطة بأقواس في النمط، ويحل النص الذي يطابق المجموعة الأولى محل ‎$1، كما يحل النص الذي يطابق المجموعة الثانية محل ‎$2، وهكذا حتى نصل إلى ‎$9؛ أما التطابق كله فيمكن الإشارة إليه باستخدام ‎$&‎. من الممكن تمرير دالة بدلًا من سلسلة نصية على أساس وسيط ثاني إلى التابع replace، حيث تُستدعى الدالة لكل استبدال مع المجموعات المطابَقة والتطابق كله على أساس وسائط arguments، وتُدخَل قيمتها المعادة في السلسلة الجديدة، أي كما في المثال التالي: let s = "the cia and fbi"; console.log(s.replace(/\b(fbi|cia)\b/g, str => str.toUpperCase())); // → the CIA and FBI وهذا مثال آخر: let stock = "1 lemon, 2 cabbages, and 101 eggs"; function minusOne(match, amount, unit) { amount = Number(amount) - 1; if (amount == 1) { // only one left, remove the 's' unit = unit.slice(0, unit.length - 1); } else if (amount == 0) { amount = "no"; } return amount + " " + unit; } console.log(stock.replace(/(\d+) (\w+)/g, minusOne)); // → no lemon, 1 cabbage, and 100 eggs يأخذ المثال أعلاه سلسلةً نصيةً، ويبحث عن حالات حدوث عدد متبوع بكلمة أبجدية رقمية، ويُعيد سلسلةً نصيةً، إذ تكون في كل حالة من تلك الحالات أُنقصت بمقدار 1. ستكون المجموعة ‎(\d+)‎ هي الوسيط amount للدالة، وتقيَّد المجموعة ‎(\w+)‎ بالوسيط unit، وتحوِّل الدالة الوسيط amount إلى عدد، وينجح ذلك بما أنه طابَق ‎\d+‎، كما تُجري بعض التعديلات في حالة إذا كان المتبقي صفر أو واحد فقط. الجشع Greed من الممكن استخدام replace لكتابة دالة تحذف جميع التعليقات من شيفرة جافاسكربت، لننظر في محاولة أولية لها: function stripComments(code) { return code.replace(/\/\/.*|\/\*[^]*\*\//g, ""); } console.log(stripComments("1 + /* 2 */3")); // → 1 + 3 console.log(stripComments("x = 10;// ten!")); // → x = 10; console.log(stripComments("1 /* a */+/* b */ 1")); // → 1 1 يطابق الجزء الذي يسبق العامل or محرفي شرطة مائلة متبوعتين بعدد من محارف لا تكون محارف سطر جديد؛ أما الجزء المتعلِّق بالتعليقات متعددة الأسطر فيملك بعض التفصيل، إذ نستخدم [^] -أيّ محرف ليس ضمن مجموعة المحارف الفارغة- على أساس طريقة لمطابقة أي محرف، غير أننا لا نستطيع استخدام محرف النقطة هنا لاحتواء التعليقات الكتلية على عدة أسطر، ولا يطابق محرف النقطة محارف السطر الجديد. لكن إذا نظرنا إلى خرج السطر الأخير فسنرى أنه خطأ نوعًا ما، وذلك أنّ الجزء ‎[^]*‎ من التعبير سيطابِق كل ما يستطيع مطابقته كما وضحنا في القسم الخاص بالتعقب الخلفي، فإذا تسبب ذلك في فشل الجزء التالي من التعبير، فسيعود المطابِق محرفًا واحدًا إلى الوراء، ثم يحاول مرةً أخرى من هناك، وهو في هذا المثال يحاول مطابقة بقية السلسلة، ثم يعود إلى الوراء من هناك. سيجد الحدث ‎*/‎ بعد العودة أربعة محارف إلى الوراء ويطابقها، وليس هذا ما أردنا، إذ كنا نريد مطابقة تعليق واحد، وليس العودة إلى نهاية الشيفرة لنجد نهاية آخر تعليق كتلي. نقول بسبب هذا السلوك أنّ عوامل التكرار مثل + و* و? و{} هي عوامل جشعة greedy، أي تطابق كل ما تستطيع مطابقته وتتعقب خلفيًا من هناك، لكن إذا وضعنا علامة استفهام بعد تلك العوامل لتصير هكذا ?+ و?* و?? و?{}، فسننفي عنها صفة الجشع لتطابق أقل ما يمكن، ولا تطابِق أكثر إلا كان النمط الباقي لا يناسب تطابقًا أصغر. هذا هو عين ما نريده في هذه الحالة، فبجعل عامل النجمة يطابق أصغر امتداد من المحارف التي تقودنا إلى ‎*/‎، فسنستهلك تعليقًا كتليًا واحدًا فقط. function stripComments(code) { return code.replace(/\/\/.*|\/\*[^]*?\*\//g, ""); } console.log(stripComments("1 /* a */+/* b */ 1")); // → 1 + 1 نستطيع على ذلك نسْب الكثير من الزلات البرمجية bugs في برامج التعابير النمطية إلى استخدام عامل جشِع من غير قصد، في حين أنّ استخدام عامل غير جشِع أفضل، لهذا يجب النظر في استخدام النسخة الغير جشعة من العامل أولًا عند استخدام أحد عوامل التكرار. إنشاء كائنات RegExp ديناميكيا ستكون لدينا حالات لا نعرف فيها النمط الذي يجب مطابقته عند كتابة الشيفرة، فمثلًا، نريد البحث عن اسم المستخدِم في جزء من النص، وإحاطته بمحرفي شرطة سفلية لإبرازه عما حوله، إذ لن نستطيع استخدام الترميز المبني على الشرطة المائلة لأننا لن نعرف الاسم إلا عند تشغيل البرنامج فعليًا، لكن نستطيع رغم ذلك بناء سلسلة نصية، واستخدام باني RegExp عليها، كما في المثال التالي: let name = "Saad"; let text = "Saad is a suspicious character."; let regexp = new RegExp("\\b(" + name + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → _Saad_ is a suspicious character. يجب استخدام شرطتين خلفيتين مائلتين عند إنشاء علامات الحدود ‎\b، وذلك لعدم كتابتها في تعبير نمطي محاط بشرطات مائلة، وإنما في سلسلة نصية عادية، كذلك يحتوي الوسيط الثاني للباني RegExp على خيارات للتعبير النمطي، وهي "gi" في هذه الحالة لتشير إلى عمومها global وعدم حساسيتها لحالة المحارف case insensitive. إذا احتوى اسم المستخدِم على محارف غريبة مثل "dea+hl[]rd"، فسيتسبب هذا في تعبير نمطي غير منطقي، وسنحصل على اسم مستخدِم لا يطابق اسم المستخدِم الفعلي. سنضيف شرطات مائلة خلفية قبل أي محرف يملك معنىً خاص به لحل هذه المشكلة. let name = "dea+hl[]rd"; let text = "This dea+hl[]rd guy is super annoying."; let escaped = name.replace(/[\\[.+*?(){|^$]/g, "\\$&"); let regexp = new RegExp("\\b" + escaped + "\\b", "gi"); console.log(text.replace(regexp, "_$&_")); // → This _dea+hl[]rd_ guy is super annoying. التابع search لا يمكن استخدام تعبير نمطي لاستدعاء التابع indexOf على سلسلة نصية، والحل هو استخدام التابع search الذي يتوقع تعبيرًا نمطيًا، حيث يُعيد أول فهرس يجده التعبير كما يفعل indexOf، أو يُعيد ‎-1 إذا لم يجده. console.log(" word".search(/\S/)); // → 2 console.log(" ".search(/\S/)); // → -1 لا توجد طريقة في التابع search لاختيار بدء المطابقة عند إزاحة offset بعينها، على عكس indexOf الذي يملكها في الوسيط الثاني، إذ تُعَدّ مفيدةً في بعض الأحيان. خاصية lastIndex لا يوفر التابع exec طريقةً سهلةً لبدء البحث من موضع بعينه في السلسلة النصية، شأنه في ذلك شأن التابع search، والطريقة التي يوفرها لذلك موجودة، لكنها ليست سهلة. تحتوي كائنات التعبير النمطي على خصائص إحداها هي source التي تحتوي على السلسلة التي أُنشئ منها التعبير، وثمة خاصية أخرى هي lastIndex التي تتحكم في موضع بدء التطابق التالي، وإن كان في حالات محدودة، وحتى حينئذ يجب أن يكون كل من الخيار العام g وخيار y اللزج sticky مفعَّلين في التعبير النمطي، كما يجب وقوع التطابق من خلال التابع exec. كان من الممكن هنا السماح بتمرير وسيط إضافي إلى exec. let pattern = /y/g; pattern.lastIndex = 3; let match = pattern.exec("xyzzy"); console.log(match.index); // → 4 console.log(pattern.lastIndex); // → 5 إذا نجح التطابق، فسيحدِّث الاستدعاء إلى exec خاصية lastIndex إلى النقطة التي تلي التطابق تلقائيًا؛ أما إذا لم يُعثر على تطابق، فستُضبِط خاصية lastIndex على الصفر، حيث يكون هو القيمة في كائن التعبير النمطي الذي سيُبنى تاليًا. يكون الفرق بين الخيارين العام واللزج هو عدم نجاح التطابق حالة الخيار اللزج إلا عندما يبدأ من lastIndex مباشرةً؛ أما في حالة الخيار العام، فسيبحث عن موضع يمكن بدء التطابق عنده. let global = /abc/g; console.log(global.exec("xyz abc")); // → ["abc"] let sticky = /abc/y; console.log(sticky.exec("xyz abc")); // → null تتسبب تلك التحديثات التلقائية لخاصية lastIndex في مشاكل عند استخدام قيمة تعبير نمطي مشتركة لاستدعاءات exec متعددة، فقد يبدأ تعبيرنا النمطي عند فهرس من مخلَّفات استدعاء سابق. let digit = /\d/g; console.log(digit.exec("here it is: 1")); // → ["1"] console.log(digit.exec("and now: 1")); // → null كذلك من الآثار اللافتة للخيار العام أنه يغيِّر الطريقة التي يعمل بها التابع match على السلاسل النصية، إذ يبحث عن جميع تطابقات النمط في السلسلة النصية، ويُعيد مصفوفةً تحتوي على السلاسل المطابَقة عندما يُستدعى مع الخيار العام، بدلًا من إعادة مصفوفة تشبه التي يُعيدها exec. console.log("Banana".match(/an/g)); // → ["an", "an"] لهذا يجب الحذر عند التعامل مع التعابير النمطية العامة، واستخدامها في الحالات الضرورية فقط،، مثل الاستدعاءات إلى replace والأماكن التي تريد استخدام lastIndex فيها صراحةً. التكرار على التطابقات يُعَدّ البحث في جميع مرات حدوث النمط في سلسلة نصية بطريقة تعطينا وصولًا إلى كائن المطابقة في متن الحلقة loop body أمرًا شائعًا، ويمكن فعل ذلك باستخدام lastIndex، وexec. let input = "A string with 3 numbers in it... 42 and 88."; let number = /\b\d+\b/g; let match; while (match = number.exec(input)) { console.log("Found", match[0], "at", match.index); } // → Found 3 at 14 // Found 42 at 33 // Found 88 at 40 يستفيد هذا من كون قيمة تعبير الإسناد = هي القيمة المسندَة، لذا ننفذ التطابق عند بداية كل تكرار باستخدام match = number.exec(input)‎ على أساس شرط في تعليمة while، ثم نحفظ النتيجة في رابطة binding، ونوقف التكرار إذا لم نجد تطابقات أخرى. تحليل ملف INI لنقل أننا نكتب برنامجًا يجمع بيانات عن أعدائنا على الإنترنت، رغم أننا لن نكتبه حقًا وإنما يهمنا الجزء الذي يقرأ ملف التهيئة، على أساس مثال على مشكلة تحتاج إلى التعابير النمطية، إذ سيبدو ملف التهيئة كما يلي: searchengine=https://duckduckgo.com/?q=$1 spitefulness=9.7 ; تُسبق التعليقات بفاصلة منقوطة... ; يختص كل قسم بعدو منفصل [larry] fullname=Larry Doe type=kindergarten bully website=http://www.geocities.com/CapeCanaveral/11451 [davaeorn] fullname=Davaeorn type=evil wizard outputdir=/home/marijn/enemies/davaeorn تكون القواعد الحاكمة لهذه الصيغة -وهي صيغة مستخدمة بكثرة، ويطلق عليها اسم INI- كما يلي: تُتجاهل الأسطر الفارغة والأسطر البادئة بفاصلة منقوطة. تبدأ الأسطر المغلَّفة بالقوسين المعقوفين [ ] قسمًا جديدًا. تضيف الأسطر التي تحتوي على معرِّف أبجدي-رقمي متبوع بمحرف = إعدادًا setting إلى القسم الحالي. لا يُسمح بأي شيء غير ما سبق، ويُعَدّ ما سواه غير صالح. مهمتنا هنا هي تحويل سلسلة نصية مثل هذه إلى كائن تحمل خصائصه سلاسل نصية للإعدادات المكتوبة قبل ترويسة القسم الأول، وكائنات فرعية للأقسام، بحيث يحمل كل كائن فرعي إعدادات القسم الخاص به، وبما أنه يجب معالجة الصيغة سطرًا سطرًا، فمن الجيد تقسيم الملف إلى أسطر منفصلة، مستفيدين من التابع split الذي تعرضنا له في هياكل البيانات: الكائنات والمصفوفات في جافاسكريبت. لا تقتصر بعض أنظمة التشغيل على محرف السطر الجديد لفصل الأسطر، وإنما تستخدِم محرف الإرجاع carriage return متبوعًا بسطر جديد ‎"\r\n"‎، وبما أنّ التابع split يسمح بالتعبير النمطي على أساس وسيط، فنستطيع استخدام تعبير نمطي مثل ‎/\r?\n/‎ للتقسيم بطريقة تسمح بوجود كل من ‎"\n"‎ و‎"\r\n"‎ بين الأسطر. function parseINI(string) { // ابدأ بكائن ليحمل حقول المستوى العلوي let result = {}; let section = result; string.split(/\r?\n/).forEach(line => { let match; if (match = line.match(/^(\w+)=(.*)$/)) { section[match[1]] = match[2]; } else if (match = line.match(/^\[(.*)\]$/)) { section = result[match[1]] = {}; } else if (!/^\s*(;.*)?$/.test(line)) { throw new Error("Line '" + line + "' is not valid."); } }); return result; } console.log(parseINI(` name=Vasilis [address] city=Tessaloniki`)); // → {name: "Vasilis", address: {city: "Tessaloniki"}} تمر الشيفرة على أسطر الملف وتبني الكائن، كما تخزَّن الخصائص التي في القمة داخل الكائن مباشرةً، بينما تخزن الخصائص الموجودة في الأقسام داخل كائن قسم مستقل، كما تشير الرابطة section إلى كائن القسم الحالي. لدينا نوعان من الأسطر المميزة، وهما ترويسة الأقسام، أو أسطر الخصائص، فإذا كان السطر خاصيةً عاديةً، فسيخزَّن في الموضع الحالي؛ أما إذا كان ترويسةً لقسم، فسيُنشأ كائن قسم جديد وتُضبط section لتشير إليه. نضمن بالاستخدام المتكرر لمحرفي ^ و$، مطابقة التعبير للسطر كاملًا وليس جزءًا منه فقط، كما ستعمل الشيفرة عند إهمالهما، لكنها ستتصرف مع بعض المدخلات بغرابة، وهو الأمر الذي سيكون زلةً bug يصعب تعقبها وإصلاحها. يُعَدّ النمط ‎if (match = string.match(...))‎ شبيهًا بما سبق في شأن استخدام الإسناد على أساس شرط لتعليمة while، فلن نكون على يقين من نجاح استدعاء match، لذا لا نستطيع الوصول إلى الكائن الناتج إلا داخل تعليمة if تختبر ذلك، ولكي لا نقطع سلسلة الصيغ else if، فسنسند نتيجة التطابق إلى رابطة، وسنستخدم هذا التعيين على أساس اختبار لتعليمة if مباشرةً. تتحقق الدالة من السطر باستخدام التعبير ‎/^\s*(;.*)?$/‎ إذا لم يكن ترويسةً لقسم أو خاصيةً ما، إذ تتحقق من أنه تعليق أو سطر فارغ، حيث يطابق الجزء الذي بين الأقواس التعليقات، ثم تتأكد ? أنه يطابق الأسطر التي تحتوي على مسافة بيضاء فقط، وإذا وُجد سطر لا يطابق أي صيغة من الصيغ المتوقعة، فسترفع الدالة اعتراضًا exception. المحارف الدولية كان اتجاه تصميم جافاسكربت في البداية نحو سهولة الاستخدام، وقد ترسخ ذلك الاتجاه مع الوقت إلى أن صار هو السمة الأساسية للغة ومعيارًا لتحديثاتها، لكن أتت هذه السهولة بعواقب لم تكن في الحسبان وقتها، إذ تُعَدّ تعابير جافاسكربت النمطية غبيةً لغويًا، فالمحرف الكلمي بالنسبة لها هو واحد من 26 محرفًا فقط، وهي المحارف الموجودة في الأبجدية اللاتينية بحالتيها الصغرى والكبرى، أو أرقامًا عشريةً، أو محرف الشرطة السفلية _؛ أما بالنسبة لأيّ شيء غير ذلك، مثل é أو β، فلن تطابق ‎\w رغم أنها محارف كلمية، لكنها ستطابق الحالة الكبرى منها ‎\W التي تشير إلى التصنيف غير الكلمي nonword category. تجدر الإشارة إلى ملاحظة غريبة في شأن محرف المسافة البيضاء العادية ‎\s، إذ لا تعاني من هذه المشكلة، وتطابق جميع المحارف التي يَعُدّها معيار اليونيكود محارف مسافة بيضاء، بما في ذلك المسافة غير الفاصلة nonbreaking space، والفاصلة المتحركة المنغولية Mongolian vowel separator. أيضًا، من المشاكل التي سنواجهها مع التعابير النمطية في جافاسكربت أنها لا تعمل على المحارف الحقيقية وإنما تعمل على الأعداد البِتّية للمحارف code units كما ذكرنا في الدوال العليا في جافاسكريبت، وبالتالي سيكون سلوك المحارف المكونة من عددين بِتّيين غريبًا، وعلى خلاف ما نريد. console.log(/?{3}/.test("???")); // → false console.log(/<.>/.test("<?>")); // → false console.log(/<.>/u.test("<?>")); // → true المشكلة أنّ ? التي في السطر الأول تعامَل على أنها عددين بِتّيين، ولا يطبَّق الجزء {3} إلا على العدد الثاني. وبالمثل، تطابق النقطة عددًا بِتَيًا واحدًا، وليس العددين اللذَين يكونان الرمز التعبيري للوردة، كما يجب إضافة خيار اليونيكود u للتعبير النمطي كي يعامَل مثل تلك المحارف على الوجه الذي ينبغي. سيظل السلوك الخاطئ للتعبير النمطي هو الافتراضي للأسف، لأنّ التغيير قد يتسبب في مشاكل للشيفرة الموجودة والتي تعتمد عليه، ومن الممكن استخدام ‎\p في تعبير نمطي مفعّل فيه خيار اليونيكود لمطابقة جميع المحارف التي يسند اليونيكود إليها خاصية معطاة، رغم أنّ هذه الطريقة معتمدة حديثًا ولم تُستخدم كثيرًا بعد. console.log(/\p{Script=Greek}/u.test("α")); // → true console.log(/\p{Script=Arabic}/u.test("α")); // → false console.log(/\p{Alphabetic}/u.test("α")); // → true console.log(/\p{Alphabetic}/u.test("!")); // → false يعرِّف اليونيكود عددًا من الخصائص المفيدة رغم أنّ إيجاد الخاصية التي نحتاجها قد لا يكون أمرًا سهلًا في كل مرة، حيث يمكن استخدام الصيغة ‎\p{Property=Value}‎ لمطابقة أيّ محرف له قيمة معطاة لتلك الخاصية، وإذا أُهمل اسم الخاصية كما في ‎\p{Name}‎، فسيُفترض الاسم إما خاصيةً بِتّيةً مثل Alphabetic، أو فئةً مثل Number. خاتمة التعبيرات النمطية هي كائنات تمثل أنماطًا في السلاسل النصية، وتستخدم لغتها الخاصة للتعبير عن تلك الأنماط. التعبير النمطي دلالته /abc/ تسلسل من المحارف /[abc]/ أيّ محرف في مجموعة محارف ‎/[^abc]/‎ أيّ محرف ليس في مجموعة ما من المحارف /[0-9]/ أيّ محرف من مجال ما من المحارف ‎/x+/‎ مرة حدوث واحدة أو أكثر للنمط x ‎/x+?/‎ مرة حدوث أو أكثر غير جشعة ‎/x*/‎ حدوث صفري أو أكثر. ‎/x?/‎ حدوث صفري أو حدوث لمرة واحدة ‎/x{2,4}/‎ حدوث لمرتَين إلى أربعة مرات /(abc)/ مجموعة `/a b c/` أيّ نمط من بين أنماط متعددة ‎/\d/‎ أيّ محرف رقمي ‎/\w/‎ محرف أبجدي رقمي alphanumeric، أي محرف كلمة ‎/\s/‎ أيّ محرف مسافة بيضاء /./ أيّ محرف عدا الأسطر الجديدة ‎/\b/‎ حد كلِمي word boundary /^/ بداية الدخل /$/ نهاية الدخل يملك التعبير النمطي التابع test للتحقق هل السلسلة المعطاة مطابقة أم لا، كما يملك التابع exec الذي يُعيد مصفوفةً تحتوي على جميع المجموعات المطابِقة إذا وُجدت مطابقات، ويكون لتلك المصفوفة خاصية index التي توضِّح أين بدأت المطابقة. تملك السلاسل النصية التابع match الذي يطابقها مع تعبير نمطي، وتابع search الذي يبحث عن التعابير النمطية ثم يُعيد موضع بداية التطابق فقط، كما تملك السلاسل النصية تابعًا اسمه replace، حيث يستبدِل سلسلةً نصيةً أو دالةً بتطابقات النمط. يمكن امتلاك التعابير النمطية خيارات تُكتب بعد شرطة الإغلاق المائلة، إذ يجعل الخيار i التطابق حساسًا لحالة الأحرف، كما يجعل الخيار g التعبير عامًا global، ويمكِّن التابع replace من استبدال جميع النسخ بدلًا من النسخة الأولى فقط؛ أما الخيار y فيجعله لزجًا، أي لن يتجاوز جزءًا من السلسلة أثناء البحث عن تطابق، كذلك يفعِّل الخيار u وضع اليونيكود الذي يصلح لنا عددًا من المشاكل المتعلقة بمعالجة المحارف التي تأخذ أكثر من عددين بتيين. وهكذا فإنّ التعابير النمطية أشبه بسكين حاد لها مقبض غريب الشكل، فهي تيسِّر المهام التي ننفذها كثيرًا، لكن قد تصبح صعبة الإدارة حين نستخدمها في مشاكل معقدة، ومن الحكمة تجنب حشر الأشياء التي لا تستطيع التعبيرات النمطية التعبير عنها بسهولة. تدريبات ستجد نفسك لا محالةً أثناء العمل على هذه التدريبات أمام سلوكيات محيِّرة للتعابير النمطية، فمن المفيد عندئذ إدخال تعبيراتك النمطية في أداة مثل https://debuggex.com لترى إن كان تصورها المرئي يوافق السلوك الذي أردت أم لا، ولترى كيف تستجيب لسلاسل الدخل المختلفة. Regexp golf Code golf هو مصطلح مستخدم للعبة تحاول التعبير عن برنامج معيَّن بأقل عدد ممكن من المحارف، وبالمثل، يكون regexp golf عملية كتابة تعابير نمطية، بحيث تكون أصغر ما يمكن، وتطابق النمط المعطى فقط. اكتب تعبيرًا نمطيًا لكل عنصر مما يلي، بحيث يتحقق من حدوث أيّ سلسلة نصية فرعية داخل السلسلة النصية الأم، ويجب على التعبير النمطي مطابقة السلاسل المحتوية على إحدى السلاسل الفرعية التي ذكرناها. لا تشغل بالك بحدود الكلمات إلا إذا ذُكر ذلك صراحةً، وإذا نجح تعبيرك النمطي فانظر إن كنت تستطيع جعله أصغر. Car وcat. Pop وprop. Ferret وferry وferrari. أيّ كلمة تنتهي بـ ious. محرف مسافة بيضاء متبوع بنقطة، أو فاصلة أجنبية، أو نقطتين رأسيتين، أو فاصلة منقوطة. كلمة أكبر من ستة أحرف. كلمة ليس فيها الحرف e أو E. استرشد بالجدول الذي في خاتمة المقال أعلاه، واختبر كل حل ببعض السلاسل النصية. تستطيع تعديل شيفرة التدريب لكتابة الحل وتشغيلها في طرفية المتصفح إن كنت تقرأ من متصفح، أو بنسخها إلى codepen. // املأ التعابير النمطية التالية verify(/.../, ["my car", "bad cats"], ["camper", "high art"]); verify(/.../, ["pop culture", "mad props"], ["plop", "prrrop"]); verify(/.../, ["ferret", "ferry", "ferrari"], ["ferrum", "transfer A"]); verify(/.../, ["how delicious", "spacious room"], ["ruinous", "consciousness"]); verify(/.../, ["bad punctuation ."], ["escape the period"]); verify(/.../, ["Siebentausenddreihundertzweiundzwanzig"], ["no", "three small words"]); verify(/.../, ["red platypus", "wobbling nest"], ["earth bed", "learning ape", "BEET"]); function verify(regexp, yes, no) { // تجاهل التدريبات غير المكتملة if (regexp.source == "...") return; for (let str of yes) if (!regexp.test(str)) { console.log(`Failure to match '${str}'`); } for (let str of no) if (regexp.test(str)) { console.log(`Unexpected match for '${str}'`); } } أسلوب الاقتباس تخيَّل أنك كتبت قصةً، واستخدمت علامات الاقتباس المفردة فيها لتحديد النصوص التي قالتها الشخصيات فيها، وتريد الآن استبدال علامات الاقتباس المزدوجة بكل تلك العلامات المفردة، لكن مع استثناء الكلمات التي تكون فيها العلامة المفردة لغرض مختلف مثل كلمة aren't. فكر في نمط يميز هذين النوعين من استخدامات الاقتباس، وصمم استدعاءً إلى التابع replace الذي ينفذ عملية الاستبدال المناسبة. تستطيع تعديل شيفرة التدريب لكتابة الحل وتشغيلها في طرفية المتصفح إن كنت تقرأ من متصفح، أو بنسخها إلى codepen. let text = "'أنا الطاهي،' he said, 'إنها وظيفتي.' "; // غيِّر هذا الاستدعاء. console.log(text.replace(/A/g, "B")); // → "أنا الطاهي،" he said, "إنها وظيفتي." إرشادات للحل يكون الحل البديهي هنا هو استبدال محرف غير كلمي nonword بعلامات الاقتباس على الأقل من جانب واحد، كما في ‎/\W'|'\W/‎، لكن سيكون عليك أخذ بداية السطر ونهايته في حسابك. كذلك يجب ضمان أنّ الاستبدال سيشمل المحارف التي طابقها نمط ‎\W كي لا تُنسى، ويمكن فعل ذلك بتغليفها في أقواس، ثم تضمين مجموعاتها في السلسلة النصية البديلة (1$‎ و2$‎)، كما لا يُستبدل شيء بالمجموعات التي لم تطابَق. الأعداد مرة أخرى اكتب تعبيرًا لا يطابق إلا الأعداد التي لها نسق جافاسكربت، ويجب عليه دعم علامة + أو - قبل العدد، والعلامة العشرية، والصيغة الأسية -أي 5e-3، أو 1E10-، مع علامتي موجب أو سالب قبل الأس. لاحظ عدم اشتراط وجود أرقام قبل العلامة العشرية أو بعدها، لكن لا يمكن أن يكون العدد مكونًا من العلامة العشرية وحدها، أي يسمح بكل من .5 و5. في جافاسكربت، لكن لا يُسمح بـ .. تستطيع تعديل شيفرة التدريب لكتابة الحل وتشغيلها في طرفية المتصفح إن كنت تقرأ من متصفح، أو بنسخها إلى codepen. // املأ التعبير النمطي التالي. let number = /^...$/; // الاختبارات: for (let str of ["1", "-1", "+15", "1.55", ".5", "5.", "1.3e2", "1E-4", "1e+12"]) { if (!number.test(str)) { console.log(`Failed to match '${str}'`); } } for (let str of ["1a", "+-1", "1.2.3", "1+1", "1e4.5", ".5.", "1f5", "."]) { if (number.test(str)) { console.log(`Incorrectly accepted '${str}'`); } } إرشادات للحل يجب عدم نسيان الشرطة المائلة الخلفية التي قبل النقطة. يمكن مطابقة العلامة الاختيارية التي قبل العدد وقبل الأس بواسطة ‎[+\-]?‎، أو ‎(\+|-|)‎، والتي تعني موجب، أو سالب، أو لا شيء. يبقى الجزء الأصعب من هذا التدريب مطابقة كل من ‎"5."‎ و‎".5"‎ دون مطابقة "."، وأحد الحلول الممتازة هنا هو استخدام العامل | لفصل الحالتين؛ فإما رقم واحد أو أكثر متبوع اختياريًا بنقطة وصفر، أو أرقام أخرى، أو نقطة متبوعة برقم واحد أو أكثر. وأخيرًا، نريد جعل e حساسة لحالتها؛ فإما نضيف الخيار i للتعبير النمطي أو نستخدم [eE]. ترجمة -بتصرف- للفصل التاسع من كتاب Elequent Javascript لصاحبه Marijn Haverbeke. اقرأ أيضًا المقال السابق: الزلات البرمجية والأخطاء في جافاسكريبت تطويع البيانات في جافاسكربت التخاطب بين نوافذ المتصفح عبر جافاسكريبت
    1 نقطة
  37. يحدث هذا الخطأ لأنك تقوم بإستدعاء التابع toggle داخل التابع render وهذا يسبب أن يقوم react بعمل re-render المكون والحل هو تغير الجزء الخاص بإستدعاء التابع toggle ليصبح كالتالي: {<div className="btn btn-lg" onClick={this.toggle}>Toggle</div>} وفي حالة أردت أن تقوم بتمرير قيمة معينة للتابع toggle مثل الكائن event يمكنك أن تستخدم الدالة السهمية onClick={(event) => this.toggle(event, params)} بهذا الشكل لن يتم إستدعاء التابع toggle مباشرة بل سيتم تنفيذه إذا قام المستخدم بالضغط عليه. بالتوفيق.
    1 نقطة
  38. يمكنك أن تستعمل صور SVG لأنها تتمدد إلى أي حجم دون أن تفقد جودتها، لذلك مهما كان حجم الموقع أو الشاشة المعروض عليها فلن تتأثر الصورة. يوجد العديد من المواقع التي تقدم صور SVG مجانية مثل: storyset و flaticon، كما يمكن أن تستعمل برامج مثل Adobe Illustrator لعمل شعارك الخاص (يفضل أن توظف مصمم محترف لعمل الشعار) أو التعديل عليه. هذه المدونة تستهدم صورة عادية بصيغة png ولكن حجمها كبير للغاية (رابط الصورة)، وبالتالي يتم تصغيرها إلى الحجم المطلوب بإستخدام CSS و خاصية media query (خاصية في CSS أيضًا).
    1 نقطة
  39. يوجد بعذ الإختلافات فعلًا بين الـ Functional Component و الـ Class Component وهنا شرح بسيط للفرق بينهما: Functional Component: هي عبارة عن دوالة جافاسكريبت عادية، في الغالب نستعمل الدوال السهمية (لأنها أبسط) لكن يمكن إستخدام دوال جافاسكريبت العادية (بإستخدام الكلمة الفتاحية function). تسمى أحيانًا بـ "stateless components" أو "dumb components"، ويمكنها إستقبال بيانات بشكل بسيط (مثل Arguments في دوال جافاسكريبت)، وفي الغالب تكون مسئولة عن عرض أجزاء الـ UI في الموقع. لا يمكن إستخدام دوال Lifecycle Hooks داخلها (مثل componentDidMount). ملاحظة: لم يعد هذا ضروري حيث بدًأ من React 16.8 حيث أصبح بإمكانك إستخدام useEffect hook للوصول إلى دوال Lifecycle Hooks لا نستخدم دالة render داخل الـ Functional Component بل نقوم بإرجاع المكون مباسرة بإستخدام return. يمكن إستخدام props داخل الـ Functional Component دون مشكلة. يُفضل إستخدامها إن لم تكن تستخدم React state. import React from "react"; const Title = props => ( <div> <h1>Hello, {props.name}</h1> </div> ); export default Title; Class Components: تستخدم خواص ES6 لعمل صنف من خلال الكلمات المفتاحية Class و extends. تسمى أحيانًا بـ "Smart Components" أو "Stateful Components" يمكن إستخدام دوال Lifecycle Hooks داخلها (مثل componentDidMount). يمكن إستخدام props داخل الـ Class Component دون مشكلة من خلال this.props import React, { Component } from "react"; class Title extends Component { render() { return ( <div> <h1>Hello, {this.props.name}</h1> </div> ); } } export default Title; الخلاصة: حاول أن تستخدم الـ Functional Component لعرض أجزاء واجهة المستخدم UI حيث أنها أبسط، وقم بإستخدام الـ Class Component في المكونات الأكثر تعقيدًا والتي تحتاج إلى إستخدام دوال Lifecycle Hooks.
    1 نقطة
  40. لغة جافاسكريبت مثل باقي لغات البرمجة تحتوي على متغييرات ودوال وجمل شرطيطة وجمل تكرار ومصفوفات إلخ، وهنا شرح مختصر بسيط لكل مما سبق: المتغيرات: يمكنك أن تتخيلها مثل صناديق لحفظ قيمة معينة لكي نستخدم هذه القيمة فيما بعد، ويمكن تشبيهها مثل س و ص في الرياضيات var x = 5; console.log(x); // Output: 5 // يمكن أن تحتوي المتغيرات على نصوص var y = "Hi"; console.log(y); // Output: Hi // يمكن أن نقوم بتغير قيمة المتغير في أي وقت نشاء x = 8; y = "Hello"; console.log(x, y); // Output: 8 Hello x = "New Variable"; y = 5.5; console.log(x, y); // Output: New Variable 5.5 الجمل الشرطية: تستخدم لتفيذ أمر معين إن تحقق الشرط، كأن تقوم بإحضار منشورات جديدة إن كان المستخدم في نهاية الصفحة (مثل فيسبوك) var age = 18; // نتحقق مما إذا كان المتغير age أكبر من 18 if (age > 18) { console.log("You are older than 18"); } // إن لم يتحقق الشرط السابق نتحقق مما إذا المتغير يساوي 18 else if (age == 18) { console.log("You have 18 years"); } // في حالة لم يتحقق أي من الشروط السابقة نقوم بتنفيذ الآتي else { console.log("You are young"); } جمل التكرار: تقوم بتكرار جزء معين من الكود بعدد المرات التي نريدها، مثل طباعة جملة "مرحبًا" 10 مرات // أول شيء نقوم بعمل متغير لعد عدد المرات // ونقوم بعمل شرط لإستمرار التكرار // ثم نقوم بزيادة قيمة المتغير بمفدار واحد كل مرة for (var counter = 1; counter <= 10; counter = counter +1) { console.log("مرحبًا"); } الدوال: مجموعة من الخطوات لتقوم بعمل شيء معين، ويمكن تنفيذ هذه الخطوات في أي وقت نشاء، مثل: طباعة جملة "مرحبًا + اسم شخص" مع طباعة تاريخ اليوم // نعطي للدالة اسم printMyName // هذه الدالة تستقبل قيمة name ليتم طباعتها function printMyName(name) { console.log("Hello" , name); console.log("The time now is:", Date()); } // بعد ذلك نقوم بإستدعاء الدالة السابقة كما نشاء وقتما نشاء // وفي كل مرة تقوم بطباعة الاسم والوقت الحالي printMyName("Mohammed"); printMyName("Sameh"); printMyName("Ali"); المصفوفات: يمكنك أن تتخيلها على أنها متغير يمكن أن يحتوي على أكثر من قيمة واحدة في نفس الوقت، ويمكنك إستخدام أحد هذه القيم في أي وقت مثل المتغيرات العادية تمامًا // مصفوفة تحتوي على بعض الأسماء var x = ["Ali", "Mohammed", "Khaled", "Sameh", "Farouk"]; // لنقوم بطباعة اسم معين من الأسماء السابقة نستخدم ترتيبه // مع العمل أننا نبدأ في العد من الصفر console.log(x[0]); // Output: Ali console.log(x[1]); // Output: Mohammed console.log(x[4]); // Output: Farouk مازال هناك الكثير من الأمور التي يمكن شرحها وما هذا إلا جزء صغير للغاية من لغة جافاسكريبت ومن الأشياء التي تسطيع عملها بها. لكي تتعلم المزيد أنصحك بأن تتابع دورة تشرح لك الأساسيات مع التطبيق على بعض المشاريع الصغيرة في البداية (يوجد الكثير منها على اليوتيوب وفي مواقع الدورات المشهورة). كما أنصحك بأن تلقي نظرة كل فترة على موسوعة حسوب للغة جافاسكريبت وقراءة مقالات الأكاديمية الخاصة باللغة (تحتوي على ما يقرب 250 مقالة الآن). بالتوفيق.
    1 نقطة
  41. يبدو أن لديك مصفوفة تحتوي على عناصر undefined وبالتأكيد هذه العناصر لا تحتوي على urls ، لذلك يجب أن تقوم بفتلرة هذه المصفوفة والتأكد من أن كل عنصر ليس من نوع undefined، ويمكنك فعل ذلك من خلال التابع filter بهذا الشكل: arr.filter(Boolean) هنا الكود الصحيح لملف Mainboard.js: function Mainboard({ pins }) { return ( <Wrapper> <Container> {pins.filter(Boolean).map((pin, index) => { const {urls} = pin; return <Pin key={index} urls={urls}/> })} </Container> </Wrapper> ); } بهذا الشكل سيتم إستخدام عناصر المصفوفة pins التي ليست من نوع undefined وليست false أيضًا.
    1 نقطة
  42. عليك فقط أن تقوم بالتطبيق على مشاريع حقيقية في البداية لكي تختبر قدراتك في العمل وتستطيع أن تقدر الوقت والتكلفة اللازمة لإنهاء المشروع، ويمكنك أن تقوم بذلك من خلال تصفح المشاريع المطلوب في مواقع العمل الحر مثل مستقل وتقوم بعمل بعض من هذه المشاريع دون أن تقوم بالتقديم عليها، فالهدف من هذه الخطوة هو التأكد من قدراتك في عمل مشاريع حقيقية ومطلوبة في السوق. خلال هذه الخطوة يمكنك أن تقيس مقدار الوقت الوقت اللازم لعمل مشروع معين ومقدار المجهود المبذول وبالتالي تستطيع أن تقدر سعر ساعة العمل الخاص بك. هنا خطوات تحديد وإختيار المشروع المناسب لك: تصفح المشاريع الموجود الخاصة بالبرمجة وتصميم المواقع من هنا أقرأ عنوان ووصف كل مشروع يمكنك القيام به، أقرأ وصف المشروع جيدًا وتأكد من فهمك لكل المطلوب تنفيذه. قدر ثمن مجهودك والوقت اللازم لتنفيذ المشروع وقارنه مع الميزانية والمدةالمقترحة لتنفيذ المشروع (موجودة على اليسار في بطاقة المشروع). قدم عرضك وأكتب كل التفاصيل التي تستطيع القيام بها والوقت اللازم لك لكي تنهي المشروع. إنتظر رسالة من صاحب المشروع للتواصل، سوف يسألك عن بعض التفاصيل الإضافية على الأغلب وسيقارن بينك وبين كل المستقلين الذي قدموا على نفس المشروع أيضُا عند الإتفاق مع العميل وإختياره لك والموافقة على عرضك سوف تصلك رسالة تخبرك بأن صاحب المشروع قد بدأ صفقة معك، وحينها يمكنك أن تتواصل معه من خلال صفحة المناقشة (ستظهر لك بعد الموافقة على عرضك). أنجز المشروع بأسرع ما يمكن وبأعلى جودة ممكنة. أخبر صاحب المشروع بكل جديد من تغيرات وإنجازات في صفحة المناقشة لا تتواصل أبدًا خارج المنصة للحفاظ على حقوقك حتى إن طلب منك العميل، وفي حالة تواصلك معه خارج موقع مستقل أكتب كل التفاصيل على الموقع أيضًا. سلم كل ملفات المشروع حسب المتفق عليه في صفحة نقاش المشروع، ولا تخشى أن يتم سرقة مجهودك فموقع مستقل تضمن لك كل حقوقك. بعد أن يراجع صاحب المشروع كل الملفات المطلوبة، سيقوم بقبول المشروع وسيتم تحويل تكلفة المشروع إلى حسابك (بعد خصم نسبة موقع مستقل) في خانة الرصيد المعلق لمدة 14 يوم ثم سيمكنك سحبها بأي وسيلة سحب مدعومة في الموقع. أبدأ من خطوة رقم 1 مرة أخرى. لا تنسى أن تتابع مدونة مستقل للحصول على معلومات ونصائح أكثر.
    1 نقطة
    بعد قراء كتابكم مدخل إلى الذكاء الاصطناعي وتعلم الآلة : تأليف (محمد لحلح) تحرير (جميل بيلوني ) إخراج فني ( فرج الشامي) تغيرت نظرتي للذكاء الاصطناعي انا اؤمن بذلك، شكرا لكم 💚 .
    1 نقطة
    كتاب ممتع وشيّق وبعيد عن التعقيد، أنصح لكل مبتدئ يريد تعلّم الذكاء الإصطناعي ولا يعلم من أينَ يبدأ أن يقوم بقرائته. شكراً للقائمين على إخراج هذا الكتاب، وبالتوفيق في مشاريعكم القادمة.
    1 نقطة
×
×
  • أضف...