import numpy as np
from queue import Queue
import random
import matplotlib.pyplot as plt
import seaborn as sns

Direction = {
    "RIGHT": 0, "UP": 1, "LEFT": 2, "DOWN": 3, "NONE": -1
}

# 八个方向的数组
MoveTO = []
MoveTO.append(np.array([1, 0]))  # RIGHT
MoveTO.append(np.array([0, -1]))  # UP
MoveTO.append(np.array([-1, 0]))  # LEFT
MoveTO.append(np.array([0, 1]))  # DOWN

MoveTO.append(np.array([1, -1]))
MoveTO.append(np.array([-1, -1]))
MoveTO.append(np.array([-1, 1]))
MoveTO.append(np.array([1, 1]))

# 输入：一条线段的两个端点（一条边的两个端点）
# 输出：整点集合
def Init_Exit(P1, P2):
    exit = list()

    # 确定相等的坐标
    if P1[0] == P2[0]:
        x = P1[0]
        for y in range(P1[1], P2[1] + 1):  # 宽度为1
            exit.append((x, y))
    elif P1[1] == P2[1]:
        y = P1[1]
        for x in range(P1[0], P2[0] + 1):
            exit.append((x, y))
    # 斜线
    else:
        pass
    return exit

# 两点坐标围成的矩形区域（左下角和右上角）
def Init_Barrier(A, B):
    # 简单的判断，保证顺序
    if A[0] > B[0]:
        A, B = B, A

    x1, y1 = A[0], A[1]
    x2, y2 = B[0], B[1]

    if y1 < y2:
        return ((x1, y1), (x2, y2))
    else:
        return ((x1, y2), (x2, y1))

def Init_Barrier1(A, B, C):
    if A[0] > B[0]:
        A, B = B, A

    # 按照比例进行缩小,且由于canvas的原点在左上角,所以需要用75减去y值
    x1, y1 = int(A[0] / 3), 75 - int(A[1] / 3)
    x2, y2 = int(B[0] / 3), 75 - int(B[1] / 3)

    if y1 < y2:
        return ((x1, y1), (x2, y2), C)
    else:
        return ((x1, y2), (x2, y1), C)

# 外墙宽度
# Size
Outer_Size = 1

# 障碍 	-1
# LEFT 	0
# UP	1
# RIGHT 2
# DOWN  3

class Map:
    def __init__(self, L, W, E, B):
        # 基本的一些数据
        self.boomsite = (0, 0)
        self.Length = L
        self.Width = W
        self.Exits = E
        self.Barrier = B
        self.newB = list()
        self.barrier_list = []
        self.Exit = list()
        for num in range(len(self.Exits)):
            for (x, y) in Exits[num]:
                self.Exit.append((x, y))
        # 0~L+1
        # 0~W+1
        # 势能
        # 出口为 1
        # 障碍为 inf
        self.space = np.zeros((self.Length + Outer_Size * 2, self.Width + Outer_Size * 2))
        for j in range(0, self.Width + Outer_Size * 2):
            self.space[0][j] = self.space[L + 1][j] = float("inf")
            self.barrier_list.append((0, j))
            self.barrier_list.append((L + 1, j))

        for i in range(0, self.Length + Outer_Size * 2):
            self.space[i][0] = self.space[i][W + 1] = float("inf")
            self.barrier_list.append((i, 0))
            self.barrier_list.append((i, W + 1))

        # 设立障碍
        for (A, B, C) in self.Barrier:
            if C == 0:
                # 找到中点
                self.boomsite = (int((A[0] + B[0]) / 2), int((A[1] + B[1]) / 2))
            for i in range(A[0], B[0] + 1):
                for j in range(A[1], B[1] + 1):
                    self.space[i][j] = float("inf")
                    self.barrier_list.append((i, j))

        # 出口
        for exit in self.Exits:
            for (ex, ey) in exit:
                self.space[ex][ey] = 1
                if ex == self.Length:
                    self.space[ex + 1][ey] = 1
                if ey == self.Width:
                    self.space[ex][ey + 1] = 1
                if (ex, ey) in self.barrier_list:
                    self.barrier_list.remove((ex, ey))

        # 通过保留space的副本来实现最后的地图显示
        self.blankspace = self.space.copy()
        # origin副本用来保留最初的地图
        self.origin=self.space.copy()
        self.Init_Potential()

    # self.print(self.space)

    def print(self, mat):
        for line in mat:
            for v in line:
                print(v, end=' ')
            print("")

    # 判断该点是否合理
    def Check_Valid(self, x, y):
        # pass
        x, y = int(x), int(y)
        # 边缘
        if x > self.Length + 1 or x < 0 or y > self.Width + 1 or y < 0:
            return False
        # 障碍
        if self.space[x][y] == float("inf"):
            return False
        else:
            return True

    # 判断该点是否位于出口
    def checkSavefy(self, pos):
        x, y = int(pos[0]), int(pos[1])
        if x == self.Length + 1:
            x -= 1
        elif x == -1:
            x += 1
        if y == self.Width + 1:
            y -= 1
        elif y == -1:
            y -= 0

        if (x, y) in self.Exit:
            return True
        else:
            return False

    # 判断该点是否会导致死亡
    def CheckDead(self, x, y):
        x = int(x)
        y = int(y)

        # 是否位于爆炸点附近,且是否位于爆炸物中
        if self.boomsite[0] - 4 <= x <= self.boomsite[0] + 4 and self.boomsite[1] - 4 <= y <= self.boomsite[1] + 4 and \
                self.space[x][y] == float("inf"):
            return True
        else:
            # 是否被扩散物击中
            if len(myMap.newB) != 0:
                (a, b, c) = self.newB[0]
                if a[0] - 1 <= x <= b[0] + 2 and a[1] - 1 <= y <= b[1] + 2:
                    return True
            else:
                return False
        return False

    def CheckHurt(self, pos):
        x, y = int(pos[0]), int(pos[1])
        # 在爆炸点附近则会受伤
        if self.boomsite[0] - 6 <= x <= self.boomsite[0] + 6 and self.boomsite[1] - 6 <= y <= self.boomsite[1] + 6:
            return True
        else:
            return False
        return False

    def getDeltaP(self, P1, P2):
        x1, y1 = int(P1[0]), int(P1[1])
        x2, y2 = int(P2[0]), int(P2[1])
        return self.space[x1][y1] - self.space[x2][y2]

    # 确立势能地图
    def Init_Potential(self):
        minDis = np.zeros((self.Length + Outer_Size * 2, self.Width + Outer_Size * 2))
        for i in range(self.Length + Outer_Size * 2):
            for j in range(self.Width + Outer_Size * 2):
                minDis[i][j] = float("inf")

        for num in range(len(self.Exits)):
            for (sx, sy) in Exits[num]:
                tmp = self.BFS(sx, sy)
                for i in range(self.Length + Outer_Size * 2):
                    for j in range(self.Width + Outer_Size * 2):
                        minDis[i][j] = min(minDis[i][j], tmp[i][j])

        seeit = minDis.copy()
        # 实现建筑附近势能提升
        for (A, B, C) in self.Barrier:
            # 危险区域的势能提升更多
            if C == 0:
                for i in range(A[0] - 1, B[0] + 2):
                    for j in range(A[1] - 1, B[1] + 2):
                        minDis[i][j] = float("inf")
            elif C <= 6:
                for i in range(A[0] - 1, B[0] + 2):
                    for j in range(A[1] - 1, B[1] + 2):
                        minDis[i][j] = float("inf")

        self.space = minDis
        for (A, B, C) in self.Barrier:
            if C <= 2:
                for i in range(A[0] - 1, B[0] + 2):
                    for j in range(A[1] - 1, B[1] + 2):
                        seeit[i][j] += 50

        for i in range(seeit.shape[0]):
            for j in range(seeit.shape[1]):
                if seeit[i][j] == float("inf"):
                    seeit[i][j] = 200
        # 查看热力地图
        sns.heatmap(seeit.T, cmap='Reds', vmax=seeit.max(), vmin=seeit.min())
        plt.axis('equal')
        plt.show()

        # toprint=minDis.copy()
        # toprint=toprint.T
        # for i in range(0,70):
        #     for j in range(90,102):
        #         if toprint[i][j]==float("inf"):
        #             print(toprint[i][j],end="  ")
        #         elif toprint[i][j]>=10:
        #             print(round(toprint[i][j],1),end=" ")
        #         else:
        #             print(round(toprint[i][j],1),end="  ")
        #     print("")
    #清楚新的障碍
    def clearNB(self):
        del self.newB
        self.newB=list()
        self.blankspace = self.origin.copy()

    # 更新势能地图
    def update_Potential(self):
        self.space = self.blankspace.copy()
        # 随机更新爆炸物
        temp = random.uniform(0, 1)
        if temp < 0.125:
            tempx = self.boomsite[0] * 3 + int(random.uniform(1, 15))
            tempy = (75 - self.boomsite[1]) * 3 + int(random.uniform(12, 14))
        elif temp < 0.25:
            tempx = self.boomsite[0] * 3 + int(random.uniform(13, 15))
            tempy = (75 - self.boomsite[1]) * 3 + int(random.uniform(1, 14))
        elif temp < 0.375:
            tempx = self.boomsite[0] * 3 - int(random.uniform(1, 15))
            tempy = (75 - self.boomsite[1]) * 3 - int(random.uniform(12, 14))
        elif temp < 0.5:
            tempx = self.boomsite[0] * 3 - int(random.uniform(13, 15))
            tempy = (75 - self.boomsite[1]) * 3 - int(random.uniform(1, 14))
        elif temp < 0.625:
            tempx = self.boomsite[0] * 3 + int(random.uniform(1, 15))
            tempy = (75 - self.boomsite[1]) * 3 - int(random.uniform(12, 14))
        elif temp < 0.75:
            tempx = self.boomsite[0] * 3 + int(random.uniform(13, 15))
            tempy = (75 - self.boomsite[1]) * 3 - int(random.uniform(1, 14))
        elif temp < 0.875:
            tempx = self.boomsite[0] * 3 - int(random.uniform(1, 15))
            tempy = (75 - self.boomsite[1]) * 3 + int(random.uniform(12, 14))
        else:
            tempx = self.boomsite[0] * 3 - int(random.uniform(13, 15))
            tempy = (75 - self.boomsite[1]) * 3 + int(random.uniform(1, 14))
        self.newB.append(Init_Barrier1(A=(tempx - 4, tempy - 4), B=(tempx + 4, tempy + 4), C=0))

        for (A, B, C) in self.newB:
            for i in range(A[0], B[0] + 1):
                for j in range(A[1], B[1] + 1):
                    self.space[i][j] = float("inf")
                    self.blankspace[i][j] = float("inf")
                    self.barrier_list.append((i, j))

        minDis = np.zeros((self.Length + Outer_Size * 2, self.Width + Outer_Size * 2))
        for i in range(self.Length + Outer_Size * 2):
            for j in range(self.Width + Outer_Size * 2):
                minDis[i][j] = float("inf")

        for (A, B, C) in self.Barrier:
            if C == 0:
                for i in range(A[0] - 2, B[0] + 3):
                    for j in range(A[1] - 2, B[1] + 3):
                        self.space[i][j] = float("inf")
            # 提高建筑势能
            elif C <= 6:
                for i in range(A[0] - 1, B[0] + 2):
                    for j in range(A[1] - 1, B[1] + 2):
                        self.space[i][j] = float("inf")
        for (A, B, C) in self.newB:
            if C <= 2:
                for i in range(A[0] - 2, B[0] + 3):
                    for j in range(A[1] - 2, B[1] + 3):
                        self.space[i][j] = float("inf")

        # #print(minDis)
        # 每一个出口都会进行势能场的构建
        for num in range(len(self.Exits)):
            for (sx, sy) in Exits[num]:
                # print(sx, sy)
                tmp = self.BFS(sx, sy)
                # self.#print(tmp)
                for i in range(self.Length + Outer_Size * 2):
                    for j in range(self.Width + Outer_Size * 2):
                        # 在每个势能场中取最小的值
                        minDis[i][j] = min(minDis[i][j], tmp[i][j])

        self.space = minDis
        # seeit = minDis.copy()
        # # Barrier.append(Init_Barrier1(A=(65, 33), B=(85, 53), C=1))
        # print(seeit.shape)
        # # for (A, B, C) in self.Barrier:
        # #     if C <= 2:
        # #         for i in range(A[0] - 1, B[0] + 2):
        # #             for j in range(A[1] - 1, B[1] + 2):
        # #                 seeit[i][j] += 50
        # for i in range(seeit.shape[0]):
        #     for j in range(seeit.shape[1]):
        #         if seeit[i][j] == float("inf"):
        #             seeit[i][j] = 200
        # sns.heatmap(seeit.T, cmap='Reds', vmax=seeit.max(), vmin=seeit.min())
        # plt.axis('equal')
        # plt.show()

    # 通过BFS算法来遍历实现势能地图的建立
    def BFS(self, x, y):
        if not self.Check_Valid(x, y):
            return

        # 初始化
        tmpDis = np.zeros((self.Length + Outer_Size * 2, self.Width + Outer_Size * 2))
        for i in range(self.Length + Outer_Size * 2):
            for j in range(self.Width + Outer_Size * 2):
                tmpDis[i][j] = self.space[i][j]

        # 通过队列来实现遍历
        queue = Queue()
        queue.put((x, y))
        tmpDis[x][y] = 1
        while not queue.empty():
            (x, y) = queue.get()
            dis = tmpDis[x][y]
            # if dis>0:
            # 	continue

            for i in range(8):
                move = MoveTO[i]
                (nx, ny) = (x, y) + move
                if self.Check_Valid(nx, ny) and tmpDis[nx][ny] == 0:
                    queue.put((nx, ny))
                    # 上下左右距离为1，斜对角距离为1.4
                    tmpDis[nx][ny] = dis + (1.0 if i < 4 else 1.4)
        return tmpDis

    # 随机初始化智能体
    def Random_Valid_Point(self):
        x = random.uniform(1, self.Length + 2)
        y = random.uniform(1, self.Width + 2)
        while not myMap.Check_Valid(x, y):
            x = random.uniform(1, self.Length + 2)
            y = random.uniform(1, self.Width + 2)

        return x, y

    # 固定范围初始化智能体
    def Random_Valid_Point_S(self, xmin, xmax, ymin, ymax):
        x = random.uniform(xmin, xmax)
        y = random.uniform(ymin, ymax)
        while not myMap.Check_Valid(x, y):
            x = random.uniform(xmin, xmax)
            y = random.uniform(ymin, ymax)
        return x, y

