Придумать рассказ библиотека будущего 2 класс

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

uqbcuwog8e3oumgi frdlc 5s g

Мы уже упоминали, как мы предоставляем бесплатные VPS для студентов, чтобы они учились программировать. Один из наших подопечных Павел сделал простеньких телеграм и ВК ботов для FAQ. Они очень простые, тем не менее, начинающему программисту не помешают комментарии опытных ребят — поэтому публикуем его рассказ — Павел будет рад, если в комментариях ему дадут советы.

Я — студент Новосибирского Государственного Технического Университета, не так давно мы с парочкой моих друзей реализовали площадку для продвижения проектов во всех возможных областях научной деятельности. Мы помогаем «сводить» заинтересованных преподавателей и студентов всех ВУЗов Сибири, чтобы проектная научная деятельность развивалась по территории Сибири и РФ.

Студенты и преподаватели часто обращались ко мне с вопросами и я решил автоматизировать этот процесс, написав ботов для ВК и Телеграм.

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

Я использовал Python версии 3.6  просто потому, что он самый простой для меня. Кодил в PyCharm Community Edition. Весь код опубликован на GitHub. Удачи!

1. Предварительные приготовления для телеграм-бота

1.1 Получение токена от BotFather в телеграмме

Первым делом, нам нужно «зарегистрировать» нашего бота в Telegram.

Для этого, в поисковике телеги ищем BotFather

далее, делаем всё также, как на скриншотах:

izohvlbkecprckefokl7 jm6hj8

После нажимаем на команду /newbot или же прописываем вручную.

j30hfikfsaywfq2seafjrsicqqe

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

1.2 Переходим в любой редактор кода и создаем файл config.py

Перед созданием данного файла, нам нужно выбрать директорию, в которой будет реализован весь функционал бота. Если вы используете PyCharm Community/Professional Edition, то предлагаю просто создать новый проект, и писать там весь функционал бота.

Если Вы используете любой другой редактор, такой как Sublime Text 3, например, то Вам самостоятельно придётся создать директорию, создать виртуальное окружение, и работать из консоли со всеми предварительными тестами. Во избежание трудностей, предлагаю скачать продукт PyCharm Community Edition от компании JetBrains, с помощью данного продукта можно обойти действия, описанные в предыдущем абзаце, так как данный продукт сделает их самостоятельно, от Вас потребуется только указать путь до интерпретатора Python в конфигурациях PyCharm, с помощью которого и будет работать Ваш бот.

В данном файле (config.py) будет храниться только токен, который нам дал BotFather, поэтому пишем:

token = "Здесь хранится Ваш токен".

1.3 Cоздаём главный файл — bot.py

Делаем cледующие импорты и для соответствующих библиотек, в консоли прописываем закоментированные строчки:

import config
import telebot # pip install telebot
from telebot import types # pip install pyTelegramBotAPI

Далее, нам необходимо использовать наш токен:

bot = telebot.TeleBot(config.token)

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

2. Разворачиваем функционал

Начнём с того, что для того, чтобы пользователю запустить бота, нам необходимо прописать команды для старта они могут быть разными, например, /start или /go и вообще любыми, какие Вы сочтёте нужными.

Для обработки команд нам потребуется message_handler, с помощью которого и будет реализован весь функционал обработки команд для старта и завершения, если Вы сочтёте нужным добавить завершение. Как только придёт команда /go или /start, message_handler с соответствующими командами сравнит, совпадают ли строки и если совпадают, то обработает соответствующей функцией.

Каждая функция, как и в примере сейчас, должна принимать один параметр — сообщение от пользователя, которое будет обработано соответствующей функции «в обёртке» декоратора. А также, каждая функция (или связка функций) должна возвращать соответсвующее сообщение от бота.

Итак:

@bot.message_handler(commands=['go', 'start'])  # Обработка команды для старта
def welcome(message):
    sti = open(path+'stiker.tgs', 'rb')
    bot.send_sticker(message.chat.id, sti)
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)

    item3 = types.KeyboardButton("Приложения")
    item2 = types.KeyboardButton("Мероприятия")
    item1 = types.KeyboardButton('О нас')

    markup.add(item1, item2, item3)

    bot.send_message(message.chat.id,
                     "Добро пожаловать, {0.first_name}!nnЯ - <b>{1.first_name}</b>, бот команды Projector в НГТУ, "
                     "создан для того, "
                     "чтобы помочь Вам влиться в нашу команду,"
                     "просто узнать что-то о нас или же просто пообщаться и весело провести время.nn"
                     "<i>Have a nice time</i>".format(
                         message.from_user, bot.get_me()),
                     parse_mode='html', reply_markup=markup)

В этой функции реализовано сразу два действия: отправка приветственного сообщения и создание встроенной клавиатуры — ReplyKeyboardMarkup, которая будет открыта, пока мы не завершим выполнения бота соответсвующей командой. Об этом будет сказано ниже.

Итак, пройдёмся по строчкам:

В строках 20-21: открывается стикер по тому пути к директории, в которой я его сохранил, после чего отправляется.

Строки 22-28: создаем встроенную клавиатуру, добавляя туда три элемента.

Строки 30-37: описано создание и отправка приветственного сообщения

Как вы можете заметить, метод send_message в строке 30, позволяет использовать HTML, для форматирования текста.

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

# RUN
if __name__ == "__main__":
    try:
        bot.polling(none_stop=True)
    except ConnectionError as e:
        print('Ошибка соединения: ', e)
    except Exception as r:
        print("Непридвиденная ошибка: ", r)
    finally:
        print("Здесь всё закончилось")

