Максим Фатин | про IT
4.13K subscribers
202 photos
4 videos
105 links
Помогаю с подготовкой к собеседованиям в RU Big Tech

https://clck.ru/3RdRKN

● Вместе с командой помогли 100+ разработчикам попасть в BigTech
● Жму 100-ку на 2 раза (есть куда расти)
● Люблю есть ночью)

Связь через Карину:
@Karina_algocode_io
Download Telegram
Когда нужен полный перебор на собеседовании?

Когда начинал учить алгосы, натыкался на видосы c таким тейком

вот предложи решение с полным перебором сначала, а потом оптимизируй

Них*ясебе совет, я вам скажу

Вообще полный перебор — нифига не тривиальная штука, на мой взгляд. Я его понял, когда решил в районе 20–30 задач

Посмотрев на достаточное число задач в этой теме, могу сказать так: если вам нужно генерировать самим все перестановки / прям явно собирать все комбинации и т. д. — это 100% полный перебор (bruteforce) или поиск с возвратом (backtracking)

В остальных случаях ну вот прям не нужен он с 99% вероятностью

bruteforce — это вот прям полный-полный перебор

backtracking — это отсечение вариантов, которые точно дадут неверный результат (в общем, оптимизация)

P.S. Пятница) Надо пати устроить, чтобы быть довольным как чел на фортке, а не про брутфорс и бектрекинг писать

но что есть то есть
🌭33❤‍🔥9
Advanced Code — теперь самый жёсткий этап собеса в Яндексе

Формат такой: 60–90 минут, тебе дают production like задачу, ты уточняешь детали у интервьюера — и пишешь код

Причём задача усложняется прямо в процессе. Например:

Есть микросервисная архитектура. Реализуй тип Balancer,
который реализует интерфейс Backend и распределяет запросы
между экземплярами сервиса.


Сначала уточняешь: алгоритм балансировки, concurrency, обработку ошибок. Потом пишешь код...

В конце интервьюер говорит:
А теперь доработай Balancer, чтобы он временно исключал проблемные бэкенды из ротации

Проверяют сразу всё: System Design + live кодинг + умение задавать правильные вопросы

И писать код так чтобы не переписывать его с нуля нафиг при следующем усложнении 🧨

Другие примеры задач:
— обёртка для долгой ресурсоёмкой операции
— буфер для переливки данных из Kafka в ClickHouse
— переливка из OLTP в OLAP
— и ещё десятки похожих

🤙 А это была ахуительно полезная реклама algocode.io

А вот
прямая ссылка для тех, кто уже с нами
❤‍🔥23🤣10🌭8
Если "ДЕК" для тебя что-то знакомое, но до конца не уверен...

- Ты не знаешь чем он отличается от двусвязного списка
- Без понятия какие там реализации


То ты 👉: среднестатистический разработчик

И сейчас я тебя прокачаю!

В общем, дек — абстрактный тип данных, который поддерживает вставку и удаление из начала и конца за O(1)

Абстрактный — значит реализация может быть любая и главное, чтобы выполнялись правила выше

Например, двусвязный список — это одна из реализаций дека

Или можно реализовать его на двух стеках


В общем — как угодно

НО! C++ ТУТ УДЕЛАЛ ВСЕХ!

Он сделал реализацию на chunked array, за счет чего появилась операция доступа по индексу за O(1)...

Т е натуральная имба, которая мало того что удаление и вставка в начало и конец, так еще и O(1) получить элемент по индексу

И вся магия в реализации...

А если соберем 100 🌭 до пятницы — расскажу как это работает под капотом


UPD: разбору быть)
🌭135🍓1
Вставляю за O(1) и в коней и в начало. Кто я?

Правильно — дек!

Как и обещал — раскрываю магию std::deque из C++ или как в деке поддержать доступ по индексу за O(1)

Если коротко — нам нужен chunked array

Идея гениальна:

Вместо одного большого массива используется массив указателей на маленькие массивы (чанки)


👉 Структура

[ chunk1 ] [ chunk2 ] [ chunk3 ] [ chunk4 ]
↓ ↓ ↓ ↓
[..............] [..............] [..............] [..............]

Каждый chunk — небольшой массив фиксированного размера B
(обычно 8, 64 или 128 элементов — зависит от типа данных)

И дополнительно хранится таблица указателей на чанки:

