"""
-*- coding: utf-8 -*-
@Time : 2021/10/25 下午 7:10
@Author : sunguoqi
@Website : https://sunguoqi.com
@Github: https://github.com/sun0225SUN
"""

from osgeo import gdal_array as gd
import operator
from functools import reduce

def histogram(a, bins=list(range(256))):
    fa = a.flat
    n = gd.numpy.searchsorted(gd.numpy.sort(fa), bins)
    n = gd.numpy.concatenate([n, [len(fa)]])
    hist = n[1:] - n[:-1]
    return hist

def stretch(a):
    hist = histogram(a)
    lut = []
    for b in range(0, len(hist), 256):
        step = reduce(operator.add, hist[b:b + 256]) / 255
        n = 0
        for i in range(256):
            lut.append(n / step)
            n += hist[i + b]
    gd.numpy.take(lut, a, out=a)
    return a

# NDVI
source = "./ndvi.tif"
target = "ndvi_color.tif"
ndvi = gd.LoadFile(source).astype(gd.numpy.uint8)
# NDVI
ndvi = stretch(ndvi)
# NDVI 3
rgb = gd.numpy.zeros((3, len(ndvi), len(ndvi[0])), gd.numpy.uint8)
# NDVI
classes = [58, 73, 110, 147, 184, 220, 255]

# lut RGB
lut = [[120, 69, 25], [255, 178, 74], [255, 237, 166], [173, 232, 94], [135, 181, 64], [3, 156, 0], [1, 100, 0]]

start = 1

for i in range(len(classes)):
    mask = gd.numpy.logical_and(start <= ndvi, ndvi <= classes[i])
    for j in range(len(lut[i])):
        rgb[j] = gd.numpy.choose(mask, (rgb[j], lut[i][j]))
        start = classes[i] + 1

# NDVI geotiff
output = gd.SaveArray(rgb, target, format="GTiff", prototype=source)
output = None
print('分类完成!')


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

N_HOURS = 4

df = pd.read_csv(r'C:\Users\LUCA SANDRI\Desktop\Tesi\07_Risultati\FF_genopt_SUBDAILY.csv')
print(len(df))

df.columns = ['Date/Time', 'Outdoor Temp', 'Diffuse Rad', 'Direct Rad', 'Occupants',
       'EC state', 'nhrs_occ', 'nhrs_sim',
        'UDI_f', 'UDI_s', 'UDI_a', 'UDI_e',                                 #a autonomous --> Only solar radiation,  e excess,   f fell short,   s supplementary --> lighting required  a+s= USEFULL
        'DGPoutputcost', 'DGPoutputcostocc', 'DGPcost', # ???
       'ILLoutput', 'Ep heat', 'Ep cool', 'Ep light', #ILLoutput
       'Termination', 'Warmup',
       'Primary energy', 'PV energy opt',
        'DayOfWeek', 'TimeOfDay', 'Zone Mean Air Temperature']
outdoor = df['Outdoor Temp']
radiation = df['Diffuse Rad'] + df['Direct Rad']

total_steps = len(df.index)
forecast_rad = []
forecast_temp = []
for k in list(range(total_steps)):
    T_FORE = outdoor[k + 1:k + 1 + N_HOURS].sum()
    forecast_temp.append(T_FORE)
    I_FORE = radiation[k + 1:k + 1 + N_HOURS].sum()
    forecast_rad.append(I_FORE)

weather = pd.DataFrame({'Outdoor Temp':outdoor,'Forecast Temp':forecast_temp,
                        'Radiation':radiation,'Forecast Rad':forecast_rad})
print(weather[8340:])

path=r'C:\Users\LUCA SANDRI\PycharmProjects\THMcontrol\Utility'
weather.to_csv(os.path.join(path,r'weather.csv'),header=True, encoding = 'utf8', index=False)

forecast_rad = weather['Forecast Rad']
forecast_temp = weather['Forecast Temp']
data = np.array(forecast_temp)
T_33 = np.nanpercentile(data, 33)
T_66 = np.nanpercentile(data, 66)
data = np.array(forecast_rad[forecast_rad>0])
I_33 = np.nanpercentile(data, 33)
I_66 = np.nanpercentile(data, 66)
max_temp = forecast_temp.max()
min_temp = forecast_temp.min()
max_rad = forecast_rad.max()
min_rad = forecast_rad.min()
print('Temperature: min = {}, 33 p = {}, 66 p = {}, max = {}'.format(min_temp, T_33, T_66, max_temp))
print('Radiation: min = {}, 33 p = {}, 66 p = {}, max = {}'.format(min_rad, I_33, I_66, max_rad))

plt.close()

constant_x = [0, len(forecast_temp)]
max_fore = max_temp
min_fore = min_temp
fig1, ax1 = plt.subplots()
ax1.set_xlabel("Time step [hours]", size=24)
ax1.set_ylabel("Cumulative temperature of the next {} steps [°C]".format(N_HOURS), size=24)
ax1.set_title("Temperature forecast set", size=24)
ax1.tick_params(labelsize=15)
ax1.scatter(forecast_temp.index,forecast_temp,s=1)
ax1.plot(constant_x, [max_fore, max_fore], color='red', label = "Max")
ax1.plot(constant_x, [min_fore,min_fore], color='red', label = "Min")
ax1.plot(constant_x, [T_33,T_33], color='blue', label = "33 percentile")
ax1.plot(constant_x, [T_66,T_66], color='blue', label = "66 percentile")
plt.legend(loc=1, fontsize=15)

#label = "curve 2", linestyle=":"

constant_x = [0, len(forecast_rad)]
max_fore = max_rad
min_fore = min_rad
fig2, ax2 = plt.subplots()
ax2.set_xlabel("Time step [hours]", size=24)
ax2.set_ylabel("Total radiation of the next {} steps [W]".format(N_HOURS), size=24)
ax2.set_title("Radiation forecast set", size=24)
ax2.tick_params(labelsize=15)
ax2.scatter(forecast_rad.index,forecast_rad,s=1)
ax2.plot(constant_x, [max_fore,max_fore], color='red', label = "Max")
ax2.plot(constant_x, [min_fore,min_fore], color='red', label = "Min")
ax2.plot(constant_x, [I_33,I_33], color='blue', label = "33 percentile")
ax2.plot(constant_x, [I_66,I_66], color='blue', label = "66 percentile")
plt.legend(loc=1, fontsize=15)
plt.yscale('log')

#OPTIMUM MONTHLY INDOOR OPERATIVE TEMPERATURE
df['Month'] = 0                                             #Create Month column
df['DayOfYear'] = 0                                        #Create Day Of the Year column
for i in df.index:
    df.loc[i, 'DayOfYear'] = df['Date/Time'].iloc[i].split()[0]
    df.loc[i,'Month'] = int(df.loc[i, 'DayOfYear'].split('/')[0])
month_list = list(df.Month.unique())
optimum_temp = []
for i in month_list:
    copy_df = df[df['Month']==i]
    mean_temp = copy_df['Outdoor Temp'].mean()
    optimum_temp.append(0.31 * mean_temp + 17.8)
opt_mon_temp = pd.DataFrame({'Month':month_list,'Optimum temperature':optimum_temp})
print(opt_mon_temp)

comparison = df[['Month','Outdoor Temp']]
comparison['Opt temp'] = 0
for i in month_list:
    opt_temp = opt_mon_temp.loc[opt_mon_temp['Month'] == i,
                                'Optimum temperature'].iloc[0]
    comparison.loc[comparison['Month'] == i, 'Opt temp'] = opt_temp

monthly_limit_temp = comparison['Opt temp'] + 2.5

daily_limit_temp = 0.31 * df['Outdoor Temp'] + 17.8 + 2.5

path=r'C:\Users\LUCA SANDRI\PycharmProjects\THMcontrol\Utility'
monthly_limit_temp.to_csv(os.path.join(path,r'monthly_limit_temp.csv'),header=True, encoding = 'utf8', index=False)
daily_limit_temp.to_csv(os.path.join(path,r'daily_limit_temp.csv'),header=True, encoding = 'utf8', index=False)
print(monthly_limit_temp)

fig, ax = plt.subplots()
ax.scatter(comparison.index, comparison['Opt temp'], s=20, c='green')
ax.scatter(monthly_limit_temp.index, monthly_limit_temp, s=20, c='red')
df['Outdoor Temp'].plot()
plt.show()


from flask import Flask, request, jsonify
import sqlite3
from flask_cors import CORS
import numpy as np

app = Flask(__name__)
CORS(app)

def save_var_list(list_name,input_label):
    conn = sqlite3.connect('database.db')
    cursor = conn.cursor()
    # store values of label values
    cursor.execute('''CREATE TABLE IF NOT EXISTS label_values (
                      id INTEGER PRIMARY KEY,
                      list_name TEXT,
                      strings TEXT)''')
    strings_str = ';'.join(input_label)  # Convert the list of strings to a semicolon-separated string
    cursor.execute('''INSERT INTO label_values (list_name, strings)
                      VALUES (?, ?)''', (list_name, strings_str))
    conn.commit()

