# -*- coding: utf-8 -*-
"""
Created on Fri Nov 24 12:52:26 2017

@author: eh94
"""

from bokeh.layouts import layout
from bokeh.models import PanTool, ResetTool, WheelZoomTool, SaveTool, TapTool, ColumnDataSource, Label
from bokeh.models.widgets import DataTable, TableColumn, Button, TextInput
from bokeh.plotting import figure
from bokeh.io import curdoc
from bokeh.models.callbacks import CustomJS
import numpy as np
from numpy import exp, log10, log, sin, sinh, sinc, cos, cosh, tan, tanh
from scipy import optimize
import pandas as pd

#initialize source data
filepath='data.xlsx'
filetype=filepath.split('.')[1]
if filetype=='csv':
    data=pd.read_csv(filepath, sep=';')
elif filetype in ['xlsx', 'xslm', 'xls', 'xlsb', 'xlt']:
    data=pd.read_excel(filepath, sep=';')
else:
    print('*.{} is invalid filetype!'.format(filetype))
columns = data.columns
source = ColumnDataSource(data=dict(x=data[columns[0]], y=data[columns[1]]))
table_source=ColumnDataSource(data=data)

#create add_button callback
def add_row():
    new_data=dict(x=[0.0], y=[0.0])
    source.stream(new_data)

#create del_button callback
def del_row():
    new_data=source.data[:-1]
    source.data=new_data

#create fit function
def fit_data():
    #define the fit function
    func=lambda x,a,b,c,d,e: eval(model_text_input.value)

    #get indices of selected data points
    indices=source.selected['1d']['indices']
    indices.sort()

    if not indices:
        x=np.array(source.data['x'])
        y=np.array(source.data['y'])
    else:
        #get x and y values of selected data points
        x=np.array([source.data['x'][index] for index in indices])
        y=np.array([source.data['y'][index] for index in indices])

    #fit the selected data points to predefined function
    parameter, variance = optimize.curve_fit(func, x, y)

    #plot the fit
    fig.line(x=source.data['x'], y=func(source.data['x'],*parameter), line_width=3, line_color='firebrick', line_alpha=1)

    parameter_text_input.value=str(parameter)
    #illustrate the parameter in textboxes
#    amplitude=Label(x=20, y=300, x_units='screen', y_units='screen', text='Amp.: {:.2f}'.format(parameter[0]), text_font_style='bold')
#    mean=Label(x=20, y=280, x_units='screen', y_units='screen', text='Mean: {:.2f}'.format(parameter[1]), text_font_style='bold')
#    std=Label(x=20, y=260, x_units='screen', y_units='screen', text='Std. Dev.: {:.2f}'.format(parameter[2]), text_font_style='bold')
#    fig.add_layout(amplitude)
#    fig.add_layout(mean)
#    fig.add_layout(std)

#create update function
def update():
    return

#create table widget
table_columns = [TableColumn(field=column, title=column) for column in columns]
table = DataTable(source=table_source, columns=table_columns, editable=True, width=400, height=600)

#create figure
fig = figure(tools=[PanTool(), WheelZoomTool(), ResetTool(), SaveTool(), TapTool()],output_backend='webgl')
fig.plot_width = 900
fig.plot_height = 600
fig.toolbar.logo = None

#style axis
fig.axis.minor_tick_line_color='black'
fig.axis.minor_tick_in=-6
fig.xaxis.axis_label=columns[0]
fig.yaxis.axis_label=columns[1]
fig.axis.axis_label_text_color=(0.7,0.7,0.7)
fig.axis.major_label_text_color=(0.7,0.7,0.7)
fig.axis.axis_label_text_font = 'helvetica'
fig.xaxis.axis_label_text_font_size = '16pt'
fig.yaxis.axis_label_text_font_size = '16pt'
fig.axis.axis_label_text_font_style = 'normal'
fig.axis.major_label_text_font = 'helvetica'
fig.axis.major_label_text_font_size = '10pt'
fig.axis.major_label_text_font_style = 'normal'

#plot data
fig.circle(x='x', y='y', size=10, line_color='firebrick', fill_color='firebrick', line_alpha=0.8, fill_alpha=0.3, source=source)
fig.line(x='x', y='y', line_width=2, line_color='gray', line_alpha=0.8, source=source)

#add widgets
add_button = Button(
        label='Add row')
add_button.on_click(add_row)

del_button = Button(
        label='Delete row')
del_button.on_click(del_row)

fit_button = Button(label='Fit data', button_type='danger')
fit_button.on_click(fit_data)

#create text input to enter fit model
model_text_input=TextInput(title='Fit model: ', value='a*exp(-((x-b)/(2*c))**2)')

#create text input to display parameter
parameter_text_input=TextInput(title='Parameter: ', value='')

#create the layout with figure and widgets
layout=layout([[[fig,[model_text_input, parameter_text_input], fit_button],[table,del_button,add_button]]])

#stream data
curdoc().add_root(layout)
curdoc().add_periodic_callback(update,500) #updates each 500ms


import pandas as pd
import random
from sklearn import LogisticRegression
from flask import Flask, request, render_template

app = Flask(__name__)

def encode_categorical(candidates_df):
    gender_mapper = {"M":1, "F":0}
    ethnicity_mapper = {"Black":0, "White":1, "Arab":2, "Asian":3, "Other":4}
    candidates_df["gender"] = candidates_df["gender"].replace(gender_mapper)
    candidates_df["ethnicity"] = candidates_df["ethnicity"].replace(ethnicity_mapper)
    return candidates_df

def calculate_bias(candidates_data):
    candidates_df = pd.DataFrame(candidates_data, columns=['gender','age', 'years_of_experience','skill_score', 'work_ethic','attitude_score', 'ethnicity', 'disability', 'legal_history','country_of_origin', 'time_spent_viewing', 'shortlisted' ])
    candidates_df = encode_categorical(candidates_df)
    columns = ['gender','age', 'years_of_experience','skill_score', 'work_ethic','attitude_score', 'ethnicity', 'disability', 'legal_history','country_of_origin', 'time_spent_viewing']
    X = candidates_df[columns]
    y = candidates_df['shortlisted']
    lr = LogisticRegression(max_iter=1000)
    lr.fit(X,y)
    gender_bias = lr.coef_[0]*100
    ethnicity_bias = lr.coef[6]  *100
    nationality_bias = lr.coef_[9] *100
    return gender_bias, ethnicity_bias, nationality_bias

@app.route('/calculate_bias', methods = ['POST'])
def bias():
    if request.method == 'POST':
        candidates_data = request.get_json()['data']

        gender_bias, ethnicity_bias, nationality_bias = calculate_bias(candidates_data)

        return {'gender bias:': gender_bias, 'ethnicity bias:': ethnicity_bias, 'nationality bias:': nationality_bias}

if __name__ == "__main__":
    app.run(debug=True)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.statespace.sarimax import SARIMAX
import mysql.connector

mydb = mysql.connector.connect(
  host="localhost",
  user="root",
  password="",
  database="pengujian"
)

# Buat cursor
mycursor = mydb.cursor()

# Eksekusi query untuk mengambil data
mycursor.execute("SELECT * FROM `honda` ORDER BY `honda`.`tahun` ASC")

# Fetch semua data
data = mycursor.fetchall()

# Konversi data ke dalam DataFrame pandas
motor_sales_data = pd.DataFrame(data, columns=['tahun', 'penjualan', 'minat', 'trand'])

# Ubah kolom 'tanggal' menjadi index
motor_sales_data = motor_sales_data.set_index('tahun')
print(motor_sales_data.head())
plt.figure(figsize=(10, 5))
plt.plot(motor_sales_data.index, motor_sales_data['penjualan'])
plt.xlabel('Date')
plt.ylabel('Sales')
plt.title('Motor Sales Data')
plt.show()

train_data = motor_sales_data.iloc[:-12] # menggunakan data sebelum 12 bulan terakhir sebagai data latih
test_data = motor_sales_data.iloc[-12:]

# Tentukan model SARIMA
model = SARIMAX(train_data['penjualan'],
                order=(1,1,1),
                seasonal_order=(1,1,1,12),
                trend='c')

results = model.fit()
print(results.summary())

# Lakukan prediksi pada data uji
predictions = results.predict(start='2023-01-01', end='2023-12-01')
print(predictions)
# Visualisasikan hasil prediksi dan data uji
plt.figure(figsize=(10, 5))
plt.plot(test_data.index, test_data['penjualan'].values, label='Actual')
plt.plot(predictions.index, predictions.values, label='Predicted')
plt.xlabel('Date')
plt.ylabel('Sales')
plt.title('SARIMA Prediction')
plt.legend()
plt.show()

# Evaluasi model dengan menggunakan mean squared error (MSE)
mse = ((predictions - test_data['penjualan'])**2).mean()
print(f"Mean Squared Error : {mse}")


