diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000..5c459fd2f
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,39 @@
+BasedOnStyle: WebKit
+AccessModifierOffset: '-4'
+AlignAfterOpenBracket: Align
+AlignConsecutiveMacros: 'true'
+AlignTrailingComments: 'true'
+AllowAllArgumentsOnNextLine: 'true'
+AllowAllParametersOfDeclarationOnNextLine: 'true'
+AllowShortBlocksOnASingleLine: 'false'
+AllowShortCaseLabelsOnASingleLine: 'true'
+AllowShortEnumsOnASingleLine: 'false'
+AllowShortFunctionsOnASingleLine: None
+AlwaysBreakTemplateDeclarations: 'No'
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Custom
+BraceWrapping:
+    AfterClass: true
+    AfterControlStatement: false
+    AfterEnum: false
+    AfterFunction: true
+    AfterNamespace: true
+    AfterObjCDeclaration: false
+    AfterStruct: true
+    AfterUnion: false
+    BeforeCatch: false
+    BeforeElse: false
+    IndentBraces: false
+BreakConstructorInitializers: BeforeColon
+ColumnLimit: '120'
+CommentPragmas: '"^!|^:"'
+ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
+ConstructorInitializerIndentWidth: '4'
+ContinuationIndentWidth: '8'
+IndentPPDirectives: BeforeHash
+NamespaceIndentation: All
+PenaltyExcessCharacter: '10'
+PointerAlignment: Right
+SortIncludes: 'true'
+SpaceAfterTemplateKeyword: 'false'
+Standard: Auto
diff --git a/.clang-format-ignore b/.clang-format-ignore
new file mode 100644
index 000000000..4019357f0
--- /dev/null
+++ b/.clang-format-ignore
@@ -0,0 +1,20 @@
+/client/3rd
+/client/3rd-prebuild
+/client/android
+/client/cmake
+/client/core/serialization
+/client/daemon
+/client/fonts
+/client/images
+/client/ios
+/client/mozilla
+/client/platforms/dummy
+/client/platforms/linux
+/client/platforms/macos
+/client/platforms/windows
+/client/server_scripts
+/client/translations
+/deploy
+/docs
+/metadata
+/service/src
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 64a4986d1..35e740b0d 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -217,7 +217,11 @@ jobs:
         export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/ios/bin"
         export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos"
         export PATH=$PATH:~/go/bin
-        sh deploy/build_ios.sh
+        sh deploy/build_ios.sh | \
+          sed -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/d' | \
+          sed -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/d' | \
+          sed -e '/-DPROD_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DPROD_AGW_PUBLIC_KEY/d' | \
+          sed -e '/-DDEV_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DDEV_AGW_PUBLIC_KEY/d'
       env:
         IOS_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }}
         IOS_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }}
@@ -256,7 +260,7 @@ jobs:
     - name: 'Setup xcode'
       uses: maxim-lobanov/setup-xcode@v1
       with:
-        xcode-version: '14.3.1'
+        xcode-version: '15.4.0'
 
     - name: 'Install Qt'
       uses: jurplel/install-qt-action@v3
@@ -331,7 +335,8 @@ jobs:
         arch: 'linux_gcc_64'
         modules: ${{ env.QT_MODULES }}
         dir: ${{ runner.temp }}
-        extra: '--external 7z --base ${{ env.QT_MIRROR }}'
+        py7zrversion: '==0.22.*'
+        extra: '--base ${{ env.QT_MIRROR }}'
 
     - name: 'Install android_x86_64 Qt'
       uses: jurplel/install-qt-action@v4
@@ -342,7 +347,8 @@ jobs:
         arch: 'android_x86_64'
         modules: ${{ env.QT_MODULES }}
         dir: ${{ runner.temp }}
-        extra: '--external 7z --base ${{ env.QT_MIRROR }}'
+        py7zrversion: '==0.22.*'
+        extra: '--base ${{ env.QT_MIRROR }}'
 
     - name: 'Install android_x86 Qt'
       uses: jurplel/install-qt-action@v4
@@ -353,7 +359,8 @@ jobs:
         arch: 'android_x86'
         modules: ${{ env.QT_MODULES }}
         dir: ${{ runner.temp }}
-        extra: '--external 7z --base ${{ env.QT_MIRROR }}'
+        py7zrversion: '==0.22.*'
+        extra: '--base ${{ env.QT_MIRROR }}'
 
     - name: 'Install android_armv7 Qt'
       uses: jurplel/install-qt-action@v4
@@ -364,7 +371,8 @@ jobs:
         arch: 'android_armv7'
         modules: ${{ env.QT_MODULES }}
         dir: ${{ runner.temp }}
-        extra: '--external 7z --base ${{ env.QT_MIRROR }}'
+        py7zrversion: '==0.22.*'
+        extra: '--base ${{ env.QT_MIRROR }}'
 
     - name: 'Install android_arm64_v8a Qt'
       uses: jurplel/install-qt-action@v4
@@ -375,7 +383,8 @@ jobs:
         arch: 'android_arm64_v8a'
         modules: ${{ env.QT_MODULES }}
         dir: ${{ runner.temp }}
-        extra: '--external 7z --base ${{ env.QT_MIRROR }}'
+        py7zrversion: '==0.22.*'
+        extra: '--base ${{ env.QT_MIRROR }}'
 
     - name: 'Grant execute permission for qt-cmake'
       shell: bash
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b5e64e324..cb6956316 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
 
 set(PROJECT AmneziaVPN)
 
