import time

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tqdm
from scipy.stats import norm

height_list = pd.read_csv('./height_data.csv', header=0, names=['height'])
height_list = [row['height'] for index, row in height_list.iterrows()]
N = len(height_list)

pai = 0.5
uF = 160
sF = 1
uM = 180
sM = 1
gama = np.zeros(N)
tol = 1e-6
max_iteration = 200
pbar = tqdm.trange(max_iteration)

for j in enumerate(pbar):
    # E-STEP
    for i in range(N):
        gama[i] = pai * norm.pdf(height_list[i], uF, sF) / (
                pai * norm.pdf(height_list[i], uF, sF) + (1 - pai) * norm.pdf(height_list[i], uM, sM))
    # M-STEP
    gama_total = uF_total = sF_total = uM_total = sM_total = 0
    for i in range(N):
        gama_total += gama[i]
        uF_total += height_list[i] * gama[i]
        uM_total += height_list[i] * (1 - gama[i])
    pai_new = gama_total / N
    uF_new = uF_total / gama_total
    uM_new = uM_total / (N - gama_total)
    for i in range(N):
        sF_total += gama[i] * np.power(height_list[i] - uF_new, 2)
        sM_total += (1 - gama[i]) * np.power(height_list[i] - uM_new, 2)
    sF_new = np.sqrt(sF_total / gama_total)
    sM_new = np.sqrt(sM_total / (N - gama_total))
    if abs(pai - pai_new) < tol and abs(uF - uF_new) < tol and abs(uM - uM_new) < tol and abs(
            sF - sF_new) < tol and abs(sM - sM_new) < tol:
        print('EM算法已经收敛！')
        break
    pai = pai_new
    uF = uF_new
    uM = uM_new
    sF = sF_new
    sM = sM_new
    log_likelihood = np.dot(np.log(pai * norm.pdf(height_list, uF, sF) + (1 - pai) * norm.pdf(height_list, uM, sM)),
                            gama)
    pbar.set_postfix(pai=pai, uF=uF, uM=uM, sF=sF, sM=sM, log_like=log_likelihood)
    time.sleep(0.2)

log_likelihood = np.dot(np.log(pai * norm.pdf(height_list, uF, sF) + (1 - pai) * norm.pdf(height_list, uM, sM)), gama)
print('女生占比:{:.4%},\n女生身高均值:{:.2f}\n女生身高标准差:{:.2f}\n男生身高均值:{:.2f}\n男生身高标准差:{:.2f}'.format(
    pai, uF, sF, uM, sM))
print('log_likelihood : ', log_likelihood)

x = np.linspace(min(height_list), max(height_list), 200)

def y(x):
    y = pai * norm.pdf(x, uF, sF) + (1 - pai) * norm.pdf(x, uM, sM)
    return y * N

plt.hist(height_list, bins=20, color="w", label="直方分布图", edgecolor='k')
plt.xlabel('height/cm')
plt.ylabel('Count')
plt.plot(x, y(x), 'r-', linewidth=1, label='f(x)')
plt.show()


from page import Page
import threading
import collections
import os

class BufferPool:

    def __init__(self, size):
        self.limit = size
        self.pages = []
        self.table_index = {}
        self.eviction_queue = collections.OrderedDict()
        self.buffer_lock = threading.Lock()

    def get_page(self, table_name, page_id):
        self.buffer_lock.acquire()
        if table_name in self.table_index:
            sub_directory = self.table_index[table_name]
        else:
            self.table_index[table_name] = {}
            sub_directory = self.table_index[table_name]

        if page_id in sub_directory:
            location = sub_directory[page_id]
            if (table_name, page_id) in self.eviction_queue:
                self.eviction_queue.pop((table_name, page_id))
            self.eviction_queue[(table_name, page_id)] = None
            self.buffer_lock.release()
            return self.pages[location]
        else:
            if len(self.pages) < self.limit:
                location = self.fetch(table_name, page_id, None)
                if (table_name, page_id) in self.eviction_queue:
                    self.eviction_queue.pop((table_name, page_id))
                self.eviction_queue[(table_name, page_id)] = None
                sub_directory[page_id] = location
                self.buffer_lock.release()
                return self.pages[location]
            else:
               location = self.evict()
               self.fetch(table_name, page_id, location)
               sub_directory[page_id] = location
               if (table_name, page_id) in self.eviction_queue:
                   self.eviction_queue.pop((table_name, page_id))
               self.eviction_queue[(table_name, page_id)] = None
               self.buffer_lock.release()
               return self.pages[location]

    def fetch(self, table_name, page_id, location):
        path = table_name+'/page_file'
        f = open(path, mode='rb+')
        f.seek(4096*page_id)
        read_data = f.read(4096)
        page = Page(page_id)
        page.load_data(read_data)
        if location == None:
            self.pages.append(page)
            location = self.pages.index(page)
        else:
            self.pages[location] = page
        f.close()
        return location

    def evict(self):
        location = None
        for e in self.eviction_queue:
            page = self.pages[self.table_index[e[0]][e[1]]]
            if page.pinned == 0:
                self.eviction_queue.pop(e)
                if page.dirty:
                    self.write_page(page, e[1], e[0])
                del self.table_index[e[0]][e[1]]
                location = self.pages.index(page)
                break
            else:
                continue
        if location == None:
            print('fatal buffer pool error: all pages are pinned')
            os._exit(1)
        return location

    def write_page(self, page, page_id, table_name):
        path = table_name+'/page_file'
        try:
            f = open(path, mode='rb+')
            f.seek(4096*page_id)
            f.write(page.data)
            f.close
        except FileNotFoundError:
            pass

    def flush(self):
        for table in self.table_index:
            sub_directory = self.table_index[table]
            for page_id in sub_directory:
                location = sub_directory[page_id]
                page = self.pages[location]
                if page.dirty:
                    self.write_page(page, page_id, table)


import json
import telebot
from telebot import types
import os
from datetime import datetime, date
bot = telebot.TeleBot('TOKEN')

current_dir = os.path.dirname(__file__)
#относительные пути для текстовых файлов
file_path_budget = os.path.join(current_dir, 'files', 'budget.png')
file_path_commercial = os.path.join(current_dir, 'files', 'commercial.png')
file_path_ege = os.path.join(current_dir, 'files', 'ege.txt')
file_path_vi1 = os.path.join(current_dir, 'files', 'vi1.txt')
file_path_vi2 = os.path.join(current_dir, 'files', 'vi2.txt')
file_path_to_log = os.path.join (current_dir, "log.log")
file_path_to_log1 = os.path.join (current_dir, "log.json")

@bot.message_handler(commands=['start']) #стартовая команда
def start(message):

    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    btn1 = types.KeyboardButton("ВО")
    btn2 = types.KeyboardButton('СПО')
    markup.add(btn1, btn2)
    bot.send_message(message.from_user.id, "Вас приветствует бот *Приёмной комиссии ЧИ БГУ*👋 \n\nУ меня вы можете узнать интересующую вас информацию о поступлении в наш институт. \n\n Выберите интересующий вас уровень образования с помощью клавиатуры⌨\n(_квадратная кнопка на поле для ввода сообщений_)", reply_markup=markup, parse_mode='Markdown')

