✨ Как связать symfony 8 и Angular 22?
Многие разработчики сталкиваются с одной и той же проблемой. Как удобно организовать связку фронтенда и бэкенда на разных технологиях в едином окружении.
В статье эта проблема решается через Docker-контейнеры, которые обеспечивают изолированную и быструю работу без установки лишних зависимостей на основную операционную систему.
Ключевым элементом связки выступает Nginx, который прозрачно распределяет трафик: запросы с префиксом /api проксируются на бэкенд, а все остальные на dev-сервер фронтенда. Рутинное управление проектом максимально упрощено за счет команд, вынесенных в Makefile.
👉 https://habr.com/ru/articles/1059392/
Многие разработчики сталкиваются с одной и той же проблемой. Как удобно организовать связку фронтенда и бэкенда на разных технологиях в едином окружении.
В статье эта проблема решается через Docker-контейнеры, которые обеспечивают изолированную и быструю работу без установки лишних зависимостей на основную операционную систему.
Ключевым элементом связки выступает Nginx, который прозрачно распределяет трафик: запросы с префиксом /api проксируются на бэкенд, а все остальные на dev-сервер фронтенда. Рутинное управление проектом максимально упрощено за счет команд, вынесенных в Makefile.
👉 https://habr.com/ru/articles/1059392/
🤣17👍2🤔2
✨ Angular переходит на ежегодный цикл релизов
Команда Angular объявила о важном изменении. Начиная с v23, мажорные версии фреймворка будут выходить раз в год вместо привычного полугодового цикла.
Новые фичи никуда не денутся и по-прежнему будут прилетать в минорных релизах, при этом их станет даже больше, было 1-3 минорных релиза на каждый мажорный, станет 4-6. Ограничение касается только breaking changes, теперь они будут собираться и выходить исключительно в рамках мажорных версий раз в год.
Спасибо katsuba.dev за новость.
👉 https://github.com/angular/angular/pull/69817
Команда Angular объявила о важном изменении. Начиная с v23, мажорные версии фреймворка будут выходить раз в год вместо привычного полугодового цикла.
Новые фичи никуда не денутся и по-прежнему будут прилетать в минорных релизах, при этом их станет даже больше, было 1-3 минорных релиза на каждый мажорный, станет 4-6. Ограничение касается только breaking changes, теперь они будут собираться и выходить исключительно в рамках мажорных версий раз в год.
Спасибо katsuba.dev за новость.
👉 https://github.com/angular/angular/pull/69817
🔥29👍18🤡3❤1
✨ Знакомство с Resource Snapshots
Стандартное поведение Resource API сбрасывает value во время загрузки, из-за чего приходится показывать skeleton-загрузчики вместо более удобного индикатора загрузки с сохранением старых данных.
Статья рассказывает о том, как сохранять предыдущие данные при изменении входных параметров запроса, например, при новом поисковом запросе.
👉 https://angular.love/getting-to-know-angular-resource-snapshots
Стандартное поведение Resource API сбрасывает value во время загрузки, из-за чего приходится показывать skeleton-загрузчики вместо более удобного индикатора загрузки с сохранением старых данных.
Статья рассказывает о том, как сохранять предыдущие данные при изменении входных параметров запроса, например, при новом поисковом запросе.
👉 https://angular.love/getting-to-know-angular-resource-snapshots
👍3🔥1🌚1
✨ Может ли айтишник обеспечить себе уверенную пенсию
Статья разбирает миф о богатых айтишниках и честно считает, сколько реально можно накопить к пенсии. Вывод неутешительный, большинство инвестиционных инструментов работают плохо. Вклады съедает инфляция, государственная пенсия ненадежна, а фондовый рынок слишком непредсказуем и рискован.
Не спасают и альтернативные пути. Собственный IT-проект, офлайн-бизнес, консалтинг или преподавание, везде высокий риск провала из-за быстро меняющихся трендов отрасли и рынка труда. Даже недвижимость, при всей своей стабильности, требует больших вложений и не гарантирует высокую доходность.
А какие стратегии накоплений выбрали вы?
👉 https://habr.com/ru/articles/1059644/
Статья разбирает миф о богатых айтишниках и честно считает, сколько реально можно накопить к пенсии. Вывод неутешительный, большинство инвестиционных инструментов работают плохо. Вклады съедает инфляция, государственная пенсия ненадежна, а фондовый рынок слишком непредсказуем и рискован.
Не спасают и альтернативные пути. Собственный IT-проект, офлайн-бизнес, консалтинг или преподавание, везде высокий риск провала из-за быстро меняющихся трендов отрасли и рынка труда. Даже недвижимость, при всей своей стабильности, требует больших вложений и не гарантирует высокую доходность.
А какие стратегии накоплений выбрали вы?
👉 https://habr.com/ru/articles/1059644/
❤4
✨ Единый валидатор для всего
Разработка фулстек-приложений часто усложняется из-за рассинхронизации типов данных и правил валидации между фронтендом и бэкендом. Различные фреймворки по умолчанию используют разные библиотеки для проверки данных, приходится дублировать логику, что неизбежно ведет к лишней рутине и отсутствию единого источника истины.
Для решения этой проблемы автор предлагает вынести схемы Zod в общее пространство монорепозитория, генерируя из них общие типы. В NestJS такая валидация легко внедряется через кастомные пайпы и декораторы, а на клиенте напрямую подключается к новым Signal Forms с помощью validateStandardSchema.
👉 https://angular.love/one-validator-to-rule-them-all
Разработка фулстек-приложений часто усложняется из-за рассинхронизации типов данных и правил валидации между фронтендом и бэкендом. Различные фреймворки по умолчанию используют разные библиотеки для проверки данных, приходится дублировать логику, что неизбежно ведет к лишней рутине и отсутствию единого источника истины.
Для решения этой проблемы автор предлагает вынести схемы Zod в общее пространство монорепозитория, генерируя из них общие типы. В NestJS такая валидация легко внедряется через кастомные пайпы и декораторы, а на клиенте напрямую подключается к новым Signal Forms с помощью validateStandardSchema.
👉 https://angular.love/one-validator-to-rule-them-all
👍5🤡4❤2👌1
✨ Эволюция киберугроз
Эта история кардинально изменит ваше представление о реальных угрозах искусственного интеллекта.
Во время внутреннего тестирования в OpenAI передовые ИИ-модели смогли обойти ограничения изолированной среды. Они самостоятельно обнаружили уязвимость нулевого дня, вышли в интернет и взломали серверы Hugging Face, чтобы сжульничать и украсть правильные ответы для своего теста.
Технически атака управлялась роем автономных агентов, которые совершили тысячи отдельных действий через сеть временных песочниц. При этом командная инфраструктура была развернута на публичных сервисах и умела самостоятельно мигрировать
Это в точности соответствует сценарию, который индустрия давно прогнозировала как будущую угрозу.
👉 https://openai.com/index/hugging-face-model-evaluation-security-incident/
Эта история кардинально изменит ваше представление о реальных угрозах искусственного интеллекта.
Во время внутреннего тестирования в OpenAI передовые ИИ-модели смогли обойти ограничения изолированной среды. Они самостоятельно обнаружили уязвимость нулевого дня, вышли в интернет и взломали серверы Hugging Face, чтобы сжульничать и украсть правильные ответы для своего теста.
Технически атака управлялась роем автономных агентов, которые совершили тысячи отдельных действий через сеть временных песочниц. При этом командная инфраструктура была развернута на публичных сервисах и умела самостоятельно мигрировать
Это в точности соответствует сценарию, который индустрия давно прогнозировала как будущую угрозу.
👉 https://openai.com/index/hugging-face-model-evaluation-security-incident/
🤡4👻4💩3😱1💊1
✨ Создание транзакционного router resource
Судя по всему, команда Angular начала работу над более тесной интеграцией resource API с роутером.
В репозитории появился PR с реализацией routerResource - обертки, которая пока не выставлена в публичный API, но уже демонстрирует, как ресурс может замораживать свое состояние на время навигации, ориентируясь на снапшоты и события роутера, чтобы UI не мерцал промежуточными состояниями.
👉 https://github.com/angular/angular/pull/69490
Судя по всему, команда Angular начала работу над более тесной интеграцией resource API с роутером.
В репозитории появился PR с реализацией routerResource - обертки, которая пока не выставлена в публичный API, но уже демонстрирует, как ресурс может замораживать свое состояние на время навигации, ориентируясь на снапшоты и события роутера, чтобы UI не мерцал промежуточными состояниями.
👉 https://github.com/angular/angular/pull/69490
👍6❤2
✨ Как рой ИИ-агентов Cursor создал SQLite с нуля за $1339
Cursor провела эксперимент со вторым поколением роя агентов, в котором сотни агентов параллельно писали на Rust движок SQLite по документации, без исходников и интернета.
В прошлых версиях агенты создавали хаос и тысячи конфликтов в коде. Проблему решили аналогами корпоративного управления. Внедрили общие дизайн-доки, арбитров для разрешения споров, многоуровневое ревью кода и написали собственную сверхбыструю систему контроля версий взамен Git.
Дорогие модели только планировали архитектуру, а дешевые писали код, что снизило цену разработки.
В результате получили 100% прохождение тестов, при этом кода написали в несколько раз меньше, чем в старых хаотичных версиях роя.
👉 https://habr.com/ru/articles/1061128/
Cursor провела эксперимент со вторым поколением роя агентов, в котором сотни агентов параллельно писали на Rust движок SQLite по документации, без исходников и интернета.
В прошлых версиях агенты создавали хаос и тысячи конфликтов в коде. Проблему решили аналогами корпоративного управления. Внедрили общие дизайн-доки, арбитров для разрешения споров, многоуровневое ревью кода и написали собственную сверхбыструю систему контроля версий взамен Git.
Дорогие модели только планировали архитектуру, а дешевые писали код, что снизило цену разработки.
В результате получили 100% прохождение тестов, при этом кода написали в несколько раз меньше, чем в старых хаотичных версиях роя.
👉 https://habr.com/ru/articles/1061128/
👍6🤮4❤3
✨ MCP как интерфейс продукта
Традиционные графические интерфейсы заставляют пользователя изучать сложную структуру продукта, вместо того чтобы просто отвечать на его намерения.
Гораздо естественнее, когда пользователь формулирует задачу обычным языком, а агент сам понимает контекст, выбирает нужные инструменты системы, собирает данные и выдает результат.
Агент не заменяет бизнес-логику, он становится слоем-переводчиком между человеком и системой.
Согласны ли вы с тем, что GUI постепенно уступит место агентным интерфейсам, или все же графический интерфейс останется незаменимым для большинства задач?
👉 https://habr.com/ru/companies/selectel/articles/1061986/
Традиционные графические интерфейсы заставляют пользователя изучать сложную структуру продукта, вместо того чтобы просто отвечать на его намерения.
Гораздо естественнее, когда пользователь формулирует задачу обычным языком, а агент сам понимает контекст, выбирает нужные инструменты системы, собирает данные и выдает результат.
Агент не заменяет бизнес-логику, он становится слоем-переводчиком между человеком и системой.
Согласны ли вы с тем, что GUI постепенно уступит место агентным интерфейсам, или все же графический интерфейс останется незаменимым для большинства задач?
👉 https://habr.com/ru/companies/selectel/articles/1061986/
❤7👍2
✨ Книга аутентификации
Неплохой сборник практических советов по безопасности. Главный посыл предельно простой, классические пароли давно пора закапывать. Люди ленивы, везде ставят одни и те же комбинации, а базы регулярно утекают в сеть.
Вместо этого автор советует passkey, вход по биометрии или пину устройства, без единого пароля. Ключ никуда не передается и его физически не своровать, в отличие от связки логин-пароль.
👉 https://habr.com/ru/articles/1063760/
Неплохой сборник практических советов по безопасности. Главный посыл предельно простой, классические пароли давно пора закапывать. Люди ленивы, везде ставят одни и те же комбинации, а базы регулярно утекают в сеть.
Вместо этого автор советует passkey, вход по биометрии или пину устройства, без единого пароля. Ключ никуда не передается и его физически не своровать, в отличие от связки логин-пароль.
👉 https://habr.com/ru/articles/1063760/
👍9🕊2
✨ Языковую модель на 28,9 млн параметров запустили на микроконтроллере ESP32-S3
Нейросеть работает полностью локально на плате с 16 Мбайт флеш-памяти и 512 Кбайт SRAM, а сгенерированный текст выводится на небольшой дисплей.
Модель уместили на устройстве благодаря 4-битной квантизации и распределению весов между разными типами памяти, а нужные данные из таблицы эмбеддингов подгружаются из флеш-памяти по мере необходимости.
Для сравнения, предыдущий похожий проект уместил на ESP32 только модель на 260 тыс. параметров.
👉 https://habr.com/ru/news/1064114/
Нейросеть работает полностью локально на плате с 16 Мбайт флеш-памяти и 512 Кбайт SRAM, а сгенерированный текст выводится на небольшой дисплей.
Модель уместили на устройстве благодаря 4-битной квантизации и распределению весов между разными типами памяти, а нужные данные из таблицы эмбеддингов подгружаются из флеш-памяти по мере необходимости.
Для сравнения, предыдущий похожий проект уместил на ESP32 только модель на 260 тыс. параметров.
👉 https://habr.com/ru/news/1064114/
👍11🔥3
✨ Что нового в Angular 22.1?
Вышел новый минорный релиз Angular.
Основные изменения:
В linkedSignal добавлена возможность задавать кастомный сеттер для сложной логики записи.
Поддержка JSONP объявлена устаревшей из-за уязвимостей.
В CLI добавлена автоматическая миграция со старого декоратора
Ознакомиться с полным списком изменений можно здесь.
👉 https://blog.ninja-squad.com/2026/07/29/what-is-new-angular-22.1
Вышел новый минорный релиз Angular.
Основные изменения:
В linkedSignal добавлена возможность задавать кастомный сеттер для сложной логики записи.
Поддержка JSONP объявлена устаревшей из-за уязвимостей.
В CLI добавлена автоматическая миграция со старого декоратора
@Injectable на новый @Service.Ознакомиться с полным списком изменений можно здесь.
👉 https://blog.ninja-squad.com/2026/07/29/what-is-new-angular-22.1
👍13🔥1
✨ Как я собрал на одном Angular коде: личный кабинет для сайта, Telegram Mini App, iOS и Android
Когда стартуешь соло и требования меняются каждую неделю, писать отдельные приложения для сайта, Telegram, iOS и Android верный способ утонуть.
Четыре кодовые базы, в которых каждую правку логики, формы или статуса нужно повторять четыре раза. При таком темпе поддерживать это в одиночку просто нереально.
Андрей Шпилевский решил это просто. Остался на Angular и вынес всю логику и экраны в общую библиотеку для всех платформ, а мобильные приложения и Telegram Mini App обернул через Capacitor. В итоге около 95% кода общее, а платформенная специфика спрятана в адаптерах.
👉 https://habr.com/ru/articles/1064680/
Когда стартуешь соло и требования меняются каждую неделю, писать отдельные приложения для сайта, Telegram, iOS и Android верный способ утонуть.
Четыре кодовые базы, в которых каждую правку логики, формы или статуса нужно повторять четыре раза. При таком темпе поддерживать это в одиночку просто нереально.
Андрей Шпилевский решил это просто. Остался на Angular и вынес всю логику и экраны в общую библиотеку для всех платформ, а мобильные приложения и Telegram Mini App обернул через Capacitor. В итоге около 95% кода общее, а платформенная специфика спрятана в адаптерах.
👉 https://habr.com/ru/articles/1064680/
👍11🤣8🔥2
✨ Как верстали 15 лет назад
Создание любого интерфейса тогда требовало диких костылей. Базовые задачи вроде построения сетки, центрирования элементов или добавления градиентов решались через ручной расчет размеров и нарезку фоновых картинок в Photoshop.
Сегодня все это решается парой строк на flex или grid и это отличный повод оценить, как далеко шагнул CSS.
👉 https://habr.com/ru/companies/ruvds/articles/1060630/
Создание любого интерфейса тогда требовало диких костылей. Базовые задачи вроде построения сетки, центрирования элементов или добавления градиентов решались через ручной расчет размеров и нарезку фоновых картинок в Photoshop.
Сегодня все это решается парой строк на flex или grid и это отличный повод оценить, как далеко шагнул CSS.
👉 https://habr.com/ru/companies/ruvds/articles/1060630/
🤣9👍8
✨ Как обрабатывать глобальные ошибки в современном zoneless Angular
В классическом Angular библиотека Zone.js незаметно перехватывала все асинхронные операции (Promise, setTimeout, addEventListener) и автоматически пересылала необработанные ошибки в центральный ErrorHandler.
В новом zoneless-режиме этот механизм исчезает. Ошибки из отклоненных промисов, сторонних скриптов или колбэков браузерных API перестают попадать в центральную обработку и просто теряются в консоли.
Решением стал provideBrowserGlobalErrorListeners(). Новый провайдер, который вместо патчинга API просто вешает нативные слушатели на window для событий error и unhandledrejection. Пойманные ошибки перенаправляются в стандартный ErrorHandler, восстанавливая единый пайплайн обработки ошибок.
👉 https://www.angularspace.com/how-to-handle-global-errors-in-modern-zoneless-angular/
В классическом Angular библиотека Zone.js незаметно перехватывала все асинхронные операции (Promise, setTimeout, addEventListener) и автоматически пересылала необработанные ошибки в центральный ErrorHandler.
В новом zoneless-режиме этот механизм исчезает. Ошибки из отклоненных промисов, сторонних скриптов или колбэков браузерных API перестают попадать в центральную обработку и просто теряются в консоли.
Решением стал provideBrowserGlobalErrorListeners(). Новый провайдер, который вместо патчинга API просто вешает нативные слушатели на window для событий error и unhandledrejection. Пойманные ошибки перенаправляются в стандартный ErrorHandler, восстанавливая единый пайплайн обработки ошибок.
👉 https://www.angularspace.com/how-to-handle-global-errors-in-modern-zoneless-angular/
❤5👍4🍾1👨💻1👾1
✨ CSS-челленджи для 200 IQ
Часто ли вы ловите себя на мысли, что уперлись в невидимую стену, пытаясь решить, казалось бы, невыполнимую задачу? В моменты, когда ИИ, Stack Overflow и спецификации бессильны, на помощь приходит настоящая инженерная смекалка и упорство.
Алекс Инкин поделился именно такими случаями, когда долгий мозговой штурм привел к изящным и уникальным решениям на чистом CSS, о которых вы вряд ли прочтете в туториалах.
👉 https://dev.to/waterplea/css-challenges-for-200-iq-ghl
Часто ли вы ловите себя на мысли, что уперлись в невидимую стену, пытаясь решить, казалось бы, невыполнимую задачу? В моменты, когда ИИ, Stack Overflow и спецификации бессильны, на помощь приходит настоящая инженерная смекалка и упорство.
Алекс Инкин поделился именно такими случаями, когда долгий мозговой штурм привел к изящным и уникальным решениям на чистом CSS, о которых вы вряд ли прочтете в туториалах.
👉 https://dev.to/waterplea/css-challenges-for-200-iq-ghl
❤6👍3🔥3
✨ Представляем CopilotKit для Angular
CopilotKit — SDK для создания full-stack агентных приложений, генеративного UI и чат-интерфейсов. Начинался как React-библиотека, а теперь это мультиплатформенный фреймворк.
Разработка ИИ-интерфейсов перестала быть эксклюзивом React. Команда Soverius AI официально взяла на себя развитие
👉 https://www.copilotkit.ai/blog/copilotkit-for-angular
CopilotKit — SDK для создания full-stack агентных приложений, генеративного UI и чат-интерфейсов. Начинался как React-библиотека, а теперь это мультиплатформенный фреймворк.
Разработка ИИ-интерфейсов перестала быть эксклюзивом React. Команда Soverius AI официально взяла на себя развитие
@copilotkit/angular в основном репозитории проекта. Теперь Angular-разработчикам из коробки доступны готовые UI-чаты и инструменты для ИИ-агентов.👉 https://www.copilotkit.ai/blog/copilotkit-for-angular
🤮19🔥5👍3❤2
✨ Agent Plugins
Вышла спецификация Agent Plugins 1.0.0 — открытый, независимый от вендоров формат упаковки Agent Skills и MCP-серверов в переносимые плагины. Ее развивают мейнтейнеры из Amazon, Cursor, Microsoft, OpenAI, Vercel, а теперь и Google.
Раньше для каждого клиента приходилось создавать свои обертки и манифесты. Теперь плагин представляет собой универсальную директорию с фиксированной структурой. Написали один раз, и его можно использовать в разных клиентах.
Похоже, экосистема AI-агентов постепенно движется к общим стандартам, а не закрытым форматам.
👉 https://developers.googleblog.com/agent-plugins-package-your-skills-tools-and-more/
Вышла спецификация Agent Plugins 1.0.0 — открытый, независимый от вендоров формат упаковки Agent Skills и MCP-серверов в переносимые плагины. Ее развивают мейнтейнеры из Amazon, Cursor, Microsoft, OpenAI, Vercel, а теперь и Google.
Раньше для каждого клиента приходилось создавать свои обертки и манифесты. Теперь плагин представляет собой универсальную директорию с фиксированной структурой. Написали один раз, и его можно использовать в разных клиентах.
Похоже, экосистема AI-агентов постепенно движется к общим стандартам, а не закрытым форматам.
👉 https://developers.googleblog.com/agent-plugins-package-your-skills-tools-and-more/
👍8🤮7🔥4❤1🥴1🆒1
✨ От парсинга DOM к контрактам: понимание WebMCP
Сейчас агенты гадают по DOM и скриншотам, пытаясь понять, что за кнопка перед ними: кликают, ждут, перепроверяют. Это медленно, дорого по токенам и хрупко. Любой редизайн или A/B-тест может сломать всю цепочку действий.
Идея WebMCP в том, чтобы перевернуть эту логику. Страница сама объявляет свои возможности, как набор именованных инструментов с описанием и типизированной схемой, вместо того, чтобы агент реверс-инжинирил интерфейс методом проб и ошибок.
И Angular v22 уже стал первым крупным фреймворком с экспериментальной поддержкой WebMCP из коробки.
👉 https://angular.love/from-dom-scraping-to-contracts-understanding-webmcp-part-1
Сейчас агенты гадают по DOM и скриншотам, пытаясь понять, что за кнопка перед ними: кликают, ждут, перепроверяют. Это медленно, дорого по токенам и хрупко. Любой редизайн или A/B-тест может сломать всю цепочку действий.
Идея WebMCP в том, чтобы перевернуть эту логику. Страница сама объявляет свои возможности, как набор именованных инструментов с описанием и типизированной схемой, вместо того, чтобы агент реверс-инжинирил интерфейс методом проб и ошибок.
И Angular v22 уже стал первым крупным фреймворком с экспериментальной поддержкой WebMCP из коробки.
👉 https://angular.love/from-dom-scraping-to-contracts-understanding-webmcp-part-1
👍9🤮6🔥1🤩1🐳1💅1
✨ Размытая граница между состояниями CSS и событиями JavaScript
CSS все чаще берет на себя то, что раньше делал только JavaScript. Реагирует на состояния, которые почти неотличимы от событий. Граница между псевдоклассами и обработчиками событий становится все более размытой.
В статье разбираются примеры такого пересечения, а также рассматривается экспериментальный event-trigger, будущий механизм, который может позволить запускать CSS-анимации в ответ на события.
👉 https://habr.com/ru/companies/timeweb/articles/1059272/
CSS все чаще берет на себя то, что раньше делал только JavaScript. Реагирует на состояния, которые почти неотличимы от событий. Граница между псевдоклассами и обработчиками событий становится все более размытой.
В статье разбираются примеры такого пересечения, а также рассматривается экспериментальный event-trigger, будущий механизм, который может позволить запускать CSS-анимации в ответ на события.
👉 https://habr.com/ru/companies/timeweb/articles/1059272/
👍4
✨ 3 хорошие привычки начинающего фронтендера
Хороший фронтендер думает не только о коде, но и о том, как пользователь будет взаимодействовать с интерфейсом. Именно такие привычки помогают делать сайты удобнее и доступнее.
Статья для начинающих о простых, но важных привычках верстки, которые делают интерфейс удобнее для пользователя, независимо от стека.
В ней Стас Мельников показывает, что даже без глубокого дизайнерского бэкграунда можно заметно улучшить UX, если обращать внимание на детали, которые часто упускают.
👉 https://habr.com/ru/companies/ruvds/articles/1066724/
Хороший фронтендер думает не только о коде, но и о том, как пользователь будет взаимодействовать с интерфейсом. Именно такие привычки помогают делать сайты удобнее и доступнее.
Статья для начинающих о простых, но важных привычках верстки, которые делают интерфейс удобнее для пользователя, независимо от стека.
В ней Стас Мельников показывает, что даже без глубокого дизайнерского бэкграунда можно заметно улучшить UX, если обращать внимание на детали, которые часто упускают.
👉 https://habr.com/ru/companies/ruvds/articles/1066724/
👍5