بالین!


سَعَد و حَمَد که در یک خوابگاه، هم‌اتاقی هستند؛ از طبقه‌ی همکف سوار آسانسور می‌شوند تا به طبقه‌ای‌ که اتاق‌شان در آن قرار دارد بروند. ولی هنگامی که سوار آسانسور می‌شوند؛ تصمیم به انجام بازی هیجان‌انگیزی می‌گیرند!

آسانسور خوابگاه آن‌ها بدین صورت است که فقط دکمه‌ی بالا و پایین دارد، دکمه‌ی بالا، آسانسور را به یک طبقه بالاتر می‌برد و دکمه‌ی پایین، آسانسور را به یک طبقه پایین‌تر.

بازی به این صورت است که این دو نفر، ۴ بار فرصت دارند تا دکمه‌ی پایین و بالای این آسانسور را فشار دهند. در نهایت، پس از اینکه ۴ بار دکمه‌های بالا و پایین آسانسور فشار داده شد؛ باید بفهمند که در کدام طبقه قرار دارند.

فرض می‌کنیم که طبقات منفی نیز داریم و آسانسور، حداکثر تا ۴ طبقه، زیر زمین نیز خواهد رفت.

حال تابع calculate_floor را به‌گونه‌ای تکمیل کنید که با گرفتن یک رشته‌ی ۴ حرفی که شامل U به معنای رفتن به طبقه‌ی بالا و D به معنای رفتن به طبقه‌ی پایین است، شماره‌ی طبقه‌ای که در نهایت به آن می‌رویم را بازگرداند.

دقت کنید که در ابتدای حرکت، در طبقه‌ی همکف (شماره ۰) قرار داریم.

extensionFromNamecalculator.py
def calculate_floor(string):
    pass
Python

نمونه ۱🔗

>>> calculate_floor('UUDU')
2
Python
توضیحات نمونه

ابتدا در طبقه‌ی همکف قرار داریم. سپس با دیدن حرف U یک طبقه به بالا می‌رویم و در طبقه‌ی ۱ قرار داریم. مجددا با دیدن حرف U یک طبقه‌ی دیگر به بالا می‌رویم و در طبقه‌ی ۲ قرار داریم. حال با دیدن D یک طبقه به پایین می‌رویم و در طبقه‌ی ‍۱ قرار داریم. در نهایت با دیدن U یک طبقه به بالا می‌رویم و در نهایت در طبقه‌ی ۲ هستیم. پس عدد ۲ را بازمی‌گردانیم.

نمونه ۲🔗

>>> calculate_floor('DDDD')
-4
Python
توضیحات نمونه

ابتدا در طبقه‌ی همکف قرار داریم. با هر بار مشاهده‌ی حرف D، یک طبقه به پایین می‌رویم. پس با ۴ بار دیدن حرف D، چهار بار به پایین می‌رویم و در نهایت در طبقه‌ی ۴- قرار می‌گیریم. پس ۴- را بازمی‌گردانیم.

نکات🔗

  • می‌توانید فایل اولیه این سوال را از این لینک دریافت کنید.
  • شما باید تابع calculate_floor موجود در فایل calculator.py را تکمیل و سپس این فایل را ارسال کنید.
  • تابع شما نباید مقداری را چاپ کند، بلکه باید مقدار مورد نظر را بازگرداند.
  • تضمین می‌شود که رشته‌های ورودی، همیشه یک رشته‌ی ۴ حرفی متشکل از حروف U و D می‌باشند.

اعتبارسنجی مقالات


تبریک! شما در ژورنالی که سلیب رئیس آن است، استخدام شده‌اید. اما سلیب که بسیار سخت‌گیر است، در همان ابتدای کار به شما یک وظیفه محول کرده است. شما باید برنامه‌ای برای اعتبارسنجی اولیهٔ مقالاتی که نویسندگان به ژورنال برای چاپ ارسال کرده‌اند، بنویسید. فرمت این اعتبارسنجی به شرح زیر است:

تابع extract_paper🔗

عملکرد تابع🔗