def generate_zpl():
    start = "^XA"
    end = "^XZ"
    label_pos = "^FT"
    label_text_tag = "^FD"

    change_font = "^CFA,30"
    start_of_field ="^FO"
    end_of_field = "^FS"

    data = request.get_json()
    print("****************************************",data)
    is_barcode = data['is_barcode']
    is_qrcode = data['is_qrcode']

    input_text = data['label_text']
    input_label = data['label_values']

    company_name = data['company_name']
    address = data['company_address']

    line_co_ordinates = data['line_co_ordinates']

    selected_element_co_text = data['selected_element_co_text']
    selected_element_co_label = data['selected_element_co_label']

    rect_co_ordinates = data['rect_co_ordinates']

    save_var_list("label1",input_label)

    x_start_label = 80
    y_start_label = 130

    x_start_value = 350
    y_start_value = 130

    y_diff_label = 40
    y_diff_value = 40

    head = start_of_field+str(330) +","+str(20)+label_text_tag+company_name+end_of_field

    code = []
    code.append(start)
    code.append("^CF0,60")
    code.append(head)
    code.append("^CF0,40")
    address = start_of_field+str(360) +","+str(80)+label_text_tag+address+end_of_field

    code.append(address)
    code.append("^CFA,30")

    input_text_x = []
    input_text_y = []
    input_label_x  = []
    input_label_y = []

    for item in selected_element_co_text:
        if(item is not None):
            #print("***************************************************",item['x1'], item['y1'])
            input_text_x.append(item['x1'])
            input_text_y.append(item['y1'])

    for item in selected_element_co_label:
        if(item is not None):
            #print("********************************************************",item['x1'], item['y1'])
            input_label_x.append(item['x1'])
            input_label_y.append(item['y1'])

    line_coordinates_x1 = []
    line_coordinates_y1 = []
    line_coordinates_x2 = []
    line_coordinates_y2 = []

    for item in line_co_ordinates:
        if(item is not None):
            line_coordinates_x1.append(item['x1'])
            line_coordinates_y1.append(item['y1'])
            line_coordinates_x2.append(item['x2'])
            line_coordinates_y2.append(item['y2'])

    for num in range(0, len(input_text)):
        print("_____________________________",input_text[num])
        print("******************************",input_label[num])

        #y_start_label = y_start_label+y_diff_label
        #y_start_value = y_start_value + y_diff_value

        #value = input_label[num]

        #print("--------------------------------------------------------------------------------",num)
        total_var =start_of_field +str(input_text_x[num])+","+str(input_text_y[num])+label_text_tag+input_text[num]+end_of_field +start_of_field +str(input_label_x[num])+","+str(input_label_y[num])+label_text_tag+ input_label[num] +end_of_field
        #print("-----------------------------  val in for loop----------------------------",total_var)
        code.append(total_var)

    items = ""
    #data for barcode
    for num in range(0, len(input_text)):
        item = input_text[num] + ":"+ input_label[num]
        items+= " "+item

    # y diff = < 5  ----> horizontal line   // y are same
    # x diff = <5 -------------> vertical line // x are same

    for num in range(0,len(line_coordinates_x1)):
        if((line_coordinates_x2[num] - line_coordinates_x1[num]) <= 10):
            # distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
            distance = math.sqrt((line_coordinates_x2[num] - line_coordinates_x1[num])**2 + (line_coordinates_y2[num]-line_coordinates_y1[num])**2)
            distance = "1," + str(distance)
            line = "^FO" + str(line_coordinates_x1[num]) + "," + str(line_coordinates_y1[num]) + "^GB"+ distance + ",1" +"^FS"
            code.append(line)
        else:
            distance = math.sqrt((line_coordinates_x2[num] - line_coordinates_x1[num])**2 + (line_coordinates_y2[num]-line_coordinates_y1[num])**2)
            distance = str(distance) + ",1"
            line = "^FO" + str(line_coordinates_x1[num]) + "," + str(line_coordinates_y1[num]) + "^GB"+ distance + ",1" +"^FS"
            code.append(line)

    line_coordinates_rect_x1 = []
    line_coordinates_rect_x2 = []
    line_coordinates_rect_y1 = []
    line_coordinates_rect_y2 = []

    for item in rect_co_ordinates:
        if(item is not None):
            print(item)
            line_coordinates_rect_x1.append(item['x1'])
            line_coordinates_rect_x2.append(item['x2'])
            line_coordinates_rect_y1.append(item['y1'])
            line_coordinates_rect_y2.append(item['y2'])

    print("line coordinates rect  x1 ",line_coordinates_rect_x1)
    print("line coordinates rect  x2 ",line_coordinates_rect_x2)
    print("line coordinates rect  y1 ",line_coordinates_rect_y1)
    print("line coordinates rect  y2 ",line_coordinates_rect_y2)

    for num in range(0,len(line_coordinates_rect_x1)):
        rectangle = "^FO" + str(line_coordinates_rect_x1[num]) + "," + str(line_coordinates_rect_y1[num]) + "^GB" + str(line_coordinates_rect_x2[num]) + "," + str(line_coordinates_rect_y2[num]) + "^FS"
        print("******************  rectangle *********************** ",rectangle)
        code.append(rectangle)

    if is_barcode == True:
        #zpl with barcode
        barcode =  "^FO"+str(x_start_label)+","+str(y_start_label+y_diff_value)+"^BY3" + "^BCN,100,Y,N,N" + items +"^FS"
        code.append(barcode)
    elif is_qrcode == True:
        barcode =  "^FO"+str(x_start_label)+","+str(y_start_label+y_diff_value)+"^BQN,2,4 ^FDMM"+items +"^FS"
        code.append(barcode)
    else:
        #zpl without qr barcode
        pass

    code.append(end)
    #total = start + change_font + code +end

    delimiter = ','  # Delimiter to be used between elements

    result_string = delimiter.join(code)
    print(result_string)

    f = open("label1.zpl", "w")
    f.write(result_string)
    f.close()

    return{"success":True}

def select_labels():
    """
    Query all rows in the tasks table
    :param conn: the Connection object
    :return:
    """
    conn = sqlite3.connect('database.db')
    print("Opened database successfully")
    cur = conn.cursor()
    cur.execute("SELECT * FROM labels_table")

    rows = cur.fetchall()

    print("rows",rows)

    conn.close()

    # Convert the results to a list of dictionaries
    columns = [col[0] for col in cur.description]
    list_of_dicts = [dict(zip(columns, row)) for row in rows]

    # Print the list of dictionaries
    for item in list_of_dicts:
        print(item)

    return {"success": True,"data":list_of_dicts}
    #return jsonify({'data':rows}), 200

def select_units():
    """
    Query all rows in the tasks table
    :param conn: the Connection object
    :return:
    """
    conn = sqlite3.connect('database.db')
    print("Opened database successfully")
    cur = conn.cursor()
    cur.execute("SELECT name FROM units_table")

    rows = cur.fetchall()

    columns = [col[0] for col in cur.description]
    list_of_dicts = [dict(zip(columns, row)) for row in rows]

    conn.close()

    # Print the list of dictionaries
    for item in list_of_dicts:
        print(item)

    return {"success": True,"data":list_of_dicts}

def select_labels():
    """
    Query all rows in the tasks table
    :param conn: the Connection object
    :return:
    """
    conn = sqlite3.connect('database.db')
    print("Opened database successfully")
    cur = conn.cursor()
    cur.execute("SELECT * FROM labels_table")

    rows = cur.fetchall()

    print("rows",rows)

    conn.close()

    # Convert the results to a list of dictionaries
    columns = [col[0] for col in cur.description]
    list_of_dicts = [dict(zip(columns, row)) for row in rows]

    # Print the list of dictionaries
    for item in list_of_dicts:
        print(item)

    return {"success": True,"data":list_of_dicts}
    #return jsonify({'data':rows}), 200

def select_units():
    """
    Query all rows in the tasks table
    :param conn: the Connection object
    :return:
    """
    conn = sqlite3.connect('database.db')
    print("Opened database successfully")
    cur = conn.cursor()
    cur.execute("SELECT name FROM units_table")

    rows = cur.fetchall()

    columns = [col[0] for col in cur.description]
    list_of_dicts = [dict(zip(columns, row)) for row in rows]

    conn.close()

    # Print the list of dictionaries
    for item in list_of_dicts:
        print(item)

    return {"success": True,"data":list_of_dicts}

def select_date_time():
    """
    Query all rows in the tasks table
    :param conn: the Connection object
    :return:
    """
    conn = sqlite3.connect('database.db')
    print("Opened database successfully")
    cur = conn.cursor()
    cur.execute("SELECT date FROM date_time_table")

    rows = cur.fetchall()

    columns = [col[0] for col in cur.description]
    list_of_dicts = [dict(zip(columns, row)) for row in rows]

    conn.close()

    # Print the list of dictionaries
    for item in list_of_dicts:
        print(item)

    return {"success": True,"data":list_of_dicts}


from scipy.io import savemat

mdict = {'Config': 'parallel',
         'timeStep': 0.4,
         'BFIndexes': [0, 8, 1, 9],
         'Antennas': [2, 6, 7, 8],
         'arr00' : arr00,
         'arr01' : arr01,
         'arr08' : arr08,
         'arr09' : arr09,
         'arr11' : arr11,
         'arr18' : arr18,
         'arr19' : arr19,
         'arr88' : arr88,
         'arr89' : arr89,
         'arr99' : arr99}
filename = 'DRAO_CW_3700KHZ'
savemat(filename, mdict, do_compression=True)


import pandas as pd
import numpy as np
import MyMod
from flask import Flask
import os
from bs4 import BeautifulSoup
from selenium import webdriver
import requests
import re
import time
import random
import configparser
from bs4 import BeautifulSoup
from flask import Flask, request, abort
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import *

app = Flask(__name__)

config = configparser.ConfigParser()
config.read("config.ini")
line_bot_api = LineBotApi(config['line_bot']['Channel_Access_Token'])
handler = WebhookHandler(config['line_bot']['Channel_Secret'])

@app.route('/')
def index():
    message = """Hello, My Friends!"""
    return message

@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    # print("body:",body)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'ok'

@app.route('/op')
def op():
    table=MyMod.opweek()

    return table.to_html()

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    print("event.reply_token:", event.reply_token)
    print("event.message.text:", event.message.text)

#簡單訊息測試
    if event.message.text == "hello":
        list=['嗶——',"歡迎使用選擇權自動裝置","本裝置提供的資訊是從網頁即時抓取，請耐心等候","使用服務請輸入「服務」"]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text='\n\n'.join(list)))
    if event.message.text == "嗨":
        list=['嗶——',"歡迎使用選擇權自動裝置","本裝置提供的資訊是從網頁即時抓取，請耐心等候","使用服務請輸入「服務」"]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text='\n\n'.join(list)))
    if event.message.text == "你好":
        list=['嗶——',"歡迎使用選擇權自動裝置","本裝置提供的資訊是從網頁即時抓取，請耐心等候","使用服務請輸入「服務」"]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text='\n\n'.join(list)))

#服務選單
    if event.message.text == "服務":
        buttons_template = TemplateSendMessage(
            alt_text='服務選單',
            template=ButtonsTemplate(
                title='選擇服務',
                text='來賓請選擇',
                thumbnail_image_url='https://i.imgur.com/Hn2nJJN.jpg',
                actions=[
                    MessageTemplateAction(
                        label='週選擇權策略所需金額計算',
                        text='週選擇權策略所需金額計算'
                    ),
                    MessageTemplateAction(
                        label='月選擇權策略所需金額計算',
                        text='月選擇權策略所需金額計算'
                    ),
                    URITemplateAction(
                        label='選擇權不太即時報價表',
                        uri='https://rocky-beyond-10519.herokuapp.com/op'
                    ),

                    MessageTemplateAction(
                        label='淨化心靈的聲音',
                        text='播放'
                    )
                ]
            )
        )
        line_bot_api.reply_message(event.reply_token, buttons_template)

    if event.message.text == "播放":
        line_bot_api.reply_message(
            event.reply_token,
            AudioSendMessage(
            original_content_url='https://drive.google.com/uc?export=download&id=1e2J4zbWdTnMyAr0qmfTMATzzhq7W28Sb',
            duration=10000))

    if event.message.text == "來個每日心靈小語":
        content=MyMod.good_word()
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=content))

    if event.message.text == "爬蟲爬起來爬起來":
        content=MyMod.good_word()
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text='https://rocky-beyond-10519.herokuapp.com/op'))