"""empty message

Revision ID: aceb1b97e466
Revises: 97103249831d
Create Date: 2022-12-25 19:01:52.598988

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'aceb1b97e466'
down_revision = '97103249831d'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('data',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('user', sa.String(length=20), nullable=False),
    sa.Column('phone', sa.String(length=20), nullable=False),
    sa.Column('fellow', sa.Integer(), nullable=False),
    sa.Column('money', sa.Float(), nullable=False),
    sa.Column('time', sa.String(length=20), nullable=False),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_table('area_data',
    sa.Column('area_id', sa.Integer(), nullable=True),
    sa.Column('data_id', sa.Integer(), nullable=True),
    sa.ForeignKeyConstraint(['area_id'], ['area.area_id'], ),
    sa.ForeignKeyConstraint(['data_id'], ['data.id'], )
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('area_data')
    op.drop_table('data')
    # ### end Alembic commands ###


##-*- coding: utf-8 -*-

import sys, os, time, re
from enum import Enum   ##枚举类型
from functools import partial

from PyQt5.QtWidgets import QApplication, QMainWindow, QTreeWidget, QTreeWidgetItem, QLabel, QProgressBar, QFileDialog, QDockWidget, QProgressDialog, QAction
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QDir, QFileInfo, QSize, QThread, QObject
from PyQt5.QtGui import QIcon, QImage, QPixmap, qGray, QPalette, QBrush

from ui_MainWindow import Ui_MainWindow
from detector import Detector

from PIL import Image
import pydicom
import matplotlib.pyplot as plt
import numpy as np
import cv2

import random
import time

import label_map_util
import visualization_utils as vis_util

class TreeItemType(Enum):    ##节点类型枚举类型
   itemPatient = 1001    #顶层节点
   itemType = 1002  #组节点
   itemFile = 1003  #CT文件节点

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.curPixmap=QPixmap()   #图片
        self.pixRatio=1            #显示比例
        self.itemFlags=(Qt.ItemIsSelectable | Qt.ItemIsEnabled)  #节点标志

        self.ui.mainToolBar.setIconSize(QSize(40, 40))    ##设置工具栏图标大小
        self.ui.mainToolBar.setFixedHeight(70)    ##设置工具栏高度
        self.setCentralWidget(self.ui.splitterH)    ##使splitter充满工作区
        #self.setCentralWidget(self.ui.scrollArea)

        self.setWindowTitle("CT Rib Fracture Detector")
        self.showMaximized()    ##全屏显示

        ##设置背景颜色
        self.setStyleSheet("#MainWindow{background-color:white}")

        ##设置图片区初始颜色
        pe = QPalette()
        pe.setColor(QPalette.Background, Qt.white)
        self.ui.labPicture.setAutoFillBackground(True)
        self.ui.labPicture.setPalette(pe)

        ##检测框显隐按钮属性
        self.iconHideBox = QIcon()
        self.iconHideBox.addPixmap(QPixmap(":/images/icons/hidebox.png"), QIcon.Normal, QIcon.Off)
        self.iconShowBox = QIcon()
        self.iconShowBox.addPixmap(QPixmap(":/images/icons/showbox.png"), QIcon.Normal, QIcon.Off)
        self.actBoxFlag = 0    ##0:隐藏Box  1:显示Box

        self.ui.actBox.setEnabled(True)
        self.ui.actBox.setVisible(False)

        ##在工具栏上添加QLabel和QProgressBar
        self.lab1 = QLabel(self)
        self.lab1.setMinimumWidth(50)
        self.actLab1 = self.ui.mainToolBar.addWidget(self.lab1)
        self.actLab1.setVisible(False)

        self.prg = QProgressBar(self)
        self.prg.setMinimumWidth(100)
        self.prg.setMaximumWidth(300)
        self.actPrg = self.ui.mainToolBar.addWidget(self.prg)
        self.actPrg.setVisible(False)

        self.lab2 = QLabel(self)
        self.lab2.setMinimumWidth(300)
        self.actLab2 = self.ui.mainToolBar.addWidget(self.lab2)
        self.actLab2.setVisible(False)

        self.numTotal = 0
        self.numLoad = 0

        ##失效检测按钮
        self.ui.actDetect.setEnabled(False)
        self.ui.actDetectThis.setEnabled(False)

        ##设置树的宽度
        self.ui.treeFiles.setColumnWidth(0, 220)
        self.ui.treeFiles.setColumnWidth(1, 40)

##  =================自定义功能函数================================
    ##显示已检测的图片
    def __displayDetectedImage(self, item):
        dcmFileName = item.data(0, Qt.UserRole)
        self.ui.statusBar.showMessage(dcmFileName)

        #预处理
        dcmFile = pydicom.read_file(dcmFileName)
        origin = dcmFile.pixel_array # type:numpy.ndarray

        intercept = dcmFile.RescaleIntercept
        slope = dcmFile.RescaleSlope
        origin = origin * slope + intercept
        origin[origin < -100] = -100 # 去除低亮部分
        origin[origin > 750] = 750 # 去除高亮部分

        # 归一化到0-255
        origin = cv2.normalize(origin, None, 0, 255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC3)
        image_np = np.expand_dims(origin,-1) # 将origin增加一个维度
        image_np = np.repeat(image_np,3,2) # 将二维矩阵重复三次

        #plt.imsave("output/undetected.jpg", image_np)

        NUM_CLASSES = 6
        PATH_TO_LABELS = 'label_map.pbtxt'
        label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
        categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
        category_index = label_map_util.create_category_index(categories)

        result = item.data(1, Qt.UserRole)
        boxes = result[1]
        scores = result[2]
        classes = result[3]

        vis_util.visualize_boxes_and_labels_on_image_array(
            image_np,
            boxes,
            classes,
            scores,
            category_index,
            use_normalized_coordinates=True,
            line_thickness=1)

        #plt.imsave("output/detected.jpg", image_np)
        image = QImage(image_np, image_np.shape[1], image_np.shape[0], QImage.Format_RGB888)

        self.curPixmap = QPixmap(image)
        self.on_actZoomFitH_triggered()

        self.ui.actZoomIn.setEnabled(True)
        self.ui.actZoomOut.setEnabled(True)
        self.ui.actZoomRealSize.setEnabled(True)
        self.ui.actZoomFitW.setEnabled(True)
        self.ui.actZoomFitH.setEnabled(True)

    ##显示图片
    def __displayImage(self, item):
        dcmFileName = item.data(0, Qt.UserRole)
        self.ui.statusBar.showMessage(dcmFileName)

        #预处理
        dcmFile = pydicom.read_file(dcmFileName)
        origin = dcmFile.pixel_array # type:numpy.ndarray

        intercept = dcmFile.RescaleIntercept
        slope = dcmFile.RescaleSlope
        origin = origin * slope + intercept
        origin[origin < -100] = -100 # 去除低亮部分
        origin[origin > 750] = 750 # 去除高亮部分

        # 归一化到0-255
        #origin = cv2.normalize(origin, None, 0, 255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC3)
        origin = cv2.normalize(origin, None, 0, 255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
        #rgb = np.expand_dims(origin,-1) # 将origin增加一个维度
        #rgb = np.repeat(rgb,3,2) # 将二维矩阵重复三次

        image = QImage(origin[:], origin.shape[1], origin.shape[0], origin.shape[1], QImage.Format_Indexed8)
        self.curPixmap = QPixmap(image)
        self.on_actZoomFitH_triggered()

        self.ui.actZoomIn.setEnabled(True)
        self.ui.actZoomOut.setEnabled(True)
        self.ui.actZoomRealSize.setEnabled(True)
        self.ui.actZoomFitW.setEnabled(True)
        self.ui.actZoomFitH.setEnabled(True)

##  ===========connectSlotsByName() 自动连接的槽函数=================
    @pyqtSlot()
    def on_actOpen_triggered(self):
        ##返回的文件夹路径
        path = QFileDialog.getExistingDirectory()
        if(path == ""):
            return

        ##生成进度条组件
        self.numTotal = len([lists for lists in os.listdir(path) if os.path.isfile(os.path.join(path, lists))])    ##文件总数
        self.numLoad = 0    ##已加载数
        self.lab1.setText(" 加载中")
        self.prg.setRange(0, self.numTotal)
        self.prg.setValue(0)
        self.lab2.setText(" 剩余文件：" + str(self.numTotal - self.numLoad))
        self.actLab1.setVisible(True)
        self.actPrg.setVisible(True)
        self.actLab2.setVisible(True)

        print("From mainThread: ", QThread.currentThreadId())

        ##建立工作线程
        workThread = QThread(parent=self)

        openDir= OpenDir(path, self.itemFlags)
        openDir.moveToThread(workThread)
        openDir.dirError.connect(self.do_dirError)
        openDir.newDcmFile.connect(self.do_newDcmFile)
        openDir.openFinished.connect(self.do_openFinished)
        openDir.openFinished.connect(workThread.quit)
        workThread.started.connect(lambda:openDir.run(self.ui.treeFiles))

        workThread.start()

    def do_dirError(self):
        self.lab2.setText("不是患者文件夹，请重新选择！")

    def do_newDcmFile(self):
        self.numLoad = self.numLoad + 1
        self.prg.setValue(self.numLoad)
        self.lab2.setText(" 剩余文件：" + str(self.numTotal - self.numLoad))

    def do_openFinished(self):
        self.actLab1.setVisible(False)
        self.actPrg.setVisible(False)
        self.actLab2.setVisible(False)

        self.ui.actDetect.setEnabled(True)

    ##检测所有按钮触发
    @pyqtSlot()
    def on_actDetect_triggered(self):
        self.ui.actDetect.setEnabled(False)
        self.ui.actOpen.setEnabled(False)
        topItem = self.ui.treeFiles.topLevelItem(0)

        ##显示进度条组件
        self.numTotal = 0
        for i in range(topItem.childCount()):
            self.numTotal = self.numTotal + topItem.child(i).childCount()
        self.numLoad = 0    ##已加载数
        self.lab1.setText(" 检测中")
        self.prg.setRange(0, self.numTotal)
        self.prg.setValue(0)
        self.lab2.setText(" 剩余文件：" + str(self.numTotal - self.numLoad))
        self.actLab1.setVisible(True)
        self.actPrg.setVisible(True)
        self.actLab2.setVisible(True)

        #print("From mainThread: ", QThread.currentThreadId())

        ##建立工作线程
        workThread = QThread(parent=self)

        self.detectTreeFiles = DetectTreeFiles(self.ui.treeFiles)
        self.detectTreeFiles.moveToThread(workThread)
        self.detectTreeFiles.detecting.connect(self.do_detecting)
        self.detectTreeFiles.gotResult.connect(self.do_gotResult)
        self.detectTreeFiles.gotAllResult.connect(self.do_gotAllResult)
        self.detectTreeFiles.gotAllResult.connect(workThread.quit)
        workThread.started.connect(self.detectTreeFiles.run)

        workThread.start()

    ##正检测在某节点
    def do_detecting(self, index):
        i = index[0]
        j = index[1]
        item = self.ui.treeFiles.topLevelItem(0).child(i).child(j)
        item.setText(1, "检测中...")
        item.setTextAlignment(1, Qt.AlignCenter)

    ##得到检测结果
    def do_gotResult(self, result):
        i = result[4]
        j = result[5]
        del result[5]
        del result[4]
        item = self.ui.treeFiles.topLevelItem(0).child(i).child(j)

        classes = result[3]
        brush = QBrush(Qt.SolidPattern)
        if 5.0 in classes:
            item.setText(1, "骨质异常")
            brush.setColor(Qt.GlobalColor.cyan)
        elif 3.0 in classes or 4.0 in classes:
            item.setText(1, "骨折")
            brush.setColor(Qt.GlobalColor.red)
        elif 6.0 in classes:
            item.setText(1, "发育异变")
            brush.setColor(Qt.GlobalColor.yellow)
        else:
            item.setText(1, "正常")
            brush.setColor(Qt.GlobalColor.white)
        item.setBackground(1, brush)
        item.setTextAlignment(1, Qt.AlignCenter)
        item.setData(1, Qt.UserRole, result)

        ##进度条
        self.numLoad = self.numLoad + 1
        self.prg.setValue(self.numLoad)
        self.lab2.setText(" 剩余文件：" + str(self.numTotal - self.numLoad))

    def do_gotAllResult(self):
        ##隐藏进度条
        self.actLab1.setVisible(False)
        self.actPrg.setVisible(False)
        self.actLab2.setVisible(False)

        self.ui.actOpen.setEnabled(True)

    ##检测当前按钮触发
    @pyqtSlot()
    def on_actDetectThis_triggered(self):
        self.ui.actOpen.setEnabled(False)
        self.ui.actDetect.setEnabled(False)
        self.ui.actDetectThis.setEnabled(False)

        print("From mainThread: ", QThread.currentThreadId())

        ##建立工作线程
        workThread = QThread(parent=self)

        detectThis = DetectThis()
        detectThis.moveToThread(workThread)
        detectThis.gotThisResult.connect(self.do_gotThisResult)
        detectThis.gotThisResult.connect(workThread.quit)
        #workThread.started.connect(lambda:detectThis.run(item))
        workThread.started.connect(partial(detectThis.run, self.ui.treeFiles.currentItem()))

        workThread.start()

        item = self.ui.treeFiles.currentItem()
        item.setText(1, "检测中...")
        item.setTextAlignment(1, Qt.AlignCenter)

    ##得到当前检测结果
    def do_gotThisResult(self):
        self.ui.actOpen.setEnabled(True)
        self.ui.actDetect.setEnabled(True)

    ##检测框显隐按钮触发
    @pyqtSlot()
    def on_actBox_triggered(self):
        if self.actBoxFlag == 0:    ##隐藏
            self.__displayImage(self.ui.treeFiles.currentItem())
            self.actBoxFlag = 1
            self.ui.actBox.setIcon(self.iconShowBox)
            self.ui.actBox.setText("显示Box")
            self.ui.actBox.setToolTip("显示检测框")

        else:    ##显示
            self.__displayDetectedImage(self.ui.treeFiles.currentItem())
            self.actBoxFlag = 0
            self.ui.actBox.setIcon(self.iconHideBox)
            self.ui.actBox.setText("隐藏Box")
            self.ui.actBox.setToolTip("隐藏检测框")

    ##当前选中节点改变
    def on_treeFiles_currentItemChanged(self, current, previous):
        if (current == None or current == previous):
            self.ui.actBox.setVisible(False)
            return
        nodeType = current.type()

        if nodeType == TreeItemType.itemFile.value:
            detected = current.data(1, Qt.UserRole)[0]
            if detected:
                self.__displayDetectedImage(current)    ##显示已检测图片
                self.actBoxFlag = 0
                self.ui.actBox.setIcon(self.iconHideBox)
                self.ui.actBox.setText("隐藏Box")
                self.ui.actBox.setToolTip("隐藏检测框")
                self.ui.actBox.setVisible(True)
                self.ui.actDetectThis.setEnabled(False)
            else:
                self.__displayImage(current)    ##显示图片
                self.ui.actBox.setVisible(False)
                self.ui.actDetectThis.setEnabled(True)
            return

        self.ui.actDetectThis.setEnabled(False)

        if nodeType == TreeItemType.itemType.value:
            current.setExpanded(True)

        self.ui.actBox.setVisible(False)

        self.ui.actZoomIn.setEnabled(False)
        self.ui.actZoomOut.setEnabled(False)
        self.ui.actZoomRealSize.setEnabled(False)
        self.ui.actZoomFitW.setEnabled(False)
        self.ui.actZoomFitH.setEnabled(False)

    @pyqtSlot()  ##适应高度显示图片
    def on_actZoomFitH_triggered(self):
        H=self.ui.scrollArea.height() #得到scrollArea的高度
        realH=self.curPixmap.height() #原始图片的实际高度
        self.pixRatio=float(H)/realH  #当前显示比例，必须转换为浮点数
        pix=self.curPixmap.scaledToHeight(H-30) #图片缩放到指定高度
        self.ui.labPicture.setPixmap(pix)         #设置Label的PixMap

    @pyqtSlot()  ##适应宽度显示
    def on_actZoomFitW_triggered(self):
        W=self.ui.scrollArea.width()-20
        realW=self.curPixmap.width()
        self.pixRatio=float(W)/realW
        pix=self.curPixmap.scaledToWidth(W-30)
        self.ui.labPicture.setPixmap(pix)         #设置Label的PixMap

    @pyqtSlot()    ##实际大小
    def on_actZoomRealSize_triggered(self):
        self.pixRatio=1  #恢复显示比例为1
        self.ui.labPicture.setPixmap(self.curPixmap)

    @pyqtSlot()  ##放大显示
    def on_actZoomIn_triggered(self):
        self.pixRatio=self.pixRatio*1.2
        W=self.pixRatio*self.curPixmap.width()
        H=self.pixRatio*self.curPixmap.height()
        pix=self.curPixmap.scaled(W,H)  #图片缩放到指定高度和宽度，保持长宽比例
        self.ui.labPicture.setPixmap(pix)

    @pyqtSlot() ##缩小显示
    def on_actZoomOut_triggered(self):
        self.pixRatio=self.pixRatio*0.8
        W=self.pixRatio*self.curPixmap.width()
        H=self.pixRatio*self.curPixmap.height()
        pix=self.curPixmap.scaled(W,H)     #图片缩放到指定高度和宽度，保持长宽比例
        self.ui.labPicture.setPixmap(pix)

##打开患者文件夹
class OpenDir(QObject):
    dirError = pyqtSignal()
    newDcmFile = pyqtSignal()
    openFinished = pyqtSignal()
    def __init__(self, path, itemFlags, parent=None):
        super().__init__(parent)
        self.path = path
        self.itemFlags = itemFlags

    def run(self, treeFiles):
        print("From workThread: ", QThread.currentThreadId())

        dcmList = os.listdir(self.path)    ##文件列表

        ##添加根节点
        for dcm in dcmList:
            dcmFile = self.path + '/' + dcm
            if os.path.isdir(dcmFile):
                continue
            if os.path.splitext(dcm)[-1] != ".dcm": # 跳过非dcm文件
                continue
            sliceFile = pydicom.read_file(dcmFile)
            patientName = str(sliceFile.PatientName)
            break
        else:
            self.dirError.emit()
            return
        treeFiles.clear()
        icon = QIcon(":/images/icons/patient.png")
        topItem = TreeWidgetItem(TreeItemType.itemPatient.value)
        topItem.setIcon(0, icon)
        topItem.setText(0, patientName)
        topItem.setFlags(self.itemFlags)
        topItem.setData(0, Qt.UserRole, "")
        topItem.setExpanded(True)
        topItem.setDisabled(False)
        treeFiles.addTopLevelItem(topItem)

        ##遍历患者文件夹
        for dcm in dcmList:
            #dcmFile = os.path.join(path, dcm)
            dcmFile = self.path + '/' + dcm

            if os.path.isdir(dcmFile):
                continue

            self.newDcmFile.emit()

            if os.path.splitext(dcm)[-1] != ".dcm": # 跳过非dcm文件
                continue

            sliceFile = pydicom.read_file(dcmFile)
            seriesDescription = str(sliceFile.SeriesDescription)

            ##只加载切片文件
            match = re.match(r"(.*?)mm(.*?)", seriesDescription, re.M | re.I)
            if not match:
                continue

            ##添加Type节点
            #exist = treeFiles.findItems(seriesDescription, Qt.MatchExactly | Qt.MatchRecursive)
            #if exist:
            #else:
            typeNum = os.path.splitext(dcmFile)[-2]
            typeNum = os.path.splitext(typeNum)[-2]
            typeNum = os.path.splitext(typeNum)[-1]
            typeNum = typeNum[1:]
            for i in range(topItem.childCount()):
                item = topItem.child(i)
                if item.data(0, Qt.UserRole) == typeNum:
                    parentItem = item
                    break
            else:
                icon = QIcon(":/images/icons/type.png")
                #item = QTreeWidgetItem(TreeItemType.itemType.value)
                item = TreeWidgetItem(TreeItemType.itemType.value)
                item.setIcon(0, icon)
                item.setText(0, seriesDescription)
                item.setFlags(self.itemFlags)
                item.setData(0, Qt.UserRole, typeNum)
                topItem.addChild(item)
                parentItem = item

            ##添加节点
            icon = QIcon(":/images/icons/file.png")
            #item = QTreeWidgetItem(TreeItemType.itemFile.value)
            item = TreeWidgetItem(TreeItemType.itemFile.value)
            item.setIcon(0, icon)
            item.setText(0, dcm)
            item.setFlags(self.itemFlags)
            item.setData(0, Qt.UserRole, dcmFile)

            result = [False]
            item.setData(1, Qt.UserRole, result)

            parentItem.addChild(item)

        ##对节点排序
        for i in range(topItem.childCount()):
            item = topItem.child(i)
            item.sortChildren(0, Qt.SortOrder.AscendingOrder)
        #topItem.sortChildren(0, Qt.SortOrder.AscendingOrder)
        topItem.setExpanded(True)

        self.openFinished.emit()

##检测所有
class DetectTreeFiles(QObject):
    detecting = pyqtSignal(list)
    gotResult = pyqtSignal(list)
    gotAllResult = pyqtSignal()
    def __init__(self, treeFiles, parent=None):
        super().__init__(parent)
        self.treeFiles = treeFiles

    def run(self):
        #print("From workThread: ", QThread.currentThreadId())
        detector = Detector()
        topItem = self.treeFiles.topLevelItem(0)
        for i in range(topItem.childCount()):
            typeItem = topItem.child(i)
            for j in range(typeItem.childCount()):
                item = typeItem.child(j)
                detected = item.data(1, Qt.UserRole)[0]
                if detected:
                    continue
                self.detecting.emit([i, j])

                dcmFileName = item.data(0, Qt.UserRole)
                result = detector.detect(dcmFileName)
                result.insert(0, True)
                result.append(i)
                result.append(j)

                self.gotResult.emit(result)
        self.gotAllResult.emit()

##检测当前
class DetectThis(QObject):
    gotThisResult = pyqtSignal()
    def __init__(self, parent=None):
        super().__init__(parent)

    def run(self, item):
        print("From workThread: ", QThread.currentThreadId())
        detector = Detector()
        detected = item.data(1, Qt.UserRole)[0]
        if detected:
            return
        dcmFileName = item.data(0, Qt.UserRole)
        result = detector.detect(dcmFileName)
        result.insert(0, True)

        classes = result[3]
        brush = QBrush(Qt.SolidPattern)
        if 5.0 in classes:
            item.setText(1, "骨质异常")
            brush.setColor(Qt.GlobalColor.cyan)
        elif 3.0 in classes or 4.0 in classes:
            item.setText(1, "骨折")
            brush.setColor(Qt.GlobalColor.red)
        elif 6.0 in classes:
            item.setText(1, "发育异变")
            brush.setColor(Qt.GlobalColor.yellow)
        else:
            item.setText(1, "正常")
            brush.setColor(Qt.GlobalColor.white)
        item.setBackground(1, brush)
        item.setTextAlignment(1, Qt.AlignCenter)
        item.setData(1, Qt.UserRole, result)

        self.gotThisResult.emit()

##重写排序的比较方式
class TreeWidgetItem(QTreeWidgetItem):
    def __init__(self, parent=None):
        QTreeWidgetItem.__init__(self, parent)

    def __lt__(self, otherItem):
        column = self.treeWidget().sortColumn()

        selfText = self.text(column)
        #print(selfText)
        selfText0 = os.path.splitext(selfText)[-2]
        selfTextNum = os.path.splitext(selfText0)[-1]
        selfNum = int(selfTextNum[1:])

        otherText = otherItem.text(column)
        otherText0 = os.path.splitext(otherText)[-2]
        otherTextNum = os.path.splitext(otherText0)[-1]
        otherNum = int(otherTextNum[1:])

        #if selfNum == otherNum

        try:
            return selfNum < otherNum
        except ValueError:
            return self.text(column) < otherItem.text(column)


from utils.threadbuffer import ThreadBuffer
from utils.query_available_devices import query_available_devices

import torch

def batch_index_select(x, idx):
    if len(x.size()) == 3:
        B, N, C = x.size()
        N_new = idx.size(1)
        offset = torch.arange(B, dtype=torch.long, device=x.device).view(B, 1) * N
        idx = idx + offset
        out = x.reshape(B*N, C)[idx.reshape(-1)].reshape(B, N_new, C)
        return out
    elif len(x.size()) == 2:
        B, N = x.size()
        N_new = idx.size(1)
        offset = torch.arange(B, dtype=torch.long, device=x.device).view(B, 1) * N
        idx = idx + offset
        out = x.reshape(B*N)[idx.reshape(-1)].reshape(B, N_new)
        return out
    else:
        raise NotImplementedError

def batch_index_fill(x, x1, x2, idx1, idx2):
    B, N, C = x.size()
    B, N1, C = x1.size()
    B, N2, C = x2.size()

    offset = torch.arange(B, dtype=torch.long, device=x.device).view(B, 1)
    idx1 = idx1 + offset * N
    idx2 = idx2 + offset * N

    x = x.reshape(B*N, C)

    x[idx1.reshape(-1)] = x1.reshape(B*N1, C)
    x[idx2.reshape(-1)] = x2.reshape(B*N2, C)

    x = x.reshape(B, N, C)
    return x

def mkdir(path, create_message=None):
    import os

    if os.path.exists(path):
        return

    import pathlib
    pathlib.Path(path).mkdir(parents=True, exist_ok=True)
    if create_message is not None:
        print(create_message)
    else:
        print(f'[INFO] Directory created. {path}')

def initialize_saves_dirs():
    mkdir('./saves')
    mkdir('./saves/vit_concrete_end2end_logs')
    mkdir('./saves/lvvit', create_message=
        '[SETUP] LVViT weight must be downloaded seperately! into ./saves/lvvit/*\n'+\
        '[SETUP] wget https://github.com/zihangJiang/TokenLabeling/releases/download/1.0/lvvit_s-26M-224-83.3.pth.tar\n'+\
        '[SETUP] from https://github.com/zihangJiang/TokenLabeling'
    )
    mkdir('./saves_plot')
    mkdir('./saves_hparam')
    mkdir('./logs')

if __name__ == '__main__':
    initialize_saves_dirs()


import numpy as np
import pandas as pd
from pathlib import Path

from src.datasets.base_dataset import SimpleAudioFakeDataset

class InTheWildDataset(SimpleAudioFakeDataset):

    def __init__(
        self,
        path,
        subset="train",
        transform=None,
        seed=None,
        partition_ratio=(0.7, 0.15),
        split_strategy="random"
    ):
        super().__init__(subset=subset, transform=transform)
        self.path = path
        self.read_samples()
        self.partition_ratio = partition_ratio
        self.seed = seed

    def read_samples(self):
        path = Path(self.path)
        meta_path = path / "meta.csv"

        self.samples = pd.read_csv(meta_path)
        self.samples["path"] = self.samples["file"].apply(lambda n: str(path / n))
        self.samples["file"] = self.samples["file"].apply(lambda n: Path(n).stem)
        self.samples["label"] = self.samples["label"].map({"bona-fide": "bonafide", "spoof": "spoof"})
        self.samples["attack_type"] = self.samples["label"].map({"bonafide": "-", "spoof": "X"})
        self.samples.rename(columns={'file': 'sample_name', 'speaker': 'user_id'}, inplace=True)

    def split_samples_per_speaker(self, samples):
        speaker_list = pd.Series(samples["user_id"].unique())
        speaker_list = speaker_list.sort_values()
        speaker_list = speaker_list.sample(frac=1, random_state=self.seed)
        speaker_list = list(speaker_list)

        p, s = self.partition_ratio
        subsets = np.split(speaker_list, [int(p * len(speaker_list)), int((p + s) * len(speaker_list))])
        speaker_subset = dict(zip(['train', 'test', 'val'], subsets))[self.subset]
        return self.samples[self.samples["user_id"].isin(speaker_subset)]

if __name__ == "__main__":
    dataset = InTheWildDataset(
        path="../datasets/release_in_the_wild",
        subset="val",
        seed=242,
        split_strategy="per_speaker"
    )

    print(len(dataset))
    print(len(dataset.samples["user_id"].unique()))
    print(dataset.samples["user_id"].unique())

    print(dataset[0])


import torch
import torch.nn as nn
import torch.nn.functional as F

class WheatClassifier(nn.Module):
    def __init__(self):
        super(WheatClassifier, self).__init__()
        self.block1 = self.conv_block(c_in=3, c_out=256, dropout=0.1, kernel_size=5, stride=1, padding=2)
        self.block2 = self.conv_block(c_in=256, c_out=128, dropout=0.1, kernel_size=3, stride=1, padding=1)
        self.block3 = self.conv_block(c_in=128, c_out=64, dropout=0.1, kernel_size=3, stride=1, padding=1)
        self.lastcnn = nn.Conv2d(in_channels=64, out_channels=3, kernel_size=75, stride=1, padding=0)
        self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
    def forward(self, x):
        x = self.block1(x)
        x = self.maxpool(x)
        x = self.block2(x)
        x = self.block3(x)
        x = self.maxpool(x)
        x = self.lastcnn(x)
        return F.log_softmax(x,dim=1)
    def conv_block(self, c_in, c_out, dropout, **kwargs):
        seq_block = nn.Sequential(
            nn.Conv2d(in_channels=c_in, out_channels=c_out, **kwargs),
            nn.BatchNorm2d(num_features=c_out),
            nn.ReLU(),
            nn.Dropout2d(p=dropout)
        )
        return seq_block


from typing import Tuple

import geopandas as gpd
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from matplotlib.colors import Colormap
from matplotlib.lines import Line2D
from matplotlib.offsetbox import AnchoredText

PADDING = 0.005

def prepare_axes(ax: plt.Axes, cycles_info: pd.DataFrame) -> Tuple[float, float, float, float]:
    min_y = cycles_info["lat"].min() - PADDING
    max_y = cycles_info["lat"].max() + PADDING
    min_x = cycles_info["lon"].min() - PADDING
    max_x = cycles_info["lon"].max() + PADDING
    ax.set_ylim((min_y, max_y))
    ax.set_xlim((min_x, max_x))
    ax.set_axis_off()
    return min_x, max_x, min_y, max_y

def save_fig(fig: plt.Figure) -> str:
    fig.patch.set_facecolor("white")
    map_file = "/tmp/map.png"
    fig.savefig(map_file)
    return map_file

def set_custom_legend(ax: plt.Axes, cmap: Colormap) -> None:
    values = [(0.0, "Empty"), (0.5, "Busy"), (1.0, "Full")]
    legend_elements = []
    for gradient, label in values:
        color = cmap(gradient)
        legend_elements.append(
            Line2D(
                [0],
                [0],
                marker="o",
                color="w",
                label=label,
                markerfacecolor=color,
                markeredgewidth=0.5,
                markeredgecolor="k",
            )
        )
    ax.legend(handles=legend_elements, loc="upper left", prop={"size": 6}, ncol=len(values))

def plot_map(cycles_info: pd.DataFrame, version: str) -> str:
    fig = plt.Figure(figsize=(6, 4), dpi=200, frameon=False)
    ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0])
    fig.add_axes(ax)

    min_x, max_x, min_y, max_y = prepare_axes(ax, cycles_info)

    # Get external resources
    cmap = plt.get_cmap("OrRd")
    london_map = gpd.read_file("shapefiles/London_Borough_Excluding_MHW.shp").to_crs(epsg=4326)

    # Plot elements
    ax.fill_between([min_x, max_x], min_y, max_y, color="#9CC0F9")
    london_map.plot(ax=ax, linewidth=0.5, color="#F4F6F7", edgecolor="black")
    sns.scatterplot(
        y="lat", x="lon", hue="proportion", edgecolor="k", linewidth=0.1, palette=cmap, data=cycles_info, s=25, ax=ax
    )

    text = AnchoredText(f"Tweeting lambda, version {version}", loc=4, prop={"size": 5}, frameon=True)
    ax.add_artist(text)

    set_custom_legend(ax, cmap)

    map_file = save_fig(fig)

    return map_file


from os import path
from setuptools import setup

with open(path.join(path.dirname(path.abspath(__file__)), 'README.rst')) as f:
    readme = f.read()

setup(
    name             = 'filefetch',
    version          = '0.1',
    description      = 'An app to fetch files from a GitHub repo andsubsequent plugins.',
    long_description = readme,
    author           = 'reedh13',
    author_email     = 'dev@babyMRI.org',
    url              = 'http://wiki',
    packages         = ['filefetch'],
    install_requires = ['chrisapp'],
    test_suite       = 'nose.collector',
    tests_require    = ['nose'],
    license          = 'MIT',
    zip_safe         = False,
    python_requires  = '>=3.6',
    entry_points     = {
        'console_scripts': [
            'filefetch = filefetch.__main__:main'
            ]
        }
)


import requests
import json
import datetime
import time
from config import OPENSEA_API_KEY

def get_collection(contract):
    """Returns collection info given a contract address"""
    url = f"https://api.opensea.io/api/v1/asset/{contract}/1/?include_orders=false"
    headers = {"X-API-KEY": OPENSEA_API_KEY}
    response = requests.get(url, headers=headers)
    collection = json.loads(response.text)
    return collection

def get_collection_stats(slug):
    url = f"https://api.opensea.io/api/v1/collection/{slug}/stats"

    headers = {
        "Accept": "application/json",
        "X-API-KEY": OPENSEA_API_KEY
    }

    response = requests.get(url, headers=headers)
    stats = json.loads(response.text)['stats']
    print(stats)
    print(type(stats))
    return stats

def get_opensea_events(token_id, contract, slug, only_opensea=True):
    """Returns a dict of successful sales on Opensea"""
    url = f"https://api.opensea.io/api/v1/events?only_opensea={only_opensea}&token_id={token_id}&asset_contract_address={contract}&collection_slug={slug}&event_type=successful"

    headers = {
        "Accept": "application/json",
        "X-API-KEY": OPENSEA_API_KEY
    }

    response = requests.get(url, headers=headers)
    try:
        events = json.loads(response.text)['asset_events']

        recent_event_date = events[0]['event_timestamp']
        today = datetime.date.today()

        if recent_event_date[0:10] == str(today):
            return events
        else:
            return None

    except:
        return None

def get_collection_slug(contract):
    return get_collection(contract)['collection']['slug']


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Modified on Wed May 05 08:58:46 2021

@author: Felipe Jaramillo
"""
import os
import glob
import sys
import cv2
import numpy as np
import time