در ورودی آدرس فایل مقاله و سایز فونت را می گیرد. باید بتواند با باز کردن و خواندن فایل مقاله، فیلدهای مختلف آن را استخراج کرده و یک دیکشنری از آن بسازد. فرمت مقاله‌ها به شکل زیر است: توضیح تصویر

در نهایت این تابع باید یک دیکشنری با کلیدهای زیر برگرداند.

  • عنوان title: از نوع str است.
  • چکیده abstract: از نوع str است.
  • کلمات کلیدی keywords: از نوع list است.
  • مقدمه introduction: از نوع str است.
  • بدنه body: از نوع str است.
  • نتیجه‌گیری conclusion: از نوع str است.
  • مراجع references: از نوع list است.
  • تعداد کلمات کل مقاله words_count: از نوع int است.
  • تعداد صفحات کل مقاله pages_count: از نوع int است.

اعتبارسنجی‌ها🔗

  • چکیده نباید بیش از ۱۵۰ کلمه باشد. درغیراین‌صورت یک Exception با پیام The abstract section can't be more than 150 words پرتاب می‌شود.
  • تعداد کلمات کلیدی نباید بیش از ۵ باشد. درغیراین‌صورتت یک Exception با پیام You can't put more than 5 keywords پرتاب می‌شود.
  • کلمات کلیدی باید بر اساس حروف الفبا مرتب شده باشند. درغیراین‌صورت یک Exception با پیام Keywords are not sorted پرتاب می‌شود.
  • طول کل مقاله نباید بیش از ۹ صفحه باشد. درغیراین‌صورت یک Exception با پیام The whole paper can't be more than 9 pages پرتاب می‌شود.

نحوهٔ شمارش کلمات🔗

جداکنندهٔ کلمات از یکدیگر، کاراکترهای «فاصله» و «خط جدید» هستند.

نحوهٔ شمارش صفحات🔗

محاسبهٔ تعداد صفحات از طریق تعداد کلمات و اندازهٔ فونت صورت می‌گیرد. هر ۵۱۲ کلمه با اندازهٔ فونت ۱۶، یک صفحه را تشکیل می‌دهند. اگر اندازهٔ فونت بزرگ‌تر شود، یک صفحه شامل تعداد کلمات کمتری خواهد بود و اگر اندازهٔ فونت کوچک‌تر شود، یک صفحه شامل تعداد کلمات بیشتری می‌شود.
به‌طور مثال فرض کنید یک مقاله ۵۱۲ کلمه باشد. اگر اندازهٔ فونت ۱۶ باشد، این مقاله یک صفحه است و اگر اندازهٔ فونت ۳۲ باشد، این مقاله ۲ صفحه خواهد بود زیرا هر صفحه شامل ۲۵۶ کلمه می‌شود.

نکات🔗

  • می‌توانید فایل اولیهٔ این سؤال را از این لینک دریافت کنید.

کارآگاه آکا


واحد جنایی کوئرا که فعالیت خودش را از سال ۱۳۹۹ آغاز کرده بود، فیلمی از کارآگاه فرهاد -یکی از اولین کارآگاه‌های کوئرا- دریافت کرده است. در این فیلم فرهاد توسط یک باند مافیایی محاصره شده است و از کوئرا درخواست کمک کرده است. فرهاد به سرنخ‌های مهمی از عملیات‌های این باند مافیایی دست پیدا کرده است و آن‌ها را داخل یکی از سرورهای امن کوئرا و با چند پیچیدگی امنیتی آپلود کرده است. باند مافیایی که از این ماجرا بسیار عصبانی شده بود، فرهاد را به قتل رساند! حال واحد جنایی کوئرا به کارآگاه کیان و کارآگاه آدرینا ماموریت داده است تا داده‌هایی که فرهاد بر روی سرور قرار داده است را رمزگشایی کنند. از آنجایی که فرهاد چندین لایه امنیتی را بر روی سرور تنظیم کرده است، آن‌ها به کمک شما برای پیدا کردن سرنخ‌ها نیاز دارند.

ساختار پروژه🔗

