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

"""
Created on Mar 21th 2019
Solver-SCIP
Problem-KWKK_MILP: All Components included. Constant powers and Constant Efficiencies. Mixed Tanks.
P8P Style of coding
"""
# %%
# Library and Package imports
import pylab as pl
from pyscipopt import quicksum, Model
from datetime import datetime
import time
from Libraries.auxiliary_functions import AuxFunc,ReadExcel,\
Forecasts,Plots,SPS,DB_Comm
pl.close("all")
# %%
# Booleans for Real/Simulation, Forecast/ NO Forecast
real = True# True/False = Experiment/Simulation
f_cast = True# True/False = darksky forecast/values on file
epex_read = False# True/False = epex forecast/values on file
# %%
# Formulate the MILP Problem as a Function
# N receives the number of time steps to solve per iteration
# dt is the amount of steps to discretizice the model eg. dt =  4 is every 15 min = 1hr /  4 for every hour dt = 1.
# Par* = the parameters that are solved every iteration as the Cost of electricity per time window.

def kwkk_opt(N, dt, past_values, Par_C_El_B, Par_C_El_S, Par_T_Amb_bin, \
             Par_Load_El, Par_Load_H, Par_Load_C, T_HP_max, T_HP_min, \
             T_AdCM_min, LS_CHP_S, LS_HP_S, LS_CCM_S, LS_AdCM_S):

    model = Model("kwkk_milp")  # Name of Model

# Declare the variables of the model as dictionaries

    Pel_CHP, Pgrid_B, Pgrid_S, Pth_COIL, Pth_HP, Pth_CHP, Pth_AdCM_HT, \
    Pth_AdCM_LT, Pel_CCM, Pel_AdCM, Pel_AUX, Pth_CCM, Pel_OC, V_FUEL,\
    CHP_bin, COIL_bin, HP_bin, CCM_bin, AdCM_bin, T_HTES, T_CTES,\
    HP_S_bin, CHP_S_bin, CCM_S_bin, AdCM_S_bin, HTES_slack, HTES_slack_obj = {},{},{},{},{},{},{},{},{},\
    {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}

# Define the variables of the model as lists of pre-defined size. These will be vectors to be fit in the optimisation framework
    for j in range((N)+past_values):  # 0 to N+past_values

        Pel_CHP[j] = model.addVar(vtype="C", name="Pel_CHP_{0}".format(j), lb=0.0, ub=Pmax_CHP_El)
        Pgrid_B[j] = model.addVar(vtype="C", name="Pgrid_B_{0}".format(j), lb=0.0)
        Pgrid_S[j] = model.addVar(vtype="C", name="Pgrid_S_{0}".format(j), lb=0.0)
        Pth_COIL[j] = model.addVar(vtype="C", name="Pth_COIL_{0}".format(j), lb=0.0, ub=Pmax_COIL_Th)
        Pth_HP[j] = model.addVar(vtype="C", name="Pth_HP_{0}".format(j), lb=0.0, ub=Pmax_HP_Th)
        Pth_CHP[j] = model.addVar(vtype="C", name="Pth_CHP_{0}".format(j), lb=0.0, ub=Pmax_CHP_Th)
        Pth_AdCM_HT[j] = model.addVar(vtype="C", name="Pth_AdCM_HT_{0}".format(j), lb=0.0, ub=Pmax_AdCM_HT_Th)
        Pth_AdCM_LT[j] = model.addVar(vtype="C", name="Pth_AdCM_LT_{0}".format(j), lb=0.0, ub=Pmax_AdCM_LT_Th)
        Pel_AdCM[j] = model.addVar(vtype="C", name="Pel_AdCM_{0}".format(j), lb=0.0, ub=Pmax_AdCM_El)
        Pel_CCM[j] = model.addVar(vtype="C", name="Pel_CCM_{0}".format(j), lb=0.0, ub=Pmax_CCM_El)
        Pel_AUX[j] = model.addVar(vtype="C", name="Pel_AUX_{0}".format(j), lb=0.0)
        Pth_CCM[j] = model.addVar(vtype="C", name="Pth_CCM_{0}".format(j), lb=0.0, ub=Pmax_CCM_Th)
        Pel_OC[j] = model.addVar(vtype="C", name="Pel_OC_{0}".format(j), lb=0.0)
        V_FUEL[j] = model.addVar(vtype="C", name="V_FUEL_{0}".format(j), lb=0.0, ub=fuel_IP)
        T_HTES[j] = model.addVar(vtype="C", name="T_HTES_{0}".format(j))  #no bounds due to slacks

        T_CTES[j] = model.addVar(vtype="C", name="T_CTES_{0}".format(j))
        CHP_bin[j] = model.addVar(vtype="B", name="CHP_bin_{0}".format(j))
        COIL_bin[j] = model.addVar(vtype="B", name="COIL_bin_{0}".format(j))
        HP_bin[j] = model.addVar(vtype="B", name="HP_bin_{0}".format(j))
        CCM_bin[j] = model.addVar(vtype="B", name="CCM_bin_{0}".format(j))
        AdCM_bin[j] = model.addVar(vtype="B", name="AdCM_bin_{0}".format(j))
        HP_S_bin[j] = model.addVar(vtype="B", name="HP_S_bin_{0}".format(j))
        CHP_S_bin[j] = model.addVar(vtype="B", name="CHP_S_bin_{0}".format(j))
        CCM_S_bin[j] = model.addVar(vtype="B", name="CCM_S_bin_{0}".format(j))
        AdCM_S_bin[j] = model.addVar(vtype="B", name="AdCM_S_bin_{0}".format(j))
        HTES_slack[j] = model.addVar(vtype="C", name="HTES_slack_{0}".format(j))
        HTES_slack_obj[j] = model.addVar(vtype="C", name="HTES_slack_obj_{0}".format(j))

    # Tank temperatures for the initial and final values in the vector
    T_HTES[(N)+past_values] = model.addVar(vtype="C", name="T_HTES_{0}".format((N)+past_values)) # N+1th variable

    T_HTES[0+past_values] = model.addVar(vtype="C", name="T_HTES_{0}".format(0+past_values), lb=T_HTES_init_0, ub=T_HTES_init_0)  # initial value variable
    T_CTES[(N)+past_values] = model.addVar(vtype="C", name="T_CTES_{0}".format((N)+past_values), lb=CTES_Cold, ub=CTES_Warm)
    T_CTES[0+past_values] = model.addVar(vtype="C", name="T_CTES_{0}".format(0+past_values), lb=T_CTES_init_0, ub=T_CTES_init_0)

# ??? For the section till runtime?? to be explained better!!

    for j in range(0, past_values):

        HP_bin[j] = model.addVar(vtype="I", name="HP_bin_{0}".format(j), lb=int(LS_HP_S[j]), ub=int(LS_HP_S[j]))
        CHP_bin[j] = model.addVar(vtype="I", name="CHP_bin_{0}".format(j), lb=int(LS_CHP_S[j]), ub=int(LS_CHP_S[j]))
        CCM_bin[j] = model.addVar(vtype="I", name="CCM_bin_{0}".format(j), lb=int(LS_CCM_S[j]), ub=int(LS_CCM_S[j]))
        AdCM_bin[j] = model.addVar(vtype="I", name="AdCM_bin_{0}".format(j), lb=int(LS_AdCM_S[j]), ub=int(LS_AdCM_S[j]))

# Define the constraints.
# First the energy balances and the physical constraints
    for t in range(past_values, (N)+past_values):
        # Electricity Balance
        # Pel_CHP - Pel_All_Loads + Pel_Grid_Buy - Pel_Grid_Sell = 0
        # In the objective function buying is +ve and selling is -ve
        # Thus if Pel_CHP - Pel_All_Loads > 0 then optimiser will sell to meet energy balance and make buying = 0. Vice-Versa is also true
        # This is however true only if buying price > selling price. Otherwise both buying and selling may occur to reach better optimisation values\
        # since the ub on these variables is inf. And energy balance can still be met. So binaries must be introduced to constraint bidirectional power flow
        model.addCons(0 == (Pel_AUX[t]) + (Pel_OC[t]) + (Pel_CCM[t]) + (Pel_AdCM[t]) + (Pth_HP[t]*(1./COP_HP)) + \
                      (Pth_COIL[t] * (1./Pth_eff_COIL)) + (Par_Load_El[t-past_values] * (1./dt)) - (Pel_CHP[t]) - Pgrid_B[t] + Pgrid_S[t])
        # Thermal Balance, Heat and Cold
        model.addCons(0 == (((T_HTES[t+1] - T_HTES[t]) * (1./3600)) * (HTES_Cap*rho_w*cp_w)) - ((Pth_HP[t] + Pth_COIL[t] + Pth_CHP[t])\
                            - Pth_AdCM_HT[t] - Par_Load_H[t-past_values] * (1./dt)))
        model.addCons(0 == (((T_CTES[t+1]-T_CTES[t]) * (1./3600)) * (CTES_Cap*rho_w*cp_w)) + ((Pth_CCM[t] + Pth_AdCM_LT[t]) \
                            - Par_Load_C[t-past_values] * (1./dt)))
        # Physical characteristics including switches
        model.addCons(0 == (Pel_CHP[t]*dt) - (Pmax_CHP_El * CHP_bin[t]))
        model.addCons(0 == (Pel_AdCM[t]*dt) - (Pmax_AdCM_El * AdCM_bin[t]))
        model.addCons(0 == (Pel_CCM[t]*dt) - (Pmax_CCM_El * CCM_bin[t]))
        model.addCons(0 == (Pel_AUX[t]*dt) - ((0.7 * HP_bin[t]) + (0.1 * AdCM_bin[t]) + (0.3 * CCM_bin[t]) + (0.1)))  # Auxiliary consumption in \
        # different modes, assumed constant and values from experiments
        model.addCons(0 == (Pel_OC[t]*dt) - ((0.9 * HP_bin[t]) + (0.9 * AdCM_bin[t])+(0.9 * CCM_bin[t])))  # Consumption of OC in different modes,\
        # assumed constant and maximum value that OC consumes = 0.9kWel
        model.addCons(0 == (Pth_HP[t]*dt) - (Pmax_HP_Th * HP_bin[t]))
        model.addCons(0 == (Pth_COIL[t]*dt) - (Pmax_COIL_Th * COIL_bin[t]))
        model.addCons(0 == (Pth_CHP[t]*dt) - (Pmax_CHP_Th * CHP_bin[t]))
        model.addCons(0 == (Pth_AdCM_HT[t]*dt) - (Pmax_AdCM_HT_Th * AdCM_bin[t]))
        model.addCons(0 == (Pth_AdCM_LT[t]*dt) - (Pmax_AdCM_LT_Th * AdCM_bin[t]))
        model.addCons(0 == (Pth_CCM[t]*dt) - (Pmax_CCM_Th * CCM_bin[t]))
        model.addCons(0 == (V_FUEL[t]*dt) - (fuel_IP * CHP_bin[t]))
        # Physical restrictions of components programmed using binaries
        model.addCons(0 <= (CHP_bin[t] + HP_bin[t] <= 1))  # HP and CHP cannot work at the same time
        model.addCons(0 <= (CCM_bin[t] + HP_bin[t] + AdCM_bin[t] <= 1))  # HP, CCM and AdCM cannot run together
        model.addCons(0 <= (Par_T_Amb_bin[t-past_values] + HP_bin[t] <= 1))  # HP can work only if T_Amb > Limit\
        # ParT_amb_bin is obtained via  function "binarytransform".
        # System  constraints big M
        model.addCons((T_HTES[t] - 500*(1-HP_bin[t])) <= T_HP_max)  # if T_HTES > T_HP_max(in K) it it not possible to turn ON the Heat Pump.
        model.addCons((-T_HTES[t] - 500*(1-AdCM_bin[t])) <= -T_AdCM_min)
        model.addCons(HTES_Cold <= (T_HTES[t+1] + HTES_slack[t] <= HTES_Warm) )
        model.addCons(HTES_slack_obj[t] == HTES_slack[t]**2 )  # this formulation used since quadratic terms are not allowed in SCIP cost functions.

