Создание реактивных аналитических веб-приложений с использованием python и библиотеки dash

Шаг 4 — Настройка виртуальной среды

Вы, должно быть думаете, что это за виртуальная среда такая, да? Я тоже так думал. Но не переживайте, я всё объясню. Виртуальная среда поможет нам отделить нашу среду разработки и установки пакетов от остальной системы. То есть, всё, что мы установим в виртуальной среде, не повлияет на реальную систему. Очень удобно, ага. Давайте же настроим её.

  1. Установим , прописав в терминале .

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

3. Для активации виртуальной среды, выполните , а для деактивации просто напишите .

Виртуальная среда создана

Когда мы войдем в виртуальную среду, увидим что-то подобное

Делать сайты на Python перспективнее?

Да. PHP ограничен одними сайтами и развивается в сторону веб (для чего он и был создан). Python в свою очередь, развивается в разные стороны, это даст вам шанс в будущем сменить свою работу и начать делать, например, программы вместо сайтов не меняя язык программирования. Вам не придется изучать опять новый язык программирования чтобы сменить род деятельности т.е. перескочить с сайтостроения на написание приложении для android, apple, symbian и т.д.

Еще один плюс в сторону Python в том, что он строго типизирован как и Java. Этот язык обучит вас хорошим манерам программиста и не даст волю творить хаос в коде. Но, не будем все обобщать, творить бессмыслицу можно и на Python и делать шедевры на том же PHP. Python научит разделать код на логические блоки чтобы понимать где зона выполнения цикла, где заканчивается один IF и начинается другой и т.д. На PHP тоже можно структурировать код на логические блоки, но там это не обязательно, следовательно новичок может написать код в одну строку и ему ничего не будет, в момент когда Python новичок получит ошибку и начнет править код.

Шаг 5 — Запуск сайта на реальном сервере

Так, давайте вернемся в нашему сайту. Запустить сайт на Python не так просто, как c HTML и PHP файлами, когда мы перетаскиваем и загружаем файлы при помощи FTP-клиента. Нам нужно делать всё по порядку, будьте терпеливы и внимательно выполняйте каждый шаг.

Шаг 5.1 — Создаем аккаунт Heroku

Создайте аккаунт на Heroku, перейдя по этой ссылке.

Шаг 5.2 — Устанавливаем необходимый инструменты

Прежде всего это , мы будем использовать git для загрузки файлов на сервер. А чтобы установить git, откройте командную строку и введите следующее:

sudo apt install git-all
git config --global user.name "John Doe"git config --global user.email johndoe@example.com

Далее следует, это такой собственный git для Heroku. Для установки:

sudo snap install --classic heroku

Отлично. Теперь у нас есть всё, что нужно. Поехали дальше.

Шаг 5.3 — Настройка Heroku через командную строку

Нужно установить Heroku туда же, где находится наше приложение. Давайте перейдем в папку с нашим основным скриптом, и зайдем в аккаунт Heroku, используя наши данные. Вас попросят нажать любую клавишу для входа и перенаправят в браузер. После того ,как вы успешно вошли, ваша командная строка будет выглядеть так:

Нажмите любую кнопку

Теперь нам нужно создать наше приложение. Хорошо подумайте над его названием, потому что это будет ваше доменное имя после herokuapp.com. Например, . Я хотел использовать своё имя, но такое название было уже занято. Поэтому я выбрал .

Шаг 5.4 — Создаем необходимые файлы (всего 3)

requirements.txt — Содержит список зависимостей (библиотек), которые Heroku должен установить, чтобы наше приложение работало правильно. Для этого, переходим в виртуальную среду, которую мы создали ранее, с помощью pip устанавливаем. Это веб-сервер Python. После этого напишите , чтобы увидеть список зависимостей, а потом , чтобы создать текстовый файл с этим списком. Это нам и нужно. Вы можете найти файл в вашей папке, переместите его туда, где находится наш файл Python.

Список зависимостей

Важное примечание — Пожалуйста, удостоверьтесь, что ваш файл requirements выглядит, как представленный ниже. Иначе Heroku не примет его и выдаст ошибку

Отредактируйте файл, чтобы он выглядел так.

requirements.txt

Procfile — У этого файла нет расширения. Он содержит имя сервера и название приложения. Создайте файл, назовите его и напишите в нем следующее:

web: gunicorn mainscript:app

Здесь, gunicorn — это используемый сервер. — это название файла Python, — это название приложения, которое мы придумали при создании экземпляра класса flask (смотри фрагмент кода в шаге 2). Если ваши названия отличаются, измените их.

