diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..32b1e7f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Git +.git +.gitignore + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# Environment files +.env +.env.* +env.example + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +venv/ +env/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log + +# Documentation +README.md +*.md + +# Temporary files +*.tmp +*.temp + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..76ec0b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +db/ +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ca565b9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# Используем официальный Python образ +FROM python:3.11-slim + +# Устанавливаем рабочую директорию +WORKDIR /app + +# Устанавливаем системные зависимости +RUN apt-get update && apt-get install -y \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# Копируем файл зависимостей +COPY requirements.txt . + +# Устанавливаем Python зависимости +RUN pip install --no-cache-dir -r requirements.txt + +# Копируем код приложения +COPY code/ ./code/ +COPY data/ ./data/ + +# Создаем директории для базы данных +RUN mkdir -p db + +# Устанавливаем рабочую директорию для запуска +WORKDIR /app/code + +# Открываем порт (если потребуется для мониторинга) +EXPOSE 8000 + +# Команда запуска +CMD ["python", "bot.py"] + diff --git a/README.md b/README.md index 0fffde4..ed23525 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,47 @@ Y.Calendarkin — некоммерческий проект, предназна ## 🚀 Установка и запуск -### Предварительные требования +### 🐳 Запуск с Docker (Рекомендуется) + +1. **Клонируйте репозиторий:** +```bash +git clone +cd y.calendarkin +``` + +2. **Создайте файл с переменными окружения:** +```bash +cp env.example .env +``` + +3. **Настройте переменные окружения:** + - Откройте файл `.env` + - Замените `your_bot_token_here` на токен вашего бота от [@BotFather](https://t.me/BotFather) + +4. **Запустите бота:** +```bash +docker-compose up -d +``` + +5. **Проверьте логи:** +```bash +docker-compose logs -f +``` + +6. **Остановите бота:** +```bash +docker-compose down +``` + +### 📦 Локальная установка + +#### Предварительные требования ```bash pip install -r requirements.txt ``` -### Настройка +#### Настройка 1. Создайте нового бота через [@BotFather](https://t.me/BotFather) 2. Получите токен и добавьте его в `config.py`: @@ -51,7 +85,7 @@ TOKEN = "your_bot_token_here" mkdir -p data/icals db ``` -### Запуск +#### Запуск ```bash cd code @@ -100,9 +134,23 @@ y.calendarkin/ │ ├── icals/ # Загруженные календари │ └── photo_edit_alarm.jpg ├── db/ # База данных SQLite +├── Dockerfile # Docker образ +├── docker-compose.yml # Docker Compose конфигурация +├── .dockerignore # Исключения для Docker +├── env.example # Пример переменных окружения └── requirements.txt ``` +### Управление данными + +```bash +# Создание резервной копии базы данных +docker cp y-calendarkin-bot:/app/db ./backup/ + +# Восстановление базы данных +docker cp ./backup/db y-calendarkin-bot:/app/ +``` + ## 📊 База данных Проект использует две основные таблицы: diff --git a/code/bot.py b/code/bot.py index 1dbb350..7185ea6 100644 --- a/code/bot.py +++ b/code/bot.py @@ -1,321 +1,326 @@ -import logging, config, sql, asyncio, wget, os - -from aiogram import Bot, Dispatcher, executor, types -from aiogram.types import ParseMode - -from datetime import datetime, time -from script import text_ical, message_form, dt_now, delta_time - -# инициализируем токен -logging.basicConfig(level=logging.INFO) - -bot = Bot(token=config.TOKEN) -dp = Dispatcher(bot) - -# инициализируем соединение с БД -du = sql.Users('../db/users.db') -dc = sql.Clock('../db/clock.db') - - -# ПРИВЕТСТВЕННОЕ СООБЩЕНИЕ -@dp.message_handler(commands=['start', 'help']) -async def helps(message: types.Message): - tg_id = int(message.chat.id) - if not du.user_exists(tg_id): - du.add_user(tg_id) - - buttons = [types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"), - types.InlineKeyboardButton(text="АВТОР", callback_data="auth")] - - keyboard = types.InlineKeyboardMarkup(row_width=2) - keyboard.add(*buttons) - - await message.answer(text="Я.Календаркин - бот для оповещения о событиях из Яндекс.Календаря. " - "Для начала работы вам нужно всего лишь прислать в чат ссылку экспорта календаря в " - "формате ICal. После получения ссылки, бот начнёт оповещать о всех новых событиях " - "и появится возможность настройки оповещений. О том, какие команды есть для настройки, " - "вы можете ознакомиться по кнопке КОМАНДЫ", - parse_mode=ParseMode.HTML, reply_markup=keyboard) - - -@dp.callback_query_handler(text="auth") -async def author(call: types.CallbackQuery): - await call.message.answer(text='*| АВТОР |*\n\n*>>* Этот бот не коммерческий проект, для упрощенного получения ' - 'уведомлений о событиях в Яндекс.Календаре. Не многим этот бот будет полезен, но ' - 'людям, чья работа подразумевает его использование, он станет лишь удобным ' - 'инструментом. Я же пишу подобные небольшие проекты, о которых вы можете узнать ' - 'больше на моём [GitHub](https://github.com/IGlek).', - parse_mode=ParseMode.MARKDOWN) - - -@dp.callback_query_handler(text="com") -async def commands(call: types.CallbackQuery): - await call.message.answer(text='| КОМАНДЫ |\n\n' - '/help - вспомогательная функция для уточнения работы команд\n' - '/list - список событий календаря, запланированных на сегодняшний день\n' - '/notif - команда, отключающая рассылку уведомлений, даже при наличии событий в календаре\n' - '/daily - оповещение в 8 утра по вашему часовому поясу со списком событий на день\n' - '/moment - напоминание, приходящее в момент начала события\n\n' - '/get_alarm - информация о времени на которое настроены оповещения\n' - '/edit_alarm - изменение времени оповещений\n' - '/stop_alarm - команда, отключающая второе оповещение о событии', - parse_mode=types.ParseMode.HTML) - - -# КОМАНДЫ -@dp.message_handler(commands=['list']) -async def check_list(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if du.url_exists(user_id): - txt = "Имеющиеся события на сегодня\n\n" - - lst_events = sorted(text_ical(user_id, du.get_tz(user_id))) - today = dt_now(du.get_tz(user_id)).date() - - counter = 0 - for event in lst_events: - if event[0] == today: - counter += 1 - txt += message_form(counter, event[3]) - - if counter: - await message.answer(text=txt, parse_mode=ParseMode.HTML) - else: - await message.answer(text="В данный момент событий на сегодня найдено не было!", - parse_mode=ParseMode.HTML) - else: - await message.answer("Для отображения событий вы должны прислать ical-ссылку на календарь!") - - -@dp.message_handler(commands=['notif']) -async def notif_up(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if du.url_exists(user_id): - if du.get_status(user_id): - await message.answer("Уведомления о событиях выключены!") - else: - await message.answer("Уведомления о событиях включены!") - - du.update_status(user_id) - else: - await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") - - -@dp.message_handler(commands=['daily']) -async def daily_up(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if dc.clock_exists(user_id): - if dc.get_daily(user_id): - await message.answer("Ежедневные утренние уведомления выключены!") - else: - await message.answer("Ежедневные утренние уведомления включены!") - - dc.update_daily(user_id) - else: - await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") - - -@dp.message_handler(commands=['moment']) -async def start_up(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if dc.clock_exists(user_id): - if dc.get_start(user_id): - await message.answer("Уведомления в момент события выключены!") - else: - await message.answer("Уведомления в момент события включены!") - - dc.update_start(user_id) - else: - await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") - - -@dp.message_handler(commands=['get_alarm']) -async def start_up(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if dc.clock_exists(user_id): - alarms = dc.get_alarm(user_id) - start = dc.get_start(user_id) - status2 = dc.get_status2(user_id) - - txt = "" - - if status2: - txt += "У вас работает два оповещения" - else: - txt += "У вас работает лишь первое оповещение" - - if start: - txt += " и сообщение в момент начала события!" - else: - txt += "!" - - await message.answer(text=(txt + f"\n\nПервое оповещение приходит за {alarms[0]} минут\n" - f"Второе оповещение приходит за {alarms[1]} минут"), - parse_mode=ParseMode.HTML) - else: - await message.answer("Для того, чтобы получить таймеры, вы должны прислать ical-ссылку на свой календарь!") - - -@dp.message_handler(commands=['edit_alarm']) -async def start_up(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if dc.clock_exists(user_id): - await message.bot.send_photo(chat_id=message.chat.id, photo=open("../data/photo_edit_alarm.jpg", "rb"), - caption="Для изменения времени вам надо в ответ на это сообщение прислать два " - "числа через пробел: разница времени первого и второго таймера по ходу " - "времени соответственно") - else: - await message.answer("Для того, чтобы изменить таймеры, вы должны прислать ical-ссылку на свой календарь!") - - -@dp.message_handler(commands=['stop_alarm']) -async def daily_up(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if dc.clock_exists(user_id): - if dc.get_status2(user_id): - await message.answer("Второе уведомление выключено!") - else: - await message.answer("Второе уведомление включено!") - - dc.update_status2(user_id) - else: - await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") - - -# ЗАГРУЗКА ССЫЛКИ -@dp.message_handler(content_types=['text']) -async def downloading_file_ics(message: types.Message): - user_id = du.get_user_id(int(message.chat.id)) - - if message.text[:5] == "https": - try: - wget.download(message.text, f'../data/icals/{str(user_id)}_new.ics') - - try: - os.remove(f'../data/icals/{str(user_id)}.ics') - except FileNotFoundError: - pass - - os.rename(f'../data/icals/{str(user_id)}_new.ics', f'../data/icals/{str(user_id)}.ics') - - time_zone = message.text.split("=")[-1] - if not du.url_exists(user_id): - du.add_url(user_id, message.text, time_zone) - dc.add_clock(user_id) - else: - du.update_url(user_id, message.text, time_zone) - - await message.answer("Ссылка успешно добавлена! Уведомления уже включены!") - except Exception: - await message.answer("Ошибка скачивания! Проверьте правильность ссылки и пришлите ещё раз") - - if 'reply_to_message' in message and dc.clock_exists(user_id): - text = "Для изменения времени вам надо в ответ на это сообщение прислать два числа через " \ - "пробел: разница времени первого и второго таймера по ходу времени соответственно" - - if message.reply_to_message.caption == text: - alarm_new = message.text.split() - - if int(alarm_new[0]) < 60 and int(alarm_new[1]) < 60: - dc.update_alarm1(user_id, int(alarm_new[0])) - dc.update_alarm2(user_id, int(alarm_new[1])) - - await message.answer("Время отправки уведомлений успешно обновлено!") - else: - await message.answer("Время отправки уведомлений должно быть меньше 60 минут!") - - -# ПРОВЕРКА НА СОБЫТИЕ -async def alarm(wait_for): - while True: - await asyncio.sleep(wait_for) - - users_id = du.all_users() - for user_id in users_id: - user_id = user_id[0] - - if dc.clock_exists(user_id): - if du.get_status(user_id): - events = sorted(text_ical(user_id, du.get_tz(user_id))) - tg_id = str(du.get_first_user_id(user_id)) - - start = dc.get_start(user_id) - daily = dc.get_daily(user_id) - alarm = dc.get_alarm(user_id) - - alarm2_status = dc.get_status2(user_id) - - today = dt_now(du.get_tz(user_id)).date() - time_check = dt_now(du.get_tz(user_id)).time() - - # ДЛЯ DAILY - counter = 0 - txt = "События сегодня\n\n" - - delta_daily1 = time(hour=8, minute=0) - delta_daily2 = time(hour=8, minute=1) - # -------------------------------- - - for event in events: - if event[0] == today: - d_event = datetime.combine(today, event[1]) - - if daily and delta_daily1 <= time_check < delta_daily2: - counter += 1 - txt += message_form(counter, event[3]) - - delta_start = delta_time(d_event, 1, 0) - if start and delta_start[0] < time_check <= delta_start[1]: - await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, - text=f"Событие начинается!\n\n" + message_form(0, event[3])) - - delta_alarm1 = delta_time(d_event, alarm[0], alarm[0] - 1) - if delta_alarm1[0] < time_check <= delta_alarm1[1]: - await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, - text=f"Напоминаю!\nЧерез {alarm[0]} минут " - f"будет событие:\n\n{message_form(0, event[3])}") - - if alarm2_status: - delta_alarm2 = delta_time(d_event, alarm[1], alarm[1] - 1) - if delta_alarm2[0] < time_check <= delta_alarm2[1]: - await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, - text=f"Напоминаю!\nЧерез {alarm[1]} минут " - f"будет событие:\n\n{message_form(0, event[3])}") - - if daily and delta_daily1 <= time_check < delta_daily2: - if counter: - await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, - text=txt) - else: - await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, - text=f"Сегодня событий нет") - - -async def update(wait_for): - while True: - await asyncio.sleep(wait_for) - - users_id = du.all_users() - for user_id in users_id: - user_id = user_id[0] - - if du.url_exists(user_id): - if du.get_status(user_id): - wget.download(du.get_url(user_id), f'../data/icals/{str(user_id)}_new.ics') - - os.remove(f'../data/icals/{str(user_id)}.ics') - os.rename(f'../data/icals/{str(user_id)}_new.ics', f'../data/icals/{str(user_id)}.ics') - - -if __name__ == '__main__': - loop = asyncio.get_event_loop() - loop.create_task(alarm(60)) # ПРОВЕРКА КАЖДУЮ 1 МИНУТУ - loop.create_task(update(780)) # ПРОВЕРКА КАЖДУЮ 13 МИНУТУ - executor.start_polling(dp, skip_updates=True) +import logging, config, sql, asyncio, wget, os + +from aiogram import Bot, Dispatcher, types, F +from aiogram.enums import ParseMode +from aiogram.filters import Command, or_f + +from datetime import datetime, time +from script import text_ical, message_form, dt_now, delta_time + +# инициализируем токен +logging.basicConfig(level=logging.INFO) + +bot = Bot(token=config.TOKEN) +dp = Dispatcher() + +# инициализируем соединение с БД +du = sql.Users('../db/users.db') +dc = sql.Clock('../db/clock.db') + + +# ПРИВЕТСТВЕННОЕ СООБЩЕНИЕ +@dp.message(or_f(Command('start'), Command('help'))) +async def helps(message: types.Message): + tg_id = int(message.chat.id) + if not du.user_exists(tg_id): + du.add_user(tg_id) + + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[ + [types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"), + types.InlineKeyboardButton(text="АВТОР", callback_data="auth")] + ]) + + await message.answer(text="Я.Календаркин - бот для оповещения о событиях из Яндекс.Календаря. " + "Для начала работы вам нужно всего лишь прислать в чат ссылку экспорта календаря в " + "формате ICal. После получения ссылки, бот начнёт оповещать о всех новых событиях " + "и появится возможность настройки оповещений. О том, какие команды есть для настройки, " + "вы можете ознакомиться по кнопке КОМАНДЫ", + parse_mode=ParseMode.HTML, reply_markup=keyboard) + + +@dp.callback_query(F.data == "auth") +async def author(call: types.CallbackQuery): + await call.message.answer(text='*| АВТОР |*\n\n*>>* Этот бот не коммерческий проект, для упрощенного получения ' + 'уведомлений о событиях в Яндекс.Календаре. Не многим этот бот будет полезен, но ' + 'людям, чья работа подразумевает его использование, он станет лишь удобным ' + 'инструментом. Я же пишу подобные небольшие проекты, о которых вы можете узнать ' + 'больше на моём [GitHub](https://github.com/IGlek).', + parse_mode=ParseMode.MARKDOWN) + + +@dp.callback_query(F.data == "com") +async def commands(call: types.CallbackQuery): + await call.message.answer(text='| КОМАНДЫ |\n\n' + '/help - вспомогательная функция для уточнения работы команд\n' + '/list - список событий календаря, запланированных на сегодняшний день\n' + '/notif - команда, отключающая рассылку уведомлений, даже при наличии событий в календаре\n' + '/daily - оповещение в 8 утра по вашему часовому поясу со списком событий на день\n' + '/moment - напоминание, приходящее в момент начала события\n\n' + '/get_alarm - информация о времени на которое настроены оповещения\n' + '/edit_alarm - изменение времени оповещений\n' + '/stop_alarm - команда, отключающая второе оповещение о событии', + parse_mode=ParseMode.HTML) + + +# КОМАНДЫ +@dp.message(Command('list')) +async def check_list(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if du.url_exists(user_id): + txt = "Имеющиеся события на сегодня\n\n" + + lst_events = sorted(text_ical(user_id, du.get_tz(user_id))) + today = dt_now(du.get_tz(user_id)).date() + + counter = 0 + for event in lst_events: + if event[0] == today: + counter += 1 + txt += message_form(counter, event[3]) + + if counter: + await message.answer(text=txt, parse_mode=ParseMode.HTML) + else: + await message.answer(text="В данный момент событий на сегодня найдено не было!", + parse_mode=ParseMode.HTML) + else: + await message.answer("Для отображения событий вы должны прислать ical-ссылку на календарь!") + + +@dp.message(Command('notif')) +async def notif_up(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if du.url_exists(user_id): + if du.get_status(user_id): + await message.answer("Уведомления о событиях выключены!") + else: + await message.answer("Уведомления о событиях включены!") + + du.update_status(user_id) + else: + await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") + + +@dp.message(Command('daily')) +async def daily_up(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if dc.clock_exists(user_id): + if dc.get_daily(user_id): + await message.answer("Ежедневные утренние уведомления выключены!") + else: + await message.answer("Ежедневные утренние уведомления включены!") + + dc.update_daily(user_id) + else: + await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") + + +@dp.message(Command('moment')) +async def start_up(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if dc.clock_exists(user_id): + if dc.get_start(user_id): + await message.answer("Уведомления в момент события выключены!") + else: + await message.answer("Уведомления в момент события включены!") + + dc.update_start(user_id) + else: + await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") + + +@dp.message(Command('get_alarm')) +async def start_up(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if dc.clock_exists(user_id): + alarms = dc.get_alarm(user_id) + start = dc.get_start(user_id) + status2 = dc.get_status2(user_id) + + txt = "" + + if status2: + txt += "У вас работает два оповещения" + else: + txt += "У вас работает лишь первое оповещение" + + if start: + txt += " и сообщение в момент начала события!" + else: + txt += "!" + + await message.answer(text=(txt + f"\n\nПервое оповещение приходит за {alarms[0]} минут\n" + f"Второе оповещение приходит за {alarms[1]} минут"), + parse_mode=ParseMode.HTML) + else: + await message.answer("Для того, чтобы получить таймеры, вы должны прислать ical-ссылку на свой календарь!") + + +@dp.message(Command('edit_alarm')) +async def start_up(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if dc.clock_exists(user_id): + await message.bot.send_photo(chat_id=message.chat.id, photo=open("../data/photo_edit_alarm.jpg", "rb"), + caption="Для изменения времени вам надо в ответ на это сообщение прислать два " + "числа через пробел: разница времени первого и второго таймера по ходу " + "времени соответственно") + else: + await message.answer("Для того, чтобы изменить таймеры, вы должны прислать ical-ссылку на свой календарь!") + + +@dp.message(Command('stop_alarm')) +async def daily_up(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if dc.clock_exists(user_id): + if dc.get_status2(user_id): + await message.answer("Второе уведомление выключено!") + else: + await message.answer("Второе уведомление включено!") + + dc.update_status2(user_id) + else: + await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!") + + +# ЗАГРУЗКА ССЫЛКИ +@dp.message(F.text) +async def downloading_file_ics(message: types.Message): + user_id = du.get_user_id(int(message.chat.id)) + + if message.text[:5] == "https": + try: + wget.download(message.text, f'../data/icals/{str(user_id)}_new.ics') + + try: + os.remove(f'../data/icals/{str(user_id)}.ics') + except FileNotFoundError: + pass + + os.rename(f'../data/icals/{str(user_id)}_new.ics', f'../data/icals/{str(user_id)}.ics') + + time_zone = message.text.split("=")[-1] + if not du.url_exists(user_id): + du.add_url(user_id, message.text, time_zone) + dc.add_clock(user_id) + else: + du.update_url(user_id, message.text, time_zone) + + await message.answer("Ссылка успешно добавлена! Уведомления уже включены!") + except Exception: + await message.answer("Ошибка скачивания! Проверьте правильность ссылки и пришлите ещё раз") + + if 'reply_to_message' in message and dc.clock_exists(user_id): + text = "Для изменения времени вам надо в ответ на это сообщение прислать два числа через " \ + "пробел: разница времени первого и второго таймера по ходу времени соответственно" + + if message.reply_to_message.caption == text: + alarm_new = message.text.split() + + if int(alarm_new[0]) < 60 and int(alarm_new[1]) < 60: + dc.update_alarm1(user_id, int(alarm_new[0])) + dc.update_alarm2(user_id, int(alarm_new[1])) + + await message.answer("Время отправки уведомлений успешно обновлено!") + else: + await message.answer("Время отправки уведомлений должно быть меньше 60 минут!") + + +# ПРОВЕРКА НА СОБЫТИЕ +async def alarm(wait_for): + while True: + await asyncio.sleep(wait_for) + + users_id = du.all_users() + for user_id in users_id: + user_id = user_id[0] + + if dc.clock_exists(user_id): + if du.get_status(user_id): + events = sorted(text_ical(user_id, du.get_tz(user_id))) + tg_id = str(du.get_first_user_id(user_id)) + + start = dc.get_start(user_id) + daily = dc.get_daily(user_id) + alarm = dc.get_alarm(user_id) + + alarm2_status = dc.get_status2(user_id) + + today = dt_now(du.get_tz(user_id)).date() + time_check = dt_now(du.get_tz(user_id)).time() + + # ДЛЯ DAILY + counter = 0 + txt = "События сегодня\n\n" + + delta_daily1 = time(hour=8, minute=0) + delta_daily2 = time(hour=8, minute=1) + # -------------------------------- + + for event in events: + if event[0] == today: + d_event = datetime.combine(today, event[1]) + + if daily and delta_daily1 <= time_check < delta_daily2: + counter += 1 + txt += message_form(counter, event[3]) + + delta_start = delta_time(d_event, 1, 0) + if start and delta_start[0] < time_check <= delta_start[1]: + await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, + text=f"Событие начинается!\n\n" + message_form(0, event[3])) + + delta_alarm1 = delta_time(d_event, alarm[0], alarm[0] - 1) + if delta_alarm1[0] < time_check <= delta_alarm1[1]: + await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, + text=f"Напоминаю!\nЧерез {alarm[0]} минут " + f"будет событие:\n\n{message_form(0, event[3])}") + + if alarm2_status: + delta_alarm2 = delta_time(d_event, alarm[1], alarm[1] - 1) + if delta_alarm2[0] < time_check <= delta_alarm2[1]: + await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, + text=f"Напоминаю!\nЧерез {alarm[1]} минут " + f"будет событие:\n\n{message_form(0, event[3])}") + + if daily and delta_daily1 <= time_check < delta_daily2: + if counter: + await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, + text=txt) + else: + await bot.send_message(chat_id=tg_id, parse_mode=ParseMode.HTML, + text=f"Сегодня событий нет") + + +async def update(wait_for): + while True: + await asyncio.sleep(wait_for) + + users_id = du.all_users() + for user_id in users_id: + user_id = user_id[0] + + if du.url_exists(user_id): + if du.get_status(user_id): + wget.download(du.get_url(user_id), f'../data/icals/{str(user_id)}_new.ics') + + os.remove(f'../data/icals/{str(user_id)}.ics') + os.rename(f'../data/icals/{str(user_id)}_new.ics', f'../data/icals/{str(user_id)}.ics') + + +async def main(): + # Создаем задачи для фоновых процессов + asyncio.create_task(alarm(60)) # ПРОВЕРКА КАЖДУЮ 1 МИНУТУ + asyncio.create_task(update(780)) # ПРОВЕРКА КАЖДУЮ 13 МИНУТУ + + # Запускаем бота + await dp.start_polling(bot, skip_updates=True) + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/code/config.py b/code/config.py index 1cf651a..ea5a18a 100644 --- a/code/config.py +++ b/code/config.py @@ -1 +1,7 @@ -TOKEN = "**********:***************************" +import os + +# Получаем токен из переменной окружения +TOKEN = os.getenv('TELEGRAM_BOT_TOKEN') + +if not TOKEN: + raise ValueError("TELEGRAM_BOT_TOKEN environment variable is required") diff --git a/data/icals/1.ics b/data/icals/1.ics index 06a840e..d29bb01 100644 --- a/data/icals/1.ics +++ b/data/icals/1.ics @@ -3,70 +3,246 @@ PRODID:-//Yandex LLC//Yandex Calendar//EN VERSION:2.0 CALSCALE:GREGORIAN METHOD:PUBLISH -X-WR-TIMEZONE:Europe/Samara -X-WR-CALNAME:Привет +X-WR-TIMEZONE:Europe/Moscow +X-WR-CALNAME:Мои события BEGIN:VTIMEZONE -TZID:Asia/Krasnoyarsk -TZURL:http://tzurl.org/zoneinfo/Asia/Krasnoyarsk -X-LIC-LOCATION:Asia/Krasnoyarsk +TZID:Etc/UTC +TZURL:http://tzurl.org/zoneinfo/Etc/UTC +X-LIC-LOCATION:Etc/UTC BEGIN:STANDARD -TZOFFSETFROM:+061126 -TZOFFSETTO:+0600 -TZNAME:+06 -DTSTART:19200106T000000 -RDATE:19200106T000000 +TZOFFSETFROM:+0000 +TZOFFSETTO:+0000 +TZNAME:UTC +DTSTART:16010101T000000 +RDATE:16010101T000000 +END:STANDARD +END:VTIMEZONE +BEGIN:VTIMEZONE +TZID:Europe/Moscow +LAST-MODIFIED:20231222T233358Z +TZURL:https://www.tzurl.org/zoneinfo/Europe/Moscow +X-LIC-LOCATION:Europe/Moscow +X-PROLEPTIC-TZNAME:LMT +BEGIN:STANDARD +TZNAME:MMT +TZOFFSETFROM:+023017 +TZOFFSETTO:+023017 +DTSTART:18800101T000000 END:STANDARD BEGIN:STANDARD -TZOFFSETFROM:+0600 -TZOFFSETTO:+0700 -TZNAME:+07 +TZNAME:MMT +TZOFFSETFROM:+023017 +TZOFFSETTO:+023119 +DTSTART:19160703T000000 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:MST +TZOFFSETFROM:+023119 +TZOFFSETTO:+033119 +DTSTART:19170701T230000 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:MMT +TZOFFSETFROM:+033119 +TZOFFSETTO:+023119 +DTSTART:19171228T000000 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:MDST +TZOFFSETFROM:+023119 +TZOFFSETTO:+043119 +DTSTART:19180531T220000 +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:MST +TZOFFSETFROM:+043119 +TZOFFSETTO:+033119 +DTSTART:19180916T010000 +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:MDST +TZOFFSETFROM:+033119 +TZOFFSETTO:+043119 +DTSTART:19190531T230000 +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:MSD +TZOFFSETFROM:+043119 +TZOFFSETTO:+0400 +DTSTART:19190701T043119 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:MSK +TZOFFSETFROM:+0400 +TZOFFSETTO:+0300 +DTSTART:19190816T000000 +RDATE:19211001T000000 +RDATE:20141026T020000 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:MSD +TZOFFSETFROM:+0300 +TZOFFSETTO:+0400 +DTSTART:19210214T230000 +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:+05 +TZOFFSETFROM:+0400 +TZOFFSETTO:+0500 +DTSTART:19210320T230000 +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:MSD +TZOFFSETFROM:+0500 +TZOFFSETTO:+0400 +DTSTART:19210901T000000 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EET +TZOFFSETFROM:+0300 +TZOFFSETTO:+0200 +DTSTART:19221001T000000 +RDATE:19910929T030000 +END:STANDARD +BEGIN:STANDARD +TZNAME:MSK +TZOFFSETFROM:+0200 +TZOFFSETTO:+0300 DTSTART:19300621T000000 -RDATE:19300621T000000 RDATE:19920119T020000 END:STANDARD BEGIN:DAYLIGHT -TZOFFSETFROM:+0700 -TZOFFSETTO:+0800 -TZNAME:+08 +TZNAME:MSD +TZOFFSETFROM:+0300 +TZOFFSETTO:+0400 DTSTART:19810401T000000 -RDATE:19810401T000000 -RDATE:19820401T000000 -RDATE:19830401T000000 -RDATE:19840401T000000 -RDATE:19850331T020000 -RDATE:19860330T020000 -RDATE:19870329T020000 -RDATE:19880327T020000 -RDATE:19890326T020000 -RDATE:19900325T020000 -RDATE:19920329T020000 -RDATE:19930328T020000 -RDATE:19940327T020000 -RDATE:19950326T020000 -RDATE:19960331T020000 -RDATE:19970330T020000 -RDATE:19980329T020000 -RDATE:19990328T020000 -RDATE:20000326T020000 -RDATE:20010325T020000 -RDATE:20020331T020000 -RDATE:20030330T020000 -RDATE:20040328T020000 -RDATE:20050327T020000 -RDATE:20060326T020000 -RDATE:20070325T020000 -RDATE:20080330T020000 -RDATE:20090329T020000 -RDATE:20100328T020000 +RRULE:FREQ=YEARLY;UNTIL=19840331T210000Z END:DAYLIGHT BEGIN:STANDARD -TZOFFSETFROM:+0800 -TZOFFSETTO:+0700 -TZNAME:+07 +TZNAME:MSK +TZOFFSETFROM:+0400 +TZOFFSETTO:+0300 DTSTART:19811001T000000 -RDATE:19811001T000000 -RDATE:19821001T000000 -RDATE:19831001T000000 +RRULE:FREQ=YEARLY;UNTIL=19830930T200000Z +END:STANDARD +BEGIN:STANDARD +TZNAME:MSK +TZOFFSETFROM:+0400 +TZOFFSETTO:+0300 +DTSTART:19840930T030000 +RRULE:FREQ=YEARLY;UNTIL=19900929T230000Z;BYMONTH=9;BYDAY=-1SU +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:MSD +TZOFFSETFROM:+0300 +TZOFFSETTO:+0400 +DTSTART:19850331T020000 +RRULE:FREQ=YEARLY;UNTIL=19900324T230000Z;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:EEST +TZOFFSETFROM:+0300 +TZOFFSETTO:+0300 +DTSTART:19910331T020000 +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:MSD +TZOFFSETFROM:+0300 +TZOFFSETTO:+0400 +DTSTART:19920329T020000 +RRULE:FREQ=YEARLY;UNTIL=20100327T230000Z;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:MSK +TZOFFSETFROM:+0400 +TZOFFSETTO:+0300 +DTSTART:19920927T030000 +RRULE:FREQ=YEARLY;UNTIL=19950923T230000Z;BYMONTH=9;BYDAY=-1SU +END:STANDARD +BEGIN:STANDARD +TZNAME:MSK +TZOFFSETFROM:+0400 +TZOFFSETTO:+0300 +DTSTART:19961027T030000 +RRULE:FREQ=YEARLY;UNTIL=20101030T230000Z;BYMONTH=10;BYDAY=-1SU +END:STANDARD +BEGIN:STANDARD +TZNAME:MSK +TZOFFSETFROM:+0300 +TZOFFSETTO:+0400 +DTSTART:20110327T020000 +END:STANDARD +BEGIN:STANDARD +TZOFFSETFROM:+0400 +TZOFFSETTO:+0300 +TZNAME:MSK +DTSTART:20141026T020000 +RDATE:20141026T020000 +END:STANDARD +END:VTIMEZONE +BEGIN:VTIMEZONE +TZID:Europe/Berlin +TZURL:http://tzurl.org/zoneinfo/Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19810329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19961027T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +BEGIN:STANDARD +TZOFFSETFROM:+005328 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:18930401T000000 +RDATE:18930401T000000 +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19160430T230000 +RDATE:19160430T230000 +RDATE:19170416T020000 +RDATE:19180415T020000 +RDATE:19400401T020000 +RDATE:19430329T020000 +RDATE:19440403T020000 +RDATE:19450402T020000 +RDATE:19460414T020000 +RDATE:19470406T030000 +RDATE:19480418T020000 +RDATE:19490410T020000 +RDATE:19800406T020000 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19161001T010000 +RDATE:19161001T010000 +RDATE:19170917T030000 +RDATE:19180916T030000 +RDATE:19421102T030000 +RDATE:19431004T030000 +RDATE:19441002T030000 +RDATE:19451118T030000 +RDATE:19461007T030000 +RDATE:19471005T030000 +RDATE:19481003T030000 +RDATE:19491002T030000 +RDATE:19800928T030000 +RDATE:19810927T030000 +RDATE:19820926T030000 +RDATE:19830925T030000 RDATE:19840930T030000 RDATE:19850929T030000 RDATE:19860928T030000 @@ -74,313 +250,1021 @@ RDATE:19870927T030000 RDATE:19880925T030000 RDATE:19890924T030000 RDATE:19900930T030000 +RDATE:19910929T030000 RDATE:19920927T030000 RDATE:19930926T030000 RDATE:19940925T030000 RDATE:19950924T030000 -RDATE:19961027T030000 -RDATE:19971026T030000 -RDATE:19981025T030000 -RDATE:19991031T030000 -RDATE:20001029T030000 -RDATE:20011028T030000 -RDATE:20021027T030000 -RDATE:20031026T030000 -RDATE:20041031T030000 -RDATE:20051030T030000 -RDATE:20061029T030000 -RDATE:20071028T030000 -RDATE:20081026T030000 -RDATE:20091025T030000 -RDATE:20101031T030000 -RDATE:20141026T020000 END:STANDARD BEGIN:DAYLIGHT -TZOFFSETFROM:+0700 -TZOFFSETTO:+0700 -TZNAME:+07 -DTSTART:19910331T020000 -RDATE:19910331T020000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0300 +TZNAME:CEMT +DTSTART:19450524T020000 +RDATE:19450524T020000 +RDATE:19470511T030000 +END:DAYLIGHT +BEGIN:DAYLIGHT +TZOFFSETFROM:+0300 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19450924T030000 +RDATE:19450924T030000 +RDATE:19470629T030000 END:DAYLIGHT BEGIN:STANDARD -TZOFFSETFROM:+0700 -TZOFFSETTO:+0600 -TZNAME:+06 -DTSTART:19910929T030000 -RDATE:19910929T030000 -END:STANDARD -BEGIN:STANDARD -TZOFFSETFROM:+0700 -TZOFFSETTO:+0800 -TZNAME:+08 -DTSTART:20110327T020000 -RDATE:20110327T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19460101T000000 +RDATE:19460101T000000 +RDATE:19800101T000000 END:STANDARD END:VTIMEZONE BEGIN:VTIMEZONE TZID:Europe/Samara -TZURL:http://tzurl.org/zoneinfo/Europe/Samara +LAST-MODIFIED:20231222T233358Z +TZURL:https://www.tzurl.org/zoneinfo/Europe/Samara X-LIC-LOCATION:Europe/Samara +X-PROLEPTIC-TZNAME:LMT BEGIN:STANDARD +TZNAME:+03 TZOFFSETFROM:+032020 TZOFFSETTO:+0300 -TZNAME:+03 DTSTART:19190701T032020 -RDATE:19190701T032020 END:STANDARD BEGIN:STANDARD +TZNAME:+04 TZOFFSETFROM:+0300 TZOFFSETTO:+0400 -TZNAME:+04 DTSTART:19300621T000000 -RDATE:19300621T000000 RDATE:19911020T030000 RDATE:20110327T020000 END:STANDARD -BEGIN:STANDARD -TZOFFSETFROM:+0400 -TZOFFSETTO:+0400 -TZNAME:+04 -DTSTART:19350127T000000 -RDATE:19350127T000000 -END:STANDARD BEGIN:DAYLIGHT +TZNAME:+05 TZOFFSETFROM:+0400 TZOFFSETTO:+0500 -TZNAME:+05 DTSTART:19810401T000000 -RDATE:19810401T000000 -RDATE:19820401T000000 -RDATE:19830401T000000 -RDATE:19840401T000000 -RDATE:19850331T020000 -RDATE:19860330T020000 -RDATE:19870329T020000 -RDATE:19880327T020000 -RDATE:19920329T020000 -RDATE:19930328T020000 -RDATE:19940327T020000 -RDATE:19950326T020000 -RDATE:19960331T020000 -RDATE:19970330T020000 -RDATE:19980329T020000 -RDATE:19990328T020000 -RDATE:20000326T020000 -RDATE:20010325T020000 -RDATE:20020331T020000 -RDATE:20030330T020000 -RDATE:20040328T020000 -RDATE:20050327T020000 -RDATE:20060326T020000 -RDATE:20070325T020000 -RDATE:20080330T020000 -RDATE:20090329T020000 +RRULE:FREQ=YEARLY;UNTIL=19840331T200000Z END:DAYLIGHT BEGIN:STANDARD +TZNAME:+04 TZOFFSETFROM:+0500 TZOFFSETTO:+0400 -TZNAME:+04 DTSTART:19811001T000000 -RDATE:19811001T000000 -RDATE:19821001T000000 -RDATE:19831001T000000 -RDATE:19840930T030000 -RDATE:19850929T030000 -RDATE:19860928T030000 -RDATE:19870927T030000 -RDATE:19880925T030000 -RDATE:19920927T030000 -RDATE:19930926T030000 -RDATE:19940925T030000 -RDATE:19950924T030000 -RDATE:19961027T030000 -RDATE:19971026T030000 -RDATE:19981025T030000 -RDATE:19991031T030000 -RDATE:20001029T030000 -RDATE:20011028T030000 -RDATE:20021027T030000 -RDATE:20031026T030000 -RDATE:20041031T030000 -RDATE:20051030T030000 -RDATE:20061029T030000 -RDATE:20071028T030000 -RDATE:20081026T030000 -RDATE:20091025T030000 +RRULE:FREQ=YEARLY;UNTIL=19830930T190000Z +END:STANDARD +BEGIN:STANDARD +TZNAME:+04 +TZOFFSETFROM:+0500 +TZOFFSETTO:+0400 +DTSTART:19840930T030000 +RRULE:FREQ=YEARLY;UNTIL=19880924T220000Z;BYMONTH=9;BYDAY=-1SU END:STANDARD BEGIN:DAYLIGHT +TZNAME:+05 +TZOFFSETFROM:+0400 +TZOFFSETTO:+0500 +DTSTART:19850331T020000 +RRULE:FREQ=YEARLY;UNTIL=19880326T220000Z;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:DAYLIGHT +TZNAME:+04 TZOFFSETFROM:+0400 TZOFFSETTO:+0400 -TZNAME:+04 DTSTART:19890326T020000 -RDATE:19890326T020000 RDATE:20100328T020000 END:DAYLIGHT BEGIN:STANDARD +TZNAME:+03 TZOFFSETFROM:+0400 TZOFFSETTO:+0300 -TZNAME:+03 DTSTART:19890924T030000 -RDATE:19890924T030000 -RDATE:19900930T030000 -RDATE:20101031T030000 +RRULE:FREQ=YEARLY;UNTIL=19900929T230000Z;BYMONTH=9;BYDAY=-1SU END:STANDARD BEGIN:DAYLIGHT +TZNAME:+04 TZOFFSETFROM:+0300 TZOFFSETTO:+0400 -TZNAME:+04 DTSTART:19900325T020000 -RDATE:19900325T020000 END:DAYLIGHT BEGIN:DAYLIGHT +TZNAME:+03 TZOFFSETFROM:+0300 TZOFFSETTO:+0300 -TZNAME:+03 DTSTART:19910331T020000 -RDATE:19910331T020000 END:DAYLIGHT BEGIN:STANDARD +TZNAME:+03 TZOFFSETFROM:+0300 TZOFFSETTO:+0300 -TZNAME:+03 DTSTART:19910929T030000 -RDATE:19910929T030000 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:+05 +TZOFFSETFROM:+0400 +TZOFFSETTO:+0500 +DTSTART:19920329T020000 +RRULE:FREQ=YEARLY;UNTIL=20090328T220000Z;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:+04 +TZOFFSETFROM:+0500 +TZOFFSETTO:+0400 +DTSTART:19920927T030000 +RRULE:FREQ=YEARLY;UNTIL=19950923T220000Z;BYMONTH=9;BYDAY=-1SU END:STANDARD BEGIN:STANDARD TZNAME:+04 -TZOFFSETFROM:+0400 +TZOFFSETFROM:+0500 TZOFFSETTO:+0400 -DTSTART:20101031T030000 +DTSTART:19961027T030000 +RRULE:FREQ=YEARLY;UNTIL=20091024T220000Z;BYMONTH=10;BYDAY=-1SU +END:STANDARD +BEGIN:STANDARD +TZNAME:+03 +TZOFFSETFROM:+0400 +TZOFFSETTO:+0300 +DTSTART:20100328T030000 +RDATE:20100328T030000 +END:STANDARD +BEGIN:STANDARD +TZNAME:+04 +TZOFFSETFROM:+0300 +TZOFFSETTO:+0400 +DTSTART:20110327T030000 END:STANDARD END:VTIMEZONE BEGIN:VEVENT -DTSTART;TZID=Asia/Krasnoyarsk:20240123T213000 -DTEND;TZID=Asia/Krasnoyarsk:20240123T220000 -SUMMARY:Собрание -UID:zwdqywax0s4lz9ybyr9yandex.ru +DTSTART:20201112T100000Z +DTEND:20201112T103000Z +SUMMARY:Обсуждение БД\, Бросиов +UID:5218iigb1ovinl69ldf5dhi46i@google.com SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240123T110608Z -DESCRIPTION:Очень важное -URL:https://calendar.yandex.ru/event?event_id=1980777684 -TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240123T110608Z +DTSTAMP:20250929T192310Z +CREATED:20201112T074258Z +DESCRIPTION:-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~::~:~::-\nНе редактируйте этот раздел описания.\n\nЭто мероприятие проводится в формате видеовстречи.\nВидеовызов: https://meet.google.com/uoa-pzwe-bxd\n(US) +1 405-586-4626 PIN-код: 248948974#\n\nПросмотрите свое мероприятие на странице https://calendar.google.com/calendar/event?action=VIEW&eid=NTIxOGlpZ2Ixb3Zpbmw2OWxkZjVkaGk0NmkgdGlyYW5hZm9sc0B5YW5kZXgucnU&tok=MjMjc2dvbHViZXZAb2dnZXR0b3dlYi5jb21hM2UyYzRmNGMzNWMxNGE1MmY1ZTcwZWZmMTdmMTdmN2NhMWFiOGM0&ctz=Europe%2FMoscow&hl=ru&es=1.\n-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~::~:~::- +URL:https://calendar.yandex.ru/event?event_id=1531757303 +CATEGORIES:Мои события +ORGANIZER;CN=sgolubev@oggettoweb.com:mailto:sgolubev@oggettoweb.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=sgolubev@oggettoweb.com;ROLE=REQ-PARTICIPANT:mailto:sgolubev@oggettoweb.com +LAST-MODIFIED:20201112T074253Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20210427T143000 +DTEND;TZID=Europe/Moscow:20210427T150000 +SUMMARY:Ярослав and Sergey Ryabtsev +UID:040000008200E00074C5B7101A82E00800000000D06C3BD88337D7010000000000000000100000001EBD615020FCF542A08C2949B1FAE528 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20210422T142912Z +LOCATION:https://zoom.us/j/669119895 +DESCRIPTION:Event Name: Meeting\n\nJoin Zoom Meeting\n\nhttps://zoom.us/j/669119895\n\nLocation: https://zoom.us/j/669119895\n\nNeed to make changes to this event?\nCancel: https://calendly.com/cancellations/EE46IMPHFBQKKTLU\nReschedule: https://calendly.com/reschedulings/EE46IMPHFBQKKTLU\n\nPowered by Calendly https://calendly.com/\n +URL:https://calendar.yandex.ru/event?event_id=1584245646 +CATEGORIES:Мои события +ORGANIZER;CN=Sergey Ryabtsev:mailto:sergey@7pace.com +ATTENDEE;PARTSTAT=ACCEPTED;CN=Sergey Ryabtsev;ROLE=REQ-PARTICIPANT:mailto:sergey@7pace.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20210422T142912Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20210430T104500 +DTEND;TZID=Europe/Berlin:20210430T111500 +SUMMARY:Ярослав and Maxim +UID:040000008200E00074C5B7101A82E0080000000035400FAD0A3DD701000000000000000010000000C4B8EA9DD6FE9C469A2613217B618A88 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20210429T151654Z +DESCRIPTION:Event Name: Meeting with Maxim\n\nPlease use following link to join the meeting:\n\n\nJoin Zoom Meeting\n\nhttps://us02web.zoom.us/j/657268661?pwd=UkFmQ2pJWkNQOTBDVzV4K2pVN0dhQT09\n\n\nMeeting ID: 657 268 661\n\nOne tap mobile\n\n+13017158592\,\,657268661# US\n\n+13126266799\,\,657268661# US (Chicago)\n\n\nDial by your location\n\n +1 301 715 8592 US\n\n +1 312 626 6799 US (Chicago)\n\n +1 346 248 7799 US (Houston)\n\n +1 646 558 8656 US (New York)\n\n +1 669 900 6833 US (San Jose)\n\n +1 253 215 8782 US\n\nMeeting ID: 657 268 661\n\nFind your local number: https://zoom.us/u/acVUaqSX8Q\n\nNeed to make changes to this event?\nCancel: https://calendly.com/cancellations/BAY4TMBCQO5742MJ\nReschedule: https://calendly.com/reschedulings/BAY4TMBCQO5742MJ\n\nPowered by Calendly https://calendly.com/\n +URL:https://calendar.yandex.ru/event?event_id=1584955048 +CATEGORIES:Мои события +ORGANIZER;CN=Maxim Lutsan:mailto:maxim@7pace.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Maxim Lutsan;ROLE=REQ-PARTICIPANT:mailto:maxim@7pace.com +LAST-MODIFIED:20210429T151654Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20210504T170000 +DTEND;TZID=Europe/Berlin:20210504T173000 +SUMMARY:Ярослав and Maxim +UID:040000008200E00074C5B7101A82E00800000000F5BDBB57C040D701000000000000000010000000E60584744D1E6C47AF53C9573FCCA212 +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20210504T083457Z +DESCRIPTION:Event Name: Meeting with Maxim\n\nPlease use following link to join the meeting:\n\n\n\nJoin Zoom Meeting\n\nhttps://us02web.zoom.us/j/657268661?pwd=UkFmQ2pJWkNQOTBDVzV4K2pVN0dhQT09\n\n\n\nMeeting ID: 657 268 661\n\nOne tap mobile\n\n+13017158592\,\,657268661# US\n\n+13126266799\,\,657268661# US (Chicago)\n\n\n\nDial by your location\n\n +1 301 715 8592 US\n\n +1 312 626 6799 US (Chicago)\n\n +1 346 248 7799 US (Houston)\n\n +1 646 558 8656 US (New York)\n\n +1 669 900 6833 US (San Jose)\n\n +1 253 215 8782 US\n\nMeeting ID: 657 268 661\n\nFind your local number: https://zoom.us/u/acVUaqSX8Q\n\nNeed to make changes to this event?\nCancel: https://calendly.com/cancellations/BC52W7AL4ZBDD6JN\nReschedule: https://calendly.com/reschedulings/BC52W7AL4ZBDD6JN\n\nPowered by Calendly https://calendly.com/\n +URL:https://calendar.yandex.ru/event?event_id=1585627641 +CATEGORIES:Мои события +ORGANIZER;CN=Maxim Lutsan:mailto:maxim@7pace.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Maxim Lutsan;ROLE=REQ-PARTICIPANT:mailto:maxim@7pace.com +LAST-MODIFIED:20210504T083457Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20210507T110000 +DTEND;TZID=Europe/Berlin:20210507T113000 +SUMMARY:Ярослав and Maxim +UID:040000008200E00074C5B7101A82E00800000000508ADE0DF740D701000000000000000010000000F846E685F267C94ABAE40043F4005426 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20210504T150631Z +DESCRIPTION:Event Name: Meeting with Maxim\n\nPlease use following link to join the meeting:\n\n\nJoin Zoom Meeting\n\nhttps://us02web.zoom.us/j/657268661?pwd=UkFmQ2pJWkNQOTBDVzV4K2pVN0dhQT09\n\n\nMeeting ID: 657 268 661\n\nOne tap mobile\n\n+13017158592\,\,657268661# US\n\n+13126266799\,\,657268661# US (Chicago)\n\n\nDial by your location\n\n +1 301 715 8592 US\n\n +1 312 626 6799 US (Chicago)\n\n +1 346 248 7799 US (Houston)\n\n +1 646 558 8656 US (New York)\n\n +1 669 900 6833 US (San Jose)\n\n +1 253 215 8782 US\n\nMeeting ID: 657 268 661\n\nFind your local number: https://zoom.us/u/acVUaqSX8Q\n\nNeed to make changes to this event?\nCancel: https://calendly.com/cancellations/EH64S7NBYDSOIGRV\nReschedule: https://calendly.com/reschedulings/EH64S7NBYDSOIGRV\n\nPowered by Calendly https://calendly.com/\n +URL:https://calendar.yandex.ru/event?event_id=1585822831 +CATEGORIES:Мои события +ORGANIZER;CN=Maxim Lutsan:mailto:maxim@7pace.com +ATTENDEE;PARTSTAT=ACCEPTED;CN=Maxim Lutsan;ROLE=REQ-PARTICIPANT:mailto:maxim@7pace.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20210504T150631Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20210510T163000 +DTEND;TZID=Europe/Berlin:20210510T170000 +SUMMARY:Ярослав and Maxim +UID:040000008200E00074C5B7101A82E00800000000C86FC7792143D7010000000000000000100000004621CF7B85DC084F959BAF166045DCF2 +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20210507T091522Z +DESCRIPTION:Event Name: Meeting with Maxim\n\nPlease use following link to join the meeting:\n\n\nJoin Zoom Meeting\n\nhttps://us02web.zoom.us/j/657268661?pwd=UkFmQ2pJWkNQOTBDVzV4K2pVN0dhQT09\n\n\nMeeting ID: 657 268 661\n\nOne tap mobile\n\n+13017158592\,\,657268661# US\n\n+13126266799\,\,657268661# US (Chicago)\n\n\nDial by your location\n\n +1 301 715 8592 US\n\n +1 312 626 6799 US (Chicago)\n\n +1 346 248 7799 US (Houston)\n\n +1 646 558 8656 US (New York)\n\n +1 669 900 6833 US (San Jose)\n\n +1 253 215 8782 US\n\nMeeting ID: 657 268 661\n\nFind your local number: https://zoom.us/u/acVUaqSX8Q\n\nNeed to make changes to this event?\nCancel: https://calendly.com/cancellations/EC364LDNEI2XXE3L\nReschedule: https://calendly.com/reschedulings/EC364LDNEI2XXE3L\n\nPowered by Calendly https://calendly.com/\n +URL:https://calendar.yandex.ru/event?event_id=1586356696 +CATEGORIES:Мои события +ORGANIZER;CN=Maxim Lutsan:mailto:maxim@7pace.com +ATTENDEE;PARTSTAT=ACCEPTED;CN=Maxim Lutsan;ROLE=REQ-PARTICIPANT:mailto:maxim@7pace.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20210507T091522Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20210511T090000 +DTEND;TZID=Europe/Berlin:20210511T093000 +SUMMARY:Ярослав and Maxim +UID:040000008200E00074C5B7101A82E0080000000092635F3AAA45D701000000000000000010000000E2F54F0B8E8CE240ADD2D6100F4F4365 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20210510T143912Z +DESCRIPTION:Event Name: Meeting with Maxim\n\nPlease use following link to join the meeting:\n\n\nJoin Zoom Meeting\n\nhttps://us02web.zoom.us/j/657268661?pwd=UkFmQ2pJWkNQOTBDVzV4K2pVN0dhQT09\n\n\nMeeting ID: 657 268 661\n\nOne tap mobile\n\n+13017158592\,\,657268661# US\n\n+13126266799\,\,657268661# US (Chicago)\n\n\nDial by your location\n\n +1 301 715 8592 US\n\n +1 312 626 6799 US (Chicago)\n\n +1 346 248 7799 US (Houston)\n\n +1 646 558 8656 US (New York)\n\n +1 669 900 6833 US (San Jose)\n\n +1 253 215 8782 US\n\nMeeting ID: 657 268 661\n\nFind your local number: https://zoom.us/u/acVUaqSX8Q\n\nNeed to make changes to this event?\nCancel: https://calendly.com/cancellations/EG647WAZV2FZCW6C\nReschedule: https://calendly.com/reschedulings/EG647WAZV2FZCW6C\n\nPowered by Calendly https://calendly.com/\n +URL:https://calendar.yandex.ru/event?event_id=1586882837 +CATEGORIES:Мои события +ORGANIZER;CN=Maxim Lutsan:mailto:maxim@7pace.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Maxim Lutsan;ROLE=REQ-PARTICIPANT:mailto:maxim@7pace.com +LAST-MODIFIED:20210510T143912Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20230720T150000 +DTEND;TZID=Europe/Moscow:20230720T160000 +SUMMARY:Консультация +UID:040000008200E00074C5B7101A82E008000000004873A33CD8BAD901000000000000000010000000685346F07F360E4EA9BEB177E2FE81B7 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20230720T070316Z +X-MICROSOFT-CDO-OWNERAPPTID:2121769032 +LOCATION:Microsoft Teams Meeting +DESCRIPTION:\n\n\n________________________________________________________________________________\nMicrosoft Teams meeting\nJoin on your computer\, mobile app or room device\nClick here to join the meeting\nMeeting ID: 372 563 506 586\nPasscode: DkCEzn\nDownload Teams | Join on the web\nLearn More | Meeting options\n________________________________________________________________________________\n\n\nYou're receiving this message because you're a member of the Вступительные испытания \"Разработка ИС и web-приложений\" group from Южный Федеральный Университет. To take part in this conversation\, reply all to this message.\n\nView group files | Leave group | Learn more about Microsoft 365 Groups\n\n +URL:https://calendar.yandex.ru/event?event_id=1885261476 +TRANSP:TRANSPARENT +CATEGORIES:Мои события +ORGANIZER;CN="Вступительные испытания Разработка ИС и web-приложений":mailto:web-152@sfedu.onmicrosoft.com +ATTENDEE;PARTSTAT=ACCEPTED;CN="Вступительные испытания Разработка ИС и web-приложений";ROLE=REQ-PARTICIPANT:mailto:web-152@sfedu.onmicrosoft.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Шкаленко Богдан Игоревич";ROLE=REQ-PARTICIPANT:mailto:shkalenko@sfedu.ru +LAST-MODIFIED:20230720T070316Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20230808T090000 +DTEND;TZID=Europe/Moscow:20230808T120000 +SUMMARY:Вступительное испытание 8.08 +UID:040000008200E00074C5B7101A82E008000000008E88499981C8D901000000000000000010000000047A320E78CB2B4DACB8311F49914E89 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20230806T161827Z +X-MICROSOFT-CDO-OWNERAPPTID:2121807246 +LOCATION:Microsoft Teams Meeting +DESCRIPTION:\n\n\n________________________________________________________________________________\nMicrosoft Teams meeting\nJoin on your computer\, mobile app or room device\nClick here to join the meeting\nMeeting ID: 371 378 578 107\nPasscode: shem7b\nDownload Teams | Join on the web\nLearn More | Meeting options\n________________________________________________________________________________\n\n\nYou're receiving this message because you're a member of the Вступительные испытания \"Разработка ИС и web-приложений\" group from Южный Федеральный Университет. To take part in this conversation\, reply all to this message.\n\nView group files | Leave group | Learn more about Microsoft 365 Groups\n\n +URL:https://calendar.yandex.ru/event?event_id=1892332731 +TRANSP:TRANSPARENT +CATEGORIES:Мои события +ORGANIZER;CN="Вступительные испытания Разработка ИС и web-приложений":mailto:web-152@sfedu.onmicrosoft.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Шкаленко Богдан Игоревич";ROLE=REQ-PARTICIPANT:mailto:shkalenko@sfedu.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Вступительные испытания Разработка ИС и web-приложений";ROLE=REQ-PARTICIPANT:mailto:web-152@sfedu.onmicrosoft.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Кулиев Эльмар Валерьевич";ROLE=REQ-PARTICIPANT:mailto:ekuliev@sfedu.ru +LAST-MODIFIED:20230806T161827Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART:20240908T225000Z +DTEND:20240909T204000Z +SUMMARY:Поезд РОСТОВ-ГЛАВНЫЙ - МОСКВА КАЗАНСКАЯ (017ЙА) +UID:10995822 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20240828T084803Z +LOCATION:Ж/д станция РОСТОВ-ГЛАВНЫЙ +DESCRIPTION:Поезд РОСТОВ-ГЛАВНЫЙ - МОСКВА КАЗАНСКАЯ\n\nПоезд: 017ЙА\nВагон: 01\nМесто: 010\nНомер билета: 76343740089172\n\nПри возникновении любых вопросов обращайтесь к travel помощникам Smartway:\n • В чате в личном кабинете или мобильном приложении\n • 8-800-775-14-28 (бесплатно\, только по РФ)\n • +7-495-128-89-96\n • help@smartway.today +URL:https://calendar.yandex.ru/event?event_id=2201441407 +TRANSP:TRANSPARENT +CATEGORIES:Мои события +LAST-MODIFIED:20240828T084803Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Asia/Krasnoyarsk:20240123T203000 -DTEND;TZID=Asia/Krasnoyarsk:20240123T210000 -SUMMARY:Без названия -UID:zwdqywax0sz8640h6m8yandex.ru +DTSTART:20240911T213200Z +DTEND:20240912T194600Z +SUMMARY:Поезд МОСКВА КАЗАНСКАЯ - РОСТОВ-ГЛАВНЫЙ (126ЭА) +UID:10995926 SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240123T110935Z -URL:https://calendar.yandex.ru/event?event_id=1980779802 -TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240123T110935Z +DTSTAMP:20250929T192310Z +CREATED:20240828T084818Z +LOCATION:Ж/д станция МОСКВА КАЗАНСКАЯ +DESCRIPTION:Поезд МОСКВА КАЗАНСКАЯ - РОСТОВ-ГЛАВНЫЙ\n\nПоезд: 126ЭА\nВагон: 11\nМесто: 026\nНомер билета: 76443740093630\n\nПри возникновении любых вопросов обращайтесь к travel помощникам Smartway:\n • В чате в личном кабинете или мобильном приложении\n • 8-800-775-14-28 (бесплатно\, только по РФ)\n • +7-495-128-89-96\n • help@smartway.today +URL:https://calendar.yandex.ru/event?event_id=2201441694 +TRANSP:TRANSPARENT +CATEGORIES:Мои события +LAST-MODIFIED:20240828T084818Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Asia/Krasnoyarsk:20240123T190000 -DTEND;TZID=Asia/Krasnoyarsk:20240123T193000 -SUMMARY:Без названия -UID:zwdqywax0szm0iv8br3yandex.ru +DTSTART:20241222T190800Z +DTEND:20241223T074600Z +SUMMARY:Поезд 340С\, Ростов-на-Дону\, Ростов-Главный - Волгоград-1 +UID:event-81a494d056c3460d6de0ba23f5f93a94 SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240123T110938Z -URL:https://calendar.yandex.ru/event?event_id=1980779831 -TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240123T110938Z +DTSTAMP:20250929T192310Z +CREATED:20241024T122209Z +LOCATION:Ростов-на-Дону\, Ростов-Главный +DESCRIPTION:Отправление в 22:08 (моск. время)\, прибытие в 10:46 (моск. время).\nСправки по телефону . +URL:https://calendar.yandex.ru/event?event_id=2268742760 +TRANSP:TRANSPARENT +CATEGORIES:Мои события +LAST-MODIFIED:20241024T122209Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Asia/Krasnoyarsk:20240123T223000 -DTEND;TZID=Asia/Krasnoyarsk:20240123T230000 -SUMMARY:Без названия -UID:zwdqywax0t03d7xqp32yandex.ru +DTSTART;TZID=Europe/Samara:20250323T140000 +DTEND;TZID=Europe/Samara:20250323T160000 +SUMMARY:Подкаст выпуск 1 +UID:6C543F78-CD98-4254-940A-6D48668FADF3 SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240123T110941Z -URL:https://calendar.yandex.ru/event?event_id=1980779871 +DTSTAMP:20250929T192310Z +CREATED:20250315T140108Z +X-MICROSOFT-CDO-OWNERAPPTID:-1321535360 +URL:https://calendar.yandex.ru/event?event_id=2426359615 TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240123T110941Z +CATEGORIES:Мои события +ORGANIZER;CN=457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09:mailto:457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09@group.calendar.google.com +ATTENDEE;PARTSTAT=ACCEPTED;CN=457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09;ROLE=REQ-PARTICIPANT:mailto:457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09@group.calendar.google.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250315T140108Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Samara:20250321T210000 +DTEND;TZID=Europe/Samara:20250321T213000 +SUMMARY:Обсуждение подкаста +UID:985DC5D3-8E6A-4010-ACE1-10926030E2F1 +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250315T141652Z +X-MICROSOFT-CDO-OWNERAPPTID:1419277172 +URL:https://calendar.yandex.ru/event?event_id=2426371381 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN=27f07ba405ec140722e61fad8608f889811f346130fd268030e28377b4871feb:mailto:27f07ba405ec140722e61fad8608f889811f346130fd268030e28377b4871feb@group.calendar.google.com +ATTENDEE;PARTSTAT=ACCEPTED;CN=27f07ba405ec140722e61fad8608f889811f346130fd268030e28377b4871feb;ROLE=REQ-PARTICIPANT:mailto:27f07ba405ec140722e61fad8608f889811f346130fd268030e28377b4871feb@group.calendar.google.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250315T145545Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Samara:20250321T210000 +DTEND;TZID=Europe/Samara:20250321T213000 +SUMMARY:Обсуждение подкаста +UID:4E3F3F31-4BD5-4B7C-801C-3C42A35B1A9D +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250315T145621Z +X-MICROSOFT-CDO-OWNERAPPTID:135734642 +URL:https://calendar.yandex.ru/event?event_id=2426410148 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN=457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09:mailto:457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09@group.calendar.google.com +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09;ROLE=REQ-PARTICIPANT:mailto:457fa5c63b465cae7d4d4b14be939cbd445ec2e0df7a3731e64ffd89ba6cdc09@group.calendar.google.com +LAST-MODIFIED:20250315T145621Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250404T173000 +DTEND;TZID=Europe/Moscow:20250404T183000 +SUMMARY:Установочная встреча_ ИИ в образовании и науке +UID:MTS-LINK.RU_Comdi\\v2Bundle\\Entity\\EventSession_1749750342_1111211511 +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250403T124224Z +LOCATION:https://my.mts-link.ru/j/103697369/1012293684/5c6303bba3b550dcdacf1910e8ed4f37 +DESCRIPTION:Расскажем про обучение на программе\, цели и результаты обучения\, систему оценивания\, актуальность темы развития ИИ-грамотности \nОтветим на ваши вопросы\nОрганизатор: Екатерина Анатольевна Безызвестных\nСсылка для входа: https://my.mts-link.ru/j/103697369/1012293684/5c6303bba3b550dcdacf1910e8ed4f37 +URL:https://calendar.yandex.ru/event?event_id=2455388562 +CATEGORIES:Мои события +ORGANIZER;CN=invitation:mailto:invitation@webinar.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=invitation;ROLE=REQ-PARTICIPANT:mailto:invitation@webinar.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250403T124224Z +CLASS:PUBLIC +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250915T200000 +DTEND;TZID=Europe/Moscow:20250915T203000 +SUMMARY:Финансы с Майей +UID:7jnxs1jynml19z26o5jyandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250915T141933Z +DESCRIPTION:- оформить подписку +URL:https://calendar.yandex.ru/event?event_id=2727365306 +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +LAST-MODIFIED:20250915T152326Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Europe/Samara:20240124T163000 -DTEND;TZID=Europe/Samara:20240124T170000 -SUMMARY:Привет -UID:zwdqywax08ke3e4lgn57yandex.ru -SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240124T090329Z -URL:https://calendar.yandex.ru/event?event_id=1981462656 -TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240124T090329Z +DTSTART;TZID=Europe/Moscow:20250915T210000 +DTEND;TZID=Europe/Moscow:20250915T214000 +SUMMARY:Рассказ про трекер +UID:7jnxs1jynm5w2iap7i7gyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250915T142102Z +URL:https://calendar.yandex.ru/event?event_id=2727367905 +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +LAST-MODIFIED:20250915T143554Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Europe/Samara:20240126T130000 -DTEND;TZID=Europe/Samara:20240126T133000 -SUMMARY:Новое событие -UID:zwdqywax25jvjlx7r4e9yandex.ru -SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240126T080645Z -DESCRIPTION:Надо встретиться -URL:https://calendar.yandex.ru/event?event_id=1983061891 -TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240126T080645Z +DTSTART;TZID=Europe/Moscow:20250915T215000 +DTEND;TZID=Europe/Moscow:20250915T222000 +SUMMARY:Отъезд +UID:7jnxs1jynm25ff8se9tyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250915T142216Z +URL:https://calendar.yandex.ru/event?event_id=2727369260 +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250915T143609Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Europe/Samara:20240126T153000 -DTEND;TZID=Europe/Samara:20240126T160000 -SUMMARY:Ещё одно новое событие -UID:zwdqywax25jy3fg604q4yandex.ru -SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240126T080704Z -DESCRIPTION:Реально надо встретиться -URL:https://calendar.yandex.ru/event?event_id=1983062020 -TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240126T080704Z +DTSTART;TZID=Europe/Moscow:20250917T200000 +DTEND;TZID=Europe/Moscow:20250917T203000 +SUMMARY:Обсуждение финансов +UID:7jnxs1jynm66lgucfgeryandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250915T142515Z +URL:https://calendar.yandex.ru/event?event_id=2727372716 +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250915T143532Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Europe/Samara:20240127T153000 -DTEND;TZID=Europe/Samara:20240127T160000 -SUMMARY:Без названия -UID:zwdqywax25sz6nhk0zfyandex.ru -SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240126T084915Z -URL:https://calendar.yandex.ru/event?event_id=1983093315 +DTSTART;TZID=Europe/Moscow:20250916T200000 +DTEND;TZID=Europe/Moscow:20250916T203000 +SUMMARY:Синк с Катей +UID:7jnxs1jynmtzg724wyfyandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250915T150219Z +URL:https://calendar.yandex.ru/event?event_id=2727432540 +RRULE:FREQ=WEEKLY;BYDAY=TU;UNTIL=20251231T180000Z;INTERVAL=1 +EXDATE;TZID=Europe/Moscow:20250923T200000 TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240126T084915Z +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250915T152158Z CLASS:PRIVATE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=Europe/Samara:20240126T140000 -DTEND;TZID=Europe/Samara:20240126T143000 -SUMMARY:Тут ещё одно событие -UID:zwdqywax26494cx3kbv7yandex.ru -SEQUENCE:0 -DTSTAMP:20240126T105030Z -CREATED:20240126T094235Z -DESCRIPTION:Забей хуй на него -URL:https://calendar.yandex.ru/event?event_id=1983139091 +DTSTART;TZID=Europe/Moscow:20250916T200000 +DTEND;TZID=Europe/Moscow:20250916T203000 +SUMMARY:Синк с Катей +UID:7jnxs1jynmtzg724wyfyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250915T152453Z +DESCRIPTION:- оформить подписку +URL:https://calendar.yandex.ru/event?event_id=2727468341 +RECURRENCE-ID;TZID=Europe/Moscow:20250916T200000 TRANSP:OPAQUE -CATEGORIES:Привет -LAST-MODIFIED:20240126T094235Z +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250915T152453Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250917T203000 +DTEND;TZID=Europe/Moscow:20250917T210000 +SUMMARY:Синк мл +UID:7jnxs1jynm981ilnbhfuyandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250915T151722Z +URL:https://calendar.yandex.ru/event?event_id=2727459166 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250915T151722Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250916T210000 +DTEND;TZID=Europe/Moscow:20250916T213000 +SUMMARY:Синк Правдина Кристина и Ким Данил - проектники +UID:7jnxs1jynn9hiq7cypzryandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250915T180816Z +URL:https://calendar.yandex.ru/event?event_id=2727681895 +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250916T182030Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20251001T190000 +DTEND;TZID=Europe/Moscow:20251001T193000 +SUMMARY:Дедлайн Дани и Кристи +UID:7jnxs1jynw6txyhh4yguyandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250916T182244Z +URL:https://calendar.yandex.ru/event?event_id=2729733876 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250916T182244Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250917T220000 +DTEND;TZID=Europe/Moscow:20250917T223000 +SUMMARY:Оплата Маше гпт +UID:7jnxs1jynx1t71ugwk4ayandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250916T194429Z +URL:https://calendar.yandex.ru/event?event_id=2729817090 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +LAST-MODIFIED:20250916T194429Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250920T200000 +DTEND;TZID=Europe/Moscow:20250920T203000 +SUMMARY:Обсуждение тг каналов +UID:7jnxs1jynx38uzpr4dbxyandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250916T200850Z +URL:https://calendar.yandex.ru/event?event_id=2729852213 +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250918T201108Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250918T210000 +DTEND;TZID=Europe/Moscow:20250918T213000 +SUMMARY:1-1 Ярик Данил +UID:7jnxs1jyo47b4iqrxe8uyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250917T164415Z +URL:https://calendar.yandex.ru/event?event_id=2731629631 +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250917T164431Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250918T213000 +DTEND;TZID=Europe/Moscow:20250918T220000 +SUMMARY:Java +UID:7jnxs1jyo564nq1kisryandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250917T173054Z +URL:https://calendar.yandex.ru/event?event_id=2731680643 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250917T173054Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART:20250919T083000Z +DTEND:20250919T083000Z +SUMMARY:Регистрация гражданина по месту пребывания +UID:1301218167 +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250918T060248Z +LOCATION:Москва г\, Варшавское ш\, д. 128\, к 2 +DESCRIPTION:Услуга: Регистрация гражданина по месту пребывания\nДата и время события: 19.09.2025 11:30 (в часовом поясе подразделения)\nВедомство: ОВМ ОМВД России по району Чертаново Северное г. Москвы (МФЦ)\nАдрес: Москва г\, Варшавское ш\, д. 128\, к 2\n\nДля просмотра информации перейдите на страницу уведомления https://lk.gosuslugi.ru/notifications/details/EQUEUE/8ae13d66-3bdb-4e02-a9da-7a4fd50b5924\n +URL:https://calendar.yandex.ru/event?event_id=2732624415 +TRANSP:TRANSPARENT +CATEGORIES:Мои события +LAST-MODIFIED:20250918T060248Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250919T203000 +DTEND;TZID=Europe/Moscow:20250919T210000 +SUMMARY:Ярик Вячеслав 1-1 +UID:7jnxs1jyoe66j58yd5s5yandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250918T201139Z +DESCRIPTION:https://dytech.ktalk.ru/1on1 +URL:https://calendar.yandex.ru/event?event_id=2733856475 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250918T201304Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250920T190000 +DTEND;TZID=Europe/Moscow:20250920T200000 +SUMMARY:Финансы с Майей +UID:7jnxs1jyom2w574uxhbfyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250919T172922Z +DESCRIPTION:позвать Машу +URL:https://calendar.yandex.ru/event?event_id=2735541210 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250919T173225Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250921T200000 +DTEND;TZID=Europe/Moscow:20250921T210000 +SUMMARY:Онлайн тренер +UID:7jnxs1jyor5rjkbu07lqyandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250920T081149Z +URL:https://calendar.yandex.ru/event?event_id=2736561721 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250920T081149Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250922T200000 +DTEND;TZID=Europe/Moscow:20250922T210000 +SUMMARY:Д. Я. В. В. +UID:7jnxs1jypd4wry1l6n2tyandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250922T210336Z +LOCATION:https://dytech.ktalk.ru/general_call +URL:https://calendar.yandex.ru/event?event_id=2741132200 +RRULE:FREQ=WEEKLY;BYDAY=MO;UNTIL=20251013T180000Z;INTERVAL=1 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=galkin.vm63;ROLE=OPT-PARTICIPANT:mailto:galkin.vm63@gmail.com +ATTENDEE;PARTSTAT=ACCEPTED;CN="Галкин Вячеслав";ROLE=OPT-PARTICIPANT:mailto:viacheslawgal@yandex.ru +LAST-MODIFIED:20250929T171015Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250922T210000 +DTEND;TZID=Europe/Moscow:20250922T213000 +SUMMARY:Csharp +UID:7jnxs1jypd4xxzxp130vyandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250922T210520Z +LOCATION:https://dytech.ktalk.ru/csharp +URL:https://calendar.yandex.ru/event?event_id=2741133343 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=-stas.horoshavtsev;ROLE=REQ-PARTICIPANT:mailto:-stas.horoshavtsev@ya.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +LAST-MODIFIED:20250923T131712Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250923T200000 +DTEND;TZID=Europe/Moscow:20250923T203000 +SUMMARY:Python +UID:7jnxs1jypd51plowvl0cyandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250922T210606Z +LOCATION:https://dytech.ktalk.ru/python +URL:https://calendar.yandex.ru/event?event_id=2741133695 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="комышев данил";ROLE=REQ-PARTICIPANT:mailto:danil.komyshev@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Игорь Костин";ROLE=REQ-PARTICIPANT:mailto:kostin-igor-mail@yandex.ru +LAST-MODIFIED:20250923T131706Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250923T203000 +DTEND;TZID=Europe/Moscow:20250923T210000 +SUMMARY:Фронт +UID:7jnxs1jypd5387zw889syandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250922T210641Z +LOCATION:https://dytech.ktalk.ru/front +URL:https://calendar.yandex.ru/event?event_id=2741134043 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Михалко Екатерина";ROLE=REQ-PARTICIPANT:mailto:fimyshkina@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +LAST-MODIFIED:20250923T131709Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250924T200000 +DTEND;TZID=Europe/Moscow:20250924T203000 +SUMMARY:Java +UID:7jnxs1jypd54yt9rqx4hyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250922T210728Z +LOCATION:https://dytech.ktalk.ru/java +URL:https://calendar.yandex.ru/event?event_id=2741134608 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=solisimo;ROLE=REQ-PARTICIPANT:mailto:solisimo@mail.ru +ATTENDEE;PARTSTAT=DECLINED;CN="Терских Константин";ROLE=REQ-PARTICIPANT:mailto:kostus.online.1974@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Правдина Кристина";ROLE=REQ-PARTICIPANT:mailto:pravdinak.o@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Галкин Вячеслав";ROLE=REQ-PARTICIPANT:mailto:viacheslawgal@yandex.ru +LAST-MODIFIED:20250924T150207Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250925T200000 +DTEND;TZID=Europe/Moscow:20250925T203000 +SUMMARY:Csharp +UID:7jnxs1jypd593vjhnitbyandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250922T210929Z +LOCATION:https://dytech.ktalk.ru/csharp +URL:https://calendar.yandex.ru/event?event_id=2741135406 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Хорошавцев Стас";ROLE=REQ-PARTICIPANT:mailto:stas.horoshavtsev@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250923T131735Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250925T203000 +DTEND;TZID=Europe/Moscow:20250925T210000 +SUMMARY:Python +UID:7jnxs1jypdj1jftl3fwyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250922T211009Z +LOCATION:https://dytech.ktalk.ru/pyhon +URL:https://calendar.yandex.ru/event?event_id=2741135769 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Игорь Костин";ROLE=REQ-PARTICIPANT:mailto:kostin-igor-mail@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="комышев данил";ROLE=REQ-PARTICIPANT:mailto:danil.komyshev@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250926T091408Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250926T200000 +DTEND;TZID=Europe/Moscow:20250926T203000 +SUMMARY:Java +UID:7jnxs1jypd5bup7u0zhfyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250922T211045Z +LOCATION:https://dytech.ktalk.ru/java +URL:https://calendar.yandex.ru/event?event_id=2741136089 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN=solisimo;ROLE=REQ-PARTICIPANT:mailto:solisimo@mail.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Галкин Вячеслав";ROLE=REQ-PARTICIPANT:mailto:viacheslawgal@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Правдина Кристина";ROLE=REQ-PARTICIPANT:mailto:pravdinak.o@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Терских Константин";ROLE=REQ-PARTICIPANT:mailto:kostus.online.1974@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250926T091338Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250926T203000 +DTEND;TZID=Europe/Moscow:20250926T210000 +SUMMARY:Фронт +UID:7jnxs1jypd5d5lsti1d7yandex.ru +SEQUENCE:2 +DTSTAMP:20250929T192310Z +CREATED:20250922T211130Z +LOCATION:https://dytech.ktalk.ru/front +URL:https://calendar.yandex.ru/event?event_id=2741136898 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Михалко Екатерина";ROLE=REQ-PARTICIPANT:mailto:fimyshkina@yandex.ru +LAST-MODIFIED:20250926T091233Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250924T190000 +DTEND;TZID=Europe/Moscow:20250924T193000 +SUMMARY:Ярослав-Кристина +UID:7jnxs1jypi2c266kqwibyandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250923T101517Z +LOCATION:https://dytech.ktalk.ru/y_k +URL:https://calendar.yandex.ru/event?event_id=2742235994 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Правдина Кристина";ROLE=REQ-PARTICIPANT:mailto:pravdinak.o@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +LAST-MODIFIED:20250923T131700Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250924T203000 +DTEND;TZID=Europe/Moscow:20250924T210000 +SUMMARY:Тестирование +UID:7jnxs1jypja4ytllpp0yandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250923T130841Z +LOCATION:https://dytech.ktalk.ru/tetsting +URL:https://calendar.yandex.ru/event?event_id=2742491382 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Varetsa Anna;ROLE=REQ-PARTICIPANT:mailto:anavaretsa@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +LAST-MODIFIED:20250923T131704Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250927T200000 +DTEND;TZID=Europe/Moscow:20250927T203000 +SUMMARY:Тестирование +UID:7jnxs1jypj3er9hztz00yandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250923T131819Z +LOCATION:https://dytech.ktalk.ru/testing +URL:https://calendar.yandex.ru/event?event_id=2742500623 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=TENTATIVE;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Varetsa Anna;ROLE=REQ-PARTICIPANT:mailto:anavaretsa@yandex.ru +LAST-MODIFIED:20250926T091439Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250926T190000 +DTEND;TZID=Europe/Moscow:20250926T193000 +SUMMARY:1-1 Ярослав Вячеслав +UID:7jnxs1jypj3gcqgwgsh8yandex.ru +SEQUENCE:1 +DTSTAMP:20250929T192310Z +CREATED:20250923T131929Z +LOCATION:https://dytech.ktalk.ru/1on1 +DESCRIPTION:По возможности добавить Диму +URL:https://calendar.yandex.ru/event?event_id=2742501748 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Галкин Вячеслав";ROLE=REQ-PARTICIPANT:mailto:viacheslawgal@yandex.ru +LAST-MODIFIED:20250923T131956Z +CLASS:PRIVATE +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Moscow:20250925T190000 +DTEND;TZID=Europe/Moscow:20250925T200000 +SUMMARY:Д. Я. В. В. +UID:7jnxs1jypqb8j2y4mkyyandex.ru +SEQUENCE:0 +DTSTAMP:20250929T192310Z +CREATED:20250924T084040Z +LOCATION:https://dytech.ktalk.ru/general_call +URL:https://calendar.yandex.ru/event?event_id=2744047054 +TRANSP:OPAQUE +CATEGORIES:Мои события +ORGANIZER;CN="Косенко Марина":mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Галкин Вячеслав";ROLE=REQ-PARTICIPANT:mailto:viacheslawgal@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN="Борисов Ярослав";ROLE=REQ-PARTICIPANT:mailto:tiranafols@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Косенко Марина";ROLE=REQ-PARTICIPANT:mailto:kosenko.marina02@yandex.ru +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=Shiryayev Dmitry;ROLE=REQ-PARTICIPANT:mailto:sh1ryayevdmitry@yandex.ru +ATTENDEE;PARTSTAT=ACCEPTED;CN="Руссо Джон";ROLE=REQ-PARTICIPANT:mailto:russo.jon@yandex.ru +LAST-MODIFIED:20250924T150245Z CLASS:PRIVATE END:VEVENT END:VCALENDAR diff --git a/db/clock.db b/db/clock.db deleted file mode 100644 index a7fda41..0000000 Binary files a/db/clock.db and /dev/null differ diff --git a/db/users.db b/db/users.db deleted file mode 100644 index 86b0d99..0000000 Binary files a/db/users.db and /dev/null differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f08b24a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +services: + calendarkin-bot: + build: . + container_name: y-calendarkin-bot + restart: unless-stopped + environment: + # Токен Telegram бота (обязательно) + - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} + + # Дополнительные переменные окружения (опционально) + - TZ=Europe/Moscow + + volumes: + # Монтируем директорию с базами данных для сохранения данных + - ./db:/app/db + # Монтируем директорию с календарями + - ./data:/app/data + + # Логирование + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # Ограничения ресурсов + deploy: + resources: + limits: + memory: 512M + reservations: + memory: 256M + +# Создаем именованные тома для данных (опционально) +volumes: + db_data: + ical_data: diff --git a/env.example b/env.example new file mode 100644 index 0000000..d3db53f --- /dev/null +++ b/env.example @@ -0,0 +1,7 @@ +# Telegram Bot Token +# Получите токен у @BotFather в Telegram +TELEGRAM_BOT_TOKEN=your_bot_token_here + +# Часовой пояс (опционально) +TZ=Europe/Moscow +