import tkinter as tk
from tkinter import ttk
import ttkbootstrap as ttkb
import custom_widget as tkpp
import pandas as pd
import joblib
import os
from PIL import Image,ImageTk
import ttkbootstrap.themes.user
import datetime
import lists
import numpy as np
from time import sleep
import tkinter.messagebox

model_path='model.pkl'
train_origin_path='train.csv'
test_origin_path='test.csv'
test_modified_path='test_modified.csv'
submission_path='submission.csv'
images_path='picture'
main_page_bg_path='images/main_page_bg.jpg'
sub_bg_path='images/sub_bg.jpg'
pre_single_path='images/pre_single_bg.jpg'

style=ttkb.Style(theme='litera')
root=style.master
sw=root.winfo_screenwidth()//2
sh=root.winfo_screenheight()//2

main_page_window_size=(900,650)
data_browser_window_size=(1400,800)
data_browser_search_window_size=(1400,300)
pre_data_page_window_size=(250,610)
predict_page_search_window_size=(250,100)
pre_single_page_window_size=data_browser_window_size
element_select_window_size=pre_single_page_window_size
analysis_page_window_size=(935,800)
message_box_window_size=(200,100)

image_size=(200,200)

def resize(image,k):
    size=image.size
    return image.resize((int(size[0]*k),int(size[1]*k)))

def load_npy(name):
    return list(np.load('npy/%s.npy'%name,allow_pickle=True))

