{"id":14285,"url":"\/distributions\/14285\/click?bit=1&hash=346f3dd5dee2d88930b559bfe049bf63f032c3f6597a81b363a99361cc92d37d","title":"\u0421\u0442\u0438\u043f\u0435\u043d\u0434\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u0442\u044c \u043d\u0430 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u043f\u0443\u0442\u0435\u0448\u0435\u0441\u0442\u0432\u0438\u044f","buttonText":"","imageUuid":""}

Как начать работать в Wappler и сделать демо-сайт, который получает данные из Airtable

Wappler — это необычный конструктор сайтов и мобильных приложений. Я уже рассказывал о его особенностях, а сегодня хочу показать, как с его помощью сделать простой демо-проект, который использует Airtable в качестве базы данных.

Так выглядит наш демо-сайт в интерфейсе программы

На Wappler можно создать лендинг, сайт-визитку, интернет-магазин, каталог, CRM для внутреннего использования, соцсеть, мобильное приложение и даже программу для десктопа.

Ещё Wappler хорошо подходит в качестве фронтенда для ноукод-решений. Его можно легко подключить к внешним источникам данных, вроде Airtable, Google Sheets или Notion. Или к сервисам обработки процессов, как Integromat.

Поэтому я записал серию роликов, в которые показываю, как начать работать в Wappler и как сделать простой демо-сайт. Представим, что мы создаем каталог фрилансеров, которые работают с ноукодом. Задача сайта — забирать список людей из таблицы в Airtable и выводить их на веб-страницу в виде карточек.

По ссылке можно посмотреть на итоговый сайт (ссылка будет работать минимум неделю после публикации статьи). Уточню, это просто демо, поэтому дизайна как такового нет. Задача только в том, чтобы показать, как работать с Wappler.

Должен предупредить: я не разработчик и мое понимание некоторых веб-технологий довольно поверхностное. Поэтому я наверняка допустил в статье и в роликах много неточностей по этим вопросам. Прошу не забрасывать помидорами и буду благодарен любым замечаниями и исправлениями (можно писать прямо в личку на VC или в Telegram).

01. Какие типы хостинга (Hosting Type) есть в Wappler и какой из них выбрать

Для того, чтобы разрабатывать проект локально на своем ПК, у вас должно быть настроено локальное окружение. Чтобы разместить проект на внешнем сервере, у вас должен быть настроен хостинг и подключение к нему. Подход к решению этих вопросов определяется настройкой Hosting Type в проекте. Тут доступны несколько вариантов:

А. Docker Hosting — самый удобный и функциональный вариант. Локальное окружение будет запущено через программу Docker Desktop, а для внешнего сервера можно выбрать один из популярных VPS-хостингов, например, Digital Ocean.

Б. Custom Hosting — самостоятельно настроенный хостинг. Этот вариант требует понимания, как работать с локальным окружением, как настраивать свой внешний хостинг и как заливать на него сайт.

В. Выбрать один хостингов с бесплатными тарифными планами — Google Firebase или Heroku. Heroku подходит, если нужно бесплатно разместить простой демо-сайт по общедоступной ссылке.

Для нашего демо-роекта мы выберем Docker Hosting. Я рекомендую этот вариант для всех начинающих. И хотя интегрированные с Wappler VPS-хостинги не имеют бесплатных тарифных планов, но большинство из них даёт пробный период для новых аккаунтов, чего будет достаточно для бесплатной работы на первое время.

Но если вам это не подходит, то можно выбрать и другие типы хостинга. Однако в таком случае не получится настроить кэширование запросов из самого Wappler. Это критично для посещаемого проекта, подключенного к базе на Airtable или Notion.

02. PHP или NodeJS: какие серверные платформы (Server Model) есть в Wappler и какую из них выбрать

Другой важный параметр проекта — выбранная платформа для серверной разработки (Server Model). Доступны языки и фреймворки программирования NodeJS, PHP, ASP.NET и Classic ASP.

Этот выбор повлияет на доступность некоторых возможностей в Wappler. У NodeJS больше возможностей и интеграций, например, доступна шаблонизация, Socket.io для создания чатов, можно включить кэширование через Redis. Последнее особенно важно для проектов, которые используют внешний источник (Airtable, Notion) в качестве базы данных.