Сделаем первый запуск! Для этого, в PyCharm-е нажмём зеленую кнопку старт в правом верхнем углу или же, можно запустить из консоли командой: python bot.py

kzzvk7yeztlh6bc65ebtytsmpu4

Результат первого запуска:

9dyt7 dni zwgmq8u5t0eqizptm

2.1 Обработка нажатия на кнопки и создание inline keyboard

Так как любое сообщение — это текст, то мы будем обрабатывать именно текстовые сообщения.

Сделаем следующее и аналогично разберём по строчкам:

@bot.message_handler(content_types=["text"])
def go_send_messages(message):
    if message.chat.type == 'private':
        if message.text == 'Приложения':

            keyboard = types.InlineKeyboardMarkup(row_width=1)
            itemboo = types.InlineKeyboardButton(text="Тыщ на кнопку и ты уже в Google", url="<https://www.google.ru>")
            itemboo1 = types.InlineKeyboardButton('Рандомное число', callback_data='good2')
            itemboo2 = types.InlineKeyboardButton("Калькулятор", callback_data='bad2')
            itemboo3 = types.InlineKeyboardButton("Хочу узнать погоду в моем городе/стране", callback_data='good3')
            itemboo4 = types.InlineKeyboardButton("Как твои дела?", callback_data='bad4')

            keyboard.add(itemboo, itemboo1, itemboo2, itemboo3, itemboo4)

            bot.send_message(message.chat.id,
                             "{0.first_name}, окей, смотри, что у нас есть тут:n".format(message.from_user),
                             reply_markup=keyboard)

        elif message.text == "Мероприятия":
            one_markup = types.InlineKeyboardMarkup(row_width=1)
            ite1 = types.InlineKeyboardButton("Ближайшие мероприятия", callback_data="one")
            ite2 = types.InlineKeyboardButton("Проведенные мероприятия", callback_data="two")
            ite3 = types.InlineKeyboardButton("Волонтерство на мероприятие", callback_data="three")
            ite4 = types.InlineKeyboardButton("Действующие проекты в НГТУ", callback_data="fourth")
            ite5 = types.InlineKeyboardButton("Мероприятия Межвузовского центра", callback_data="five")
            one_markup.add(ite1, ite2, ite3, ite4, ite5)
            bot.send_message(message.chat.id, "{0.first_name}, у нас <u>ежемесячно</u> проводится множество "
                                              "мероприятий,nмы постарались разбить их на следующие составляющие:".format(
                message.from_user), parse_mode="html", reply_markup=one_markup)

Строка 339 — обработчик любых текстовых сообщений

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

Строки 344 — 351 — создаём инлайновую клавиатуру InlineKeyboardMarkup и помещаем в эту клавиатуру 5 элементов, которые также можно будет обработать по установленной callback_data. Элементы данной клавиатуры будут расположены друг под другом, так как в строке 344, мы установили row_width = 1, что обозначает самую широкую грань одной кнопки, поэтому они и будут расположены друг под другом.

Строки 353-355 — отправляют текст, вместе с нашей Inline Keyboard.

В условиях ниже представлены аналогичные представления обработки сообщений.

Итак, сделаем запуск:

2.2 Обработка InlineKeyboardButton

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

@bot.callback_query_handler(func=lambda call: call.data in ['one', 'two', 'three', 'fourth', 'five'])  # Мероприятия
def callback_inline_one(call):
    try:
        if call.message:
            if call.data == 'one':  # Ближайшие мероприятия
                bot.send_message(call.message.chat.id,
                                 "Итак,<b>ближайшие мероприятия</b>:nn"  # Здесь будут ссылки ещё
                                 "Форум «Байкал»n"
                                 "Конкурс «Цифровой ветер»n"
                                 "PRONETI", parse_mode="html")
            elif call.data == 'two':  # Проведённые мероприятия
                bot.send_message(call.message.chat.id, "Вот список <b>проведённых мероприятий</b>:nn"
                                                       "МНТКn"
                                                       "Семинары по проектной деятельностиn"
                                                       "Встреча с представителями предприятий", parse_mode="html")
            elif call.data == 'three':

Итак, разберём построчно:

Строка 269 — объявляем обработчик, который будет обрабатывать каждую из нажатых кнопок с использованием лямбда-функции

Строки 273-278 — В данном блоке if, мы просто обрабатываем сообщение и отправляем сообщение пользователю.

Строки 279-283 — Делают аналогичное действие, что и в предыдущем условном блоке.

и т. д.

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

Результат:

Так просто и обрабатываются inline keyboards.

3. Завершаем работу бота

Данная функция будет аналогичной функции обработки команд для старта бота, поэтому Вы сможете легко понять её функционал:

@bot.message_handler(commands=['stop'])  # Обработка команды для выхода
def bye(message):
    bye_Sti = open(path+'byeMorty.tgs', 'rb')

    hideBoard = types.ReplyKeyboardRemove()
    bot.send_message(message.chat.id,
                     "Досвидания, {0.first_name}!nМы, команда <b>{1.first_name}</b>, надеемся, что ты хорошо провел(а) время nn"
                     "Присоединяйся к нашей команде в <a href='<https://vk.com/projector_neti>'>vk</a>n"
                     "Наш <a href='<https://instagram.com/projector_neti>'>inst</a>nn"
                     "Напиши Координатору проектов (<a href='<https://vk.com/nikyats>'>Никите Яцию</a>) и задай интересующие тебя вопросы по <i>проектной деятельности</i>nn"
                     "Надеемся, что тебе ответят очень скоро nn"
                     "<u>Don't be ill and have a nice day</u> nnn"
                     "P.S.: Если есть какие-то пожелания или вопросы по боту, то напиши <a href='<https://vk.com/setmyaddresspls>'>мне</a>".format(
                         message.from_user, bot.get_me()), parse_mode='html', reply_markup=hideBoard)
    exit()