def set_window_position(root,pos):
    ws=pos
    root.geometry(str(ws[0])+'x'+str(ws[1]))
    root.geometry('+{}+{}'.format(sw-ws[0]//2,sh-ws[1]//2))
    root.resizable(0,0)

def multipleList(root,area,data=None,height=5,width=100,width_column=20,anchor='n',padding=(0,0,0,0),style='info',place_anchor='nw',relx=0,rely=0.1,command=None):#padding为表外留白
    ac=[]
    for i in range(len(area)):
        ac.append(i)
    ac=tuple(ac)

    tv=ttkb.Treeview(
        root,
        columns=ac,
        show='headings',
        height=height,
        padding=padding,
        bootstyle=style)

    for i in range(len(area)):
        tv.column(
            ac[i],
            width=int(width/len(area)),
            minwidth=width_column,
            stretch=True,
            anchor=anchor)

        tv.heading(ac[i],text=area[i])

    tv.bind('<Double-Button-1>',command)
    tv.place(anchor=place_anchor,relx=relx,rely=rely)

    if isinstance(data,pd.core.frame.DataFrame):
        for index, row in data.iterrows():
            tv.insert('','end',values=row.tolist())
    elif data==None:
        return tv
    else:
        for i in data:
            tv.insert('','end',values=i)
        return tv

class message_box:
    def __init__(self,content):
        self.root=ttkb.Toplevel(title=' ')
        set_window_position(self.root,message_box_window_size)
        ttkb.Label(
            self.root,
            text=content,
            bootstyle='dark').place(anchor='n',relx=0.5,rely=0.2)
        ttkb.Button(
            self.root,
            text='确定',
            bootstyle='primary',
            command=self.exit).place(anchor='n',relx=0.5,rely=0.55)

    def exit(self):
        self.root.destroy()

class data_browser:
    def __init__(self,path):
        if path==train_origin_path:
            self.root=ttkb.Toplevel(title='训练数据集')
        elif path==test_origin_path:
            self.root=ttkb.Toplevel(title='测试数据集')

        set_window_position(self.root,data_browser_window_size)

        image=Image.open(sub_bg_path)
        image=resize(image,1)
        bg=ImageTk.PhotoImage(image)
        cv =ttkb.Canvas(self.root,width=data_browser_window_size[0],height=data_browser_window_size[1])
        cv.pack()
        cv.create_image(data_browser_window_size[0]//2,data_browser_window_size[1]//2,image=bg)

        self.data=pd.read_csv(path)
        self.data2=self.data
        self.data=self.data.astype(str)
        self.features=list(self.data)
        size=len(self.data)

        self.balloon=None

        ttkb.Button(
            self.root,
            text='退出',
            bootstyle='primary',
            command=self.exit).place(anchor='n',relx=0.04,rely=0.05)

        self.search_layer=ttkb.Combobox(
            self.root,
            values=self.features,
            width=8,
            bootstyle="primary")
        self.search_layer.place(anchor='n',relx=0.75,rely=0.05)

        # self.search_layer.bind('<<ComboboxSelected>>',self.seperate)

        self.search_entry = ttkb.Entry(
            self.root,
            width=9,
            bootstyle='dark')
        self.search_entry.place(anchor='n', relx=0.83, rely=0.05)
        self.search_entry.bind('<Enter>',lambda event=True,x=0.80,y=0.05-0.03:self.balloon_show(event,x,y))
        self.search_entry.bind('<Leave>',self.balloon_hide)

        # self.left_search_entry=None
        # self.label_to=None
        # self.right_search_entry=None

        search_button=ttkb.Button(
            self.root,
            text='搜索',
            bootstyle='primary',
            command=self.search)
        search_button.place(anchor='n',relx=0.9,rely=0.05)

        multipleList(
            self.root,
            self.features,
            self.data,
            width=data_browser_window_size[0],
            width_column=100,
            height=38)

        show_size=ttkb.Label(
            self.root,
            bootstyle='info',
            text='共 '+str(size)+' 个样本')
        show_size.place(anchor='n',relx=0.05,rely=0.91)

        self.root.mainloop()

    # def seperate(self,event):
    #     _type=self.data2.dtypes[self.search_layer.get()]
    #     if _type==np.dtype('float64') or _type==np.dtype('int64'):
    #         self.search_entry.destroy()

    #         self.left_search_entry=ttkb.Entry(
    #             self.root,
    #             width=4,
    #             bootstyle='dart')
    #         self.left_search_entry.place(anchor='nw', relx=0.79, rely=0.05)

    #         self.label_to=ttkb.Label(
    #             self.root,
    #             text='~',
    #             bootstyle='dart')
    #         self.label_to.place(anchor='nw', relx=0.83, rely=0.055)

    #         self.right_search_entry=ttkb.Entry(
    #             self.root,
    #             width=4,
    #             bootstyle='dart')
    #         self.right_search_entry.place(anchor='nw', relx=0.844, rely=0.05)
    #     else:
    #         self.left_search_entry.destroy()
    #         self.label_to.destroy()
    #         self.right_search_entry.destroy()

    #         self.search_entry = ttkb.Entry(
    #             self.root,
    #             width=9,
    #             bootstyle='dark')
    #         self.search_entry.place(anchor='n', relx=0.83, rely=0.05)

    def balloon_show(self,event,x,y):
        _type=self.data2.dtypes[self.search_layer.get()]
        if _type==np.dtype('float64') or _type==np.dtype('int64'):
            self.balloon=ttkb.Label(
                self.root,
                text="输入单个数或用'-'分隔")
        else:
            self.balloon=ttkb.Label(
                self.root,
                text='输入单个值')
        self.balloon.place(relx=x,rely=y)

    def balloon_hide(self,event):
        self.balloon.destroy()

    def search(self):
        feature=self.search_layer.get()
        if self.data2.dtypes[self.search_layer.get()] == object:
            result=self.data.loc[self.data[feature]==self.search_entry.get()]
        else:
            try:
                sp=self.search_entry.get().split('-')
                if len(sp)==2:
                    bottom,top=sp
                    result=self.data.loc[(self.data2[feature]>=float(bottom))&(self.data2[feature]<=float(top))]
                else:
                    result=self.data.loc[self.data2[feature]==float(sp[0])]
                # print(bottom,top)

            except:
                message_box('请规范输入！')

        if len(result)>0:
            show=ttkb.Toplevel(title='搜索结果  共 '+str(len(result))+' 条结果')
            set_window_position(show,data_browser_search_window_size)
            multipleList(
                show,
                self.features,
                result,
                width=data_browser_window_size[0],
                width_column=100,
                height=16,
                style='success',
                rely=0.01)
        else:
            message_box('没有搜索到结果！')

    def exit(self):
        global root
        self.root.destroy()
        root.destroy()

class analysis_page:
    def __init__(self):
        self.root=ttkb.Toplevel(title='分析')

        set_window_position(self.root,analysis_page_window_size)

        size,self.image_names,self.images,self.images_origin=self.get_images()

        image=Image.open(sub_bg_path)
        image=resize(image,1)
        bg=ImageTk.PhotoImage(image)
        cv =ttkb.Canvas(self.root,width=analysis_page_window_size[0],height=analysis_page_window_size[1])
        cv.pack()
        cv.create_image(analysis_page_window_size[0]//2,analysis_page_window_size[1]//2,image=bg)

        pos=(3,4)
        self.c=0

        ttkb.Button(
            self.root,
            text='退出',
            bootstyle='primary',
            command=self.quit).place(relx=0.05,rely=0.02)

        pady=40
        x=analysis_page_window_size[0]
        y=analysis_page_window_size[1]-pady
        relx=1/8
        rely=1/6
        for i in range(pos[0]):
            if self.c>=size:
                break
            for j in range(pos[1]):
                if self.c>=size:
                    break
                frame=ttkb.Frame(self.root)
                frame.place(anchor='center',x=x*(relx+2*relx*j),y=y*(rely+2*rely*i)+pady)
                tk.Button(
                    frame,
                    image=self.images[self.c],
                    command=lambda x=self.c:self.zoom(x)).pack()
                ttkb.Label(
                    frame,
                    text=self.image_names[self.c]).pack()
                self.c+=1

        self.root.mainloop()

    def get_images(self):
        image_names=[i for i in os.listdir(images_path) if not i.startswith('.')]
        size=len(image_names)
        images=[]
        images_origin=[]
        for i in image_names:
            image=Image.open(images_path+'/'+i)
            if i=='热力图.jpg':
                image=resize(image,0.3)
                # image=image.resize((750,700),Image.BILINEAR)
            elif i=='多维关系图.jpg':
                image=resize(image,0.25)
                # image=image.resize((350,700),Image.BILINEAR)
            elif i=='前四个数量最多的房型密度图.jpg':
                image=resize(image,0.25)
                # image=image.resize((900,700),Image.BILINEAR)
            images_origin.append(image)
            image=image.resize(image_size,Image.BILINEAR)
            image=ImageTk.PhotoImage(image)
            images.append(image)
        image_names=[i.split('.')[0] for i in image_names]
        return size,image_names,images,images_origin

    def zoom(self,x):
        c=x
        root=ttkb.Toplevel(title='详情')

        size=list(self.images_origin[c].size)
        size[1]+=40
        set_window_position(root,size)

        cv =ttkb.Canvas(root,width=size[0],height=size[1])
        cv.pack()

        image=ImageTk.PhotoImage(self.images_origin[c])

        pic = cv.create_image(size[0]//2,(size[1]-40)//2,image=image)

        ttkb.Button(
            root,
            text='确定',
            command=lambda x=root:self.exit(x)).place(anchor='s',relx=0.5,rely=0.98)

        root.mainloop()

    def exit(self,x):
        global root
        x.destroy()
        root.destroy()

    def quit(self):
        global root
        self.root.destroy()
        root.destroy()

class pre_data_page:
    def __init__(self):
        self.root=ttkb.Toplevel(title='测试集预测')
        set_window_position(self.root,pre_data_page_window_size)

        try:
            self.data=pd.read_csv(submission_path)
        except FileNotFoundError:
            self.clf=joblib.load(model_path)
            self.data=self.predict()

        self.data['Price']=self.data['Price'].map(lambda x:'%.2f美元'%x)

        size=len(self.data)

        image=Image.open(sub_bg_path)
        image=resize(image,1)
        bg=ImageTk.PhotoImage(image)
        cv =ttkb.Canvas(self.root,width=pre_data_page_window_size[0],height=pre_data_page_window_size[1])
        cv.pack()
        cv.create_image(pre_data_page_window_size[0]//2,pre_data_page_window_size[1]//2,image=bg)

        ttkb.Button(
            self.root,
            text='退出',
            bootstyle='primary',
            command=self.exit).place(relx=0.05,rely=0.04)

        ttkb.Label(
            self.root,
            text='Id',
            bootstyle='primary').place(relx=0.30,rely=0.05)

        self.search_entry=ttkb.Entry(
            self.root,
            width=7,
            bootstyle='primary')
        self.search_entry.place(relx=0.4,rely=0.04)

        search_button=ttkb.Button(
            self.root,
            text='搜索',
            bootstyle='primary',
            command=self.search)
        search_button.place(relx=0.75,rely=0.04)

        multipleList(
                self.root,
                ['Id','Price'],
                self.data,
                width=pre_data_page_window_size[0]-20,
                width_column=60,
                height=29,
                place_anchor='n',
                relx=0.5)

        show_size=ttkb.Label(
            self.root,
            bootstyle='info',
            text='共 '+str(size)+' 个样本')
        show_size.place(relx=0.05,rely=0.93)

        self.root.mainloop()

    def predict(self):
        test_data=pd.read_csv(test_origin_path)
        test_sub=test_data.pop('Id')
        test_sub=test_sub.astype(int)
        test_data=pd.read_csv(test_modified_path)
        y_pred = self.clf.predict(test_data)
        price = []
        for i in range(len(test_sub)):
            price.append(y_pred[i])
        df_price = pd.DataFrame({'Price':price})
        # 将id列和预测出来的房价列拼接并输出submission文件
        df=pd.concat([test_sub,df_price],axis=1)
        df.to_csv(submission_path,header=['Id','Price'], index=False)
        return df

    def search(self):
        feature='Id'
        result=self.data.loc[self.data[feature]==int(self.search_entry.get())]
        if len(result)>0:
            show=ttkb.Toplevel(title='搜索结果  共 '+str(len(result))+' 条结果')
            set_window_position(show,predict_page_search_window_size)
            multipleList(
                show,
                ['Id','Price'],
                result,
                width=pre_data_page_window_size[0]-20,
                width_column=100,
                height=3,
                style='success',
                place_anchor='n',
                relx=0.5,
                rely=0.01)
        else:
            message_box('没有搜索到结果！')

    def exit(self):
        global root
        self.root.destroy()
        root.destroy()

class pre_single_page:
    def __init__(self):
        self.clf=joblib.load(model_path)
        self.root=ttkb.Toplevel(title='样本预测')
        set_window_position(self.root,pre_single_page_window_size)

        self.features_combobox=lists.features_combobox

        image=Image.open(pre_single_path)
        image=resize(image,0.5)
        bg=ImageTk.PhotoImage(image)
        cv =ttkb.Canvas(self.root,width=pre_single_page_window_size[0],height=pre_single_page_window_size[1])
        cv.pack()
        cv.create_image(pre_single_page_window_size[0]//2,pre_single_page_window_size[1]//2+7,image=bg)

        x=150
        combobox_y=130
        padx=300
        pady=70
        self.Region=self.combobox('Region',load_npy('Region'),'Los Angeles',x,combobox_y)
        self.State=self.combobox('State',load_npy('State'),'CA',x+padx,combobox_y)
        self.seperate(x-100,combobox_y-26,13,1,style='warning')

        date_entry_y=combobox_y+pady
        self.Listed_On=self.date_entry('Listed On','2021-01-13',x,date_entry_y)
        self.Last_Sold_On=self.date_entry('Last Sold On','2017-06-30',x+padx,date_entry_y)
        self.seperate(x-100,date_entry_y-26,13,1,style='info')

        elements_y=date_entry_y+pady
        self.Type=self.elements('Type','SingleFamily',x,elements_y)
        self.Heating=self.elements('Heating','Central',x+padx,elements_y)
        self.Cooling=self.elements('Cooling','Central Air',x,elements_y+pady)
        self.Parking=self.elements('Parking','Garage, Garage - Attached, Covered',x+padx,elements_y+pady)
        self.Bedrooms=self.elements('Bedrooms','3',x,elements_y+pady*2)
        self.Flooring=self.elements('Flooring','Wood',x+padx,elements_y+pady*2)
        self.Appliances_included=self.elements('Appliances included','Dishwasher, Dryer, Garbage disposal, Microwave, Range / Oven, Refrigerator, Washer',x,elements_y+pady*3)
        self.Laundry_features=self.elements('Laundry features','In Garage',x+padx,elements_y+pady*3)
        self.Parking_features=self.elements('Parking features','Garage, Garage - Attached, Covered',x,elements_y+pady*4)
        self.seperate(x-100,elements_y-26,13,7,style='primary')

        entry_y=combobox_y
        x=800
        self.Year_built=self.entry('Year built',2020,x,entry_y)
        self.Lot=self.entry('Lot',6098.0,x+padx,entry_y)
        self.Bathrooms=self.entry('Bathrooms',2.0,x,entry_y+pady)
        self.Full_bathrooms=self.entry('Full bathrooms',2.0,x+padx,entry_y+pady)
        self.Total_interior_livable_area=self.entry('Total interior livable area',1200.0,x,entry_y+pady*2)
        self.Total_spaces=self.entry('Total spaces',2.0,x+padx,entry_y+pady*2)
        self.Garage_spaces=self.entry('Garage spaces',2.0,x,entry_y+pady*3)
        self.Elementary_School_Score=self.entry('Elementary School Score',5.0,x+padx,entry_y+pady*3)
        self.Elementary_School_Distance=self.entry('Elementary School Distance',0.3,x,entry_y+pady*4)
        self.Middle_School_Score=self.entry('Middle School Score',6.0,x+padx,entry_y+pady*4)
        self.Middle_School_Distance=self.entry('Middle School Distance',0.6,x,entry_y+pady*5)
        self.High_School_Score=self.entry('High School Score',7.0,x+padx,entry_y+pady*5)
        self.High_School_Distance=self.entry('High School Distance',0.8,x,entry_y+pady*6)
        self.Tax_assessed_value=self.entry('Tax assessed value',510000.0,x+padx,entry_y+pady*6)
        self.Annual_tax_amount=self.entry('Annual tax amount',1395.0,x,entry_y+pady*7)
        self.Listed_Price=self.entry('Listed Price',799000.0,x+padx,entry_y+pady*7)
        self.Last_Sold_Price=self.entry('Last Sold Price',300000.0,x,entry_y+pady*8)
        self.Zip=self.entry('Zip',95123,x+padx,entry_y+pady*8)
        self.seperate(x-90,entry_y-26,13,13,style='danger')

        ttkb.Button(
            self.root,
            text='退出',
            bootstyle='primary',
            command=self.exit).place(anchor='ne',x=x-650,y=combobox_y-70)

        ttkb.Button(
            self.root,
            text='预测',
            bootstyle='success',
            command=self.predict).place(anchor='ne',x=x-650,y=elements_y+pady*6-50)

        self.labelframe=ttkb.Labelframe(
            self.root,
            text='预测结果',
            bootstyle='success')
        self.labelframe.place(anchor='nw',x=x-630,y=elements_y+pady*6-60)

        self.result=ttkb.Label(
            self.labelframe,
            width=16,
            bootstyle='success')
        self.result.pack()

        ttkb.Label(
            self.root,
            text='美元',
            bootstyle='success').place(anchor='nw',x=x-476,y=elements_y+pady*6-48)

        self.root.mainloop()

    def predict(self):
        def devide(data,name):
            data[name]=data[name].fillna('unknown')
            all=load_npy(name+'_devided')
            for i in all:
                data[name+'_'+str(i)]=data[name].map(lambda x:1 if i in x else 0)
            data.drop(columns=[name],inplace=True)

        def devide_time(data,name):
            data[name].fillna('0-0-0',inplace=True)
            data[name]=data[name].map(lambda x:x.split('-'))
            data[name+'_year']=data[name].map(lambda x:int(x[0]))
            data[name+'_month']=data[name].map(lambda x:int(x[1]))
            data[name+'_day']=data[name].map(lambda x:int(x[2]))
            data.drop(columns=[name],inplace=True)

        def one_hot(data,name):
            temp=load_npy(name+'_onehot')
            for i in temp:
                data[name+'_'+str(i)]=data[name].map(lambda x:1 if x==i else 0)
            data.drop(columns=[name],inplace=True)

        data=pd.DataFrame()
        data['Type']=[self.Type.get()]
        data['Year built']=[self.Year_built.get()]
        data['Heating']=[self.Heating.get()]
        data['Cooling']=[self.Cooling.get()]
        data['Parking']=[self.Parking.get()]
        data['Lot']=[self.Lot.get()]
        data['Bedrooms']=[self.Bedrooms.get()]
        data['Bathrooms']=[self.Bathrooms.get()]
        data['Full bathrooms']=[self.Full_bathrooms.get()]
        data['Total interior livable area']=[self.Total_interior_livable_area.get()]
        data['Total spaces']=[self.Total_spaces.get()]
        data['Garage spaces']=[self.Garage_spaces.get()]
        data['Region']=[self.Region.get()]
        data['Elementary School Score']=[self.Elementary_School_Score.get()]
        data['Elementary School Distance']=[self.Elementary_School_Distance.get()]
        data['Middle School Score']=[self.Middle_School_Score.get()]
        data['Middle School Distance']=[self.Middle_School_Distance.get()]
        data['High School Score']=[self.High_School_Score.get()]
        data['High School Distance']=[self.High_School_Distance.get()]
        data['Flooring']=[self.Flooring.get()]
        data['Appliances included']=[self.Appliances_included.get()]
        data['Laundry features']=[self.Laundry_features.get()]
        data['Parking features']=[self.Parking_features.get()]
        data['Tax assessed value']=[self.Tax_assessed_value.get()]
        data['Annual tax amount']=[self.Annual_tax_amount.get()]
        data['Listed On']=[self.Listed_On.entry.get()]
        data['Listed Price']=[self.Listed_Price.get()]
        data['Last Sold On']=[self.Last_Sold_On.entry.get()]
        data['Last Sold Price']=[self.Last_Sold_Price.get()]
        data['Zip']=[self.Zip.get()]
        data['State']=[self.State.get()]

        devide(data,'Type')
        devide(data,'Heating')
        devide(data,'Cooling')
        devide(data,'Parking')
        devide(data,'Bedrooms')
        devide(data,'Flooring')
        devide(data,'Appliances included')
        devide(data,'Laundry features')
        devide(data,'Parking features')

        devide_time(data,'Listed On')
        devide_time(data,'Last Sold On')

        one_hot(data,'Region')
        one_hot(data,'State')

        data['Zip_National_Area']=data['Zip'].map(lambda x:int(str(x)[0]))
        data['Zip_Sectional_Center']=data['Zip'].map(lambda x:int(str(x)[1:3]))
        data['Zip_Delivery_Area']=data['Zip'].map(lambda x:int(str(x)[3:]))
        data.drop(columns=['Zip'],inplace=True)

        y_pred = self.clf.predict(data)
        print(data)
        data.to_csv('2.csv')
        self.result['text']='%.2f'%y_pred[0]

    def devide_name(self,name):
        temp=name.split(' ')
        temp1=temp[0]
        if len(temp)>1:
            for i in temp[1:]:
                temp1+='\n'+i
        return temp1

    def seperate(self,x1,y1,sizex,sizey,style):
        pad=50
        for i in range(sizex):
            ttkb.Separator(
                self.root,
                bootstyle=style).place(x=x1+i*pad,y=y1)
            ttkb.Separator(
                self.root,
                bootstyle=style).place(x=x1+i*pad,y=y1+sizey*pad)

        for i in range(sizey):
            ttkb.Separator(
                self.root,
                bootstyle=style,
                orient='vertical').place(x=x1,y=y1+5+i*pad)
            ttkb.Separator(
                self.root,
                bootstyle=style,
                orient='vertical').place(x=x1+sizex*pad,y=y1+5+i*pad)

    def entry(self,name,value,x,y,padx=20):
        name=self.devide_name(name)
        ttkb.Label(
            self.root,
            text=name,
            justify='right',
            bootstyle='danger').place(anchor='e',x=x,y=y+0.005)

        _entry=ttkb.Entry(
            self.root,
            width=20,
            bootstyle='danger')
        _entry.place(anchor='w',x=x+padx,y=y)
        _entry.insert(0,value)
        return _entry

    def combobox(self,name,_features,default,x,y,padx=20):
        name=self.devide_name(name)
        ttkb.Label(
            self.root,
            text=name,
            justify='right',
            bootstyle='warning').place(anchor='e',x=x,y=y+0.005)

        _combobox=ttkb.Combobox(
            self.root,
            values=_features,
            width=20,
            bootstyle="warning")
        _combobox.current(_features.index(default))
        _combobox.place(anchor='w',x=x+padx,y=y)
        return _combobox

    def date_entry(self,name,date,x,y,padx=20):
        name=self.devide_name(name)
        ttkb.Label(
            self.root,
            text=name,
            justify='right',
            bootstyle='info').place(anchor='e',x=x,y=y+0.005)

        _date_entry=ttkb.DateEntry(
            self.root,
            firstweekday=1,
            width=18,
            startdate=datetime.datetime.strptime(date,'%Y-%m-%d'),
            bootstyle='info')
        _date_entry.place(anchor='w',x=x+padx,y=y)
        return _date_entry

    def elements(self,name,value,x,y,padx=20):
        name1=self.devide_name(name)
        ttkb.Label(
            self.root,
            text=name1,
            justify='right',
            bootstyle='primary').place(anchor='e',x=x,y=y+0.005)

        _entry=ttkb.Entry(
            self.root,
            width=15,
            bootstyle='primary')
        _entry.place(anchor='w',x=x+padx,y=y)
        _entry.insert(0,value)

        _button=ttkb.Button(
            self.root,
            text='选择',
            bootstyle='primary',
            command=lambda v=value,x=name,y=lists.elements[name],z=_entry:self.select(v,x,y,z))
        _button.place(anchor='w',x=x+padx+155,y=y)
        return _entry

    def select(self,value,name,elements,entry):
        root=element_select(value,name,elements)
        entry.delete(0,'end')
        entry.insert(0,root.get())

    def exit(self):
        global root
        self.root.destroy()
        root.destroy()

class element_select:
    def __init__(self,value,name,elements): #value 默认值
        self.root=ttkb.Toplevel(title='样本预测')
        set_window_position(self.root,element_select_window_size)

        self.value=value

        self.elements=elements

        image=Image.open(sub_bg_path)
        image=resize(image,1)
        bg=ImageTk.PhotoImage(image)
        cv =ttkb.Canvas(self.root,width=element_select_window_size[0],height=element_select_window_size[1])
        cv.pack()
        cv.create_image(element_select_window_size[0]//2,element_select_window_size[1]//2,image=bg)

        self.balloon=None

        ttkb.Label(
            self.root,
            text='选择 '+name+' 的值',
            bootstyle='primary').place(relx=0.02,rely=0.04)

        self.number=[-1 for i in range(len(self.elements))]

        x=0.02
        y=0.07
        count=0
        for i in self.elements:
            count+=1
            self.check_button(i,x,y)
            if count%16==0:
                x+=0.08
                y=0.07
            else:
                y+=0.055

        ttkb.Button(self.root,
                    text='完成',
                    command=self.exit).place(relx=0.9,rely=0.95)

        self.root.mainloop()

    def check_button(self,name,x,y):
        _check_button=ttkb.Checkbutton(
            self.root,
            text=name,
            width=9,
            bootstyle="primary-outline-toolbutton",
            command=lambda x=name:self.toggle(name))
        _check_button.place(relx=x,rely=y)
        _check_button.bind('<Enter>',lambda event=True,name=name,x=x,y=y+0.04:self.balloon_show(event,name,x,y))
        _check_button.bind('<Leave>',self.balloon_hide)
        return _check_button

    def balloon_show(self,event,name,x,y):
        self.balloon=ttkb.Label(
            self.root,
            text=name)
        self.balloon.place(relx=x,rely=y)

    def balloon_hide(self,event):
        self.balloon.destroy()

    def toggle(self,name):
        self.number[self.elements.index(name)]*=-1

    def exit(self):
        global root
        self.root.destroy()
        root.destroy()

    def get(self):
        result=''
        temp=[]
        for i in range(len(self.number)):
            if self.number[i]==1:
                temp.append(self.elements[i])

        if len(temp)==1:
            result+=temp[0]
        elif len(temp)>1:
            result+=temp[0]
            for i in temp[1:]:
                result+=', '+i
        else:
            result=self.value
        return result

class main_page:
    def __init__(self,root):
        self.root=root
        self.root.title('加州房价预测系统')

        image=Image.open(main_page_bg_path)
        image=resize(image,0.73)
        bg=ImageTk.PhotoImage(image)
        cv =ttkb.Canvas(self.root,width=main_page_window_size[0],height=main_page_window_size[1])
        cv.pack()
        cv.create_image(main_page_window_size[0]//2,main_page_window_size[1]//2,image=bg)

        ttkb.Button(
            self.root,
            text='浏览训练数据集',
            bootstyle="primary",
            command=self.data_train_browser).place(anchor='center',relx=0.3,rely=0.8)

        ttkb.Button(
            self.root,
            text='浏览测试数据集',
            bootstyle="primary",
            command=self.data_test_browser).place(anchor='center',relx=0.3,rely=0.9)

        ttkb.Button(
            self.root,
            text='测试集预测',
            width=8,
            bootstyle="info",
            command=self.pre_data_page).place(anchor='center',relx=0.5,rely=0.8)

        ttkb.Button(
            self.root,
            text='样本预测',
            width=8,
            bootstyle="info",
            command=self.pre_single_page).place(anchor='center',relx=0.5,rely=0.9)

        ttkb.Button(
            self.root,
            text='分析',
            bootstyle="danger",
            command=self.analysis_page).place(anchor='center',relx=0.7,rely=0.8)

        ttkb.Button(
            self.root,
            text='退出',
            bootstyle="danger",
            command=self.exit).place(anchor='center',relx=0.7,rely=0.9)

        self.root.mainloop()

    def data_train_browser(self):
        data_browser(train_origin_path)

    def data_test_browser(self):
        data_browser(test_origin_path)

    def pre_data_page(self):
        pre_data_page()

    def pre_single_page(self):
        pre_single_page()

    def analysis_page(self):
        analysis_page()

    def exit(self):
        self.root.destroy()

# root.geometry('+{}+{}'.format(sw-main_page_window_size[0]//2,sh-main_page_window_size[1]//2))
set_window_position(root,main_page_window_size)
main_page(root)
# element_select('123','Parking',lists.elements['Parking'])
# pre_single_page()


"""Primary interface and object model definition for APS journals.

Object Model:
    For the purposes of this package, the highest-level publication is a Journal. Each Journal
    consists of Issues that are published in Volumes. Each Issue is essentially a collection of articles,
    though the articles may be grouped into sections or subsections.

Classes defined with brief descriptions:
    Journal - the APS publication
    Volume - a volume of a particular journal, a collection of issues
    Issue - a particular instance of the publication, a collection of articles
    Section - a part of an Issue, may contain subsections or articles
    Article - an individual article published in the Journal
    Author - A contributor to an article
"""

import collections
import datetime
import itertools
import typing
from apsjournals.web import scrapers
from apsjournals import pdf

class Journal:
    def __init__(self, name: str, url_path: str, description: str=None, short_name: str=None):
        """The highest-level abstraction in the library, the Journal represents an APS publication

        Args:
            name:
                str, the name of the publication, e.g. "Physical Review Letters"
            url_path:
                str, the piece of the URL that specifies the journal, i.e. "prl"
            description:
                str, default None, the description of the Journal
            short_name:
                str, the short name of the Journal, used in the repr if specified
        """
        self.name = name
        self.url_path = url_path
        self.description = description
        self.short_name = short_name
        self._volumes = collections.OrderedDict() # cache

    def __repr__(self):
        return 'Journal({!r})'.format(self.name if self.short_name is None else self.short_name)

    @property
    def volumes(self) -> typing.List[int]:
        if not self._volumes:
            s = scrapers.VolumeIndexScraper()
            info = s.load(journal=self.url_path, volume=None)
            for i in info:
                self._volumes[i.num] = Volume(journal=self, num=i.num, start=i.start, end=i.end)
        return list(self._volumes.keys())

    def volume(self, n: int=None):
        """Get a particular Volume of the journal

        Args:
            n:
                int, the volume number

        Returns:
            Volume
        """
        volumes = self.volumes
        if n is None:
            n = volumes[0]
        elif n not in volumes:
            raise ValueError('Invalid volume number {} for journal {}, valid numbers are: {}'.format(n, self, volumes)) # load volume info from web
        return self._volumes[n]

    def issue(self, vol: int, issue: int):
        return self.volume(vol).issue(issue)

class Volume:
    def __init__(self, journal: Journal, num: int, start: datetime.date, end: datetime.date):
        """A Volume of a journal is an increment of issuance, containing one or more Issues

        Args:
            journal:
                Journal, the journal from which the Volume comes
            num:
                int, the Volume number
            start:
                datetime.date, the starting date of the Volume (if known)
            end:
                datetime.date, the ending date of the Volume (if known)
        """
        self.journal = journal
        self.num = num
        self.start = start
        self.end = end
        self._issues = collections.OrderedDict()

    def __repr__(self):
        return 'Volume({!r}, {:d})'.format(self.journal.name if self.journal.short_name is None else self.journal.short_name, self.num)

    @property
    def issues(self) -> typing.List[int]:
        if not self._issues:
            s = scrapers.IssueIndexScraper()
            info = s.load(journal=self.journal.url_path, volume=self.num, issue=None)
            for i in info:
                self._issues[i.num] = Issue(vol=self, num=i.num)
        return list(self._issues.keys())

    def issue(self, num: int):
        """Load a particular Issue from this volume

        Args:
            num:
                int, the number of the issue. If None, get the most recent Issue

        Returns:
            Issue
        """
        issues = self.issues
        if num not in issues:
            raise ValueError('Invalid issue number, valid numbers include: {}'.format(issues))
        if self._issues[num] is None:
            pass # load issue from web and cache
        return self._issues[num]

class Issue:
    def __init__(self, vol: Volume, num: int):
        """An Issue is the most granular unit of the Journal, in that it is the immediate
        container of Articles

        Args:
            vol:
                Volume, the Volume from which the Issue comes
            num:
                int, the issue number
        """
        self.vol = vol
        self.num = num
        self.__contents = None

    def __repr__(self):
        return "Issue({!r}, {:d}, {:d})".format(self.journal.name, self.vol.num, self.num)

    @property
    def journal(self):
        return self.vol.journal

    @property
    def _contents(self):
        """Load the contents of the Issue, returning a list of Sections and Articles

        Returns:
            List[Union[Section, Article]]
        """
        if not self.__contents:
            s = scrapers.IssueScraper()
            info = s.load(journal=self.journal.url_path, volume=self.vol.num, issue=self.num)
            self.__contents = parse_contents_from_info(info, issue=self)
        return self.__contents

    def contents(self, include_level: bool=False):
        return traverse_issue_contents(self, include_level=include_level)

    @property
    def articles(self):
        def extract_articles(x):
            if isinstance(x, Article):
                return [x]
            elif isinstance(x, Section):
                return list(itertools.chain.from_iterable([extract_articles(m) for m in x.members]))
        return list(itertools.chain.from_iterable([extract_articles(c) for c in self._contents]))

    def pdf(self, out_file: str):
        doc = pdf.ApsPDF(self, out_file)
        doc.build()

class Author:
    def __init__(self, name: str):
        """An author is a contributor to an Article.

        Args:
            name:
        """
        if ', ' in name: # nonstandard aps format
            last, first = name.split(', ')
        elif ' ' in name:
            pieces = name.split(' ')
            first, last = pieces[0], ' '.join(pieces[1:])
        else:
            first, last = name, name
            # raise ValueError('Unable to parse Author name: {}'.format(name))
        self.first_name = first
        self.last_name = last

    def __repr__(self):
        return "Author({!r})".format(self.name)

    @property
    def name(self):
        return '{}, {}'.format(self.last_name, self.first_name)

class Section:
    def __init__(self, name, members):
        """A section contains subsections or Articles

        Args:
            name:
                str, the name of the section
            members:
                List[Union[Section, Article]]
        """
        self.name = name
        self.members = members

    def __repr__(self):
        return "Section({}, {:d} members)".format(self.name, len(self.members))

class Article:
    def __init__(self, issue: Issue, name: str, authors: typing.List[Author], url: str, pdf_url: str, teaser: str=None):
        """An article represents a published paper in an APS journal. It is organized into
        a parent Issue, and has several pieces of meta data (authors, url, etc.).

        Args:
            issue:
                Issue, the issue in which the Article is published
            name:
                str, the name of the article
            authors:
                List[Author], the list of authors
            url:
                str, the url for the Article webpage
            pdf_url:
                str, the url for the PDF format of the Article
            teaser:
                str or None, the teaser for the article if one exists
        """
        self.issue = issue
        self.name = name
        self.authors = authors
        self.url = url
        self.pdf_url = pdf_url
        self.teaser = teaser

    def __repr__(self):
        return "Article({!r})".format(self.name)

    @property
    def journal(self):
        return self.issue.vol.journal

    def pdf(self, filepath: str):
        scrapers.download_pdf(self.pdf_url, out_file=filepath)

def parse_contents_from_info(info: typing.List[typing.Union[scrapers.DividerInfo, scrapers.SectionInfo, scrapers.ArticleInfo]], issue: Issue) -> typing.List[Section]:
    """Convert an iterable of raw web-scraped information into api objects.

    Args:
        info:
            List[Union[DividerInfo, SectionInfo, ArticleInfo]]
        issue:
            Issue, the issue to which the contents belong

    Returns:
        List of Section and Article instances
    """
    contents = []
    for n, i in enumerate(info):
        if isinstance(i, scrapers.DividerInfo):
            divider_info = []
            while len(info) > n + 1 and not isinstance(info[n+1], scrapers.DividerInfo):
                divider_info.append(info.pop(n+1))
            divider_contents = parse_contents_from_info(divider_info, issue=issue)
            contents.append(Section(i.name, members=divider_contents))
        elif isinstance(i, scrapers.SectionInfo):
            contents.append(Section(name=i.name, members=parse_contents_from_info(i.articles, issue=issue)))
        elif isinstance(i, scrapers.ArticleInfo):
            contents.append(Article(issue=issue,
                                    name=i.name,
                                    authors=[Author(n.strip()) for n in i.author.replace('and', '').encode('ascii', 'ignore').decode('ascii').split(',')],
                                    url=i.url,
                                    pdf_url=i.pdf_url,
                                    teaser=i.teaser))
        else:
            raise ValueError('Unable to parse contents from type {}'.format(type(i)))
    return contents

def traverse_issue_contents(x, level: int=0, include_level: bool=True):
    """Traverse the issue contents

    Args:
        x:
            Issue, Section, or Article
        level:
            int, default 0 the level of nested

    Returns:
        Generator
    """
    if isinstance(x, Issue):
        for m in x._contents:
            yield from traverse_issue_contents(m, level=level + 1, include_level=include_level)
    elif isinstance(x, Section):
        yield ((level, x) if include_level else x)
        for m in x.members:
            yield from traverse_issue_contents(m, level=level + 1, include_level=include_level)
    elif isinstance(x, Article):
        yield ((level, x) if include_level else x)
    else:
        raise ValueError('Unable to traverse object of type: {}'.format(type(x)))


#!/usr/bin/python

"""
kinematics.py

DE3 Applied Robotics, Coursework 1 - MODEL

"""

from math import cos, sin, acos, asin, atan2, sqrt, pi
from numpy.linalg import matrix_rank as rank
from numpy.linalg import pinv, norm
from std_msgs.msg import Float64
from numpy import genfromtxt
import numpy as np
import rospy
import sys

def main(task):
    #GENERATE ROBOT MODEL
    l1 = 1.
    l2 = 1.
    l3 = 1.

    Robot = RobotKineClass([l1,l2,l3])

    # FORWARD KINEMATICS
    if task == "fk":
        print("============================================================")
        print("Testing Forward Kinematics")
        print("------------------------------------------------------------")
        fk_points_file = "test_points/fk_points.csv"
        fk_points = ReadCSV(fk_points_file)
        for i, points in zip(range(len(fk_points)), fk_points):
            print("Test point:\t", i+1)
            joint_space_points = points[:3]
            task_space_points = points[3:]
            print("Joint space points to test:\n", joint_space_points)
            predicted_task_space_points = Robot.getFK(joint_space_points)
            print("Calculated task space points:\n", np.round(predicted_task_space_points, 3))
            error = np.linalg.norm(task_space_points - predicted_task_space_points)
            print("Passed?\t", error<1e-3)
            if error > 1e-3:
                print("Forward Kinematics calculations incorrect, exiting.")
                return
            print("------------------------------------------------------------")
        print("Forward Kinematics calculations correct, well done!")
    elif task == "ws":
        print("============================================================")
        print("Testing Workspace")
        print("------------------------------------------------------------")
        ws_points_file = "test_points/workspace_points.csv"
        ws_points = ReadCSV(ws_points_file)
        for i, points in zip(range(len(ws_points)), ws_points):
            print("Test point:\t", i+1)
            task_space_points = points[:3]
            workspace_flag = points[3:]
            print("Task space points to test:\n", task_space_points)
            predicted_workspace_flag = Robot.checkInWS(task_space_points)
            print("Calculated work space flag:\t", predicted_workspace_flag)
            print("Passed?\t", workspace_flag == predicted_workspace_flag)
            if workspace_flag != predicted_workspace_flag:
                print("Workspace calculations incorrect, exiting.")
                return
            print("------------------------------------------------------------")
        print("Workspace calculations correct, well done!")
    elif task=="ik":
        print("============================================================")
        print("Testing Inverse Kinematics")
        print("------------------------------------------------------------")
        ik_points_file = "test_points/ik_points.csv"
        ik_points = ReadCSV(ik_points_file)
        for i, points in zip(range(len(ik_points)), ik_points):
            print("Test point:\t", i+1)
            task_space_points = points[:3]
            joint_space_points_1 = points[3:6]
            joint_space_points_2 = points[6:]
            print("Task space points to test:\n", task_space_points)
            predicted_joint_space_points_1 = Robot.getIK(task_space_points)[0][0]
            predicted_joint_space_points_2 = Robot.getIK(task_space_points)[0][1]
            print("Calculated joint space points 1:\n", predicted_joint_space_points_1)
            print("Calculated joint space points 2:\n", predicted_joint_space_points_2)
            error1 = np.linalg.norm(joint_space_points_1 - predicted_joint_space_points_1)
            error2 = np.linalg.norm(joint_space_points_2 - predicted_joint_space_points_2)
            pass1 = error1 < 1e-2 and error2 < 1e-2
            error3 = np.linalg.norm(joint_space_points_1 - predicted_joint_space_points_2)
            error4 = np.linalg.norm(joint_space_points_2 - predicted_joint_space_points_1)
            pass2 = error3 < 1e-2 and error4 < 1e-2
            passed = pass1 or pass2
            print("Passed?\t", passed)
            if not passed:
                print("Inverse Kinematics calculations incorrect, exiting.")
                return
            print("------------------------------------------------------------")
        print("Inverse Kinematics calculations correct, well done!")
    elif task=="dk":
        print("============================================================")
        print("Testing Differential Kinematics")
        print("------------------------------------------------------------")
        dk_points_file = "test_points/dk_points.csv"
        dk_points = ReadCSV(dk_points_file)
        for i, points in zip(range(len(dk_points)), dk_points):
            print("Test point:\t", i+1)
            joint_space_points = points[:3]
            joint_space_velocities = points[3:6]
            task_space_velocities = points[6:]
            print("Joint space points to test:\n", joint_space_points)
            print("Joint space velocities to test:\n", joint_space_velocities)
            predicted_task_space_velocities = Robot.getDK(joint_space_points, joint_space_velocities)
            print("Calculated task space velocities:\n", predicted_task_space_velocities)
            error = np.linalg.norm(task_space_velocities - predicted_task_space_velocities)
            passed = error < 1e-3
            print("Passed?\t", passed)
            if not passed:
                print("Differential Kinematics calculations incorrect, exiting.")
                return
            print("------------------------------------------------------------")
        print("Differential Kinematics calculations correct, well done!")
    elif task=="full":
        print("============================================================")
        print("Testing Full Setup")
        print("------------------------------------------------------------")
        #LOAD TASK SPACE POINTS
        points_file = "test_points/points.csv"

        CartPoints = ReadCSV(points_file)

        m = CartPoints.shape[0]

        q_old = np.zeros(3) #initial configuration
        Robot.sendCommands(q_old)
        for i in range(m):

            P = CartPoints[i, :]
            print(" Step " + str(i+1) + "/" + str(m))
            print("Desired Point ", P)
            [q_IK, Positions] = Robot.getIK(P)

            #check solution closer to previous step
            q = Robot.chooseSol(q_IK, q_old)[0]

            #Interpolate
            N_steps = 100
            Q = LinInterp(q_old, q, N_steps)
            q_old = q

            for j in range(N_steps):
                q_comm = Q[j, :]

                #send commands
                Robot.sendCommands(q_comm)

            P_achieved = Robot.getFK(q)
            P_error = P-P_achieved
            print("p achieved", np.round(P_achieved, 3))
            print("position error", np.round(P_error, 3))
            print("------------------------------------------------------------")

#Creates joint publishers
def set_joint_publisher():
    rospy.init_node("joint_positions_node")

    wait = True
    while(wait):
        now = rospy.Time.now()
        if now.to_sec() > 0:
            wait = False

    pubs = []

    for i in range(3):
        topic_name = "/DESE3R/joint_"+str(i)+"_position_controller/command"
        pub = rospy.Publisher(topic_name,Float64,queue_size=1000)
        pubs.append(pub)

    return pubs

#Returns matrix in R^mx3
def ReadCSV(filename):

    Data = genfromtxt(filename, delimiter=',')
    return Data

#returns a matrix of interpolated pints in R^N_stepsx3
def LinInterp(qi,qf,N_steps):

    n = np.linspace(0,1,num=N_steps)

    dq = qf-qi

    Q_interp = np.multiply(dq.reshape(-1,1),n)+qi.reshape(-1,1)
    Q_interp = Q_interp.T

    return Q_interp

#DH_params = parameters for link i
#d,theta,a,alpha
def DH_matrix(DH_params):

    #DH_Params is a variable created within the getFK method fo the RobotKineClass
    #The variable is a copy of the i th row of the DH_Table
    #Indexing this variable extracts a singular value for each D-H variable

    d = DH_params[0]
    theta = DH_params[1]
    a = DH_params[2]
    alpha = DH_params[3]

    ################################################ TASK 2
    DH_matrix = np.array([[cos(theta), -sin(theta), 0., a],
            [sin(theta)*cos(alpha), cos(theta)*cos(alpha), -sin(alpha), -sin(alpha)*d],
            [sin(theta)*sin(alpha), cos(theta)*sin(alpha), cos(alpha), cos(alpha)*d],
            [0., 0., 0., 1.]])

    return DH_matrix

class RobotKineClass():

    def __init__(self,link_lengths):

        self.ROSPublishers = set_joint_publisher()

        self.nj = 3    #number of joints
        self.links = link_lengths    # length of links

        ################################################ TASK 1
        #Define DH table for each link. DH_tab in R^njx4
        #d,theta,a,alpha

        #Save the DH_table as a numpy array.
        #Link length is accessed by indexing the instance variable
        self.DH_tab = np.array([[self.links[0],0.,0.,0.],
                                [0.,0.,0.,pi/2],
                                [0,0.,self.links[1],0.],
                                [0., 0., self.links[2], 0.]])

        self.joint_types = 'rrr'	# three revolute joints

    #Computes Forward Kinematics. Returns 3x1 position vector
    def getFK(self,q):

        #Create a 4x4 identity matrix
        # (this is used within the first iteration of the loop so the first T_i_1_i becomes T_0_i)
        T_0_i_1 = np.identity(4)

        #Loop through from joints 0 to n-1
        for i in range(self.nj):
            print(i)

            # Create a new variable from the current row in the D-H table
            DH_params = np.copy(self.DH_tab[i,:])
            #print('q',q)
            #print(DH_params)

            ### UPDATE THE DH TABLE VALUES ###
            #Check if the joint is a revolute
            if self.joint_types[i] == 'r':
                #If so, add the joint angle to the theta value for the current row
                DH_params[1] = DH_params[1]+q[i]
            #Check if the joint is a prismatic
            elif self.joint_types[i] == 'p':
                #If so, add the current joint angle to the d value for the current row
                DH_params[0] = DH_params[0]+q[i]

            # Input the updated table row to get a transformation matrix
            T_i_1_i = DH_matrix(DH_params) #Pose of joint i wrt i-1

            print(T_i_1_i)

            ################################################ TASK 3 (replace np.eye(4) with the correct matrices)

            # Calculate the transformation matrix up to this point
            T_0_i = np.matmul(T_0_i_1, T_i_1_i) #Pose of joint i wrt base

            # Update the i-1_T_i matrix to be the matrix product up to i
            T_0_i_1 = T_0_i

        T_0_n_1 = T_0_i

        #Create a copy of the last row of the DH Table
        DH_params = np.copy(self.DH_tab[self.nj, :])

        #Create the last transformation matrix with the final row of the DH table
        T_n_1_n = DH_matrix(DH_params)

        #Multiply the transformation matrix up to n-1 with Tn
        T_0_n = np.matmul(T_0_n_1, T_n_1_n)

        #return the first three rows of the third column
        #these represent the translation part of the transformation matrix
        #this vector is the carteian coordinates of the end effector

        return T_0_n[0:3,3]

    #Check if point is in WS. returns true or false
    def checkInWS(self, P): #Define function and set P (the desired point in taskspace) as input

        #This step creates varaibles to make key equations easier to write and understand
        xP, yP, zP = P #Seperate P in seperate variables for each dimension
        l0, l1, l2 = self.links #Seperate links in seperate variables for each arm length

        ################################################ TASK 4
        val = np.power(xP,2) + np.power(yP,2)+np.power((zP-l0),2) #Calculates distnace of P from the origin of joint 1
        r_max = l1 + l2 #Calcuates the maximum distance the end-effector can be from the origin of joint 1
        r_min = l1 - l2 #Calcuates the minimum distance the end-effector can be from the origin of joint 1

        inWS = True #Sets default output of function to be TRUE

        #Checks to see if point P does not meet the inequalities and is outside the workspace
        if val > r_max**2. or val < r_min**2.: #Checks if val is less then the min distnace or greater than
                                               #the max distance from joint 1 origin
            inWS = False #If P is outside workspace chnage output variable to FALSE

        return inWS #Return boolean ouput variable

    # Solve IK gemoetrically. Returns list of all possible solutions
    def getIK(self,P): #Define function and set P (the desired point in taskspace) as input

        #This step creates varaibles to make key equations easier to write and understand
        xP, yP, zP = P #Seperate P in seperate variables for each dimension
        l0, l1, l2 = self.links #Seperate links in seperate variables for each arm length

        inWS = self.checkInWS(P) #Check if desired point is within the reachable workspace

        q = [] #Create empty joint-space vector
        Poses = [] #Create empty task-space vector

        if not inWS: #If desired pose P not in workspace
            print("OUT OF WS. NO SOLUTION FOUND") #Print "OUT OF WS. NO SOLUTION FOUND" to terminal
            return q,Poses #output empty vectors from function

        ################################################ TASK 6
        q_a = np.zeros(3) #Create empty 1x3 array for first joint-space configuration
        q_b = np.zeros(3) #Create empty 1x3 array for second joint-space configuration

        q_a[0] = atan2(yP,xP) #Config. a inverse kinematics equation for the first joint angle
        q_b[0] = q_a[0] #Config. b inverse kinematics equation for the first joint angle

        r = np.sqrt(np.power(xP,2) + np.power(yP,2)) #Define r, the radius of P from the central axis
        z = zP - l0 #Define z, adjusts z dimenions to be in the reference fram of axes 1

        q_a[2] = acos((np.power(r,2)+np.power(z,2)-np.power(l1,2)-np.power(l2,2))/(2*l1*l2)) #Config. a inverse kinematics equation for the third joint angle
        q_b[2] = -q_a[2] #Config. b inverse kinematics equation for the third joint angle. Simply negative of the other config.

        #Both configs. of the second joint angle have the same acos function, with different signs. Below is the acos function.
        q1_acos =  acos((np.power(r,2)+np.power(z,2)+np.power(l1,2)-np.power(l2,2))/(2*l1*np.sqrt(np.power(r,2)+np.power(z,2))))

        q_a[1] = atan2(z,r) - q1_acos #Config. a inverse kinematics equation for the second joint angle
        q_b[1] = atan2(z,r) + q1_acos #Config. b inverse kinematics equation for the second joint angle

        q = [q_a, q_b] #bring both configurations into one variable of joint-space

        Poses = [self.getFK(q_a), self.getFK(q_b)] #Run both joint-space configurations through forward kinematics to get the pose, this can be compared to P
        return q, Poses #Ouput the cacuated joint-space and the confirmation poses

    #given list of solutions q_IK, returns closest value to old one and list of error norms
    def chooseSol(self,q_IK,q_old):

        diff = []
        q = q_old
        for i in range(len(q_IK)):

            dq = norm(q_IK[i]-q_old)
            diff.append(dq)

        if len(diff) > 0:
            index = np.argmin(diff)
            q = q_IK[index]

        return q,diff

    # Computes Direct Differential Kinematics.
    # Returns 1x3 array of x_dot containing x, y and z end-effector velocities respectivly
    def getDK(self, q, q_dot): #Define function and sets q & q_dot, the joint angles and their velocities for a desired pose as inputs

        #Creating individual variables make the Jacobian Matrix calculations more legible and understandable
        q0, q1, q2 = q #Seperating q into three variables for each joint angle
        l1, l2, l3 = self.links #Seperating links in seperate variables for each arm length

        ################################################ TASK 7
        #Creating a new global variable, Jacobian, that is a 3x3 array consisting of the partial derivatives of each position vector w.r.t. each joint angle

        self.Jacobian = np.array([[-(l1*cos(q1)+l2*cos(q1+q2))*sin(q0), -(l1*sin(q1)+l2*sin(q1+q2))*cos(q0), -(l2*sin(q1+q2))*cos(q0)], #J1 with three terms consisting of partial derivatives of xP w.r.t. each joint angle q0, q1, q2 respectivly
                                  [(l1*cos(q1)+l2*cos(q1+q2))*cos(q0), -(l1*sin(q1)+l2*sin(q1+q2))*sin(q0), -(l2*sin(q1+q2)*sin(q0))], #J2 with three terms consisting of partial derivatives of yP w.r.t. each joint angle q0, q1, q2 respectivly
                                  [0., (l1*cos(q1)+l2*cos(q1+q2)),(l2*cos(q1+q2))]]) #J3 with three terms consisting of partial derivatives of zP w.r.t. each joint angle q0, q1, q2 respectivly

        #Performing matrix multiplication of the Jacobian for the desired pose with the desired joint velocities
        x_dot = np.matmul(self.Jacobian, q_dot) # 1x3 array of end-effector velocities in x, y and z axis

        return x_dot #Output the calculated end-effector velocities

    #send commands to Gazebo
    def sendCommands(self,q):

        #print("SENDING JOINT VALUES ", q)
        rate = rospy.Rate(100) #Hz
        for i in range(3):

            n_conn = 0
            while not n_conn:
                self.ROSPublishers[i].publish(q[i])
                n_conn = self.ROSPublishers[i].get_num_connections()
                rate.sleep()

if __name__ == "__main__":
    tasks = ['fk', 'ws', 'ik', 'dk', 'full']
    if len(sys.argv) <= 1:
        print('Please include a task to run from the following options:\n', tasks)
    else:
        task = str(sys.argv[1])
        if task in tasks:
            print("Running Coursework 1 -", task)
            main(task)
        else:
            print('Please include a task to run from the following options:\n', tasks)


#!/usr/bin/env python

import os.path
from glob import glob
from os.path import basename, splitext

from setuptools import find_packages, setup

def read(fname):
    return open(os.path.join(os.path.dirname(__file__), fname)).read()

with open("requirements.txt") as f:
    required = f.read().splitlines()

long_description = read("Readme.rst")

setup(
    name="porepy",
    version="1.6.0",
    license="GPL",
    keywords=["porous media simulation fractures deformable"],
    author="Eirik Keilegavlen, Runar Berge, Omar Duran, Alessio Fumagalli, Michele Starnoni, Ivar Stefansson and Jhabriel Varela",
    install_requires=required,
    description="Simulation tool for fractured and deformable porous media",
    long_description=long_description,
    maintainer="Eirik Keilegavlen",
    maintainer_email="Eirik.Keilegavlen@uib.no",
    platforms=["Linux", "Windows"],
    package_data={"porepy": ["py.typed"]},
    packages=find_packages("src"),
    package_dir={"": "src"},
    py_modules=[
        os.path.splitext(os.path.basename(path))[0] for path in glob("src/*.py")
    ],
    zip_safe=False,
)


import numpy as np
import urllib.request
from sklearn import preprocessing
from sklearn import metrics
from sklearn.linear_model import LogisticRegression

# 加载数据
url = "http://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
raw_data = urllib.request.urlopen(url)
# 把CSV文件转化为numpy matrix
dataset = np.loadtxt(raw_data, delimiter=",")
# 训练集和结果
x = dataset[:, 0:7]
y = dataset[:, 8]
# 数据归一化
normalized_x = preprocessing.normalize(x)
# 逻辑回归
model = LogisticRegression()

model.fit(normalized_x, y)

# 预测
expected = y
predicted = model.predict(normalized_x)

# 模型拟合概述
print(metrics.classification_report(expected, predicted))
print(metrics.confusion_matrix(expected, predicted))


def gcdRecur(a, b):
    '''
    a, b: positive integers

    returns: a positive integer, the greatest common divisor of a & b.
    '''
    # Your code here
    small=min(a,b)
    if (a%small+b%small)==0 or small==1:
        return small
    else:
        return gcdRecur(b,a%b)

print(gcdRecur(6,12))


from django.urls import path
from Base.views import order_views as views

urlpatterns = [
    path('', views.getAllOrders, name='orders'),

    path('user/<str:pk>/', views.getUserOrders, name='user-orders'),

    path('<str:pk>/', views.createOrder, name='order'),

    path('create/', views.getOrderById, name='create-order'),

    path('update/<str:pk>/', views.updateOrder, name='order-update'),
    path('<str:pk>/deliver/', views.updateOrderToDelivered, name='order-delivered'),
    path('<str:pk>/pay/', views.updateOrderToPaid, name='order-paid'),

    path('delete/<str:pk>/', views.deleteOrder, name='order-delete'),
]


from rest_framework import serializers

from products import models

class ProductSerializer(serializers.ModelSerializer):
    image = serializers.SerializerMethodField()
    category = serializers.SerializerMethodField()

    class Meta:
        model = models.Product
        fields = [
            'id',
            'user',
            'name',
            'image',
            'brand',
            'category',
            'description',
            'rating',
            'reviews_count',
            'price',
            'count_in_stock',
            'created_at',
            'updated_at',
        ]
        read_only_fields = [
            'user',
            'id',
            'rating',
            'reviews_count',
            'stock',
        ]

    def get_image(self, product: models.Product) -> str:
        request = self.context.get('request')
        if request:
            image_url = product.image.url
            return request.build_absolute_uri(image_url)
        return product.image.url

    def get_category(self, product: models.Product) -> str:
        if product.category:
            return product.category.name
        return None


import logging
from email.utils import parseaddr, formataddr
from config.settings import owner_email, silent, server_name_config, campaign_reports_url_config
from salmon.routing import route, route_like, stateless, Router
from salmon.bounce import bounce_to
from salmon.mail import MailResponse
from salmon import view
from salmon.server import SMTPError
from app.model.emails import tst_email_processed, send_or_queue, sanitize
import app.model.campaign as c
from app.model.end_campaign import end_campaign
from app.model.campaign import INTERNAL, UNKNOWN
from app.model.unicode_helper import safe_unicode

#@route(".+")
#def GM_BOUNCE(message):
#    c.set_bouncing(message)

#@route(".+")
#def IGNORE_BOUNCE(message):
#    return START

@route("pm-new-game@(host)")
@stateless
def NEW_CAMPAIGN(message, host=None):
    return _new_campaign(message, 'en', 'pm-new-game')

@route("pm-new-game-es@(host)")
@stateless
def NEW_CAMPAIGN_ES(message, host=None):
    return _new_campaign(message, 'es', 'pm-new-game-es')

def _new_campaign(message, lang, service_address):

    # check if the email address is know, if it is, croak
    sender = c.place_sender(message)
    if sender == INTERNAL:
        return # ignore

    server_name = server_name_config
    if sender != UNKNOWN:
        msg = "Already playing"
        if type(sender) is tuple:
            msg = msg + " " + c.campaign_name(sender[0])
        if silent:
            logging.debug(u"MESSAGE to %s@%s from %s - already playing" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, msg)

    # use subject for name of campaign
    campaign_name = message['subject']

    # create campaign, set language to lang
    cid = c.new_campaign(campaign_name, message['from'], lang)

    # generate reply
    attribution = c.get_attribution(message['from'])
    msg = view.respond(locals(), "%s/new_campaign.msg" % (lang,),
                           From="%s@%s" % (service_address, server_name),
                           To=message['from'],
                           Subject=view.render(locals(),
                                               "%s/new_campaign.subj"  % (lang,)))

    logging.debug(u"MESSAGE to %s@%s from %s, new campaign %s - %s" %
                      (service_address, server_name,
                           safe_unicode(message['from']),
                      str(cid), campaign_name))
    send_or_queue(msg, cid)
    return

@route("pm-new-attribution@(host)")
@stateless
def NEW_ATTRIBUTION(message, host=None):
    service_address = 'pm-new-attribution'
    server_name = server_name_config

    # check the sender is known
    sender = c.place_sender(message)
    if sender == INTERNAL:
        logging.debug(u"INTERNAL ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
        return # ignore
    if sender == UNKNOWN:
        if silent:
            logging.debug(u"UNKNOWN ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, "Unknown sender")

    cid = sender[0]
    lang = c.campaign_language(cid)
    campaign_name = c.campaign_name(cid)
    attribution = message['subject']
    c.set_attribution(message['from'], attribution)

    msg = view.respond(locals(), "%s/new_attribution.msg" % (lang,),
                           From="%s@%s" % (service_address, server_name),
                           To=message['from'],
                           Subject=view.render(locals(),
                                               "%s/new_attribution.subj"  % (lang,)))
    logging.debug(u"New attribution: %s attribute to %s" % (message['from'],attribution))
    send_or_queue(msg, cid)
    return

@route("pm-new-(pc_or_npc)pc@(host)", pc_or_npc="n?")
@stateless
def NEW_CHARACTER(message, host=None, pc_or_npc="n"):
    service_address = 'pm-new-' + ("n" if pc_or_npc else "") + "pc"
    server_name = server_name_config

    # check the sender is an active GM, otherwise raise 550
    sender = c.place_sender(message)
    if sender == INTERNAL:
        logging.debug(u"INTERNAL ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
        return # ignore
    if sender == UNKNOWN:
        if silent:
            logging.debug(u"UNKNOWN ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, "Unknown sender")

    if not sender[1]:
        if silent:
            logging.debug(u"NOT_GM ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, "Not a GM")
    cid = sender[0]
    lang = c.campaign_language(cid)
    campaign_name = c.campaign_name(cid)
    attribution = c.get_attribution(message['from'])

    # get name of the character from subject, produce short form,
    # ensure short form doesn't collide with existing characters
    full_name = message['subject']

    if '(' in full_name:
        ( full_name, short_form ) = full_name.split('(')
        full_name = full_name.strip()
        if ')' in short_form:
            short_form = short_form.split(')')[0].strip()
    else:
        short_form = full_name.split(' ')[0]
        full_name = full_name.strip()
    short_form = short_form.lower()

    if c.character_exists(cid, short_form):
        all_characters = c.all_characters(cid)
        msg = view.respond(locals(), "%s/repeated_short_form.msg" % (lang,),
                            From="%s@%s" % (service_address, server_name),
                            To=message['from'],
                            Subject=view.render(locals(),
                                                    "%s/repeated_short_form.subj"  % (lang,)))

        logging.debug(u"DUPLICATE short form %s, campaign %s" %
                        (short_form, str(cid)))
        send_or_queue(msg, cid)
        return

    if pc_or_npc:
        # create NPC, associate it with current campaign
        c.new_npc(cid, short_form, full_name)
        all_characters = c.all_characters(cid)

        # return template on the campaign language confirming its creation
        msg = view.respond(locals(), "%s/new_npc.msg" % (lang,),
                            From="%s@%s" % (service_address, server_name),
                            To=message['from'],
                            Subject=view.render(locals(),
                                                    "%s/new_npc.subj" % (lang,)))

        logging.debug(u"NEW_NPC short form %s, campaign %s" %
                        (short_form, str(cid)))
        send_or_queue(msg, cid)
        return
    else:
        # create PC, associate it with current campaign and generate
        # enrollment email
        enrollment_address = c.new_pc(cid, short_form, full_name)
        all_characters = c.all_characters(cid)

        # return template on the campaign language with the enrollment email
        msg = view.respond(locals(), "%s/new_pc.msg" % (lang,),
                            From="%s@%s" % (service_address, server_name),
                            To=message['from'],
                            Subject=view.render(locals(),
                                                    "%s/new_pc.subj" % (lang,)))

        logging.debug(u"NEW_PC short form %s, enroll at %s, campaign %s" %
                        (short_form, enrollment_address, str(cid)))
        send_or_queue(msg, cid)
        return

@route("pm-enroll-(nonce)@(host)", nonce=".+")
@stateless
def ENROLL(message, nonce, host=None):
    server_name = server_name_config
    service_address = 'pm-enroll-%s' % (nonce,)

    # check if the email address is know, if it is, croak
    sender = c.place_sender(message)
    if sender == INTERNAL:
        logging.debug(u"INTERNAL ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
        return # ignore
    if sender != UNKNOWN:
        msg = "Already playing"
        if type(sender) is tuple:
            msg = msg + " " + c.campaign_name(sender[0])
        if silent:
            logging.debug(u"ALREADY ignoring %s@%s from %s - already playing" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, msg)

    enrollment = c.find_enrollment(nonce)

    if enrollment is None:
        if silent:
            logging.debug(u"INVALID code, ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, "Enrollment code invalid")

    (cid, short_form) = enrollment

    c.do_enrollment(cid, nonce, message['from'], short_form)

    lang = c.campaign_language(cid)
    campaign_name = c.campaign_name(cid)
    attribution = c.get_attribution(message['from'])

    msg = view.respond(locals(), "%s/enrolled_pc.msg" % (lang,),
                           From="%s@%s" % (service_address, server_name),
                           To=message['from'],
                           Subject=view.render(locals(),
                                                   "%s/enrolled_pc.subj" % (lang,)))

    logging.debug(u"ENROLLED short form %s, enrolled at %s, campaign %s" %
                      (short_form, service_address, str(cid)))
    send_or_queue(msg, cid)

    (gm_address, gm_full, attribution) = c.campaign_gm(cid)
    msg = view.respond(locals(), "%s/enrolled_gm.msg" % (lang,),
                           From="pm-enroll@%s" % (server_name,),
                           To=gm_full,
                           Subject=view.render(locals(),
                                                   "%s/enrolled_gm.subj" % (lang,)))
    send_or_queue(msg, cid)
    return

@route("pm-end@(host)")
@stateless
def GAME_END(message, host=None):
    service_address = 'pm-end'
    server_name = server_name_config

    sender = c.place_sender(message)
    if sender == INTERNAL:
        return # ignore
    if sender == UNKNOWN:
        if silent:
            return
        raise SMTPError(550, "Unknown sender")

    cid = sender[0]
    lang = c.campaign_language(cid)
    campaign_name = c.campaign_name(cid)

    if sender[1]:
        # GM, pack and go
        logging.debug(u"END_GAME request from gm, campaign %s" % (str(cid),))

        all_characters = c.all_characters(cid)
        emails = set() # save emails before the purge
        for character in all_characters:
            emails.add(character['controller'])

        report_id  = end_campaign(cid)
        report_url = '%s/%s.zip' % (campaign_reports_url_config, report_id)

        for email in emails:
            msg = view.respond(locals(), "%s/end_game.msg" % (lang,),
                From="%s@%s" % (service_address, server_name,),
                To=email,
                Subject=view.render(locals(), "%s/end_game.subj" % (lang,)))
            send_or_queue(msg, cid)
    else:
        # PC, generate unenrollment address
        short_form = sender[2]
        unenrollment_address = t.start_unenrollment(cid, short_form)

        msg = view.respond(locals(), "%s/drop_pc.msg" % (lang,),
                            From="%s@%s" % (service_address, server_name),
                            To=message['from'],
                            Subject=view.render(locals(),
                                                    "%s/drop_pc.subj" % (lang,)))
        msg['Reply-To'] = "pm-unenroll-%s@%s" % (unenrollment_address, server_name)

        logging.debug(u"END_PC short form %s, unenroll at %s, campaign %s" %
                        (short_form, unenrollment_address, str(cid)))
        send_or_queue(msg, cid)
    return

@route("pm-summary@(host)")
@stateless
def GAME_SUMMARY(message, host=None):
    service_address = 'pm-summary'
    server_name = server_name_config

    sender = c.place_sender(message)
    if sender == INTERNAL:
        return # ignore
    if sender == UNKNOWN:
        if silent:
            return
        raise SMTPError(550, "Unknown sender")

    cid = sender[0]
    lang = c.campaign_language(cid)
    campaign_name = c.campaign_name(cid)

    if not sender[1]:
        if silent:
            logging.debug(u"NOT_GM ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, "Not a GM")

    logging.debug(u"GAME_SUMMARY request from gm, campaign %s" % (str(cid),))

    all_characters = c.all_characters(cid)
    emails = set() # save emails before the purge
    for character in all_characters:
        emails.add(character['controller'])

    report_id  = end_campaign(cid, purge=False)
    report_url = '%s/%s.zip' % (campaign_reports_url_config, report_id)

    msg = view.respond(locals(), "%s/game_summary.msg" % (lang,),
                    From="%s@%s" % (service_address, server_name,),
                    To=message['from'],
                    Subject=view.render(locals(), "%s/game_summary.subj" % (lang,)))
    send_or_queue(msg, cid)
    return

@route("pm-unenroll-(nonce)@(host)")
@stateless
def PC_END(message, nonce, host=None):
    # drop to NPC and inform the GM

    service_address = 'pm-unenroll-%s' % (nonce,)
    server_name = server_name_config

    sender = c.place_sender(message)
    if sender == INTERNAL:
        logging.debug(u"INTERNAL ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
        return # ignore
    if sender == UNKNOWN:
        if silent:
            return
        raise SMTPError(550, "Unknown sender")

    unenrollment = c.find_unenrollment(nonce)

    if unenrollment is None:
        if silent:
            logging.debug(u"INVALID code, ignoring %s@%s from %s" %
                      (service_address, server_name, message['from']))
            return
        raise SMTPError(550, "Unenrollment code invalid")

    (cid, short_form) = unenrollment

    lang = c.campaign_language(cid)
    campaign_name = c.campaign_name(cid)
    attribution = c.get_attribution(message['from'])

    c.do_unenrollment(cid, nonce)
    logging.debug(u"UNENROLLED short form %s, unenrolled at %s, campaign %s" %
                      (short_form, service_address, str(cid)))

    msg = view.respond(locals(), "%s/unenrolled_pc.msg" % (lang,),
                           From="%s@%s" % (service_address, server_name),
                           To=message['from'],
                           Subject=view.render(locals(),
                                                   "%s/unenrolled_pc.subj" % (lang,)))
    send_or_queue(msg, cid)

    # inform the GM
    (gm_address, gm_full, attribution) = c.campaign_gm(cid)
    msg = view.respond(locals(), "%s/unenrolled_gm.msg" % (lang,),
                           From="pm-unenrolled@%s" % (server_name,),
                           To=gm_full,
                           Subject=view.render(locals(),
                                                   "%s/unenrolled_gm.subj" % (lang,)))
    send_or_queue(msg, cid)
    return

# main entry point, messaging the GM/Character
@route("(address)@(host)", address=".+")
@stateless
#@bounce_to(soft=GM_BOUNCE, hard=GM_BOUNCE)
def START(message, address=None, host=None):
    server_name = server_name_config

    if(address.startswith("pm-")):
        return # ignore

    sender = c.place_sender(message)
    if sender == INTERNAL:
        return # ignore
    if sender == UNKNOWN:
        if silent:
            logging.debug(u"MESSAGE to %s@%s from %s - unknown" %
                      (address, server_name, message['from']))
            return
        raise SMTPError(550, "Unknown sender")

    cid = sender[0]
    # check the message haven't been processed already
    if tst_email_processed(message, cid):
        logging.debug(u"IGNORING processed email %s" % (message['message-id'],))
        return # ignore
    # the message as been set as processed

    lang = c.campaign_language(cid)
    campaign_name = c.campaign_name(cid)
    server_name = server_name_config

    recipients = c.get_recipients(message)

    if sender[1]: # GM EMAIL
        # determine if the email is sent as somebody else
        (gm_address, gm_full, attribution) = c.campaign_gm(cid)

        send_as = None
        for recipient in recipients:
            if recipient.startswith('as-'):
                if send_as:
                    other = send_as = recipient[3:].lower()
                    msg = view.respond(locals(), "%s/repeated_as.msg" % (lang,),
                                From="gm@%s" % (server_name,),
                                To=gm_full,
                                Subject=view.render(locals(),
                                               "%s/repeated_as.subj"  % (lang,)))
                    send_or_queue(msg, cid)
                    return
                send_as = recipient[3:].lower()

        # validate the as-XYZ is valid or note, otherwise
        if send_as:
            original_send_as = send_as
            send_as = c.get_character(cid, send_as)

            if not send_as:
                # reply with error to the GM with list of valid send-as
                all_characters = c.all_characters(cid)
                send_as = original_send_as

                msg = view.respond(locals(), "%s/unknown_as.msg" % (lang,),
                                   From="gm@%s" % (server_name,),
                                   To=gm_full,
                                   Subject=view.render(locals(),
                                                "%s/unknown_as.subj"  % (lang,)))
                send_or_queue(msg, cid)
                return

        if send_as:
           sender = formataddr( (send_as['name'], '%s@%s' % (send_as['address'], server_name)) )
        else:
           sender = 'gm@%s' % (server_name,)

        # for each recipient that is not an NPC, generate an email
        # either from the gm or from whomever is send_as to them with
        # cc: to the other characters and send them

        # extract the text
        full_content = message.body()
        #TODO check message.base.parts

        for recipient in recipients:
            if recipient.startswith('as-'):
                continue
            if recipient.startswith('pm-'):
                continue
            character = c.get_character(cid, recipient)

            if int(character['is_npc']) :
                continue

            if character is None:
                #TODO localize
                full_content = "UNKNOWN: " + recipient
                msg = view.respond(locals(), "%s/base.msg" % (lang,),
                                    From="gm@%s" % (server_name,),
                                    To=gm_full,
                                    Subject=full_content)
                logging.debug(u"INVALID character %s" % (recipient,))
                send_or_queue(msg, cid)
                return # ignore

            cc_list = []
            for other in recipients:
                if other.startswith('as-'):
                    cc_list.append('gm@%s' % (server_name,))
                elif other.startswith('pm-') and not send_as:
                    # this will be ignored by the server, but notifies
                    # the users unless is a send-as which will
                    # highlight the send-as to the players
                    cc_list.append('%s@%s' % (other, server_name))
                elif other != recipient:
                    other_character = c.get_character(cid, other)
                    if other_character is None:
                        full_content = "UNKNOWN: " + other
                        msg = view.respond(locals(), "%s/base.msg" % (lang,),
                                    From="gm@%s" % (server_name,),
                                    To=gm_full,
                                    Subject=full_content)
                        logging.debug(u"INVALID character %s" % (othert,))
                        send_or_queue(msg, cid)
                        return # ignore

                    cc_list.append(formataddr( (other_character['name'], '%s@%s' % (other,server_name,)) ))
            # sort them
            cc_list = sorted(cc_list)

            attribution = c.get_attribution(character['controller'])
            msg = view.respond(locals(), "%s/base.msg" % (lang,),
                            From=sender,
                            To=formataddr( (attribution, character['controller']) ),
                            Subject=campaign_name)
            if cc_list:
                msg['cc'] = ", ".join(cc_list)
            send_or_queue(msg, cid)
    else:
        short_form = sender[2]
        full_character = c.get_character(cid, short_form)

        # change the sender to their character email and send to GM
        (gm_address, gm_full, attribution) = c.campaign_gm(cid)

        # cc: for show
        cc_list = []

        for recipient in recipients:
            if recipient == 'gm':
                continue
            character = c.get_character(cid, recipient)
            cc_list.append(formataddr( (character['name'], '%s@%s' % (recipient,server_name,)) ))
        # sort them
        cc_list = sorted(cc_list)

        # extract the text
        full_content = sanitize(message.body())
        #TODO check message.base.parts
        msg = view.respond(locals(), "%s/base.msg" % (lang,),
                            From=formataddr( (full_character['name'], "%s@%s" % (short_form, server_name)) ),
                            To=gm_full,
                            Subject="%s: %s" % (campaign_name, full_character['name']))
        if cc_list:
                msg['cc'] = ", ".join(cc_list)
        send_or_queue(msg, cid)
        return


import sys
read=sys.stdin.readline
N,M=map(int,read().split())
matrix=[[0]*(N+1) for _ in range(N+1)]
topological=[]

for _ in range(M):
    i,j=map(int,read().split())
    matrix[i][j]=1

j=1
while(len(topological)<N):

    input=0
    for i in range(1,N+1):
        if j in topological:
            input=-1
            continue
        input+=matrix[i][j]
    if input==0:
        print(j,end=' ')
        topological.append(j)
        matrix[j]=[0]*(N+1)
        j=0
    j+=1

    if len(topological)==N:
        print('')


class Tool(object):
    # 使用赋值语句定义类属性，记录所有工具对象的数量
    count = 0

    @classmethod  # 使用类方法都要写这个前提。
    def show_tool_count(cls):  # 定义类方法
        print("工具对象的数量 %d" % cls.count)

    def __init__(self, name):
        self.name = name

        # 让类属性的值+1
        Tool.count += 1

# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("榔头")

# 调用类方法
Tool.show_tool_count()  # python 解释器会自动传递cls方法，所以括号内不需要写。