Поэтому рекомендую выбирать для бэкенда именно NodeJS. Хотя стоит учитывать, что хостинг для NodeJS может обойтись дороже, чем для PHP.

03. Как установить и настроить Docker Desktop в Windows 10 для работы в Wappler

Если вы выбрали Docker Hosting, то для локальной работы нужно установить на ПК бесплатную программу Docker Desktop.

В Windows 10 работа программы основана на технологии WSL (Подсистема Windows для Linux), и чтобы она заработала, для ПК должна быть включена виртуализация. Например, у меня на ноутбуке с Windows 10 виртуализация включается в BIOS.

Docker Desktop любит забирать много оперативной памяти от системы, поэтому желательно его ограничить. На Win10 для этого нужно сначала выключить WSL командой "wsl --shutdown", например через PowerShell. Затем в папку с вашим системным профилем закинуть файл .wslconfig с двумя строками:

[wsl2]

memory=1GB

Эти настройки ограничат память WSL до 1 гб. Это вариант, который подошел для моего ПК с 8 гб.

При этом мне пришлось включить файл подкачки в Windows, иначе оперативной памяти все равно не хватает.

04. Как создать новый проект в Wappler с типом хостинга Docker Hosting и с бэкендом на NodeJS

При создании нового проекта в Wappler нужно ввести название проекта, указать папку на ПК, выбрать Hosting Type и Server Model.

Далее Wappler проверит, установлены ли нужные приложения, и если нет, то предложит их установить.

В моем случае было, что Wappler не мог установить нужную программу Scoop Installer, и ее нужно было скачать и установить вручную.

А. Новый проект с Docker Hosting

В этом случае надежней сначала самостоятельно установить и запустить Docker Desktop, и только потом создавать проект.

При создании проекта Wappler создает одно окружение (Target) с названием Development и один контейнер в Docker Desktop с веб-сервером.

Б. Создание проекта с типом хостинга Heroku Hosting.

В этом случае до создания проекта нужно создать аккаунт Heroku и создать там новый App. При создании проекта нужно указать название App.

При первом запуске проекта будет сразу предложено сделать деплой (загрузку проекта) на хостинг Heroku. Лучше согласиться, чтобы сразу проверить, что подключение работает.

При самом первом создании проекта с этим типом хостинга появится запрос на подключение к Heroku. В браузере откроется страница для предоставления доступа. Если страница не открылась сама, то нужно будет открыть консоль в Wappler (стрелка в нижнем правом углу) и просто кликнуть на любое место в консоли.

05. Как подготовить базу данных и API в Airtable для работы в Wappler

Сначала нужно создать базу и таблицу в Airtable. Название базы можно писать на любом языке, но названия таблиц желательно писать на латинице (по-английски). Названия полей могут быть на любом языке, но если есть выбор, то лучше тоже на латинице.

Проверьте, что у вас указаны верные типы полей. Например, что числа — это именно числа, а даты — именно даты, а не текст.

Когда потом Wappler будет делать первый запрос к Airtable, он будет анализировать структуру полей на основании первой записи в таблице. Поэтому важно, чтобы в первой записи в таблице не было пустых полей.

Далее нужно зайти в настройки аккаунта в Airtable и создать ключ доступа по API.

Теперь открываем документацию API Airtable для вашей базы, чтобы найти нужный эндпоинт (адрес, по которому нужно отправлять запрос). В документации пролистываем до нужной таблицы, в нашем случае это Persons.

Смотрим на запрос List Records (получить записи). Справа есть пример запроса. Нам не нужны url-параметры, поэтому для URI берем из примера всё до знака вопроса. В итоге у нас получится https://api.airtable.com/v0/appveDS53DbZmvQ/Persons, где appveDS53DbZmvQ — ID базы, а Persons — название таблицы.

Из примера также видно, что для авторизации нужно будет указать в заголовке запроса параметр "Authorization" со значением "Bearer ВАШ_КЛЮЧ_API".

06. Как забирать данные из Airtable в Wappler

В Wappler в главном меню (слева) выбираем раздел Server Connect. Там показываются все наши серверные сценарии.

Создаем новый сценарий (кнопка плюса или через контекстное меню).

Рядом появляется блок списка шагов (действий) в этом сценарии.

