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

import time
import json
import requests
from datetime import datetime
import numpy as np
import matplotlib
import matplotlib.figure
from matplotlib.font_manager import FontProperties
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

plt.rcParams['font.sans-serif'] = ['FangSong']  # 设置默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像时'-'显示为方块的问题

def catch_daily():
    """抓取每日确诊和死亡数据"""

    date_list = list() # 日期
    confirm_list = list() # 确诊
    suspect_list = list() # 疑似
    dead_list = list() # 死亡
    heal_list = list() # 治愈

    url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5&callback=&_=%d'%int(time.time()*1000)
    for item in json.loads(requests.get(url=url).json()['data'])['chinaDayList']:
        month, day = item['date'].split('.')
        date_list.append(datetime.strptime('2020-%s-%s'%(month, day), '%Y-%m-%d'))
        confirm_list.append(int(item['confirm']))
        suspect_list.append(int(item['suspect']))
        dead_list.append(int(item['dead']))
        heal_list.append(int(item['heal']))

    return date_list, confirm_list, suspect_list, dead_list, heal_list

def catch_distribution():
    """抓取行政区域确诊分布数据"""

    data = {}
    url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5&callback=&_=%d'%int(time.time()*1000)
    for item in json.loads(requests.get(url=url).json()['data'])['areaTree'][0]['children']:
        if item['name'] not in data:
            data.update({item['name']:0})
        for city_data in item['children']:
            data[item['name']] += int(city_data['total']['confirm'])

    return data

def plot_daily():
    """绘制每日确诊和死亡数据"""

    date_list, confirm_list, suspect_list, dead_list, heal_list = catch_daily() # 获取数据

    plt.figure('2019-nCoV疫情统计图表', facecolor='#f4f4f4', figsize=(10, 8))
    plt.title('2019-nCoV疫情曲线', fontsize=20)

    plt.plot(date_list, confirm_list, label='确诊')
    plt.plot(date_list, suspect_list, label='疑似')
    plt.plot(date_list, dead_list, label='死亡')
    plt.plot(date_list, heal_list, label='治愈')

    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d')) # 格式化时间轴标注
    plt.gcf().autofmt_xdate() # 优化标注（自动倾斜）
    plt.grid(linestyle=':') # 显示网格
    plt.legend(loc='best') # 显示图例
    plt.savefig('fb/2019-nCoV疫情曲线.png') # 保存为文件
    plt.show()

def plot_distribution(mode='lcc', plot_name=True):
    """绘制行政区域确诊分布数据

    mode        - 投影模式，可选项：
                -- 'lcc'            兰博托投影
                -- 'ortho'          正射投影
                -- 'etopo'          全球等经纬投影模式，etopo风格
                -- 'shadedrelief'   全球等经纬投影模式，shadedrelief风格
                -- 'bluemarble'     全球等经纬投影模式，bluemarble风格
    plot_name   - 是否打印行政区域名
    """

    data = catch_distribution()

    font_14 = FontProperties(fname='res/simsun.ttf', size=14)
    font_11 = FontProperties(fname='res/simsun.ttf', size=11)

    if mode in ['etopo', 'shadedrelief', 'bluemarble']:
        width = 1600
        height = 800
        rect = [0, 0, 1, 1]
        lat_min = -90
        lat_max = 90
        lon_min = 0
        lon_max = 360
    else:
        width = 1200
        height = 800
        rect = [0.1, 0.12, 0.8, 0.8]
        lat_min = 0
        lat_max = 60
        lon_min = 77
        lon_max = 140

    handles = [
            matplotlib.patches.Patch(color='#ffaa85', alpha=1, linewidth=0),
            matplotlib.patches.Patch(color='#ff7b69', alpha=1, linewidth=0),
            matplotlib.patches.Patch(color='#bf2121', alpha=1, linewidth=0),
            matplotlib.patches.Patch(color='#7f1818', alpha=1, linewidth=0),
]
    labels = [ '1-9人', '10-99人', '100-999人', '>1000人']

    provincePos = {
        "辽宁省":[121.7,40.9],
        "吉林省":[124.5,43.5],
        "黑龙江省":[125.6,46.5],
        "北京市":[116.0,39.9],
        "天津市":[117.0,38.7],
        "内蒙古自治区":[110.0,41.5],
        "宁夏回族自治区":[105.2,37.0],
        "山西省":[111.0,37.0],
        "河北省":[114.0,37.8],
        "山东省":[116.5,36.0],
        "河南省":[111.8,33.5],
        "陕西省":[107.5,33.5],
        "湖北省":[111.0,30.5],
        "江苏省":[119.2,32.5],
        "安徽省":[115.5,31.8],
        "上海市":[121.0,31.0],
        "湖南省":[110.3,27.0],
        "江西省":[114.0,27.0],
        "浙江省":[118.8,28.5],
        "福建省":[116.2,25.5],
        "广东省":[113.2,23.1],
        "台湾省":[120.5,23.5],
        "海南省":[108.0,19.0],
        "广西壮族自治区":[107.3,23.0],
        "重庆市":[106.5,29.5],
        "云南省":[101.0,24.0],
        "贵州省":[106.0,26.5],
        "四川省":[102.0,30.5],
        "甘肃省":[103.0,35.0],
        "青海省":[95.0,35.0],
        "新疆维吾尔自治区":[85.5,42.5],
        "西藏自治区":[85.0,31.5],
        "香港特别行政区":[115.1,21.2],
        "澳门特别行政区":[112.5,21.2]
    }

    fig = matplotlib.figure.Figure()
    fig.set_size_inches(width/100, height/100) # 设置绘图板尺寸
    axes = fig.add_axes(rect)

    if mode == 'lcc': # 兰博托投影模式
        m = Basemap(projection='lcc', llcrnrlon=77, llcrnrlat=14, urcrnrlon=140, urcrnrlat=51, lat_1=33, lat_2=45, lon_0=100, ax=axes)

        # 兰博托投影模式，全图
        #m = Basemap(projection='lcc', llcrnrlon=80, llcrnrlat=0, urcrnrlon=140, urcrnrlat=51, lat_1=33, lat_2=45, lon_0=100, ax=axes)
    elif mode == 'ortho': # 正射投影模式
        m = Basemap(projection='ortho', lat_0=36, lon_0=102, resolution='l', ax=axes)
    else: # 全球等经纬投影模式，
        m = Basemap(llcrnrlon=lon_min, urcrnrlon=lon_max, llcrnrlat=lat_min, urcrnrlat=lat_max, resolution='l', ax=axes)
        if mode == 'etopo':
            m.etopo()
        elif mode == 'shadedrelief':
            m.shadedrelief()
        else:
            m.bluemarble()

    m.readshapefile('res/china-shapefiles-master/china', 'province', drawbounds=True)
    m.readshapefile('res/china-shapefiles-master/china_nine_dotted_line', 'section', drawbounds=True)
    m.drawcoastlines(color='black') # 洲际线
    m.drawcountries(color='black')  # 国界线

    if mode in ['etopo', 'shadedrelief', 'bluemarble']:
        m.drawparallels(np.arange(lat_min,lat_max,30), labels=[1,0,0,0]) #画经度线
        m.drawmeridians(np.arange(lon_min,lon_max,30), labels=[0,0,0,1]) #画纬度线
    else:
        m.drawparallels(np.arange(lat_min,lat_max,10), labels=[1,0,0,0]) #画经度线
        m.drawmeridians(np.arange(lon_min,lon_max,10), labels=[0,0,0,1]) #画纬度线

    pset = set()
    for info, shape in zip(m.province_info, m.province):
        pname = info['OWNER'].strip('\x00')
        fcname = info['FCNAME'].strip('\x00')
        if pname != fcname: # 不绘制海岛
            continue

        for key in data.keys():
            if key in pname:
                if data[key] == 0:
                    color = '#f0f0f0'
                elif data[key] < 10:
                    color = '#ffaa85'
                elif data[key] <100:
                    color = '#ff7b69'
                elif  data[key] < 1000:
                    color = '#bf2121'
                else:
                    color = '#7f1818'
                break

        poly = Polygon(shape, facecolor=color, edgecolor=color)
        axes.add_patch(poly)

        if plot_name:
            pos = provincePos[pname]
            text = pname.replace("自治区", "").replace("特别行政区", "").replace("壮族", "").replace("维吾尔", "").replace("回族", "").replace("省", "").replace("市", "")
            if text not in pset:
                x,  y = m(pos[0], pos[1])
                axes.text(x,  y, text, fontproperties=font_11, color='#00FFFF')
                pset.add(text)

    axes.legend(handles, labels, bbox_to_anchor=(0.5, -0.11), loc='lower center', ncol=4, prop=font_14)
    axes.set_title("2019-nCoV疫情地图", fontproperties=font_14)
    FigureCanvasAgg(fig)
    fig.savefig('fb/2019-nCoV疫情地图_%s.png'%mode)

if __name__ == '__main__':
    #plot_daily()
    #plot_distribution()
    #plot_distribution(mode='ortho', plot_name=False)
    plot_distribution(mode='etopo', plot_name=False)
    #plot_distribution(mode='shadedrelief', plot_name=False)
    #plot_distribution(mode='bluemarble', plot_name=False)


'''
Author: James Hibben
A simple python implementation of an RSA cryptographic algorithm, for
MSU CSC 590-002 in the Spring Semester of 2016.

This file was written in conjunction with Zach Gilmer for an assignment in
implementing both symmetric-key and public-key (asymmetric-key) algorithms.

This program is based on avalonalex's RSA.py project, found
at https://gist.github.com/avalonalex/2122098. Some parts are removed or edited
due to alternate library imports and alternate ways to deal with certain
functions. Additionally, some functions were restructured to run as inner
functions in cases where they were only called from one function.
'''

from fractions import gcd
from random import randint
from math import log
from copy import copy

def coPrime(a, b):
    """Determine if a and b are coprime; return false if gcd(a,b) is anything
       other than 1"""
    if gcd(a,b) != 1:
        return False
    return True

def modExp(a, d, n):
    '''returns (a ** d) mod n'''
    def int2baseTwo(x):
        '''
        Convert x from positive integer to base-2.
        Returns list of bits in reverse order.
        '''
        assert x >= 0
        bitInverse = []
        while x != 0:
            bitInverse.append(x & 1)
            x >>= 1
        return bitInverse

    assert d >= 0
    assert n >= 0
    base2D = int2baseTwo(d)
    base2DLength = len(base2D)
    modArray = []
    result = 1
    for i in range(1, base2DLength + 1):
        if i == 1:
            modArray.append(a % n)
        else:
            modArray.append((modArray[i - 2] ** 2) % n)
    for i in range(0, base2DLength):
        if base2D[i] == 1:
            result *= base2D[i] * modArray[i]
    return result % n

def millerRabinTest(n, k):
    '''
    Miller-Rabin pseudo-prime test.
    Test is a fast approximation for a prime with good accuracy.
    Returning True: most likely a prime
    Returning False: definitely a composite
    k -> used to determine accuracy
    '''
    # go ahead and define function(s) here; the actual Miller-Rabin test is
    #   after the functions
    def extractTwos(m):
        '''
        Strict: m is non-negative.
        Counts the number of 0-bits there are at the end of bin(m), which can
        represented as (2 ** n) - 1.
        Returns a tuple (s, d) such that m = (2 ** i) * d.
        Only called within millerRabinTest
        '''
        assert m >= 0
        i = 0
        while m & (2 ** i) == 0:
            i += 1
        return i, m >> i

    def isComposite(a):
        x = modExp(a, d, n)
        if x == 1 or x == (n - 1):
            return None
        else:
            for i in range(1, s):
                x = modExp(x, 2, n)
                if x == 1:
                    return False
                elif x == (n - 1):
                    return None
            return False

    # millerRabinTest body
    assert n >= 1  # ensure that n is larger than 1
    assert k > 0  # ensure k is positive

    # 2 is a prime; show this
    if n == 2:
        return True

    # all even integers other than 2 are composites; show this
    if n % 2 == 0:
        return False

    extracted = extractTwos(n - 1)
    s = extracted[0]
    d = extracted[1]
    assert 2 ** s * d == n - 1

    for i in range(0, k):
        a = randint(2, n - 2)
        if isComposite(a) == False:
            return False
    return True  # reasonably certain that n is prime

