import numpy as np
import scipy.io as sio
from datetime import datetime, timedelta
import pandas as pd
import os
import csv
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter, MultipleLocator
import matplotlib.mlab as mlab
import scipy as sp
from scipy.interpolate import UnivariateSpline
import scipy.interpolate as si
from scipy.interpolate import interp1d

base_dir = os.path.expanduser('~')
path_data=base_dir+'/Dropbox/Monash_Uni/SO/MAC/Data/YOTC/mat/'

#*****************************************************************************\
#Default Info
mac = {'name': 'Macquarie Island, Australia', 'lat': -54.62, 'lon': 158.85}
lat_mac = mac['lat']
lon_mac = mac['lon']

ptemp_thold_main=0.010           # K/m
ptemp_thold_sec=0.005            # K/m
shear_thold=0.015               # 1/s

#*****************************************************************************\
#*****************************************************************************\
#                            YOTC Data
#*****************************************************************************\
# #*****************************************************************************\
mat= sio.loadmat(path_data+'yotc_data.mat')
#*****************************************************************************\
#Crear fecha de inicio leyendo time
time= mat['time'][0]
date_ini=datetime(1900, 1, 1) + timedelta(hours=int(time[0])) #hours since
#Arreglo de fechas
date_yotc = pd.date_range(date_ini, periods=len(time), freq='12H')
#*****************************************************************************\
#Reading variables
t_ori= mat['temp'][:] #K
u_ori= mat['u'][:]
v_ori= mat['v'][:]
q_ori= mat['q'][:]

#rotate from surface to free atmosphere
temp=t_ori[:,::-1]
u=u_ori[:,::-1]
v=v_ori[:,::-1]
q=q_ori[:,::-1] #kg/kg
mixr= q*1000 #g/kg

#*****************************************************************************\
#Leyendo Alturas y press
file_levels = np.genfromtxt('./Read_Files/YOTC/levels.csv', delimiter=',')
hlev_yotc=file_levels[:,6]
#plev_yotc=file_levels[:,3]
plev_yotc=file_levels[:,4] #value 10 is 925

#*****************************************************************************\
g=9.8 #m seg^-2

#Calculate Virtual Temperature
theta=(temp)*(1000./plev_yotc)**0.287;
#Calculate Potential Temperature
pot_temp=(1+0.61*(mixr/1000.))*theta;

pot_temp_grad=np.zeros(pot_temp.shape)
yvert_shear=np.empty(pot_temp.shape)*np.nan
brn_yotca=np.empty(pot_temp.shape)*np.nan
#Calculate Wind Shear and Gradiente Potential Temp
for j in range(0,len(time)):
    for i in range(1,len(hlev_yotc)-1):
        pot_temp_grad[j,i]=(pot_temp[j,i+1]-pot_temp[j,i])/float(hlev_yotc[i+1]-hlev_yotc[i])
        yvert_shear[j,i]=np.sqrt(float((u[j,i]-u[j,i-1])**2+(v[j,i]-v[j,i-1])**2))/float(hlev_yotc[i]-hlev_yotc[i-1])

for j in range(0,len(time)):
    for i in range(1,len(hlev_yotc)):
        brn_yotca[j,i]=(g/float(pot_temp[j,0]))*((hlev_yotc[i]-hlev_yotc[0])*(pot_temp[j,i]-pot_temp[j,0]))/float((u[j,i]-u[j,0])**2+(v[j,i]-v[j,0])**2)

#Calculate Relative Humidity
relhum=0.263*plev_yotc*q*np.exp((17.67*(temp-273.16))/(temp-29.65))**(-1)*100
relhum[relhum>100]=100
relhum[relhum<0]=0

#******************************************************************************
#Boundary Layer Height Inversion 1 and 2
#Variables Initialization
sec_ind=np.empty(len(time))
#main_inv=np.empty(len(time),'float')
sec_inv=np.empty(len(time))
main_inversion=np.empty(len(time))
sec_inversion=np.empty(len(time))
main_inv_hght=np.empty(len(time))
sec_inv_hght=np.empty(len(time))
yotc_clas=np.empty(len(time))
yotc_depth=np.empty(len(time))
yotc_hght_1invBL=np.empty(len(time))
yotc_hght_2invBL=np.empty(len(time))
yotc_hght_1invDL=np.empty(len(time))
yotc_hght_2invDL=np.empty(len(time))
yotc_hght_1inv=np.empty(len(time))
yotc_hght_2inv=np.empty(len(time))
yotc_strg_1inv=np.empty(len(time))
yotc_strg_2inv=np.empty(len(time))

relhum_yotc=np.empty(len(time))
temp_yotc=np.empty(len(time))
u_yotc=np.empty(len(time))
v_yotc=np.empty(len(time))
mixr_yotc=np.empty(len(time))
pot_temp_yotc=np.empty(len(time))
brn_yotc=np.empty(len(time))

#******************************************************************************
#Main Inversion Position
for ind,line in enumerate(hlev_yotc):
    if line>=float(100.):
        twenty_y_index=ind
        break
for ind,line in enumerate(hlev_yotc):
    if line>=2500:
        twoky=ind
        break

main_inv=pot_temp_grad[:,twenty_y_index:twoky].argmax(axis=1)
[i for i, j in enumerate(pot_temp_grad[:,twenty_y_index:twoky]) if j == main_inv]
main_inv+=twenty_y_index #posicion main inv mas indice de sobre 100 m (3)

# Second Inversion Position
for i in range(0,len(time)):
    for ind in range(twenty_y_index,main_inv[i]):
    #height 2da inv 80% main inv
        if hlev_yotc[ind]>=(0.8)*hlev_yotc[main_inv[i]]:
            sec_ind[i]=ind
            break
        else:
            sec_ind[i]=np.nan
    if main_inv[i]==twenty_y_index:
        sec_ind[i]=np.nan
    #calcula la posicion de la sec inv (trata si se puede, si no asigna nan)
    try:
        sec_inv[i]=pot_temp_grad[i,twenty_y_index:sec_ind[i]].argmax(0)
        [z for z, j in enumerate(pot_temp_grad[i,twenty_y_index:sec_ind[i]]) if j == sec_inv[i]]
        sec_inv[i]+=twenty_y_index
    except:
        sec_inv[i]=np.nan

# main inversion must be > theta_v threshold
ptemp_comp1=pot_temp_grad[:,main_inv[:]].diagonal() #extrae diagonal de pot temp
for i in range(0,len(time)):
    if ptemp_comp1[i]<ptemp_thold_main:
        #main_inv[i]=np.nan
        main_inv[i]=-9999 # Cannot convert float NaN to integer
        main_inversion[i]=False
        sec_inv[i]=np.nan
    else:
        main_inv_hght[i]=hlev_yotc[main_inv[i]]
        main_inversion[i]=True

    if main_inv_hght[i]<=1:
        main_inv_hght[i]=np.nan #Corrige el -9999 para calcular alt

    # secondary inversion must be > theta_v threshold

    if np.isnan(sec_inv[i])==False and pot_temp_grad[i,sec_inv[i]]>=ptemp_thold_sec:
        sec_inversion[i]=True
        sec_inv_hght[i]=hlev_yotc[sec_inv[i]]
    else:
        sec_inversion[i]=False
        sec_inv_hght[i]=np.nan

    #Clasification
    if sec_inversion[i]==False and main_inversion[i]==True:
        yotc_clas[i]=2
        yotc_depth[i]=np.nan
        yotc_hght_1invBL[i]=np.nan
        yotc_hght_2invBL[i]=np.nan
        yotc_hght_1invDL[i]=np.nan
        yotc_hght_2invDL[i]=np.nan
        yotc_hght_1inv[i]=hlev_yotc[main_inv[i]]
        yotc_hght_2inv[i]=np.nan
        yotc_strg_1inv[i]=pot_temp_grad[i,main_inv[i]]
        yotc_strg_2inv[i]=np.nan
    elif sec_inversion[i]==False and main_inversion[i]==False:
        yotc_clas[i]=1
        yotc_depth[i]=np.nan
        yotc_hght_1invBL[i]=np.nan
        yotc_hght_2invBL[i]=np.nan
        yotc_hght_1invDL[i]=np.nan
        yotc_hght_2invDL[i]=np.nan
        yotc_hght_1inv[i]=np.nan
        yotc_hght_2inv[i]=np.nan
        yotc_strg_1inv[i]=np.nan
        yotc_strg_2inv[i]=np.nan
    elif main_inversion[i]==True and sec_inversion[i]==True and yvert_shear[i,sec_inv[i]]>=shear_thold:
        yotc_clas[i]=4
        yotc_depth[i]=(hlev_yotc[main_inv[i]]-hlev_yotc[sec_inv[i]])
        yotc_hght_1invBL[i]=hlev_yotc[main_inv[i]]
        yotc_hght_2invBL[i]=hlev_yotc[sec_inv[i]]
        yotc_hght_1invDL[i]=np.nan
        yotc_hght_2invDL[i]=np.nan
        yotc_hght_1inv[i]=hlev_yotc[main_inv[i]]
        yotc_hght_2inv[i]=hlev_yotc[sec_inv[i]]
        yotc_strg_1inv[i]=pot_temp_grad[i,main_inv[i]]
        yotc_strg_2inv[i]=pot_temp_grad[i,sec_inv[i]]
    else:
        yotc_clas[i]=3
        yotc_hght_1invDL[i]=hlev_yotc[main_inv[i]]
        yotc_hght_2invDL[i]=hlev_yotc[sec_inv[i]]
        yotc_depth[i]=(hlev_yotc[main_inv[i]]-hlev_yotc[sec_inv[i]])
        yotc_hght_1invBL[i]=np.nan
        yotc_hght_2invBL[i]=np.nan
        yotc_hght_1inv[i]=hlev_yotc[main_inv[i]]
        yotc_hght_2inv[i]=hlev_yotc[sec_inv[i]]
        yotc_strg_1inv[i]=pot_temp_grad[i,main_inv[i]]
        yotc_strg_2inv[i]=pot_temp_grad[i,sec_inv[i]]

    #print

    relhum_yotc[i]=relhum[i,10]
    temp_yotc[i]=temp[i,10]
    u_yotc[i]=u[i,10]
    v_yotc[i]=v[i,10]
    mixr_yotc[i]=mixr[i,10]
    pot_temp_yotc[i]=pot_temp[i,10]
    brn_yotc[i]=brn_yotca[i,10]
#np.count_nonzero(~np.isnan(main_inv))

#*****************************************************************************\
# # #Histogram
# n, bin_edges =np.histogram(yotc_clas, bins=[1, 2, 3, 4,5],normed=1)

# plt.figure(0)
# y=bin_edges[0:4]

# #clas = ('No Inv.', 'Single Inv.', 'Decoupled L.', 'Buffer L.')
# clas = ('NI', 'SI', 'DL', 'BL')
# y_pos = np.arange(len(clas))

# plt.barh(y_pos, n, align='center', color='green')
# plt.yticks(y_pos, clas)
# plt.xticks(np.arange(0, 1.1, 0.1))
# plt.xlabel('Performance')
# plt.xlim([0,1])
# #plt.show()