Здесь происходит следующее:

  1. Отправляется прощальный стикер.
  2. Закрывается встроенная клавиатура (строка 44).
  3. Отправляется прощальное сообщение.

Так как мы используем bot.polling, с параметром none_stop = True, то пользователь может снова вознообновить общение с ботом при помощи команды /start или /go, обработка которых показано в пункте выше.

Результат:

ВК БОТ

Перейдём к реализации бота Вконтакте, написанном на том же родном языке Python, его основное отличие от предыдущего в том, что он был написан с использованием ООП, а именно класса. Внешне, он выполняет ту же миссию. Сама библиотека для написания вк бота намного проще телеграмм бота, поэтому разобраться в ней самостоятельно не составит большого труда. Итак, начнём.

1. Предварительные подготовления

Установим следующие библиотеки по тем же технологиям:

import vk_api # pip install vk-api
import json   # pip install json
from vk_api.longpoll import VkLongPoll, VkEventType

▍1.1 Получение токена для сообщества Вконтакте.

  1. На главной странице сообщества найти раздел «Управление»
  2. Работа с API
  3. Создать ключ. Выбираете нужные для вас пункты, которые будут доступны боту.

В итоге должно получиться примерно следующее:

Берем ключ и переходим в среду разработки и делаем следующее:

vk = vk_api.VkApi(token=
                  "Ваш_токен")

Далее — следующее:

longpoll = VkLongPoll(vk)

На этом, закончим подготавления.

2. Разворачиваем функционал

Первым делом создадим файл manage.py

Cоздадим прототип встроенной клавиатуры ( всё с помощью документации VkBotAPI ).

main_keyboard = {
    "one_time": False,
    "buttons": [
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "1"}",
                "label": "О нас"
            },
            "color": "positive"
        }],
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "2"}",
                "label": "Мероприятия"
            },
            "color": "positive"
        },
            {
                "action": {
                    "type": "text",
                    "payload": "{"button": "3"}",
                    "label": "Приложения"
                },
                "color": "positive"
            }
        ],
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "4"}",
                "label": "Контакты"
            },
            "color": "primary"
        }]
    ]
}

Затем переводим её в формат json, как требуется в документации:

main_keyboard = json.dumps(main_keyboard, ensure_ascii=False).encode('utf-8')
main_keyboard = str(main_keyboard.decode('utf-8'))

Пример инлайн клавиатуры:

about_us_keyboard = {
    "inline": True,
    "buttons": [
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "1"}",
                "label": "Основная информация"
            },
            "color": "positive"
        }],
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "2"}",
                "label": "Чем мы занимаемся ?"
            },
            "color": "primary"
        },
        {
            "action": {
                "type": "text",
                "payload": "{"button": "3"}",
                "label": "Где мы находимся ?",
            },
            "color": "positive"
        }],
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "4"}",
                "label": "Как попасть в команду ?",
            },
            "color": "primary"
        }],
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "5"}",
                "label": "Контакты",
            },
            "color": "secondary"
        }],
        [{
            "action": {
                "type": "text",
                "payload": "{"button": "6"}",
                "label": "Задать вопрос руководителю проекта",
            },
            "color": "negative"
        }]
    ],
}

Не забываем все используемые клавиатуры переводить в формат json:

about_us_keyboard = json.dumps(about_us_keyboard, ensure_ascii=False).encode('utf-8')
about_us_keyboard = str(about_us_keyboard.decode('utf-8'))

Создадим функцию write_msg, для того, чтобы не мучиться с постоянной отправкой сообщений от бота:

def write_msg(user_id, message, key):
    vk.method('messages.send',
              {'user_id': user_id,
               'message': message,
               'keyboard': key,
               'random_id': random.randint(0, 2048)})

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

▍2.1 Основной функционал (создаем файл vk_bot.py)

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

Конструктор класса:

class VkBot:

    def __init__(self, user_id):
        self.USER_ID = user_id
        self._USERNAME = self._get_user_name_from_vk_id(user_id)
        self.my_str = ""
        self._COMMANDS = ["привет", "погода", "время", "пока"]

        self._inputMes = {"основная информация": answers.about_us1,
                          "чем мы занимаемся ?": answers.about_us2,
                          "где мы находимся ?": answers.about_us3,
                          "ближайшие мероприятия": answers.events1,
                          "проведённые мероприятия": answers.events2,
                          "волонтёрство на мероприятие": answers.events3,
                          "действующие проекты в нгту": answers.events4,
                          "мероприятия межвузовского центра": answers.events5
                          }

Последнее свойство класса — inputMes — это особый словарь, у которого значения ключей — это текст из файла answers.py, где я расположил текст в виде строк, поэтому, чтобы не загромождать код я и вынес основной текст в другой файл.

(Пример кода из файла answers.py)

events1 = "Итак,ближайшие мероприятия:nn" 
          "Форум «Байкал»n"
          "Конкурс «Цифровой ветер»n"
          "PRONETI"

events2 = "Вот список проведенных мероприятий:n"
        "МНТКn"
        "Семинары по проектной деятельностиn"
        "Встреча с представителями предприятийn"

events3 = "По поводу этого критерия напиши Илье (<https://vk.com/ki1337ki>)n"
        "А также, ты можешь заполнить анкету, благодаря которой,n"
        "с тобой лично свяжется один из руководителей направленияn"
        "или координатор проекта (<https://vk.com/nikyats>)"