def newKey(a, b, k):
    '''
    Try to find two pseudo primes ~ between a, b to generate the keys.
    Raises a ValueError if it cannot find one.
    '''
    # define inner functions
    def findPrime(a, b, k):
        '''
        Returns a pseudo-prime roughly between a, b (may be greater than b).
        Limit the number of attempts to find a pseudo-prime to
        10*ln(x)+3 (most likely thousands of attempts, so it shouldn't fail).
        If it can't find a prime, throw a ValueError to halt the program.
        '''
        x = randint(a, b)
        for i in range(0, int(10 * log(x) + 3)):
            if millerRabinTest(x, k):
                return x
            else:
                x += 1
        raise ValueError

    def extendedGCD(a, b):
        if a == 0:
            return b, 0, 1
        else:
            g, y, x = extendedGCD(b % a, a)
            return g, x - (b // a) * y, y

    def modMultInverse(e, totient):
        '''Modular Multiplicative Inverse function'''
        if coPrime(e, totient):
            combined = extendedGCD(e, totient)
            return combined[1] % totient
        else:
            return 0

    # newKey function body
    try:
        p = findPrime(a, b, k)
        while True:
            q = findPrime(a, b, k)
            if q != p:
                break
    except:
        raise ValueError

    n = p * q
    m = (p - 1) * (q - 1)

    while True:
        e = randint(1, m)
        if coPrime(e, m):
            break

    d = modMultInverse(e, m)
    return (n, e, d)

def encrypt(message, modN, e, blockSize):
    '''
    given a string message, public keys (e, n), and blockSize,
    encrypt using RSA algorithms
    '''
    # inner functions
    def string2numList(strn):
        '''convert an ASCII string to a list of integers'''
        return [ ord(char) for char in strn ]

    def numList2blocks(lst, blockSize):
        '''
        Takes a list of integers (range: 0-127) and combines them to be
        blockSize using base 256. If the length is not blockSize, then
        random integers will be generated to fill it.
        '''
        returnList = []
        toProcess = copy(lst)
        if len(toProcess) % blockSize != 0:
            for i in range(0, blockSize - len(toProcess) % blockSize):
                toProcess.append(randint(32, 126))
        for i in range(0, len(toProcess), blockSize):
            block = 0
            for j in range(0, blockSize):
                block += toProcess[i + j] << (8 * (blockSize - j - 1))
            returnList.append(block)
        return returnList

    numList = string2numList(message)
    numBlocks = numList2blocks(numList, blockSize)
    return [ modExp(blocks, e, modN) for blocks in numBlocks ]

def decrypt(cipher, modN, d, blockSize):
    '''reverses encryption'''
    # inner functions
    def numList2string(lst):
        '''convert a list of integers to a string based on their ASCII values'''
        return ''.join(map(chr, lst))

    def blocks2numList(blocks, blockSize):
        '''inverses numList2blocks'''
        toProcess = copy(blocks)
        returnList = []
        for numBlock in toProcess:
            inner = []
            for i in range(0, blockSize):
                inner.append(numBlock % 256)
                numBlock >>= 8
            inner.reverse()
            returnList.extend(inner)
        return returnList

    numBlocks = [ modExp(blocks, d, modN) for blocks in cipher ]
    numList = blocks2numList(numBlocks, blockSize)
    return numList2string(numList)


import controller
import time
from hardpotato import *
import numpy as np
import matplotlib.pyplot as plt
import softpotato as sp
from scipy.optimize import curve_fit
import os
from scipy.stats import linregress
import shutil
import serial
import time
import dill
from pathlib import Path

import datetime

number_runs = 5

start_time = time.time()

###make parent folder
experiment_name = "expt1"
parent_dir1 = "C:/Data Path"
# Path
path = os.path.join(parent_dir1, experiment_name)
os.mkdir(path)
print("Directory '% s' created" % experiment_name)
parent_folder = str(path)
######################### GENERATE DUPLICATE CODE ################
# generate filename with timestring
copied_script_name = time.strftime("%Y-%m-%d_%H%M") + "_" + os.path.basename(__file__)
# copy script
shutil.copy(__file__, parent_folder + os.sep + copied_script_name)
##################################################################

############################ setup control board and MUX###############################

####define com ports for controller and MUX + baudrate (keep at 115200 for both)
controllerPort = "COM5"
muxPort = "COM4"
baud_rate = 115200
###setup mux
mux = serial.Serial(port=muxPort, baudrate=baud_rate, timeout=0.1)
###setup controller
setup = controller.Setup(controllerPort, baud_rate)
setup.connect()

#### This section of the code just cycles a couple of states in the multiplexer, it can be deleted (but may cause issues if not present)
mux.write(bytes(str(1), "utf-8"))
msg = mux.readline()
print(msg.decode("utf-8"))
time.sleep(5)
mux.write(bytes(str(3), "utf-8"))
msg = mux.readline()
print(msg.decode("utf-8"))
time.sleep(5)
mux.write(bytes(str(5), "utf-8"))
msg = mux.readline()
print(msg.decode("utf-8"))
time.sleep(5)

###setup serial commands for the macro electrode chip
serialNum = [11, 12, 13, 14, 15, 16, 17, 18]

##########setup pstat ##################3
##### Setup
# Select the potentiostat model to use:
# emstatpico, chi1205b, chi760e
#### Potentiostat setup #####
model = "chi760e"  # Model to use
path_exe = (
    "C:/Potentiostat Path/chi760e.exe"  # Path to the chi760e.exe
)
potentiostat.Setup(model, path_exe, parent_folder)  # Setup

#################### Fluidics parameters ###########################
wait = 10
move = controller.Motor()
power = controller.MainPower()

# Parameters related to peristaltic pumps
p1_new = [
    13.712609063042798,
    0.977763871750637,
    4.104248850640944e-05,
    -4.143399187088928e-08,
]
p1_default = [
    19.801938114061617,
    0.964367848880719,
    1.167139063529185e-05,
    -2.873709837738213e-09,
]
p2_default = [
    11.765533598083050,
    0.994151183002726,
    -2.200584843815698e-05,
    5.268389857671134e-09,
]
p_linear = [0, 1, 0, 0]

disp1_cutoff = 600
disp2_cutoff = 600

########### start of script! #################################################

# Main Power ON
print("\n----MAIN POWER ON----")
power.state("ON")
time.sleep(2)

# Homming
print("\n----NOZZLES HOMING----")
message_home2 = bytes("<homeDisp,0,0>", "UTF-8")
move.send(message_home2)
time.sleep(wait + 15)

print("\n----GANTRY HOMING----")
message_home1 = bytes("<homeGantry,0,0>", "UTF-8")
move.send(message_home1)
time.sleep(wait + 5)

######## Dispense in the dummy cell  + cleaning ######################################################
# Move to the dummy cell
print("\n----Moving to cell 4 (dummy)----")
pos = controller.Position_in_cell(4)
pos.run()
time.sleep(wait + 5)

# Dummy dispensing to remove trapped air bubbles in tubes
print("\n----Dispense in cell 4 (dummy) from Nozzle 1 & 2----")
dispense_1d = controller.Dispense(
    nozzle=1,
    volume=200,
    speed=8000,
    wait_time=[0, 3, 26.4, 3, 0],
    motor_values=[-9000, 20, -2755, 20, 9000],
    p=p_linear,
)
dispense_1d.run()
time.sleep(7)

dispense_2d = controller.Dispense(
    nozzle=2,
    volume=200,
    speed=8000,
    wait_time=[0, 3, 26.4, 3, 0],
    motor_values=[-9000, 20, -2755, 20, 9000],
    p=p_linear,
)
dispense_2d.run()
time.sleep(7)

# Dummy cell suction
suction_only = controller.Rinse_dummy(loop=1, wait_time=[16, 12, 0, 0, 16])
suction_only.run()
time.sleep(5)

######## Move to actual cell  ##########################################################

# Move to the cell
print("\n----Moving to cell 3----")
pos = controller.Position_in_cell(3)
pos.run()
time.sleep(15)

for a in range(number_runs):
    ### dispense 1 mL of Electrolyte first ##############################################
    dispense_2d = controller.Dispense(
        nozzle=2,
        volume=1000,
        speed=8000,
        wait_time=[0, 3, 26.4, 3, 0],
        motor_values=[-9000, 20, -2755, 20, 9000],
        p=p_linear,
    )
    print(f"From nozzle 2, dispensing \033[33m{1000} \033[0muL  \n")
    dispense_2d.run()
    time.sleep(wait)

    ### Argon bubbling #################################################################
    print("\n----\033[31mN2 bubbling\033[0m----")
    n2_bubbling = controller.N2(loop=1, nozzle=2, wait_time=[12, 3, 12], mode="dual")
    n2_bubbling.run()
    time.sleep(7)

    ### Main Power OFF #################################################################
    print("\n----MAIN POWER OFF----")
    power.state("OFF")
    time.sleep(15)

    ########### echem with just electrolyte ######################################################
    ##### Experimental parameters:
    Ei = -0.2  # V, initial potential
    Eh = 0.3  # V, first vertex potential
    El = -0.2  # V, second vertex potential
    nSweeps = 2  # number of sweeps
    sens = 1e-7  # A/V, current sensitivity                              ### CHANGE THIS IF NEEDED
    header = "CV"  # header for data file
    ##### Experiment:
    sr = np.array([0.1, 0.15, 0.2, 0.25, 0.3])  # V/s, scan rate
    for y in serialNum:
        mux.write(bytes(str(y), "utf-8"))
        msg = mux.readline()
        print(msg.decode("utf-8"))
        time.sleep(5)
        for x in range(sr.size):
            # initialize experiment:
            fileName_CV = f"0mM_Electrode{y-10}_{int(sr[x]*1000)}mVs_CV_{a+1}"  # base file name for data file
            cv = potentiostat.CV(
                Eini=Ei,
                Ev1=Eh,
                Ev2=El,
                Efin=Ei,
                sr=sr[x],
                sens=sens,
                dE=0.001,
                nSweeps=2,
                qt=2,
                fileName=fileName_CV,
            )
            # Run experiment:
            cv.run()
            data = load_data.CV(fileName_CV + ".txt", parent_folder, model)
            # load data to do the data analysis later

    ####################################### cleaning ##############################################
    ### Main Power ON #############################################################################
    print("\n----MAIN POWER ON----")
    power.state("ON")
    time.sleep(5)

    ### Initial Electrode Rinsing #################################################################
    ## "wait_time" in Rinse function (0 will skip the step, and below is the sequence)
    ## (1) Down / [LOOP start [ (2) suction / (3) flush / (4) suction] LOOP end] / (5) Up
    ## = [16, 12, 15, 12, 16]
    rinse = controller.Rinse(
        loop=3, wait_time=[16, 12, 15, 12, 16]
    )  # change the number of loops if needed
    rinse.run()
    time.sleep(5)

    ### Electrode strong rinsing / bubbling / drying (SR) ###############################################
    # (SR1) Filling reservoir with solvent
    print("\n----\033[31m Filling reservoir with solvent \033[0m----")
    filling_only = controller.Rinse(loop=1, wait_time=[16, 0, 15, 0, 16])
    filling_only.run()

    # (SR2) Argon bubbling
    print("\n----\033[31mN2 bubbling\033[0m----")
    n2_bubbling = controller.N2(loop=1, nozzle=2, wait_time=[12, 3, 12], mode="dual")
    n2_bubbling.run()
    time.sleep(7)

    # (SR3) Suction only
    suction_only = controller.Rinse(loop=1, wait_time=[16, 12, 0, 0, 16])
    suction_only.run()
    time.sleep(7)

    # (SR4) Argon drying
    print("\n----\033[31mN2 drying\033[0m----")
    n2_drying = controller.N2(loop=1, nozzle=1, wait_time=[12, 3, 12], mode="single")
    n2_drying.run()
    time.sleep(10)

    ### dispense 1 mL of FcMeOh ########################################################################
    dispense_1d = controller.Dispense(
        nozzle=1,
        volume=1000,
        speed=8000,
        wait_time=[0, 3, 26.4, 3, 0],
        motor_values=[-9000, 20, -2755, 20, 9000],
        p=p_linear,
    )
    print(f"From nozzle 1, dispensing \033[33m{1000} \033[0muL  \n")
    dispense_1d.run()
    time.sleep(wait)

    ### Argon bubbling #################################################################################
    print("\n----\033[31mN2 bubbling\033[0m----")
    n2_bubbling = controller.N2(loop=1, nozzle=2, wait_time=[12, 3, 12], mode="dual")
    n2_bubbling.run()
    time.sleep(7)

    ### Main Power OFF ##################################################################################
    print("\n----MAIN POWER OFF----")
    power.state("OFF")
    time.sleep(15)

    ########### echem with fcmeoh #######################################################################
    ##### Experimental parameters:
    Ei = -0.2  # V, initial potential
    Eh = 0.3  # V, first vertex potential
    El = -0.2  # V, second vertex potential
    nSweeps = 2  # number of sweeps
    sens = 1e-7  # A/V, current sensitivity                              ### (2) CHANGE THIS !!!!
    header = "CV"  # header for data file
    ##### Experiment:
    sr = np.array([0.1, 0.15, 0.2, 0.25, 0.3])  # V/s, scan rate
    for y in serialNum:
        mux.write(bytes(str(y), "utf-8"))
        msg = mux.readline()
        print(msg.decode("utf-8"))
        time.sleep(5)
        for x in range(sr.size):
            # initialize experiment:
            fileName_CV = f"1mM_Electrode{y-10}_{int(sr[x]*1000)}mVs_CV_{a+1}"  # base file name for data file
            cv = potentiostat.CV(
                Eini=Ei,
                Ev1=Eh,
                Ev2=El,
                Efin=Ei,
                sr=sr[x],
                sens=sens,
                dE=0.001,
                nSweeps=2,
                qt=2,
                fileName=fileName_CV,
            )
            # Run experiment:
            cv.run()
            data = load_data.CV(fileName_CV + ".txt", parent_folder, model)
            # load data to do the data analysis later

    ####################################### cleaning ##############################################
    # Main Power ON
    print("\n----MAIN POWER ON----")
    power.state("ON")
    time.sleep(5)

    ### Initial Electrode Rinsing #################################################################
    ## "wait_time" in Rinse function (0 will skip the step, and below is the sequence)
    ## (1) Down / [LOOP start [ (2) suction / (3) flush / (4) suction] LOOP end] / (5) Up
    ## = [16, 12, 15, 12, 16]

    rinse = controller.Rinse(
        loop=3, wait_time=[16, 12, 15, 12, 16]
    )  # change the number of loops if needed
    rinse.run()
    time.sleep(5)

    ### Electrode strong rinsing / bubbling / drying (SR) ###############################################
    # (SR1) Filling reservoir with solvent
    print("\n----\033[31m Filling reservoir with solvent \033[0m----")
    filling_only = controller.Rinse(loop=1, wait_time=[16, 0, 15, 0, 16])
    filling_only.run()

    # (SR2) Argon bubbling
    print("\n----\033[31mN2 bubbling\033[0m----")
    n2_bubbling = controller.N2(loop=1, nozzle=2, wait_time=[12, 3, 12], mode="dual")
    n2_bubbling.run()
    time.sleep(7)

    # (SR3) Suction only
    suction_only = controller.Rinse(loop=1, wait_time=[16, 12, 0, 0, 16])
    suction_only.run()
    time.sleep(7)

    # (SR4) Argon drying
    print("\n----\033[31mN2 drying\033[0m----")
    n2_drying = controller.N2(loop=1, nozzle=1, wait_time=[12, 3, 12], mode="single")
    n2_drying.run()
    time.sleep(10)

########## Main Power OFF ##################################################################################
print("\n----MAIN POWER OFF----")
power.state("OFF")
time.sleep(10)

print("Finished")
setup.disconnect()

print("\n----\033[31m Print the total time duration \033[0m----")
end_time = time.time()
total_time = end_time - start_time
total_time_list = str(datetime.timedelta(seconds=total_time)).split(".")
print(total_time_list[0])  # Hrs:Mins:Secs format


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

from flask import Blueprint
from flask import redirect, request
from flask.helpers import url_for, flash
from flask_login import login_required
from models import Client, db
from flask.templating import render_template
from flask.views import MethodView
from messages import ClientMessages, CssMessages

bp = Blueprint('client', __name__)

class ClientAPIForm(MethodView):

    @login_required
    def post(self):

        client = Client()

        client.nome =  request.form.get('nome')
        client.razao_social =  request.form.get('razao_social')
        client.rua =  request.form.get('rua')
        client.cep =  request.form.get('cep')
        client.bairro =  request.form.get('bairro')
        client.cidade =  request.form.get('cidade')
        client.email = request.form.get('email')
        client.observacao =  request.form.get('observacao')

        client.save()

        flash(ClientMessages.CLIENT_ADD_SUCCESS, CssMessages.SUCCESS)
        return redirect(url_for('.ClientAPIForm'))

    @login_required
    def get(self):
        return render_template('client_add.html')

bp.add_url_rule('/client', view_func=ClientAPIForm.as_view('ClientAPIForm'))

class ClientAPI(MethodView):

    @login_required
    def get(self, id=None):

        client = Client.query.get(id)

        if client:
            return render_template('client_update.html', client=client)
        else:
            return render_template('page_404.html')

    @login_required
    def post(self, id=None):

        client = Client.query.get(id)

        client.nome =  request.form.get('nome')
        client.razao_social =  request.form.get('razao_social')
        client.rua =  request.form.get('rua')
        client.cep =  request.form.get('cep')
        client.bairro =  request.form.get('bairro')
        client.cidade =  request.form.get('cidade')
        client.email = request.form.get('email')
        client.observacao =  request.form.get('observacao')

        client.save()

        flash(ClientMessages.CLIENT_UPDATE_SUCCESS, 'success')

        return redirect(url_for('.ClientAPI', id=id))

bp.add_url_rule('/client/<id>', view_func=ClientAPI.as_view('ClientAPI'), methods=['GET', 'POST'])

class ClientAPIList(MethodView):

    @login_required
    def get(self, id=None):

        if id:
            clients = Client.query.filter_by(id=id)
        else:
            clients = Client.query.all()

        return render_template('client_list.html', clients=clients)

bp.add_url_rule('/clients', view_func=ClientAPIList.as_view('ClientAPIList'))

# @bp.before_request
# def restrict_bp_to_admins():
#     if not users.is_current_user_admin():
#         return redirect(users.create_login_url(request.url))


T = int(input())
for tc in range(1, T + 1):
    N, M = map(int, input().split())
    arr = list(map(int, input().split()))

    first_value = 0
    for i in range(M):
        first_value += arr[i]

    max_v = first_value
    min_v = first_value
    print(max_v,min_v)

    for i in range(1, N - M + 1):
        sum = 0
        for j in range(i, i + M):
            sum += arr[j]

        if max_v < sum:
            min_v = sum
        if min_v > sum:
            min_v = sum

    ans = max_v - min_v
    print(f'#{tc} {ans}')


import cv2
import time
import sys
import traceback
import numpy as np
from .utils import EasyDict

from rich import print
import slideflow as sf
from slideflow.util import model_backend

if sf.util.tf_available:
    import tensorflow as tf
    import slideflow.io.tensorflow
    gpus = tf.config.experimental.list_physical_devices('GPU')
    for gpu in gpus:
        try:
            tf.config.experimental.set_memory_growth(gpu, True)
        except RuntimeError:
            pass
if sf.util.torch_available:
    import torch
    import torchvision
    import slideflow.io.torch

#----------------------------------------------------------------------------

class CapturedException(Exception):
    def __init__(self, msg=None):
        if msg is None:
            _type, value, _traceback = sys.exc_info()
            assert value is not None
            if isinstance(value, CapturedException):
                msg = str(value)
            else:
                msg = traceback.format_exc()
        assert isinstance(msg, str)
        super().__init__(msg)

#----------------------------------------------------------------------------

class CaptureSuccess(Exception):
    def __init__(self, out):
        super().__init__()
        self.out = out

#----------------------------------------------------------------------------

def _reduce_dropout_preds_torch(yp_drop, num_outcomes, stack=True):
    if num_outcomes > 1:
        if stack:
            yp_drop = [torch.stack(yp_drop[n], dim=0) for n in range(num_outcomes)]
        else:
            yp_drop = [yp_drop[0] for n in range(num_outcomes)]
        yp_mean = [torch.mean(yp_drop[n], dim=0) for n in range(num_outcomes)]
        yp_std = [torch.std(yp_drop[n], dim=0) for n in range(num_outcomes)]
    else:
        if stack:
            yp_drop = torch.stack(yp_drop[0], dim=0)  # type: ignore
        else:
            yp_drop = yp_drop[0]
        yp_mean = torch.mean(yp_drop, dim=0)  # type: ignore
        yp_std = torch.std(yp_drop, dim=0)  # type: ignore
    return yp_mean, yp_std

def _reduce_dropout_preds_tf(yp_drop, num_outcomes, stack=True):
    if num_outcomes > 1:
        if stack:
            yp_drop = [tf.stack(yp_drop[n], axis=0) for n in range(num_outcomes)]
        else:
            yp_drop = [yp_drop[0] for n in range(num_outcomes)]
        yp_mean = [tf.math.reduce_mean(yp_drop[n], axis=0).numpy() for n in range(num_outcomes)]
        yp_std = [tf.math.reduce_std(yp_drop[n], axis=0).numpy() for n in range(num_outcomes)]
    else:
        if stack:
            yp_drop = tf.stack(yp_drop[0], axis=0)
        else:
            yp_drop = yp_drop[0]
        yp_mean = tf.math.reduce_mean(yp_drop, axis=0).numpy()
        yp_std = tf.math.reduce_std(yp_drop, axis=0).numpy()
    return yp_mean, yp_std

def _decode_jpeg(img, _model_type):
    if _model_type in ('tensorflow', 'tflite'):
        return tf.image.decode_jpeg(img, channels=3)
    else:
        np_data = torch.from_numpy(np.fromstring(img, dtype=np.uint8))
        return torchvision.io.decode_image(np_data)

def _umap_normalize(vector, clip_min, clip_max, norm_min, norm_max):
    vector = np.clip(vector, clip_min, clip_max)
    vector -= norm_min
    vector /= (norm_max - norm_min)
    return vector

#----------------------------------------------------------------------------

class Renderer:
    def __init__(self, device=None, buffer=None, extract_px=None, tile_px=None):
        #self._device            = torch.device('cuda')
        self._pkl_data          = dict()    # {pkl: dict | CapturedException, ...}
        self._pinned_bufs       = dict()    # {(shape, dtype): torch.Tensor, ...}
        self._cmaps             = dict()    # {name: torch.Tensor, ...}
        self._is_timing         = False
        #self._start_event       = torch.cuda.Event(enable_timing=True)
        #self._end_event         = torch.cuda.Event(enable_timing=True)
        self._net_layers        = dict()
        self._uq_thread         = None
        self._model             = None
        self._saliency          = None
        self._buffer            = buffer
        self.extract_px         = extract_px
        self.tile_px            = tile_px
        self.device             = device
        self._umap_encoders     = None
        self._addl_renderers    = []

    @property
    def model_type(self):
        if self._model is None:
            return None
        else:
            return model_backend(self._model)

    def process_tf_preds(self, preds):
        if isinstance(preds, list):
            return [self.to_numpy(p[0]) for p in preds]
        else:
            return self.to_numpy(preds[0])

    def to_numpy(self, x):
        if self.model_type in ('tensorflow', 'tflite'):
            return x.numpy()
        else:
            return x.cpu().detach().numpy()

    def add_renderer(self, renderer):
        self._addl_renderers += [renderer]

    def render(self, **args):
        self._is_timing = True
        #self._start_event.record(torch.cuda.current_stream(self._device))
        self._start_time = time.time()
        res = EasyDict()
        try:
            self._render_impl(res, **args)
        except:
            res.error = CapturedException()
        #self._end_event.record(torch.cuda.current_stream(self._device))
        if 'error' in res:
            res.error = str(res.error)
        if self._is_timing:
            #self._end_event.synchronize()
            res.render_time = time.time() - self._start_time #self._start_event.elapsed_time(self._end_event) * 1e-3
            self._is_timing = False
        return res

    def _ignore_timing(self):
        self._is_timing = False

    def _calc_preds_and_uncertainty(self, img, uq_n=30):

        if self.model_type in ('tensorflow', 'tflite'):
            yp = self._model(tf.repeat(img, repeats=uq_n, axis=0), training=False)
            reduce_fn = _reduce_dropout_preds_tf
        else:
            yp = self._model(torch.repeat(img, repeats=uq_n, dim=0), training=False)
            reduce_fn = _reduce_dropout_preds_torch

        num_outcomes = 1 if not isinstance(yp, list) else len(yp)
        yp_drop = {n: [] for n in range(num_outcomes)}
        if num_outcomes > 1:
            for o in range(num_outcomes):
                yp_drop[o] = yp[o]
        else:
            yp_drop[0] = yp
        yp_mean, yp_std = reduce_fn(yp_drop, num_outcomes, stack=False)
        if num_outcomes > 1:
            uncertainty = [np.mean(s) for s in yp_std]
        else:
            uncertainty = np.mean(yp_std)
        predictions = yp_mean
        return predictions, uncertainty

    def _classify_img(self, img, use_uncertainty=False):
        """Classify an image, returning predictions and uncertainty.

        Args:
            img (_type_): _description_

        Returns:
            Predictions, Uncertainty
        """
        if self.model_type in ('tensorflow', 'tflite'):
            img = tf.expand_dims(img, axis=0)
        elif self.model_type == 'torch':
            img = torch.unsqueeze(img, dim=0)

        if use_uncertainty:
            return self._calc_preds_and_uncertainty(img)
        elif self.model_type == 'tflite':
            sig_name = list(self._model._inputs.keys())[0]
            preds = self._model(**{sig_name: img})['output']
            if isinstance(preds, list):
                preds = [p[0] for p in preds]
            else:
                preds = preds[0]
        else:
            preds = self._model(img)
            preds = self.process_tf_preds(preds)
        return preds, None

    def _render_impl(self, res,
        x                   = 0,
        y                   = 0,
        saliency_overlay    = False,
        saliency_method     = 0,
        img_format          = None,
        use_model           = False,
        use_uncertainty     = False,
        use_saliency        = False,
        normalizer          = None,
        viewer              = None,
        tile_px             = None,
        tile_um             = None,
        full_image          = None,
        use_umap_encoders   = False,
        **kwargs
    ):
        args = locals()
        del args['kwargs']
        del args['self']
        args.update(kwargs)
        args['use_model'] = False
        for renderer in self._addl_renderers:
            renderer._render_impl(**args)
        if (x is None or y is None) and 'image' not in res:
            return
        if full_image is not None:
            img = cv2.resize(full_image, (tile_px, tile_px))
            res.image = img
        elif viewer is not None:

            if not self._model:
                res.message = "Model not loaded"
                print(res.message)
                return

            res.predictions = None
            res.uncertainty = None

            if self.model_type in ('tensorflow', 'tflite'):
                dtype = tf.uint8
            elif self.model_type == 'torch':
                dtype = torch.uint8

            use_jpeg = use_model and img_format is not None and img_format.lower() in ('jpg', 'jpeg')
            img = viewer.read_tile(x, y, img_format='jpg' if use_jpeg else None, allow_errors=True)
            if img is None:
                res.message = "Invalid tile location."
                print(res.message)
                return
            if use_jpeg:
                img = _decode_jpeg(img, self.model_type)
                if self.model_type == 'torch':
                    res.image = sf.io.torch.cwh_to_whc(img).numpy()
                res.image = img.numpy()
                img = sf.io.convert_dtype(img, dtype)
            else:
                res.image = img
        elif 'image' in res and use_model:
            # Image was generated by one of the additional renderers.
            # Check if any additional pre-processing needs to be done.
            img = res.image
            for renderer in self._addl_renderers:
                if hasattr(renderer, 'preprocess'):
                    img = renderer.preprocess(img, tile_px=tile_px, tile_um=tile_um)

        if use_model:
            if self.model_type in ('tensorflow', 'tflite') and isinstance(img, np.ndarray):
                proc_img = tf.convert_to_tensor(img)
            elif isinstance(img, np.ndarray):
                proc_img = sf.io.torch.whc_to_cwh(torch.from_numpy(img)).to(self.device)
            else:
                proc_img = img

            # Pre-process image.
            if normalizer:
                _norm_start = time.time()
                proc_img = normalizer.transform(proc_img)
                if not isinstance(proc_img, np.ndarray):
                    if self.model_type == 'torch':
                        res.normalized = sf.io.torch.cwh_to_whc(proc_img).numpy().astype(np.uint8)
                    else:
                        res.normalized = proc_img.numpy().astype(np.uint8)
                else:
                    res.normalized = proc_img.astype(np.uint8)
                res.norm_time = time.time() - _norm_start
            if self.model_type in ('tensorflow', 'tflite'):
                proc_img = sf.io.tensorflow.preprocess_uint8(proc_img, standardize=True)['tile_image']
            elif self.model_type == 'torch':
                proc_img = sf.io.torch.preprocess_uint8(proc_img, standardize=True)
                if self.device is not None:
                    proc_img = proc_img.to(self.device)

            # Saliency.
            if use_saliency:
                mask = self._saliency.get(self.to_numpy(proc_img), method=saliency_method)
                if saliency_overlay:
                    res.image = sf.grad.plot_utils.overlay(res.image, mask)
                else:
                    res.image = sf.grad.plot_utils.inferno(mask)
                if res.image.shape[-1] == 4:
                    res.image = res.image[:, :, 0:3]

            # Show predictions.
            _inference_start = time.time()
            if use_umap_encoders:
                u = self._umap_encoders
                encoder_out = u.encoder(tf.expand_dims(proc_img, axis=0))
                res.umap_coords = {}
                for i, layer in enumerate(u.layers):
                    res.umap_coords[layer] = _umap_normalize(
                        encoder_out[i],
                        clip_min=u.clip[layer][0],
                        clip_max=u.clip[layer][1],
                        norm_min=u.range[layer][0],
                        norm_max=u.range[layer][1]
                    )[0]
                res.predictions = self.process_tf_preds(encoder_out[-1])
                res.uncertainty = None
            else:
                res.predictions, res.uncertainty = self._classify_img(proc_img, use_uncertainty=use_uncertainty)
            res.inference_time = time.time() - _inference_start

#----------------------------------------------------------------------------


import os
import time

from urllib.parse import urlparse

from django.core.management.base import BaseCommand, CommandError

import requests

from images.models import Image, ImageSourceResult

def get_any_value(d: dict, *keys):
    """
    Returns the first valid key's value.
    """

    for key in keys:
        if key in d:
            return d.get(key)
    return None

class Command(BaseCommand):
    def handle(self, *args, **options):
        """
        Handle image source fetching.
        """

        for image in Image.objects.filter(
            source_queries=None, source_url=None
        ).exclude(file=None).exclude(file='')[:100]:
            # Handle the 100 daily images.

            file_url = image.file.url

            with requests.get(file_url) as f:
                r = requests.post(
                    "https://saucenao.com/search.php",
                    params={
                        "db": 999,
                        "output_type": 2,
                        "testmode": 1,
                        "numres": 16,
                        "api_key": os.getenv("BACKEND_SAUCENAO_TOKEN"),
                    },
                    files=dict(file=f.content),
                )

                try:
                    results = r.json()["results"]
                except:
                    self.stderr.write(self.style.ERROR(f"ERROR - Key error in response - {r.status_code}"))
                    continue
                possible_sources = []

                for result in results:
                    if float(result["header"]["similarity"]) >= 85:
                        possible_sources.append(
                            {
                                "title": get_any_value(results, "title", "index_name"),
                                "similarity": float(result["header"]["similarity"]),
                                "ext_urls": result["data"].get("ext_urls"),
                                "source": result["data"].get("source"),
                                "artist": {
                                    "name": get_any_value(
                                        result["data"],
                                        "member_name",
                                        "creator",
                                        "author_name",
                                        "artist",
                                    ),
                                    "url": get_any_value(result["data"], "author_url"),
                                },
                            }
                        )

                if len(possible_sources) == 0:
                    ImageSourceResult.objects.create(
                        image=image, status=0, similarity=0
                    )
                    self.stderr.write(
                        f"QUERIED: ERROR - Image ID: {image.id} - Status code: {r.status_code}"
                    )
                    self.stdout.write("Sleeping 10s...\n")
                    time.sleep(10)
                    continue

                possible_sources = sorted(
                    possible_sources, key=lambda d: d["similarity"], reverse=True
                )

                source = possible_sources[0]

                ImageSourceResult.objects.create(
                    image=image,
                    status=r.status_code,
                    title=source["title"],
                    similarity=source["similarity"],
                    ext_urls=source["ext_urls"],
                    source=source["source"],
                    artist_name=source["artist"]["name"],
                    artist_url=source["artist"]["url"],
                )

                image.source_url = (
                    source["ext_urls"][0]
                    if source["ext_urls"] is not None and len(source["ext_urls"])
                    else None
                )

                source_hostname = urlparse(image.source_url).netloc

                source_names = {
                    "www.pixiv.net": "Pixiv",
                    "danbooru.donmai.us": "Danbooru",
                    "gelbooru.com": "Gelbooru",
                    "deviantart.com": "DevianArt",
                    "www.mangaupdates.com": "Manga Updates",
                    "mangadex.org": "Mangadex",
                    "yande.re": "yande.re",
                }

                image.source_name = (
                    source_names[source_hostname]
                    if source_hostname in source_names
                    else None
                )
                image.save()

                self.stdout.write(
                    self.style.SUCCESS(
                        f"QUERIED - Image ID: {image.id} - Results: {len(possible_sources)} - Status code: {r.status_code}"
                    )
                )
                self.stdout.write("Sleeping 10s...\n")
                time.sleep(10)


number_plants = int(input())
plants_dict = {}
rate_dict = {}

for i in range(number_plants):
    plants = input().split("<->")
    current_plant = plants[0]
    rarity = int(plants[1])
    rarity_dict = {}
    rarity_dict["Rarity"] = rarity

    if current_plant not in plants_dict:
        plants_dict[current_plant] = rarity_dict

    else:
        plants_dict[current_plant]["Rarity"] = rarity

command = input()

while command != "Exhibition":
    command = command.split(":")
    current_command = command[0]
    command = command[1].split("-")
    command = [x.strip(" ") for x in command]

    if current_command == "Rate":
        plant = command[0]
        rating = int(command[1])

        if plant in plants_dict:
            if plant not in rate_dict:
                rate_dict[plant] = []
                rate_dict[plant].append(rating)
            else:
                rate_dict[plant].append(rating)
        else:
            print("error")
    elif current_command == "Update":
        plant = command[0]
        new_rarity = int(command[1])

        if plant in plants_dict:
            plants_dict[plant]["Rarity"] = new_rarity
        else:
            print("error")

    elif current_command == "Reset":
        plant = command[0]

        if plant in rate_dict:
            rate_dict[plant].pop()
        else:
            print("error")

    command = input()

print("Plants for the exhibition:")
for key in plants_dict:
    average = 0
    if len(rate_dict[key]) > 0:
        average = sum(rate_dict[key]) / len(rate_dict[key])
    print(f"- {key}; Rarity: {plants_dict[key]['Rarity']}; Rating: {average:.2f}")

#vtori nachin
n = int(input())
plants = {}

for num in range(n):
    data = input().split('<->')
    plant_name = data[0]
    plant_rarity = int(data[1])
    plants[plant_name] = {"rarity": plant_rarity, "rating": []}

command = input()

while not command == 'Exhibition':
    data_1 = command.split(': ')
    data_2 = data_1[1].split(' - ')
    action = data_1[0]
    plant_name = data_2[0]
    if plant_name not in plants:
        print("error")
    elif action == "Rate":
        rating = int(data_2[1])
        plants[plant_name]["rating"].append(rating)
    elif action == "Update":
        new_rarity = int(data_2[1])
        plants[plant_name]["rarity"] = new_rarity
    elif action == "Reset":
        plants[plant_name]["rating"].clear()

    command = input()

print("Plants for the exhibition:")

for plant in plants:
    average_rating = 0
    if plants[plant]["rating"]:
        average_rating = sum(plants[plant]["rating"]) / len(plants[plant]["rating"])
    print(f"- {plant}; Rarity: {plants[plant]['rarity']}; Rating: {average_rating:.2f}")

Programming fundamentals with Python/Exam Prep/Final exam prep/task3_plant_discovery_exam02.py


from aiogram import Router, F, types
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import StatesGroup, State
from aiogram.types import Message, ReplyKeyboardRemove
import json

router = Router()

nicknames = []

class OrderFood(StatesGroup):
    choosing_nickname = State()

@router.callback_query()
async def handler_inline(call: types.CallbackQuery, state: FSMContext):
    await call.answer(
        text="Напишите ваш никнейм:",
    )
    # Устанавливаем пользователю состояние "выбирает название"
    await state.set_state(OrderFood.choosing_nickname)

# Этап выбора блюда #

@router.message(OrderFood.choosing_nickname, F.text.not_in(nicknames))
async def nickname_chosen(message: Message, state: FSMContext):
    await state.update_data(chosen_food=message.text.lower())
    await message.answer(
        text="Спасибо. Идёт создание вашего юзербота...",
    )
    nicknames.append(message.text.lower())
    with open('nicknames.json', 'w') as f:
        json.dump(nicknames, f)

@router.message(OrderFood.choosing_nickname)
async def nickname_chosen_incorecctly(message: Message):
    await message.answer(
        text="Ник уже зарегистрирован, выберите другой"
    )

@router.message(Command("cancel"))
async def cancel(message: Message, state: FSMContext):
    state.clear()

# Этап выбора размера порции и отображение сводной информации #


#!/usr/bin/env python
# coding: utf-8

import os
import argparse

import numpy as np
import tensorflow as tf

from keras.utils import to_categorical
from keras import Sequential
from keras.layers import Conv2D, MaxPooling2D, Dense, Flatten

from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split

from PIL import Image

import matplotlib.pyplot as plt
from matplotlib import image

tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)