# ****************************************************************************\
# ****************************************************************************\
#                            MAC Data Original Levels
#*****************************************************************************\
# ****************************************************************************\
path_databom=base_dir+'/Dropbox/Monash_Uni/SO/MAC/MatFiles/files_bom/'
matb= sio.loadmat(path_databom+'BOM_2006-2010.mat')
#*****************************************************************************\

bom=matb['SD'][:]#(3000,8,3594)
ni=bom.shape
timesd= matb['timesd'][:]
#*****************************************************************************\
#Delete special cases
indexdel1=[]
indexdel2=[]
#Delete when array is only NaN
for j in range(0,ni[2]):
    if np.isnan(np.nansum(bom[:,0,j]))==True:
        indexdel1=np.append(indexdel1,j)

bom=np.delete(bom, indexdel1,axis=2)
ni=bom.shape
timesd=np.delete(timesd, indexdel1)

#Delete when max height is lower than 2500 mts
for j in range(0,ni[2]):
    if np.nanmax(bom[:,1,j])<2500:
        indexdel2=np.append(indexdel2,j)

bom=np.delete(bom, indexdel2,axis=2) #(3000,8,3545)
ni=bom.shape
timesd=np.delete(timesd, indexdel2)
#*****************************************************************************\

#Convert Matlab datenum into Python datetime source: https://gist.github.com/vicow)
def datenum_to_datetime(datenum):
    days = datenum % 1
    hours = days % 1 * 24
    minutes = hours % 1 * 60
    seconds = minutes % 1 * 60
    return datetime.fromordinal(int(datenum)) \
        + timedelta(days=int(days)) \
        + timedelta(hours=int(hours)) \
        + timedelta(minutes=int(minutes)) \
        + timedelta(seconds=round(seconds)) \
        - timedelta(days=366)

#*****************************************************************************\
#Separation of Variables
pres=bom[:,0,:].reshape(ni[0],ni[2])
hght=bom[:,1,:].reshape(ni[0],ni[2])
temp=bom[:,2,:].reshape(ni[0],ni[2])
mixr=bom[:,5,:].reshape(ni[0],ni[2])
wdir_initial=bom[:,6,:].reshape(ni[0],ni[2])
wspd=bom[:,7,:].reshape(ni[0],ni[2])
relh=bom[:,4,:].reshape(ni[0],ni[2])

# vni=-wspd*(np.cos(np.radians(wdir_initial)))
# uni=-wspd*(np.sin(np.radians(wdir_initial)))

u=wspd*(np.cos(np.radians(270-wdir_initial)))
v=wspd*(np.sin(np.radians(270-wdir_initial)))

#*****************************************************************************\
#*****************************************************************************\
#                            MAC Data YOTC Levels
#*****************************************************************************\
#*****************************************************************************\
#Interpolation to YOTC Levels
# plt.plot(hght[0:200,1], 'ro')
# plt.show()

prutemp=np.empty((len(hlev_yotc),0))
prumixr=np.empty((len(hlev_yotc),0))
# pruwspd=np.empty((len(hlev_yotc),0))
# pruwdir=np.empty((len(hlev_yotc),0))
pruu=np.empty((len(hlev_yotc),0))
pruv=np.empty((len(hlev_yotc),0))
prurelh=np.empty((len(hlev_yotc),0))

for j in range(0,ni[2]):
#for j in range(0,100):
#height initialization
    x=hght[:,j]
    x[-1]=np.nan
    new_x=hlev_yotc
#Interpolation YOTC levels
    yt=temp[:,j]
    rest=interp1d(x,yt)(new_x)
    prutemp=np.append(prutemp,rest)

    ym=mixr[:,j]
    resm=interp1d(x,ym)(new_x)
    prumixr=np.append(prumixr,resm)

    yw=u[:,j]
    resw=interp1d(x,yw)(new_x)
    pruu=np.append(pruu,resw)

    yd=v[:,j]
    resd=interp1d(x,yd)(new_x)
    pruv=np.append(pruv,resd)

    yr=relh[:,j]
    resr=interp1d(x,yr)(new_x)
    prurelh=np.append(prurelh,resr)

tempmac_ylev=prutemp.reshape(-1,len(hlev_yotc)).transpose()
umac_ylev=pruu.reshape(-1,len(hlev_yotc)).transpose()
vmac_ylev=pruv.reshape(-1,len(hlev_yotc)).transpose()
mixrmac_ylev=prumixr.reshape(-1,len(hlev_yotc)).transpose()
relhmac_ylev=prurelh.reshape(-1,len(hlev_yotc)).transpose()

# wspdmac_ylev=pruwspd.reshape(-1,len(hlev_yotc)).transpose()
# wdirmac_ylev=pruwdir.reshape(-1,len(hlev_yotc)).transpose()

wspdmac_ylev=np.sqrt(umac_ylev**2 + vmac_ylev**2)
wdirmac_ylev=np.arctan2(-umac_ylev, -vmac_ylev)*(180/np.pi)
wdirmac_ylev[(umac_ylev == 0) & (vmac_ylev == 0)]=0

#*****************************************************************************\
#Initialization Variables
wdir_my=np.empty(tempmac_ylev.shape)

spec_hum_my=np.empty(tempmac_ylev.shape)
tempv_my=np.empty(tempmac_ylev.shape)
ptemp_my=np.empty(tempmac_ylev.shape)
brn_mya=np.empty(tempmac_ylev.shape)

ucomp_my=np.empty(tempmac_ylev.shape)
vcomp_my=np.empty(tempmac_ylev.shape)

ucomp_initial_my=np.empty(tempmac_ylev.shape)
vcomp_initial_my=np.empty(tempmac_ylev.shape)

vert_shear_my=np.empty(tempmac_ylev.shape)*np.nan
ptemp_gmy=np.empty(tempmac_ylev.shape)*np.nan
main_my_inv=np.empty(ni[2])*np.nan
twenty_my_index=[]
twokmy=[]
sec_my_ind=np.empty(ni[2])*np.nan
sec_my_inv=np.empty(ni[2])*np.nan
ptemp_comp2=np.empty(ni[2])*np.nan
main_my_inv_hght=np.empty(ni[2])*np.nan
main_my_inversion=np.empty(ni[2])*np.nan
sec_my_inv_hght=np.empty(ni[2])*np.nan
sec_my_inversion=np.empty(ni[2])*np.nan
mac_y_clas=np.empty(ni[2])*np.nan
mac_y_hght_1invDL=np.empty(ni[2])*np.nan
mac_y_hght_2invDL=np.empty(ni[2])*np.nan
mac_y_depth=np.empty(ni[2])*np.nan
mac_y_hght_1invBL=np.empty(ni[2])*np.nan
mac_y_hght_2invBL=np.empty(ni[2])*np.nan
mac_y_hght_1inv=np.empty(ni[2])*np.nan
mac_y_hght_2inv=np.empty(ni[2])*np.nan
mac_y_strg_1inv=np.empty(ni[2])*np.nan
mac_y_strg_2inv=np.empty(ni[2])*np.nan

relhum_my=np.empty(ni[2])*np.nan
temp_my=np.empty(ni[2])*np.nan
u_my=np.empty(ni[2])*np.nan
v_my=np.empty(ni[2])*np.nan
mixr_my=np.empty(ni[2])*np.nan
pot_temp_my=np.empty(ni[2])*np.nan
brn_my=np.empty(ni[2])*np.nan

#*****************************************************************************\
for j in range(0,ni[2]):
#for j in range(0,100):
#Calculate new variables
    for i in range(0,len(hlev_yotc)):
        if 0.<=wdirmac_ylev[i,j]<=90.:
            wdir_my[i,j]=wdirmac_ylev[i,j]+270.
        elif 90.<=wdirmac_ylev[i,j]<=360.:
            wdir_my[i,j]=wdirmac_ylev[i,j]-90.

        spec_hum_my[i,j]=(float(mixrmac_ylev[i,j])/1000.)/(1+(float(mixrmac_ylev[i,j])/1000.))

        tempv_my[i,j]=tempmac_ylev[i,j]*float(1+0.61*spec_hum_my[i,j])
        ptemp_my[i,j]=(tempv_my[i,j]+273.16)*((1000./plev_yotc[i])**0.286) #Ok

        brn_mya[i,j]=(g/float(ptemp_my[0,j]))*((hlev_yotc[i]-hlev_yotc[0])*(ptemp_my[i,j]-ptemp_my[0,j]))/float((umac_ylev[i,j]-umac_ylev[0,j])**2+(vmac_ylev[i,j]-vmac_ylev[0,j])**2)

        # vcomp_my[i,j]=-wspdmac_ylev[i,j]*(np.cos(np.radians(wdir_my[i,j])))
        # ucomp_my[i,j]=-wspdmac_ylev[i,j]*(np.sin(np.radians(wdir_my[i,j])))

        # vcomp_initial_my[i,j]=-wspdmac_ylev[i,j]*(np.cos(np.radians(wdirmac_ylev[i,j])))
        # ucomp_initial_my[i,j]=-wspdmac_ylev[i,j]*(np.sin(np.radians(wdirmac_ylev[i,j])))

    for i in range(0,len(hlev_yotc)-1):
        vert_shear_my[i,j]=np.sqrt(float((umac_ylev[i,j]-umac_ylev[i-1,j])**2+(vmac_ylev[i,j]-vmac_ylev[i-1,j])**2))/float(hlev_yotc[i+1]-hlev_yotc[i])

        ptemp_gmy[i,j]=(ptemp_my[i+1,j]-ptemp_my[i,j])/float(hlev_yotc[i+1]-hlev_yotc[i])

    vert_shear_my[-1,j]=np.nan
    ptemp_gmy[-1,j]=np.nan

#*****************************************************************************\
# #Main Inversion Position
for ind,line in enumerate(hlev_yotc):
    if line>=float(100.):
        twenty_my_index=ind
        break
for ind,line in enumerate(hlev_yotc):
    if line>=2500:
        twokmy=ind
        break

main_my_inv=ptemp_gmy[twenty_my_index:twokmy,:].argmax(axis=0)
main_my_inv+=twenty_my_index #posicion main inv mas indice de sobre 100 m (3)

# # Second Inversion Position
for j in range(0,ni[2]):
#for j in range(0,100):
    for ind in range(twenty_my_index,main_my_inv[j]):
    #height 2da inv 80% main inv
        if hlev_yotc[ind]>=(0.8)*hlev_yotc[main_my_inv[j]]:
            sec_my_ind[j]=ind
            break
        else:
            sec_my_ind[j]=np.nan
    if main_my_inv[j]==twenty_my_index:
        sec_my_ind[j]=np.nan
    #calcula la posicion de la sec inv (trata si se puede, si no asigna nan)
    try:
        sec_my_inv[j]=ptemp_gmy[twenty_my_index:sec_my_ind[j],j].argmax(0)
        sec_my_inv[j]+=twenty_my_index
    except:
        sec_my_inv[j]=np.nan