@bot.message_handler(content_types=['text'])
def get_text_messages(message):

    now = datetime.now()
    current_time = str(date.today()) + " " + now.strftime("%H:%M:%S")

    text =  current_time+" @" +message.from_user.username + " ("+str(message.from_user.id) +") : " +message.text
    json_log = {"time" : current_time, "username":message.from_user.username, "userid": message.from_user.id, "text":message.text }
    with open(file_path_to_log, "a",encoding="utf-8") as file:
        file.write("\n"+text)
    # with open(file_path_to_log1, "a",encoding="utf-8") as file:
    #     json.dump(json_log, file, ensure_ascii=False)
    #     file.write(', \n')
    bot.send_message(575078092, text)

    #ВО
    if message.text == 'ВО':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton("📚Направления подготовки")
        btn2 = types.KeyboardButton('📰Способы подачи документов')
        btn3 = types.KeyboardButton('✍План приёма')
        btn4 = types.KeyboardButton('📊Мин. баллы ЕГЭ')
        btn5 = types.KeyboardButton('🔎ВИ')
        btn6 = types.KeyboardButton('💳 Стоимость обучения')
        btn7 = types.KeyboardButton('💻 Образцы документов')
        btn8 = types.KeyboardButton('📋 Списки абитуриентов')
        btn9 = types.KeyboardButton('📱 Контакты')
        btn10 = types.KeyboardButton('🔙 Вернуться к выбору уровня образования')
        btn11 = types.KeyboardButton('Связаться с тех.секретарём')
        markup.add(btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn10,btn11)
        bot.send_message(message.from_user.id, "👋 ВО - программы Высшего образования", reply_markup=markup)
        bot.send_message(message.from_user.id, '👀 Выберите интересующий вас раздел \n\nЕсли бот не сможет ответить на интересующие вас вопросы нажмите кнопку `Связаться с тех.секретарём` и мы ответим на все ваши вопросы!',reply_markup=markup, parse_mode='Markdown')

    elif message.text == '🔙 Вернуться к выбору уровня образования':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton("ВО")
        btn2 = types.KeyboardButton('СПО')
        markup.add(btn1, btn2)
        bot.send_message(message.from_user.id, "✔Выберите уровень образования", reply_markup=markup)

    elif message.text == '📚Направления подготовки':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('Юриспруденция')
        btn2 = types.KeyboardButton('ЭПиПД')
        btn3 = types.KeyboardButton('ВЭД')
        btn4 = types.KeyboardButton('ФК')
        btn5 = types.KeyboardButton('УП')
        btn6 = types.KeyboardButton('ГМУ')
        btn7 = types.KeyboardButton('ИСТУ')
        btn8 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8)
        bot.send_message(message.from_user.id, '⬇ Выберите интересующее вас направление подготовки', reply_markup=markup)

    elif message.text == 'Юриспруденция':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📚Направления подготовки')
        btn2 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "Юриспруденция" в ВУЗах предназначено для обучения студентов основам права и юридической деятельности.'
                        'В ходе обучения студенты изучают такие дисциплины, как гражданское право, уголовное право, административное право, конституционное право и другие отрасли права. \n\nПодробнее об направлении подготовки "Юриспруденция" можно прочитать по [ссылке](https://abit.bgu-chita.ru/abiturient/134-40-03-01-yurisprudentsiya)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ЭПиПД':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📚Направления подготовки')
        btn2 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "Экономика предприятия и предпринимательская деятельность" в ВУЗах предназначено для обучения студентов основам экономической науки, а также формирования навыков и знаний, необходимых для организации и управления предприятиями и ведения предпринимательской деятельности.'
                        '\n\nПодробнее об направлении подготовки "Экономика предприятия и предпринимательская деятельность" можно прочитать по [ссылке](https://abit.bgu-chita.ru/abiturient/106-38-03-01-ekonomika-po-profilyu-ekonomika-predpriyatiya-i-predprinimatelskaya-deyatelnost)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ВЭД':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📚Направления подготовки')
        btn2 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "Внешнеэкономическая деятельность" в ВУЗах предназначено для обучения студентов основам международных экономических отношений и внешней торговли. Оно призвано развить у студентов навыки и знания, необходимые для работы в области международного бизнеса, внешнеэкономических отношений и торговли.'
                        '\n\nПодробнее об направлении подготовки "Внешнеэкономическая деятельность" можно прочитать по [ссылке](https://abit.bgu-chita.ru/abiturient/90-38-03-01-ekonomika-po-profilyu-mirovaya-ekonomika)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ФК':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📚Направления подготовки')
        btn2 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "Финансы и кредит" в ВУЗах предназначено для обучения студентов основам финансовой науки, понятиям и принципам, связанным с финансовой системой и кредитной деятельностью. Оно направлено на развитие навыков и знаний, необходимых для работы в банковской сфере, финансовых учреждениях, финансовых отделах предприятий и организациях.'
                        '\n\nПодробнее об направлении подготовки "Финансы и кредит" можно прочитать по [ссылке](https://abit.bgu-chita.ru/abiturient/111-38-03-01-ekonomika-po-profilyu-finansy-i-kredit)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'УП':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📚Направления подготовки')
        btn2 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "Управление персоналом" в ВУЗах предназначено для обучения студентов основам управления персоналом, развитию навыков и знаний, необходимых для эффективной работы с сотрудниками в организациях различного типа.'
                        '\n\nПодробнее об направлении подготовки "Управление персоналом" можно прочитать по [ссылке](https://abit.bgu-chita.ru/abiturient/116-38-03-03-upravlenie-personalom)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ГМУ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📚Направления подготовки')
        btn2 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "Государственное и муниципальное управление" в ВУЗах направлено на обучение студентов основам государственного аппарата и муниципального управления. Цель такого обучения - развитие навыков и знаний, необходимых для работы в государственных и муниципальных органах, а также в организациях, связанных с государственным и муниципальным сектором.'
                        '\n\nПодробнее об направлении подготовки "Государственное и муниципальное управление" можно прочитать по [ссылке](https://abit.bgu-chita.ru/abiturient/120-38-03-04-gosudarstvennoe-i-munitsipalnoe-upravlenie)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ИСТУ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📚Направления подготовки')
        btn2 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "Информационные системы и технологии в управлении" в ВУЗах предназначено для студентов, которые интересуются применением информационных технологий в сфере управления и бизнеса. Курс обучения включает изучение основных принципов информационных систем, разработку программного обеспечения, анализ данных, управление проектами, электронную коммерцию и другие смежные темы.'
                        '\n\nПодробнее об направлении подготовки "Информационные системы и технологии в управлении" можно прочитать по [ссылке](https://abit.bgu-chita.ru/abiturient/104-09-03-03-prikladnaya-informatika-po-profilyu-informatsionnye-sistemy-i-tekhnologii-v-upravlenii)', reply_markup=markup, parse_mode='Markdown')

    #общая кнопка для ВО и СПО
    elif message.text == 'Связаться с тех.секретарём':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)

        bot.send_message(message.from_user.id, 'Напишите свой вопрос техническому секретарю. Для того чтобы связаться с ним нажмите на ссылку - @chita_baikaluniversity\nЧасы работы: пн-пт:9:00-17:00,сб:9:00-13:00 ', reply_markup=markup )

    elif message.text == '🔙 Главное меню':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton("📚Направления подготовки")
        btn2 = types.KeyboardButton('📰Способы подачи документов')
        btn3 = types.KeyboardButton('✍План приёма')
        btn4 = types.KeyboardButton('📊Мин. баллы ЕГЭ')
        btn5 = types.KeyboardButton('🔎ВИ')
        btn6 = types.KeyboardButton('💳 Стоимость обучения')
        btn7 = types.KeyboardButton('💻 Образцы документов')
        btn8 = types.KeyboardButton('📋 Списки абитуриентов')
        btn9 = types.KeyboardButton('📱 Контакты')
        btn10 = types.KeyboardButton('🔙 Вернуться к выбору уровня образования')
        btn11 = types.KeyboardButton('Связаться с тех.секретарём')
        markup.add(btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn10,btn11)
        bot.send_message(message.from_user.id, "👋 ВО - программы Высшего образования", reply_markup=markup)
        bot.send_message(message.from_user.id, '👀 Выберите интересующий вас раздел \n\nЕсли бот не сможет ответить на интересующие вас вопросы нажмите кнопку `Связаться с тех.секретарём` и мы ответим на все ваши вопросы!',reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📰Способы подачи документов':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, '*Способы подачи документов:*\n\
🚩Лично в приемную комиссию по адресу _г.Чита, ул.Анохина 56_\n\
🚩Через сайт онлайн-приёма ЧИ БГУ https://priem.bgu-chita.ru/\n\
🚩Через единый портал государственных услуг https://www.gosuslugi.ru/vuzonline\ ', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '✍План приёма':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('Бюджет')
        btn2 = types.KeyboardButton('Коммерция')
        btn3 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2,btn3)
        bot.send_message(message.from_user.id, "Выберите источник финансирования", reply_markup=markup)
    elif message.text =='Бюджет':
        bot.send_photo(message.from_user.id, open(file_path_budget, 'rb'))
    elif message.text=='Коммерция':
        bot.send_photo(message.from_user.id, open(file_path_commercial, 'rb'))

    elif message.text == '📊Мин. баллы ЕГЭ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1)
        with open(file_path_ege, 'r',encoding='utf-8') as file:
            text = file.read()
        bot.send_message(message.from_user.id,text=text, reply_markup=markup, parse_mode='Markdown')

    elif message.text == '🔎ВИ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('📃Перечень ВИ для всех направлений подготовки')
        btn2 = types.KeyboardButton('📧 Форма проведения ВИ')
        btn3 = types.KeyboardButton('📉Мин.баллы по ВИ')
        btn4 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1,btn2,btn3,btn4)
        bot.send_message(message.from_user.id, 'Выберите интересующую вас информацию по вступительным испытаниям ' , reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📃Перечень ВИ для всех направлений подготовки':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        with open(file_path_vi1, 'r',encoding='utf-8') as file:
            text = file.read()
        bot.send_message(message.from_user.id,text=text, reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📧 Форма проведения ВИ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        bot.send_message(message.from_user.id, 'У вступительных испытаний есть две формы проведения:очно и дистанционно. Заполняя заявление, вы должны отразить в каком формате вам будет удобнее пройти ВИ. Если вы поступаете на бюджет, вы можете сдавать их только очно.\n\
Очно вам нужно будет придти в установленную [расписанием ВИ](https://abit.bgu-chita.ru/priem/wpo/13-priem/43-examtime) очно в институт. При выборе дистанционной формы сдачи ВИ необходимо наличие камеры,т.к потребуется показать своё лицо и фотографию из документа подтвержающего личность и весь экзамен писать под камерой\n\
Допускается сдача нескольких вступительных испытаний в один день.' ,reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📉Мин.баллы по ВИ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        with open(file_path_vi2, 'r',encoding='utf-8') as file:
            text = file.read()
        bot.send_message(message.from_user.id,text=text, reply_markup=markup, parse_mode='Markdown')

    elif message.text == '💳 Стоимость обучения':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, 'Ознакомиться со стоимостью обучения вы можете на нашем [сайте](https://abit.bgu-chita.ru/stoimost)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '💻 Образцы документов':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, 'Ознакомиться с образцами документов и бланков вы можете на нашем [сайте](https://abit.bgu-chita.ru/index.php/priem/wpo/18-priem/40) ', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📋 Списки абитуриентов':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, "Ознакомиться со списками абитуриентов вы можете по следующей [ссылке](https://abit.bgu-chita.ru/priem/wpo/13-priem/57-ablist).\nВыставите интересующий вас источник финансирования,организацию(ЧИ БГУ/Колледж),форму обучения и направление подготовки и нажмите кнопку *Показать*.\
                         \nНа сайте в таблице отразится перечень абитуриентов по заданным критериям.Абитуриенты отражаются по номеру *СНИЛС*", reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📱 Контакты':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🔙 Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, '*Контакты:*\nтел. (3022) 32-34-21\
        \nтел. 8-914-145-18-88(_Telegram,WhatsApp,Viber_)\n*e-mail*: `priem@bgu-chita.ru`\n*Мы в ВКонтакте*: https://vk.com/4itnarhoz\
        \n*Адрес*: г.Чита, ул. Анохина,56, каб. 70\n*Часы работы*:пн-пт:_9:00-17:00_,сб:_9:00-13:00_', reply_markup=markup, parse_mode='Markdown')

    #Small talk
    elif message.text == 'Привет' or message.text == 'привет':
        bot.send_message(message.from_user.id, 'Привет!')

    elif message.text == 'как дела?' or message.text == "Как дела?":
        bot.send_message(message.from_user.id, 'Хорошо!')

    elif message.text == 'Что делаешь?' or message.text == 'что делаешь?':
        bot.send_message(message.from_user.id, 'Консультирую абитуриентов!')

    elif message.text == 'Здравствуйте' or message.text == 'здравствуйте':
        bot.send_message(message.from_user.id, 'Здравствуйте,уважаемый абитуриент')

    #СПО
    if message.text == 'СПО':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton("🗒Специальности")
        btn2 = types.KeyboardButton('📰Подача документов')
        btn3 = types.KeyboardButton('📮План приёма')
        btn4 = types.KeyboardButton('💳 Стоимость обучения')
        btn5 = types.KeyboardButton('💻 Образцы документов')
        btn6 = types.KeyboardButton('📋 Списки абитуриентов')
        btn7 = types.KeyboardButton('☎Контакты')
        btn8 = types.KeyboardButton('🔙 Вернуться к выбору уровня образования')
        btn9 = types.KeyboardButton('Связаться с тех.секретарём')
        markup.add(btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9)
        bot.send_message(message.from_user.id, "👋 СПО - программы среднего профессионального образования", reply_markup=markup)
        bot.send_message(message.from_user.id, '👀 Выберите интересующий вас раздел \n\nЕсли бот не сможет ответить на интересующие вас вопросы нажмите кнопку `Связаться с тех.секретарём` и мы ответим на все ваши вопросы!',reply_markup=markup, parse_mode='Markdown')

    elif message.text == '🗒Специальности':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('ПСО')
        btn2 = types.KeyboardButton('ДОУ')
        btn3 = types.KeyboardButton('БД')
        btn4 = types.KeyboardButton('ЭиБУ')
        btn5 = types.KeyboardButton('Коммерция(по отраслям)')
        btn6 = types.KeyboardButton('Товароведение')
        btn7 = types.KeyboardButton('ИСиП')
        btn8 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8)
        bot.send_message(message.from_user.id, '⬇ Выберите интересующую вас специальность', reply_markup=markup)

    elif message.text == 'ПСО':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🗒Специальности')
        btn2 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "*Право и организация социального обеспечения*" в колледжах предназначено для студентов, которые заинтересованы в изучении правовых аспектов, связанных с организацией и управлением социальным обеспечением.\
                            \n\nПодробнее об направлении подготовки "*Право и организация социального обеспечения*" можно прочитать по [ссылке](https://college.bgu-chita.ru/specialnosti/specialnost-40-02-01-pravo-i-organizaciya-socialnogo-obespecheniya/)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ДОУ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🗒Специальности')
        btn2 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "*Документационное обеспечение управления и архивоведение*" в колледжах предназначено для студентов, которые интересуются организацией и управлением документацией в организациях, а также изучением архивоведения.\
                            \n\nПодробнее об направлении подготовки "*Документационное обеспечение управления и архивоведение*" можно прочитать по [ссылке](https://college.bgu-chita.ru/specialnosti/specialnost-46-02-01-dokumentacionnoe-obespechenie-upravleniya-i-arkhivovedenie/)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'БД':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🗒Специальности')
        btn2 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки "*Банковское дело*" в колледжах предназначено для студентов, желающих приобрести профессиональные навыки и знания, необходимые для работы в сфере банковской деятельности. Курс обучения включает изучение основных принципов и функций банков, правовых аспектов финансовых операций, анализа финансовой деятельности, управления рисками и др.\
                         Студенты также ознакамливаются с практическими аспектами работы в банке, включая клиентское обслуживание, операции с денежными средствами и кредитование. После завершения обучения выпускники могут претендовать на работу в коммерческих банках, кредитных учреждениях, финансовых компаниях и других смежных секторах экономики.\
                            \n\nПодробнее об направлении подготовки "*Банковское дело*" можно прочитать по [ссылке](https://college.bgu-chita.ru/specialnosti/specialnost-38-02-07-bankovskoe-delo/)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ЭиБУ':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🗒Специальности')
        btn2 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки в колледжах "*Экономика и бухгалтерский учет*" предназначено для студентов, желающих получить знания и навыки в области экономики, финансов, бухгалтерии и аналитики, необходимые для работы в сфере бизнеса и учета. Курс обучения включает изучение основных экономических теорий, методов бухгалтерии, анализа финансовой отчетности, налогообложения, управленческого учета и других финансово-экономических дисциплин.\
                          Студенты также осваивают принципы планирования, оценки и анализа экономической деятельности предприятий, а также нормативно-правовые аспекты бухгалтерии и налогообложения. После окончания обучения выпускники могут работать в финансовых и бухгалтерских службах компаний, аудиторских фирмах, банках, налоговых органах и в других сферах, связанных с финансово-экономической деятельностью.\
                            \n\nПодробнее об направлении подготовки "*Экономика и бухгалтерский учет *" можно прочитать по [ссылке](https://college.bgu-chita.ru/specialnosti/specialnost-38-02-01-ehkonomika-i-bukhgalterskijj-uchet/)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'Коммерция(по отраслям)':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🗒Специальности')
        btn2 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки в колледжах "*Коммерция*" предназначено для студентов, желающих получить знания и навыки в области коммерческой деятельности и бизнеса. Курсы обучения включают изучение основных принципов и методов ведения коммерческой деятельности, торговли, маркетинга, логистики, управления персоналом и других коммерческих дисциплин. Студенты также ознакамливаются с принципами организации и управления предприятиями, планированием продаж, международным бизнесом и договорными отношениями.\
                         В процессе обучения студенты получают практические навыки в области продаж, презентаций, управления проектами и командой, а также разрабатывают бизнес-планы и стратегии развития. После окончания обучения выпускники могут работать в коммерческих организациях, торговых сетях, розничной и оптовой торговле, маркетинговых и рекламных агентствах и в других сферах связанных с коммерцией.\
                            \n\nПодробнее об направлении подготовки "*Коммерция*" можно прочитать по [ссылке](https://college.bgu-chita.ru/specialnosti/specialnost-38-02-04-kommerciya-po-otraslyam/)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'Товароведение':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🗒Специальности')
        btn2 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки в колледжах "*Товароведение и экспертиза качества потребительских товаров*" предназначено для студентов, желающих приобрести знания и навыки в области исследования и оценки качества товаров, а также различных аспектов товароведения. Курс обучения включает изучение основных принципов товароведения, стандартов качества, методов оценки, контроля и сертификации товаров.\
                         Студенты также осваивают понятия и практики товарной экспертизы, которые включают анализ состава и свойств товаров, их безопасности, соответствия требованиям нормативных документов и стандартов. В процессе обучения студенты ознакамливаются с основами маркетинга, логистики, закупок и снабжения, а также изучают основы управления качеством товаров. После завершения обучения выпускники могут работать в сфере товароведения и экспертизы качества в компаниях, занимающихся производством, реализацией и контролем качества потребительских товаров, а также в органах по сертификации и стандартизации.\
                            \n\nПодробнее об направлении подготовки "*Товароведение и экспертиза качества потребительских товаров*" можно прочитать по [ссылке](https://college.bgu-chita.ru/specialnosti/specialnost-38-02-05-tovarovedenie-i-ehkspertiza-kachestva-potrebitelskikh-tovarov/)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == 'ИСиП':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('🗒Специальности')
        btn2 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2)
        bot.send_message(message.from_user.id, 'Направление подготовки в колледжах "*Информационные системы и программирование*" предназначено для студентов, желающих получить глубокие знания и навыки в области информационных технологий, программирования и разработки программного обеспечения. Курс обучения включает изучение основных языков программирования, структур данных, алгоритмов, баз данных, компьютерных сетей и других компьютерно-технических дисциплин.', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📰Подача документов':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, '*Способы подачи документов:*\n\
🚩Лично в приемную комиссию по адресу _г.Чита, ул.Анохина 56_\n\
🚩Через сайт онлайн-приёма ЧИ БГУ https://priem.bgu-chita.ru/', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📮План приёма':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('Бюджетный')
        btn2 = types.KeyboardButton('Коммерческий')
        btn3 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1,btn2,btn3)
        bot.send_message(message.from_user.id, "Выберите источник финансирования", reply_markup=markup)

    elif message.text =='Бюджетный':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        bot.send_message(message.from_user.id, 'Бюджетный набор в этом году на программы СПО не запланирован ' , reply_markup=markup)
    elif message.text=='Коммерческий':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        bot.send_message(message.from_user.id, 'Ограничений по количеству заявлений на коммерческую основу нет. Вам требуется подать заявление, заключить договор и оплатить 10% суммы в установленный срок для того чтобы быть зачисленными.' , reply_markup=markup)

    elif message.text == '💸 Стоимость обучения':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, 'Ознакомиться со стоимостью обучения вы можете на нашем [сайте](https://abit.bgu-chita.ru/stoimost)', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '🗃 Образцы документов':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, 'Ознакомиться с образцами документов и бланков вы можете на нашем [сайте](https://abit.bgu-chita.ru/index.php/priem/wpo/18-priem/40) ', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '📝 Списки абитуриентов':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, "Ознакомиться со списками абитуриентов вы можете по следующей [ссылке](https://abit.bgu-chita.ru/priem/wpo/13-priem/57-ablist).\nВыставите интересующий вас источник финансирования,организацию(ЧИ БГУ/Колледж),форму обучения и направление подготовки и нажмите кнопку *Показать*.\
                         \nНа сайте в таблице отразится перечень абитуриентов по заданным критериям.Абитуриенты отражаются по номеру *СНИЛС*", reply_markup=markup, parse_mode='Markdown')

    elif message.text == '☎Контакты':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton('⏪ Главное меню')
        markup.add(btn1)
        bot.send_message(message.from_user.id, '*Контакты:*\nтел. (3022) 32-34-21\
        \nтел. 8-914-145-18-88(_Telegram,WhatsApp,Viber_)\n*e-mail*: `priem@bgu-chita.ru`\n*Мы в ВКонтакте*: https://vk.com/4itnarhoz\
        \n*Адрес*: г.Чита, ул. Анохина,56, каб. 70\n*Часы работы*:пн-пт:_9:00-17:00_,сб:_9:00-13:00_', reply_markup=markup, parse_mode='Markdown')

    elif message.text == '⏪ Главное меню':
        markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
        btn1 = types.KeyboardButton("🗒Специальности")
        btn2 = types.KeyboardButton('📰Подача документов')
        btn3 = types.KeyboardButton('📮План приёма')
        btn4 = types.KeyboardButton('💸 Стоимость обучения')
        btn5 = types.KeyboardButton('🗃 Образцы документов')
        btn6 = types.KeyboardButton('📝 Списки абитуриентов')
        btn7 = types.KeyboardButton('☎Контакты')
        btn8 = types.KeyboardButton('🔙 Вернуться к выбору уровня образования')
        btn9 = types.KeyboardButton('Связаться с тех.секретарём')
        markup.add(btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9)
        bot.send_message(message.from_user.id, "👋 СПО - программы среднего профессионального образования", reply_markup=markup)
        bot.send_message(message.from_user.id, '👀 Выберите интересующий вас раздел \n\nЕсли бот не сможет ответить на интересующие вас вопросы нажмите кнопку `Связаться с тех.секретарём` и мы ответим на все ваши вопросы!',reply_markup=markup, parse_mode='Markdown')

bot.polling(none_stop=True, interval=0)


import math

import numpy as np
import torch
import torch.nn as nn

def get_samples(n_samples):
    x0 = np.random.random(3)-0.5
    x0 /= np.linalg.norm(x0)

    X0 = np.ndarray((n_samples, 3), dtype=np.float32)
    X1 = np.ndarray((n_samples, 3), dtype=np.float32)
    targets = np.ndarray((n_samples, ), dtype=np.float32)

    for i in range(n_samples):
        x1 = np.random.random(3)-0.5
        x1 /= np.linalg.norm(x0)

        X0[i] = x0
        X1[i] = x1

        d = math.acos(np.dot(x0, x1))
        targets[i] = d
    X0 = torch.from_numpy(X0)
    X1 = torch.from_numpy(X1)
    targets = torch.from_numpy(targets)
    return X0, X1, targets

class Model(nn.Module):

    def __init__(self):
        super().__init__()

        self.layer1 = nn.Linear(3, 64)
        self.layer2 = nn.Linear(128, 64)
        self.layer3 = nn.Linear(64, 64)
        self.layer4 = nn.Linear(64, 1)

    def forward(self, x0, x1):
        x0 = torch.relu(self.layer1(x0))
        x1 = torch.relu(self.layer1(x1))

        x = torch.cat([x0, x1], dim=1)
        x = torch.relu(self.layer2(x))
        x = torch.relu(self.layer3(x))
        x = self.layer4(x)
        return x

model = Model()
optim = torch.optim.SGD(model.parameters(), lr=0.001)

n_iters = 10000
batch_size = 64
model.train()
for i in range(n_iters):
    optim.zero_grad()
    X0, X1, targets = get_samples(batch_size)
    pred = torch.flatten(model(X0, X1))
    loss = torch.nn.functional.mse_loss(pred, targets)
    loss.backward()

    print(f'{i}: {loss.item()}')

    optim.step()


import pandas as pd
import numpy as np

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import pathlib

from typing import Union, Tuple, List, Iterable

'''defity the fuction to import, split, clean and normalize data'''
class dataTool():
    def __init__(self, trainDF_Path: str, testDF_Path: str):
        '''importing training and test sets'''
        self.train = pd.read_csv(trainDF_Path)
        self.test = pd.read_csv(testDF_Path)
    #cleaning part
    def cleaning(self):
        '''to be defined'''
        pass
    #splitting part
    def split_data(self, data: pd.DataFrame, targetVar: str, split: bool = False, testSize: float = 0.25) -> Iterable[Union[pd.DataFrame, pd.DataFrame]]:
        '''split data based on users defne paramater'''
        df = data
        x_df = df.drop(targetVar, axis=1)
        y_df = df[targetVar]

        if split:

            x_train, x_test, y_train, y_test = train_test_split(x_df, y_df, test_size=testSize)
            self.brr

            return x_train, x_test, y_train, y_test

        self.brr

        return x_df, y_df
    # normalizing part
    def normalize(self, trainData, data: List[pd.DataFrame]) -> np.array:
        '''normalize data with minmaxscaler, using train data to train model'''
        outputList = []
        scalar = MinMaxScaler()
        scalar.fit(trainData)

        for item in data:
            normalData = scalar.transform(item)
            outputList.append(normalData)

        return outputList

    def __create_directory(self, path):
        pathlib.Path(path).mkdir(parents=True, exist_ok=True)

    def write_models(self, path):
        '''
        Kaan write your code here :dogeBuff:
        and also a really quick but clear documentation for the method :dogeBuff:
        '''
        self.__create_directory(path) # the path should end with a '/' for example 'models/'
        # Here use the pickle library to "pickle" the models, the return from that is a .pkl file
        # which can then be imported and used for prediction on any platform, even webpages back code, cool huh?
        # dogeBuff
        return f'Models written, located in {path}'

    @property
    def retrieveData(self) -> Union[pd.DataFrame, pd.DataFrame]:
        self.brr

        return self.train, self.test

    @property
    def brr(self):
        print(f'Data go {"brr"}')


# -*- coding: utf-8 -*-
"""
@author:XuMing(xuming624@qq.com)
@description:
"""
import os
import sys
from codecs import open
import pickle
from sklearn.cluster import MiniBatchKMeans
from sklearn.feature_extraction.text import TfidfVectorizer
from loguru import logger

sys.path.append('..')
from pytextclassifier.tokenizer import Tokenizer

pwd_path = os.path.abspath(os.path.dirname(__file__))
default_stopwords_path = os.path.join(pwd_path, 'stopwords.txt')

class TextCluster(object):
    def __init__(
            self,
            output_dir="outputs",
            model=None, tokenizer=None, feature=None,
            stopwords_path=default_stopwords_path,
            n_clusters=3, n_init=10, ngram_range=(1, 2), **kwargs
    ):
        self.output_dir = output_dir
        self.model = model if model else MiniBatchKMeans(n_clusters=n_clusters, n_init=n_init)
        self.tokenizer = tokenizer if tokenizer else Tokenizer()
        self.feature = feature if feature else TfidfVectorizer(ngram_range=ngram_range, **kwargs)
        self.stopwords = set(self.load_list(stopwords_path)) if stopwords_path and os.path.exists(
            stopwords_path) else set()
        self.is_trained = False

    def __str__(self):
        return 'TextCluster instance ({}, {}, {})'.format(self.model, self.tokenizer, self.feature)

    @staticmethod
    def load_file_data(file_path, sep='\t', use_col=1):
        """
        Load text file, format(txt): text
        :param file_path: str
        :param sep: \t
        :param use_col: int or None
        :return: list, text list
        """
        contents = []
        if not os.path.exists(file_path):
            raise ValueError('file not found. path: {}'.format(file_path))
        with open(file_path, "r", encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if use_col:
                    contents.append(line.split(sep)[use_col])
                else:
                    contents.append(line)
        logger.info('load file done. path: {}, size: {}'.format(file_path, len(contents)))
        return contents

    @staticmethod
    def load_list(path):
        """
        加载停用词
        :param path:
        :return: list
        """
        return [word for word in open(path, 'r', encoding='utf-8').read().split()]

    @staticmethod
    def load_pkl(pkl_path):
        """
        加载词典文件
        :param pkl_path:
        :return:
        """
        with open(pkl_path, 'rb') as f:
            result = pickle.load(f)
        return result

    @staticmethod
    def save_pkl(vocab, pkl_path, overwrite=True):
        """
        存储文件
        :param pkl_path:
        :param overwrite:
        :return:
        """
        if pkl_path and os.path.exists(pkl_path) and not overwrite:
            return
        if pkl_path:
            with open(pkl_path, 'wb') as f:
                pickle.dump(vocab, f, protocol=pickle.HIGHEST_PROTOCOL)
                # pickle.dump(vocab, f, protocol=2)  # 兼容python2和python3
            print("save %s ok." % pkl_path)

    @staticmethod
    def show_plt(feature_matrix, labels, image_file='cluster.png'):
        """
        Show cluster plt
        :param feature_matrix:
        :param labels:
        :param image_file:
        :return:
        """
        from sklearn.decomposition import TruncatedSVD
        import matplotlib.pyplot as plt
        svd = TruncatedSVD()
        plot_columns = svd.fit_transform(feature_matrix)
        plt.scatter(x=plot_columns[:, 0], y=plot_columns[:, 1], c=labels)
        if image_file:
            plt.savefig(image_file)
        plt.show()

    def tokenize_sentences(self, sentences):
        """
        Encoding input text
        :param sentences: list of text, eg: [text1, text2, ...]
        :return: X_tokens
        """
        X_tokens = [' '.join([w for w in self.tokenizer.tokenize(line) if w not in self.stopwords]) for line in
                    sentences]
        return X_tokens

    def train(self, sentences):
        """
        Train model and save model
        :param sentences: list of text, eg: [text1, text2, ...]
        :return: model
        """
        logger.debug('train model')
        X_tokens = self.tokenize_sentences(sentences)
        logger.debug('data tokens top 1: {}'.format(X_tokens[:1]))
        feature = self.feature.fit_transform(X_tokens)
        # fit cluster
        self.model.fit(feature)
        labels = self.model.labels_
        logger.debug('cluster labels:{}'.format(labels))
        output_dir = self.output_dir
        if output_dir:
            os.makedirs(output_dir, exist_ok=True)
        feature_path = os.path.join(output_dir, 'cluster_feature.pkl')
        self.save_pkl(self.feature, feature_path)
        model_path = os.path.join(output_dir, 'cluster_model.pkl')
        self.save_pkl(self.model, model_path)
        logger.info('save done. feature path: {}, model path: {}'.format(feature_path, model_path))

        self.is_trained = True
        return feature, labels

    def predict(self, X):
        """
        Predict label
        :param X: list, input text list, eg: [text1, text2, ...]
        :return: list, label name
        """
        if not self.is_trained:
            raise ValueError('model is None, run train first.')
        # tokenize text
        X_tokens = self.tokenize_sentences(X)
        # transform
        feat = self.feature.transform(X_tokens)
        return self.model.predict(feat)

    def show_clusters(self, feature_matrix, labels, image_file='cluster.png'):
        """
        Show cluster plt image
        :param feature_matrix:
        :param labels:
        :param image_file:
        :return:
        """
        if not self.is_trained:
            raise ValueError('model is None, run train first.')
        self.show_plt(feature_matrix, labels, image_file)

    def load_model(self):
        """
        Load model from output_dir
        :param output_dir: path
        :return: None
        """
        model_path = os.path.join(self.output_dir, 'cluster_model.pkl')
        if not os.path.exists(model_path):
            raise ValueError("model is not found. please train and save model first.")
        self.model = self.load_pkl(model_path)
        feature_path = os.path.join(self.output_dir, 'cluster_feature.pkl')
        self.feature = self.load_pkl(feature_path)
        self.is_trained = True
        logger.info('model loaded {}'.format(self.output_dir))
        return self.is_trained

if __name__ == '__main__':
    m = TextCluster(output_dir='models/cluster', n_clusters=2)
    print(m)
    data = [
        'Student debt to cost Britain billions within decades',
        'Chinese education for TV experiment',
        'Abbott government spends $8 million on higher education',
        'Middle East and Asia boost investment in top level sports',
        'Summit Series look launches HBO Canada sports doc series: Mudhar'
    ]
    feat, labels = m.train(data)
    m.show_clusters(feat, labels, image_file='models/cluster/cluster.png')
    m.load_model()
    r = m.predict(['Abbott government spends $8 million on higher education media blitz',
                   'Middle East and Asia boost investment in top level sports'])
    print(r)

{'TruncatedSVD': 'sklearn.decomposition.TruncatedSVD', 'plt': 'matplotlib.pyplot'}


import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

def create_train_vaidate():
    data = pd.read_csv('./data/train.csv')
    data = data.sample(frac=1).reset_index(drop=True)

    labels = data['label']
    images = data[[i for i in data.columns if i != 'label']]

    images = images.values
    images = np.reshape(images, (images.shape[0], 28, 28, 1))

    train_data, valid_data, train_labels, valid_labels = train_test_split(images, labels, test_size=0.25)

    np.save('./data/train_data.pickle', train_data)
    np.save('./data/train_labels.pickle', train_labels)
    np.save('./data/valid_data.pickle', valid_data)
    np.save('./data/valid_labels.pickle', valid_labels)

if __name__ == '__main__':
    create_train_vaidate()


"""
Functions for utilization.

# Requirements
tensorflow==2.0.0a0
tensorlayer==2.0.1

"""
import os
import re

import gym
import matplotlib.pyplot as plt
import numpy as np
import tensorlayer as tl
import tensorflow as tf
from importlib import import_module

def plot(episode_rewards, algorithm_name, env_name):
    """
    plot the learning curve, saved as ./img/algorithm_name-env_name.png

    :param episode_rewards: array of floats
    :param algorithm_name: string
    :param env_name: string
    """
    path = os.path.join('.', 'img')
    name = algorithm_name + '-' + env_name
    plt.figure(figsize=(10, 5))
    plt.title(name)
    plt.plot(np.arange(len(episode_rewards)), episode_rewards)
    plt.xlabel('Episode')
    plt.ylabel('Episode Reward')
    if not os.path.exists(path):
        os.makedirs(path)
    plt.savefig(os.path.join(path, name + '.png'))
    plt.close()

def plot_save_log(episode_rewards, algorithm_name, env_name):
    """
    plot the learning curve, saved as ./img/algorithm_name-env_name.png,
    and save the rewards log as ./log/algorithm_name-env_name.npy

    :param episode_rewards: array of floats
    :param algorithm_name: string
    :param env_name: string
    """
    path = os.path.join('.', 'log')
    name = algorithm_name + '-' + env_name
    plot(episode_rewards, algorithm_name, env_name)
    if not os.path.exists(path):
        os.makedirs(path)
    np.save(os.path.join(path, name), episode_rewards)

def save_model(model, model_name, algorithm_name, env_name):
    """
    save trained neural network model

    :param model: tensorlayer.models.Model
    :param model_name: string, e.g. 'model_sac_q1'
    :param algorithm_name: string, e.g. 'SAC'
    """
    name = algorithm_name + '-' + env_name
    path = os.path.join('.', 'model', name)
    if not os.path.exists(path):
        os.makedirs(path)
    tl.files.save_npz(model.trainable_weights, os.path.join(path, model_name))

def load_model(model, model_name, algorithm_name, env_name):
    """
    load saved neural network model

    :param model: tensorlayer.models.Model
    :param model_name: string, e.g. 'model_sac_q1'
    :param algorithm_name: string, e.g. 'SAC'
    """
    name = algorithm_name + '-' + env_name
    path = os.path.join('.', 'model', name)
    try:
        param = tl.files.load_npz(path, model_name + '.npz')
        for p0, p1 in zip(model.trainable_weights, param):
            p0.assign(p1)
    except Exception as e:
        print('Load Model Fails!')
        raise e

def parse_all_args(parser):
    """ Parse known and unknown args """
    common_options, other_args = parser.parse_known_args()
    other_options = dict()
    index = 0
    n = len(other_args)
    float_pattern = re.compile(r'^[-+]?[-0-9]\d*\.\d*|[-+]?\.?[0-9]\d*$')
    while index < n:  # only str, int and float type will be parsed
        if other_args[index].startswith('--'):
            if other_args[index].__contains__('='):
                key, value = other_args[index].split('=')
                index += 1
            else:
                key, value = other_args[index:index + 2]
                index += 2
            if re.match(float_pattern, value):
                value = float(value)
                if value.is_integer():
                    value = int(value)
            other_options[key[2:]] = value
    return common_options, other_options

def make_env(env_id):
    env = gym.make(env_id).unwrapped
    """ add env wrappers here """
    return env

def get_algorithm_module(algorithm, submodule):
    """ Get algorithm module in the corresponding folder """
    return import_module('.'.join(['rlzoo', 'algorithms', algorithm, submodule]))

def call_default_params(env, envtype, alg, default_seed=True):
    """ Get the default parameters for training from the default script """
    alg = alg.lower()
    default = import_module('.'.join(['rlzoo', 'algorithms', alg, 'default']))
    params = getattr(default, envtype)(env,
                                       default_seed)  # need manually set seed in the main script if default_seed = False
    return params

def set_seed(seed, env=None):
    """ set random seed for reproduciblity """
    if isinstance(env, list):
        assert isinstance(seed, list)
        for i in range(len(env)):
            env[i].seed(seed[i])
        seed = seed[0]  # pick one seed for np and tf
    elif env is not None:
        env.seed(seed)
    np.random.seed(seed)
    tf.random.set_seed(seed)


import xml.etree.ElementTree as ET
from optparse import OptionParser

import re

PGSL_DLDATA_REQ = 1
PGSL_DLDATA_IND = 2
PGSL_ULDATA_IND = 3
PGSL_STATUS_REQ = 4

SS = "\t"

class PgslParser(object):
    def __init__(self, file, tei, tn, msg):
        self.file = file
        self.tei = tei
        self.tn = tn
        self.msg = msg

        self.MSGS = ["Not Defined", "PGSL-DLDATA-REQ", "PGSL-DLDATA-IND", "PGSL-ULDATA-IND", "PGSL-STATUS-IND",
                     "PGSL-DLDATA-RTTI-IND"]

    def parse(self):
        with open("result1.txt", "w") as output_file:
            self.parse_xml(output_file)

    def parse_xml(self, output_file):
#        tei_flag = False
        rec_time = None
        ip_dec = None
        ip_src = None
        packet_num = 0
        for event, packet in ET.iterparse(self.file):
            if packet.tag == 'packet':
                packet_num += 1
                if packet_num % 1000 == 0:
                    print("Packet number:", packet_num)

                for proto in packet.findall("proto"):
                    if proto.get("name") == 'frame':
                        for field in proto.findall('field'):
                            if field.get('name') == 'frame.time':
                                rec_time = field.get('show').split("China")[0]

                    if proto.get("name") == "ip":
                        m = re.search("(\d+\.\d+\.\d+\.\d+), Dst: (\d+\.\d+\.\d+\.\d+)", proto.get("showname"))
                        if m is not None:
                            ip_src = m.group(1)
                            ip_dec = m.group(2)

                    if proto.get("name") == "bp":
                        msg_tei = int(proto.get("showname").split("TEI:")[1])

                    if proto.get("name") == "pgsl":

                        tn = None
                        msg = None
                        frame_num = None
                        tn_map = None
                        error_cause = None
                        error_value = None
                        for field in proto.findall("field"):
                            if field.get("name") == "pgsl.msgdisc":
                                msg = int(field.get("value"))
                            if field.get("name") == "pgsl.tnres":
                                tn = int(field.get("value"))
                            if field.get("name") == "pgsl.afnd" or field.get("name") == "pgsl.afnu":
                                frame_num = int(field.get("show"))
                            if field.get("show").find("TN Bitmap") != -1:
                                tn_map = int(field.get("value"), 16)

                            if msg == PGSL_STATUS_REQ:
                                if field.get("name") == "pgsl.cause":
                                    error_cause = field.get("value")
                                if field.get("name") == "pgsl.add_info":
                                    error_value = field.get("value")

                        # if self.msg is not None and self.msg != msg:
                        #     continue
                        #
                        # if (msg == PGSL_DLDATA_IND or msg == PGSL_STATUS_REQ) and self.tn is not None and self.tn != tn:
                        #     continue

                        output = None
                        if msg == PGSL_DLDATA_REQ:
                            output = rec_time + SS + ip_src + SS + ip_dec + SS + self.MSGS[int(
                                msg)] + SS + str(msg_tei) + SS + str(tn_map) + SS + str(frame_num) + "\n"

                        elif msg == PGSL_DLDATA_IND:
                            output = rec_time + SS + ip_dec + SS + ip_src + SS + self.MSGS[int(
                                msg)] + SS + str(msg_tei) + SS + str(tn) + SS + str(
                                frame_num) + "\n"

                        elif msg == PGSL_STATUS_REQ:
                            output = rec_time + SS + ip_src + SS + ip_dec + SS + self.MSGS[int(
                                msg)] + SS + str(msg_tei) + SS + str(tn) + SS + str(
                                frame_num) + SS + error_cause + SS + error_value + "\n"

                        if output is not None:
                            output_file.write(output)
                packet.clear()

if __name__ == "__main__":
    usage = "usage: %prog [options] xml_file"
    parser = OptionParser(usage=usage)
    parser.add_option("-e", "--TEI", type="int", dest="TEI", help="filter the TEI")
    parser.add_option("-t", "--TN", type="int", dest="TN", help="filter the time slot")
    parser.add_option("-m", "--MSG", type="int", dest="MSG", help="filter PGSL message")

    (options, agrs) = parser.parse_args()

    tei = options.TEI
    tn = options.TN
    msg = options.MSG

    if len(agrs) == 1:
        xml = agrs[0]
    else:
        parser.print_help()
        exit()

    parser = PgslParser(file=xml, tei=tei, tn=tn, msg=msg)
    parser.parse()


__author__ = 'Charlie'
# Converting udacity tensorflow tutorial code such that notMNIST can be accessed with ease
#Note that the taining data set size is set to 20k - The data set has 500k in large and 20k in small
import numpy as np
import os
import sys
import tarfile
from IPython.display import display, Image
from scipy import ndimage
from six.moves.urllib.request import urlretrieve
from six.moves import cPickle as pickle

url = 'http://commondatastorage.googleapis.com/books1000/'

num_classes = 10
np.random.seed(133)

image_size = 28  # Pixel width and height.
pixel_depth = 255.0  # Number of levels per pixel.

def maybe_download(dir_path, filename, expected_bytes, force=False):
    """Download a file if not present, and make sure it's the right size."""
    file_path = os.path.join(dir_path, filename)
    if force or not os.path.exists(file_path):
        file_path, _ = urlretrieve(url + filename, file_path)
    statinfo = os.stat(file_path)
    if statinfo.st_size == expected_bytes:
        print('Found and verified', filename)
    else:
        raise Exception(
            'Failed to verify ' + filename + '. Can you get to it with a browser?')
    return filename

def maybe_extract(dir_path, filename, force=False):
    root = os.path.join(dir_path, os.path.splitext(os.path.splitext(filename)[0])[0])  # remove .tar.gz
    if os.path.isdir(root) and not force:
        # You may override by setting force=True.
        print('%s already present - Skipping extraction of %s.' % (root, filename))
    else:
        print('Extracting data for %s. This may take a while. Please wait.' % root)
        tar = tarfile.open(os.path.join(dir_path, filename))
        sys.stdout.flush()
        tar.extractall(dir_path)
        tar.close()
    data_folders = [
        os.path.join(root, d) for d in sorted(os.listdir(root))
        if os.path.isdir(os.path.join(root, d))]
    if len(data_folders) != num_classes:
        raise Exception(
            'Expected %d folders, one per class. Found %d instead.' % (
                num_classes, len(data_folders)))
    print(data_folders)
    return data_folders

def load_letter(folder, min_num_images):
    """Load the data for a single letter label."""
    image_files = os.listdir(folder)
    dataset = np.ndarray(shape=(len(image_files), image_size, image_size),
                         dtype=np.float32)
    image_index = 0
    print(folder)
    for image in os.listdir(folder):
        image_file = os.path.join(folder, image)
        try:
            image_data = (ndimage.imread(image_file).astype(float) -
                          pixel_depth / 2) / pixel_depth
            if image_data.shape != (image_size, image_size):
                raise Exception('Unexpected image shape: %s' % str(image_data.shape))
            dataset[image_index, :, :] = image_data
            image_index += 1
        except IOError as e:
            print('Could not read:', image_file, ':', e, '- it\'s ok, skipping.')

    num_images = image_index
    dataset = dataset[0:num_images, :, :]
    if num_images < min_num_images:
        raise Exception('Many fewer images than expected: %d < %d' %
                        (num_images, min_num_images))

    print('Full dataset tensor:', dataset.shape)
    print('Mean:', np.mean(dataset))
    print('Standard deviation:', np.std(dataset))
    return dataset

def maybe_pickle(data_folders, min_num_images_per_class, force=False):
    dataset_names = []
    for folder in data_folders:
        set_filename = folder + '.pickle'
        dataset_names.append(set_filename)
        if os.path.exists(set_filename) and not force:
            # You may override by setting force=True.
            print('%s already present - Skipping pickling.' % set_filename)
        else:
            print('Pickling %s.' % set_filename)
            dataset = load_letter(folder, min_num_images_per_class)
            try:
                with open(set_filename, 'wb') as f:
                    pickle.dump(dataset, f, pickle.HIGHEST_PROTOCOL)
            except Exception as e:
                print('Unable to save data to', set_filename, ':', e)

    return dataset_names

def make_arrays(nb_rows, img_size):
    if nb_rows:
        dataset = np.ndarray((nb_rows, img_size, img_size), dtype=np.float32)
        labels = np.ndarray(nb_rows, dtype=np.int32)
    else:
        dataset, labels = None, None
    return dataset, labels

def merge_datasets(pickle_files, train_size, valid_size=0):
    num_classes = len(pickle_files)
    valid_dataset, valid_labels = make_arrays(valid_size, image_size)
    train_dataset, train_labels = make_arrays(train_size, image_size)
    vsize_per_class = valid_size // num_classes
    tsize_per_class = train_size // num_classes

    start_v, start_t = 0, 0
    end_v, end_t = vsize_per_class, tsize_per_class
    end_l = vsize_per_class + tsize_per_class
    for label, pickle_file in enumerate(pickle_files):
        try:
            with open(pickle_file, 'rb') as f:
                letter_set = pickle.load(f)
                # let's shuffle the letters to have random validation and training set
                np.random.shuffle(letter_set)
                if valid_dataset is not None:
                    valid_letter = letter_set[:vsize_per_class, :, :]
                    valid_dataset[start_v:end_v, :, :] = valid_letter
                    valid_labels[start_v:end_v] = label
                    start_v += vsize_per_class
                    end_v += vsize_per_class

                train_letter = letter_set[vsize_per_class:end_l, :, :]
                train_dataset[start_t:end_t, :, :] = train_letter
                train_labels[start_t:end_t] = label
                start_t += tsize_per_class
                end_t += tsize_per_class
        except Exception as e:
            print('Unable to process data from', pickle_file, ':', e)
            raise

    return valid_dataset, valid_labels, train_dataset, train_labels

def randomize(dataset, labels):
    permutation = np.random.permutation(labels.shape[0])
    shuffled_dataset = dataset[permutation, :, :]
    shuffled_labels = labels[permutation]
    return shuffled_dataset, shuffled_labels

def reformat(dataset, labels):
    dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32)
    # Map 0 to [1.0, 0.0, 0.0 ...], 1 to [0.0, 1.0, 0.0 ...]
    labels = (np.arange(num_classes) == labels[:, None]).astype(np.float32)
    return dataset, labels

def initialize_read(data_dir):
    train_filename = maybe_download(data_dir, 'notMNIST_large.tar.gz', 247336696)
    test_filename = maybe_download(data_dir, 'notMNIST_small.tar.gz', 8458043)

    train_folders = maybe_extract(data_dir, train_filename)
    test_folders = maybe_extract(data_dir, test_filename)

    train_datasets = maybe_pickle(train_folders, 45000)
    test_datasets = maybe_pickle(test_folders, 1800)

    train_size = 200000
    valid_size = 10000
    test_size = 10000

    valid_dataset, valid_labels, train_dataset, train_labels = merge_datasets(
        train_datasets, train_size, valid_size)
    _, _, test_dataset, test_labels = merge_datasets(test_datasets, test_size)

    print('Training:', train_dataset.shape, train_labels.shape)
    print('Validation:', valid_dataset.shape, valid_labels.shape)
    print('Testing:', test_dataset.shape, test_labels.shape)

    train_dataset, train_labels = randomize(train_dataset, train_labels)
    test_dataset, test_labels = randomize(test_dataset, test_labels)
    valid_dataset, valid_labels = randomize(valid_dataset, valid_labels)

    pickle_file = os.path.join(data_dir, 'notMNIST.pickle')
    if not os.path.exists(pickle_file):
        try:
            f = open(pickle_file, 'wb')
            save = {
                'train_dataset': train_dataset,
                'train_labels': train_labels,
                'valid_dataset': valid_dataset,
                'valid_labels': valid_labels,
                'test_dataset': test_dataset,
                'test_labels': test_labels,
            }
            pickle.dump(save, f, pickle.HIGHEST_PROTOCOL)
            f.close()
        except Exception as e:
            print('Unable to save data to', pickle_file, ':', e)
            raise

    statinfo = os.stat(pickle_file)
    print('Compressed pickle size:', statinfo.st_size)

def get_notMNISTData(data_dir):
    initialize_read(data_dir)

    pickle_file = os.path.join(data_dir, 'notMNIST.pickle')

    with open(pickle_file, 'rb') as f:
        save = pickle.load(f)
        train_dataset = save['train_dataset']
        train_labels = save['train_labels']
        valid_dataset = save['valid_dataset']
        valid_labels = save['valid_labels']
        test_dataset = save['test_dataset']
        test_labels = save['test_labels']
        del save  # hint to help gc free up memory
        print('Training set', train_dataset.shape, train_labels.shape)
        print('Validation set', valid_dataset.shape, valid_labels.shape)
        print('Test set', test_dataset.shape, test_labels.shape)

    train_dataset, train_labels = reformat(train_dataset, train_labels)
    valid_dataset, valid_labels = reformat(valid_dataset, valid_labels)
    test_dataset, test_labels = reformat(test_dataset, test_labels)
    print('Training set', train_dataset.shape, train_labels.shape)
    print('Validation set', valid_dataset.shape, valid_labels.shape)
    print('Test set', test_dataset.shape, test_labels.shape)

    return train_dataset, train_labels, valid_dataset, valid_labels, test_dataset, test_labels


import numpy as np
import scipy.ndimage as nd
from sklearn.base import BaseEstimator
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.dummy import DummyClassifier

class SegmentationClassifier(BaseEstimator):
    def __init__(self):
        #self.clf = RandomForestClassifier(n_estimators=3, max_depth=10)
        self.clf = DummyClassifier(strategy="constant", constant=0)
        #self.shift = 2 # how many neighbours are taken for calculating features

    def _get_features(self, X):
        # very slow
        n_img, n_h, n_w, n_d = X.shape
        n_features = 2
        x_features = np.zeros((n_img, n_h, n_w, n_d, n_features))
        for img_no in range(n_img):
            for h in range(self.shift,n_h-self.shift):
                for w in range(self.shift,n_w-self.shift):
                    for d in range(self.shift,n_d-self.shift):
                        # calculate features: mean and std of all neighbouring voxels
                        cube = X[img_no,h-self.shift:h+self.shift,w-self.shift:w+self.shift,d-self.shift:d+self.shift]

                        x_features[img_no,h,w,d,:] = (cube.mean(), np.std(cube))
        x_features = x_features.reshape(n_img * n_h * n_w * n_d, n_features)

        return x_features

    def _get_features_scipy(self, X):

        n_features = 1
        n_img, n_h, n_w, n_d = X.shape

        x_features = np.zeros((n_img, n_h, n_w, n_d, n_features))
        # for every patient separately
        for img_no in range(n_img):
            # calculate gaussian filter
            x_features[img_no,:,:,:,0] = nd.gaussian_filter(X[img_no,:,:,:],sigma=5)

            # calculate uniform filter
            #x_features[img_no,:,:,:,1] = nd.uniform_filter(X[img_no,:,:,:])

        x_features = x_features.reshape(n_img * n_h * n_w * n_d, n_features)
        return x_features

    def _get_features_strided(self, X):

        # cut the borders
        n_img, n_h, n_w, n_d = X.shape
        n_features = 2
        new_shape = (n_img, n_h - (2 * self.shift), n_w - (2 * self.shift), n_d - (2 * self.shift),
                     (2 * self.shift), 2 * self.shift, 2 * self.shift)
        new_strides = X.strides + X.strides[1:]
        X_cube = np.lib.stride_tricks.as_strided(X, shape=new_shape, strides=new_strides, writeable = False)

        #  FIXME: produces nans
        #  calculate feature: STD avoiding creation of large temporary arrays
        Xsq_cube = np.lib.stride_tricks.as_strided(X * X, new_shape, new_strides)

        # calculate feature: means
        X_means = np.mean(X_cube, axis=(4, 5, 6))
        Xsq_means = np.mean(Xsq_cube, axis=(4, 5, 6))
        X_stds = np.sqrt(Xsq_means - X_means * X_means)

        # get voxel value
        #voxel = np.reshape(X, new_shape[:4])

        X_features = np.stack([X_means, voxel], axis=4).reshape(n_img * (n_h - 2 * self.shift) * (n_w - 2 * self.shift)  * (n_d - 2 * self.shift), n_features)

        return X_features

    def _unpack_y(self, y, cut_bordering_pixels=False):
        # return y flattened and sparse matrices unpacked
        n_img, n_h = y.shape
        n_w, n_d = y[0][0].shape

        if cut_bordering_pixels:
            # cut out the bordering voxels (if you want to use it with strided function)
            new_h = n_h - (2 * self.shift)
            new_w = n_w - (2 * self.shift)
            new_d = n_d - (2 * self.shift)
            y_new = np.zeros((n_img,new_h, new_w, new_d))

            for img_no in range(n_img):
                for h in range(new_h):
                    y_new[img_no, h, :, :] = y[img_no, h].todense()[self.shift:-self.shift,self.shift:-self.shift]
                    y_new = y_new.reshape(n_img * new_h * new_w * new_d)
        else:
            y_new = np.zeros((n_img,n_h, n_w, n_d))

            for img_no in range(n_img):
                for h in range(n_h):
                    y_new[img_no, h, :, :] = y[img_no, h].todense()
            y_new = y_new.reshape(n_img * n_h * n_w * n_d)
        return y_new

    def fit(self, X, y):
        # takes image ravels it and returns 1s where there are maxs
        return self

    def predict(self, X):
        # X_features = self._get_features_scipy(X)
        #X = X.ravel()[:, np.newaxis]

        #return self.clf.predict(X)
        # takes image ravels it and returns 1s where there are maxs
        #X = X.ravel() #[:, np.newaxis]
        thres = np.max(X)
        X[X < thres] = 0
        X[X == thres] = 1
        return X.astype(np.uint8)

    def predict_proba(self, X):
        # X_features = self._get_features_scipy(X)
        X = X.ravel()[:, np.newaxis]
        y_pred = self.clf.predict_proba(X)
        print(y_pred)

        return np.hstack([y_pred, 1 - y_pred])


import json

import pandas as pd
from fastapi import UploadFile, HTTPException, status

def get_list_current_names(list_names: list[str]) -> list[str]:
    result_list = []
    for i in list_names:
        names = i
        if i.find(';') != -1:
            names = names.replace(',', '')
            names = names.replace(';', ',')
        result_list.append(names)
    return result_list

async def service_view_data_from_file(file: UploadFile):
    df = pd.read_excel(file.file.read())
    cols_name = (
        'title',
        'source',
        'authors',
        'publication date',
        'link',
        'document type',
    )
    df_cols = list(df.columns)
    for i in cols_name:
        if i not in df_cols:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Столбик {i} не найден")
    get_authors = df['authors'].to_list()
    df.drop(columns=['authors'], axis=1)
    df['authors'] = get_list_current_names(get_authors)
    df.rename(columns={'publication date': 'publication_date', 'document type': 'document_type'}, inplace=True)
    json_result = json.loads(df.to_json(orient="table", index=False))
    return json.dumps(json_result, indent=4)


import sys
from collections import deque
T = int(sys.stdin.readline())
for _ in range(T):
    N, M = map(int, sys.stdin.readline().split())
    cnts = [0]*9
    documents = deque([])
    for i, importance in enumerate(sys.stdin.readline().split()):
        documents.append((i, int(importance)))
        cnts[documents[-1][-1]-1] += 1
    cnt = 0
    while True:
        document = documents.popleft()
        for i in range(document[-1], 9):
            if cnts[i]:
                documents.append(document)
                break
        else:
            cnt += 1
            cnts[document[-1]-1] -= 1
            if document[0] == M:
                print(cnt)
                break


import numpy as np
import matplotlib.pyplot as plt

r_values = np.linspace(0.2, 4, num=100000)
points_y = []
points_r = []
for r in r_values:
    x = 0.4
    for i in range(50):
        y = r*x*(1-x)
        if i >= 40:
            points_r.append(r)
            points_y.append(y)
        x = y
fig, ax = plt.subplots(figsize=(17, 10))
ax.scatter(points_r, points_y, alpha=0.07, edgecolors='none', s=21,
           marker='.', color='#4da4eb', label=r'$x_{n+1} = r x_n(1-x_n)$')
ax.grid(True)
ax.set_facecolor("#f5f5f5")
ax.set_xlabel("r", fontsize="xx-large")
ax.set_ylabel("x", fontsize="xx-large")
ax.set_title("Bifurcation Diagram of Logistic Map", fontsize="xx-large")
ax.legend(loc='upper left', fontsize='xx-large')


import pandas as pd
import pytest

import awkward_pandas

def test_len():
    s = pd.Series(awkward_pandas.AwkwardExtensionArray([[6, 2, 3], [4, 5]]))
    assert s.ak.count() == 5
    s2 = s.ak.count(axis=1)
    assert s2.tolist() == [3, 2]

def test_no_access():
    s = pd.Series([1, 2])
    with pytest.raises(Exception):
        s.ak.count()

def test_getitem():
    s = pd.Series(awkward_pandas.AwkwardExtensionArray([[6, 2, 3], [4, 5]]))
    s2 = s.ak[:, :1]
    assert isinstance(s2, pd.Series)
    assert s2.dtype == "awkward"
    assert s2.tolist() == [[6], [4]]

def test_to_column():
    s = pd.Series(awkward_pandas.AwkwardExtensionArray([6, 2, 3]), name="test")
    s2 = s.ak.to_column()
    assert s2.dtype == "int64"

    s = pd.Series(awkward_pandas.AwkwardExtensionArray(["6", "2", "3"]), name="test")
    s2 = s.ak.to_column()
    assert s2.dtype == "string[pyarrow]"

    s = pd.Series(awkward_pandas.AwkwardExtensionArray([["6", "2", "3"]]), name="test")
    with pytest.raises(ValueError):
        s.ak.to_column()

def test_to_columns():
    s = pd.Series(
        awkward_pandas.AwkwardExtensionArray(
            {"num": [6, 2, 3], "deep": [[0], [], None], "text": ["hi", "ho", "hum"]}
        ),
        name="test",
    )
    df = s.ak.to_columns()
    assert df.columns.tolist() == ["num", "text", "test"]
    assert df.num.tolist() == [6, 2, 3]
    assert df.test.tolist() == [{"deep": [0]}, {"deep": []}, {"deep": None}]
    assert df.text.tolist() == ["hi", "ho", "hum"]

    df = s.ak.to_columns(cull=False)
    assert df.columns.tolist() == ["num", "text", "test"]
    assert df.num.tolist() == [6, 2, 3]
    assert df.test[0].tolist() == {"num": 6, "deep": [0], "text": "hi"}
    assert df.text.tolist() == ["hi", "ho", "hum"]

def test_dir():
    s = pd.Series(awkward_pandas.AwkwardExtensionArray([6, 2, 3]), name="test")
    assert "sum" in dir(s.ak)
    assert "Array" not in dir(s.ak)
    assert "ak_num" not in dir(s.ak)
    assert "_util" not in dir(s.ak)


from itertools import izip_longest

from flask import url_for, request

from flask_cms.page.models import Page
from flask.ext.security import current_user

def get_breadcrumbs(page, breadcrumbs=None):
    if not breadcrumbs:
        breadcrumbs = []

    breadcrumbs.append(page.slug)
    if page.parent is None:
        breadcrumbs.reverse()
        return breadcrumbs
    breadcrumbs = get_breadcrumbs(page.parent, breadcrumbs)
    return breadcrumbs

def create_breadcrumbs_snippet():
    def add_breadcrumbs_snippet(page):
        snippet = ''
        breadcrumbs = get_breadcrumbs(page)
        if not breadcrumbs:
            return snippet
        snippet = "
"
        for breadcrumb in breadcrumbs:
            snippet += '
{camelized_slug}
'. \
                format(url=url_for('page.show', slug=breadcrumb),
                       camelized_slug=breadcrumb.title())
        snippet += '
'
        return snippet

    return dict(add_breadcrumbs_snippet=add_breadcrumbs_snippet)

def add_grouper():
    def grouper(iterable, n, fillvalue=None):
        "Collect data into fixed-length chunks or blocks"
        # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
        args = [iter(iterable)] * n
        return izip_longest(fillvalue=fillvalue, *args)

    return dict(grouper=grouper)

def add_navbar():
    def navbar():
        snippet = '
'
        if current_user.is_authenticated:
            pages_to_show = Page.query.filter_by(publish=True, show_in_nav=True, level=0)
        else:
            pages_to_show = Page.query.filter_by(publish=True, show_in_nav=True, level=0, login_required=False)

        for page in pages_to_show:
            if page.children.all():
                snippet += '
'
                snippet += '''
                {title}'''. \
                    format(title=page.title.title())
                snippet += '
'
                for child in page.children:
                    snippet += '
{title}
'. \
                        format(url=url_for("page.show", slug=child.slug),
                               title=child.title.title(), )
                snippet += '

'
            else:
                css_class = ""
                if request.path.split("/")[-1] == page.slug:
                    css_class = 'class="active"'
                snippet += '
{title}
'. \
                    format(css_class=css_class,
                           url=url_for("page.show", slug=page.slug),
                           title=page.title.title())
        snippet += '
'
        return snippet

    return dict(navbar=navbar)

def add_flash_form_errors():
    def flash_form_errors(form):
        snippet = ""
        for field, errors in form.errors.items():
            for error in errors:
                snippet += '
'
                snippet += ''
                snippet += '{}
'.format(error)
        return snippet

    return dict(flash_form_errors=flash_form_errors)


from loguru import logger
import select
import utils.base as base
from conf.conf import *
from queue import Queue
import socket
import threading

class IOWorker:
    def __init__(self, inq, outq, buffers, lock):
        logger.debug("init server socket")
        self.m_sock = base.init_server_socket()
        self.epoll = select.epoll()
        self.m_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
        self.epoll.register(self.m_sock.fileno(), select.EPOLLIN | select.EPOLLET)
        self.conns = {}
        self.inq = inq  # 入包
        self.outq = outq  # 出包
        self.buffers = buffers  # 用于处理粘包
        self.lock = lock

    def run(self):
        while True:
            epoll_lst = self.epoll.poll()
            for fd, ev in epoll_lst:
                logger.debug(f"e: {ev}, con {len(self.conns)}, 'inq/ouq' {len(self.inq)}/{len(self.outq)}")
                if fd == self.m_sock.fileno():
                    self.on_connect()
                elif ev & select.EPOLLOUT:
                    self.on_write(fd)
                elif ev & select.EPOLLIN:
                    self.on_read(fd)
                else:
                    self.on_close(fd)

    def on_connect(self):
        try:
            while True:
                conn, addr = self.m_sock.accept()
                conn.setblocking(0)
                self.epoll.register(conn.fileno(), select.EPOLLIN | select.EPOLLET)
                self.conns[conn.fileno()] = conn

                logger.debug(f"new connect {conn.getpeername()}")
                with self.lock:
                    self.inq[conn.fileno()] = bytearray()
                    self.outq[conn.fileno()] = bytearray()
                    self.buffers[conn.fileno()] = bytearray()
        except socket.error:
            pass

    def on_read(self, fd):
        logger.debug(f"new epoll in")
        conn = self.conns[fd]
        try:
            data = conn.recv(1024)
            if not len(data):
                self.on_close(fd)
                return
            while True:
                data += conn.recv(1024)
        except socket.error:
            pass
        logger.debug(f"read data {data}")
        msgs = data.split(DELIM)
        if len(msgs) == 0:  # 当前包不构成完整消息，与buffer拼接
            self.buffers[fd] = self.buffers[fd] + bytearray(data)
        else:
            for idx, msg in enumerate(msgs):
                if len(msg):
                    last = self.buffers.get(fd, bytearray())
                    if idx < len(msgs):  # 后面还有说明本段构成了完整消息
                        self.inq[fd] = last + bytearray(msg) + DELIM
                        self.buffers[fd] = bytearray()
                    else:
                        self.buffers[fd] = bytearray(msg)
        self.epoll.modify(fd, select.EPOLLOUT | select.EPOLLET)

    def on_write(self, fd):
        data = memoryview(self.outq[fd])
        if not len(self.outq[fd]):
            logger.debug("出包为空")
            self.epoll.modify(fd, select.EPOLLOUT | select.EPOLLET)
            return
        try:
            while len(data) > 0:
                cnt = self.conns[fd].send(data)
                data = data[cnt:]
        except socket.error:
            pass
        # self.conns[fd].sendall(self.outq[fd])
        # self.epoll.modify(fd, select.EPOLLIN | select.EPOLLET)
        self.on_close(fd)

    def on_close(self, fd): # todo 超时控制 用堆？链表？map？
        self.conns[fd].shutdown(socket.SHUT_RDWR)
        self.epoll.unregister(fd)
        self.conns[fd].close()
        del self.conns[fd]
        with self.lock:
            try:
                del self.outq[fd]
                del self.buffers[fd]
            except:
                pass


import numpy as np
import matplotlib.pyplot as plt
import warnings
#warnings.filterwarnings("error")

"""
Solves equations for a (rotating) relativistic star, as based on the method described on page 51 of 'An introduction to the theory of rotating relativistic stars', Gourgoulhon 2010

Going to do axisymmetric, non-rotating first but leave some doors open
to eventually include rotation
"""

from functools import partial

def polytropic_eos(H, gamma=5./3., K=1.e3):
    eps = np.zeros_like(H)
    p = np.zeros_like(H)
    rho = np.zeros_like(H)

    eps[H > 0.] = (np.exp(H[H > 0.]) - 1.0) / gamma
    p[H > 0.] = (gamma * K**(1./gamma) / ((gamma-1.)*(np.exp(H[H > 0.])-1.))) ** (gamma/(gamma+1.))
    rho[H > 0.] = (p[H > 0.]/K)**(1./gamma)

    return eps, p, rho

class Star(object):

    def __init__(self, Hc, Omega, R, eos=None, theta=0.5*np.pi, n=1e4, nIts=100):
        r"""
        Parameters
        ----------
        Hc:     scalar
            central log enthalpy
        Omega:  scalar
            constant angular velocity
        R:      scalar
            guess for radius of final model
        theta:  scalar
            theta at which want to calculate star's profile
        n:      integer
            number of grid points
        nIts:   integer
            number of iterations
        """
        n = int(n)
        self.n = n
        self.Hc = Hc
        self.Omega = Omega
        self.theta = theta
        self.nIts = nIts

        self.R = R

        self.r = np.linspace(0.0, 2.5*R, num=n)
        self.dr = self.r[1] - self.r[0]

        # metric functions
        self.N = np.ones(n)
        self.omega = np.zeros(n)
        self.A = np.ones(n)
        self.B = np.ones(n)

        # thermo variables
        self.U = np.zeros(n)
        self.W = np.zeros(n)
        self.H = Hc * (1. - self.r**2/R**2)

        self.H[self.H < 0.] = 0.
        self.eps = np.zeros(n)
        self.p = np.zeros(n)

        # matter sources
        self.E = np.zeros(n)
        self.p_phi = np.zeros(n)
        self.S_rr = np.zeros(n)
        self.S_thth = np.zeros(n)
        self.S_phiphi = np.zeros(n)
        self.S = np.zeros(n)

        if eos is None:
            self.eos = self.default_eos
        else:
            self.eos = eos

        self.eps, self.p, _ = self.eos(self.H)

    @staticmethod
    def default_eos(H, gamma=5./3., K=1.e3):
        eps = np.zeros_like(H)
        p = np.zeros_like(H)
        rho = np.zeros_like(H)

        eps[H > 0.] = (np.exp(H[H > 0.]) - 1.0) / gamma
        p[H > 0.] = (gamma * K**(1./gamma) / ((gamma-1.)*(np.exp(H[H > 0.])-1.))) ** (gamma/(gamma+1.))
        rho[H > 0.] = (p[H > 0.]/K)**(1./gamma)

        return eps, p, rho

    def evolve_star(self):
        """
        Evolves star's solution through a single iteration
        """
        np.set_printoptions(threshold=np.nan)

        # calculate eos

        self.eps, self.p, _ = self.eos(self.H)

        # compute matter sources

        self.E = self.W**2 * (self.eps + self.p) - self.p
        self.p_phi = self.B * (self.E + self.p) * self.U * self.r * np.sin(self.theta)
        self.S_rr = self.p
        self.S_thth = self.p
        self.S_phiphi = self.p + (self.E + self.p) * self.U**2
        self.S = 3. * self.p + (self.E + self.p) * self.U**2

        # solve the Einstein equations

        nu = np.log(self.N)
        new_nu = np.log(self.N)

        del2omega = np.zeros(self.n)
        del2omega[1:-1] = 0.25 * (self.omega[2:] - self.omega[:-2])**2 / self.dr**2

        delnu_delnuB = np.zeros(self.n)
        try:
            delnu_delnuB[1:-1] = 0.25 * (nu[2:] - nu[:-2]) * (nu[2:] + np.log(self.B[2:]) - nu[:-2] - np.log(self.B[:-2])) / self.dr**2
        except RuntimeWarning:
            print('B: {}'.format(self.B[1:-1]))

        del3_nu = 4. * np.pi * self.A**2 * (self.E + self.S) + 0.5 * self.B**2 * self.r**2 * np.sin(self.theta)**2 * del2omega / self.N**2 - delnu_delnuB

        new_nu[1:-1] = 0.5 * (nu[2:] + nu[:-2] + self.dr * (nu[2:] - nu[:-2])/self.r[1:-1] - self.dr**2 * del3_nu[1:-1])

        delom_delnu3B = np.zeros(self.n)
        delom_delnu3B[1:-1] = 0.25 * (self.omega[2:] - self.omega[:-2]) * (nu[2:] - 3.*np.log(self.B[2:]) - nu[:-2] + 3.*np.log(self.B[:-2])) / self.dr**2

        del3_wrsin = np.zeros(self.n)
        del3_wrsin[1:-1] = -16 * np.pi * self.N[1:-1] * self.A[1:-1]**2 * self.p_phi[1:-1] / (self.B[1:-1]**2 * self.r[1:-1] * np.sin(self.theta)) + self.r[1:-1] * np.sin(self.theta) * delom_delnu3B[1:-1]

        omegarsin = self.omega * self.r * np.sin(self.theta)

        omegarsin[1:-1] = ((omegarsin[2:] + omegarsin[:-2])/self.dr**2 + (omegarsin[2:] - omegarsin[:-2]) / (self.r[1:-1] * self.dr) - del3_wrsin[1:-1]) / (2. / self.dr**2 + 1./(self.r[1:-1] * np.sin(self.theta))**2)

        NBrsin = (self.N * self.B - 1.) * self.r * np.sin(self.theta)

        del2NB = 8. * np.pi * self.N * self.A**2 * self.B * self.r * np.sin(self.theta) * (self.S_rr + self.S_thth)

        NBrsin[1:-1] = 0.5 * (NBrsin[2:] + NBrsin[:-2] + self.dr * 0.5 * (NBrsin[2:] - NBrsin[:-2]) / self.r[1:-1] - self.dr**2 * del2NB[1:-1])

        try:
            lnAnu = np.log(self.A + nu)
        except RuntimeWarning:
            #print('A + nu: {}'.format(self.A + nu))
            lnAnu = np.log(abs(self.A + nu))

        del2nu = np.zeros(self.n)
        del2nu[1:-1] = 0.25 * (nu[2:] - nu[:-2])**2 / self.dr**2

        del2lnAnu = 8. * np.pi * self.A**2 * self.S_phiphi + 0.25 * 3. * self.B**2 * self.r**2 * np.sin(self.theta)**2 * del2omega / self.N**2 - del2nu

        lnAnu[1:-1] = 0.5 * (lnAnu[2:] + lnAnu[:-2] + self.dr * 0.5 * (lnAnu[2:] - lnAnu[:-2]) / self.r[1:-1] - self.dr**2 * del2lnAnu[1:-1])

        # change back to variables we actually want

        self.N[1:-1] = np.exp(new_nu[1:-1])
        self.omega[1:-1] = omegarsin[1:-1] / (self.r[1:-1] * np.sin(self.theta))
        try:
            self.B[1:-1] = (NBrsin[1:-1] / (self.r[1:-1] * np.sin(self.theta)) + 1.) / self.N[1:-1]
        except RuntimeWarning:
            self.N[self.N < 1.e-15] = 1.e-15
            self.B[1:-1] = (NBrsin[1:-1] / (self.r[1:-1] * np.sin(self.theta)) + 1.) / self.N[1:-1]
            #print('N: {}'.format(self.N[1:-1]))

        try:
            self.A[1:-1] = np.exp(lnAnu[1:-1] - new_nu[1:-1])
        except RuntimeWarning:
            #print('lnA - nu: {}'.format(lnAnu[1:-1] - new_nu[1:-1]))
            self.A[1:-1] = np.exp(np.minimum((lnAnu[1:-1] - new_nu[1:-1]), 10.))

        # enforce some outflow boundary conditions for the last data point

        self.N[0] = self.N[1]
        self.omega[0] = self.omega[1]
        self.B[0] = self.B[1]
        self.A[0] = self.A[1]
        new_nu[0] = new_nu[1]

        self.N[-1] = self.N[-2]
        self.omega[-1] = self.omega[-2]
        self.B[-1] = self.B[-2]
        self.A[-1] = self.A[-2]
        new_nu[-1] = new_nu[-2]

        # make sure B is positive
        self.B[self.B < 0.] = abs(self.B[self.B < 0.])

        #print(self.B)

        # find new velocity field

        self.U = (self.Omega - self.omega) * self.r * np.sin(self.theta) * self.B / self.N

        try:
            self.W = 1. / np.sqrt(1. - self.U**2)
        except RuntimeWarning:
            # if U is too big, set it to 0.9
            self.U[self.U > 1.] = 0.9
            self.U[self.U < -1.] = -0.9
            self.W = 1. / np.sqrt(1. - self.U**2)

        self.H = self.Hc + np.log(self.N[0]) - new_nu + np.log(self.W)

        # find the edge of the star and set H to zero there

        self.H[self.H - self.Hc <= 0.] = 0.0
        self.H[0] = self.Hc
        self.H[self.H > 10.] = 10.

    def make_star(self):
        """
        evolves star through self.nIts iterations
        """

        for i in range(int(self.nIts)):
            #print('Step {}'.format(i))
            self.evolve_star()

    def evolve_tov(self, K=1., gamma=5./3.):
        """
        Finds tov solution
        """

        # calculate eos

        nu = np.log(self.N)
        new_nu = np.log(self.N)

        m = np.zeros(self.n)
        m[1:-1] = 2. * np.pi * (self.r[2:]**2 * self.eps[2:] - self.r[:-2]**2 * self.eps[:-2]) / self.dr
        m[-1] = m[-2]

        dnu_dr = (m / self.r**2 + 4. * np.pi * self.r * self.p) / (1. - 2. * m / self.r)

        new_nu[1:-1] = 0.5 * (dnu_dr[2:] - dnu_dr[:-2]) / self.dr

        self.p[1:-1] = -0.5 * ((self.eps[2:] + self.p[2:]) * dnu_dr[2:] - (self.eps[:-2] + self.p[:-2]) * dnu_dr[:-2]) / self.dr
        self.p[-1] = self.p[-2]

        self.N[1:-1] = np.exp(new_nu[1:-1])
        self.N[-1] = self.N[-2]

        self.eps = p**((gamma-1.)/gamma) / ((gamma-1.) * K**(-1./gamma))

    def make_tov(self, K=1., gamma=5./3.):
        """
        Evolve tov solution
        """
        for i in range(int(self.nIts)):
            #print('Step {}'.format(i))
            self.evolve_star()

        self.H[:] = 0.
        self.H[self.p > 0.] = np.exp(1. + gamma / (self.p[self.p > 0.]**(1.-1./gamma) * K**(-1./gamma) * (gamma-1.)))

    def plot_star(self):
        """
        Plots H, p and N against radius
        """
        self.eps, self.p, rho = self.eos(self.H)

        # calculate mass
        # find cell-centred densities
        av_rho = np.zeros_like(rho)
        av_rho[:-1] = 0.5 * (rho[:-1] + rho[1:])
        M = np.zeros_like(rho)
        for i in range(int(self.n)-1):
            M[i] = 4. * np.pi * np.sum((self.r[1:i+2]**3 - self.r[:i+1]**3) * av_rho[:i+1]) / 3.
        M[-1] = M[-2]

        # normalise everything
        H = self.H / max(self.H[1:])
        p = self.p / max(self.p[1:])
        N = self.N / max(self.N[1:])
        M = M / max(M[1:])
        B = self.B / max(self.B[1:])
        A = self.A / max(self.A[1:])

        plt.clf()
        plt.rc("font", size=15)
        ax = plt.subplot(111)
        lines = ax.plot(self.r, H, '--', self.r, B, ':', self.r, A, '--', self.r, M, '-.')
        plt.setp(lines, linewidth=2)
        box = ax.get_position()
        ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
        lgd = plt.legend([r'$H$', r'$B$', r'$A$', r'$M$'], loc='center left', bbox_to_anchor=(1, 0.5))
        plt.xlabel(r'$r$')
        plt.ylim([0., 1.1])
        plt.xlim([0., self.r[-1]])
        plt.show()

if __name__ == "__main__":

    Hc = 0.2262
    Omega = 0.0
    R = 7.e-4
    gamma = 8./3.0
    K = 1.e-5

    eos_star = partial(polytropic_eos, gamma=gamma, K=K)

    star = Star(Hc, Omega, R, eos=eos_star, nIts=1e3)
    star.make_star()
    star.plot_star()

    tov_star = Star(Hc, Omega, R, eos=eos_star, nIts=1e3)
    tov_star.make_tov(K=K, gamma=gamma)
    tov_star.plot_star()


from flask import request, jsonify, Response
from werkzeug.utils import secure_filename

from pathlib import Path
from datetime import datetime
from nonrepeat import nonrepeat_filename
import shutil

from . import app

filename = None

@app.route('/api/images/create', methods=['POST'])
def create_image():
    global filename

    if 'file' in request.files:
        image_path = Path(request.form.get('imagePath'))
        if image_path.suffix:
            image_path = image_path.parent
        image_path.mkdir(parents=True, exist_ok=True)

        file = request.files['file']
        filename = str(image_path.joinpath(secure_filename(file.filename)))
        filename = nonrepeat_filename(filename,
                                      primary_suffix=datetime.now().isoformat()[:10])
        file.save(filename)

        return jsonify({
            'filename': filename
        }), 201

    return Response(status=304)

@app.route('/api/images/rename', methods=['POST'])
def rename_image():
    global filename

    if filename is not None:
        new_filename = Path(request.get_json()['filename']).with_suffix(Path(filename).suffix)
        new_filename.parent.mkdir(parents=True, exist_ok=True)

        new_filename = new_filename.with_name(secure_filename(new_filename.name))
        new_filename = nonrepeat_filename(str(new_filename))

        shutil.move(filename, new_filename)
        filename = new_filename

        return jsonify({
            'filename': filename
        }), 201

    return Response(status=304)


from typing import List

from pydantic import parse_obj_as

from app.repository.residential_repo import get_handbooks_by_block_house_ids, get_handbook_detail
from app.schemas import Handbook, HandbookDetail
from app.utilities.common import get_data_image
from app.utilities.pagination import parsing_pagination, get_paging_config
from configs import get_settings

async def get_list(db, request, house):
    try:
        paging_config = get_paging_config(request)
        data, total = await get_handbooks_by_block_house_ids(
            db=db,
            house=house,
            paging=paging_config
        )
        data = parse_obj_as(List[Handbook], data)
        data = get_data_image(data, 'tb_resident_handbook')
        return parsing_pagination(data, total, request)
    except Exception as e:
        return e

async def get_detail(db, handbook_id):
    try:
        data = await get_handbook_detail(db, handbook_id)
        data = HandbookDetail.from_orm(data)
        data.image = f"{get_settings().residential_server_url}/web/image?model=tb_resident_handbook&id={data.id}&field=image"
        return data
    except Exception as e:
        return e