Нам нужен всего 1 шаг — запрос к Airtable на получение данных. Нажимаем "добавить шаг" и выбираем "API action".

В настройках шага прописываем:

URI: https://api.airtable.com/v0/appveDS53DbZmvQ/Persons (пример)

Header (в самом низу): Authorization: Bearer 8cXssU7yX^AZhhRV (пример)

Метод запроса по-умолчанию проставлен нужный — GET, поэтому его не меняем.

Сохраняем сценарий (кнопка дискеты).

Можно нажать правой кнопкой на сценарий и выбрать "Open in browser" — тогда результат запроса откроется в браузере и так мы убедимся, что запрос работает.

Чтобы видеть JSON-данные в браузере в читабельном виде, нужно поставить расширение, например JSONview.

Убедившись, что запрос работает, возвращаемся в настройки шага и нажимаем кнопку Fetch Schema. Появляется окно настройки схемы данных. Нажимаем start, и видим, как в правой части окна появилась актуальная схема данных: можно раскрыть её и проверить. В завершение еще раз нажимаем сохранить сценарий.

07. Какие типы страниц есть в Wappler на проекте с NodeJS

В Wappler при работе с NodeJS есть 3 типа страниц — Pages, Layouts и Partials.

Layouts — это страницы-шаблоны. В них находятся элементы, общие для многих страниц. Например, шапка, футер и вся информация в тэге head.

Pages — страницы с контентом. Каждая такая страница обязательно должна быть связана хотя бы одной страницей типа Layouts.

Partials — это страницы, которые являются элементами других страниц и могут добавляться в любое место. Пример использования partials — рекламный баннер, который создан как partial-страница и вставлен в код других страниц в виде компонента.

При создании нового проекта по-умолчанию создаются 2 пустые страницы: один шаблон (layout) и одна страница для контента (pages).

Управлять страницами можно через раздел Site Manager (верхняя иконка в главном меню, слева). Первая выбранная вкладка раздела — Pages, тут показываются все страницы сайты. Мы видим 3 папки — Pages, Layouts и Partials. Каждая — для страниц соответствующего типа.

Для нашего демо-проекта нам не нужно создавать новые страницы, нам достаточно двух созданных по-умолчанию.

08. Как сверстать элементы на странице в Wappler (пока без стилей и без адаптивности)

Дизайн в Wappler строится на универсальных правилах html-css и на фреймворке Bootstrap. Поэтому, чтобы собирать страницы в Wappler, нужно понимать хотя бы поверхностно, как работают эти технологии.

Все элементы страницы образуют иерархическую структуру. Она видна в панели структуры (App Structure) справа сверху. На самом верхнем уровне один элемент. В нашем случае он называется App, потому что на странице подключен фронтенд-фреймворк. Если бы мы работали со статичной страницей, то на верхнем уровне вместо App был бы элемент body.

Но мы не можем сразу добавить элемент с контентом, например, текст. Сначала нужно создать элемент Container (Контейнер) или аналогичный. В нем — сколько угодно Row (Ряды). В Row может быть только Column (Колонка), любое их количество. И уже внутри Column помещается нужный контент.

В Wappler есть готовые блоки (Blocks) для построения страницы, поэтому для обучения имеет смысл добавить на страницу несколько готовых блоков и посмотреть, как они устроены.

Добавлять новые элементы на страницу можно прям с макета страницы через синие кнопки или из App Structure: через иконку плюса или через правую кнопку мыши. Появляется модальное окно с двумя вкладками: Elements и Blocks. В первой — все элементы, доступные для добавления в этом месте. Во второй — готовые блоки.

Нам нужно сверстать всего один элемент — карточку фрилансера.

Добавляем Container, внутри добавляем Row, и внутри добавляем две колонки Column. Первая колонка для фото и важных ссылок под фото. Вторая колонка — для имени, биографии, навыков и другой информации.

По-умолчанию Column делят между собой всю ширину родительского элемента поровну. Колонке можно задать ширину числом от 1 до 12. Где 12 соответствует всей ширине родительского элемента, а 1 — 1/12 его части.

Для первой колонки устанавливаем ширину в 2 части, для этого можно схватить и передвинуть ее правый край прямо в макете, или в настройках элемента установить size = 2. Вторая колонка сама займет оставшееся место, что нас устраивает.