# main inversion must be > theta_v threshold
for j in range(0,ni[2]):
#for j in range(0,100):
    ptemp_comp2[j]=ptemp_gmy[main_my_inv[j],j]#.diagonal() #extrae diagonal de pot temp
    if ptemp_comp2[j]<ptemp_thold_main:
        #main_inv[i]=np.nan
        main_my_inv[j]=-9999 # Cannot convert float NaN to integer
        main_my_inversion[j]=False
        sec_my_inv[j]=np.nan
    else:
        main_my_inv_hght[j]=hlev_yotc[main_my_inv[j]]
        main_my_inversion[j]=True

    if main_my_inv_hght[j]<=1:
        main_my_inv_hght[j]=np.nan #Corrige el -9999 para calcular alt

# secondary inversion must be > theta_v threshold

    if np.isnan(sec_my_inv[j])==False and ptemp_gmy[sec_my_inv[j],j]>=ptemp_thold_sec:
        sec_my_inversion[j]=True
        sec_my_inv_hght[j]=hlev_yotc[sec_my_inv[j]]
    else:
        sec_my_inversion[j]=False
        sec_my_inv_hght[j]=np.nan

# #Clasification
    if sec_my_inversion[j]==False and main_my_inversion[j]==True:
        mac_y_clas[j]=2
        mac_y_depth[j]=np.nan
        mac_y_hght_1invBL[j]=np.nan
        mac_y_hght_2invBL[j]=np.nan
        mac_y_hght_1invDL[j]=np.nan
        mac_y_hght_2invDL[j]=np.nan
        mac_y_hght_1inv[j]=hlev_yotc[main_my_inv[j]]
        mac_y_hght_2inv[j]=np.nan
        mac_y_strg_1inv[j]=ptemp_gmy[main_my_inv[j],j]
        mac_y_strg_2inv[j]=np.nan
    elif sec_my_inversion[j]==False and main_my_inversion[j]==False:
        mac_y_clas[j]=1
        mac_y_depth[j]=np.nan
        mac_y_hght_1invBL[j]=np.nan
        mac_y_hght_2invBL[j]=np.nan
        mac_y_hght_1invDL[j]=np.nan
        mac_y_hght_2invDL[j]=np.nan
        mac_y_hght_1inv[j]=np.nan
        mac_y_hght_2inv[j]=np.nan
        mac_y_strg_1inv[j]=np.nan
        mac_y_strg_2inv[j]=np.nan
    elif main_my_inversion[j]==True and sec_my_inversion[j]==True and vert_shear_my[sec_my_inv[j],j]>=shear_thold:
        mac_y_clas[j]=4
        mac_y_depth[j]=(hlev_yotc[main_my_inv[j]]-hlev_yotc[sec_my_inv[j]])
        mac_y_hght_1invBL[j]=hlev_yotc[main_my_inv[j]]
        mac_y_hght_2invBL[j]=hlev_yotc[sec_my_inv[j]]
        mac_y_hght_1invDL[j]=np.nan
        mac_y_hght_2invDL[j]=np.nan
        mac_y_hght_1inv[j]=hlev_yotc[main_my_inv[j]]
        mac_y_hght_2inv[j]=hlev_yotc[sec_my_inv[j]]
        mac_y_strg_1inv[j]=ptemp_gmy[main_my_inv[j],j]
        mac_y_strg_2inv[j]=ptemp_gmy[sec_my_inv[j],j]
    else:
        mac_y_clas[j]=3
        mac_y_hght_1invDL[j]=hlev_yotc[main_my_inv[j]]
        mac_y_hght_2invDL[j]=hlev_yotc[sec_my_inv[j]]
        mac_y_depth[j]=(hlev_yotc[main_my_inv[j]]-hlev_yotc[sec_my_inv[j]])
        mac_y_hght_1invBL[j]=np.nan
        mac_y_hght_2invBL[j]=np.nan
        mac_y_hght_1inv[j]=hlev_yotc[main_my_inv[j]]
        mac_y_hght_2inv[j]=hlev_yotc[sec_my_inv[j]]
        mac_y_strg_1inv[j]=ptemp_gmy[main_my_inv[j],j]
        mac_y_strg_2inv[j]=ptemp_gmy[sec_my_inv[j],j]

    relhum_my[j]=relhmac_ylev[10,j]
    temp_my[j]=tempmac_ylev[10,j]+273.16
    u_my[j]=umac_ylev[10,j]
    v_my[j]=vmac_ylev[10,j]
    mixr_my[j]=mixrmac_ylev[10,j]
    pot_temp_my[j]=ptemp_my[10,j]
    brn_my[j]=brn_mya[10,j]
#*****************************************************************************\
# #Histogram
# n, bin_edges =np.histogram(mac_y_clas, bins=[1, 2, 3, 4,5],normed=1)

# plt.figure(0)
# y=bin_edges[0:4]

# #clas = ('No Inv.', 'Single Inv.', 'Decoupled L.', 'Buffer L.')
# clas = ('NI', 'SI', 'DL', 'BL')
# y_pos = np.arange(len(clas))

# plt.barh(y_pos, n, align='center', color='green')
# plt.yticks(y_pos, clas)
# plt.xticks(np.arange(0, 1.1, 0.1))
# plt.xlabel('Performance')
# plt.xlim([0,1])
# #plt.show()

#*****************************************************************************\
#Cambiar fechas
timestamp = [datenum_to_datetime(t) for t in timesd]
time_my = np.array(timestamp)
time_my_ori = np.array(timestamp)

for i in range(0,ni[2]):
    #Cuando cae 23 horas del 31 de diciembre agrega un anio
    if time_my[i].hour==23 and time_my[i].day==31 and time_my[i].month==12:
        y1=time_my[i].year
        time_my[i]=time_my[i].replace(year=y1+1,hour=0, month=1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==31 and time_my[i].month==1:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==31 and time_my[i].month==3:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==31 and time_my[i].month==5:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==31 and time_my[i].month==7:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==31 and time_my[i].month==8:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==31 and time_my[i].month==10:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==30 and time_my[i].month==4:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==30 and time_my[i].month==6:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==30 and time_my[i].month==9:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==30 and time_my[i].month==11:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    if  time_my[i].hour==23 and time_my[i].day==28 and time_my[i].month==2:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)
    #Bisiesto 2008
    if  time_my[i].hour==23 and time_my[i].day==29 and time_my[i].month==4 and time_my[i].year==2008:
        m1=time_my[i].month
        time_my[i]=time_my[i].replace(hour=0, month=m1+1,day=1)

    #Cuando cae 23 horas, mueve hora a las 00 del dia siguiente
    if time_my[i].hour==23:
        d1=time_my[i].day
        time_my[i]=time_my[i].replace(hour=0,day=d1+1)
    else:
        time_my[i]=time_my[i]
    #Cuando cae 11 horas, mueve hora a las 12 del mismo dia
    if time_my[i].hour==11:
        time_my[i]=time_my[i].replace(hour=12)
    else:
        time_my[i]=time_my[i]

    #Cuando cae 1 horas, mueve hora a las 0 del mismo dia
    if time_my[i].hour==1:
        time_my[i]=time_my[i].replace(hour=0)
    else:
        time_my[i]=time_my[i]

#*****************************************************************************\
#*****************************************************************************\
#                          Dataframes 2006-2010                               \
#*****************************************************************************\
#*****************************************************************************\
#Date index del periodo 2006-2010
date_index_all = pd.date_range('2006-01-01 00:00', periods=3652, freq='12H')
# #*****************************************************************************\
#Dataframe YOTC 2008-2010
dy={'Clas':yotc_clas,
'Depth':yotc_depth,
#'1 Inv BL': yotc_hght_1invBL,
#'2 Inv BL': yotc_hght_2invBL,
#'1 Inv DL': yotc_hght_1invDL,
#'2 Inv DL': yotc_hght_2invDL,
'1ra Inv': yotc_hght_1inv,
'2da Inv': yotc_hght_2inv,
'Strg 1inv': yotc_strg_1inv,
'Strg 2inv': yotc_strg_2inv,
'Mix R 925':mixr_yotc,
'T 925':temp_yotc,
'Theta v 925':pot_temp_yotc,
'u 925':u_yotc,
'v 925':v_yotc,
'RH 925':relhum_yotc}
#'BRN 925':brn_yotc}

df_yotc = pd.DataFrame(data=dy,index=date_yotc)
df_yotc.index.name = 'Date'
#*****************************************************************************\
#Dataframe YOTC All
df_yotc_all=df_yotc.reindex(date_index_all)
df_yotc_all.index.name = 'Date'
# #*****************************************************************************\
# #Dataframe MAC
# dm={'Clas':mac_clas,
# 'Depth':mac_depth,
# '1 Inv BL': mac_hght_1invBL,
# '2 Inv BL': mac_hght_2invBL,
# '1 Inv DL': mac_hght_1invDL,
# '2 Inv DL': mac_hght_2invDL,
# '1ra Inv': mac_hght_1inv,
# '2da Inv': mac_hght_2inv,
# 'Strg 1inv': mac_strg_1inv,
# 'Strg 2inv': mac_strg_2inv}

# df_mac = pd.DataFrame(data=dm,index=time_my)
# # Eliminate Duplicate Soundings

# dfm=df_mac.reset_index().drop_duplicates(cols='index',take_last=True).set_index('index')

# df_mac_final=dfm.reindex(date_index_all)
# df_mac_final.index.name = 'Date'
# # count_nan = len(df_my_final) - df_my_final.count()

# #*****************************************************************************\
#Dataframe MAC YOTC levels
dmy={'Clas':mac_y_clas,
'Depth':mac_y_depth,
# '1 Inv BL': mac_y_hght_1invBL,
# '2 Inv BL': mac_y_hght_2invBL,
# '1 Inv DL': mac_y_hght_1invDL,
# '2 Inv DL': mac_y_hght_2invDL,
'1ra Inv': mac_y_hght_1inv,
'2da Inv': mac_y_hght_2inv,
'Strg 1inv': mac_y_strg_1inv,
'Strg 2inv': mac_y_strg_2inv,
'Mix R 925':mixr_my,
'T 925':temp_my,
'Theta v 925':pot_temp_my,
'u 925':u_my,
'v 925':v_my,
'RH 925':relhum_my}

df_mac_y = pd.DataFrame(data=dmy,index=time_my)
# Eliminate Duplicate Soundings
dfmy=df_mac_y.reset_index().drop_duplicates(cols='index',take_last=True).set_index('index')

df_macyotc_final=dfmy.reindex(date_index_all)
df_macyotc_final.index.name = 'Date'
#*****************************************************************************\
#Saving CSV
path_data_save=base_dir+'/Dropbox/Monash_Uni/SO/MAC/Data/00 CSV/'

#df_yotc.to_csv(path_data_save + 'df_yotc925.csv', sep='\t', encoding='utf-8')
df_yotc_all.to_csv(path_data_save + 'df_yotc_all925.csv', sep='\t', encoding='utf-8')
# df_mac_final.to_csv(path_data_save + 'df_mac_final.csv', sep='\t', encoding='utf-8')
df_macyotc_final.to_csv(path_data_save + 'df_macyotc_final925.csv', sep='\t', encoding='utf-8')

#*****************************************************************************\