-project(${PROJECT} VERSION 4.8.2.3
+project(${PROJECT} VERSION 4.8.2.4
         DESCRIPTION "AmneziaVPN"
         HOMEPAGE_URL "https://amnezia.org/"
 )
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
 set(RELEASE_DATE "${CURRENT_DATE}")
 
 set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
-set(APP_ANDROID_VERSION_CODE 2069)
+set(APP_ANDROID_VERSION_CODE 2071)
 
 if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
     set(MZ_PLATFORM_NAME "linux")
diff --git a/README.md b/README.md
index eed800f5d..8f8878081 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,29 @@
 # Amnezia VPN
-## _The best client for self-hosted VPN_
+
+### _The best client for self-hosted VPN_
+
 
 [![Build Status](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml/badge.svg?branch=dev)](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
 [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
 
-Amnezia is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
+### [English]([https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md](https://github.com/amnezia-vpn/amnezia-client/tree/dev?tab=readme-ov-file#)) | [Русский](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md)
+
 
-![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)
+[Amnezia](https://amnezia.org) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
 
-<br>
+[![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org)
 
-<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download.png" width="150" style="max-width: 100%;"></a>
-<a href="https://play.google.com/store/search?q=amnezia+vpn&c=apps"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/play.png" width="150" style="max-width: 100%;"></a>
-<a href="https://apps.apple.com/us/app/amneziavpn/id1600529900"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/apl.png" width="150" style="max-width: 100%;"></a>
+### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/kldscp/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
 
-[Alternative download link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org/downloads)
+> [!TIP]
+> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/kldscp/amnezia.org).
+
+<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
+<a href="https://storage.googleapis.com/kldscp/amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
 
 [All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
 
-<br>
+<br/>
 
 <a href="https://www.testiny.io"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/testiny.png" height="28px"></a>
 
@@ -33,7 +38,8 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
 
 ## Links
 
-- [https://amnezia.org](https://amnezia.org) - project website | [Alternative link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org)
+- [https://amnezia.org](https://amnezia.org) - Project website | [Alternative link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org)
+- [https://docs.amnezia.org](https://docs.amnezia.org) - Documentation
 - [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit  
 - [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Telegram support channel (English) 
 - [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi) 
@@ -182,8 +188,8 @@ Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn
 Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p <br>
 USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4 <br>
 USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d <br>
-XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3  
-
+XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3 <br> 
+TON: UQDpU1CyKRmg7L8mNScKk9FRc2SlESuI7N-Hby4nX-CcVmns
 ## Acknowledgments
 
 This project is tested with BrowserStack.
diff --git a/README_RU.md b/README_RU.md
new file mode 100644
index 000000000..59518f4b8
--- /dev/null
+++ b/README_RU.md
@@ -0,0 +1,181 @@
+# Amnezia VPN
+
+### _Лучший клиент для создания VPN на собственном сервере_
+
+[![Build Status](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml/badge.svg?branch=dev)](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
+[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
+
+### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
+[AmneziaVPN](https://amnezia.org) — это open sourse VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
+
+[![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org)
+
+### [Сайт](https://amnezia.org) | [Зеркало на сайт](https://storage.googleapis.com/kldscp/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
+
+> [!TIP]
+> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/kldscp/amnezia.org).
+
+<a href="https://storage.googleapis.com/kldscp/amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
+
+
+[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
+
+<br/>
+
+<a href="https://www.testiny.io"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/testiny.png" height="28px"></a>
+
+## Особенности
+
+- Простой в использовании — введите IP-адрес, SSH-логин и пароль, и Amnezia автоматически установит VPN-контейнеры Docker на ваш сервер и подключится к VPN.
+- Классические VPN-протоколы: OpenVPN, WireGuard и IKEv2.
+- Протоколы с маскировкой трафика (обфускацией): OpenVPN с плагином [Cloak](https://github.com/cbeuw/Cloak), Shadowsocks (OpenVPN over Shadowsocks), [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) and XRay.
+- Поддержка Split Tunneling — добавляйте любые сайты или приложения в список, чтобы включить VPN только для них.
+- Поддерживает платформы: Windows, MacOS, Linux, Android, iOS.
+- Поддержка конфигурации протокола AmneziaWG на [бета-прошивке Keenetic](https://docs.keenetic.com/ua/air/kn-1611/en/6319-latest-development-release.html#UUID-186c4108-5afd-c10b-f38a-cdff6c17fab3_section-idm33192196168192-improved).
+
+## Ссылки
+
+- [https://amnezia.org](https://amnezia.org) - Веб-сайт проекта | [Альтернативная ссылка (зеркало)](https://storage.googleapis.com/kldscp/amnezia.org)
+- [https://docs.amnezia.org](https://docs.amnezia.org) - Документация
+- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit  
+- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Канал поддржки в Telegram (Английский)
+- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Канал поддржки в Telegram (Фарси)
+- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Канал поддржки в Telegram (Мьянма) 
+- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Канал поддржки в Telegram  (Русский)
+- [https://vpnpay.io/en/amnezia-premium/](https://vpnpay.io/en/amnezia-premium/) - Amnezia Premium | [Зеркало](https://storage.googleapis.com/kldscp/vpnpay.io/ru/amnezia-premium\)
+
+## Технологии
+
+AmneziaVPN использует несколько проектов с открытым исходным кодом:
+
+- [OpenSSL](https://www.openssl.org/)
+- [OpenVPN](https://openvpn.net/)
+- [Shadowsocks](https://shadowsocks.org/)
+- [Qt](https://www.qt.io/)
+- [LibSsh](https://libssh.org)
+- и другие...
+
+## Проверка исходного кода
+После клонирования репозитория обязательно загрузите все подмодули.
+
+```bash
+git submodule update --init --recursive
+```
+
+
+## Разработка
+Хотите внести свой вклад? Добро пожаловать!
+
+### Помощь с переводами
+
+Загрузите самые актуальные файлы перевода.
+
+Перейдите на [вкладку "Actions"](https://github.com/amnezia-vpn/amnezia-client/actions?query=is%3Asuccess+branch%3Adev), нажмите на первую строку. Затем прокрутите вниз до раздела "Artifacts" и скачайте "AmneziaVPN_translations".
+
+Распакуйте этот файл. Каждый файл с расширением *.ts содержит строки для соответствующего языка.
+
+Переведите или исправьте строки в одном или нескольких файлах *.ts и загрузите их обратно в этот репозиторий в папку ``client/translations``. Это можно сделать через веб-интерфейс или любым другим знакомым вам способом.
+
+### Сборка исходного кода и деплой
+Проверьте папку deploy для скриптов сборки.
+
+### Как собрать iOS-приложение из исходного кода на MacOS
+1. Убедитесь, что у вас установлен XCode версии 14 или выше.
+2. Для генерации проекта XCode используется QT. Требуется версия QT 6.6.2. Установите QT для MacOS здесь или через QT Online Installer. Необходимые модули:
+- MacOS
+- iOS
+- Модуль совместимости с Qt 5
+- Qt Shader Tools
+- Дополнительные библиотеки:
+ - Qt Image Formats
+ - Qt Multimedia
+ - Qt Remote Objects
+
+   
+3. Установите CMake, если это необходимо. Рекомендуемая версия — 3.25. Скачать CMake можно здесь.
+4. Установите Go версии >= v1.16. Если Go ещё не установлен, скачайте его с  [официального сайта](https://golang.org/dl/) или используйте Homebrew. Установите gomobile:
+
+```bash
+export PATH=$PATH:~/go/bin
+go install golang.org/x/mobile/cmd/gomobile@latest
+gomobile init
+```
+
+5. Соберите проект:
+```bash
+export QT_BIN_DIR="<PATH-TO-QT-FOLDER>/Qt/<QT-VERSION>/ios/bin"
+export QT_MACOS_ROOT_DIR="<PATH-TO-QT-FOLDER>/Qt/<QT-VERSION>/macos"
+export QT_IOS_BIN=$QT_BIN_DIR
+export PATH=$PATH:~/go/bin
+mkdir build-ios
+$QT_IOS_BIN/qt-cmake . -B build-ios -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR
+```
+Замените <PATH-TO-QT-FOLDER> и <QT-VERSION> на ваши значения.
+
+Если появляется ошибка gomobile: command not found, убедитесь, что PATH настроен на папку bin, где установлен gomobile:
+```bash
+export PATH=$(PATH):/path/to/GOPATH/bin
+```
+
+6. Откройте проект в XCode. Теперь вы можете тестировать, архивировать или публиковать приложение.
+   
+Если сборка завершится с ошибкой:
+```
+make: *** 
+[$(PROJECTDIR)/client/build/AmneziaVPN.build/Debug-iphoneos/wireguard-go-bridge/goroot/.prepared] 
+Error 1
+```
+Добавьте пользовательскую переменную PATH в настройки сборки для целей AmneziaVPN и WireGuardNetworkExtension с ключом `PATH` и значением `${PATH}/path/to/bin/folder/with/go/executable`, e.g. `${PATH}:/usr/local/go/bin`.
+
+Если ошибка повторяется на Mac с M1, установите версию CMake для архитектуры ARM:
+```
+arch -arm64 brew install cmake
+```
+
+ При первой попытке сборка может завершиться с ошибкой source files not found. Это происходит из-за параллельной компиляции зависимостей в XCode. Просто перезапустите сборку.
+
+
+## Как собрать Android-приложение
+Сборка тестировалась на MacOS. Требования:
+- JDK 11
+- Android SDK 33
+- CMake 3.25.0
+  
+Установите QT, QT Creator и Android Studio.
+Настройте QT Creator:
+
+- В меню QT Creator перейдите в  `QT Creator` -> `Preferences` -> `Devices` ->`Android`.
+- Укажите путь к JDK 11.
+- Укажите путь к Android SDK (`$ANDROID_HOME`)
+
+Если вы сталкиваетесь с ошибками, связанными с отсутствием SDK или сообщением «SDK manager not running», их нельзя исправить просто корректировкой путей. Если у вас есть несколько свободных гигабайт на диске, вы можете позволить Qt Creator установить все необходимые компоненты, выбрав пустую папку для расположения Android SDK и нажав кнопку **Set Up SDK**. Учтите: это установит второй Android SDK и NDK на вашем компьютере!
+
+Убедитесь, что настроена правильная версия CMake: перейдите в **Qt Creator -> Preferences** и в боковом меню выберите пункт **Kits**. В центральной части окна, на вкладке **Kits**, найдите запись для инструмента **CMake Tool**. Если выбранная по умолчанию версия CMake ниже 3.25.0, установите на свою систему CMake версии 3.25.0 или выше, а затем выберите опцию **System CMake at <путь>** из выпадающего списка. Если этот пункт отсутствует, это может означать, что вы еще не установили CMake, или Qt Creator не смог найти путь к нему. В таком случае в окне **Preferences** перейдите в боковое меню **CMake**, затем во вкладку **Tools** в центральной части окна и нажмите кнопку **Add**, чтобы указать путь к установленному CMake.
+
+Убедитесь, что для вашего проекта выбрана Android Platform SDK 33: в главном окне на боковой панели выберите пункт **Projects**, и слева вы увидите раздел **Build & Run**, показывающий различные целевые Android-платформы. Вы можете выбрать любую из них, так как настройка проекта Amnezia VPN разработана таким образом, чтобы все Android-цели могли быть собраны. Перейдите в подраздел **Build** и прокрутите центральную часть окна до раздела **Build Steps**. Нажмите **Details** в заголовке **Build Android APK** (кнопка **Details** может быть скрыта, если окно Qt Creator не запущено в полноэкранном режиме!). Вот здесь выберите **android-33** в качестве Android Build Platform SDK.
+
+### Разработка Android-компонентов
+
+После сборки QT Creator копирует проект в отдельную папку, например, `build-amnezia-client-Android_Qt_<version>_Clang_<architecture>-<BuildType>`. Для разработки Android-компонентов откройте сгенерированный проект в Android Studio, указав папку `build-amnezia-client-Android_Qt_<version>_Clang_<architecture>-<BuildType>/client/android-build` в качестве корневой.
+Изменения в сгенерированном проекте нужно вручную перенести в репозиторий. После этого можно коммитить изменения.
+Если возникают проблемы со сборкой в QT Creator после работы в Android Studio, выполните команду `./gradlew clean` в корневой папке сгенерированного проекта (`<path>/client/android-build/.`).
+
+
+## Лицензия
+
+GPL v3.0
+
+## Донаты
+
+Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn)
+
+Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p <br>
+USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4 <br>
+USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d <br>
+XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3 <br> 
+TON: UQDpU1CyKRmg7L8mNScKk9FRc2SlESuI7N-Hby4nX-CcVmns
+
+## Благодарности
+
+Этот проект тестируется с помощью BrowserStack.
+Мы выражаем благодарность [BrowserStack](https://www.browserstack.com) за поддержку нашего проекта.
diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml
index 179def863..9e44e0221 100644
--- a/client/android/AndroidManifest.xml
+++ b/client/android/AndroidManifest.xml
@@ -20,7 +20,7 @@
 
     <uses-permission android:name="android.permission.INTERNET" />
     <!-- To request network state -->
-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" android:maxSdkVersion="30" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
index e93834f4f..80cab96d3 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
@@ -1,11 +1,12 @@
 package org.amnezia.vpn.protocol.wireguard
 
 import android.net.VpnService.Builder
-import java.io.IOException
-import java.util.Locale
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.launch
 import org.amnezia.awg.GoBackend
 import org.amnezia.vpn.protocol.Protocol
 import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
@@ -27,6 +28,8 @@ open class Wireguard : Protocol() {
 
     private var tunnelHandle: Int = -1
     protected open val ifName: String = "amn0"
+    private lateinit var scope: CoroutineScope
+    private var statusJob: Job? = null
 
     override val statistics: Statistics
         get() {
@@ -49,46 +52,17 @@ open class Wireguard : Protocol() {
 
     override fun internalInit() {
         if (!isInitialized) loadSharedLibrary(context, "wg-go")
+        if (this::scope.isInitialized) {
+            scope.cancel()
+        }
+        scope = CoroutineScope(Dispatchers.IO)
     }
 
     override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
         val wireguardConfig = parseConfig(config)
-        val startTime = System.currentTimeMillis()
         start(wireguardConfig, vpnBuilder, protect)
-        waitForConnection(startTime)
-        state.value = CONNECTED
     }
 
-    private suspend fun waitForConnection(startTime: Long) {
-        Log.d(TAG, "Waiting for connection")
-        withContext(Dispatchers.IO) {
-            val time = String.format(Locale.ROOT,"%.3f", startTime / 1000.0)
-            try {
-                delay(1000)
-                var log = getLogcat(time)
-                Log.v(TAG, "First waiting log: $log")
-                // check that there is a connection log,
-                // to avoid infinite connection
-                if (!log.contains("Attaching to interface")) {
-                    Log.w(TAG, "Logs do not contain a connection log")
-                    return@withContext
-                }
-                while (!log.contains("Received handshake response")) {
-                    delay(1000)
-                    log = getLogcat(time)
-                }
-            } catch (e: IOException) {
-                Log.e(TAG, "Failed to get logcat: $e")
-            }
-        }
-    }
-
-    private fun getLogcat(time: String): String =
-        ProcessBuilder("logcat", "--buffer=main", "--format=raw", "*:S AmneziaWG/awg0", "-t", time)
-            .redirectErrorStream(true)
-            .start()
-            .inputStream.reader().readText()
-
     protected open fun parseConfig(config: JSONObject): WireguardConfig {
         val configData = config.getJSONObject("wireguard_config_data")
         return WireguardConfig.build {
@@ -178,6 +152,43 @@ open class Wireguard : Protocol() {
             tunnelHandle = -1
             throw VpnStartException("Protect VPN interface: permission not granted or revoked")
         }
+        launchStatusJob()
+    }
+
+    private fun launchStatusJob() {
+        Log.d(TAG, "Launch status job")
+        statusJob = scope.launch {
+            while (true) {
+                val lastHandshake = getLastHandshake()
+                Log.v(TAG, "lastHandshake=$lastHandshake")
+                if (lastHandshake == 0L) {
+                    delay(1000)
+                    continue
+                }
+                if (lastHandshake == -2L || lastHandshake > 0L) state.value = CONNECTED
+                else if (lastHandshake == -1L) state.value = DISCONNECTED
+                statusJob = null
+                break
+            }
+        }
+    }
+
+    private fun getLastHandshake(): Long {
+        if (tunnelHandle == -1) {
+            Log.e(TAG, "Trying to get config of a non-existent tunnel")
+            return -1
+        }
+        val config = GoBackend.awgGetConfig(tunnelHandle)
+        if (config == null) {
+            Log.e(TAG, "Failed to get tunnel config")
+            return -2
+        }
+        val lastHandshake = config.lines().find { it.startsWith("last_handshake_time_sec=") }?.substring(24)?.toLong()
+        if (lastHandshake == null) {
+            Log.e(TAG, "Failed to get last_handshake_time_sec")
+            return -2
+        }
+        return lastHandshake
     }
 
     override fun stopVpn() {
@@ -185,6 +196,8 @@ open class Wireguard : Protocol() {
             Log.w(TAG, "Tunnel already down")
             return
         }
+        statusJob?.cancel()
+        statusJob = null
         val handleToClose = tunnelHandle
         tunnelHandle = -1
         GoBackend.awgTurnOff(handleToClose)
diff --git a/client/configurators/xray_configurator.cpp b/client/configurators/xray_configurator.cpp
index 786da47c5..514aa8211 100644
--- a/client/configurators/xray_configurator.cpp
+++ b/client/configurators/xray_configurator.cpp
@@ -3,38 +3,169 @@
 #include <QFile>
 #include <QJsonDocument>
 #include <QJsonObject>
+#include <QUuid>
+#include "logger.h"
 
 #include "containers/containers_defs.h"
 #include "core/controllers/serverController.h"
 #include "core/scripts_registry.h"
 
+namespace {
+Logger logger("XrayConfigurator");
+}
+
 XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, QObject *parent)
     : ConfiguratorBase(settings, serverController, parent)
 {
 }
 
-QString XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
-                                       ErrorCode &errorCode)
+QString XrayConfigurator::prepareServerConfig(const ServerCredentials &credentials, DockerContainer container,
+                                               const QJsonObject &containerConfig, ErrorCode &errorCode)
+{
+    // Generate new UUID for client
+    QString clientId = QUuid::createUuid().toString(QUuid::WithoutBraces);
+    
+    // Get current server config
+    QString currentConfig = m_serverController->getTextFileFromContainer(
+        container, credentials, amnezia::protocols::xray::serverConfigPath, errorCode);
+    
+    if (errorCode != ErrorCode::NoError) {
+        logger.error() << "Failed to get server config file";
+        return "";
+    }
+
+    // Parse current config as JSON
+    QJsonDocument doc = QJsonDocument::fromJson(currentConfig.toUtf8());
+    if (doc.isNull() || !doc.isObject()) {
+        logger.error() << "Failed to parse server config JSON";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
+
+    QJsonObject serverConfig = doc.object();
+    
+    // Validate server config structure
+    if (!serverConfig.contains("inbounds")) {
+        logger.error() << "Server config missing 'inbounds' field";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
+
+    QJsonArray inbounds = serverConfig["inbounds"].toArray();
+    if (inbounds.isEmpty()) {
+        logger.error() << "Server config has empty 'inbounds' array";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
+    
+    QJsonObject inbound = inbounds[0].toObject();
+    if (!inbound.contains("settings")) {
+        logger.error() << "Inbound missing 'settings' field";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
+
+    QJsonObject settings = inbound["settings"].toObject();
+    if (!settings.contains("clients")) {
+        logger.error() << "Settings missing 'clients' field";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
+
+    QJsonArray clients = settings["clients"].toArray();
+    
+    // Create configuration for new client
+    QJsonObject clientConfig {
+        {"id", clientId},
+        {"flow", "xtls-rprx-vision"}
+    };
+    
+    clients.append(clientConfig);
+    
+    // Update config
+    settings["clients"] = clients;
+    inbound["settings"] = settings;
+    inbounds[0] = inbound;
+    serverConfig["inbounds"] = inbounds;
+    
+    // Save updated config to server
+    QString updatedConfig = QJsonDocument(serverConfig).toJson();
+    errorCode = m_serverController->uploadTextFileToContainer(
+        container, 
+        credentials, 
+        updatedConfig,
+        amnezia::protocols::xray::serverConfigPath,
+        libssh::ScpOverwriteMode::ScpOverwriteExisting
+    );
+    if (errorCode != ErrorCode::NoError) {
+        logger.error() << "Failed to upload updated config";
+        return "";
+    }
+
+    // Restart container
+    QString restartScript = QString("sudo docker restart $CONTAINER_NAME");
+    errorCode = m_serverController->runScript(
+        credentials, 
+        m_serverController->replaceVars(restartScript, m_serverController->genVarsForScript(credentials, container))
+    );
+
+    if (errorCode != ErrorCode::NoError) {
+        logger.error() << "Failed to restart container";
+        return "";
+    }
+
+    return clientId;
+}
+
+QString XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
+                                       const QJsonObject &containerConfig, ErrorCode &errorCode)
 {
+    // Get client ID from prepareServerConfig
+    QString xrayClientId = prepareServerConfig(credentials, container, containerConfig, errorCode);
+    if (errorCode != ErrorCode::NoError || xrayClientId.isEmpty()) {
+        logger.error() << "Failed to prepare server config";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
+
     QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container),
                                                      m_serverController->genVarsForScript(credentials, container, containerConfig));
+    
+    if (config.isEmpty()) {
+        logger.error() << "Failed to get config template";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
 
     QString xrayPublicKey =
             m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::PublicKeyPath, errorCode);
+    if (errorCode != ErrorCode::NoError || xrayPublicKey.isEmpty()) {
+        logger.error() << "Failed to get public key";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
     xrayPublicKey.replace("\n", "");
-
-    QString xrayUuid = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, errorCode);
-    xrayUuid.replace("\n", "");
-
+    
     QString xrayShortId =
             m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::shortidPath, errorCode);
+    if (errorCode != ErrorCode::NoError || xrayShortId.isEmpty()) {
+        logger.error() << "Failed to get short ID";
+        errorCode = ErrorCode::InternalError;
+        return "";
+    }
     xrayShortId.replace("\n", "");
 
-    if (errorCode != ErrorCode::NoError) {
+    // Validate all required variables are present
+    if (!config.contains("$XRAY_CLIENT_ID") || !config.contains("$XRAY_PUBLIC_KEY") || !config.contains("$XRAY_SHORT_ID")) {
+        logger.error() << "Config template missing required variables:"
+                      << "XRAY_CLIENT_ID:" << !config.contains("$XRAY_CLIENT_ID")
+                      << "XRAY_PUBLIC_KEY:" << !config.contains("$XRAY_PUBLIC_KEY")
+                      << "XRAY_SHORT_ID:" << !config.contains("$XRAY_SHORT_ID");
+        errorCode = ErrorCode::InternalError;
         return "";
     }
 
-    config.replace("$XRAY_CLIENT_ID", xrayUuid);
+    config.replace("$XRAY_CLIENT_ID", xrayClientId);
     config.replace("$XRAY_PUBLIC_KEY", xrayPublicKey);
     config.replace("$XRAY_SHORT_ID", xrayShortId);
 
diff --git a/client/configurators/xray_configurator.h b/client/configurators/xray_configurator.h
index 2acfdf71d..8ed4e7752 100644
--- a/client/configurators/xray_configurator.h
+++ b/client/configurators/xray_configurator.h
@@ -14,6 +14,10 @@ class XrayConfigurator : public ConfiguratorBase
 
     QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
                          ErrorCode &errorCode);
+
+private:
+    QString prepareServerConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
+                                ErrorCode &errorCode);
 };
 
 #endif // XRAY_CONFIGURATOR_H
diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp
index 75a3f93cb..6562632a9 100644
--- a/client/core/controllers/apiController.cpp
+++ b/client/core/controllers/apiController.cpp
@@ -50,6 +50,8 @@ namespace
         constexpr char authData[] = "auth_data";
     }
 
+    const int requestTimeoutMsecs = 12 * 1000; // 12 secs
+
     ErrorCode checkErrors(const QList<QSslError> &sslErrors, QNetworkReply *reply)
     {
         if (!sslErrors.empty()) {
@@ -177,7 +179,7 @@ void ApiController::fillServerConfig(const QString &protocol, const ApiControlle
 QStringList ApiController::getProxyUrls()
 {
     QNetworkRequest request;
-    request.setTransferTimeout(7000);
+    request.setTransferTimeout(requestTimeoutMsecs);
     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 
     QEventLoop wait;
@@ -280,7 +282,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
 
     if (serverConfig.value(config_key::configVersion).toInt()) {
         QNetworkRequest request;
-        request.setTransferTimeout(7000);
+        request.setTransferTimeout(requestTimeoutMsecs);
         request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
         request.setRawHeader("Authorization", "Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
         QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
@@ -336,7 +338,7 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
 #endif
 
     QNetworkRequest request;
-    request.setTransferTimeout(7000);
+    request.setTransferTimeout(requestTimeoutMsecs);
     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 
     request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
@@ -377,6 +379,13 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
 
     auto errorCode = checkErrors(sslErrors, reply);
     reply->deleteLater();
+
+    if (errorCode == ErrorCode::NoError) {
+        if (!responseBody.contains("services")) {
+            return ErrorCode::ApiServicesMissingError;
+        }
+    }
+
     return errorCode;
 }
 
@@ -390,7 +399,7 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
 #endif
 
     QNetworkRequest request;
-    request.setTransferTimeout(7000);
+    request.setTransferTimeout(requestTimeoutMsecs);
     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 
     request.setUrl(QString("%1v1/config").arg(m_gatewayEndpoint));
diff --git a/client/core/defs.h b/client/core/defs.h
index d00d347b1..c0db2e127 100644
--- a/client/core/defs.h
+++ b/client/core/defs.h
@@ -109,6 +109,7 @@ namespace amnezia
         ApiConfigSslError = 1104,
         ApiMissingAgwPublicKey = 1105,
         ApiConfigDecryptionError = 1106,
+        ApiServicesMissingError = 1107,
 
         // QFile errors
         OpenError = 1200,
diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp
index 495346063..70f433c62 100644
--- a/client/core/errorstrings.cpp
+++ b/client/core/errorstrings.cpp
@@ -63,7 +63,8 @@ QString errorString(ErrorCode code) {
     case (ErrorCode::ApiConfigTimeoutError): errorMessage = QObject::tr("Server response timeout on api request"); break;
     case (ErrorCode::ApiMissingAgwPublicKey): errorMessage = QObject::tr("Missing AGW public key"); break;
     case (ErrorCode::ApiConfigDecryptionError): errorMessage = QObject::tr("Failed to decrypt response payload"); break;
-      
+    case (ErrorCode::ApiServicesMissingError): errorMessage = QObject::tr("Missing list of available services"); break;
+
     // QFile errors
     case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
     case(ErrorCode::ReadError): errorMessage = QObject::tr("QFile error: An error occurred when reading from the file"); break;
diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts
index 2fb21259e..c0d855b25 100644
--- a/client/translations/amneziavpn_ru_RU.ts
+++ b/client/translations/amneziavpn_ru_RU.ts
@@ -2679,7 +2679,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
     <message>
         <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
         <source>Where to get connection data, step-by-step instructions for buying a VPS</source>
-        <translation>Где взять данные для подключения, пошаговые инстуркции по покупке VPS</translation>
+        <translation>Где взять данные для подключения, пошаговые инструкции по покупке VPS</translation>
     </message>
     <message>
         <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
diff --git a/client/ui/controllers/connectionController.cpp b/client/ui/controllers/connectionController.cpp
index f8516f6e3..f9491d4e6 100644
--- a/client/ui/controllers/connectionController.cpp
+++ b/client/ui/controllers/connectionController.cpp
@@ -55,7 +55,7 @@ void ConnectionController::openConnection()
         && !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
         emit updateApiConfigFromGateway();
     } else if (configVersion && m_serversModel->isApiKeyExpired(serverIndex)) {
-        qDebug() << "attempt to update api config by end_date event";
+        qDebug() << "attempt to update api config by expires_at event";
         if (configVersion == ApiConfigSources::Telegram) {
             emit updateApiConfigFromTelegram();
         } else {
diff --git a/client/ui/controllers/exportController.cpp b/client/ui/controllers/exportController.cpp
index 2690b5b1e..8681406e9 100644
--- a/client/ui/controllers/exportController.cpp
+++ b/client/ui/controllers/exportController.cpp
@@ -121,9 +121,8 @@ ErrorCode ExportController::generateNativeConfig(const DockerContainer container
 
     jsonNativeConfig = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
 
-    if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg) {
-        auto clientId = jsonNativeConfig.value(config_key::clientId).toString();
-        errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials, serverController);
+    if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg || protocol == Proto::Xray) {
+        errorCode = m_clientManagementModel->appendClient(jsonNativeConfig, clientName, container, credentials, serverController);
     }
     return errorCode;
 }
@@ -248,10 +247,10 @@ void ExportController::generateCloakConfig()
     emit exportConfigChanged();
 }
 
-void ExportController::generateXrayConfig()
+void ExportController::generateXrayConfig(const QString &clientName)
 {
     QJsonObject nativeConfig;
-    ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, "", Proto::Xray, nativeConfig);
+    ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, clientName, Proto::Xray, nativeConfig);
     if (errorCode) {
         emit exportErrorOccurred(errorCode);
         return;
diff --git a/client/ui/controllers/exportController.h b/client/ui/controllers/exportController.h
index b031ea393..a2c9fcfaf 100644
--- a/client/ui/controllers/exportController.h
+++ b/client/ui/controllers/exportController.h
@@ -28,7 +28,7 @@ public slots:
     void generateAwgConfig(const QString &clientName);
     void generateShadowSocksConfig();
     void generateCloakConfig();
-    void generateXrayConfig();
+    void generateXrayConfig(const QString &clientName);
 
     QString getConfig();
     QString getNativeConfigString();
diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp
index 306e7f38a..ae0804cb7 100755
--- a/client/ui/controllers/installController.cpp
+++ b/client/ui/controllers/installController.cpp
@@ -848,7 +848,6 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
 
     newServerConfig.insert(configKey::apiConfig, newApiConfig);
     newServerConfig.insert(configKey::authData, authData);
-    newServerConfig.insert(config_key::crc, serverConfig.value(config_key::crc));
     m_serversModel->editServer(newServerConfig, serverIndex);
 
     if (reloadServiceConfig) {
diff --git a/client/ui/models/apiServicesModel.cpp b/client/ui/models/apiServicesModel.cpp
index 2a87bde3f..81a10f873 100644
--- a/client/ui/models/apiServicesModel.cpp
+++ b/client/ui/models/apiServicesModel.cpp
@@ -27,6 +27,9 @@ namespace
         constexpr char storeEndpoint[] = "store_endpoint";
 
         constexpr char isAvailable[] = "is_available";
+
+        constexpr char subscription[] = "subscription";
+        constexpr char endDate[] = "end_date";
     }
 
     namespace serviceType
@@ -51,23 +54,23 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
     if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
         return QVariant();
 
-    QJsonObject service = m_services.at(index.row()).toObject();
-    QJsonObject serviceInfo = service.value(configKey::serviceInfo).toObject();
-    auto serviceType = service.value(configKey::serviceType).toString();
+    auto apiServiceData = m_services.at(index.row());
+    auto serviceType = apiServiceData.type;
+    auto isServiceAvailable = apiServiceData.isServiceAvailable;
 
     switch (role) {
     case NameRole: {
-        return serviceInfo.value(configKey::name).toString();
+        return apiServiceData.serviceInfo.name;
     }
     case CardDescriptionRole: {
-        auto speed = serviceInfo.value(configKey::speed).toString();
+        auto speed = apiServiceData.serviceInfo.speed;
         if (serviceType == serviceType::amneziaPremium) {
             return tr("Classic VPN for comfortable work, downloading large files and watching videos. "
                       "Works for any sites. Speed up to %1 MBit/s")
                     .arg(speed);
         } else if (serviceType == serviceType::amneziaFree){
             QString description = tr("VPN to access blocked sites in regions with high levels of Internet censorship. ");
-            if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) {
+            if (isServiceAvailable) {
                 description += tr("<p><a style=\"color: #EB5757;\">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a>");
             }
             return description;
@@ -83,25 +86,24 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
     }
     case IsServiceAvailableRole: {
         if (serviceType == serviceType::amneziaFree) {
-            if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) {
+            if (isServiceAvailable) {
                 return false;
             }
         }
         return true;
     }
     case SpeedRole: {
-        auto speed = serviceInfo.value(configKey::speed).toString();
-        return tr("%1 MBit/s").arg(speed);
+        return tr("%1 MBit/s").arg(apiServiceData.serviceInfo.speed);
     }
-    case WorkPeriodRole: {
-        auto timelimit = serviceInfo.value(configKey::timelimit).toString();
-        if (timelimit == "0") {
+    case TimeLimitRole: {
+        auto timeLimit = apiServiceData.serviceInfo.timeLimit;
+        if (timeLimit == "0") {
             return "";
         }
-        return tr("%1 days").arg(timelimit);
+        return tr("%1 days").arg(timeLimit);
     }
     case RegionRole: {
-        return serviceInfo.value(configKey::region).toString();
+        return apiServiceData.serviceInfo.region;
     }
     case FeaturesRole: {
         if (serviceType == serviceType::amneziaPremium) {
@@ -113,12 +115,15 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
         }
     }
     case PriceRole: {
-        auto price = serviceInfo.value(configKey::price).toString();
+        auto price = apiServiceData.serviceInfo.price;
         if (price == "free") {
             return tr("Free");
         }
         return tr("%1 $/month").arg(price);
     }
+    case EndDateRole: {
+        return QDateTime::fromString(apiServiceData.subscription.endDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy");
+    }
     }
 
     return QVariant();
@@ -128,15 +133,18 @@ void ApiServicesModel::updateModel(const QJsonObject &data)
 {
     beginResetModel();
 
+    m_services.clear();
+
     m_countryCode = data.value(configKey::userCountryCode).toString();
-    m_services = data.value(configKey::services).toArray();
-    if (m_services.isEmpty()) {
-        QJsonObject service;
-        service.insert(configKey::serviceInfo, data.value(configKey::serviceInfo));
-        service.insert(configKey::serviceType, data.value(configKey::serviceType));
+    auto services = data.value(configKey::services).toArray();
 
-        m_services.push_back(service);
+    if (services.isEmpty()) {
+        m_services.push_back(getApiServicesData(data));
         m_selectedServiceIndex = 0;
+    } else {
+        for (const auto &service : services) {
+            m_services.push_back(getApiServicesData(service.toObject()));
+        }
     }
 
     endResetModel();
@@ -149,32 +157,32 @@ void ApiServicesModel::setServiceIndex(const int index)
 
 QJsonObject ApiServicesModel::getSelectedServiceInfo()
 {
-    QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
-    return service.value(configKey::serviceInfo).toObject();
+    auto service = m_services.at(m_selectedServiceIndex);
+    return service.serviceInfo.object;
 }
 
 QString ApiServicesModel::getSelectedServiceType()
 {
-    QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
-    return service.value(configKey::serviceType).toString();
+    auto service = m_services.at(m_selectedServiceIndex);
+    return service.type;
 }
 
 QString ApiServicesModel::getSelectedServiceProtocol()
 {
-    QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
-    return service.value(configKey::serviceProtocol).toString();
+    auto service = m_services.at(m_selectedServiceIndex);
+    return service.protocol;
 }
 
 QString ApiServicesModel::getSelectedServiceName()
 {
-    auto modelIndex = index(m_selectedServiceIndex, 0);
-    return data(modelIndex, ApiServicesModel::Roles::NameRole).toString();
+    auto service = m_services.at(m_selectedServiceIndex);
+    return service.serviceInfo.name;
 }
 
 QJsonArray ApiServicesModel::getSelectedServiceCountries()
 {
-    QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
-    return service.value(configKey::availableCountries).toArray();
+    auto service = m_services.at(m_selectedServiceIndex);
+    return service.availableCountries;
 }
 
 QString ApiServicesModel::getCountryCode()
@@ -184,8 +192,8 @@ QString ApiServicesModel::getCountryCode()
 
 QString ApiServicesModel::getStoreEndpoint()
 {
-    QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
-    return service.value(configKey::storeEndpoint).toString();
+    auto service = m_services.at(m_selectedServiceIndex);
+    return service.storeEndpoint;
 }
 
 QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
@@ -209,10 +217,46 @@ QHash<int, QByteArray> ApiServicesModel::roleNames() const
     roles[ServiceDescriptionRole] = "serviceDescription";
     roles[IsServiceAvailableRole] = "isServiceAvailable";
     roles[SpeedRole] = "speed";
-    roles[WorkPeriodRole] = "workPeriod";
+    roles[TimeLimitRole] = "timeLimit";
     roles[RegionRole] = "region";
     roles[FeaturesRole] = "features";
     roles[PriceRole] = "price";
+    roles[EndDateRole] = "endDate";
 
     return roles;
 }
+
+ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJsonObject &data)
+{
+    auto serviceInfo =  data.value(configKey::serviceInfo).toObject();
+    auto serviceType = data.value(configKey::serviceType).toString();
+    auto serviceProtocol = data.value(configKey::serviceProtocol).toString();
+    auto availableCountries = data.value(configKey::availableCountries).toArray();
+
+    auto subscriptionObject = data.value(configKey::subscription).toObject();
+
+    ApiServicesData serviceData;
+    serviceData.serviceInfo.name = serviceInfo.value(configKey::name).toString();
+    serviceData.serviceInfo.price = serviceInfo.value(configKey::price).toString();
+    serviceData.serviceInfo.region = serviceInfo.value(configKey::region).toString();
+    serviceData.serviceInfo.speed = serviceInfo.value(configKey::speed).toString();
+    serviceData.serviceInfo.timeLimit = serviceInfo.value(configKey::timelimit).toString();
+
+    serviceData.type = serviceType;
+    serviceData.protocol = serviceProtocol;
+
+    serviceData.storeEndpoint = serviceInfo.value(configKey::storeEndpoint).toString();
+
+    if (serviceInfo.value(configKey::isAvailable).isBool()) {
+        serviceData.isServiceAvailable = data.value(configKey::isAvailable).toBool();
+    } else {
+        serviceData.isServiceAvailable = true;
+    }
+
+    serviceData.serviceInfo.object = serviceInfo;
+    serviceData.availableCountries = availableCountries;
+
+    serviceData.subscription.endDate = subscriptionObject.value(configKey::endDate).toString();
+
+    return serviceData;
+}
diff --git a/client/ui/models/apiServicesModel.h b/client/ui/models/apiServicesModel.h
index 499189401..c96a49abc 100644
--- a/client/ui/models/apiServicesModel.h
+++ b/client/ui/models/apiServicesModel.h
@@ -3,6 +3,7 @@
 
 #include <QAbstractListModel>
 #include <QJsonArray>
+#include <QJsonObject>
 
 class ApiServicesModel : public QAbstractListModel
 {
@@ -15,10 +16,11 @@ class ApiServicesModel : public QAbstractListModel
         ServiceDescriptionRole,
         IsServiceAvailableRole,
         SpeedRole,
-        WorkPeriodRole,
+        TimeLimitRole,
         RegionRole,
         FeaturesRole,
-        PriceRole
+        PriceRole,
+        EndDateRole
     };
 
     explicit ApiServicesModel(QObject *parent = nullptr);
@@ -48,8 +50,40 @@ public slots:
     QHash<int, QByteArray> roleNames() const override;
 
 private:
+    struct ServiceInfo
+    {
+        QString name;
+        QString speed;
+        QString timeLimit;
+        QString region;
+        QString price;
+
+        QJsonObject object;
+    };
+
+    struct Subscription
+    {
+        QString endDate;
+    };
+
+    struct ApiServicesData
+    {
+        bool isServiceAvailable;
+
+        QString type;
+        QString protocol;
+        QString storeEndpoint;
+
+        ServiceInfo serviceInfo;
+        Subscription subscription;
+
+        QJsonArray availableCountries;
+    };
+
+    ApiServicesData getApiServicesData(const QJsonObject &data);
+
     QString m_countryCode;
-    QJsonArray m_services;
+    QVector<ApiServicesData> m_services;
 
     int m_selectedServiceIndex;
 };
diff --git a/client/ui/models/clientManagementModel.cpp b/client/ui/models/clientManagementModel.cpp
index 7445d60fb..f07eae712 100644
--- a/client/ui/models/clientManagementModel.cpp
+++ b/client/ui/models/clientManagementModel.cpp
@@ -106,6 +106,8 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
             error = getOpenVpnClients(container, credentials, serverController, count);
         } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
             error = getWireGuardClients(container, credentials, serverController, count);
+        } else if (container == DockerContainer::Xray) {
+            error = getXrayClients(container, credentials, serverController, count);
         }
         if (error != ErrorCode::NoError) {
             endResetModel();
@@ -239,6 +241,68 @@ ErrorCode ClientManagementModel::getWireGuardClients(const DockerContainer conta
     }
     return error;
 }
+ErrorCode ClientManagementModel::getXrayClients(const DockerContainer container, const ServerCredentials& credentials,
+                                                const QSharedPointer<ServerController> &serverController, int &count)
+{
+    ErrorCode error = ErrorCode::NoError;
+
+    const QString serverConfigPath = amnezia::protocols::xray::serverConfigPath;
+    const QString configString = serverController->getTextFileFromContainer(container, credentials, serverConfigPath, error);
+    if (error != ErrorCode::NoError) {
+        logger.error() << "Failed to get the xray server config file from the server";
+        return error;
+    }
+
+    QJsonDocument serverConfig = QJsonDocument::fromJson(configString.toUtf8());
+    if (serverConfig.isNull()) {
+        logger.error() << "Failed to parse xray server config JSON";
+        return ErrorCode::InternalError;
+    }
+
+    if (!serverConfig.object().contains("inbounds") || serverConfig.object()["inbounds"].toArray().isEmpty()) {
+        logger.error() << "Invalid xray server config structure";
+        return ErrorCode::InternalError;
+    }
+
+    const QJsonObject inbound = serverConfig.object()["inbounds"].toArray()[0].toObject();
+    if (!inbound.contains("settings")) {
+        logger.error() << "Missing settings in xray inbound config";
+        return ErrorCode::InternalError;
+    }
+
+    const QJsonObject settings = inbound["settings"].toObject();
+    if (!settings.contains("clients")) {
+        logger.error() << "Missing clients in xray settings config"; 
+        return ErrorCode::InternalError;
+    }
+
+    const QJsonArray clients = settings["clients"].toArray();
+    for (const auto &clientValue : clients) {
+        const QJsonObject clientObj = clientValue.toObject();
+        if (!clientObj.contains("id")) {
+            logger.error() << "Missing id in xray client config";
+            continue;
+        }
+        QString clientId = clientObj["id"].toString();
+        
+        QString xrayDefaultUuid = serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, error);
+        xrayDefaultUuid.replace("\n", "");
+
+        if (!isClientExists(clientId) && clientId != xrayDefaultUuid) {
+            QJsonObject client;
+            client[configKey::clientId] = clientId;
+
+            QJsonObject userData;
+            userData[configKey::clientName] = QString("Client %1").arg(count);
+            client[configKey::userData] = userData;
+
+            m_clientsTable.push_back(client);
+            count++;
+        }
+    }
+
+    return error;
+}
 
 ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const ServerCredentials &credentials,
                                         const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data)
@@ -326,17 +390,67 @@ ErrorCode ClientManagementModel::appendClient(const DockerContainer container, c
                                               const QSharedPointer<ServerController> &serverController)
 {
     Proto protocol;
-    if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
-        protocol = Proto::OpenVpn;
-    } else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
-        protocol = ContainerProps::defaultProtocol(container);
-    } else {
-        return ErrorCode::NoError;
+    switch (container) {
+        case DockerContainer::ShadowSocks:
+        case DockerContainer::Cloak:
+            protocol = Proto::OpenVpn;
+            break;
+        case DockerContainer::OpenVpn:
+        case DockerContainer::WireGuard:
+        case DockerContainer::Awg:
+        case DockerContainer::Xray:
+            protocol = ContainerProps::defaultProtocol(container);
+            break;
+        default:
+            return ErrorCode::NoError;
     }
 
     auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
+    return appendClient(protocolConfig, clientName, container, credentials, serverController);
+}
 
-    return appendClient(protocolConfig.value(config_key::clientId).toString(), clientName, container, credentials, serverController);
+ErrorCode ClientManagementModel::appendClient(QJsonObject &protocolConfig, const QString &clientName, const DockerContainer container,
+                                              const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController)
+{
+    QString clientId;
+    if (container == DockerContainer::Xray) {
+        if (!protocolConfig.contains("outbounds")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonArray outbounds = protocolConfig.value("outbounds").toArray();
+        if (outbounds.isEmpty()) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject outbound = outbounds[0].toObject();
+        if (!outbound.contains("settings")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject settings = outbound["settings"].toObject();
+        if (!settings.contains("vnext")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonArray vnext = settings["vnext"].toArray();
+        if (vnext.isEmpty()) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject vnextObj = vnext[0].toObject();
+        if (!vnextObj.contains("users")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonArray users = vnextObj["users"].toArray();
+        if (users.isEmpty()) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject user = users[0].toObject();
+        if (!user.contains("id")) {
+            return ErrorCode::InternalError;
+        }
+        clientId = user["id"].toString();
+    } else {
+        clientId = protocolConfig.value(config_key::clientId).toString();
+    }
+    
+    return appendClient(clientId, clientName, container, credentials, serverController);
 }
 
 ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
@@ -422,10 +536,27 @@ ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContain
     auto client = m_clientsTable.at(row).toObject();
     QString clientId = client.value(configKey::clientId).toString();
 
-    if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
-        errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
-    } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
-        errorCode = revokeWireGuard(row, container, credentials, serverController);
+    switch(container)
+    {
+        case DockerContainer::OpenVpn:
+        case DockerContainer::ShadowSocks:
+        case DockerContainer::Cloak: {
+            errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
+            break;
+        }
+        case DockerContainer::WireGuard:
+        case DockerContainer::Awg: {
+            errorCode = revokeWireGuard(row, container, credentials, serverController);
+            break;
+        }
+        case DockerContainer::Xray: {
+            errorCode = revokeXray(row, container, credentials, serverController);
+            break;
+        }
+        default: {
+            logger.error() << "Internal error: received unexpected container type";
+            return ErrorCode::InternalError;
+        }
     }
 
     if (errorCode == ErrorCode::NoError) {
@@ -463,19 +594,69 @@ ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig
     }
 
     Proto protocol;
-    if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
-        protocol = Proto::OpenVpn;
-    } else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
-        protocol = ContainerProps::defaultProtocol(container);
-    } else {
-        return ErrorCode::NoError;
+
+    switch(container)
+    {
+        case DockerContainer::ShadowSocks:
+        case DockerContainer::Cloak: {
+            protocol = Proto::OpenVpn;
+            break;
+        }
+        case DockerContainer::OpenVpn:
+        case DockerContainer::WireGuard:
+        case DockerContainer::Awg:
+        case DockerContainer::Xray: {
+            protocol = ContainerProps::defaultProtocol(container);
+            break;
+        }
+        default: {
+            logger.error() << "Internal error: received unexpected container type";
+            return ErrorCode::InternalError;
+        }
     }
 
     auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
 
+    QString clientId;
+    if (container == DockerContainer::Xray) {
+        if (!protocolConfig.contains("outbounds")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonArray outbounds = protocolConfig.value("outbounds").toArray();
+        if (outbounds.isEmpty()) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject outbound = outbounds[0].toObject();
+        if (!outbound.contains("settings")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject settings = outbound["settings"].toObject();
+        if (!settings.contains("vnext")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonArray vnext = settings["vnext"].toArray();
+        if (vnext.isEmpty()) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject vnextObj = vnext[0].toObject();
+        if (!vnextObj.contains("users")) {
+            return ErrorCode::InternalError;
+        }
+        QJsonArray users = vnextObj["users"].toArray();
+        if (users.isEmpty()) {
+            return ErrorCode::InternalError;
+        }
+        QJsonObject user = users[0].toObject();
+        if (!user.contains("id")) {
+            return ErrorCode::InternalError;
+        }
+        clientId = user["id"].toString();
+    } else {
+        clientId = protocolConfig.value(config_key::clientId).toString();
+    }
+
     int row;
     bool clientExists = false;
-    QString clientId = protocolConfig.value(config_key::clientId).toString();
     for (row = 0; row < rowCount(); row++) {
         auto client = m_clientsTable.at(row).toObject();
         if (clientId == client.value(configKey::clientId).toString()) {
@@ -487,11 +668,28 @@ ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig
         return errorCode;
     }
 
-    if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
+    switch (container)
+    {
+    case DockerContainer::OpenVpn:
+    case DockerContainer::ShadowSocks:
+    case DockerContainer::Cloak: {
         errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
-    } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
+        break;
+    }
+    case DockerContainer::WireGuard:
+    case DockerContainer::Awg: {
         errorCode = revokeWireGuard(row, container, credentials, serverController);
+        break;
+    }
+    case DockerContainer::Xray: {
+        errorCode = revokeXray(row, container, credentials, serverController);
+        break;
     }
+    default:
+        logger.error() << "Internal error: received unexpected container type";
+        return ErrorCode::InternalError;
+    }
+
     return errorCode;
 }
 
@@ -594,6 +792,117 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
     return ErrorCode::NoError;
 }
 
+ErrorCode ClientManagementModel::revokeXray(const int row,
+                                            const DockerContainer container,
+                                            const ServerCredentials &credentials,
+                                            const QSharedPointer<ServerController> &serverController)
+{
+    ErrorCode error = ErrorCode::NoError;
+
+    // Get server config
+    const QString serverConfigPath = amnezia::protocols::xray::serverConfigPath;
+    const QString configString = serverController->getTextFileFromContainer(container, credentials, serverConfigPath, error);
+    if (error != ErrorCode::NoError) {
+        logger.error() << "Failed to get the xray server config file";
+        return error;
+    }
+
+    QJsonDocument serverConfig = QJsonDocument::fromJson(configString.toUtf8());
+    if (serverConfig.isNull()) {
+        logger.error() << "Failed to parse xray server config JSON";
+        return ErrorCode::InternalError;
+    }
+
+    // Get client ID to remove
+    auto client = m_clientsTable.at(row).toObject();
+    QString clientId = client.value(configKey::clientId).toString();
+
+    // Remove client from server config
+    QJsonObject configObj = serverConfig.object();
+    if (!configObj.contains("inbounds")) {
+        logger.error() << "Missing inbounds in xray config";
+        return ErrorCode::InternalError;
+    }
+
+    QJsonArray inbounds = configObj["inbounds"].toArray();
+    if (inbounds.isEmpty()) {
+        logger.error() << "Empty inbounds array in xray config";
+        return ErrorCode::InternalError;
+    }
+
+    QJsonObject inbound = inbounds[0].toObject();
+    if (!inbound.contains("settings")) {
+        logger.error() << "Missing settings in xray inbound config";
+        return ErrorCode::InternalError;
+    }
+
+    QJsonObject settings = inbound["settings"].toObject();
+    if (!settings.contains("clients")) {
+        logger.error() << "Missing clients in xray settings";
+        return ErrorCode::InternalError;
+    }
+
+    QJsonArray clients = settings["clients"].toArray();
+    if (clients.isEmpty()) {
+        logger.error() << "Empty clients array in xray config";
+        return ErrorCode::InternalError;
+    }
+
+    for (int i = 0; i < clients.size(); ++i) {
+        QJsonObject clientObj = clients[i].toObject();
+        if (clientObj.contains("id") && clientObj["id"].toString() == clientId) {
+            clients.removeAt(i);
+            break;
+        }
+    }
+
+    // Update server config
+    settings["clients"] = clients;
+    inbound["settings"] = settings;
+    inbounds[0] = inbound;
+    configObj["inbounds"] = inbounds;
+
+    // Upload updated config
+    error = serverController->uploadTextFileToContainer(
+        container, 
+        credentials,
+        QJsonDocument(configObj).toJson(),
+        serverConfigPath
+    );
+    if (error != ErrorCode::NoError) {
+        logger.error() << "Failed to upload updated xray config";
+        return error;
+    }
+
+    // Remove from local table
+    beginRemoveRows(QModelIndex(), row, row);
+    m_clientsTable.removeAt(row);
+    endRemoveRows();
+
+    // Update clients table file on server
+    const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
+    QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable")
+        .arg(ContainerProps::containerTypeToString(container));
+
+    error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
+    if (error != ErrorCode::NoError) {
+        logger.error() << "Failed to upload the clientsTable file";
+    }
+
+    // Restart container
+    QString restartScript = QString("sudo docker restart $CONTAINER_NAME");
+    error = serverController->runScript(
+        credentials, 
+        serverController->replaceVars(restartScript, serverController->genVarsForScript(credentials, container))
+    );
+    if (error != ErrorCode::NoError) {
+        logger.error() << "Failed to restart xray container";
+        return error;
+    }
+
+    return error;
+}
+
 QHash<int, QByteArray> ClientManagementModel::roleNames() const
 {
     QHash<int, QByteArray> roles;
@@ -604,4 +913,4 @@ QHash<int, QByteArray> ClientManagementModel::roleNames() const
     roles[DataSentRole] = "dataSent";
     roles[AllowedIpsRole] = "allowedIps";
     return roles;
-}
+}
\ No newline at end of file
diff --git a/client/ui/models/clientManagementModel.h b/client/ui/models/clientManagementModel.h
index 60132abe2..989120a9e 100644
--- a/client/ui/models/clientManagementModel.h
+++ b/client/ui/models/clientManagementModel.h
@@ -40,6 +40,8 @@ public slots:
                           const QSharedPointer<ServerController> &serverController);
     ErrorCode appendClient(const DockerContainer container, const ServerCredentials &credentials, const QJsonObject &containerConfig,
                            const QString &clientName, const QSharedPointer<ServerController> &serverController);
+    ErrorCode appendClient(QJsonObject &protocolConfig, const QString &clientName,const DockerContainer container,
+                           const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
     ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
                            const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
     ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, const ServerCredentials &credentials,
@@ -64,11 +66,15 @@ public slots:
                             const QSharedPointer<ServerController> &serverController);
     ErrorCode revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
                               const QSharedPointer<ServerController> &serverController);
+    ErrorCode revokeXray(const int row, const DockerContainer container, const ServerCredentials &credentials,
+                         const QSharedPointer<ServerController> &serverController);
 
     ErrorCode getOpenVpnClients(const DockerContainer container, const ServerCredentials &credentials,
                                 const QSharedPointer<ServerController> &serverController, int &count);
     ErrorCode getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
                                   const QSharedPointer<ServerController> &serverController, int &count);
+    ErrorCode getXrayClients(const DockerContainer container, const ServerCredentials& credentials,
+                             const QSharedPointer<ServerController> &serverController, int &count);
 
     ErrorCode wgShow(const DockerContainer container, const ServerCredentials &credentials,
                      const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data);
diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp
index c87499a73..b72b10c31 100644
--- a/client/ui/models/servers_model.cpp
+++ b/client/ui/models/servers_model.cpp
@@ -22,7 +22,7 @@ namespace
         constexpr char serviceProtocol[] = "service_protocol";
 
         constexpr char publicKeyInfo[] = "public_key";
-        constexpr char endDate[] = "end_date";
+        constexpr char expiresAt[] = "expires_at";
     }
 }
 
@@ -39,6 +39,9 @@ ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent)
         emit ServersModel::defaultServerNameChanged();
         updateDefaultServerContainersModel();
     });
+
+    connect(this, &ServersModel::processedServerIndexChanged, this, &ServersModel::processedServerChanged);
+    connect(this, &ServersModel::dataChanged, this, &ServersModel::processedServerChanged);
 }
 
 int ServersModel::rowCount(const QModelIndex &parent) const
@@ -79,6 +82,12 @@ bool ServersModel::setData(const QModelIndex &index, const QVariant &value, int
     return true;
 }
 
+bool ServersModel::setData(const int index, const QVariant &value, int role)
+{
+    QModelIndex modelIndex = this->index(index);
+    return setData(modelIndex, value, role);
+}
+
 QVariant ServersModel::data(const QModelIndex &index, int role) const
 {
     if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_servers.size())) {
@@ -679,6 +688,18 @@ QVariant ServersModel::getProcessedServerData(const QString roleString)
     return {};
 }
 
+bool ServersModel::setProcessedServerData(const QString &roleString, const QVariant &value)
+{
+    const auto roles = roleNames();
+    for (auto it = roles.begin(); it != roles.end(); it++) {
+        if (QString(it.value()) == roleString) {
+            return setData(m_processedServerIndex, value, it.key());
+        }
+    }
+
+    return false;
+}
+
 bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
 {
     auto server = m_servers.at(m_defaultServerIndex).toObject();
@@ -718,9 +739,9 @@ bool ServersModel::isApiKeyExpired(const int serverIndex)
     auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
 
     auto publicKeyInfo = apiConfig.value(configKey::publicKeyInfo).toObject();
-    const QString endDate = publicKeyInfo.value(configKey::endDate).toString();
-    if (endDate.isEmpty()) {
-        publicKeyInfo.insert(configKey::endDate, QDateTime::currentDateTimeUtc().addDays(1).toString(Qt::ISODate));
+    const QString expiresAt = publicKeyInfo.value(configKey::expiresAt).toString();
+    if (expiresAt.isEmpty()) {
+        publicKeyInfo.insert(configKey::expiresAt, QDateTime::currentDateTimeUtc().addDays(1).toString(Qt::ISODate));
         apiConfig.insert(configKey::publicKeyInfo, publicKeyInfo);
         serverConfig.insert(configKey::apiConfig, apiConfig);
         editServer(serverConfig, serverIndex);
@@ -728,8 +749,8 @@ bool ServersModel::isApiKeyExpired(const int serverIndex)
         return false;
     }
 
-    auto endDateDateTime = QDateTime::fromString(endDate, Qt::ISODate).toUTC();
-    if (endDateDateTime < QDateTime::currentDateTimeUtc()) {
+    auto expiresAtDateTime = QDateTime::fromString(expiresAt, Qt::ISODate).toUTC();
+    if (expiresAtDateTime < QDateTime::currentDateTimeUtc()) {
         return true;
     }
     return false;
diff --git a/client/ui/models/servers_model.h b/client/ui/models/servers_model.h
index 0f18ea301..78bc22cc0 100644
--- a/client/ui/models/servers_model.h
+++ b/client/ui/models/servers_model.h
@@ -46,6 +46,7 @@ class ServersModel : public QAbstractListModel
     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
 
     bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+    bool setData(const int index, const QVariant &value, int role = Qt::EditRole);
     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
     QVariant data(const int index, int role = Qt::DisplayRole) const;
 
@@ -115,6 +116,7 @@ public slots:
     QVariant getDefaultServerData(const QString roleString);
 
     QVariant getProcessedServerData(const QString roleString);
+    bool setProcessedServerData(const QString &roleString, const QVariant &value);
 
     bool isDefaultServerDefaultContainerHasSplitTunneling();
 
@@ -127,6 +129,9 @@ public slots:
 
 signals:
     void processedServerIndexChanged(const int index);
+    // emitted when the processed server index or processed server data is changed
+    void processedServerChanged();
+
     void defaultServerIndexChanged(const int index);
     void defaultServerNameChanged();
     void defaultServerDescriptionChanged();
diff --git a/client/ui/qml/Components/ShareConnectionDrawer.qml b/client/ui/qml/Components/ShareConnectionDrawer.qml
index 3235ad0a0..d2bf28ab8 100644
--- a/client/ui/qml/Components/ShareConnectionDrawer.qml
+++ b/client/ui/qml/Components/ShareConnectionDrawer.qml
@@ -84,7 +84,7 @@ DrawerType2 {
                     Layout.topMargin: 16
 
                     text: qsTr("Share")
-                    imageSource: "qrc:/images/controls/share-2.svg"
+                    leftImageSource: "qrc:/images/controls/share-2.svg"
 
                     KeyNavigation.tab: copyConfigTextButton
 
@@ -120,7 +120,7 @@ DrawerType2 {
                     borderWidth: 1
 
                     text: qsTr("Copy")
-                    imageSource: "qrc:/images/controls/copy.svg"
+                    leftImageSource: "qrc:/images/controls/copy.svg"
 
                     Keys.onReturnPressed: { copyConfigTextButton.clicked() }
                     Keys.onEnterPressed: { copyConfigTextButton.clicked() }
@@ -143,7 +143,7 @@ DrawerType2 {
                     borderWidth: 1
 
                     text: qsTr("Copy config string")
-                    imageSource: "qrc:/images/controls/copy.svg"
+                    leftImageSource: "qrc:/images/controls/copy.svg"
 
                     KeyNavigation.tab: showSettingsButton
                 }
diff --git a/client/ui/qml/Controls2/BasicButtonType.qml b/client/ui/qml/Controls2/BasicButtonType.qml
index 5c599013e..ef66e0e22 100644
--- a/client/ui/qml/Controls2/BasicButtonType.qml
+++ b/client/ui/qml/Controls2/BasicButtonType.qml
@@ -22,9 +22,10 @@ Button {
     property int borderWidth: 0
     property int borderFocusedWidth: 1
 
-    property string imageSource
+    property string leftImageSource
     property string rightImageSource
     property string leftImageColor: textColor
+    property bool changeLeftImageSize: true
 
     property bool squareLeftSide: false
 
@@ -127,18 +128,23 @@ Button {
             anchors.centerIn: parent
 
             Image {
-                Layout.preferredHeight: 20
-                Layout.preferredWidth: 20
-
-                source: root.imageSource
-                visible: root.imageSource === "" ? false : true
+                id: leftImage
+                source: root.leftImageSource
+                visible: root.leftImageSource === "" ? false : true
 
                 layer {
-                    enabled: true
+                    enabled: leftImageColor !== "" ? true : false
                     effect: ColorOverlay {
                         color: leftImageColor
                     }
                 }
+
+                Component.onCompleted: {
+                    if (root.changeLeftImageSize) {
+                        leftImage.Layout.preferredHeight = 20
+                        leftImage.Layout.preferredWidth = 20
+                    }
+                }
             }
 
             ButtonTextType {
diff --git a/client/ui/qml/Controls2/BusyIndicatorType.qml b/client/ui/qml/Controls2/BusyIndicatorType.qml
index 55af280f6..480f25c1a 100644
--- a/client/ui/qml/Controls2/BusyIndicatorType.qml
+++ b/client/ui/qml/Controls2/BusyIndicatorType.qml
@@ -14,7 +14,7 @@ Popup {
     visible: false
 
     Overlay.modal: Rectangle {
-        color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+        color: AmneziaStyle.color.translucentMidnightBlack
     }
 
     background: Rectangle {
diff --git a/client/ui/qml/Controls2/CardType.qml b/client/ui/qml/Controls2/CardType.qml
index 50f84dbf5..f584a8fcd 100644
--- a/client/ui/qml/Controls2/CardType.qml
+++ b/client/ui/qml/Controls2/CardType.qml
@@ -19,7 +19,7 @@ RadioButton {
 
     property string textColor: AmneziaStyle.color.midnightBlack
 
-    property string pressedBorderColor: Qt.rgba(251/255, 178/255, 106/255, 0.3)
+    property string pressedBorderColor: AmneziaStyle.color.softGoldenApricot
     property string selectedBorderColor: AmneziaStyle.color.goldenApricot
     property string defaultBodredColor: AmneziaStyle.color.transparent
     property int borderWidth: 0
diff --git a/client/ui/qml/Controls2/CardWithIconsType.qml b/client/ui/qml/Controls2/CardWithIconsType.qml
index fea651167..18a29b872 100644
--- a/client/ui/qml/Controls2/CardWithIconsType.qml
+++ b/client/ui/qml/Controls2/CardWithIconsType.qml
@@ -145,6 +145,7 @@ Button {
 
         cursorShape: Qt.PointingHandCursor
         hoverEnabled: true
+        enabled: root.enabled
 
         onEntered: {
             backgroundRect.color = root.hoveredColor
diff --git a/client/ui/qml/Controls2/DrawerType2.qml b/client/ui/qml/Controls2/DrawerType2.qml
index 6647bc88b..c4b584c1e 100644
--- a/client/ui/qml/Controls2/DrawerType2.qml
+++ b/client/ui/qml/Controls2/DrawerType2.qml
@@ -92,7 +92,7 @@ Item {
         id: background
 
         anchors.fill: parent
-        color: root.isCollapsed ? AmneziaStyle.color.transparent : Qt.rgba(14/255, 14/255, 17/255, 0.8)
+        color: root.isCollapsed ? AmneziaStyle.color.transparent : AmneziaStyle.color.translucentMidnightBlack
 
         Behavior on color {
             PropertyAnimation { duration: 200 }
diff --git a/client/ui/qml/Controls2/PopupType.qml b/client/ui/qml/Controls2/PopupType.qml
index bd4aa4fbc..7a6a770e0 100644
--- a/client/ui/qml/Controls2/PopupType.qml
+++ b/client/ui/qml/Controls2/PopupType.qml
@@ -24,7 +24,7 @@ Popup {
 
     Overlay.modal: Rectangle {
         visible: root.closeButtonVisible
-        color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+        color: AmneziaStyle.color.translucentMidnightBlack
     }
 
     onOpened: {
diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
index 4ec0976bc..365faa94c 100644
--- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
+++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
@@ -183,7 +183,7 @@ Item {
 
         focusPolicy: Qt.NoFocus
         text: root.buttonText
-        imageSource: root.buttonImageSource
+        leftImageSource: root.buttonImageSource
 
         anchors.top: content.top
         anchors.bottom: content.bottom
diff --git a/client/ui/qml/Controls2/TopCloseButtonType.qml b/client/ui/qml/Controls2/TopCloseButtonType.qml
index 1bd7fef6b..3a652da6c 100644
--- a/client/ui/qml/Controls2/TopCloseButtonType.qml
+++ b/client/ui/qml/Controls2/TopCloseButtonType.qml
@@ -14,7 +14,7 @@ Popup {
     visible: false
 
     Overlay.modal: Rectangle {
-        color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+        color: AmneziaStyle.color.translucentMidnightBlack
     }
 
     background: Rectangle {
diff --git a/client/ui/qml/Modules/Style/AmneziaStyle.qml b/client/ui/qml/Modules/Style/AmneziaStyle.qml
index c0038246d..1abfbe3ae 100644
--- a/client/ui/qml/Modules/Style/AmneziaStyle.qml
+++ b/client/ui/qml/Modules/Style/AmneziaStyle.qml
@@ -22,5 +22,9 @@ QtObject {
         readonly property color sheerWhite: Qt.rgba(1, 1, 1, 0.12)
         readonly property color translucentWhite: Qt.rgba(1, 1, 1, 0.08)
         readonly property color barelyTranslucentWhite: Qt.rgba(1, 1, 1, 0.05)
+        readonly property color translucentMidnightBlack: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+        readonly property color softGoldenApricot: Qt.rgba(251/255, 178/255, 106/255, 0.3)
+        readonly property color mistyGray: Qt.rgba(215/255, 216/255, 219/255, 0.8)
+        readonly property color cloudyGray: Qt.rgba(215/255, 216/255, 219/255, 0.65)
     }
 }
diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml
index 8074337a9..e51125758 100644
--- a/client/ui/qml/Pages2/PageHome.qml
+++ b/client/ui/qml/Pages2/PageHome.qml
@@ -98,7 +98,6 @@ PageType {
                 pressedColor: AmneziaStyle.color.sheerWhite
                 disabledColor: AmneziaStyle.color.mutedGray
                 textColor: AmneziaStyle.color.mutedGray
-                leftImageColor: AmneziaStyle.color.transparent
                 borderWidth: 0
 
                 buttonTextLabel.lineHeight: 20
@@ -110,7 +109,8 @@ PageType {
 
                 text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
 
-                imageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
+                leftImageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
+                leftImageColor: ""
                 rightImageSource: "qrc:/images/controls/chevron-down.svg"
 
                 Keys.onEnterPressed: splitTunnelingButton.clicked()
@@ -166,6 +166,7 @@ PageType {
 
                 anchors.left: parent.left
                 anchors.right: parent.right
+                spacing: 0
 
                 Component.onCompleted: {
                     drawer.collapsedHeight = collapsed.implicitHeight
@@ -267,18 +268,39 @@ PageType {
 
                 RowLayout {
                     Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
-                    Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
+                    Layout.topMargin: 8
+                    Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16
                     spacing: 0
 
-                    Image {
-                        Layout.rightMargin: 8
-                        visible: source !== ""
-                        source: ServersModel.defaultServerImagePathCollapsed
-                    }
+                    BasicButtonType {
+                        enabled: (ServersModel.defaultServerImagePathCollapsed !== "") && drawer.isCollapsed
+                        hoverEnabled: enabled
+
+                        implicitHeight: 36
+
+                        leftPadding: 16
+                        rightPadding: 16
+
+                        defaultColor: AmneziaStyle.color.transparent
+                        hoveredColor: AmneziaStyle.color.translucentWhite
+                        pressedColor: AmneziaStyle.color.sheerWhite
+                        disabledColor: AmneziaStyle.color.transparent
+                        textColor: AmneziaStyle.color.mutedGray
+
+                        buttonTextLabel.lineHeight: 16
+                        buttonTextLabel.font.pixelSize: 13
+                        buttonTextLabel.font.weight: 400
 
-                    LabelTextType {
-                        id: collapsedServerMenuDescription
                         text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
+                        leftImageSource: ServersModel.defaultServerImagePathCollapsed
+                        changeLeftImageSize: false
+
+                        rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : ""
+
+                        onClicked: {
+                            ServersModel.processedIndex = ServersModel.defaultIndex
+                            PageController.goToPage(PageEnum.PageSettingsServerInfo)
+                        }
                     }
                 }
             }
@@ -316,8 +338,8 @@ PageType {
 
                         rootButtonImageColor: AmneziaStyle.color.midnightBlack
                         rootButtonBackgroundColor: AmneziaStyle.color.paleGray
-                        rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
-                        rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
+                        rootButtonBackgroundHoveredColor: AmneziaStyle.color.mistyGray
+                        rootButtonBackgroundPressedColor: AmneziaStyle.color.cloudyGray
                         rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
                         rootButtonDefaultBorderColor: AmneziaStyle.color.transparent
                         rootButtonTextTopMargin: 8
diff --git a/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml b/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
index 120313cd1..600db85d1 100644
--- a/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
+++ b/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
@@ -54,8 +54,14 @@ PageType {
                         imageSource: "qrc:/images/controls/download.svg"
 
                         checked: index === ApiCountryModel.currentIndex
+                        checkable: !ConnectionController.isConnected
 
                         onClicked: {
+                            if (ConnectionController.isConnected) {
+                                PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection"))
+                                return
+                            }
+
                             if (index !== ApiCountryModel.currentIndex) {
                                 PageController.showBusyIndicator(true)
                                 var prevIndex = ApiCountryModel.currentIndex
diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
index f23e36d9e..167e56e5a 100644
--- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
+++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
@@ -56,12 +56,15 @@ PageType {
             }
 
             LabelWithImageType {
+                property bool showSubscriptionEndDate: ServersModel.getProcessedServerData("isCountrySelectionAvailable")
+
                 Layout.fillWidth: true
                 Layout.margins: 16
 
                 imageSource: "qrc:/images/controls/history.svg"
-                leftText: qsTr("Work period")
-                rightText: ApiServicesModel.getSelectedServiceData("workPeriod")
+                leftText: showSubscriptionEndDate ? qsTr("Valid until") : qsTr("Work period")
+                rightText: showSubscriptionEndDate ? ApiServicesModel.getSelectedServiceData("endDate")
+                                                   : ApiServicesModel.getSelectedServiceData("workPeriod")
 
                 visible: rightText !== ""
             }
@@ -132,8 +135,8 @@ PageType {
                 implicitHeight: 32
 
                 defaultColor: "transparent"
-                hoveredColor: Qt.rgba(1, 1, 1, 0.08)
-                pressedColor: Qt.rgba(1, 1, 1, 0.12)
+                hoveredColor: AmneziaStyle.color.translucentWhite
+                pressedColor: AmneziaStyle.color.sheerWhite
                 textColor: AmneziaStyle.color.vibrantRed
 
                 text: qsTr("Reload API config")
@@ -172,8 +175,8 @@ PageType {
                 implicitHeight: 32
 
                 defaultColor: "transparent"
-                hoveredColor: Qt.rgba(1, 1, 1, 0.08)
-                pressedColor: Qt.rgba(1, 1, 1, 0.12)
+                hoveredColor: AmneziaStyle.color.translucentWhite
+                pressedColor: AmneziaStyle.color.sheerWhite
                 textColor: AmneziaStyle.color.vibrantRed
 
                 text: qsTr("Remove from application")
diff --git a/client/ui/qml/Pages2/PageSettingsServerInfo.qml b/client/ui/qml/Pages2/PageSettingsServerInfo.qml
index 95ae5c8a6..ffcfb4411 100644
--- a/client/ui/qml/Pages2/PageSettingsServerInfo.qml
+++ b/client/ui/qml/Pages2/PageSettingsServerInfo.qml
@@ -25,6 +25,8 @@ PageType {
     property int pageSettingsApiServerInfo: 3
     property int pageSettingsApiLanguageList: 4
 
+    property var processedServer
+
     defaultActiveFocusItem: focusItem
 
     Connections {
@@ -35,8 +37,18 @@ PageType {
         }
     }
 
+    Connections {
+        target: ServersModel
+
+        function onProcessedServerChanged() {
+            root.processedServer = proxyServersModel.get(0)
+        }
+    }
+
     SortFilterProxyModel {
         id: proxyServersModel
+        objectName: "proxyServersModel"
+
         sourceModel: ServersModel
         filters: [
             ValueFilter {
@@ -44,147 +56,139 @@ PageType {
                 value: true
             }
         ]
+
+        Component.onCompleted: {
+            root.processedServer = proxyServersModel.get(0)
+        }
     }
 
     Item {
         id: focusItem
-        KeyNavigation.tab: header
+        //KeyNavigation.tab: header
     }
 
     ColumnLayout {
         anchors.fill: parent
 
-        spacing: 16
-
-        Repeater {
-            id: header
-            model: proxyServersModel
-
-            activeFocusOnTab: true
-            onFocusChanged: {
-                header.itemAt(0).focusItem.forceActiveFocus()
-            }
+        spacing: 4
 
-            delegate: ColumnLayout {
+        BackButtonType {
+            id: backButton
 
-                property alias focusItem: backButton
+            Layout.topMargin: 20
+            KeyNavigation.tab: headerContent.actionButton
 
-                id: content
+            backButtonFunction: function() {
+                if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo &&
+                        root.processedServer.isCountrySelectionAvailable) {
+                    nestedStackView.currentIndex = root.pageSettingsApiLanguageList
+                } else {
+                    PageController.closePage()
+                }
+            }
+        }
 
-                Layout.topMargin: 20
+        HeaderType {
+            id: headerContent
+            Layout.fillWidth: true
+            Layout.leftMargin: 16
+            Layout.rightMargin: 16
 
-                BackButtonType {
-                    id: backButton
-                    KeyNavigation.tab: headerContent.actionButton
+            actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg"
+                                                                                                 : "qrc:/images/controls/edit-3.svg"
 
-                    backButtonFunction: function() {
-                        if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo &&
-                                ServersModel.getProcessedServerData("isCountrySelectionAvailable")) {
-                            nestedStackView.currentIndex = root.pageSettingsApiLanguageList
-                        } else {
-                            PageController.closePage()
-                        }
+            headerText: root.processedServer.name
+            descriptionText: {
+                if (root.processedServer.isServerFromGatewayApi) {
+                    if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
+                        return qsTr("Subscription is valid until ") + ApiServicesModel.getSelectedServiceData("endDate")
+                    } else {
+                        return ApiServicesModel.getSelectedServiceData("serviceDescription")
                     }
+                } else if (root.processedServer.isServerFromTelegramApi) {
+                    return root.processedServer.serverDescription
+                } else if (root.processedServer.hasWriteAccess) {
+                    return root.processedServer.credentialsLogin + " · " + root.processedServer.hostName
+                } else {
+                    return root.processedServer.hostName
                 }
+            }
 
-                HeaderType {
-                    id: headerContent
-                    Layout.fillWidth: true
-                    Layout.leftMargin: 16
-                    Layout.rightMargin: 16
-
-                    actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg" : "qrc:/images/controls/edit-3.svg"
-
-                    headerText: name
-                    descriptionText: {
-                        if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
-                            return ApiServicesModel.getSelectedServiceData("serviceDescription")
-                        } else if (ServersModel.getProcessedServerData("isServerFromTelegramApi")) {
-                            return serverDescription
-                        } else if (ServersModel.isProcessedServerHasWriteAccess()) {
-                            return credentialsLogin + " · " + hostName
-                        } else {
-                            return hostName
-                        }
-                    }
-
-                    KeyNavigation.tab: tabBar
+            KeyNavigation.tab: tabBar
 
-                    actionButtonFunction: function() {
-                        if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
-                            nestedStackView.currentIndex = root.pageSettingsApiServerInfo
-                        } else {
-                            serverNameEditDrawer.open()
-                        }
-                    }
+            actionButtonFunction: function() {
+                if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
+                    nestedStackView.currentIndex = root.pageSettingsApiServerInfo
+                } else {
+                    serverNameEditDrawer.open()
                 }
+            }
+        }
 
-                DrawerType2 {
-                    id: serverNameEditDrawer
+        DrawerType2 {
+            id: serverNameEditDrawer
 
-                    parent: root
+            parent: root
 
-                    anchors.fill: parent
-                    expandedHeight: root.height * 0.35
+            anchors.fill: parent
+            expandedHeight: root.height * 0.35
 
-                    onClosed: {
-                        if (!GC.isMobile()) {
-                            headerContent.actionButton.forceActiveFocus()
-                        }
-                    }
+            onClosed: {
+                if (!GC.isMobile()) {
+                    headerContent.actionButton.forceActiveFocus()
+                }
+            }
 
-                    expandedContent: ColumnLayout {
-                        anchors.top: parent.top
-                        anchors.left: parent.left
-                        anchors.right: parent.right
-                        anchors.topMargin: 32
-                        anchors.leftMargin: 16
-                        anchors.rightMargin: 16
-
-                        Connections {
-                            target: serverNameEditDrawer
-                            enabled: !GC.isMobile()
-                            function onOpened() {
-                                serverName.textField.forceActiveFocus()
-                            }
-                        }
+            expandedContent: ColumnLayout {
+                anchors.top: parent.top
+                anchors.left: parent.left
+                anchors.right: parent.right
+                anchors.topMargin: 32
+                anchors.leftMargin: 16
+                anchors.rightMargin: 16
+
+                Connections {
+                    target: serverNameEditDrawer
+                    enabled: !GC.isMobile()
+                    function onOpened() {
+                        serverName.textField.forceActiveFocus()
+                    }
+                }
 
-                        Item {
-                            id: focusItem1
-                            KeyNavigation.tab: serverName.textField
-                        }
+                Item {
+                    id: focusItem1
+                    KeyNavigation.tab: serverName.textField
+                }
 
-                        TextFieldWithHeaderType {
-                            id: serverName
+                TextFieldWithHeaderType {
+                    id: serverName
 
-                            Layout.fillWidth: true
-                            headerText: qsTr("Server name")
-                            textFieldText: name
-                            textField.maximumLength: 30
-                            checkEmptyText: true
+                    Layout.fillWidth: true
+                    headerText: qsTr("Server name")
+                    textFieldText: root.processedServer.name
+                    textField.maximumLength: 30
+                    checkEmptyText: true
 
-                            KeyNavigation.tab: saveButton
-                        }
+                    KeyNavigation.tab: saveButton
+                }
 
-                        BasicButtonType {
-                            id: saveButton
+                BasicButtonType {
+                    id: saveButton
 
-                            Layout.fillWidth: true
+                    Layout.fillWidth: true
 
-                            text: qsTr("Save")
-                            KeyNavigation.tab: focusItem1
+                    text: qsTr("Save")
+                    KeyNavigation.tab: focusItem1
 
-                            clickedFunc: function() {
-                                if (serverName.textFieldText === "") {
-                                    return
-                                }
+                    clickedFunc: function() {
+                        if (serverName.textFieldText === "") {
+                            return
+                        }
 
-                                if (serverName.textFieldText !== name) {
-                                    name = serverName.textFieldText
-                                }
-                                serverNameEditDrawer.close()
-                            }
+                        if (serverName.textFieldText !== root.processedServer.name) {
+                            ServersModel.setProcessedServerData("name", serverName.textFieldText);
                         }
+                        serverNameEditDrawer.close()
                     }
                 }
             }
@@ -257,8 +261,7 @@ PageType {
 
         StackLayout {
             id: nestedStackView
-            Layout.preferredWidth: root.width
-            Layout.preferredHeight: root.height - tabBar.implicitHeight - header.implicitHeight
+            Layout.fillWidth: true
 
             currentIndex: ServersModel.getProcessedServerData("isServerFromGatewayApi") ?
                               (ServersModel.getProcessedServerData("isCountrySelectionAvailable") ?
diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
index 85a50393c..f726cd49a 100644
--- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
+++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
@@ -16,83 +16,82 @@ PageType {
 
     defaultActiveFocusItem: focusItem
 
-    FlickableType {
-        id: fl
+    ColumnLayout {
+        id: header
+
         anchors.top: parent.top
-        anchors.bottom: parent.bottom
-        contentHeight: content.height
+        anchors.left: parent.left
+        anchors.right: parent.right
 
-        ColumnLayout {
-            id: content
+        spacing: 0
 
-            anchors.top: parent.top
-            anchors.left: parent.left
-            anchors.right: parent.right
+        Item {
+            id: focusItem
+            KeyNavigation.tab: backButton
+        }
 
-            spacing: 0
+        BackButtonType {
+            id: backButton
+            Layout.topMargin: 20
+//                KeyNavigation.tab: fileButton.rightButton
+        }
 
-            Item {
-                id: focusItem
-                KeyNavigation.tab: backButton
-            }
+        HeaderType {
+            Layout.fillWidth: true
+            Layout.topMargin: 8
+            Layout.rightMargin: 16
+            Layout.leftMargin: 16
+            Layout.bottomMargin: 16
 
-            BackButtonType {
-                id: backButton
-                Layout.topMargin: 20
-//                KeyNavigation.tab: fileButton.rightButton
-            }
+            headerText: qsTr("VPN by Amnezia")
+            descriptionText: qsTr("Choose a VPN service that suits your needs.")
+        }
+    }
 
-            HeaderType {
-                Layout.fillWidth: true
-                Layout.topMargin: 8
-                Layout.rightMargin: 16
-                Layout.leftMargin: 16
-                Layout.bottomMargin: 32
+    ListView {
+        id: servicesListView
+        anchors.top: header.bottom
+        anchors.right: parent.right
+        anchors.left: parent.left
+        anchors.bottom: parent.bottom
+        anchors.topMargin: 16
+        spacing: 0
 
-                headerText: qsTr("VPN by Amnezia")
-                descriptionText: qsTr("Choose a VPN service that suits your needs.")
-            }
+        currentIndex: 1
+        clip: true
+        model: ApiServicesModel
 
-            ListView {
-                id: containers
-                width: parent.width
-                height: containers.contentItem.height
-                spacing: 16
+        ScrollBar.vertical: ScrollBar {}
 
-                currentIndex: 1
-                interactive: false
-                model: ApiServicesModel
+        delegate: Item {
+            implicitWidth: servicesListView.width
+            implicitHeight: delegateContent.implicitHeight
 
-                delegate: Item {
-                    implicitWidth: containers.width
-                    implicitHeight: delegateContent.implicitHeight
+            ColumnLayout {
+                id: delegateContent
 
-                    ColumnLayout {
-                        id: delegateContent
+                anchors.fill: parent
 
-                        anchors.top: parent.top
-                        anchors.left: parent.left
-                        anchors.right: parent.right
+                CardWithIconsType {
+                    id: card
 
-                        CardWithIconsType {
-                            id: card
+                    Layout.fillWidth: true
+                    Layout.rightMargin: 16
+                    Layout.leftMargin: 16
+                    Layout.bottomMargin: 16
 
-                            Layout.fillWidth: true
-                            Layout.rightMargin: 16
-                            Layout.leftMargin: 16
+                    headerText: name
+                    bodyText: cardDescription
+                    footerText: price
 
-                            headerText: name
-                            bodyText: cardDescription
-                            footerText: price
+                    rightImageSource: "qrc:/images/controls/chevron-right.svg"
 
-                            rightImageSource: "qrc:/images/controls/chevron-right.svg"
+                    enabled: isServiceAvailable
 
-                            onClicked: {
-                                if (isServiceAvailable) {
-                                    ApiServicesModel.setServiceIndex(index)
-                                    PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
-                                }
-                            }
+                    onClicked: {
+                        if (isServiceAvailable) {
+                            ApiServicesModel.setServiceIndex(index)
+                            PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
                         }
                     }
                 }
diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
index 7c031997f..f973c89cf 100644
--- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
+++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
@@ -47,7 +47,6 @@ PageType {
                 KeyNavigation.tab: textKey.textField
             }
 
-
             HeaderType {
                 property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
 
diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml
index 617b1091a..d6ce78488 100644
--- a/client/ui/qml/Pages2/PageShare.qml
+++ b/client/ui/qml/Pages2/PageShare.qml
@@ -92,7 +92,7 @@ PageType {
                 break
             }
             case PageShare.ConfigType.Xray: {
-                ExportController.generateXrayConfig()
+                ExportController.generateXrayConfig(clientNameTextField.textFieldText)
                 shareConnectionDrawer.configCaption = qsTr("Save XRay config")
                 shareConnectionDrawer.configExtension = ".json"
                 shareConnectionDrawer.configFileName = "amnezia_for_xray"
@@ -573,7 +573,7 @@ PageType {
                 visible: accessTypeSelector.currentIndex === 0
 
                 text: qsTr("Share")
-                imageSource: "qrc:/images/controls/share-2.svg"                
+                leftImageSource: "qrc:/images/controls/share-2.svg"
 
                 Keys.onTabPressed: lastItemTabClicked(focusItem)
 
diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml
index 2a5652309..404ba563f 100644
--- a/client/ui/qml/Pages2/PageShareFullAccess.qml
+++ b/client/ui/qml/Pages2/PageShareFullAccess.qml
@@ -135,7 +135,7 @@ PageType {
                 Layout.topMargin: 40
 
                 text: qsTr("Share")
-                imageSource: "qrc:/images/controls/share-2.svg"
+                leftImageSource: "qrc:/images/controls/share-2.svg"
 
                 Keys.onTabPressed: lastItemTabClicked(focusItem)
 
diff --git a/deploy/data/linux/post_install.sh b/deploy/data/linux/post_install.sh
index b3345bac8..324462d91 100755
--- a/deploy/data/linux/post_install.sh
+++ b/deploy/data/linux/post_install.sh
@@ -19,6 +19,11 @@ date > $LOG_FILE
 echo "Script started" >> $LOG_FILE
 sudo killall -9 $APP_NAME 2>> $LOG_FILE
 
+if command -v steamos-readonly &> /dev/null; then
+        sudo steamos-readonly disable >> $LOG_FILE
+        echo "steamos-readonly disabled" >> $LOG_FILE
+fi
+
 if sudo systemctl is-active --quiet $APP_NAME; then
 	sudo systemctl stop $APP_NAME >> $LOG_FILE
 	sudo systemctl disable $APP_NAME >> $LOG_FILE
@@ -42,6 +47,11 @@ sudo chmod 555 /usr/share/applications/$APP_NAME.desktop >> $LOG_FILE
 
 echo "user desktop creation loop ended" >> $LOG_FILE
 
+if command -v steamos-readonly &> /dev/null; then
+        sudo steamos-readonly enable >> $LOG_FILE
+        echo "steamos-readonly enabled" >> $LOG_FILE
+fi
+
 date >> $LOG_FILE
 echo "Service status:" >> $LOG_FILE
 sudo systemctl status $APP_NAME >> $LOG_FILE
diff --git a/deploy/data/linux/post_uninstall.sh b/deploy/data/linux/post_uninstall.sh
index 5849a90e4..98090d20a 100755
--- a/deploy/data/linux/post_uninstall.sh
+++ b/deploy/data/linux/post_uninstall.sh
@@ -13,6 +13,11 @@ date >> $LOG_FILE
 echo "Uninstall Script started" >> $LOG_FILE
 sudo killall -9 $APP_NAME 2>> $LOG_FILE
 
+if command -v steamos-readonly &> /dev/null; then
+	sudo steamos-readonly disable >> $LOG_FILE
+	echo "steamos-readonly disabled" >> $LOG_FILE
+fi
+
 ls /opt/AmneziaVPN/client/lib/* | while IFS=: read -r dir; do
 	sudo unlink $dir  >> $LOG_FILE
 done
@@ -59,6 +64,11 @@ if test -f /usr/share/pixmaps/$APP_NAME.png; then
 
 fi
 
+if command -v steamos-readonly &> /dev/null; then
+	sudo steamos-readonly enable >> $LOG_FILE
+	echo "steamos-readonly enabled" >> $LOG_FILE
+fi
+
 date >> $LOG_FILE
 echo "Service after uninstall status:" >> $LOG_FILE
 sudo systemctl status $APP_NAME >> $LOG_FILE
diff --git a/metadata/img-readme/apl.png b/metadata/img-readme/apl.png
deleted file mode 100644
index 6dedfa12e..000000000
Binary files a/metadata/img-readme/apl.png and /dev/null differ
diff --git a/metadata/img-readme/download-alt.svg b/metadata/img-readme/download-alt.svg
new file mode 100644
index 000000000..f97c9c3df
--- /dev/null
+++ b/metadata/img-readme/download-alt.svg
@@ -0,0 +1,8 @@
+<svg width="208" height="56" viewBox="0 0 208 56" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="208" height="56" rx="16" fill="#FBB36A"/>
+<path d="M70.206 13.04H75.466C76.386 13.04 77.226 13.1867 77.986 13.48C78.746 13.7733 79.3927 14.2133 79.926 14.8C80.4593 15.3733 80.8727 16.1 81.166 16.98C81.4593 17.8467 81.606 18.86 81.606 20.02C81.606 21.18 81.4593 22.2 81.166 23.08C80.8727 23.9467 80.4593 24.6733 79.926 25.26C79.3927 25.8333 78.746 26.2667 77.986 26.56C77.226 26.8533 76.386 27 75.466 27H70.206V13.04ZM75.466 24.3C76.3727 24.3 77.086 24.0467 77.606 23.54C78.126 23.0333 78.386 22.22 78.386 21.1V18.94C78.386 17.82 78.126 17.0067 77.606 16.5C77.086 15.9933 76.3727 15.74 75.466 15.74H73.246V24.3H75.466ZM88.2513 27.24C87.478 27.24 86.7847 27.1133 86.1713 26.86C85.5713 26.6067 85.058 26.24 84.6313 25.76C84.218 25.28 83.898 24.7 83.6713 24.02C83.4447 23.34 83.3313 22.58 83.3313 21.74C83.3313 20.9 83.4447 20.14 83.6713 19.46C83.898 18.78 84.218 18.2067 84.6313 17.74C85.058 17.26 85.5713 16.8933 86.1713 16.64C86.7847 16.3867 87.478 16.26 88.2513 16.26C89.0247 16.26 89.7113 16.3867 90.3113 16.64C90.9247 16.8933 91.438 17.26 91.8513 17.74C92.278 18.2067 92.6047 18.78 92.8313 19.46C93.058 20.14 93.1713 20.9 93.1713 21.74C93.1713 22.58 93.058 23.34 92.8313 24.02C92.6047 24.7 92.278 25.28 91.8513 25.76C91.438 26.24 90.9247 26.6067 90.3113 26.86C89.7113 27.1133 89.0247 27.24 88.2513 27.24ZM88.2513 24.9C88.838 24.9 89.2913 24.72 89.6113 24.36C89.9313 24 90.0913 23.4867 90.0913 22.82V20.68C90.0913 20.0133 89.9313 19.5 89.6113 19.14C89.2913 18.78 88.838 18.6 88.2513 18.6C87.6647 18.6 87.2113 18.78 86.8913 19.14C86.5713 19.5 86.4113 20.0133 86.4113 20.68V22.82C86.4113 23.4867 86.5713 24 86.8913 24.36C87.2113 24.72 87.6647 24.9 88.2513 24.9ZM94.0851 16.5H96.9451L97.9651 20.74L98.6851 23.94H98.7651L99.6051 20.74L100.805 16.5H103.505L104.725 20.74L105.585 23.94H105.665L106.385 20.74L107.405 16.5H110.145L107.245 27H104.145L102.865 22.56L102.125 19.84H102.065L101.345 22.56L100.065 27H97.0251L94.0851 16.5ZM111.901 27V16.5H114.861V18.28H114.981C115.168 17.7333 115.495 17.26 115.961 16.86C116.428 16.46 117.075 16.26 117.901 16.26C118.981 16.26 119.795 16.62 120.341 17.34C120.901 18.06 121.181 19.0867 121.181 20.42V27H118.221V20.66C118.221 19.98 118.115 19.48 117.901 19.16C117.688 18.8267 117.308 18.66 116.761 18.66C116.521 18.66 116.288 18.6933 116.061 18.76C115.835 18.8133 115.628 18.9067 115.441 19.04C115.268 19.1733 115.128 19.34 115.021 19.54C114.915 19.7267 114.861 19.9467 114.861 20.2V27H111.901ZM126.756 27C125.742 27 124.996 26.7533 124.516 26.26C124.049 25.7667 123.816 25.0533 123.816 24.12V12.2H126.776V24.7H128.096V27H126.756ZM134.13 27.24C133.357 27.24 132.664 27.1133 132.05 26.86C131.45 26.6067 130.937 26.24 130.51 25.76C130.097 25.28 129.777 24.7 129.55 24.02C129.324 23.34 129.21 22.58 129.21 21.74C129.21 20.9 129.324 20.14 129.55 19.46C129.777 18.78 130.097 18.2067 130.51 17.74C130.937 17.26 131.45 16.8933 132.05 16.64C132.664 16.3867 133.357 16.26 134.13 16.26C134.904 16.26 135.59 16.3867 136.19 16.64C136.804 16.8933 137.317 17.26 137.73 17.74C138.157 18.2067 138.484 18.78 138.71 19.46C138.937 20.14 139.05 20.9 139.05 21.74C139.05 22.58 138.937 23.34 138.71 24.02C138.484 24.7 138.157 25.28 137.73 25.76C137.317 26.24 136.804 26.6067 136.19 26.86C135.59 27.1133 134.904 27.24 134.13 27.24ZM134.13 24.9C134.717 24.9 135.17 24.72 135.49 24.36C135.81 24 135.97 23.4867 135.97 22.82V20.68C135.97 20.0133 135.81 19.5 135.49 19.14C135.17 18.78 134.717 18.6 134.13 18.6C133.544 18.6 133.09 18.78 132.77 19.14C132.45 19.5 132.29 20.0133 132.29 20.68V22.82C132.29 23.4867 132.45 24 132.77 24.36C133.09 24.72 133.544 24.9 134.13 24.9ZM148.919 27C148.386 27 147.939 26.8333 147.579 26.5C147.233 26.1667 147.013 25.72 146.919 25.16H146.799C146.639 25.84 146.286 26.36 145.739 26.72C145.193 27.0667 144.519 27.24 143.719 27.24C142.666 27.24 141.859 26.96 141.299 26.4C140.739 25.84 140.459 25.1 140.459 24.18C140.459 23.0733 140.859 22.2533 141.659 21.72C142.473 21.1733 143.573 20.9 144.959 20.9H146.619V20.24C146.619 19.7333 146.486 19.3333 146.219 19.04C145.953 18.7333 145.506 18.58 144.879 18.58C144.293 18.58 143.826 18.7067 143.479 18.96C143.133 19.2133 142.846 19.5 142.619 19.82L140.859 18.26C141.286 17.6333 141.819 17.1467 142.459 16.8C143.113 16.44 143.993 16.26 145.099 16.26C146.593 16.26 147.713 16.5867 148.459 17.24C149.206 17.8933 149.579 18.8467 149.579 20.1V24.7H150.559V27H148.919ZM144.819 25.18C145.313 25.18 145.733 25.0733 146.079 24.86C146.439 24.6467 146.619 24.3 146.619 23.82V22.58H145.179C144.019 22.58 143.439 22.9733 143.439 23.76V24.06C143.439 24.4467 143.559 24.7333 143.799 24.92C144.039 25.0933 144.379 25.18 144.819 25.18ZM158.986 25.24H158.886C158.806 25.52 158.679 25.7867 158.506 26.04C158.333 26.28 158.119 26.4933 157.866 26.68C157.626 26.8533 157.346 26.9867 157.026 27.08C156.719 27.1867 156.399 27.24 156.066 27.24C154.733 27.24 153.726 26.7733 153.046 25.84C152.366 24.8933 152.026 23.5267 152.026 21.74C152.026 19.9533 152.366 18.5933 153.046 17.66C153.726 16.7267 154.733 16.26 156.066 16.26C156.746 16.26 157.346 16.4467 157.866 16.82C158.399 17.1933 158.739 17.6733 158.886 18.26H158.986V12.2H161.946V27H158.986V25.24ZM157.046 24.84C157.606 24.84 158.066 24.7067 158.426 24.44C158.799 24.16 158.986 23.78 158.986 23.3V20.2C158.986 19.72 158.799 19.3467 158.426 19.08C158.066 18.8 157.606 18.66 157.046 18.66C156.486 18.66 156.019 18.86 155.646 19.26C155.286 19.6467 155.106 20.1733 155.106 20.84V22.66C155.106 23.3267 155.286 23.86 155.646 24.26C156.019 24.6467 156.486 24.84 157.046 24.84Z" fill="#472402"/>
+<path opacity="0.8" d="M76.084 45L75.484 43.008H72.688L72.088 45H70.24L73 36.624H75.256L77.98 45H76.084ZM74.104 38.28H74.044L73.12 41.46H75.04L74.104 38.28ZM80.8068 45C80.1988 45 79.7508 44.852 79.4628 44.556C79.1828 44.26 79.0428 43.832 79.0428 43.272V36.12H80.8188V43.62H81.6108V45H80.8068ZM84.8251 45C84.2091 45 83.7411 44.844 83.4211 44.532C83.1091 44.22 82.9531 43.764 82.9531 43.164V40.08H82.0651V38.7H82.5091C82.7491 38.7 82.9131 38.644 83.0011 38.532C83.0891 38.412 83.1331 38.244 83.1331 38.028V36.996H84.7291V38.7H85.9771V40.08H84.7291V43.62H85.8811V45H84.8251ZM89.7919 45.144C89.3119 45.144 88.8839 45.068 88.5079 44.916C88.1319 44.756 87.8119 44.536 87.5479 44.256C87.2919 43.968 87.0959 43.62 86.9599 43.212C86.8319 42.804 86.7679 42.348 86.7679 41.844C86.7679 41.348 86.8319 40.9 86.9599 40.5C87.0879 40.092 87.2759 39.744 87.5239 39.456C87.7799 39.168 88.0919 38.948 88.4599 38.796C88.8279 38.636 89.2479 38.556 89.7199 38.556C90.2399 38.556 90.6839 38.644 91.0519 38.82C91.4279 38.996 91.7319 39.232 91.9639 39.528C92.2039 39.824 92.3759 40.168 92.4799 40.56C92.5919 40.944 92.6479 41.348 92.6479 41.772V42.3H88.6039V42.396C88.6039 42.812 88.7159 43.144 88.9399 43.392C89.1639 43.632 89.5159 43.752 89.9959 43.752C90.3639 43.752 90.6639 43.68 90.8959 43.536C91.1279 43.384 91.3439 43.204 91.5439 42.996L92.4319 44.1C92.1519 44.428 91.7839 44.684 91.3279 44.868C90.8799 45.052 90.3679 45.144 89.7919 45.144ZM89.7559 39.864C89.3959 39.864 89.1119 39.984 88.9039 40.224C88.7039 40.456 88.6039 40.768 88.6039 41.16V41.256H90.8119V41.148C90.8119 40.764 90.7239 40.456 90.5479 40.224C90.3799 39.984 90.1159 39.864 89.7559 39.864ZM93.9022 45V38.7H95.6782V40.068H95.7382C95.7702 39.892 95.8262 39.724 95.9062 39.564C95.9862 39.396 96.0902 39.248 96.2182 39.12C96.3542 38.992 96.5142 38.892 96.6982 38.82C96.8822 38.74 97.0982 38.7 97.3462 38.7H97.6582V40.356H97.2142C96.6942 40.356 96.3062 40.424 96.0502 40.56C95.8022 40.696 95.6782 40.948 95.6782 41.316V45H93.9022ZM98.7538 45V38.7H100.53V39.768H100.602C100.714 39.44 100.91 39.156 101.19 38.916C101.47 38.676 101.858 38.556 102.354 38.556C103.002 38.556 103.49 38.772 103.818 39.204C104.154 39.636 104.322 40.252 104.322 41.052V45H102.546V41.196C102.546 40.788 102.482 40.488 102.354 40.296C102.226 40.096 101.998 39.996 101.67 39.996C101.526 39.996 101.386 40.016 101.25 40.056C101.114 40.088 100.99 40.144 100.878 40.224C100.774 40.304 100.69 40.404 100.626 40.524C100.562 40.636 100.53 40.768 100.53 40.92V45H98.7538ZM110.558 45C110.238 45 109.97 44.9 109.754 44.7C109.546 44.5 109.414 44.232 109.358 43.896H109.286C109.19 44.304 108.978 44.616 108.65 44.832C108.322 45.04 107.918 45.144 107.438 45.144C106.806 45.144 106.322 44.976 105.986 44.64C105.65 44.304 105.482 43.86 105.482 43.308C105.482 42.644 105.722 42.152 106.202 41.832C106.69 41.504 107.35 41.34 108.182 41.34H109.178V40.944C109.178 40.64 109.098 40.4 108.938 40.224C108.778 40.04 108.51 39.948 108.134 39.948C107.782 39.948 107.502 40.024 107.294 40.176C107.086 40.328 106.914 40.5 106.778 40.692L105.722 39.756C105.978 39.38 106.298 39.088 106.682 38.88C107.074 38.664 107.602 38.556 108.266 38.556C109.162 38.556 109.834 38.752 110.282 39.144C110.73 39.536 110.954 40.108 110.954 40.86V43.62H111.542V45H110.558ZM108.098 43.908C108.394 43.908 108.646 43.844 108.854 43.716C109.07 43.588 109.178 43.38 109.178 43.092V42.348H108.314C107.618 42.348 107.27 42.584 107.27 43.056V43.236C107.27 43.468 107.342 43.64 107.486 43.752C107.63 43.856 107.834 43.908 108.098 43.908ZM114.872 45C114.256 45 113.788 44.844 113.468 44.532C113.156 44.22 113 43.764 113 43.164V40.08H112.112V38.7H112.556C112.796 38.7 112.96 38.644 113.048 38.532C113.136 38.412 113.18 38.244 113.18 38.028V36.996H114.776V38.7H116.024V40.08H114.776V43.62H115.928V45H114.872ZM118.146 38.028C117.786 38.028 117.522 37.948 117.354 37.788C117.194 37.62 117.114 37.408 117.114 37.152V36.888C117.114 36.632 117.194 36.424 117.354 36.264C117.522 36.096 117.786 36.012 118.146 36.012C118.506 36.012 118.766 36.096 118.926 36.264C119.094 36.424 119.178 36.632 119.178 36.888V37.152C119.178 37.408 119.094 37.62 118.926 37.788C118.766 37.948 118.506 38.028 118.146 38.028ZM117.258 38.7H119.034V45H117.258V38.7ZM122.035 45L119.971 38.7H121.723L122.503 41.244L123.091 43.524H123.187L123.775 41.244L124.531 38.7H126.211L124.147 45H122.035ZM129.683 45.144C129.203 45.144 128.775 45.068 128.399 44.916C128.023 44.756 127.703 44.536 127.439 44.256C127.183 43.968 126.987 43.62 126.851 43.212C126.723 42.804 126.659 42.348 126.659 41.844C126.659 41.348 126.723 40.9 126.851 40.5C126.979 40.092 127.167 39.744 127.415 39.456C127.671 39.168 127.983 38.948 128.351 38.796C128.719 38.636 129.139 38.556 129.611 38.556C130.131 38.556 130.575 38.644 130.943 38.82C131.319 38.996 131.623 39.232 131.855 39.528C132.095 39.824 132.267 40.168 132.371 40.56C132.483 40.944 132.539 41.348 132.539 41.772V42.3H128.495V42.396C128.495 42.812 128.607 43.144 128.831 43.392C129.055 43.632 129.407 43.752 129.887 43.752C130.255 43.752 130.555 43.68 130.787 43.536C131.019 43.384 131.235 43.204 131.435 42.996L132.323 44.1C132.043 44.428 131.675 44.684 131.219 44.868C130.771 45.052 130.259 45.144 129.683 45.144ZM129.647 39.864C129.287 39.864 129.003 39.984 128.795 40.224C128.595 40.456 128.495 40.768 128.495 41.16V41.256H130.703V41.148C130.703 40.764 130.615 40.456 130.439 40.224C130.271 39.984 130.007 39.864 129.647 39.864ZM138.393 45C137.785 45 137.337 44.852 137.049 44.556C136.769 44.26 136.629 43.832 136.629 43.272V36.12H138.405V43.62H139.197V45H138.393ZM141.15 38.028C140.79 38.028 140.526 37.948 140.358 37.788C140.198 37.62 140.118 37.408 140.118 37.152V36.888C140.118 36.632 140.198 36.424 140.358 36.264C140.526 36.096 140.79 36.012 141.15 36.012C141.51 36.012 141.77 36.096 141.93 36.264C142.098 36.424 142.182 36.632 142.182 36.888V37.152C142.182 37.408 142.098 37.62 141.93 37.788C141.77 37.948 141.51 38.028 141.15 38.028ZM140.262 38.7H142.038V45H140.262V38.7ZM143.695 45V38.7H145.471V39.768H145.543C145.655 39.44 145.851 39.156 146.131 38.916C146.411 38.676 146.799 38.556 147.295 38.556C147.943 38.556 148.431 38.772 148.759 39.204C149.095 39.636 149.263 40.252 149.263 41.052V45H147.487V41.196C147.487 40.788 147.423 40.488 147.295 40.296C147.167 40.096 146.939 39.996 146.611 39.996C146.467 39.996 146.327 40.016 146.191 40.056C146.055 40.088 145.931 40.144 145.819 40.224C145.715 40.304 145.631 40.404 145.567 40.524C145.503 40.636 145.471 40.768 145.471 40.92V45H143.695ZM150.844 36.12H152.62V41.364H152.692L153.472 40.2L154.732 38.7H156.7L154.6 41.112L156.94 45H154.828L153.412 42.336L152.62 43.224V45H150.844V36.12Z" fill="#472402"/>
+<path d="M40.625 19.125H46.875V25.375" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M35.418 30.5833L46.8763 19.125" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M43.75 29.5417V35.7917C43.75 36.3442 43.5305 36.8741 43.1398 37.2648C42.7491 37.6555 42.2192 37.875 41.6667 37.875H30.2083C29.6558 37.875 29.1259 37.6555 28.7352 37.2648C28.3445 36.8741 28.125 36.3442 28.125 35.7917V24.3333C28.125 23.7808 28.3445 23.2509 28.7352 22.8602C29.1259 22.4695 29.6558 22.25 30.2083 22.25H36.4583" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/metadata/img-readme/download-website-ru.svg b/metadata/img-readme/download-website-ru.svg
new file mode 100644
index 000000000..386ae4fe5
--- /dev/null
+++ b/metadata/img-readme/download-website-ru.svg
@@ -0,0 +1,8 @@
+<svg width="208" height="56" viewBox="0 0 208 56" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="208" height="56" rx="16" fill="#FBB36A"/>
+<path d="M76.012 27.24C75.0654 27.24 74.212 27.0933 73.452 26.8C72.692 26.4933 72.0454 26.0467 71.512 25.46C70.9787 24.86 70.5654 24.12 70.272 23.24C69.9787 22.3467 69.832 21.3067 69.832 20.12C69.832 18.9467 69.9787 17.9067 70.272 17C70.5654 16.08 70.9787 15.3133 71.512 14.7C72.0454 14.0733 72.692 13.6 73.452 13.28C74.212 12.96 75.0654 12.8 76.012 12.8C77.3054 12.8 78.372 13.0667 79.212 13.6C80.052 14.12 80.7254 14.9467 81.232 16.08L78.612 17.44C78.4254 16.8533 78.132 16.3867 77.732 16.04C77.3454 15.68 76.772 15.5 76.012 15.5C75.1187 15.5 74.3987 15.7933 73.852 16.38C73.3187 16.9533 73.052 17.7933 73.052 18.9V21.14C73.052 22.2467 73.3187 23.0933 73.852 23.68C74.3987 24.2533 75.1187 24.54 76.012 24.54C76.7587 24.54 77.352 24.34 77.792 23.94C78.2454 23.5267 78.5787 23.0333 78.792 22.46L81.272 23.9C80.752 24.9667 80.0654 25.7933 79.212 26.38C78.372 26.9533 77.3054 27.24 76.012 27.24ZM83.2394 16.5H86.1994V20.52H87.7194L89.0994 17.96C89.3794 17.44 89.6927 17.0667 90.0394 16.84C90.3994 16.6133 90.8594 16.5 91.4194 16.5H92.6394V18.8H91.5794L90.6794 20.48C90.4927 20.8267 90.306 21.0733 90.1194 21.22C89.946 21.3667 89.7394 21.4733 89.4994 21.54V21.64C89.726 21.6933 89.9327 21.7867 90.1194 21.92C90.3194 22.0533 90.4994 22.2667 90.6594 22.56L91.8394 24.7H92.9194V27H91.5394C90.9794 27 90.526 26.8867 90.1794 26.66C89.8327 26.4333 89.506 26.0467 89.1994 25.5L87.7194 22.82H86.1994V27H83.2394V16.5ZM102.62 27C102.087 27 101.64 26.8333 101.28 26.5C100.934 26.1667 100.714 25.72 100.62 25.16H100.5C100.34 25.84 99.9871 26.36 99.4405 26.72C98.8938 27.0667 98.2205 27.24 97.4205 27.24C96.3671 27.24 95.5605 26.96 95.0005 26.4C94.4405 25.84 94.1605 25.1 94.1605 24.18C94.1605 23.0733 94.5605 22.2533 95.3605 21.72C96.1738 21.1733 97.2738 20.9 98.6605 20.9H100.32V20.24C100.32 19.7333 100.187 19.3333 99.9205 19.04C99.6538 18.7333 99.2071 18.58 98.5805 18.58C97.9938 18.58 97.5271 18.7067 97.1805 18.96C96.8338 19.2133 96.5471 19.5 96.3205 19.82L94.5605 18.26C94.9871 17.6333 95.5205 17.1467 96.1605 16.8C96.8138 16.44 97.6938 16.26 98.8005 16.26C100.294 16.26 101.414 16.5867 102.16 17.24C102.907 17.8933 103.28 18.8467 103.28 20.1V24.7H104.26V27H102.62ZM98.5205 25.18C99.0138 25.18 99.4338 25.0733 99.7805 24.86C100.14 24.6467 100.32 24.3 100.32 23.82V22.58H98.8805C97.7205 22.58 97.1405 22.9733 97.1405 23.76V24.06C97.1405 24.4467 97.2605 24.7333 97.5005 24.92C97.7405 25.0933 98.0805 25.18 98.5205 25.18ZM111.736 22.54H111.636C111.396 22.9667 111.049 23.3067 110.596 23.56C110.156 23.8 109.596 23.92 108.916 23.92C107.729 23.92 106.862 23.6133 106.316 23C105.782 22.3867 105.516 21.4467 105.516 20.18V16.5H108.476V20.04C108.476 20.56 108.596 20.94 108.836 21.18C109.089 21.4067 109.496 21.52 110.056 21.52C110.616 21.52 111.036 21.42 111.316 21.22C111.596 21.02 111.736 20.7667 111.736 20.46V16.5H114.696V27H111.736V22.54ZM125.218 27C124.685 27 124.238 26.8333 123.878 26.5C123.531 26.1667 123.311 25.72 123.218 25.16H123.098C122.938 25.84 122.585 26.36 122.038 26.72C121.491 27.0667 120.818 27.24 120.018 27.24C118.965 27.24 118.158 26.96 117.598 26.4C117.038 25.84 116.758 25.1 116.758 24.18C116.758 23.0733 117.158 22.2533 117.958 21.72C118.771 21.1733 119.871 20.9 121.258 20.9H122.918V20.24C122.918 19.7333 122.785 19.3333 122.518 19.04C122.251 18.7333 121.805 18.58 121.178 18.58C120.591 18.58 120.125 18.7067 119.778 18.96C119.431 19.2133 119.145 19.5 118.918 19.82L117.158 18.26C117.585 17.6333 118.118 17.1467 118.758 16.8C119.411 16.44 120.291 16.26 121.398 16.26C122.891 16.26 124.011 16.5867 124.758 17.24C125.505 17.8933 125.878 18.8467 125.878 20.1V24.7H126.858V27H125.218ZM121.118 25.18C121.611 25.18 122.031 25.0733 122.378 24.86C122.738 24.6467 122.918 24.3 122.918 23.82V22.58H121.478C120.318 22.58 119.738 22.9733 119.738 23.76V24.06C119.738 24.4467 119.858 24.7333 120.098 24.92C120.338 25.0933 120.678 25.18 121.118 25.18ZM130.553 18.8H127.513V16.5H136.553V18.8H133.513V27H130.553V18.8ZM138.337 16.5H141.297V19.62H144.057C144.564 19.62 145.037 19.7 145.477 19.86C145.917 20.02 146.297 20.26 146.617 20.58C146.95 20.8867 147.21 21.2667 147.397 21.72C147.584 22.1733 147.677 22.7 147.677 23.3C147.677 23.9 147.584 24.4333 147.397 24.9C147.21 25.3533 146.95 25.74 146.617 26.06C146.297 26.3667 145.917 26.6 145.477 26.76C145.037 26.92 144.564 27 144.057 27H138.337V16.5ZM143.417 24.9C143.804 24.9 144.11 24.8 144.337 24.6C144.577 24.3867 144.697 24.0867 144.697 23.7V22.92C144.697 22.5333 144.577 22.24 144.337 22.04C144.11 21.8267 143.804 21.72 143.417 21.72H141.297V24.9H143.417Z" fill="#472402"/>
+<path opacity="0.8" d="M74.308 45.144C73.74 45.144 73.228 45.056 72.772 44.88C72.316 44.696 71.928 44.428 71.608 44.076C71.288 43.716 71.04 43.272 70.864 42.744C70.688 42.208 70.6 41.584 70.6 40.872C70.6 40.168 70.688 39.544 70.864 39C71.04 38.448 71.288 37.988 71.608 37.62C71.928 37.244 72.316 36.96 72.772 36.768C73.228 36.576 73.74 36.48 74.308 36.48C75.084 36.48 75.724 36.64 76.228 36.96C76.732 37.272 77.136 37.768 77.44 38.448L75.868 39.264C75.756 38.912 75.58 38.632 75.34 38.424C75.108 38.208 74.764 38.1 74.308 38.1C73.772 38.1 73.34 38.276 73.012 38.628C72.692 38.972 72.532 39.476 72.532 40.14V41.484C72.532 42.148 72.692 42.656 73.012 43.008C73.34 43.352 73.772 43.524 74.308 43.524C74.756 43.524 75.112 43.404 75.376 43.164C75.648 42.916 75.848 42.62 75.976 42.276L77.464 43.14C77.152 43.78 76.74 44.276 76.228 44.628C75.724 44.972 75.084 45.144 74.308 45.144ZM84.0243 45.144C83.5523 45.144 83.1323 45.068 82.7643 44.916C82.3963 44.756 82.0883 44.536 81.8403 44.256C81.5923 43.968 81.4043 43.62 81.2763 43.212C81.1483 42.804 81.0843 42.348 81.0843 41.844C81.0843 41.34 81.1483 40.888 81.2763 40.488C81.4043 40.08 81.5923 39.732 81.8403 39.444C82.0883 39.156 82.3963 38.936 82.7643 38.784C83.1323 38.632 83.5523 38.556 84.0243 38.556C84.6643 38.556 85.1963 38.7 85.6203 38.988C86.0523 39.276 86.3603 39.68 86.5443 40.2L85.1043 40.824C85.0483 40.584 84.9323 40.38 84.7563 40.212C84.5803 40.044 84.3363 39.96 84.0243 39.96C83.6643 39.96 83.3923 40.08 83.2083 40.32C83.0243 40.552 82.9323 40.868 82.9323 41.268V42.444C82.9323 42.844 83.0243 43.16 83.2083 43.392C83.3923 43.624 83.6643 43.74 84.0243 43.74C84.3443 43.74 84.5963 43.656 84.7803 43.488C84.9723 43.312 85.1123 43.084 85.2003 42.804L86.5803 43.404C86.3723 44.004 86.0483 44.444 85.6083 44.724C85.1763 45.004 84.6483 45.144 84.0243 45.144ZM92.3356 45C92.0156 45 91.7476 44.9 91.5316 44.7C91.3236 44.5 91.1916 44.232 91.1356 43.896H91.0636C90.9676 44.304 90.7556 44.616 90.4276 44.832C90.0996 45.04 89.6956 45.144 89.2156 45.144C88.5836 45.144 88.0996 44.976 87.7636 44.64C87.4276 44.304 87.2596 43.86 87.2596 43.308C87.2596 42.644 87.4996 42.152 87.9796 41.832C88.4676 41.504 89.1276 41.34 89.9596 41.34H90.9556V40.944C90.9556 40.64 90.8756 40.4 90.7156 40.224C90.5556 40.04 90.2876 39.948 89.9116 39.948C89.5596 39.948 89.2796 40.024 89.0716 40.176C88.8636 40.328 88.6916 40.5 88.5556 40.692L87.4996 39.756C87.7556 39.38 88.0756 39.088 88.4596 38.88C88.8516 38.664 89.3796 38.556 90.0436 38.556C90.9396 38.556 91.6116 38.752 92.0596 39.144C92.5076 39.536 92.7316 40.108 92.7316 40.86V43.62H93.3196V45H92.3356ZM89.8756 43.908C90.1716 43.908 90.4236 43.844 90.6316 43.716C90.8476 43.588 90.9556 43.38 90.9556 43.092V42.348H90.0916C89.3956 42.348 89.0476 42.584 89.0476 43.056V43.236C89.0476 43.468 89.1196 43.64 89.2636 43.752C89.4076 43.856 89.6116 43.908 89.8756 43.908ZM94.5116 38.7H96.2516V41.232L96.0956 42.696H96.1316L96.8636 41.352L98.6156 38.7H100.2V45H98.4596V42.468L98.6156 41.004H98.5796L97.8476 42.348L96.0956 45H94.5116V38.7ZM97.3676 38.052C96.8396 38.052 96.4116 37.936 96.0836 37.704C95.7556 37.472 95.4996 37.14 95.3156 36.708L95.0636 36.096L96.4436 35.58L96.8276 36.792C96.8756 36.816 96.9516 36.836 97.0556 36.852C97.1596 36.868 97.2636 36.876 97.3676 36.876C97.4716 36.876 97.5756 36.868 97.6796 36.852C97.7836 36.836 97.8596 36.816 97.9076 36.792L98.2916 35.58L99.6716 36.096L99.4196 36.708C99.2356 37.14 98.9796 37.472 98.6516 37.704C98.3236 37.936 97.8956 38.052 97.3676 38.052ZM103.095 40.08H101.271V38.7H106.695V40.08H104.871V45H103.095V40.08ZM112.363 45C112.043 45 111.775 44.9 111.559 44.7C111.351 44.5 111.219 44.232 111.163 43.896H111.091C110.995 44.304 110.783 44.616 110.455 44.832C110.127 45.04 109.723 45.144 109.243 45.144C108.611 45.144 108.127 44.976 107.791 44.64C107.455 44.304 107.287 43.86 107.287 43.308C107.287 42.644 107.527 42.152 108.007 41.832C108.495 41.504 109.155 41.34 109.987 41.34H110.983V40.944C110.983 40.64 110.903 40.4 110.743 40.224C110.583 40.04 110.315 39.948 109.939 39.948C109.587 39.948 109.307 40.024 109.099 40.176C108.891 40.328 108.719 40.5 108.583 40.692L107.527 39.756C107.783 39.38 108.103 39.088 108.487 38.88C108.879 38.664 109.407 38.556 110.071 38.556C110.967 38.556 111.639 38.752 112.087 39.144C112.535 39.536 112.759 40.108 112.759 40.86V43.62H113.347V45H112.363ZM109.903 43.908C110.199 43.908 110.451 43.844 110.659 43.716C110.875 43.588 110.983 43.38 110.983 43.092V42.348H110.119C109.423 42.348 109.075 42.584 109.075 43.056V43.236C109.075 43.468 109.147 43.64 109.291 43.752C109.435 43.856 109.639 43.908 109.903 43.908Z" fill="#472402"/>
+<path d="M37.4987 29.5415V37.8748L33.332 33.7082" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M37.5 37.8752L41.6667 33.7085" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M29.5766 31.9052C28.7259 31.161 28.0598 30.2292 27.631 29.1833C27.2022 28.1374 27.0224 27.0062 27.1058 25.8789C27.1893 24.7516 27.5336 23.6592 28.1118 22.6879C28.6899 21.7165 29.4859 20.8929 30.437 20.282C31.388 19.6712 32.4681 19.2898 33.5919 19.1679C34.7157 19.0461 35.8524 19.1873 36.9122 19.5802C37.9721 19.9731 38.9261 20.6071 39.6989 21.432C40.4717 22.2569 41.0422 23.2502 41.3652 24.3334H43.2298C44.2423 24.3332 45.2277 24.661 46.0385 25.2676C46.8492 25.8742 47.4418 26.727 47.7274 27.6985C48.0131 28.6699 47.9765 29.7077 47.6232 30.6566C47.2698 31.6055 46.6187 32.4145 45.7673 32.9625" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/metadata/img-readme/download-website.svg b/metadata/img-readme/download-website.svg
new file mode 100644
index 000000000..d0cf83753
--- /dev/null
+++ b/metadata/img-readme/download-website.svg
@@ -0,0 +1,8 @@
+<svg width="208" height="56" viewBox="0 0 208 56" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="208" height="56" rx="16" fill="#FBB36A"/>
+<path d="M70.206 13.04H75.466C76.386 13.04 77.226 13.1867 77.986 13.48C78.746 13.7733 79.3927 14.2133 79.926 14.8C80.4593 15.3733 80.8727 16.1 81.166 16.98C81.4593 17.8467 81.606 18.86 81.606 20.02C81.606 21.18 81.4593 22.2 81.166 23.08C80.8727 23.9467 80.4593 24.6733 79.926 25.26C79.3927 25.8333 78.746 26.2667 77.986 26.56C77.226 26.8533 76.386 27 75.466 27H70.206V13.04ZM75.466 24.3C76.3727 24.3 77.086 24.0467 77.606 23.54C78.126 23.0333 78.386 22.22 78.386 21.1V18.94C78.386 17.82 78.126 17.0067 77.606 16.5C77.086 15.9933 76.3727 15.74 75.466 15.74H73.246V24.3H75.466ZM88.2513 27.24C87.478 27.24 86.7847 27.1133 86.1713 26.86C85.5713 26.6067 85.058 26.24 84.6313 25.76C84.218 25.28 83.898 24.7 83.6713 24.02C83.4447 23.34 83.3313 22.58 83.3313 21.74C83.3313 20.9 83.4447 20.14 83.6713 19.46C83.898 18.78 84.218 18.2067 84.6313 17.74C85.058 17.26 85.5713 16.8933 86.1713 16.64C86.7847 16.3867 87.478 16.26 88.2513 16.26C89.0247 16.26 89.7113 16.3867 90.3113 16.64C90.9247 16.8933 91.438 17.26 91.8513 17.74C92.278 18.2067 92.6047 18.78 92.8313 19.46C93.058 20.14 93.1713 20.9 93.1713 21.74C93.1713 22.58 93.058 23.34 92.8313 24.02C92.6047 24.7 92.278 25.28 91.8513 25.76C91.438 26.24 90.9247 26.6067 90.3113 26.86C89.7113 27.1133 89.0247 27.24 88.2513 27.24ZM88.2513 24.9C88.838 24.9 89.2913 24.72 89.6113 24.36C89.9313 24 90.0913 23.4867 90.0913 22.82V20.68C90.0913 20.0133 89.9313 19.5 89.6113 19.14C89.2913 18.78 88.838 18.6 88.2513 18.6C87.6647 18.6 87.2113 18.78 86.8913 19.14C86.5713 19.5 86.4113 20.0133 86.4113 20.68V22.82C86.4113 23.4867 86.5713 24 86.8913 24.36C87.2113 24.72 87.6647 24.9 88.2513 24.9ZM94.0851 16.5H96.9451L97.9651 20.74L98.6851 23.94H98.7651L99.6051 20.74L100.805 16.5H103.505L104.725 20.74L105.585 23.94H105.665L106.385 20.74L107.405 16.5H110.145L107.245 27H104.145L102.865 22.56L102.125 19.84H102.065L101.345 22.56L100.065 27H97.0251L94.0851 16.5ZM111.901 27V16.5H114.861V18.28H114.981C115.168 17.7333 115.495 17.26 115.961 16.86C116.428 16.46 117.075 16.26 117.901 16.26C118.981 16.26 119.795 16.62 120.341 17.34C120.901 18.06 121.181 19.0867 121.181 20.42V27H118.221V20.66C118.221 19.98 118.115 19.48 117.901 19.16C117.688 18.8267 117.308 18.66 116.761 18.66C116.521 18.66 116.288 18.6933 116.061 18.76C115.835 18.8133 115.628 18.9067 115.441 19.04C115.268 19.1733 115.128 19.34 115.021 19.54C114.915 19.7267 114.861 19.9467 114.861 20.2V27H111.901ZM126.756 27C125.742 27 124.996 26.7533 124.516 26.26C124.049 25.7667 123.816 25.0533 123.816 24.12V12.2H126.776V24.7H128.096V27H126.756ZM134.13 27.24C133.357 27.24 132.664 27.1133 132.05 26.86C131.45 26.6067 130.937 26.24 130.51 25.76C130.097 25.28 129.777 24.7 129.55 24.02C129.324 23.34 129.21 22.58 129.21 21.74C129.21 20.9 129.324 20.14 129.55 19.46C129.777 18.78 130.097 18.2067 130.51 17.74C130.937 17.26 131.45 16.8933 132.05 16.64C132.664 16.3867 133.357 16.26 134.13 16.26C134.904 16.26 135.59 16.3867 136.19 16.64C136.804 16.8933 137.317 17.26 137.73 17.74C138.157 18.2067 138.484 18.78 138.71 19.46C138.937 20.14 139.05 20.9 139.05 21.74C139.05 22.58 138.937 23.34 138.71 24.02C138.484 24.7 138.157 25.28 137.73 25.76C137.317 26.24 136.804 26.6067 136.19 26.86C135.59 27.1133 134.904 27.24 134.13 27.24ZM134.13 24.9C134.717 24.9 135.17 24.72 135.49 24.36C135.81 24 135.97 23.4867 135.97 22.82V20.68C135.97 20.0133 135.81 19.5 135.49 19.14C135.17 18.78 134.717 18.6 134.13 18.6C133.544 18.6 133.09 18.78 132.77 19.14C132.45 19.5 132.29 20.0133 132.29 20.68V22.82C132.29 23.4867 132.45 24 132.77 24.36C133.09 24.72 133.544 24.9 134.13 24.9ZM148.919 27C148.386 27 147.939 26.8333 147.579 26.5C147.233 26.1667 147.013 25.72 146.919 25.16H146.799C146.639 25.84 146.286 26.36 145.739 26.72C145.193 27.0667 144.519 27.24 143.719 27.24C142.666 27.24 141.859 26.96 141.299 26.4C140.739 25.84 140.459 25.1 140.459 24.18C140.459 23.0733 140.859 22.2533 141.659 21.72C142.473 21.1733 143.573 20.9 144.959 20.9H146.619V20.24C146.619 19.7333 146.486 19.3333 146.219 19.04C145.953 18.7333 145.506 18.58 144.879 18.58C144.293 18.58 143.826 18.7067 143.479 18.96C143.133 19.2133 142.846 19.5 142.619 19.82L140.859 18.26C141.286 17.6333 141.819 17.1467 142.459 16.8C143.113 16.44 143.993 16.26 145.099 16.26C146.593 16.26 147.713 16.5867 148.459 17.24C149.206 17.8933 149.579 18.8467 149.579 20.1V24.7H150.559V27H148.919ZM144.819 25.18C145.313 25.18 145.733 25.0733 146.079 24.86C146.439 24.6467 146.619 24.3 146.619 23.82V22.58H145.179C144.019 22.58 143.439 22.9733 143.439 23.76V24.06C143.439 24.4467 143.559 24.7333 143.799 24.92C144.039 25.0933 144.379 25.18 144.819 25.18ZM158.986 25.24H158.886C158.806 25.52 158.679 25.7867 158.506 26.04C158.333 26.28 158.119 26.4933 157.866 26.68C157.626 26.8533 157.346 26.9867 157.026 27.08C156.719 27.1867 156.399 27.24 156.066 27.24C154.733 27.24 153.726 26.7733 153.046 25.84C152.366 24.8933 152.026 23.5267 152.026 21.74C152.026 19.9533 152.366 18.5933 153.046 17.66C153.726 16.7267 154.733 16.26 156.066 16.26C156.746 16.26 157.346 16.4467 157.866 16.82C158.399 17.1933 158.739 17.6733 158.886 18.26H158.986V12.2H161.946V27H158.986V25.24ZM157.046 24.84C157.606 24.84 158.066 24.7067 158.426 24.44C158.799 24.16 158.986 23.78 158.986 23.3V20.2C158.986 19.72 158.799 19.3467 158.426 19.08C158.066 18.8 157.606 18.66 157.046 18.66C156.486 18.66 156.019 18.86 155.646 19.26C155.286 19.6467 155.106 20.1733 155.106 20.84V22.66C155.106 23.3267 155.286 23.86 155.646 24.26C156.019 24.6467 156.486 24.84 157.046 24.84Z" fill="#472402"/>
+<path opacity="0.8" d="M70.924 45V36.624H76.48V38.244H72.748V39.96H75.928V41.568H72.748V45H70.924ZM77.4843 45V38.7H79.2603V40.068H79.3203C79.3523 39.892 79.4083 39.724 79.4883 39.564C79.5683 39.396 79.6723 39.248 79.8003 39.12C79.9363 38.992 80.0963 38.892 80.2803 38.82C80.4643 38.74 80.6803 38.7 80.9283 38.7H81.2403V40.356H80.7963C80.2763 40.356 79.8883 40.424 79.6323 40.56C79.3843 40.696 79.2603 40.948 79.2603 41.316V45H77.4843ZM84.8332 45.144C84.3692 45.144 83.9532 45.068 83.5852 44.916C83.2252 44.764 82.9172 44.544 82.6612 44.256C82.4132 43.968 82.2212 43.62 82.0852 43.212C81.9492 42.804 81.8812 42.348 81.8812 41.844C81.8812 41.34 81.9492 40.884 82.0852 40.476C82.2212 40.068 82.4132 39.724 82.6612 39.444C82.9172 39.156 83.2252 38.936 83.5852 38.784C83.9532 38.632 84.3692 38.556 84.8332 38.556C85.2972 38.556 85.7092 38.632 86.0692 38.784C86.4372 38.936 86.7452 39.156 86.9932 39.444C87.2492 39.724 87.4452 40.068 87.5812 40.476C87.7172 40.884 87.7852 41.34 87.7852 41.844C87.7852 42.348 87.7172 42.804 87.5812 43.212C87.4452 43.62 87.2492 43.968 86.9932 44.256C86.7452 44.544 86.4372 44.764 86.0692 44.916C85.7092 45.068 85.2972 45.144 84.8332 45.144ZM84.8332 43.74C85.1852 43.74 85.4572 43.632 85.6492 43.416C85.8412 43.2 85.9372 42.892 85.9372 42.492V41.208C85.9372 40.808 85.8412 40.5 85.6492 40.284C85.4572 40.068 85.1852 39.96 84.8332 39.96C84.4812 39.96 84.2092 40.068 84.0172 40.284C83.8252 40.5 83.7292 40.808 83.7292 41.208V42.492C83.7292 42.892 83.8252 43.2 84.0172 43.416C84.2092 43.632 84.4812 43.74 84.8332 43.74ZM89.0507 45V38.7H90.8267V39.768H90.8987C91.0107 39.432 91.2027 39.148 91.4747 38.916C91.7467 38.676 92.1187 38.556 92.5907 38.556C93.0227 38.556 93.3907 38.664 93.6947 38.88C93.9987 39.096 94.2187 39.412 94.3547 39.828H94.3907C94.4467 39.652 94.5307 39.488 94.6427 39.336C94.7627 39.176 94.9067 39.04 95.0747 38.928C95.2427 38.816 95.4307 38.728 95.6387 38.664C95.8467 38.592 96.0707 38.556 96.3107 38.556C96.9187 38.556 97.3827 38.772 97.7027 39.204C98.0307 39.636 98.1947 40.252 98.1947 41.052V45H96.4187V41.196C96.4187 40.396 96.1307 39.996 95.5547 39.996C95.2907 39.996 95.0507 40.072 94.8347 40.224C94.6187 40.376 94.5107 40.608 94.5107 40.92V45H92.7347V41.196C92.7347 40.396 92.4467 39.996 91.8707 39.996C91.7427 39.996 91.6147 40.016 91.4867 40.056C91.3667 40.088 91.2547 40.144 91.1507 40.224C91.0547 40.304 90.9747 40.404 90.9107 40.524C90.8547 40.636 90.8267 40.768 90.8267 40.92V45H89.0507ZM102.009 38.7H103.725L104.337 41.244L104.769 43.164H104.817L105.321 41.244L106.041 38.7H107.661L108.393 41.244L108.909 43.164H108.957L109.389 41.244L110.001 38.7H111.645L109.905 45H108.045L107.277 42.336L106.833 40.704H106.797L106.365 42.336L105.597 45H103.773L102.009 38.7ZM115.21 45.144C114.73 45.144 114.302 45.068 113.926 44.916C113.55 44.756 113.23 44.536 112.966 44.256C112.71 43.968 112.514 43.62 112.378 43.212C112.25 42.804 112.186 42.348 112.186 41.844C112.186 41.348 112.25 40.9 112.378 40.5C112.506 40.092 112.694 39.744 112.942 39.456C113.198 39.168 113.51 38.948 113.878 38.796C114.246 38.636 114.666 38.556 115.138 38.556C115.658 38.556 116.102 38.644 116.47 38.82C116.846 38.996 117.15 39.232 117.382 39.528C117.622 39.824 117.794 40.168 117.898 40.56C118.01 40.944 118.066 41.348 118.066 41.772V42.3H114.022V42.396C114.022 42.812 114.134 43.144 114.358 43.392C114.582 43.632 114.934 43.752 115.414 43.752C115.782 43.752 116.082 43.68 116.314 43.536C116.546 43.384 116.762 43.204 116.962 42.996L117.85 44.1C117.57 44.428 117.202 44.684 116.746 44.868C116.298 45.052 115.786 45.144 115.21 45.144ZM115.174 39.864C114.814 39.864 114.53 39.984 114.322 40.224C114.122 40.456 114.022 40.768 114.022 41.16V41.256H116.23V41.148C116.23 40.764 116.142 40.456 115.966 40.224C115.798 39.984 115.534 39.864 115.174 39.864ZM119.32 36.12H121.096V39.756H121.156C121.244 39.404 121.444 39.116 121.756 38.892C122.076 38.668 122.44 38.556 122.848 38.556C123.648 38.556 124.252 38.836 124.66 39.396C125.068 39.956 125.272 40.772 125.272 41.844C125.272 42.916 125.068 43.736 124.66 44.304C124.252 44.864 123.648 45.144 122.848 45.144C122.64 45.144 122.444 45.112 122.26 45.048C122.076 44.992 121.908 44.912 121.756 44.808C121.612 44.696 121.488 44.568 121.384 44.424C121.28 44.272 121.204 44.112 121.156 43.944H121.096V45H119.32V36.12ZM122.26 43.704C122.596 43.704 122.872 43.588 123.088 43.356C123.312 43.116 123.424 42.796 123.424 42.396V41.304C123.424 40.904 123.312 40.588 123.088 40.356C122.872 40.116 122.596 39.996 122.26 39.996C121.924 39.996 121.644 40.08 121.42 40.248C121.204 40.408 121.096 40.632 121.096 40.92V42.78C121.096 43.068 121.204 43.296 121.42 43.464C121.644 43.624 121.924 43.704 122.26 43.704ZM128.757 45.144C128.149 45.144 127.637 45.048 127.221 44.856C126.805 44.656 126.433 44.376 126.105 44.016L127.149 42.96C127.373 43.208 127.621 43.404 127.893 43.548C128.165 43.692 128.473 43.764 128.817 43.764C129.169 43.764 129.413 43.712 129.549 43.608C129.685 43.496 129.753 43.348 129.753 43.164C129.753 42.868 129.541 42.692 129.117 42.636L128.433 42.552C127.017 42.376 126.309 41.728 126.309 40.608C126.309 40.304 126.365 40.028 126.477 39.78C126.597 39.524 126.761 39.308 126.969 39.132C127.185 38.948 127.441 38.808 127.737 38.712C128.041 38.608 128.381 38.556 128.757 38.556C129.085 38.556 129.373 38.58 129.621 38.628C129.877 38.668 130.101 38.732 130.293 38.82C130.493 38.9 130.673 39.004 130.833 39.132C131.001 39.252 131.165 39.388 131.325 39.54L130.305 40.584C130.105 40.384 129.877 40.228 129.621 40.116C129.373 39.996 129.117 39.936 128.853 39.936C128.549 39.936 128.333 39.984 128.205 40.08C128.077 40.176 128.013 40.304 128.013 40.464C128.013 40.632 128.057 40.764 128.145 40.86C128.241 40.948 128.417 41.012 128.673 41.052L129.381 41.148C130.765 41.332 131.457 41.964 131.457 43.044C131.457 43.348 131.393 43.628 131.265 43.884C131.137 44.14 130.953 44.364 130.713 44.556C130.481 44.74 130.197 44.884 129.861 44.988C129.533 45.092 129.165 45.144 128.757 45.144ZM133.556 38.028C133.196 38.028 132.932 37.948 132.764 37.788C132.604 37.62 132.524 37.408 132.524 37.152V36.888C132.524 36.632 132.604 36.424 132.764 36.264C132.932 36.096 133.196 36.012 133.556 36.012C133.916 36.012 134.176 36.096 134.336 36.264C134.504 36.424 134.588 36.632 134.588 36.888V37.152C134.588 37.408 134.504 37.62 134.336 37.788C134.176 37.948 133.916 38.028 133.556 38.028ZM132.668 38.7H134.444V45H132.668V38.7ZM138.309 45C137.693 45 137.225 44.844 136.905 44.532C136.593 44.22 136.437 43.764 136.437 43.164V40.08H135.549V38.7H135.993C136.233 38.7 136.397 38.644 136.485 38.532C136.573 38.412 136.617 38.244 136.617 38.028V36.996H138.213V38.7H139.461V40.08H138.213V43.62H139.365V45H138.309ZM143.276 45.144C142.796 45.144 142.368 45.068 141.992 44.916C141.616 44.756 141.296 44.536 141.032 44.256C140.776 43.968 140.58 43.62 140.444 43.212C140.316 42.804 140.252 42.348 140.252 41.844C140.252 41.348 140.316 40.9 140.444 40.5C140.572 40.092 140.76 39.744 141.008 39.456C141.264 39.168 141.576 38.948 141.944 38.796C142.312 38.636 142.732 38.556 143.204 38.556C143.724 38.556 144.168 38.644 144.536 38.82C144.912 38.996 145.216 39.232 145.448 39.528C145.688 39.824 145.86 40.168 145.964 40.56C146.076 40.944 146.132 41.348 146.132 41.772V42.3H142.088V42.396C142.088 42.812 142.2 43.144 142.424 43.392C142.648 43.632 143 43.752 143.48 43.752C143.848 43.752 144.148 43.68 144.38 43.536C144.612 43.384 144.828 43.204 145.028 42.996L145.916 44.1C145.636 44.428 145.268 44.684 144.812 44.868C144.364 45.052 143.852 45.144 143.276 45.144ZM143.24 39.864C142.88 39.864 142.596 39.984 142.388 40.224C142.188 40.456 142.088 40.768 142.088 41.16V41.256H144.296V41.148C144.296 40.764 144.208 40.456 144.032 40.224C143.864 39.984 143.6 39.864 143.24 39.864Z" fill="#472402"/>
+<path d="M37.4987 29.5417V37.8751L33.332 33.7084" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M37.5 37.8749L41.6667 33.7083" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M29.5766 31.9052C28.7259 31.161 28.0598 30.2292 27.631 29.1833C27.2022 28.1374 27.0224 27.0062 27.1058 25.8789C27.1893 24.7516 27.5336 23.6592 28.1118 22.6879C28.6899 21.7165 29.4859 20.8929 30.437 20.282C31.388 19.6712 32.4681 19.2898 33.5919 19.1679C34.7157 19.0461 35.8524 19.1873 36.9122 19.5802C37.9721 19.9731 38.9261 20.6071 39.6989 21.432C40.4717 22.2569 41.0422 23.2502 41.3652 24.3334H43.2298C44.2423 24.3332 45.2277 24.661 46.0385 25.2676C46.8492 25.8742 47.4418 26.727 47.7274 27.6985C48.0131 28.6699 47.9765 29.7077 47.6232 30.6566C47.2698 31.6055 46.6187 32.4145 45.7673 32.9625" stroke="#472402" stroke-width="3.33" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/metadata/img-readme/download.png b/metadata/img-readme/download.png
deleted file mode 100644
index 0e6a88500..000000000
Binary files a/metadata/img-readme/download.png and /dev/null differ
diff --git a/metadata/img-readme/play.png b/metadata/img-readme/play.png
deleted file mode 100644
index 2fb316c8d..000000000
Binary files a/metadata/img-readme/play.png and /dev/null differ