IMAGE_PATH = os.getcwd() + '/images'
SPECIES_MODE = True

parser = argparse.ArgumentParser()
parser.add_argument('-g', '--genus', action='store_true')
if parser.parse_args().genus:
    SPECIES_MODE = False

#CROP_X =
#960x320+62+0

images = []
labels = []

# subfolders of images should be genus names
genera = [folder for folder in os.listdir(IMAGE_PATH)
          if os.path.isdir(os.path.join(IMAGE_PATH, folder))]

if not genera:
    print("Need to download genera first.")
    quit()

for genus in genera:
    new_image_path = os.path.join(IMAGE_PATH, genus)
    for img_file in os.listdir(new_image_path):
        img = Image.open(os.path.join(new_image_path, img_file)).convert('L')
        # crop away the part that all images share
        #img = img.crop((960,320,62,0))

        # shape: (height, width)
        img_array = np.asarray(img)
        img_array = img_array.reshape(img_array.shape[0], img_array.shape[1], 1)

        #plt.imshow(img_array, cmap='gray', vmin=0, vmax=255)
        #plt.show()

        images.append(img_array)

        # parse label from file
        if SPECIES_MODE:
            labels.append(img_file.split(".")[0].split("-")[1])
        else:
            labels.append(genus)

#for img in images:
    #print(img)