# #T1 = pd.read_csv(path_data_save + 'df_macyotc_final.csv', sep='\t')

# #Dataframe datos per level
# #nlevel=range(1,31)
# #Crear listas con variables y unirlas a dataframe 3D
# #t_list=temp.tolist()
# #u_list=u.tolist()
# #v_list=v.tolist()
# #q_list=q.tolist()

# #data={'temp':t_list, 'q':q_list,'u':u_list, 'v':v_list}
# #df=pd.DataFrame(data=data, index=date_range)


#!/usr/bin/python3.1
from Graph import *
from LettersGenerator import *
from Dictionary import *

class Solver:
    """ classe qui résoud le jeu :
    self.graph = le graph qui represente toutes les cases du plateau,
    self.d = objet Dictionnary,
    self.dico = l'arbre dictionnaire
    self.lettersList = la liste des letters du plateau,
    self.solution = la liste des solutions du solver"""

    def __init__(self, graphParent, dicoParent, lettersList, solver):
        self.g = graphParent
        self.graph = self.g.graph
        self.d = dicoParent
        self.dico = dicoParent.trie
        self.lettersList = lettersList
        self.solver = solver
        self.solution = self.setSolverType(solver)
        print(self.wordsCounter(self.solution), "words found.")

    def setSolverType(self, solver):
        if solver == 0:
            return self.solver_init()
        elif self.solver == 1:
            return self.solver2_init()
        else :
            print("xxx","solver execution error.")

    def solver_init(self):
        wordsFound = []
        colors = ["white" for e in self.lettersList]
        positions = [(i,e) for i,e in enumerate(self.lettersList)]
        for e in positions:
            self.solver_rec([], e, wordsFound, colors)
        res = set(wordsFound)
        res = self.decreasingList(res)
        return res

    def solver_rec(self, parcours, position, ensWordsFound, colors):
        """ ensMotTrouves = ensemble des words trouves, selections = une liste de selection de letters, colors nous permet de savoir si l'etat à déja ete visité ou non"""
        wordPotentiel = self.getWord(parcours + [position])
        if self.d.isInTree( wordPotentiel) :
            ensWordsFound.append(wordPotentiel)
        if not self.d.prefixIsInTree(wordPotentiel):
            return
        else :
            numCase = position[0]
            newParcours = list(parcours)
            newParcours.append((numCase, self.lettersList[numCase]))
            newColors = list(colors)
            newColors[numCase] = "black"
            for neighbour in self.graph[numCase]:
                if newColors[neighbour]=="white":
                    newPosition = (neighbour, self.lettersList[neighbour]);
                    self.solver_rec(newParcours, newPosition, ensWordsFound, newColors)

    def solver2_init(self):
        """ solver qui recherche dans le dictionnaire """
        result = []
        colors = ["white" for e in self.lettersList]
        for letter in self.dico:
            #print(letter)
            self.solver2_rec([], letter, result, colors, self.dico)
        res = set(result)
        res = self.decreasingList(res)
        return res

    def solver2_rec(self, prefix, letter, result, colors, dico_current):
        emplacements = self.g.isInGraph(letter)
        #print(emplacements)
        if emplacements==[]:
            #print("-> emplacement VIDE")
            return
        else :
            for emplacement in emplacements :
                #print("->", emplacement)
                if prefix ==[] or self.g.isNeighbour(emplacement, prefix[-1][0]):
                    #print("-> est neighbour de precedent")
                    if colors[emplacement] == "white":
                        #print(colors[emplacement])
                        wordPotentiel = self.getWord(prefix + [(emplacement,letter)])
                        if '_NULL_' in dico_current[letter]:
                            result.append(wordPotentiel)
                        if dico_current[letter] != {'_NULL_':'_NULL_'}:
                            new_dico_current = dico_current[letter]
                            newColors = list(colors)
                            newColors[emplacement] = "black"
                            for newLetter in new_dico_current:
                                self.solver2_rec(prefix + [(emplacement, letter)], newLetter, result, newColors, new_dico_current)

    def getWord(self, list_couple):
        """recupere un string correspondant à la suite de cases séléctionnées """
        if list_couple == []:
            return ""
        return ''.join([e[1].lower() for e in list_couple])

    def decreasingList(self, words):
        """ retourne les words d'une liste en ordre decroissant de longueur"""
        dic = {}
        words = self.d.lowerList(words)
        for word in words:
            if not len(word) in dic:
                dic[len(word)] = []
            dic[len(word)].append(word)
        dic = dic.items()
        dic = sorted(dic)
        #dic.reverse()
        return [f for e in dic for f in e[1]]

    def wordsCounter(self, myList):
        res = 0
        if myList != None:
            for e in myList:
                res +=1
        return res


import calendar
from datetime import date

from django.contrib import admin
from django.db.models import Sum, Count
from django.utils.html import format_html
from django.utils.html import mark_safe

from .forms import StudentFeeAdd
from .models import Student, StudentFee, FeeGroup, FeeType#, FeeSummary

# Register your models here.
admin.site.register(FeeGroup)
admin.site.register(FeeType)

admin.site.site_header = "My School Admin"
admin.site.site_title = "My School Admin Portal"
admin.site.index_title = "Welcome to My School Portal"

@admin.register(Student)
class StudentAdmin(admin.ModelAdmin):
    """ Display Class of Student Model in Admin Panel"""

    # remove delete actions
    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    # Custom Actions
    def expel_from_school(self, request, queryset):
        rows_updated = queryset.update(is_studying=False)
        if rows_updated == 1:
            message_bit = "1 student was"
        else:
            message_bit = "%s students were" % rows_updated
        self.message_user(request, "%s successfully marked as expelled" % message_bit)

    expel_from_school.short_description = 'Expel From School'
    expel_from_school.allowed_permissions = ('change',)

    def last_fee_submitted(self):
        paid_color = 'green'
        unpaid_color = 'red'

        if self.is_studying:
            obj = self.studentfee_set.last()
            if obj is not None:  # if a record exists
                if obj.valid_until >= date.today():  # if paid this month
                    return format_html(
                        '{}',
                        paid_color,
                        calendar.month_name[int(obj.valid_until.month)] + ', ' + str(obj.valid_until.year)
                    )
                else:  # if not paid this month
                    return format_html(
                        '{}',
                        unpaid_color,
                        calendar.month_name[int(obj.date.month)] + ', ' + str(obj.date.year)
                    )
            else:  # if record does not exists
                return format_html(
                    '{}',
                    unpaid_color,
                    "No Fee Paid"
                )
        else:
            return "Left School"

    last_fee_submitted.short_description = 'Last Fee Submitted'

    def profile_image_display(self, obj):
        return mark_safe(
            ''.format(
                url=obj.profile_image.url,
                width=200,
                height=200,
                style='',
            )
        )

    profile_image_display.short_description = "Student Image"

    empty_value_display = '--Empty--'

    list_display = (
        'full_name',
        'father_name',
        'is_studying',
        'gender',
        last_fee_submitted,
    )

    list_filter = (
        'is_studying',
        'current_class',
        'gender'
    )

    search_fields = (
        'first_name', 'last_name', 'admission_no'
    )

    ordering = ('first_name',)

    fieldsets = (
        ("School Record", {
            'fields': (
                'admission_no',
                'date_of_admission',
                'is_studying',
                'current_class',
                'profile_image',
                'profile_image_display',  # callable function,
            )
        }),
        ("Personal Information", {
            'fields': ('first_name', 'last_name', 'date_of_birth', 'gender', 'address')
        }),
        ("Guardian Information", {
            'fields': ('father_name', 'father_cnic', 'fathers_phone_no', 'fathers_proffesion')
        })
    )

    actions = ['expel_from_school', ]

    def get_readonly_fields(self, request, obj=None):
        """ Make admission_no and date_of_admission uneditable if
        opened the admin change form but editable if opened
        the create form
        """

        if obj:  # if the object exists then make them readonly
            return ['admission_no', 'date_of_admission', 'profile_image_display']
        else:
            return ['profile_image_display', ]

@admin.register(StudentFee)
class StudentFeeAdmin(admin.ModelAdmin):
    """ Admin display class for the model StudentFee """

    # Delete Delete Action from admin
    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    form = StudentFeeAdd

    raw_id_fields = (
        'student',
        'fee_group',
        )
    # Filtering
    list_filter = (
        'valid_until',
    )

    # searching
    search_fields = [
        'student__admission_no',
        'student__first_name',
        'student__last_name',
    ]

    list_display = (
        'student',
        'valid_until',
        'total_amount',
        'date_submitted',
    )

# @admin.register(FeeSummary)
# class FeeSummary(admin.ModelAdmin):
#     change_list_template = 'students/admin/fee_summary_change_list.html'
#     date_hierarchy = 'date'

#     def changelist_view(self, request, extra_context=None):
#         response = super().changelist_view(
#             request,
#             extra_context=extra_context,
#         )

#         try:
#             qs = response.context_data['cl'].queryset
#         except (AttributeError, KeyError):
#             return response

#         metrics = {
#             'total': Count('id'),
#             'total_sales': Sum('amount'),
#         }

#         response.context_data['summary'] = list(
#             qs
#                 .values('date')
#                 .annotate(**metrics)
#                 .order_by('date')
#         )

#         response.context_data['summary_total'] = dict(
#             qs.aggregate(**metrics)
#         )

#         return response


import RPi.GPIO as GPIO
import time
from mfrc522 import SimpleMFRC522
from datetime import datetime, time as dt_time

# Set the GPIO mode
GPIO.setmode(GPIO.BOARD)

# Define the motor driver pins for the stepper motor
motor_pins = [13, 11, 15, 12]

# Set the motor pins as output
for pin in motor_pins:
    GPIO.setup(pin, GPIO.OUT)

# Define the servo motor pin
servo_pin = 16

# Create an instance of the RFID reader
reader = SimpleMFRC522()

# Define the stepper motor sequence
seq = [
    [1, 0, 0, 1],  # Step 1
    [1, 0, 0, 0],  # Step 2
    [1, 1, 0, 0],  # Step 3
    [0, 1, 0, 0],  # Step 4
    [0, 1, 1, 0],  # Step 5
    [0, 0, 1, 0],  # Step 6
    [0, 0, 1, 1],  # Step 7
    [0, 0, 0, 1]   # Step 8
]

