اختبر المشاريع بدون ألم. تقرير ياندكس

نحن في فريق Yandex.Maps لنظام iOS ننشئ مشاريع اختبار باستخدام مكون إضافي صغير لـ CocoaPods والعديد من فئات المرافق. إنشاء مشروع سريع وموثوق. لكن ربما نتعب نفسك كثيرًا وليس من الصعب تجميع مشروع يدويًا بالإعدادات والتبعيات الضرورية؟ في التقرير ، ذهبت من العكس: نظرت أولاً إلى العملية اليدوية ، ثم إلى عمليتنا.


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

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

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



ماذا يجب أن يكون في مشروع الاختبار؟ يجب أن نكون قادرين على تشغيل وتصحيح تطبيقنا على نفس الأجهزة التي اعتدنا عليها لتشغيل وتصحيح تطبيقنا الرئيسي.

يجب أن يتم تكوين المشروع على نحو مشابه قدر الإمكان للمشروع الرئيسي ، بحيث في عملية نقل الميزات من المشروع التجريبي إلى المشروع الرئيسي ، لن نفاجأ. أو على الأقل خفض عدد المفاجآت المستلمة إلى الحد الأدنى.

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

تطبيق CocoaPods


سيتم بناء قصتي بالكامل اليوم حول ميزة CocoaPods تسمى app_spec.



يشبه App_spec نوعًا فرعيًا عاديًا ، إلا أنه لا ينشئ إطار عمل يمكن توصيله ، ولكنه تطبيق يمكن تشغيله على الجهاز.



وخارج الصندوق ، يسمح لنا CocoaPods بدفع Info.plist و xcconfig إلى app_spec. هذا يسمح لنا بالفعل بإعداد مشروعنا بشكل جيد.

ولكن إذا أردنا كتابة قواميس ضخمة في كل pods_spec ، مع قيم Info.plist و xcconfig ، فسوف ننمي podspec بأنفسنا وسيكون من غير المناسب تعديلها. إذا كنا بحاجة إلى تغيير شيء ما ، فيجب علينا الذهاب إلى كل ملف podspec وتعديل شيء باستخدام الأقلام. على أي حال ، هذا غير مريح.



للتخلص من هذا ، قمنا بعمل مكون إضافي محلي بسيط للغاية لـ CocoaPods. حتى أنه يناسب تمامًا شريحة واحدة. وهو يفعل الشيء الوحيد والوحيد: يمنحنا دقة DSL CocoaPods ، التي تنشئ app_spec بقيم مسدودة بالفعل في Info.plist و xcconfig. هذا يسمح لنا بالفعل بتكوين التوقيع ، تكوين تلك الأشياء الهامة التي نريد أن نرى تكوينها في مشروعنا التجريبي.



السؤال: كيفية نقل المسار إلى الاستحقاقات ، بشكل أدق ، مكان تخزين الاستحقاقات حتى نتمكن من ترميز المسار في المكونات الإضافية.

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



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

من المهم التأكيد هنا أنه يجب تحديد مسار نسبي ، لأن هذا المسار يبقى في pods_spec. هذا يعني أنه سيشارك في حساب مبلغ الشيك المخزن في Podfile.lock. وإذا كان هناك مسار مطلق ، فسيؤثر ذلك على مبلغ الشيك. هذا يعني أن مبلغ الشيك سيختلف اعتمادًا على المجلد الذي سيتم استدعاء $ pod install منه ، ومن أين لديك المستودع ، والجهاز الذي تقوم بتشغيل $ pod install عليه. بشكل عام ، هذا يؤدي إلى الصراع.



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

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



إذن ، ما الذي حصلنا عليه عندما قمنا بالفعل بتكوين app_spec بهذه الطريقة؟ يمكننا تشغيل مشروعنا التجريبي على نفس الأجهزة على الفور. لدينا عدد هائل من الإعدادات ، بما في ذلك الاستحقاقات ، التي نحتاجها.

بيئة


الشيء التالي الذي أريد أن أتحدث عنه هو البيئة ، الحد الأدنى من البيئة الضرورية التي نحتاجها لبدء كتابة التعليمات البرمجية على الفور.



في حالتنا ، نحتاج إلى MapKit ، التي تم تكوينها بالفعل ، مع المفاتيح المنقولة ، مع إعادة توجيه المكالمات في AccountManager. هذه هي مكتبة التفويض الخاصة بنا. كما أنها تحتاج إلى إجراء مكالمات النظام ، كما أنها تحتاج إلى نقل المفاتيح ، بما في ذلك تمرير فتح التطبيق عن طريق المرجع.

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