runtime.txt — Содержит информацию о версии Python, которую вы хотите использовать. В этом файле напишите:

python-3.7.0

Я использую Python 3.x, поэтому я использовал эту среду. Если вы используете Python 2.x, укажите вместо этого. Отлично, все готово. Теперь нам нужно просто всё загрузить.

Наконец, всё, что нам нужно, в одном месте

Шаг 5.5 — Загрузка всего необходимого

Отлично. Чтобы не объяснять всё по отдельности, к каждой строке дам комментарий. Каждую строку нужно выполнять отдельно.

#Убедитесь, что находитесь в той же директории, где лежит ваш файл Python#Убедитесь, что вы залогинены в heroku#Вызовите свое приложениеheroku git:remote --app dhrumilp#Инициализируйте git, чтобы загрузить все файлыgit init#Добавьте все файлы (это точка в конце, что означает все)git add .#Теперь, зафиксируйте все добавленные файлы на серверgit commit -m "First upload"#Запушьте все в master branchgit push heroku master

Загрузка…

Готово.

Всё готов. Уфф. Поздравляю, если вы смогли добраться до этого этапа. Моё приложение доступно на dhrumilp.herokuapp.com, можете посмотреть.

#10: Скажите “Привет, мир!” машинному обучению

Машинное обучение может быть фундаментальной областью в понимании искусственного интеллекта. Однако, в этой сфере легко запутаться, так как она постоянно развивается и меняется.
К счастью, в вашем распоряжении имеются онлайн ресурсы, которые могут помочь освоиться, перед тем как нырнуть с головой в мир под названием data science. Это руководство создано Джейсоном Браунли, и является хорошим примером введением в использование Python для машинного обучения.

Вы пройдетесь по ряду базовых алгоритмов машинного обучения, как и по библиотекам Python, которые помогут вам в составлении прогнозов.

Руководство очень простое и в нем легко ориентироваться. Вы можете окончить его всего за несколько часов. По окончанию курса, у вас будет общее представление о том, как использовать Python в науке данных.

Когда вы будете уверены в том, что можно нырять с головой, можете ознакомиться с этими руководствами, где вы сможете научиться анализировать отпечатки, создавать визуализации, распознавать речь и лица, и все это в Python!

Шаг 3 — HTML и CSS

Созданный нами сайт выглядит не очень красиво. Что нужно использовать, чтобы улучшить его? Конечно же, HTML и CSS. Они лучше всего подходят для этой задачи. Если вы разбираетесь в веб-разработке, вы можете создать новый файл .html с нуля. Но если вы не умеете это делать, в Интернете существует немало платформ для этого. Найдите наиболее подходящую для вас.

Теперь мы хотим, чтобы программа возвращала не простой текст, а конкретные html-страницы, которые мы создали. Для этого нужно импортировать ещё один класс, render_template. Тогда наша функция должна возвращать, чтобы мы видели конкретную html-страницу по этому маршруту.

#Import dependenciesfrom flask import Flask, render_template#Create instance of Flask Appapp = Flask(__name__)#Define Route and Contant of that page@app.route("/")def home():    return render_template("home.html")#Define 2nd Route and Content@app.route("/blog")def about():    return render_template("blog.html")#Running and Controlling the scriptif (__name__ =="__main__"):    app.run(debug=True)

Для HTML — все файлы .html, которые вы вызываете, должны содержаться в папке под названием в вашей рабочей папке.

Для CSS — вам нужно создать папку и добавить в нее папку , а уже потом добавить в неё ваши файлы .css.

Cookies

Cookies (печеньки) — небольшой фрагмент данных, отправленный веб-сервером и сохраняемый на компьютере пользователя. Браузер всякий раз при попытке открыть страницу соответствующего сайта пересылает этот фрагмент данных веб-серверу в составе HTTP-запроса.

Собственно, cookies — хороший способ сохранить некоторые данные о пользователях.

Отправка печенек осуществляется заголовком Set-cookie:

#!/usr/bin/env python3
print("Set-cookie: name=value; expires=Wed May 18 03:33:20 2033; path=/cgi-bin/; httponly")

print("Content-type: text/html\n")
print("Cookies!!!")

Например, если сохранить этот скрипт в /cgi-bin/cookie.py и зайти на localhost:8000/cgi-bin/cookie.py, то вам поставится печенька с именем name и значением value. Срок её хранения до мая 2033 года, отправляется повторно на сервер только к скриптам, которые расположены в /cgi-bin/, и передается только http-запросами (её нельзя получить из браузера пользователя с помощью javascript).

Все эти параметры не являются обязательными. Можно написать так:

#!/usr/bin/env python3
print("Set-cookie: name=value")