#週選策略金額計算

    if event.message.text == "週選擇權策略所需金額計算":
        buttons_template = TemplateSendMessage(
            alt_text='週選擇權策略所需金額計算',
            template=ButtonsTemplate(
                title='週選擇權策略所需金額計算',
                text='來賓請選擇',
                thumbnail_image_url='https://i.imgur.com/Hn2nJJN.jpg',
                actions=[
                    MessageTemplateAction(
                        label='跨式策略',
                        text='買入週選價平跨式'
                    ),
                    MessageTemplateAction(
                        label='勒式勿賭',
                        text='買入週選價平上下兩檔勒式'
                    ),
                    MessageTemplateAction(
                        label='多頭價差',
                        text='買入週選多頭價差，價平上下兩檔'
                    ),
                    MessageTemplateAction(
                        label='空頭價差',
                        text='買入週選空頭價差，價平上下兩檔'
                    )
                ]
            )
        )
        line_bot_api.reply_message(event.reply_token, buttons_template)

    if event.message.text == "買入週選多頭價差，價平上下兩檔":

        df=MyMod.opweek()
        content=MyMod.bullish_spread(df)
        a=['買入Call履約價為',str(content[0]),'\n\n',
           '權利金成本為',str(content[1]),'\n\n',
           '賣出Call履約價為',str(content[2]),'\n\n',
           '權利金收入為',str(content[3]),'\n\n',
           '所需保證金為',str(content[4])]

        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

    if event.message.text == "買入週選空頭價差，價平上下兩檔":

        df=MyMod.opweek()
        content=MyMod.bearish_spread(df)
        a=['買入Call履約價為',str(content[0]),'\n\n',
           '權利金成本為',str(content[1]),'\n\n',
           '賣出Call履約價為',str(content[2]),'\n\n',
           '權利金收入為',str(content[3]),'\n\n',
           '所需保證金為',str(content[4])]

        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

    if event.message.text == "買入週選價平跨式":

        df=MyMod.opweek()
        content=MyMod.triangle(df)
        a=['權利金成本為',str(content)]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

    if event.message.text == "買入週選價平上下兩檔勒式":

        df=MyMod.opweek()
        content=MyMod.square(df)
        a=['權利金成本為',str(content)]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

#月選策略金額計算

    if event.message.text == "月選擇權策略所需金額計算":
        buttons_template = TemplateSendMessage(
            alt_text='月選擇權策略所需金額計算',
            template=ButtonsTemplate(
                title='月選擇權策略所需金額計算',
                text='來賓請選擇',
                thumbnail_image_url='https://i.imgur.com/Hn2nJJN.jpg',
                actions=[
                    MessageTemplateAction(
                        label='跨式策略',
                        text='買入月選價平跨式'
                    ),
                    MessageTemplateAction(
                        label='勒式勿賭',
                        text='買入月選價平上下兩檔勒式'
                    ),
                    MessageTemplateAction(
                        label='多頭價差',
                        text='買入月選多頭價差，價平上下兩檔'
                    ),
                    MessageTemplateAction(
                        label='空頭價差',
                        text='買入月選空頭價差，價平上下兩檔'
                    )
                ]
            )
        )
        line_bot_api.reply_message(event.reply_token, buttons_template)

    if event.message.text == "買入月選多頭價差，價平上下兩檔":

        df=MyMod.opmonth()
        content=MyMod.bullish_spread(df)
        a=['買入Call履約價為',str(content[0]),'\n\n',
           '權利金成本為',str(content[1]),'\n\n',
           '賣出Call履約價為',str(content[2]),'\n\n',
           '權利金收入為',str(content[3]),'\n\n',
           '所需保證金為',str(content[4])]

        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

    if event.message.text == "買入月選空頭價差，價平上下兩檔":

        df=MyMod.opmonth()
        content=MyMod.bearish_spread(df)
        a=['買入Call履約價為',str(content[0]),'\n\n',
           '權利金成本為',str(content[1]),'\n\n',
           '賣出Call履約價為',str(content[2]),'\n\n',
           '權利金收入為',str(content[3]),'\n\n',
           '所需保證金為',str(content[4])]

        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

    if event.message.text == "買入月選價平跨式":

        df=MyMod.opmonth()
        content=MyMod.triangle(df)
        a=['權利金成本為',str(content)]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

    if event.message.text == "買入月選價平勒式":

        df=MyMod.opmonth()
        content=MyMod.square(df)
        a=['權利金成本為',str(content)]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text="".join(a)))

    return 0

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


from flask import Flask, jsonify, request, redirect
from flask_restful import Resource, Api, reqparse
from flasgger import Swagger
from flasgger.utils import swag_from, validate
from jsonschema import ValidationError
import json
from pathlib import Path
import requests
import os
import subprocess
import time
import logging
from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"/*": {"origins": "*"}})
swagger = Swagger(app)

@app.route ('/')
def root():
    return redirect("/apidocs", code=302)
@app.route('/app', methods=['GET', 'POST', 'DELETE'])
@swag_from('app.yml')
def config():
    result_data = request.get_data()
    method = request.method
    print(result_data)
    print(method)

    if method == 'GET':
      print("received get")
      # perform get of unit config
      # list out apps and ports
      message = {"message": "GET RECEIVED"}
      #return jsonify(message)
      url = "http://127.0.0.1:8888/config/"
      logging.info(url)
      complete_config = requests.get(url, headers={'Accept': 'application/json'})
      with open("/tmp/foo", mode='wb') as localfile:
          localfile.write(complete_config.content)
      logging.info(complete_config)
      return (complete_config.content)

    if method == 'DELETE':
      print("received delete")
      # send delete for listener then the app
      # get all listeners and search for app

      message = {"message": "DELETE RECEIVED"}
      return jsonify(message)
    # This is the POST which should really be a function in its own right that just handles different variables and selects different templates based on the inputs.
    if method == 'POST':
      data = request.get_json(force=True)
      name = data['name']
      port = data['port']
      w_dir = data['directory']
      language = data['language']

      logging.basicConfig(filename='/tmp/tetsuo.log', encoding='utf-8', level=logging.DEBUG)
      # if we are njs or python or language we select a different template and modify if accordingly.
      # probably good to do functions here that can just have info passed to them.
      if language == 'node':
        f = open('unit-configs/node-template')

        data = json.load(f)

        data['applications'][name] = data['applications'].pop('node')
        data['listeners']={ "*:" + port : { "pass": "applications/" + name} }
        data['applications'][name]['working_directory']=w_dir
        logging.info("**************************************")
        logging.info(data['listeners'])
        logging.info(data['applications'][name]['working_directory'])
        logging.info(data)
        isExist = os.path.exists(w_dir)
        if isExist == False:
          print(isExist)
          message = {"ERROR": "Directory does not exist"}
          return jsonify(message)
        else:
          result = subprocess.run(['/usr/bin/npm', 'install'], capture_output=True, cwd=w_dir)
          logging.info(result)
          unit_module = subprocess.run(['/usr/bin/npm', 'install', 'unit-http'], capture_output=True, cwd=w_dir)
          logging.info(unit_module)

        # update the application component
        url = "http://127.0.0.1:8888/config/applications/" + name
        app_r = requests.put(url, json=data['applications'][name])
        logging.info(data['applications'][name])
        logging.info(app_r.text)
        #time.sleep(15)

        # update the listener
        url = "http://127.0.0.1:8888/config/listeners/" + "*:" + port
        logging.info(url)
        listener_r = requests.put(url, json=data['listeners']['*:' + port])
        logging.info(listener_r.text)
        logging.info(app_r.text)
        #return (app_r.content, listener_r.content)
        return (app_r.content)
      # Select python as a language
      if language == 'python':
        f = open('unit-configs/python-template')

        data = json.load(f)
        data['applications'][name] = data['applications'].pop(language)
        data['listeners']={ "*:" + port : { "pass": "applications/" + name} }
        data['applications'][name]['working_directory']=w_dir
        data['applications'][name]['path']=w_dir

        # update the application component
        url = "http://127.0.0.1:8888/config/applications/" + name
        app_r = requests.put(url, json=data['applications'][name])
        logging.info(data)
        logging.info(app_r.text)

        # update the listener
        url = "http://127.0.0.1:8888/config/listeners/" + "*:" + port
        logging.info(url)
        listener_r = requests.put(url, json=data['listeners']['*:' + port])
        logging.info(listener_r.text)
        logging.info(app_r.text)
        return (app_r.content)

@app.route('/info', methods=['GET'])
@swag_from('info.yml')
def info():
    msg = 'Tetsuo application deployment API'
    api_ver = '1.0'

    return jsonify(status=msg, version=api_ver)

if __name__ == "__main__":
  app.run(host='0.0.0.0')


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

"""
redis async操作接口
    * Redis连接池
    - Redis消息发布
    - Redis消息订阅

Author: huangtao
Date:   2017/05/08
Update: None
"""

import aioredis
from tbag.utils import log as logger

__all__ = ('initRedisPool', 'RedisDBBase')

REDIS_CONN_POOL = None  # redis连接池

async def initRedisPool(host='redis://127.0.0.1:6379', db=None):
    """ 初始化连接池
    """
    global REDIS_CONN_POOL
    REDIS_CONN_POOL = await aioredis.create_redis_pool(host, db=db, encoding='utf-8')
    logger.info('create redis pool success.')

class RedisDBBase:
    """ redis db基类
    """

    async def exec_cmd(self, *args, **kwargs):
        """ 执行命令
        """
        result = await REDIS_CONN_POOL.execute(*args, **kwargs)
        logger.debug('cmd:', *args, 'result:', result, caller=self)
        return result

#import asyncio
#from tornado.ioloop import IOLoop
#
# class RedisDBBase:
#     """ redis连接
#     """
#
#     def __init__(self, host='redis://127.0.0.1:6379', channel='test'):
#         self.pool = None    # 连接池
#         self.pub_conn = None    # publish连接
#         self.host = host
#         self.channel = channel
#
#     async def start(self):
#         await self._init_pool()
#         await self._init_publish()
#         await self._init_subscribe()
#
#     async def _init_pool(self):
#         """ 初始化连接池
#         """
#         self.pool = await aioredis.create_redis_pool(self.host, encoding='utf-8')
#         logger.info('create redis pool success.', caller=self)
#
#     async def _init_publish(self):
#         """ 初始化事件发布
#         """
#         self.pub_conn = await aioredis.create_redis(self.host)
#         logger.info('create redis publish channel success. channel:', self.channel, caller=self)
#
#     async def _init_subscribe(self):
#         """ 初始化订阅连接
#         """
#         sub = await aioredis.create_redis(self.host)
#         channel, = await sub.subscribe(self.channel)
#         await asyncio.ensure_future(self.async_reader(channel))
#         logger.info('subscribe channel success. channel:', self.channel, caller=self)
#
#     async def exec_redis_cmd(self, *args):
#         logger.debug('cmd:', *args, caller=self)
#         result = await self.pool.execute(*args)
#         return result
#
#     async def publish(self, content):
#         data = json.dumps(content)
#         await self.pub_conn.execute('PUBLISH', self.channel, data)
#         # logger.debug('content:', content, caller=self)
#
#     async def async_reader(self, channel):
#         while await channel.wait_message():
#             msg = await channel.get(encoding='utf-8')
#             data = json.loads(msg)
#             IOLoop.current().add_callback(WebsocketHandler.push_message, data)
#             # logger.debug('receive data:', data, caller=self)
#
#
# redis_srv = RedisDBBase()
# ioloop.run_until_complete(redis_srv.start())
#


"""
https://github.com/LevinJ/SSD_tensorflow_VOC
training gitproject

"""

import numpy as np
import xml.etree.ElementTree as ET
from tensorflow.keras.utils import Sequence
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import cv2
from utils.utils import imshow

voc_path = 'data/dataset/VOCdevkit/'