# System maximum switching constraints
    for k in range(1, (N)+past_values):  # Number of flanks calculation
        model.addCons((CHP_bin[k-1]-CHP_bin[k]-CHP_S_bin[k] <= 0))  # calculates flanks by calculating for CHP_S_bin after checking binary value at t-1 and t
        model.addCons((-CHP_bin[k-1]+CHP_bin[k]-CHP_S_bin[k] <= 0))  # same as above
        model.addCons((HP_bin[k-1]-HP_bin[k]-HP_S_bin[k] <= 0))  #
        model.addCons((-HP_bin[k-1]+HP_bin[k]-HP_S_bin[k] <= 0))
        model.addCons((CCM_bin[k-1]-CCM_bin[k]-CCM_S_bin[k] <= 0))
        model.addCons((-CCM_bin[k-1]+CCM_bin[k]-CCM_S_bin[k] <= 0))
        model.addCons((AdCM_bin[k-1]-AdCM_bin[k]-AdCM_S_bin[k] <= 0))
        model.addCons((-AdCM_bin[k-1]+AdCM_bin[k]-AdCM_S_bin[k] <= 0))

    for k in range((past_values-1), (N)+past_values):  # for ex. range (3, N+3). this is one value before . The optimisation horizon starts at 4 and goes till N+4

        model.addCons((quicksum(CHP_S_bin[k-j] for j in range(int(min_runtime_CHP*dt))) <= 1))  # loops this loop first before doing the outer loop \
        # Example Calculation: for min_runtime_CHP = 1 and dt = 1 -> CHP_bin[3] <= 1 and then CHP_bin[4] < 1 and so on.\
        # Example Calculation: for min_runtime_CHP = 1 and dt = 2 -> CHP_bin[3] + CHP_bin[2] <= 1 and then CHP_bin[4] + CHP_bin[3] <= 1 and so on.\
        # Example Calculation: for min_runtime_CHP = 1 and dt = 4 -> CHP_bin[3] + CHP_bin[2] + CHP_bin[1] + CHP_bin[0] <= 1
        model.addCons((quicksum(AdCM_S_bin[k-j] for j in range(int(min_runtime_CHP*dt))) <= 1))

    for k in range((past_values-1), (N)+past_values):
        model.addCons((quicksum(HP_S_bin[k-j] for j in range(int(min_runtime_HP*dt))) <= 1))
        # Example Calculation: for min_runtime_HP = 0.5 and dt = 2 -> HP_bin[3] <= 1 and then HP_bin[4] < 1 and so on.\
        # Example Calculation: for min_runtime_HP = 0.5 and dt = 4 -> HP_bin[3] + HP_bin[2] <= 1 and then HP_bin[4] + HP_bin[3] <= 1 and so on.\
        model.addCons((quicksum(CCM_S_bin[k-j] for j in range(int(min_runtime_HP*dt))) <= 1))  #
# Cost Function
    model.setObjective(quicksum((Par_C_El_B[t-past_values]*Pgrid_B[t]) + (fuel_price*V_FUEL[t]) + (1e4* HTES_slack_obj[t]) - (Par_C_El_S[t-past_values]*Pgrid_S[t]) \
                                for t in range(past_values, (N)+past_values)))
# Add the variables to the data set, for later retrieval ----
    model.data = Pel_CHP, Pgrid_B, Pgrid_S, Pth_COIL, Pth_HP, Pth_CHP, V_FUEL, CHP_bin, COIL_bin, \
        HP_bin, CCM_bin, AdCM_bin, T_HTES, CHP_S_bin, HP_S_bin, CCM_S_bin, AdCM_S_bin, Pel_CCM, \
        Pel_AdCM, Pel_AUX, Pel_OC, Pth_CCM, Pth_AdCM_HT, Pth_AdCM_LT, T_CTES, HTES_slack, HTES_slack_obj
    return model
# %%
# Variables to store data at each step of the optimization

Step_T_HTES, Step_T_CTES, Stepplus_T_HTES, Stepplus_T_CTES, T_Amb_f_15 , \
T_Amb_Forec_real_15 , Pth_Load_Heat , Pth_Load_Cool = \
[],[],[],[],[],[],[],[]
# %%
# User input for component parameters

# Powers
Pmin_CHP_Th = 0  # kW_th
Pmax_CHP_Th = 0 # 10.3 "-1.3" is for the thermal losses
Pmin_CHP_El = 0
Pmax_CHP_El = 0  # kW_el
Pmin_COIL_Th = 0
Pmax_COIL_Th = 5.7  # kW_th
Pmin_HP_Th = 0
Pmax_HP_Th = 0  # 16 kW_Th, 0 for Summer when HP is not considered
Pmin_AdCM_Th = 0
Pmax_AdCM_HT_Th = 0  # For the system we have 10 is OK. It is impractical to run COIL and heat up tank to convert to cooling
Pmax_AdCM_LT_Th = 0  # 7.5 with latest test, 6.5 considering Manufacturer's COP of 0.65
Pmin_AdCM_El = 0
Pmax_AdCM_El = 0
Pmin_CCM_Th = 0
Pmax_CCM_Th = 0
Pmin_CCM_El = 0
Pmax_CCM_El = 0

# Efficiencies
COP_HP = 4.45
Pth_eff_COIL = 0.95

# Storage Tank
HTES_Cap = 1.5  # m³, Assuming no loss in the tank
CTES_Cap = 1.5

# Thermodynamical properties
rho_w = 977.8  # kg/m³
cp_w = 4.180  # kJ/kg.K

# Volume flow of Fuel for CHP. Assuming Gas CHP and using HCV
fuel_IP = 1.48  # m³/h

# Fuel Price
fuel_price = 0.72  # Eur/m³ for Gas

# Electricity Base Price
base_sell = 0.150  # Euro/kWh_el
base_buy = 0.209

# User input for temperature ranges in tanks
HTES_Warm = 80 + 273.15  # K, Highest allowed temp in HTES
HTES_Cold = 36 + 273.15  # K, Lowest allowed temp in HTES, 55 for summer considering AdCM
CTES_Warm = 50 + 273.15  # K, 18 could be considered thinkin of a 2 K in-built slack variable for T_Fl_Load of 16°C
CTES_Cold = 10 + 273.15  # K, Optimiser must decide how much the tank should be cooled down

# User input for ambient temperature constraints
T_HP_min = 12  # Minimum ambient temp. to operate the HP

# User input for HTES temp. restrictions for HP and AdCM
T_HP_max = 40 + 273.15  # Max HTES temp. when HP is ON, Could be different in case of mixed tank
T_AdCM_min = 50 + 273.15  # Minimum temp. the HTES must have to operate the AdCM.

#Initial tank temperatures and energies
T_HTES_init_0 = 50 +273.15
T_CTES_init_0 = 13 +273.15  # Initial temperature in the Tank

Q_HTES_init = ((((T_HTES_init_0-HTES_Cold)/3600.)*(HTES_Cap*rho_w*cp_w)))  # 77.5 # kW Initial Power in Tank
Q_CTES_init = ((((T_CTES_init_0-CTES_Cold)/3600.)*(CTES_Cap*rho_w*cp_w)))

# Previous four values
LS_CHP_S = pl.array([0, 0, 0, 0]) # ??? check for possibility of multiplying with min_runtime
LS_CHP_S = pl.array([0, 0, 0, 0]) # ??? check for possibility of multiplying with min_runtime
LS_HP_S = pl.array([0, 0, 0, 0])
LS_CCM_S = pl.array([0, 0, 0, 0])
LS_AdCM_S = pl.array([0, 0, 0, 0])

""" User input to formulate the MILP Problem and discretisations The horizon part is a bit complicated to make the minimum run time constraint work.
The entire horizon over which the calculation works is the sum of the past horizon and forecast horizon. Calculation horizon = [0:N+past_values] which could be imagined to be made up of \
(0,1,2,3, 'past_values', 5 ,6 .... N + 'past_values'). Thus for the optimisation itself the user-defined value of 'past_values' is the first"""

dt = 4  # Hour splitting factor or Discretization step. dt = 60 mins / time step(in mins). For ex. if time step = 15 mins, dt = 4.\
# This is called control_actions_per_hour in MINLP problem
forecast_horizon = 24 * 1  # hours to solve each iteration * number of days . This is the forecast horizon
N = forecast_horizon * dt  # N Total number of discretisations over the forecast horizon. +1 for Euler intergrator.
sampling_time = 60 / dt # in min  --- Time to wait between iterations
t_amb_horz = forecast_horizon + 1  # 168hours in total can be set. this means weather will be forecasted for the next t_amb_horz hours.\
# 25 is the min required as it is forecasting for the 24 h + 15 min
past_values = 4  # must be >= to minimum run times. This represents the number of values that should be remembered for the calculation horizon
min_runtime_HP = 1  # minimum run time of HP and CCM in hours. Should be defined such that int(min_runtime_HP * dt) > 1.\
# For ex. for a dt = 1 (1 hour grid) it is not sensible to keep a min_runtime of 0.5 hours
min_runtime_CHP = 1  # minimum run time of CHP and AdCM in hours
path = "C:/Users/PXI-PC/Documents/"
file_name = "Winter_7.5kW_Mixed_2019.05.23_Python.xlsx"
sheet_name = "Loadprofil_EPEX_EWERK_2week"

# Start the load depending on the hour
st = datetime.now().time().hour*dt + int(datetime.now().time().minute/(60/dt))  # In this case st is also a value based on the actual time and multiple of dt
#st = 0 * dt  # Give here number of hours to move ahead in the load file. st = Starting hour * dt.
# %%
# Define number of iterations to solve
# Start the solving iteration loop
# Variable declaration of the looping
i = 0
#steps = 1  # DE- ACTIVATE for Experiments
while True:  # ACTIVATE for experiments
#while i != steps:  # DE- ACTIVATE for Experiments. To solve for the amount of time steps defined
    # Define the incoming variables
    start_time = time.time()
    date = datetime.now()
    solv_error = None
    print('CPU_Clock_Time',date.time())

    """------ Retrieve data from excel ----"""
    file_data = ReadExcel(path + file_name, sheet_name)
    Pth_Load_Heat_File, Pth_Load_Cool_File, Time, Pel_Load, C_El_B, C_El_S, T_Amb \
    = file_data.excel_data(dt)

    """------ Retrieve load data from sps + correction ----"""
    if real:
        real_load = SPS.read_sps("LOAD_HC_W_PT_M___")
    else:
        real_load = None

    Pth_Load_Heat, Pth_Load_Cool = AuxFunc.correction_load(i, st, Pth_Load_Heat_File, Pth_Load_Heat, \
                                                   Pth_Load_Cool_File, Pth_Load_Cool, real_load)

    if real:  # If running real mode, read from sps the initial value
        T_HTES_init_0 = SPS.read_sps("HTES_H_W_T_M_IT_"+str(1)+"_") + 273.15
        T_CTES_init_0 = (SPS.read_sps("CTES_C_W_T_M_IT_"+str(1)+"_") + SPS.read_sps("CTES_C_W_T_M_IT_"+str(2)+"_") \
        + SPS.read_sps("CTES_C_W_T_M_IT_"+str(3)+"_") + SPS.read_sps("CTES_C_W_T_M_IT_"+str(4)+"_"))/4 + 273.15  # Average of the 4 CTES temperatures \
                         # since delta T is not large

    """------ Electricity Forecast ----"""
    try:
        da_buy15, da_sell15 = Forecasts.epexdata(dt, N, date, base_sell, base_buy, epex_read)
        Par_C_El_B = da_buy15
        Par_C_El_S = da_sell15
        print('EPEX READ')
    except:
        print('EPEX NOT READ')
        Par_C_El_B = C_El_B[0+i+st:(N)+i+st]  # updating the parameter acccording to where we want to start
        Par_C_El_S = C_El_S[0+i+st:(N)+i+st]

    """------ Temperature forecast ----"""
    # call the forecast up to "t_amb_horz" times, transform it to 15 min intevals and append each one to the last forecast ´+ 1 step. Also first hour is same as real Aux_Tamb value
    if real:
        sps_temp = SPS.read_sps("AUX_HC_A_T_M___")
    else:
        sps_temp = None
    T_Amb_f_15, T_Amb_Forec_real_15 = \
    Forecasts.t_amb_forecast(t_amb_horz, i, T_Amb_f_15, sps_temp,f_cast,T_Amb,T_Amb_Forec_real_15,dt)

    """------ Parameters ----"""
    # define the parameter values that will change through time
    Par_T_Amb_bin = AuxFunc.binarytransform(T_HP_min, T_Amb_f_15[0+i:(N)+i])
    Par_Load_El = Pel_Load[0+i+st:(N)+i+st]
    Par_Load_H = Pth_Load_Heat[0+i+st:(N)+i+st]
    Par_Load_H_File = Pth_Load_Heat_File[0+i+st:(N)+i+st]
    Par_Load_C_File = Pth_Load_Cool_File[0+i+st:(N)+i+st]
    Par_Load_C = Pth_Load_Cool[0+i+st:(N)+i+st]

    """------ Create the optimization model from function ----"""
    try:
        model = kwkk_opt(N, dt, past_values, Par_C_El_B, Par_C_El_S, Par_T_Amb_bin, \
                         Par_Load_El, Par_Load_H, Par_Load_C, T_HP_max, T_HP_min, \
                         T_AdCM_min, LS_CHP_S, LS_HP_S, LS_CCM_S, LS_AdCM_S)

        print("Initial Temp = ", T_HTES_init_0-273.15, T_CTES_init_0-273.15)
        print("Iteration No.= _{0}_".format(i))

        """---------------- Optimize the model ------------------"""

        model.setRealParam('limits/time', 30)  # for limiting the solving time (seconds)
        model.optimize()  # optimize the model
    except:
        solv_error = 'Solving_error'
# Extract the variables from the model
    Pel_CHP, Pgrid_B, Pgrid_S, Pth_COIL, Pth_HP, Pth_CHP, V_FUEL, CHP_bin, COIL_bin, \
        HP_bin, CCM_bin, AdCM_bin, T_HTES, CHP_S_bin, HP_S_bin, CCM_S_bin, AdCM_S_bin, \
        Pel_CCM, Pel_AdCM, Pel_AUX, Pel_OC, Pth_CCM, Pth_AdCM_HT, Pth_AdCM_LT, T_CTES, HTES_slack, HTES_slack_obj = model.data