Заполняем колонки нужными нам элементами для контента: заголовок для ФИО, изображение для фото, ссылки для ссылок под фото и для остального - простой текст (paragraph). Для каждой новой строки контента создаем новый Row, а для каждого элемента в строке — свой Column. Включаем для изображения свойство responsive, чтобы оно не выходило за ширину колонки.

09. Как вывести данные на страницу в Wappler (Data Binding)

Собственный фронтенд-фреймворк, который используется в Wappler, называется App Connect. Он автоматически подключается, когда вы создаете проект или страницу.

Сначала нам нужно забирать данные из бэкенда. Для этого добавлем компонент Server Connect. В его настройках выбираем созданный до этого серверный сценарий.

Теперь нужно вывести данные с помощью инструмента Repeat (Повтор). Он позволяет задать повторение какого-либо элемента на странице вместе со всем его содержимым. Повторение будет происходить столько раз, сколько объектов находится в массиве поступающих данных.

Выбираем элемент row, в котором находится column с карточкой человека. Нажимаем "make repeat children". Для удобства придумаем называние этого повтора, например, main_repeat, и пропишем название в атрибут id.

Нажимаем на молнию возле поля expression (выражение) — открывается окно для связывания данных (Data Binding). Выбираем компонент Server Connect, раскрываем данные и находим нужный нам массив "records".

Сразу видим, что теперь карточек на странице стало несколько — значит, повтор работает.

Если изменения не появились, то проверьте, что над страницей горит иконка молнии — это означает, что на странице показывается не просто верстка, а реальные данные в соответствии с тем, что запрограммировано.

Теперь нужно связать все поля карточки с нужными данными. Начнем с поля имени человека (Name).

Есть два способа связывать данные, оба рабочие, и в процессе вы поймете что вам удоблней.

Вариант А. Выделяем нужный элемент на странице или в структуре и в properities (свойствах) переходим к разделу dynamic attributes (динамические свойства). Добавляем новое свойство Inner text (Внутренний текст), оно находится в подразделе display (отображение).

Нужно выбрать данные для связывания. Нажимаем на иконку молнии и в окне Data Binding выбираем нужные данные (в нашем случае поле Name). Только данные нужно выбирать именно из нашего повтора (main_repeat).

Вариант Б. Дважды кликаем на элемент на странице, чтобы перейти к редактированию содержимого. Среди иконок возле текста есть иконка молнии. Нажимаем ее и выбираем данные для связывания.

В любом из вариантов данные должны сразу загрузиться и показаться на странице.

Повторяем это с другими полями, где мы выводим просто текст или число: биография, город, опыт, ставка.

При этом в настройках поля, где мы прописываем динамическое значение для Inner text, можно также добавить обычный текст в формулу. Например, чтобы после ставки всегда были единицы измерения.

Чтобы вставить изображение, нужно прописать не свойство Inner text, а Image Source. И выбрать в качестве значения ссылку, которую мы получаем из Airtable.

Чтобы вставить ссылку на сайт, нужно прописать значение link. А чтобы вставить электронную почту, нужно прописать значение link, но кроме этого перед значением прописать текстом "mailto:".

Интересней ситуация с тэгами. У нас есть поля Categories, Names (from Tools), Skills, которые являются массивами, т.е. содержат в себе несколько записей. Поэтому, чтобы вывести их правильно, нужно включить повтор внутри повтора.

Порядок аналогичный: создаем row, внутри column и только внутри column добавляем текст. У row включаем repeat children и выбираем в качестве expression массив данных из нашего main_repeat. У текста включаем динамическое свойство, выбираем Inner text и привязываем к значению $value из нашего нового повтора, который мы только что создали.

Повторяем еще 2 раза для других полей.

10. Как стилизовать тему Bootstrap в Wappler через Theme Manager

Wappler интегрирован с фреймворком для верстки Bootstrap. Бутстрап предоставляет много готовых классов, которые задают стиль и поведение элементов.

Поэтому первый способ изменения стилей сайта — менять стили самой темы Бутстрапа. Такие настройки применяются ко всем страницам на сайте и ко всем элементам.

Для этого нужно в меню слева открыть окно Theme Manager. Мы видим разные настройки: цвета, шрифты и стили кнопок.