try:
    while True:
        current_time = datetime.now().time()

        # Check if the current time is within the desired time range
        start_time = dt_time(14, 38)  # Start time: 2:38 PM
        end_time = dt_time(14, 45)    # End time: 2:45 PM

        if start_time <= current_time <= end_time:
            # Wait for an RFID tag to be detected
            print("Hold a tag near the reader")
            id, text = reader.read()

            # If a tag is detected, activate the stepper motor and servo motor
            if id is not None:
                print("Tag detected")

                # Function to move the stepper motor for 60 degrees clockwise
                def move_stepper_motor_clockwise(delay):
                    steps = 0
                    while steps < 100:  # Adjust steps for 60 degrees rotation
                        for halfstep in range(8):
                            for pin in range(4):
                                GPIO.output(motor_pins[pin], seq[halfstep][pin])
                            time.sleep(delay)
                            steps += 1

                # Function to move the stepper motor for 60 degrees counterclockwise
                def move_stepper_motor_counterclockwise(delay):
                    steps = 0
                    while steps < 100:  # Adjust steps for 60 degrees rotation
                        for halfstep in range(7, -1, -1):
                            for pin in range(4):
                                GPIO.output(motor_pins[pin], seq[halfstep][pin])
                            time.sleep(delay)
                            steps += 1

                # Code for controlling the servo motor
                GPIO.setup(servo_pin, GPIO.OUT)
                pwm = GPIO.PWM(servo_pin, 50)  # 50 Hz frequency
                pwm.start(0)

                # Rotate the stepper motor 60 degrees clockwise
                move_stepper_motor_clockwise(0.01)

                # Rotate the servo motor 120 degrees clockwise
                duty_cycle = 2 + (120 / 18)  # Calculate duty cycle for 120 degrees
                GPIO.output(servo_pin, True)
                pwm.ChangeDutyCycle(duty_cycle)
                time.sleep(1)
                GPIO.output(servo_pin, False)
                pwm.ChangeDutyCycle(0)

                # Rotate the servo motor 120 degrees counterclockwise
                duty_cycle = 2 + (0 / 18)  # Calculate duty cycle for 0 degrees
                GPIO.output(servo_pin, True)
                pwm.ChangeDutyCycle(duty_cycle)
                time.sleep(1)
                GPIO.output(servo_pin, False)
                pwm.ChangeDutyCycle(0)

                # Rotate the stepper motor 60 degrees counterclockwise
                move_stepper_motor_counterclockwise(0.01)

                pwm.stop()

        # Delay between checking the time
        time.sleep(60)  # Check every minute

except KeyboardInterrupt:
    # Stop the motors and cleanup GPIO pins on keyboard interrupt
    GPIO.output(motor_pins, 0)
    GPIO.cleanup()


# Ensure that profiles with empty / invalid entries for 'country' get
# mapped to the new 'XX' / 'Unknown' marker.

from karl.consts import countries
from karl.utils import find_catalog
from karl.utils import find_profiles

def evolve(context):
    catalog = find_catalog(context)
    profiles = find_profiles(context)
    for profile in profiles.values():
        if profile.country not in countries.as_dict:
            print ('Evolving profile %s country from "%s" to "XX"' %
                      (profile.__name__, profile.country))
            profile.country = 'XX'
            catalog.reindex_doc(profile.docid, profile)


import logging
from unittest import TestCase
from Signage.src.google_street_view_etl import GoogleStreetViewEtl as GSVE
import geopandas as gpd
import numpy as np
import random

class TestGoogleStreetViewEtl(TestCase):
    @classmethod
    def _get_iter(cls):
        _st_shp = gpd.read_file(
            "/Users/sunghoonyang/PycharmProjects/groundwork-detection/Signage/asset/geo_export_ce677b00-822e-465b-8b4f-aacaff026101.shp")
        mh_sts = \
            _st_shp[(_st_shp["borocode"] == "2") & (_st_shp["st_width"] > 20) & (_st_shp["st_width"] < 30)][
                'geometry']
        for street in list(mh_sts.get_values()).__reversed__():
            for i in np.arange(0, len(street.xy[0]), 5):
                x = street.xy[0][i]
                y = street.xy[1][i]
                yield x, y

    @classmethod
    def _get_puma_iter(cls):
        _raw = gpd.read_file(
            r"/Users/sunghoonyang/Google Drive/Argo/groundwork-detection/intersection_dta/StreetsOnlyGCSNA1983/OnStreetOnlyGCSNA1983.shp")
        # random sampling from the population of intersection coordinates
        # in the below set up each coordinate pair will create 6 * 2 = 12 images
        _x_shp = _raw.loc[random.sample(range(0, _raw.size), int(1e4)), :]
        for ix, _row in _x_shp.iterrows():
            puma, pt = _row
            if pt is np.nan:
                logging.warning('Point is np.nan. Skipping...')
                continue
            yield pt.x, pt.y, {'demarcation': puma, 'fov': [30, 90], 'heading': list(np.arange(0, 360, 60))}

    @classmethod
    def _get_nh_iter(cls):
        _raw = gpd.read_file(
            r"/Users/sunghoonyang/Google Drive/Argo/groundwork-detection/intersection_dta/20190114 Neighborhood Intersections/neighborhood_intersections.shp")
        # random sampling from the population of intersection coordinates
        # in the below set up each coordinate pair will create 6 * 2 = 12 images
        _x_shp = _raw.loc[random.sample(range(0, _raw.size), int(1e4)), :]
        for ix, _row in _x_shp.iterrows():
            nh, pt = _row
            if pt is np.nan:
                logging.warning('Point is np.nan. Skipping...')
                continue
            yield pt.x, pt.y, {'demarcation': nh, 'fov': [30, 90], 'heading': list(np.arange(0, 360, 60))}

    def test_iter_work(self):
        GSVE.work(
            TestGoogleStreetViewEtl._get_iter()
            , r'/Users/sunghoonyang/Google Drive/Argo/groundwork-detection/img'
        )

    def test_puma_iter_work(self):
        GSVE.work(
            TestGoogleStreetViewEtl._get_puma_iter()
            , r'/Users/sunghoonyang/Google Drive/Argo/groundwork-detection/img'
        )

    def test_nh_iter_work(self):
        GSVE.work(
            TestGoogleStreetViewEtl._get_nh_iter()
            , r'/Users/sunghoonyang/Google Drive/Argo/groundwork-detection/img/neighborhood-images/'
        )


#coding=utf-8
# 05.16 교수요청사항
# 기존의 Search Engine 에서 했던것처럼
# 단어들을 lexical 단위에서 + 형태소 단위에서
# 구조가 아닌 단어들의 이치를 보고 하면 어떻게 되느냐에 대한 코드 작성

import operator
import os
from whoosh.index import create_in
from whoosh.fields import *
from whoosh.qparser import QueryParser
from typing import List, TextIO,Dict
import time
'''__________ CONFIG AREA START __________'''
DATA_DIR: str         = "../WISEKB/data/"
Q_FILE_NAME: str      = "tmpQ_WT.txt" # Q.txt
Q_MORP_FILE_NAME: str = "tmpQ_M_WT.txt" ## Q_MORP.txt
'''__________ CONFIG AREA END   __________'''

def log(tag, text)-> None:
    # Info tag
    if (tag == 'i'):
        print("[INFO] " + text)
    # Error tag
    elif (tag == 'e'):
        print("[ERROR] " + text)
    # Success tag
    elif (tag == 's'):
        print("[SUCCESS] " + text)

def get_data_from_txt(_filename)-> List[str]:
    """`

    :return: data List
    """
    dataList :List[str] = []
    f : TextIO = open(file=_filename, mode='r', encoding='utf8')

    for line in f.readlines():
        dataList.append(line.strip())

    f.close()
    log('s', "{} 파일에서 {} 줄 불러옴".format(_filename, len(dataList)))

    return dataList

def extract_morp_str(_morpStr: str) -> str:
    """

    :param _morpStr: morp long string
    :return: 품사만 남은 string
    """
    tmp: str = ""
    splitList = _morpStr.split(' ')
    for morp in splitList:
        try:
            tmp += morp.split('/')[1] + " "
        except:  # 공백인 경우, 형태소분석결과가 없음
            pass
    return tmp.strip()

def tmp_get_morp_from_list(_sentece)-> str:
    idx: int = QList.index(_sentece)
    tmp: str = ""
    splitList = QMList[idx].split(' ')
    for morp in splitList:
        try:
            tmp += morp.strip() + " "
        except:  # 공백인 경우, 형태소분석결과가 없음
            pass

    return tmp.strip()

def get_morp_from_list(_sentece)-> str:
    idx: int = QList.index(_sentece)
    morpStr: str = extract_morp_str(QMList[idx])
    return morpStr

if __name__ == "__main__":
    # Load dataset data
    QList: List[str] = get_data_from_txt(DATA_DIR + Q_FILE_NAME)
    QMList: List[str] = get_data_from_txt(DATA_DIR + Q_MORP_FILE_NAME)
    tuneQMList :List[str] = []
    # Set index directory
    indexdir = './origin_ndx'
    if not os.path.exists(indexdir):
        os.makedirs(indexdir)

    # Set schema
    schema = Schema(title=TEXT(stored=True),
                    path=ID(stored=True),
                    content=NGRAMWORDS(minsize=2, maxsize=3, stored=True),
                    idx=ID(stored=True))
    # create schema
    ix = create_in(indexdir, schema)

    # Define the writer for search Inverted
    writer = ix.writer()

    # Preprocess
    # 1. lexical 단위에서 할꺼면 그냥 문장 그대로 content 에 넣으면 됨.
    # 2. 형태소 단위니까 태그 안 떼고 넣기로함

    #for fori in range(len(QList)):# 1. Lexical
        #tuneQMList.append(QList[fori])# 1. Lexical
    for fori in range(len(QMList)):
        tuneQMList.append(QMList[fori])# 2. g형태소단위

    # Build DB
    for fori in range( len(QList) ):
        writer.add_document(title=u"{}".format(QList[fori]),
                            path=u"/wt",
                            content=u"{}".format(tuneQMList[fori]),
                            idx=u"{}".format(fori))
    writer.commit()

    # create query datas from input file and
    # create output file stream
    f = open('input.txt','r',encoding='utf8')
    querys: List[str] = f.readlines()
    f.close()

    outF = open('output.txt','w',encoding='utf8')
    '''
    # 데이터 모자른거 채울때 문서수정할때
    for query in querys:
        query = query.strip()
        try:
            queryIdx = QList.index(query)
        except:
            print(query)
    exit(-1)
    '''

    # Search
    with ix.searcher() as searcher:
        qp = QueryParser("content", ix.schema)
        idx = 1
        # time checking
        start = time.time()
        for query in querys:
            dataDict: Dict[int, int] = {}
            log('i', "{}번째 검색중..".format(idx))
            idx += 1
            query = query.strip()
            queryIdx = QList.index(query)

            # 1. lexical 단위이기에 필요없음
            #    추가적으로 N-gram 햇던부분도 필요없어서 뺌
            # querySplit = query.split(' ')
            # for q in querySplit:
            #     user_q = qp.parse(u'{}'.format(q))
            #     results = searcher.search(user_q, limit=5)
            #     for r in results:
            #         try:
            #             dataDict[r['idx']] += r.score
            #         except:
            #             dataDict[r['idx']] = r.score
            #
            # sortedTmp = sorted(dataDict.items(), key=operator.itemgetter(1), reverse=True)

            # 2. 형태소 단위이기에 필요없음
            morpStr = tmp_get_morp_from_list(query)
            splitMorp = morpStr.split(' ')
            for q in splitMorp:
                user_q = qp.parse(u'{}'.format(q))
                results = searcher.search(user_q, limit=5)
                for r in results:
                    try:
                        dataDict[r['idx']] += r.score
                    except:
                        dataDict[r['idx']] = r.score

            sortedTmp = sorted(dataDict.items(), key=operator.itemgetter(1), reverse=True)

            #morpStr = get_morp_from_list(query)
            #splitMorp = morpStr.split(' ')

            # # bi-gram weight sum
            # for fori in range(len(splitMorp) - 1):
            #     user_q = qp.parse(u'{}'.format(splitMorp[fori]+" "+splitMorp[fori+1]))
            #     results = searcher.search(user_q, limit=10)
            #     for r in results:
            #         try:
            #             dataDict[r['idx']] += r.score
            #         except:
            #             dataDict[r['idx']] = r.score
            # # Tri-gram weight sum
            # # 여기를 지우면 단순하게 bi-gram 까지만의 weight sum 을 이용
            # for fori in range(len(splitMorp) - 2):
            #     user_q = qp.parse(u'{}'.format(splitMorp[fori]+" "+splitMorp[fori+1]+" "+splitMorp[fori+2]))
            #     results = searcher.search(user_q, limit=10)
            #     for r in results:
            #         try:
            #             dataDict[r['idx']] += r.score
            #         except:
            #             dataDict[r['idx']] = r.score
            # sortedTmp = sorted(dataDict.items(), key=operator.itemgetter(1), reverse=True)
            # Toprank 5개 뽑아야하니까
            cnt = 0
            if len(sortedTmp) < 6:
                for _ in range(5):
                    outF.write('\n')
            else:
                while True:
                    if cnt == 5:
                        break

                    top = sortedTmp.pop(0)

                    if int(top[0]) == queryIdx: # 자기랑 같은 문장은 제외
                        first = False
                        pass
                    else:
                        outF.write(QList[int(top[0])] + '\n')
                        cnt += 1
        end = time.time()
        # time checking end
        print(end-start) # only bi-gram = 42.87초, 개당 0.21초  | include tri-gram 57.36초 개당 0.28초
    outF.close()