# %%
# Optimal variables
# Retrieve the  values of each optimization and append them as the optimal values
    P_El_CHP_opt = pl.array([model.getVal(Pel_CHP[j]) for j in range(past_values, (N)+past_values)])*dt
    P_El_CCM_opt = pl.array([model.getVal(Pel_CCM[j]) for j in range(past_values, (N)+past_values)])*dt
    P_El_AdCM_opt = pl.array([model.getVal(Pel_AdCM[j]) for j in range(past_values, (N)+past_values)])*dt
    P_El_AUX_opt = pl.array([model.getVal(Pel_AUX[j]) for j in range(past_values, (N)+past_values)])*dt
    P_El_OC_opt = pl.array([model.getVal(Pel_OC[j]) for j in range(past_values, (N)+past_values)])*dt
    Pgrid_B_opt = pl.array([model.getVal(Pgrid_B[j]) for j in range(past_values, (N)+past_values)])*dt
    Pgrid_S_opt = pl.array([model.getVal(Pgrid_S[j]) for j in range(past_values, (N)+past_values)])*dt
    Pth_COIL_opt = pl.array([model.getVal(Pth_COIL[j]) for j in range(past_values, (N)+past_values)])*dt
    Pth_HP_opt = pl.array([model.getVal(Pth_HP[j]) for j in range(past_values, (N)+past_values)])*dt
    Pth_CHP_opt = pl.array([model.getVal(Pth_CHP[j]) for j in range(past_values, (N)+past_values)])*dt
    Pth_AdCM_HT_opt = pl.array([model.getVal(Pth_AdCM_HT[j]) for j in range(past_values, (N)+past_values)])*dt
    Pth_AdCM_LT_opt = pl.array([model.getVal(Pth_AdCM_LT[j]) for j in range(past_values, (N)+past_values)])*dt
    Pth_CCM_opt = pl.array([model.getVal(Pth_CCM[j]) for j in range(past_values, (N)+past_values)])*dt
    V_FUEL_opt = pl.array([model.getVal(V_FUEL[j]) for j in range(past_values, (N)+past_values)])
# Binary Decision Variables
    CHP_bin_opt = pl.array([model.getVal(CHP_bin[j]) for j in range(past_values, (N)+past_values)])
    COIL_bin_opt = pl.array([model.getVal(COIL_bin[j]) for j in range(past_values, (N)+past_values)])
    HP_bin_opt = pl.array([model.getVal(HP_bin[j]) for j in range(past_values, (N)+past_values)])
    CCM_bin_opt = pl.array([model.getVal(CCM_bin[j]) for j in range(past_values, (N)+past_values)])
    AdCM_bin_opt = pl.array([model.getVal(AdCM_bin[j]) for j in range(past_values, (N)+past_values)])
# Tank Temperatures
    T_HTES_opt = pl.array([model.getVal(T_HTES[j]) for j in range(past_values, (N+1)+past_values)])
    T_CTES_opt = pl.array([model.getVal(T_CTES[j]) for j in range(past_values, (N+1)+past_values)])
    HTES_slack_opt = pl.array([model.getVal(HTES_slack_obj[j]) for j in range(past_values, (N)+past_values)])

    E_El_HP_opt = Pth_HP_opt*(1./COP_HP)
    E_El_COIL_opt = Pth_COIL_opt*(1./Pth_eff_COIL)

# Save the first optimal actions from each optimal solution for printing the whole optimal actions in time
    Step_T_HTES.append(T_HTES_opt[0])
    Step_T_CTES.append(T_CTES_opt[0])

    if i == 0:  # Used for plotting the temperature expected versus real temperature in the tank
        Stepplus_T_HTES.append(T_HTES_opt[0])
        Stepplus_T_CTES.append(T_CTES_opt[0])

    Stepplus_T_HTES.append(T_HTES_opt[1]) # This is the temperature which the model would have achieved if the optimal solution would have been applied
    Stepplus_T_CTES.append(T_CTES_opt[1])

# Part to append optimal control values  to the past defined values and delete the first value of the past list. Acts like a shifing mechanism
    LS_CHP_S = pl.delete(pl.append(LS_CHP_S, pl.array([model.getVal(CHP_bin[0+past_values])])), 0)
    LS_HP_S = pl.delete(pl.append(LS_HP_S, pl.array([model.getVal(HP_bin[0+past_values])])), 0)
    LS_CCM_S = pl.delete(pl.append(LS_CCM_S, pl.array([model.getVal(CCM_bin[0+past_values])])), 0)
    LS_AdCM_S = pl.delete(pl.append(LS_AdCM_S, pl.array([model.getVal(AdCM_bin[0+past_values])])), 0)

# %% Calculating and writing the optimal mode

    operation_mode = SPS.oprtmode(HP_bin_opt[0], CHP_bin_opt[0], CCM_bin_opt[0], AdCM_bin_opt[0])
    print('SOLVING TIME FOR OPTIMISER =', round(model.getSolvingTime(),2),'s')
    print('TOTAL TIME FOR OPTIMISER =', round(model.getTotalTime(),2),'s')

    if real:
        SPS.write_sps(operation_mode, COIL_bin_opt[0])  # To write the optimal mode and coil switch on the sps
# %%
# Plot Graphs
    Plots.plotall(Time[0+i+st:(N)+i+st], 1 , dt, Par_Load_H, Pth_CHP_opt, Pth_HP_opt, Pth_COIL_opt, \
                 Par_C_El_B, Par_C_El_S, E_El_HP_opt, E_El_COIL_opt, Par_Load_El, Pgrid_B_opt, \
                 Pgrid_S_opt, P_El_CHP_opt, T_HTES_opt, T_Amb_f_15[0+i:(N)+i], T_HP_min, \
                 COIL_bin_opt, CHP_bin_opt, HP_bin_opt, T_Amb_Forec_real_15[0+i:(N)+i], \
                 Par_Load_H_File, Par_Load_C_File, Par_Load_C, P_El_AUX_opt, P_El_CCM_opt, P_El_AdCM_opt, Pth_AdCM_HT_opt, \
                 Pth_AdCM_LT_opt, P_El_OC_opt, Pth_CCM_opt, CCM_bin_opt, AdCM_bin_opt, N, T_CTES_opt, \
                 Q_HTES_init, Q_CTES_init, HTES_Cap, rho_w, cp_w, CTES_Cap)
    Plots.plotTdev(Step_T_HTES, Stepplus_T_HTES,0,'*')  # plot deviation in HTES temperature. Check which one to ACTIVATE
#    Plots.plotTdev(Step_T_CTES, Stepplus_T_CTES,0,'*')  # plot deviation in CTES temperature

# %%
# Write to the IMG_KWKK Database

    data = {
        'Pel_KWKK': Pgrid_B_opt-Pgrid_S_opt,
        'CHP_Switch': CHP_bin_opt,
        'HP_Switch': HP_bin_opt,
        'COIL_Switch': COIL_bin_opt,
        'CCM_Switch': CCM_bin_opt,
        'AdCM_Switch': AdCM_bin_opt,
        'T_HTES': T_HTES_opt[0:N],
        'T_CTES': T_CTES_opt[0:N],
        'T_Amb': T_Amb_f_15[0+i:(N)+i],
        'Heat_Load': Par_Load_H,
        'Cool_Load': Par_Load_C,
        'P_El_CHP': P_El_CHP_opt,
        'P_El_HP': E_El_HP_opt,
        'P_El_COIL': E_El_COIL_opt,
        'P_El_CCM': P_El_CCM_opt,
        'P_El_AdCM': P_El_AdCM_opt,
        'P_El_AUX': P_El_AUX_opt,
        'P_El_OC': P_El_OC_opt,
        'Pgrid_B': Pgrid_B_opt,
        'Pgrid_S': Pgrid_S_opt,
        'Pth_COIL': Pth_COIL_opt,
        'Pth_HP': Pth_HP_opt,
        'Pth_CHP': Pth_CHP_opt,
        'Pth_AdCM': Pth_AdCM_HT_opt,
        'Pth_AdCM_LT' :Pth_AdCM_LT_opt,
        'Pth_CCM': Pth_CCM_opt,
        'El_Price_Buy' : Par_C_El_B,
        'El_Price_Sell' : Par_C_El_S
            }

    DB_Comm.db_rw(N, date, (Pgrid_B_opt-Pgrid_S_opt), data, write = True)  # Activate or Deactivate

# %%
# Calculate the time correction. Also to make sure we start at multiple of the sampling_time
    end_time = time.time()
    print('TOTAL TIME TAKEN = ',round(end_time-start_time,2),'s')
    time_correction = ((sampling_time - (((int(datetime.now().time().minute/(60/dt))+1)*(60/dt))-\
                                         (datetime.now().time().minute)))*60)+datetime.now().second

    time.sleep((sampling_time*60)-time_correction) #  ACTIVATE for experiments

# For simulation purpose next optimisation the initial temperature in tank is reset.
    if real:
        pass
    else:
        T_HTES_init_0 = model.getVal(T_HTES[1+past_values])
        T_CTES_init_0 = model.getVal(T_CTES[1+past_values])

    print('THE TOTAL COST OF OPERATION FOR THE FORECAST HORIZON IS=', round(model.getObjVal()-pl.sum(HTES_slack_opt)*1e4,2),'€')

    i = i+1  # End of the loop, rest of calculations and increment i


import os
import sys
import json
import kenlm

if __name__ == '__main__':
    in_json_file = sys.argv[1]
    lm_path = sys.argv[2]
    rescore_weight = float(sys.argv[3])
    out_json_file = sys.argv[4]
    print(sys.argv)

    model = kenlm.LanguageModel(lm_path)
    print('{0}-gram model'.format(model.order))

    new_json = {}
    with open(in_json_file, 'r', encoding='utf-8') as f:
        j = json.load(f)

    for x in j['utts']:
        try:
            rec_text = j['utts'][x]['output'][0]['rec_text'].replace('<eos>', '')
            text = j['utts'][x]['output'][0]['text']
            ##if rec_text != text:
            new_json[x] = j['utts'][x]
            new_scores = []
            for num in range(12):
                rec_token = j['utts'][x]['rec_token[{0:05d}]'.format(num)].replace('<eos>', '')
                score = float(j['utts'][x]['score[{0:05d}]'.format(num)])
                kenlm_score = float(model.score(rec_token) / len(rec_token))
                new_score = rescore_weight * kenlm_score + score
                new_json[x]['kenlm_score' + '[' + '{:05d}'.format(num) + ']'] = kenlm_score
                new_scores.append(new_score)

            max_score = max(new_scores)
            max_score_idx = new_scores.index(max(new_scores))
            j['utts'][x]['output'][0]['rec_text'] = j['utts'][x]['rec_text[{0:05d}]'.format(max_score_idx)]
            j['utts'][x]['output'][0]['rec_token'] = j['utts'][x]['rec_token[{0:05d}]'.format(max_score_idx)]
            j['utts'][x]['output'][0]['rec_tokenid'] = j['utts'][x]['rec_tokenid[{0:05d}]'.format(max_score_idx)]
        except:
            new_json[x] = j['utts'][x]

    with open(out_json_file, 'w', encoding='utf-8') as f:
        f.write(json.dumps({'utts': new_json}, indent=4, sort_keys=True, ensure_ascii=False))


from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from django.http.response import JsonResponse

from colorpredApp.models import ColorInterface
from colorpredApp.serializers import ColorInterfaceSerializer
from colorpredApp.models import SaveColors
from colorpredApp.serializers import SaveColorsSerializer

from colorpredApp.models import ManageAudioBooks
from colorpredApp.serializers import ManageAudioBooksSerializer

import pandas as pd
from sklearn.neighbors import NearestNeighbors

from sklearn.linear_model import LogisticRegression
import random
import warnings
#import matplotlib.pyplot as plt

#displaying colors that relavant for color type (protanopia/deutanopia) seperately
@csrf_exempt
def colorsPred(request, id=0):
    if request.method=='POST':
        data = JSONParser().parse(request)
        type = data.get('type','')
        print(type)

    # Step 1: Load and preprocess the dataset
    data = pd.read_csv('./color_names3.csv')

    # Convert hex color codes to RGB - Preprocessing
    data['Red (8 bit)'] = data['Hex (24 bit)'].apply(lambda x: int(x[1:3], 16))
    data['Green (8 bit)'] = data['Hex (24 bit)'].apply(lambda x: int(x[3:5], 16))
    data['Blue (8 bit)'] = data['Hex (24 bit)'].apply(lambda x: int(x[5:7], 16))

    # Encode boolean values as 0 and 1
    data['Visible to Protonopia'] = data['Visible to Protonopia'].astype(int)
    data['Visible to deuternopia'] = data['Visible to deuternopia'].astype(int)

    # Split the dataset into training and testing sets
    X = data[['Red (8 bit)', 'Green (8 bit)', 'Blue (8 bit)']]
    y_protonopia = data['Visible to Protonopia']
    y_deuternopia = data['Visible to deuternopia']

    warnings.filterwarnings("ignore")

    # Create the LogisticRegression models
    # This model fit to the data for predicting color visibility to different types of color blindness (Protonopia and Deuternopia)
    model_protonopia = LogisticRegression()
    model_protonopia.fit(X, y_protonopia)

    model_deuternopia = LogisticRegression()
    model_deuternopia.fit(X, y_deuternopia)

    #Function to predict visible colors for Protonopia
    def predict_visible_colors_protonopia():
        visible_colors = []
        for index, row in data.iterrows():
            color_rgb = [row['Red (8 bit)'], row['Green (8 bit)'], row['Blue (8 bit)']]
            if model_protonopia.predict([color_rgb])[0]:
                #visible_colors.append(row['Name'])
                visible_colors.append(row['Hex (24 bit)'])

        #Randomly select 5 colors if there are more than 5
        if len(visible_colors) > 5:
            visible_colors = random.sample(visible_colors, 5)
        return visible_colors

    # Function to predict visible colors for Deuternopia
    def predict_visible_colors_deuternopia():
        visible_colors = []
        for index, row in data.iterrows():
            color_rgb = [row['Red (8 bit)'], row['Green (8 bit)'], row['Blue (8 bit)']]
            if model_deuternopia.predict([color_rgb])[0]:
                #visible_colors.append(row['Name'])
                visible_colors.append(row['Hex (24 bit)'])

        # Randomly select 5 colors if there are more than 5
        if len(visible_colors) > 5:
            visible_colors = random.sample(visible_colors, 5)
        return visible_colors

    # Example usage
    # color_blind_type = input("Enter the type of color blindness (protonopia or deuternopia): ").strip().lower()

    color_blind_type = type.strip().lower()

    response_data = {}

    if color_blind_type == 'protanopia':
        visible_colors = predict_visible_colors_protonopia()
        print("Visible Colors for Protonopia:")
        for color in visible_colors:
            print(color)
            response_data = visible_colors
    elif color_blind_type == 'deuteranopia':
        visible_colors = predict_visible_colors_deuternopia()
        print("Visible Colors for Deuteranopia:")
        for color in visible_colors:
            print(color)
            response_data = visible_colors
    else:
        print("Invalid color blindness type. Please enter 'protanopia' or 'deuteranopia'.")

    return JsonResponse(response_data, safe=False)