في حالتك ، قد يكون هذا ، على سبيل المثال ، إعداد Facebook SDK ، الذي تحتاج أيضًا إلى نقل المفاتيح إليه ؛ مكتباتك لتسجيل الدخول ، والتي ستحتاج بالتأكيد إلى تخطي رابط فتح التطبيق. نوع من وحدة تحكم بدء تشغيل Windows ، ونقطة الإدخال نفسها لتشغيل البرنامج النصي الرئيسي الذي تريد تطويره في مشروع الاختبار الخاص بك.



كيف وصلنا قيام بذلك؟ من خلال عمل قالب AppDelegate واحد. هناك نقوم بتهيئة جميع البيئات والمكتبات اللازمة. نعيد توجيه جميع المكالمات اللازمة ، وننقل المفاتيح الضرورية. عند إنشاء مشروع اختبار ، يبقى لنا إنشاء AppDelegate جديد لمشروع الاختبار والوراثة من القالب.

بعد ذلك ، تجاوزنا الطريقة الوحيدة التي يتم استدعاؤها بعد أن قام القالب AppDelegate بكل ما هو ضروري. وهناك بالفعل برنامج ViewController الأولي ، وفوق كل ذلك يمكننا تشغيل البرنامج النصي الخاص بنا ، والذي نريد تصحيحه في مشروع الاختبار.

كان / أصبح


كيف يمكنني إنشاء مشروع اختبار في الجبين ، وكيف يمكنني إنشائه باستخدام الطريقة التي وصفتها اليوم؟

إنشاء مشروع اختبار في الجبهة:

- نذهب إلى Xcode ، وننشئ مشروعًا جديدًا (ملف> مشروع جديد).

- أدخل الاسم ، ويفضل أن يكون ذلك بدون أخطاء ، قم بتوقيع معرف الحزمة. نحن ننشئ هذا المشروع.

- قم بتغيير إصدار Swift ، قم بتغيير الإصدار المستهدف. نحن نحاول تشغيله كله على الجهاز ، وتحرير التوقيع ، وما إلى ذلك. هذه عملية كئيبة نوعًا ما.

- بعد ذلك ، نقوم بإنشاء ملف podfile ، وربط التبعيات هناك ، وتثبيت pods.

- بعد ذلك ، نبدأ ونبدأ في تكوين AppDelegate بشكل ممل وهادئ ، وننقل من خلال قطع تهيئة المكتبات التي نحتاجها.

- قم بإنشاء UIWindows مع ViewController

وفقط بعد ذلك يمكننا بدء تشغيل الكود المفيد. إجراء غير سار إلى حد ما ، يوافق.

كيف يمكننا إنشاء مشروع اختباري باستخدام أفضل الممارسات التي وصفتها في تقرير اليوم؟

- نقوم بإنشاء sample_app_spec ، باستخدام الامتداد ، لـ CocoaPods ، التي بدأنا بها.

- إنشاء AppDelegate ، وترثه من قالب AppDelegate.

بعد ذلك ، يمكننا البدء في كتابة تعليمات برمجية مفيدة.

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

هل يمكن أن يكون أسهل؟


يمكنك طرح سؤال - هل يمكن القيام بذلك بسهولة؟ بالطبع بكل تأكيد.



لقد حددت ثلاثة مستويات صعوبة. الأول هو ما تحدثت عنه اليوم ، دفعة واحدة ، عندما نصنع مكونًا إضافيًا لـ CocoaPods ، والذي يمكنه إصلاح مسارات الاستحقاقات ، ونموذج AppDelegate.

الطريقة الثانية مثالية في نسبة الجهود إلى الربح. يحتوي فقط على البرنامج المساعد لـ CocoaPods ، والذي كان الأول في قصة اليوم. أي أنه ببساطة يستبدل القيم الموجودة في Info.plist و xcconfig. بالفعل يجعل الحياة أسهل بكثير.

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