کیان و آدرینا کلاسی به نام Detective را طراحی کردند که دارای توابع زیر هست:

تابع login

این تابع با دریافت username و password و URL صفحه ورود، وظیفه احراز هویت کاربران را به عهده دارد. در صورتی که عملیات احراز هویت موفقیت آمیز باشد، یک فایل JSON به فرمت زیر برگردانده می‌شود:

{
    "token": <Authorization Token>,
    "first_name": "Kian",
    "last_name": "Majlessi",
    "email": "contact@quera.org",
    "upload_url": <UPLOAD_URL>
}
JSON

از آنجایی که token و upload_url محرمانه هستند؛ لازم هست که شما یک دیکشنری تنها با دو کلید full_name و email برگردانید.

  • full_name یک کاربر نام و نام خانوادگی او است که با یک اسپیس از هم جدا شده‌اند.

و در صورتی که عملیات احراز هویت موفقیت آمیز نبود، باید یک Exception با پیغام زیر پرتاب کنید:

[<STATUS_CODE>]: Unable to log in with provided credentials.
Plain text

نکات مهم🔗

  • درخواست‌های شما به صفحه ورود باید از طریق متد POST انجام شوند.
  • سرور فرهاد از احراز هویت با توکن استفاده می‌کند. به این صورت که هر کابر برای لاگین کردن پس از ارسال نام کاربری و رمز عبور خود و در صورت درست بودن اطلاعات، یک نشانه‌ی منحصر به فرد (Unique Token) را به عنوان پاسخ دریافت می‌کند. از این پس هر ریکوئستی که آن کاربر به ای‌پی‌آی‌های آن سرور می‌زند، برای آن که لاگین بودن خود را ثابت کند، باید این نشانه‌ی منحصر به فرد را برای سرور ارسال کند تا سرور بتواند هویت ‌آن شخص را بر اساس این نشانه، تشخیص دهد و به او اجازه‌های دسترسی لازم را بدهد.
  • برای ارسال توکن به سرور باید مقدار زیر را در Header درخواست‌های خود به سرور قرار دهید.
    Authorization: Token <Token>
    Plain text
  • برای امنیت بیشتر، پس از لاگین کاربر، یک کوکی مخفی در سیستم او ذخیره می‌شود. برای انجام درخواست‌های بعدی لازم است که این کوکی را در سیستم خود در اختیار داشته باشید!
تابع upload_clues

سعید و مهدی که موازی با فرهاد در حال کار بر روی این پرونده بودند، مدارکی را جمع‌آوری و در پوشه‌ای به نام secrets در کنار فایل کلاینت شما قرار دادند. شما باید تمامی این مدارک را پیدا کرده و از طریق متد PUT و فیلد uploaded_files داخل آدرسی که در مرحله قبل دریافت کرده‌اید در سرور آپلود کنید. در نهایت، سرور یک فایل JSON که شامل کلیدهای detail و download_url هست را به شما برمی‌گرداند. از مقدار download_url برای قسمت بعدی سوال استفاده کنید و مقدار detail را برای ما برگردانید!

put(url=upload_url, files=[('uploaded_files', open(file_address,"rb")),('uploaded_files', , open(file_address,"rb")), ......])
Python
تابع html_scraper

تبریک! شما به اسناد فرهاد دسترسی پیدا کردید. اما عجله نکنید! این تازه اول راه است. فرهاد که هیچ‌وقت نمی‌خواست باند مافیا به اسناد دست پیدا کند، آن‌ها را در مکان‌های مختلفی قرار داد و لینک‌هایش را در صفحه HTML ای مخفی کرد. شما در این تابع با استفاده از متد GET و آدرس صفحه‌ای که در مرحله قبل دریافت کرده‌اید، می‌توانید این صفحه HTML را دانلود کنید. حال، تمامی لینک‌های آن و عنوان‌هایش را پیدا کنید و در دیکشنری‌ای به تیم جنایی کوئرا برگردانید. کلید دیکشنری شما باید عنوان لینک و مقدار آن آدرس لینک‌ باشد.

  • توجه کنید که تنها لینک‌هایی را باید داخل دیکشنری قرار دهید که دارای عنوان باشند.