voc_2012_image_folder = 'VOC2012/JPEGImages/'
voc_2012_annot_folder = 'VOC2012/Annotations/'
voc_2012_train_image_folder = 'VOC2012/ImageSets/Main/train.txt'
voc_2012_valid_image_folder = 'VOC2012/ImageSets/Main/val.txt'

voc_2007_image_folder = 'VOC2007/JPEGImages/'
voc_2007_annot_folder = 'VOC2007/Annotations/'
voc_2007_train_image_folder = 'VOC2007/ImageSets/Main/train.txt'
voc_2007_valid_image_folder = 'VOC2007/ImageSets/Main/val.txt'
voc_2007_test_image_folder = 'VOC2007/ImageSets/Main/test.txt'

voc_class = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle',
'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog',
'horse', 'motorbike', 'person', 'pottedplant', 'sheep',
'sofa', 'train', 'tvmonitor']

voc_class_key = {key:item for item, key in enumerate(voc_class)}
voc_class_idx = np.zeros((len(voc_class)))

VOC_2007 = 0
VOC_2012 = 1
VOC_ALL  = 2

BATCH_SIZE = 4
NUM_CLASSES = 20
EPOCHS = 1
DATASET = "."
INPUT_DIM = (227, 227, 3)

config = {
    'dataset': 'voc',
    'data_mode': 'none',
    'batch_size': BATCH_SIZE,
    'img_h': INPUT_DIM[0],
    'img_w': INPUT_DIM[1],
    'img_c': INPUT_DIM[2],
    'num_class': NUM_CLASSES,
    'epochs': EPOCHS,
    'shuffle': 1,
    'do_augment': 0
}

class VOC2007(object):
    image_folder = voc_2007_image_folder
    annot_folder = voc_2007_annot_folder
    train_image_folder = voc_2007_train_image_folder
    valid_image_folder = voc_2007_valid_image_folder
    test_image_folder  = voc_2007_test_image_folder
    trainval_img_folder = [train_image_folder, valid_image_folder]
    test_img_folder = [test_image_folder]

class VOC2012(object):
    image_folder = voc_2012_image_folder
    annot_folder = voc_2012_annot_folder
    train_image_folder = voc_2012_train_image_folder
    valid_image_folder = voc_2012_valid_image_folder
    trainval_img_folder = [ train_image_folder, valid_image_folder ]

class VOC(object):

    datagen = ImageDataGenerator(
                featurewise_center=False,
                samplewise_center=False,
                featurewise_std_normalization=False,
                samplewise_std_normalization=False,
                zca_whitening=False,
                zca_epsilon=1e-6,
                rotation_range=20,
                width_shift_range=0.1,
                height_shift_range=0.1,
                shear_range=0.3,
                zoom_range=0.1,
                channel_shift_range=30,
                fill_mode='nearest',
                cval=0.,
                horizontal_flip=True,
                vertical_flip=False,
                rescale=None,
                preprocessing_function=None)

    VOC_2007 = VOC_2007
    VOC_2012 = VOC_2012
    VOC_ALL  = VOC_ALL
    voc_class = voc_class
    def __init__(self, voc_data= VOC_2012):

        self.dirs = {'voc_path': voc_path }

        if voc_data == VOC_2012:
            self.train_image_folder = [VOC2012.train_image_folder]
            self.valid_image_folder = [VOC2012.valid_image_folder]
        elif voc_data == VOC_2007:
            self.train_image_folder = VOC2007.trainval_img_folder
            self.valid_image_folder = VOC2007.test_img_folder
        elif voc_data == VOC_ALL:
            self.train_image_folder = VOC2007.trainval_img_folder + VOC2012.trainval_img_folder
            self.valid_image_folder = VOC2007.test_img_folder

    def set(self, voc_path):
        self.dirs['voc_path'] = voc_path

        if not os.path.exists(self.dir['voc_path']):
            print("Cannot find dataset from %s", voc_path)
            exit()

    def getFileList(self):
        print("[INFO] Loading File list ...")
        self.train_img_list = []
        self.train_annot_list = []

        for filepath in self.train_image_folder:
            filepath = self.dirs['voc_path'] + filepath
            with  open(filepath, 'r') as f:
                img_list = f.read().split('\n')
            if filepath.find('2012')>=0:
                image_folder = VOC2012.image_folder
                annot_folder = VOC2012.annot_folder
            else:
                image_folder = VOC2007.image_folder
                annot_folder = VOC2007.annot_folder
            print(filepath, image_folder,  annot_folder)
            for l in img_list:
                if l:
                    img_path = '%s%s%s.jpg' % (self.dirs['voc_path'],
                            image_folder, l)
                    self.train_img_list.append(img_path)
                    annot_path = '%s%s%s.xml' % (self.dirs['voc_path'],
                            annot_folder, l)
                    self.train_annot_list.append(annot_path)

        self.valid_img_list = []
        self.valid_annot_list = []

        for filepath in self.valid_image_folder:
            filepath = self.dirs['voc_path'] + filepath
            with  open(filepath, 'r') as f:
                img_list = f.read().split('\n')
            if filepath.find('2012')>=0:
                image_folder = VOC2012.image_folder
                annot_folder = VOC2012.annot_folder
            else:
                image_folder = VOC2007.image_folder
                annot_folder = VOC2007.annot_folder
            print(filepath, image_folder,  annot_folder)
            for l in img_list:
                if l:
                    img_path = '%s%s%s.jpg' % (self.dirs['voc_path'],
                            image_folder, l)
                    self.valid_img_list.append(img_path)
                    annot_path = '%s%s%s.xml' % (self.dirs['voc_path'],
                            annot_folder, l)
                    self.valid_annot_list.append(annot_path)

    def getClassAnnot(self):
        print("[INFO] Getting Class annot  ...")
        _len = len(self.train_annot)
        self.train_label = np.zeros((_len, len(voc_class)))
        j = 0
        for i in self.train_annot:
            objs = i.findall('object')
            for obj in objs:
                self.train_label[j, voc_class_key[obj[0].text]] = 1
            j += 1

        _len = len(self.valid_annot)
        self.valid_label = np.zeros((_len, len(voc_class)))
        j = 0
        for i in self.valid_annot:
            objs = i.findall('object')
            for obj in objs:
                self.valid_label[j, voc_class_key[obj[0].text]] = 1
            j += 1

    def getAnnot(self):
        print("[INFO] Load annot from list ...")
        self.train_annot = []
        for i in self.train_annot_list:
            f = open(i, 'r')
            self.train_annot.append(ET.fromstring(f.read()))
            f.close()

        self.valid_annot = []
        for i in self.valid_annot_list:
            f = open(i, 'r')
            self.valid_annot.append(ET.fromstring(f.read()))
            f.close()

    def setGeneratorConfig(self, config=config):
        """
        batch_size : 64
        img_h : 224
        img_w : 224
        img_c : 3
        norm : 1
        num_classes: 20
        shuffle : 0
        """
        self.config = config
        self.shuffle = config['shuffle']
        if self.config['data_mode'] == 'on_memory':
            self.getImage()

    def getImage(self):
        print("[INFO] Load image from list to memory ...")
        _len = len(self.train_annot)
        self.train_images = np.zeros((_len,
                            self.config['img_h'],
                            self.config['img_w'],
                            self.config['img_c']))
        for j in range(_len):
            img_path = self.train_img_list[j]
            img = cv2.imread(img_path)[:,:,::-1]
            img = cv2.resize(img, (self.config['img_w'],self.config['img_h']))
            self.train_images[j, ...] = img

        _len = len(self.valid_annot)
        self.valid_images = np.zeros((_len,
                            self.config['img_h'],
                            self.config['img_w'],
                            self.config['img_c']))
        for j in range(_len):
            img_path = self.train_img_list[j]
            img = cv2.imread(img_path)
            img = cv2.resize(img, (self.config['img_w'],self.config['img_h']))
            self.valid_images[j, ...] = img

    def getTrainBatch(self):
        if self.config['data_mode'] == 'on_memory':
            return self.train_image, self.train_label
        return VOC_TRAIN_BATCH(self)

    def getValidBatch(self):
        if self.config['data_mode'] == 'on_memory':
            return self.valid_images, self.valid_label
        return VOC_VAL_BATCH(self)

    def preprocessData(img):
        #img = img.astype(np.float32) / 255 - 0.5
        return img

    def augment_data(img_batch, y_batch, batch_size):
        img_batch, y_batch = VOC.datagen.flow((img_batch, y_batch), batch_size=batch_size).next()
        return img_batch, y_batch

class VOC_TRAIN_BATCH(Sequence):

    def __init__(self, voc):
        self.config = voc.config
        self.train_label = voc.train_label
        self.train_img_list = voc.train_img_list
        self.shuffle = voc.config['shuffle']
        self.generate_list = list(range(len(self)))
        self.augment_data = 0
        print("[INFO] total %d training images" % len(voc.train_img_list))

    def __len__(self):
        return int((self.train_label.shape[0] / self.config['batch_size']) + 0.5)

    def size(self):
        return self.train_label.shape[0]

    def on_epoch_end(self):
        if self.shuffle: np.random.shuffle(self.generate_list)
        if self.config['do_augment']: self.augment_data = 1

    def __getitem__(self, idx):
        x_batch = np.empty((self.config['batch_size'],
                            self.config['img_h'],
                            self.config['img_w'],
                            self.config['img_c']))
        y_batch = np.empty((self.config['batch_size'],
                            self.config['num_class']))
        idx = self.generate_list[idx]
        idx_base = idx * self.config['batch_size']
        idx_top = idx_base + self.config['batch_size']
        if idx_top > self.size():
            idx_top = self.size()
            size = idx_top - idx_base
            x_batch = x_batch[:size, ...]
            y_batch = y_batch[:size, ...]
        i = 0
        for j in range(idx_base, idx_top):
            img_path = self.train_img_list[j]
            img = cv2.imread(img_path)[:,:,::-1]
            img = cv2.resize(img, (self.config['img_w'], self.config['img_h']))
            x_batch[i, ...] = img
            y_batch[i, ...] = self.train_label[j, ...]
            i += 1
        if self.augment_data:
            x_batch, y_batch = VOC.augment_data(x_batch, y_batch, batch_size=self.config['batch_size'])
        x_batch = VOC.preprocessData(x_batch)
        return x_batch, y_batch

class VOC_VAL_BATCH(Sequence):

    def __init__(self, voc):
        self.config = voc.config
        self.valid_label = voc.valid_label
        self.valid_img_list = voc.valid_img_list
        self.shuffle = voc.config['shuffle']
        self.generate_list = list(range(len(self)))
        print("[INFO] total %d validation images" % len(voc.valid_img_list))

    def __len__(self):
        return int((self.valid_label.shape[0] / self.config['batch_size']) + 0.5)

    def size(self):
        return self.valid_label.shape[0]

    def on_epoch_end(self):
        if self.shuffle: np.random.shuffle(self.generate_list)
        self.augment_data = 1

    def __getitem__(self, idx):
        x_batch = np.empty((self.config['batch_size'],
                            self.config['img_h'],
                            self.config['img_w'],
                            self.config['img_c']))
        y_batch = np.empty((self.config['batch_size'],
                            self.config['num_class']))

        #for idx in self.generate_list:
        idx_base = idx * self.config['batch_size']
        idx_top = idx_base + self.config['batch_size']
        if idx_top > self.size():
            idx_top = self.size()
            size = idx_top - idx_base
            x_batch = x_batch[:size, ...]
            y_batch = y_batch[:size, ...]
        i = 0
        for j in range(idx_base, idx_top):
            img_path = self.valid_img_list[j]
            img = cv2.imread(img_path)[:,:,::-1]
            img = cv2.resize(img, (self.config['img_w'], self.config['img_h']))
            x_batch[i, ...] = img
            y_batch[i, ...] = self.valid_label[j, ...]
            i += 1
        x_batch = VOC.preprocessData(x_batch)
        return x_batch, y_batch
                #yield x_batch, y_batch