Можно кликнуть на вкладку Advanced — тут можно изменить глобальные значения любых других переменных вашей темы Бутстрапа.

11. Как стилизовать страницу в Wappler через готовые классы Bootstrap

Другой способ изменения дизайна — задавать элементам уже существующие классы Bootstrap.

Для этого мы должны сначала выбрать элемент на странице или в структуре. Справа снизу появляется окно Properties, где в том числе доступны все возможные изменения для данного элемента, которые можно внести через добавление классов Bootstrap.

Например, здесь можно задать выравнивание, толщину и другие стили текста; ширину и высоту элемента в процентах; отступы; скрытие на разных устройствах; настройки flexbox.

Каждое изменение этих настроек будет добавлять класс к данному элементу, или менять/удалять класс. Процесс будет отражаться в поле class в настройках.

Например, если внешний отступ сверху установить как 2, то появится класс mt-2, который расшифровывается как "margin top с значением 2".

При этом 2 в данном случае это не rem и не px, а внутренний параметр Бутстрапа, который рассчитывается по формуле. Подробней узнать можно в документации фреймворка.

12. Как стилизовать страницу в Wappler через создание своих классов в Design Panel

Но самый гибкий способ стилизации элементов страницы — самому вручную создать и назначить классы с нужными стилями.

Для этого нужно выбрать элемент, а затем нажать сверху справа вкладку Design. Появляется панель для настройки дизайна элемента по вашему желанию (Design Panel). Но сначала вам нужно в верхнем поле Class Selector создать новый класс. Для этого просто напишите любое подходящее название на латинице.

А дальше просто настраивайте стили для данного класса. При этом не все изменения будут показываться сразу на странице — иногда нужно обновлять страницу вручную.

При желании можно добавить этот же созданный класс и к другим элементам на странице.

В нашем случае мы выбираем элемент column, который содержит весь наш контент карточки фрилансера, создаем ему класс и настраиваем нужное отображение: добавляем фон и отступы.

Однако, через визуальные элементы в Wappler можно настроить лишь часть стилей. В остальных случаях вам нужно будет самостоятельно прописывать классы и стили в файл style.css, в котором хранятся все ваши стили. Найти этот файл можно, если нажать Site Manager сверху справа, затем вкладку Files и в папке public/css будет нужный файл.

В нашем случае нам не хватает возможности настроить тени для нашей карточки человека. Поэтому нужные стили для тени прописываем вручную в style.css.

13. Как настроить адаптивность на странице в Wappler

Можно задать разный размер колонок для устройств с разной шириной экрана. Тем самым настроить адаптивный дизайн страницы.

В верхней части интерфейса есть иконки переключения между разными устройствами. При их нажатии меняется ширина рабочей области макета. Каждому устройству соответствует определенная ширина и определенный код: xs, sm, md, lg, xl.

Например, когда выбрано устройство md (планшет), при установке элементу размера 6, ему будет задан не класс col-6, а col-md-6. Это значит, что на устройстве с кодом md (планшет) и выше (lg, xl) будет применяться размер 6.

При этом запись класса для самого меньшего по ширине устройства идёт без приписки. Например, col-4.

В нашем случае для левой колонки с фотографией и ссылками нужно задать ширину 12 для мобильных устройств и 2 — для планшетов и больше. Этому поведению соответствуют классы col-12 col-md-2.

При этом, левая колонка с фотографией и ссылками на мобильных устройствах должна делиться на 2 равные части (колонки) по ширине — слева фото, а справа — ссылки. Поэтому для каждой из этих двух колонок будет указано col-6 col-md-12.

Аналогично, если вы настраиваете стили через панель дизайна, и при этом у вас выбрано конкретное устройство, то эти стили будут работать только от данной ширины экрана и выше. Это обеспечивается через медиазапросы (media queries).

14. Для чего нужно кэширование запросов через Redis и как его включить в Wappler

Минус использования Airtable или Notion в качестве базы данных для сайта заключается в том, что эти сервисы ограничивают количество запросов к себе: в среднем, не более 5 запросов в секунду к одной базе. Чтобы это обойти, нужно включить для сайта кэширование запросов на бэкенде.

Это можно легко настроить через интерфейс Wappler, но только если для проекта выбраны Docker Hosting и NodeJS.