# one hot encoding on labels
encoder = LabelBinarizer()
one_hot_labels = encoder.fit_transform(labels)

print(one_hot_labels.shape)

X_train, X_val, y_train, y_val = train_test_split(images, one_hot_labels, test_size=0.2, random_state=31)
X_train = np.array(X_train)
X_val = np.array(X_val)

#X_train_shaped = X_train.reshape(X_train.shape[0], X_train.shape[1], X_train.shape[2], 1)
#X_val_shaped = X_val.reshape(X_val.shape[0], X_val.shape[1], X_val.shape[2], 1)

model = Sequential()

model.add(Conv2D(filters=32, input_shape=(X_train.shape[1], X_train.shape[2], 1), data_format="channels_last", kernel_size=2,
                 strides=2, activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(one_hot_labels.shape[1], activation='sigmoid'))
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

model.summary()

model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=10)

#model.predict(test_X_shaped[:4])


import os
import sys
import shutil
import argparse
import concurrent.futures

from tqdm import tqdm

def copy_file(src, dst):
    if os.path.exists(src):
        shutil.copy2(src, dst)

def organize_and_copy(line, data_dir, class_grouping, dst_fold_group_dir, split):
    image_filename = f'{line.strip()}.jpg'
    label_filename = f'{line.strip()}.txt'

    src_image = os.path.join(data_dir, 'images', image_filename)
    dst_image = os.path.join(dst_fold_group_dir, 'images', split, image_filename)
    copy_file(src_image, dst_image)

    src_label = os.path.join(data_dir, f'labels_{class_grouping}', label_filename)
    dst_label = os.path.join(dst_fold_group_dir, 'labels', split, label_filename)
    copy_file(src_label, dst_label)

    if class_grouping in ['3cls', '8cls']:
        src_label_size = os.path.join(data_dir, f'labels_{class_grouping}_size', label_filename)
        dst_label_size = os.path.join(dst_fold_group_dir, 'labels_size', split, label_filename)
        copy_file(src_label_size, dst_label_size)

