mefody.dev – Telegram
mefody.dev
5.31K subscribers
14 photos
1 video
3 files
425 links
Доброжелюбный бородач про фронтенд, тимлидство, спикерство.
Автор — @dark_mefody

Канал про работу: @mefody_work.

Не размещаю рекламу в своём канале. Даже за деньги. Даже большие.
Download Telegram
Firefox Public Data Report

У Firefox есть сайт, где они каждую неделю делятся данными о пользователях браузера. Они пишут, что анализируют обезличенные данные от 10% пользователей различных версий и собирают только те, которые не нарушают приватность.

А статистика, на самом деле, интересная.

1. Хоть многие и предрекают Firefox смерть на рынке браузеров, они всё ещё удерживают 200 миллионов активных пользователей в месяц, что не такое уж и маленькое число. К сожалению, оно снижается каждый год, но не так, как рисовало моё воображение.

2. В среднем пользователи Firefox сидят в браузере 5.3 часа в день.

3. «Вечнозелёность» Firefox вполне себе хорошая: обычно за месяц 70% пользователей переходят на самый свежий релиз.

4. Почти у 40% пользователей есть какое-либо браузерное расширение, причём в России — у 60% пользователей. Из них самые популярные — блокировщики рекламы, скачивалки видео, расширения социальных сетей. Что как бы намекает, что тестировать сайты в инкогнито глупо — правильнее создавать профили для тестирования с расширениями, чтобы видеть реальную картину.

5. Разрешение экрана 1920x1080 с каждым годом всё увереннее забирает долю у разрешения 1366x768. Десктопные мониторы становятся всё больше либо поддерживают более чёткую картинку. Тестировать сайты только на 1024x768 уже странно.

6. Пока что у пользователей преобладает 2 ядра CPU, хотя всё больше могут позволить себе 4 ядра и больше. Выносить тяжёлые вычисления в воркеры однозначно пора.

7. Доля macOS как операционной системы пользователей настолько низкая по сравнению с Windows, что если вы проверяете свои сайты только в ОС от Apple, вы точно живёте в каком-то мире фантазий и понятия не имеете, как на самом деле видят ваш сайт пользователи. При этом на последней тимлидской конференции в спикерской были только макбуки, что забавно.

8. После 2021 года доля пользователей с Flash резко упала, на сегодня всего 1.771% никак не могут обновиться.

Графики однозначно полезные. Как и Веб-альманах, такой отчёт показывает реальную картину мира, пусть пока только для десктопных браузеров. Конечно, правильнее всего опираться на статистику именно про ваших пользователей, но когда вы только начинаете разработку веб-приложения, такой статистики у вас банально ещё нет.

https://data.firefox.com/
👍224
Chrome extension that steals everything

Мэтт Фрисби показывает, как собрать на коленке браузерное расширение для Chrome, которое умеет:
- собирать все куки со страницы;
- получать всю браузерную историю пользователя;
- делать скриншоты страниц;
- отслеживать пользовательские переходы по любым урлам;
- доставать тела запросов;
- логировать нажатия клавиш;
- захватывать буфер обмена;
- загружаться в инкогнито;
- смотреть на геолокацию пользователя;
- подменять фоновые табы контентом из расширения;
- выдавать себя за приложение для локальных заметок.

Разумеется, браузер при установке расширения выдаёт попап, который показывает список API, в которые ломится зловред. Но, во-первых, слишком длинные списки просто спрятаны за скроллом, а во-вторых, далеко не все пользователи читают и понимают, что это за API такие, поэтому просто соглашаются на всё, лишь бы получить нужную им функциональность. Многие из вас читали лицензионное соглашение вашего браузера?

На самом деле ревью расширения в Chrome Web Store должно блокировать таких зловредов. Но хороший лендинг с понятной инструкцией, как установить пользовательское расширение, может помочь сотворить зло.

Мораль:
1. Проверьте, что умеют расширения, которые установлены у вас прямо сейчас. Действительно им нужны все эти доступы?
2. Не зря браузеры ведут работу над тем, чтобы ограничивать доступы расширениям.

https://mattfrisbie.substack.com/p/spy-chrome-extension
👍14🔥9😱2
PWA для новичков