def Init_Map():
    # 房间长宽
    Length = 60
    Width = 10

    # 出口
    # 点集
    Exit = Init_Exit(P1=(60, 2), P2=(60, 4))
    Exit.extend(Init_Exit(P1=(0, 8), P2=(0, 9)))

    # 障碍 矩形区域
    Barrier = list()
    Barrier.append(Init_Barrier(A=(3, 5), B=(60, 7)))
    Barrier.append(Init_Barrier(A=(10, 6), B=(15, 8)))

    return Map(L=Length, W=Width, E=Exit, B=Barrier)

# 厂区长宽
Length = 100
Width = 75

# 出口
# 点集
Exits = list()
Exits.append(Init_Exit(P1=(100, 27), P2=(100, 29)))
Exits.append(Init_Exit(P1=(75, 0), P2=(77, 0)))

# 甲乙丙丁戊危险划分 1-5，0为爆炸点
# 障碍 矩形区域
Barrier = list()
# 事故应急池，污水收集池
Barrier.append(Init_Barrier1(A=(33, 35), B=(53, 50), C=3))
# 正丁醇储罐
Barrier.append(Init_Barrier1(A=(65, 33), B=(85, 53), C=0))
# 甲醛储罐1
Barrier.append(Init_Barrier1(A=(33, 64), B=(53, 84), C=1))
# 甲醛储罐2
Barrier.append(Init_Barrier1(A=(65, 64), B=(85, 84), C=1))
# 丁二醇储罐1
Barrier.append(Init_Barrier1(A=(33, 96), B=(53, 116), C=1))
# 丁二醇储罐2
Barrier.append(Init_Barrier1(A=(65, 96), B=(85, 116), C=1))
# 装卸区
Barrier.append(Init_Barrier1(A=(22, 154), B=(52, 198), C=1))
# 仓库
Barrier.append(Init_Barrier1(A=(79, 154), B=(108, 198), C=1))
# 泡沫站
Barrier.append(Init_Barrier1(A=(135, 183), B=(147, 198), C=5))
# 循环水站
Barrier.append(Init_Barrier1(A=(159, 183), B=(171, 198), C=5))
# 公用工程中转站
Barrier.append(Init_Barrier1(A=(137, 154), B=(170, 170), C=5))
# 化验室
Barrier.append(Init_Barrier1(A=(183, 183), B=(215, 198), C=1))
# 中控室
Barrier.append(Init_Barrier1(A=(182, 154), B=(215, 171), C=5))
# 行政楼
Barrier.append(Init_Barrier1(A=(242, 186), B=(278, 198), C=5))
# 食堂
Barrier.append(Init_Barrier1(A=(242, 154), B=(254, 174), C=5))
# 停车场
Barrier.append(Init_Barrier1(A=(266, 154), B=(278, 174), C=5))
# 炔醛反应车间
Barrier.append(Init_Barrier1(A=(117, 80), B=(153, 125), C=1))
# 加氢车间
Barrier.append(Init_Barrier1(A=(169, 80), B=(205, 125), C=1))
# 精制车间
Barrier.append(Init_Barrier1(A=(117, 24), B=(153, 64), C=1))
# 预留用地
Barrier.append(Init_Barrier1(A=(169, 24), B=(205, 64), C=4))
# 消防中心
Barrier.append(Init_Barrier1(A=(234, 112), B=(254, 127), C=5))
# 消防车库
Barrier.append(Init_Barrier1(A=(239, 86), B=(254, 101), C=5))
# 维修站
Barrier.append(Init_Barrier1(A=(266, 112), B=(280, 127), C=5))
# 消防水池
Barrier.append(Init_Barrier1(A=(266, 86), B=(280, 101), C=5))
# 配电室
Barrier.append(Init_Barrier1(A=(234, 46), B=(248, 57), C=3))
# 压缩机房
Barrier.append(Init_Barrier1(A=(234, 22), B=(248, 34), C=1))
# 三废处理站
Barrier.append(Init_Barrier1(A=(260, 22), B=(278, 57), C=2))

# 第一种情况
myMap = Map(L=Length, W=Width, E=Exits, B=Barrier)


import streamlit as st
import datetime

def create_search_field():
    search = st.text_input('Texte à rechercher')
    return search

def create_year_selector():
    current_year = datetime.datetime.now().year
    years_list = list(range(2009, current_year + 1))
    year_min, year_max = st.select_slider('Années de lecture', options=years_list, value=(2009, current_year))
    return year_min, year_max

def filter_data(df, search, year_min, year_max):
    mask_writer = df['writer'].str.contains(search, case=False)
    mask_title = df['title'].str.contains(search, case=False)
    filtered_df = df[mask_writer | mask_title]
    filtered_df = filtered_df.loc[(df['annee'] >= year_min) & (df['annee'] <= year_max)]
    return filtered_df

def display_filtered_data(filtered_df):
    st.dataframe(filtered_df.sort_values(by='date', ascending=False)[['imageUrl', 'date', 'writer', 'title', 'rating']], column_config={
        "imageUrl": st.column_config.ImageColumn("Affiche", help="Affiche du film"),
        "date": st.column_config.DateColumn("Date", format="DD/MM/YYYY"),
        "director": "Réalisateur",
        "title": "Titre",
        "rating": st.column_config.NumberColumn(
            "Note",
            help="Note attribuée",
            format="%d ⭐",
        ),
    }, hide_index=True, width=800, height=800)

def books_list(df):
    with st.container():
        search = create_search_field()
        year_min, year_max = create_year_selector()
    filtered_df = filter_data(df, search, year_min, year_max)
    display_filtered_data(filtered_df)


import numpy as np
import struct
import pickle
import matplotlib.pyplot as plt
from PIL import Image

#data load
def load_mnist(is_training=True):
    if is_training:
        fd = open('./train-images.idx3-ubyte','rb')
        loaded = np.fromfile(file=fd, dtype=np.uint8)
        trainX = loaded[16:].reshape((60000, 784)).astype(np.float32)

        fd = open('./train-labels.idx1-ubyte','rb')
        loaded = np.fromfile(file=fd, dtype=np.uint8)
        trY = loaded[8:].reshape((60000)).astype(np.int32)

        #trX = trainX / 255.
        trX = trainX

        return trX, trY
    else:
        fd = open('./t10k-images.idx3-ubyte','rb')
        loaded = np.fromfile(file=fd, dtype=np.uint8)
        teX = loaded[16:].reshape((10000, 784)).astype(np.float)

        fd = open('./t10k-labels.idx1-ubyte','rb')
        loaded = np.fromfile(file=fd, dtype=np.uint8)
        teY = loaded[8:].reshape((10000)).astype(np.int32)

        #teX = teX / 255.
        teX = teX

        return teX, teY

def pca(data_mat, top_n_feat=99999999):
    num_data,dim = data_mat.shape

    mean_vals = data_mat.mean(axis=0)# データ中心化
    mean_removed = data_mat - mean_vals

    cov_mat = np.cov(mean_removed, rowvar=0)#共分散行列（Find covariance matrix）

    eig_vals, eig_vects = np.linalg.eig(np.mat(cov_mat))# 固有値(Find eigenvalues and eigenvectors)
    #print(eig_vals)
    #print(eig_vects)
    eig_val_index = np.argsort(eig_vals) # 固有値を大きい順にソート
    eig_val_index = eig_val_index[:-(top_n_feat + 1) : -1]# 大きい方からtop_n_feat個の固有値
    reg_eig_vects = eig_vects[:, eig_val_index]# 上記固有値に対応する固有ベクトル
    low_d_data_mat = mean_removed * reg_eig_vects# 上記ベクトルが張る空間へ射影
    new_vecte = reg_eig_vects.T * reg_eig_vects
    # top_n_feat個の固有ベクトル
    print(new_vecte)
    # low_d_data_mat を原空間の座標に変換
    recon_mat = (low_d_data_mat * reg_eig_vects.T) + mean_vals
    return low_d_data_mat, recon_mat