import h5py
import random

#------------------------------------------------------------------------------------------------------
# Angular downsampling from original subaperture images of each light field,
# - angular downsampled subaperture images synthesizing
# - angular upsampled via nearest, bicubic and lanczos subaperture images synthesizing
# - angular downsampled and original light field structure stuv synthesizing (for visual purposes)
# - angular downsampled, original and upsampled subaperture images video synthesizing (for visual purposes)

def LFuvst(imgs, st_hr, pth_LFuvst, folder):
  # Construct a spatial image with each spatial point compund by the angular
  # matrix corresponding to that u,v coordinate
  lfimg = np.zeros((imgs[0].shape[0]*st_hr, imgs[0].shape[1]*st_hr, 3), np.uint8)
  for u in range(imgs[0].shape[0]):
    print('.', end="")
    for v in range(imgs[0].shape[1]):
      i = 0
      for s in range(st_hr):
        for t in range(st_hr):
          img = imgs[i]
          lfimg[(u*st_hr+s),(v*st_hr+t), :] = img[u, v, :]
          i += 1
  if not os.path.exists(pth_LFuvst+folder):
    os.makedirs(pth_LFuvst+folder)
  name = pth_LFuvst + folder + '/' + folder + '_stuv.png'
  cv2.imwrite(name, lfimg)