У Microsoft есть неплохой бесплатный видеокурс по тому, что такое PWA, как начать их разрабатывать, как они интегрированы в операционные системы и как их дебажить.

Диванная аналитика: когда большие корпорации создают подобные курсы, у них явно есть планы о поддержке технологии. Это значит, что за PWA сейчас как минимум два гиганта: Google и Microsoft. Для меня это сигнал, что вкладываться в изучение прогрессивных веб-приложений точно стоит, эти знания смогут мне помочь.

https://learn.microsoft.com/en-us/shows/pwa-for-beginners/
👍36💯6
Дебаг свойств-асесcоров в JS

Если у вас бывало такое, что нужно раздебажить странное поведение кода в продакшене, когда кто-то где-то зачем-то трогает свойства объектов, которые не должен как будто трогать, то Вячеслав Москаленко делится способом отладки такого поведения.

В случае автора статьи на странице каждые 10 секунд происходил скролл вверх. И он логично предположил, что нужно проверить, кто трогает scrollTop у document.documentElement. И если сначала Вячеслав играется с сеттером свойства, попутно разбираясь, что не каждое свойство получится так дебажить, то потом вспоминает крайне удобную функцию debug, которая работает в DevTools. Сам постоянно про неё забываю.

https://blog.griddynamics.com/debugging-accessor-properties-in-javanoscript-everything-you-should-know/
👍14🤔1
Хороший доклад. Рекомендую. Смотрел его ещё в Салехарде, много думал.
1
Скруглённые относительно друг друга углы

Довольно часто встречаю как в интерфейсах, так и в бумажной графике ужасный для перфекциониста подход: в блок с каким-то радиусом скругления вкладывают другой блок с таким же радиусом скругления. Выглядит плохо, потому что математика должна быть другой.

Рассматривайте такие вкладывания как поворот дороги, где дорога — полоска между краем внешнего блока и внутренним блоком. Для поворота правильно и естественно, что для внешней стороны и внутренней есть один общий центр окружности, отличается только радиус. И тогда решение для вёрстки приходит само собой.

В статье можно подсмотреть формулы, которые можно добавить в вашу вёрстку, чтобы такие скругления автоматом подстраивались под особенности блоков.

https://set.studio/relative-rounded-corners/
👍26💯7🔥1
Когда :focus-visible виден?

Ире Адеринокун простыми словами объясняет спецификацию псевдокласса :focus-visible. Браузер применяет стили для него, если:
1. Пользователь установил настройку «Всегда показывать фокус».
2. Сфокусированный элемент поддерживает работу с вводом с клавиатуры. То есть для инпутов с текстом применит стили, а для кнопок — не факт.
3. Пользователь переключается между фокусируемыми элементами при помощи устройства без указателя. Например, клавиатурой.
4. JS-скрипт переместил фокус с элемента, на котором стили применялись.

Просто и понятно. В статье есть демки, которые помогут понять на примерах.

Для меня самое ценное в статье — сниппет, который как будто можно брать и копировать почти в любой проект, где нет кастомных стилей выделения для отдельных элементов.


/* Apply focus styles */
:focus-visible, :focus {
outline: 1px solid red;
}

/* Remove the focus outline */
:focus:not(:focus-visible) {
outline: none;
}


https://bitsofco.de/when-is-focus-visible-visible/
👍143🔥3👌1
Клиент подсказывает или клиент врёт?

Люблю читать про разное интересное, с чем приходится сталкиваться браузерам, чтобы не сломать интернет. Ингве Петтерсен рассказывает о том, почему заголовок User-Agent — то ещё зло для всех.

Когда-то, когда про кроссбраузерность говорили только грустным шёпотом, а разработчики вполне могли себе позволить гордо выставить плашку «W3C Validated», некоторые начали опираться на заголовок User-Agent, чтобы в зависимости от него выдавать разную вёрстку. Или, будем честны, отдавать экран, на котором требовать установить тот браузер, в котором разработчики смогли сверстать почти без багов.

Уже тогда возникла проблема вайтлистов и блоклистов. Допустим, вы точно знаете, что ваш сайт хорошо показывается в Firefox и плохо в Chrome (фантазируем). Есть три пути:
1. Починить и в Chrome.
2. Разрешать пользоваться только в Firefox.
3. Запрещать пользоваться в Chrome.

