C++ and other lectures
Відкрити в Telegram
Учебный канал в Телеграм: тут будут анонсы и ссылки на лекции и стримы. Написать автору: @Tilir Boosty автора: https://boosty.to/cpp_lects_rus
Показати більше9 609
Підписники
+1224 години
+157 днів
+9930 день
Триває завантаження даних...
Схожі канали
Хмара тегів
Вхідні та вихідні згадування
---
---
---
---
---
---
Залучення підписників
червень '26
червень '26
+34
в 0 каналах
травень '26
+204
в 3 каналах
Get PRO
квітень '26
+126
в 0 каналах
Get PRO
березень '26
+119
в 0 каналах
Get PRO
лютий '26
+148
в 0 каналах
Get PRO
січень '26
+266
в 2 каналах
Get PRO
грудень '25
+228
в 1 каналах
Get PRO
листопад '25
+234
в 0 каналах
Get PRO
жовтень '25
+283
в 2 каналах
Get PRO
вересень '25
+207
в 1 каналах
Get PRO
серпень '25
+257
в 2 каналах
Get PRO
липень '25
+304
в 0 каналах
Get PRO
червень '25
+225
в 3 каналах
Get PRO
травень '25
+362
в 4 каналах
Get PRO
квітень '25
+172
в 2 каналах
Get PRO
березень '25
+212
в 2 каналах
Get PRO
лютий '25
+270
в 0 каналах
Get PRO
січень '25
+540
в 3 каналах
Get PRO
грудень '24
+986
в 2 каналах
Get PRO
листопад '24
+219
в 1 каналах
Get PRO
жовтень '24
+383
в 2 каналах
Get PRO
вересень '24
+230
в 1 каналах
Get PRO
серпень '24
+472
в 4 каналах
Get PRO
липень '24
+178
в 1 каналах
Get PRO
червень '24
+176
в 0 каналах
Get PRO
травень '24
+251
в 1 каналах
Get PRO
квітень '24
+567
в 2 каналах
Get PRO
березень '24
+269
в 1 каналах
Get PRO
лютий '24
+291
в 0 каналах
Get PRO
січень '24
+244
в 1 каналах
Get PRO
грудень '23
+255
в 2 каналах
Get PRO
листопад '23
+191
в 0 каналах
Get PRO
жовтень '23
+168
в 0 каналах
Get PRO
вересень '23
+190
в 0 каналах
Get PRO
серпень '23
+114
в 0 каналах
Get PRO
липень '23
+134
в 0 каналах
Get PRO
червень '23
+221
в 0 каналах
Get PRO
травень '23
+136
в 0 каналах
Get PRO
квітень '23
+192
в 0 каналах
Get PRO
березень '23
+138
в 0 каналах
Get PRO
лютий '23
+82
в 0 каналах
Get PRO
січень '23
+103
в 0 каналах
Get PRO
грудень '22
+118
в 0 каналах
Get PRO
листопад '22
+73
в 0 каналах
Get PRO
жовтень '22
+104
в 0 каналах
Get PRO
вересень '22
+93
в 0 каналах
Get PRO
серпень '22
+686
в 0 каналах
| Дата | Залучення підписників | Згадування | Канали | |
| 05 червня | +4 | |||
| 04 червня | +12 | |||
| 03 червня | +5 | |||
| 02 червня | +10 | |||
| 01 червня | +3 |
Дописи каналу
Выложил лекцию по std::execution на английском языке. Это последняя, 28-я лекция англоязычного магистерского курса.
https://youtu.be/ZMcUTZppCAw
Финальная лекция магистерского курса по C++ посвящена std::execution -- новой модели исполнения, которая входит в C++26. Мы начнём с давно известных механизмов: параллельных алгоритмов стандартной библиотеки, ручного запуска потоков и std::async. На примере параллельного reduce посмотрим, почему этих средств быстро становится недостаточно, если хочется не просто запустить несколько потоков, но также аккуратно описывать и комбинировать вычисления. После этого перейдём к senders/receivers: разберём, что такое scheduler, sender, receiver и operation state, как работают адапторы и как вычисление может переходить между разными execution resources. Свяжем эту тему с миром GPGPU через bulk-вычисления, посмотрим на рекурсивное порождение асинхронных задач через execution scopes и обсудим разные варианты завершения вычислений. В конце поговорим о связи std::execution с корутинами, отмене задач через environment и ещё раз соберём общую картину: как C++26 предлагает описывать асинхронное и параллельное исполнение без ручного управления потоками.
Timeline
00:00 Введение. Параллельные алгоритмы в стандартной библиотеке.
03:30 Пишем собственный параллельный reduce.
10:05 std::async и его особенности. Замеры производительности.
16:50 Единая абстракция исполнения. Основы std::execution в C++26.
26:59 Концепт sender и адапторы.
35:00 Монадическая природа вычислений и let_value.
40:16 Адаптор bulk: снова заходим в мир GPGPU.
46:05 Параллельный reduce с использованием std::execution.
49:40 Execution scopes: динамическое создание задач. Параллельная сортировка.
54:41 Каналы в sender. Поведение upon_error и upon_stopped. Сигнатуры завершения.
01:02:19 Проверка completion signatures: упражнение в метапрограммировании и рефлексии.
01:06:50 Связь сендеров с корутинами: execution::task.
01:14:40 Снова многопоточная подписка и отмена задач.
01:18:47 Основные концепции ещё раз, список литературы и завершение.
#cpp_postgraduate
| 2 | В этом июле где то в 10-х числах у меня есть шанс побывать на Дальнем Востоке. Просьба местных обозначиться в чате и сказать есть ли заинтеремованность, когда и где лучше устроить встречу с читателями и можете ли вы помочь с организацией. | 5 676 |
| 3 | Выложил лекцию по GPGPU и SYCL на английском языке.
https://youtu.be/Ebj21eXDRDY
В этой лекции мы обсудим, почему модель программирования для графики и гетерогенных вычислений исторически отличается от обычного C++. Начнём с классических шейдерных языков, stateful memory, binding tables и адресных пространств, а затем перейдём к OpenCL и проблемам separate-source compute API. После этого разберём основы SYCL как примера single-source подхода к гетерогенному программированию, познакомимся с устройствами и очередями, а также с моделью исполнения SIMT. На примерах сложения векторов и перемножения матриц посмотрим, как часть работы отправляется на устройство и как SYCL описывает зависимости между вычислениями. Основная часть лекции посвящена памяти и синхронизации. Мы постепенно оптимизируем перемножение матриц и разбираем, как на производительность влияют разные виды памяти, tiled execution, барьеры и specialization constants. Затем обсудим гистограмму как пример конкурентного доступа к данным и поговорим об атомиках в GPU API. В финале вернёмся к C++ и обсудим природу указателей, а также generic address space в SYCL. На протяжении всей лекции нас будет сопровождать большое количество замеров производительности.
Timeline.
00:00 Введение. Гетерогенные вычисления и GPU как execution model.
03:50 Память в классических шейдерных языках на примере GLSL: stateful и stateless pointers.
10:35 Первые compute API с раздельными исходниками на примере OpenCL. Проблема небезопасности типов в API.
15:40 На пути к единому compute API: как расширять C++ для гетерогенного программирования?
19:34 Основы SYCL: очереди, command groups, iteration space и vector addition.
29:15 Перемножение матриц -- основная задача GPGPU.
35:28 Более интересное управление памятью: shared memory, device memory и снова аллокаторы.
40:25 Продолжаем умножать матрицы: приватная память, oneMKL и первые замеры.
45:15 Локальная память и барьеры. Инверсия параллелизма внутри рабочей группы.
52:52 Улучшаем перемножение матриц: tiled multiplication, specialization constants и ещё немного замеров.
59:52 Конкурентный доступ к данным: гистограмма, атомики и memory model в GPU API.
01:09:53 Обсуждение природы указателей, generic address space в SYCL, hierarchical parallelism и завершение лекции.
#cpp_postgraduate | 7 738 |
| 4 | Не могу не поделиться самым веселым, на мой взгляд, примером из доклада великолепного Константина Владимирова. Он делал анонс доклада в своем tg канале.
Пример вот такой:
template <auto T = []{}>
struct S {};
S a; S b;
В чем тут цимес. У нас T - это лямбда. И если мы таким образом определяем переменные, то в тип S записываются разные лямбды, и у нас получаются два разных типа:
static_assert(
!std::is_same_v<decltype(a), decltype (b)>
);
Если же мы явно укажем пустые треугольные скобки вот так:
S<> a, b;
static_assert(
std::is_same_v<decltype(a), decltype (b)>
);
То типы, внезапно, станут одинаковыми. Ну, мы один раз объявили тип, и две переменные этого типа.
А теперь вопрос в зал. А что если мы определим эти две переменные точно так же, как во втором варианте, но только без явного указания треугольных скобок?
S a, b;
Давайте вы попробуете угадать?
Ставя треугольные скобки мы исключаем вывод типов. Мы явно указываем, какой тип мы используем.
Но если у нас есть вывод типов, у нас компиляторы начинают вести себя по-разному.
clang падает с ошибкой
```
error: template arguments deduced as 'S<(lambda at <source>:4:20){}>' in declaration of 'a' and deduced as 'S<(lambda at <source>:4:20){}>' in declaration of 'b'
7 | S a, b;
```
А gcc считает, что это два разных типа.
```
static_assert(
!std::is_same_v<decltype(a), decltype (b)>
);
```
Пруф.
Вцелом доклад Константина был просто прекрасным, и я, наверное, понатырю сюда еще примеров из его доклада через пару месяцев. А когда он выйдет в открытый доступ - обязательно дам ссылку. Я был просто в восторге от дурки, которую он показывал. | 7 661 |
| 5 | Отличный реакт и канал интересный.
К слову. У моего доклада маловато оценок "супер" и пока что их можно ставить. Если у вас есть билет, зайти и кликнуть "оценить". Это намёк )) | 5 861 |
| 6 | Выложил вторую лекцию по корутинам на английском языке.
https://youtu.be/huitkyM1UQE
Во второй лекции мы переходим от базовой механики co_await и promise_type к более сложным и практическим аспектам программирования с использованием корутин в C++20/23. Сначала мы обсудим симметричные корутины, различные варианты await_suspend и то, как корутины могут напрямую передавать управление друг другу. Затем, на примере корутинной реализации конечных автоматов, разберём, как с помощью awaiters можно строить довольно сложные модели выполнения. Важной частью лекции является обсуждение взаимодействия корутин с потоками на примере многопоточной подписки на события. Мы разберём, почему встроенные (stackless) корутины могут продолжать выполнение на другом потоке, как устроен фрейм корутины и почему это создаёт сложности для оптимизаций в компиляторах. Также мы рассмотрим корутины как основу для композиции асинхронных вычислений и увидим, как корутины позволяют писать существенно более читаемый асинхронный код по сравнению с callback-based подходами. В завершение разберём внутреннее устройство корутин в компиляторах: фреймы корутин, порождаемые конечные автоматы и даже генерируемый ассемблер.
00:00 Введение. Вспоминаем пройденное.
04:38 Обобщаем awaitable transformations: что, кроме перегрузки co_await, нам доступно?
13:09 Изобретаем симметричные корутины в C++: await_suspend и его механика.
18:42 Case study: конечные автоматы на корутинах.
31:00 Монадические свойства co_await.
37:55 Сочетание корутин с потоками. Многопоточная подписка на события и её сюрпризы.
48:00 Корутинный интерфейс для std::future.
52:05 Корутины как механизм композиции асинхронных задач.
56:18 Внутреннее устройство корутин и их реализация в компиляторах.
01:02:04 Обзор литературы и завершение.
#cpp_postgraduate | 6 452 |
| 7 | Всем привет. Кто идёт на C++ Russia из моих уважаемых подписчиков, обратите пожалуйста внимание на изменения в программе, внесённые в последний момент.
https://cppconf.ru/schedule/table/#day-2
Теперь мой доклад открывает конференцию в субботу утром, а Антон Полухин закрывает в воскресенье вечером (ранее было наоборот).
Поэтому, если вы хотите попасть на мой доклад, вам надо будет встать утром в субботу и не опоздать к получению бейджа. Я в вас верю ))
#official | 7 918 |
| 8 | Минутка 3d-моделей.
Ребята из Iridi прислали исходники Крыса Кейта (Кита?) с обложки моей книги.
Выложил на boosty в бесплатный доступ чисто чтобы хранить поближе к собственно книжке.
https://boosty.to/cpp_lects_rus/posts/7f9999a9-4249-4538-9ddb-40b9338fe40f
#boosty #cppbook | 10 349 |
| 9 | Выложил первую лекцию по корутинам на английском языке.
https://youtu.be/wmrW6AkRo3c
В этой лекции мы начинаем с базового вопроса: что вообще такое корутина и чем она отличается от обычной функции или thread routine, а также обсуждаем исторический контекст и классификацию сопрограмм: стековые и встроенные (stackless), асимметричные и симметричные и т.д. Основная часть лекции посвящена внутреннему устройству корутин в C++20/23. Разбираем три ко-оператора, интерфейс promise_type, coroutine_handle, awaiters и их контракт. На протяжении лекции мы будем постепенно строить собственные корутинные абстракции -- несколько наивные, но полезные в образовательных целях. Когда основы станут ясны, мы обсудим более сложные вещи, например то, как через awaiters можно реализовать более сложные механизмы -- подписку на событие и пробуждение нескольких корутин на едином объекте синхронизации. Также мы кратко обсудим оператор co_await и возможности для его перегрузки.
00:00 Introduction. Программы, подпрограммы и thread routines.
10:11 Сопрограммы и их классификация. Stackful- и stackless-сопрограммы в C++.
15:41 Генераторы в Python и C++23.
22:10 Внутреннее устройство и строительные блоки сопрограмм. Ко-операторы.
27:25 Интерфейс promise_type и Hello World.
36:50 Напишем свой простой генератор.
45:00 Range-based-использование и когенерация.
50:40 Детали работы ко-операторов. Awaiters.
56:23 Case study: подписка на результат.
01:05:42 Оператор co_await, завершение и список литературы.
#cpp_postgraduate | 9 481 |
| 10 | Стрим на Boosty скоро подрубаю. После завершения тут размещу ссылку на запись.
Подключайтесь:
https://boosty.to/cpp_lects_rus/streams/video_stream
#official #boosty | 0 |
| 11 | Выложил третью лекцию по атомикам на английском языке.
https://youtu.be/h4k3z69aIMY
В третьей части лекции мы переходим к рассмотрению проблемы рекламации памяти и построению lock-free структур данных. Начинаем мы с рекламации памяти, разбирая в процессе, почему наивные решения на указателях и CAS ломаются, и где именно возникает необходимость аккуратно управлять временем жизни объектов. Далее рассматриваем новые подходы, которые введены в стандарт C++26: RCU и hazard pointers. Обсуждаем, как они работают, какие гарантии дают и какие накладные расходы вносят. После этого мы приступаем к рассмотрению lock-free структур данных. Сначала разбираем простой пример unbounded стека с использованием hazard pointers. Затем bounded MPMC стек, где появляются уже другие сложности: проблема публикации и проблема ABA. Разбираем, как они возникают и как с ними бороться. В завершение рассматриваем lock-free MPMC очередь, обсуждаем влияние моделей памяти на производительность и смотрим на результаты бенчмарков.
00:00 Введение. Проблема рекламации памяти.
07:03 Идея атомарного shared_ptr и её ограничения.
11:05 Решения в C++26: RCU.
23:01 Решения в C++26: Hazard pointers.
31:20 Lock-free unbounded stack с использованием hazard pointers.
35:45 Lock-free bounded MPMC stack: проблема публикации.
42:42 Проблема ABA и способы её решения.
54:40 Lock-free bounded MPMC queue, бенчмаркинг и литература.
#cpp_postgraduate | 9 710 |
| 12 | Очередной отчётный стрим на бусти проведу 3 мая в 19 часов по Москве.
В программе:
* Новые интересные факты про моего несостоявшегося менеджера Игоря.
* Как меня разводили на смарт-контрактах.
* Зачем был опрос про столы.
* Когда новые главы книги, почему задержка.
* А также любые ваши вопросы, которые можно накидать уже сейчас: https://www.donationalerts.com/r/cpp_lects_rus
P. S. Ваша поддержка моей просветительской деятельности меня очень мотивирует: https://boosty.to/cpp_lects_rus
Минимальная подписка для участия в стриме всего-то 128 рублей. Мне кажется для всех кто на этом канале вообще не деньги ))
#official #boosty | 6 913 |
| 13 | У вас в офисе какая длина у вашего рабочего стола? Предполагаем что у стола три параметра: длина, высота и глубина. Если работаете из дома или из коворкинга, тоже сойдёт. | 0 |
| 14 | Выложил вторую лекцию по атомикам на английском языке.
https://youtu.be/hikc1u-zOhQ
Во второй лекции по атомикам мы в основном сосредоточимся на моделях памяти в C++ и на том, как они соотносятся с реальной аппаратурой. Поговорим про переупорядочивание, happens-before и о том, почему без этого невозможно понять поведение многопоточного кода. Подробно рассмотрим модели памяти для атомиков и покажем, как relaxed легко приводит к неожиданным эффектам и даже UB, а также где он действительно полезен. Детально разберём барьеры памяти -- как они работают и как их можно воспроизводить вручную. Отдельно обсудим, почему атомики иногда тяжелее, чем кажется, и как атомики в C++ конкурируют с инлайн-ассемблером. В конце познакомимся с "теорией относительности" и разберём последовательные и непоследовательные модели.
Timeline
00:00 Начало. Переупорядочение повсюду.
09:15 Модели памяти в аппаратуре.
15:40 Отношение "happens after / before" в C++ и его корни.
21:05 Модели памяти атомиков в C++. Когда relaxed ведёт к UB.
29:09 Барьеры своими руками
36:25 Соревнуемся с инлайн-ассемблером.
41:12 Теория относительности.
47:33 Немного про Multithread COW Disease, литература и завершение.
#cpp_postgraduate | 0 |
| 15 | Съездил в Нижний Тагил по приглашению компании Iridi с лекцией по RAII. В частности рассказал что-то и про новые RAII-обёртки в C++26: std::polymorphic и std::indirect. К сожалению нормальной записи не велось, поэтому запись экрана выкладываю на правах черновика.
https://rutube.ru/video/491df36a93e245aaefa116026cf775ef
Timeline:
00:00 Введение. Инварианты классов.
07:58 Инкапсуляция и ряд смежных наблюдений.
14:23 Big-5 и безопасность исключений. Изобретаем RAII.
25:15 RAII и Value-семантика. Мотивируем std::polymorphic.
37:43 Детали std::polymorphic и делаем систему открытой.
43:20 Немного о некопируемых типах. RVO.
50:03 Некоторые советы по работе с unique pointers.
55:26 PImpl и мотивация для std::indirect.
58:32 Shared pointers и их проблемы.
01:03:25 Завершение: пара слов про интрузивные указатели, литература, первые пара вопросов.
Слайды: https://sourceforge.net/projects/cpp-lects-rus/files/conference-talks/raii.pdf/download
Получил в подарок удивительно тёплую толстовку (я в ней на фотографии) и прекрасную статуэтку работы местных мастеров.
Новость о событии на канале Iridi: https://t.me/iRidiummobileRu/2344
Спасибо Марату Гилязетдинову за его усилия в организации этой поездки и за короткую экскурсию по Тагилу после лекции.
P. S. Также недавно был в Йошкар-Оле но там слишком уж хорошая запись, так что пост выложу когда придёт время её выкладки на youtube.
P. P. S. Приближается лето — лучшая пора когда меня можно позвать в ваш город, в ваш университет или в офис вашей компании с лекцией, на встречу с читателями и т. п. Если вы человек, который способен организовать такого рода поездку (найти помещение, договориться с администрацией, привести аудиторию), пишите мне в лс.
#official #author_event | 0 |
| 16 | Выложил первую лекцию по атомикам на английском языке.
https://youtu.be/dRlOwdj8BHI
В этой лекции мы начнём переход к настоящему lock-free программированию. Для этого нам понадобится серьёзная база в атомиках C++. Первое, что мы сделаем в начале лекции, -- это мотивируем атомик через конкретный пример контрольного блока shared_ptr и убедительный бенчмаркинг. Далее, рассматривая обычный инкремент, мы изобретём идиому Compare-And-Swap (CAS). Центральным понятием лекции является lock-freeness. Мы разберём иерархию гарантий прогресса, а также вернёмся к классическим антипаттернам, вроде double-checked locking, и покажем, как их корректно реализовать с помощью атомиков. Отдельно обсудим статическую инициализацию и thread-local переменные. Во второй половине лекции мы перейдём к более сложной теме -- API races. Посмотрим, как такие ошибки возникают даже при использовании атомиков, и почему их сложно обнаружить, в частности обсудим подход через формальную верификацию. Закончим мы разбором ситуаций активной блокировки.
Timeline
00:00 Intro. Контрольный блок для разделяемого указателя и снова data race.
04:30 Проблема контрольного блока. Бенчмаркинг atomic vs mutex.
10:25 Дуальность синхронизации. Какой единственный тип должен быть действительно атомарным.
17:30 Проблема инкремента для аомика. Мотивация для CAS.
28:24 Концепция lock-freeness и иерархия свободы.
38:45 Снова антипаттерн DCL. Чиним через атомики.
45:10 Синглтон Майерса: синхронизация вокруг статических переменных. Thread local переменные.
50:15 Снова Copy On Write: проблемы в простом COW подходе.
56:57 Поиск API Races в коде, активно использующем атомики.
01:04:30 Методы формальной верификации для поиска API races.
01:08:46 Завершение: livelocks и литература.
#cpp_postgraduate | 0 |
| 17 | Минутка дружественного пиара.
В компании YADRO стартовал набор на программу стажировки Импульс. В этом году открыто более 30 направлений.
В том числе:
* Разработка на C++.
* C, системное программирование.
* Тестирование.
* Математика и алгоритмы.
* и много чего ещё.
Возможна удалёнка или гибрид.
Детали можно узнать на вебинарах 16 и 23 апреля. Регистрация уже доступна на сайте.
https://edu.yadro.com/impulse
#official | 0 |
| 18 | Выложил лекцию по многопоточным очередям на английском языке.
https://www.youtube.com/watch?v=86aNZgS9SOU
В этой лекции мы завершаем обсуждение lock-based примитивов синхронизации в C++ и подводим итог всему, что связано с классическим многопоточным программированием на мьютексах и condition variables. Мы рассмотрим producer–consumer паттерн, реализуем ограниченные MPMC-структуры (стек и очередь), разберём типичные проблемы таких решений и попробуем их исправить. Отдельно обсудим, почему даже "правильные" на первый взгляд интерфейсы могут приводить к потере задач. Далее перейдём к более выразительным механизмам коммуникации между потоками: future/promise, обработке исключений, packaged_task и std::jthread. Посмотрим, как современные абстракции позволяют писать более чистый и безопасный код. В завершение попробуем объединить всё вместе и построить очередь с произвольными задачами.
Timeline
00:00 Введение. Ментальная модель мьютекса.
06:33 Thread-Safe Lock-Based Bounded MPMC Stack.
11:01 Измеряем производительность и обнаруживаем проблему.
18:00 Пробуем пофиксить проблему: Wake and Done.
22:30 Thread-Safe Lock-Based Bounded MPMC Queue.
29:00 Критика интерфейса: очередь, которая не может не терять задачи.
33:46 Что если мы позволим неограниченный размер?
36:52 Возврат данных из потока и механизм future/promise.
42:45 Обработка исключений в потоках.
46:43 Packaged Tasks and Joinable Threads.
51:28 Проблема постановки барьера.
57:46 MPMC Queue с произвольными задачами.
01:03:26 Задача на подумать и список литературы.
#cpp_postgraduate | 0 |
| 19 | Ссылку на прошедший стрим и его таймлан размещу тут, когда обработается. Пока немного забавного take-away.
На стриме был задан интересный вопрос. Я его докрутил до следующего примера.
int x;
int *p = &x;
x = 0;
std::thread t([p]{ *p = 42; });
t.join();
use(x);
Компилятору в этом коде кажется ничто не мешает трансформировать его примерно так:
int x;
int *p = &x;
std::thread t([p]{ *p = 42; });
x = 0;
t.join();
use(x);
И тем самым создать UB (data race).
В лямбду уходит указатель, он не пересекается как область памяти, happens-before вроде нет и т.п.
—
На стриме я задумался и не нашёл что сказать, но сейчас после стрима я почитал стандарт и внезапно мы тут защищены.
The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of f.
https://eel.is/c%2B%2Bdraft/thread.thread.constr#6
Так что happens-before всё-таки есть, кто бы мог подумать ))
Дмитрий, который задавал вопрос, FYI.
#boosty #questions | 0 |
| 20 | Начинаем в 19 часов.
https://boosty.to/cpp_lects_rus/streams/video_stream
Пост временный, снесу по завершении стрима.
#boosty #official. | 0 |
Вже доступно! Дослідження Telegram за 2025 — головні інсайти року 