print("Content-type: text/html\n")
print("Cookies!!!")

Локальный веб-сервер или Продакшн?

До этого момента, для запуска приложения Pages локально на компьютере мы использовали внутренний веб-сервер Django. Однако локальным адресом нельзя ни с кем поделиться. Для того чтобы запустить сайт в Интернете, сделав его доступным для всех, необходимо разместить код на внешнем сервере. Данный процесс получил английское название продакшн, под которым понимается процесс эксплуатации программы реальными людьми через интернет. Локальные данные доступны только на компьютере разработчика, а продакшн-код находятся на внешнем сервере и становятся доступными для всех.

Существует великое множество серверов. Мы будем использовать Heroku. Для небольших проектов его можно использовать бесплатно, а несложный процесс размещения кода позволил Heroku завоевать большую популярность.

#8: Играйте в PyGames

Этот раздел для тех, кто хочет весело провести время. Python может быть использован для написания различных аркадных игр, адвенчур и пазлов, на разработку которых уйдет всего несколько дней. К классическим играм, типа пинг-понга вы сможете перейти, когда освоите новые навыки программирования.

Библиотека Pygame заметно упрощает разработку собственных игр. Он включает в себя практически все необходимое, чтобы вы могли приступить к разработке игр.

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

Вам доступны десятки игр, которые вы можете создать при помощи библиотеки. Что-бы вы не хотели придумать, чувствуйте себя комфортно и делитесь своими работами в сообществе Pygame!

#7: Разбираемся с лентой Twitter

Интересует постройка веб приложений, но не хватает уверенности, чтобы начать мега-проект? Не беспокойтесь, мы кое-что подготовили для вас. С нами вы сможете научиться создавать простое веб приложение всего за несколько часов.

Боб Белдерброс делится кейсом, где он создал 40th PyBites Code Challenge, в котором участникам нужно было построить простое веб приложение для лучшей навигации по ленте новостей Daily Python Tip в Твиттере. Вы можете пройтись по результатам данного челенджа и ознакомиться с кодом.

Вместо Flask, вы будете использовать микро веб-фреймворк Bottle. Он славится тем, что является слабо зависимым решением для быстрого создания приложений. Так как он был разработан таким образом, чтобы быть легким и простым в использовании, вы сможете получить свое приложение практически мгновенно.
Вы также сможете работать с модулем Tweepy, чтобы загружать данные из API Твиттера. Вы сможете хранить данные в базе SQLAlchemy или Peewee, так что заодно получите небольшую практику в запросах SQL.

#9: Выберите свое собственное приключение

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

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

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

Создаем проект на Django

На этом этапе мы выполним команду, которая создаст проект на Django внутри нашего проекта на Python.

django-admin startproject mysite

В результате мы получим каталог внутри проекта с именем mysite, который будет содержать файлы настроек проекта. Внутри первого каталога будет еще один каталог с идентичным названием

Обратите внимание, что первый каталог – это всего лишь контейнер проекта на Django. Его имя можно назвать или переименовать на ваше усмотрение

Второй же каталог содержит файлы проекта, фактически это т.н. Python-пакет. Файлы созданные внутри него содержат базовые настройки сайта на Django.

Для удобства работы с проектом, на этом этапе рекомендую переместить содержимое второй папки mysite в первую, а файл manage.py в корень проекта. Это облегчит работу с проектом и не будет требовать от нас входить каждый раз когда открываем терминал внутрь первого каталога mysite. В результате структра проекта должна быть примерно следующей: 

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

python manage.py runserver

Исходя из информации на скриншоте мы делаем вывод, что все работает и готово к созданию приложений уже внутри Django-проекта, но делать мы это будем уже в следующей части публикации.

А пока все! До новых встреч и удачи в создании сайта на Django!

Почему выбрать Django?

Хорошая документация — документация данного фреймворка выполнена на высшем уровне. Все статьи написаны понятным языком и снабжены примерами и объяснениями которые не освятят ни единого вопроса. Есть даже книги на русском языке по данному фреймворку которые занимают лидирующие места продаж в своем разделе.

Самостоятельная генерация админ панели — Это пожалуй самая уникальная сторона Django по сравнению с другими фреймворками а том же PHP. Данная возможность поможет вам выиграть во времени написания сайта т.к. создание админ интерфейса сводится наброску нужных моделей и можно уже начать работать с сайтом.