И вот тут многие решили пойти по надёжному способу: разрешать смотреть страницу только там, где она точно работает. То есть все остальные браузеры в пролёте.

Допустим, команда сделала исследование браузеров на рынке, протестировала, закрепила где-то на уровне Apache этот самый вайтлист. И тут появлятся браузер Opera, который хочет честно подписать себя в User-Agent как Opera, но все сайты с вайтлистами просто в нём не работают. При этом инженеры Opera уверены, что у них самые современные реализации стандартов, сайты точно будут работать хорошо. Что они делают? Правильно, начинают подписываться как другие браузеры. И получаем что-то вроде Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 OPR/97.0.4719.17.

Или вообще выходит браузер Arc, который под капотом Chromium. Разумеется, он тоже из коробки мимикрирует под Chrome. Просто чтобы работало.

В общем, идея изначально была хороша, но реалии разработки её извратили, поэтому опираться на User-Agent сейчас можно только если у вас есть все User-Agent всех браузеров мира — только так можно быть уверенным, что никого из пользователей не обидел зря, но и разработчиков не заставил реализовывать что-то, что они пока не умеют. (Надеюсь, сарказм распарсили.)

И собрались популярные браузеры, и придумали новую группу заголовков, и назвали их Client Hints. И стали передавать туда информацию только ту, что посчитали важным: мажорную версию движка, операционную систему, а вообще — то, что сервер спросит явно. Зачем гонять лишние байты, если у сервера в принципе нет обработки нюансов вроде разрядности процессора и типа устройства?

Вот только даже с таким решением случаются казусы. Написал разработчик регулярку v=\d{2}, а тут браузеры внезапно стали версии 100+ выпускать. И всё, теперь страница не показывается у тех, кто сидит на Intel Pentium 2 c Windows 98, и у большей части аудитории с самым последним Chrome на почти любой ОС. Казус.

Автор статьи как раз вспоминает про бесконечную версию Opera 9.9. Всё уже было в Симпсонах.

Мораль:
- User-Agent всё. Если вы на него опираетесь, то делаете пустую работу и рискуете сломать сайт нечаянно.
- Client Hints нужно уметь принимать. Придётся повозиться с сервером, чтобы запрашивать какие-то очень нужные вам детали о клиенте.
- Пишите регулярки внимательнее — версии браузера могут дойти до 1000 когда-нибудь (а что, ежедневные релизы от ChatGPT), а могут и вообще придумать альтернативу SemVer.
- Проверяйте фичи не по названию и версии браузера, а через прогрессивное улучшение на клиенте или те самые Client Hints. Всё равно браузеры врут, особенно новые, которых разработчики так и норовят оставить без рабочих сайтов, хоть они под капотом Chromium.

https://vivaldi.com/blog/technology/client-hints-or-client-lies/
https://github.com/WICG/ua-client-hints
👍10🔥5
Разбираемся с Style Queries

Юна Кравец рассказывает о ещё одной интересной возможности, которая пришла к нам вместе с Container Queries.

В самой спецификации CSS Containment Module Level 3 очень много текста уделено тому, как работать с размерами контейнера, и буквально 3 абзаца — про то, как опираться на почти любые свойства контейнера.

Представьте, что у вас есть компонент карточки товара, который вы берёте из дизайн-системы. И эти карточки должны уметь рисоваться по-разному, с темами. Для начала можно расставить много классов по всему HTML, чтобы явно задавать тему этим карточки. Можно ещё поставить тему на какой-то родительский блок, но тогда начинается борьба со специфичностью вида .theme_dark .card, которую к тому же довольно просто сломать неправильным подключением файлов со стилями. А можно завязаться на кастомные переменные, которые в некоторых проектах уже используют как API. По аналогии с переменными окружения в серверных приложениях.

Допустим, вы договорились, что для темизации вместо навешивания классов в нужных местах вы задаёте всего один класс на родителе, тот же .theme_dark, но внутри простой код:


.theme_dark {
--theme: dark;
}


Теперь эта переменная доступна всем вложенным тегам. И было бы классно подсматривать её значение и каким-то образом изменять внешний вид карточки.


@container style(--theme: dark) {
.card_bright {
background: linear-gradient(-30deg, yellow, orange);
}
}