В настройках окружения (Target) надо включить Redis. И после этого выбираем нужный серверный сценарий, заходим в настройки и прописываем время хранения кэша в секундах.

Теперь, когда нужно получить данные от Airtable, сайт не будет обращаться к базе каждый раз, а будет делать это только тогда, когда истекло время хранения кэша.

15. Как загрузить проект Wappler с типом хостинга Docker Hosting на сервер Digital Ocean

Wappler позволяет создавать VPS-сервера для проектов из собственного интерфейса, и тем самым упростить настройку и загрузку на сервер.

Сначала нужно в Digital Ocean зайти в раздел API и сгенерировать ключ.

Далее нужно создать новое окружение (Target) в Вэпплере — это можно сделать в настройках проекта. В настройках Target выбираем тип Production. В разделе Docker Machine выбираем Manage. В открывшейся панели нажимаем на иконку создания новой Docker Machine (удаленного сервера). В окне создания выбираем провайдера (в нашем случае Digital Ocean), вводим ключ и выбираем настройки для VPS-сервера. Выбираем минимальный тариф $5 и меняем локацию на Frankfurt.

Когда сервер будет готов, закрываем окно и в настройках окружения выбираем созданную Docker Machine из списка.

Закрываем окно настроек. Затем в панели управления окружением в нижней части экрана меняем Target на только что созданный. Нажимаем Deploy, чтобы запустить загрузку проекта на созданный сервер. Через несколько минут появится сообщение об успешной загрузке и можно будет увидеть работающий сайт, если ввести в браузере IP-адрес нашего сервера.

16. Как подключить домен в Digital Ocean

Сначала нам нужно направить домен на неймсервера Digital Ocean. В настройках доменного регистратора находим настройки Nameservers и прописываем ns1.digitalocean.com, ns2.digitalocean.com, ns3.digitalocean.com.

Затем в Digital Ocean заходим а раздел Networking и выбираем вкладку Domain. Добавляем наш домен и переходим в настройки его записей. Автоматически добавлены три NS-записи, но нужно добавить еще A-запись. В Hostname прописываем @, а в поле WILL DIRECT TO выбираем наш сервер. При первой настройке TTL можно поставить 600, а позже увеличить его до 3200.

Через некоторое время сайт будет доступен по нашему адресу.

17. Как подключить SSL-сертификат Let's Encrypt в Wappler (для HTTPS)

SSL-сертификат необходим, чтобы сайт работал по безопасному протоколу HTTPS.

Wappler позволяет легко настроить сертификат прямо из своего интерфейса, но только для проектов с типом хостинга Docker Hosting.

Сначала нужно зайти в настройки окружения (Target), которое соответствует нужному серверу. В нашем случае это Development. В разделе Web очищаем поле Port, сохраняем настройки и делаем Deploy.

После этого снова заходим в настройки окружения, заходим в управление Docker Machines (кнопка Manage). Выбираем нужный сервер и нажимаем на иконку гаечного ключа, чтобы перейти в настройки. Включаем галочку Install Traefik, вводим любой имейл и нажимаем Apply. Через пару минут настройки готовы. Закрываем все окна настроек и снова нажимаем Deploy, чтобы загрузить проект на хостинг.

После этого SSL-сертификат будет установлен, и сайт будет работать по протоколу HTTPS.

Надеюсь, что я смог заинтересовать вас и что мои инструкции были понятными.

Если у вас возникнут вопросы, то пишите в Telegram-чат по Wappler. Я постараюсь помочь.

Если вы хотите заказать мне разработку подобного или другого проекта на Wappler, то пишите мне в ЛС в Telegram @nickneustroev.

0
3 комментария
Alexander Voynov

Такой материал и тишина :-)))
Спасибо!

Еще бы узнать как за ваплер не платить, пока его изучаешь - все, что после 7 дней намертво отказывается, как бы хвосты ни чистил - как он так ума не приложу

Ответить
Развернуть ветку
Николай Неустроев
Автор

Спасибо за поддержку!
Отвечу в личку

Ответить
Развернуть ветку
Dmitry

Спасибо за ваш труд, очень мало инфы по Wappler! 

Ответить
Развернуть ветку
0 комментариев
Раскрывать всегда