برای شروع، از شما میخواهیم به کسانی که بعد از شما وارد مسابقه میشوند خوشآمد بگویید. برای این منظور یک تابع با نام `HelloCodeCup` تعریف کردهایم.
اما از آنجا که میخواهیم برنامه برای مسابقات بعدی کدکاپ نیز قابل استفاده باشد، از کاربر میخواهیم که شمارهی مسابقه را به تابع بدهد، سپس براساس آن، عبارت خوشآمدگویی مناسب را برگردانیم.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/45365/download_problem_initial_project/155877/) دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
```
hello-codecup
├── go.mod
├── go.sum
├── main.go
└── main_sample_test.go
```
در فایل `main.go` تابعی با نام `HelloCodeCup` تعریف شده که امضای آن بهصورت زیر است:
```go
func HelloCodeCup(n int) string {
// TODO: Implement
}
```
این تابع را طوری پیادهسازی کنید که به ازای ورودی `n`، رشتهی `Hello Codecup n` را برگرداند.
# مثال
به ازای ورودی `7`، تابع باید چنین مقداری را برگرداند:
```
Hello CodeCup 7
```
**توجه:** در این سؤال مجاز به استفاده از کتابخانههای شخص ثالث نیستید.
# آنچه باید آپلود کنید
پس از پیادهسازی تابع `HelloCodeCup`، فایل `main.go` را آپلود کنید.
برنامهنویسان در شرکت *اسنپ* عادت دارند برای تشخیص اینکه ارور برگرداندهشده از متد چیست، کدهایی مثل کد زیر مینویسند:
```go
n, err := f.Read(data)
if err != nil {
if errors.Is(err, io.EOF) {
break
}
fmt.Println(err)
return
}
```
در نتیجه انتظار دارند پکیج مربوطه، همه ارورهایی که ممکن است برگردانده شوند را به شکل فیلد در خود داشته باشد.
متاسفانه یا خوشبختانه یک کتابخانهی فوقالعاده مفید به دست تیم فنی *اسنپ* رسیده است. این کتابخانه اگرچه بسیار مفید است و کارهای آنها را راحت میکند، اما این قاعده در آن برقرار نیست.
حالا برنامهنویسان *اسنپ* میخواهند برخلاف عادت خود عمل نکنند، بنابراین نیاز به یک پکیج کمکی برای پکیج اصلی دارند که ارورها را در خودش داشته باشد.
خوشبختانه این کتابخانه، سورسکد قابل خواندن (و نه تغییر) دارد و میتوان از آن به منظور توسعهی پکیج کمکی استفاده کرد.
# جزئیات پروژه
+ سورسکد فعلی شرکت را از [این لینک](/contest/assignments/45365/download_problem_initial_project/155875/) دانلود کنید.
+ فایل `helper.go` در پکیج `helper` را به گونهای تغییر دهید تا فیلدهای ارورها در آن مقداردهی شوند.
+ باید با تغییرات جزئی در کتابخانه، برنامه شما دچار مشکل نشود. مثلا متن ارورها ممکن است تغییرات جزئی بکند.
+ در پکیج `helper` میتوانید به صورت زیر از کتابخانهی `the_lib` استفاده کنید.
```go
package helper
import (
"snapp/the_lib"
)
// the_lib.LoadData()
```
# آنچه باید آپلود کنید
فایل `helper.go` تغییریافتهی خود را آپلود کنید.
*اسنپ* برای افزایش کارایی کد در سرورهای خود، میخواهد از تکنیک **[SIMD](https://en.wikipedia.org/wiki/SIMD)** استفاده کند. این تکنیک به این صورت عمل میکند که به جای اینکه در آن واحد یک عملیات روی دیتای ۳۲ بیتی انجام شود، ۴ عملیات روی ۴ دیتای ۸ بیتی بدون علامت انجام میشود. به این ترتیب به Parallelism دست پیدا میکنیم. اما نکته مهم اینکه اینجا به جای استفاده از قابلیت سختافزاری پردازندهها برای SIMD، از امکانات همروندی زبان گو استفاده میکنیم.
# جزئیات پروژه
پروژه اولیه را از [این لینک](/contest/assignments/45365/download_problem_initial_project/155876/) دانلود کنید.
در این سوال شما باید تابع `Simd` را پیاده سازی کنید. تابع شما ورودیهای زیر را دارد:
+ یک تابع به عنوان عملیات
+ یک `uint32` به عنوان ورودی
+ یک `uint32` به عنوان خروجی محاسبات
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواسته شده، فایل `main.go` را آپلود کنید. در صورتی که از _dependency_ خاصی استفاده کردهاید، فایلهای `go.mod` و `go.sum` را بههمراه فایل `main.go` زیپ کرده و آن را آپلود کنید.
آرش قصد دارد یک وبسرویس خفن پیادهسازی کند، اما او میداند که از همان ابتدای کار، تعداد درخواستهای کاربران به *endpoint* هایی که بار پردازشی بالایی دارند بسیار زیاد خواهد بود. بنابراین او تصمیم گرفته که از *rate limiter* استفاده کند. از آنجایی که او نمیداند این *rate limiter* را چگونه پیادهسازی کند، از شما خواسته تا آن را برایش پیادهسازی کنید.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/45365/download_problem_initial_project/155878/) دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
```
rate-limit
├── db
│ └── connection.go
├── handlers
│ └── root.go
├── limiters
│ ├── by_app_key.go
│ └── by_ip.go
├── test
│ └── ratelimit_sample_test.go
├── go.mod
├── go.sum
└── main.go
```
%align_right_start%
وابستگی [`time/rate`](https://pkg.go.dev/golang.org/x/time/rate) در پروژه تعریف شده و برای پیادهسازی *rate limiter* باید از آن استفاده کنید.
%align_end%
## پایگاه داده
در این پروژه از پایگاه دادهی *PostgreSQL* استفاده شده است. برنامه شامل جدولی با نام `app_keys` است که شامل دو ستون `id` از نوع `BIGSERIAL` و `key` از نوع `VARCHAR(255)` است.
در پکیج `db` تابعی با نام `GetConnection` تعریف شده که باید از آن برای دریافت کانکشن دیتابیس استفاده کنید. میتوانید اطلاعات اتصال به دیتابیس را در این فایل تغییر دهید.
## روتها
تنها یک روت با آدرس `/` در برنامه تعریف شده است که میتوان *rate limiter* های مختلف را روی *handler* آن اعمال کرد.
## تابع `ByIp`
این تابع بهترتیب شامل سه پارامتر زیر است:
+ `next` از نوع `http.Handler`: همان *handler* اصلی روت است.
+ `refillRate` از نوع `rate.Limit`: میزان افزایش تعداد درخواستهای مجاز کاربر در هر ثانیه (برای مثال اگر مقدار آن برابر با ۳ باشد، در هر ثانیه، ۳ واحد به تعداد درخواستهای مجاز کاربر اضافه میشود، به شرطی که تعداد درخواستهای مجاز فعلیاش کوچکتر از `tokenBucketSize` باشد.)
+ `tokenBucketSize` از نوع `int`: سقف تعداد درخواستهای پیاپی کاربر
این تابع را طوری پیادهسازی کنید که درخواستها را براساس آیپی محدود کند. در صورتی که کاربر با محدودیت مواجه نشده باشد، پردازش درخواست باید توسط `next` صورت گیرد. در غیر اینصورت، کد پاسخ باید به `429` تغییر کند، مقدار هدر `Content-Type` باید برابر با `application/json` قرار داده شود و بدنهی پاسخ بهصورت زیر باشد:
```json
{"error": "too many requests"}
```
## تابع `ByAppKey`
امضای این تابع مشابه تابع `ByIp` است.
این تابع را طوری پیادهسازی کنید که درخواستها را براساس مقدار هدر `X-App-Key` موجود در درخواست محدود کند. اگر مقدار این هدر در جدول `app_keys` وجود نداشته باشد، محدودیت نباید اعمال شود. در غیر اینصورت، محدودیت باید اعمال شود. اگر کاربر با محدودیت مواجه شده باشد، پاسخ باید مشابه پاسخ مورد انتظار برای تابع `ByIp` باشد.
**تضمین میشود** که هنگام استفاده از این تابع، هدر `X-App-Key` در درخواست موجود است.
## ترکیب *rate limiter* ها
ممکن است بخواهیم *rate limiter* ها را ترکیب کنیم. اگر از توابع `ByIp` و `ByAppKey` در کنار یکدیگر استفاده شود، محدودیت باید هم براساس آیپی و هم براساس مقدار هدر `X-App-Key` اعمال شود. مثلاً اگر مقدار `tokenBucketSize` برابر با ۵ باشد و ۵ درخواست پیاپی با آیپیهای مختلف، اما با `X-App-Key` یکسان (بهطوری که در جدول `app_keys` موجود باشد) ارسال کنیم، باید با محدودیت مواجه شویم. همچنین اگر این درخواستها را با آیپی یکسان، اما با `X-App-Key`های متفاوت (بهطوری که در جدول `app_keys` موجود باشند) ارسال کنیم، باز هم باید با محدودیت مواجه شویم.
# نکات
+ نیازی به *persistent* بودن اطلاعات مربوط به *rate limiter* ها نیست (با خاتمهی برنامه، دادههای مربوط به *rate limiter* ها میتوانند از بین بروند).
+ شما تنها مجاز به اعمال تغییرات در پوشهی `limiters` هستید.
+ در صورت نیاز، میتوانید فایلهای جدیدی در پوشهی `limiters` تعریف کنید.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، پوشهی `limiters` را زیپ کرده و آپلود کنید.