def AngularDownsampling(imgs, st_hr, st_lr):

  dwnfactor = int(st_hr/st_lr)
  # Extract angular matrices for a single spatial point and then downsampling it
  ang_mtx = []
  nearest_ang_mtx = []
  bicubic_ang_mtx = []
  lanczos_ang_mtx = []
  height = imgs[0].shape[0]
  width = imgs[0].shape[1]
  for u in range(height):
    print('.', end="")
    for v in range(width):
      a_mtx = np.zeros((st_hr, st_hr, 3), np.uint8)
      i = 0
      for s in range(st_hr):
        for t in range(st_hr):
          img = imgs[i]
          a_mtx[s, t, :] = img[u, v, :]
          i += 1
      # angular downsampling
      fx = 1/dwnfactor
      fy = 1/dwnfactor
      amtx = cv2.resize(a_mtx, None, fx=fx, fy=fy, interpolation=cv2.INTER_AREA)
      ang_mtx.append(amtx)

      amtx = (np.float32(amtx) / 127.5) - 1 # Normalization between [-1, 1]
      amtx = np.uint8((amtx + 1) * 127.5)

      nr = cv2.resize(amtx, None, fx=2, fy=2, interpolation=cv2.INTER_NEAREST)
      bc = cv2.resize(amtx, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
      lc = cv2.resize(amtx, None, fx=2, fy=2, interpolation=cv2.INTER_LANCZOS4)
      nearest_ang_mtx.append(nr)
      bicubic_ang_mtx.append(bc)
      lanczos_ang_mtx.append(lc)

  return ang_mtx, nearest_ang_mtx, bicubic_ang_mtx, lanczos_ang_mtx

def SynthesizeImgs(a_mtxdwn, st_hr, h, w, pth_frames, folder, indx):
  '''
  Function to synthesize and save the new sub-aperture images from the angular
  upsampled matrices of the corresponding LF
  '''
  imgs_new = []
  for s in range(st_hr):
    for t in range(st_hr):
      img = np.zeros((int(h), int(w), 3), np.uint8)
      i = 0
      for u in range(int(h)):
        for v in range(int(w)):
          img[u, v, :] = a_mtxdwn[i][s, t, :]
          i += 1
      print('.', end="")
      imgs_new.append(img)

  if indx == 'adownsampled':
    # Path to save original LF organized by stuv coordinates
    pth_LFuvst = os.getcwd() + '/LF/LF_stuv/'
    print("Saving angular downsampled light field structure stuv into %s " % ((pth_LFuvst+folder+'_'+indx)), end="")
    LFuvst(imgs_new, st_lr, pth_LFuvst, (folder+'_adownsampled'))
    print()
    print("done")

  print("Saving angular new %s sub-aperture images into %s..." % (indx,(pth_frames+folder+'_'+indx)))
  if not os.path.exists(pth_frames+folder+'_'+indx):
    os.makedirs(pth_frames+folder+'_'+indx)
  cont = 1
  i = 0
  filenames = []
  for s in range(st_hr):
    auxx = imgs_new[i:(st_hr+i)]
    if s%2 == 0:
      init = 0
      step = 1
      finish = st_hr
    else:
      init = st_hr-1
      step = -1
      finish = -1
      auxx.reverse()
    j = 0
    for t in range(init, finish, step):
      name = "%s%s_%s/%s_%03d_%02d_%02d.png" % (pth_frames, folder, indx, folder, cont, s+1, t+1)
      cv2.imwrite(name, auxx[j])
      cont+=1
      j += 1
      filenames.append(name)
      print('.', end="")
    i += st_hr
  print()
  print("done")
  return filenames

def save_frames(files):
  '''
  Function to save sub-aperture images into list in order to pass to video
  constructor
    Input:
      files: list with complete file name of sub-aperture images
    Outputs:
      frame_array: list with the frames
      height: number of rows in frames
      width: number of columns in frames
  '''
  frame_array = []
  for i in files:
    img = cv2.imread(i)
    height, width = img.shape[0:2]
    frame_array.append(img)
  return frame_array, height, width

def write_video(frame_array, name, height, width):
  '''
  Function to invoke a video codec constructor in order to insert frames and
  generate a video with the sub-aperture images
    Inputs:
      frame_array: list with the frames
      name: name of the video to save
      height: number of rows in frames
      width: number of columns in frames
  '''
  #fourcc = cv2.VideoWriter_fourcc(*'XVID') - Linux
  #fourcc = cv2.VideoWriter_fourcc('M','J','P','G') - Windows, avi
  fourcc = cv2.VideoWriter_fourcc(*'mp4v') # MP4
  out = cv2.VideoWriter(name,fourcc, 23.0, (width,height))
  for i in range(len(frame_array)):
    out.write(frame_array[i]) # writing the frame into the codec constructor
  out.release()

# Path withl LF subimages
pth_frames = os.getcwd() + '/LF/Frames/'

f_list = os.listdir(pth_frames)
LRfolders = []
HRfolders = []
for i in f_list:
  if 'adownsampled' in i:
    LRfolders.append(i)
  elif ('adownsampled' not in i) and ('SRv9' not in i) and ('SRv10' not in i) and ('SRv8' not in i) and ('BC' not in i) and ('NR' not in i) and ('LC' not in i):
    HRfolders.append(i)
  LRfolders.sort()
  HRfolders.sort()

# Path to save original LF organized by stuv coordinates
pth_LFuvst = os.getcwd() + '/LF/LF_stuv/'

st_hr, st_lr = 10, 5 # original angular resolution, downsampled angular resolution

print("\nLF angular donwsampling: ")
for folder in HRfolders:

  start_time = time.time()
  print("\nProcessing light field %s " % (folder))
  subimgs_list = glob.glob(pth_frames+folder+'/*.png')
  subimgs_list.sort()

  #-7
  appnd = [f[-9:] for f in subimgs_list]
  appnd.sort()

  imgshr = []
  for i in appnd:
    for f in subimgs_list:
      #-7
      if i in f[-9:]:
        imghr = cv2.imread(f)
        imgshr.append(imghr)
        h, w, _ = imghr.shape
        break

  print("Saving original light field structure stuv into %s ..." % ((pth_LFuvst + folder)), end="")
  LFuvst(imgshr, st_hr, pth_LFuvst, folder)
  print('')
  print("done")

  print("Angular downsampling from %d to %d ..." % (st_hr, st_lr), end="")
  ang_mtx, nearest_ang_mtx, bicubic_ang_mtx, lanczos_ang_mtx = AngularDownsampling(imgshr, st_hr, st_lr)
  imgshr = 0
  print('')
  print("done")

  LRsubimgs_list = SynthesizeImgs(ang_mtx, st_lr, h, w, pth_frames, folder, 'adownsampled')
  NRsubimgs_list = SynthesizeImgs(nearest_ang_mtx, st_hr, h, w, pth_frames, folder, 'NR')
  BCsubimgs_list = SynthesizeImgs(bicubic_ang_mtx, st_hr, h, w, pth_frames, folder, 'BC')
  LCsubimgs_list = SynthesizeImgs(lanczos_ang_mtx, st_hr, h, w, pth_frames, folder, 'LC')

  print("Generating video for angular LR light field...")
  frame_array, height, width = save_frames(LRsubimgs_list)
  VD_pth = 'LF/Videos/'
  name = VD_pth + folder + '_adonwsampled.mp4'
  write_video(frame_array, name, height, width)
  print("Video %s has been saved correctly..." % (name))

  print("Generating video for angular HR light field...")
  HRsubimgs_list = glob.glob(pth_frames+folder+'/*.png')
  HRsubimgs_list.sort()
  frame_array, height, width = save_frames(HRsubimgs_list)
  VD_pth = 'LF/Videos/'
  name = VD_pth + folder + '.mp4'
  write_video(frame_array, name, height, width)
  print("Video %s has been saved correctly..." % (name))

  print("Generating video for angular nearest upsampled light field...")
  frame_array, height, width = save_frames(NRsubimgs_list)
  VD_pth = 'LF/Videos/'
  name = VD_pth + folder + '_NR.mp4'
  write_video(frame_array, name, height, width)
  print("Video %s has been saved correctly..." % (name))

  print("Generating video for angular bicubic upsampled light field...")
  frame_array, height, width = save_frames(BCsubimgs_list)
  VD_pth = 'LF/Videos/'
  name = VD_pth + folder + '_BC.mp4'
  write_video(frame_array, name, height, width)
  print("Video %s has been saved correctly..." % (name))

  print("Generating video for angular lanczos upsampled light field...")
  frame_array, height, width = save_frames(LCsubimgs_list)
  VD_pth = 'LF/Videos/'
  name = VD_pth + folder + '_LC.mp4'
  write_video(frame_array, name, height, width)
  print("Video %s has been saved correctly..." % (name))

  print("--- Elapsed time: %s seconds ---" % (time.time() - start_time))

#-----------------------------------------------------------------------------------------------------------------------
# - angular downsampled ando original light field structure uvst synthesizing

# Path withl LF subimages
pth_frames = os.getcwd() + '/LF/Frames/'

f_list = os.listdir(pth_frames)
LRfolders = []
HRfolders = []
for i in f_list:
  if 'adownsampled' in i:
    LRfolders.append(i)
  elif ('adownsampled' not in i) and ('SRv9' not in i) and ('SRv10' not in i) and ('SRv8' not in i) and ('BC' not in i) and ('NR' not in i) and ('LC' not in i):
    HRfolders.append(i)
  LRfolders.sort()
  HRfolders.sort()

if len(LRfolders)!=len(HRfolders):
  print("Number of LF are not symetric within different methods of upscaling... Exit program")
  sys.exit("aa! errors!")

def handleimgs(lf_folder):
  imgsfiles = glob.glob(pth_frames+lf_folder+'/*.png')
  imgsfiles.sort()
  return imgsfiles

pth_mosiacos = os.getcwd() + '/LF/LF_uvst/'
print("Saving original and angular donwsampled light field structure uvst into %s ..." % (pth_mosiacos), end="")

startglob_time = time.time()
for LRfolder, HRfolder in zip(LRfolders, HRfolders):

  start_time = time.time()

  print("\nEvaluation of light field %s " % (HRfolder))
  LRsubimgs_list = handleimgs(LRfolder)
  HRsubimgs_list = handleimgs(HRfolder)

  HRimg = cv2.imread(HRsubimgs_list[0])
  HRmosaico = np.zeros((HRimg.shape[0]*10,HRimg.shape[1]*10, 3), np.uint8)

  rowhr = 0
  colhr = 0
  for i in range(len(HRsubimgs_list)):

    HRimg = cv2.imread(HRsubimgs_list[i])

    yi = rowhr*HRimg.shape[1]
    yo = (rowhr*HRimg.shape[1]) + HRimg.shape[1]
    xi = colhr*HRimg.shape[0]
    xo = (colhr*HRimg.shape[0]) + HRimg.shape[0]
    HRmosaico[yi:yo, xi:xo, :] = HRimg
    rowhr += 1
    if rowhr == 10:
      rowhr = 0
      colhr += 1

  print("Saving mosaico images  into %s..." % (pth_mosiacos+HRfolder))
  if not os.path.exists(pth_mosiacos+HRfolder):
    os.makedirs(pth_mosiacos+HRfolder)
  hrname = pth_mosiacos + HRfolder + '/' + HRfolder + '_uvst.png'
  cv2.imwrite(hrname, HRmosaico)

  LRimg = cv2.imread(LRsubimgs_list[0])
  LRmosaico = np.zeros((LRimg.shape[0]*5,LRimg.shape[1]*5, 3), np.uint8)
  rowlr = 0
  collr = 0

  for i in range(len(LRsubimgs_list)):

    LRimg = cv2.imread(LRsubimgs_list[i])

    yi = rowlr*LRimg.shape[1]
    yo = (rowlr*LRimg.shape[1]) + LRimg.shape[1]
    xi = collr*LRimg.shape[0]
    xo = (collr*LRimg.shape[0]) + LRimg.shape[0]
    LRmosaico[yi:yo, xi:xo, :] = LRimg
    rowlr += 1
    if rowlr == 5:
      rowlr = 0
      collr += 1

  print("Saving mosaico images  into %s..." % (pth_mosiacos+LRfolder))
  if not os.path.exists(pth_mosiacos+LRfolder):
    os.makedirs(pth_mosiacos+LRfolder)
  lrname = pth_mosiacos + LRfolder + '/' + LRfolder + '_uvst.png'
  cv2.imwrite(lrname, LRmosaico)

  print("--- Elapsed time: %s seconds ---" % (time.time() - start_time))

print("--- Elapsed time: %s seconds ---" % (time.time() - startglob_time))

#-------------------------------------------------------------------------------------------------------------------------
# - create h5 dataset for training
import os
import glob
import sys
import cv2
import numpy as np
import time

import h5py
import random

def AngularDownsampling(imgs, st_hr, st_lr):
  dwnfactor = int(st_hr/st_lr)
  # Extract angular matrices for a single spatial point and then downsampling it
  angular_mtcs_hr = []
  angular_mtcs_lr = []
  for u in range(imgs[0].shape[0]):
    print('.', end="")
    for v in range(imgs[0].shape[1]):
      a_mtx = np.zeros((st_hr, st_hr, 3), np.uint8)
      i = 0
      for s in range(st_hr):
        for t in range(st_hr):
          img = imgs[i]
          a_mtx[s, t, :] = img[u, v, :]
          i += 1
      angular_mtcs_hr.append(a_mtx)
      # angular downsampling
      fx = 1/dwnfactor
      fy = 1/dwnfactor
      amtx = cv2.resize(a_mtx, None, fx=fx, fy=fy, interpolation=cv2.INTER_AREA)
      angular_mtcs_lr.append(amtx)
  return angular_mtcs_hr, angular_mtcs_lr

# Path withl LF subimages
pth_frames = os.getcwd() + '/LF/Frames/'

f_list = os.listdir(pth_frames)
LRfolders = []
HRfolders = []
for i in f_list:
  if 'adownsampled' in i:
    LRfolders.append(i)
  elif ('adownsampled' not in i) and ('SRv9' not in i) and ('SRv10' not in i) and ('SRv8' not in i) and ('BC' not in i) and ('NR' not in i) and ('LC' not in i):
    HRfolders.append(i)
  LRfolders.sort()
  HRfolders.sort()

# Randomly shuffle list
random.seed(118)
random.shuffle(HRfolders)

# Separate train and validation LFs
aux = int(len(HRfolders)*0.80)
HRfolders_Train = HRfolders[0:aux] # Training dataset by 80% of full dataset
HRfolders_Test = HRfolders[aux:] # Validation dataset by 20% of full dataset

st_hr, st_lr = 10, 5 # original angular resolution, downsampled angular resolution

#fileName = os.getcwd() + '/LF/HDF5_dataset/LF_angular_dataset.h5'
fileName = os.getcwd() + '/LF_angular_dataset_final.h5'

print(len(HRfolders_Train))
print(len(HRfolders_Test))

ang_smpls = 700 * 10 # angular samples to extract from each LF
#ang_smpls = 15 # angular samples to extract from each LF
train_ang_dataset_smpls = len(HRfolders_Train) * ang_smpls # number of angular samples in train dataset
test_ang_dataset_smpls = len(HRfolders_Test) * ang_smpls # number of angular samples in test dataset

print(train_ang_dataset_smpls)
print(test_ang_dataset_smpls)

with h5py.File(fileName, "w") as out:
  out.create_dataset("X_ang_train",(train_ang_dataset_smpls,5,5,3),dtype=np.uint8)
  out.create_dataset("Y_ang_train",(train_ang_dataset_smpls,10,10,3),dtype=np.uint8)
  out.create_dataset("X_ang_test",(test_ang_dataset_smpls,5,5,3),dtype=np.uint8)
  out.create_dataset("Y_ang_test",(test_ang_dataset_smpls,10,10,3),dtype=np.uint8)

anglr_train = []
anghr_train = []
for folder in HRfolders_Train:

  start_time = time.time()
  print("\nProcessing light field %s " % (folder))
  subimgs_list = glob.glob(pth_frames+folder+'/*.png')
  subimgs_list.sort()

  appnd = [f[-9:] for f in subimgs_list]
  appnd.sort()

  imgshr = []
  for i in appnd:
    for f in subimgs_list:
      if i in f[-9:]:
        imghr = cv2.imread(f)
        imghr = cv2.cvtColor(imghr,cv2.COLOR_BGR2RGB)
        imgshr.append(imghr)
        break

  print("Angular downsampling from %d to %d ..." % (st_hr, st_lr), end="")
  mtx_hr, mtx_lr = AngularDownsampling(imgshr, st_hr, st_lr)
  print('')
  print("done")

  if len(mtx_hr) != len(mtx_lr):
    sys.exit("aa! errors! Dataset is not symmetric.. Exit program")

  # Randomly select 'ang_smpls' samples from both hr and lr angular samples
  c = list(zip(mtx_lr, mtx_hr))
  d = random.sample(c, ang_smpls)
  mtx_lr, mtx_hr = zip(*d)

  for i in range(len(mtx_lr)):
    anglr_train.append(mtx_lr[i])
    anghr_train.append(mtx_hr[i])

  print("--- Elapsed time: %s seconds ---" % (time.time() - start_time))

c = list(zip(anglr_train, anghr_train)) # Randomly shuffle both lists in the same order
random.seed(len(anglr_train))
random.shuffle(c)
anglr_train, anghr_train = zip(*c)

def WriteHDF5(samples, dataset):
  k = 0
  with h5py.File(fileName, "a") as out:
    for sample in samples:
      out[dataset][k, ...] = sample
      k+=1

print("\nSaving X_ang_train samples into dataset file...")
WriteHDF5(anglr_train, 'X_ang_train')
print("done")
print("\nSaving Y_ang_train samples into dataset file...")
WriteHDF5(anghr_train, 'Y_ang_train')
print("done")

anglr_test = []
anghr_test = []

for folder in HRfolders_Test:

  start_time = time.time()
  print("\nProcessing light field %s " % (folder))
  subimgs_list = glob.glob(pth_frames+folder+'/*.png')
  subimgs_list.sort()

  appnd = [f[-9:] for f in subimgs_list]
  appnd.sort()

  imgshr = []
  for i in appnd:
    for f in subimgs_list:
      if i in f[-9:]:
        imghr = cv2.imread(f)
        imghr = cv2.cvtColor(imghr,cv2.COLOR_BGR2RGB)
        imgshr.append(imghr)
        break

  print("Angular downsampling from %d to %d ..." % (st_hr, st_lr), end="")
  mtx_hr, mtx_lr = AngularDownsampling(imgshr, st_hr, st_lr)
  print('')
  print("done")

  if len(mtx_hr) != len(mtx_lr):
    sys.exit("aa! errors! Dataset is not symmetric.. Exit program")

  # Randomly select 'ang_smpls' samples from both hr and lr angular samples
  c = list(zip(mtx_lr, mtx_hr))
  d = random.sample(c, ang_smpls)
  mtx_lr, mtx_hr = zip(*d)

  for i in range(len(mtx_lr)):
    anglr_test.append(mtx_lr[i])
    anghr_test.append(mtx_hr[i])

  print("--- Elapsed time: %s seconds ---" % (time.time() - start_time))

c = list(zip(anglr_test, anghr_test)) # Randomly shuffle both lists in the same order
random.seed(len(anglr_test))
random.shuffle(c)
anglr_test, anghr_test = zip(*c)

print("\nSaving X_ang_test samples into dataset file...")
WriteHDF5(anglr_test, 'X_ang_test')
print("done")
print("\nSaving Y_ang_test samples into dataset file...")
WriteHDF5(anghr_test, 'Y_ang_test')
print("done")


import torch
import numpy as np

def calculate_hidden_init_limits(layer):
    """
    Calculate the initialization limits for the hidden layer.

    Args:
        layer (torch.nn.Module): The hidden layer for which to calculate initialization limits.

    Returns:
        tuple: A tuple containing the lower and upper limits for the initialization.
    """
    # Get the number of input units (fan-in) for the given hidden layer
    fan_in = layer.weight.data.size()[0]

    # Calculate the initialization limit using the 1/sqrt(fan_in) formula
    # This is a common initialization technique to improve convergence during training.
    lim = 1. / np.sqrt(fan_in)

    # The initialization limits are symmetric around zero, so we return (-lim, lim)
    # This means the initial weights of the hidden layer will be randomly
    # initialized within the range [-lim, lim].
    return (-lim, lim)

class Feedforward(torch.nn.Module):
    def __init__(self, input_size, hidden_sizes, output_size, upper_bound, activation_fun=torch.nn.Tanh(), output_activation=None, batch_norm=False):
        super(Feedforward, self).__init__()
        self.input_size = input_size
        self.hidden_sizes = hidden_sizes
        self.output_size = output_size
        self.output_activation = output_activation
        layer_sizes = [self.input_size] + self.hidden_sizes
        self.layers = torch.nn.ModuleList([ torch.nn.Linear(i, o) for i,o in zip(layer_sizes[:-1], layer_sizes[1:])])
        self.activations = [activation_fun for l in  self.layers]
        self.readout = torch.nn.Linear(self.hidden_sizes[-1], self.output_size)

        self.batch_norm = batch_norm
        self.b0 = torch.nn.BatchNorm1d(self.input_size)
        self.batch_norms = [torch.nn.BatchNorm1d(self.hidden_sizes[i]) for i in range(len(self.layers))]
        self.upper_bound = upper_bound

        self.init_weights()

    # Initialize the weights of the hidden layers
    def init_weights(self):
        for layer in self.layers:
            layer.weight.data.uniform_(*calculate_hidden_init_limits(layer))
            #layer.bias.data.uniform_(*calculate_hidden_init_limits(layer))

    def forward(self, x, type):

        x = self.b0(x) if self.batch_norm else x

        if type == "actor":
            if x.dim() == 1:
                print("X dim is 1")
                x = x.unsqueeze(0)

            if self.batch_norm is True:
                for layer,activation_fun, batch_norm in zip(self.layers, self.activations, self.batch_norms):
                    x = activation_fun(batch_norm(layer(x)))
            else:
                for layer,activation_fun in zip(self.layers, self.activations):
                    x = activation_fun(layer(x))

        elif type == "critic":

            for layer, activation_fun in zip(self.layers, self.activations):
                x = activation_fun(layer(x))

        if self.output_activation is not None:
            if self.upper_bound is not None:
                return self.output_activation(self.readout(x)) * self.upper_bound
            else:
                return self.output_activation(self.readout(x))
        else:
            return self.readout(x)

    def predict(self, x):

        with torch.no_grad():
            try:
                x = torch.from_numpy(x.astype(np.float32)).numpy()
            except:
                x = x

            for layer, activation_fun in zip(self.layers, self.activations):
                x = activation_fun(layer(x))
            if self.output_activation is not None:
                if self.upper_bound is not None:
                    return self.output_activation(self.readout(x)) * self.upper_bound
                else:
                    return self.output_activation(self.readout(x))
            else:
                return self.readout(x)


from fastapi import FastAPI, Request
# from log import logger, init_logger
from logger import init_logging
from loguru import logger
import logging

app = FastAPI()

init_logging()

@app.get("/")
async def root(request: Request):
    logger.info("loguru info log")
    logging.info("logging info log")

    logging.getLogger("fastapi").debug("fatapi info log")
    logger.bind(payload=dict(request.query_params)).debug("params with formating")

    print("Hi")
    return {"message": "Hello World"}


from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from .models import Response
from .models import Notification

@receiver(post_save, sender=Response)
def student_response_add_notify(sender, instance, **kwargs):
    print('Hello')
    try:
        recipient = instance.assignment.get_teacher()
        message = "{}: Nueva respuesta de {} en {}.".format(instance.assignment.subject,
                                                            instance.student, instance.assignment)
        response_id = instance.id
        Notification.objects.create(
            sender=instance.student.user, recipient=recipient,
            message=message,
            response_id=response_id)
    except KeyError as e:
        print(e)
        return False

@receiver(post_delete, sender=Response)
def delete_student_response_notification(sender, instance, **kwargs):
    try:
        notification = Notification.objects.filter(response_id=instance.id)
        notification.delete()
    except:
        pass


import getServerInfo
import asyncio
import time
import datetime
import json
import os
import discord
from discord.ext import commands
from discord import app_commands
from discord.ext import tasks

try:
	import config # import configuration stuff locally
except ImportError:
	print("Hey! You don't have a valid bot token yet! Go edit config.py before trying again!")
	import shutil
	shutil.copy('config.py.template', 'config.py')
	import sys
	sys.exit(1)

if not os.path.isfile("servers.txt"):
	open("servers.txt",'w').close()
servers = open('servers.txt','r').readlines()

if config.token == "your token here":
	print("Hey! You don't have a valid bot token yet! Go edit config.py before trying again!")
	import sys
	sys.exit(1)
else:
	token = config.token

imgDir = config.imageDir

cooldown = config.time_delay * 60

client = commands.Bot(command_prefix="!!!!!", intents = discord.Intents.default())

if config.owner_id == "-1":
	print("Hey! No owner ID is set up. Some commands may not work without the owner running them, and could crash the bot. To change this, edit config.py")
else:
	client.owner_id = config.owner_id

#class MyClient(discord.Client):
#	async def on_ready(self):
#		print("Logged in as {}".format(self.user))
#		owner = await self.fetch_user(280804464355573770)
#		if owner != None:
#			await owner.send("Ayo! Bot online!")
#			await owner.send("Current servers: {}".format(servers))
#		else:
#			print("Bad user id")

#	@client.command(name="testcommand")
#	async def testcommand(interaction: discord.Interaction, message: discord.Message):
#		await interaction.send_message(content="it Worked!")

updateStuff = []

def updateServers():
	updateStuff = []
	if os.stat("servers.txt").st_size != 0:
		file = open("servers.txt", 'r')
		for x in file.readlines():
#			print("ayo {}".format(x))
			x = x.split("\t")
			updateStuff.append([x[0],x[1],x[2].strip("\n")])
#		print("Persistent messages updated! {}".format(updateStuff))
#	else:
#		print("No persistent messages to update")
	return updateStuff

@discord.ext.tasks.loop(minutes=5,reconnect=True)
async def updateMessages():
	while True:
		updateStuff = updateServers()
#		print("messages updating: {}".format(updateStuff))
		if len(updateStuff) > 0:
			for x in updateStuff:
				if x[0] != '-1':
					ip = x[0]
					status = getServerInfo.getInfo(ip)
					if status != None:
						getServerInfo.getImage(ip)
						img = discord.File(imgDir + "image.png")
						embed = discord.Embed()
						embed.color = discord.Color.green()
						players = ""
						isOk = True
						if status["players"]["online"] > 0:
							for i in range(len(status["players"]["sample"])):
								temp = status["players"]["sample"][i]["name"]
								if temp.startswith('.'):
									temp = temp[1:]
								players = players + temp
								if i+1 < len(status["players"]["sample"]):
									players = players + ", "
								if not status["players"]["sample"][i]["name"].isalnum() and not status["players"]["sample"][i]["name"].startswith('.'):
									isOk = False
#								print("Length: {}".format(len(players)))
						if len(players) != 0 and isOk:
							if len(status["players"]["sample"]) < status["players"]["online"]:
								players = players + " + {} others.".format(status["players"]["online"] - len(status["players"]["sample"]))
							embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: {4}".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"], players)
						elif status["players"]["online"] == 0:
							embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: None".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"])
						else:
							embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: Not Available".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"])