chunks = [&chunk1, &chunk2, &chunk3, &chunk4]

👉 Начальное состояние

При создании deque выделяется первый chunk.

Кроме этого создаётся таблица указателей на чанки (chunks).
Она выделяется с запасом и стартует примерно с середины массива.

Это сделано специально, чтобы таблица могла расти и влево, и вправо.

Н
апример:

chunks = [ _ _ _ &chunk1 _ _ _ ]

Теперь внутри chunk выбирается позиция:

head = tail

[ _ _ _ _ _ _ _ _ ]
↑
head, tail

Это означает, что дек пустой.

head — позиция первого элемента
tail — позиция сразу после последнего элемента

То есть элементы всегда лежат в диапазоне:

[ head ........ tail )

🚨 КАПЕЦ ВАЖНО!!!

head и tail — это глобальные позиции в структуре,
а не индексы внутри конкретного чанка.

Поэтому head может указывать НЕ на начало чанка, а на любую позицию внутри него.

Крайние чанки часто заполнены лишь частично — и это нормально.

Например дек может выглядеть так:

[ _ _ _ A B C D _ ]
↑ ↑
head tail

Здесь:

head -> указывает на первый элемент A
tail -> указывает на позицию сразу после последнего элемента D

То
есть элементы лежат в диапазоне:

[ head ..... tail )

👉 Как работает push_front (вставка в начало)

Вставка в начало — это просто сдвиг head влево.

1) Уменьшаем head

head -= 1

2) Теперь нужно понять в какой chunk писать

chunk = head / m
offset = head % m
m — это размер чанка

3) Если нужного chunk ещё нет — создаём
и кладём ссылку на него в таблицу chunks

4) Записываем элемент

chunks[chunk][offset] = value

Если раньше head стоял в начале чанка — после head -= 1
мы автоматически перейдём в предыдущий chunk.

Никакие элементы не двигаются.

❗ Что если chunk получился отрицательным?

Это значит, что мы ушли левее начала массива chunks.

В этом случае:

1) создаётся новый массив указателей большего размера
2
) старые указатели копируются примерно в середину нового массива
(копируются только указатели, не сами данные)
3) таблица снова получает свободное место слева и справа

После этого продолжаем вставку.

Такая операция происходит редко, поэтому вставка остаётся амортизированно O(1).


👉 Как работает pop_front (удаление из начала)


Удаление — это просто сдвиг head вправо.

1) Находим текущую позицию

chunk = head / m
offset = head % m
m — это размер чанка

2) Читаем элемент

value = chunks[chunk][offset]

3) Сдвигаем начало

head += 1

Если чанк слева полностью опустел — его можно удалить.

👉 Как получить i-й элемент (доступ по индексу)

Индекс i считается от текущего начала (head).

Сначала переводим его в абсолютную позицию:

pos = head + i

Теперь находим чанк и позицию внутри него:

chunk = pos / m
offset = pos % m
m — это размер чанка

И получаем элемент:

chunks[chunk][offset]


Вся магия в том, что deque никогда не двигает элементы

Он двигает только head/tail и добавляет новые чанки при необходимости

ФУУХХХХ

Если просто долистал до конца, то красавчик! Ставлю тебе 🌭
🌭65🍓1
Как я начал видеть бинарный поиск вообще везде

В общем, была у меня проблема с бинарным поиском - я мало где его вообще видел

Если задача начиналась не с "массив отсортирован, нужно проверить наличие числа target" - то считал, что бинарным поиском вообще не решить...

Полечилось это очень интересным приседанием

Я стал искать способ решить буквально каждую задачу бинарным поиском

Даже на таких задачах:
• Даны массивы строк и нужно найти общий префикс
• Проверка, что число — степень двойки

И прикол в том, что это реально помогло

ИМЕННО БЛАГОДАРЯ ТАКИМ ПРОСТЫМ ЗАДАЧАМ Я ЕГО И НАЧАЛ ЧУВСТВОВАТЬ - где можно, а где нельзя его применить

Как только я понял, что существует "бинарный поиск по ответу" и бинарить можно не только по индексам, то дело пошло прям намного быстрее

И как оказалось даже неоптимальное и странное решение задач может дать свои плоды

В моем случае научился видеть бинарный поиск и больше не могу его развидеть 🌭
🌭45
Свеженькая задача Яндекса