import os

class CodeWriter:

    def __init__(self, out, file):
        self.out = out
        self.static_vars = {}
        self.static_index = 20
        self.file = file
        self.label_num = 0

    @property
    def file(self):
        return self._file

    @file.setter
    def file(self, file):
        self._file = file
        if file not in self.static_vars:
            self.static_vars[file] = {}

    def write(self, *args, sep=' ', end='\n'):
        if type(args[0]) == list:
            for arg in args:
                if type(arg) == list:
                    self.write(*arg, sep=sep, end=end)
                else:
                    self.write(arg, sep=sep, end=end)
        else:
            for arg in args:
                self.out.write(str(arg) + sep)
            self.out.write(end)

    def get_static_address(self, index):
        if index not in self.static_vars[self.file]:
            self.static_vars[self.file][index] = self.static_index
            self.static_index += 1

        return self.static_vars[self.file][index]

    def load_sp(self, offset=0):
        if offset < 0:
            self.load_sp_neg(-offset)
            return

        self.write('lda sp[0]')
        self.write('mov M A')
        self.write('inc L L')
        self.write('mov M H')
        if offset > 1:
            self.write('ldb', offset)
            self.write('add A L L')
            self.write('carry')
        elif offset == 1:
            self.write('inc A L')
            self.write('carry')
        else:
            self.write('mov A L')

    def load_sp_neg(self, offset):
        if offset == 1:
            self.write(['lda sp[0]'],
                       'dec M A')
        else:
            self.write(['lda sp[0]'],
                       'mov M A',
                       ['ldb', offset],
                       'sub A L A')
        self.write(['lda L', self.label_num],
                   'jmpc',
                   'lda sp[1]',
                   'dec M B',
                   ['lda L', self.label_num + 1],
                   'jmp',
                   ['L', self.label_num, ':'],
                   'lda sp[1]',
                   'mov M B',
                   ['L', self.label_num + 1, ':'],
                   'mov B H',
                   'mov A L', sep='')
        self.label_num += 2

    def increment_sp(self, amount=1):
        if amount == 1:
            self.write(['lda sp[0]'],
                       'inc M A')
        else:
            self.write(['ldb', amount],
                       'mov L A',
                       'lda sp[0]',
                       'add A M A')
        self.write(['mov A M'],
                   ['lda L', self.label_num],
                   'jmpc',
                   ['lda L', self.label_num + 1],
                   'jmp',
                   ['L', self.label_num, ':'],
                   'lda sp[1]',
                   'inc M A',
                   'mov A M',
                   ['L', self.label_num + 1, ':'], sep='')
        self.label_num += 2

    def decrement_sp(self, amount=1):
        if amount == 1:
            self.write(['lda sp[0]'],
                       'dec M A')
        else:
            self.write(['ldb', amount],
                       'mov L A',
                       'lda sp[0]',
                       'sub M A A')
        self.write(['mov A M'],
                   ['lda L', self.label_num],
                   'jmpc',
                   'lda sp[1]',
                   'dec M A',
                   'mov A M',
                   ['L', self.label_num, ':'], sep='')
        self.label_num += 1

    def write_arithmetic(self, command):
        if command in ['add', 'sub', 'or', 'and']:
            self.decrement_sp(1)
            self.load_sp(-1)
            self.write(['mov M A'],
                       'inc L L',
                       'carry',
                       [command, 'A M A'],
                       'mov A M')

        if command in ['neg', 'not']:
            self.load_sp(-1)
            self.write(['mov M A'],
                       [command, 'A A'],
                       'mov A M')
        inequalities = {'lt': 'jlt', 'gt': 'jgt', 'eq': 'jeq', 'neq': 'jne', 'lte': 'jle', 'gte': 'jge'}
        if command in inequalities:
            self.decrement_sp(1)
            self.load_sp(-1)
            self.write(['mov M A'],
                       'inc L L',
                       'carry',
                       'sub A M A',
                       ['lda L', self.label_num],
                       inequalities[command],
                       'ldb 1',
                       'mov L B',
                       ['lda L', self.label_num + 1],
                       'jmp',
                       ['L', self.label_num, ':'],
                       'ldb 0',
                       'mov L B',
                       ['L', self.label_num + 1, ':'], sep='')
            self.load_sp(-1)
            self.write('mov B M')

    def write_push(self, seg, indices):
        indices = indices[::-1]
        if seg == 'in':
            self.write('mov I B')
            self.load_sp()
            self.write('mov B M')
            self.increment_sp()
            return

        if seg in ['pointer', 'temp']:
            for i in range(len(indices)):
                self.write(['lda', (10 if seg == 'temp' else 6) + indices[i]],
                           'mov M B')
                self.load_sp(i)
                self.write('mov B M')

        elif seg == 'static':
            for i in range(len(indices)):
                self.write(['lda', self.get_static_address(indices[i])],
                           'mov M B')
                self.load_sp(i)
                self.write('mov B M')

        elif seg == 'constant':
            self.write(['lda sp[0]'],
                       'mov M A',
                       'inc L L',
                       'mov M H')
            self.write(['ldb', indices[0]],
                       'mov L B',
                       'mov A L',
                       'mov B M')
            for i in range(1, len(indices)):
                self.write(['inc L A'],
                           'carry',
                           ['ldb', indices[i]],
                           'mov L B',
                           'mov A L',
                           'mov B M')

        elif seg in ['this', 'that', 'local', 'argument']:
            for i in range(len(indices)):
                self.write(['lda', seg, '[0]'],
                           ['mov M A'],
                           ['inc L L'],
                           ['mov M H'],
                           ['ldb', indices[i]],
                           ['add L A L'],
                           ['carry'],
                           ['mov M B'])
                self.load_sp(i)
                self.write('mov B M')

        self.increment_sp(len(indices))

    def write_pop(self, seg, indices):
        if seg == 'out':
            self.decrement_sp(indices[0])
            for i in range(indices[0]):
                self.load_sp(indices[0] - i - 1)
                self.write(['mov M L'],
                           'out')
            return

        self.decrement_sp(len(indices))
        for i in range(len(indices)):
            index = indices[i]
            self.load_sp(len(indices) - i - 1)
            self.write('mov M B')

            if seg in ['temp', 'pointer']:
                self.write(
                    ['lda', index + (10 if seg == 'temp' else 6)],
                    ['mov B M'])

            elif seg == 'static':
                self.write(
                    ['lda', self.get_static_address(index)],
                    ['mov B M'])

            elif seg in ['this', 'that', 'local', 'argument']:
                # Load address stored at this/that into L and H and add index
                self.write(
                    ['lda', seg, '[0]'],
                    ['mov M A'],
                    ['inc L L'],
                    ['mov M H'],
                    ['ldb', index],
                    ['add L A L'],
                    ['carry'],
                    ['mov B M'])

def main():
    os.chdir("/Users/nicholasprowse/Desktop")
    file = open('out.asm', 'w')
    writer = CodeWriter(file, "hello")
    writer.write_push('constant', [21, 62])
    writer.write_arithmetic('add')
    writer.write_pop('out', [1])
    file.close()

if __name__ == '__main__':
    main()


"""
BFS
1st group
    check visited
    add group
2nd+ group
    group -> check visited initial
    check visited
    add group

if len(group) > 0:
    Calc

처음부터 말렸다. DFS BFS 중에 고민했고, BFS가 더 효율적으로 제거할 수 있을거라 생각했다.
근데, 생각보다 모든 Cell을 Search하는게 시간을 많이 잡아먹었다.
비효율적으로 Search 할 수 밖에 없다고 생각은 했는데,
바꾼 영역만을 다시 Search하는게 더 좋다는 것은 영역이 커질수록 영향을 많이 준다는 것을 깨달았다...
생각해보면 N=50일 때, 가장 마지막 일부 영역만 숫자가 바뀐다면,
굳이 처음부터 Search를 할 필요는 없을테니....아쉽다.
"""
# start 21.04.15 AM09:32
# Reading 3mins
# Alg Writing  7mins
# First AM10:42 - Wrong Answer
# Second 21.04.17 PM03:40 - Time
# Third 21.04.17 PM05:00 - PASS

import sys; input = sys.stdin.readline
from collections import deque