Итак, основной метод класса — это new_message, который принимает один параметр — message, который обрабатывается соответствующим условным блоком и возвращает какое -то значение обратно туда, откуда был вызван.

def _get_user_name_from_vk_id(self, user_id):
    request = requests.get("<https://vk.com/id>" + str(user_id))

    bs = bs4.BeautifulSoup(request.text, "html.parser")

    user_name = self._clean_all_tag_from_str(bs.findAll("title")[0])

    return user_name.split()[0]

def new_message(self, message):
    # self.my_str = " ".join(re.findall('[0-9]{2}', message))

    if message.lower() == self._COMMANDS[0]:
        return f"Привет, {self._USERNAME}!"

    elif message.lower() == self._COMMANDS[1] or message.lower() == "узнать погоду ":
        return self._get_weather()

    elif message.lower() == self._COMMANDS[2] or message.lower() == "узнать точное время ":
        return self._get_time()

    elif message.lower() == self._COMMANDS[3]:
        return f"До скорой встречи, {self._USERNAME}!"

    else:
        for key, value in self._inputMes.items():
            if message.lower() == key:
                return value
        return "Не понимаю тебя "

3. Возвращаемся в manage.py и дописываем функционал

Теперь в первых строках нам необходимо проимпортить файл vk_bot. А также нам потребуется библиотека random.

import random # pip install random
from vk_bot import VkBot

После того, как мы объявили longpoll, дописываем основной функционал.

longpoll = VkLongPoll(vk)

try:
    for event in longpoll.listen():
        if event.type == VkEventType.MESSAGE_NEW:
            if event.to_me:
                bot = VkBot(event.user_id)

                if event.text.lower() == "о нас":
                    write_msg(event.user_id, "Немного о нашем проекте", about_us_keyboard)
                elif event.text.lower() == "мероприятия":
                    write_msg(event.user_id, "Что ты хочешь узнать?", events_keyboard)
                elif event.text.lower() == "приложения":
                    write_msg(event.user_id, "Посмотри, что есть здесь!", app_keyboard)
                elif event.text.lower() == "контакты":
                    write_msg(event.user_id, "По любым вопросам можешь обращаться к:", contacts_keyboard)
                elif event.text.lower() == "задать вопрос руководителю проекта":
                    write_msg(event.user_id, "У тебя есть возможность написать сообщение нашему Руководителю проекта",
                              go_answer)
                elif event.text.lower() == "калькулятор":
                    write_msg(event.user_id, "В разработке...", calc_keyboard)
                # elif event.text == " ".join(re.findall('d{2}', event.text)):
                #     write_msg(event.user_id, "Отлично, мы здесь", calc_keyboard)
                elif event.text.lower() == "как попасть в команду ?":
                    write_msg(event.user_id, "Напиши координатору проекта - Никитеn"
                                             "или перейди на сайт проектной деятельности,n"
                                             "найди проект номер 612 и подай заявку", in_team)
                else:
                    write_msg(event.user_id, bot.new_message(event.text), main_keyboard)

except Exception as e:
    print(e)

Как можете заметить, в условных блоках if и elif — присутствует обработка тех сообщений, которые подразумевают под собой вывод инлайн или встроенной клавиатуры (в данном примере — выводятся только инлайн клавиатуры). Сюда также можно добавить более сложные обработки сообщений, после которых обработка будет метаться туда сюда по блокам if и elif. Таким образом бот будет работать, пока не «упадёт с ошибкой».

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

Заключение

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

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

Весь код опубликован в моём профиле GitHub:

  • Телеграм Бот
  • Бот Вконтакте

oug5kh6sjydt9llengsiebnp40w

У большинства россиян есть любимый советский фильм (82%), любимая советская песня (61%) и любимая советская книга (55%), свидетельствуют данные ВЦИОМ, собранные в рамках совместного проекта с РБК «30 лет без СССР». Всего в ходе открытого опроса (респонденту нужно было самому назвать произведение, а не выбирать из списка) участники перечислили по несколько десятков кинолент, музыкальных и литературных произведений времен СССР. Абсолютных лидеров по предпочтениям среди них нет: самые популярные произведения набрали максимум 6% приверженцев.

Среди советских фильмов планку в 1% преодолели 25 картин, среди книг — 19 произведений, среди песен — 23 (с учетом таких сборных ответов, как песни Аллы Пугачевой, песни Муслима Магомаева, песни Виктора Цоя, песни Анны Герман). Не обошлось и без курьезов: по 1% опрошенных назвали своей самой любимой советской книгой «Войну и мир» Льва Толстого, написанную более чем за полвека до создания СССР, а также «Три мушкетера» Александра Дюма, изданную еще раньше.

Опрос ВЦИОМа был проведен 24 ноября среди 1,6 тыс. россиян в возрасте от 18 лет методом телефонного интервью. Для выборки максимальный размер ошибки с вероятностью 95% не превышает 2,5%, отмечает ВЦИОМ.

Список самых любимых кинолент россиян возглавили две мелодрамы — «Москва слезам не верит» (6%) и «Девчата» (5%). Женщины их упоминали чаще (8%), чем мужчины (3 и 1% соответственно), а люди старше 25 лет — чаще, чем более молодые. На третьем месте по числу голосов — комедия «Операция “Ы” и другие приключения Шурика» (4%), фильм, который оказался самым популярным среди молодежи: его назвали любимым 11% людей в возрасте от 18 до 24 лет. Мужчины вспоминали о нем чаще, чем женщины (5 и 2% соответственно). По 4% голосов набрали военные фильмы «В бой идут одни старики» и «А зори здесь тихие».