Поддержка паттерна MTV (Model-Template-View) — он напоминает классический MVC. MTV разделяет бизнес логику от дизайна, что очень хорошо сказывается на будущее огромного проекта которого будет поддерживать несколько людей. Пока дизайнер будет разбираться каким цветом и шрифтом он выведет мета теги, меню сайта и текст то программист независимо от дизайнера, будет писать для сайта функционал. Это позволит увеличить КПД в работе сайта.

Да и работать в кругах программистов авторитетнее на Python, C#, Java. PHP хороший язык программирования он будет жить и занимать лидирующее место инструмента создании сайтов еще много лет, но вы же не хотите ограничивать свои возможности только на создании сайтов?

#6: Создание блокчейна

Хотя блокчейн в основном разрабатывается как финансовая технология, его можно применять во многих других областях. Блокчейны можно применять практически во всех транзакциях: от сделок с недвижимостью, до передач медицинских отчетов.

Вы можете получить лучшее представление о том, как это работает, построив свой блокчейн! Руководство Hackernoon поможет вам реализовать блокчейн с нуля. К концу проекта, вы получите глубокое представление того, как работает эта технология транзакций.

Вы будете работать с HTTP клиентами и библиотекой requests. После установки веб-фреймворка Flask, вы сможете использовать запросы HTTP и взаимодействовать со своим блокчейном в интернете.

Помните, блокчейн – это не только для фанатов криптовалюты. Построив такой самим, вы легко найдете креативный способ реализовать эту технологию в интересующей вас области.

#5: Создание микроблога с помощью Flask

Похоже, что у каждого сегодня есть блог, и нет ничего плохого в том, чтобы иметь собственный уютный хаб онлайн. С развитием и Instagram, микроблоги стали чрезвычайно популярными. В этом проекте Мигеля Гринерга, вы научитесь создавать собственный микроблог.

Он называется «Мега-руководство Flask», и однозначно соответствует названию. Проработав 23 главы, вы получите глубокое представление о веб-фреймворке Flask. К концу проекта, вы сможете создать полностью работающее веб приложение.
Вам не нужно знать что-либо о Flask, чтобы приступить к делу, так что это идеально для тех, у кого чешутся руки, чтобы приступить к веб разработке.

#4: Майнинг данных Twitter

Благодаря интернету, и (все чаще и чаще) интернету вещей (IoT) – у нас есть доступ к огромному количеству данных, о которых не могли мечтать всего десять лет назад. Аналитика – это огромная часть любой сферы, которая связана с данными. О чем люди разговаривают? Какие шаблоны видны в их поведении?

Твиттер – отличное место, чтобы получить ответы на эти вопросы. Если вам интересен анализ данных, тогда майнинг данных в Twitter – отличный способ попробовать свои навыки в Python, чтобы ответить на вопросы об окружающем мире.

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

Вы увидите, как использовать Tweepy для фильтрации твитов, которые вы хотите вытягивать, TextBlob для подсчета настроения этих твитов, Elasticsearch для анализа содержимого этих твитов и Kibana для показа результатов. По окончанию данного руководства, вы уже будете готовы к тому, чтобы заняться другими проектами, которые используют Python для обработки текстов и распознавания речи.

Шаблоны в Django

Каждый веб-фреймворк нуждается в удобном способе генерации файлов HTML. В Django за это отвечают шаблоны: индивидуальные файлы HTML, которые связаны между собой и включают базовые логические операции.

Вспомним, что в предыдущей уроке на сайте «Hello, World» фраза была вписана сразу в код файла как строка игнорируя какие либо HTML шаблоны. Технически это работает, но масштабируется не очень хорошо. Предпочтительнее будет связать представление (View) с шаблоном (Template), таким образом отделяя информацию из каждого.

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

Для начала нужно определить, где поместить шаблоны внутри структуры проекта Django. Есть два варианта. По умолчанию загрузчик шаблонов Django осмотрит каждое приложение, выискивая связанные шаблоны. Тем не менее, структура остается несколько запутанной: каждое приложение нуждается в новой директории , другой директории с таким же названием, как и у приложения, а также в файле шаблона.

Следовательно, рассматривая приложение , Django будет ожидать следующую структуру:

Shell

└── pages
├── templates
├── pages
├── home.html

1
2
3
4

└──pages

├──templates

├──pages

├──home.html

Отсюда следует, что нам нужно будет создать новую директорию , новую директорию с названием приложения и сам шаблон под названием .

Существует еще один подход к решению вопроса — это создание одной директории на уровне проекта и размещение там всех шаблонов. Сделав небольшие поправки в файле , можно указать Django, чтобы в поисках верного шаблона он рассматривал также эту новую директорию. Именно этот подход мы сейчас используем.

Первым делом покинем запущенный веб-сервер, применив комбинацию . Затем создадим директорию под названием и файл HTML под названием .