class MAP():
    def __init__(self, tbl, N, L, R):
        self.N = N
        self.L = L
        self.R = R
        self.M = tbl
        self.visited = None
        self.groups = None
        self.sums = None
        self.GM = None
        self.flag = True
        self.dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]]

        self.raw_gm = [[-1 for _ in range(self.N)] for _ in range(self.N)]
        self.raw_vis = [[0 for _ in range(self.N)] for _ in range(self.N)]
        # self.print(self.M)
        # print("")

    def print(self, tbl):
        print('\n')
        for i in range(self.N):
            for j in range(self.N):
                print(tbl[i][j], end=' ')
            print('\n')
        print("===================")
        return

    def feasible(self, r, c):
        if 0 <= r < self.N and 0 <= c < self.N:
            return True
        else:
            return False

    def thres(self, v):
        if self.L <= abs(v) <= self.R:
            return True
        else:
            return False

    def BFS(self, pr, pc, g):
        if not self.visited[pr][pc]:
            self.visited[pr][pc] = 1
            visited = [row[:] for row in self.visited]

            dq = deque([(pr, pc)])
            tmp = [(pr, pc)]
            _s = 0
            while dq:
                r, c = dq.popleft()
                visited[r][c] = 1
                self.GM[r][c] = g
                pv = self.M[r][c]
                _s += pv
                # print(dq)

                for d in self.dirs:
                    nr, nc = r+d[0], c+d[1]
                    if self.feasible(nr, nc) and not visited[nr][nc]:
                        nv = self.M[nr][nc]
                        if self.thres(nv - pv) and self.GM[nr][nc] < 0:
                            visited[nr][nc] = 1
                            self.visited[nr][nc] = 1
                            dq.append((nr, nc))
                            tmp.append((nr, nc))
                            # print(dq)
                            # self.visited[nr][nc] = 1
                            # tmp.append((nr, nc))
                            # _s += nv
                            # self.GM[nr][nc] = g
            if len(tmp) > 1:
                self.groups.append(tmp)
                self.sums.append(_s)
                return True
            else:
                self.GM[pr][pc] = 1
                return False
        else:
            return False

    def init_map(self):
        self.GM = [raw[:] for raw in self.raw_gm]
        self.visited = [raw[:] for raw in self.raw_vis]
        self.groups = []
        self.sums = []
        return

    def run(self):
        step = 0
        search = deque([])  #! 이게 진짜 좋은 부분인 듯.
        for i in range(self.N):
            for j in range(self.N):
                search.append((i, j))

        while self.flag:
            g = 2
            self.init_map()
            while search:
                i, j = search.popleft()
                if self.BFS(i, j, g):
                    g = g+1

            # self.print(self.GM)
            # self.print(self.visited)

            if len(self.groups):
                self.flag = True

                for gg, ss in zip(self.groups, self.sums):
                    avg_sums = ss//len(gg)
                    for cell in gg:
                        r, c = cell
                        self.M[r][c] = avg_sums
                        search.append((r,c))  #! 이게 진짜 좋은 부분인 듯.

                step += 1
                # self.print(self.M)
                # print("")
            else:
                self.flag = False

        return step

def main():
    N, L, R = list(map(int, input().split()))
    tbl = []
    for _ in range(N):
        tbl.append(list(map(int, input().split())))
    m = MAP(tbl, N, L, R)
    ret = m.run()
    print(ret)

if __name__ == '__main__':
    main()


# auther：Liul8
# date：2020/7/27 15:01
# tools：PyCharm
# Python：3.7.7
from flask import Flask, request, jsonify
from pytesseract import pytesseract
from PIL import Image
import os
import urllib.request

app = Flask(__name__)
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def get_blackwhite_image(picture_name, threshold=160):
    """图片处理成黑白色"""
    table = [0 if _ < threshold else 1 for _ in range(256)]
    image = Image.open(picture_name)
    imgry = image.convert('L')
    out = imgry.point(table, '1')
    return out

def download_image(url):
    files = 'images'
    try:
        if not os.path.exists(files):
            os.makedirs(files)  # 如果没有这个path则直接创建
        image_path = os.path.join(files, "validate_code.jpg")
        # 利用urllib.request.urltrieve方法下载图片
        urllib.request.urlretrieve(url, filename=image_path)
        return image_path
    except IOError as e:
        print(1, e)
        return False
    except Exception as e:
        print(2, e)
        return False

@app.route("/validate-code-recognition", methods=['POST'])
def validate_code_recognition():
    flag = request.form.get("flag", True)
    image = request.files.get("image", None)
    lang = request.form.get("lang", "eng")
    oem = request.form.get("oem", "1")
    psm = request.form.get("psm", "3")
    url = request.form.get("url", None)
    config = f"-l {lang} --oem {oem} --psm {psm}"
    if not image and not url:
        return jsonify({"msg": "image file don`t exist!", "code": 0}), 400
    if image:
        filename = image.filename
    else:
        filename = download_image(url)
        image = filename
    if not allowed_file(filename):
        return jsonify({"msg": f"Allowed file types are: {ALLOWED_EXTENSIONS}", "code": 0}), 400

    if flag:
        image = get_blackwhite_image(image)
    else:
        image = Image.open(image)
    text = pytesseract.image_to_string(image, config=config)
    return jsonify({"code": 1, "msg": "success", "data": {"text": text}}), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)


#continuity of function at an interval
from sympy import *
from numpy import arange
x = Symbol('x')
y = Symbol('y')
h = Symbol('h')
y = x**2
is_continous = True
a =1
b =4
#checking the continuity in the interval a,b
for c in arange(a,b,0.5):
   y1 = y.subs({x:c}).evalf()
   q1 = y.subs({x:c+h}).evalf()
   q2 = y.subs({x:c-h}).evalf()
   w1 = Limit(q1,h,0).doit()   # Left Hand Limit - LHL
   w2 = Limit(q2,h,0).doit()   # Right Hand Limit - RHL
   if (y1 != w1 and y1 != w2): #checking if  LHL is equal to RHL
      is_continous = False
      break
if is_continous:
   print(" The function is continous")
else:
     print(" The Function is not continous ")


from typing import Tuple
from neural import *
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np

def parse_line(line: str) -> Tuple[List[float], List[float]]:
    """Splits line of CSV into inputs and output (transormfing output as appropriate)

    Args:
        line - one line of the CSV as a string

    Returns:
        tuple of input list and output list
    """
    tokens = line.split("\t")
    # print(tokens)
    out = int(tokens[0])
    # print(out)
    output = [0 if out < 3000000 else 0.5 if out < 5000000 else 1]
    # print(output)

    inpt = [float(x) for x in tokens[1:5]]
    # print(inpt)
    return (inpt, output)

def normalize(data: List[Tuple[List[float], List[float]]]):
    """Makes the data range for each input feature from 0 to 1

    Args:
        data - list of (input, output) tuples

    Returns:
        normalized data where input features are mapped to 0-1 range (output already
        mapped in parse_line)
    """
    leasts = len(data[0][0]) * [100.0]
    mosts = len(data[0][0]) * [0.0]

    for i in range(len(data)):
        for j in range(len(data[i][0])):
            if data[i][0][j] < leasts[j]:
                leasts[j] = data[i][0][j]
            if data[i][0][j] > mosts[j]:
                mosts[j] = data[i][0][j]

    for i in range(len(data)):
        for j in range(len(data[i][0])):
            data[i][0][j] = (data[i][0][j] - leasts[j]) / \
                (mosts[j] - leasts[j])
    return data

with open("data.txt", "r") as f:
    f.readline()
    training_data = [parse_line(line)
                     for line in f.readlines() if len(line) > 4]

# for line in training_data:
#     print(line)

td = normalize(training_data)

train_data, test_data = train_test_split(td, test_size=.15)
print(len(train_data))
print(len(test_data))
# for line in td:
#     print(line)

nn = NeuralNet(4, 6, 1)

nn.train(train_data, learning_rate=.85)
result = nn.test_with_expected(test_data)
x, y = [], []
print(x, y)
for i in result:
    print(f"desired: {i[1]}, actual: {i[2]}")
    x += (i[1])
    y += (i[2])
print(x, y)

# print(result)

# make data:
# np.random.seed(3)
# x = 0.5 + np.arange(10)
# y = np.random.uniform(2, 7, len(x))

# # plot
# fig, ax = plt.subplots()

# ax.bar(x, y, width=1, edgecolor="white", linewidth=0.7)

# ax.set(xlim=(0, 8), xticks=np.arange(0, 10),
#        ylim=(0, 8), yticks=np.arange(0, 10))

# plt.show()

# plt.style.use('_mpl-gallery-nogrid')

# # make data
# x = [1,2]
# colors = plt.get_cmap('Blues')(np.linspace(0.2, 0.7, len(x)))

# # plot
# fig, ax = plt.subplots()
# ax.pie(x, colors=colors, radius=3, center=(4, 4),
#        wedgeprops={"linewidth": 1, "edgecolor": "white"}, frame=True)

# ax.set(xlim=(0, 8), xticks=np.arange(1, 8),
#        ylim=(0, 8), yticks=np.arange(1, 8))

# plt.show()

plt.style.use('_mpl-gallery')

# make the data
# np.random.seed(3)
# x = 4 + np.random.normal(0, 2, 24)
# y = 4 + np.random.normal(0, 2, len(x))
# size and color:
sizes = np.random.uniform(15, 80, len(x))
colors = np.random.uniform(15, 80, len(x))

# plot
fig, ax = plt.subplots()

ax.scatter(x, y, s=sizes, c=colors, vmin=0, vmax=1)

ax.set(xlim=(0, 1), xticks=np.arange(0, 1),
       ylim=(0, 1), yticks=np.arange(0, 1))

plt.show()


# All extension functions for SRW should be imported into this space
# even if they're defined elsewhere.

# Functions should modify extra*Data in place.
# Add DOM node for serialization by ZSI.
# Fr'ex:
# object.extraFooData.append(r.fromString('<a:b c="d">e</a:b>'))

# Configuration in SRW ZeeRex file should look like:
#
#  <zeerex:supports type="extension"
#                   c3:type="record"
#                   c3:function="docidRecordHandler"
#                   c3:sruName="x-info-2-docid"
#                   c3:sruFunction="docidRequestXform">
#     info:srw/extension/2/docid-v1.0 docid
#  </zeerex:supports>
#
# Where c3:type is one of: record, term, search, scan, explain, response

# Useful tools:
from xml.sax.saxutils import escape

#from cheshire3.utils import reader as domReader
#reader = domReader()
from lxml import etree
from lxml.builder import ElementMaker

# Simple SRU->SRW transformation

def simpleRequestXform(item, config):
    data = config.sruExtensionMap.get(item[0], None)
    if data:
        xml = '<%s:%s xmlns:%s="%s">%s</%s:%s>' % (data[1], data[1], data[1], data[0], item[1], data[1], data[1])
        val = reader.fromString(xml)
        return val
    return None

namespaces = {
    'sru' : 'http://www.loc.gov/zing/srw/',
    'diag' : 'http://www.loc.gov/zing/srw/diagnostic/'
    }

sruElemFac = ElementMaker(namespace=namespaces['sru'], nsmap=namespaces)
diagElemFac = ElementMaker(namespace=namespaces['diag'], nsmap=namespaces)
# Diagnostic XML formatter
def diagnosticToXML(diag):
    el = diagElemFac.diagnostic(
        diagElemFac.uri(diag.uri)
        )
    if diag.message:
        el.append(diagElemFac.message(diag.message))
    if diag.details:
        el.append(diagElemFac.details(diag.details))
    return el

# Extension Handler Functions:

import cheshire3.internal
def implementationResponseHandler(session, val, resp, other=None):
    """ Put our implementation id into the response """
    # Stored in ZeeRex, so on config object
    txt = """
    <ident:serverInfo xmlns:ident="info:srw/extensions/1/ident-v1.0">
      <ident:institution>University of Liverpool</ident:institution>
      <ident:vendor>Cheshire3 Project</ident:vendor>
      <ident:application>Cheshire3 SRW Server</ident:application>
      <ident:version>%s</ident:version>
    </ident:serverInfo>
    """ % ('.'.join([str(x) for x in internal.cheshire3Version]))
    return etree.XML(txt)