@csrf_exempt
def predictcolorApi(request, id=0):
    if request.method=='POST':
        data = JSONParser().parse(request)
        color = data.get('color','')
        print(color)

    #Load the dataset
    df = pd.read_csv("./color_names.csv")

    # Preprocessing stepsnm
    # For example, convert hex color codes to RGB values
    df['Hex (24 bit)'] = df['Hex (24 bit)'].apply(lambda x: x.lstrip('#'))  # Remove '#' if present
    df['R'] = df['Hex (24 bit)'].apply(lambda x: int(x[0:2], 16) if len(x) == 6 else 0)
    df['G'] = df['Hex (24 bit)'].apply(lambda x: int(x[2:4], 16) if len(x) == 6 else 0)
    df['B'] = df['Hex (24 bit)'].apply(lambda x: int(x[4:6], 16) if len(x) == 6 else 0)

    # Prepare the input features
    X = df[['R', 'G', 'B']]

    # Train the model
    model = NearestNeighbors(n_neighbors=5, algorithm='ball_tree')
    model.fit(X)

    def get_similar_colors(color, num_neighbors=10):
        # Preprocess the user's input color
        r = int(color[0:2], 16)
        g = int(color[2:4], 16)
        b = int(color[4:6], 16)

        # Find the nearest neighbors
        distances, indices = model.kneighbors([[r, g, b]], n_neighbors=num_neighbors)

        # Get the similar colors from the dataset
        similar_colors = df.loc[indices[0], ['Hex (24 bit)', 'Name']]

        return similar_colors

    #color_code = '00ff00'  # Red color code

    similar_colors = get_similar_colors(color)
    similar_colors_dict = similar_colors.to_dict(orient='records')

    return JsonResponse({'predictedcolors': similar_colors_dict}, safe=False)

# Create your views here.
@csrf_exempt
def colorInterfaceApi(request, id=0):
    if request.method=='GET':
        colorinterface = ColorInterface.objects.all()
        colorinterface_serializer = ColorInterfaceSerializer(colorinterface, many=True)
        return JsonResponse(colorinterface_serializer.data, safe=False)
    elif request.method=='POST':
        colorinterface_data=JSONParser().parse(request)
        colorinterface_serializer = ColorInterfaceSerializer(data=colorinterface_data)
        if colorinterface_serializer.is_valid():
            colorinterface_serializer.save()
            return JsonResponse("Added Successfully!!", safe=False)
        return JsonResponse("Failed to Add.", safe=False)
    elif request.method=='PUT':
        colorinterface_data = JSONParser().parse(request)
        colorinterface = ColorInterface.objects.get(studentId=colorinterface_data['studentId'])
        colorinterface_serializer = ColorInterfaceSerializer(colorinterface, data=colorinterface_data)
        if colorinterface_serializer.is_valid():
            colorinterface_serializer.save()
            return JsonResponse("Updated Successfully!!", safe=False)
        return JsonResponse("Failed to Update.", safe=False)
    elif request.method=='DELETE':
        colorinterface_data = JSONParser().parse(request)
        colorinterface = ColorInterface.objects.get(studentId=colorinterface_data['studentId'])
        colorinterface.delete()
        return JsonResponse("Deleted Succeffully!!", safe=False)

@csrf_exempt
def manageAudioBooksApi(request, id=0):
    if request.method=='GET':
        manageaudiobooks = ManageAudioBooks.objects.all()
        manageaudiobooks_serializer = ManageAudioBooksSerializer(manageaudiobooks, many=True)
        return JsonResponse(manageaudiobooks_serializer.data, safe=False)
    elif request.method=='POST':
        manageaudiobooks_data=JSONParser().parse(request)
        manageaudiobooks_serializer = ManageAudioBooksSerializer(data=manageaudiobooks_data)
        if manageaudiobooks_serializer.is_valid():
            manageaudiobooks_serializer.save()
            return JsonResponse("Added Successfully!!", safe=False)
        return JsonResponse("Failed to Add.", safe=False)
    elif request.method=='PUT':
        manageaudiobooks_data = JSONParser().parse(request)
        manageaudiobooks = ManageAudioBooks.objects.get(bookId=manageaudiobooks_data['bookId'])
        manageaudiobooks_serializer = ManageAudioBooksSerializer(manageaudiobooks, data=manageaudiobooks_data)
        if manageaudiobooks_serializer.is_valid():
            manageaudiobooks_serializer.save()
            return JsonResponse("Updated Successfully!!", safe=False)
        return JsonResponse("Failed to Update.", safe=False)
    elif request.method=='DELETE':
        manageaudiobooks_data = JSONParser().parse(request)
        manageaudiobooks = ManageAudioBooks.objects.get(bookId=manageaudiobooks_data['bookId'])
        manageaudiobooks.delete()
        return JsonResponse("Deleted Succeffully!!", safe=False)

@csrf_exempt
def saveColorsApi(request, pk=0):
    if request.method == 'GET':
        savecolors = SaveColors.objects.all()
        savecolors_serializer = SaveColorsSerializer(savecolors, many=True)
        return JsonResponse(savecolors_serializer.data, safe=False)

    elif request.method == 'POST':
        savecolors_data = JSONParser().parse(request)
        savecolors_serializer = SaveColorsSerializer(data=savecolors_data)
        if savecolors_serializer.is_valid():
            savecolors_serializer.save()
            return JsonResponse("Added Successfully!!", safe=False)
        return JsonResponse(savecolors_serializer.errors, status=400)

    elif request.method == 'PUT':
        try:
            savecolors_data = JSONParser().parse(request)
            savecolors = SaveColors.objects.get(userid=savecolors_data['userid'])
            savecolors_serializer = SaveColorsSerializer(savecolors, data=savecolors_data)
            if savecolors_serializer.is_valid():
                savecolors_serializer.save()
                return JsonResponse("Updated Successfully!!", safe=False)
            return JsonResponse(savecolors_serializer.errors, status=400)
        except SaveColors.DoesNotExist:
            return JsonResponse("SaveColors with the specified ID does not exist.", status=404)

    elif request.method == 'DELETE':
        try:
            savecolors = SaveColors.objects.get(pk=pk)
            savecolors.delete()
            return JsonResponse("Deleted Successfully!!", safe=False)
        except SaveColors.DoesNotExist:
            return JsonResponse("SaveColors with the specified ID does not exist.", status=404)

    # get by userid
    elif request.method == 'GET':
        try:
            savecolors = SaveColors.objects.filter(userid=pk)
            savecolors_serializer = SaveColorsSerializer(savecolors, many=True)
            return JsonResponse(savecolors_serializer.data, safe=False)
        except SaveColors.DoesNotExist:
            return JsonResponse("SaveColors for the specified user do not exist.", status=404)


import cv2
import numpy as np
import pickle
import shutil
from os import path, walk, makedirs, getcwd, walk, scandir
from final_project.settings import BASE_DIR