В число любимых также вошла знаменитая новогодняя кинолента «Ирония судьбы, или С легким паром!» с 3% голосов (ее одинаково любят и мужчины, и женщины, а среди молодежи за нее высказались 7% опрошенных). Столько же голосов получили комедия «Бриллиантовая рука», многосерийный фильм «17 мгновений весны» (особенно популярен на Северном Кавказе, 10% голосов) и военная драма «Офицеры» (чаще ее называли люди от 45 лет и старше).

Выбор россиян нельзя назвать неожиданным, сказал РБК доцент кафедры драматургии кино ВГИКа Всеволод Коршунов. «“Москва слезам не верит” — одна из любимых мелодрам в истории советского кино, и плюс ко всему у [фильма] самая высокая посещаемость в истории советского проката», — напомнил он.

Среди песен больше всего голосов опрошенных — по 4% — набрали гимн Советского Союза и песня «Катюша», показал опрос ВЦИОМ. Гимн СССР — самый популярный ответ у представителей среднего возраста от 34 до 59 лет (5−7%), у «Катюши» почитатели более молодые: ее назвали любимой 5% респондентов в возрасте до 25 лет, 7% — в возрасте до 34 лет и 6% — в возрасте до 45 лет, среди старшего поколения ее выбрали лишь по 2−3% опрошенных. Если исходить из географии, то гимн СССР лидирует на Дальнем Востоке с 11% голосов, а «Катюша» — на Северном Кавказе с 14% голосов. Ни в одном из других федеральных округов ярко выраженных лидеров нет.

Самой популярной у возрастной категории от 18 до 25 лет оказалась песня «Прекрасное далеко» из подросткового фильма «Гостья из будущего» (ее назвали 7% в этой категории, тогда как в целом она набрала 1% почитателей). Впрочем именно среди молодежи велика доля тех, кто ответил, что среди советских песен любимых нет: так сказала почти треть опрошенных в группах от 18 до 34 лет (32−33%).

Больше 1% также набрали песни, связанные с Великой Отечественной войной: «День Победы» (3%), «Священная война» (2%), «Смуглянка» (2%), а также песня «Надежда» Александры Пахмутовой и Николая Добронравова (2%).

Любимые книги времен СССР назвали 55% опрошенных. Среди самых популярных оказались «Как закалялась сталь» Николая Островского (5%), «Тихий Дон» Михаила Шолохова (4%) и «Мастер и Маргарита» Михаила Булгакова (3%). Роман Булгакова оказался популярен среди молодежи: в возрастной группе до 25 лет его назвали 7% опрошенных. К романам Островского и Шолохова молодые люди, напротив, оказались равнодушны: среди любимых их назвали менее 1% россиян этого возраста. Роман Островского наиболее популярен в Южном (8% проживающих там) и Северо-Кавказском (6%) федеральных округах, роман Шолохова предпочитают на Дальнем Востоке (9%) и не очень ценят на Урале (1%). Булгакова больше всего любят в Южном ФО (7%) и в Северо-Западном ФО (5%).

svg+xml;uft 8,%3Csvg%20width%3D%22117%22%20height%3D%2228%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Cpath%20d%3D%22M46.939%207.84h 9.846l.001.005c.002.517 .127%206.472 .217%208.185 .083%201.579 .396%202.123 2.081%202.235 .145.003 .29.004 .436.003l .012%202.341c.04.008%201.924.29%203.16 .447%201.585 .945%201.9 2.638%201.972 3.995.054 1.039.125 3.864.171 5.816h4.683l .003%2010.258h2.608V7.84Z%22%20fill%3D%22%23fff%22%2F%3E%0A%20%20%3Cpath%20fill rule%3D%22evenodd%22%20clip rule%3D%22evenodd%22%20d%3D%22M61.843%2018.399c .04.046 .082.094 .125.139 2.036%202.144 4.13%202.428 5.718%202.428a6.714%206.714%200%200%201 6.712 6.712A6.715%206.715%200%200%201%2056%207.542c2.625%200%204.9%201.51%206.003%203.709.163.335.815%201.858.583%204.3H52.101c.491%201.648%202.07%202.837%203.899%202.837%201.914 .001%203.263 .819%204.172 1.679l1.671%201.69Zm 1.874 5.359c .415 1.589 1.92 2.886 3.969 2.886 2.05%200 3.542%201.27 3.937%202.886h7.906Z%22%20fill%3D%22%23fff%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M73.428%2018.098h 5.831c1.044 .953%201.354 2.86%201.335 4.959l .001 .225h.001v 2.563h4.496v7.747Zm4.316%200h 1.707V7.84h 9.713v5.074h.001v.005l.004.698c.007%201.172 .004%204.461 2.463%204.475l .484.006v5.371h2.608v 2.86h9.146v2.86h2.608v 5.371Z%22%20fill%3D%22%23fff%22%2F%3E%0A%20%20%3Cpath%20fill rule%3D%22evenodd%22%20clip rule%3D%22evenodd%22%20d%3D%22M82.318%2020.609H80.15V7.84h2.609v8.525l7.409 8.525h2.168v12.769h 2.609v 8.348l 7.409%208.348Z%22%20fill%3D%22%23fff%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M18.211%2014A4.216%204.216%200%200%201%2014%2018.211%204.216%204.216%200%200%201%209.789%2014%204.216%204.216%200%200%201%2014%209.789%204.216%204.216%200%200%201%2018.211%2014ZM14%200C6.28%200%200%206.28%200%2014s6.28%2014%2014%2014a13.92%2013.92%200%200%200%207.886 2.435l.04 .028 1.886 2.192 .032.02A11.077%2011.077%200%200%201%2014%2025.13C7.863%2025.13%202.87%2020.137%202.87%2014%202.87%207.863%207.863%202.87%2014%202.87c6.137%200%2011.13%204.993%2011.13%2011.13%200%20.795 .089%201.6 .262%202.392 .352%201.445 1.364%201.887 2.123%201.829 .764 .062 1.658 .606 1.664 1.938V14A7.088%207.088%200%200%200%2014%206.919%207.088%207.088%200%200%200%206.919%2014a7.088%207.088%200%200%200%209.8%206.541%207.022%207.022%200%200%200%202.298 1.55%204.55%204.55%200%200%200%203.498%202.091%204.733%204.733%200%200%200%203.218 .943c.839 .638%201.466 1.559%201.812 2.666.055 .179.157 .588.157 .591l.003 .015c.204 .888.295 1.773.295 2.867%200 7.72 6.28 14 14 14%22%20fill%3D%22%23FF9E00%22%2F%3E%0A%20%20%3Cpath%20d%3D%22M110.51%2017.091c 3.159%200 5.074 2.19 5.147 5.83h1.602c.05%202.672%201.265%203.809%202.201%204.038v 4.037h1.534v2.307c.902 .101%201.842 1.148%202.156 2.307h1.506c .24%201.422 1.265%202.475 1.988%202.906.723.347%201.893%201.266%202.341%202.923h 1.657c .348 1.109 1.21 1.965 2.358 2.083v2.083h .19ZM109.714%2021h.583c3.164%200%204.749%200%205.729 .98.974 .986.974 2.57.974 5.723v .594c0 3.158%200 4.737 .974 5.723 .98 .98 2.565 .98 5.729 .98h .583c 3.164%200 4.748%200 5.734.98 .986.98 .98%202.57 .98%205.723v.594c0%203.158%200%204.737.98%205.723.98.986%202.57.98%205.734.98Z%22%20fill%3D%22%23fff%22%20fill opacity%3D%22