# Record
def docidRecordHandler(session, val, resp, rec):
    """ Put the record identifier into extraRecordData"""
    txt = '<docid:recordIdentifier xmlns:docid="info:srw/extension/2/docid-v1.0">%s</docid:recordIdentifier>' % escape(str(rec))
    return etree.XML(txt)

def recordMetadataHandler(session, val, resp, rsi, rec):
    """ Put resultSetItem info into extraRecordData"""
    mdBits = ['<rec:metaData xmlns:rec="info:srw/extension/2/record-1.1">']
    # ids may contain nasties - escape them
    mdBits.append('<rec:identifier>%s</rec:identifier>' % escape(unicode(rec.id, 'utf-8')))
    if rec.recordStore:
        mdBits.append('<rec:locationIdentifier>%s</rec:locationIdentifier>' % escape(rec.recordStore))
    if rec.wordCount:
        mdBits.append('<rec:wordCount>%d</rec:wordCount>' % rec.wordCount)
    if rec.wordCount:
        mdBits.append('<rec:byteCount>%d</rec:byteCount>' % rec.byteCount)
    # now get stuff from resultSetItem
    if rsi.weight:
        mdBits.append('<rec:relevanceValue rec:relevanceType="raw">%f</rec:relevanceValue>' % rsi.weight)
    if rsi.scaledWeight:
        mdBits.append('<rec:relevanceValue rec:relevanceType="scaled">%f</rec:relevanceValue>' % rsi.scaledWeight)
    if rsi.occurences:
        mdBits.append('<rec:termOccurences>%d</rec:termOccurences>' % rsi.occurences)
    if rsi.proxInfo:
        mdBits.append('<rec:termPositionList>%r</rec:termPositionList>' % (rsi.proxInfo))

    mdBits.append('</rec:metaData>')
    return etree.XML(''.join(mdBits))

# SearchRetrieve
def resultSetSummaryHandler(session, val, resp, resultSet=[], db=None):
    """ Put summary of resultSet into extraSearchRetrieveData"""
    if not len(resultSet):
        return

    mdBits = ['<rs:resultSetData xmlns:rs="info:srw/extension/2/resultSet-1.1">']
    if hasattr(resultSet[0], 'weight'):
        allids = [escape(r.id) for r in resultSet] # ids may contain nasties - escape them
        mdBits.append('<rs:ids>%r</rs:ids>' % allids)
    if hasattr(resultSet[0], 'weight'):
        allweights = [r.weight for r in resultSet]
        mdBits.append('<rs:weights>%r</rs:weights>' % allweights)
    if hasattr(resultSet[0], 'proxInfo') and resultSet[0].proxInfo:
        prox = [r.proxInfo for r in resultSet]
        mdBits.append('<rs:proxInfo>%r</rs:proxInfo>' % prox)

    mdBits.append('</rs:resultSetData>')
    return etree.XML(''.join(mdBits))

import cheshire3.cqlParser as cql
def resultSetFacetsHandler(session, val, resp, resultSet=[], db=None):
    """Put facet for requested index into extraSearchRetrieveData
       val is a CQL query.
           Boolean used is meaningless, facets are returned for each clause.
           Term in each clause is also meaningless and need be nothing more than *
       Result looks something like browse response e.g.
    <facets>
        <facetByIndex index="dc.subject" relation"exact">
            <term>
                <value>Genetics</value>
                <numberOfRecords>2</numberOfRecords>
            </term>
            ...
        </facet>
        ...
    </facets>
    """
    # quick escapes
    if not len(resultSet) or db is None:
        return

    global namespaces, sruElemFac
    myNamespaces = namespaces.copy()
    myNamespaces['fct'] = "info:srw/extension/2/facets-1.0"

    pm = db.get_path(session, 'protocolMap')
    if not pm:
        db._cacheProtocolMaps(session)
        pm = db.protocolMaps.get('http://www.loc.gov/zing/srw/')
        self.paths['protocolMap'] = pm

    fctElemFac = ElementMaker(namespace=myNamespaces['fct'], nsmap=myNamespaces)

    def getFacets(query):
        if (isinstance(query, cql.SearchClause)):
            fctEl = fctElemFac.facetsByIndex({'index': query.index.toCQL(), 'relation': query.relation.toCQL()})
#            fctEl.append(sruElemFac.index(query.index.toCQL()))
#            fctEl.append(sruElemFac.relation(query.relation.toCQL()))
            idx = pm.resolveIndex(session, query)
            if idx is None:
                fctEl.append(diagnosticToXML(cql.Diagnostic(code=16, message="Unsupported Index", details=query.index.toCQL())))
                return fctEl

            try:
                facets = idx.facets(session, resultSet)
            except:
                # index doesn't support facets
                # TODO: diagnostic?
                facets = []

            termsEl = sruElemFac.terms()
            for f in facets:
                termsEl.append(sruElemFac.term(
                                               sruElemFac.value(f[0]),
                                               sruElemFac.numberOfRecords(str(f[1][1]))
                                               )
                               )

            fctEl.append(termsEl)
            return [fctEl]
        else:
            fctEls = getFacets(query.leftOperand)
            fctEls.extend(getFacets(query.rightOperand))
            return fctEls

    fctsEl = fctElemFac.facets()
    try:
        query = cql.parse(val)
    except cql.Diagnostic as d:
        fctsEl.append(diagnosticToXML(d))
        return fctsEl

    for el in getFacets(query):
        fctsEl.append(el)

    return fctsEl


def reverse(x: int) -> int:
    INT_MAX = 2**31 - 1
    INT_MIN = -2**31

    result = 0
    while x != 0:
        digit = x % 10
        x = x // 10
        if result > INT_MAX // 10 or (result == INT_MAX // 10 and digit > INT_MAX % 10):
            return 0
        elif result < INT_MIN // 10 or (result == INT_MIN // 10 and digit < INT_MIN % 10):
            return 0
        else:
            result = result * 10 + digit
    return result


"""Management command for syncing requirements."""
from argparse import ArgumentParser
from collections import defaultdict
from logging import getLogger
from typing import Any, Dict, List

from django.core.mail import send_mail
from django.core.management.base import BaseCommand
from django.db.utils import IntegrityError
from django.template.loader import render_to_string
from django.utils.timezone import now as tz_now
from requirements.parser import parse
from requirements.requirement import Requirement

from ...models import PackageVersion
from ...settings import REQUIREMENTS_FILE

logger = getLogger(__name__)

def create_package_version(requirement: Requirement) -> None:
    """Create a new PackageVersion from a requirement. Handles errors."""
    try:
        PackageVersion(requirement=requirement).save()
        logger.info("Package '%s' added.", requirement.name)  # noqa
    except IntegrityError:
        logger.info("Package '%s' already exists.", requirement.name)  # noqa

def local() -> None:
    """Load local requirements file."""
    logger.info("Loading requirements from local file.")
    with open(REQUIREMENTS_FILE, "r") as f:
        requirements = parse(f)
        for r in requirements:
            logger.debug("Creating new package: %r", r)
            create_package_version(r)

def remote() -> Dict[str, List]:
    """Update package info from PyPI."""
    logger.info("Fetching latest data from PyPI.")
    results = defaultdict(list)
    packages = PackageVersion.objects.exclude(is_editable=True)
    for pv in packages:
        pv.update_from_pypi()
        results[pv.diff_status].append(pv)
        logger.debug("Updated package from PyPI: %r", pv)
    results["refreshed_at"] = tz_now()
    return results

def clean() -> None:
    """Clean out all packages."""
    PackageVersion.objects.all().delete()
    logger.info("Deleted all existing packages.")

class Command(BaseCommand):

    help = (
        "This command can be used to load up a requirements file "
        "and check against PyPI for updates."
    )

    def add_arguments(self, parser: ArgumentParser) -> None:
        parser.add_argument(
            "--local",
            action="store_true",
            dest="local",
            default=False,
            help="Load local requirements file",
        )
        parser.add_argument(
            "--remote",
            action="store_true",
            dest="remote",
            default=False,
            help="Load latest from PyPI",
        )
        parser.add_argument(
            "--clean",
            action="store_true",
            dest="clean",
            default=False,
            help="Delete all existing requirements",
        )
        parser.add_argument("--notify", help="Send results notification email")
        parser.add_argument(
            "--from",
            default="Django Package Monitor <packages@example.com>",
            help="Notification email 'from' address",
        )
        parser.add_argument(
            "--subject",
            default="Package manager update",
            help="Notification email subject line.",
        )

    def handle(self, *args: Any, **options: Any) -> None:
        """Run the managemement command."""
        if options["clean"]:
            clean()

        if options["local"]:
            local()

        if options["remote"]:
            results = remote()
            if options["notify"]:
                send_mail(
                    options["subject"],
                    render_to_string("summary.txt", results),
                    options["from"],
                    [options["notify"]],
                    html_message=render_to_string("summary.html", results),
                    fail_silently=False,
                )


# *ЗАДАЧА 1:
# Реализовать класс Person, у которого должно быть два публичных поля: age и name.
# Также у него должен быть следующий набор методов: know(person), который позволяет
# добавить другого человека в список знакомых. И метод is_known(person), который возвращает знакомы ли два человека
class Person:

    def __init__(self, name: str, age: int) -> None:
        self.familiars = []
        self.name = name
        self.age = age

    def know(self, person) -> None:
        if person not in self.familiars:
            self.familiars.append(person)
            print('{} is added to {} friend list'.format(person.name, self.name))
        else:
            print('{} is already in your friend list')

    def is_known(self, person) -> bool:
        return person in self.familiars

arthur = Person('Arthur', 27)
kevin = Person('Kevin', 25)

print(kevin.is_known(arthur))
kevin.know(arthur)
print(kevin.is_known(arthur))

# *ЗАДАЧА 2:
# Есть класс, который выводит информацию в консоль: Printer, у него есть метод: log(*values).
# Написать класс FormattedPrinter, который выводит в консоль информацию, окружая ее строками из *
class Printer:
    def log(self, * values):
        print(values)

class FormattedPrinter(Printer):
    def log(self, *values):
        print('****************')
        super().log(*values)
        print('****************')

a = Printer()
a.log(1, 2, 3, 4, 5, 6, 7, 8, 9)

b = FormattedPrinter()
b.log(1, 2, 3, 4, 5, 6, 7, 8, 9)

# *ЗАДАЧА 3:
# Написать класс Animal и Human,сделать так, чтобы некоторые животные были опасны для человека (хищники, ядовитые).
# Другие - нет. За что будет отвечать метод is_dangerous(animal)
class Animal:
    def __init__(self, name: str, is_predator, is_poisonous) -> None:
        self.name = name
        self.is_predator = is_predator
        self.is_poisonous = is_poisonous

class Human:
    def is_dangerous(self, animal) -> bool:
        return animal.is_predator or animal.is_poisonous

human = Human()
tiger = Animal('tiger', True, False)
snake = Animal('snake', False, True)
rabbit = Animal('rabbit', False, False)

print(human.is_dangerous(tiger))
print(human.is_dangerous(snake))
print(human.is_dangerous(rabbit))