Недавно ребята из сообщества
algocode.io гоняли на собесы и принесли такую задачку
Дан список перелётов tickets, где
tickets[i] = [A, B] — перелёт между городами A и B (направление неизвестно).

Все перелёты относятся к одному путешествию:
• каждый следующий перелёт начинается в городе, где закончился предыдущий
• ни один город не посещается дважды
• начальный город ≠ конечному

Нужно восстановить порядок городов в маршруте.
Если есть несколько вариантов — вернуть любой.

Пример

Ввод:
tickets = [["Berlin","Rome"],["Berlin","Dubai"]]

Вывод:
["Dubai","Berlin","Rome"] или ["Rome","Berlin","Dubai"]
Вся сложность в том, что направления запутаны!

Именно на этом валятся


Идея решения такая

• строим хеш-таблицу graph, где ключ — город отправления, а значение — список городов прибытия (в 2 стороны строим путь)

• находим любую вершину, у которой в значении только 1 город — это будет точка старта

• обходим граф из стартовой точки, поддерживая visited и не посещая уже отмеченные точки

И в итоге получим такое решение

from typing import *
from collections import defaultdict

def route(tickets: List[List[str]]) -> List[str]:
# для каждого города храним список городов, с которыми он связан
graph = defaultdict(list)
for a, b in tickets:
graph[a].append(b)
graph[b].append(a)

# начальный город — тот, у которого ровно одна связь (край маршрута)
start = ""
for city, neighbors in graph.items():
if len(neighbors) == 1:
start = city
break

# восстанавливаем маршрут, отмечая посещённые города
result = [start]
visited = {start}
for _ in range(len(tickets)):
current = result[-1]
for neighbor in graph[current]:
if neighbor not in visited:
visited.add(neighbor)
result.append(neighbor)
break

return result



На leetcode не нашел такой задачки

Для тех кто уже в сообществе: решить можно самому ТУТ
❤‍🔥22🌭6
Чисто BigTech классика

Я: надо доработать ручку, чтобы была политика CREATE OR UPDATE, а не только CREATE, на нашей стороне возникает сложная логика ретраев

Лид другой команды: можем доработать, но не раньше 25 марта, не можем отвлекаться на мелочи

Я: Так если это мелочи, мб доработаем быстро? Вам 1 if поставить, а с нашей стороны кратно большие доработки нужны + вы мейнтените эту дату, а нам доп хранение нужно, хендлинг ошибок и т д

Лид другой команды: Ок, в понедельник сделаем

Я: спасибо

—-

Тут главное не очковать, как говорится, и поддавать джазу где надо, а то так все строки можно провафлить)))

Бахни 🌭 если тоже такое было
🌭50🤣5
Кручу кручу педали кручу
ЗП ЗП ЗП, ЗП повысить хочу....


В посте кратко расскажу про этичность повышения ЗП через контр-офер

Другими словами...

Сгонял ты на собес и получил +20% к ЗП и теперь думаешь, как сказать лиду


Первым делом предлагаю написать тебе письмо с таким посылом
Привет! Я ходил на собеседование и мне поступило интересное предложение от компании МТС

Мне нравится работать в команде и уходить не планировал

Хочу созвониться и обсудить, что могу сделать/какие задачи взять, чтобы приблизиться к предложенной сумме

Понимаю, что моментально повышения не получу, но мне важно знать есть ли такая возможность в принципе и что для этого нужно сделать



На мой взгляд важно показать 2 вещи:


1. Ты хочешь остаться (если конечно это так)

2. Ты готов обсуждать scope задач и обязанностей и просишь повышение не просто так


У меня у самого была такая ситуация, когда МТС предложил большую котлету, но уходить не хотел

Написал аналогичное письмо и через несколько месяцев +20% к ЗП прилетело вместе с повышением. Но и задачку я прям нормальную такую закрыл

P.S. меня просили показать офер, так что лучше тут не блефовать, особенно если текущая команда нравится

Ты в любом случае в плюсе от такого сообщения

- если руководитель не готов это обсуждать/моросит, то и дальше со всеми повышениями моросить будет

- если все гуд, то наметите четкий план

Ну а если писать страшно, то просто скидывай пост тим-лиду 😂
❤‍🔥20🌭5🍓1
Как на собесе выпендриваются олимпиадники