def process_split(fold_dir, data_dir, class_grouping, dst_fold_group_dir, split):
    txt_file_path = os.path.join(fold_dir, f'{split}.txt')
    if os.path.exists(txt_file_path):
        with open(txt_file_path, 'r') as file:
            lines = file.readlines()
            with concurrent.futures.ThreadPoolExecutor() as executor:
                futures = [executor.submit(organize_and_copy, line, data_dir, class_grouping, dst_fold_group_dir, split)
                           for line in lines]
                for future in concurrent.futures.as_completed(futures):
                    future.result()

def process_class_grouping(fold_dir, data_dir, datasets_dir, fold, class_grouping):
    dst_fold_group_dir = os.path.join(datasets_dir, f'{fold}', f'{class_grouping}_{fold}')

    os.makedirs(os.path.join(dst_fold_group_dir, 'images', 'train'), exist_ok=True)
    os.makedirs(os.path.join(dst_fold_group_dir, 'images', 'val'), exist_ok=True)
    os.makedirs(os.path.join(dst_fold_group_dir, 'images', 'test'), exist_ok=True)
    os.makedirs(os.path.join(dst_fold_group_dir, 'labels', 'train'), exist_ok=True)
    os.makedirs(os.path.join(dst_fold_group_dir, 'labels', 'val'), exist_ok=True)
    os.makedirs(os.path.join(dst_fold_group_dir, 'labels', 'test'), exist_ok=True)

    if class_grouping in ['3cls', '8cls']:
        os.makedirs(os.path.join(dst_fold_group_dir, 'labels_size', 'train'), exist_ok=True)
        os.makedirs(os.path.join(dst_fold_group_dir, 'labels_size', 'val'), exist_ok=True)
        os.makedirs(os.path.join(dst_fold_group_dir, 'labels_size', 'test'), exist_ok=True)

    for split in ['train', 'val', 'test']:
        process_split(fold_dir, data_dir, class_grouping, dst_fold_group_dir, split)

def organize_datasets(data_dir, datasets_dir):
    splits_dir = os.path.join(data_dir, 'splits')

    if not os.path.exists(os.path.join(data_dir, 'images')):
        print(f'[ERROR] {os.path.join(data_dir, "images")} does not exist...')
        sys.exit()

    if not os.listdir(os.path.join(data_dir, 'images')):
        response = input('[INPUT] Image directory is empty. Continue? (y/n): ')
        if response.lower() != 'y':
            print('[EXITING]')
            sys.exit()
        print('[INFO] Continuing...')

    for fold in tqdm(os.listdir(splits_dir), desc='Organising folds...'):
        fold_dir = os.path.join(splits_dir, fold)
        class_groupings = ['1cls', '3cls', '8cls']
        with concurrent.futures.ThreadPoolExecutor() as executor:
            futures = [executor.submit(process_class_grouping, fold_dir, data_dir, datasets_dir, fold, class_grouping) for class_grouping in class_groupings]
            # Progress bar for class groupings
            for _ in tqdm(concurrent.futures.as_completed(futures), desc='Organising class groups...', total=len(class_groupings)):
                pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Organize datasets.')
    parser.add_argument('--data-dir', default='data', required=False, help='Directory containing the data')
    parser.add_argument('--output-dir', default='datasets', required=False, help='Directory to output the organized datasets')
    args = parser.parse_args()

    organize_datasets(args.data_dir, args.output_dir)


import torch
from torch import nn
import torch.nn.functional as F
from torch.autograd import Function, Variable
from .backbone import build_backbone
from .transformer import build_transformer, TransformerEncoder, TransformerEncoderLayer

import numpy as np

import IPython
e = IPython.embed

def reparametrize(mu, logvar):
    std = logvar.div(2).exp()
    eps = Variable(std.data.new(std.size()).normal_())
    return mu + std * eps