""" Unit and regression test for the run module. """

import logging
import os
import pathlib
import subprocess
from glob import glob
from tempfile import TemporaryDirectory

import numpy as np
import pytest

import EnsEquil as ee

from . import GROMACS_PRESENT, RUN_SLURM_TESTS, SLURM_PRESENT
from .fixtures import calc, restrain_stage

LEGS_WITH_STAGES = {"bound": ["discharge", "vanish"], "free": ["discharge", "vanish"]}

# Load calc and check it has all the required stuff
def test_calculation_loading(calc):
    """Check that the calculation loads correctly"""
    # Check that the calculation has the correct attributes
    assert calc.loaded_from_pickle == False
    assert calc.ensemble_size == 6
    assert calc.input_dir == str(
        pathlib.Path("EnsEquil/data/example_run_dir/input").resolve()
    )
    assert calc.output_dir == os.path.join(calc.base_dir, "output")
    assert calc.setup_complete == False
    assert calc.prep_stage == ee.run.enums.PreparationStage.PARAMETERISED
    assert calc.stream_log_level == logging.INFO
    # Check that pickle file exists
    assert os.path.exists(os.path.join(calc.base_dir, "Calculation.pkl"))

def test_calculation_logging(calc):
    """Check that the calculation logging is set up correctly"""
    assert type(calc._logger.handlers[0]) == logging.FileHandler  # type: ignore
    assert calc._logger.handlers[0].baseFilename == os.path.join(calc.base_dir, "Calculation.log")  # type: ignore
    assert calc._logger.handlers[0].level == logging.DEBUG  # type: ignore
    assert type(calc._logger.handlers[1]) == logging.StreamHandler  # type: ignore
    assert calc._logger.handlers[1].level == logging.INFO  # type: ignore

    # Try writing to the log and check that it's written to the file
    calc._logger.info("Test message")
    with open(os.path.join(calc.base_dir, "Calculation.log"), "r") as f:
        assert "Test message" in f.read()

def test_calculation_reloading(calc):
    """Check that the calculations can be correctly loaded from a pickle."""
    calc2 = ee.Calculation(
        base_dir=calc.base_dir, input_dir="EnsEquil/data/example_run_dir/input"
    )
    assert calc2.loaded_from_pickle == True
    assert calc2.ensemble_size == 6
    assert calc2.input_dir == str(
        pathlib.Path("EnsEquil/data/example_run_dir/input").resolve()
    )
    assert calc2.output_dir == os.path.join(calc.base_dir, "output")
    assert calc2.setup_complete == False
    assert calc2.prep_stage == ee.run.enums.PreparationStage.PARAMETERISED
    assert calc2.stream_log_level == logging.INFO

def test_update_paths(calc):
    """Check that the calculation paths can be updated correctly."""
    with TemporaryDirectory() as new_dir:
        for file in glob(os.path.join(calc.base_dir, "*")):
            subprocess.run(["cp", "-r", file, new_dir])
        calc3 = ee.Calculation(
            base_dir=new_dir, input_dir="EnsEquil/data/example_run_dir/input"
        )
        assert calc3.loaded_from_pickle == True
        current_dir = os.getcwd()
        calc3.update_paths(old_sub_path=calc3.base_dir, new_sub_path=current_dir)
        assert calc3.base_dir == current_dir
        assert calc3._logger.handlers[0].baseFilename == os.path.join(current_dir, "Calculation.log")  # type: ignore

def test_set_and_get_attributes(restrain_stage):
    """Check that the calculation attributes can be set and obtained correctly."""
    attr_dict = restrain_stage.get_attr_values("ensemble_size")
    assert attr_dict["ensemble_size"] == 5
    assert (
        attr_dict["sub_sim_runners"][list(attr_dict["sub_sim_runners"].keys())[0]][
            "ensemble_size"
        ]
        == 5
    )
    # Check it fails if the attribute doesn't exist
    restrain_stage.set_attr_values("ensemble_sizee", 7)
    attr_dict = restrain_stage.get_attr_values("ensemble_sizee")
    assert attr_dict["ensemble_sizee"] == None
    # Check that we can force it to set the attribute
    restrain_stage.set_attr_values("ensemble_sizee", 7, force=True)
    attr_dict = restrain_stage.get_attr_values("ensemble_sizee")
    assert attr_dict["ensemble_sizee"] == 7
    # Change the ensemble size attribute
    restrain_stage.set_attr_values("ensemble_size", 7)
    attr_dict = restrain_stage.get_attr_values("ensemble_size")
    assert attr_dict["ensemble_size"] == 7

def test_reset(restrain_stage):
    """Test that runtime attributes are reset correctly"""
    # First, check that they're consistent with having run the stage
    equilibrated = all([lam._equilibrated for lam in restrain_stage.lam_windows])
    equil_times = [lam._equil_time for lam in restrain_stage.lam_windows]
    assert equilibrated == True
    assert None not in equil_times
    # Now reset the stage and recheck
    restrain_stage.reset()
    print([lam._equilibrated for lam in restrain_stage.lam_windows])
    equilibrated = any([lam._equilibrated for lam in restrain_stage.lam_windows])
    equil_times = [lam._equil_time for lam in restrain_stage.lam_windows]
    equil_times_none = all([time is None for time in equil_times])
    assert not equilibrated
    assert equil_times_none

def test_update(restrain_stage):
    """Check that the stage update method works"""
    # Change the positions of the lambda windows and ensemble size
    # and ensure that this is reflected in the lambda windows
    # after updating
    new_lam_vals = list(np.arange(0.0, 1.1, 0.1))
    restrain_stage.lam_vals = new_lam_vals
    restrain_stage.ensemble_size = 2
    restrain_stage.update()
    assert len(restrain_stage.lam_windows) == 11
    for lam, lam_val in zip(restrain_stage.lam_windows, new_lam_vals):
        assert lam.lam == lam_val
        assert lam.ensemble_size == 2

@pytest.mark.skipif(not GROMACS_PRESENT, reason="GROMACS not present")
def test_setup_no_slurm():
    """Test short setup stages without SLURM"""
    with TemporaryDirectory() as dirname:
        # Copy the example input directory to the temporary directory
        # as we'll create some new files there
        subprocess.run(
            ["cp", "-r", "EnsEquil/data/example_run_dir/input", f"{dirname}/input"]
        )
        free_leg = ee.Leg(
            base_dir=dirname,
            input_dir=f"{dirname}/input",
            ensemble_size=1,
            stream_log_level=logging.CRITICAL,  # Silence the logging
            leg_type=ee.run.enums.LegType.FREE,
        )
        # Test that the preparation stages work for the free leg to avoid wasting time
        # running the complex
        assert free_leg.leg_type == ee.run.enums.LegType.FREE
        assert free_leg.prep_stage == ee.run.enums.PreparationStage.PARAMETERISED
        free_leg.setup(slurm=False, short_ensemble_equil=True)
        assert free_leg.prep_stage == ee.run.enums.PreparationStage.PREEQUILIBRATED
        # Check that the required output files exist
        for file in ["free_preequil.prm7", "free_preequil.rst7"]:
            assert os.path.exists(os.path.join(free_leg.input_dir, file))
        for file in ["somd_1.rst7", "somd.prm7", "somd.pert"]:
            assert os.path.exists(
                os.path.join(free_leg.base_dir, "discharge", "input", file)
            )

def test_simulation_runner_iterator(restrain_stage):
    """Test that the simulation runner iterator works as expected."""
    # Take the first 3 lambda windows
    base_dirs = [window.base_dir for window in restrain_stage.lam_windows[:3]]
    sim_runner_iterator = ee.run._utils.SimulationRunnerIterator(
        base_dirs=base_dirs,
        subclass=ee.LamWindow,
        lam=0,  # Overwritten once pickle loaded
        virtual_queue=restrain_stage.virtual_queue,
    )
    # Check that the iterator works as expected
    for i, sim_runner in enumerate(sim_runner_iterator):
        assert sim_runner.base_dir == base_dirs[i]

    # Cycle through the iterator again and check that it still works
    for i, sim_runner in enumerate(sim_runner_iterator):
        assert sim_runner.base_dir == base_dirs[i]

######################## Tests Requiring SLURM ########################

@pytest.fixture(scope="module")
def calc_slurm():
    """Create a calculation object to use in tests"""
    with TemporaryDirectory() as dirname:
        # Copy the example input directory to the temporary directory
        # as we'll create some new files there
        subprocess.run(["mkdir", "-p", dirname])
        subprocess.run(
            ["cp", "-r", "EnsEquil/data/example_run_dir/input", f"{dirname}/input"]
        )
        calc = ee.Calculation(
            base_dir=dirname,
            input_dir=f"{dirname}/input",
            ensemble_size=2,
            stream_log_level=logging.CRITICAL,
        )  # Shut up the logging
        calc._dump()
        # Must use yield so that the temporary directory is deleted after the tests
        # by the context manager and does not persist
        yield calc