В общем то базовая задачка: дана строка из символов 'a' - 'z'. Нужно проверить можно ли сделать из строки палиндром

СНАЧАЛА СМОТРИМ БАЗУ, а потом самый сок

Идея решения: подсчитать число каждой буквы. Если все буквы имеют четное число - то точно палиндром

Если все четные кроме одного - тоже палиндром можем получить

В остальных случаях false

Базовое решение выглядит так

def can_be_palindrome(s: str) -> bool:
freq = {}

for ch in s:
freq[ch] = freq.get(ch, 0) + 1

odd_count = 0
for count in freq.values():
if count % 2 != 0:
odd_count += 1

return odd_count <= 1


НО! Если ты олимпиадник, то вот эти все решения не для тебя

Ты на изи воспользуешься свойсвом ascii таблицы что все символы идут подряд и уместишь их в int32

ШАХ и МАТ!


def can_be_palindrome(s: str) -> bool:
mask = 0

for ch in s:
bit = ord(ch) - ord('a')
mask ^= (1 << bit)

return mask == 0 or (mask & (mask - 1)) == 0


Ну и это, 🌭 бахни, по-братски)
🌭103🤣6❤‍🔥2🍓1
Как я возненавидел LINUX

4 курс универа. 5 дней до защиты курсача. 12 ночи. У меня windows ноут с ubuntu

Без перерыва фигачу курсач. Остается пара моментов допилить в коде, чтобы демо-версия работала...

И ТУТ КОМП ПРОСТО ВЫРУБАЕТСЯ

Я такой — эй братан, вставай

Нажимаю кнопку запуска


А он такой: у тебя место закончилось. И ТУТ Я ПРОСТО ВЫПАЛ

1) Я не могу включить ПК, потому что не хватает места
2) Чтобы почистить место — нужно его включить

ТАМ ДАЖЕ BIOS ЗАВИСАЛ!


Я перепробовал все лайфхаки интернета, чтобы его включить. Я буквально не мог спать — меня нереально трясло от мысли, что придется все переписывать за 5 дней

И тут я нахожу божественный совет, как зайти в консоль

Зайти-то я зашел… но прав не хватало на удаление даже обычных папок...
Но я нашел все же несколько файлов которые можно было редачить и перезаписал их на пустые

Я думал, что сейчас он включится — и я узнаю кто былин виновник что забил мне всю память


И что вы думаете?

ВСЮ ПАМЯТЬ СОЖРАЛ ЧЕРТОВ DOCKER

Я его почистил — и все стало работать

Через 2 недели я купил мак и в ubuntu больше не возвращался

Ну и бахни 🌭если тоже кайфуешь от мака
🌭73🤣31❤‍🔥3🍓1
Как же бесят мега-ультра правила к паролям

К сервисам, где хранить-то особо и нечего

Создавал аккаунт Polar для мониторинга сердцебиения на кардиотренировке

И как будто оказался в password game

P.S. когда только запускал algocode — сам навертел пипец правил...

Больше так не делаю)

Ну и бахни 🌭 если тоже любишь усложнять
🌭51🍓8❤‍🔥3
Ультимативный гайд по алгосам

За 2 дня 1500 лайков - я такого в жизни не видел 😂

Думал, меня любит только мама, а тут такое

Максимально советую к просмотру на канале тем, кто еще не видел

Если кратко, то разложил все алгоритмические паттерны от А до Я
🌭61❤‍🔥27🤣2
Я умножил свою ЗП на 3, когда попал в Яндекс

Переход из Huawei в Яндекс дал мне ЗП 300 000. В то время я смотрел YouTube, и везде говорили, что ЗП большие

Ну вот я и решил рискнуть

Все 3 алго-секции Яндекса я щёлкнул за 30–45 минут (да-да, в те времена ещё были 3 секции алгосов)

Я понимал, что даже вслух сказать «хочу 300 000» вызывало у меня улыбку до ушей

Поэтому я тренировался с зеркалом

Смотрел в него 5 секунд и говорил «хочу 300 000» — как я думал


А по факту просто 5 секунд сдерживал улыбку, а потом ржал 2 минуты 😂

P.S. это буквально могли быть 2 минуты смеха

Спустя несколько дней — усердно тренируясь по несколько подходов в день — я освоил эту технику

И мог гордо сказать: «хочу 300 000»