class Recognize:
    def recognize(self):
        face_classifier = cv2.CascadeClassifier(str(BASE_DIR) + '\\fr\\haarcascade_frontalface_default.xml')
        recognizer_lbph = cv2.face.LBPHFaceRecognizer_create()
        recognizer_lbph.read(str(BASE_DIR) + "\\fr\\trainner.yml")

        labels = {}
        with open(str(BASE_DIR) + '\\labels\\face-labels.pickle', 'rb') as file:
            org_labels = pickle.load(file)
            labels = {v: k for k, v in org_labels.items()}

        cap = cv2.VideoCapture(0)
        username = ''
        while True:
            retval, frame = cap.read()
            # Face detection
            gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            cap_face = face_classifier.detectMultiScale(gray_frame, scaleFactor=1.3, minNeighbors=5)

            for (x, y, w, h) in cap_face:
                roi_gray = gray_frame[y:y + h, x:x + h]
                cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)

                # Recognition based on trained model
                id_, confidence = recognizer_lbph.predict(roi_gray)
                confidence = int(100 * (1 - (confidence / 300)))
                #if face is recognized
                if confidence > 80:
                    name = labels[id_]
                    cv2.putText(frame, str(name) + ' ' + str(confidence) + '%', (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2)
                    username = str(name)
                    #return username of recognized user
                    return username
                #if face is not recognized then
                else:
                    cv2.putText(frame, 'unknown', (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2)
                    return username

            cv2.imshow('frame', frame)
            if cv2.waitKey(30) & 0xFF == ord('q'):
                break

        cap.release()
        cv2.destroyAllWindows()

        return username

class Training:
    def labels_for_training_data(self):
        current_id = 0
        label_ids = dict()
        faces, faces_ids = list(), list()

        # Go through directories and find label and path to image
        for root, dirs, files in walk(str(BASE_DIR) + '\\data'):
            for file in files:
                if file.endswith('.jpg') or file.endswith('.png'):
                    img_path = path.join(root, file)
                    label = path.basename(root).replace(' ', '-')
                    # print('LABEL :- ',s label)
                    if label not in label_ids:
                        label_ids[label] = current_id
                        current_id += 1
                    id_ = label_ids[label]

                    test_img = cv2.imread(img_path)
                    test_img = cv2.cvtColor(test_img, cv2.COLOR_BGR2GRAY)
                    if test_img is None:
                        print('Image not loaded properly')
                        continue

                    faces.append(test_img)
                    faces_ids.append(id_)

        # Make directory with labels doesn't exist make directory and file with labels
        # print(path.exists(str(BASE_DIR) + 'labels\\'))
        # if not path.exists(str(BASE_DIR) + 'labels\\'):
        #     makedirs('labels\\')
        with open(str(BASE_DIR) + '\\labels\\face-labels.pickle', 'wb') as file:
            pickle.dump(label_ids, file)

        return faces, faces_ids

    def train_classifier(self, train_faces, train_faces_ids):
        """Function train model to recognize face with local binary pattern histogram algorithm"""
        recognizer_lbph = cv2.face.LBPHFaceRecognizer_create()
        print('Training model in progress...')
        recognizer_lbph.train(train_faces, np.array(train_faces_ids))
        print('Saving...')
        recognizer_lbph.save(str(BASE_DIR) + '\\fr\\trainner.yml')
        print('Model training complete!')

class Capture(Training, Recognize):
    #face_classifier = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

    def __init__(self):
        # print(str(BASE_DIR))
        self.face_classifier = cv2.CascadeClassifier(str(BASE_DIR) + '\\fr\\haarcascade_frontalface_default.xml')
        # print('Enter username: ', end='')
        self.directory = ''
        self.username = self.directory
        self.currDirectory = getcwd() + '\\data'
        print('Current-working directroy', self.currDirectory)
        # if not path.exists(str(BASE_DIR) + '\\data\\' + str(self.directory.lower())):
        #     makedirs(str(BASE_DIR) + '\\data\\' + str(self.directory.lower()))

    def face_extractor(self, cap_frame):
        """Function detect face and return region of interest"""
        gray_frame = cv2.cvtColor(cap_frame, cv2.COLOR_BGR2GRAY)  # cv2.cvtColor()  method is used to convert an image from one color space to another
        cap_face = self.face_classifier.detectMultiScale(gray_frame, scaleFactor=1.3, minNeighbors=5)  # Detects objects of different sizes in the input image. The detected objects are returned as a list of rectangles.

        for (x, y, w, h) in cap_face:
            roi = cap_frame[y:y + h, x:x + w]
            return roi

    def deleteTheDirectory(self):
        flag = False
        for dirpath, dirnames, filenames in walk(self.currDirectory):
            print('dirnames', dirnames)
            for x in dirnames:
                print('x', x, 'usernmae', self.username)
                if x == self.username.lower():
                    result = dirpath
                    flag = True
                    break
            if flag:
                break
        #print(result)

        for f in scandir(result):
            if f.is_dir() and f.name == self.username.lower():
                final = f.path
                break

        #print(final)
        shutil.rmtree(final)

    def invokeTraining(self):
        faces, face_ids = self.labels_for_training_data()
        self.train_classifier(faces, face_ids)

    def takePhotos(self, data):
        self.directory = data
        self.username = self.directory

        if not path.exists(str(BASE_DIR) + '\\data\\' + str(self.directory)):
            makedirs(str(BASE_DIR) + '\\data\\' + str(self.directory))

        cap = cv2.VideoCapture(0)
        count = 0
        not_found = 0

        while True:
            ret, frame = cap.read()
            if self.face_extractor(frame) is not None:
                face = cv2.resize(self.face_extractor(frame), (200, 200))
                face = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY)

                # If face was detected save region of interest in user directory
                file_name_path = str(BASE_DIR) + '\\data\\'+str(self.directory)+'\\'+str(count)+'.jpg'
                # str(BASE_DIR) +'\\fr\\dataset\\User.' + str(face_id) + '.' + str(count) + ".jpg"
                print(file_name_path)
                res = cv2.imwrite(file_name_path, face)
                print('imwrite', res)
                count += 1

                # Print number of already saved samples
                cv2.putText(face, str(count), (50, 50), cv2.FONT_HERSHEY_COMPLEX, 1, 200, 2)
                cv2.imshow('Collecting samples', face)
            else:
                #print('Face not found')
                not_found += 1

            if cv2.waitKey(30) & 0xFF == ord('q') or count == 50:
                break

        cap.release()
        cv2.destroyAllWindows()
        #print('Collecting samples complete!')
        #print(count)
        # if images without face are <= 5 out of total 15 images train the data else
        # print('not found', not_found, 'count', count)
        # if not_found <= 5:
        #     return True
        # else:
        #     return False
        return True

# c = Capture()
# result = c.takePhotos()
# if not result:
#     c.deleteTheDirectory()
#     print("take the photos again")
# else:
#     c.invokeTraining()
#     user = c.recognize()
#     if len(user) == 0:
#         print("Not allowed")
#     else:
#         print(user)

'''
r = Recognize()
user = r.recognize()
if len(user) == 0:
    print("not allowed")
else:
    print(user)
'''

#Steps to run from signup using Capture:

# 1) Object of Capture --> created username and userdirectory in data folder.
# 2) call the takePhotos method --> take 15 sample pictures of the user and check if there are atleast 10 photos that are completely accurate.
#    if True : training, else : then delete the user folder from data directory by caling the method deleteTheDirectory using Capture object and show the user the message to take photos again ie. takePhotos called again and
# 3) If there are atleast 10 photos then we move on to training ie. the condition is true, then we invoke invokeTraining method in Capture class.
# 4) Then we call the recogize method in Recognize class to recognize the face. If True print the name of the user otherwise the user is not allowed.
# 5) All this is done using the object of the Capture class.

#Steps to run from login using Recognize:

# 1) make an object of the Recognize class --> it will just check for the procedure of recognition
# 2) if an empty string is returned then the user is not authenticated ie. show the message not allowed
# 3) Otherwise direct the user to the profile page.


import pymaid.rpc.pb

from examples.template import get_client_parser, parse_args

async def wrapper(address):
    conn = await pymaid.rpc.pb.dial_stream(address)
    # will be closed by server due to heartbeat timeout
    await conn.wait_for_closed()

async def main():
    args = parse_args(get_client_parser())
    tasks = []
    for x in range(args.concurrency):
        tasks.append(pymaid.create_task(wrapper(args.address)))

    # await pymaid.wait(tasks, timeout=args.timeout)
    await pymaid.gather(*tasks)

if __name__ == '__main__':
    pymaid.run(main())


from pyspark.sql.functions import rank, col, row_number
from pyspark.sql.window import Window

from sparkdq.analytics.Preconditions import has_columns, has_column
from sparkdq.exceptions.TransformExceptions import IllegalTransformerParameterException
from sparkdq.models.CommonUtils import DEFAULT_INDEX_COL
from sparkdq.repairs.CommonUtils import KeepType
from sparkdq.repairs.transformers.complex_repairers.ComplexRepairer import ComplexRepairer

WINDOW_RANK_COL = "window_rank"

class DeDuplicator(ComplexRepairer):

    def __init__(self, column_or_columns, keep=KeepType.DEFAULT.value, order_by=DEFAULT_INDEX_COL):
        if not isinstance(column_or_columns, list):
            column_or_columns = [column_or_columns]
        self.columns = column_or_columns
        self.keep = keep.lower()
        self.order_by = order_by

    def preconditions(self):
        return [has_columns(self.columns), DeDuplicator._param_check(self.keep), has_column(self.order_by)]

    def transform(self, df, state_provider=None, check=True):
        if check:
            for condition in self.preconditions():
                condition(df.schema)
        if self.keep == KeepType.DEFAULT.value:
            return df.drop_duplicates(self.columns)
        else:
            if self.keep == KeepType.FIRST.value:
                window = Window.partitionBy(self.columns).orderBy(col(self.order_by))
            else:
                window = Window.partitionBy(self.columns).orderBy(col(self.order_by).desc())
            return df.select('*', row_number().over(window).alias(WINDOW_RANK_COL))\
                .where('{} == 1'.format(WINDOW_RANK_COL)).drop(WINDOW_RANK_COL)

    @staticmethod
    def _param_check(keep):
        def _param_check(_):
            supported_keep = [KeepType.DEFAULT.value, KeepType.FIRST.value, KeepType.LAST.value]
            if keep not in supported_keep:
                raise IllegalTransformerParameterException("Unsupported keep way {}, only {} are supported now!"
                                                            .format(keep, ", ".join(supported_keep)))
        return _param_check


import argparse
import os
import json
from unittest.mock import DEFAULT

import numpy as np
import matplotlib.pyplot as plt
from rliable import plot_utils as rl_plot_utils

EXPERIMENT_PRETTY_NAMES = {
    "vin_sample_nogoal_16_logsumexp_end_to_end_sparse:mvprop": "End-to-End Factored/MVProp",
    "vin_sample_nogoal_16_logsumexp_ignorance:mvprop": "Factored/MVProp Planner (ours)",
    "vin_sample_nogoal_16_logsumexp_ignorance_transformer:mvprop": "Transformer/MVProp Planner",
    "vin_sample_nogoal_16_logsumexp_k_0:mvprop": "Factored/CNN Policy",
    "imitation:pure_transformer": "Encoder-Decoder Transformer",
    "imitation:fused_inputs_next_step_encoder": "Encoder-only Transformer",
    "imitation:film_lstm_policy": "GRU-Encoder ResNet/FiLM Decoder",
}
DEFAULT_LIMITS = [50, 100, 250, 500, 1000, 2500, 5000, 9980]

OOD_ANNOTATIONS = (
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", -3, 0.03),
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", -4, 0.03),
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", -5, 0.03),
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", 0, 0.03),
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", 1, 0.03),
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", 2, 0.03),
    ("imitation:film_lstm_policy", -1, 0.03),
    ("imitation:film_lstm_policy", -2, 0.03),
    ("imitation:film_lstm_policy", -3, 0.03),
    ("vin_sample_nogoal_16_logsumexp_k_0:mvprop", -1, 0.03),
    ("vin_sample_nogoal_16_logsumexp_k_0:mvprop", -2, 0.03),
    ("vin_sample_nogoal_16_logsumexp_k_0:mvprop", -3, 0.03),
    ("imitation:pure_transformer", -1, -0.05),
    ("imitation:pure_transformer", -2, -0.05),
    ("imitation:pure_transformer", -3, -0.05),
)

ID_ANNOTATIONS = (
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", 0, 0.03),
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", 1, 0.03),
    ("vin_sample_nogoal_16_logsumexp_ignorance:mvprop", 2, 0.03),
    ("imitation:pure_transformer", -1, -0.05),
    ("imitation:pure_transformer", -2, -0.05),
    ("imitation:pure_transformer", -3, -0.05),
)

def add_annotations(ax, annotations, limits, means):
    for tag, offset, yoffset in annotations:
        real = EXPERIMENT_PRETTY_NAMES.get(tag, tag)
        if real in means:
            ax.text(
                limits[offset],
                means[real][offset] + yoffset,
                f"{means[real][offset]:.2}"[1:],
            )

def translate_dict_keys(dictionary, translation):
    return {translation.get(k, k): v for k, v in dictionary.items()}

def plot_to_file(
    aggregate_iqms, aggregate_cis, limits, annotations, filename, title, ylabel=None
):
    ax = rl_plot_utils.plot_sample_efficiency_curve(
        limits,
        translate_dict_keys(aggregate_iqms, EXPERIMENT_PRETTY_NAMES),
        translate_dict_keys(aggregate_cis, EXPERIMENT_PRETTY_NAMES),
        algorithms=None,
        xlabel="Samples per goal",
        ylabel=ylabel or "Success rate",
    )

    for line, marker in zip(ax.lines, ("o", "P", "s", "^", "p", "*", "x")):
        line.set_marker(marker)

    ax.set_xscale("log")
    ax.legend(loc="lower right", bbox_to_anchor=(1.0, 0.1))
    ax.set_ylim((-0.05, 1.05))
    ax.spines["left"].set_position(("outward", 0))
    ax.spines["bottom"].set_position(("outward", 0))

    for item in (
        [ax.title, ax.xaxis.label, ax.yaxis.label]
        + ax.get_xticklabels()
        + ax.get_yticklabels()
    ):
        item.set_fontsize(12)

    ax.set_title(title)
    add_annotations(ax, annotations, limits, aggregate_iqms)

    dirname = os.path.dirname(filename)
    if dirname:
        os.makedirs(dirname, exist_ok=True)
    ax.get_figure().savefig(filename)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("plot_data", type=str)
    parser.add_argument("output_id_pdf", type=str)
    parser.add_argument("output_ood_pdf", type=str)
    parser.add_argument("--ylabel", type=str)
    parser.add_argument("--limits", nargs="*", type=int)
    args = parser.parse_args()
    plt.rcParams["text.usetex"] = True

    with open(args.plot_data) as f:
        plot_data = json.load(f)

    plot_to_file(
        plot_data["ood"]["means"],
        plot_data["ood"]["cis"],
        args.limits or DEFAULT_LIMITS,
        OOD_ANNOTATIONS,
        args.output_ood_pdf,
        "$\\mathcal{D}_{\\textrm{v\\_OOD}}$\n",
    )

    plot_to_file(
        plot_data["id"]["means"],
        plot_data["id"]["cis"],
        args.limits or DEFAULT_LIMITS,
        ID_ANNOTATIONS,
        args.output_id_pdf,
        "$\\mathcal{D}_{\\textrm{v\\_ID}}$\n",
    )

if __name__ == "__main__":
    main()


def solution(elements):
    answer = set()
    n = len(elements)
    arr = elements * 2
    # print(arr)
    for i in range(1, len(arr)):
        arr[i] = arr[i - 1] + arr[i]

    # print(arr)
    for i in range(1, n + 1):
        for j in range(n):
            answer.add(arr[j + i] - arr[j])
        # print(arr[j + i] - arr[j])

    return len(answer)

print(solution([7, 9, 1, 1, 4]))  # 18

2023.10/프로그래머스_연속부분수열합의 개수.py

프로그래머스_연속부분수열합의 개수.py


import sys
import os
import datetime
sys.path.append(os.path.abspath('..'))
from active_objects import ActiveObjectsController, ActiveObjectWithRetries, simple_loop, emulate_asap

class TestAO(ActiveObjectWithRetries):

    def __init__(self, controller):
        super().__init__(controller)
        self.max_retry_interval = 10
        self.stop_time = None
        self.next1 = None
        self.next2 = None
        self.signal() # auto start

    def process(self):

        # emulate error to check WithRetries
        # raise Exception("error")

        # stop in 60 seconds
        if self.stop_time is None:
            self.stop_time = self.schedule_seconds(60)
        elif self.reached(self.stop_time):
            self.controller.terminate()
            print(self.now(), 'stop')
            return

        # each 3 seconds
        if self.reached(self.next1):
            print(self.now(), "3")
            self.next1 = self.schedule_seconds(3)

        # each 4 seconds
        if self.reached(self.next2):
            print(self.now(), "4")
            self.next2 = self.schedule_seconds(4)

    def process_internal(self):
        try:
            # continue on error (with retries)
            super().process_internal()
        except Exception as e:
            print(self.now(), str(e))

controller = ActiveObjectsController()
ao = TestAO(controller)

simple_loop(controller)
#emulate_asap(controller, datetime.datetime(year=2000, month=1, day=1))


#!/usr/bin/python3
# dd1term.py -*- mode: Python; coding: utf-8 -*-
"""
This file is named ~/simka/dd1term.py
It is an implementation of one Stanford Data Disc TV terminal
at DKB   keyboard #06,
at VDS TV    line #26,
located in room 233, the computer room, Mordor, at the DCPower Lab building,
1600 Arastradero Road, Palo Alto California in 1974.
"""
import tkinter as tk
from tkinter import font
from tkinter import *

import socket
import threading

import dd1k as ddd
import lester_keyboard as lkb
import pdb

# global
root=None
servsock=None
usersock=None
roomlabel=[ "TV-26 PDP-6 area", "TV-27 Binford", "TV-30 Earnest", "TV-31 Colby", ]
# VDS crossbar switch has one 36-bit PDP10 word for each of 64(58) video lines
# video lines are TV set destinations, corresponding to DKB keyboard numbers.
bar=[1<<(31-9)]*64 # high order 32 bits, digital video from data disc channels
foo=[0]*64 # low order bits for selecting an analog video source

def one_panel():
    global root
    offblack="#444"
    root = Tk()
    root.geometry('1100x1140+170+670')
    root.tk_focusFollowsMouse()
    root.title("Data Disc Terminal");
    root["bg"]=offblack
    Button( root, text="Quit",
            font = font.Font(size=40,weight='bold'),
            fg="#822",
            bg="gray",
            activeforeground="white",
            activebackground="darkred",
            command=root.quit ).pack(side="bottom")
    root.banner = Label(
        root, text="banner",
        fg="gray", bg=offblack,
    )
    root.banner.pack(side="top")
    root.lab = Label(
        root, text="Label",
        fg="gray", bg=offblack,
        font = font.Font(size=20,weight='bold'),
    )
    root.lab.pack(side="bottom")
    can = [0]*1
    i=0
    can[i] = Canvas(root,
                    width=(2*512+32),
                    height=(2*480+32),takefocus=1,
                    highlightthicknes=4,
                    highlightcolor="#aa0",
                    highlightbackground="gray",
                    background=offblack,
                    name="tv26")
    ( dd, kb, ln, tag ) = ( i, 6+i, 0o26+i, "DD{:o}".format(i) )
    ( can[i].dd, can[i].kb, can[i].ln, can[i].tag ) = ( dd, kb, ln, tag )
    can[i].pack(side="top",expand=True)
    # use one transparent pixel for raster addressing a canvas
    pixel_gif="R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
    can[i].pixel = PhotoImage(data=pixel_gif)
    can[i].create_image(0,1,anchor=NW,image=can[i].pixel,tag=can[i].tag)
    text = "Terminal TV#{:o} keyboard#{:o} crossbar hex {:08X} atv#{:2o}".format( ln, kb, bar[kb], foo[kb] )
    root.lab.configure(text=text)
    root.can = can
    return root

class sock_service( threading.Thread ):
    def __init__( me ):
        threading.Thread.__init__( me )
    def run( me ):
        global tick,root,servsock,usersock
        print("datadisc service for one terminals at port #2026")
        servsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        servsock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        servsock.bind(('',2026))
        servsock.listen(5)
        try:
            while True:
                print("Waiting at port #2026")
                (usersock,a) = servsock.accept()
                # print("Connected ",a,usersock)
                lkb.usersock = usersock
                ddd.usersock = usersock
                kid2 = ddd.display_service()
                kid2.setDaemon(True)
                kid2.start()
        finally:
            servsock.close()
            print("ddd6term display server thread exiting")

def main():
    global root,foo,bar
    root= one_panel()
    DDD = ddd.DDD_App()
    LKB = lkb.LKB_App()
    kid = sock_service()
    kid.setDaemon(True)
    kid.start()
    ddd.app = DDD
    ddd.root = root
    ddd.tk = root
    ddd.foo = foo
    ddd.bar = bar
    for canv in root.can:
        canv.bind("<Any-KeyPress>",   LKB.keyhit)
        canv.bind("<Any-KeyRelease>", LKB.keyrelease)
        ddd.test_pattern(canv)
    try:
        root.mainloop()
    finally:
        if servsock is not None:
           servsock.close()
        if ddd.usersock is not None:
            ddd.usersock.close()

if __name__ == "__main__" :
    main()


from sklearn import tree, svm
from sklearn.linear_model import Perceptron
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import NearestCentroid
from sklearn.metrics import accuracy_score

# [ height, weight, shoe_size]
X = [[181,80,44], [177,70,43], [160,60,38], [154,54,37], [166,65,40], [190,90,47], [175,64,39], [177,70,40], [171,75,42], [181,85,43]]

Y = ['female','female','female','male','female','male','female','male','female','male']

clf_tree = tree.DecisionTreeClassifier()
clf_svm = svm.SVC()
clf_PR = Perceptron()
clf_gnb = GaussianNB()
clf_cntrd = NearestCentroid()

# Desision Tree classifier
clf_tree = clf_tree.fit(X,Y)
# SVM Classifier
clf_svm = clf_svm.fit(X,Y)
# Perceptron
clf_PR = clf_PR.fit(X,Y)
# Naive Bayes Classifier
clf_gnb = clf_gnb.fit(X,Y)
# Nearest Centroid Classifier
clf_cntrd = clf_cntrd.fit(X,Y)

#using accuracy_score
prediction_tree = clf_tree.predict(X)
accuracy = accuracy_score(Y,prediction_tree) *100

prediction_svm = clf_svm.predict([[181,80,44]])
prediction_PR = clf_PR.predict([[181,80,44]])
prediction_gnb = clf_gnb.predict([[181,80,44]])
prediction_cntrd = clf_cntrd.predict([[181,80,44]])
print(accuracy, prediction_svm, prediction_PR, prediction_gnb,prediction_cntrd)


import campusgraph
import networkx as nx
from shortestpath import *

def simple_example():
    G = nx.DiGraph()
    G.add_edge(0, 1, weight=2.)
    G.add_edge(0, 2, weight=6.)
    G.add_edge(0, 3, weight=5.)
    G.add_edge(1, 3, weight=4.)
    G.add_edge(2, 3, weight=1.)
    p = shortest_path(G, 0, 3)
    print(p)

def campus_problem():
    G = campusgraph.create_graph()
    p = shortest_path(G, 0, 49)
    print(p)

def main():
    simple_example()
    print()
    campus_problem()

if __name__ == '__main__':
    main()


from matplotlib import pyplot as plt
import numpy as np
import argparse
import cv2

# fetching the arguments and save in dictionary
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "Enter path to the image")
args = vars(ap.parse_args())