#						embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: {4}".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"], players)
						embed.title="Server is Online!"
						embed.set_thumbnail(url="attachment://image.png")
#						if len(status["players"
						img = discord.File(imgDir + "image.png")
					else:
						embed = discord.Embed()
						embed.color = discord.Color.red()
						embed.title="Server is unreachable!"
						embed.description = "The server `{}` is either offline, or it doesn't exist.".format(ip)
						img = discord.File(imgDir + "fail.png")
						embed.set_thumbnail(url=f"attachment://fail.png")
#					embed.set_footer(text="Last updated: <t:{:.0f}:R>".format(time.time()))
					embed.timestamp = datetime.datetime.utcnow()
					channel = await client.fetch_channel(x[2])
					msg = await channel.fetch_message(x[1])
#					print("Message content: {}".format(msg.content))
					await msg.edit(embed=embed, content="", attachments=[img])
		await asyncio.sleep(cooldown)

@client.event
async def on_ready():
	owner = await client.fetch_user(client.owner_id)
#	await owner.send("Ayo 2!")
#	print("It worked maybe")
	await client.tree.sync()
#	print("Commands Synced")
#	updateStuff = []
	updateServers()
	updateMessages.start()
#	if len(updateStuff) > 0:
#		print("Servers: {}".format(updateStuff))
#	else:
#		print("No servers being updated")
##	asyncio.ensure_future(updateMessages())
#	asyncio.set_event_loop(updateMessages())
##	loop.run_forever
	print("Bot successfully connected to {0} at {1}:{2}".format(client.user.display_name, datetime.time().hour, datetime.time().minute))