محتویات فایل solution.py
extensionFromNamesolution.py
class Detective:

    def login(self, username: str, password: str, login_url: str):
        pass
        #TODO: Complete login Function

    def upload_clues(self):
        pass
        #TODO: Complete upload_clues Function

    def html_scraper(self):
        pass
        #TODO: Complete html_scraper Function
Python

همچنین شما می‌توانید پروژه اولیه را از این لینک دانلود کنید.

پاسخ ارسالی🔗

در پاسخ ارسالی خود می‌توانید از هر کتابخانه‌ای که لازم می‌دانید استفاده کنید. اما در فایل ارسالی خود، علاوه بر فایل solution.py که حاوی راه‌حل شما است، باید فایلی با نام python_requirements.txt نیز موجود باشد که در آن نام کتابخانه‌های مورد نیاز و شمارهٔ نسخهٔ آن‌ها به فرمت زیر در آن موجود باشد:

extensionFromNamepython_requirements.txt
firstlib==1.2.3
secondlib==4.5.6
...
Plain text

ساختار فایل ارسالی🔗

ساختار فایل .zip ارسالی شما باید به صورت زیر باشد:

<your_zip_file_name.zip>
         ├── solution.py
         └── python_requirements.txt
Plain text

تخفیف


فرهاد که به تازگی کتاب‌فروشی آنلاین خود را باز کرده، تصمیم گرفته قابلیت تخفیف را به آن اضافه کند. ولی برای این کار نیاز به کمک شما دارد تا پروژه را طبق توضیحات ادامه تکمیل کنید.

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایلهای این پروژه به صورت زیر است:

Discount
├── accounts
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── authors
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── > books <
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── > models.py <
│   ├── > serializers.py <
│   ├── tests.py
│   ├── urls.py
│   └── > views.py <
├── BookStore Quera.postman_collection.json
├── config
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── discounts
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── permissions.py
│   ├── serializers.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── fixtures
│   └── postman_sample_fixture.json
├── manage.py
├── requirements.txt
└── tests
    ├── __init__.py
    └── testsample.py
Plain text

اپلیکشن discounts🔗

اپلیکیشن discounts شامل مدل‌های مختلفی می‌شود که کتاب می‌تواند براساس آن شامل تخفیف شود. در ادامه شرایط اعمال آنها را برای کتاب‌ها مشخص شده است.

مدل CountryDiscount

اگر کشور کاربر با کشور مشخص شده در این تخفیف یکسان بود، تمامی کتاب‌های موجود شامل درصد تخفیف مشخص شده می‌شوند.

مدل AuthorDiscount

تمامی کتاب‌هایی که یکی از نویسندگان آن، نویسنده مشخص شده بود، شامل درصد تخفیف مشخص شده می‌شوند

مدل ‍CategoryDiscount

تمامی کتاب‌هایی که یکی از دسته‌بندی‌های آن، دسته‌بندی مشخص شده بود، شامل درصد تخفیف مشخص شده می‌شوند.

مدل BookDiscount

در این تخیفیف تنها کتاب مشخص شده، شامل درصد تخفیف مشخص شده می‌شود.

پیاده‌سازی مورد انتظار🔗

اکیدا توصیه می‌شود پیش از حل این بخش سایر قسمت‌های پروژه را مطالعه کنید.

تابع get_discount در books/models.py

این تابع باید بهترین تخفیفی که شامل کتاب مورد نظر (self) می‌شود. را انتخاب و قیمت بعد از اعمال شدن آن تخفیف را خروجی دهد.

نکات

* ممکن است چندین تخفیف مختلف را برای کتاب بتوان اعمال کرد. ولی فقط باید بهترین تخفیف بر روی آن، اعمال شود و در خروجی قیمت پس از اعمال تخفیف برگردانده شود. * دقت کنید ممکن است ریکوئست دریافتی از طرف کاربری که احراز هویت نشده فرستاده شود.

ویو BookViewSet در books/views.py