В таком случае вес селектора тот же, осталась только проблема с правильным порядком подключения стилей. Для этого, к слову, можно посмотреть в сторону CSS Cascade Layers.

Прелесть такого подхода, что выражения от стиля можно комбинировать точно так же, как медиавыражения, и при помощи бинарной логики сделать почти полноценный if внутри CSS (`else` пока не завезли, да он и не нужен, так как есть not и каскад). При этом на метрики Core Web Vitals новинка может повлиять положительно: раньше нужно было дождаться загрузки стилей, теперь тоже нужно дождаться загрузки стилей, но динамический HTML может стать приятно меньше, а стили при этом обычно кладут на CDN и настраивают для них кеширование.

Минусы подхода:
- Пока работает только в Chromium и только с кастомными свойствами. Но по спецификации должны будут в будущем поддерживаться и обычные свойства.
- Нужно переучиться использовать не классы, а кастомные переменные как API для связки CSS с HTML.
- Нужно явно задавать контейнеры, а это тоже требует перестроения мышления. А с большим количеством контейнеров на всём подряд можно и навредить производительности.

Но фича многообещающая. Я уже вижу, как можно её классно будет применять для стилизации всякого встраиваемого в места, где нет контроля над HTML. Для тех же браузерных расширений, которые что-то добавляют прямо на страницы. Или для обеспечения доступности, если подглядывать за текущими цветами фонов и текстов.

https://developer.chrome.com/blog/style-queries/
👍16🎉32💯1
«Как лгать при помощи статистики»

Дарелл Хафф написал очень понятную и интересную книгу о том, как правильно реагировать на фразы «98% наших выпускников успешно устроились в жизни», «Это средство помогает 4 из 5 покупателей», «Исследование показывает, что на удалёнке эффективность сотрудников упала от 3% до 12%» и подобные им. Заметьте, я не пишу, что эти фразы — бред. В каждой нужно разобраться.

Читается за пару вечеров. Узнаете, как корректно собирать контрольную выборку, почему красивые графики могут врать, как простые дизайнерские приёмы искажают восприятие информации и зачем знать про перцентили и средние.

Если до этого вы очень много работали со статистикой и соц. исследованиями, то вряд ли найдёте для себя что-то новое. Остальным книгу крайне рекомендую.

https://alpinabook.ru/catalog/book-kak-lgat-pri-pomoshchi-statistiki/
🔥18
Публичное собеседование junior-разработчика

Хекслет искал собеседующих в твиттере, а мне давно хотелось попробовать себя в таком формате. Вопросы задавал ровно те, которые обычно на собеседованиях и задаю, когда пробую нащупать, а что же умеет кандидат.

Виталий большой молодец, что решился публично проверить свои силы. Не знаю, хватило ли бы смелости у меня прийти на большую аудиторию и где-нибудь под запись не вспомнить какие-то вещи, просто потому что волнение. К слову, я сам немножко поплыл, когда мы стали обсуждать отличие специфичности от каскада, поэтому этот момент из финального видео вырезали, чтобы не вводить в заблуждение аудиторию, которая плохому бы научилась.

https://www.youtube.com/watch?v=9nBbRK-Gfjg
👍294
CodeRun

Только что наша большая команда запустила бету нового сервиса для решения алгоритмических и не только задач. Если кто-то знаком с https://contest.yandex.ru/, то вы знаете, что у нас уже много лет есть платформа для проведения олимпиад и контестов. Но хотелось сделать что-то, что будет доступно не только олимпиадникам, а вообще всем. Например, полноценные задачи на вёрстку, а не только на написание кода на JavaScript.

Комментарии про аналог leetcode знаем, мы это не отрицаем. Самая мощная часть проекта вертится на сервере, мы очень многое умеем, и скоро добавим фичей, которых я раньше не видел.

Но хочется делать сервис для пользователей, а не для себя. Поэтому призываю всех, кому интересна такая движуха, смело набрасывать в форму поддержки, что можно улучшить, каких задач не хватает, где у нас баги. Это пока бета, но бета — не повод делать так себе. А мы с командой ближайшие пару недель будем активно этот фидбек разбирать и обрабатывать.

Например, адаптивности пока нет, доступность некоторых элементов не доделана, нет OpenGraph.