الطريقة الثالثة هي الأسهل ، ولا تتطلب أي تحضير. ما عليك سوى البدء في استخدام app_spec. يتم إنشاء المشروع الذي تم إنشاؤه من app_spec في نفس مساحة العمل مثل مشروعك الرئيسي. لذلك ، فإنه يرث بالفعل ، على سبيل المثال ، Swift ، الإصدار المستهدف وجميع الإعدادات الموجودة في مساحة العمل. سيكون من الأسهل بالنسبة لك أن تبدأ العمل معه. هذا كل شيء ، أشكركم على اهتمامكم. سأخبركم اليوم بكيفية إنشاء مشاريع اختبار بدون ألم ، وكيف ننشئ مشاريع اختبار في Yandex.Maps.

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

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

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



ماذا يجب أن يكون في مشروع الاختبار؟ يجب أن نكون قادرين على تشغيل وتصحيح تطبيقنا على نفس الأجهزة التي اعتدنا عليها لتشغيل وتصحيح تطبيقنا الرئيسي.

يجب أن يتم تكوين المشروع على نحو مشابه قدر الإمكان للمشروع الرئيسي ، بحيث في عملية نقل الميزات من المشروع التجريبي إلى المشروع الرئيسي ، لن نفاجأ. أو على الأقل خفض عدد المفاجآت المستلمة إلى الحد الأدنى.

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

تطبيق CocoaPods


سيتم بناء قصتي بالكامل اليوم حول ميزة CocoaPods تسمى app_spec.



يشبه App_spec نوعًا فرعيًا عاديًا ، إلا أنه لا ينشئ إطار عمل يمكن توصيله ، ولكنه تطبيق يمكن تشغيله على الجهاز.



وخارج الصندوق ، يسمح لنا CocoaPods بدفع Info.plist و xcconfig إلى app_spec. هذا يسمح لنا بالفعل بإعداد مشروعنا بشكل جيد.

ولكن إذا أردنا كتابة قواميس ضخمة في كل pods_spec ، مع قيم Info.plist و xcconfig ، فسوف ننمي podspec بأنفسنا وسيكون من غير المناسب تعديلها. إذا كنا بحاجة إلى تغيير شيء ما ، فيجب علينا الذهاب إلى كل ملف podspec وتعديل شيء باستخدام الأقلام. أو لا أقلام. على أي حال ، هذا غير مريح.



للتخلص من هذا ، قمنا بعمل مكون إضافي محلي بسيط للغاية لـ CocoaPods. حتى أنه يناسب تمامًا شريحة واحدة. وهو يفعل الشيء الوحيد والوحيد: يمنحنا دقة DSL CocoaPods ، التي تنشئ app_spec بقيم مسدودة بالفعل في Info.plist و xcconfig. هذا يسمح لنا بالفعل بتكوين التوقيع ، تكوين تلك الأشياء الهامة التي نريد أن نرى تكوينها في مشروعنا التجريبي.



السؤال: كيفية نقل المسار إلى الاستحقاقات ، بشكل أدق ، مكان تخزين الاستحقاقات حتى نتمكن من ترميز المسار في المكونات الإضافية.

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



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

من المهم التأكيد هنا أنه يجب تحديد مسار نسبي ، لأن هذا المسار يبقى في pods_spec. هذا يعني أنه سيشارك في حساب مبلغ الشيك المخزن في Podfile.lock. وإذا كان هناك مسار مطلق ، فسيؤثر ذلك على مبلغ الشيك. هذا يعني أن مبلغ الشيك سيختلف اعتمادًا على المجلد الذي سيتم استدعاء $ pod install منه ، ومن أين لديك المستودع ، والجهاز الذي تقوم بتشغيل $ pod install عليه. بشكل عام ، هذا يؤدي إلى الصراع.



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

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



إذن ، ما الذي حصلنا عليه عندما قمنا بالفعل بتكوين app_spec بهذه الطريقة؟ يمكننا تشغيل مشروعنا التجريبي على نفس الأجهزة على الفور. لدينا عدد هائل من الإعدادات ، بما في ذلك الاستحقاقات ، التي نحتاجها.

بيئة


الشيء التالي الذي أريد أن أتحدث عنه هو البيئة ، الحد الأدنى من البيئة الضرورية التي نحتاجها لبدء كتابة التعليمات البرمجية على الفور.



في حالتنا ، نحتاج إلى MapKit ، التي تم تكوينها بالفعل ، مع المفاتيح المنقولة ، مع إعادة توجيه المكالمات في AccountManager. هذه هي مكتبة التفويض الخاصة بنا. كما أنها تحتاج إلى إجراء مكالمات النظام ، كما أنها تحتاج إلى نقل المفاتيح ، بما في ذلك تمرير فتح التطبيق عن طريق المرجع.

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