По 2% голосов, согласно опросу ВЦИОМ, набрали еще всего две книги — еще один роман Шолохова «Поднятая целина» и роман Александра Фадеева «Молодая гвардия». Про «Поднятую целину» чаще вспоминали люди старше 60 лет (4% голосов в этой возрастной группе), а «Молодую гвардию» чаще называли женщины, чем мужчины (3 против 1%). По 1% приверженцев набрали еще 12 произведений, а также общие категории «Книги Валентина Пикуля» и «Детские сказки, рассказы».

Относительно популярным среди молодежи стал «Пикник на обочине» братьев Стругацких (3% голосов людей моложе 25 лет), а снятый по мотивам этой повести «Сталкер» Андрея Тарковского не получил поддержку среди молодежи, собрав менее 1% голосов. Также по 3% голосов среди молодежи получило еще одно произведение Булгакова — повесть «Собачье сердце».

Профессор, доктор филологических наук, заведующий кафедрой литературы и лингвистики, проректор МГИК Александр Ужанков в разговоре с РБК назвал тройку любимых россиянами советских книг предсказуемой. «Все три книги являются знаковыми для XX века, — пояснил он. — Если мы посмотрим на русскую литературу XIX века, то увидим, что в ней не было идеальных героев, а вот Островский создает идеального героя советской эпохи — Павла Корчагина, который готов пожертвовать своей жизнью ради строительства будущего коммунизма».

«Тихий Дон», по мнению Ужанкова, привлекает внимание не только читателей, но и экспертов — ведь благодаря нему Шолохов стал одним из немногочисленных россиян — лауреатов Нобелевской премии по литературе.

«“Мастер и Маргарита” — это совершенно иного плана роман, но тоже актуальный для XX века, — считает филолог. — Булгаков закончил его в 1940 году, но опубликован он был в конце 60-х, а это время гонения на РПЦ, так что русский человек, который принадлежит русской культуре, в этом романе увидел духовную наполняемость». Все перечисленные романы были изданы огромными тиражами, напомнил Ужанков.

Сейчас то, как будет восприниматься советская эпоха будущими поколениями, зависит от восприятия этого периода российской истории современной молодежью, отметила в разговоре с РБК советник гендиректора ВЦИОМ Елена Михайлова.

«Через призму новой системы приоритетов и ценностных ориентаций постепенно происходит переосмысление событий, уходят на второй план знаковые фигуры и отдельные культурные символические элементы», — отмечает она.

В рамках опроса ВЦИОМ также выяснилось, что только каждый пятый россиянин не смог правильно расшифровать аббервиатуру СССР и что главным антигероем советской эпохи в России считают Михаила Горбачева.

Евгения Кузнецова при участии Анастасии Серовой

Во время загрузки произошла ошибка.

Написание воркер-сервисов на .NET часто сопряжено с написанием большого количества повторяющегося boilerplate-кода. Однажды мне это надоело и я попытался упростить этот процесс, перенеся часть бойлерплейта в отдельную библиотеку, которой и посвящена эта статья.

Знакомство с библиотекой

Библиотека называется dotWork, у нее есть репозиторий на GitHub, а сборки выкладываются на NuGet. По большей части библиотека представляет собой обертку над BackgroundService, встроенным в .NET решением для написания воркеров.

Что конкретно упрощает dotWork?

Если вкратце, dotWork упрощает следующие аспекты разработки воркеров:

  • регистрацию работ (works);

  • регистрацию соответствующих работам настроек;

  • написание кода для повторения итераций.

В моей практике именно эти три момента требуют практически шаблонного кода и тем не менее не имеют возможности стандартизации «из коробки».

