*بله* میخواهد برای کاربرانش در کانالها محدودیت ایجاد کند. او پس از تحقیقات بسیار در مورد روشهای پیش رو، تصمیم گرفت که دسترسی هر کاربر را با یک عدد نشان دهد. هر بیت این عدد نشاندهندهی یکی از دسترسیها است. مقدار ۱ برای هر بیت نشاندهندهی دارا بودن دسترسی و صفر، نشاندهندهی عدم دسترسی است.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/31741/download_problem_initial_project/104909/) دانلود کنید.
*بله* دو تابع `GetUserPermissions` و `SetUserPermissions` را برای مدیریت دسترسیها در فایل `main.go` در نظر گرفته است:
+ تابع `GetUserPermissions` یک ورودی از نوع `int8` میپذیرد که هر بیت آن عدد نشاندهندهی هر یک از دسترسیها است و بهعنوان خروجی، یک ساختار به نام `Permissons` را بر میگرداند که شامل دسترسیهای مختلف از نوع `bool` است.
+ تابع `SetUserPermissions` یک ساختار `Permissions` را بهعنوان ورودی دریافت کرده و یک عدد از نوع `int8` را برمیگرداند.
*بله* برای این کار ۶ دسترسی در نظر گرفته که بهترتیب از کمارزشترین بیت به پرارزشترین بیت در زیر آمدهاند:
```
canSeeMessages (کمارزشترین بیت)
canDeleteMessages
canEditMessages
canKickMembers
canMakeMembersAdmin
canAddMembers
```
حال، او از شما خواسته تا این دو تابع را پیادهسازی کنید تا او بتواند بهتر از گذشته کانالهایش را مدیریت کند.
# آنچه باید آپلود کنید
پس از پیادهسازی توابع، فایل `main.go` را آپلود کنید. در صورتی که از *dependency* خاصی استفاده کردهاید، فایلهای `go.mod` و `go.sum` را بههمراه فایل `main.go` زیپ کرده و آن را آپلود کنید.
یک دسترسی خیلی ساده
اعضای تیم فنی *بله* پس از امتحان کردن زبانهای برنامهنویسی مختلف، به این نتیجه رسیدند که خودشان دست به کار شوند و یک زبان جدید مخصوص خود بنویسند.
پس از جلسات متعدد تیم در این زمینه، به این نتیجه رسیدند که کل نیازهایشان با دو ساختار شرطی و حلقه برطرف میشود و باقی موارد اضافی هستند آنها و از زبان خود حذف کردند. همچنین، به نظر آن ها کل کد را میتوان در یک خط نوشت.
به همین خاطر، آنها تصمیم گرفتند به جای کلیدواژهی `if` از کلیدواژهی `bale` استفاده کنند و پایان آن را با `kheir` نشان دهند. همچنین، آنها تصمیم گرفتند بهجای کلیدواژهی `for` از کلیدواژهی `areh` استفاده کنند و پایان آن را با `na` نمایش دهند. آنها پس از طراحی زبان موردنظر خود، نیاز به یک مترجم برای زبان خود داشتند که بگوید آیا زبانشان قابل ترجمه هست یا خیر، اما با توجه به وقت کم و کار بسیارشان، از شما کمک خواستند تا این کار را برایشان انجام دهید.
# ورودی
در یک خط از ورودی استاندارد، یک رشته بهعنوان کدی که شما باید آن را ترجمه کنید وارد میشود. ترجمه به اینصورت است که هر `bale` باید حتماً با `kheir` و هر `areh` با `na` تمام شود و این کلید واژهها باید به صورت **متوازن** در کد قرار گرفته باشند.
**تضمین میشود** که در کد ورودی، کاراکتر *whitespace* وجود ندارد.
# خروجی
اگر زبان قابل ترجمه بود، در خروجی استاندارد `YES` و در غیر اینصورت، `NO` را چاپ کنید.
برای درک بهتر سؤال، به مثالها توجه کنید.
# مثال
## ورودی نمونه ۱
```
balex==1arehy==1y++nakheir
```
## خروجی نمونه ۱
```
YES
```
## ورودی نمونه ۲
```
baleball==1na
```
## خروجی نمونه ۲
```
NO
```
## ورودی نمونه ۳
```
balearehkheirna
```
## خروجی نمونه ۳
```
NO
```
# نکات
+ امکان استفاده از کتابخانههایی که بهصورت پیشفرض در *Go* موجود نیستند وجود ندارد.
+ کد شما باید در پکیج `main` باشد.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، یک فایل با پسوند `.go` آپلود کنید.
بله یا خیر؟
در این سؤال، شما باید `Bale` را پیادهسازی کنید!
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/31741/download_problem_initial_project/104103/) دانلود کنید.
متدهایی که باید پیادهسازی کنید به شرح زیر هستند:
+ **متد** `AddUser`: این متد یک کاربر جدید ایجاد میکند. این متد دو مقدار ورودی میگیرد. اولین مقدار، نام کاربری و دومین مقدار، مشخصکنندهی نوع کاربر است. نام کاربری مقداری **یکتا** است و باید دارای طول **بیشتر از** ۳ باشد. همچنین، نام کاربری باید هم شامل حروف انگلیسی و هم ارقام باشد. اگر هر یک از این شرایط برقرار نبود، این متد خطا با پیام `invalid username` را برمیگرداند. در حالتی که خطایی وجود نداشته باشد، این تابع خطا برابر با `nil` و آیدی کاربر را برمیگرداند. آیدی کاربران از عدد ۱ شروع شده و در هر ایجاد کاربر جدید، یک واحد به آن افزوده میشود.
+ **متد** `AddChat`: این متد یک چت جدید ایجاد میکند. این متد چهار ورودی دارد. اولین ورودی، نام چت است. دومین ورودی، نوع چت را مشخص میکند که می تواند از نوع **کانال** یا **گروه** باشد. سومین ورودی، آیدی سازندهی چت است. در نهایت، آخرین ورودی آرایهای از آیدیهاست که نشاندهندهی ادمینهای چت است. **تضمین میشود** که آیدی سازنده حتماً در این آرایه وجود دارد. سازندهی چت نمیتواند بات باشد و در این حالت، متد ارور با پیام `could not create chat` را برمیگرداند. در صورت موفقیتآمیز بودن عملیات، این متد آیدی چت را برمیگرداند. آیدی چتها نیز مانند آیدی کاربران ایجاد میشود.
+ **متد** `SendMessage`: از این متد برای ارسال پیام به یک چت استفاده میشود. اولین ورودی این تابع، کاربری است که میخواهد این پیام را ارسال کند. دومین ورودی، آیدی چتی است که پیام در آن ارسال میشود. آخرین ورودی، متن پیام است. در چتهایی که از نوع کانال هستند، تنها **ادمین**های کانال می توانند پیام ارسال کنند و اگر کاربری که در کانالی ادمین نیست بخواهد در آن کانال پیام ارسال کند، این متد یک ارور با پیام `user could not send message` برمیگرداند. در صورت موفقیتآمیز بودن عملیات، این متد باید آیدی پیام را برگرداند. آیدی پیامها نیز مانند آیدی کاربران ایجاد میشود.
+ **متد** `SendLike`: این متد برای لایک کردن یک پیام خاص کاربرد دارد. هر کاربر هر پیام را تنها یک بار میتواند لایک کند. اگر کاربری بخواهد یک پیام را **بیش از یک بار** لایک کند، باید ارور با پیام `this user has liked this message before` را برگردانید. اگر پیام وجود نداشت، این متد ارور با پیام `message not found` را برمیگرداند.
+ **متد** `GetNumberOfLikes`: این متد، تعداد لایکهای یک پیام را برمیگرداند. مقدار ارور خروجی باید `nil` باشد. **تضمین میشود** که پیامی با آیدی ورودی در بین پیامها موجود است.
+ **متد** `SetChatAdmin`: این متد یک کاربر مشخص را تبدیل به ادمین در یک چت مشخص میکند. اگر کاربر در حال حاضر ادمین آن چت باشد، این متد یک ارور با پیام `user is already admin` را برمیگرداند.
+ **متد** `GetLastMessage`: این متد، متن پیام و آیدی آخرین پیام در چت مشخص شده را برمیگرداند.
+ **متد** `GetLastUserMessage`: این متد، متن پیام و آیدی آخرین پیامی که کاربر مشخصشده ارسال کرده است را برمیگرداند.
# نکات
+ داده ساختارهای موردنیاز خود را در `BaleImpl` تعریف کنید.
+ برای ساخت یک `Bale` جدید، از `NewBaleImpl` استفاده میشود. مقداردهی اولیهی داده ساختارهای خود را در این تابع قرار دهید.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواسته شده، فایل `main.go` را آپلود کنید. در صورتی که از *dependency* خاصی استفاده کردهاید، فایلهای `go.mod` و `go.sum` را بههمراه فایل `main.go` زیپ کرده و آن را آپلود کنید.
پیامرسان سادهی بله
[بازوها در *بله*](https://devbale.ir/) برای این که بتوانند درخواستهایشان را مطرح کنند از *JSON* استفاده میکنند، اما درخواستهایشان از قاعدهی خاصی پیروی نمیکند. *بله* که از این وضعیت خسته شده، از شما خواسته تا این درخواستها را برایش ترجمه کنید و در قالب یک ساختار مشخص به او بدهید.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/31741/download_problem_initial_project/104104/) دانلود کنید.
در این سؤال شما باید یک فایل *JSON* را که در کنار فایل اجرایی قرار دارد بخوانید و آن را تبدیل به ساختار `SendMessage` کنید.
فیلدهای *JSON* ورودی بهشرح زیر هستند:
+ **فیلد** `chat_id` : این فیلد یک عدد صحیح ۶۴ بیتی است که در ورودی میتواند بهصورت **عدد** یا **رشته** داده شود. در ساختار خروجی، این فیلد باید دارای نوع **رشته** باشد. برای مثال در ورودی، این فیلد میتواند به صورت `123` و یا `"123"` داده شود، و مقداری که در ساختار برای این فیلد ذخیره میشود بهصورت `"123"` است. این فیلد حتماً باید در فایل ورودی وجود داشته باشد و در غیر اینصورت، باید ارور با پیام `chat_id is empty` برگردانید.
+ **فیلد** `text`: این فیلد مشخصکنندهی متن پیام بوده و از نوع **رشته** است. این فیلد نیز حتماً باید در ورودی وجود داشته باشد و رشتهی خالی نباشد. در غیر اینصورت، باید ارور با پیام `text is empty` را برگردانید.
+ **فیلد** `parse_mode`: این فیلد از نوع رشته است، اما میتواند در *JSON* ورودی نباشد (فیلدی ضروری نیست).
+ **فیلد** `reply_markup`: این فیلد از نوع `ReplyMarkup` بوده و فیلدی ضروری نیست و میتواند در ورودی نباشد. مقدار این فیلد، خود یک *object* است که حالتهای زیر را میتواند داشته باشد:
```json
{
"keyboard" : [[{"text" : string, "request_contact" : bool, "request_location" : bool}]]
"resize_keyboard" : bool
"one_time_keyboard" : bool
"selective" : bool
}
```
در این حالت، سه مقدار `resize_keyboard` و `one_time_keyboard` و `selective` از نوع *bool* هستند و فیلدهای ضروری نیستند. `keyboard` در این حالت فیلدی ضروری است و مقدار آن آرایهای از آرایههایی است که هر عنصر آن یک *object* با سه فیلد `text` و `request_contact` و `request_location` است. فیلدهای `request_location` و `request_contact` از نوع *bool* بوده و اجباری نیستند.
```json
{
"keyboard" : [[string, string]]
"resize_keyboard" : bool
"one_time_keyboard" : bool
"selective" : bool
}
```
تفاوت این حالت با حالت قبلی، تنها در این است که در این حالت، مقدار `keyboard` به صورت آرایهای از آرایههایی است که هر عنصر آن یک رشته است. در این حالت، هر رشته باید بهعنوان مقدار برای کلید `text` درنظر گرفته شود.
```json
{
"inline_keyboard" : [[{"text" : string, "callback_data" : string, "url" : string}]]
}
```
در این حالت، یک فیلد ضروری `inline_keyboard` داده میشود که آرایهای از آرایههایی است که هر عنصر آن یک *object* است که در آن سه فیلد `text` و `callback_data` و `url` قرار دارد. دو فیلد `callback_data` و `url` ضروری نیستند.
```json
{
"inline_keyboard" : [[string, string]]
}
```
تفاوت این حالت با حالت قبلی، تنها در این است که در این حالت، مقدار `inline_keyboard` بهصورت آرایهای از آرایههایی است که هر عنصر آن یک رشته است. در این حالت، هر رشته باید بهعنوان مقدار برای کلید `text` در نظر گرفته شود.
توجه داشته باشید که هر یک از حالتهای بالا میتوانند در *JSON* ورودی به صورت **رشته** باشد. برای مثال، حالت دوم می تواند در فایل ورودی بهصورت زیر باشد:
```json
"{\"keyboard\" : [[\"string\",\"string\"], [\"string\", \"string\"]]}"
```
تابع `ReadSendMessageRequest(fileName string)` را بهگونهای پیاده کنید که نام فایل را بهعنوان ورودی دریافت کرده و *JSON* درون فایل را به ساختار `SendMessage` تبدیل کند. اگر خطایی وجود نداشت (تنها دو خطای گفتهشده با متن خطای مشخصشده ممکن است رخ دهد و خطای دیگری وجود ندارد)، یک اشارهگر به این ساختار برگردانید و مقدار ارور را نیز `nil` برگردانید. در صورت وجود خطا، مقدار اشارهگر را `nil` و مقدار ارور را با خطای مناسب برگردانید.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواسته شده، فایل `main.go` را آپلود کنید. در صورتی که از _dependency_ خاصی استفاده کردهاید، فایلهای `go.mod` و `go.sum` را بههمراه فایل `main.go` زیپ کرده و آن را آپلود کنید.
بازوهای بله
*بله* میخواهد به همهی کانالهای خود یک پیام واحد ارسال کند، اما متأسفانه بعضی از کانالها بسته شدهاند و دیگر پیامی نمیپذیرند. همچنین، بعضی از کانالها وضعیت نامشخصی دارند و *بله* نمیتواند تشخیص دهد که این کانالها در چه زمانی باز و در چه زمانی بسته هستند.
با توجه به این که *بله* کارهای بسیار دیگری بهجز این کار دارد، یک زمان مشخص را در نظر گرفته و سعی میکند در این زمان پیام خود را به همهی کانالها بفرستد. حال، او از شما خواسته تا این مورد را برای او پیادهسازی کنید.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/31741/download_problem_initial_project/104105/) دانلود کنید.
در این سؤال، شما باید تابع `Solution` را پیادهسازی کنید. این تابع سعی میکند که در `d` ثانیه، پیام مشخصشده را در کانالهای ورودی باز بریزد. دقت کنید که پیام در کانالها باید **حداکثر یک بار** نوشته شود. همچنین، ممکن است که در این مدت، حالت کانالها تغییر کند. در نهایت، شما باید یک عدد برگردانید که نشاندهندهی تعداد کانالهایی است که توانستهاید پیام را در آنها قرار دهید.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواسته شده، فایل `main.go` را آپلود کنید. در صورتی که از _dependency_ خاصی استفاده کردهاید، فایلهای `go.mod` و `go.sum` را بههمراه فایل `main.go` زیپ کرده و آن را آپلود کنید.
کانالهای یکبارمصرف
**کد شما باید روی نسخهی استاندارد *PostgreSQL* قابل اجرا باشد.**
---
علی پسر کنجکاوی است. او پس از این که دوری کارآموزیاش را گذرانده و در *بله* ماندگار شده، دلش میخواهد کمی اطلاعات از الگوهای رفتاری کاربران بهدست آورد.
تعدادی سؤال در ذهن علی پیش آمده و علی میخواهد به پاسخ این سؤالات برسد. به همین دلیل، باید تعدادی کوئری در دیتابیس اجرا کند. به علی کمک کنید تا به کنجکاویاش برسد :)
# جزئیات پروژه
ساختار جداول بهصورت زیر است:
1. اطلاعات کاربران (`users`):
| نام ستون | نوع | تعریف | ملاحضات |
|--------|--------------|--------------|---------------|
| `id` | `INTEGER` | شناسهی کاربر | `PRIMARY KEY` |
| `name` | `VARCHAR(255)` | نام | |
| `nick` | `VARCHAR(32)` | نام کاربری | |
2. وضعیت بلاک بودن کاربران توسط یکدیگر (`relations`):
| نام ستون | نوع | تعریف | ملاحظات |
|--------------|--------------|---------------------------------|--------------------------------------|
| `from_user_id` | `INTEGER` | شناسهی کاربری که میتواند بلاک کند | |
| `to_user_id` | `INTEGER` | شناسهی کاربری که میتواند بلاک شود | |
| `blocked` | `BOOLEAN` | وضعیت بلاک بودن کاربر | `DEFAULT FALSE` |
| `blocked_at` | `TIMESTAMP` | زمان بلاک شدن کاربر | `DEFAULT NULL` |
3. پیامها (`messages`):
| نام ستون | نوع | تعریف | ملاحظات |
|--------------|--------------|-------------------------------------------|---------------|
| `id` | `INTEGER` | شناسهی پیام | `PRIMARY KEY` |
| `from_user_id` | `INTEGER` | شناسهی کاربر ارسالکنندهی پیام | |
| `to_user_id` | `INTEGER` | شناسهی کاربر دریافتکنندهی پیام | |
| `body` | `BYTEA` | متن پیام | |
| `created_at` | `TIMESTAMP` | زمان ارسال شدن پیام | |
| `edited_at` | `TIMESTAMP` | زمان آخرین ویرایش پیام (در صورت ویرایش شدن) | |
| `deleted_at` | `TIMESTAMP` | زمان حذف پیام (در صورت حذف شدن) | |
سؤالات ذهن آشفتهی علی بهشرح زیر هستند:
1. شناسهی کاربرانی که نام کاربری (`nick`) آنها با `am` شروع میشود بهترتیب صعودی
2. شناسهی کاربرانی که حداقل یک کاربر را بلاک کردهاند بهترتیب صعودی
3. شناسهی پیامهایی که کاربران در چتهای خصوصی بلاکنشده ارسال کردهاند (یعنی در حال حاضر کاربر ارسالکننده، کاربر دریافتکننده را بلاک نکرده باشد) و قبل از حذف شدن ویرایش شدهاند بهترتیب صعودی (اگر شخص پس از ارسال پیام بلاک شده باشد، پیامها نباید در خروجی موجود باشند.)
**نکته:** نام ستون خروجی مهم نیست.
# آنچه باید آپلود کنید
کوئریهای خود را در قالب زیر، در یک فایل با پسوند `.sql` قرار داده و آن را ارسال کنید (فایل را زیپ نکنید).
```sql
-- Section1
your 1st query here
-- Section2
your 2nd query here
-- Section3
your 3rd query here
```