# loading and converting the image into numpy array
image = cv2.imread(args["image"])

chans = cv2.split( image )
colors = ( "b" , "g" , "r" )

plt.figure()
plt.title("Color Hist")
plt.xlabel( "Bins" )
plt.ylabel( "No. of Pixels" )

for (chan , color) in zip(chans , colors):
    hist = cv2.calcHist( [chan] , [0] , None , [256] , [0 , 256] )
    plt.plot( hist , color = color )
    plt.xlim( [ 0 , 256 ] )

plt.show()
# # BGR to GRAY
# gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# cv2.imshow("GRAY", gray)
# cv2.waitKey(0)

# hist = cv2.calcHist( [image] , [0] , None , [256] , [ 0 , 256 ] )

# plt.figure()
# plt.title( "Gray Scale" )
# plt.xlabel( "Bins" )
# plt.ylabel( "No. of Pixels" )
# plt.plot(hist)
# plt.xlim( [ 0 , 256 ] )
# plt._show()

cv2.waitKey(0)


from django.urls import path
from . import views

urlpatterns = [

    path('',views.DisplayQuizzes.as_view(),name='display_quizzes'),
    path('display-questions/<quiz_id>',views.DisplayQuestions.as_view(),name='display_questions'),
    path('create-info/',views.CreateInfo.as_view(),name='create_info'),
    path('create/<quiz_id>',views.Create.as_view(),name='create'),
    path('delete-quiz/<quiz_id>',views.Delete.as_view(),name='delete_quiz'),
    path('delete-question/<question_id>',views.Delete.as_view(),name='delete_question'),
    path('update-question/<question_id>',views.UpdateQuestion.as_view(),name='update_question'),
    path('update-quiz/<quiz_id>',views.UpdateQuiz.as_view(),name='update_quiz'),
    path('attempt-quiz/<quiz_id>',views.AttemptQuiz.as_view(),name='attempt_quiz'),
    path('result/<quiz_id>',views.StudentResult.as_view(),name='result')

]


#!/usr/bin/python3.4
# coding: utf-8
"""
Programme (classe) : cb.py       version 1.0
Date : 09-02-2018
Auteur : Hervé Dugast
Source : http://deusyss.developpez.com/tutoriels/Python/Pyreverse/

------- affichage console ----------------
Citizen-Band
------------------------------------------
"""

class CB():
   def __init__(self):
      self.marque = "Citizen-Band"

if __name__ == "__main__":
   ma_cb = CB()
   print(ma_cb.marque)


filename = input("Enter a file name:")
wordToReplace = input("Enter the string to be removed:")
inFile = open(filename,"r")
text = inFile.read()
text = text.replace(wordToReplace,"")

outFile = open(filename,"w+")
outFile.write(text)

inFile.close()
outFile.close()


class Solution(object):
    def largestRectangleArea(self, heights):
        """
        :type heights: List[int]
        :rtype: int
        """
        ret = 0
        heights.append(0)
        index = []
        for i in range(len(heights)):
            while len(index) > 0 and heights[index[-1]] > heights[i]:
                h = heights[index.pop()]
                sidx = index[-1] if len(index) > 0 else -1
                if h * (i - sidx - 1) > ret:
                    ret = h * (i - sidx - 1)
            index.append(i)
        return ret


import numpy as np

import pytest
from pytest import approx

from spike2py_preprocess import trial
from spike2py_preprocess import subject
from spike2py_preprocess import study
import spike2py

def test_preprocess_trial_no_trial_preprocess(sub1_trial_info, temp_path):
    trial.trial(sub1_trial_info)
    pkl_file = temp_path / (sub1_trial_info.name + ".pkl")
    assert pkl_file.exists()
    data = spike2py.trial.load(pkl_file)
    assert np.mean(data.Fdi.values) == approx(-0.02452170146926789)

def test_preprocess_trial_with_trial_preprocess(sub2_trial_info, temp_path):
    trial.trial(sub2_trial_info)
    pkl_file = temp_path / (sub2_trial_info.name + ".pkl")
    assert pkl_file.exists()
    data = spike2py.trial.load(pkl_file)
    assert np.mean(data.W_Ext.values) == approx(-1.9762610940015095)

def test_preprocess_trial_with_subject_preprocess(
    sub1_trial_info, temp_path, subject_preprocess_details
):
    trial.trial(sub1_trial_info)
    pkl_file = temp_path / (sub1_trial_info.name + ".pkl")
    assert pkl_file.exists()

def test_subject_paths_create_method(tmp_path):
    paths = subject.SubjectPaths(tmp_path)
    paths.create()
    assert paths.raw == tmp_path / "raw"
    assert paths.proc == tmp_path / "proc"
    assert paths.figures == tmp_path / "figures" / "preprocess"

def test_preprocess_subject_no_subject_preprocess(sub01_paths, channels_file1):
    subject.subject(subject_path=sub01_paths.home)
    file1 = sub01_paths.proc / "conv_biphasic.pkl"
    file2 = sub01_paths.proc / "khz_biphasic.pkl"
    assert file1.exists()
    assert file2.exists()
    data1 = spike2py.trial.load(file1)
    data2 = spike2py.trial.load(file2)
    assert data1.channels == channels_file1
    assert data2.channels == [
        ("W_Ext", "waveform"),
        ("Fdi", "waveform"),
        ("Stim", "waveform"),
    ]
    assert np.mean(data1.Fdi.values) == approx(-0.026770833935985772)
    file1.unlink()
    file2.unlink()

def test_preprocess_subject_with_subject_preprocess(sub02_paths):
    subject.subject(subject_path=sub02_paths.home)
    file1 = sub02_paths.proc / "conv_biphasic.pkl"
    file2 = sub02_paths.proc / "khz_biphasic.pkl"
    assert file1.exists()
    assert file2.exists()
    data1 = spike2py.trial.load(file1)
    assert np.mean(data1.Fdi.values) == approx(4.973229169271819)
    file1.unlink()
    file2.unlink()


"""Centralized catalog of paths."""
import os

class DatasetCatalog(object):
    DATA_DIR = "./datasets"

    DATASETS = {
        "MAD_train":{
            "video_dir": "MAD/",
            "ann_file" : "MAD/annotations/MAD_train.json",
            "feat_file": "MAD/features/CLIP_frames_features_5fps.h5",
            "lang_feat": "MAD/features/CLIP_language_tokens_features.h5",
            "tokenizer_folder": "stanford-corenlp-4.0.0",
            "fps" : 5,
            "split" : "train",
        },
        "MAD_val":{
            "video_dir": "MAD/",
            "ann_file":  "MAD/annotations/MAD_val.json",
            "feat_file": "MAD/features/CLIP_frames_features_5fps.h5",
            "lang_feat": "MAD/features/CLIP_language_tokens_features.h5",
            "tokenizer_folder": "stanford-corenlp-4.0.0",
            "fps" : 5,
            "split" : "val",
        },
        "MAD_test":{
            "video_dir": "MAD/",
            "ann_file":  "MAD/annotations/MAD_test.json",
            "feat_file": "MAD/features/CLIP_frames_features_5fps.h5",
            "lang_feat": "MAD/features/CLIP_language_tokens_features.h5",
            "tokenizer_folder": "stanford-corenlp-4.0.0",
            "fps" : 5,
            "split" : "test",
        }
    }

    @staticmethod
    def get(name):
        data_dir = DatasetCatalog.DATA_DIR
        attrs = DatasetCatalog.DATASETS[name]
        args = dict(
            root=os.path.join(data_dir, attrs["video_dir"]),
            ann_file=os.path.join(data_dir, attrs["ann_file"]),
            feat_file=os.path.join(data_dir, attrs["feat_file"]),
            lang_feat_file=os.path.join(data_dir, attrs["lang_feat"]),
            tokenizer_folder=os.path.join(data_dir, attrs["tokenizer_folder"]),
            split=attrs["split"],
            fps=attrs["fps"],
        )
        if "MAD" in name:
            return dict(
                factory = "MADdataset",
                args = args
            )
        raise RuntimeError("Dataset not available: {}".format(name))