Установка

Для установки достаточно поставить NuGet пакет:

dotnet add package dotWork

Использование

Для использования библиотеки нам нужно создать один или несколько классов-работ (works), описывающих, что должен делать работник (worker). В контексте .NET работником выступает само приложение, либо хост, если приложение содержит несколько хостов.

Создание класса-работы

Для создания работы добавим в приложение новый класс, унаследованный от WorkBase:

public class ExampleWork : WorkBase<DefaultWorkOptions> { }

Теперь добавим метод, описывающий, из чего состоит работа. Работник будет вызывать его с определенной периодичностью, поэтому этот метод можно назвать итерацией:

public class ExampleWork : WorkBase<DefaultWorkOptions>
{
    public async Task ExecuteIteration(CancellationToken ct)
    {
        await Task.Delay(TimeSpan.FromSeconds(1), ct); // симулируем работу
        Console.WriteLine("Work iteration finished!");
    }
}

Важно! Чтобы dotWork нашла метод итерации, необходимо, чтобы он соответствовал следующим правилам:

  • имел название ExecuteIteration;

  • был помечен модификатором public;

  • возвращал void или Task.

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

Внедрение зависимостей

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

Singleton-зависимости

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

public class ExampleWork : WorkBase<DefaultWorkOptions>
{
    readonly SingletonService _singletonService;

    public ExampleWork(SingletonService singletonService)
    {
        _singletonService = singletonService;
    }

    ...
}

Scoped и Transient зависимости

Часто возникает необходимость внедрить не-singleton зависимости в работу. Типичный пример — база данных. Поскольку работа живет до остановки хоста, то внедрение в нее коннектора базы данных может привести к тому, что соединение с БД будет открыто с самого начала и до самого конца работы программы. Это может быть нежелательно, например, если работа короткая и выполняется раз в длительный промежуток времени.

В таком случае, зависимость можно внедрить напрямую в метод итерации:

public async Task ExecuteIteration(ScopedService scopedService)
{
    await Task.Delay(TimeSpan.FromSeconds(1), ct);
    Console.WriteLine("Work iteration finished!");
}

Сервисы, внедренные таким образом, будут удалены после окончания итерации. dotWork создает новый scope на каждую итерацию.

Помимо сервисов, в метод итерации можно также внедрить CancellationToken. Он сработает, когда хост начнет остановку

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

Регистрация работ

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

Регистрация одной работы

Зарегистрировать одну отдельную работу можно, добавив следующий вызов в метод ConfigureServices HostBuilder-a:

.ConfigureServices(services =>
{
    services.AddWork<ExampleWork, DefaultWorkOptions>(); // <- наш метод
})

Здесь первым дженерик-параметром является тип работы, а вторым — тип настроек работы. Важно, чтобы тип настроек, указанный при регистрации, совпадал с тем, который указан при наследовании работы от класса WorkBase.

На данном этапе наша работа полностью готова к запуску. Однако, если запустить ее, обнаружится, что итерация выполняется только один раз. Это нормально — настройка работы по-умолчанию (DefaultWorkOptions) устанавливает бесконечную задержку между итерациями. Мы можем изменить это, переопределив стандартную настройку:

services.AddWork<ExampleWork, DefaultWorkOptions>(configure: opt =>
{
    opt.DelayBetweenIterationsInSeconds = 10;
});

Теперь следующая итерация работы начнется через 10 секунд после окончания предыдущей.

Автоматическая регистрация работ

Вместо того, чтобы регистрировать каждую работу по-отдельности, мы можем зарегистрировать все работы сразу. Очевидно, что при этом у нас нет возможности настроить каждую работу, поэтому этот способ регистрации требует обязательного указания раздела конфигурации с настроками работ. Этот раздел должен представлять из себя словарь, где ключами являются названия классов работ. Легче всего продемонстрировать это на примере. Предcтавим, что у нас есть приложение с двумя работами:

  • ExampleWork1

  • ExampleWork2

Файл appSettings.json, в таком случае, может выглядеть следующим образом:

{
    "Works": {
        "ExampleWork1": {
            "IsEnabled": false,
            "DelayBetweenIterationsInSeconds": 86400 // 1 day
        },
        "ExampleWork2": {
            "DelayBetweenIterationsInSeconds": 3600 // 1 hour
        }
    }
}

И мы можем зарегистрировать все наши работы одной строчкой кода:

.ConfigureServices((ctx, services) =>
{
    services.AddWorks(ctx.Configuration.GetSection("Works"));
});

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

.ConfigureServices((ctx, services) =>
{
    var cfg = ctx.Configuration;
    services.AddWorks(cfg.GetSection("Works"));
    services.AddWork<ExampleWork1, DefaultWorkOptions>(configure: opt =>
    {
        opt.DelayBetweenIterationsInSeconds = 86400 * 2; // 2 days
    });
})

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

Изменение класса настроек

Работа необязательно должна использовать DefaultWorkOptions в качестве настроек. Можно создать свой класс, унаследовав его от DefaultWorkOptions или даже напрямую от интерфейса IWorkOptions:

public class MyWorkOptions : DefaultWorkOptions
{
    public string MyProp { get; set; }
}

public class Work_With_DefaultWorkOptions2 : WorkBase<DefaultWorkOptions2>
{
    public async Task ExecuteIteration()
    {
        Console.WriteLine("MyProp value is: " + Options.MyProp);
    }
}

Заключение

Надеюсь, dotWork поможет сэкономить время при написании приложений-воркеров. Если после начала использования библиотеки Вы обнаружите, что в ней отсутствует какая-то важная ожидаемая функциональность, пожалуйста, откройте issue в репозитории GitHub.