شما باید با نوشتن سریالایزر یا سریالایزرهایی در books/serializers.py برای مدل Book و تکمیل ویو BookViewSet ریکوئست‌هایی مشابه نمونه‌های آورده شده در فایل BookStore Quera.postman_collection.json (این فایل را با اپلیکیشن postman باز کنید.) مدیریت کنید و پاسخ مشابهی دریافت کنید.

نکات

* از فیکسچر postman_sample_fixture.josn برای ایجاد مثال‌های موجود در کالکشن پستمن استفاده شده، در صورتی که مایل باشید می‌توانید این فیکسچر را load کرده و ریکوئست‌ها را مجدد اجرا کنید.

نکات🔗

  • شما تنها مجوز ایجاد تغییرات در فایل‌های books/views.py‍، books/models.py و books/serializers.py و ایجاد فایل جدیدی در books/ را دارید و تمامی تغییرات دیگر شما در فایل‌های پروژه نادیده گرفته خواهند شد.
  • فراموش نکنید که می‌توانید با مطالعه‌ی testsample.py با روش تست کردن مدل‌ها، فرم‌ها و ادمین‌ها آشنا شوید.

نحوه ارسال🔗

یک فایل ZIP حاوی همه‌ی فایل‌های پروژه، آپلود کنید. نام فایل ZIP اهمیتی ندارد.

آپلودسنتر


کوئرا قصد دارد تا آپلودسنتری برای کاربران سامانه LMS اش طراحی کند. بدین ترتیب کاربران می‌توانند فایل‌های آموزشی موردنیاز خود برای هر کلاس را داخل صفحه کلاس آپلود کنند و لینکش را با بقیه به اشتراک قرار دهند. از آنجایی که همه آپلودسنترها دارای محدودیت‌هایی برای آپلود فایل هستند و تیم فنی کوئرا وقتی برای پیاده‌سازی این سامانه ندارند، از شما می‌خواهیم تا API آپلودسنتر مدنظرشان را طراحی کنید.

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است:

django_upload_center
├── account
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── config
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── tests
│   └── testssample.py
├── upload_center
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── serializers.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── manage.py
└── requirements.txt
Plain text

اپلیکشن account🔗

اپلیکیشن account شامل دو مدل می‌شود که محدودیت‌های کاربران را مشخص می‌کنند. در ادامه فیلدهای هر یک توضیح داده شده است.

مدل User

این مدل شامل فیلدهای زیر است:

  • فیلد account‍ که مشخص کننده نوع حساب کاربری یک User است.
  • فیلد used_storage که مقدار فضای اشغال شده در سرور توسط User را بر حسب بایت نشان می‌دهد.
مدل Account

این مدل شامل فیلدهای زیر است:

  • فیلد title که عنوان اکانت را مشخص می‌کند.
  • فیلد storage که حداکثر فضای مربوط به این نوع حساب کاربری را بر حسب بایت مشخص می‌کند.
  • فیلد max_file_transfer که حداکثر محدودیت حجمی فایل‌های آپلود شده مربوط به این نوع حساب کاربری را بر حسب بایت مشخص می‌کند.

پیاده‌سازی مورد انتظار🔗

اکیدا توصیه می‌شود پیش از حل این بخش سایر قسمت‌های پروژه را مطالعه کنید.

ویو UploadFile

متد PUT در این ویو، وظیفه آپلود فایل کاربران را بر عهده دارد و در پاسخ یک دیکشنری به صورت فایل JSON مانند زیر برمی‌گرداند:

{
    "city-g948bcbda2_640.jpg": "/fm/download/kian/city-g948bcbda2_640.jpg",
    "a-month-ga3e069e51_640.jpg": "/fm/download/kian/a-month-ga3e069e51_640.jpg",
    "Kargah.rar": "You don't have enough space to upload this file!",
    "Tedx_Intro.pdf": "You can't upload files more than 1.000 Megabytes!"
}
JSON