Сказал так уверенно, что дали 320 000 :))) В общем, я попросил, а они согласились. Вот я ах*ел в моменте

А если наберем 100 🌭, то напишу как я просил у Авито 600 000 с двумя годами опыта и что из этого вышло
🌭193🤣3🍓1
Попросил у Авито 600 000

Тогда у меня было ~2 года коммерческого опыта

Попал туда по рекомендации очень заряженного чувака из Авито, который меня менторил

Он как раз уходил в Amazon и порекомендовал меня в соседние команды

Собесы пролетели на изи

— Платформу решил минут за 40-50 на senior
— Алго-секцию закрыл за 40 минут на senior
— Даже System Design умудрился пройти на middle+ (хотя я только начинал его изучать)

Да и в целом рекрутер мне написал

МАКСОН! ТЫ МАШИНА! ЩАС БУДЕМ ИСКАТЬ ТЕБЕ СИНЬОРНУЮ ВАКАНСИЮ...


А я знал, что синьор в Авито тогда — это примерно 450 000 net

И думаю:
а что если попросить 600 000… вдруг прокатит

Ну и попросил 😄

---

И вот тут началось интересное

После финала мой senior-грейд внезапно испарился
И меня позвали уже на middle+ (E4)

А финальные вопросы тогда казались вообще странными:

• Как ты решаешь задачи?
• Что важнее: клиент или бизнес?

Сейчас понимаю, что это ключевые вопросы, которые меня и подвели...


---

Ни одна команда мне не зашла
И я решил: ну ок, попробую дожать по максимуму, все равно идти не собираюсь

И отказался от оффера 360 000 net

Дальше было:

→ 380 000
→ + welcome бонус

Но я продолжал упираться

---

В итоге меня просто… слили 😄
И больше не зовут на собесы 😂


---

Пообщавшись после этого на отдельных созвонах с лидами из Авито, я уже понял:

— как реально проходить на senior
— почему мне дали middle+
— как правильно отвечать на такие "странные" вопросы

О чем и проводил стрим в сообществе algocode.io, а если уже в сообществе, то глянуть можно по ссылке (много инсайдерской инфы)
🌭39❤‍🔥2
Как СБЕР ДЕВАЙСЫ меня нанимали

История из примерно 2022, когда всё ещё был айтишный пайм и нанимали как не в себя

Я слышал, что ПРЕМИИ в СБЕРе такие БОЛЬШИЕ, перебить могут только web3-скамеры

И думаю — а почему бы не сходить и не посмотреть

Все тех. секции прошёл — всё ОК

А потом финал...

Я прихожу, и вот такой незатейливый ДИАЛОГ был
И — интервьюер, CTO

И: "Ну что, как прошёл все секции?"
Я: "Мне не показались они сложными"
И: "А как ты вообще себя оцениваешь?"
Я: "Senior"
И: "Ну вот давай поподробнее, что тебе интервьюер говорил и как он тебя оценил"
Я: "Не уточнял, но думаю, что он у вас есть — я сам как интервьюер заполняю отчёты"
И: "Проблема в том, что мы ПОТЕРЯЛИ ВЕСЬ ФИТБЕК ПО ТВОИМ СОБЕСАМ"


Меня просто разорвало от смеха

Такой фигни я ещё нигде не видел, прям подняли настроение

Может, кто недавно гонял к ним и расскажет, как сейчас с процессами?

P.S. но премии там действительно прям высокие оказались
🤣43🌭17
Я не общался с лидом 3 месяца

1-2-1 — вполне понятная практика

Так вот, после НГ у меня не было ни одного 1-2-1

Пару мыслишек о моём отношении к этому и как я ДЕЛАЮ ИЗ ЭТОГО КОНКУРЕНТНОЕ ПРЕИМУЩЕСТВО:

———

СТАДИЯ: да зачем мне 1-2-1

В целом, с текущим лидом больше обсуждали всегда технические моменты не же ли мотивацию и т д

Но я как бы и на других встречах с ним это проговаривал...

Так что появление этого вопроса вполне закономерно

———

СТАДИЯ: а что происходит


Тут я уже начал писать в личку, спрашивать, что там по 1-2-1

Но, видимо, затерялось сообщение, а я его и не поднимал особо вверх

———

СТАДИЯ: а может, мне и не нужны 1-2-1