Еврокомиссар Оливер Вархели пока не может сказать наверняка, попадёт ли “Белавиа” в новый пакет европейских санкций.

Но если европейские лизинговые компании расторгнут контракты с “Белавиа”, у белорусского перевозчика останется ещё 12 самолётов. Минимум 8 из них — в собственности.

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

Еврокомиссар Оливер Вархели пока не может сказать наверняка, попадёт ли “Белавиа” в новый пакет европейских санкций.

Но если европейские лизинговые компании расторгнут контракты с “Белавиа”, у белорусского перевозчика останется ещё 12 самолётов. Минимум 8 из них — в собственности.

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

1. Sukhoi Superjet 100
Почему.
Выгодно. А в пандемию — дважды выгодно.

Нюанс. “Суперджетов” побаиваются после катастрофы в аэропорту “Шереметьево”.

Если западные компании откажутся дать самолёт в аренду из-за санкций, то “Белавиа” сможет обратиться за “Суперджетами” в Россию.

Это ближне- и среднемагистральные самолёты. То есть ими можно заменить и бразильские “Эмбраеры”, и небольшие американские “Боинги”.

Правда, взять в аренду “Суперджет” сейчас не так и просто — за ним уже выстроилась очередь, говорит руководитель интернет-портала Avia.ru Роман Гусаров. Во-первых, потому что производитель предлагает выгодные условия и льготные кредиты. Во-вторых, потому что Covid-кризис показал: летать на заполненном маленьком самолёте выгоднее, чем на полупустом большом.

— На днях я вернулся из командировки. Летал большим самолётом — порядка 180 кресел. На борту было человек 50. Такой рейс для авиакомпании убыточный, потому что доход будет меньшим, чем расходы. А если бы вместо этого самолёта летел “Суперджет” [87-108 пассажиров. — Еврорадио], рейс был бы рентабельным. Роман Гусаров, руководитель интернет-портала Avia.ru

Поэтому может оказаться, что в условиях снижения пассажиропотока “Суперджет” станет популярным самолётом, пусть и не на всех направлениях.

— По всем параметрам это современный магистральный самолёт. Хотя у нас, в России, его называют региональным. Но самолёт, который с пассажирами может пролететь 4,5 тысячи километров — вся Европа поперёк, всё же сложно назвать региональным. Это обычный магистральный самолёт.

2. МС-21, он же — Магистральный самолёт ХХI века
Почему.
Российский аналог Airbus A320neo и Boeing 737 8.

Нюанс. Придётся подождать лет 10.

Этот самолёт проходит завершающую стадию сертификации.

— Я недавно вернулся с авиасалона в Дубае, где презентовали этот самолёт с российскими двигателями. Получить его у “Белавиа” шанс есть — но нескоро. Начало серийных поставок намечено только на следующий год. И первые самолёты, скорее всего, получит группа компаний “Аэрофлот”, — говорит Роман Гусаров.

К тому же в первый год произвести много самолётов не получится. Серийное производство лайнеров — это маховик, который раскручивается постепенно, поясняет нам эксперт. В лучшем случае в следующем году сделают 5 самолётов, ещё через год — 10. Ждать долго.

— Боюсь, что в ближайшие годы “Белавиа” не перепадёт. Заказы примерно на 200 самолётов уже размещены — а это до конца десятилетия.
 

3. Турбовинтовой самолёт L-410
Почему.
Производится в России в немалых количествах, можно заказать хоть сегодня.

Нюанс. Летает недалеко.

Купить такой самолёт довольно легко — нехватки нет.

Вот только “Белавиа” в основном ориентируется на среднемагистральные полёты, так что и самолёты нужны не турбовинтовые, а реактивные. С хорошей скоростью и большой дальностью полёта. Чтобы не до Москвы довезли, а до курорта, так что едва ли это будет хорошим вариантом пополнения парка.
 

4. Российские турбовинтовые самолёты регионального класса
Почему.
Летают далеко, до курорта довезут.

Нюанс. Поставки могут начаться только в 2024 году.

Авиакомпании могли бы подойти турбовинтовые самолёты регионального класса, говорит Гусаров.

Например, Ил 114-300, который в России производят для внутренних перелётов.

— Но их поставка находится ещё в более дальней перспективе, чем МС-21.
 

5. Взять в субаренду всё, что захочешь
Почему
. У многих авиакомпаний из-за пандемии парк простаивает.

Нюанс. Было бы куда лететь.

— Сейчас рынок в таком состоянии, что у любой авиакомпании можно взять самолёт в субаренду. У всех авиакомпаний немалый процент парка стоит — можно взять и полететь, — говорит Гусаров.

А можно взять технику в аренду через китайские лизинговые компании. Главные проблемы у “Белавиа” связаны вовсе не с техникой.

— Немалую часть бизнеса “Белавиа” составляло обслуживание транзитного пассажиропотока. Это и полёты из Украины в Россию — после того, как прямых рейсов не стало, многие пользовались минским аэропортом как пересадочным пунктом. Это и транзитные пассажиропотоки российских туристов, следующих в Европу. Сейчас всё это в основном закрыто, подавляющая часть бизнеса блокирована санкциями”.

И это — проблема. А техника — не проблема, уверен Гусаров.

  • Придумать продолжение сказки телевизионные макароны
  • Придумать продолжение рассказа летний дождь пришвина
  • Придумать продолжение рассказа дубровского 6 класс
  • Придумать продолжение к рассказу приемыш
  • Придумать продолжение сказки серая шейка 4 класс