# Test that the preparation stages work
@pytest.mark.skipif(not SLURM_PRESENT, reason="SLURM not present")
@pytest.mark.skipif(not RUN_SLURM_TESTS, reason="RUN_SLURM_TESTS is False")
def test_integration_calculation(calc_slurm):
    """Integration test to check that all major stages of the calculation work."""

    # Check that the preparation stages work
    assert calc_slurm.prep_stage == ee.run.enums.PreparationStage.PARAMETERISED
    calc_slurm.setup(short_ensemble_equil=True)
    assert calc_slurm.setup_complete == True
    # Check that all required slurm bash jobs have been created
    required_slurm_jobnames = ["minimise", "solvate", "heat_preequil"]
    for leg in LEGS_WITH_STAGES.keys():
        for jobname in [f"{job}_{leg}.sh" for job in required_slurm_jobnames]:
            assert os.path.exists(os.path.join(calc_slurm.base_dir, "input", jobname))
    # Check that all required slurm output files have been created
    assert len(glob(os.path.join(calc_slurm.base_dir, "input", "*.out"))) == 6
    # Check that all required stage dirs have been created for each leg
    for leg in LEGS_WITH_STAGES.keys():
        for stage in LEGS_WITH_STAGES[leg]:
            assert os.path.exists(os.path.join(calc_slurm.base_dir, leg, stage))
    # Check that all required input files have been created
    for leg in LEGS_WITH_STAGES.keys():
        for stage in LEGS_WITH_STAGES[leg]:
            required_files = [
                "somd.cfg",
                "somd.rst7",
                "somd.prm7",
                "somd.pert",
                "run_somd.sh",
                "somd_1.rst7",
                "somd_2.rst7",
            ]
            if leg == "bound":
                required_files.extend(["restraint_1.txt", "restraint_2.txt"])
            for file in required_files:
                assert os.path.exists(
                    os.path.join(calc_slurm.base_dir, leg, stage, "input", file)
                )
    # Check that the optimal lambda window creation function works
    calc_slurm.get_optimal_lam_vals()
    # Check that the old runs have been moved, and that the new lambda values are
    # different to the old ones
    for leg in LEGS_WITH_STAGES.keys():
        for stage in LEGS_WITH_STAGES[leg]:
            assert os.path.exists(
                os.path.join(calc_slurm.base_dir, leg, stage, "lam_val_determination")
            )
            lam_dirs_old = glob(
                os.path.join(
                    calc_slurm.base_dir, leg, stage, "lam_val_determination", "lam*"
                )
            )
            lam_dirs_new = glob(
                os.path.join(calc_slurm.base_dir, leg, stage, "output", "lam*")
            )
            assert lam_dirs_old != lam_dirs_new

    # Check that a short, non-adaptive run works
    calc_slurm.run(adaptive=False, runtime=0.1)
    calc_slurm.wait()
    assert calc_slurm.running == False
    # Set the entire simulation time to equilibrated
    for leg in calc_slurm.legs:
        for stage in leg.stages:
            for lam_win in stage.lam_windows:
                lam_win._equilibrated = True
                lam_win._equil_time = 0
    for leg in calc_slurm.legs:
        for stage in leg.stages:
            for lam_win in stage.lam_windows:
                assert round(lam_win.tot_simtime / lam_win.ensemble_size, 1) == 0.1

    # Check that analysis runs and gives a sane result
    calc_slurm.analyse()
    # Check that the output file exists
    assert os.path.exists(
        os.path.join(calc_slurm.base_dir, "output", "overall_stats.dat")
    )
    # Check that the free energy change is sane
    with open(
        os.path.join(calc_slurm.base_dir, "output", "overall_stats.dat"), "r"
    ) as f:
        dg = float(f.readlines()[1].split(" ")[3])
        assert dg < -5
        assert dg > -25

    # Check that all calculations can be killed
    calc_slurm.run(adaptive=False, runtime=0.1)
    calc_slurm.kill()
    assert not calc_slurm.running


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('tasks', '0012_task_review_comments'),
    ]

    operations = [
        migrations.AddField(
            model_name='task',
            name='priority',
            field=models.CharField(default=b'normal', max_length=16),
        ),
    ]


from toybox.interventions.base import *
from toybox.interventions.core import *
try:
  import ujson as json
except:
  import json
import typing
"""An API for interventions on Breakout."""

class Breakout(Game):

  expected_keys = Game.expected_keys + ['paddle', 'is_dead', 'balls', 'ball_radius', 'paddle_speed', 'reset', 'bricks', 'paddle_width']

  immutable_fields = ['balls', 'bricks', 'intervention']

  def __init__(self, intervention,
    score=None, lives=None, rand=None, level=None,
    paddle=None, paddle_width=None, paddle_speed=None,
    ball_radius=None, balls=None,
    bricks=None,
    reset=None, is_dead=None):

      super().__init__(intervention, score, lives, rand, level)
      self.paddle = Paddle.decode(intervention, paddle, Paddle)
      self.reset = reset
      self.ball_radius = ball_radius
      self.bricks = BrickCollection.decode(intervention, bricks, BrickCollection)
      self.balls = BallCollection.decode(intervention, balls, BallCollection)
      self.paddle_speed = paddle_speed
      self.paddle_width = paddle_width
      self.is_dead = is_dead
      self._in_init = False

  def __eq__(self, other) -> Either:
    names = {
      'score'       : (self.score,        other.score),
      'lives'       : (self.lives,        other.lives),
      'level'       : (self.level,        other.level),
      'paddle'      : (self.paddle,       other.paddle),
      'reset'       : (self.reset,        other.reset),
      'ball_radius' : (self.ball_radius,  other.ball_radius) ,
      'bricks'      : (self.bricks,       other.bricks),
      'balls'       : (self.balls,        other.balls),
      'paddle_speed': (self.paddle_speed, other.paddle_speed),
      'paddle_width': (self.paddle_width, other.paddle_width),
      'is_dead'     : (self.is_dead,      other.is_dead)
    }
    return eq_map(names)

    def __str__(self):
        return """
Breakout
==========
    score: {}
    lives: {}
    level: {}
    paddle: {}
    reset: {}
    ball_radius: {}
    bricks: {}
    balls: {}
    paddle_speed: {}
    paddle_width: {}
    is_dead: {}""".format(self.score, self.lives, self.level, str(self.paddle),
        self.reset, self.ball_radius, self.bricks.__str__(), self.balls.__str__(), self.paddle_speed,
        self.paddle_width, self.is_dead)

class Paddle(BaseMixin):

  expected_keys = ['velocity', 'position']
  immutable_fields = []

  def __init__(self, intervention, velocity, position):
    super().__init__(intervention)
    self.velocity = Vec2D.decode(intervention, velocity, Vec2D)
    self.position = Vec2D.decode(intervention, position, Vec2D)
    self._in_init = False

  def __eq__(self, other) -> Either:
    names = {
      'velocity': (self.velocity, other.velocity),
      'position': (self.position, other.position)
    }
    return eq_map(names)

  def __str__(self):
      return '<position: {}, velocity: {}>'.format(self.position, self.velocity)

class BrickCollection(Collection):

  def __init__(self, intervention, bricks):
    super().__init__(intervention, bricks, Brick)
    self._in_init = False

  def decode(intervention, bricks, clz):
    return BrickCollection(intervention, bricks)

class Brick(BaseMixin):

  expected_keys = ['destructible', 'depth', 'color', 'alive', 'points', 'size', 'position', 'row', 'col']
  immutable_fields = ['intervention']

  def __init__(self, intervention, destructible, depth, color, alive, points, size, position, row, col):
    super().__init__(intervention)
    self.destructible = destructible
    self.depth = depth
    self.color = Color.decode(intervention, color, Color)
    self.alive = alive
    self.points = points
    self.size = Vec2D.decode(intervention, size, Vec2D)
    self.position = Vec2D.decode(intervention, position, Vec2D)
    self.row = row
    self.col = col
    self._in_init = False

  def __eq__(self, other) -> Either:
    names = {
      'destructible': (self.destructible, other.destructible),
      'depth':        (self.depth,    other.depth),
      'color':        (self.color,    other.color),
      'alive':        (self.alive,    other.alive),
      'points':       (self.points,   other.points),
      'size':         (self.size,     other.size),
      'position':     (self.position, other.position),
      'row':          (self.row,      other.row),
      'col':          (self.col,      other.col)
    }
    return eq_map(names)

class BallCollection(Collection):

  def __init__(self, intervention, balls):
    super().__init__(intervention, balls, Ball)
    self._in_init = False

  def __str__(self):
    if len(self) == 1:
      return str(self[0])
    else:
      return '[{}]'.format(', '.join(str(b) for b in self))

class Ball(BaseMixin):

  expected_keys = ['position', 'velocity']
  immutable_fields = ['intervention']

  def __init__(self, intervention, position, velocity):
    super().__init__(intervention)
    self.position = Vec2D.decode(intervention, position, Vec2D)
    self.velocity = Vec2D.decode(intervention, velocity, Vec2D)
    self._in_init = False

  def __eq__(self, other) -> Either:
    names = {
        'position': (self.position, other.position),
        'velocity': (self.velocity, other.velocity)
    }
    return eq_map(names)

  def __str__(self):
    return 'Ball(position: {}, velocity: {})'.format(self.position, self.velocity)

class BreakoutIntervention(Intervention):

    def __init__(self, tb, game_name='breakout'):
        # check that the simulation in tb matches the game name.
        Intervention.__init__(self, tb, game_name, Breakout)

    def num_bricks_remaining(self):
        return sum([int(brick.alive) for brick in self.game.bricks])

    def num_bricks(self):
        return len(self.game.bricks)

    def num_rows(self):
        return len(self.config['row_scores'])

    def num_columns(self):
        """Returns the number of columns in the layout."""
        rows = self.num_rows()
        bricks = self.num_bricks()
        return bricks // rows

    def add_row(self, bricks, points, pre=None, post=None):
        """Adds the input row of bricks to the playing board.

        Parameters
        ====
        bricks: a list of brick objects
        value: the points associated with this row
        pre: add the list above
        post: add the list below
        """

        input_len = len(bricks)
        target_len = self.num_bricks()

        if input_len != target_len:
            raise ValueError('Input brick list length incorrect (is %d; should be %d)' % (input_len, target_len))

        if pre:
            for brick in bricks.reverse():
                self.bricks.insert(0, brick)

        elif post:
            self.bricks.extend(bricks)

        else:
            raise ValueError('Must provide one optional argument: pre or post.')

        self.config['row_scores'].append(points)
        self.dirty_config = True

    def is_stack(self, bricks):
        col = bricks[0].col
        return all([b.col == col for b in bricks])

    def is_channel(self, bricklist):
        """Predicate indicating whether the input list of bricks constitutes a channel."""
        col = bricklist[0].col
        for brick in bricklist:
            if brick.col != col: return False
            if brick.alive: return False
        return True

    def get_column(self, i):
        """Returns the ith column of bricks."""
        bricks = []
        for brick in self.game.bricks:
            if brick.col == i:
                bricks.append(brick)
        return bricks

    def channel_count(self):
        count = 0
        for i in range(self.num_columns()):
            channel = self.get_column(i)
            if self.is_channel(channel): count += 1
        return count

    def get_ball_position(self):
        """Returns a list of positions, if there is more than one ball, and a single Vec2D object otherwise.:"""
        nballs = len(self.game.balls)
        if nballs > 1:
            return [ball.position for ball in self.game.balls]
        else:
            return self.game.balls[0].position

    def get_ball_velocity(self):
        nballs = len(self.game.balls)
        if nballs > 1:
            return [ball.velocity for ball in self.game.balls]
        else:
            return self.game.balls[0].velocity

    def get_paddle_position(self):
        return self.game.paddle.position

    def get_paddle_velocity(self):
        return self.game.paddle.velocity

    def find_brick(self, pred):
        for i, b in enumerate(self.game.bricks):
            if pred(b):
                return i, b
        raise ValueError('No bricks that satisfy the input predicate found.')

    def add_channel(self, i):
        """Turns the ith column into a channel"""
        for brick in self.game.bricks:
            if brick.col == i and brick.alive:
                brick.alive = False

    def fill_column(self, i):
        """Fills the ith column, so that all bricks are now alive."""
        for brick in self.game.bricks:
            if brick.col == i and not brick.alive:
                brick.alive = True

    def find_channel(self):
        """Returns the first channel found."""
        for i in range(self.num_columns()):
            col = self.get_column(i)
            if self.is_channel(col):
                return i, col
        return -1, None

    def clear_board(self):
        """Clears the board of all bricks"""
        for brick in self.game.bricks:
            brick.alive = False