У меня и свой скоуп работ есть, и, как правило, продакты ко мне заходят с соседними командами

И в целом мне понятно, что и с каким приоритетом делать

———

Так что посмотрю, что из этого получится

Знаю, что у лида завал, и, пожалуй, лучший способ помочь — максимальная автономность, насколько это возможно (о чем он уже говорил, что ценит мою автономность)

Ну а раз я ей обладаю, почему бы и не выделиться

Считаю, что в этой ситуации это является крутым преимуществом, которое в дальнейшем можно и раскешить

Ну и в целом эксперимент интересный

———

Йоу! Бахни 🌭 по-братски, если твой 1-2-1 отменяли
🌭55❤‍🔥1🍓1
Всю пятницу ЛЕГЕНДАРНО КАТИЛ НОВЫЙ СЕРВИС

Напомню, что я работаю в AB-платформе

В общем, сервис, чтобы проводить эксперименты и смотреть, какая кнопка больше привлекает пользователя

И выносили в отдельный сервис получение списка экспериментов

Там уже капец был под капотом, да еще и агрегировать данные от нескольких сервисов

В общем, распил монолита!

И как же я с*ка сгорел, когда затащили всю эту адскую миграцию, а потом нам говорят

А вы когда переливать данные хотите?

Я такой: мы же все перелили...

А это да, но нас тут попросили все пересчитать, и данные вообще новые, и у вас сейчас невалидные...


ЭХ СУУУУМКА ЕБУЧАЯ, думаю я

Но что ж, вот 17:00, а мы в легендарном дуо делаем переливку и все тестируем перед демо во вторник

Накидайте плз 🌭, а то я уже есть хочу, но нужно все доделать 😄
🌭105🤣1🍓1
У меня инсульт
🤣37🌭23❤‍🔥2
+1 хардкорный Яндексоид

Недавно прилетел вот такой вот отзыв
по подготовке на algocode.io

=============

Привет!
Только что был алго-собес в Яндекс.
Вот задачи с него:
- К ближайших чисел (algocode)
- Последовательность с суммой K (algocode)

обе решил за 40 мин)))

Макс, огромное тебе спасибо за твой титанический труд в алгосах))) Ты пушка-бомба, курсы просто охренительные!))))
Теперь пойду готовиться к TDD и SD, благо по ним курсы от Дани тоже есть))))

=============

А в посте хочу разобрать "К ближайших чисел" (условие на скриншоте)

В общем, дан отсортированный массив nums, индекс idx и число k. Нужно найти k ближайших чисел к nums[idx]

И ЯНДЕКС ЖДЁТ ОТ ТЕБЯ САМОЕ ПРЯМОЛИНЕЙНОЕ РЕШЕНИЕ

Решаем просто в лоб:
• ставим указатели l и r слева и справа от idx
• добавляем в ответ ближайшее число к nums[idx] и смещаем указатели

Главное НЕ ЗАБЫТЬ:
• Отслеживать выход за границы массива
• При равной удалённости чисел nums[l] и nums[r] от nums[idx] отдать предпочтение левому

И получим O(k) времени и O(k) памяти (память только на ответ тратим)
—-

И вуаля, ты в Яндексе 😏
Please open Telegram to view this post
VIEW IN TELEGRAM
🌭35🤣3
Самая важная новость текущей недели

Состоялась сделка по объединению ООО Отус (ярдовая компания) и algocode

И я КАПЕЦ РАД!

Это мега выгодная сделка вообще для всех: для клиентов, которые получат бОльше контента, для меня с Данилом (кореш с которым начинали делать algocode с самого начала) и для Отуса

6 месяцев шло обсуждение, и вчера всё подписали

Так что скоро в резюме напишут "Руководитель отдела разработки"

———

Я вот смотрю на весь путь, что прошёл, и вообще не жалею

Попробовал не только микросервисы пораспиливать и пообъединять, но и бизнесы 😂

P.S. микросервисы вообще фигня по сравнению с этим
🌭59❤‍🔥26🍓6🤣2
Гонял тут на конфу amoConf

Один из спикеров на полном серьёзе сказал:

"Промпты для AI — это прошлый век" ))))))))

Вот сижу и думаю — а может, это я отсталый…
Уже так сходу и не разберёшься 😂
🌭16🤣14🍓1