#!/usr/bin/python
import sqlite3
from flask import Flask, request, jsonify
from flask_cors import CORS

def connect_to_db():
    conn = sqlite3.connect('database.db')
    return conn

def insert_product(product):
    inserted_product = {}
    try:
        conn = connect_to_db()
        cur = conn.cursor()
        cur.execute("INSERT INTO product (name, desc, supplier, price) VALUES (?, ?, ?, ?)", (product['name'], product['desc'], product['supplier'], product['price']) )
        conn.commit()
        inserted_product = get_product_by_code(cur.lastrowid)
    except:
        conn().rollback()

    finally:
        conn.close()

    return inserted_product

def get_products():
    products = []
    try:
        conn = connect_to_db()
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT * FROM product")
        rows = cur.fetchall()

        # convert row objects to dictionary
        for i in rows:
            product = {}
            product["code"] = i["code"]
            product["name"] = i["name"]
            product["desc"] = i["desc"]
            product["supplier"] = i["supplier"]
            product["price"] = i["price"]
            products.append(product)

    except:
        products = []

    return products

def get_product_by_code(product_code):
    product = {}
    try:
        conn = connect_to_db()
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT * FROM product WHERE code = ?", (product_code,))
        row = cur.fetchone()
        # convert row object to dictionary
        product["code"] = row["code"]
        product["name"] = row["name"]
        product["desc"] = row["desc"]
        product["supplier"] = row["supplier"]
        product["price"] = row["price"]
    except:
        product = {}

    return product

def update_product(product):
    updated_product = {}
    try:
        conn = connect_to_db()
        cur = conn.cursor()
        cur.execute("UPDATE product SET name = ?, desc = ?, supplier = ?, price = ? WHERE code =?", (product["name"], product["desc"], product["supplier"], product["price"], product["code"],))
        conn.commit()
        #return the product
        updated_product = get_product_by_code(product["code"])

    except:
        conn.rollback()
        updated_product = {}
    finally:
        conn.close()

    return updated_product

def delete_product(product_code):
    message = {}
    try:
        conn = connect_to_db()
        conn.execute("DELETE from product WHERE code = ?", (product_code,))
        conn.commit()
        message["status"] = "Product deleted successfully"
    except:
        conn.rollback()
        message["status"] = "Cannot delete product"
    finally:
        conn.close()

    return message

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

@app.route('/api/product', methods=['GET'])
def api_get_products():
    return jsonify(get_products())

@app.route('/api/product/<product_code>', methods=['GET'])
def api_get_product(product_code):
    return jsonify(get_product_by_code(product_code))

@app.route('/api/product',  methods = ['POST'])
def api_add_product():
    product = request.get_json()
    return jsonify(insert_product(product))

@app.route('/api/product',  methods = ['PUT'])
def api_update_product():
    product = request.get_json()
    return jsonify(update_product(product))

@app.route('/api/product/<product_code>',  methods = ['DELETE'])
def api_delete_product(product_code):
    return jsonify(delete_product(product_code))

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


import datetime
from aoc_2023 import helpers, day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day13

content = helpers.ContentLoader()

day = 13

# if datetime.datetime.now().date() > datetime.date(2023, 12, 25):
#     day = input("choose a day (1 ... 25): ")
# else:
#     day = datetime.datetime.now().day

if day == 1:
    content.set_filename("./aoc_2023/input_01.txt")
    r = day01.Trebuchet(content=content.load())
    print("Day 01. The calibration value:", r.calibration_value())
    print("Day 01. The second corrected calibration value:", r.corrected_calibration_value())

if day == 2:
    content.set_filename("./aoc_2023/input_02.txt")
    r = day02.CubeConundrum(content=content.load())
    print("Day 02: The sum of the game IDs:", r.possible_games())
    print("Day 02: The sum of the power of the cube sets:", r.required_cubes())

if day == 3:
    content.set_filename("./aoc_2023/input_03.txt")
    r = day03.GearRatios(content=content.load())
    print("Day 03: The missing engine part:", r.part_number())
    print("Day 03: The gear ratios:", r.gear_ratios())

if day == 4:
    content.set_filename("./aoc_2023/input_04.txt")
    r = day04.ScratchCards(content=content.load())
    print("Day 04: The cards points:", r.points())
    print("Day 04: The number of scretchcards:", r.card_matches())

if day == 5:
    content.set_filename("./aoc_2023/input_05.txt")
    r = day05.Seed(content=content.load())
    print("Day 05: The lowest location:", r.lowest_location())
    print("Day 05: The lowest location with lots of seeds:", r.lowest_location_with_lots_of_seeds())

if day == 6:
    content.set_filename("./aoc_2023/input_06.txt")
    r = day06.BoatRace(content=content.load())
    print("Day 06: The product of winning variants:", r.winning_variants())
    print("Day 06: The second product of winning variants:", r.winning_variants_v2())

if day == 7:
    content.set_filename("./aoc_2023/input_07.txt")
    r = day07.CamelCards(content=content.load())
    print("Day 07: The total winnings are:", r.total_winnings(joker=False))
    print("Day 07: The total joker winnings are:", r.total_winnings(joker=True))

if day == 8:
    content.set_filename("./aoc_2023/input_08.txt")
    r = day08.HauntedWasteland(content=content.load())
    print("Day 08: Required steps:", r.steps())
    print("Day 08: Required steps v2:", r.steps_v2())

if day == 9:
    content.set_filename("./aoc_2023/input_09.txt")
    r = day09.MirageMaintenance(content=content.load())
    print("Day 09: Sum of extrapolated values at the end of each serie:", r.sum_of_extrapolated_values_end())
    print("Day 09: Sum of extrapolated values: at the beginning of ech serie", r.sum_of_extrapolated_values_beginning())

if day == 10:
    content.set_filename("./aoc_2023/input_10.txt")
    r = day10.PipeMaze(content=content.load())
    print("Day 10: Steps from the starting position to the farthest point:", r.steps())
    print("Day 10: Tiles are enclosed by the loop:", r.find_enclosed(), "But this is false. :-(")

if day == 11:
    content.set_filename("./aoc_2023/input_11.txt")
    r = day11.CosmicExpansion(content=content.load())
    print("Day 11: The sum of the lengths:", r.sum_of_lengths())
    print("Day 11: The sum of the lengths in rapid expanded space:", r.sum_of_lengths_2())

if day == 12:
    print("Day 12: without me.")

if day == 13:
    content.set_filename("./aoc_2023/input_13.txt")
    r= day13.PointOfIncidence(content=content.load())
    print("Day 13: The summarizing all of all notes:", r.summared_notes())
    print("Day 13: The summarizing all of all notes with corrected blind fields:", r.summared_corrected_notes())


import warnings

warnings.simplefilter("always")

def test_warning_broker():
    with warnings.catch_warnings(record=True) as w:
        from fastbt.brokers.zerodha import Zerodha

        message = str(w[-1].message)
        assert len(w) == 1
        assert issubclass(w[-1].category, DeprecationWarning)
        assert "Brokers support would be removed from version 0.7.0" in message
        assert "omspy" in message


import datetime
import json
import logging

from odoo import api, models, fields, _

BASE_URL = "http://pl.numeraliot.com:8010/meter"
POWER_API = "/power"
MODE_API = "/mode"
CLEAR_BALANCE_API = "/clear_balance"
BALANCE_API = "/balance"
RECHARGE_API = "/recharge"

class Meter(models.Model):
    _name = 'power.meter'
    _inherit = 'mail.thread'

    _description = 'Model that holds meter details'

    name = fields.Char()
    imei = fields.Char(required=True, tracking=True)
    serial_no = fields.Char(required=True, tracking=True)
    address = fields.Char(required=True, tracking=True)
    power_status = fields.Boolean(required=True, default=False, tracking=True)
    mode = fields.Selection([('prepaid', 'PREPAID'), ('postpaid', 'POSTPAID')], tracking=True,
                            default='prepaid')
    user_id = fields.Many2one('res.partner')
    units = fields.Float(required=True, tracking=True, default=0.0)
    _sql_constraints = [
        ('imei_unique', 'unique (imei)', "IMEI already exists!"),
        ('serial_no_unique', 'unique (serial_no)', "Serial No already exists!"),
        ('address_unique', 'unique (address)', "Address already exists!"),
        ('meter_unique', 'unique (imei,address)', "Meter already exists!"),
    ]
    last_update = fields.Datetime()

    model = fields.Char(tracking=True, default='', required=True)
    current_a = fields.Float('Current (A) Amps')
    current_b = fields.Float('Current (B) Amps')
    current_c = fields.Float('Current (C) Amps')
    current_n = fields.Float('Current (N) Amps')

    voltage_a = fields.Float('Voltage (A) Volts')
    voltage_b = fields.Float('Voltage (B) Volts')
    voltage_c = fields.Float('Voltage (C) Volts')

    power = fields.Float('Power (KW)')
    frequency = fields.Float('Frequency (Hz)')
    balance = fields.Float('Balance (KWH)')
    signal = fields.Integer()

    def get_formatted_address(self):
        address_list = []
        len_address = x = len(self.address)
        for i in range(0, len_address, 2):
            address_list.append(self.address[x - 2: x])
            x -= 2
        return ''.join(address_list)

    @staticmethod
    def call_endpoint(_api, payload):
        try:
            import requests
            url = BASE_URL + _api
            headers = {
                'Content-Type': 'application/json'
            }

            response = requests.request("POST", url, headers=headers, data=json.dumps(payload), timeout=5)
            if response.status_code == 200 and response.json()['result']:
                return True
            return False
        except Exception as ex:
            logging.error(ex)
            return False

    def set_power_status(self, status):
        return {
            "address": self.get_formatted_address(),
            "imei": self.imei,
            "status": status
        }

    def set_mode(self, mode):
        return {
            "address": self.get_formatted_address(),
            "imei": self.imei,
            "mode": mode
        }

    def set_balance(self, units=0.00, clear_balance=False):
        if clear_balance:
            return {
                "address": self.get_formatted_address(),
                "imei": self.imei,
            }
        else:
            return {
                "address": self.get_formatted_address(),
                "imei": self.imei,
                "amount": units
            }

    def get_balance(self):
        return {
            "address": self.get_formatted_address(),
            "imei": self.imei,
            "mode": self.mode
        }

    def action_power_on(self):
        payload = self.set_power_status('on')
        if self.call_endpoint(POWER_API, payload):
            self.power_status = True

    def action_power_off(self):
        payload = self.set_power_status('off')
        if self.call_endpoint(POWER_API, payload):
            self.power_status = False

    def action_prepaid(self):
        payload = self.set_mode('prepaid')
        if self.call_endpoint(MODE_API, payload):
            self.mode = 'prepaid'

    def action_post_paid(self):
        payload = self.set_mode('postpaid')
        if self.call_endpoint(MODE_API, payload):
            self.mode = 'postpaid'

    def action_clear_balance(self):
        payload = self.set_balance(clear_balance=True)
        if self.call_endpoint(CLEAR_BALANCE_API, payload):
            self.units = 0.0

    def action_get_balance(self):
        payload = self.get_balance()
        if self.call_endpoint(BALANCE_API, payload):
            pass

    def action_recharge_meter(self):
        view = self.env.ref('niot_meter.wizard_recharge_meter_form')
        # TDE FIXME: a return in a loop, what a good idea. Really.
        return {
            'name': _(f'Recharge Power Meter: {self.imei}'),
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'wizard.recharge.meter',
            'views': [(view.id, 'form')],
            'view_id': view.id,
            'target': 'new',
            'context': {'default_meter_id': self.id}
        }

    @api.model
    def set_units(self, vals):
        logging.info(f"PowerMeter::set_units::  vals --> {vals}")
        address = vals['address']
        units = vals['balance']
        meter = self.search([('address', '=', address)])
        if meter:
            meter.units = units

    @api.model
    def set_last_update(self, vals):
        address = vals['address']
        meter = self.search([('address', '=', address)])
        if meter:
            meter.last_update = datetime.datetime.now()

class MeterAssignment(models.Model):
    _name = 'meter.assignment'
    _description = 'Meter assignment history'

    meter_id = fields.Many2one('power.meter')
    user_id = fields.Many2one('res.partner')
    data_assigned = fields.Datetime()
    date_unassigned = fields.Datetime()
    assigned_by = fields.Many2one('res.partner')
    unassigned_by = fields.Many2one('res.partner')


from PIL import Image
import numpy as np
import os