@client.tree.command(name="testcommand", description="don't use, or do.")
async def testcommand(interaction: discord.Interaction):
	await interaction.response.send_message("No, you're a test", ephemeral=True)

@client.tree.command(name="serverstatus", description="Check on the status of a server!")
@app_commands.describe(ip="IP to get the status of")
async def serverstatus(interaction: discord.Interaction, ip: str):
	status = getServerInfo.getInfo(ip)

	if status != None:
		getServerInfo.getImage(ip)
		img = discord.File(imgDir + "image.png")
		embed = discord.Embed()
		embed.color = discord.Color.green()
		players = ""
		isOk = True
		if status["players"]["online"] > 0:
			for x in range(len(status["players"]["sample"])):
				temp = status["players"]["sample"][x]["name"]
				if temp.startswith('.'):
					temp = temp[1:]
				players = players + temp
				if x+1 < len(status["players"]["sample"]):
					players = players + ", "
				if not status["players"]["sample"][x]["name"].isalnum() and  not status["players"]["sample"][x]["name"].startswith('.'):
					isOk = False
#			print("Length: {}".format(len(players)))
		if len(players) != 0 and isOk:
			if len(status["players"]["sample"]) < status["players"]["online"]:
				players = players + " + {} others.".format(status["players"]["online"] - len(status["players"]["sample"]))

			embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: {4}".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"], players)
		elif status["players"]["online"] == 0:
			embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: None".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"])
		else:
			embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: Not Available".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"])
#		embed.description = "IP: {0}\nVersion: {1}\nPlayers count: {2}/{3}\nPlayers: {4}".format(ip,status["version"]["name"],status["players"]["online"],status["players"]["max"], players)
		embed.title="Server is Online!"
		embed.set_thumbnail(url=f"attachment://image.png")
#		if len(status["players"
	else:
		embed = discord.Embed()
		embed.color = discord.Color.red()
		embed.title="Server is unreachable!"
		embed.description = "The server `{}` is either offline, or it doesn't exist.".format(ip)
		img = discord.File(imgDir + "fail.png")
		embed.set_thumbnail(url=f"attachment://fail.png")