در این دیکشنری، کلیدها نام فایل ذخیره شده در سرور و مقدار آن‌ها آدرس دانلود فایل مربوطه می‌باشد. در صورتی که حجم فایل ارسالی از محدودیت مشخص شده (max_file_transfer) بیشتر باشد، کلید دیکشنری اسم فایل ارسالی و مقدار آن باید عبارت زیر باشد:

You can't upload files more than <user_max_file_transfer> Megabytes!
Plain text

و در صورتی که کاربر فضایی برای آپلود فایل جدید نداشت، کلید دیکشنری اسم فایل ارسالی و مقدار آن باید عبارت زیر باشد:

You don't have enough space to upload this file!
Plain text

نکات مهم🔗

  • فایل‌های کاربران باید در root پروژه و در دایرکتوری زیر ذخیره شوند.
.uploaded_files/<username>
Plain text
  • کاربران باید امکان آپلود چندین فایل را به صورت همزمان داشته باشند.
  • در صورتی که یک فایل خالی آپلود شود، استاتوس کد ۴۰۰ را برگردانید.
  • آپلودسنتر حداکثر تعداد فایلی که از کاربر دریافت می‌کند را باید با توجه به محدودیت‌های اکانت کاربر آپلود کند.
  • کاربران باید بتوانند فایل‌هایی تکراری یا با نام یکسان آپلود کنند.
  • برای مدیریت آپلود فایل‌هایی با نام مشابه، فقط به انتهای نام فایل می‌توانید یک شناسه (suffix) اضافه کنید و نام فایل نباید تغییری کند.
  • برای تبدیل کیلوبایت به مگابایت تنها کافیست که عدد موردنظر را بر عدد ۱۰۲۴ تقسیم کنید.
ویو FileManager
متد GET

در این متد، اطلاعات کاربر به صورت یک فایل JSON مانند زیر برمی‌گردد:

{
    "Account": "Pro",
    "Storage": 5.000,
    "Used": 0.916,
    "Files": [
        "a-month-ga3e069e51_640.jpg",
        "city-g948bcbda2_640.jpg"
    ]
}
JSON
  • در صورتی که کاربر فایلی در سرور نداشت، متن زیر را به عنوان مقدار کلید Files قرار دهید:
    <username> doesn't have any files!
    Plain text
متد DELETE

در این متد، نام فایلی که قرار است حذف شود در پارامتر file_name از طریق دیکشنری POST‍‍‍ شئ ریکوئست در دسترس است. در صورتی که فایل موردنظر در سرور وجود داشت، فایل را از سرور حذف کنید، اطلاعات کاربر را به‌روز کنید و پاسخ زیر را در قالب JSON به کاربر نشان دهید:

{
    "detail": "<FILE_NAME> Deleted Successfully."
}
JSON

و در صورتی که فایل در سرور موجود نبود، پاسخ زیر را در قالب JSON و با استاتوس کد ۴۰۴ به کاربر ارائه دهید:

{
    "detail": "<FILE_NAME> hasn't existed!"
}
JSON
ویو DownloadFile

در متد GET‍ این ویو، فایل خواسته شده را به صورت یک FileResponse برگردانید.

  • پارامتر user‍ نام کاربری کاربر آپلودکننده فایل است و پارامتر filename نام فایل را مشخص می‌کند.
  • در صورتی که فایل درخواست شده موجود نباشد، یک دیکشنری به فرمت زیر و با کد وضعیت ۴۰۴ برگردانید:
    {"detail": f"{filename} hasn't existed!"}
    Python

نکات🔗

  • شما تنها مجوز ایجاد تغییرات در فایل‌های upload_center/views.py‍، config/settings.py و upload_center/serializers.py را دارید و تمامی تغییرات دیگر شما در فایل‌های پروژه نادیده گرفته خواهند شد.
  • فراموش نکنید که می‌توانید با مطالعه‌ی testssample.py با روش تست کردن مدل‌ها، فرم‌ها و ویوها آشنا شوید.

نحوه ارسال🔗

یک فایل ZIP حاوی همه‌ی فایل‌های پروژه، آپلود کنید. نام فایل ZIP اهمیتی ندارد.