Всем заранее спасибо, кто откликнется. Мы очень старались сделать хорошо, но хотим ещё лучше!

https://coderun.yandex.ru/catalog
🔥31👍92🥴1
«Давайте созвонимся на пару минут»

Вчера читал доклад у Podlodka TeamLead Crew про то, нужны ли созвоны, как их проводить более эффективно и можно ли ставить все встречи впритык, чтобы потом после них пойти поработать.

Всё сказанное основано на моём личном опыте, поэтому воспринимайте советы со здоровой долей критики — что-то в ваших командах сработает точно, а что-то лучше внедрять осторожно.

https://www.youtube.com/watch?v=EEGM38yA9Wo
🔥143👍2
text-wrap: balance

Сначала Адам Аргайл написал статью, про то, как это работает. Потом Ахмад Шадид добавил полезных примеров.
В общем, прямо во время записи подкаста заслал в Shower пулл-реквест, чтобы в теме Ribbon тоже автоматом рисовались красивые заголовки.

text-wrap: balance — это способ попросить браузер рисовать текст внутри какого-то контейнера до 4 строчек сбалансированно. Например, если у вас на сайте есть длинные заголовки, в которых постоянно в последней строчке висячее слово остаётся, то браузер постарается сделать все строчки приблизительно одной длины, что по меркам типографики красиво и правильно.

Это свойство пока работает только в Chrome Canary за флагом, но как только оно начнёт работать в стабильном браузере, у вас просто станет красиво сразу. Поэтому есть смысл показать свойство дизайнерам уже сейчас, добавить его в правильных местах (см. статью Ахмада, очень хорошие примеры на мой субъективный взгляд) и уже выкатить в прод. Люблю CSS за то, что он не ломается, когда не знает какое-то свойство.

https://ishadeed.com/article/css-text-wrap-balance/
https://developer.chrome.com/blog/css-text-wrap-balance/
👍18👌72
Новые_возможности_CSS_Никита_Дубко.pdf
30.7 MB
Новые возможности CSS, которые меняют взгляд на вёрстку

Вчера читал доклад на конференции DUMP про то, что наши страхи использовать новые фичи в CSS во многом обусловлены «детской травмой» веб-мастеров 2000-ых, что любое новое свойство скорее всего работает всего в одном браузере, а в остальных либо кое-как, либо никак. А на самом деле благодаря инициативе Interop многие фичи появляются чуть ли ни одновременно в вечнозелёных браузерах (вот бы ещё Safari подтянули релизный цикл хотя бы до обновления в пару месяцев).

Заодно поделился CSS-свойствами, которые нашёл крайне интересными за последние полгода.

Приятно, доклад зрители оценили как лучший во фронтенд-секции. Значит, много у кого болело. Постараюсь поделиться с вами видео выступления, когда оно появится в сети. А слайдами делюсь уже сейчас.
👍44🔥187❤‍🔥4😱1🥴1
Переопределение заголовков ответа для дебага

В Chrome 113 Dev Tools появилась, на мой взгляд, потрясающая фича, которая сильно ускорит параллельную разработку фронтенда и бэкенда в некоторых конкретных случаях.

Представьте, что у вас есть какая-то функциональность на сайте, которая зависит от HTTP-заголовков ответа сервера. Да даже представлять особо не надо, она точно есть: кэширование, куки, CORS, CSP, скачивание файлов, редиректы и разное другое. И вот в какой-то момент эту функциональность нужно доработать новыми заголовками, но на бэкенде доработка требует 2 дня разработки, тестирование и деплой, а на фронтенде — пары часов небольших правок с тестированием. Что можно сделать, чтобы не стопорить фронтенд в таком случае:

1. Сделать заглушку на бэкенде, которая топорно возвращает нужные заголовки по параметрам в URL. Плохой вариант, потому что отвлекается бэкендер, который мог бы уже фичу начать делать. И всё равно нужно ждать деплой.

2. Настроить фронтендеру что-то проксирующее, вроде Charles, научить подменять конкретные заголовки на уровне сети. Уже лучше, но джуну, который только-только освоил вёрстку и какой-нибудь фреймворк, объяснять, как сниффить трафик, кажется оверинжинирингом. К тому же не на всех корпоративных машинках можно ставить сторонние прокси.

