*عَلی* و *مِلی* و *سَلیب* و *سَمیرا* که با یکدیگر همکار هستند؛ به صرف شام به منزل *عَلی* دعوت شدهاند. ولی از آنجایی که حوصلهشان سر رفته، به دنبال بازی هیجانانگیزی برای افزایش آدرنالین خونشان هستند!
بازی از این قرار است که *مِلی* ، *سَلیب* و *سَمیرا* ، هر کدام از بین اعداد ۱، ۲، ۳ و ۴، یک عدد انتخاب میکنند (اعداد انتخابی متمایز هستند)؛ سپس *عَلی* باید عددی که از بین این ۴ عدد، انتخاب نشده است را حدس بزند! اگر عددی که *عَلی* حدس زد درست نبود؛ باید برای مهمانهایش پیتزا بخرد، درغیر اینصورت آنها را با نان و پنیر و سبزی، سیر میکند! *عَلی* از شما میخواهد که به او کمک کنید تا بتواند برندهی این بازی شود.
حال شما باید تابعی به نام `find(num1, num2, num3)` پیادهسازی کنید که با گرفتن سه عدد ورودی (`num1` عدد انتخابی *مِلی* ، `num2` عدد انتخابی *سَلیب* و `num3` عدد انتخابی *سَمیرا* است.)، عددی که در بین این اعداد وجود ندارد را بازگرداند.
``` python
def find(num1, num2, num3):
pass
```
## نمونه ۱
``` python
>>> find(1, 2, 3)
4
```
## نمونه ۲
``` python
>>> find(1, 4, 3)
2
```
## نکات
+ میتوانید فایل اولیه این سوال را از [این لینک](/contest/assignments/30822/download_problem_initial_project/102171/) دریافت کنید.
+ شما باید تابع `find` موجود در فایل `peydayesh.py` را تکمیل و سپس این فایل را ارسال کنید.
+ تضمین میشود که اعداد ورودی، از بین اعداد ۱، ۲، ۳ و ۴ هستند.
*عَلی* و *سَلیب* که با یکدیگر برادر هستند، تصمیم گرفتند یک بازی هیجانانگیز دو نفرهای را انجام دهند تا شاید آدرنالین خونشان افزایش پیدا کند.
بازی از این قرار است که *عَلی* و *سَلیب*، هر کدام یک رشته انتخاب میکنند. سپس حرف اول رشتهای که حرف اولش از لحاظ لغتنامهای کوچکتر است را حذف (اگر حرف اول دو رشته برابر بودند، حرف اول هر دو رشته را حذف میکنند.) و هر دو رشته را معکوس میکنند. این کار را تا جایی انجام میدهند که یکی از دو رشته یا هر دو رشته، خالی شوند.
حال شما باید تابع `compare(string1, string2)` (که `string1` رشتهی انتخابی عَلی و `string2` رشتهی انتخابی سَلیب است.) را به گونهای تکمیل کنید که:
+ اگر در نهایت یکی از دو رشته خالی شده بود، محتویات رشتهی دیگر را بازگرداند.
+ اگر در نهایت هر دو رشته خالی شده بودند؛ عبارت `Both strings are empty!` را بازگرداند.
توجه کنید که اگر یکی از رشتهها خالی شد؛ رشتهی دیگر، نباید مجدداً معکوس شود.
``` python
def compare(string1, string2):
pass
```
## نمونه ۱
``` python
>>> compare('ali', 'salib')
'las'
```
<details class="green">
<summary> **توضیحات نمونه ۱** </summary>
ابتدا حرف اول هر دو رشته بررسی میشود. چون `a` از `s` کوچکتر است، پس `a` از `ali` حذف شده و `ali` به `li` تبدیل میشود. سپس هر دو رشته معکوس (`li` به `il` و `salib` به `bilas`) میشوند.
حال از بین دو رشتهی جدید، چون `b` از `i` کوچکتر است، پس `b` از `bilas` حذف شده و `bilas` به `ilas` تبدیل میشود. سپس هر دو رشته معکوس (`il` به `li` و `ilas` به `sali`) میشوند.
حال مجددا از بین دو رشتهی جدید، چون `l` از `s` کوچکتر است، پس `l` از `li` حذف شده و `li` به `i` تبدیل میشود. سپس هر دو رشته معکوس (`i` به `i` و `sali` به `ilas` ) میشوند.
در نهایت، از بین ۲ رشتهی جدید، چون `i` و `i` با یکدیگر برابر هستند، پس هر دو `i` حذف میشود و `i` به یک رشتهی خالی و `ilas` به `las` تبدیل میشوند و چون یکی از رشتهها، خالی شدهاند، محتوای رشتهی دیگر (که برابر `las` است.) بازگردانده میشود.
</details>
## نمونه ۲
``` python
>>> compare('amin', 'nima')
'Both strings are empty!'
```
<details class="green">
<summary> **توضیحات نمونه ۲** </summary>
ابتدا حرف اول هر دو رشته بررسی میشود. چون `a` از `n` کوچکتر است، پس `a` از `amin` حذف شده و `amin` به `min` تبدیل میشود. سپس هر دو رشته معکوس (`min` به `nim` و `nima` به `amin`) میشوند.
حال از بین دو رشتهی جدید، چون `a` از `n` کوچکتر است، پس `a` از `amin` حذف شده و `amin` به `min` تبدیل میشود. سپس هر دو رشته معکوس (`nim` به `min` و `min` به `nim`) میشوند.
حال مجددا از بین دو رشتهی جدید، چون `m` از `n` کوچکتر است، پس `m` از `min` حذف شده و `min` به `in` تبدیل میشود. سپس هر دو رشته معکوس (`in` به `ni` و `nim` به `min` ) میشوند.
دوباره از بین دو رشتهی جدید، چون `m` از `n` کوچکتر است، پس `m` از `min` حذف شده و `min` به `in` تبدیل میشود. سپس هر دو رشته معکوس (`ni` به `in` و `in` به `ni`) میشوند.
سپس از بین دو رشتهی جدید، چون `i` از `n` کوچکتر است، پس `i` از `in` حذف شده و `in` به `n` تبدیل میشود. سپس هر دو رشته معکوس (`n` به `n` و `ni` به `in`) میشوند.
مجددا از بین دو رشتهی جدید، چون `i` از `n` کوچکتر است، پس `i` از `in` حذف شده و `in` به `n` تبدیل میشود. سپس هر دو رشته معکوس (`n` به `n` و `n` به `n`) میشوند.
در نهایت، از بین ۲ رشتهی جدید، چون `n` و `n` با یکدیگر برابر هستند، پس هر دو `n` حذف میشود و `n` به یک رشتهی خالی و `n` دوم نیز به یک رشتهی خالی تبدیل میشوند و چون هر دو رشته، خالی شدهاند، عبارت `Both strings are empty!` بازگردانده میشود.
</details>
## نکات
+ میتوانید فایل اولیه این سوال را از [این لینک](/contest/assignments/30822/download_problem_initial_project/102169/) دریافت کنید.
+ شما باید تابع `compare` موجود در فایل `moghayeseGar.py` را تکمیل و سپس این فایل را ارسال کنید.
+ تضمین میشود که رشتههای ورودی، تنها از حروف کوچک انگلیسی تشکیل شدهاند و شامل کاراکترهای _Whitespace_ نیستند.
برای *سَلیب* و *اِبلیس* سوال شده بود که چه کسی در کدنویسی مهارت بیشتری دارد. بنابراین آنها تصمیم گرفتند تا پروژه ای شبیه به بخش [مسابقات کوئرا](https://quera.ir/contest/) پیادهسازی کنند. سپس در آن به مسابقه بپردازند تا مشخص شود که کدامیک، کُدزن قَهارتری است!
اما در پیادهسازی بخشهایی از پروژه به مشکل خوردهاند و از شما میخواهند تا این بخشها را تکمیل کنید تا هر چه سریعتر بتوانند به مسابقهی خود بپردازند.
## پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/30822/download_problem_initial_project/102172/) دانلود کنید.
ساختار فایلهای این پروژه به صورت زیر است.
<details class="green">
<summary> **ساختار درختی پروژه** </summary>
```
quera_contest
├── accounts
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── permissions.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ ├── validators.py
│ └── views.py
├── contests
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── <mark class="yellow" title="این فایل را تغییر دهید"> > query.py < </mark>
│ ├── tests.py
│ └── views.py
├── fixtures
│ ├── sample_contest.json
│ └── sample_data.json
├── problems
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── <mark class="yellow" title="این فایل را تغییر دهید"> > models.py < </mark>
│ ├── tests.py
│ └── views.py
├── tests
│ ├── __init__.py
│ └── testsample.py
├── manage.py
└── requirements.txt
```
</details>
## مدلهایی که شما باید پیادهسازی کنید
<details class="blue">
<summary>
**مدل** `Problem`
</summary>
هر شئ این مدل معادل یک مسئله (*problem*) در کوئراست.
این مدل دارای ویژٰگیهای زیر است:
+ فیلد `name`:
نشاندهنده نام مسئله میباشد و از نوع `CharField` است. باید حداکثر طولی برابر با 50 کاراکتر داشته باشد.
+ فیلد `description`:
نشاندهنده توضیحات مسئله میباشد و از نوع `CharField` است. باید حداکثر طولی برابر با 1000 کاراکتر داشته باشد.
+ فیلد `writer`:
نشان دهنده طراح و نویسنده مسئله میباشد و از طریق رابطهی `many-to-one` به مدل `User` وصل میشود.
**توجه داشته باشید** مدل `User` درون اپ `accounts` در پروژه اولیه پیادهسازی شده و شما نیازی به ایجاد هیچ تغییری در آن ندارید.
+ فیلد `score`:
نشاندهنده نمره مسئله میباشد و از نوع `PositiveIntegerField` است. باید مقدار پیشفرضی برابر با 100 داشته باشد.
</details>
<details class="blue">
<summary>
**مدل** `Submission`
</summary>
هر شئ این مدل معادل یک پاسخ ارسال شده برای سیستم داوری کوئراست.
این مدل دارای ویژگیهای زیر است:
+ فیلد `submitted_time`:
نشاندهنده زمان پاسخ ارسالی میباشد و از نوع `DateTimeField` است.
+ فیلد `participant`:
نشان دهنده فرستنده پاسخ ارسالی میباشد و از طریق رابطهی `many-to-one` به مدل `User` وصل میشود و دارای آرگومان `related_name="submissions"` است.
**توجه داشته باشید** مدل `User` درون اپ `accounts` در پروژه اولیه پیادهسازی شده و شما نیازی به ایجاد هیچ تغییری در آن ندارید.
+ فیلد `problem`:
نشان دهنده مسئله پاسخ ارسالی میباشد و از طریق رابطهی `many-to-one` به مدل `Problem` وصل میشود و دارای آرگومان `related_name="submissions"` است.
+ فیلد `code`:
نشاندهنده آدرس ذخیره پاسخ ارسالی میباشد و از نوع `URLField` است. باید حداکثر طولی برابر با 200 کاراکتر داشته باشد.
+ فیلد `score`:
نشاندهنده نمره مسئله میباشد و از نوع `PositiveIntegerField` است. باید مقدار پیشفرضی برابر با 0 داشته باشد.
</details>
## کوئریهایی که شما باید پیادهسازی کنید
**اکیداً توصیه میشود** پیش از حل این بخش مدل `Contest` موجود در اپ `contests` را مطالعه کنید و با این مدل به خوبی آشنا شوید.
<details class="blue">
<summary>
**کوئری** `list_problems`
</summary>
این کوئری `id` یک `Contest` را ورودی گرفته و تمامی مسائل آن `Contest` را در قالب یک کوئریست بازمیگرداند.
مثالِ خروجی این تابع به صورت زیر است:
```python
<QuerySet [<Problem: Problem object (1)>, <Problem: Problem object (2)>, <Problem: Problem object (3)>]>
```
</details>
<details class="blue">
<summary>
**کوئری** `list_users`
</summary>
این کوئری `id` یک `Contest` را ورودی گرفته و تمامی کاربرانی که در آن `Contest` شرکت داشتهاند را در قالب یک کوئریست بازمیگرداند.
مثال خروجی این تابع به صورت زیر است:
```python
<QuerySet [<User: SAliB>, <User: Saeid>, <User: Ali>]>
```
</details>
<details class="blue">
<summary>
**کوئری** `list_submissions`
</summary>
این کوئری `id` یک `Contest` را ورودی گرفته و تمامی ارسالهای آن `Contest` را به ترتیب زمان ارسال (`submitted_time` در مدل `Submission`) از آخرین به اولین ارسال در قالب یک کوئریست بازمیگرداند.
مثال خروجی این تابع به صورت زیر است:
```python
<QuerySet [<Submission: Submission object (12)>, <Submission: Submission object (6)>, <Submission: Submission object (16)>, <Submission: Submission object (5)>, <Submission: Submission object (11)>, <Submission: Submission object (15)>, <Submission: Submission object (14)>, <Submission: Submission object (4)>, <Submission: Submission object (10)>, <Submission: Submission object (9)>, <Submission: Submission object (3)>, <Submission: Submission object (8)>, <Submission: Submission object (2)>, <Submission: Submission object (13)>, <Submission: Submission object (1)>, <Submission: Submission object (7)>]>
```
</details>
<details class="blue">
<summary>
**کوئری** `list_problem_submissions`
</summary>
این کوئری `id` یک `Contest` و `id` یک مسئله را ورودی گرفته و تمامی ارسالهای آن مسئله در `Contest` را به ترتیب زمان ارسال (`submitted_time` در مدل `Submission`) از آخرین به اولین ارسال در قالب یک کوئریست بازمیگرداند.
مثال خروجی این تابع به صورت زیر است:
```python
<QuerySet [<Submission: Submission object (9)>, <Submission: Submission object (8)>, <Submission: Submission object (2)>, <Submission: Submission object (13)>, <Submission: Submission object (1)>, <Submission: Submission object (7)>]>
```
</details>
<details class="blue">
<summary>
**کوئری** `list_user_submissions`
</summary>
این کوئری `id` یک `Contest` و `id` یک کاربر را ورودی گرفته و تمامی ارسالهای آن کاربر در `Contest` را به ترتیب زمان ارسال (`submitted_time` در مدل `Submission`) از آخرین ارسال به اولین ارسال در قالب یک کوئریست بازمیگرداند.
مثال خروجی این تابع به صورت زیر است:
```python
<QuerySet [<Submission: Submission object (6)>, <Submission: Submission object (5)>, <Submission: Submission object (4)>, <Submission: Submission object (3)>, <Submission: Submission object (2)>, <Submission: Submission object (1)>]>
```
</details>
<details class="blue">
<summary>
**کوئری** `list_problem_user_submissions`
</summary>
این کوئری `id` یک `Contest`، `id` یک کاربر و `id` یک مسئله را ورودی گرفته و تمامی ارسالهای آن کاربر در `Contest` برای آن مسئله را به ترتیب زمان ارسال (`submitted_time` در مدل `Submission`) از آخرین به اولین ارسال در قالب یک کوئریست بازمیگرداند.
مثال خروجی این تابع به صورت زیر است:
```python
<QuerySet [<Submission: Submission object (2)>, <Submission: Submission object (1)>]>
```
</details>
<details class="blue">
<summary>
**کوئری** `list_users_solved_problem`
</summary>
این کوئری `id` یک `Contest` و `id` یک مسئله را ورودی گرفته و تمامی کاربرانی که آن مسئله را در `Contest` حل کردهاند به ترتیب زمان ارسال (`submitted_time` در مدل `Submission`) از آخرین به اولین ارسال در قالب یک کوئریست بازمیگرداند.
**توجه کنید** تنها در صورتی یک پاسخ ارسالی درست است که نمره آن برابر با نمره اصلی مسئله باشد.
مثال خروجی این تابع به صورت زیر است:
```python
<QuerySet [<User: SAliB>]>
```
</details>
<details class="blue">
<summary>
**کوئری** `user_score`
</summary>
خروجی این کوئری از جنس عدد است. این کوئری `id` یک `Contest` و `id` یک کاربر را ورودی گرفته و مجموع امتیاز آن کاربر در `Contest` را خروجی میدهد.
**توجه داشته باشید** امتیاز هر کاربر در یک `Contest` برابر با جمع بیشترین امتیازات آن کاربر برای هر سوال است. مثلاً اگر یک کاربر برای سوال اول، امتیازات ۱۰۰، ۱۵۰ و ۲۰۰ را کسب کرده و برای سوال دوم، امتیازات ۵۰ و ۱۰۰ را کسب کرده باشد؛ امتیاز او برابر با بیشترین امتیاز کسب شده در سوال اول (۲۰۰) بعلاوه بیشترین امتیاز کسب شده در سوال دوم (۱۰۰) است (یعنی ۳۰۰).
مثال خروجی این تابع به صورت زیر است:
```python
600
```
</details>
<details class="blue">
<summary>
**کوئری** `list_final_submissions`
</summary>
این کوئری `id` یک `Contest` را ورودی گرفته و ارسالهای نهایی آن `Contest` را به ترتیب زمان ارسال (`submitted_time` در مدل `Submission`) از آخرین به اولین ارسال، در قالب یک کوئریست بازمیگرداند.
مثال خروجی این تابع به صورت زیر است:
```python
<QuerySet [{'participant_id': 1, 'problem_id': 1, 'score__max': 100}, {'participant_id': 1, 'problem_id': 2, 'score__max': 200}, {'participant_id': 1, 'problem_id': 3, 'score__max': 300}, {'participant_id': 2, 'problem_id': 1, 'score__max': 100}, {'participant_id': 2, 'problem_id': 2, 'score__max': 120}, {'participant_id': 3, 'problem_id': 1, 'score__max': 100}, {'participant_id': 3, 'problem_id': 2, 'score__max': 200}, {'participant_id': 3, 'problem_id': 3, 'score__max': 240}]>
```
</details>
## زیرمسئلهها
| امتیاز | بخش |
|:------------------:|:------------------:|
| ۱۰ | Problem Model |
| ۱۰ | Submission Model |
| ۱۵ | Query List Problem |
| ۱۵ | Query List Users |
| ۱۵ | Query List Submissions |
| ۲۰ | Query List Problem Submissions |
| ۲۰ | Query List User Submissions |
| ۲۵ | Query List Problem User Submissions |
| ۳۰ | Query List User Solved Problem |
| ۴۰ | Query User Score |
| ۴۰ | Query List Final Submissions |
### امکانات اضافه
در صورتی که علاقمندید که خودتان به صورت دستی کوئریهای خود را امتحان کنید و از درستی آنها اطمینان حاصل کنید، یا اینکه به بررسی بیشتر از این تمرین بپردازید، برای راحتی بیشتر شما، فایلهای مایگریشنها ساخته شدهاند و شما کافیست پس از پیادهسازی فایل `problems/models.py` جهت ایجاد پایگاهداده، یک بار دستور `migrate` را اجرا کنید.
علاوهبر این، یک سری دادهی از پیش آماده شده، فراهم شده که بعد از اجرای دستور `migrate`، میتوانید آنها را وارد پایگاهدادهی پروژهی خود کنید. به این منظور، دستور زیر را اجرا کنید. میتوانید از این دادهها به جهت تست کردن کوئریهای خود استفاده کنید.
**۱. ایجاد پایگاهداده**
```bash
python manage.py migrate
```
**۲. وارد کردن دادههای از پیش آماده شده (fixture)**
```bash
python manage.py loaddata fixtures/sample_data.json
python manage.py loaddata fixtures/sample_contest.json
```
در صورتی که علاقمند به تست نیستید، نیازی به ایجاد پایگاهداده و وارد کردن دادههای آزمایشی نیست، و تنها کافیست که در فایل `query.py` کوئریهای خود را بنویسید و از کوئرا جهت امتحان کردن درستی کوئریهایتان استفاده کنید.
## نکات
+ شما تنها مجوز ایجاد تغییرات در فایلهای زیر را دارید و **تمامی تغییرات دیگر شما** در فایلهای پروژه **نادیده گرفته خواهند شد.**
+ فایل `contests/query.py`
+ فایل `problems/models.py`
+ فراموش نکنید که میتوانید با مطالعهی `testsample.py` با روش تست کردن مدلها آشنا شوید.
## آنچه باید آپلود کنید
این سوال از نوع سوالات چندفایلی است. برای حل سوال میتوانید پروژه را در قالب یک فایل *ZIP* که شامل کلیه فایلهای موجود در پروژه است، ارسال کنید.
*فرهاد* که به تازگی در کوئرا استخدام شده، تصمیم گرفته برای کمک به بخش [Careers کوئرا](https://talent.quera.ir/) تعدادی دستور طراحی کند. او که تسلط کمی به خط فرمان دارد و فقط توانسته مدل شرکت را تکمیل کند و به علت همزمان شدن امتحاناتش با زمان تحویل، به کمک شما برای تکمیل دستورات نیاز دارد.
## پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/30822/download_problem_initial_project/102170/) دریافت کنید.
ساختار فایلهای این پروژه به صورت زیر است.
<details class="green">
<summary> **ساختار درختی پروژه** </summary>
```
CLI
├── career
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── management
│ │ ├── commands
│ │ │ ├── <mark class="yellow" title="این فایل را تغییر دهید"> > addCompany.py < </mark>
│ │ │ ├── <mark class="yellow" title="این فایل را تغییر دهید"> > collectCompany.py < </mark>
│ │ │ ├── <mark class="yellow" title="این فایل را تغییر دهید"> > editCompany.py < </mark>
│ │ │ ├── __init__.py
│ │ │ └── <mark class="yellow" title="این فایل را تغییر دهید"> > rmCompany.py < </mark>
│ │ └── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── utils.py
│ └── views.py
├── config
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── requirements.txt
└── tests
├── __init__.py
└── testssample.py
```
</details>
برای کمک به *فرهاد*، دستورات خواسته شده را در فایلهای خواسته شده پیادهسازی کنید.
<details class="blue">
<summary> **دستور** `addCompany` </summary>
میخواهیم درون فایل `addCompany.py`، دستوری برای جنگو بنویسیم که با اجرای آن، به ترتیب مقادیر *name*, *email*, *phone*, *description* (از چپ به راست) را از کاربر دریافت کند و با این مقادیر، یک نمونه از کلاس *Company* بسازد.
+ برای فیلدهايی که دارای ویژگی `null=False` هستند، کاربر حتما باید مقداری را وارد کند. در صورتی که کاربر بدون وارد کردن مقداری *Enter* زد باید خطای `Error: This field cannot be blank.` نمایش داده شود و برای فیلدهایی که دارای ویژگی `null=True` هستند، با زدن *Enter* به مرحله بعد رفته و مقدار آن فیلد *None* شود.
### اعتبارسنجی مخصوص هر فیلد:
<details class="grey">
<summary> **name** </summary>
فیلد `name` باید حداکثر ۵۰ کاراکتر باشد؛ در غیر اینصورت، عبارت
`Error: Ensure this value has at most 50 characters (it has COUNT).`
نمایش داده شود که به جای کلمهی *COUNT*، تعداد کاراکترهای عبارت شما قرار میگیرد.
همچنین این فیلد باید یکتا باشد؛ در غیر اینصورت، عبارت
`Error: That name is already taken.`
نمایش داده شود.
</details>
<details class="grey">
<summary> **email** </summary>
آدرس وارد شده باید یک ایمیل معتبر باشد، در غیر اینصورت باید عبارت
`Error: Enter a valid email address.`
نمایش داده شود.
</details>
<details class="grey">
<summary> **phone** </summary>
یک شماره موبایل در صورتی معتبر است که یکی از حالتهای زیر را دارا باشد:
* شامل ۱۱ رقم باشد و با 09 آغاز شود.
* شامل ۱۳ رقم باشد و با 98+ آغاز شود.
* شامل ۱۴ رقم باشد و با 0098 آغاز شود.
در غیر این صورت باید عبارت
`Error: Phone number format is not valid.`
نمایش داده شود.
</details>
<details class="grey">
<summary> **description** </summary>
این فیلد محدودیتی ندارد.
</details>
### نکات مهم
* در صورت وارد شدن مقدار غیر قابل قبول برای هر فیلد، خط فرمان همچنان منتظر وارد شدن مقدار قابل قبول برای همان فیلد میماند.
* برای چاپ خطاها، حتماً از دستور `self.stderr.write(error_msg)` استفاده کنید.
### نمونه
![توضیح تصویر](https://s4.uupload.ir/files/contest1_pdos.png)
</details>
</details>
<details class="blue">
<summary> **دستور** `editCompany` </summary>
میخواهیم درون فایل `editCompany.py`، دستوری برای جنگو بنویسیم که یک *positional arguments* به عنوان نام شرکت و همچنین چهار *optional arguments* (`--description` ,`--phone` ,`--email` ,`--name`) دریافت و فیلدهای مربوط به آن شرکت را بروز کند.
+ برای فیلدهايی که دارای ویژگی `null=False` هستند، اگر آرگومان آنها برابر `''` بود؛ استثنای *CommandError* با پیام `Field cannot be blank.` رخ دهد (به جای کلمهی `Field`، نام فیلد با حرف ابتدای **بزرگ** قرار میگیرد.) اما برای فیلدهایی که دارای ویژگی `null=True` هستند، میتواند برابر `''` باشد؛ ولی مقدار فیلد تغییری نمیکند.
+ در هر مرحله از اعتبار سنجی که در ادامه اشاره میشود، اگر مقادیر، معتبر نبودند باید استثنای *CommandError* با پیام خطای مربوط رخ دهد.
+ موارد، به ترتیب نوشتهشده باید بررسی شوند.
<details class="grey">
<summary> **positional arguments** </summary>
در صورتی که شرکتی با این نام وجود نداشت؛ باید یک `Exception` با پیام
`Company matching query does not exist.`
رخ دهد.
</details>
<details class="grey">
<summary> **optional arguments** </summary>
<details class="yellow">
<summary> **name** </summary>
آرگومان `name` باید حداکثر ۵۰ کاراکتر باشد؛ در غیر اینصورت، یک `Exception` با پیام
`Error: Ensure this value has at most 50 characters (it has NUM).`
رخ دهد که به جای *NUM* تعداد کاراکترهای عبارت شما قرار میگیرد.
همچنین این فیلد باید یکتا باشد، در غیر اینصورت، باید یک `Exception` با پیام
`Error: That name is already taken.`
رخ دهد.
</details>
<details class="yellow">
<summary> **email** </summary>
آدرس وارد شده باید یک ایمیل معتبر باشد در غیر این صورت باید یک `Exception` با پیام
`Error: Enter a valid email address.`
رخ دهد.
</details>
<details class="yellow">
<summary> **phone** </summary>
یک شماره موبایل در صورتی معتبر است که یکی از حالتهای زیر را دارا باشد:
* شامل ۱۱ رقم باشد و با 09 آغاز شود.
* شامل ۱۳ رقم باشد و با 98+ آغاز شود.
* شامل ۱۴ رقم باشد و با 0098 آغاز شود.
در غیر این صورت باید یک `Exception` با پیام
`Error: Phone number format is not valid.`
رخ دهد.
</details>
<details class="yellow">
<summary> **description** </summary>
این آرگومان محدودیتی ندارد.
</details>
</details>
### نمونه
![توضیح تصویر](https://s4.uupload.ir/files/contest2_xqbo.png)
</details>
</details>
<details class="blue">
<summary> **دستور** `rmCompany` </summary>
میخواهیم درون فایل `rmCompany.py`، برای جنگو بنویسیم که نام تعدادی (صفر یا بیشتر) شرکت را دریافت کند و درصورتی که شرکتی با آن نامها وجود داشت آن را از پایگاه داده حذف کند.
<details class="grey">
<summary> **positional argument** </summary>
در صورتی که شرکتی با این نامها وجود نداشت، به ازای هر نام غیرمعتبر باید عبارت
`COMPANY matching query does not exist.`
نمایش داده شود، که به جای *COMPANY* نام شرکت وارد شده قرار میگیرد.
</details>
<details class="grey">
<summary> **optional argument** </summary>
در صورت وجود `--all` در دستور، بدون توجه به نام شرکتهای وارد شده (در صورت وجود)، تمام شرکتها حذف میشوند.
</details>
### نکات مهم
+ برای چاپ خطا، حتماً از دستور `self.stderr.write(error_msg)` استفاده کنید.
### نمونه
![توضیح تصویر](https://s4.uupload.ir/files/contest3_7vly.png)
</details>
<details class="blue">
<summary> **دستور** `collectCompany` </summary>
میخواهیم درون فایل `collectCompany.py`، دستوری برای جنگو بنویسیم که با اجرای آن، یک فایل *CSV* به نام `company.csv` شامل اطلاعات تماس شرکتها، در ریشهی پروژه ایجاد شود.
+ ستونهای فایل *CSV* به ترتیب (از چپ به راست) نام، ایمیل و تلفن شرکت است.
</details>
## نکات
+ توجه کنید که در قسمتهایی که گفته شده عبارت مورد نظر نمایش داده شود، باید از دستور `self.stderr.write(error_msg)` و در قسمتهایی که گفته شده یک `Exception` رخ دهد، از دستور `raise` استفاده کنید.
+ شما تنها مجوز ایجاد تغییرات در فایلهای زیر را دارید و **تمامی تغییرات دیگر شما** در فایلهای پروژه **نادیده گرفته خواهند شد.**
+ فایل `career/management/commands/addCompany.py`
+ فایل `career/management/commands/collectCompany.py`
+ فایل `career/management/commands/editCompany.py`
+ فایل `career/management/commands/rmCompany.py`
## آنچه باید آپلود کنید
این سوال از نوع سوالات چندفایلی است. برای حل سوال میتوانید پروژه را در قالب یک فایل *ZIP* که شامل کلیه فایلهای موجود در پروژه است، ارسال کنید.