#img　画像を表示用に1つにまとめる
def comb_imgs(origin_imgs, col, row, each_width, each_height, new_type):
    new_img = Image.new(new_type, (col* each_width, row* each_height))
    for i in range(len(origin_imgs)):
        each_img = array_to_img(np.array(origin_imgs[i]).reshape(each_width, each_width))
        new_img.paste(each_img, ((i % col) * each_width, (i // col) * each_width))
    return new_img
# 配列を画像に
def array_to_img(array):
    #array=array*255
    new_img=Image.fromarray(array.astype(np.uint8))
    return new_img

X_train, y_train= load_mnist(is_training=True)
X_test, y_test= load_mnist(is_training=False)
low_train_img = comb_imgs(X_train, 100, 100, 28, 28, 'L')

# train data すべてを表示
# low_train_img.show()

#8_img 「8」だけを抜き出して、origin_8_imgsに格納、表示
origin_9_imgs = []
for i in range(60000):
     if y_train[i] == 9 and len(origin_9_imgs) < 1000:
        origin_9_imgs.append(X_train[i])
low_9_img = comb_imgs(origin_9_imgs, 25, 40, 28, 28, 'L')
# low_8_img.show()

#0_img 「0」だけを抜き出して、origin_0_imgsに格納、表示
origin_5_imgs = []
for i in range(10000):
     if y_test[i] == 5 and len(origin_5_imgs) < 1000:
        origin_5_imgs.append(X_test[i])
low_5_img = comb_imgs(origin_5_imgs, 25, 40, 28, 28, 'L')
#low_5_img.show()

# origin_8_imgsに対してPCAをかけ、pcadim 次元の空間を構成
# origin_8_imgs をその空間に対して射影した画像を表示
pcadim = 500
low_d_feat_for_9_imgs, recon_mat_for_9_imgs = pca(np.array(origin_9_imgs), pcadim)
low_d_img = comb_imgs(recon_mat_for_9_imgs, 25, 40, 28, 28, 'L')
low_d_img.show()
#'''

# origin_0_imgsに対してPCAをかけ、pcadim 次元の空間を構成
# origin_0_imgs をその空間に対して射影した画像を表示
pcadim = 500
low_d_feat_for_5_imgs, recon_mat_for_5_imgs = pca(np.array(origin_5_imgs), pcadim)
low_d_img = comb_imgs(recon_mat_for_5_imgs, 25, 40, 28, 28, 'L')

low_d_img.show()

# origin_8_imgsに対してPCAをかけ、pcadim 次元の空間を構成
# origin_0_imgs をその空間に対して射影した画像を表示


import json

import logging
from slack_bolt import App, BoltContext
import slack_sdk

import buddy.utils as utils
import buddy.constants as c

mlogger = logging.getLogger(__name__)

def register(slack_app: App):
    slack_app.event(c.EVENT_APP_MENTION)(listener_generic_event_handler)
    slack_app.event(c.EVENT_CHANNEL_ARCHIVE)(listener_generic_event_handler)
    slack_app.event(c.EVENT_CHANNEL_CREATED)(listener_generic_event_handler)
    slack_app.event(c.EVENT_CHANNEL_DELETED)(listener_generic_event_handler)
    slack_app.event(c.EVENT_CHANNEL_UNARCHIVE)(listener_generic_event_handler)
    slack_app.event(c.EVENT_REACTION_ADDED)(listener_generic_event_handler)
    slack_app.event(c.EVENT_APP_HOME_OPENED)(listener_update_app_home)
    # Mediocre ability to track how many workflows currently are using App Steps
    # https://api.slack.com/workflows/steps#tracking
    # slack_app.event(c.EVENT_WORKFLOW_PUBLISHED)
    # slack_app.event(c.EVENT_WORKFLOW_UNPUBLISHED)
    # slack_app.event(c.EVENT_WORKFLOW_DELETED)
    # slack_app.event(c.EVENT_WORKFLOW_STEP_DELETED)

def listener_generic_event_handler(
    logger: logging.Logger, event: dict, body: dict, context: BoltContext
):
    utils.generic_event_proxy(logger, event, context.team_id, context.enterprise_id)

def listener_update_app_home(
    event: dict,
    logger: logging.Logger,
    client: slack_sdk.WebClient,
    context: BoltContext,
):
    team_id = context.team_id
    app_home_view = utils.build_app_home_view(
        context.team_id, enterprise_id=context.enterprise_id
    )
    client.views_publish(user_id=event["user"], view=app_home_view)


import datetime
import json
import requests

def newton(update, context):
    update.message.reply_text(juvenes())

def reaktori(update, context):
    update.message.reply_text(returnreaktori())

def hertsi(update, context):
    update.message.reply_text(returnhertsi())

def juvenes(KitchenId="6", MenuTypeId="60"):
    try:
        date = str(datetime.date.today())
        day = date[8:]
        month = date[5:7]

        teksti = ""
        url = "http://www.juvenes.fi/DesktopModules/Talents.LunchMenu/LunchMenuServices.asmx/GetMenuByDate?KitchenId=" \
              + KitchenId + "&MenuTypeId=" + MenuTypeId + "&Date='" + day + "/" + month + "'&lang='fi'&format=json"
        x = requests.get(url)

        if x.status_code != 200:
            return "Error " + x.status_code + "occured when retrieving data."

        x = x.content

        menu = json.loads(json.loads(x, encoding='utf-8')['d'])

        for item in menu["MealOptions"]:
            first_menu_item = item["MenuItems"][0]
            name = first_menu_item["Name"]
            diets = first_menu_item["Diets"]
            teksti += "• " + name + " " + diets + "\n"

        if not teksti:
            teksti = "Ei mitään syötävää!\n\n"
    except ValueError:
        teksti = "Ei mitään syötävää!\n\n"
    return teksti

def returnreaktori(compact=False):
    date = str(datetime.date.today())

    url = "https://www.fazerfoodco.fi/modules/json/json/Index?costNumber=0812&language=fi"
    x = requests.get(url)

    if x.status_code != 200:
        return "Error " + x.status_code + "occured when retrieving data."

    x = x.content.decode("utf-8")
    x = x.replace("  ", "")

    teksti = ""
    menu = json.loads(x, encoding='utf-8')

    for item in menu["MenusForDays"]:
        if date in item["Date"]:
            for set_menu in item["SetMenus"]:
                if compact is True:
                    if set_menu["Name"] == "lounas":
                        if set_menu["Name"] not in teksti:
                            teksti += set_menu["Name"] + ": " + "\n"
                        for menu_component in set_menu["Components"]:
                            teksti += "    • " + menu_component + "\n"

                else:
                    if set_menu["Name"] not in teksti:
                        teksti += set_menu["Name"] + ": " + "\n"
                    for menu_component in set_menu["Components"]:
                        teksti += "    • " + menu_component + "\n"
            teksti = teksti.replace("xc2xb4", "'")
            aukioloaika = str(item["LunchTime"])

            teksti += "\nReaktori on avoinna " + aukioloaika + "\n"

    if not teksti:
        teksti = "Ei mitään syötävää!\n\n"

    return teksti

def returnhertsi(compact=False):
    date = str(datetime.date.today())
    day = date[8:]
    month = date[5:7]
    year = date[:4]

    url = "http://www.sodexo.fi/ruokalistat/output/daily_json/12812/" + year + "/" + month + "/" + day + "/fi"
    x = requests.get(url)

    if x.status_code != 200:
        return "Error " + x.status_code + "occured when retrieving data."

    x = x.content.decode("utf-8")

    menu = json.loads(x, encoding='utf-8')

    teksti = "\n⚡" + "Hertsissä tänään" + "⚡\n\n"

    try:
        for item in menu["courses"]:

            # tarkasta erikoisruokavaliot

            if "properties" in item.keys():
                properties = item["properties"] + "\n"
            else:
                properties = "\n"

            # tulosta compact modessa vain 2,60 maksavat ruuat
            if compact is True:
                if "2,60" in item["price"]:
                    teksti += item["category"] + ":\n"
                    teksti += "    • " + item["title_fi"] + properties

            # muussa modessa tulosta kaikki ruuat
            else:
                teksti += item["category"] + ":\n"
                teksti += "    • " + item["title_fi"] + properties

    except KeyError:
        teksti += "Ei mitään syötävää!\n\n"

    teksti += "\nHertsi on avoinna Ma-Pe 10.30 - 15.00, kahvila Bitti palvelee klo 08.00 - 17.00 Ma-Pe"

    return teksti

def returnmenu():
    päämuuttuja = "⚖ Newtonissa tarjolla ⚖\n\n"

    päämuuttuja += juvenes("6", "60")
    päämuuttuja += "\nRavintola Newton palvelee yleensä ma-to 10.30-16.00 ja pe 10.30-15.00" + "\n\n" + "🍛 Sååsibaarissa 🍛\n\n"
    päämuuttuja += juvenes("60038", "77")
    päämuuttuja += "SÅÅSBAR on avoinna ma-pe 10.30-19.00" + "\n\n" + "🍔 Fusarissa 🍔\n\n"
    päämuuttuja += juvenes("60038", "3")
    päämuuttuja += "Fusion Kitchen on avoinna ma-pe 10.30-18.45, Café Konehuone palvelee ma-pe klo 8-19" + "\n"

    päämuuttuja += "\n☢ Reaktori tarjoaa ☢\n\n"
    päämuuttuja += returnreaktori(True)  # reaktorin tiedot

    päämuuttuja += returnhertsi(True)  # hertsin tiedot

    päämuuttuja += "\n\nFor more options, see /fullmenu"

    return päämuuttuja

def returnfullmenu():
    päämuuttuja = "⚖ Newtonissa tarjolla ⚖\n\n"

    päämuuttuja += juvenes("6", "60")
    päämuuttuja += "\nRavintola Newton palvelee yleensä ma-to 10.30-16.00 ja pe 10.30-15.00" + "\n\n" + "🍛 Sååsibaarissa 🍛\n\n"
    päämuuttuja += juvenes("60038", "77")
    päämuuttuja += "\nSÅÅSBAR on avoinna ma-pe 10.30-19.00" + "\n\n" + "🍔 Fusarissa 🍔\n\n"
    päämuuttuja += juvenes("60038", "3")
    päämuuttuja += "\nFusion Kitchen on avoinna ma-pe 10.30-18.45, Café Konehuone palvelee ma-pe klo 8-19" + "\n"

    päämuuttuja += "\n☢ Reaktori tarjoaa ☢\n\n"
    päämuuttuja += returnreaktori(False)  # reaktorin tiedot

    päämuuttuja += returnhertsi(False)  # hertsin tiedot

    return päämuuttuja

def menu(update, context):
    update.message.reply_text(returnmenu())

def fullmenu(update, context):
    update.message.reply_text(returnfullmenu())


from flask import Flask, request, abort, render_template
from flask_restful import Resource, Api
from multiprocessing import Process, Pipe
from ctypes import c_bool
import re, os, subprocess

from program import Program
from pixels import Pixels

class ProgramProcess(Process):
    def __init__(self, name, data):
        super().__init__()
        self.pipe_in, self.pipe_out = Pipe()
        self.program = Program(name=name, data=data, pixels=Pixels())

    def run(self):
        while True:
            if self.program and self.program.running:
                self.program.step()
            if self.pipe_out.poll():
                self.program = self.pipe_out.recv()
                assert type(self.program) == Program

binaries = {}
BUILTIN = ["idle", "rainbow", "life"]
for name in BUILTIN:
    with open(f"programs/{name}.bin", "rb") as binary:
        binaries[name] = binary.read()

current = ProgramProcess(name="idle", data=binaries["idle"])

app = Flask(__name__)
api = Api(app)

@app.route("/")
def index():
    return render_template("index.html")

class StatusResource(Resource):
    # GET /status/
    # get server status
    def get(self):
        return f"GET /status"

api.add_resource(StatusResource, "/status")

class ProgramsResource(Resource):
    # GET /programs
    # list all programs
    def get(self):
        global binaries
        return {"programs": list(binaries.keys())}

api.add_resource(ProgramsResource, "/programs")

class ModifyProgramResource(Resource):
    # GET /programs/<name>
    # download a program
    def get(self, name):
        global binaries
        if name not in binaries:
            abort(404, "Program not found.")
        return binaries[name]

    # POST /programs/<name>
    # upload a program
    def post(self, name):
        global binaries
        if not request.data:
            abort(400, "Binary data required.")
        if name in BUILTIN:
            abort(403, f"Program {name} cannot be modified.")
        binaries[name] = request.data
        return "", 204

    # DELETE /programs/<name>
    # delete a program
    def delete(self, name):
        global binaries
        if name not in binaries:
            abort(404, "The program does not exist.")
        del binaries[name]
        return "", 204

api.add_resource(ModifyProgramResource, "/programs/<string:name>")

class ExecuteResource(Resource):
    # GET /execute
    # get running program name
    def get(self):
        global current
        return current.program.name

api.add_resource(ExecuteResource, "/execute")

class ExecuteProgramResource(Resource):
    # POST /execute/<name>
    # set running program
    def post(self, name):
        global binaries, current
        if name not in binaries:
            abort(404, "The program does not exist.")
        current.pipe_in.send(Program(name=name, data=binaries[name], pixels=Pixels()))
        return "", 204

api.add_resource(ExecuteProgramResource, "/execute/<string:name>")

class ColorResource(Resource):
    color_pattern = re.compile(r"^[0-9a-f]{6}$")

    # POST /color/<value>
    # set running program to run solid color
    def post(self, value):
        global binaries, current
        if not ColorResource.color_pattern.match(value):
            abort(404, "Invalid color code.")
        value = int(value, 16)
        r, g, b = ((value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF)
        current.pipe_in.send(
            Program(
                name="color",
                data=bytes([
                    0x31,    r,    g,    b,
                    0x00, 0xe7, 0x11, 0x0a,
                    0xf9, 0x40, 0x06, 0x00
                ]),
                pixels=Pixels(),
            )
        )
        return "", 204

api.add_resource(ColorResource, "/color/<string:value>")

if __name__ == "__main__":
    current.start()
    app.secret_key = os.urandom(12)
    try:
        host = (
            subprocess.check_output(["/bin/hostname", "-I"])
            .split()[0]
            .strip()
            .decode("utf-8")
        )
    except IndexError:
        raise Exception(subprocess.check_output(["/bin/hostname", "-I"]))
    print("Host:", host)  # Right now this breaks under Darnell wifi
    app.run(
        debug=False, use_reloader=False, host=host, port=8010
    )  # change use_reloader to True when running


# coding: utf-8

import requests
import json
import random

class expansion_temp(expansion):
    def __init__(self, name):
        expansion.__init__(self, name)

    def command_boobs(self, stype, source, body, disp):
        request_temp_str = 'http://api.oboobs.ru/boobs/%d/%d/'
        count_boobs_req = 'http://api.oboobs.ru/boobs/count/'

        try:
            c = requests.get(count_boobs_req, verify=False)
            boobs_count = json.loads(c.text)[0]['count']
            c.close()
        except:
            boobs_count = 0

        i = int(body) if body.isdigit() else 1

        id_bs = random.choice(xrange(boobs_count))

        if id_bs < i:
            id_bs = i

        print(boobs_count)

        rs = request_temp_str % (id_bs,i)

        r = requests.get(rs, verify=False)
        print(r.text)
        rq_ans = json.loads(r.text)

        ans = []
        for x in rq_ans:
            id_str = '0'*(1 + len(str(boobs_count)) - len(str(x['id']))) + str(x['id'])
            ans.append('http://media.oboobs.ru/boobs/' + id_str + '.jpg')

        answer = '\n'.join(ans)

        if body.startswith('всего'):
            Answer('Сисек всего %d.' % boobs_count, stype, source, disp)
        else:
            if 5 < i < 10:
                Message(source[0], answer, disp)
                Answer('Сиськи в личке.', stype, source, disp)
            elif 10 <= i <= boobs_count:
                Answer('Зачем тебе столько?!', stype, source, disp)
            elif boobs_count == 0:
                Answer("Нет сисек :'(", stype, source, disp)
            elif i > boobs_count:
                Answer("Столько сисек нет :'(", stype, source, disp)
            else:
                Answer(answer, stype, source, disp)

    commands = ((command_boobs, "boobs", 1,),)


from operator import itemgetter

from numpy import asarray, column_stack, ones_like, array, average, ravel, zeros_like

# ============= local library imports  ==========================
from scipy.interpolate import Rbf, bisplrep, bisplev, griddata
from statsmodels.regression.linear_model import WLS, OLS

# ============= enthought library imports =======================
from traits.api import Bool, Int

from pychron.core.geometry.geometry import calc_distances
from pychron.core.regression.base_regressor import BaseRegressor
from pychron.core.regression.ols_regressor import MultipleLinearRegressor
from pychron.core.stats.idw import Invdisttree

class SpecialFluxRegressor(BaseRegressor):
    use_weighted_fit = Bool

    def predict(self, pts):
        return array(self._predict(pts))

    def predict_error(self, pts, error_calc=None):
        return array(self._predict(pts, return_error=True))

    def get_exog(self, x):
        return x

    def _calculate_coefficients(self):
        return ""

    def _calculate_coefficient_errors(self):
        return ""

class InterpolationRegressor(SpecialFluxRegressor):
    def predict(self, pts):
        return zeros_like(pts)

    def predict_error(self, pts, **kw):
        return zeros_like(pts)

class BSplineRegressor(InterpolationRegressor):
    def calculate(self):
        x, y = self.clean_xs.T

        z = self.clean_ys
        # self.rbf = Rbf(x, y, z)

        self._tck = bisplrep(x, y, z, kx=4, ky=4)

    def predict_grid(self, x, y):
        znew = bisplev(x, y, self._tck)
        return znew

class RBFRegressor(InterpolationRegressor):
    rbf_kind = "multiquadric"

    def calculate(self):
        x, y = self.clean_xs.T

        z = self.clean_ys
        self.rbf = Rbf(x, y, z, function=self.rbf_kind)

    def predict_grid(self, x, y):
        return self.rbf(x, y)

class GridDataRegressor(InterpolationRegressor):
    method = "cubic"

    def calculate(self):
        pass

    def predict_grid(self, x, y):
        return griddata(self.clean_xs, self.clean_ys, (x, y), method=self.method)

class IDWRegressor(InterpolationRegressor):
    def calculate(self):
        leafsize = 10
        known = self.clean_xs
        z = self.clean_ys
        self._invdisttree = Invdisttree(known, z, leafsize=leafsize, stat=1)

    def predict(self, pts):
        nnear = 8  # 8 2d, 11 3d => 5 % chance one-sided -- Wendel, mathoverflow.com
        eps = 0.1  # approximate nearest, dist <= (1 + eps) * true nearest
        p = 2  # weights ~ 1 / distance**p
        return self._invdisttree(pts, nnear=nnear, eps=eps, p=p)

class NearestNeighborFluxRegressor(SpecialFluxRegressor):
    n = Int(3)

    def _predict(self, pts, return_error=False):
        def pred(x, y):
            """
            get the n positions that are closest (eucledian distance) to x,y
            """

            v2 = array([[x, y]])
            ds = ravel(calc_distances(self.clean_xs, v2))
            idx = sorted(enumerate(ds), key=itemgetter(1))
            idx, ds = zip(*idx[: self.n])

            v = 0
            if idx:
                idx = array(idx)

                vs = self.clean_ys[idx]

                if self.use_weighted_fit:
                    es = self.clean_yserr[idx]
                    ws = es**-2
                    if return_error:
                        v = ws.sum()
                    else:
                        v = average(vs, weights=ws)
                else:
                    if return_error:
                        v = vs.std()
                    else:
                        v = vs.mean()
            return v

        ret = [pred(*pt) for pt in pts]
        return ret

# class BracketingFluxRegressor(SpecialFluxRegressor):
#
#     def _predict(self, pts, return_error=False):
#         def pred(x, y):
#             """
#             get points with same y value
#             :param p:
#             :return:
#             """
#             tol = 0.001
#
#             # idx = (i for i, p in enumerate(self.clean_xs) if ((x - p[0]) ** 2 + (y - p[1]) ** 2) ** 0.5 < tol)
#             # idx = (i for i, p in enumerate(self.clean_xs) if )
#             idx = [abs(y - p[1]) < tol for p in self.clean_xs]
#             v = 0
#             if idx:
#                 vs = self.clean_ys[idx]
#
#                 if self.use_weighted_fit:
#                     es = self.clean_yserr[idx]
#                     ws = es ** -2
#                     if return_error:
#                         v = ws.sum()
#                     else:
#                         v = average(vs, weights=ws)
#                 else:
#                     if return_error:
#                         v = vs.std()
#                     else:
#                         v = vs.mean()
#             return v
#
#         ret = [pred(*pt) for pt in pts]
#         return ret
#
#
# class MatchingFluxRegressor(BaseRegressor):
#     def predict(self, pts):
#         return self._predict(pts, self.clean_ys)
#
#     def predict_error(self, pts, error_calc=None):
#         # pts = pts[0]
#         return self._predict(pts, self.clean_yserr)
#
#     def _predict(self, pts, ret):
#         def matching(xx, yy):
#             for i, pt in enumerate(self.clean_xs):
#                 if ((xx - pt[0]) ** 2 + (yy - pt[1]) ** 2) ** 0.5 < 0.0001:
#                     return ret[i]
#             else:
#                 return 0
#
#         return array([matching(x, y) for x, y in pts])

class BowlFluxRegressor(MultipleLinearRegressor):
    def _get_X(self, xs=None):
        if xs is None:
            xs = self.xs
        xs = asarray(xs)
        x1, x2 = xs.T

        return column_stack(
            (
                x1**2,
                x2**2,
                x1**2 * x2,
                x2**2 * x1,
                x1 * x2,
                x1,
                x2,
                ones_like(x1),
            )
        )
        # return column_stack((x1, x2, x1 ** 2, x2 ** 2, x1 * x2, x1**2*x2, x2**2*x1, ones_like(x1)))
        # return column_stack((x1**2, x2**2, x1, x2, ones_like(x1)))

class PlaneFluxRegressor(MultipleLinearRegressor):
    use_weighted_fit = Bool(False)

    def _get_weights(self):
        e = self.clean_yserr
        if self._check_integrity(e, e):
            return 1 / e**2

    def _engine_factory(self, fy, X, check_integrity=True):
        if self.use_weighted_fit:
            return WLS(fy, X, weights=self._get_weights())
        else:
            return OLS(fy, X)

# ============= EOF =============================================


from weasyprint import HTML
from flask import Flask, render_template, request, send_file
import os
from datetime import datetime
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # This will enable CORS for all routes

@app.route("/", methods=["GET", "POST"])
def create_pdf():
    if request.headers.get("Content-Type") == "application/json":
        posted_data = request.get_json() or {}
        today = datetime.today().strftime("%B %#d, %Y")
        default_data = {
            "duedate": "November 7, 2023",
            "from_addr": {
                "company_name": "Python Tip.",
                "addr1": "12345 Sunny Road",
                "addr2": "Sunnyville, CA 12345",
            },
            "invoice_number": 123,
            "items": [
                {"title": "website design", "charge": 300.00},
                {"title": "Hosting (3 months)", "charge": 75.00},
                {"title": "Domain name (1 year)", "charge": 10.00},
            ],
            "to_addr": {
                "company_name": "Acme Corp.",
                "person_name": "John Dilly",
                "person_email": "john@example.com",
            },
        }
        duedate = posted_data.get("duedate", default_data["duedate"])
        from_addr = posted_data.get("from_addr", default_data["from_addr"])
        to_addr = posted_data.get("to_addr", default_data["to_addr"])
        items = posted_data.get("items", default_data["items"])
        invoice_number = posted_data.get(
            "invoice_number", default_data["invoice_number"]
        )

        total = sum([i["charge"] for i in items])
        rendered = render_template(
            "invoice.html",
            date=today,
            from_addr=from_addr,
            to_addr=to_addr,
            items=items,
            total=total,
            invoice_number=invoice_number,
            duedate=duedate,
        )
        HTML(string=rendered).write_pdf("./static/invoice.pdf")
        return "OK", 200

    else:
        return (
            "Invalid Content-Type. Please use application/json",
            400,
        )  # HTTP 400 Bad Request

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(host="0.0.0.0", port=port, debug=True)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

matches = pd.read_csv('matches.csv')
#creating new column for Year by extracting Year from date column
matches["Year"] = year=pd.DatetimeIndex(matches['date']).year

csk = matches[matches["winner"] == "Chennai Super Kings"]
rcb = matches[matches["winner"] == "Royal Challengers Bangalore"]
mi = matches[matches["winner"] == "Mumbai Indians"]
sh = matches[matches["winner"] == "Sunrisers Hyderabad"]
kkr = matches[matches["winner"] == "Kolkata Knight Riders"]

plt.figure(figsize=(12, 6))
plt.plot(mi['Year'].value_counts().sort_index(), label="Mumbai Indians")
plt.plot(sh['Year'].value_counts().sort_index(), label="Sunrisers Hyderabad")
plt.plot(kkr['Year'].value_counts().sort_index(), label="Kolkata Knight Riders")

plt.title("Number of matches won by three IPL teams")
plt.xlabel("Number of time a team won")
plt.ylabel("Year")
plt.xticks(np.arange(2008, 2019, 1))
plt.legend()
plt.show()


import requests as req
import pandas as pd
from bs4 import BeautifulSoup
from configparser import ConfigParser

config = ConfigParser()
config.read('/Users/kimsunjung/Desktop/dev/dataGeneration/config.ini')
config.sections()
AMC_URL = config['url']['amc_url']
AMC_SYM_URL = config['url']['amc_sym_url']
SYM_ALL_LISTS = list()

# return { '증상명': '세부증상1', '세부증상2', '세부증상3', '''' }
def crawling():
    res = req.get(AMC_URL)
    soup = BeautifulSoup(res.text, 'html.parser')
    titles = soup.select('ul.contList > li > a')
    sym_dict = dict()
    result_num = 0

    for i in range(len(titles)):
        res = req.get(AMC_SYM_URL + titles[i]['href'])
        title = titles[i].text
        soup = BeautifulSoup(res.text, 'html.parser')
        result = soup.select("div.searchCont > ul > li > label")
        sym_list = list()
        for i in range(len(result)):
            SYM_ALL_LISTS.append(result[i].string)
            sym_list.append(result[i].string)
        result_num += len(sym_list)
        sym_dict[title] = sym_list
    return sym_dict


#!/usr/bin/env python3
import pygame as G
import innie

MT_LADDER = 8
MT_DOOR = 12
MT_DOOR_UNFINISHED_BOTTOM = 9
MT_OPEN_DOOR = 14
MT_ELEVATOR_SIGNAL = 43
MT_ELEVATOR_DOOR = 44

# 0-7: background patterns
# 8: ladder
# 12, 13: closed door
# 14, 15: open door
# 16: block (+1: top connect, +2: right connect,
#     +4: bottom connect, +8: left connect)
mttable = bytes([
  1, 1, 1, 1,  1, 2, 2, 1,  2, 2, 2, 2,  3, 3, 3, 3,
  5, 5, 5, 5,  6, 6, 6, 6,  6, 7, 7, 6,  7, 7, 7, 7,
 0xD6,0xD7,0xD6,0xD7, 0xF3,0xE4,0xF8,0xF9,  0, 0, 0, 0,  0, 0, 0, 0,
 0xD3,0xD4,0xE3,0xE4, 0xF3,0xE4,0xE3,0xE4, 0x08,0xD5,0x08,0xE5, 0x08,0xF5,0x08,0xE5,

 0xD0,0xD2,0xF0,0xF2, 0xE0,0xE2,0xF0,0xF2, 0xD0,0xD1,0xF0,0xF1, 0xE0,0xE1,0xF0,0xF1,
 0xD0,0xD2,0xE0,0xE2, 0xE0,0xE2,0xE0,0xE2, 0xD0,0xD1,0xE0,0xE1, 0xE0,0xE1,0xE0,0xE1,
 0xD1,0xD2,0xF1,0xF2, 0xE1,0xE2,0xF1,0xF2, 0xD1,0xD1,0xF1,0xF1, 0xE1,0xE1,0xF1,0xF1,
 0xD1,0xD2,0xE1,0xE2, 0xE1,0xE2,0xE1,0xE2, 0xD1,0xD1,0xE1,0xE1, 0xE1,0xE1,0xE1,0xE1,

 0x03,0x02,0x02,0x01, 0xE6,0xE7,0x01,0x00, 0xE7,0xF6,0x00,0x01, 0x02,0x03,0x01,0x02,
 0x02,0x01,0x02,0x02, 0x01,0x02,0x02,0x02, 0x03,0x02,0x03,0x03, 0x02,0x03,0x03,0x03,
 0x03,0x03,0x04,0x04, 0x05,0x04,0x06,0x05, 0x07,0x06,0x07,0x07, 0x01,0x02,0x02,0xF7,
 0xF4,0x04,0xF4,0x04, 0x07,0x06,0x07,0x07, 0x05,0x04,0x06,0x05, 0x04,0x04,0x04,0x04
])

mtmap_fluoro = bytes([6, 4,
 0x03,0x20,0x21,0x22,0x23,0x03,
 0x03,0x24,0x00,0x00,0x25,0x03,
 0x03,0x26,0x02,0x02,0x27,0x03,
 0x28,0x28,0x03,0x03,0x28,0x28
])
mtmap_elevator = bytes([1, 4,
 0x10,0x10,0x2C,0x2C
])
mtmap_backshadow = bytearray()

def add_mtmap(level, area, x, y):
    w, h = area[:2]
    pitch = w
    i = 2
    skip = 0
    if x < 0:
        skip -= x
        i -= x
        w += x
    if w > 16 - x:
        skip += w + x - 16
        w = 16 - x
    if w <= 0:
        return
    di = y * 16 + x
    while h > 0:
        for lx in range(w):
            level[di] = level[di] or area[i]
            di += 1
            i += 1
        i += skip
        di += 16 - w
        h -= 1

def makemetatilesheet(chrrom_bmp, mttable):
    tilestall = -(-len(mttable) // 64)
    out = G.Surface((256, tilestall * 16))
    mttable = iter(mttable)
    outy = 0
    try:
        for outy in range(0, tilestall * 16, 16):
            for outx in range(0, 256, 16):
                for dsty in (outy, outy + 8):
                    for dstx in (outx, outx + 8):
                        tileno = next(mttable)
                        srcarea = (8 * (tileno % 16), 8 * (tileno // 16), 8, 8)
                        out.blit(chrrom_bmp, (dstx, dsty), srcarea)
    except StopIteration:
        pass
    return out

def connect_level(level):
    from random import choice, shuffle

    # Break existing connections
    for y in range(0, len(level), 16):
        for x in range(y, y + 15):
            b = level[x]
            if 16 <= b < 32:
                b = 16
            level[x] = b

    # Connect blocks across
    for y in range(0, len(level), 16):
        for x in range(y, y + 15):
            if 16 <= level[x] < 32 and 16 <= level[x + 1] < 32:
                level[x] |= 2
                level[x + 1] |= 8

    # Connect blocks down
    for x in range(len(level) - 16):
        if 16 <= level[x] < 32 and 16 <= level[x + 16] < 32:
            level[x] |= 4
            level[x + 16] |= 1

def randomize_level_bg(level):
    from random import choice

    for y in range(0, len(level), 16):
        for x in range(y, y + 15):
            if level[x] < 8:
                level[x] = 0

    # Break up background monotony
    rowwts = iter([0, 0, 1, 2, 3, 3])
    for y1 in range(0, len(level), 32):
        rowwt = next(rowwts)
        colchoice = [(rowwt + choice((0, 2)), choice((0, 1)), choice((0, 1)))
                     for x in range(8)]
        row0 = [[basewt + (ysub ^ yflip) + (xsub ^ xflip)
                 for (basewt, xflip, yflip) in colchoice
                 for xsub in (0, 1)]
                for ysub in (0, 1)]
        whichcol = [choice((0, 1)) for x in range(8)]
        for x in range(16):
            xy = x + y1
            level[xy] = level[xy] or row0[0][x]
        if y1 + 32 <= len(level):
            for x in range(16):
                xy = x + y1 + 16
                if level[xy] < 8:
                    level[xy] = row0[1][x]

class LevelsParser(innie.InnieParser):
    mtnums = {ord('#'): MT_LADDER, ord(' '): 0}

    def __init__(self, data=None, filenames=None):
        innie.InnieParser.__init__(self)
        self.maps = []
        self.maps_by_name = {}
        self.levels = []
        self.addfilter(self.do_map)
        if data:
            self.readstring(data)
        if filenames:
            ok = self.read(filenames)

    def do_map(self, k, v):
        from array import array

        if k == 'map':
            v = v.strip()
            self.maps_by_name[v.lower()] = len(self.maps)
            self.maps.append([v, None, None])
            # name, starting position, block map
            # (default position: lowest unfilled row on column 1)
        elif k == 'start':
            self.maps[-1][1] = tuple(int(i.strip()) for i in v.split(','))
        elif k == 'bg':
            level = [b'%-16s' % line.rstrip().encode("ascii")[:16]
                     for line in v.split('\n')][:11]
            g = self.mtnums.get
            level = bytearray(g(c, 16) for c in b''.join(level))
            connect_level(level)
            randomize_level_bg(level)
            self.maps[-1][2] = level
        elif k == 'level':
            self.levels.append([v, None, 1, [], 0])
            # name, map id, limit, enemies, floating_items
        elif k == 'usemap':
            self.levels[-1][1] = self.maps_by_name[v.strip().lower()]
        elif k == 'limit':
            self.levels[-1][2] = max(int(v), 1)
        elif k == 'tokens':
            self.levels[-1][4] = max(int(v), 1)
        elif k == 'enemy':
            for v in v.split(','):
                v = v.rsplit('*', 1)
                n = int(v[1]) if len(v) > 1 else 1
                self.levels[-1][3].extend([v[0]] * n)
        else:
            return (k, v)

def load_levels(filenames=None):
    parser = LevelsParser(filenames=filenames or ['levels.ini'])
    return (parser.maps, parser.levels)

def save_levels(filename, maps, levels):
    rows = []

    for (name, starting_position, mapdata) in maps:
        rows.extend(('map=%s' % name,
                     'start=%d,%d' % starting_position,
                     'bg:'))
        mapdata = ''.join((
            '%' if c >= 16 else '#' if c == MT_LADDER else ' '
            for c in mapdata
        ))
        rows.extend(mapdata[i:i + 16] for i in range(0, len(mapdata), 16))
        rows.extend(('.', ''))
    for (name, mapid, limit, enemies, floating_items) in levels:
        rows.extend(('level=%s' % name,
                     'usemap=%s' % maps[mapid][0],
                     'limit=%d' % limit,
                     'enemy=%s' % ','.join(enemies)))
        if floating_items:
            rows.append('tokens=%d' % floating_items)
        rows.append('')
    with open(filename, 'wt') as outfp:
        outfp.write('\n'.join(rows))

def build_outer_room(x, y, cleared_bits, open_elevator=-1):
    if y > 0:
        cleared_bits >>= 8
    if x > 0:
        cleared_bits >>= 2

    lv = bytearray(176)
    for i in range(16):
        lv[i] = lv[i + 80] = lv[i + 160] = 16
    if x > 0:
        add_mtmap(lv, mtmap_elevator, 15, 1)
        lv[46] = MT_ELEVATOR_SIGNAL
    else:
        for base in range(16, 80, 16):
            lv[base] = lv[base + 1] = 16
    for tx in range(0 if x > 0 else 1, 15, 5):
        add_mtmap(lv, mtmap_fluoro, tx, 1)
    doorbase = 4 if x > 0 else 5
    for tx in range(doorbase, 15, 7):
        lv[48 + tx] = MT_DOOR
        lv[64 + tx] = MT_DOOR + 1

    # replicate floors
    lv[96:160] = lv[16:80]

    # shadow only bottomleft
    if x == 0 and y == 0:
        lv[144] = 45
        lv[145] = lv[128] = 46
        lv[129] = 47
    # doors
    if not (cleared_bits & 0x10):
        lv[64 + doorbase] = MT_DOOR_UNFINISHED_BOTTOM
    if not (cleared_bits & 0x20):
        lv[71 + doorbase] = MT_DOOR_UNFINISHED_BOTTOM
    if not (cleared_bits & 0x01):
        lv[144 + doorbase] = MT_DOOR_UNFINISHED_BOTTOM
    if not (cleared_bits & 0x02):
        lv[151 + doorbase] = MT_DOOR_UNFINISHED_BOTTOM
    if open_elevator == 0:
        lv[159] = lv[143] = 4
    elif open_elevator == 1:
        lv[79] = lv[63] = 4

    connect_level(lv)
    return lv

if __name__=='__main__':
##    load_levels()
    for y in (0, 1):
        for x in (0, 1):
            build_outer_room(x, y, 0x0000)


import unittest
from typing import Any, Iterator, Mapping, Tuple
from unittest.mock import MagicMock

import torch
from torch import nn
from torchtnt.framework._test_utils import DummyEvalUnit, generate_random_dataloader
from torchtnt.framework.callback import Callback
from torchtnt.framework.evaluate import evaluate
from torchtnt.framework.state import State
from torchtnt.framework.unit import EvalUnit, TEvalUnit
from torchtnt.utils.timer import Timer

class EvaluateTest(unittest.TestCase):
    def test_evaluate(self) -> None:
        """
        Test evaluate entry point
        """
        input_dim = 2
        dataset_len = 10
        batch_size = 2
        expected_steps = dataset_len / batch_size

        my_unit = DummyEvalUnit(input_dim=input_dim)
        initial_training_mode = my_unit.module.training

        dataloader = generate_random_dataloader(dataset_len, input_dim, batch_size)
        evaluate(my_unit, dataloader)

        self.assertEqual(my_unit.eval_progress.num_epochs_completed, 1)
        self.assertEqual(my_unit.eval_progress.num_steps_completed_in_epoch, 0)
        self.assertEqual(my_unit.eval_progress.num_steps_completed, expected_steps)
        self.assertEqual(my_unit.module.training, initial_training_mode)

    def test_evaluate_max_steps_per_epoch(self) -> None:
        """
        Test evaluate entry point with max_steps_per_epoch
        """
        input_dim = 2
        dataset_len = 10
        batch_size = 2
        max_steps_per_epoch = 4

        my_unit = DummyEvalUnit(input_dim=input_dim)
        initial_training_mode = my_unit.module.training

        dataloader = generate_random_dataloader(dataset_len, input_dim, batch_size)

        evaluate(my_unit, dataloader, max_steps_per_epoch=max_steps_per_epoch)

        self.assertEqual(my_unit.eval_progress.num_epochs_completed, 1)
        self.assertEqual(my_unit.eval_progress.num_steps_completed_in_epoch, 0)
        self.assertEqual(my_unit.eval_progress.num_steps_completed, max_steps_per_epoch)
        self.assertEqual(my_unit.module.training, initial_training_mode)

    def test_evaluate_stop(self) -> None:
        """
        Test evaluate entry point with setting state's `stop()` flag
        """
        input_dim = 2
        dataset_len = 10
        batch_size = 2
        max_steps_per_epoch = 4
        steps_before_stopping = 2

        my_unit = StopEvalUnit(
            input_dim=input_dim, steps_before_stopping=steps_before_stopping
        )
        dataloader = generate_random_dataloader(dataset_len, input_dim, batch_size)
        evaluate(my_unit, dataloader, max_steps_per_epoch=max_steps_per_epoch)

        self.assertEqual(my_unit.eval_progress.num_epochs_completed, 1)
        self.assertEqual(my_unit.eval_progress.num_steps_completed_in_epoch, 0)
        self.assertEqual(
            my_unit.steps_processed, my_unit.eval_progress.num_steps_completed
        )
        self.assertEqual(my_unit.steps_processed, steps_before_stopping)

    def test_evaluate_data_iter_step(self) -> None:
        class EvalIteratorUnit(EvalUnit[Iterator[Tuple[torch.Tensor, torch.Tensor]]]):
            def __init__(self, input_dim: int) -> None:
                super().__init__()
                self.module = nn.Linear(input_dim, 2)
                self.loss_fn = nn.CrossEntropyLoss()

            def eval_step(
                self, state: State, data: Iterator[Tuple[torch.Tensor, torch.Tensor]]
            ) -> Tuple[torch.Tensor, torch.Tensor]:
                batch = next(data)
                inputs, targets = batch

                outputs = self.module(inputs)
                loss = self.loss_fn(outputs, targets)
                return loss, outputs

        input_dim = 2
        dataset_len = 10
        batch_size = 2
        expected_steps = dataset_len / batch_size

        my_unit = EvalIteratorUnit(input_dim=input_dim)
        initial_training_mode = my_unit.module.training

        dataloader = generate_random_dataloader(dataset_len, input_dim, batch_size)
        evaluate(my_unit, dataloader)

        self.assertEqual(my_unit.eval_progress.num_epochs_completed, 1)
        self.assertEqual(my_unit.eval_progress.num_steps_completed_in_epoch, 0)
        self.assertEqual(my_unit.eval_progress.num_steps_completed, expected_steps)
        self.assertEqual(my_unit.module.training, initial_training_mode)

    def test_evaluate_with_callback(self) -> None:
        """
        Test evaluate entry point with a callback
        """
        input_dim = 2
        dataset_len = 10
        batch_size = 2
        max_steps_per_epoch = 6
        expected_num_steps = dataset_len / batch_size

        my_unit = DummyEvalUnit(2)
        dataloader = generate_random_dataloader(dataset_len, input_dim, batch_size)

        callback_mock = MagicMock()

        evaluate(
            my_unit,
            dataloader,
            max_steps_per_epoch=max_steps_per_epoch,
            callbacks=[callback_mock],
        )

        self.assertEqual(callback_mock.on_eval_start.call_count, 1)
        self.assertEqual(callback_mock.on_eval_epoch_start.call_count, 1)
        self.assertEqual(
            callback_mock.on_eval_step_start.call_count, expected_num_steps
        )
        self.assertEqual(callback_mock.on_eval_step_end.call_count, expected_num_steps)
        self.assertEqual(callback_mock.on_eval_epoch_end.call_count, 1)
        self.assertEqual(callback_mock.on_eval_end.call_count, 1)

    def test_evaluate_uses_iteration_timer(self) -> None:
        """
        Test evaluate records time in the iteration_timer
        """
        input_dim = 2
        dataset_len = 10
        batch_size = 2
        max_steps_per_epoch = 1

        my_unit = DummyEvalUnit(2)
        dataloader = generate_random_dataloader(dataset_len, input_dim, batch_size)

        def assertInTest(key: str, mapping: Mapping[str, Any]) -> None:
            self.assertIn(key, mapping)

        class CheckTimerUsedCallback(Callback):
            def on_eval_end(self, state: State, unit: TEvalUnit) -> None:
                assertInTest(
                    "data_wait_time",
                    state.eval_state.iteration_timer.recorded_durations,
                )
                assertInTest(
                    "eval_iteration_time",
                    state.eval_state.iteration_timer.recorded_durations,
                )

        check_timer_callback = CheckTimerUsedCallback()

        evaluate(
            my_unit,
            dataloader,
            max_steps_per_epoch=max_steps_per_epoch,
            callbacks=[check_timer_callback],
        )

    def test_evaluate_timing(self) -> None:
        """
        Test timing in evaluate
        """

        input_dim = 2
        dataset_len = 10
        batch_size = 2
        max_steps_per_epoch = 2

        dataloader = generate_random_dataloader(dataset_len, input_dim, batch_size)
        timer = Timer()
        evaluate(
            DummyEvalUnit(input_dim=input_dim),
            dataloader,
            max_steps_per_epoch=max_steps_per_epoch,
            timer=timer,
        )
        self.assertIn("evaluate.next(data_iter)", timer.recorded_durations.keys())

class StopEvalUnit(EvalUnit[Tuple[torch.Tensor, torch.Tensor]]):
    def __init__(self, input_dim: int, steps_before_stopping: int) -> None:
        super().__init__()
        # initialize module & loss_fn
        self.module = nn.Linear(input_dim, 2)
        self.loss_fn = nn.CrossEntropyLoss()
        self.steps_processed = 0
        self.steps_before_stopping = steps_before_stopping

    def eval_step(
        self, state: State, data: Tuple[torch.Tensor, torch.Tensor]
    ) -> Tuple[torch.Tensor, torch.Tensor]:

        inputs, targets = data

        outputs = self.module(inputs)
        loss = self.loss_fn(outputs, targets)

        assert state.eval_state
        if (
            self.eval_progress.num_steps_completed_in_epoch + 1
            == self.steps_before_stopping
        ):
            state.stop()

        self.steps_processed += 1
        return loss, outputs

Batch = Tuple[torch.Tensor, torch.Tensor]


import uuid
from django.db import models
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.utils import timezone
import pandas as pd
from server.pandas_util import hash_table
from server import minio, parquet

def _build_key(workflow_id: int, wf_module_id: int) -> str:
    """Build a helpful S3 key."""
    return f'{workflow_id}/{wf_module_id}/{uuid.uuid1()}.dat'

# StoredObject is our persistence layer.
# Allows WfModules to store keyed, versioned binary objects
class StoredObject(models.Model):
    # delete stored data if WfModule deleted
    wf_module = models.ForeignKey('WfModule', related_name='stored_objects',
                                  on_delete=models.CASCADE)

    # identification for file backing store
    bucket = models.CharField(max_length=255, null=False, blank=True,
                              default='')
    key = models.CharField(max_length=255, null=False, blank=True, default='')
    stored_at = models.DateTimeField(default=timezone.now)

    # used only for stored tables
    hash = models.CharField(max_length=32)
    metadata = models.CharField(default=None, max_length=255, null=True)
    size = models.IntegerField(default=0)  # file size

    # keeping track of whether this version of the data has ever been loaded
    # and delivered to the frontend
    read = models.BooleanField(default=False)

    @staticmethod
    def create_table(wf_module, table, metadata=None):
        hash = hash_table(table)
        return StoredObject.__create_table_internal(wf_module, table,
                                                    metadata, hash)

    # Create a new StoredObject if it's going to store different data than the
    # previous one. Otherwise null Fast; checks hash without loading file
    # contents
    @staticmethod
    def create_table_if_different(wf_module, old_so, table, metadata=None):
        if old_so is None:
            return StoredObject.create_table(wf_module, table,
                                             metadata=metadata)

        hash = hash_table(table)
        if hash != old_so.hash:
            old_table = old_so.get_table()
            if not old_table.equals(table):
                return StoredObject.__create_table_internal(wf_module, table,
                                                            metadata, hash)

        return None

    @staticmethod
    def __create_table_internal(wf_module, table, metadata, hash):
        # Write to minio bucket/key
        bucket = minio.StoredObjectsBucket
        key = _build_key(wf_module.workflow_id, wf_module.id)
        size = parquet.write(bucket, key, table)

        # Create the object that references the bucket/key
        return wf_module.stored_objects.create(
            metadata=metadata,
            bucket=minio.StoredObjectsBucket,
            key=key,
            size=size,
            hash=hash
        )

    def get_table(self):
        if not self.bucket or not self.key:
            # Old (obsolete) objects have no bucket/key, usually because
            # empty tables weren't being written.
            return pd.DataFrame()

        try:
            return parquet.read(self.bucket, self.key)
        except parquet.FastparquetCouldNotHandleFile:
            return pd.DataFrame()  # empty table

    # make a deep copy for another WfModule
    def duplicate(self, to_wf_module):
        key = _build_key(to_wf_module.workflow_id, to_wf_module.id)
        minio.copy(self.bucket, key, f'{self.bucket}/{self.key}')

        return to_wf_module.stored_objects.create(
            stored_at=self.stored_at,
            hash=self.hash,
            metadata=self.metadata,
            bucket=self.bucket,
            key=key,
            size=self.size
        )

@receiver(pre_delete, sender=StoredObject)
def _delete_from_s3_pre_delete(sender, instance, **kwargs):
    """
    Delete file from S3, pre-delete.

    Why pre-delete and not post-delete? Because our user expects the file to be
    _gone_, completely, forever -- that's what "delete" means to the user. If
    deletion fails, we need the link to remain in our database -- that's how
    the user will know it isn't deleted.
    """
    if instance.bucket and instance.key:
        minio.remove(instance.bucket, instance.key)


import os
import time
import urllib.request
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

print("")
print("네이버 이미지 줍줍이입니다.")
print("")
maxium_img = input("몇장 : ")
print("")
query = input("검색창 : ")
print("")
print("진행 상황 : ")

driver = webdriver.Chrome("C:\\Users\\HYEONGJUN\\Desktop\\파이썬\\selenium\\chromedriver.exe")
driver.get("https://search.naver.com/search.naver?where=image")
elem = driver.find_element_by_id("nx_query")
elem.send_keys(query)
elem.send_keys(Keys.RETURN)
time.sleep(2)

#스크롤 끝까지 내리기
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(2)
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight-50);")
    time.sleep(2)
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

imgs = driver.find_elements_by_css_selector("img._listImage")

links = []

for img in imgs:
    click = img.click()
    time.sleep(2)
    link = driver.find_element_by_xpath("/html/body/div[3]/div[2]/div/div[1]/section/div[2]/div[2]/div/div[1]/div[1]/div[1]/div/div/div[1]/div[1]/img").get_attribute("src")
    if "http" in link:
        links.append(link)
        if len(links) >= int(maxium_img):
            break

if not os.path.isdir(os.getcwd()+"\\"+query):
    os.mkdir(os.getcwd()+"\\"+query)

count = 1
for i in range(len(links)):
    urllib.request.urlretrieve(links[i], os.getcwd()+"\\"+query+"\\" +str(count)+".jpg")
    count=count+1

driver.close()
print("")
print("완료")


from keras import Sequential
from keras.callbacks import TensorBoard, EarlyStopping, ReduceLROnPlateau, LearningRateScheduler, ModelCheckpoint
from keras.layers import Conv2D, regularizers, BatchNormalization, Activation, MaxPooling2D, SpatialDropout2D, Input
from keras.layers import Dense, Flatten, Lambda, LocallyConnected2D, ZeroPadding2D, Dropout
from keras.models import Model
import keras.backend as K

from models.TemplateNet import TemplateNet

class BaseNet(TemplateNet):

    def __init__(self, embedding_dim=512, input_shape=(32, 32, 3), drop=0.25, blocks=2, locallyC_blocks=0, n_channels=32,
                 weight_decay=1e-4, **kwargs):
        self.embedding_dim = embedding_dim
        self.input_size = input_shape
        self.drop = drop
        self.blocks = blocks
        self.n_channels = n_channels
        self.weight_decay = weight_decay
        self.locallyC_blocks = locallyC_blocks
        super().__init__(**kwargs)

    def def_model(self):
        channels = self.n_channels
        inp = Input(shape=self.input_size)
        x = inp
        x = BatchNormalization()(inp)
        for i in range(self.blocks):

            x = Conv2D(channels, 3, padding='same', activation='relu')(x)
            x = BatchNormalization()(x)
            #x = ZeroPadding2D(padding=((0,1), (0,1)))(x)
            x = MaxPooling2D(pool_size=2, strides=2)(x)
            x = Dropout(rate=self.drop)(x)
            channels = int(channels * 1.5)
        for i in range(self.locallyC_blocks):
            x = LocallyConnected2D(channels, 1, padding='valid', activation='relu')(x)
        x = Flatten()(x)
        #x = Lambda(lambda x: K.l2_normalize(x, axis=-1))(x)
        model = Model(inp, x)
        model.summary()
        return model

    def def_model_(self):
        model = Sequential()
        model.add(Conv2D(self.n_channels, 3, padding='same',input_shape=self.input_size,
                         kernel_regularizer=regularizers.l2(self.weight_decay)))
        model.add(Activation('relu'))
        model.add(BatchNormalization(momentum=0.9))
        model.add(MaxPooling2D(pool_size=3, strides=2))
        model.add(SpatialDropout2D(rate=self.drop))
        #  model.add(Dropout(drop))

        for _ in range(self.blocks - 1):
            self.n_channels *= 2
            model.add(Conv2D(self.n_channels, (3, 3), padding='same',
                             kernel_regularizer=regularizers.l2(self.weight_decay)))
            model.add(Activation('relu'))
            model.add(BatchNormalization(momentum=0.9))
            model.add(MaxPooling2D(pool_size=3, strides=2))
            model.add(SpatialDropout2D(rate=self.drop))
            #  model.add(Dropout(drop))

        model.add(Flatten())
        model.add(Dense(self.embedding_dim, kernel_regularizer=regularizers.l2(self.weight_decay)))
        model.add(Lambda(lambda x: K.l2_normalize(x, axis=-1)))
        model.summary()
        return model

    def compile(self, optimizer, loss):
        self.model.compile(optimizer=optimizer, loss=loss)

    def save_model(self, model_weights_path):
        super().save_model(model_weights_path)

    def get_callbacks(self, model_weights_path, log_dir):
        return super().get_callbacks(model_weights_path, log_dir)

    def train_generator(self, dataloader, model_weights_path, epochs=50,
                        learning_rate=0.001, log_dir='./log'):
        super().train_generator(dataloader, model_weights_path, epochs=epochs, learning_rate=learning_rate, log_dir=log_dir)

    def train(self, data, model_weights_path, epochs=50, batch_size=64, log_dir='./log'):
        (x_train, y_train), (x_test, y_test) = data
        callbacks = self.get_callbacks(model_weights_path, log_dir)
        self.model.fit(x=x_train, y=y_train, batch_size=batch_size,
                       epochs=epochs, verbose=2, callbacks=callbacks,
                       validation_data=(x_test, y_test))


from __future__ import annotations
import neo4j

import strawberry

from strawberry.fastapi import GraphQLRouter, BaseContext
from strawberry.types import Info
from typing import Union, Optional
from fastapi import Depends
from neo4j import GraphDatabase, basic_auth
from enum import Enum

from ..dependencies import custom_context_dependency, CustomContext

# resolvers
def driver_meta_resolver(root: ControllerMeta, info: Info,
                    id: Optional[int] = None, name: Optional[str] = None, model: Optional[str] = None,
                    vendor: Optional[str] = None, capacity: Optional[float] = None,
                    linked_id: Optional[int] = None
                    ) -> list[Union[DriverMeta, None]]:
        def cypher_query_driver_meta(tx: neo4j.Transaction, id, name, model, vendor, capacity):
            if linked_id or root:
                relation_id = linked_id if linked_id else root.id
                results = tx.run(
                    f"""
                    MATCH (m:`{Label.DRIVER_META.value}`)-[r]-(n)
                    WHERE (id(n) = $linked_id)
                    AND (id(m) = $id or $id is null)
                    AND (m.name CONTAINS $name or $name is null)
                    AND (m.model CONTAINS $model or $model is null)
                    AND (m.vendor CONTAINS $vendor or $vendor is null)
                    AND (m.capacity = $capacity or $capacity is null)
                    AND (id(n) = $linked_id or $linked_id is null)
                    RETURN id(m) as id, m
                    """,
                    id=id, name=name, model=model, vendor=vendor, capacity=capacity, linked_id=relation_id
                )
            else:
                results = tx.run(
                    f"""
                    MATCH (m:`{Label.DRIVER_META.value}`)
                    WHERE (id(m) = $id or $id is null)
                    AND (m.name CONTAINS $name or $name is null)
                    AND (m.model CONTAINS $model or $model is null)
                    AND (m.vendor CONTAINS $vendor or $vendor is null)
                    AND (m.capacity = $capacity or $capacity is null)
                    RETURN id(m) as id, m
                    """,
                    id=id, name=name, model=model, vendor=vendor, capacity=capacity
                )
            return list(results)

        c_contex: CustomContext = info.context

        with c_contex.driver.session(database="neo4j") as session:
            results = session.execute_read(cypher_query_driver_meta, id=id, name=name, model=model, vendor=vendor, capacity=capacity)
            resolver_result = [DriverMeta(id=result["id"], **result['m']) for result in results]
            return resolver_result

def controller_meta_resolver(root: ControllerMeta, info: Info,
                    id: Optional [int] = None, model: Optional[str] = None, vendor: Optional[str] = None,
                    description: Optional[str] = None, created_at: Optional[int] = None,
                    linked_id: Optional[int] = None
                    ) -> list[Union[ControllerMeta, None]]:
    def cypher_query_controller_meta(tx: neo4j.Transaction, id, model, vendor, description, created_at):
        if linked_id or root:
            relation_id = linked_id if linked_id else root.id
            results = tx.run(
                f"""
                MATCH (m:`{Label.CONTROLLER_META.value}`)-[r]-(n)
                WHERE (id(n) = $linked_id )
                AND (id(m) = $id or $id is null)
                AND (m.model CONTAINS $model or $model is null)
                AND (m.vendor CONTAINS $vendor or $vendor is null)
                AND (m.description CONTAINS $description or $description is null)
                AND (m.created_at = $created_at or $created_at is null)
                RETURN id(m) as id ,m
                """,
                id=id, model=model, vendor=vendor, description=description, created_at=created_at, linked_id=relation_id
            )
        else :
            results = tx.run(
                f"""
                MATCH (m:`{Label.CONTROLLER_META.value}`)
                WHERE (id(m) = $id or $id is null)
                AND (m.model CONTAINS $model or $model is null)
                AND (m.vendor CONTAINS $vendor or $vendor is null)
                AND (m.description CONTAINS $description or $description is null)
                AND (m.created_at = $created_at or $created_at is null)
                RETURN id(m) as id ,m
                """,
                id=id, model=model, vendor=vendor, description=description, created_at=created_at
            )
        return list(results)

    c_contex: CustomContext = info.context
    with c_contex.driver.session(database="neo4j") as session:
        results = session.execute_read(cypher_query_controller_meta,
                                        id, model, vendor, description, created_at)
        return [ControllerMeta(id=result["id"], model=result["m"]["model"], vendor=result["m"]["vendor"],
                                description=result["m"]["description"], created_at=result["m"]["created_at"]) for result in results]

def asssd_benchmark_resolver(root: ControllerMeta, info: Info,
                    id: Optional[int] = None, name: Optional[str] = None,
                    ) -> list[Union[ASSSDBenchMark, None]]:
    def cypher_query_asssd_benchmark(tx: neo4j.Transaction, id, name):
        results = tx.run(
            f"""
            MATCH (m:`{Label.ASSSD_BENCHMARK.value}`)-[r]-(n)
            WHERE (id(n) = $linked_id)
            AND (id(m) = $id or $id is null)
            AND (m.name CONTAINS $name or $name is null)
            RETURN id(m) as id, m
            """,
            id=id, name=name, linked_id=root.id
        )
        return list(results)

    c_contex: CustomContext = info.context
    with c_contex.driver.session(database="neo4j") as session:
        results = session.execute_read(cypher_query_asssd_benchmark, id=id, name=name)
        return [ASSSDBenchMark(id=result["id"], name=result["m"]["name"], description=result["m"]['description']) for result in results]

def record_value_resolver(root: ASSSDBenchMark, info: Info,
                    id: Optional[int] = None, type: Optional[RecordType] = None,
                    unit: Optional[RecordUnit] = None, name: Optional[RecordName] = None,
                    value: Optional[float] = None, created_at: Optional[int] = None,
                    ) -> list[Union[RecordValue, None]]:
    def cypher_query_record_value(tx: neo4j.Transaction, id, type, unit, name, value, created_at):
        results = tx.run(
            f"""
            MATCH (m:`{Label.RECORD_VALUE.value}`)-[r]-(n)
            WHERE (id(n) = $linked_id)
            AND (id(m) = $id or $id is null)
            AND (m.type = $record_type or $record_type is null)
            AND (m.unit = $record_unit or $record_unit is null)
            AND (m.name = $record_name or $record_name is null)
            AND (m.value = $value or $value is null)
            AND (m.created_at = $created_at or $created_at is null)
            RETURN id(m) as id, m
            """,
            id=id, record_type=type, record_unit=unit, record_name=name, value=value, created_at=created_at, linked_id=root.id
        )
        return list(results)

    c_contex: CustomContext = info.context
    with c_contex.driver.session(database="neo4j") as session:
        results = session.execute_read(cypher_query_record_value, id=id, type=type, unit=unit, name=name, value=value, created_at=created_at)
        return [RecordValue(id=result["id"], type=RecordType(result["m"]["type"]), unit=RecordUnit(result["m"]["unit"]),
                            name=RecordName(result["m"]["name"]), value=result["m"]["value"], created_at=result["m"]["created_at"]) for result in results]

# 枚举类
@strawberry.enum
class RecordType(Enum):
    READ = "READ"
    WRITE = "WRITE"
    MIX = "MIX"

@strawberry.enum
class RecordUnit(Enum):
    IOPS = "IOPS"
    MBPS = "MBPS"
    LATENCY = "LATENCY"

@strawberry.enum
class RecordName(Enum):
    SEQ = "SEQ"
    RAND = "RAND"
    SEQ_LATENCY = "SEQ_LATENCY"
    RAND_LATENCY = "RAND_LATENCY"

class Label(Enum):
    DRIVER_META = "Driver"
    CONTROLLER_META = "ControllerMeta"
    ASSSD_BENCHMARK = "ASSSDBenchMark"
    RECORD_VALUE = "RecordValue"

class Relationship(Enum):
    CONTROLLER_META = "CONTROLLER_META"
    ASSSD_BENCHMARK = "ASSSD_BENCHMARK"
    RECORD_VALUE = "RECORD_VALUE"

@strawberry.type(description="记录值的基本单位", )
class RecordValue:
    id: int
    type: RecordType
    name: RecordName
    value: int
    unit: RecordUnit
    created_at: Optional[int] = None

@strawberry.input
class RecordValueInput:
    type: RecordType
    name: RecordName
    value: int
    unit: RecordUnit
    created_at: Optional[int] = None

@strawberry.type
class ASSSDBenchMark:
    id: int
    name: str = strawberry.field(description="测评结果名称")
    description: Optional[str] = strawberry.field(description="测评结果描述")
    created_at: Optional[int] = None

    record_value : list[Union[RecordValue, None]] = strawberry.field(resolver=record_value_resolver, description="测评结果细节数据",)

@strawberry.type
class ControllerMeta:
    id: int
    model: Optional[str] = None
    vendor: Optional[str] = None
    description: Optional[str] = None
    created_at: Optional[int] = None
    createdAt: Optional[int] = strawberry.field(default=None, deprecation_reason="Use `created_at` instead.")

    driver_meta: list[DriverMeta] = strawberry.field(resolver=driver_meta_resolver)

@strawberry.type
class DriverMeta:
    id: int
    name: Optional[str] = None
    model: Optional[str] = None
    vendor: Optional[str] = None
    capacity: Optional[float] = None
    created_at: Optional[int] = None

    controller_meta: list[Union[ControllerMeta, None]] = strawberry.field(resolver=controller_meta_resolver, description="controller_meta",)
    as_ssd_benchmark: list[Union[ASSSDBenchMark, None]] = strawberry.field(resolver=asssd_benchmark_resolver, description="as_ssd_benchmark",)

@strawberry.type
class Query:
    driver_meta: list[Union[DriverMeta, None]] = strawberry.field(resolver=driver_meta_resolver)
    controller_meta: list[Union[ControllerMeta, None]] = strawberry.field(resolver=controller_meta_resolver)

@strawberry.type
class Mutation:
    @strawberry.mutation
    def create_driver_meta(self, info: Info, name: str, model: str, vendor: str, capacity: float) -> DriverMeta:
        def cypher_create_driver_meta(tx: neo4j.Transaction, name, model, vendor, capacity):
            results = tx.run(
                f"""
                CREATE (m:`{Label.DRIVER_META.value}`
                {{name: $name, model: $model, vendor: $vendor, capacity: $capacity, created_at: timestamp()}})
                RETURN id(m) as id, m
                """,
                name=name, model=model, vendor=vendor, capacity=capacity
            )
            return list(results)

        c_contex: CustomContext = info.context

        with c_contex.driver.session(database="neo4j") as session:
            results = session.execute_write(cypher_create_driver_meta, name=name, model=model, vendor=vendor, capacity=capacity)
            resolver_result = DriverMeta(id=results[0]["id"], **results[0]['m'])
            return resolver_result

    @strawberry.mutation
    def create_controller_meta(self, driver_id: int, info: Info, model: str, vendor: str, description: str) -> ControllerMeta:
        def cypher_create_controller_meta(tx: neo4j.Transaction, model, vendor, description):
            if driver_id:
                results = tx.run(
                    f"""
                    MATCH (n:`{Label.DRIVER_META.value}`)
                    WHERE id(n) = $driver_id
                    CREATE (n)-[:{Relationship.CONTROLLER_META.value}]->(m:`{Label.CONTROLLER_META.value}`
                    {{model: $model, vendor: $vendor, description: $description, created_at: timestamp()}})
                    RETURN id(m) as id, m
                    """,
                    driver_id=driver_id, model=model, vendor=vendor, description=description
                )
                return list(results)
            else:
                results = tx.run(
                    f"""
                    CREATE (m:`{Label.CONTROLLER_META.value}` {{model: $model, vendor: $vendor, description: $description}})
                    RETURN id(m) as id, m
                    """,
                    model=model, vendor=vendor, description=description
                )
                return list(results)

        c_contex: CustomContext = info.context

        with c_contex.driver.session(database="neo4j") as session:
            results = session.execute_write(cypher_create_controller_meta, model=model, vendor=vendor, description=description)
            resolver_result = ControllerMeta(id=results[0]["id"], **results[0]['m'])
            return resolver_result

    @strawberry.mutation
    def create_as_ssd_benchmark(self, info: Info, driver_id: int, name: str, description: str, records: list[RecordValueInput]) -> ASSSDBenchMark:
        def cypher_create_as_ssd_benchmark(tx: neo4j.Transaction, name, description, records: list[RecordValueInput]):
            records_decoded = [r.__dict__ for r in records]
            records_decoded = [dict((k, v.value) if isinstance(v, Enum) else (k, v) for k, v in r.items()) for r in records_decoded]
            table = tx.run(
                f"""
                MERGE (m:`{Label.ASSSD_BENCHMARK.value}` {{name: $name}})
                    ON CREATE SET m.description = $description, m.created_at = timestamp()
                    ON MATCH SET m.description = $description
                RETURN id(m) as id, m
                """,
                name=name, description=description,
            )
            table_result = list(table)
            record_id = table_result[0]["id"]
            for r in records_decoded:
                result = tx.run(
                    f"""
                    MERGE (m:`{Label.RECORD_VALUE.value}` {{type: $record.type, name: $record.name}})
                        ON CREATE SET m.created_at = timestamp(), m.value = $record.value, m.unit = $record.unit, m.name = $record.name
                        ON MATCH SET
                            m.created_at = timestamp(), m.value = $record.value, m.unit = $record.unit, m.name = $record.name
                    return id(m) as id, m
                    """,
                    record = r
                )
                tx.run(
                    f"""
                    MATCH (n:`{Label.ASSSD_BENCHMARK.value}`), (m:`{Label.RECORD_VALUE.value}`)
                    WHERE id(n) = $record_id AND id(m) = $record_value_id
                    MERGE (n)-[:{Relationship.RECORD_VALUE.value}]->(m)
                    """,
                    record_id=record_id, record_value_id=result.single()['id']
                )
            tx.run(
                f"""
                MATCH (n:`{Label.DRIVER_META.value}`), (m:`{Label.ASSSD_BENCHMARK.value}`)
                WHERE id(n) = $driver_id AND id(m) = $record_id
                MERGE (n)-[:{Relationship.ASSSD_BENCHMARK.value}]->(m)
                """,
                driver_id=driver_id, record_id=record_id
            )
            return table_result

        c_contex: CustomContext = info.context

        with c_contex.driver.session(database="neo4j") as session:
            results = session.execute_write(cypher_create_as_ssd_benchmark, name=name, description=description, records=records)
            resolver_result = ASSSDBenchMark(id=results[0]["id"], **results[0]['m'])
            return resolver_result

async def get_context(custom_context=Depends(custom_context_dependency),):
    return custom_context

schema = strawberry.Schema(query=Query, mutation=Mutation)

graphql_app = GraphQLRouter(
    schema,
    context_getter=get_context,
)


# -*- coding: utf-8 -*-
import numpy as np

from OpenGL.GL import *

from lib.utils.meshrenderer.gl_utils.ebo import EBO

class VAO(object):

    def __init__(self, vbo_attrib, ebo=None):
        self.__id = np.empty(1, dtype=np.uint32)
        glCreateVertexArrays(len(self.__id), self.__id)
        i = 0
        for vbo_offset_stride, attribs in vbo_attrib.items():
            vbo = vbo_offset_stride[0]
            offset = vbo_offset_stride[1]
            stride = vbo_offset_stride[2]
            for attrib in attribs:
                attribindex = attrib[0]
                size = attrib[1]
                attribtype = attrib[2]
                normalized = attrib[3]
                relativeoffset = attrib[4]
                glVertexArrayAttribFormat(self.__id, attribindex, size, attribtype, normalized, relativeoffset)
                glVertexArrayAttribBinding(self.__id, attribindex, i)
                glEnableVertexArrayAttrib(self.__id, attribindex)
            glVertexArrayVertexBuffer(self.__id, i, vbo.id, offset, stride)
            i += 1
        if ebo != None:
            if isinstance(ebo, EBO):
                glVertexArrayElementBuffer(self.__id, ebo.id)
            else:
                ValueError('Invalid EBO type.')

    def bind(self):
        glBindVertexArray(self.__id)


# Import libraries
import matplotlib.pyplot as plt
import numpy as np
from csv import DictReader
from scipy import stats

# function to add labels on box plot elements
def draw_text(bp_dict):
    for line in bp_dict['medians']:
        # get position data for median line
        x, y = line.get_xydata()[1] # top of median line
        # overlay median value
        plt.text(x, y, '%.2f' % x,
            horizontalalignment='center') # draw above, centered

    for line in bp_dict['boxes']:
        x, y = line.get_xydata()[0] # bottom of left line
        plt.text(x,y, '%.2f' % x,
            horizontalalignment='center', # centered
            verticalalignment='top')      # below
        x, y = line.get_xydata()[3] # bottom of right line
        plt.text(x,y, '%.2f' % x,
            horizontalalignment='center', # centered
                verticalalignment='top')      # below

    for line in bp_dict['caps']:
        x, y = line.get_xydata()[0] # bottom of left line
        plt.text(x,y, '%.2f' % x,
            horizontalalignment='center', # centered
            verticalalignment='top')      # below

    for line in bp_dict['fliers']:
        for point in line.get_xydata():
            x, y = point # bottom of left line
            plt.text(x,y*0.975, '%.2f' % x,
                horizontalalignment='center', # centered
                verticalalignment='bottom')      # below

# Extracting data from the csv dataset
with open('jfreechart-stats.csv', newline='') as csvfile:
    # we obtain an iterator to extract the csv data
    reader = DictReader(csvfile)
    # initialising the data lists
    data_NOCom = []
    data_NCLOC = []
    data_DCP = []
    for row in reader:
        # We have to convert and cast to float the str corresponding to each
        # value since the boxplot takes a list of numbers
        data_NOCom.append(float(row[reader.fieldnames[1]]))
        data_NCLOC.append(float(row[reader.fieldnames[2]]))
        data_DCP.append(float(row[reader.fieldnames[3]]))

# Conversion of data lists to numpy array in order to compute the pearson and spearman coeffs
data_NOCom = np.array(data_NOCom)
data_NCLOC = np.array(data_NCLOC)
data_DCP = np.array(data_DCP)

# Draw box plots
# We will need a special marker to display the extremes values
little_dot = dict(markerfacecolor='r', marker='.', markersize=5)

# NOCom box plot
# We use this numpy function to obtain the quantiles
[vmin,l,m,u,vmax] = np.quantile(data_NOCom, [0,0.25,0.5,0.75,1])

# We then compute the box plot parameters
d = u - l
s = u + 1.5*d
i = max(u - 1.5*d, vmin)

# We create a new figure to display the box plot
fig, ax = plt.subplots(figsize=(15,3), label="Boîte à moustache NOCom")

# We define the data structure that will be used to draw the box plot
boxes = [
    {
        'label' : "NOCom",
        'whislo': i,    # Bottom whisker position
        'q1'    : l,    # First quartile (25th percentile)
        'med'   : m,    # Median         (50th percentile)
        'q3'    : u,    # Third quartile (75th percentile)
        'whishi': s,    # Top whisker position
        'fliers': data_NOCom[data_NOCom>s]        # Outliers
    }
]

# We declare the box plot, passing the values we computed earlier
bp_dict = ax.bxp(boxes, showfliers=True, vert=False, flierprops=little_dot)

# We add labels to the box plot elements
draw_text(bp_dict)

# We add to the right of the plot the values used to draw the box plot
plt.gcf().text(0.835, 0.75, "quartile supérieur = " + str(u), fontsize=10)
plt.gcf().text(0.835, 0.7, "quartile inférieur = " + str(l), fontsize=10)
plt.gcf().text(0.835, 0.65, "longueur de la boîte = " + str(d), fontsize=10)
plt.gcf().text(0.835, 0.6, "limite supérieure = " + str(s), fontsize=10)
plt.gcf().text(0.835, 0.55, "limite inférieure = " + str(i), fontsize=10)

# We must adjust the size of the plot in order to make room for the text on the right
plt.subplots_adjust(bottom=0.17, right=0.825)

plt.title("Boîte à moustache NOCom")
# This is required to draw the plot
plt.draw()
# We save the plot to a pdf file
plt.savefig('exports/moustache_NOCom.pdf', bbox_inches='tight')

# We do the same thing for NCLOC box plot
[vmin,l,m,u,vmax] = np.quantile(data_NCLOC, [0,0.25,0.5,0.75,1])
d = u - l
s = u + 1.5*d
i = max(u - 1.5*d, vmin)
fig, ax = plt.subplots(figsize=(15,3), label="Boîte à moustache NCLOC")
boxes = [
    {
        'label' : "NCLOC",
        'whislo': i,    # Bottom whisker position
        'q1'    : l,    # First quartile (25th percentile)
        'med'   : m,    # Median         (50th percentile)
        'q3'    : u,    # Third quartile (75th percentile)
        'whishi': s,    # Top whisker position
        'fliers': data_NCLOC[data_NCLOC>s]        # Outliers
    }
]
bp_dict = ax.bxp(boxes, showfliers=True, vert=False, flierprops=little_dot)
draw_text(bp_dict)
plt.title("Boîte à moustache NCLOC")
plt.gcf().text(0.835, 0.75, "quartile supérieur = " + str(u), fontsize=10)
plt.gcf().text(0.835, 0.7, "quartile inférieur = " + str(l), fontsize=10)
plt.gcf().text(0.835, 0.65, "longueur de la boîte = " + str(d), fontsize=10)
plt.gcf().text(0.835, 0.6, "limite supérieure = " + str(s), fontsize=10)
plt.gcf().text(0.835, 0.55, "limite inférieure = " + str(i), fontsize=10)
plt.subplots_adjust(bottom=0.17, right=0.825)
plt.draw()
plt.savefig('exports/moustache_NCLOC.pdf', bbox_inches='tight')

# We do the same thing for DCP box plot
[vmin,l,m,u,vmax] = np.quantile(data_DCP, [0,0.25,0.5,0.75,1])
d = u - l
s = u + 1.5*d
i = max(u - 1.5*d, vmin)
fig, ax = plt.subplots(figsize=(15,3), label="Boîte à moustache DCP")
boxes = [
    {
        'label' : "DCP",
        'whislo': i,    # Bottom whisker position
        'q1'    : l,    # First quartile (25th percentile)
        'med'   : m,    # Median         (50th percentile)
        'q3'    : u,    # Third quartile (75th percentile)
        'whishi': s,    # Top whisker position
        'fliers': data_DCP[data_DCP>s]         # Outliers
    }
]
bp_dict = ax.bxp(boxes, showfliers=True, vert=False, flierprops=little_dot)
draw_text(bp_dict)
plt.title("Boîte à moustache DCP")
plt.gcf().text(0.835, 0.75, "quartile supérieur = " + str(u), fontsize=10)
plt.gcf().text(0.835, 0.7, "quartile inférieur = " + str(l), fontsize=10)
plt.gcf().text(0.835, 0.65, "longueur de la boîte = " + str(d), fontsize=10)
plt.gcf().text(0.835, 0.6, "limite supérieure = " + str(s), fontsize=10)
plt.gcf().text(0.835, 0.55, "limite inférieure = " + str(i), fontsize=10)
plt.subplots_adjust(bottom=0.17, right=0.825)
plt.draw()
plt.savefig('exports/moustache_DCP.pdf', bbox_inches='tight')

# Draw data visualisation
# NOCom
fig, ax = plt.subplots(figsize=(15,7), label="Nuage de points NOCom")
# We define a scatter plot using the data set element numbers as x and the data set values as y
plt.scatter(np.arange(1, data_NOCom.size+1), data_NOCom)
plt.title("Nuage de points NOCom")
plt.ylabel("NOCom")
plt.draw()
plt.savefig('exports/nuage_NOCom.pdf', bbox_inches='tight')

# NCLOC
fig, ax = plt.subplots(figsize=(15,7), label="Nuage de points NCLOC")
plt.scatter(np.arange(1, data_NCLOC.size+1), data_NCLOC)
plt.title("Nuage de points NCLOC")
plt.ylabel("NCLOC")
plt.draw()
plt.savefig('exports/nuage_NCLOC.pdf', bbox_inches='tight')

# DCP
fig, ax = plt.subplots(figsize=(15,7), label="Nuage de points DCP")
plt.scatter(np.arange(1, data_DCP.size+1), data_DCP)
plt.title("Nuage de points DCP")
plt.ylabel("DCP")
plt.draw()
plt.savefig('exports/nuage_DCP.pdf', bbox_inches='tight')

# Correlation and regression compute
# pearson
pearson_NOCom_NCLOC = stats.pearsonr(data_NOCom, data_NCLOC)
pearson_NOCom_DCP = stats.pearsonr(data_NOCom, data_DCP)

# spearman
spearman_NOCom_NCLOC = stats.spearmanr(data_NOCom, data_NCLOC)
spearman_NOCom_DCP = stats.spearmanr(data_NOCom, data_DCP)

# linear regression compute
lreg_NOCom_NCLOC = stats.linregress(data_NOCom, data_NCLOC)
# We extract the coefficient and the y-intercept
a_NCLOC = lreg_NOCom_NCLOC[0]
b_NCLOC = lreg_NOCom_NCLOC[1]
lreg_NOCom_DCP = stats.linregress(data_NOCom, data_DCP)
a_DCP = lreg_NOCom_DCP[0]
b_DCP = lreg_NOCom_DCP[1]

# Draw data relation
# NCLOC/NOCom
fig, ax = plt.subplots(figsize=(15,7), label="Nuage de points NCLOC en fonction de NOCom")
# We define a scatter plot using values for NOCom as x and values for NCLOC as y
plt.scatter(data_NOCom, data_NCLOC)
# We plot the line corresponding to the linear regression
plt.plot(data_NOCom,a_NCLOC*data_NOCom+b_NCLOC,
        label="Régression linéaire : y = "+str(a_NCLOC)+"x + "+str(b_NCLOC),
        color="red")
plt.legend()
plt.title("Nuage de points NCLOC en fonction de NOCom")
plt.xlabel("NOCom")
plt.ylabel("NCLOC")
# We add text to the bottom of the plot to display the correlation coeffs
plt.gcf().text(0.125, 0.045, "pearson = " + str(pearson_NOCom_NCLOC[0]), fontsize=12)
plt.gcf().text(0.125, 0.02, "spearman = " + str(spearman_NOCom_NCLOC[0]), fontsize=12)
plt.subplots_adjust(bottom=0.15)
plt.draw()
plt.savefig('exports/relation_NCLOC_NOCom.pdf', bbox_inches='tight')

# DCP/NOCom
fig, ax = plt.subplots(figsize=(15,7), label="Nuage de points DCP en fonction de NOCom")
plt.scatter(data_NOCom, data_DCP)
plt.plot(data_NOCom,a_DCP*data_NOCom+b_DCP,
        label="Régression linéaire : y = "+str(a_DCP)+"x + "+str(b_DCP),
        color="red")
plt.legend()
plt.title("Nuage de points DCP en fonction de NOCom")
plt.xlabel("NOCom")
plt.ylabel("DCP")
plt.gcf().text(0.125, 0.045, "pearson = " + str(pearson_NOCom_DCP[0]), fontsize=12)
plt.gcf().text(0.125, 0.02, "spearman = " + str(spearman_NOCom_DCP[0]), fontsize=12)
plt.subplots_adjust(bottom=0.15)
plt.draw()
plt.savefig('exports/relation_DCP_NOCom.pdf', bbox_inches='tight')

# We show all the figures we created
plt.show()