if __name__ == "__main__":
  import argparse
  from ctoybox import Toybox, Input

  parser = argparse.ArgumentParser(description='test Amidar interventions')
  parser.add_argument('--partial_config', type=str, default="null")
  parser.add_argument('--save_json', type=bool, default=False)
  args = parser.parse_args()

  with Toybox('breakout') as tb:

    fire = Input()
    fire.button1 = True
    noop = Input()
    tb.apply_action(fire)

    state = tb.to_state_json()
    config = tb.config_to_json()

    if args.save_json:
        # save a sample starting state and config
        with open('toybox/toybox/interventions/defaults/breakout_state_default.json', 'w') as outfile:
            json.dump(state, outfile)

        with open('toybox/toybox/interventions/defaults/breakout_config_default.json', 'w') as outfile:
            json.dump(config, outfile)

    with BreakoutIntervention(tb) as intervention:
        intervention.game.lives = 1
        assert intervention.dirty_state

    # remove and assert that the brick is gone
    with BreakoutIntervention(tb) as intervention:
        nbricks = intervention.num_bricks_remaining()
        intervention.game.bricks[0].alive = False
        nbricks_post = intervention.num_bricks_remaining()

        assert nbricks - 1 == nbricks_post

    # reset and assert that the brick is present
    with BreakoutIntervention(tb) as intervention:
        nbricks = intervention.num_bricks_remaining()
        intervention.game.bricks[0].alive = True
        nbricks_post = intervention.num_bricks_remaining()

        assert nbricks + 1 == nbricks_post

    # add a channel and assert that num_rows bricks have been removed
    with BreakoutIntervention(tb) as intervention:
        nbricks = intervention.num_bricks_remaining()
        intervention.add_channel(0)
        nbricks_post = intervention.num_bricks_remaining()
        assert nbricks_post == nbricks - intervention.num_rows()

        col, channel = intervention.find_channel()
        assert channel

        assert intervention.channel_count() == 1

    # remove a channel and assert that num_rows bricks have been added
    with BreakoutIntervention(tb) as intervention:
        nbricks = intervention.num_bricks_remaining()
        intervention.fill_column(0)
        nbricks_post = intervention.num_bricks_remaining()
        assert nbricks_post == nbricks + intervention.num_rows()

    # get ball position, even when multiple balls present
    with BreakoutIntervention(tb) as intervention:
        game = intervention.game
        assert len(game.balls) > 0

        ball = game.balls[0]
        game.balls.append(ball)
        ball_positions = intervention.get_ball_position()
        assert len(ball_positions) == 2
        ball_velocities = intervention.get_ball_velocity()
        assert len(ball_velocities) == 2
        game.balls.clear()
        game.balls.append(ball)
        # the line above should have triggered an error
        ball_positions = intervention.get_ball_position()

    # move ball diagonally by sqrt(2) pixels
    with BreakoutIntervention(tb) as intervention:
        ball_pos = intervention.get_ball_position()
        ball_pos.x = ball_pos.x + 1
        ball_pos.y = ball_pos.y + 1
    with BreakoutIntervention(tb) as intervention:
        ball_pos_post = intervention.get_ball_position()
        assert ball_pos_post.x == ball_pos.x
        ball_pos_post.x = ball_pos.x - 1
        ball_pos_post.y = ball_pos.y - 1
    with BreakoutIntervention(tb) as intervention:
        ball_pos_post_post = intervention.get_ball_position()
        assert ball_pos_post.x == ball_pos_post_post.x

    # change ball velocity
    with BreakoutIntervention(tb) as intervention:
        ball_vel = intervention.get_ball_velocity()
        ball_vel.x = ball_vel.x + 1
        ball_vel.y = ball_vel.y + 1
        ball_vel_post = intervention.get_ball_velocity()
        assert ball_vel_post.x == ball_vel.x

        ball_vel.x = ball_vel.x - 1
        ball_vel.y = ball_vel.y - 1
        ball_vel_post = intervention.get_ball_velocity()
        assert ball_vel_post.x == ball_vel.x

    # get paddle position and move
    with BreakoutIntervention(tb) as intervention:
        pos = intervention.get_paddle_position()
        assert pos.x == 120.0 and pos.y == 143.0

        pos.x = pos.x + 10
        pos_post = intervention.get_paddle_position()
        assert pos.x == pos_post.x


from torch.utils.data import Subset
import torch.nn as nn
import torch
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
image_path = './ch-13'
transform = transforms.Compose([transforms.ToTensor()])
mnist_dataset = torchvision.datasets.MNIST(
    root=image_path, train=True, transform=transform, download=False)

mnist_valid_dataset = Subset(mnist_dataset, torch.arange(10000))
mnist_train_dataset = Subset(
    mnist_dataset, torch.arange(10000, len(mnist_dataset)))

mnist_test_dataset = torchvision.datasets.MNIST(
    root=image_path, train=False, transform=transform, download=False)

batch_size = 64
torch.manual_seed(1)

train_dl = DataLoader(mnist_train_dataset, batch_size, shuffle=True)
valid_dl = DataLoader(mnist_valid_dataset, batch_size, shuffle=True)

model = nn.Sequential()
model.add_module('conv1', nn.Conv2d(
    in_channels=1, out_channels=32, kernel_size=5, padding=2))
model.add_module('relu1', nn.ReLU())
model.add_module('pool1', nn.MaxPool2d(kernel_size=2))
model.add_module('conv2', nn.Conv2d(
    in_channels=32, out_channels=64, kernel_size=5, padding=2))
model.add_module('relu2', nn.ReLU())
model.add_module('pool2', nn.MaxPool2d(kernel_size=2))
model.add_module('flatten', nn.Flatten())
model.add_module('fc1', nn.Linear(3136, 1024))
model.add_module('relu3', nn.ReLU())
model.add_module('dropout', nn.Dropout(p=0.5))
model.add_module('fc2', nn.Linear(1024, 10))
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
model.to('cuda')

def train(model, num_epochs, train_dl, valid_dl, device='cuda'):
    loss_hist_train = [0] * num_epochs
    accuracy_hist_train = [0] * num_epochs
    loss_hist_valid = [0] * num_epochs
    accuracy_hist_valid = [0] * num_epochs
    for epoch in range(num_epochs):
        model.train()
        for x_batch, y_batch in train_dl:
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)
            pred = model(x_batch)
            loss = loss_fn(pred, y_batch)
            loss.backward()
            optimizer.step()
            optimizer.zero_grad()
            loss_hist_train[epoch] += loss.item()*y_batch.size(0)
            is_correct = (torch.argmax(pred, dim=1) == y_batch).float()
            accuracy_hist_train[epoch] += is_correct.sum().cpu()

        loss_hist_train[epoch] /= len(train_dl.dataset)
        accuracy_hist_train[epoch] /= len(train_dl.dataset)

        model.eval()
        with torch.no_grad():
            for x_batch, y_batch in valid_dl:
                x_batch = x_batch.to(device)
                y_batch = y_batch.to(device)
                pred = model(x_batch)
                loss = loss_fn(pred, y_batch)
                loss_hist_valid[epoch] += loss.item()*y_batch.size(0)
                is_correct = (torch.argmax(pred, dim=1) == y_batch).float()
                accuracy_hist_valid[epoch] += is_correct.sum().cpu()

        loss_hist_valid[epoch] /= len(valid_dl.dataset)
        accuracy_hist_valid[epoch] /= len(valid_dl.dataset)

        print(
            f'Epoch {epoch+1} accuracy: {accuracy_hist_train[epoch]:.4f} val_accuracy: {accuracy_hist_valid[epoch]:.4f}')
    return loss_hist_train, loss_hist_valid, accuracy_hist_train, accuracy_hist_valid

torch.manual_seed(1)
num_epochs = 5
hist = train(model, num_epochs, train_dl, valid_dl)

pred = model(mnist_test_dataset.data.to('cuda').unsqueeze(1) / 255.)
is_correct = (torch.argmax(pred, dim=1) ==
              mnist_test_dataset.targets.to('cuda')).float()
print(f'Test accuracy: {is_correct.mean():.4f}')

fig = plt.figure(figsize=(12, 4))
for i in range(12):
    ax = fig.add_subplot(2, 6, i+1)
    ax.set_xticks([])
    ax.set_yticks([])
    img = mnist_test_dataset[i][0][0, :, :]
    pred = model(img.unsqueeze(0).unsqueeze(1).to('cuda'))
    y_pred = torch.argmax(pred)
    ax.imshow(img, cmap='gray_r')
    ax.text(0.9, 0.1, y_pred.item(),
            size=15, color='blue',
            horizontalalignment='center',
            verticalalignment='center',
            transform=ax.transAxes)
plt.show()


import requests
import base64
import json
from typing import List, Tuple

class Tweet:
  def __init__(self, text: str, lang: str=None, retweet_count: int=0):
    self.text = text
    self.lang = lang
    self.retweet_count = retweet_count

class TwitterHandler:
  def __init__(self):
    f = open('secrets/twitter_api_key.json')
    twitter_api_key = json.load(f)
    f.close()

    api_key = twitter_api_key["API_KEY"]
    api_key_secret = twitter_api_key["API_KEY_SECRET"]

    credentials = api_key + ":" + api_key_secret
    credentials_base64 = base64.b64encode(credentials.encode('ascii'))
    basic_token = "Basic " + credentials_base64.decode('ascii')

    headers = {
      "Authorization": basic_token,
      "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
    }
    body = "grant_type=client_credentials"

    response = requests.post('https://api.twitter.com/oauth2/token',
     headers=headers, data=body)

    self.__bearer_token = "Bearer " + response.json()["access_token"]

  def get_tweets(self, keyphrase:str='') -> Tuple[List[Tweet], str]:
    """
    Returns a pair with the list of the last 10 most popular tweets containing
    the specified keyphrase and with the topic queried. If no keyphrase is
    specified, it will be the main trending topic. If max_results is greater
    than 100, it will only return 100.
    """
    max_results = 100
    if keyphrase == '':
      keyphrase = self.main_trend_topic()
      print("Using the main trend topic: " + keyphrase + "\n\n")

    headers = {"Authorization": self.__bearer_token}
    payload = {
      'q': keyphrase,
      'count': 100 if max_results > 100 else max_results,
      'result_type': 'popular',
      'lang': 'pt'
    }
    # response = requests.get('https://api.twitter.com/2/search/recent',
    #  params=payload, headers=headers)
    response = requests.get('https://api.twitter.com/1.1/search/tweets.json',
     params=payload, headers=headers)

    # print(response.json())

    # V2
    # if response.json()['meta']['result_count'] == 0:
    #   return []

    if response.json()['search_metadata']['count'] == 0:
      return []

    # V2
    # tweet_list = [Tweet(data['text'], data['lang']) for data in response.json()['data']]

    tweet_list = [Tweet(data['text'], data['lang'], data['retweet_count'])
     for data in response.json()['statuses']]

    # tweet_list.sort(key=lambda tweet: tweet.retweet_count, reverse=True)
    # tweet_list = tweet_list[0:10]

    return (tweet_list, keyphrase)

  def main_trend_topic(self):
    headers = {"Authorization": self.__bearer_token}
    payload = {
      'id': 23424768, # Worldwide: 1 UK: 23424975 Brazil: 23424768
       # Germany: 23424829 Mexico: 23424900 Canada: 23424775
       # United States: 23424977 New York: 2459115
      'exclude': "%23"
    }
    response = requests.get('https://api.twitter.com/1.1/trends/place.json',
     params=payload, headers=headers)

    trend_topics = []
    for data in response.json()[0]['trends']:
      trend_topics.append( ( 0 if data['tweet_volume'] is None
       else data['tweet_volume'], data['name']) )

    return trend_topics[0][1]