#	embed.set_footer(text="Last updated: <t:{:.0f}:R>".format(time.time()))
	embed.timestamp = datetime.datetime.utcnow()
	await interaction.response.send_message(embed= embed, file=img)

@client.tree.command(name="watchserver", description="will create a permanent message to constantly update a server's status")
@app_commands.describe(ip="IP to keep updates for", channel_id="Which channel to put the message in. Use \"here\" for the current channel")
async def watchserver(interaction: discord.Interaction, ip: str, channel_id: str):
#	print("start")
	if channel_id == "here":
		channel_id = interaction.id
	try:
		Channel = await client.fetch_channel(channel_id)
	except NotFound:
		await interaction.response.send_message("Invalid Channel ID!", ephemeral=True)
	try:
		msgID = await Channel.send("Awaiting update!")
	except Forbidden:
		await interaction.response.send_message("Unable to send a message in that channel! Do I not have permission? :(", ephemeral=True)
	with open("servers.txt", "r+") as file:
		lines = file.readlines()
		lines = lines[:-1]
#		file.write(lines)

	file = open("servers.txt",'a')
	for i in lines:
		file.write(i)
	file.write("{}\t{}\t{}\n".format(ip,msgID.id,channel_id))
	file.write("-1\t-1\t-1")
	file.close()
	print("done")
	updateServers()
	await interaction.response.send_message("Message Sent!", ephemeral=True, delete_after=60)

@client.tree.command(name="serverjson")
@app_commands.describe(ip="IP for the json obtaining")
async def serverjson(interaction: discord.Interaction, ip: str):
	status = getServerInfo.getInfo(ip)
	if status != None:
		try:
			await interaction.response.send_message("Json response from {0}:\n{1}".format(ip,status))
		except discord.errors.HTTPException:
			await interaction.response.send_message("Error: json too long! Go to <https://api.mcstatus.io/v2/status/java/{0}>".format(ip), ephemeral=True)
	else:
		await interaction.response.send_message("Error: No server found. Either the server is offline, or check the IP and try again", ephemeral=True, delete_after=30)

@client.tree.command(name="removestatus", description="Remove messages from updates")
@app_commands.describe(message_id="Message ID to remove from updates (use * to remove all)")
async def removestatus(interaction: discord.Interaction, message_id: str):
	if channel_id == '*':
		file = open("servers.txt",'w')
		file.close()
		updateServers()
		await interaction.response.send_message("All update messages have been removed from memory!")
	else:
		with open("servers.txt", 'r') as file:
			lines = file.readlines()
		with open("servers.txt", 'w') as file:
			content = ""
			for x in lines:
				temp = x
				x.strip("\n")
				x = x.split("\t")
				if x[1] != message_id:
					file.write(temp)
		await interaction.response.send_message("Message has been removed from updates!")

@client.tree.command(name="help", description="display the list of commands, and their uses")
async def help(interaction: discord.Interaction):
	embed = discord.Embed()
	embed.color = discord.Color.blue()
	embed.title = "Minecraft Server Bot Help!"
	embed.description = "This bot is designed to allow you to easily check the status of different minecraft servers!\n**__Commands:__**\n> /serverstatus - check the status of a server\n> /watchserver - create an automatically-updating message, displays the same info as /serverstatus\n> /removestatus - tells the bot to stop updating the message set from /watchserver\n> /serverjson - get the raw json status from a server"
	embed.set_footer(text="Created by Nathan Fullerton")
	embed.set_thumbnail(url=client.user.avatar.url)
	await interaction.response.send_message(embed=embed, ephemeral = True)

if __name__ == "__main__":
#	await client.tree.sync()
#	await asyncio.gather()
#	updateMessages.start()
	client.run(token)


from typing import List, Set

from .attribute_specification import AttributeSpecification as As
from .grid_edge import GridEdge
from .bus import Bus
from ..values.grid_value_context import GridValueContext as Gvc
from ..values.units.scale import Scale
from ..values.units.unit import Unit
from ...network.configuration.providers.power_grid_provider_info import PowerGridProviderInfo

class DcLine(GridEdge):
    prefix = "dcline"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    @staticmethod
    def get_specifications() -> List[As]:
        return [
            As("name", Gvc.GENERIC, str, None, required=False),
            As("observable", Gvc.GENERIC, bool, True, required=False),

            As("from_bus", Gvc.PROPERTY, Bus, None),
            As("to_bus", Gvc.PROPERTY, Bus, None),
            As("loss_relative", Gvc.PROPERTY, float, None, Unit.PERCENT),
            As("loss_total", Gvc.PROPERTY, float, None, Unit.WATT, Scale.BASE),
            As("maximum_active_power", Gvc.PROPERTY, float, None, Unit.WATT, Scale.BASE, required=False),
            As("minimum_reactive_power_from", Gvc.PROPERTY, float, None, Unit.VAR, Scale.BASE, required=False),
            As("maximum_reactive_power_from", Gvc.PROPERTY, float, None, Unit.VAR, Scale.BASE, required=False),
            As("minimum_reactive_power_to", Gvc.PROPERTY, float, None, Unit.VAR, Scale.BASE, required=False),
            As("maximum_reactive_power_to", Gvc.PROPERTY, float, None, Unit.VAR, Scale.BASE, required=False),

            As("in_service", Gvc.CONFIGURATION, bool, True),
            As("active_power", Gvc.CONFIGURATION, float, None, Unit.WATT, Scale.BASE),
            As("voltage_from_bus", Gvc.CONFIGURATION, float, None, Unit.PER_UNIT),
            As("voltage_to_bus", Gvc.CONFIGURATION, float, None, Unit.PER_UNIT),

            As("active_power_from", Gvc.MEASUREMENT, float, None, Unit.WATT, Scale.BASE, required=False),
            As("reactive_power_from", Gvc.MEASUREMENT, float, None, Unit.VAR, Scale.BASE, required=False),
            As("active_power_to", Gvc.MEASUREMENT, float, None, Unit.WATT, Scale.BASE, required=False),
            As("reactive_power_to", Gvc.MEASUREMENT, float, None, Unit.VAR, Scale.BASE, required=False),
            As("active_power_loss", Gvc.MEASUREMENT, float, None, Unit.WATT, Scale.BASE, required=False),
            As("voltage_from_bus", Gvc.MEASUREMENT, float, None, Unit.PER_UNIT, required=False),
            As("voltage_to_bus", Gvc.MEASUREMENT, float, None, Unit.PER_UNIT, required=False),
            As("voltage_angle_from_bus", Gvc.MEASUREMENT, float, None, Unit.DEGREE, required=False),
            As("voltage_angle_to_bus", Gvc.MEASUREMENT, float, None, Unit.DEGREE, required=False),
        ]


import sys, os, time
import importlib
importlib.reload(sys)
from input_data import DataLoader, bacth_yield, padding
import argparse
import tensorflow as tf
import utils
from tensorflow.contrib.rnn import BasicRNNCell, LSTMCell
from tensorflow.python.layers import core as layers_core
import sacrebleu
import numpy as np
from collections import Counter

def parse_args():
    parser = argparse.ArgumentParser()
    # 训练数据路径
    parser.add_argument('--train_src_path', type = str, default = './data/train.zh.tok')
    parser.add_argument('--train_target_path', type = str, default = './data/train.en.tok')
    # 验证数据路径
    parser.add_argument('--valid_src_path', type = str, default = './data/valid.zh.tok')
    parser.add_argument('--valid_target_path', type = str, default = './data/valid.en.tok')
    # 测试数据路径
    parser.add_argument('--test_src_path', type = str, default = './data/test.zh.tok')
    parser.add_argument('--test_target_path', type = str, default = './data/test.en.tok')
    # 测试结果输出路径
    # parser.add_argument('--result_path', type = str, default = './result/translate.en.tok')
    # 日志记录路径
    parser.add_argument('--log_path', type = str, default = 'log.txt')
    # 训练轮数
    parser.add_argument('--epochs', type = int, default = 10)
    # batch_size
    parser.add_argument('--batch_size', type = int, default = 64)
    # embedding_dim
    parser.add_argument('--embedding_dim', type = int, default = 300)
    # hidden_dim
    parser.add_argument('--hidden_dim', type = int, default = 300)
    # learning_rate
    parser.add_argument('--learning_rate', type = float, default = 0.001)
    # mode, 设置是训练模型train, 还是根据模型预测infer
    parser.add_argument('--mode', type = str, default = 'train', help = 'train / infer')
    # beam_width
    parser.add_argument('--beam_width', type = int, default = 2)
    # model_path
    parser.add_argument('--model_path', type = str, default = '')
    return parser.parse_args()