في حالتك ، قد يكون هذا ، على سبيل المثال ، إعداد Facebook SDK ، الذي تحتاج أيضًا إلى نقل المفاتيح إليه ؛ مكتباتك لتسجيل الدخول ، والتي ستحتاج بالتأكيد إلى تخطي رابط فتح التطبيق. نوع من وحدة تحكم بدء تشغيل Windows ، ونقطة الإدخال نفسها لتشغيل البرنامج النصي الرئيسي الذي تريد تطويره في مشروع الاختبار الخاص بك.



كيف وصلنا قيام بذلك؟ من خلال عمل قالب AppDelegate واحد. هناك نقوم بتهيئة جميع البيئات والمكتبات اللازمة. نعيد توجيه جميع المكالمات اللازمة ، وننقل المفاتيح الضرورية. عند إنشاء مشروع اختبار ، يبقى لنا إنشاء AppDelegate جديد لمشروع الاختبار والوراثة من القالب.

بعد ذلك ، تجاوزنا الطريقة الوحيدة التي يتم استدعاؤها بعد أن قام القالب AppDelegate بكل ما هو ضروري. وهناك بالفعل برنامج ViewController الأولي ، وفوق كل ذلك يمكننا تشغيل البرنامج النصي الخاص بنا ، والذي نريد تصحيحه في مشروع الاختبار.

كان / أصبح


كيف يمكنني إنشاء مشروع اختبار في الجبين ، وكيف يمكنني إنشائه باستخدام الطريقة التي وصفتها اليوم؟

إنشاء مشروع اختبار في الجبهة:

- نذهب إلى Xcode ، وننشئ مشروعًا جديدًا (ملف> مشروع جديد).

- أدخل الاسم ، ويفضل أن يكون ذلك بدون أخطاء ، قم بتوقيع معرف الحزمة. نحن ننشئ هذا المشروع.

- قم بتغيير إصدار Swift ، قم بتغيير الإصدار المستهدف. نحن نحاول تشغيله كله على الجهاز ، وتحرير التوقيع ، وما إلى ذلك. هذه عملية كئيبة نوعًا ما.

- بعد ذلك ، نقوم بإنشاء ملف podfile ، وربط التبعيات هناك ، وتثبيت pods.

- بعد ذلك ، نبدأ ونبدأ في تكوين AppDelegate بشكل ممل وهادئ ، وننقل من خلال قطع تهيئة المكتبات التي نحتاجها.

- قم بإنشاء UIWindows مع ViewController

وفقط بعد ذلك يمكننا بدء تشغيل الكود المفيد. إجراء غير سار إلى حد ما ، يوافق.

كيف يمكننا إنشاء مشروع اختباري باستخدام أفضل الممارسات التي وصفتها في تقرير اليوم؟

- نقوم بإنشاء sample_app_spec ، باستخدام الامتداد ، لـ CocoaPods ، التي بدأنا بها.

- إنشاء AppDelegate ، وترثه من قالب AppDelegate.

بعد ذلك ، يمكننا البدء في كتابة تعليمات برمجية مفيدة.

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

هل يمكن أن يكون أسهل؟


يمكنك طرح سؤال - هل يمكن القيام بذلك بسهولة؟ بالطبع بكل تأكيد.



لقد حددت ثلاثة مستويات صعوبة. الأول هو ما تحدثت عنه اليوم ، دفعة واحدة ، عندما نصنع مكونًا إضافيًا لـ CocoaPods ، والذي يمكنه إصلاح مسارات الاستحقاقات ، ونموذج AppDelegate.

الطريقة الثانية مثالية في نسبة الجهود إلى الربح. يحتوي فقط على البرنامج المساعد لـ CocoaPods ، والذي كان الأول في قصة اليوم. أي أنه ببساطة يستبدل القيم الموجودة في Info.plist و xcconfig. بالفعل يجعل الحياة أسهل بكثير.

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

الطريقة الثالثة هي الأسهل ، ولا تتطلب أي تحضير. ما عليك سوى البدء في استخدام app_spec. يتم إنشاء المشروع الذي تم إنشاؤه من app_spec في نفس مساحة العمل مثل مشروعك الرئيسي. لذلك ، فإنه يرث بالفعل إصدار Swift والنسخة المستهدفة وجميع الإعدادات الموجودة في مساحة العمل. سيكون من الأسهل بالنسبة لك أن تبدأ العمل معه.
شكرا للانتباه.

All Articles