3. Воспользоваться новой фичей Chrome Dev Tools! (как будто в телемагазине вещаю, простите)

В чём суть фичи:
- В открытых Dev Tools во вкладке Network > Headers > Response Headers теперь можно редактировать заголовки ответа сервера. Или добавить новые.
- Во вкладке Sources > Overrides можно найти домен, на котором экспериментируете с заголовками, и отредактировать там файл .headers, внутри которого можно задать переопределения не конкретному ответу, а вообще всем ответам.

А ещё обязательно покажите эту фичу вашему QA, чтобы ему было ещё удобнее ломать тестировать подобные кейсы без страданий.

https://developer.chrome.com/blog/new-in-devtools-113/#network
🔥28👍7🤯3🥴1
D&D Tokenizer

Давно хотел попробовать написать какое-нибудь настоящее PWA: чтобы хорошо работало в офлайне, выглядело более-менее нативно, интегрировалось в операционную систему, при этом всё на чистых веб-технологиях.

За выходные собрал приложение для рисования токенов персонажей в настольных играх. По названию можно понять, что фокус сделал на D&D. Мы с друзьями привыкли, что у всех NPC и у наших игровых альтер-эго есть красивые картинки, а рамка — часть этого впечатления. Делал для себя, но почему бы не поделиться со всеми.

Разумеется, буду приложение дорабатывать постепенно, там есть над чем работать. Но PWA на вкус попробовал — очень нравится.

Исходники: https://github.com/MeFoDy/dnd-tokenizer
Сам проект: https://dnd-tokenizer-41471e.netlify.app/
🔥38🤔1
Одно PWA, чтобы править всеми

Вчера на HolyJS читал доклад про то самое приложение для генерации картинок-токенов, про которое писал выше. Цель доклада в том, чтобы убедить разработчиков, что PWA вполне себе могут заменить нативные приложения в каких-то случаях. Не во всех, это точно, но во многих. На самом деле не так уж и часто нативные приложения нуждаются в каких-то редких низкоуровневых API, при этом под капотом часто у них WebView, из которого уже можно сделать PWA меньшими усилиями.

Самую большую дискуссию вызвал вопрос безопасности PWA: «Можно ли написать что-то банковское и безопасное фронтенд-инструментами?» На мой взгляд, здесь между нативным и PWA разница очень маленькая:

— Да, нативное сложнее ломать, потому что нужна экспертиза. Но если она есть и вся логика по безопасности у вас зашита на клиенте — приложение дырявое. На фронтенде посмотреть логику гораздо проще, но имея под рукой хороший прокси (аналог вкладки Network в Dev Tools) можно расковырять почти любые запросы-ответы.

— Любой клиент, как фронтенд, так и нативный, не должен содержать в себе какой-то сложной логики по безопасности. Клиент — это вьюшка, которой должен управлять бэкенд. И именно бэкенд должен давать или не давать доступ к тем или иным действиям на сайте.

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

— Банковские приложения внезапно начали писать на PWA. А у банков аудиты безопасности обычно очень даже серьёзные.

Дискуссия интересная, на конференциях явно нужен доклад про безопасность в PWA, будет полезно.

Видео доклада пока нет, но слайдами уже могу поделиться: https://mefody.github.io/talks/pwa-2023/
👍26🔥63
MinskJS #10

Кто давно со мной знаком, знают, что когда-то я был в составе организаторов минских сообществ MinskJS и MinskCSS. У нас были крутые оффлайн-митапы с трансляциями, полные залы на площадке Space в Минске.

Недавно вернулся в мои любимые сообщества, помогаю Саше Шинкевич и Глаше Жур делать классные онлайн-митапы: искать спикеров, прогонять доклады, делать минский движ ярче. MinskCSS #10 вообще транслировали из моей квартиры.

Завтра (31 мая) в 19:00 у нас как раз состоится онлайн-митап MinskJS #10, где поговорим про путь браузера от ввода урла в адресную строку до отрендеренной страницы, «толстые клиенты» и расширение круга знакомств в индустрии, если ты интроверт. Всех приглашаю, заваривайте пельмешки, зовите коллег и задавайте вопросы в чате. Увидимся!

https://minskjs.timepad.ru/event/2406669/
🔥30👍6🥴1