class NMT():
    def __init__(self, args, train_loader, valid_loader, test_loader):
        self.args = args
        self.train_loader = train_loader
        self.valid_loader = valid_loader
        self.test_loader = test_loader
        self.add_placeholder()
        self.add_embedding()
        self.build_encoder()
        self.build_decoder()
        self.loss_op()
        self._init_op()
        # 日志记录
        self.logger = utils.get_logger(self.args.log_path)

    # 设置placeholder
    def add_placeholder(self):
        # encoder输入
        self.encoder_inputs = tf.placeholder(tf.int32, [None, None], name = 'encoder_inputs')
        # encoder输入长度
        self.encoder_inputs_length = tf.placeholder(tf.int32, [None], name = 'encoder_inputs_length')
        # decoder输入
        self.decoder_inputs = tf.placeholder(tf.int32, [None, None], name = 'decoder_inputs')
        # decoder输出
        self.decoder_outputs = tf.placeholder(tf.int32, [None, None], name = 'decoder_outputs')
        # decoder输入\输出长度
        self.decoder_length = tf.placeholder(tf.int32, [None], name = 'decoder_length')
        # 最大输出序列长度
        self.max_decoder_length = tf.reduce_max(self.decoder_length, name = 'max_decoder_length')
        # 设置dropout
        self.dropout = tf.placeholder(dtype=tf.float32, shape=[], name="dropout")

    # 设置共享embedding层
    def add_embedding(self):
        with tf.variable_scope('embedding'):
            # 输入层嵌入
            # shape(src_vocab_size, embedding_dim)
            self.embeddings_zh = tf.Variable(tf.random_uniform([self.train_loader.src_vocab_size, self.args.embedding_dim], -1.0, 1.0), name = 'embeddings_zh')

            # 输出层嵌入
            # shape(target_vocab_size, embedding_dim)
            self.embeddings_en = tf.Variable(tf.random_uniform([self.train_loader.target_vocab_size, self.args.embedding_dim], -1.0, 1.0), name = 'embeddings_en')

    # 构建编码器
    def build_encoder(self):
        with tf.variable_scope('encoder'):
            # 查找词向量
            # shape(None, None, embedding_dim)
            encoder_emb_in = tf.nn.embedding_lookup(self.embeddings_zh, self.encoder_inputs)
            # dropout
            encoder_emb_in = tf.nn.dropout(encoder_emb_in, self.dropout)
            # 本来使用的BasicRNNCell, 在训练过程中会梯度爆炸, 改成LSTMCell
            encoder_cell = LSTMCell(self.args.hidden_dim)
            # encoder_outputs存放着隐藏层的输出，encoder_state是最后一次隐藏层的输出
            self.encoder_outputs, self.encoder_state = tf.nn.dynamic_rnn(cell = encoder_cell,
                                                                         inputs = encoder_emb_in,
                                                                         sequence_length = self.encoder_inputs_length,
                                                                         dtype = tf.float32)
    # 构建解码器
    def build_decoder(self):
        with tf.variable_scope('decoder') as scope:
            # 定义BasicRNNCell decoder_cell
            decoder_cell, decoder_initial_state = self._build_decoder_cell()

            # 解码器输出的全连接层
            # shape(hidden_dim, target_vocab_size)
            projection_layer = layers_core.Dense(self.train_loader.target_vocab_size, use_bias = False)
            maximum_iterations = self.max_decoder_length

            if self.args.mode == 'train':
                # 查找词向量
                # shape(None, None, embedding_dim)
                decoder_emb_in = tf.nn.embedding_lookup(self.embeddings_en, self.decoder_inputs)
                # dropout
                decoder_emb_in = tf.nn.dropout(decoder_emb_in, self.dropout)

                # Helper
                # 接收参数
                # inputs: shape(batch_size, seqlen, embedding_dim)
                # sequence_length: 真实的句子长度
                training_helper = tf.contrib.seq2seq.TrainingHelper(inputs = decoder_emb_in,
                                                                    sequence_length = self.decoder_length)
                # 解码器
                training_decoder = tf.contrib.seq2seq.BasicDecoder(cell = decoder_cell,
                                                                   helper = training_helper,
                                                                   initial_state = decoder_initial_state,
                                                                   output_layer = projection_layer)
                # 解码
                decoder_outputs, final_context_state, _ = tf.contrib.seq2seq.dynamic_decode(decoder = training_decoder, scope = scope)

                self.decoder_sample_id = decoder_outputs.sample_id
                self.logits = decoder_outputs.rnn_output
                self.decoder_final_context_state = final_context_state

            elif self.args.mode == 'infer':
                start_tokens = tf.ones([self.args.batch_size,], tf.int32) * self.train_loader.target_word2id['<START>']
                end_token = self.train_loader.target_word2id['<END>']
                # 解码器, 使用BeamSearch方法
                inference_decoder = tf.contrib.seq2seq.BeamSearchDecoder(cell = decoder_cell,
                                                                            embedding = self.embeddings_en,
                                                                            start_tokens = start_tokens,
                                                                            end_token = end_token,
                                                                            initial_state = decoder_initial_state,
                                                                            beam_width = self.args.beam_width,
                                                                            output_layer = projection_layer)
                # 解码
                decoder_outputs, final_context_state, _ = tf.contrib.seq2seq.dynamic_decode(decoder = inference_decoder,
                                                                                maximum_iterations = maximum_iterations,
                                                                                scope = scope)

                self.logits = tf.no_op()
                self.predicted_sample_id = decoder_outputs.predicted_ids

    def _build_decoder_cell(self):
        beam_width = self.args.beam_width
        # memory保存着前面隐藏层的输出，用于做attention计算
        # shape(None, None, hidden_dim)
        # encoder_state是encoder最后隐藏层输出
        memory, encoder_state, encoder_inputs_length = self.encoder_outputs, self.encoder_state, self.encoder_inputs_length

        # beam search是神经序列生成模型最基本的解码算法
        if self.args.mode == 'infer' and beam_width > 0:
            # 将batch内的每个样本复制beam_width次
            memory = tf.contrib.seq2seq.tile_batch(memory, multiplier = beam_width)
            encoder_state = tf.contrib.seq2seq.tile_batch(encoder_state, multiplier = beam_width)
            encoder_inputs_length = tf.contrib.seq2seq.tile_batch(encoder_inputs_length, multiplier = beam_width)
            batch_size = self.args.batch_size * beam_width
        else:
            batch_size = self.args.batch_size

        # attention模块
        attention_mechanism = tf.contrib.seq2seq.LuongAttention(self.args.hidden_dim, memory = memory,
                                                                memory_sequence_length = encoder_inputs_length)
        # 本来使用的BasicRNNCell, 在训练过程中会梯度爆炸, 改成LSTMCell
        basic_cell = LSTMCell(self.args.hidden_dim)
        # 应该是basic_cell和attention模块结合, 实现attention机制
        cell = tf.contrib.seq2seq.AttentionWrapper(basic_cell, attention_mechanism,
                                                   attention_layer_size = self.args.hidden_dim,
                                                   output_attention = True,
                                                   name = 'attention')
        # 定义decoder阶段的初始化状态，直接使用encoder阶段的最后一个隐层状态进行赋值
        decoder_initial_state = cell.zero_state(batch_size, tf.float32).clone(cell_state = encoder_state)
        return cell, decoder_initial_state

    def loss_op(self):
        if self.args.mode == 'train':
            max_times = self.max_decoder_length
            # 计算交叉熵
            crossent = tf.nn.sparse_softmax_cross_entropy_with_logits(labels = self.decoder_outputs,
                                                                      logits = self.logits)
            # 设置mask, 屏蔽掉padding部分数据, 是二进制向量
            target_weights = tf.sequence_mask(self.decoder_length, max_times, dtype = self.logits.dtype)
            # 定义loss
            self.train_loss = (tf.reduce_sum(crossent * target_weights) / self.args.batch_size)
            # 设置优化方法
            optim = tf.train.AdamOptimizer(learning_rate = self.args.learning_rate)
            self.train_op = optim.minimize(self.train_loss)

    # 初始化变量
    def _init_op(self):
        self.init_op = tf.global_variables_initializer()

    # 模型训练
    def train(self):
        config = tf.ConfigProto()
        config.gpu_options.allow_growth = True
        saver = tf.train.Saver(tf.global_variables())
        with tf.Session(config = config) as sess:
            sess.run(self.init_op)
            for epoch in range(self.args.epochs):
                self.run_one_epoch(sess, epoch, saver)
    # 训练一轮
    def run_one_epoch(self, sess, epoch, saver):
        num_batches = (len(self.train_loader.data) + self.args.batch_size - 1) // self.args.batch_size
        start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        train_batches = bacth_yield(self.train_loader.data, self.args.batch_size, shuffle = True)
        for step, (src, target_in, target_out) in enumerate(train_batches):
            sys.stdout.write(' processing: {} batch / {} batches.'.format(step + 1, num_batches) + '\r')
            step_num = epoch * num_batches + step + 1
            # 填充
            encoder_inputs, encoder_inputs_length, decoder_inputs, decoder_outputs, decoder_length = padding(src, target_in, target_out, pad_mark = 3)
            # 构造馈送的数据
            feed_dict = {
                self.encoder_inputs: encoder_inputs,
                self.encoder_inputs_length: encoder_inputs_length,
                self.decoder_inputs: decoder_inputs,
                self.decoder_outputs: decoder_outputs,
                self.decoder_length: decoder_length,
                self.dropout: 0.5
            }
            # 计算loss
            _, loss_train = sess.run([self.train_op, self.train_loss], feed_dict = feed_dict)

            if step + 1 == 1 or (step + 1) % 300 == 0 or step + 1 == num_batches:

                self.logger.info('{} epoch {}, step {}, loss: {:.4}, global_step: {}'.format(start_time, epoch + 1,
                                                                                step + 1,loss_train, step_num))
            if step + 1 == num_batches:
                saver.save(sess, self.args.model_path, global_step = step_num)

    def test(self):
        self.logger.info('===========test, beam width: %d===========' %self.args.beam_width)
        all_candidates = []
        config = tf.ConfigProto()
        config.gpu_options.allow_growth = True
        with tf.Session(config = config) as sess:
            sess.run(tf.global_variables_initializer())
            saver = tf.train.Saver(tf.global_variables())
            # 载入模型
            saver.restore(sess, self.args.model_path)

            test_batches =  bacth_yield(self.test_loader.data, self.args.batch_size, shuffle = False)
            for i, (src, target_in, target_out) in enumerate(test_batches):
                sys.stdout.write('evaluating: #{} batch'.format(i + 1) + '\r')
                encoder_inputs, encoder_inputs_length, _, _, decoder_length = padding(src, target_in, target_out, pad_mark = 3)
                # 构造馈送的数据
                feed_dict = {
                    self.encoder_inputs: encoder_inputs,
                    self.encoder_inputs_length: encoder_inputs_length,
                    self.decoder_length: decoder_length,
                    self.dropout: 1.0
                }
                # 模型预测
                predict = sess.run([self.predicted_sample_id], feed_dict=feed_dict)
                predict = np.array(predict)
                temp = predict[0]
                for item in temp:
                    sent = []
                    # beam search选择概率最大的一句输出
                    for beam_item in item:
                        most_common_res = Counter(list(beam_item)).most_common(1)[0][0]
                        sent.append(most_common_res)
                    # 去除END_ID
                    if utils.END_ID in sent:
                        sent = sent[:sent.index(utils.END_ID)]
                    # 从单词id还原出单词
                    sent_word = utils.id2sentence(sent, self.train_loader.target_id2word)
                    all_candidates.append(sent_word)

            # 讲预测的结果写入infer.en.tok中
            with open('infer.en.tok', 'w') as f:
                candicates = [' '.join(line) + '\n' for line in all_candidates]
                f.writelines(candicates)
            # 将参考的结果写入ref.en.tok中
            with open('ref.en.tok', 'w') as f:
                target_lines = [' '.join(line) + '\n' for line in self.test_loader.target_lines]
                # 由于测试按batch_size划分, 导致原始的测试数据部分丢失, 于是使用切片，只保留与candicates同样长度的部分。
                f.writelines(target_lines[:len(candicates)])
            # 逐句测试
            bleuscore = []
            for syst, ref in zip(all_candidates, self.test_loader.target_lines):
                syst = ' '.join(syst)
                ref = ' '.join(ref)
                bleu = sacrebleu.corpus_bleu(syst, ref)
                bleuscore.append(bleu.score)
            # 求bleuscore均值
            self.logger.info('\nbleuscore: %f' %np.mean(bleuscore))

if __name__ == '__main__':
    args = parse_args()

    # 训练数据
    train_loader = DataLoader(args.train_src_path, args.train_target_path,3)
    # 验证数据
    valid_loader = DataLoader(args.valid_src_path, args.valid_target_path,3)
    # 测试数据
    test_loader = DataLoader(args.test_src_path, args.test_target_path,3)

    if args.mode == 'train':
        print ("\n训练模式...")
        timestamp = str(time.strftime('%Y-%m-%d %H-%M-%S', time.localtime(time.time())))
        args.model_path = os.path.join('.', "model", timestamp + "/")
        if not os.path.exists(args.model_path): os.makedirs(args.model_path)
    else:
        timestamp = args.model_path
        args.model_path = os.path.join('.', "model", timestamp + "/")
        print ("\n加载的模型是：", timestamp, '\n')

    if args.mode == 'train':
        model = NMT(args, train_loader, valid_loader, test_loader)
        model.train()
    elif args.mode == 'infer':
        args.model_path = tf.train.latest_checkpoint(args.model_path)
        model = NMT(args, train_loader, valid_loader, test_loader)
        print ("=============================")
        model.test()


import datetime
import json
from interval import intervalRandOrNot
from sendMail import sendMail

def sender(mails,repet=1,interval=-1,approx=-1):
    repet = int(repet)
    dateStart = datetime.datetime.today()
    spaceTime = intervalRandOrNot(interval,approx)

    count = 0

    stop = False

    while stop != True :
        diffTmstp = datetime.datetime.today().timestamp() - dateStart.timestamp()

        if (diffTmstp >= spaceTime["spaceTime"]):

            mailToRemoveList = []

            for mail in mails :

                sendPending = sendMail(mail)
                logFile = '..\logs\log_' + str(datetime.datetime.today().timestamp())+ '.json'

                if sendPending["error"] != -1:

                    logContent = {
                        "mail" :{
                            "sendTime":str(datetime.datetime.today()),
                            "diffTime":str(spaceTime["randomInterval"]),
                            "sender":mail["email_address"],
                            "receiver": mail["email_receiver"]
                            }
                        }
                    dateStart = datetime.datetime.today()
                    spaceTime = intervalRandOrNot(spaceTime["interval"],spaceTime["approx"])

                else :

                    logContent = {
                        "error" : {
                            "errorTime":str(datetime.datetime.today()),
                            "errorMsg":str(sendPending["errorText"]),
                            "sender":mail["email_address"],
                            "receiver": mail["email_receiver"]
                        }
                    }
                    mailToRemoveList.append(mail)

                f = open(logFile, 'w')
                json.dump(logContent,f)
                f.close()

            for mailToRemove in mailToRemoveList:

                mails.remove(mailToRemove)

                if len(mails)<1:
                    return None
            count += 1
            if count == repet:
                stop = True


from collections import deque
n = int(input())

def d(p1, p2):
    return ((p1[0]-p2[0])**2+(p1[1]-p2[1])**2)**0.5

p = [[*map(int, input().split())]for _ in range(n)]
g = [[]for _ in range(n)]
for i in range(n-1):
    for j in range(i+1, n):
        dist = d(p[i], p[j])
        g[i].append((dist, j))
        g[j].append((dist, i))

dp = [[1e9]*n for _ in range(1 << n)]
r = 1e9
q = deque([(1, 0)])
dp[1][0] = 0
while q:
    qry, now = q.popleft()
    if qry+1 == 1 << n:
        r = min(r, dp[qry][now] + g[now][0][0])
        continue
    for next_dist, next_node in g[now]:
        if qry & ~(1 << next_node) and dp[qry | (1 << next_node)][next_node] > dp[qry][now]+next_dist:
            dp[qry | (1 << next_node)][next_node] = dp[qry][now]+next_dist
            q.append((qry | (1 << next_node), next_node))

print(r)


from django.contrib import admin
from django.urls import path,include
from . import views

urlpatterns=[

     path('', views.products, name='products'),
     path('product_details<int:id>/', views.product_details, name = 'product_details'),
     path('add_product/<int:id>', views.add_product, name='add_product'),
     path('delete_product<int:id>', views.delete_product, name = 'delete_product'),
     path('edit_product<int:id>/', views.edit_product, name = 'edit_product')

]