Shell

(pages) $ mkdir templates
(pages) $ touch templates/home.html

1
2

(pages)$mkdirtemplates

(pages)$touchtemplateshome.html

После этого нам нужно обновить файл и указать Django место новой директории . Это изменение находятся в одну строчку в настройках под .

Python

# pages_project/settings.py
TEMPLATES = , # new

},
]

1
2
3
4
5
6
7
8

# pages_project/settings.py

TEMPLATES=

{

‘DIRS’os.path.join(BASE_DIR,’templates’),# new

},

Затем для файла добавляем обычный H1 заголовок.

Python

<!— templates/home.html —>
<h1>Homepage</h1>

1
2

<!—templateshome.html—>

<h1>Homepage<h1>

Вот и все, шаблон готов! Следующим шагом будет конфигурация нашего URL и файлов представления (views.py).

Установка и настройка среды разработки Python/Django

На этом этапе мы видим перед собой приветственное окно приложения с предложением создать новый проект, открыть существующий или же импортировать из системы контроля версий. Нас же пока интересует первый пункт – Create New Project. Нажимаем его и переходим в созданию нового проекта.

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

Вторая строчка Interpreter отвечает за выбор установленного в системе интерпретатора языка Python. Их может быть несколько, но пока мы не будем вдаваться в нюансы. Сразу отмечу, что для каждого проекта лучше создавать отдельную виртуальную среду (VirtualEnv), которая будет содержать установленные модули, необходимые для конкретного проекта и их настройки и версии не будут влиять на другие проекты. Давайте создадим новую VirtualEnv нажав на шестеренке справа и выбрав пункт Create VirtualEnv.

Для VirtualEnv так же необходимо задать имя, выбрать расположение в файловой системе и версию интерпретатора Python, которая будет использоваться. Я предпочитаю виртуальной среде давать имена аналогичные проекту, чтобы так же легко можно было разобраться для какого проекта она была создана.

Нажимаем ОК и ждем пока закончится процесс создания виртуальной среды. После нажимаем на кнопку Create внизу справа и запускаем процесс создания проекта.

Далее откроется окошко среды разработки, которое сигнализирует о том, что проект создан и теперь мы может переходить к разработке сайта на Django.

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

Настройка URL для приложений в Django

На последнем этапе необходимо обновить URLConfs. Обновления требуется делать в двух местах. Первым делом обновляем файл самого проекта , чтобы отметить наше приложение , а затем внутри приложения мы связываем представления (View) с URL-адресами.

Начнем с файла .

Python

# pages_project/urls.py
from django.contrib import admin
from django.urls import path, include # новое

urlpatterns = [
path(‘admin/’, admin.site.urls),
path(», include(‘pages.urls’)), # новое
]

1
2
3
4
5
6
7
8

# pages_project/urls.py

fromdjango.contrib importadmin

fromdjango.urls importpath,include# новое

urlpatterns=

path(‘admin/’,admin.site.urls),

path(»,include(‘pages.urls’)),# новое

Данный код вам уже знаком. На второй строке мы добавляем , что нужно для указания существующего URL-адреса для приложения . Затем создаем на уровне приложений  файл .

Shell

(pages) $ touch pages/urls.py

1 (pages)$touchpagesurls.py

И затем добавляем следующий код.

Python

# pages/urls.py
from django.urls import path

from .views import HomePageView

urlpatterns =

1
2
3
4
5
6
7
8

# pages/urls.py

fromdjango.urls importpath

from.views importHomePageView

urlpatterns=

path(»,HomePageView.as_view(),name=’home’),

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

Вот и все! Теперь запустите веб-сервер через , а затем откройте . Должна открыться новая домашняя страница.

Домашняя страница

Свойство text библиотеки Beautiful Soup

Возвращаемая разметка — это не совсем то, что нужно. Для получения только данных — цитат в этом случае — можно использовать свойство из библиотеки Beautiful Soup

Обратите внимание на код, где происходит перебор всех полученных данных с выводом только нужного содержимого

Копировать

Это и дает вывод, который требовался с самого начала.

Для поиска и вывода всех авторов можно использовать следующий код. Работаем по тому же принципу — сперва нужно вручную изучить страницу

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

Также стоит поменять цикл, чтобы перебирать сразу и цитаты, и авторов.

Копировать

Таким образом теперь есть и цитаты, и их авторы.

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

Когда блок получен, можно опускаться ниже с помощью функции для полученного подмножества. А уже дальше потребуется добавить внутренний цикл для завершения процесса.

Копировать

Этот код даст такой результат. Круто, не так ли?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector