-
المساهمات
18935 -
تاريخ الانضمام
-
تاريخ آخر زيارة
-
عدد الأيام التي تصدر بها
448
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو Mustafa Suleiman
-
ما قمت به حتى الآن عمل رائع جدًا والقليل من يقوم بالتطبيق بشكل عملي بجانب الدورة أي عدم الإكتفاء بما يتم شرحه والتطبيقات العملية المتاحة. وبخصوص المشاريع فلا أنصحك بوضع المشاريع التي تقوم بها في البداية، فالتصميم لن يكون جيد بطبيعة الحال، لذا انتظر لبعض الوقت لحين العمل على تحسين مهارة التصميم والتي هي بحاجة إلى وقت، وبالطبع ليس عليك أن تكون مُصمم فأنت مطور، أقصد تحسين تلك المهارة من خلال الاستلهام وتعلم أساسيات التصميم الجيد، ولا مشكلة في نقل التصميم كما هو لكن يجب توضيح ذلك عند نشره أي أنك قمت بالجزء البرمجي فقط. المشاريع الأولية هي بمثابة تدريب لك، وكذلك المشاريع التي تتم بالدورة الجميع قام بها، لذا حاول التعديل في التصميم ووضع لمسة خاصة بك وإضافة مزايا أخرى أيضًا، وهي مشاريع مناسبة للنشر لكن مع التعديل. الحالة الوحيدة التي يمكنك بها نشر المشاريع الأولية التي تقوم بها بجانب الدورة، هي بنشر ما تعلمته أيضًا، بمعنى كتابة شرح مفيد به معلومات تختصر ما تعلمته أثناء تنفيذك للمشروع والتحديات التي واجهتها، أي تستطيع نشر المشروعين في منشور واحد، مع وضع صور للتوضيح وليس الروابط فقط. ومع مرور الوقت اختر 3 مشاريع ناضجة وبمستوى جيد وقم بنشرهم على فترات وكتابة ما تعلمته في كل مشروع ونتيجة تراكم الخبرات التي أوصلتك لتنفيذه، وتعيينهم لقسم Featured في حسابك. وبالنسبة للصور اعتمد على التالي: Unsplash https://www.pexels.com/ https://www.freepik.com/ https://www.humaaans.com/ https://www.drawkit.io/ https://blush.design/
-
ستحتاج إلى مجموعة من المكتبات لتنفيذ ما تريد، وهم: pyautogui لمحاكاة حركة الماوس والكيبورد. subprocess و os لتشغيل أوامر النظام. psutil لمراقبة موارد النظام CPU، RAM، وخلافه. pywin32 (Windows) للتحكم في نوافذ Windows وتطبيقاتها. أما بالنسبة لأندرويد فستعتمد على ADB للتحكم في الهاتف من الكمبيوتر باستخدام مكتبة بايثون adb-shell وبالطبع يجب ربط الهاتف بالحاسوب عن طريق الـ USB. ثم ستحتاج إلى أتمتة واجهة المستخدم من خلال أحد المكتبات التالية uiautomator, Appium, أو scrcpy مع بايثون. ومثلاً لإرسال رسالة SMS من أندرويد عبر ADB: from adb_shell.adb_device import AdbDeviceTcp device = AdbDeviceTcp("192.168.1.100", 5555) device.connect() device.shell("am start -a android.intent.action.SENDTO -d sms:123456789 --es sms_body 'مرحباً من بايثون' --ez exit_on_sent true") وبالطبع استبدل الرقم 123456789 بالرقم الذي تريد الإرسال إليه، واستبدل 192.168.1.100 بعنوان هاتفك ولمعرفته، افتح الإعدادات ثم خيارات المطور ثم فعل ADB over network، وسيظهر لك عنوان IP مثل 192.168.x.x واستخدمه بدل 192.168.1.100 في الكود. أما بالنسبة لـ IOS فالأمر صعب ومعقد.
- 5 اجابة
-
- 1
-
-
أحسنت في ذلك، فيما يخص TypeScript، فالأفضل تعريف الـ Interfaces في ملف منفصل وليكن types.ts أو interfaces.ts في حال إذا ستُستخدم في أكثر من مكان، أو على الأقل خارج الدالة المكونة. أيضاً، النوع id: number | null غير ضروري بما أنك تستخدم Date.now()، فالملاحظة ستحصل دائمًا على id عند إنشائها، وتستطيع تبسيطه إلى id: number. الحالة الوحيدة التي تكون فيها القيمة null هي للمتغير selectedNote، وهو ما قمت به بشكل صحيح useState<number| null>(null)، لكن id داخل كائن الملاحظة نفسه لن يكون null أبدًا. وبالنسبة لتحديد أنواع الدوال، فمعظم الدوال سواء addToNoteHandler و updateNoteHandler لا تحتوي على أنواع محددة للـ parameters الخاصة بها أو القيمة العائدة منها ، وTypeScript تستنتجها بناءًا على الكود الخاص بالدالة، لكن تحديدها صراحةً يجعل الكود أوضح. وللعلم بإمكانك إنشاء Hook مخصص وقابل لإعادة الاستخدام لإدارة أي حالة في localStorage كالتالي: import { useState, useEffect } from 'react'; function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T) => void] { const [storedValue, setStoredValue] = useState<T>(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error(error); return initialValue; } }); const setValue = (value: T) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error(error); } }; return [storedValue, setValue]; } export default useLocalStorage; واستخدامه في App.tsx كالتالي: import useLocalStorage from './hooks/useLocalStorage'; const [notes, setNotes] = useLocalStorage<Note[]>('notes', []);
-
Git ليست من اختصاص الدورة، فهي خاصة بدورة واجهات المستخدم، ستجد هنا شرح لتعلم Git: وبخصوص react وعدم تضمينها في دورة تطوير واجهات المستخدم، السبب هو أن الدورة موجهة لتعلم أساسيات الواجهة الأمامية من خلال تعلم اللغات الأساسية التي يعتمد عليها أي مكتبة أو إطار للواجهة الأمامية وهو HTML, CSS, JS. وتعلم تلك اللغات في البداية واجب وضروري، وبدونها ستعاني في فهم ما يدور في الكود الخاص بك عند تعلم تلك المكتبات والإطارات، وأيضًا ستواجه صعوبة في حل المشكلات التي تواجهك وأيضًا تخصيص مشروعك بالشكل الذي ترغب به. ولتعلم React.js الأمر يحتاج إلى فرد مساحة في دورة مختلفة تمامًا، والدورة لن تكون للمبتدئين في الواجهة الأمامية، فأنت بحاجة إلى تعلم اللغات الأساسية كما ذكرت لتفهم ما يحدث وما فائدة ما تتعلمه وتكتبته. ولذلك ستجد أنه تم تخصيص دورة تطوير التطبيقات باستخدام لغة JavaScript من أجل تعلم مكتبة React وإطارات جافاسكريبت الأخرى مثل React Native لتطوير تطبيقات الهاتف وأيضًا Ionic ثم ستتعلم Electron.js لتطوير برامج سطح المكتب. وأيضًا يوجد شرح لإطار Next.js وهو هام جدًا بعد تعلم React من أجل التصيير من جهة الخادم Server-side Rendering. وجميع المسارات الأولى من الدورات الأخرى متاحة لك، وتستطيع الإطلاع عليها فمثلاً في دورة تطوير التطبيقات باستخدام لغة JavaScript المسار الأول هو أساسيات لغة JavaScript وأنصحك بالإطلاع عليه لتعلم المزيد عن جافاسكريبت بجانب ما درسته في دورة تطوير واجهة المستخدم.
-
أرجو توضيح ما هي الدورة المقصودة، عامًة يوجد تمارين عملية ولكن ليس في جميع المسارات، وأحيانًا هناك مسارات نظرية لذا لا يوجد بها تمارين بطبيعة الحال، كذلك يوجد مشاريع عملية مباشرًة بعد شرح الأسياسات للتطبيق على ما قمنا بدراسته والتوسع أيضًا في الشرح. وفي حال احتجت إلى تمارين ولم تجدها، تستطيع السؤال أسفل الدروس في التعليقات وسيتم توفيرها لك.
- 2 اجابة
-
- 1
-
-
بشكل بسيط، في البرمجة الإجرائية التركيز على ما هي الخطوات التي يجب أن تقوم بها، أي البرنامج هو سلسلة من الأوامر، الأمر أشبه بكتابة وصفة طبخ أي تكتب قائمة من التعليمات المرتبة. والبيانات هي كيان سلبي ومنفصل، بمعنى الدوال هي التي تأتي من الخارج وتعمل على تلك البيانات، ويبدأ البرنامج بشكل هرمي بمعنى الدالة الرئيسية تستدعي دوال، وتلك الدوال تستدعي دوال أخرى. والبيانات العامة يمكن الوصول إليها وتعديلها من أي دالة، وذلك يسبب آثارًا جانبية غير متوقعة، كذلك وحالة البرنامج بأكمله محفوظة في متغيرات عامة، مما يجعل تتبع التغييرات صعبًا. للتوضيح: account_balance = 0.0 def deposit(amount): """Procedure to add an amount to the overall balance""" global account_balance account_balance += amount print(f"Deposited {amount}. New balance: {account_balance}") def withdraw(amount): global account_balance if amount <= account_balance: account_balance -= amount print(f"Withdrew {amount}. New balance: {account_balance}") else: print("Error: Insufficient balance.") def show_balance(): print(f"Current balance is: {account_balance}") show_balance() deposit(1000) withdraw(300) show_balance() account_balance = -5000.0 print("Balance manipulated from outside the functions!") show_balance() أما في البرمجاة الكائنية تُعالج ما سبق من خلال التركيز على بناء كائنات رئيسية وكائنات فرعية والتي ترث من الرئيسية، والبيانات والدوال مرتبتطان بشكل وثيق، فالكائن مسؤول عن حماية وإدارة بياناته الخاصة، أي البرنامج يتكون من مجموعة من الكائنات المستقلة التي تتواصل مع بعضها البعض عن طريق استدعاء توابع (الميثودز) بعضها البعض. والغرض من ذلك تطوير نظام معقد بطريقة تجعله سهل الفهم، الصيانة، والتوسيع، وذلك عن طريق مباديء البرمجة الكائنية وهي الوراثة وتعدد الأشكال والتغليف والتجريد. ونفس الكود السابق يُصبح كالتالي: class BankAccount: def __init__(self, initial_balance=0.0): self.balance = initial_balance def deposit(self, amount): if amount > 0: self.balance += amount print(f"Deposited {amount}. New balance: {self.balance}") def withdraw(self, amount): if amount <= self.balance: self.balance -= amount print(f"Withdrew {amount}. New balance: {self.balance}") else: print("Error: Insufficient balance.") def show_balance(self): print(f"Current balance is: {self.balance}") account1 = BankAccount(1000) account2 = BankAccount(5000) account1.show_balance() account1.deposit(200) account1.withdraw(50) account2.show_balance() account2.withdraw(1000) print("Final balance of the first account:") account1.show_balance() print("Final balance of the second account:") account2.show_balance()
- 6 اجابة
-
- 1
-
-
بالطبع تستطيع ذلك، يمكنك طرح أي أسئلة متعلقة بأقسام الأسئلة المتاحة بالأكاديمية، ومنها قسم البرمجة والخاص بجميع أسئلة البرمجة.
-
هل رقمك شخصي أم تجاري؟ فواتساب لا يوفر API رسمي ومجاني للتفاعل مع حسابات واتساب الشخصية بينما يوفر ذلك للحسابات التجارية، بالتالي ستحتاج إلى الإلتفاف حول ذلك. ويوجد حلول عن طريق جافاسكريبت ومنها مكتبة whatsapp-web.js وopen-wa. أما في بايثون فالحل الأفضل هو Selenium لمحاكاة استخدامك لموقع web.whatsapp.com في متصفح حقيقي، وستقوم بكتابة سكربت بايثون يتحكم في المتصفح ليقوم بالخطوات التي كنت ستقوم بها يدويًا. أو استخدام WhatsApp Business API لقراءة الرسائل من المجموعات التي يكون رقمك المرتبط بالـ API عضوًا فيها، وليس فقط الرسائل المباشرة الموجهة لرقمك، وبالطبع الاستخدام ليس مجاني.
-
الأفضل تعلم أساسيات Git وكيفية استخدام منصة GitHub من الآن، فهي مهارة أساسية لا غنى عنها لأي شخص يعمل في مجال البرمجة، أي اعتد على استخدام Git من الآن، ستجد هنا مصادر: وبخصوص الإختبار، فستقوم بإختباره بشكل يدوي في البداية، وهل يعمل بشكل سليم وفق المطلوب أم لا، وفي حال هناك إدخال من قبل المستخدم فيجب تجربة إدخالات خاطئة ومن المفترض أن يتم التعامل مع تلك الحالات في الكود لديك، أي بدلاً من رقم تُدخل نص وهكذا أو لا تُدخل أي شيء. وكذلك تفقد الأخطاء من خلال الإعتماد على دالة print لطباعة قيم معينة في الكود لتتفقد هل يعمل بشكل سليم أم لا. وبعد فترة ستقوم بتعلم مفهوم Unit testing وهناك مكتبة باسم pytest لذلك.
- 3 اجابة
-
- 1
-
-
المشكلة أنك تستخدم كائن حالة واحد filters لجميع متغيرات الفلترة والبحث والترقيم، وباستدعاء setFilters لتغيير أي خاصية مثلاً keyword عند البحث، يتم إنشاء كائن جديد تمامًا في الذاكرة. بالتالي FormFilters يتلقى كائنًا جديدًا في كل مرة ويتلقى دالة جديدة في كل مرة في onApplyFilters، ونفس المبدأ ينطبق على مكون Search عندما تتغير الفلاتر الجانبية. والمشكلة أيضًا ليست فقط في إنشاء كائن جديد، بل في تمرير نفس الكائن وإن كان جديدًا إلى جميع المكونات في آنٍ واحد، فكل مكون يرى أنّ أحد الـ props تغير، فيُعاد تركيبه. لو استخدمت مكتبة إدارة حالة مثل Zustand كان سيجنبك تلك المشكلة من البداية بكل سهولة. بدونها الأفضل استخدام useReducer بدلاً من useState لكن للتسهيل استخدم useState، أي يجب فصل الحالة إلى أجزاء مستقلة، فبدلاً من كائن واحد، استخدم أكثر من useState، بتقسيم كائن filters إلى حالات مستقلة في ProductsPage.jsx: const [keyword, setKeyword] = useState(""); const [pageNumber, setPageNumber] = useState(1); const [formFilters, setFormFilters] = useState({ category: [], minPrice: 0, maxPrice: 2000, sort: "", }); وبما أن useFetchProducts يتوقع كائن واحد، فنستطيع تجميعه باستخدام useMemo، وبالتالي كائن الفلاتر لن يتم إنشاؤه من جديد إلا إذا تغيرت إحدى الحالات التي يعتمد عليها: import { useCallback, useState, useMemo } from "react"; // بعد تعريف الحالات المنفصلة const apiFilters = useMemo(() => ({ keyword, pageNumber, ...formFilters, }), [keyword, pageNumber, formFilters]); const { data, isPending: isProductsPending, isError: isProductsError, error: productsError, } = useFetchProducts(apiFilters); ثم إنشاء دوال المعالجة عن طريق useCallback مع dependencies صحيحة. const handleSearchProducts = useCallback((text) => { setKeyword(text.trim()); setPageNumber(1); }, []); const handlePageChange = useCallback((newPage) => { setPageNumber(newPage); }, []); const handleApplyFilters = useCallback((newFilters) => { setFormFilters(newFilters); setPageNumber(1); }, []); ثم تغليف المكونات الفرعية FormFilters, Search, Pagination بـ React.memo لتستفيد من الـ props المستقرة، في FormFilters.js: import React from 'react'; const FormFilters = ({ }) => { }; export default React.memo(FormFilters); وفي Search.js: import React from 'react'; const Search = ({ }) => { }; export default React.memo(Search);
- 2 اجابة
-
- 1
-
-
إذن المتغير buybillForm.BillItemsTable الذي تستخدمه لإضافة الصنف الجديد فارغ في كل مرة تبدأ فيها عملية الإضافة، قم بتجربة العمل على نفس نسخة الـ DataTable التي يستخدمها DataGridView كمصدر بيانات منذ البداية. أي يجب أن يكون فورم الإضافة لا ينشئ DataTable جديد، بل يحصل على مرجع للجدول الأصلي الموجود في buybillForm ويعمل عليه مباشرًة. بمعنى عن فتح فورم إضافة الصنف، قم بتمرير BillItemsTable الحالي إليه عبر الـ constructor وهو AddItemForm: AddItemForm addItemForm = new AddItemForm(this.BillItemsTable); addItemForm.ShowDialog(); ثم استقبل الـ DataTable في الـ constructor واحتفظ به في متغير خاص بالفورم. public partial class AddItemForm : Form { private DataTable currentBillItems; private BuyBillForm mainBuyBillForm; public AddItemForm(DataTable billItemsTable, BuyBillForm ownerForm) { InitializeComponent(); this.currentBillItems = billItemsTable; this.mainBuyBillForm = ownerForm; } } ثم استخدم المتغير المحلي currentBillItems بدلاً من buybillForm.BillItemsTable لكي تضمن أنك تضيف الصفوف إلى نفس الجدول المرتبط بالـ DataGridView. if (e.KeyCode == Keys.Enter) { try { int quantity = 0; decimal price = 0; if (!int.TryParse(qty.Text, out quantity) || !decimal.TryParse(label5.Text, out price)) { MessageBox.Show("تأكد من صحة إدخال الكمية أو السعر", "تنبيه", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } bool itemFound = false; foreach (DataRow row in this.currentBillItems.Rows) { if (row["item_code"]?.ToString() == label11.Text) { int oldQty = Convert.ToInt32(row["qty"]); row["qty"] = oldQty + quantity; row["total"] = Convert.ToDecimal(row["price"]) * Convert.ToInt32(row["qty"]); itemFound = true; MessageBox.Show("تم تحديث كمية الصنف بنجاح"); this.mainBuyBillForm.UpdateTotals(); break; } } if (!itemFound) { DataRow newRow = this.currentBillItems.NewRow(); newRow["item_name"] = label3.Text; newRow["item_date"] = label7.Text; newRow["qty"] = quantity; newRow["price"] = price; newRow["total"] = quantity * price; newRow["item_code"] = label11.Text; this.currentBillItems.Rows.Add(newRow); // الإضافة تتم على نفس الجدول الأصلي MessageBox.Show("تمت إضافة الصنف بنجاح"); this.mainBuyBillForm.UpdateTotals(); } } catch (Exception ex) { this.Dispose(); MessageBox.Show("حدث خطأ:\n" + ex.Message, "خطأ", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
-
يتوفر برنامج WARP من شركة Cloudflare على مختلف الأنظمة، أي متاح للويندوز والهواتف أيضًا، وهو أشبه بالـ VPN لكن لا يسمح لكِ بتغيير الـ IP لبلد معينة. آلية عمله هي تشفير الإتصال وحماية بياناتك، بالتالي مزود خدمة الإنترنت ISP الخاص بك أو أي شخص على نفس الشبكة العامة لا يمكنه رؤية المواقع التي تتصفحينها أو البيانات التي تتبادليها. كذلك توجيه بياناتك عبر مسارات أسرع وأقل ازدحاماً على شبكة الإنترنت، وذلك يؤدي إلى تحسين ملحوظ في سرعة الإنترنت في حال واجهتي بطيء في إتصال الإنترنت لديكِ. https://one.one.one.one/
-
لكل شخص طريقته المناسبة في الدراسة، تستطيع تجربة طرق مختلفة وإعتماد ما تجده أنسب لك، البعض يُفضل تدوين النقاط الهامة في مدونة ورقية أو رقمية، والبعض الآخر يُفضل الاستيعاب ثم الحفظ في البداية ثم التطبيق العملي، والأهم نقطة الاستيعاب حيث تستطيع البحث عما تريده في حال نسيته لا مشكلة لأنك استوعبته. الجزئية الأهم هو تجنب الدراسة السلبية، بمعنى المشاهدة كثيرًا وتجنب التطبيق العملي، لكن هناك توضيح هنا، التطبيق العملي لا أقصد به التطبيق بشكل حرفي مع الشرح، فنسبة الاستفادة هنا ليست كبيرة، بل استيعاب الشرح ثم التوقف والتطبيق بمفردك. ستجد تفصيل هنا:
- 2 اجابة
-
- 1
-
-
المشكلة ليست في إضافة البيانات، بل في عرضها، أي الـ DataGridView لا يقوم بتحديث نفسه تلقائيًا في كل الحالات عند تعديل الـ DataTable المرتبط به مباشرة، أي بحاجة إلى إشعار بأن البيانات قد تغيرت. وأبسط حل هو أن تخبر الـ DataGridView أن يعيد ربط نفسه بمصدر البيانات بعد إضافة الصف الجديد لإجباره على قراءة البيانات من جديد وعرضها. if (!itemFound) { DataRow newRow = buybillForm.BillItemsTable.NewRow(); newRow["item_name"] = label3.Text; newRow["item_date"] = label7.Text; newRow["qty"] = quantity; newRow["price"] = price; newRow["total"] = quantity * price; newRow["item_code"] = label11.Text; buybillForm.BillItemsTable.Rows.Add(newRow); // <<-- هنا -->> buybillForm.dataGridView1.DataSource = buybillForm.BillItemsTable; MessageBox.Show("تمت إضافة الصنف بنجاح"); } فعند تعيين خاصية DataSource مرة أخرى، سيتم إجبار الـ DataGridView على التخلص من العرض القديم للبيانات ورسم نفسه من جديد بناءًا على الحالة الحالية لـ BillItemsTable، والتي تحتوي الآن على الصف الجديد.
- 4 اجابة
-
- 1
-
-
الهدف من الدورة هو شرح أساسيات المفاهيم الخاصة بالبرمجة وعلوم الحاسوب من أجل التأسيس في مجال البرمجة، أي ستحصل على نظرة عامة للمجال ويصبح لديك وعي حقيقي به، وبعدها تستطيع اختيار المجال الذي تريد التخصص به واستكمال مسيرتك البرمجية. أي أنّ الدورة لا توفر تخصص في مجال برمجي محدد أو شرح تقنيات بعينها، وشرط الحصول على وظيفة المذكور في وصف الدورة هو حقك بالطبع، وتستطيع المناقشة حوله من خلال مركز المساعدة فهو المختص بالأمور المالية. وبعد الإنتهاء من الدورة وإجتياز الإختبار سيتم توجهيك وإرشادك لمدة 6 أشهر بعد التخرج. ستجد هنا تفصل لفائدة دورة علوم الحاسوب ليتضح لك الأمر:
- 3 اجابة
-
- 1
-
-
المتاح في الأكاديمية هي الدورات الخاصة بالبرمجة، أما فترات التدريب Internships فهي غير متاحة، تستطيعي البحث على مواقع التوظيف مثل LinkedIn و Indeed عن ذلك، وتفقدي المنشورات للأشخاص العاملين في ذلك التخصص فمن فترة لأخرى تجدي مثل تلك الفرص، لذا تحتاجين إلى متابعتهم. لكن تلك الفرص قليلة حاليًا، لذا الطريقة الأفضل للحصول على خبرة هي من خلال التدريب الذاتي وتنفيذ مشاريع قريبة من الواقع العملي وغير مستهلكة بمعنى تجنب المشاريع التي يقوم بها الجميع ومتاحة بكثرة على اليوتيوب. أيضًا العمل على مواقع العمل الحر طريقة جيدة لاكتساب خبرة والإحتكاك بالواقع العملي عن طريق التعامل مع العملاء وتنفيذ المشاريع وتفهم المطلوب، لكن تجنبي التقديم على عروض بدون خبرة جيدة لكي لا تحصلين على تقييمات سلبية، الفكرة الإلمام بما هو مطلوب بنسبة 70% على الأقل. بالنسبة لمصادر تعلم UI/UX تفقدي التالي: وبالنسبة للأمن السيبراني فغير متاح دورات له، وستجدي مصادر هنا:
-
متاح Oh My Posh على مختلف الأنظمة، وهو محرك ثيمات مفتوح المصدر، وظيفته تخصيص شكل ومحتوى التيرمنال، بجانب عرض معلومات إضافية مثل اسم الفرع الذي تعمل عليه حاليًا في Git، كذلك عرض معلومات إصدار Node.js أو Python النشطة. وهو قابل للتخصيص أي تستطيع التحكم في كل شيء تقريبًا سواء الألوان والأيقونات، المعلومات التي يتم عرضها أو ترتيب ظهورها وستجدها باسم Segment. ستجد هنا تفصيل لطريقة التثبيت والاستخدام: https://ohmyposh.dev/docs/installation/windows لكن قم بتثبيت الإصدار 7.3 من powershell لتجنب مشاكل في الإصدار 7.4: v7.3.12 Release of PowerShell
-
ما هو الكورس المقصود لتوضيح الأمر لك؟
-
لتصبح مبرمج جيد ستحتاج إلى التعمق أكثر بجانب الدرس والمشاهدة والقراءة، ولكن ليس بشكل متعمق كثيرًا فتنجرف وتضيع الوقت، أي خير الأمور الوسط، ثم بعد ذلك لو احتجت أمر ما تستطيع البحث عنه ودراسته. والتركيز على المفاهيم المؤثرة بنسبة كبيرة والتي ستسخدمها بنسبة كبيرة في المشاريع، وليس التركيز على الأمور الدقيقة التي تستخدمها بشكل قليل أو نادر. أي إتباع قاعدة 80/20. والفكرة ليس في التطبيق على كل 15 دقيقة، بل التطبيق على مفهوم معين تعلمته، مثلاً تعلمت أساسيات حلقات التكرار في بايثون، هنا تتوقف وتقوم بتنفيذ تمرين للتطبيق على ذلك المفهوم، وربط التمرين بما تعلمته سابقًا أي القوائم والمتغيرات والجمل الشرطية وهكذا. في حال كان الدرس طويل أو به مفاهيم مختلفة، أرجو قراءة التالي، ستجد به توضيح لما سبق:
- 5 اجابة
-
- 1
-
-
ذلك متاح من خلال مكتبة asyncio تماماً كما في جافاسكريبت، حيث تعتمد البرمجية الغير متزامنة في بايثون على ثلاثة أعمدة رئيسية، أولاً الـ Event Loop وهو المنسق أو المدير، لتتبع المهام وتوزيع وقت التنفيذ عليها. والـ Coroutines أو الروتينات المساعدة والتي هي الدوال التي يمكن إيقافها مؤقتًا واستئنافها لاحقًا، وفي بايثون، يتم تعريفها من خلال الكلمة المفتاحية async def وهي تعادل الدوال async في جافاسكريبت. والكلمة المفتاحية await هي الأداة التي تخبر الـ Event Loop، بأنها على وشك القيام بعملية تستغرق وقت مثل طلب للـ API أو قراءة ملف، لذا تعمل في الخلفية ويستمر البرنامج في العمل لحين أن تنتهي من عملها، وبالطبع الـ Event Loop هو ما يقوم بجدولة تلك المهام. وبيئة Node.js بالفعل Single-Threaded، لكنها تستعين بـ Worker Pool أو مجموعة عمال منفصلة مكتوبة بلغة C++ عبر مكتبة libuv لتنفيذ عمليات I/O الثقيلة، بالتالي العمل الفعلي للـ I/O يحدث خارج الـ Thread الرئيسي لجافاسكريبت. أما بايثون لديها ما يسمى بـ Global Interpreter Lock (GIL)، أي قفل وهو ما يضمن أن خيطًا واحدًا فقط يمكنه تنفيذ Python Bytecode في نفس اللحظة الزمنية، حتى لو كان لديك معالج متعدد النوى. وasyncio تعمل بالكامل داخل Single Thread، لذا الـ GIL ليس مشكلة بالنسبة لـ asyncio بما أن كل شيء يحدث في خيط واحد، فلا يوجد تنافس بين الخيوط على الـ GIL. فعندما تقوم دالة async بعمل await لعملية I/O مثل asyncio.sleep أو قراءة ملف، فمكتبة asyncio تتواصل مع نظام التشغيل من خلال آليات مثل select أو epoll لتسجيل العملية، وأثناء انتظار نظام التشغيل للرد، يتم تحرير الـ GIL، ولكن الأهم من ذلك، أن الـ Event Loop في بايثون تكون حرة لتشغيل Coroutine آخر في نفس الخيط.
-
الأمر يعود إليك، قم بمقارنة محتوى الدورتين واختر الأنسب لك، حيث دورة علوم الحاسوب تقدم لك التالي: أساسيات الحاسوب وعلومه والتفكير المنطقي وما هي الخوارزميات وكيف تفيد في البرمجة تطبيقات عملية على أساسيات التفكير المنطقي باستخدام بيئة سكراتش Scratch التفاعلية أساسيات لغة البرمجة JavaScript وتطبيق المفاهيم التي تم شرحها باستخدامها، والتوسع في شرح التطبيقات العملية للغات البرمجة أساسيات أنظمة التشغيل المختلفة وكيفية تثبيت البرمجيات اللازمة للبرمجة عليها أساسيات سطر الأوامر في نظام لينكس، وشرح الأسس التي بني عليها النظام مع تطبيقها عمليًا أنظمة قواعد البيانات المختلفة، مع شرح تفصيلي للغة SQL للتعامل معها مبادئ أساسية في أنظمة قواعد البيانات NoSQL المفاهيم الأساسية التي تبنى فيها صفحات الويب أساسيات بايثون والبرمجة كائنية التوجه مفاهيم أساسية في الشبكات والخوادم، وكيف يتم استقبال الطلبيات إلى الخادم والرد عليها مبادئ الحماية والأمان في الويب الخوارزميات وبنى المعطيات أنماط التصميم أساسيات هندسة البرمجيات وإعادة تصميم البرمجيات Refactoring بينما CS50x: تعلم كيفية التفكير وليس فقط كيفية البرمجة، فالهدف الأساسي للكورس هو تعليمك التفكير بشكل برمجي، أي كيفية تحليل المشاكل وتقسيمها إلى خطوات منطقية يمكن للحاسوب فهمها وحلها بكفاءة. التجريد والتغليف وهم مباديء في البرمجة الكائنية الخوارزميات هياكل البيانات إدارة الموارد الأمن هندسة البرمجيات C لفهم كيفية عمل الكمبيوتر على المستوى المنخفض. Python SQL للتعامل مع قواعد البيانات. JavaScript, HTML, CSS لتطوير وبناء مواقع الويب.