import click
from tools.memoization import memoize
from math import factorial

@click.command('53')
@click.option('--limit', '-l', type=int, default=100)
@click.option('--threshold', '-t', type=int, default=1000000)
@click.option('--verbose', '-v', count=True)
def problem_053(limit, threshold, verbose):
    """Combinatoric selections.

    There are exactly ten ways of selecting three from five, 12345:

    123, 124, 125, 134, 135, 145, 234, 235, 245, and 345

    In combinatorics, we use the notation, 5C3 = 10.

    In general,

    nCr =  |

    n!
    r!(n−r)!

    | ,where r ≤ n, n! = n×(n−1)×...×3×2×1, and 0! = 1.
    ---|---|---

    It is not until n = 23, that a value exceeds one-million: 23C10 = 1144066.

    How many, not necessarily distinct, values of nCr, for 1 ≤ n ≤ 100, are
    greater than one-million?

    """

    numbers = range(1, limit + 1)
    pairs = ((n, r) for n in numbers for r in range(1, n + 1))
    combos = ((n, r, combinations(n, r)) for n, r in pairs)
    over_threshold = (combo for combo in combos if combo[2] > threshold)
    click.echo(len(list(over_threshold)))

factorial = memoize(factorial)

@memoize
def combinations(n, r):
    return factorial(n) // (factorial(r) * factorial(n - r))


from jinja2.ext import Extension
from textwrap import dedent
from io import StringIO
import os
import sys
import re
import ctypes
from jinja2 import nodes, Environment
import contextlib

#
# From https://stackoverflow.com/a/55545295
class PythonExtension(Extension):
    # a set of names that trigger the extension.
    tags = {'py'}

    def __init__(self, environment: Environment):
        super().__init__(environment)

    def parse(self, parser):
        """
        Parse {% py %} blocks in templates.

        Inserts an appropriate CallBlock into the parse tree where a {% py %}
        block is found, so it can be executed when the template is rendered.

        No actual code execution happens here.
        """
        lineno = next(parser.stream).lineno
        # Get contents until an {% endpy %} declaration
        # drop_needle drops the {% endpy %} at the end
        body = parser.parse_statements(['name:endpy'], drop_needle=True)

        # Insert a CallBlock that'll call our `_exec_python` method with
        # the body of {% py %} when rendering
        return nodes.CallBlock(self.call_method('_exec_python',
                                                [nodes.ContextReference(), nodes.Const(lineno), nodes.Const(parser.filename)]),
                               [], [], body).set_lineno(lineno)

    def _exec_python(self, ctx, lineno, filename, caller):
        """
        Execute python code from inside a parsed {% py %} block.

        Anything printed to stdout from the code in the block will be substituted
        in the template output. Locals & imports persist between different {% py %}
        blocks in the same template.
        """

        # Remove excess indentation
        code = dedent(caller())

        # Compile the code in this block so it can be executed.  We prepend
        # enough newlines that when the code is compiled, the line numbers of
        # the code *just* in this compiled block match the line numbers of the
        # code in the template itself. This provides us with useful error
        # messages.
        compiled_code = compile("\n" * (lineno - 1) + code, filename, "exec")

        # when a pyhp file is executed, the cwd should be set to the directory the
        # file is in. Similarly, when it tries to import python files, we should
        # look for it in the directory the pyhp file is in, *not* the directory
        # where the server started. So we save the current values and restore them
        # when done.
        # FIXME: If the {% py %} block calls os.chdir, that will not persist across
        # other blocks in the file. Same for `sys.path` manipulation
        cur_cwd = os.getcwd()
        cur_sys_path = sys.path

        # Capture stdout from this code block
        sout = StringIO()
        try:
            # FIXME: Make sure this isn't allowing for path traversal attacks?
            file_dir = os.path.dirname(os.path.abspath(filename))
            os.chdir(file_dir)
            new_sys_path = sys.path.copy()
            # The first entry in sys.path will always (haha) be the current directory.
            # By setting it to the directory of our pyhp file, our pyhp file can import
            # other .py files there!
            new_sys_path[0] = file_dir
            sys.path = new_sys_path
            with contextlib.redirect_stdout(sout):
                # Execute the code, with globals & locals from our jinja2 context
                exec(compiled_code, ctx.parent, ctx.vars)
        finally:
            sys.path = cur_sys_path
            os.chdir(cur_cwd)

        # WARNING: Everything from below here is Yuvi's guess of what's actually
        # happening.

        # jinja2 generates python code for each template, and executes it.
        # This generated python code calls this method to execute our
        # {% py %} block. Once the code block executes, the following must
        # be true:
        #
        # 1. Any new top-level locals defined in our code block must be available
        #    for any new jinja2 blocks
        # 2. Any pre-existing top level locals modified in our code block must have
        #    their new values reflected in any further jinja2 blocks
        #
        # This is pretty messy!
        #
        # We will:
        #
        # 1. Peer into this generated code that is calling us, by looking
        #    two frames in the call stack below our current frame. This is
        #    probably very brittle, but it works for now.
        # 2. Find local variables declared there, by making use of the fact that
        #    local variables are defined in the jinja2 generated code of the
        #    form `l_\d+_<variable-name>`. Again, very brittle.
        # 3. If our block overrides any of those top level locals, we explicitly
        #    *modify this generated code frame* so their values point to our
        #    new values. This is pretty nuts.

        # Get list of all local variable names defined in the top level in
        # our code.
        code_names = set(compiled_code.co_names)

        #
        generated_code_frame = sys._getframe(2)

        for local_var_name in generated_code_frame.f_locals:
            # Look for variables that are jinja2 generated top-level locals
            match = re.match(r"l_(\d+)_(?P<var_name>.+)", local_var_name)

            if match:
                var_name = match.group('var_name')

                # If the variable name appears in our code block, and is also a top-level local,
                # we update it to match its new value
                if (var_name in code_names) and (var_name in ctx.vars):
                    # Copy the value to the frame's locals.
                    generated_code_frame.f_locals[local_var_name] = ctx.vars[var_name]
                    # Do some ctypes vodo to make sure the frame locals are actually updated.
                    ctx.exported_vars.add(var_name)
                    # https://pydev.blogspot.com/2014/02/changing-locals-of-frame-frameflocals.html
                    ctypes.pythonapi.PyFrame_LocalsToFast(
                        ctypes.py_object(generated_code_frame),
                        ctypes.c_int(1))

        # Return the captured text.
        return sout.getvalue()


class SimpleGraph:
    def __init__(self):
        self.edges = {}

    def neighbors(self, id):
        return self.edges[id]

example_graph = SimpleGraph()
example_graph.edges = {
    'A': ['B','C'],
    'B': [ 'D','E'],
    'C': [],
    'D': [],
    'E': ['F','G'],
    'F': ['H','I'],
    'G': [],
    'H': [],
    'I': ['J','K'],
    'J': [],
    'K': ['L','M'],
    'L': []
}

import collections

class Queue:
    def __init__(self):
        self.elements = collections.deque()

    def empty(self):
        return len(self.elements) == 0

    def put(self, x):
        self.elements.append(x)

    def get(self):
        return self.elements.popleft()

#from implementation import *

def breadth_first_search_1(graph, start, goal):
    frontier = Queue()
    frontier.put(start)
    visited = {}
    visited[start] = True

    while not frontier.empty():
        current = frontier.get()
        print("Visiting %r" % current)
        if current == goal:
            break
        for next in graph.neighbors(current):
            if next not in visited:
                frontier.put(next)
                visited[next] = True

breadth_first_search_1(example_graph, 'A','M')


# 이하 교재에 있는 코드

from __future__ import annotations
from typing import Any, Type
import hashlib

class Node:
# 해시 구성 노드
    def __init_(self,key : Any, value : Any, next : Node) -> None:
        # 초기화
        self.key = key
        self.value = value
        self.next = next

class ChainedHash:
# 해시 클래스 구현
    def __init__(self,capacity: int) -> None:
        # 초기화
        self.capacity = capacity
        self.table = [None] * self.capacity

    def hash_value(self, key : Any) -> int:
        # 해시값 구하기
        if isinstance(key, int):
            return key % self.capacity
        return(int(hashlib.sha256(str(key).encode()).hexdigest(),16) % self.capacity)

    def search(self, key : Any) -> Any:
        # 해시에서 키 값을 검색한 후 해당 값 반환
        hash = self.hash_value(key)
        p = self.table[hash]

        while p is not None:    # 해시에 어떤 값이 있을 때
            if p.key == key:    # 찾으려는 값과 키 값이 일치하면
                return p.value  # 검색 성공
            p = p.next          # 뒤쪽 노드 주목

    def add(self, key : Any, value : Any) -> bool:
        # 키가 key이고 값이 value인 원소 추가
        hash = self.hash_value(key)
        p = self.table[hash]

        while p is not None:
            if p.key == key:
                return False
            p = p.next

        temp = Node(key, value, self.table[hash])
        self.table[hash] = temp
        return True

    def remove(self, key: Any) -> bool:
        # 해시 값 삭제 함수
        hash = self.hash_value(key)
        p = self.table[hash]
        pp = None

        while p is not None:
            if p.key == key:
                if pp is None:
                    self.table[hash] = p.next
                else:
                    pp.next = p.next
                return True
            pp = p
            p = p.next
        return False

    def dump(self) -> None:
        # 모든 키 값 반환 함수
        for i in range(self.capacity):
            p = self.table[i]
            print(i, end=' ')
            while p is not None:
                print(f' -> {p.key} ({p.value})', end=' ')
                p = p.next
            print()


## This is intended to be run from Azure Devops as a test of succesfull docker deployment
import json
import numpy as np

def test():
# find 30 random samples from test set
    n = 30
    sample_indices = np.random.permutation(X_test.shape[0])[0:n]

    test_samples = json.dumps({"data": X_test[sample_indices].tolist()})
    test_samples = bytes(test_samples, encoding='utf8')

    # predict using the deployed model
    result = service.run(input_data=test_samples)

    # compare actual value vs. the predicted values:
    i = 0
    plt.figure(figsize = (20, 1))

    for s in sample_indices:
        plt.subplot(1, n, i + 1)
        plt.axhline('')
        plt.axvline('')

        # use different color for misclassified sample
        font_color = 'red' if y_test[s] != result[i] else 'black'
        clr_map = plt.cm.gray if y_test[s] != result[i] else plt.cm.Greys

        plt.text(x=10, y =-10, s=result[i], fontsize=18, color=font_color)
        plt.imshow(X_test[s].reshape(28, 28), cmap=clr_map)

        i = i + 1
    plt.show()