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

سامح أشرف

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

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

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

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

    56

كل منشورات العضو سامح أشرف

  1. في Laravel لا تحتاج أن تستعمل الدالة asset لتقوم بتضمين مكتبات خارجية، يمكنك تضمين المكتبة بشكل عادي كالتالي: <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> ويمكنك أن تقوم بتحميل ملفات Font-awesome نفسها وتقوم بإضافتها إلى مجلد public وتستدعيها كباقي ملفات CSS العادية. لكن إن كنت تستعمل Laravel Mix فيجب عليك تثبيت Font-awesome أولا من خلال NPM كالتالي: npm install font-awesome --save ثم قم بتعديل ملف resources/assets/sass/app.scss وإضافة font-awesome كتالي: @import "node_modules/font-awesome/scss/font-awesome.scss"; ثم تشغيل المشروع من خلال الأمر التالي: npm run dev ولا تنسى ربط ملف public\css\app.css في ملفات blade التي لديك.
  2. يمكنك إعداد أو تغير متغيرات البيئة من خلال تغير قيمة start في ملف package.json كالتالي: // قم بتعديل السطر التالي "start": "webpack serve" // ليكون مثل هذا السطر "start": "set NODE_ENV=development && webpack serve" على Linux و Mac نستعمل export بدلًا من set كالتالي: "start": "export NODE_ENV=development && webpack serve"
  3. يمكنك إستخدام شهادات SSL في nodejs كالتالي: const https = require('https'); const fs = require('fs'); // تستخدم للتعامل مع الملفات، وسنحتاجها لقراءة محتوى ملفات pem // key.pem و cert.pem عبارة عن مشارات ملفات الشهادة والمفتاح const options = { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem') }; // نقوم بتمرير الإعدادات السابقة في التابع createServer // مع إرسال رسالة Hello, World! للتأكد من أن كل شيء يعمل بشكل سليم https.createServer(options, function (req, res) { res.writeHead(200); res.end("Hello, World!\n"); }).listen(8000); الآن يمكنك التوجه إلى الرابط التالي للتأكد من أن شهادة SSL تعمل: https://localhost:8000
  4. dirname__ تقوم بإرجاع المسار الكامل للملف الموجودة فيه، بينما "/." تقوم بإرجاع مسار المجلد الذي تم تنفيذ الكود منه، ولتوضيح الفرق أكثر هنا مثال للتوضيح، لنفترض أن لدينا ملف باسم script.js موجود في مجلد dist والذي بدوره موجود داخل مجلد root، أي أن هيكلية الملفات كالتالي: |-- root |-- dist |--- script.js الآن لنكتب الكود التالي داخل ملف script.js: var path = require("path"); console.log(". = %s", path.resolve(".")); console.log("__dirname = %s", path.resolve(__dirname)); الكود السابق يقوم بطباعة مسار المجلد بالطريقتين، الآن نقوم بتشغيل الملف من داخل المجلد dist (أي نقوم بالدخول إلى المجلد أولًا قبل تشغيل الملف) ولنرى النتيجة: cd /root/dist node script.js وستكون النتيجة كالتالي: . = /root/dist __dirname = /root/dist الآن نقوم بتشغيل البرنامج من داخل مجلد root كالتالي: cd /root node dist/script.js وستكون النتيجة كالتالي: . = /root __dirname = /root/dist هنا يتضح الفرق بين الطريقتين، وهو أن dirname__ تقوم دائمًا بإرجاع مسار المجلد الموجودة فيه، بينما "/." تقوم بإرجاع مسار مجلد العمل الحالي current working directory
  5. يوجد عدة طرق لرفع مشروع Laravel على الويب حسب نوع الإستضافة (Cpanel أو unmanaged server .. إلخ)، لكن سأفترض أنك تقوم برفع المشروع على إستضافة عادية تحتوي على cpanel أضغط ملفات المشروع بالكامل في شكل ملف zip قمت بإستخراج قاعدة البيانات الخاصة بالمشروع (يمكنك عمل ذلك من خلال phpmyadmin)، ستحصل في النهاية على ملف sql قم بتسجيل الدخول إلى لوحة cPanel وتوجه إلى مدير الملفات File Manager أذهب إلى المجلد الرئيسي وأضغط على upload قم بتحديد ملف zip الخاص بالمشروع الذي قمت بعمله في الخطوة الأولى قم بإستخراج ملف zip الذي قمت برفعه للتو قم بنقل محتوى المجلد public (الموجود في مشروع) إلى مجلد public_html (يكون موجود بشكل إفتراضي على الإستضافة) الآن قم بالذهاب إلى لوحة Cpanel وتوجه إلى قسم Databases قم بعمل قاعدة بيانات جديدة وقم بحفظ بيانات قاعدة البيانات (اسم قاعدة البيانات، اسم المستخدم، كلمة المرور) لأننا سنستخدمها لاحقًا قم بعمل إستيراد import لقاعدة البيانات التي قمت بإستخراجها في الخطوة رقم 2 قم بتعديل معلومات قاعدة البيانات في ملف .env الآن حاول تشغيل موقعك في المتصفح لترى النتيجة. في الغالب يوفر موقع الإستضافة شرح ليكيفة رفع وإعداد مشروع Laravel، حاول البحث في مدونة الإستضافة أو تواصل مع الدعم الفني.
  6. يمكنك أن تبني المشروع بالكامل في نفس مجلد لأن Laravel يأتي مجهزًا للتعامل مع الـ API، ويمكنك أن تقوم بعمل RESTful API من خلال عمل Routes في ملف routes/api.php بنفس الطريقة العادية كم اتقوم بها في ملف routes/web.php ويفضل أن تفصل المتحكمات controllers في مجلد داخلي باسم api ليكون في المسار التاليعلى سبيل المثال: /app/Http/Controllers/Api/UsersController.php ويمكنك تقسم الـ API إلى إصدار (V1, V2 .. إلخ) حتى إذا أردت أن تقوم بعمل تحديثات في المستقبل، تقوم بعمل إصدار جديد لذلك قم بوضع المتحكمات في مجلد باسم الإصدار أيضًا كالتالي: /app/Http/Controllers/Api/V1/UsersController.php ويمكنك أن تستخدم التابع prefix لإستخدام الإصدار في مسارات routes الـ API أيضًا كالتالي: Route::prefix('v1')->group(function () { Route::get('/users', [UsersController::class, 'index']); // http://localhost/api/v1/users Route::get('/posts', [PostsController::class, 'index']); // http://localhost/api/v1/posts });
  7. نظام كالي لينكس ليس سوى نظام Linux عادي ولكن يأتي بكثير من أدوات إختبار الإختراق مثبته بالفعل، ويمكنك أن تقوم بتثبيت هذه الأدوات على أي توزيعة لينكس عادية بدون مشكلة، ففي الغالب تكوون هذه الأداوات مفتوحة المصدر. لذلك إن كنت ترغب في تعلم إختبار الإختراق فسيكون هدفك هو تعلم لغة برمجة واحدة على الأقل مثل Python أو Ruby إلخ مع تعلم أساسيات المجال الذي ترغب فيه (إختبار إختراق أنظمة التشغيل - الهواتف الذكية - مواقع الويب - الأنظمة المدمجة .. إلخ) وهذه الأدوات التي تأتي مسبقًا في كالي لينكس ستساعدك فقط في مهمتك، حينها يمكنك أن تبحث عن شروجات لمثل هذه الأدوات أو قراءة التوثيق الخاص بكل أداة إن كان متوفرًا.
  8. عمل رائع في تعلم كل هذه التقنيات، أعتقد أنك الآن تستطيع أن تقوم ببناء مشروع من الصفر (متجر إلكتروني أو مدونة على سبيل المثال)، وإن لم تفعل هذا بعد فقد حان الوقت لكي تقوم بالتطبيق على ما تعلمته في شكل مشروع واحد كبير يحتوي على كل التقنيات التي تعلمتها. ليس شرطًا أساسيًا أن تتعلم الـ testing ويمكنك القيام بأي مشروع بدون إستخدامه على الإطلاق، لكنه سيسهل عليك الكثير من العمل، لأنك ستقوم بعمل ملفات صغيرة تقوم بتجربة مكونات المشروع وتوافقها مع بعضها البعض، وهذا سيوفر عليك عناء التجربة اليديوية وإصلاح الأخطاء في كل مرة وهذا الأمر يستغرق الكثير من الوقع خصوصًا في المشاريع الكبيرة، بالنسبة لأنواع الـ testing فيوجد أنواع أخرى غير unit testing و integration testing وعندما تبدأ في تعلم وإستخدام أحد المكتبات للقيام بذلم مثل jest على سبيل المثال ستتعرف على باقي الأنواع ومتى تستخدم كل نوع منهم. الكاش أو الملفات المؤقتة هي بيانات يتم تخزينها في الذاكرة العشوائية في الغالب، لكي يتم الوصول إليها بشكل سريع بدلًا من البحث في ملايين السجلات في قاعدة البيانات على سبيل المثال، ويتم بشكل واسع في المشاريع الضخمة والمشاريع التي تحتوي على حجم بيانات كبير للغاية، ومثله مثل الـ testing ليس عليك تعليمه في البداية وليس شرطًا لكي تبدأ في عمل مشروع جديد. جدولة المهام يقصد به تنفيذ كود معين في وقت محدد مسبقًا، على سبيل المثال، إرسال رسالة بريد إلكتروني إلى المستخدمين في أول كل شهر تذكرهم بتجديد الإشتراك. الـ microservice أو كما يعرف بـ microservice architecture هي طريقة لتنظيم وتقسيم الكود ليكون: يمكن صيانتها واختبارها بدرجة عالية كل المكونات تكون المتباعدة (أي لا يعتمد بعضها على بعض) يمكن نشر كل المكونات بشكل مستقل تتيح بنية الـ microservice التسليم السريع والمتكرر والموثوق للتطبيقات الكبيرة والمعقدة. كما أنه يمكّن المنظمة أو الشركة من تطوير مجموعة التكنولوجيا والتقنيات الخاصة بها. كل أسلفت في البداية، يمكنك أن تبدأ الآن في إنشاء مشروع جديد، لكي تطبق على ما تعليمته بشكل سليم، وبعد إنتهاء المشروع يمكنك أن تقوم بتحسينه وتطبيق مميزات أخرى مثل الـ testing والـ caching والـ task Scheduling .. إلخ
  9. يمكنك أن تقوم بعمل حقل في لوحة التحكم يقوم بتعديل قيمة في جدول ما في قاعدة البيانات (جدول Settings على سبيل المثال)، وفي الموقع نفسه (أي في القالب المستخدم في الموقع) نقوم بإستخدام القيمة الموجودة في جدول settings، بهذا يمكنك التحكم في الكثير من المميزات الموجودة في الموقع من خلال لوحة التحكم عبر إنشاء حقل input لكل قيمة تريد التحكم بها وتخزينها في قاعدة البيانات وإستخدام هذه القيمة من قاعدة البيانات وإستخدامها في واجهة الموقع.
  10. يقوم الموقع بوضع نص فوق الصورة من خلال خاصية position في CSS وتحريك النص إلى الأعلى من خلال خاصية top و left و right و bottom ليكون النص فوق الصورة، ويمكنك أن تتحقق من ذلك من خلال فحص كود الموقع من خلال أدوات المطورين في المتصفح الخاص بك، وهنا مثال يقوم بنفس الأمر: <div class="wrapper"> <img src="https://cast-media.netlify.app/eid/card.png" width="100%"> <div class="text">Hello, world!</div> </div> .text { position: relative; top: -70px; left: 150px; font-size: 2rem; margin: auto; text-align: center; color: lightgreen; } يقوم المثال السابق بعرض نفس الصورة ووضع النص Hello, world! فوق الصورة كالتالي:
  11. يمكنك إستعمال جملة SQL التالية: UPDATE C SET C.ColumnName = concat( (SELECT A.ColumnName1 from A where A.id =1 LIMTIT 1), # قيمة العمود من الجدول الأول A (SELECT B.ColumnName2 from B where B.id =1 LIMTIT 1), # قيمة العمود من الجدول الثاني B C.id # id الجدول الثالث C ) WHERE C.id =1 لاحظ أن جملة SELECT الأولى والثانية يجب أن ترجع كل منهما صف واحد فقط لهذا قمت بوضع LIMIT 1 تحسبًا فقط في حالة كان الشرط يتحقق مع أكثر من صف. دالة concat تقوم بربط أكثر من قيمة لتصبح قية واحدة كالتالي: concat( 'hello' , ' world' ) # hello world يمكنك أيضًا أن تستعمل JOIN لعمل نفس الأمر لكن يجب أن تشترك الجداول في عمود واحد على الأقل.
  12. الطريقة التي ذكرها @محمد صقر3ستعمل حتى وإن كان حقل birth يحتوي على السنة فقط ولن تحدث مشكلة، حيث يتم إعتبار أن القيمة 2000 تساوي 2000-01-01 (أول يوم في السنة)، لكن إن كان حقل birth يحتوي على قيم غير منظمة (ليس من نوع Date أو Date Time) من نوع String على سبيل المثال، فلن يمكنك أن تحثل على أكبر أو أصغر الأعضاء حتى تقوم بترتيب محتوى العمود birth يدويًا.
  13. أكواد جافاسكريبت لا يمكن إخفائها، لأن المتصفح يجب أن يقوم بتحميلها حتى يستطيع أن ينفذها، وبما أن المتصفح يقوم بتحميلها فيمكن للمستخدم الحصول على هذه الأكواد من خلال أدوات المطورين dev tools في المتصفح، لكن يمكنك أن تقوم بتحويل الكود لكي يكون صعب الفهم، وهذا ما يسمى التعميم Obfuscation حيث نقوم بتحويل الكود التالي: function NewObject(prefix) { var count=0; this.SayHello=function(msg) { count++; alert(prefix+msg); } this.GetCount=function() { return count; } } var obj=new NewObject("Message : "); obj.SayHello("You are welcome."); ليكون بهذا الشكل على سبيل المثال: var _0xafc3=["\x53\x61\x79\x48\x65\x6C\x6C\x6F","\x47\x65\x74\x43\x6F\x75\x6E\x74","\x4D\x65\x73\x73\x61\x67\x65\x20\x3A\x20","\x59\x6F\x75\x20\x61\x72\x65\x20\x77\x65\x6C\x63\x6F\x6D\x65\x2E"];function NewObject(_0xe9e5x2){var _0xe9e5x3=0;this[_0xafc3[0]]= function(_0xe9e5x4){_0xe9e5x3++;alert(_0xe9e5x2+ _0xe9e5x4)};this[_0xafc3[1]]= function(){return _0xe9e5x3}}var obj= new NewObject(_0xafc3[2]);obj.SayHello(_0xafc3[3]) وسيعمل كل شيء على ما يرام، يمكنك تجربة الكود من خلال تشغيله في الـ console توجد أداة مجانية تسمى Javascript Obfuscator تقوم بهذا الأمر
  14. يجب أن تقوم برفع الكود الخاص بالـ backend (الجزء المختص بالـ API) على أي إستضافة (ليس شرط أن تكون إستضافة heroku ، لكنها الأسهل في التعامل وأيضُا مجانية)، وذلك لأن localhost لن يعمل على الهواتف الحقيقية أو الموجودة خارج شبكتك الخاصة وعندما تقوم برفع الكود على إستضافة heroku تحصل على رابط مثل my-app.herku.com وتقوم بإستعمال هذا الرابط بدلًا من localhost:3000 كالتالي: http://localhost:3000/api/v1/products # يصبح الرابط السابق كالتالي http://my-app.heroku.com/api/v1/products بعد رفع الكود على الإستضافة والحصول على رابط مشابهة يجب أن تقوم بتعديل الكود في التطبيق ليقوم بإستعمال الرابط الجديد بدلًا من localhost
  15. مكتبة React.js المستخدمه في الويب تختلف عن React Native المستخدمه في عمل تطبيقات الهواتف الذكية، لكنهما يشتركان في نفس طريقة كتابة الكود بالإضافة إلى إستخدام نفس المباديء لتنفيذ الأمور، مما يعني أنه بمجرد تعلم React سيكون من السهل جدًا تعلم React Native. وبالتأكيد يمكن إستخدام React للمشاريع الكبيرة، وتوجد بالفعل الكثير من المواقع الضخمة التي تستعمله مثل Trello و AWS و Udacity وغيرهم الكثير من المشاريع والمواقع الكبيرة. بالإضافة إلى تطبيقات كبيرة ومعروفة (على الهواتف الذكية) التي بنيت بإستخدم React Native مثل Instagram و Pinterest و جميع تطبيقات office 365 و tesla و walmart و wix.
  16. حسب هذا التعديل في منتدى Adobe فإن إمكانية تغير كلمة Sample في هذه القائمة سوف يؤدي إلى بطئ في الفوتوشوب، لذلك لا توجد إمكانية لتغير هذه الكلمة في الوقت الحالي، بدلًا من ذلك يمكنك أن تقوم بكتابة الجملة التي تريد وتحديدها وفتح قائمة تغير الخط والتنقل بين الخطوط من خلال الأسهم لتشاهد شكل الجملة يتغير مع تغير الخط. وبإمكانك أيضًا تستعمل خدمة مثل Google Fonts أو Adobe Fonts لتبحث الخط المناسب لك، كما تقدم هذه المواقع إمكانية كتابة جملة مخصصة لترى شكل الجملة في كل الخطوط كما في الصورة:
  17. يمكنك أن تستعمل أي مكتبة خاصة بتنسيقات CSS بدون مشكلة من خلال إستدعاء ملفات CSS الخاصة بهذه المكتبة في مكونات React وتوجد العديد من المكتبات غير Bootstrap مثل: Material Design Foundation chakra UI Semantic UI Ant design بالإضافة إلى وجود مكتبات مثل Tailwind CSS والتي تقدم لك كل خصائص CSS في شكل أصناف Classes ومن خلالها يمكنك تطبيق خواص CSS من خلال إستخدام أصناف فقط.
  18. إستضافات VPS فالغالب تكون من نوع unmanaged أي أنك من تقوم بكل العمل بدون مساعدة من شركة الإستضافة وهذا عكس الإستضافات العادية من نوع managed التي تحتوي على لوحة تحكم مثل Cpanel أو Plesk، لذلك ستحتاج أن تقوم بتجهيز الخادم من خلال تثبيت جدار حماية وضبط إعدادات SSH وحمايتها وتثبيت خادم apache أو nginx ولغة PHP بالإصدار الذي تريده أو المناسب لموقعك، بالإضافة إلى قواعد بيانات مثل MySQL أو MariaDB، يمكنك تثبيت كل ما سبق من خلال تثبيت LAMP بشكل مباشر مع ضبط بعض الإعدادات ولنقل الملفات من سيرفر إلى آخر تحتاج أن تقوم بتثبيت FTP Server أو إستخدام تقنية مثل Git و GitHub. كل تقنية من التقنيات السابقة تحتاج إلى الكثير من الإعدادات ولا أنصحك إن تقوم بعمل هذا بنفسك إن لم تكن تمتلك الخبرة الكافية لذلك، بدلًا من ذلك يمكنك أن تقوم بتعين مدير سيرفرات أو شخص مختص من أحد مواقع العمل الحر مثل مستقل أو خمسات.
  19. هل يمكنك أن توضح سؤالك أكثر فيما يخص النقطة الأولى، إن كنت تقصد الدوائر الصغيرة فيمكن عملها من خلال عمل دوائر صغيرة متوازية وتقليل الشفافية الخاصة بهم أو يمكنك أن تستعمل أحد فرش halftone brushes بالنسبة لرقم 2: فهي عبارة عن دائرتين واحدة بيضاء صغيرة والثانية زرقاء كبيرة وتم تحريكهما ليكون الشكل الناتج هو القوس الأزرق أو يمكن رسمها من خلال أداة Pen tool
  20. ليس بالضبط، فمجال الـ IT أكبر بكثير من أن تشمله دورة واحدة، فهو يحتوي على أفرع كثيرة، بينما هذه الدورة تعد بداية ممتازة لأي شخص لم يتعلم البرمجة من قبل أو أن تعامله من الحسوب قليل بشكل عام أو للمبرمجين الذين يريدون تعلم الأساسيات بشكل متقن أو لمن حاول تعلم البرمجة بشكل مسبق ووجد أنها مهمة صعبة عليه، وسوف تتعلم أساسيات الحاسوب وعلومه والتفكير المنطقي وما هي الخوارزميات مرورًا بلغة البرمجة JavaScript والتعامل مع أنظمة التشغيل وأساسيات سطر الأوامر في نظام لينكس. بينما مجال الـ IT يحتوي على أساسيات الحسوب من Software و Hardware بالإضافة إلى التعامل مع الشبكات، وإدارة أنظمة التشغيل وحمايتها من عمليات الإختراق إلخ. لذلك يمكن إعتبار أن دورة علوم الحسوب هي بداية الطريق في مجال الـ IT
  21. هل يمكنكِ إرفاق ملفات المشروع حتى يمكننا المساعدة؟
  22. يتم تبديله بالطبع، لكن هذا الأمر لن يؤثر على أي شيء لأن المتغير j يتم إسناد قمية عشوائية جديدة في كل دورة.
  23. شرط التكرار هو أن يكون المتغير i أكبر من صفر (i > 0)، وبما أن المتغير تبدأ قيمته من 4 (طول المصفوفة - 1) فستكون قيمة هذا المتغير 4 ثم في الدورة الثانية ستكون قيمته 3 ثم 2 في التي تليها ثم 1 في آخر دورة تكرار. (4 - 3 - 2 - 1) ثم في السطر المسئول عن إسناد قيمة للمتغير j : // قيمة عشوائية ما بين 0 و 4 let j = Math.floor(Math.random() * (i + 1)); أي أن قيمة المتغير j ستكون ما بين 0 و 4 في أول دورة، وستكون قيمته ما بين 0 و 3 في ثاني دورة وهكذا. ( [0:4] - [0:3] - [0:2] - [0:1] ) ثم في السطر التالي يتم تبديل قيمة العنصر ذي الفهرس 4 index مع عنصر آخر مختار بطريقة عشوائية: // في الدورة الأولى // i = 4 // j = رقم عشوائي من 0 إلى 4 // أي سيتم تبديل العنصر 4 بأحد العناصر الأخرى في المصفوفة [array[i], array[j]] = [array[j], array[i]]; يتم نفس الأمر في الدورة الثانية مع العنصر 3 (أي يتم تبديله مع أحد العناصر الأخرى) وهكذا إلى أن تنتهي آخر دورة.
  24. يقوم هذا السطر بتبديل قيمة عنصرين معًا، فمثلًا إن كان لدينا المصفوفة التالية: let array = [1, 2, 3, 4, 5]; وقمنا بتنفيذ السطر التالي: // يقوم السطر التالي بتبديل قيمة أول عنصرين في المصفوفة [array[0], array[1]] = [array[1], array[0]] console.log(array) // Output: [2, 1, 3, 4, 5] وفي الدالة التي أرفقتها في الأعلى (shuffle) يتم إستعمال هذه الطريقة لخلط العناصر في المصفوفة بطريقة عشوائية
  25. هذا السطر مسئول عن التحقق مما إذا كان الملف تم تنفيذه (تشغيله) أم تم إستدعائه في ملف بايثون آخر (وكأنه مكتبة) ويمكنك أن تقوم بتطبيق المثال التالي لكي تفهم أكثر. أولًا قم بعمل ملفين بايثون الأول اسمه first.py والثاني اسمه second.py ولن نضع في كل ملف دالة print بسيطة تعمل عند تشغيل الملف كالتالي: # first.py print('First file') # second.py print('Second file') بالتأكيد عند تشغيل كل ملف من الملفين السابقين سيتم طباعة الجملة التي بداخله، الآن لنقم بتعديل الملف الأول first.py ليكون محتواه كالتالي: import second print('First file') كل ما قمنا به هو إستدعاء الملف الثاني بداخل الملف الأول، الآن لنقم بتشغيل الملف الأول python first.py وستجد أن النتيجة كالتالي: Second file First file لاحظ هنا أنه تم تنفيذ الملف الثاني بمجرد إستدعائه وليس هذا ما نريده، ولكي نتجنب هذا الأمر نقوم بإستخدام السطر التالي في الملف الثاني: if __name__ == "__main__": print('Second file') هنا نقوم بالتحقق مما إذا كان الملف الثاني يتم تشغيله بطريقة مباشرة (True) أم تم إستدعائه في ملف آخر (False). ويتم إستخدام هذه الطريقة في أغلب الحزم والمكتبات التي تقوم بتثبيتها لديك من خلال pip.
×
×
  • أضف...