def get_sinusoid_encoding_table(n_position, d_hid):
    def get_position_angle_vec(position):
        return [position / np.power(10000, 2 * (hid_j // 2) / d_hid) for hid_j in range(d_hid)]

    sinusoid_table = np.array([get_position_angle_vec(pos_i)
                              for pos_i in range(n_position)])
    sinusoid_table[:, 0::2] = np.sin(sinusoid_table[:, 0::2])  # dim 2i
    sinusoid_table[:, 1::2] = np.cos(sinusoid_table[:, 1::2])  # dim 2i+1

    return torch.FloatTensor(sinusoid_table).unsqueeze(0)

class GradientReversalFunc(Function):
    @staticmethod
    def forward(ctx, x, alpha):
        ctx.save_for_backward(x, alpha)
        return x

    @staticmethod
    def backward(ctx, grad_output):
        grad_input = None
        _, alpha = ctx.saved_tensors
        if ctx.needs_input_grad[0]:
            grad_input = - alpha*grad_output
        return grad_input, None

revgrad = GradientReversalFunc.apply

class GradientReversalLayer(nn.Module):
    def __init__(self, alpha=1):
        super().__init__()
        self.alpha = torch.tensor(alpha, requires_grad=False)

    def forward(self, x):
        return revgrad(x, self.alpha)

class DETRVAE(nn.Module):
    """ This is the DETR module that performs object detection """

    def __init__(self, backbones, transformer, encoder, action_dim, num_queries, dann):
        """ Initializes the model.
        Parameters:
            backbones: torch module of the backbone to be used. See backbone.py
            transformer: torch module of the transformer architecture. See transformer.py
            action_dim: action dimension
            num_queries: number of object queries, ie detection slot. This is the maximal number of objects
                         DETR can detect in a single image. For COCO, we recommend 100 queries.
            aux_loss: True if auxiliary decoding losses (loss at each decoder layer) are to be used.
        """
        super().__init__()
        self.camera_names = ["rgb1"]

        self.num_queries = num_queries
        self.transformer = transformer
        self.encoder = encoder
        hidden_dim = transformer.d_model
        self.action_head = nn.Linear(hidden_dim, action_dim)
        self.is_pad_head = nn.Linear(hidden_dim, 1)
        self.query_embed = nn.Embedding(num_queries, hidden_dim)
        self.input_proj_robot_state = nn.Linear(29, hidden_dim)

        if backbones is not None:
            # Use backbone to extract features
            self.is_feature = False
            self.input_proj = nn.Conv2d(
                backbones[0].num_channels, hidden_dim, kernel_size=1)
            self.backbones = nn.ModuleList(backbones)
            self.encoder_obs_proj = nn.Linear(
                256*3*3, hidden_dim)  # project feature to embedding
        else:
            self.fea_pos_embed = nn.Embedding(1, hidden_dim)
            self.encoder_obs_proj = nn.Linear(
                2048, hidden_dim)  # project obs to embedding
            # self.encoder_obs_proj = nn.Linear(
            #     768, hidden_dim)  # project obs to embedding for mvp
            self.is_feature = True

        # encoder extra parameters
        self.latent_dim = 256  # final size of latent z # TODO tune
        # extra cls token embedding
        self.cls_embed = nn.Embedding(1, hidden_dim)
        self.encoder_action_proj = nn.Linear(
            22, hidden_dim)  # project action to embedding
        self.encoder_qpos_proj = nn.Linear(
            29, hidden_dim)  # project qpos to embedding
        # project hidden state to latent std, var
        self.latent_proj = nn.Linear(hidden_dim, self.latent_dim*2)
        self.register_buffer('pos_table', get_sinusoid_encoding_table(
            1+1+1+num_queries, hidden_dim))  # [CLS], obs, qpos, a_seq

        # decoder extra parameters
        # project latent sample to embedding
        self.latent_out_proj = nn.Linear(self.latent_dim, hidden_dim)
        # learned position embedding for proprio and latent
        self.additional_pos_embed = nn.Embedding(2, hidden_dim)

        # Add DANN
        self.dann = dann
        if self.dann:
            self.domain_clf = nn.Sequential(
                GradientReversalLayer(),
                nn.Linear(256*7*7, hidden_dim),
                nn.BatchNorm1d(hidden_dim),
                nn.ReLU(),
                nn.Linear(hidden_dim, hidden_dim),
                nn.BatchNorm1d(hidden_dim),
                nn.ReLU(),
                nn.Linear(hidden_dim, 1),
            )

    def forward(self, image, qpos, actions=None, is_pad=None):
        """
        image: batch, num_cam, channel, height, width
        qpos: batch, qpos_dim
        env_state: None
        actions: batch, seq, action_dim
        """
        is_training = actions is not None  # train or val
        bs, _ = qpos.shape

        if not self.is_feature:
            # Image observation features and position embeddings
            all_cam_features = []
            all_cam_pos = []
            for cam_id, cam_name in enumerate(self.camera_names):
                features, pos = self.backbones[0](
                    image[:, cam_id])  # HARDCODED
                features = features[0]  # take the last layer feature
                pos = pos[0]
                all_cam_features.append(self.input_proj(features))
                all_cam_pos.append(pos)

            # fold camera dimension into width dimension
            src = torch.cat(all_cam_features, axis=3)  # (bs, 256, 7, 7)
            pos = torch.cat(all_cam_pos, axis=3)

        else:
            # Features and position embeddings
            src = self.encoder_obs_proj(image)  # hidden_dim
            pos = self.fea_pos_embed.weight  # (1, hidden_dim)

        # Obtain latent z from action sequence
        if is_training:
            # project action sequence to embedding dim, and concat with a CLS token
            action_embed = self.encoder_action_proj(
                actions)  # (bs, seq, hidden_dim)
            if not self.is_feature:
                feature = F.max_pool2d(src, kernel_size=2, stride=2)
                feature = feature.flatten(1)  # (bs, 256*3*3)
                obs_embed = self.encoder_obs_proj(feature)
            else:
                obs_embed = src
            obs_embed = torch.unsqueeze(obs_embed, axis=1)
            qpos_embed = self.encoder_qpos_proj(qpos)  # (bs, hidden_dim)
            qpos_embed = torch.unsqueeze(
                qpos_embed, axis=1)  # (bs, 1, hidden_dim)
            cls_embed = self.cls_embed.weight  # (1, hidden_dim)
            cls_embed = torch.unsqueeze(cls_embed, axis=0).repeat(
                bs, 1, 1)  # (bs, 1, hidden_dim)
            # (bs, seq+1, hidden_dim)
            encoder_input = torch.cat(
                [cls_embed, obs_embed, qpos_embed, action_embed], axis=1)
            encoder_input = encoder_input.permute(
                1, 0, 2)  # (seq+1, bs, hidden_dim)
            # do not mask cls token
            cls_joint_is_pad = torch.full((bs, 3), False).to(
                qpos.device)  # False: not a padding
            is_pad = torch.cat([cls_joint_is_pad, is_pad],
                               axis=1)  # (bs, seq+1)
            # obtain position embedding
            pos_embed = self.pos_table.clone().detach()
            pos_embed = pos_embed.permute(1, 0, 2)  # (seq+1, 1, hidden_dim)
            # query model
            encoder_output = self.encoder(
                encoder_input, pos=pos_embed, src_key_padding_mask=is_pad)
            encoder_output = encoder_output[0]  # take cls output only
            latent_info = self.latent_proj(encoder_output)
            mu = latent_info[:, :self.latent_dim]
            logvar = latent_info[:, self.latent_dim:]
            latent_sample = reparametrize(mu, logvar)
            latent_input = self.latent_out_proj(latent_sample)
        else:
            mu = logvar = None
            latent_sample = torch.zeros(
                [bs, self.latent_dim], dtype=torch.float32).to(qpos.device)
            latent_input = self.latent_out_proj(latent_sample)

        # proprioception features
        proprio_input = self.input_proj_robot_state(qpos)
        hs = self.transformer(src, None, self.query_embed.weight, pos,
                              latent_input, proprio_input, self.additional_pos_embed.weight, self.is_feature)[0]

        a_hat = self.action_head(hs)
        is_pad_hat = self.is_pad_head(hs)

        if self.dann and is_training:
            src = src.flatten(1)
            domain_logits = self.domain_clf(src)
            domain_logits = domain_logits.view(bs, 1)
            domain_logits = torch.sigmoid(domain_logits)
            return a_hat, is_pad_hat, [mu, logvar], domain_logits

        return a_hat, is_pad_hat, [mu, logvar]

def build_encoder(args):
    d_model = args.hidden_dim  # 256
    dropout = args.dropout  # 0.1
    nhead = args.nheads  # 8
    dim_feedforward = args.dim_feedforward  # 2048
    num_encoder_layers = args.enc_layers  # 4 # TODO shared with VAE decoder
    normalize_before = args.pre_norm  # False
    activation = "relu"

    encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward,
                                            dropout, activation, normalize_before)
    encoder_norm = nn.LayerNorm(d_model) if normalize_before else None
    encoder = TransformerEncoder(
        encoder_layer, num_encoder_layers, encoder_norm)

    return encoder

def build_ACT_model(args):
    action_dim = 22  # TODO hardcode

    # From state
    # backbone = None # from state for now, no need for conv nets
    # From image

    transformer = build_transformer(args)

    encoder = build_encoder(args)

    if not args.is_feature:
        backbones = []
        backbone = build_backbone(args)
        backbones.append(backbone)

        model = DETRVAE(
            backbones=backbones,
            transformer=transformer,
            encoder=encoder,
            action_dim=action_dim,
            num_queries=args.num_queries,
            dann=args.dann
        )
    else:
        model = DETRVAE(
            backbones=None,
            transformer=transformer,
            encoder=encoder,
            action_dim=action_dim,
            num_queries=args.num_queries,
            dann=args.dann
        )

    n_parameters = sum(p.numel()
                       for p in model.parameters() if p.requires_grad)
    print("number of parameters: %.2fM" % (n_parameters/1e6,))

    return model


import logging
from pathlib import Path
import pytest

from flit_core import config

samples_dir = Path(__file__).parent / 'samples'

def test_flatten_entrypoints():
    r = config.flatten_entrypoints({'a': {'b': {'c': 'd'}, 'e': {'f': {'g': 'h'}}, 'i': 'j'}})
    assert r == {'a': {'i': 'j'}, 'a.b': {'c': 'd'}, 'a.e.f': {'g': 'h'}}

def test_load_toml():
    inf = config.read_flit_config(samples_dir / 'module1-pkg.toml')
    assert inf.module == 'module1'
    assert inf.metadata['home_page'] == 'http://github.com/sirrobin/module1'

def test_load_toml_ns():
    inf = config.read_flit_config(samples_dir / 'ns1-pkg' / 'pyproject.toml')
    assert inf.module == 'ns1.pkg'
    assert inf.metadata['home_page'] == 'http://github.com/sirrobin/module1'

def test_load_normalization():
    inf = config.read_flit_config(samples_dir / 'normalization' / 'pyproject.toml')
    assert inf.module == 'my_python_module'
    assert inf.metadata['name'] == 'my-python-module'

def test_load_pep621():
    inf = config.read_flit_config(samples_dir / 'pep621' / 'pyproject.toml')
    assert inf.module == 'module1a'
    assert inf.metadata['name'] == 'module1'
    assert inf.metadata['description_content_type'] == 'text/x-rst'
    # Remove all whitespace from requirements so we don't check exact format:
    assert {r.replace(' ', '') for r in inf.metadata['requires_dist']} == {
        'docutils',
        'requests>=2.18',
        'pytest;extra=="test"',  # from [project.optional-dependencies]
        'mock;extra=="test"and(python_version<\'3.6\')',
    }
    assert inf.metadata['author_email'] == "Sir Röbin <robin@camelot.uk>"
    assert inf.entrypoints['flit_test_example']['foo'] == 'module1:main'
    assert set(inf.dynamic_metadata) == {'version', 'description'}

def test_load_pep621_nodynamic():
    inf = config.read_flit_config(samples_dir / 'pep621_nodynamic' / 'pyproject.toml')
    assert inf.module == 'module1'
    assert inf.metadata['name'] == 'module1'
    assert inf.metadata['version'] == '0.3'
    assert inf.metadata['summary'] == 'Statically specified description'
    assert set(inf.dynamic_metadata) == set()

    # Filling reqs_by_extra when dependencies were specified but no optional
    # dependencies was a bug.
    assert inf.reqs_by_extra == {'.none':  ['requests >= 2.18', 'docutils']}

def test_misspelled_key():
    with pytest.raises(config.ConfigError) as e_info:
        config.read_flit_config(samples_dir / 'misspelled-key.toml')

    assert 'description-file' in str(e_info.value)

def test_description_file():
    info = config.read_flit_config(samples_dir / 'package1.toml')
    assert info.metadata['description'] == \
        "Sample description for test.\n"
    assert info.metadata['description_content_type'] == 'text/x-rst'

def test_missing_description_file():
    with pytest.raises(config.ConfigError, match=r"Description file .* does not exist"):
        config.read_flit_config(samples_dir / 'missing-description-file.toml')

def test_bad_description_extension(caplog):
    info = config.read_flit_config(samples_dir / 'bad-description-ext.toml')
    assert info.metadata['description_content_type'] is None
    assert any((r.levelno == logging.WARN and "Unknown extension" in r.msg)
                for r in caplog.records)

def test_extras():
    info = config.read_flit_config(samples_dir / 'extras.toml')
    requires_dist = set(info.metadata['requires_dist'])
    assert requires_dist == {
        'toml',
        'pytest ; extra == "test"',
        'requests ; extra == "custom"',
    }
    assert set(info.metadata['provides_extra']) == {'test', 'custom'}

def test_extras_dev_conflict():
    with pytest.raises(config.ConfigError, match=r'dev-requires'):
        config.read_flit_config(samples_dir / 'extras-dev-conflict.toml')

def test_extras_dev_warning(caplog):
    info = config.read_flit_config(samples_dir / 'requires-dev.toml')
    assert '"dev-requires = ..." is obsolete' in caplog.text
    assert set(info.metadata['requires_dist']) == {'apackage ; extra == "dev"'}

def test_requires_extra_env_marker():
    info = config.read_flit_config(samples_dir / 'requires-extra-envmark.toml')
    assert info.metadata['requires_dist'][0].startswith('pathlib2 ;')

@pytest.mark.parametrize(('erroneous', 'match'), [
    ({'requires-extra': None}, r'Expected a dict for requires-extra field'),
    ({'requires-extra': dict(dev=None)}, r'Expected a dict of lists for requires-extra field'),
    ({'requires-extra': dict(dev=[1])}, r'Expected a string list for requires-extra'),
])
def test_faulty_requires_extra(erroneous, match):
    metadata = {'module': 'mymod', 'author': '', 'author-email': ''}
    with pytest.raises(config.ConfigError, match=match):
        config._prep_metadata(dict(metadata, **erroneous), None)

@pytest.mark.parametrize(('path', 'err_match'), [
    ('../bar', 'out of the directory'),
    ('foo/../../bar', 'out of the directory'),
    ('/home', 'absolute path'),
    ('foo:bar', 'bad character'),
])
def test_bad_include_paths(path, err_match):
    toml_cfg = {'tool': {'flit': {
        'metadata': {'module': 'xyz', 'author': 'nobody'},
        'sdist': {'include': [path]}
    }}}

    with pytest.raises(config.ConfigError, match=err_match):
        config.prep_toml_config(toml_cfg, None)

@pytest.mark.parametrize(('proj_bad', 'err_match'), [
    ({'version': 1}, r'\bstr\b'),
    ({'license': {'fromage': 2}}, '[Uu]nrecognised'),
    ({'license': {'file': 'LICENSE', 'text': 'xyz'}}, 'both'),
    ({'license': {}}, 'required'),
    ({'keywords': 'foo'}, 'list'),
    ({'keywords': ['foo', 7]}, 'strings'),
    ({'entry-points': {'foo': 'module1:main'}}, 'entry-point.*tables'),
    ({'entry-points': {'group': {'foo': 7}}}, 'entry-point.*string'),
    ({'entry-points': {'gui_scripts': {'foo': 'a:b'}}}, r'\[project\.gui-scripts\]'),
    ({'scripts': {'foo': 7}}, 'scripts.*string'),
    ({'gui-scripts': {'foo': 7}}, 'gui-scripts.*string'),
    ({'optional-dependencies': {'test': 'requests'}}, 'list.*optional-dep'),
    ({'optional-dependencies': {'test': [7]}}, 'string.*optional-dep'),
    ({'dynamic': ['classifiers']}, 'dynamic'),
    ({'dynamic': ['version']}, r'dynamic.*\[project\]'),
    ({'authors': ['thomas']}, r'author.*\bdict'),
    ({'maintainers': [{'title': 'Dr'}]}, r'maintainer.*title'),
])
def test_bad_pep621_info(proj_bad, err_match):
    proj = {'name': 'module1', 'version': '1.0', 'description': 'x'}
    proj.update(proj_bad)
    with pytest.raises(config.ConfigError, match=err_match):
        config.read_pep621_metadata(proj, samples_dir / 'pep621')

@pytest.mark.parametrize(('readme', 'err_match'), [
    ({'file': 'README.rst'}, 'required'),
    ({'file': 'README.rst', 'content-type': 'text/x-python'}, 'content-type'),
    ('/opt/README.rst', 'relative'),
    ({'file': 'README.rst', 'text': '', 'content-type': 'text/x-rst'}, 'both'),
    ({'content-type': 'text/x-rst'}, 'required'),
    ({'file': 'README.rst', 'content-type': 'text/x-rst', 'a': 'b'}, '[Uu]nrecognised'),
    (5, r'readme.*string'),
])
def test_bad_pep621_readme(readme, err_match):
    proj = {
        'name': 'module1', 'version': '1.0', 'description': 'x', 'readme': readme
    }
    with pytest.raises(config.ConfigError, match=err_match):
        config.read_pep621_metadata(proj, samples_dir / 'pep621')


def solution(park, routes):
    # 위치 index
    x = 0
    y = 0

    # 시작 위치 찾기
    for i in range(len(park)):
        for j in range(len(park[i])):
            if park[i][j] == 'S':
                x = i
                y = j
                break

    # 이동
    dx = [-1, 1, 0, 0]  # 서쪽, 동쪽, 북쪽, 남쪽의 x 방향 이동
    dy = [0, 0, -1, 1]  # 서쪽, 동쪽, 북쪽, 남쪽의 y 방향 이동
    direction = ['N', 'S', 'W', 'E']  # 방향 배열

    for route in routes:
        # 위치 초기화
        xx = x
        yy = y
        # 이동 - 장애물이 있거나 공원을 벗어나면 명령 무시
        for step in range(int(route[2])):
            index = direction.index(route[0])  # 현재 방향의 인덱스 가져오기
            nx = xx + dx[index]
            ny = yy + dy[index]

            # 이동할 곳이 공원 범위 내이고 장애물이 아닌지 확인
            if 0 <= nx < len(park) and 0 <= ny < len(park[0]) and park[nx][ny] != 'X':
                xx = nx
                yy = ny
                if step == int(route[2])-1:
                    x = xx  # step만큼 움직였으면 위치 초기화
                    y = yy

    return [x, y]


import ffbot

# Yahoo league/team id
# Visit your team at https://football.fantasysports.yahoo.com/f1/, and the url will also include your league and team ID
LEAGUE = 123456
TEAM = 1
POSITIONS = "QB, WR, WR, WR, RB, RB, TE, W/R/T, K, DEF, BN, BN, BN, BN, IR"
week = ffbot.current_week()

# Scrape data for current and available players, and their point forecasts for each week
df = ffbot.scrape(LEAGUE)
# If playing an Individual Defensive Player (IDP) league, then scrape additional players with:
# df = ffbot.scrape(LEAGUE, is_IDP=True)

# Optional save data to CSV, and load latest data
# ffbot.save(df, week)
# df, week = ffbot.load()

# Optimize the assignment of players to positions each week to maximize remaining season discounted total points
# (points this week are worth more than points in future weeks)
#  decides which players to add and drop
#  optimization is repeated for current roster, for one player add/drop, two player add/drops, etc.
df_opt = ffbot.optimize(df, week, TEAM, POSITIONS)
print(df_opt)


def imrotate(img_path:str, degree:np.float32, interpolation='nearest'):

    if interpolation not in ['nearest','bilinear']:
        print("Unknown Interpolation. Plese Choose either 'nearest' or 'bilinear'")
        import sys
        sys.exit(1)

    import skimage.io
    import math as ma
    # check for no. of channels
    img_data = skimage.io.imread(img_path.as_posix(), as_gray=True)

    rads = degree * 22/(7*180)
    h, w = img_data.shape[0], img_data.shape[1]

    # New size of image
    newW = int(np.ceil(abs(w*np.cos(rads)) + abs(h*np.sin(rads))) + 1)
    newH = int(np.ceil(abs(w*np.sin(rads)) + abs(h*np.cos(rads))) + 1)

    x0, y0 = h/2, w/2

    def linear_interpolation(pt1, pt2, unknown):
        temp1 = pt1[1]*((pt2[0]-unknown[0])/(pt2[0]-pt1[0]))
        temp2 = pt2[1]*((unknown[0]-pt1[0])/(pt2[0]-pt1[0]))
        return temp1 + temp2

    def bilinear_interpolation(pt1, pt2, pt3, pt4, unknown):
        if pt1[0] == pt3[0]:
            return linear_interpolation((pt1[1], pt1[2]), (pt2[1], pt2[2]), (unknown[1], unknown[2]))
        if pt1[1] == pt2[1]:
            return linear_interpolation((pt1[0], pt1[2]), (pt3[0], pt3[2]), (unknown[0], unknown[2]))

        R1 = linear_interpolation((pt1[0], pt1[2]), (pt3[0], pt3[2]), (unknown[0], unknown[2]))
        R2 = linear_interpolation((pt2[0], pt2[2]), (pt4[0], pt4[2]), (unknown[0], unknown[2]))
        P = linear_interpolation((pt1[1], R1), (pt2[1], R2), (unknown[1], unknown[2]))
        return P

    # New image initialisation
    newImg = np.zeros([newH, newW])

    for i in tqdm.tqdm(range(newH)):
        for j in range(newW):

            # shifting the origin
            x = (newH/2 - i)
            y = (j - newW/2)

            # calculating new x and y co-ordinates after rotating
            xx = (x*np.cos(rads) - y*np.sin(rads))
            yy = (x*np.sin(rads) + y*np.cos(rads))

            xx = (h/2 - xx)
            yy = (yy + w/2)

            if interpolation=='bilinear':
                x, y = xx, yy
                if (x<0 or x>=h or y<0 or y>=w):
                    newImg[i][j] = 255
                else:
                    x1, x2 = ma.floor(x), ma.ceil(x)
                    y1, y2 = ma.floor(y), ma.ceil(y)

                    x1 = x1-1 if x1==h else x1
                    x2 = x2-1 if x2==h else x2
                    y1 = y1-1 if y1==w else y1
                    y2 = y2-1 if y2==w else y2

                    pt1, pt2 = (x1, y1, img_data[x1, y1]), (x1, y2, img_data[x1, y2])
                    pt3, pt4 = (x2, y1, img_data[x2, y1]), (x2, y2, img_data[x2, y2])
                    unknown = (x, y, 0)

                    if pt1[0] == pt3[0] and pt1[2] == pt2[2]:
                        newImg[i, j] = img_data[int(x), int(y)]
                    else:
                        newImg[i,j] = bilinear_interpolation(pt1, pt2, pt3, pt4, unknown)

            elif interpolation=='nearest':
                xx, yy = int(xx), int(yy)

                # checking if any of the following conditions satisfy then assigning it 255

                if (xx<0 or xx>=h or yy<0 or yy>=w):
                    newImg[i][j] = 255
                else:
                    newImg[i][j] = img_data[xx][yy]

    #plt.imshow(newImg, cmap='gray')
    return  newImg


from flask import Flask
#from werkzeug.datastructures import T #架站軟體 做route回應
app = Flask(__name__) # route 設定
from flask import request,abort #request接收訊息
from linebot import LineBotApi,WebhookHandler # LINEBOTAPI接收訊息 # handle 識別碼
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent,TextMessage,TextSendMessage
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
import numpy as np
from linebot.models import *
import tempfile
import os
## 授權
line_bot_api = LineBotApi("r7Zq64defLm6ZXPBwUUT8AS+/5Rbau+jUnOY+lcDWTx+p/b0pX94AdeSbiPrGuxMDDkDfy6m0GQcJcLNc7Y5Ie49HQh+dl8nmJytkntT52AA3XAgO83kqGrntlNFOoaInPOJD0QAqbd/E6jZFoPFtQdB04t89/1O/w1cDnyilFU=")
## channel secert
handler = WebhookHandler("cfc2857f38799f624e02148130e0706c")
static_tmp_path = os.path.join(os.path.dirname(__file__), 'static', 'tmp')
# @app.route("/",methods=["POST"]) # 接收資料 不傳密碼
# def callback(): #回覆函數
#     signature = request.headers["X-Line-Signature"] #查詢簽名
#     body = request.get_data(as_text = True) # get
#     try:
#         handler.handle(body,signature)
#     except InvalidSignatureError:
#         abort(500)
#     return "OK"

# @handler.add(MessageEvent,message= TextMessage)  # handler become router cope with textmessage
# def handle_message(event):
#     line_bot_api.reply_message(event.reply_token,TextSendMessage(text=event.message.text))
# 回覆訊息 event連接 text event所送過來的文字
# event.replt_token識別跟誰對話
# TextSendMessage(text=event.message.text)) event的message
dic = {0 : '三杯雞', 1 : '什錦炒麵',2:"咖哩雞",3:"塔香海茸",4:"大陸妹",5:"客家小炒",6:"小番茄",7:"有機小松菜",8:"有機青松菜",9:"木瓜",
        10:"柳丁",11:"棗子",12:"橘子",13:"沙茶肉片",14:"油菜",15:"洋蔥炒蛋",16:"滷蛋",17:"滷雞腿",18:"玉米炒蛋",19:"瓜仔肉",
        20:"番茄炒蛋",21:"白米飯",22:"白菜滷",23:"福山萵苣",24:"空心菜",25:"糖醋雞丁",26:"紅蘿蔔炒蛋",27:"義大利麵",28:"芥藍菜",29:"菠菜",
        30:"葡萄",31:"蒜泥白肉",32:"蒸蛋",33:"蓮霧",34:"螞蟻上樹",35:"西瓜",36:"豆芽菜",37:"關東煮",38:"青江菜",39:"香蕉",40:"香酥魚排",
        41:"馬鈴薯燉肉",42:"高麗菜",43:"鳳梨'",44:"鵝白菜",45:"鹽酥雞",46:"麥克雞塊",47:"麻婆豆腐",48:"麻油雞",49:"黑胡椒豬柳"}
model = load_model('model.h5')
def predict_label(img_path):
    i = image.load_img(img_path, target_size=(224,224))
    #i = image.img_to_array(i)/255.0
	#i = i.reshape(None,224,224,3)
    #i = np.expand_dims(i,axis=0)
    i  = np.expand_dims( i , axis = 0)
    p = model.predict(i)[0]
    top = p.argsort()[::-1][:5]
    return dic[top[0]]
@app.route("/", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']
    body = request.get_data(as_text=True)
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    return 'OK'
@handler.add(MessageEvent,message= TextMessage)  # handler become router cope with textmessage
def handle_message(event):
    message = TextSendMessage(text='哈囉你好，第一道謎題，請問某水果以屏東黑珍珠著稱，請回傳圖片解題！')
    line_bot_api.reply_message(event.reply_token,TextSendMessage(text='哈囉你好，第一道謎題，請問某水果以屏東黑珍珠著稱，請回傳圖片解題！'))
@handler.add(MessageEvent, message=ImageMessage)
def handle_message(event):

    #line_bot_api.reply_message(event.reply_token, message)
    if isinstance(event.message,ImageMessage):
        ext = "jpg"
        #line_bot_api.reply_message(event.reply_token, message)
        message_content = line_bot_api.get_message_content(event.message.id)
        with tempfile.NamedTemporaryFile(dir=static_tmp_path, prefix=ext + '-', delete=False) as tf:
            for chunk in message_content.iter_content():
                tf.write(chunk)
            tempfile_path = tf.name
        dist_path = tempfile_path + '.' + ext
        dist_name = os.path.basename(dist_path)
        os.rename(tempfile_path, dist_path)
        res = predict_label(dist_path)
        if(res=="蓮霧"):
            message =TextSendMessage(text="答對了，是蓮霧")
        else:
            message = TextSendMessage(text="答錯了，你給的是{}".format(res))
        line_bot_api.reply_message(event.reply_token, message)
    #print('-----------------')
    # if event.message.type=="image":
    #     #line_bot_api.reply_message(event.reply_token,message)
    #     res = predict_label(event.message)
    #     line_bot_api.reply_message(event.reply_token,res)
    #line_bot_api.reply_message(event.reply_token,TextSendMessage(text=event.message.text))

# @handler.add(MessageEvent, message=(ImageMessage, VideoMessage, AudioMessage))
# def handle_content_message(event):
#     if event.message.type=="image":
#         line_bot_api.reply_message(event.reply_token,"ff")

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


import torch
import torch.nn as nn
from timm.models.layers import DropPath
from model.gcn_lib.torch_edge import DenseDilatedKnnGraph
from model.gcn_lib.torch_vertex import GraphConv2d
from model.gcn_lib.torch_nn import get_act_layer
from torch.nn import Sequential as Seq
from data import ClipFramesLen

class FFN(nn.Module):
    def __init__(self, in_features, hidden_features=None, out_features=None, act='relu', drop_path=0.0):
        super().__init__()
        out_features = out_features or in_features
        hidden_features = hidden_features or in_features
        self.fc1 = nn.Sequential(
            nn.Conv2d(in_features, hidden_features, 1, stride=1, padding=0),
            nn.BatchNorm2d(hidden_features),
        )
        self.act = get_act_layer(act)
        self.fc2 = nn.Sequential(
            nn.Conv2d(hidden_features, out_features, 1, stride=1, padding=0),
            nn.BatchNorm2d(out_features),
        )
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()

    def forward(self, x):
        # shortcut = x
        x = self.fc1(x)
        x = self.act(x)
        x = self.fc2(x)
        x = self.drop_path(x)
        # x = self.drop_path(x) + shortcut
        return x

class SignalGraphConv2d(GraphConv2d):
    """
    Dynamic graph convolution layer
    """

    def __init__(self, in_channels, out_channels, kernel_size=9, dilation=1, conv='edge', act='relu',
                 norm=None, bias=True, stochastic=False, epsilon=0.0):
        super(SignalGraphConv2d, self).__init__(in_channels, out_channels, conv, act, norm, bias)
        self.dilated_knn_graph = DenseDilatedKnnGraph(kernel_size, dilation, stochastic, epsilon)

    def forward(self, x, relative_pos=None, **kwargs):
        tmp = x
        y = None
        edge_index = self.dilated_knn_graph(x, y, relative_pos)
        x = super(SignalGraphConv2d, self).forward(x, edge_index, y)
        return tmp + x

class DenoiseGraph(torch.nn.Module):
    def __init__(self, opt):
        super(DenoiseGraph, self).__init__()
        k = opt.wave_gnn_k
        act = opt.wave_gnn_act
        norm = opt.wave_gnn_norm
        bias = opt.wave_gnn_bias
        epsilon = opt.wave_gnn_epsilon
        stochastic = opt.wave_gnn_use_stochastic
        conv = opt.wave_gnn_conv
        drop_path = opt.wave_gnn_drop_path
        blocks = opt.wave_gnn_blocks
        channels = opt.wave_channels
        self.last_dim = opt.wave_last_dim

        self.n_blocks = sum(blocks)
        dpr = [x.item() for x in torch.linspace(0, drop_path, self.n_blocks)]  # stochastic depth decay rule
        num_knn = [int(x.item()) for x in torch.linspace(k, k, self.n_blocks)]  # number of knn's k
        max_dilation = max(1, 49 // max(num_knn))

        idx = 0
        self.graph_backbone = nn.ModuleList([])
        start_dim = channels[0]
        self.change_dim_layout = None
        if start_dim != self.last_dim:
            self.change_dim_layout = nn.Linear(self.last_dim, start_dim, bias=True)
        for i in range(len(blocks)):
            for j in range(blocks[i]):
                self.graph_backbone += [
                    Seq(SignalGraphConv2d(ClipFramesLen, ClipFramesLen, num_knn[idx], min(idx // 4 + 1, max_dilation),
                                          conv, act, norm, bias, stochastic, epsilon),
                        FFN(ClipFramesLen, ClipFramesLen, act=act, drop_path=dpr[idx]))]
                idx += 1

        dim = channels[0]
        self.graph_backbone = Seq(*self.graph_backbone)
        self.backbone = nn.ModuleList([])
        for id in range(1, len(channels)):
            self.backbone += [Seq(nn.Conv1d(dim, channels[id], 1, stride=1, padding=0), get_act_layer(act))]
            dim = channels[id]

        self.backbone = Seq(*self.backbone)

        self.model_init()

    def model_init(self):
        for m in self.modules():
            if isinstance(m, torch.nn.Conv2d):
                torch.nn.init.kaiming_normal_(m.weight)
                m.weight.requires_grad = True
                if m.bias is not None:
                    m.bias.data.zero_()
                    m.bias.requires_grad = True

    def forward(self, x):
        batch_size = x.shape[0]
        features_last = x.permute(0, 2, 1, 3, 4)
        features_last = features_last.reshape(batch_size, 160, self.last_dim)  # x [B, 160, self.last_dim]
        if self.change_dim_layout is not None:
            features_last = self.change_dim_layout(features_last)
        ecg = features_last.unsqueeze(3)  # [B, 160, start_dim, 1]

        for i in range(len(self.graph_backbone)):
            ecg = self.graph_backbone[i](ecg)

        ecg = ecg.squeeze(3).permute(0, 2, 1)  # x [B, start_dim, 160]
        for i in range(len(self.backbone)):
            ecg = self.backbone[i](ecg)
        # [B, 1, 160]

        ecg = ecg.squeeze(1)  # x [B, 160]
        return ecg

def denoise_graph(opt):
    model = DenoiseGraph(opt)
    return model


import feedparser
from lxml.html import fromstring
from config.config import get_software_list, save_threat_db, save_vuln
from config.config import check_saved_threats, check_saved_vulns

class CISAVulnerability:
    def __init__(self, vendor_product, description, published, cvss, cve_info):
        self.vendor_product = vendor_product
        self.description = description
        self.published = published
        self.cvss = cvss
        self.cve_info = cve_info

    def show_vulnerability_info(self):
        print("[*] Vulnerability found!")
        print("\t[-] Vendor-product: "+self.vendor_product)
        print("\t[-] Description: "+self.description)
        print("\t[-] Published: "+self.published)
        print("\t[-] Scoring: "+self.cvss)
        print("\t[-] CVE: " + self.cve_info)

class CISAICSThreat:
    def __init__(self, title, summary, published, link):
        self.title = title
        self.summary = summary
        self.published = published
        self.link = link

    def show_threat_info(self):
        print("[*] Threat found!")
        print("\t[-] Title: "+self.title)
        print("\t[-] Summary: "+self.summary)
        print("\t[-] Published: "+self.published)
        print("\t[-] Link: "+self.link)

def check_vuln_products(vulnerabibility_list):
    product_list = get_software_list()
    vuln_alert = []
    for v in vulnerabibility_list:
        for p in product_list:
            if p in v.description:
                vuln_alert.append(v)
    return vuln_alert

def check_ics_threats(threat_list):
    threats= get_software_list()
    threat_alert = []
    for t in threat_list:
        for p in threats:
            if p in t.summary:
                threat_alert.append(t)
    return threat_alert

def feed_vulnerability_reports():
    vulnerability_list = []
    rss = 'https://us-cert.cisa.gov/ncas/bulletins.xml'
    feed = feedparser.parse(rss)
    for key in feed["entries"]:
        title = key['title']
        url = key['links'][0]['href']
        published = key['published']
        summary = key['summary']
        already_stored = check_saved_vulns(url)
        if already_stored is False:
            save_vuln(url, title, published)
            doc = fromstring(summary)
            tr_elements = doc.xpath('//tr')
            for j in range(1, len(tr_elements)):
                items = tr_elements[j]
                if len(items) != 5:
                    break
                count = 0
                for t in items.iterchildren():
                    data = t.text_content().strip()
                    if count == 0:
                        vendor = data
                    elif count == 1:
                        description = data
                    elif count == 2:
                        published = data
                    elif count == 3:
                        cvss = data
                    elif count == 4:
                        info = data
                        cisa = CISAVulnerability(vendor, description, published, cvss, info)
                        vulnerability_list.append(cisa)
                    count = count + 1
    return vulnerability_list

def feed_ics_threats():
    cisa_threats = []
    rss="https://us-cert.cisa.gov/ics/advisories/advisories.xml"
    feed = feedparser.parse(rss)
    for key in feed["entries"]:
        title = key['title']
        summary = key['summary'].replace("<p>","").replace("<p>","")
        published = key['published']
        link = key['link']
        already_stored = check_saved_threats(link)
        if already_stored is False:
            save_threat_db(link, title, published)
            threat = CISAICSThreat(title, summary, published, link)
            cisa_threats.append(threat)
    return cisa_threats

def get_vulnerability_reports():
    products_wt_vulns = []
    vulnerability_list = feed_vulnerability_reports()
    if vulnerability_list is not None:
        products_wt_vulns = check_vuln_products(vulnerability_list)
        for p in products_wt_vulns:
            p.show_vulnerability_info()
    return products_wt_vulns
    return vulnerability_list

def get_ics_threats():
    threats = feed_ics_threats()
    if threats is not None:
        filtered_threats = check_ics_threats(threats)
        for t in filtered_threats:
            t.show_threat_info()
    return filtered_threats
    return threats


import os
import numpy as np
import matplotlib.pylab as plt

def get_grad_norm_from_file(fp):
    if not os.path.exists(fp):
        return -1

    with open(fp, "r") as f:
        grad_norms = []
        for line in f.readlines():
            line = line.strip()
            if 'grad_norm' in line:
                grad_norm = line.split('|')[-2]
                grad_norm = float(grad_norm)

                grad_norms.append(grad_norm)
    try:
        return sum(grad_norms) / len(grad_norms)
    except ZeroDivisionError:
        return -1

def parse_exp_dir(dir):
    sub_dirs = os.listdir(dir)
    sub_dirs = [int(x) for x in sub_dirs]
    sub_dirs.sort()
    sub_dirs = [f"{x:06d}" for x in sub_dirs]
    print(sub_dirs)

    # different iters
    grad_norm_at_iters = []
    for _sub_dir in sub_dirs:
        # from-to dir

        # different timesteps for each iter
        grad_norm_at_steps = []
        for i in range(100):
            _from = 10 * i
            _to = 10 * (i + 1) - 1

            _fp = f"{dir}/{_sub_dir}/from-to-{_from}-{_to}/log.txt"
            grad_norm = get_grad_norm_from_file(_fp)
            # print(grad_norm)
            if grad_norm > 0:
                grad_norm_at_steps.append(grad_norm)

        grad_norm_at_iters.append(grad_norm_at_steps)

    return grad_norm_at_iters

def main():
    # x = get_grad_norm_from_file("/home/v-tiahang/code_base/others/analyze_gradnorm/data/28/nov11_imnet_beit_base_layer12_lr1e-4_099_099_img64_pred_x0_loss-eps_fp16_bs8x64/070000/from-to-150-159/log.txt")
    # print(x)

    exp_list = [
        "nov3_imnet_beit_base_layer12_lr1e-4_099_099_img64_pred_noise_fp16_bs8x64",
        "nov11_imnet_beit_base_layer12_lr1e-4_099_099_img64_pred_x0_loss-eps_fp16_bs8x64",
        "nov15_imnet_beit_base_layer12_lr1e-4_099_099_img64_pred_x0__min_snr_1__fp16_bs8x64",
        "nov15_imnet_beit_base_layer12_lr1e-4_099_099_img64_pred_x0__min_snr_5__fp16_bs8x64",
        "nov23_imnet_beit_base_layer12_lr1e-4_099_099_img64_pred_noise__min_snr_1__fp16_bs8x64",
        "nov23_imnet_beit_base_layer12_lr1e-4_099_099_img64_pred_noise__min_snr_5__fp16_bs8x64",
    ]

    for exp in exp_list:
        result = parse_exp_dir(f"data/28/{exp}")
        # import pdb; pdb.set_trace()

        for iter, norms_at_iter in enumerate(result):
            plt.plot(norms_at_iter, label=f"{(iter + 1)*10000}")

        plt.legend()
        plt.savefig(f"{exp}.png")

        plt.close(); plt.clf()
        # import pdb; pdb.set_trace()

if __name__ == '__main__':
    main()