class Operations :
	def __init__(self, img1, img2 = None):
		os.system("clear")
		print("Processing image...")
		self.Lmax = 255

		if(img2 is None) :
			self.img = self.openImage(img1)
		else :
			self.img = self.openImage(img1)
			self.imgAux = self.openImage(img2)

	def openImage(self, path) :
		image = Image.open(path)

		if(image.mode != "RGB") :
			image = image.convert("RGB")

		return image

	def constSum(self, const = 0) :
		f = np.asarray(self.img, dtype=int)
		f = f + int(const)

		f[f > self.Lmax] = self.Lmax
		f[f < 0] = 0

		return Image.fromarray(np.uint8(f))

	def constMult(self, const = 1) :
		f = np.asarray(self.img, dtype=float)
		f = float(const)*f

		f[f > self.Lmax] = self.Lmax

		return Image.fromarray(np.uint8(np.round(f)))

	def constNegative(self) :
		f = np.asarray(self.img, dtype=int)
		f = self.Lmax - f

		return Image.fromarray(np.uint8(f))

	def constMono(self) :
		f = np.asarray(self.img, dtype=int)
		f = 0.299 * f[:,:,0] + 0.587 * f[:,:,1] + 0.114 * f[:,:,2]

		return Image.fromarray(np.uint8(f))

	def constRot(self, rotation = 1) :
		f = np.asarray(self.img, dtype=int)

		return Image.fromarray(np.uint8(np.rot90(f, rotation)))

	def constMirror(self, axis) :
		f = np.asarray(self.img, dtype=int)

		return Image.fromarray(np.uint8(np.flip(f, axis=axis)))

	def imagesSum(self, w = -1) :
		w = w/100
		f = np.asarray(self.img, dtype=float)
		g = np.asarray(self.imgAux, dtype=float)

		if(w < 0 or w > 100) :
			f = f + g
		else :
			f = w*f + (1-w)*g

		f[f > self.Lmax] = self.Lmax

		return Image.fromarray(np.uint8(np.round(f)))

	def imagesSub(self, w = -1) :
		w = w/100
		f = np.asarray(self.img, dtype=float)
		g = np.asarray(self.imgAux, dtype=float)

		if(w < 0 or w > 100) :
			f = f - g
		else :
			f = w*f - (1-w)*g

		f[f < 0] = 0

		return Image.fromarray(np.uint8(np.round(f)))

	def imagesMult(self) :
		f = np.asarray(self.img, dtype=float)
		g = np.asarray(self.imgAux, dtype=float)/self.Lmax

		f = f * g

		f[f > self.Lmax] = self.Lmax

		return Image.fromarray(np.uint8(np.round(f)))

	def imagesDiv(self) :
		f = np.asarray(self.img, dtype=float)
		g = np.asarray(self.imgAux, dtype=float)/self.Lmax

		f = f / g

		f[np.isnan(f)] = self.Lmax
		f[f > self.Lmax] = self.Lmax

		return Image.fromarray(np.uint8(np.round(f)))

	def images3D(self) :
		f = np.asarray(self.img, dtype=int)
		g = np.asarray(self.img, dtype=int)
		h = np.asarray(self.img, dtype=int)

		f[:,:,1] = 0
		f[:,:,2] = 0
		g[:,:,0] = 0

		disp = f.shape[1]*0.002

		f = np.roll(f, int(disp), axis=1)
		g = np.roll(g, -int(disp), axis=1)
		# h = f + g + 0.5*h
		h = f + g

		h[h > self.Lmax] = self.Lmax

		return Image.fromarray(np.uint8(h))


#!/usr/bin/env python3

### Advent of Code - 2020 - Day 20

import sys
import requests
import re
import math
import itertools
import functools
import os
import collections
from functools import lru_cache

sys.path.append('../../python/')
from aoc_utils import *

# read input data file as one long string and as an array of lines
inputfile = 'input'
if len(sys.argv) == 2:
    inputfile = sys.argv[1]
if not os.path.exists(inputfile):
    print(RED+f"Input file {inputfile} not found!"+CLEAR)
    quit()
input = open(inputfile,'r').read().rstrip()
input_lines = [line.strip() for line in input.split('\n')]
#input_nums = list(map(int,input_lines))
print(DBLUE+f"Input <{inputfile}>, num lines: {len(input_lines)}"+CLEAR)

p1 = 0
p2 = 0

TOP = 0
RIGHT = 1
BOTTOM = 2
LEFT = 3

def create_mirrors(grid):
    mirrors = [grid]
    mirrors.append(grid[::-1])
    mirrors.append([r[::-1] for r in grid])
    mirrors.append([r[::-1] for r in grid][::-1])
    return mirrors

# rotates grid left
def create_rotations(grid):
    rot = [grid]
    last = grid
    for _ in range(3):
        grid = [l[:] for l in grid]
        for x in range(len(grid)):
            for y in range(len(grid[x])):
                grid[x][y] = last[len(grid)-y-1][x]
        last = grid
        rot.append(grid)
    return rot

class Tile:
    def __init__(self,id):
        self.id = id
        self.rows = []
        self.options = []
        self.edges = []

    def compute_orientations(self):
        # compute all options
        all_grids = []

        mirrors = create_mirrors(self.rows)
        for m in mirrors:
            all_grids.extend(create_rotations(m))

        # after flipping and creating the rotations of each
        # we may have some duplicate grids, get rid of them
        for e in all_grids:
            if e not in self.options:
                self.options.append(e)

        def get_edges(grid):
            top = grid[0]
            right = ''.join(l[-1] for l in grid)
            bottom = grid[-1]
            left = ''.join(l[0] for l in grid)
            return (top,right,bottom,left)
        # create the list of edges (T,R,B,L) for every possible
        # tile orientation
        for o in self.options:
            self.edges.append(get_edges(o))

    # def __repr__(self):
    #     repr = f"Tile {self.id}:\n"
    #     for r in self.rows:
    #         repr += r+'\n'
    #     return repr

tiles = []
intiles = input.split('\n\n')
#print(intiles)
for it in [x.split('\n') for x in intiles]:
    m = re.match(r"Tile (\d+):",it[0])
    t = Tile(int(m.group(1)))
    for l in it[1:]:
        t.rows.append(list(l))
    t.compute_orientations()
    tiles.append(t)

dim = math.isqrt(len(intiles))

def can_place(grid,t,e,x,y):
    """Given a (grid) state, a tile (t), an index (e) into the list of
    tile orientations, and an (x), (y) location, see if that tile
    can fit, by checking all edges with its neighbors"""
    # look above
    if y > 0 and grid[x][y-1]:
        above,i = grid[x][y-1]
        if above.edges[i][BOTTOM] != t.edges[e][TOP]:
            return False
    # look right
    if x < dim-1 and grid[x+1][y]:
        right,i = grid[x+1][y]
        if right.edges[i][LEFT] != t.edges[e][RIGHT]:
            return False
    # look down
    if y < dim-1 and grid[x][y+1]:
        below,i = grid[x][y+1]
        if below.edges[i][TOP] != t.edges[e][BOTTOM]:
            return False
    # look left
    if x > 0 and grid[x-1][y]:
        left,i = grid[x-1][y]
        if left.edges[i][RIGHT] != t.edges[e][LEFT]:
            return False
    return True

def create_tile_grid(grid,x,y,seen):
    """Starting at position (x),(y), iterate over the tiles
    and try placing each one, and then recurse using the next
    position (nx),(ny). Keep track of which tiles were placed
    with the set (seen)"""
    if y == dim:
        return grid
    nx, ny = x+1, y
    if nx == dim:
        nx = 0
        ny += 1
    for t in tiles:
        if t.id in seen:
            continue
        seen.add(t.id)
        for i,_ in enumerate(t.options):
            if can_place(grid,t,i,x,y):
                grid[x][y] = (t,i)
                newg = create_tile_grid(grid,nx,ny,seen)
                if newg is not None:
                    return newg
        seen.remove(t.id)
    grid[x][y] = None
    return None

# Part 1
grid = [[None for _ in range(dim)] for _ in range(dim)]
g = create_tile_grid(grid,0,0,set())

# multiply the Tile ids at the corners
print(g[0][0][0].id,g[dim-1][0][0].id,g[dim-1][dim-1][0].id,g[0][dim-1][0].id)
part1(g[0][0][0].id*g[dim-1][0][0].id*g[dim-1][dim-1][0].id*g[0][dim-1][0].id)

tsize = len(tiles[0].rows)

# Part 2
def merge_tiles(grid):
    """combine the tiles, after removing the borders on each"""
    merge = []
    for sy in range(dim):
        for y in range(1,tsize-1):
            merge.append([])
            for sx in range(dim):
                t,i = grid[sx][sy]
                merge[sy*(tsize-2)+y-1] += t.options[i][y][1:-1]
    return merge

mg = merge_tiles(g)
def print_sea(sea):
    for y in sea:
        print(''.join(x for x in y))
print_sea(mg)

def count_waves(sea):
    waves = 0
    for y in sea:
        waves += ''.join(x for x in y).count('#')
    return waves

monster = """
                  #
#    ##    ##    ###
 #  #  #  #  #  #
"""
mc = [(0,1),(1,2),                      # tail
    (4,2),(5,1),(6,1),(7,2),            # hump
    (10,2),(11,1),(12,1),(13,2),        # hump
    (16,2),(17,1),(18,0),(18,1),(19,1)] # head

all_seas = []
mirrors = create_mirrors(mg)
for m in mirrors:
    all_seas.extend(create_rotations(m))

for s in all_seas:
    monsters = []
    sea = s[:]
    for y in range((tsize-2)*dim-3):        # monster is 3 rows tall
        for x in range(0,(tsize-2)*dim-20): # and 20 cols wide
            found = True
            for mx,my in mc:
                if sea[y+my][x+mx] != '#':
                    found = False
                    break
            if found:
                monsters.append((x,y))
    if len(monsters) > 0:
        print(f"found {len(monsters)}")
        for m in monsters:
            for mx,my in mc:
                sea[m[1]+my][m[0]+mx] = GREEN+'O'+CLEAR
        print_sea(sea)
        part2(count_waves(sea))
        quit()


from tkinter import *
from tkinter import messagebox
import backend
from btn_hover import *

def main(root):
# def main():
  fontUsed = "Segoe UI"

  def searchBtnClick():
    if bookID.get()!='':
      if bookID.get().isnumeric():
        entries = backend.search_book_full(bookID.get())
        if entries!=None:
          bookID.config(state='disabled')
          i = 0
          for key in strEntries.keys():
            strEntries[key].set(entries[i])
            i+=1
        else:
          messagebox.showerror("Not found", "Specified BookID not found!", parent=win)
          for key in strEntries.keys():
            strEntries[key].set('')
      else:
        messagebox.showinfo("BookID", "BookID must be a number!", parent=win)
    else:
      messagebox.showinfo("BookID", "Enter BookID first!", parent=win)

  def resetBtnClick():
    sbookID.set("")
    bookID.config(state='normal')
    for key in strEntries.keys():
      strEntries[key].set("")
    win.focus()

  win = Toplevel(root)
  # win = Tk()
  strEntries={"sisbn": StringVar(), "stitle": StringVar(), "sauthor": StringVar(), "spublisher": StringVar(), "sedition": StringVar(), "stotal_copies": StringVar(), "sissued_copies": StringVar(), "savail_copies": StringVar()}

  win.grab_set()
  win.focus()
  win.title("Search Book")
  width = 700
  height = 550
  x = ((win.winfo_screenwidth() - width)//2)-30
  y = ((win.winfo_screenheight() - height)//2)-30
  win.geometry(f"{width}x{height}+{x}+{y}")
  win.resizable(0, 0)
  bgimage=PhotoImage(file="images/search_book.png")
  bg=Label(win, image=bgimage)
  bg.place(x=0,y=0)

  sbookID = StringVar()
  bookID = Entry(win, font=(fontUsed, 14), width=8, textvariable=sbookID)
  bookID.place(x=395,y=44)

  searchBtn = Button(win, text="Search", bg='#655bd6', fg='white', font=(fontUsed, 11), borderwidth=0, width=8, command=searchBtnClick)
  searchBtn.place(x=500, y=43)

  searchBtn.bind("<Enter>", lambda e: btnMouseEnter(searchBtn))
  searchBtn.bind("<Leave>", lambda e: btnMouseLeave(searchBtn))

  isbn = Entry(win, font=(fontUsed, 14), width=21, state='disabled', textvariable=strEntries["sisbn"])
  isbn.place(x=371,y=130)

  book_title = Entry(win, font=(fontUsed, 13), width=19, state='disabled', textvariable=strEntries["stitle"])
  book_title.place(x=410,y=172)

  author = Entry(win, font=(fontUsed, 13), width=22, state='disabled', textvariable=strEntries["sauthor"])
  author.place(x=383,y=212)

  publisher = Entry(win, font=(fontUsed, 13), width=20, state='disabled', textvariable=strEntries["spublisher"])
  publisher.place(x=402,y=252)

  edition = Entry(win, font=(fontUsed, 13),width=22, state='disabled', textvariable=strEntries["sedition"])
  edition.place(x=385,y=295)

  total_copies = Entry(win, font=(fontUsed, 13),width=14, state='disabled', textvariable=strEntries["stotal_copies"])
  total_copies.place(x=432,y=371)

  issued_copies = Entry(win, font=(fontUsed, 13),width=12, state='disabled', textvariable=strEntries["sissued_copies"])
  issued_copies.place(x=451,y=410)

  avail_copies = Entry(win, font=(fontUsed, 13),width=9, state='disabled', textvariable=strEntries["savail_copies"])
  avail_copies.place(x=479,y=452)

  resetBtn = Button(win, text="Reset", bg='#655bd6', fg='white', font=(fontUsed, 11), borderwidth=0, width=8, command=resetBtnClick)
  resetBtn.place(x=580, y=43)

  resetBtn.bind("<Enter>", lambda e: btnMouseEnter(resetBtn))
  resetBtn.bind("<Leave>", lambda e: btnMouseLeave(resetBtn))

  win.mainloop()

# main()