Введение в UWP
UWP (Universal Windows Platform) представляет собой унифицированную платформу для создания и запуска приложений в Windows 10 и Windows 10 Mobile.
UWP стала результатом эволюции более ранних технологий. Так, с выходом Windows 8 была внедрена новая архитектурная платформа для приложений — Windows Runtime (WinRT), которая позволяла запускать приложения в так называемом режиме Modern (Metro) на десктопах, планшетах. Затем с выходом Windows 8.1 и Windows Phone 8.1 эта технология получила развитие — появились «универсальные приложения», которые можно было запускать сразу Windows 8.1 и WP8.1. И в июле 2015 года официально вышла новая ОС Windows 10. Она использует платформу UWP, которая представляет собой развитие Windows Runtime.
Как подсказывает название платформы, она является универсальной — универсальной для всех устройств экосистемы Windows 10. А это обычные дестопы, планшеты, мобильные устройства, устройства IoT (интернет вещей), Xbox, устройства Surface Hub. И приложение UWP может одинаково работать на всех этих платформах, если на них установлена Windows 10.
Почему UWP?
Программирование под UWP несет ряд преимуществ:
Широта распространения . На текущий момент (апрель 2017) Windows 10 установлена уже более чем на 400 миллионах устройств. На десктопах Windows 10 уже опередила Windows 8/8.1.
Поддержка широкого круга устройств . Десктопы, планшеты, смартфоны, большие планшеты Surface Hub, различные IoT-устройства, в перспективе устройства виртуальной реальности HoloLens — круг устрйоств, на которых может работать Windows 10 действительно широк.
Поддержка разных языков и технологий программирования . UWP-приложения можно создавать с помощью таких языков, как Visual C++, C#, Visual Basic, JavaScript. В качестве технологии для создания графического интерфейса Visual C++, C# и Visual Basic используют XAML, JavaScript применяет HTML. Кроме того, С++ может вместо XAML использовать DirectX. То есть достаточно распространенные и и знакомые многим технологии.
Магазин приложений и удобство распространения . Windows Store представляет собой прекрасное место для распространения UWP-приложений, как платных, так и бесплатных. Сами возможности платформы и магазина Windows Store позволяют использовать разные способы монетизации. Например, можно интегрировать в приложения блоки для показа рекламы через различные SDK. Можно распространять за определенную плату, причем оплату можно гибко настраивать. При необходимости можно встроить предоставление ознакомительной версии, после использования которой пользователь может решить, покупать приложение или нет. И также можно монетизировать по модели freemium, при которой приложение условно бесплатное, а отдельные услуги внутри приложения предоставляются за определенную плату. Причем все эти возможности монетизации обесечиваются встроенными инструментами SDK.
Богатые возможности платформы . UWP многое наследует от Windows Runtime из Windows 8.1 и в то же время предоставляет много новых функцональностей, как, более богатые возможности по интеграции с облаком, использование Cortana, системы уведомлений в Win10 и многое другое.
Что необходимо для разработки под UWP
Для программирования под UWP необходима ОС Windows 10. Все другие операционные системы, как Windows 8.1/8/7, не говоря уже о Windows XP, не подходят !
Также потребуется среда разработки Visual Studio 2017 Community. Это полнофункциональная бесплатная среда разработки, которую можно загрузить с официального сайта по адресу https://www.visualstudio.com/downloads/download-visual-studio-vs.
Также можно использовать версию VS 2015, а все остальные предыдущие версии Visual Studio — 2013, 2012, 2010 и т.д. с UWP не работают.
При установке Visual Studio 2017 в программе установщика необходимо отметить соответствующий пункт:
Перед чем как начать создание приложений, убедитесь, что в центре обновления в Windows 10 установлена соответствующая опция для разработчиков:
И имея Windows 10 и установленную Visual Studio 2017, можно приступать к разработке приложений.
О приложениях UWP для разработчиков WPF
Хотел бы закодировать разработчиков WPF от боязни чего-то нового, рассказав про отличия, которые ожидают их при разработке приложений под универсальную платформу Windows. Так что ставьте банки перед монитором, я начинаю давать установку.
Какие-то изменения в языках программирования и платформах происходят постоянно. Представьте себе на минуту, что выйдет C# версии 10 и все. Это последняя версия. Представили? Я представил. И в моем представлении если это и случится когда-нибудь, то эта последняя версия языка будет регулярно обновляться.
Были «чудесные» времена, когда у меня немного разбегались глаза от различий в коде (даже в коде XAML): WPF, Silverlight, Windows Phone, потом WinRT, а теперь еще и UWP. Сколько разработчиков никогда не путаются? Я думаю, что большинство разработчиков не держат все в памяти. Достаточно держать в памяти основные концепты работы. Когда дело касается кодирования, то используются вспомогательные инструменты вроде IntelliSense, Blend и т.п. Никуда не уйти и от использования сниппетов.
По каким причинам происходят изменения:
1. Где-то сидит вредный дядя, который ждет момента, когда все привыкнут к платформе/среде разработки. И тогда он что-то меняет.
2. Усовершенствования/новый функционал.
3. Отзывы пользователей или разработчиков (не понравилось и все тут). Исправление ошибок.
4. Аппаратная часть совершенствуется. Акцент на энергосбережение, на производительность или же на красивые эффекты.
5. Что-то глобальное. Например, последнее объединение платформ в UWP или что-то вроде «Мы хотим чтобы на C# писали под все платформы сразу, минуя Xamarin, поэтому добавили вам новые аналогичные другим платформам контролы». Кто знает, может через несколько лет будет и такое.
6. Ваш вариант напишите в комментариях.
Для чего разработчикам нужно знание UWP? Да, хотя бы из-за того, что в .Net приложениях можно будет в скором времени использовать API и сервисы UWP. Все это может в скором времени стать возможным с помощью Project Cenntenial.
Так что вполне можно начать знакомиться с новой платформой. Давайте я сделаю небольшой экскурс, описав некоторые отличия.
Начну с того, что приложения UWP обладают кое-чем, чего нет у классических приложений Windows – у них есть App Model. Что такое App Model? Это своеобразный регламент. Описание всех возможностей приложения — его прав доступа, способа установки, обновления, хранения информации и т.п.
У приложений Windows Store, точно так же как и у приложений UWP есть файл манифеста, в котором описаны все возможности и права приложения. Это файл Package.appxmanifest. Его можно редактировать как в графическом редакторе, так и в виде кода XML. Скриншот графического редактора смотрите ниже.
Элементы управления
Если вы помните, то совсем недавно у Windows 8 и 8.1 была Charm panel – волшебная панелька:
Сейчас же вместо нее используются более привычные для WPF разработчиков контролы:
Здесь новым контролом является ContentDialog, который блокирует приложение, примерно так же, как блокирует его MessageBox.
Кроме того в UWP более привычная для разработчиков WP навигация:
Что может показаться интересным, так это то, что некоторые элементы управления могут иметь различный внешний вид при отображении на различных устройствах. Простыми словами, контрол может выглядеть немного иначе, например, при отображении на десктопе и на мобильном устройстве.
В целом, я так полагаю, среднестатистический разработчик уже давно привык большому разнообразию контролов. Освоение новых трудностей вызвать не должно.
Разработка под различные устройства
Постараюсь разобрать то, что для WPF разработчика будет необычным. Например, это то, что при разработке приложений Windows 8.1 можно было в одном решении разрабатывать одновременно и под телефон и под десктоп.
В таком случае создавалось 3 проекта. В приложениях WP и WinRT хранился xaml код «вьюшек» и какой-то особый код под устройства, а в общем проекте хранился общий код xaml и общий для двух проектов код C#.
Сейчас же, так как платформа UWP универсальная, то для каждого типа устройств можно создать папку, в которую можно поместить «вьюшку» — т.е. xaml файл с дизайном под параметры устройства.
Жизненный цикл
Есть старая шутку про формулу-1: «У Ральфа Шумахера два положения педали – включено и выключено. Остальными положениями можно пренебречь».
Этой шуткой я могу немного подколоть классические приложения .Net. Они либо работают, либо не работают. В приложениях Store все немного иначе. У них кроме состояний «Включено/выключено» есть еще и промежуточное состояние «Приостановлено». Жизненный цикл приложений 8.x и UWP отображен на следующей картинке:
Триггеры и фоновые задания
Приложения .Net могут быть либо исполняемыми файлами либо могут быть службами/сервисами. Это совершенно разные виды приложений. То есть не может быть такого, что приложение exe, но при этом оно работает в фоне. Нет, конечно же, приложение может работать в трее. Но фактически получается, что оно запущено и просто свернуто.
Что касается приложений 8.x и UWP, то они могут содержать в себе фоновые задания. Фоновые задания это некоторое подобие сервиса. То есть приложение может не работать, но в системе будет выполняться какая-то задача. Кроме того фоновая задача может «отлавливать» какие-то события в работе системы триггером.
Один из самых популярных триггеров это SystemTrigger. С помощью него приложение может выполнить какой-либо код при наступлении таких событий как: появление или пропажа интернета, изменение состояния сети, подключение или отключение пользователя, получение смс, изменение часовой зоны и т.п.
Также довольно популярны TimeTrigger и MaintenanceTrigger. Оба триггера выполняют какой-либо код с периодичностью в определенный промежуток времени. Промежуток времени должен быть не менее 15 минут. Отличие в то, что TimeTrigger требует регистрации приложения на экране блокировки, а MaintenanceTrigger-у требуется чтобы устройство работало не от батареи, а от сети.
В UWP появилось много новых триггеров. Взять, например такой вот интересный триггер как MediaProcessingTrigger, который позволяет приложению перекодировать мультимедиа в рамках фоновой задачи.
Использование библиотек
Если в классических приложениях вы использовали библиотеки DLL, то в приложениях 8.x и UWP вы сможете использовать как PCL, так и компонент среды выполнения WinMD. В чем отличие?
PCL (portable class library) может быть добавлена приложениям под различные платформы. И под .Net Framework различных версий, и под Windows 8.x и под WP, под UWP и даже под iOS/Android приложения Xamarin. То есть в эту библиотеку можно запихнуть какой-то общий платформонезависимый код.
WinMD может быть использован только под 8.x или UWP. Вне зависимости от языка, на котором написаны приложения, они могут работать с WinMD. Но сам WinMD в случае если он содержит в себе сложные вычисления лучше писать на C++ для достижения наилучшей производительности.
Впрочем, при разработке под UWP вы можете создать и библиотеку классов (DLL).
Работа с данными
В чем еще заключается отличие приложений UWP, так это в том, что они не работают с базами данных напрямую. То есть такие базы данных, как, скажем SQL Server или Oracle, расположенные на сервере организации, будут вам недоступны. Впрочем, это было бы странно, если бы пользователь скачивал из Store приложение, и приложение начинало бы работать с базой SQL Server-а, расположенной на сервере в локальной сети. Но вы сможете работать с данными, используя веб-сервисы. Есть возможность использовать для баз MySQL оракловский Connector/Net, но он на данный момент не поддерживает SSL и потому не особо интересен. Так что лучше не отклоняться от концепта использования сервисов для доступа к данным.
Для хранения информации внутри приложения вы можете использовать SQLite.
Хранения параметров приложения и работа с файлами
Хранение параметров приложения возможно не только на устройстве, но и в облаке. Таким образом, если запускать приложение на различных устройствах, то настройки везде будут одинаковыми.
Следующий небольшой сниппет сохраняет количество вызова кода в облаке:
Если заменить Windows.Storage.ApplicationData.Current.RoamingSettings на Windows.Storage.ApplicationData.Current.LocalSettings, то параметр будет сохранен локально на устройстве.
Настройки могут быть скомпонованы как в составные параметры, так и в контейнеры. Файлы точно так же как и настройки можно хранить как на устройстве в локальной папке, так и в облаке. Но кроме этого есть возможность хранить файлы во временной папке, которая при необходимости может быть очищена системой — ApplicationData.TemporaryFolder.
Кроме того можно получить доступ к папке, которая содержится в приложении с помощью
Windows.ApplicationModel.Package.Current.InstalledLocation
Доступ к файлам, хранящимся на дисках, тоже организован по особой модели. Содержимое папок документов, фотографий, видео и подобных может быть получено с помощью класса KnownFolders, но в таком случае необходима установка разрешений в манифесте. Доступ к какой-либо другой папке возможен только в случае, если пользователь выберет папку сам в процессе работы с приложением. Посещенные папки можно сохранять, дабы при повторном запуске приложения не заставлять пользователя делать лишние действия
Получить после этого последнюю сохраненную папку можно так:
Привязки данных
Как в приложениях WPF, так и в приложениях UWP, а также при разработке под 8.x можно использовать привязки данных –
Эффективные пиксели
Создавая приложение UWP, вы ведете разработку в эффективных пикселях, а не физических. Особый алгоритм масштабирования позволяет добиться того, что шрифт размера в 24 пикселя будет одинаково читаемым и на большом экране PC и на экране телефона.
Таким образом, получается, что разработчик может не заботится о плотности пикселей на различных устройствах или дистанции просмотра. Но он должен позаботиться о том, чтобы на устройствах с высоким разрешением изображения смотрелись качественно. Давайте рассмотрим папку Assets стандартного только что созданного универсального приложения:
Вы можете заметить, что у некоторых изображений имеется постфикс .scale-200. Это значит, что установлен размер масштабирования 200. Для примера возьмем файл Square44x44Logo.scale-200.png – его физический размер 88×88 пикселей. То есть масштаб 200%. Все доступные варианты это – 100, 125, 150, 200, 250, 300, 400.
Пример: если вы заходите создать вариант изображения для устройств с коэффициентом масштабирования 150, то вам нужно создать изображение размера 66×66 и назвать его Square44x44Logo.scale-150.png.
Это касается не только изображений, используемых в описании приложения, но и изображений, которые вы используете в UI.
Что такое Universal Windows Platform (UWP)?
1975
Универсальная платформа Windows (UWP) – это специальная платформа для создания приложений на Windows 10. Вы можете разрабатывать приложения для UWP с помощью всего одного набора API, одного пакета приложений и одного магазина для доступа ко всем устройствам Windows 10 – ПК, планшета, телефона, Xbox, HoloLens, Surface Hub и других. Легче поддерживать несколько размеров экрана, а также различные модели взаимодействия, будь то сенсор, мышь и клавиатура, игровой контроллер или ручка. В основе приложений UWP лежит идея, что пользователи хотят, чтобы их работа, их задачи были мобильными через ВСЕ устройства, чтобы можно было использовать любое устройство, наиболее удобное или производительное для конкретной задачи.
UWP является гибким: вам не нужно использовать C# и XAML, если вы этого не хотите. Вам нравится развиваться в Unity или MonoGame? Предпочитаете JavaScript? Не проблема, используйте все, что хотите. У вас есть настольное приложение C++, которое вы хотите расширить с помощью функций UWP и продавать в магазине? И тут все будет работать.
В итоге вы можете потратить свое время на работу со знакомыми языками программирования, фреймворками и API-интерфейсами, все в одном проекте, и иметь тот же самый код, который работает на огромном диапазоне оборудования Windows из существующих сегодня. После того, как вы написали свое приложение UWP, вы можете опубликовать его в магазине на обозрение всего мира.
Итак, что такое UWP-приложение?
- Существует общая среда API для всех устройств
Основа API-интерфейсов универсальной платформы Windows (UWP) одинакова для всех классов устройства Windows. Если ваше приложение использует только основные API-интерфейсы, оно будет запускаться на любом устройстве Windows 10, независимо от того, планируете ли вы использование настольного ПК, гарнитуры Xbox или наушников Mixed Reality.
Тема связана со специальностями:
- Расширение SDK позволяет вашему приложению делать классные вещи на определенных типах устройств
- Приложения упакованы с использованием формата упаковки .AppX и распространяются из магазина
- Одно хранилище для всех устройств
- Приложения поддерживают адаптивные элементы управления и ввода
Элементы пользовательского интерфейса используют эффективные пиксели, поэтому они могут отображать макет в зависимости от количества пикселей экрана, доступных на устройстве. И они хорошо работают с несколькими типами ввода, такими как клавиатура, мышь, сенсорный экран, ручка и контроллеры Xbox One. Если вам нужно дополнительно адаптировать свой пользовательский интерфейс к определенному размеру экрана или устройству, новые панели макетов и инструменты помогут вам в этом.
Используйте язык, который вы уже знаете
Приложения UWP используют Windows Runtime, собственный API, встроенный в операционную систему. Этот API реализован на C++ и поддерживается на C#, Visual Basic, C++ и JavaScript. Некоторые варианты написания приложений в UWP включают:
Видео курсы по схожей тематике:
Разработка игр для Steam VR c использованием PlayStation VR
Создание адаптивного сайта с Bootstrap 3
- XAML UI и C#, VB или C++ backend
- DirectX UI и C++ backend
- JavaScript и HTML
Microsoft Visual Studio 2017 предоставляет шаблон приложения UWP для каждого языка, который позволяет вам создать единый проект для всех устройств. Когда ваша работа будет завершена, вы можете создать пакет приложений и отправить его в Windows Store из Visual Studio, чтобы сделать ваше приложение доступным для клиентов на любом устройстве Windows 10.
Приложения UWP оживают в Windows
- Живые фрагменты и экран блокировки отображают контекстно-зависимую и своевременную информацию.
- Push-уведомления приносят сигналы в реальном времени, отправляя предупреждения вашему пользователю, когда это необходимо.
- Центр действий – это место, где вы можете организовывать и отображать уведомления и контент, на которые пользователи должны обратить внимание.
- Background — исполнение и триггеры оживляют ваше приложение, когда пользователю это нужно.
- В вашем приложении могут использоваться голосовые и Bluetooth-устройства LE, чтобы помочь пользователям взаимодействовать с окружающим миром.
- Поддержка богатых, цифровых чернил и инновационного набора.
- Cortana добавляет индивидуальность вашему программному обеспечению.
- XAML предоставляет вам инструменты для создания плавных анимированных пользовательских интерфейсов.
Наконец, вы можете использовать данные о роуминге и Windows Credential Locker, чтобы обеспечить постоянный роуминг на всех экранах Windows, где пользователи запускают ваше приложение. Данные о роуминге дают вам простой способ сохранить пользовательские настройки и настройки в облаке, не создавая собственную инфраструктуру синхронизации. И вы можете хранить учетные данные пользователя в хранилище учетных данных, где безопасность и надежность являются главным приоритетом.
Монетизируйте ваше приложение
В Windows вы можете выбрать, как вы будете монетизировать свои приложения на телефонах, планшетах, ПК и других устройствах. Вот несколько способов заработать деньги с помощью вашего приложения и услуг, которые оно предоставляет. Все, что вам нужно сделать, это выбрать то, что лучше подходит для вас:
Бесплатные вебинары по схожей тематике:
Как стать UI/UX дизайнером
Как правильно создать CV Junior разработчику
Увлекательное путешествие в страну динамического программирования
- Платная загрузка – это самый простой вариант. Просто назовите цену.
- Система нескольких пробных попыток позволит пользователям оценить ваше приложение перед его покупкой. Это обеспечит более легкую конверсию, чем более традиционные варианты «freemium».
- Используйте скидки для привлечения внимания к своим приложениям.
- Также доступны покупки и реклама в приложении.
Как начать?
Более подробный обзор UWP читайте в официальном Руководстве по приложениям для универсальной платформы Windows. Затем ознакомьтесь с настройкой Get set up, чтобы загрузить инструменты, необходимые для начала создания приложений, и напишите свое первое приложение!
Записки IT специалиста
У Microsoft была мечта о Windows 8, которая включала бы универсальные приложения Windows, распространяющиеся на телефоны, планшеты, ПК и даже консоли Xbox. План состоял в том, чтобы разработчики могли написать одно приложение для всех этих устройств, и оно волшебным образом работало бы везде. Эта мечта начала разваливаться после провала Windows Phone, с тех пор прошлом много времени, и похоже, что теперь все закончено.
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном курсе по администрированию MikroTik. Автор курса, сертифицированный тренер MikroTik Дмитрий Скоромнов, лично проверяет лабораторные работы и контролирует прогресс каждого своего студента. В три раза больше информации, чем в вендорской программе MTCNA, более 20 часов практики и доступ навсегда.
Microsoft потратила годы на то, чтобы подтолкнуть разработчиков к созданию специальных приложений для универсальной платформы Windows (Universal Windows Platform, UWP), но сегодня она забила последний гвоздь в гроб UWP.
Компания наконец-то разрешила разработчикам добавлять полностью нативные игры Win32 в Microsoft Store, а это значит, что многие игры, публикуемые разработчиками в других популярных магазинах, таких как Steam, теперь не нужно перестраивать для UWP.
«Мы понимаем, что Win32 — это формат приложений, который любят использовать разработчики игр, а геймеры любят играть, поэтому мы рады сообщить, что мы обеспечим полную поддержку нативных игр Win32 для Microsoft Store в Windows», — пояснил глава Microsoft по играм Фил Спенсер. «Это откроет больше возможностей как для разработчиков, так и для геймеров, предоставляя возможности контроля и настройки которые они ожидают от открытой игровой экосистемы Windows».
Фил Спенсер, глава игрового подразделения Microsoft
Это большой шаг вперед для магазина приложений Windows, учитывая, что игры являются одними из самых загружаемых программ из магазинов. Ранее разработчики были вынуждены публиковать игры для Windows 10 через универсальную платформу Windows, которая просто не имеет того уровня возможностей, которые привыкли видеть в Windows на протяжении многих лет.
Недавно Microsoft объявила о своих планах по переводу браузера Edge на движок Chromium и отказе от UWP, чтобы сделать его доступным для Windows 7, Windows 8 и macOS. Джо Бельфиоре из Microsoft признался в интервью The Verge в начале прошлого месяца, что UWP только «вставляла палки в колеса» для Edge. «Дело не в том, что UWP — это плохо, но UWP не является зрелой 35-летней платформой, для которой написано огромное количество приложений», — сказал тогда Бельфиоре.
Я слышал много историй, когда инженеры и разработчики Microsoft жаловались на то, что UWP накладывает ограничения на свои приложения, и сторонним разработчикам часто приходилось выбирать между созданием приложения UWP для Windows 10 или традиционным настольным приложением, которое будет работать в Windows 7, Windows 8 и Windows 10.
Джо Бельфиоре, вице-президент Microsoft и руководитель разработки Windows
Microsoft постоянно расширяла свое определение UWP, чтобы позволить разработчикам переупаковывать настольные приложения в Microsoft Store, но первоначальное видение приложений нового стиля, которые будут работать на ПК, телефонах, планшетах, Xbox и HoloLens становилось все более маловероятным.
Microsoft также приостановила работы над своей версией Office с поддержкой сенсорного ввода, предпочитая вместо этого сосредоточиться на облачных решениях, iOS, Android и настольных приложениях. Office всегда был центральным элементом UWP и хорошим примером того, как можно создать большое и требовательное приложение на новой платформе. Microsoft наконец прислушалась к разработчикам и больше не пытается навязывать им UWP.
«Вы сказали, что хотите, чтобы мы продолжили разделять многие части универсальной платформы, чтобы их можно было применять отдельно», — пояснил Кевин Галло, руководитель платформы Microsoft для разработчиков Windows, в начале прошлого месяца. Это означает, что со временем разработчики смогут использовать некоторые из положительных сторон UWP.
В отдельном интервью ZDNet Галло рассказал, что «к тому времени, когда мы закончим, останутся только «приложения для Windows». Еще не все готово, но компания стремится сделать каждую функцию UWP доступной для разработчиков.
В конечном итоге, это хорошая новость как для разработчиков, так и для пользователей Windows. Теперь мы должны увидеть больше игр в Магазине Microsoft, которые работают так, как того ожидают геймеры, и, надеемся, больше приложений. Магазин Windows был полон барахла на протяжении многих лет, и Microsoft с трудом привлекала туда разработчиков.
Старый подход Microsoft к магазину вызывал резкую критику закрытой платформы в Windows 10 и попыток компании заставить разработчиков распространять приложения через Microsoft Store. Microsoft даже создала версии Windows S и Windows RT в которых установка обычных приложений была заблокирована.
Новый шаг Microsoft по добавлению своих игр в Steam — это хороший признак того, что Спенсер меняет внутри Microsoft больше, чем просто консоль Xbox. Теперь нам нужно подождать, чтобы увидеть, что разработчики приложений и игр на этот раз сделают с Microsoft Store и платформой приложений Windows, которая станет гораздо менее ограничена.
Автор: Том Уоррен (Tom Warren)
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном курсе по администрированию MikroTik. Автор курса, сертифицированный тренер MikroTik Дмитрий Скоромнов, лично проверяет лабораторные работы и контролирует прогресс каждого своего студента. В три раза больше информации, чем в вендорской программе MTCNA, более 20 часов практики и доступ навсегда.
Помогла статья? Поддержи автора и новые статьи будут выходить чаще:
Или подпишись на наш Телеграм-канал: