Глава 43. Объект JS и JS-ресурс EasyBuilder на русском Руководство пользователя
В этом руководстве мы расскажем вам про такие объекты, как: Объект JS и JS-ресурс.
43.1 Обзор
С помощью объектов JS можно можно проектировать функционал для панелей оператора, который нельзя сделать с помощью встроенных функций EasyBuilder Pro. Использование JavaScript позволяет свободно контролировать внешний вид и поведением объектов.
43.1.1 Предложения по использованию
Используйте встроенные функции EasyBuilder Pro там, где это возможно, в свою очередь объекты JS могут пригодиться когда требования трудно или невозможно выполнить с помощью встроенных функций.
При разработке проекта в старайтесь использовать встроенные функции EasyBuilder Pro, и когда стандартных возможностей будет не хватать, вы можете использовать JS
43.1.2 Требования к оборудованию и программному обеспечению
- -EasyBuilder Pro V6.05.01 или новее
- Используется JavaScript версии: ECMAScript 2017 (кроме SharedArrayBuffer и Atomics)
- Подходящие серии панелей оператора: серия cMT X
- Объекты JS не поддерживаются на 32-разрядных устройствах Android.

43.1.3 Предупреждение
Объекты JS предоставляют мощные возможности настройки, но их неправильное использование может привести к системным ошибкам или снижению производительности. Пожалуйста, используйте JS-объекты осторожно.
43.1.4. Объект JS — SDK
Для получения дополнительной информации о SDK, поддерживаемом Объектом JS, перейдите по этой ссылке:
JS Object SDK
43.2. Объект JS
Конфигурирование
Конфигурация свойств объекта JS может содержать следующие типы данных:
- Адрес
- Подписка
- Пользовательские данные к которым можно обращаться в JS функции
Эти данные будут доступны в объекте: “config” и обращение будет выглядеть следующим образом: this.config
| Настройка | Описание |
|---|---|
| Новый объект | Добавляет новый объект JavaScript, который может иметь свои объекты, и другие свойства |
| Новый массив | Добавляет новый массив |
| Новое значение | Добавляет новое значение со следующими типами данных: Строка Число Булево значение Адрес Подписка |
| Удалить | Удаляет выбранный элемент |
| Настройки | Изменяет выбранный элемент |
| Копировать | Копирует выбранный элемент |
| Вставить | Вставляет копию элемента в выбранное место |
| Шаблон | Показывает текущую структуру объектов в формате JSON в окне редактирования. После редактирования содержимого JSON и последующего нажатия кнопки [OK] содержимое (JSON) будет проанализировано и преобразовано обратно в конфигурацию. Пользователи, знакомые с JSON, могут с его помощью ускорить процесс настройки. |
Вкладка исходный код
| Настройка | Описание |
|---|---|
| Компиляция | Скомпилируйте исходный код, чтобы проверить, правильно ли он работает. |
| Отредактируйте исходный код в отдельном всплывающем окне. |
43.3 JS-ресурс
При использовании внешних модулей JS для объектов JS сначала добавьте модули JS в ресурс JS проекта EasyBuilder Pro, а затем модули можно будет импортировать в [исходный код] объектов JS.
На снимке экрана ниже показан пример JS-ресурса, а его настройки описаны в таблице ниже.
| Настройка | Описание |
|---|---|
| Имя | Имя импортированного файла или папки |
| Новая папка | Создать новую папку |
| Добавить папку | Импорт папки |
| Добавить файл | Импорт файла |
| Удалить | Удаление файла или папки |
| Переименовать | Изменение папки или файла |
| Скопировать путь | Скопировать путь до папки или файла |
Заметка:
Максимальный общий размер ресурсов JS: 10 МБ.
43.3.1. Временная папка
При открытии проекта EasyBuilder Pro создает временную папку и извлекает в нее содержимое ресурса JS. При сохранении проекта EasyBuilder Pro синхронизирует содержимое временной папки с проектом.
43.3.1.1. Открытие временной папки
В окне ресурсов JS выберите файл или папку, а затем щелкните правой кнопкой мыши, чтобы открыть меню, и выберите [Открыть содержащую папку].
Изменения, внесенные в папку, также будут отображаться в окне ресурсов JS.
Заметка:
- Временная папка создается автоматически при открытии проекта и автоматически удаляется при закрытии проекта.
- Имя временной папки не фиксировано и генерируется случайным образом при открытии проекта.
- Внесение изменений во временную папку переведет проект в состояние «Изменено», и содержимое временной папки будет синхронизироваться с проектом только тогда, когда пользователь сохранит проект
43.4. Пример работы
В этой главе демонстрируются некоторые примеры, призванные помочь пользователям научиться использовать объект JS.
Для получения дополнительной информации о функциях и классах, используемых для программного кода, см. JS Object SDK.
43.4.1 Имитация объекта [Переключатель]
В этой главе мы сделаем JS Объект, который будет имитировать функционал объекта [Переключатель]
Для этого:
- Разработайте объект JS, который может читать назначенный адрес и инвертировать сигнал.
- Включите возможность установки назначенного адреса для объекта JS.
- Включите возможность выключить назначенный адрес для объекта JS.
- Включите возможность инвертировать состояние назначенного адреса для объекта JS.
- Включите функцию мгновенного управления для объекта JS.
Чтобы спроектировать объект JS для реализации функции переключателя, имена свойств объекта JS, которые соответствуют настройкам тумблера, показаны ниже.
Мы откроем настройки объекта [Переключатель] и продумаем на перед, какие объекты нам понадобятся.
43.4.1.1. Объект JS, который считывает адрес и инвертирует сигнал
Сейчас мы создадим объект JS для чтения назначенного адреса и инвертирования сигнала.
| Настройка | Описание |
|---|---|
| readAddressSub | Чтение состояния назначенного битового адреса. Установите [Тип] на [Подписка], установите [Тип значения] на [Бит] и установите адрес на [LB-100]. |
| invertSignal | Выберите, нужно ли инвертировать сигнал. Установите [Тип] на [Boolean], установите [Значение] на [false] (не инвертировать сигнал) |
Вкладка исходный код
Во вкладке Исходный код мы напишем логику работы нашего JS объекта.
- Строка 2: this — объект JS. Через ‘this.config’ мы получаем доступ к значением наших значений (‘readAddressSub’ и ‘invertSignal’)
- Строка 2: Вызов функции onResponse объекта this.config.readAddressSub для получение уведомления при изменении значения в адресе чтения.

- Строка 3 ~ 9: Определение условий выполнения функции
- Строка 3 ~ 4: Проверка, не произошла ли ошибка. Выведет сообщение об ошибке в консоль отладки, если произошла ошибка.
- Строка 5 ~ 8: Если переменная err имеет значение Null, то, чтение прошло успешно и было обнаружено изменение данных. Затем устанавливается состояние объекта JS в соответствии с данными и свойством invertSignal.
| Значение в Адресе чтения | Инверсия | Состояние JS объекта |
| 0 | False | 0 |
| 1 | False | 1 |
| 0 | True | 1 |
| 1 | True | 0 |
43.4.1.2. Режим переключателя [Установить ON]
Следуя предыдущему разделу, в этом разделе объясняется, как заставить объект JS работать как переключатель в режиме ON. Для этого необходимо добавить еще два свойства: writeAddress и switchStyle.
Вкладка конфигурирование
| Настройка | Описание |
|---|---|
| readAddressSub | Чтение адреса |
| invertSignal | Инверсия входного сигнала.![]() |
| writeAddress | Установите адрес для записи. Когда пользователь нажимает этот объект, значение будет записано по этому адресу в соответствии со значением ‘switchStyle’. |
| switchStyle | Установка режима. Укажите значение [Set ON]. |
Вкладка исходный код
Используйте объект MouseArea для выполнения операции записи при нажатии или отпускании объекта.
- Строка 1 ~ 11: смотрите главу 43.4.1.1 в этом руководстве пользователя.
- Строка 12: Создайте объект MouseArea с именем «mouseArea».
- Строка 13: ‘this.widget’ это графический виджет объекта JS. Этот виджет отвечает за отображение изображений и взаимодействие с пользователем.
- Строка 13: добавление mouseArea к объекту JS.
- Строка 15: Регистрация слушателя событий mousedown с помощью mouseArea. Когда пользователь нажимает на объект, mouseArea уведомляет слушателя с помощью объекта MouseEvent.

- Строка 15 ~ 19: слушатель события ‘mousedown’.
- Строка 16 ~ 18: Когда [Тип переключателя] установлен на «Set ON», значение 1 будет записано в [Адрес записи] с использованием метода setData модуля драйвера.
43.4.1.3. Режим переключателя [Установить OFF]
Следуя предыдущим разделам, в этом разделе объясняется, как заставить объект JS работать как тумблер, который может быть отключен.
| Настройка | Описание |
|---|---|
| readAddressSub | Чтение адреса |
| invertSignal | Инверсия входного сигнала. |
| writeAddress | Установите адрес для записи. Когда пользователь нажимает этот объект, значение будет записано по этому адресу в соответствии со значением ‘switchStyle’. |
| switchStyle | Установка режима. Укажите значение [Set OFF].![]() |
Вкладка исходный код
- Строка 1 ~ 17: Смотрите главу 43.4.1.2 руководства пользователя.
- Строка 18 ~ 19: Когда [Тип переключения] установлен на «OFF», значение 0 будет записано в [Адрес записи].
43.4.1.4. Режим переключателя [Переключить]
Сейчас мы превратим объект JS работать в объект переключатель в режиме [переключить], который будет инвертировать состояние назначенного адреса.
Вкладка конфигурирования
| Настройка | Описание |
|---|---|
| readAddressSub | Чтение адреса |
| invertSignal | Инверсия входного сигнала. |
| writeAddress | Установите адрес для записи. Когда пользователь нажимает этот объект, значение будет записано по этому адресу в соответствии со значением ‘switchStyle’. |
| switchStyle | Установка режима. Укажите значение [Toggle]. |
Вкладка исходный код
- Строка 1 ~ 19: Смотрите главу 43.4.1.3 данного руководства пользователя.
- Строка 20 ~ 23: Когда режим установлен на «Переключение», [Адрес записи] будет установлен в инвертированное состояние.
43.4.1.5. Режим переключателя [Моментально]
Сделаем объект JS который работает, как объект EasyBuilder [Переключатель] в мгновенном режиме.
Вкладка конфигурирования
| Настройка | Описание |
|---|---|
| readAddressSub | Чтение адреса |
| invertSignal | Инверсия входного сигнала. |
| writeAddress | Адрес записи, когда пользователь нажмет на объект, то по этому адресу будет записано значение 1, а когда пользователь отпустит этот объект, по этому адресу будет записано значение 0.![]() |
| switchStyle | Установите [Значение] на [Momentary]. |
Вкладка исходный код
- Строка 1 ~ 23: Смотрите главу 43.4.1.4 в этом руководстве пользователя.
- Строка 24 ~ 25: Когда установлен режим «Мгновенный» и нажат объект, будет записано значение 1 в [Адрес записи].
- Строка 29 ~ 33: Когда пользователь отпускает объект, будет записано значение 0 в [Адрес записи].
43.4.2. Примеры использования ресурсов JS
Мы познакомим вас с импортом внешних JS модулей в JS ресурсы
Объект JS поддерживает следующие способы импорта модулей:
- Динамический импорт ES6: используйте функцию import (). Обратите внимание, что статический импорт ES6 не поддерживается объектом JS.
- CommonJS: используйте функцию require ().
43.4.2.1. ES6 динамический импорт
На примере продемонстрируем импорт модулей JS с помощью динамического импорта ES6.
В объекте JS при изменении радиуса площадь и окружность круга могут быть вычислены с помощью функций в модуле JS (circle.js), и результат выводится по указанным адресам.
Программный код circle.js:
- Настройки для создания JS-объекта показаны ниже:
Настройка Описание radiusSub Получает текущее значение радиуса и отслеживает его изменения. (Выберите LW-100, 64-bit Double) areaAddress Адрес для вывода результата расчета площади круга. (Выберите LW-110, 64-bit Double) circumferenceAddress Адрес для вывода результата вычисления длины окружности. (Выберите LW-120, 64-bit Double) - Отредактируйте программный код, как показано ниже на странице настроек [Исходный код]:
- Строка 1: Импорт файл /circle.js из ресурсов JS и объявление объекта circle.

- Строка 3: вызовите функцию ‘this.config.radiusSub’ ‘onResponse’, чтобы регистрировать изменения в радиусе круга.
- Строка 8: вычисление площадь круга, вызов метода из circle.js, и сохранение результата в переменной area.
- Строка 9: вычисление длины окружности круга, вызов метода в circle.js, и сохранение результата в переменной circumference.
- Строка 1: Импорт файл /circle.js из ресурсов JS и объявление объекта circle.
- В проекте создайте три числовых объекта (64-битное Double) и установите адрес LW-100 (радиус), LW-110 (область) и LW-120 (окружность).
- При введении значения в LW-100 (Радиус), результаты автоматически обновляются в LW-110 (Площадь) и LW-120 (Окружность).
Заметка:
Чтобы импортировать модуль «default export», воспользуйтесь приведенным ниже кодом.
43.4.2.2. CommonJS
Следующая демонстрация показывает, как импортировать модули JS с помощью функции require (). Этот объект JS ведет себя так же, как при использовании ES6, но в этом разделе внешний модуль JS импортируется с использованием CommonJS.
Программный код circle.js:
- Настройки свойств такие же, как описано в предыдущем разделе.
- Отредактируйте программный код, как показано ниже на странице настроек [Исходный код]:
- Строка 1: импорт файла ‘/circle.js’ в ресурс JS и привязка результат к объекту circle.
- Строка 3 ~ 13: Смотрите главу 43.4.2.1 в данном руководстве пользователя.
- В проекте создайте три числовых объекта (64-битное Double) и установите адрес LW-100 (радиус), LW-110 (область) и LW-120 (окружность).
- Когда значения вводятся в LW-100 (Радиус), результаты автоматически обновляются в LW-110 (Площадь) и LW-120 (Окружность).
43.5. Ограничения
- Максимальный размер исходного кода JS-объекта: 100 КБ.
- Максимальный размер файла ресурсов JS: 10 МБ.
- Ограничение размера использования памяти JS-контекста (*): 20 МБ.
(*) Контекст JS — это изолированный контекст выполнения с собственным набором встроенных объектов и функций.
И все объекты JS в одном окне совместно используют один контекст JS, то есть используют одну и ту же кучу памяти и глобальный объект.
43.6 Жизненный цикл объекта JS
- Создание JS контекста
- Создание JS объекта
- Инициализация JS объекта ‘config’ (=>this.config).
- Инициализация JS объекта ‘widget’ (=>this.widget).
- Ожидание ответа от подписок
- Оборачивание исходного кода в функцию async и ее вызов
Object | JavaScript справочник
| Метод | Описание | Chrome | Firefox | Opera | Safari | IExplorer | Edge |
|---|---|---|---|---|---|---|---|
| assign() | Метод позволяет произвести поверхностное копирование значений всех перечислимых собственных свойств и методов из одного или нескольких исходных объектов в целевой объект. | 45.0 | 34.0 | 32.0 | 9.0 | Нет | Да |
| create() | Позволяет создать новый объект с указанным объектом прототипом и при необходимости свойствами, описываемые дескрипторами.![]() | 5.0 | 4.0 | 11.6 | 5.0 | 9.0 | Да |
| defineProperties() | Позволяет определить новые или изменить существующие свойства объекта, описывая их дескрипторами. | 5.0 | 4.0 | 11.6 | 5.1* | 9.0* | Да |
| defineProperty() | Позволяет определить новое или изменить существующее свойство объекта, описывая его дескрипторами. | 5.0 | 4.0 | 11.6 | 5.1* | 9.0* | Да |
| entries() | Позволяет возвратить массив, содержащий собственные перечислимые свойства и методы заданного объекта, включая их значения, при этом по каждому свойству или методу с его значением создается отдельный массив.![]() | 54.0 | 47.0 | Нет | 10.1 | Нет | Да |
| freeze() | Позволяет сделать объект нерасширяемым (предотвращает добавление новых собственных (неунаследованных) свойств), устанавливает все его собственные свойства как ненастраиваемые (предотвращает их удаление и изменение дескриптора), а также устанавливает все его собственные свойства недоступными для записи (изменение свойства объекта с помощью оператора присваивания не допускается). | 6.0 | 4.0 | 12.0 | 5.1 | 9.0 | Да |
| getOwnPropertyDescriptor() | Возвращает объект дескриптор для указанного собственного (неунаследованного) свойства заданного объекта. | 5.0 | 4.0 | 12.0 | 5.0 | 8.0 | Да |
| getOwnPropertyDescriptors() | Позволяет возвратить объект, содержащий дескрипторы всех собственных (неунаследованных) свойств заданного объекта. | 54.0 | 50.0 | 41.0 | 10. 0 | Нет | Да |
| getOwnPropertyNames() | Метод возвращает массив, состоящий из всех имен собственных (неунаследованных) свойств и методов объекта (включая неперечислимые свойства и методы). | 5.0 | 4.0 | 12.0 | 5.0 | 9.0 | Да |
| getOwnPropertySymbols() | Метод возвращает массив, состоящий из всех символьных (Symbol) свойств переданного объекта (массив символов конкретного объекта). | 38.0 | 36.0 | 25.0 | 9.0 | Нет | Да |
| getPrototypeOf() | Метод возвращает прототип переданного объекта. | 5.0 | 3.5 | 12.1 | 5.0 | 9.0 | Да |
| hasOwnProperty() | Метод возвращает логическое значение, которое указывает на то содержит ли объект указанное cобственное (неунаследованное) свойство, или метод. | Да | Да | Да | Да | Да | Да |
| is() | Метод возвращает логическое значение, которое определяет являются ли два переданных значения одинаковыми.![]() | 30.0 | 22.0 | Да | 9.0 | Нет | Да |
| isExtensible() | Метод возвращает логическое значение, которое определяет является ли объект расширяемым (доступно добавление новых собственных свойств), или нет. | 6.0 | 4.0 | 12.0 | 5.1 | 9.0 | Да |
| isFrozen() | Позволяет вернуть логическое значение, которое определяет является ли объект нерасширяемым с недоступными для настройки и изменения свойствами. | 6.0 | 4.0 | 12.0 | 5.1 | 9.0 | Да |
| isPrototypeOf() | Проверяет существует ли указанный объект в цепочке прототипов другого объекта, возвращая при этом логическое значение. | Да | Да | Да | Да | Да | Да |
| isSealed() | Метод возвращает логическое значение, которое определяет является ли объект нерасширяемым и с недоступными для настройки свойствами, или нет. | 6. 0 | 4.0 | 12.0 | 5.1 | 9.0 | Да |
| keys() | Позволяет вернуть массив, содержащий имена всех собственных (неунаследованных) перечислимых свойств и методов указанного объекта. | 5.0 | 4.0 | 12.0 | 5.0 | 9.0 | Да |
| preventExtensions() | Позволяет сделать объект нерасширяемым (предотвращает добавление новых собственных (неунаследованных) свойств). | 6.0 | 4.0 | 12.0 | 5.1 | 9.0 | Да |
| propertyIsEnumerable() | Возвращает логическое значение, которое определяет является ли указанное свойство или метод целевого объекта перечислимым. | Да | Да | Да | Да | Да | Да |
| seal() | Позволяет сделать объект нерасширяемым (предотвращает добавление новых собственных (неунаследованных) свойств), а также устанавливает все его собственные свойства как ненастраиваемые (предотвращает их удаление и изменение дескриптора).![]() | 6.0 | 4.0 | 12.0 | 5.1 | 9.0 | Да |
| setPrototypeOf() | Метод позволяет установить или изменить прототип указанному объекту. | 34.0 | 31.0 | Да | 9.0 | 11.0 | Да |
| toLocaleString() | Метод возвращает строковое представление указанного объекта. Этот метод предназначен для переопределения производными объектами для возвращения локализованного строкового представления указанного объекта. | Да | Да | Да | Да | Да | Да |
| toString() | Метод возвращает строковое представление указанного объекта. | Да | Да | Да | Да | Да | Да |
| valueOf() | Возвращает примитивное значение указанного объекта. | Да | Да | Да | Да | Да | Да |
| values() | Метод возвращает массив собственных перечислимых значений свойств и методов указанного объекта.![]() | 54.0 | 47.0 | Да | 10.1 | Нет | Да |
Документация JDK 19 — Главная
- Главная
- Ява
- Java SE
- 19
Обзор
- Прочтите меня
- Примечания к выпуску
- Что нового
- Руководство по миграции
- Загрузить JDK
- Руководство по установке
- Формат строки версии
Инструменты
- Технические характеристики инструментов JDK
- Руководство пользователя JShell
- Руководство по JavaDoc
- Руководство пользователя средства упаковки
Язык и библиотеки
- Обновления языка
- Основные библиотеки
- HTTP-клиент JDK
- Учебники по Java
- Модульный JDK
- Руководство программиста API бортового регистратора
- Руководство по интернационализации
Технические характеристики
- Документация API
- Язык и ВМ
- Имена стандартных алгоритмов безопасности Java
- банок
- Собственный интерфейс Java (JNI)
- Инструментальный интерфейс JVM (JVM TI)
- Сериализация
- Проводной протокол отладки Java (JDWP)
- Спецификация комментариев к документации для стандартного доклета
- Прочие характеристики
Безопасность
- Руководство по безопасному кодированию
- Руководство по безопасности
Виртуальная машина HotSpot
- Руководство по виртуальной машине Java
- Настройка сборки мусора
Управление и устранение неполадок
- Руководство по устранению неполадок
- Руководство по мониторингу и управлению
- Руководство по JMX
Client Technologies
- Руководство по специальным возможностям Java
Объект | Руководство по языку ReScript
Документы / Руководство по языку / Объект
Редактировать
Объекты ReScript аналогичны записям, но:
Объявление типа не требуется.

Структурный и более полиморфный, в отличие от записей.
Не поддерживает обновления, если только объект не поступает со стороны JS.
Не поддерживает сопоставление с образцом.
Хотя записи ReScript компилируются для очистки объектов JavaScript, объекты ReScript, как вы увидите, лучше подходят для эмуляции/привязки к объектам JS.
Декларация типа
Дополнительно , в отличие от записей. Тип объекта выводится из значения, поэтому вам никогда не нужно записывать определение его типа. Тем не менее, вот его синтаксис объявления типа:
ReScriptJS Output
тип человек = {
"возраст": инт,
"имя": строка
};
Визуально похож на синтаксис типа записи, с именами полей в кавычках.
Создание
Чтобы создать новый объект:
Вывод ReScriptJS
позвольте мне = {
"возраст": 5,
"name": "Большой рескрипт"
}
Примечание : как сказано выше, в отличие от записи, это значение me , а не пытается найти объявление соответствующего типа с полем "возраст" и "имя" ; скорее, тип me выводится как {"age": int, "name": string} .
Это удобно, но также означает, что этот код проходит проверку типов без ошибок:
ReScriptJS Output
type person = {
"возраст": интервал
};
позвольте мне = {
"возраст": "привет!" // возраст — это строка. Нет ошибки.
}
Поскольку программа проверки типов не пытается сопоставить me с типом person . Если вы когда-нибудь захотите, чтобы значение объекта имело предварительно объявленный тип объекта, просто аннотируйте значение:
RES
позвольте мне: человек = { "возраст": "привет!" }
Теперь система типов будет корректно выдавать ошибки.
Доступ
Вывод ReScriptJS
let age = me["age"]
Обновление
Запрещено, если только объект не является привязкой, полученной со стороны JavaScript. В этом случае используйте =
ReScriptJS Output
type student = {
@set "возраст": int,
@set "имя": строка,
}
@module("MyJSFile") внешний студент1: студент = "студент1"
студент1["имя"] = "Мэри"
Объединить типы
Вы можете преобразовать одно определение типа объекта в другое, используя . :
..
ReScriptJS Output
type point2d = {
"х": плавающий,
"у": плавающий,
}
введите point3d = {
... точка2d,
"г": плавающий,
}
пусть myPoint: point3d = {
"х": 1,0,
"у": 2,0,
"з": 3,0,
}
Это работает только с типами объектов, а не со значениями объектов!
Советы и подсказки
Так как объекты не требуют объявления типов и поскольку ReScript выводит все типы за вас, вы можете очень быстро и легко (и опасно) выполнить привязку к любому JavaScript API. Проверьте вкладку вывода JS:
ReScriptJS Output
// Тип документа — просто случайный тип 'a
// что мы не будем указывать
@val внешний документ: 'a = "document"
// вызов метода
document["addEventListener"](. "mouseup", _event => {
Js.log("Нажатие!")
})
// получить свойство
пусть лок = документ["местоположение"]
// устанавливаем свойство
document["location"]["href"] = "rescript-lang.org"
Внешняя функция и использование этого трюка также задокументированы во внешнем разделе позже.



Пользователи, знакомые с JSON, могут с его помощью ускорить процесс настройки.







0
0

