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

كل الأنشطة

تحدث تلقائيًا

  1. الساعة الماضية
  2. ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم الأسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  3. بعد ما اكتب الأوامر في أدوات المطور كيف أحفظ الأكواد دون تخريب ما كتبت
  4. لا داعي لذكر مدة زمنية محددة وإلزام نفسك بها، بل اطرح ما تستطيع فعله وذكر المهارات التي تمتلكها وما الفائدة التي ستعود على العميل من تلك المهارات فهو لا يدري ما معنى Full-Stack. ويجب أن تظهر بمظهر إحترافي ومنظم وعدم الإنجراف وراء ما يطرحه الآخرين. مع ذكر شرط أنه يتم تحديد مدة المشروع بناءًا على المتطلبات ومدى تعقيد المشروع، وعند إعطاء مدة زمنية للعميل قم بمضاعفتها ففي البداية لن تكون لديك خبرة بتحديد المدة اللازمة، وفي حال قمت بإنجاز المشروع في أقل من ذلك فستكون تلك نقطة جيدة لصالحك وليس العكس. يمكنك ذكر مثلاً أن تطبيق بسيط مكون من 5 صفحات يستغرق مدة زمنية تساوي كذا
  5. السلام عليكم، في موقع خمسات مثلا، حين أود أن أقدم خدمة، كإنشاء تطبيق واب أو هاتف من الصفر، بإستعمال React و React Nativeو Node، أي أن التطبيق Fullstack. كيف يمكنني تحديد المدة اللازمة لإنشاء التطبيق؟ أعني بذلك كيف يمكنني تحديد المجال الزمني المناسب و اللازم لإنشاء التطبيق؟ أعلم أنه ليست هناك إجابة محددة، كون تواجد العديد من العوامل المتحكمة و المتغيرات، كالخبرة و درجة تعقيد التطبيق وماشابه. ولكن على الأقل هناك ما يساعدني على تحديد مجال زمني مناسب ؟ شكرا مسبقا.
  6. اليوم
  7. قم بتثبيت مديز الحزم snap من خلال تنفيذ الأوامر التالية بالترتيب: sudo mv /etc/apt/preferences.d/nosnap.pref ~/Documents/nosnap.backup sudo apt update sudo apt install snapd ثم قم بتسجيل الخروج من حسابك وتسجيل الدخول مجددًا في النظام أو أعد تشغيل النظام. ثم تثبيت البرنامج من خلال: sudo snap install gabutdm
  8. كيف اثبت Gabut Sownload manager كيف تثبيته ومنه على لينكس منت صيغا التثييتbad
  9. لا يوجد بديل مماثل تمامًا، لكن لتحميل الفيديوهات من اليوتيوب يوجد أداة stacher توجه إلى موقع stacher.io لتحميلها. أما بالنسبة لبرامج تحميل ملفات مشابهة لبرنامج IDM، فيوجد: Motrix Gabut Download Manager jdownloader2
  10. لا حاجة إلى ذلك، في حال لديك البيانات الخاصة بالحساب وتتذكريها جيدًا، تستطيعي استرجاع الحساب من خلال مراسلة الدعم، توجهي للصفحة التالية من خلال هاتفك: https://www.instagram.com/hacked/ ثم اختاري my account was hacked ثم اضغطي على next، بعد ذلك عليك إدخال اسم المستخدم أو رقم الهاتف أو البريد للبحث عن حسابك ثم اضغطي على next. وسيتم سؤالك عن رفع صور للتعرف عليك وإثبات أنك صاحبة الحساب عليك الضغط على yes i have photos ثم سيطلب منك بريد إلكتروني أدخليه للتواصل معك وإرسال رابط إليه. بعد ذلك سيطلب منك تصوير نفسك بالكاميرا الأمامية للتعرف عليك وإتباع تعليمات التصوير مثل تدوير الوجه وخلافه. والآن انتظري يوم إلى يومين وسيتم إرسال بريد على الإيميل الذي أدخلتيه به رابط لاسترجاع الحساب.
  11. مرحبا احتاج خبير استعداد حساب مهكر في الانستقرام. الهكر غير الايميل و رقم التلفون و حط F2A. احتاج استراجعه باسرع وقت، مستعدة ادفع المبلغ المطلوب، بس بدي يرجعلي حسابي ضروري. ارجو الرد بسرعة
  12. البارحة
  13. أولاً لديك خطأ في حساب متوسط التقييمات في السطر الذي يحسب فيه المتوسط النهائي finalRate. فالمتغير rate ربما يتم إرساله كقيمة غير صحيحة مثل قيمة نصية من الواجهة الأمامية، لذا لنتأكد من أن rate يتم تحويله إلى رقم صحيح قبل استخدامه في الحساب، وأيضًا التأكد من صحة قيم التقييم المرسلة من الواجهة الأمامية. أيضًا بعد إضافة المراجعة إلى قاعدة البيانات، عليك إعادة بيانات الكتاب المحدثة إلى الواجهة الأمامية، بما في ذلك التقييم الجديد، وبعد تلقي بيانات الكتاب المحدثة من الخادم، يجب تحديث حالة الكتاب في الواجهة الأمامية لتعكس التقييم الجديد. ثم استخدام البيانات المحدثة للكتاب في المكون لعرض التقييم الجديد. إليك التعديلات مع تعليقات لتوضيح أماكن التعديل. تعديل في bookController.js: const addReview = asyncHandler(async(req, res) => { const { id } = req.params const { comment, rate } = req.body const book = await Book.findById(id) const user = await User.findById(req.userId) // التحقق من وجود الكتاب if (!book) { return res.status(404).json({ message: "Book Not Found" }) } // التحقق من أن المستخدم لم يقيم الكتاب مسبقاً const isRated = book.reviews.findIndex(m => m.user == req.userId) if (isRated > -1){ return res.status(403).send({ message: "Review Is Already Added" }); } // تحويل تقييم المستخدم إلى رقم صحيح والتحقق من صحته const numericRate = parseInt(rate, 10); if (isNaN(numericRate) || numericRate < 1 || numericRate > 5) { return res.status(400).send({ message: "Invalid rating value" }); } // حساب التقييم النهائي const totalRate = book.reviews.reduce((sum, review) => sum + review.rate ,0) const finalRate = (totalRate + numericRate) / (book.reviews.length + 1) // تحديث بيانات الكتاب بإضافة المراجعة الجديدة وتحديث التقييم await Book.updateOne( { _id: id }, { $push: { reviews: { user: req.userId, username: user.name, comment, rate: numericRate } }, $set: { rate: finalRate } } ) // إعادة بيانات الكتاب المحدثة بعد الإضافة const updatedBook = await Book.findById(id); res.status(201).json(updatedBook) }) تحديث الدالة postReview في apiCall: export function postReview(bookId, review) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.post(`${BOOK_URL}/${bookId}/reviews`, review, { headers: { "authorization": getState().auth.user.accessToken } }); // عرض رسالة نجاح باستخدام toast toast.success(data?.message) // تحديث بيانات الكتاب المحدثة في الحالة dispatch(bookActions.updateBook(data)); dispatch(bookActions.clearLoading()); } catch (error) { // عرض رسالة خطأ باستخدام toast toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } تعديل في الواجهة الأمامية Modal.js const Modal = ({ showModal, handleClose, book }) => { const [rate, setRating] = useState(0); const [comment, setComment] = useState(""); const dispatch = useDispatch(); const navigate = useNavigate(); const submitReview = (e) => { e.preventDefault(); if (comment === "") { // التحقق من وجود تعليق وعرض رسالة خطأ في حال عدم وجوده return toast.error("Comment is required") } // تحويل تقييم المستخدم إلى رقم صحيح والتحقق من صحته const numericRate = parseInt(rate, 10); if (isNaN(numericRate) || numericRate < 1 || numericRate > 5) { return toast.error("Invalid rating value"); } // إرسال المراجعة باستخدام الدالة postReview dispatch(postReview(book._id, { rate: numericRate, comment })) }; return ( <div className={`modal ${showModal ? "show" : ""}`}> <div className="modal-content"> <span className="close" onClick={handleClose}>&times;</span> <h2>Submit Your Review</h2> <form onSubmit={submitReview}> <div className="rating-input"> <label>Rating:</label> <select value={rate} onChange={(e) => setRating(e.target.value)} required> <option value="" disabled>Select a rating</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> </select> </div> <div className="comment"> <label>Comment:</label> <textarea value={comment} onChange={(e) => setComment(e.target.value)} required /> </div> <button className='modal-btn' type="submit">Submit</button> </form> </div> </div> ); }; export default Modal; تحديث bookSlice لتضمين الدالة updateBook: const bookSlice = createSlice({ name: "book", initialState: { books: [], error: false, loading: false, }, reducers: { getBooks(state, action) { state.books = action.payload; }, findBook(state, action) { state.books = action.payload; }, addReviews(state, action) { state.books = action.payload; }, updateBook(state, action) { // البحث عن الكتاب المحدث وتحديثه const updatedBook = action.payload; const index = state.books.findIndex(book => book._id === updatedBook._id); if (index !== -1) { state.books[index] = updatedBook; } }, setLoading(state) { state.loading = true; }, clearLoading(state) { state.loading = false; }, setError(state) { state.error = true; }, clearError(state) { state.error = false; }, } }); export const bookActions = bookSlice.actions; export default bookSlice.reducer;
  14. السلام عليكم. في المثال التالي، أواجه الأخطاء التالية: عندما أضيف Review معين (بين 1 و 5) فإنه يتم إرسال عدد أكبر من 5 إلى قاعدة البيانات لايتم إضافة التقييم إلى واجهة الصفحة إلا بعد التحديث الكود bookController // method POST // route api/books/:id/reviews // desc Add a book review // access Private | auth const addReview = asyncHandler(async(req, res) => { const { id } = req.params const { comment, rate } = req.body const book = await Book.findById(id) const user = await User.findById(req.userId) if (!book) { return res.status(404).json({ message: "Book Not Found" }) } const isRated = book.reviews.findIndex(m => m.user == req.userId) if (isRated > -1){ return res.status(403).send({ message: "Review Is Already Added" }); } const totalRate = book.reviews.reduce((sum, review) => sum + review.rate ,0) const finalRate = (totalRate + rate) / (book.reviews.length + 1) await Book.updateOne( { _id: id } , { $push: { reviews: { user: req.userId, username: user.name, comment, rate } }, $set: { rate: finalRate } } ) res.status(201).json({ message: "Review added successfully" }) }) Frontend apiCall // Post Review export function postReview(bookId, review) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.post(`${BOOK_URL}/${bookId}/reviews`, review, { headers: { "authorization": getState().auth.user.accessToken } }); toast.success(data?.message) dispatch(bookActions.addReviews()); dispatch(bookActions.clearLoading()); } catch (error) { toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } bookSlice const bookSlice = createSlice({ name: "book", initialState: { books: [], error: false, loading: false, }, reducers: { getBooks(state, action) { state.books = action.payload; }, findBook(state, action) { state.books = action.payload; }, addReviews(state, action) { state.books = action.payload; }, setLoading(state) { state.loading = true; }, clearLoading(state) { state.loading = false; }, setError(state) { state.error = true; }, clearError(state) { state.error = false; }, } } Component const Modal = ({ showModal, handleClose, book }) => { const [rate, setRating] = useState(0); const [comment, setComment] = useState(""); const dispatch = useDispatch(); const navigate = useNavigate(); const submitReview = (e) => { e.preventDefault(); if (comment === "") { return toast.error("Comment is required") } dispatch(postReview(book, { rate, comment })) navigate(`/${book}`) }; return ( <div className={`modal ${showModal ? "show" : ""}`}> <div className="modal-content"> <span className="close" onClick={handleClose}>&times;</span> <h2>Submit Your Review</h2> <form onSubmit={submitReview}> <div className="rating-input"> <label>Rating:</label> <select value={rate} onChange={(e) => setRating(e.target.value)} required> <option value="" disabled>Select a rating</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> </select> </div> <div className="comment"> <label>Comment:</label> <textarea value={comment} onChange={(e) => setComment(e.target.value)}/> </div> <button className='modal-btn' type="submit">Submit</button> </form> </div> </div> ); }; export default Modal; شكرا على المساعدة
  15. سنشرح في هذا المقال نوع البيانات المسمى بالقاموس dictionary، الذي يوفر طريقة مرنة للوصول إلى البيانات وتنظيمها، ثم سنتعلم كيفية كتابة لعبة إكس-أو عبر دمج ما تعلمناه في المقالات السابقة من هذه السلسلة مع القواميس. نوع البيانات dictionary القواميس تشبه القوائم في أنها مجموعة قابلة للتعديل mutable من القيم، لكن بدلًا من وجود الفهارس الرقمية للعناصر كما في القوائم، يمكن استخدام مختلف أنواع البيانات في القواميس. نسمي المفاتيح في القواميس بالمفاتيح keys، وكل مفتاح مرتبط بقيمة، ونسمي ذلك زوجًا من المفاتيح والقيم key-value pair. نكتب القواميس في بايثون بإحاطها بقوسين مجعدين أو معقوصين {}: >>> myCat = {'size': 'fat', 'color': 'gray', 'disposition': 'loud'} السطر السابق يسند قاموسًا إلى المتغير myCat، ومفاتيح هذا القاموس هي 'size' و 'color' و 'disposition'، والقيم المرتبطة بتلك المفاتيح هي 'fat' و 'gray' و 'loud' على التوالي وبالترتيب. يمكنك الوصول إلى هذه القيم عبر مفاتيحها: >>> myCat['size'] 'fat' >>> 'My cat has ' + myCat['color'] + ' fur.' 'My cat has gray fur.' ما يزال بالإمكان استخدام الأعداد الصحيحة مفاتيحًا لقيم القواميس، لكن ليس من الضروري أن تبدأ من الصفر 0 ويمكنك استخدام أي رقم: >>> spam = {12345: 'Luggage Combination', 42: 'The Answer'} مقارنة القواميس والقوائم على خلاف القوائم، لا تكون القواميس مرتبةً، فأول عنصر في قائمة اسمها spam سيكون spam[0]‎، لكن لا يوجد «أول» عنصر في القاموس. سيكون ترتيب العناصر مهمًا في حال أردنا تحديد إن كانت قائمتان متساويتين، بينما لا يفرق ترتيب كتابة أزواج المفاتيح-القيم في القواميس: >>> spam = ['cats', 'dogs', 'moose'] >>> olive = ['dogs', 'moose', 'cats'] >>> spam == olive False >>> eggs = {'name': 'Zophie', 'species': 'cat', 'age': '8'} >>> steak = {'species': 'cat', 'age': '8', 'name': 'Zophie'} >>> eggs == steak True ولأن القواميس غير مرتبة، فلا يمكن تقسيمها كما في القوائم. محاولة الوصول إلى مفتاح غير موجود في قاموس ما سيؤدي إلى حدوث الخطأ KeyError، وهي تشبه رسالة الخطأ IndexError في القوائم حين محاولة الوصول إلى قيمة خارج مجال فهارس القائمة. لاحظ رسالة الخطأ الآتية التي تظهر لعدم وجود المفتاح 'color': >>> spam = {'name': 'Zophie', 'age': 7} >>> spam['color'] Traceback (most recent call last): File "<pyshell#1>", line 1, in <module> spam['color'] KeyError: 'color' وصحيحٌ أن القواميس غير مرتبة، لكن إمكانية استخدام أي قيمة تريدها للمفاتيح يسمح لنا بترتيب البيانات بطرائق رائعة! لنقل أننا نريد كتابة برنامج يخزن معلومات حول أعياد ميلاد أصدقائك، يمكنك أن تكتب الشيفرة الآتية birthdays.py التي تستخدم القواميس وتجعل أسماء أصدقائك مفاتيحًا للقيم: ➊ birthdays = {'Alice': 'Apr 1', 'Bob': 'Dec 12', 'Carol': 'Mar 4'} while True: print('Enter a name: (blank to quit)') name = input() if name == '': break ➋ if name in birthdays: ➌ print(birthdays[name] + ' is the birthday of ' + name) else: print('I do not have birthday information for ' + name) print('What is their birthday?') bday = input() ➍ birthdays[name] = bday print('Birthday database updated.') أنشأنا قاموسًا وخزناه في المتغير birthdays ➊، ثم تحققنا إن كان الاسم المدخل موجودًا في القاموس عبر الكلمة المحجوزة in ➋ كما كنا نفعل مع القوائم. إذا كان الاسم موجودًا في القاموس فيمكنك الوصول إلى القيمة المرتبطة به عبر استخدام الأقواس المربعة ➌، وإلّا فيمكنك إضافتها باستخدام صيغة الأقواس المربعة مع عامل الإسناد ➍: Enter a name: (blank to quit) Alice Apr 1 is the birthday of Alice Enter a name: (blank to quit) Eve I do not have birthday information for Eve What is their birthday? Dec 5 Birthday database updated. Enter a name: (blank to quit) Eve Dec 5 is the birthday of Eve Enter a name: (blank to quit) للأسف ستحذف كل المعلومات التي أدخلتها في هذا البرنامج حين انتهاء تنفيذه. ستتعلم كيفية حفظ الملفات على القرص في مقال لاحق من هذه السلسلة. القواميس المرتبة في بايثون 3.7 صحيح أن القواميس غير مرتبة ولا يوجد فيها عنصر «أول»، لكن القواميس في الإصدار 3.7 من بايثون وما يليه ستتذكر ترتيب أزواج القيم الموجودة فيها حين إنشاء متسلسل sequence منها. فمثلًا لاحظ أن ترتيب العناصر في القائمتين المنشأتين من القاموسين eggs و steak يطابق ترتيب إدخالها: >>> eggs = {'name': 'Zophie', 'species': 'cat', 'age': '8'} >>> list(eggs) ['name', 'species', 'age'] >>> steak = {'species': 'cat', 'age': '8', 'name': 'Zophie'} >>> list(steak) ['species', 'age', 'name'] ستبقى القواميس غير مرتبة، ولا يمكنك أن تصل إلى العناصر فيها عبر فهرس رقمي مثل eggs[0]‎ أو steak[2]‎، لا يجدر بك الاعتماد على هذا السلوك لأن بايثون لا تتذكر ترتيب إدخال العناصر في الإصدارات القيمة منها، فلاحظ المثال الآتي الذي لا يطابق ترتيب عناصر القاموس الناتج النهائي الترتيبَ الذي أدخلتها به، ناتج التنفيذ الآتي على إصدار بايثون 3.5: >>> spam = {} >>> spam['first key'] = 'value' >>> spam['second key'] = 'value' >>> spam['third key'] = 'value' >>> list(spam) ['first key', 'third key', 'second key'] التوابع keys()‎ و values()‎ و items()‎ هنالك ثلاثة توابع خاصة بالقواميس التي تعيد قيمًا شبيهة بالقوائم list-like من مفاتيح القواميس أو قيمها أو كلًا من المفاتيح والقيم معًا وهي التوابع keys()‎ و values()‎ و items()‎ بالترتيب. القيم المعادة من هذه التوابع ليست قوائم حقيقيةً، فلا يمكننا تعديلها وليس لها التابع append()‎، لكن أنواع البيانات المعادة (وهي dictkeys و dictvalues و dict_items بالترتيب) يمكن أن تستخدم في حلقات التكرار for: >>> spam = {'color': 'red', 'age': 42} >>> for v in spam.values(): ... print(v) red 42 ستمر حلقة for هنا على كل قيمة في القاموس spam، يمكن لحلقة for المرور على المفاتيح فقط، وعلى المفاتيح والقيم معًا: >>> for k in spam.keys(): ... print(k) color age >>> for i in spam.items(): ... print(i) ('color', 'red') ('age', 42) حين استخدامنا للتوابع keys()‎ و values()‎ و items()‎ فيمكن للحلقة for المرور على قيم المفاتيح أو قيم العناصر أو قيم أزواج المفتاح-القيمة على التوالي. لاحظ أن القيم المعادة من items()‎ هي صفوف tuples تحتوي على المفتاح ثم قيمته. إذا أردتَ قائمةً حقيقية من ناتج أحد تلك التوابع، فيمكننا تمرير القيمة الشبيهة بالقوائم إلى الدالة list()‎ كما يلي: >>> spam = {'color': 'red', 'age': 42} >>> spam.keys() dict_keys(['color', 'age']) >>> list(spam.keys()) ['color', 'age'] يأخذ السطر list(spam.keys())‎ القيمة ذات النوع dict_keys المعادة من التابع keys()‎ ويمررها إلى الدالة list()‎، والتي تعيد بدورها قائمةً فيها ['color', 'age']. يمكنك استخدام الإسناد المتعدد مع حلقة for لإسناد المفتاح والقيمة إلى متغيرات منفصلة: >>> spam = {'color': 'red', 'age': 42} >>> for k, v in spam.items(): ... print('Key: ' + k + ' Value: ' + str(v)) Key: age Value: 42 Key: color Value: red التحقق من وجود مفتاح أو قيمة في قاموس نتذكر من المقال السابق أن العاملين in و not in يمكن أن يستخدما للتحقق من وجود قيمة في قائمة. ويمكننا استخدام نفس العاملين للتحقق من وجود قيمة ما في مفتاح أو قيمة في قاموس: >>> spam = {'name': 'Zophie', 'age': 7} >>> 'name' in spam.keys() True >>> 'Zophie' in spam.values() True >>> 'color' in spam.keys() False >>> 'color' not in spam.keys() True >>> 'color' in spam False لاحظ أن كتابة ‎'color' in spam هي مطابقة لكتابة ‎'color' in spam.keys()‎. فإذا أردت التحقق من وجود (أو عدم وجود) مفتاح ما في قاموس فاستعمل الكلمة المحجوزة in (أو not in) مع القاموس نفسه. التابع get()‎ من الرتيب أن نتحقق من وجود مفتاح ما في القاموس قبل الوصول إلى القيمة المرتبطة به، لكن لحسن الحظ هنالك تابع باسم get()‎ يأخذ وسيطين: الأول هو المفتاح الذي نريد الوصول إلى قيمته، والثاني هو قيمة افتراضية ستعاد إن لم يكن المفتاح موجودًا: >>> picnicItems = {'apples': 5, 'cups': 2} >>> 'I am bringing ' + str(picnicItems.get('cups', 0)) + ' cups.' 'I am bringing 2 cups.' >>> 'I am bringing ' + str(picnicItems.get('eggs', 0)) + ' eggs.' 'I am bringing 0 eggs.' ولعدم وجود المفتاح 'eggs' في القاموس picnicItems فستعاد القيمة 0 من التابع get()‎، وإن لم نستعمل التابع get()‎ في المثال السابق فستظهر رسالة خطأ كما يلي: >>> picnicItems = {'apples': 5, 'cups': 2} >>> 'I am bringing ' + str(picnicItems['eggs']) + ' eggs.' Traceback (most recent call last): File "<pyshell#34>", line 1, in <module> 'I am bringing ' + str(picnicItems['eggs']) + ' eggs.' KeyError: 'eggs' التابع setdefault()‎ الحاجة إلى ضبط قيمة في القاموس مرتبطة بمفتاح معين إن لم يكن ذاك المفتاح موجودًا مسبقًا هو أمرٌ شائع، وتكون الشيفرة بالشكل الآتي: spam = {'name': 'Pooka', 'age': 5} if 'color' not in spam: spam['color'] = 'black' يوفر التابع setdefault()‎ طريقة أسهل لفعل ذلك بسطر برمجي وحيد، فأول وسيط يمرر إلى التابع هو المفتاح الذي سنتحقق من وجوده، والوسيط الثاني هو القيمة التي ستُضبَط إن لم يكن المفتاح موجودًا. إذا كان المفتاح موجودًا فسيعيد التابع setdefault()‎ قيمة ذاك المفتاح: >>> spam = {'name': 'Pooka', 'age': 5} >>> spam.setdefault('color', 'black') 'black' >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} >>> spam.setdefault('color', 'white') 'black' >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} حينما استدعينا التابع setdefault()‎ أول مرة، فتغيرت قيمة القاموس spam إلى ‎{'color': 'black', 'age': 5, 'name': 'Pooka'}‎، وسيعيد التابع setdefault()‎ القيمة 'black' لأنها القيمة المضبوطة للمفتاح 'color' حاليًا. لكن حين استدعاء spam.setdefault('color', 'white')‎ فإن القيمة لن تتغير إلى 'white' لأن القاموس spam يحتوي على مفتاح باسم 'color'. التابع setdefault()‎ هو اختصار جميل للتأكد من وجود مفتاح معين وضبط قيمته. هذا مثال عن برنامج يعدّ عدد مرات وجود كل حرف في سلسلة نصية. احفظ المثال الآتي باسم characterCount.py: message = 'It was a bright cold day in April, and the clocks were striking thirteen.' count = {} for character in message: ➊ count.setdefault(character, 0) ➋ count[character] = count[character] + 1 print(count) سيمر البرنامج على كل محرف في السلسلة النصية المخزنة في المتغير message، ويعد كم مرة يظهر فيها كل محرف. استدعاء الدالة setdefault()‎ ➊ سيضمن وجود المفتاح في القاموس count ويضبط قيمته الافتراضية إلى 0، وبالتالي لا يرمي البرنامج الخطأ KeyError حين تنفيذ التعبير البرمجي count[character] = count[character] + 1 ➋. سيبدو الناتج كما يلي: {' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, 'a': 4, 'c': 3, 'b': 1, 'e': 5, 'd': 3, 'g': 2, 'i': 6, 'h': 3, 'k': 2, 'l': 3, 'o': 2, 'n': 4, 'p': 1, 's': 3, 'r': 5, 't': 6, 'w': 2, 'y': 1} سترى من الناتج السابق أن الحرف c الصغير مكرر 3 مرات، بينما الفراغ مكرر 13 مرة، والحرف A الكبير يظهر مرة واحدة. سيعمل البرنامج السابق على جميع السلاسل النصية بغض النظر عن محتويات المتغير message حتى لو كان يحتوي على مليون حرف! تجميل الطباعة إذا استوردت الوحدة pprint في برامجك، فيمكنك الوصول إلى الدالتين pprint()‎ و pformat()‎ التي «تجمل طباعة» pretty print قيم القواميس، ستستفيد من هذه الدوال إن أردت عرض قيم القواميس عرضًا أجمل من طريقة عرض الدالة print()‎، لنعدل المثال السابق: import pprint message = 'It was a bright cold day in April, and the clocks were striking thirteen.' count = {} for character in message: count.setdefault(character, 0) count[character] = count[character] + 1 pprint.pprint(count) سيظهر لنا الناتج الجميل الآتي: {' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, --snip-- 't': 6, 'w': 2, 'y': 1} سنستفيد فعليًا من الدالة pprint.pprint()‎ عندما يحتوي القاموس على قوائم أو قواميس متشعبة داخله nested. إذا أردت الحصول على قيمة النص المجمّل بدلًا من طباعته على الشاشة مباشرةً، فاستدعِ الدالة pprint.pformat()‎. السطران الآتيان متكافئان تمامًا: pprint.pprint(someDictionaryValue) print(pprint.pformat(someDictionaryValue)) استخدام بنى المعطيات لنمذجة عناصر حقيقية كان بإمكاننا لعب الشطرنج مع شخص آخر عن بعد قليل ظهور الإنترنت، فكان يعد كل لاعب رقعة الشطرنج في منزله، ثم يبادلان الرسائل البريدية يصف كل منهما خطوته، ولكي يستطيعوا فعل ذلك كان لاعبو الشطرنج بحاجة إلى وصف حالة رقعة الشطرنج والحركات التي يجريها وصفًا لا لبس فيه. تمثل الفراغات في رقعة الشطرنج في التأشير الجبري Algebraic chess notation بإحداثيات تتألف من حرف ورقم كما في الشكل 5-1. الشكل 5-1: إحداثيات رقعة الشطرنج في التأشير الجبري تُعرّف قطع الشطرنج بالأحرف: K للملك king، و Q للملكة queen (يسميها البعض بالوزير)، و R للقلعة rook، و B للفيل bishop، و N للحصان knight. أما الجنود فلا رمز لهم. يكون وصف الحركات متألفًا من الحرف الذي يمثل القطعة، وإحداثيات الوجهة. وزوج من تلك الحركات يصف ما يحدث في دورٍ واحد (بفرض أن صاحب اللون الأبيض يبدأ أولًا)؛ فمثلًا التأشير 2‎. Nf3 Nc6 يعني أن الأبيض حرك الحصان إلى f3 والأسود حرك الحصان إلى c6 في الدور الثاني من اللعبة. هنالك المزيد من القواعد للتأشير الجبري للشطرنج، لكن الفكرة التي أحاول إيصالها هي أننا نستطيع وصف لعبة الشطرنج دون الحاجة إلى أن نكون أمام رقعة، ويمكن أن يكون خصمك في الطرف الثاني من الكوكب، وإذا كانت لديك ذاكرة ومخيلة جيدة فلا تحتاج إلى رقعة شطرنج حقيقية من الأساس: فيمكنك أن تقرأ الحركات من الرسائل البريدية وتحدِّث الرقعة الموجودة في مخيلتك! تمتلك الحواسيب ذواكر رائعة، فيمكن أن يخزن الحاسوب مليارات السلاسل النصية من الشكل ‎'2. Nf3 Nc6'‎، وبهذا يمكن أن تلعب الحواسيب الشطرنج دون لوحة حقيقية؛ فما تفعله الحواسيب هو نمذجة البيانات لتمثيل رقعة الشطرنج، ويمكنك كتابة شيفرة تفعل ذلك بنفسك. هنا تلعب القوائم والقواميس دورها، فمثلًا القاموس ‎{'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', '5h': 'bqueen', '3e': 'wking'}‎ يمثل الرقعة في الشكل 5-2: الشكل 5-2: رقعة شطرنج منمذجة وفق قيمة قاموس لكن لمثالنا القادمة سنستعمل لعبة أسهل وأبسط من الشطرنج وهي لعبة إكس-أو. لعبة إكس-أو لعبة إكس-أو (تسمى بالإنكليزية tic-tac-toe) تشبه رمز # كبير فيه 9 خانات يمكن أن تكون قيمها X أو O أو أن تكون فارغة. لتمثيل هذه الرقعة بقاموس، فيجب أن نسند لكل خانة زوجًا من المفتاح-القيمة كما في الشكل 5-3. الشكل 5-3: خانات رقعة إكس-أو مع المفاتيح الموافقة لها يمكنك استخدام القيم النصية لتمثيل ما هو موجود في كل خانة في الرقعة: 'x' أو 'o' أو ' ' (فراغ)، وبالتالي نحتاج إلى تسع سلاسل نصية، يمكنك استخدام قاموس من القيم لهذا الأمر، فالقيمة النصية المرتبطة مع المفتاح 'top-R' تمثل القيمة في الركن العلوي الأيمن، والسلسل النصية المرتبطة مع المفتاح 'low-L' تمثل الركن السفلي الأيسر، والسلسلة النصية المرتبطة مع المفتاح 'mid-m' تمثل المنتصف، وهلم جرًا للبقية. هذا القاموس هو بنية معطيات تمثل رقعة لعبة إكس-أو، ولنخزن هذا القاموس في متغير باسم theBoard، ولنحفظ الشيفرة الآتية في ملف باسم ticTacToe.py: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} بنية المعطيات المخزنة في المتغير theBoard تمثل رقعة إكس-أو الموضحة في الشكل 5-4. الشكل 5-4: لوحة إكس-أو فارغة ولما كانت قيمة كل مفتاح في القاموس theBoard هي فراغ واحد فيمثل ذاك القاموس رقعةً فارغةً تمامًا. وإذا بدأت اللاعب X واختار الخانة في المنتصف تمامًا فسيصبح القاموس الذي يمثل الرقعة على الشكل: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': 'X', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} أصبحت بنية المعطيات theBoard تمثل الرقعة الموضحة في الشكل 5-5. الشكل 5-5: الحركة الأولى وتكون رقعة ربح فيها اللاعب O بوضع الشكل O في الصف العلوي كما يلي: theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O', 'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': 'X'} وهي ممثلة في الشكل 5-6. الشكل 5-6: ربح اللاعب O وبالتأكيد لا يستطيع أن يرى اللاعب إلا ما يطبع على الشاشة أمامه، ولا يعرف محتويات المتغيرات، فلننشئ دالةً تطبع القاموس الذي يحتوي على الرقعة على الشاشة. أضف ما يلي إلى ملف ticTacToe.py: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} def printBoard(board): print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) printBoard(theBoard) حينما تشغل هذا البرنامج فستطبع رقعة إكس-أو فارغة: | | -+-+- | | -+-+- | | يمكن أن تتوالى الدالة printBoard()‎ أي بنية معطيات تمثل رقعة إكس-أو تمررها إليها، جرب تغيير الشيفرة إلى ما يلي: theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O', 'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': 'X'} def printBoard(board): print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) printBoard(theBoard) ستعرض الرقعة الآتية على الشاشة: O|O|O -+-+- X|X| -+-+- | |X ولأنك أنشأت بنية معطيات تمثل لوحة إكس-أو وكتبت الشيفرة في printBoard()‎ التي تفسر بنية المعطيات وتظهر الرقعة، فأنت كتبت برنامجًا «ينمذج» models رقعة إكس-أو. كان بإمكانك تنظيم البيانات في بنية المعطيات بطريقة مختلفة، فمثلًا يمكنك استخدام المفتاح 'TOP-LEFT' بدلًا من 'top-L'، لكن طالما كانت شيفرتك تعمل مع بنية المعطيات التي لديك، فأنت كتبت عملية النمذجة بشكل صحيح. فمثلًا تتوقع الدالة printBoard()‎ أن بنية المعطيات التي تمثل الرقعة هي قاموس فيه مفاتيح لجميع الخانات التسع، لكن إن كان في قاموسك مفتاحٌ ناقص وليكن 'mid-L' فلن يعمل برنامجك: O|O|O -+-+- Traceback (most recent call last): File "ticTacToe.py", line 10, in <module> printBoard(theBoard) File "ticTacToe.py", line 6, in printBoard print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) KeyError: 'mid-L' لنضف الآن الشيفرة التي تسمح للاعبين بإدخال حركاتهم. لنعدل برنامجنا ليبدو كما يلي: theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} def printBoard(board): print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) turn = 'X' for i in range(9): ➊ printBoard(theBoard) print('Turn for ' + turn + '. Move on which space?') ➋ move = input() ➌ theBoard[move] = turn ➍ if turn == 'X': turn = 'O' else: turn = 'X' printBoard(theBoard) الشيفرة الجديدة تطبع اللوحة في بداية كل دور ➊ ثم تطلب المدخلات من اللاعب الحالي ➋ ثم تحدث الرقعة وفقًا لذلك ➌ ثم تبدل اللاعب الحالي ➍ قبل الانتقال إلى الدور القادم. | | -+-+- | | -+-+- | | Turn for X. Move on which space? mid-M | | -+-+- |X| -+-+- | | --snip-- O|O|X -+-+- X|X|O -+-+- O| |X Turn for X. Move on which space? low-M O|O|X -+-+- X|X|O -+-+- O|X|X صحيحٌ أن البرنامج ليس لعبة إكس-أو كاملة، فلن يتحقق إن ربح أحد اللاعبين مثلًا؛ لكنه كافٍ لمعرفة كيفية استخدام بنى المعطيات في برامج حقيقية. القواميس والقوائم المتشعبة نمذجة لوحة إكس-أو هو أمر سهل: تحتاج اللوحة إلى قاموس فيه 9 مفاتيح تمثل خاناتها. لكن إن أردت نموذج أمور أكثر تعقيدًا فستجد أنك تحتاج إلى القواميس والقوائم التي تحتوي على قواميس وقوائم أخرى داخلها. تناسب القوائم تخزين سلسلة مرتبة من القيم، بينما تفيد القواميس بتخزين قواميس التي ترتبط فيها المفاتيح مع القيم. هذا مثال يستعمل قاموسًا يحتوي على قواميس داخله فيها الأغراض التي أتى بها الضيوف إلى الرحلة. يمكن أن تقرأ الدالة totalBrought()‎ بنية المعطيات وتحسب العدد الكلي للعناصر المجلوبة من كل الضيوف: allGuests = {'Alice': {'apples': 5, 'pretzels': 12}, 'Bob': {'steak sandwiches': 3, 'apples': 2}, 'Carol': {'cups': 3, 'apple pies': 1}} def totalBrought(guests, item): numBrought = 0 ➊ for k, v in guests.items(): ➋ numBrought = numBrought + v.get(item, 0) return numBrought print('Number of things being brought:') print(' - Apples ' + str(totalBrought(allGuests, 'apples'))) print(' - Cups ' + str(totalBrought(allGuests, 'cups'))) print(' - Cakes ' + str(totalBrought(allGuests, 'cakes'))) print(' - Steak Sandwiches ' + str(totalBrought(allGuests, 'steak sandwiches'))) print(' - Apple Pies ' + str(totalBrought(allGuests, 'apple pies'))) داخل الدالة totalBrought()‎ هنالك حلقة for تدور على أزواج مفتاح-قيمة في المتغير guests ➊، وسنسند داخل الحلقة اسم كل ضيف إلى المتغير k، وسنسند القاموس الذي يحتوي على قائمة الأغراض التي سيجلبها معه إلى الرحلة إلى المتغير v. إذا كان أحد المعامل item موجودة في القاموس، فستضاف قيمته (كمية الأغراض المجلوبة) إلى المتغير numBrought ➋، لكن إذا لم يكن المفتاح موجودًا فيسعيد التابع get()‎ القيمة 0 لإضافتها إلى numBrought. سيكون ناتج تنفيذ البرنامج كما يلي: Number of things being brought: - Apples 7 - Cups 3 - Cakes 0 - Steak Sandwiches 3 - Apple Pies 1 قد يبدو لك أن حالة الاستخدام السابقة بسيطة ولا حاجة إلى نمذجتها، لكن فكر أن الدالة totalBrought()‎ يمكن أن تتعامل بسهولة مع قاموس يحتوي على آلاف الضيوف، وكل ضيف يجلب آلاف العناصر، وتنظيم هذه المعلومات في بنية معطيات واضحة ووجود الدالة totalBrought()‎ سيوفر عليك وقتًا كثيرًا. يمكنك أن تنمذج العناصر في بنى المعطيات بالطريقة التي تراها مناسبة، لطالما كانت بقية الشيفرة في برنامج قادرةً على التعامل مع بنية المعطيات المنشأة. حينما تبدأ البرمجة فلا تقلق أن تنمذج البيانات بالطريقة «الصحيحة»، فكلما ازدادت خبرتك أصبحت تخطر ببالك طرائق أكثر فاعلية وكفاءة للنمذجة، لكن أهم ما في الأمر أن تعمل بنية المعطيات مع احتياجات برنامجك. الخلاصة يمكن أن تحتوي القوائم والقواميس على عدّة قيم، بما فيها قوائم وقواميس أخرى. القواميس مفيدة لأنك تستطيع ربط مفتاح معين مع قيمة، على عكس القوائم التي هي سلسلة من القيم المرتبة. يمكن الوصول إلى القيم داخل القاموس عبر استخدام الأقواس المربعة كما في القوائم، لكن بدلًا من استخدام فهرس رقمي فيمكن أن تكون المفاتيح في القواميس من مختلف القيم سواءً كانت أعدادًا صحيحةً أو أعدادًا عشريةً أو سلاسل نصية أو صفوف tuples. يمكنك تمثيل الكائنات الحقيقية بتنظيم قيم البرنامج في بنى المعطيات، ورأينا مثال ذلك عمليًا على لعبة إكس-أو. مشاريع تدريبية لكي تتدرب، اكتب برامج لتنفيذ المهام الآتية. مدقق لقواميس الشطرنج استعملنا في هذا المقال قيمةً مثل ‎{'1h': 'bking', '6c': 'wqueen', '2g': 'bbishop', '5h': 'bqueen', '3e': 'wking'}‎ لتمثيل رقعة الشطرنج. اكتب دالةً باسم isValidChessBoard()‎ التي تقبل وسيطًا هو قاموس وتعيد القيمة True أو False اعتمادًا إن كان القاموس صالحًا لتمثيل رقعة الشطرنج. تحتوي الرقعة السليمة على ملك أسود واحد وملك أبيض واحد. ويمكن لأيٍ من اللاعبين امتلاك 16 قطعة كحد أقصى، و 8 جنود كحد أقصى، ويجب أن تكون جميع القطع في المجال بين 1a و 8h، أي لا يمكن أن تكون القطعة في المكان 9z. يجب أن تبدأ أسماء القطع بحرف w أو b لتمثيل اللونين الأبيض أو الأسود، متبوعًا بإحدى الكلمات pawn أو knight أو bishop أو rook أو queen أو king. قائمة الأدوات في لعبة نحن نعمل على لعبة فيها قائمة أدوات يمكن أن يمتلكها اللاعب، والتي سننمذجها باستخدام بنية معطيات تتألف من قاموس تكون فيه مفاتيحه هي سلاسل نصية تصف القيمة الموجودة في قائمة الأدوات، وقيمتها هي عدد نصي يمثل عدد الأدوات التي يمتلكها اللاعب مثلًا القاموس ‎{'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}‎ تعني أن اللاعب يملك حبلًا واحدًا، و 6 شعلات، و 42 قطعة ذهبية …إلخ. اكتب دالةً باسم displayInventory()‎ التي تأخذ أي قاموس يمثل قائمة أدوات ويعرضه بالشكل: Inventory: 12 arrow 42 gold coin 1 rope 6 torch 1 dagger Total number of items: 62 تلميح: يمكنك استخدام حلقة for للمرور على جميع المفاتيح في القاموس: # inventory.py stuff = {'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12} def displayInventory(inventory): print("Inventory:") item_total = 0 for k, v in inventory.items(): # أكمل الشيفرة هنا print("Total number of items: " + str(item_total)) displayInventory(stuff) دالة تحويل قائمة إلى قاموس في لعبة لنفترض أن لاعبنا في اللعبة السابقة قد حصل على غنيمة ممثلة في القائمة الآتية: playerLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby'] اكتب دالةً باسم addToInventory(inventory, addedItems)‎ حيث أن المعامل inventory هو قاموس يمثل قائمة أدوات اللاعب (كما في المثال السابق) والمعامل addedItems يشبه المتغير playerLoot. يجب أن تعيد الدالة addToInventory()‎ قاموسًا يمثل قائمة الأدوات المحدثة. لاحظ أن القائمة الموجودة في addedItems قد تحتوي على عدة نسخ من نفس الأداة. يفترض أن تكون شيفرتك شبيهة بما يلي: def addToInventory(inventory, addedItems): # اكتب الدالة هنا inv = {'gold coin': 42, 'rope': 1} dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby'] inv = addToInventory(inv, dragonLoot) displayInventory(inv) يجب أن يظهر البرنامج السابق (مع الدالة displayInventory()‎ من المثال السابق) الناتج الآتي: Inventory: 45 gold coin 1 rope 1 ruby 1 dagger Total number of items: 48 ترجمة -بتصرف- للفصل Dictionaries And Structuring DATA من كتاب Automate the Boring Stuff with Python. اقرأ أيضًا المقال السابق: القوائم Lists في لغة بايثون أنواع البيانات والعمليات الأساسية في لغة بايثون تعلم لغة بايثون النسخة العربية الكاملة لكتاب البرمجة بلغة بايثون
  16. في البداية بدون دراية برمجية لن تتمكن من التعديل والتطوير، يجب الإلمام بلغة PHP لفعل ذلك بجانب لغات الويب HTML, CSS, JS. أولاً، عليك تثبيت Smarty: composer require smarty/smarty ثم قم بتهيئة Smarty في ملف PHP الرئيسي، ولنفترض أن ملفك الرئيسي هو index.php. <?php require_once 'vendor/autoload.php'; $smarty = new Smarty(); $smarty->setTemplateDir(__DIR__ . '/template'); $smarty->setCompileDir(__DIR__ . '/template_c'); $smarty->setCacheDir(__DIR__ . '/cache'); $smarty->setConfigDir(__DIR__ . '/configs'); ثم لنقم بكتابة كود PHP لقراءة القوالب المتاحة في مجلد القوالب. <?php // تابع للخطوة 2 $templateDir = __DIR__ . '/template'; $templateFolders = array_filter(glob($templateDir . '/*'), 'is_dir'); $templates = []; foreach ($templateFolders as $folder) { $templateName = basename($folder); $templates[] = $templateName; } $smarty->assign('templates', $templates); $smarty->display('admin.tpl'); بعد ذلك إنشاء ملف قالب Smarty يسمى admin.tpl لعرض القوالب في جدول. <!-- admin.tpl --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Admin Panel - Templates</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1>Available Templates</h1> <table class="table table-bordered"> <thead> <tr> <th>Template Name</th> <th>Action</th> </tr> </thead> <tbody> {foreach from=$templates item=template} <tr> <td>{$template}</td> <td> <form method="post" action="install_template.php"> <input type="hidden" name="template_name" value="{$template}"> <button type="submit" class="btn btn-primary">Install Template</button> </form> </td> </tr> {/foreach} </tbody> </table> </div> </body> </html> ثم إنشاء ملف PHP يسمى install_template.php لتنفيذ عملية تركيب القالب. <?php if ($_SERVER['REQUEST_METHOD'] === 'POST') { $templateName = $_POST['template_name']; // نفذ عملية تركيب القالب هنا // تستطيع نسخ الملفات إلى مجلد آخر أو تحديث إعدادات قاعدة البيانات echo "Template '{$templateName}' has been installed!"; } else { echo "Invalid request."; } بذلك ستتمكن من عرض القوالب المتاحة في مجلد template على شكل جدول في صفحة لوحة التحكم، مع زر لتركيب كل قالب، وعند النقر على زر "تركيب القالب"، سيتم إرسال طلب POST إلى install_template.php لتنفيذ عملية التركيب، تستطيع تعديل عملية التركيب حسب متطلباتك.
  17. في البداية ستحتاج بالطبع إلى إنشاء حساب مطور على Google Cloud Vision API أو Amazon Rekognition. ثم ضبط إعدادات متغيرات البيئة في المشروع في ملف .env وأهما مفاتيح الـ API، عليك إضافة إعدادات Google Cloud Vision API أو Amazon Rekognition فقط، وإليك كلاهما: GOOGLE_CLOUD_VISION_API_KEY=google_api_key AWS_ACCESS_KEY_ID=aws_access_key AWS_SECRET_ACCESS_KEY=aws_secret_key AWS_REGION=aws_region ثم أنشئ نموذج وقاعدة بيانات لتخزين بيانات الصور: php artisan make:model Image -m في ملف التهجير: Schema::create('images', function (Blueprint $table) { $table->id(); $table->string('image_path'); $table->json('features'); // لتخزين بيانات الميزات (features) $table->timestamps(); }); أيضًا اعتمد على مكتبة مثل intervention/image لمعالجة الصور وضغط حجمها قبل إرسالها. ثم استخدام مكتبة google/cloud-vision أو aws/aws-sdk-php للتواصل مع المنصة. وإليك مثال لكلاهما اختر ما تريد: // ImageController.php use Illuminate\Http\Request; use Intervention\Image\Facades\Image; use Google\Cloud\Vision\V1\ImageAnnotatorClient; // or Aws\Rekognition\RekognitionClient; public function uploadImage(Request $request) { $image = $request->file('image'); // Process and resize the image $image->resize(300, 300); // Analyze the image using Google Cloud Vision API or Amazon Rekognition $visionClient = new ImageAnnotatorClient(); // or $rekognitionClient = new RekognitionClient(); $response = $visionClient->annotateImage(file_get_contents($image->getPathname()), ['LABEL_DETECTION']); // or $rekognitionClient->detectLabels(['Image' => ['Bytes' => file_get_contents($image->getPathname())]]); $features = $response->getLabelAnnotations(); // or $response->getLabels(); // Store the features in the database $imageFeatures = new ImageFeatures(); $imageFeatures->features = json_encode($features); $imageFeatures->save(); return response()->json(['message' => 'Image uploaded and analyzed successfully']); } بعد ذلك اعتمد على مكتبة doctrine/dbal للتفاعل مع قاعدة البيانات، حيث تتوفر cosine similarity أو Euclidean distance لقياس التشابه بين ميزات الصور. use App\ImageFeatures; use Illuminate\Http\Request; public function searchByImage(Request $request) { $searchImage = $request->file('image'); $searchFeatures = $this->analyzeImage($searchImage); // Query the database to find similar images $similarImages = ImageFeatures::all()->filter(function ($imageFeature) use ($searchFeatures) { $storedFeatures = json_decode($imageFeature->features, true); return $this->cosineSimilarity($searchFeatures, $storedFeatures) > 0.5; }); return response()->json(['similar_images' => $similarImages]); } private function analyzeImage($image) { // هنا يجب أن تضع الكود الخاص بتحليل الصورة والحصول على الميزات // سأضع مثال بسيط لتحليل الصورة return [/* array of features */]; } private function cosineSimilarity($features1, $features2) { $dotProduct = 0; $magnitude1 = 0; $magnitude2 = 0; foreach ($features1 as $index => $feature1) { $dotProduct += $feature1 * $features2[$index]; $magnitude1 += $feature1 * $feature1; $magnitude2 += $features2[$index] * $features2[$index]; } $magnitude1 = sqrt($magnitude1); $magnitude2 = sqrt($magnitude2); if ($magnitude1 * $magnitude2 == 0) { return 0; } return $dotProduct / ($magnitude1 * $magnitude2); } لتحسين الأداء، باستطاعتك استخدام تقنيات مثل الفهرسة المكانية أو مكتبات متخصصة في البحث عن الصور مثل Elasticsearch.
  18. افتحي مشروع Unity الذي تريدين تصديره كمكتبة، وانتقلي إلى File > Build Settings، وفي نافذة Build Settings، اختاري المنصة المستهدفة (Android أو iOS). وفي حال تستهدفي Android، اختاري Android من القائمة. ثم اضغطي على Player Settings في الزاوية السفلية اليسرى من نافذة Build Settings، وضبط الإعدادات اللازمة مثل اسم الحزمة (Package Name) وغيرها. وفي نافذة Build Settings، تأكدي من اختيار المنصة الصحيحة ثم اضغطي على Export في الزاوية اليمنى السفلى. وعندما تظهر نافذة التصدير، عليك تحديد خيار Export as a Library (أو خيار مشابه يعبر عن تصدير كمكتبة)، ثم اختيار مكان حفظ المجلد الذي سيحتوي على مكتبة Unity والضغط على Export لبدء عملية التصدير. بعد اكتمال التصدير، ستجدي مجلد يحتوي على مكتبة Unity في المسار الذي اخترتيه، باستطاعتك الآن دمج تلك المكتبة في مشروع Flutter كما هو موضح في الخطوات التي شرحها سابقًا.
  19. يمكنك ربط Python بلغة JavaScript .و هناك عدة طرق لتحقيق ذلك، ولكن الطريقة الأكثر شيوعًا هي استخدام واجهات برمجة التطبيقات (APIs). يمكنك إنشاء واجهة برمجة تطبيقات (API) باستخدام إطار عمل مثل Flask أو Django في Python كما بالعليق السابق . حيث ستقوم هذه الواجهة بتعريف نقاط نهاية تتيح لك الوصول إلى الدوال التي كتبتها في Python. بعد ذلك، يمكنك استدعاء هذه النقاط النهائية من جانب العميل (Client-side) باستخدام JavaScript وإجراء طلبات HTTP مثل GET أو POST لتمرير البيانات والحصول على النتائج. على سبيل المثال، إذا كتبت دالة في Python لحساب المتوسط الحسابي لمجموعة من الأرقام، يمكنك إنشاء نقطة نهائية في واجهة برمجة التطبيقات تسمح لك بإرسال الأرقام كبيانات JSON وتستدعي دالة Python لحساب المتوسط وإرجاع النتيجة. هناك أيضًا طرق أخرى مثل استخدام WebAssembly أو إطارات عمل مثل Transcrypt أو Brython التي تتيح لك كتابة كود Python يمكن تشغيله مباشرة في المتصفح. ومع ذلك، فإن استخدام واجهات برمجة التطبيقات هو الأكثر شيوعًا وفعالية.
  20. ملحوظة: يرجى كتابة عنوان واضح حتى تعم الفائدة على الجميع. بخصوص استخدام لغة البايثون من خلال الجافاسكريبت، فيمكن ذلك عن طريق إنشاء واجهات برمجية التطبيقات APIs ثم استدعاؤها من خلال الجافاسكريبت، وفي الحقيقة هذا يتم مع كل لغات البرمجة وليس مع البايثون فقط. ووجهة برمجة التطيبقات API هي عبارة عن وظائف يتم كتابتها بلغة برمجة معينة على الخادم، ثم تهيئتها لتكون متاحة لاستدعائها بواسطة أي لغة أخرى. بالنسبة لبايثون، فإن أطر عمل مثل الفلاسك والجانجو Flask & Django يوفران بيئة تطوير جاهزة تُمكن المبرمج من البدء في كتابة الواجهات البرمجية بكل سهولة ويسر.
  21. هل استطيع ربط بايثون بلغة الجافا سكريبت بحيث استخدم ال Functions التي اكتبها بالبايثون في الجافا سكريبت واضيفهم الى موقعي؟
  22. وعليكم السلام ورحمة الله وبركاته . مرحبا محمد . نعتذر عن المشكلة التي تواجاهك حاليا . من المفترض حين الإشتراك فإن قسم دوراتى يظهر فوريا بعد الإشتراك ويمكنك الدخول ومشاهدة الدورة دون أى مشاكل . ولكن يبدوا أنه حدثت مشكلة لديك تمنع ظهور القسم لديك.لذلك الحل هو التواصل مع الدعم كما فعلت وسيتم الرد عليك في أسرع وقت إن شاء الله . لا تقلق من التأخير في الرد فسوف يتم حل المشكلة لديك إن شاء الله . إذا لم يتم الرد عليك بحلول نهاية اليوم الحالي من فضلك أخبرنى . شكرا لتفهمك وبالتوفيق إن شاء الله
  23. السلام عليكم أود الاستفسار عن الوقت اللازم حتى أتمكن من الوصول لمحتوى الدورة التي اشتركت بها؟؟ حيث أني قمت بالاشتراك بدورة الذكاء الاصطناعي منذ صباح الأمس و تمت عملية الدفع بنجاح وإلى الآن لم أتمكن من الوصول إلى محتوى الدورة ولم يظهر لي خيار (دوراتي) على شريط المهام الرئيسي على صفحة الحساب الخاص بي!!! مع العلم اني قمت بالتواصل مع المساعدة الخاصة بموقع الأكاديمية عبر المحادثة المباشرة و عبر البريد الالكتروني ولم يتم الرد حتى الآن!!! هل هناك أي طريقة أخرى للتواصل لحل المشكلة؟ مع الشكر
  24. وعليكم السلام، إذا لم تكن باحثا في الذكاء الاصطناعي، فهذا ليس اختصاصك، لأن تطوير المعادلات شيء معقد، ومعظم ما سيأتي في بالك من تطويرات ستجد أن هناك من سبقك وقام بها على أغلب الظن. لذلك، فالنماذج الموجودة في مكتبات تعلم الآلة هي أكثر النماذج التي تمت مراجعتها ويمكنك أن تضمن أنها تعمل بشكل صحيح ويمكنك الاعتماد عليها. بينما لو طورت نموذجا خاصا بك فهناك احتمالية كبيرة في أن تقع في خطأ ما ويتسبب في إعطائك نتائج خاطئة يصعب إصلاحها. عندما تفهم كيف تعمل نماذج الآلة على الأمثلة التي تدرسها، يمكنك بعدها تطبيقها على مواضيع مختلفة لم يتم تدريسها، وقد يكون بعضها جديدا كليا لم يقم به أحد من قبلك. وهذا ممكن جدا، لأن المواضيع تختلف باختلاف الأماكن والأزمنة. فقد يكون هناك مشكل محدد في بلادك لا يوجد في البلدان الأخرى، وهنا يمكنك البحث عن كيفية الحصول على المعلومات اللازمة من بلادك، ثم معالجتها واستخدامها في نموذج تعلم آلة لحل ذلك المشكل. وربما تتمكن بعدها من نشر هذا النموذج كخدمة مدفوعة، أو شيء مشابه. هذا يعتبر إبداعا في المجال.
  25. وعليكم السلام لنبدأ أولا بالتكلم عن فهم المعادلات المقصود هنا هو أنك تفهم كيف تعمل المعادلات المستخدمة في النماذج، مثل معادلات الانحدار الخطي أو الشبكات العصبية. هذا الفهم يساعدك على استخدام هذه النماذج بفعالية وتحديد متى يكون النموذج مناسبا للمشكلة التي تعمل عليها. فهمك للمعادلات يساعدك أيضًا في تحسين النماذج واكتشاف الأخطاء. ثم تطوير المعادلات هذا يتطلب مستوى أعلى من الفهم والابتكار. يعني أنك تقوم بابتكار وتطوير معادلات جديدة أو تحسين المعادلات الحالية بشكل مبتكر. هذا يتطلب معرفة عميقة بالرياضيات والخوارزميات. فالخطوة الأولى هي فهم كيف تعمل الأشياء الموجودة، ثم بعد ذلك يمكنك محاولة تطوير أشياء جديدة.
  26. السلام عليكم هل المقصود ان اطور المعادالات الموجود في النماذج ؟ والا المقصود ان افهم المعادالات وسعاتها اقدر ان ابداع في المجال ؟ انا كا مطور في المجال ده اقصد كده
  1. عرض المزيد
×
×
  • أضف...