import numpy as np
import pandas as pd
from pandas import DataFrame
from tqdm import tqdm
from collections import defaultdict
import pickle
import itertools
import random

random.seed(0)
traj_tr = pickle.load(open('trajDr_tr.pkl', 'rb'))

# mask out actions that clinicians never taken
Q_mask = np.load('action_mask.npy')

gamma = 0.99
nS, nA = 750, 25
n_episodes = 1000000
alpha_max, alpha_min, alpha_decay = 0.9, 1e-10, 1e-2
alpha = lambda ep: alpha_min + (alpha_max-alpha_min)*np.exp(-alpha_decay*(ep//1000))

def run_qlearn(trajectories, n_episodes, gamma, alpha=0.5, Q_init=None):
    if not callable(alpha): # step size
        alpha_ = alpha
        alpha = lambda episode: alpha_

    if Q_init is None:
        Q = np.zeros((nS, nA))
    else:
        Q = Q_init.copy().astype(float)

    Q[~Q_mask] = np.nan

    TD_errors = []
    Qs = [Q.copy()]
    for episode in tqdm(range(n_episodes)):
        trajectory = random.choice(trajectories)
        for t, transition in enumerate(trajectory):
            S = transition['s']
            A = transition['a']
            R = transition['r']
            S_ = transition['s_']
            done = transition['done']
            if done:
                target = R
            else:
                assert S_ is not None
                target = R + gamma * np.nanmax(Q[S_])

            TD_errors.append(target - Q[S,A])
            Q[S,A] = Q[S,A] + alpha(episode) * (target - Q[S,A])

        if episode % 500 == 0:
            Qs.append(Q.copy())

    return Q, {
        'Qs': Qs,
        'TD_errors': TD_errors,
    }

Q, metadata = run_qlearn(traj_tr, n_episodes, gamma, alpha)
np.save('qlearn_Q.npy', Q)
pickle.dump(metadata, open('qlearn_metadata.p', 'wb'))

exit()


# In[22]:

## THIS SCRIPT STORES THE FUNCTIONS AND CLASSES NECESSARY TO CREATE A 'FEEDER' OBJECT FROM AN EPHASORSIM MODEL
#SPBC-HIL files moved 7/15/19

# In[23]:

import pandas as pd
import numpy as np
import cvxpy as cp
import string
import networkx as nx
from copy import deepcopy
import pdb
import matplotlib.pyplot as plt

# In[24]:

# Adds traceback to warning messages, which is sometimes useful
import traceback
import warnings
import sys

def warn_with_traceback(message, category, filename, lineno, file=None, line=None):

    log = file if hasattr(file,'write') else sys.stderr
    traceback.print_stack(file=log)
    log.write(warnings.formatwarning(message, category, filename, lineno, line))

warnings.showwarning = warn_with_traceback

# In[25]:

## CLASS DEFINITIONS/HELPER FUNCTIONS

# In[26]:

class feeder:
# The main class. Creating this from an ePHASORsim model and set of loads stores all the information about your network
# Buses, loads, lines, actuators, etc. are all stored as dictionaries within this object
    #[HIL] - added ICDI vars and phasor reference vars
    def __init__(self,modelpath,loadfolder,loadpath,actpath,timesteps,timestepcur,subkVbase_phg,subkVAbase,refphasor,Psat_nodes,Qsat_nodes,PVforecast):
        # import data
        self.modeldata = pd.ExcelFile(modelpath)
        self.loadfolder = loadfolder
        self.loadpath = loadpath
        self.actpath = actpath
        self.timesteps = timesteps
        self.timestepcur = timestepcur
        self.subkVbase_phg = subkVbase_phg
        self.subkVAbase = subkVAbase
        self.refphasor = refphasor
        self.Psat_nodes = Psat_nodes
        self.Qsat_nodes = Qsat_nodes
        self.PVforecast = PVforecast
        # groom data (note that the functions below are not separable...
        # ...e.g. buses are not completely defined until all these functions have been run)
        self.busdict = busbuilder(self.modeldata, subkVbase_phg, subkVAbase, timesteps)
        self.Vsrcdict = Vsrcbuilder(self.modeldata, self.busdict)
        self.shuntdict = shuntbuilder(self.modeldata, self.busdict,timesteps)
        self.loaddict = loadbuilderPQ(self.modeldata, self.busdict, loadpath, timesteps, timestepcur)
        self.actdict = actbuilder(self.modeldata, self.busdict, loadpath, timesteps, timestepcur)
        self.linedict = linebuilder(self.modeldata, self.busdict, timesteps)
        self.transdict = transbuilder(self.modeldata, self.busdict, self.subkVAbase, timesteps)
        self.switchdict = switchbuilder(self.modeldata, self.busdict, timesteps)
        self.network = network_mapper(self.modeldata,self.busdict,self.linedict,self.transdict,self.switchdict)
        set_per_unit(self.linedict)

class bus:
    def __init__(self,desig,subkVbase_phg,subkVAbase,timesteps):
        self.name = 'bus_' + str(desig)
        self.phases = list()
        self.phasevec = np.zeros((3,1))
        self.type = ''
        self.kVbase_phg = subkVbase_phg
        self.kVAbase = subkVAbase
        self.Zbase = subkVbase_phg*subkVbase_phg*1000/subkVAbase
        self.loads = list()
        self.cap = list()
        self.actuators = list()
        self.edges_out = list()
        self.edges_in = list()
        self.Vsrcs = list()

        self.Vmagsq_linopt = cp.Variable((3,timesteps), name=self.name + '_Vmagsq')
        self.Vang_linopt = cp.Variable((3,timesteps), self.name + '_Vang')

        self.Vmag_NL = np.ones((3,timesteps))
        self.Vang_NL = np.array([[0.],[240.],[120.]])
        for idx in range(timesteps-1): #[HIL] - delete -1? or set timesteps=2 and just use first value
            self.Vang_NL = np.concatenate((self.Vang_NL,np.array([[0.],[240.],[120.]])), axis=1)

class connector:
# Includes lines, transformers, and switches as subclasses
    def __init__(self,timesteps):
        self.phasevec = np.zeros((3,1))
        self.Imag_NL = np.zeros((3,timesteps))
        self.Iang_NL = np.array([[0.],[0.],[0.]])
        for idx in range(timesteps-1):
            self.Iang_NL = np.concatenate((self.Iang_NL,np.array([[0.],[0.],[0.]])), axis=1)

class Vsrc:
# These are defined and populated, but as of 7/31/2018 they are not used.
    def __init__(self,desig):
        self.name = 'Vsrc_' + str(desig)
        self.id = ''
        self.phases = list()
        self.kV = complex(0)
        self.angle_phA = complex(0)

        self.phasevec = np.zeros((3,1))
        self.Vvec_phg = np.zeros((3,1))
        self.Vangvec = np.zeros((3,1))

class shunt:
# As of 7/31/2018, this class only supports cap banks.
    def __init__(self,desig,timesteps):
        self.name = 'cap_' + str(desig)
        self.id = ''
        self.node = None
        self.phases = list()
        self.phasevec = np.zeros((3,1))
        self.kV_phg = complex(0)

        self.phasevec = np.zeros((3,1))
        self.Pvec = np.zeros((3,1))
        self.Qvec = np.zeros((3,1))
        self.statusvec = np.zeros((3,1))

        self.P_NL = np.zeros((3,timesteps))
        self.Q_NL = np.zeros((3,timesteps))

class load:
    def __init__(self, desig, timesteps):
        self.name = 'load_' + str(desig)
        self.id = ''
        self.type = ''
        self.node = None
        self.phases = list()
        self.phasevec = np.zeros((3,1))
        self.kV_phph = complex(0)
        self.bandwidth = complex(0)
        self.conn = ''
        self.constZ = complex(0)
        self.constI = complex(0)
        self.constP = complex(0)
        self.status = list()

        self.Rsched = np.zeros((3,timesteps))
        self.Xsched = np.zeros((3,timesteps))
        self.Psched = np.zeros((3,timesteps))
        self.Qsched = np.zeros((3,timesteps))

        self.P_NL = np.zeros((3,timesteps))
        self.Q_NL = np.zeros((3,timesteps))

class actuator:
# As of 7/31/2018, only set up to handle one actuator per node
    def __init__(self, desig, timesteps):
        self.name = 'act_' + str(desig)
        self.node = None
        self.phases = list()
        self.phasevec = np.zeros((3,1))

        self.Psched = np.zeros((3,timesteps))
        self.Ssched = np.zeros((3,timesteps))

        self.Pgen = cp.Variable((3,timesteps), name=self.name + '_actP')
        self.Qgen = cp.Variable((3,timesteps), name=self.name + '_actQ')

class line(connector):
    def __init__(self, desig, timesteps):
        connector.__init__(self,timesteps)
        self.name = 'line_' + str(desig)
        self.id = ''

        self.from_node = None
        self.from_phases = list()
        self.to_node = None
        self.to_phases = list()
        self.length = complex(0)
        self.kVbase_phg = complex(0)
        self.kVAbase = complex(0)
        self.Zbase = complex(0)

        self.R = np.zeros((3, 3))
        self.X = np.zeros((3, 3))
        self.shuntB = np.zeros((3, 3), dtype=np.complex_)

        self.Z = np.zeros((3, 3), dtype=np.complex_)
        self.Y = np.zeros((3, 3), dtype=np.complex_)

        self.Zpu = np.zeros((3, 3), dtype=np.complex_)
        self.Ypu = np.zeros((3, 3), dtype=np.complex_)

        self.P_linopt = cp.Variable((3,timesteps), self.name + '_P')
        self.Q_linopt = cp.Variable((3,timesteps), self.name + '_Q')

class switch(connector):
    def __init__(self,desig,timesteps):
        connector.__init__(self,timesteps)
        self.name = 'switch_' + str(desig)
        self.phases_from = list()
        self.phases_to = list()
        self.from_node = None
        self.to_node = None
        self.status = list()

        self.Z = np.zeros((3, 3), dtype=np.complex_)
        self.Y = np.zeros((3, 3), dtype=np.complex_)
        self.Zpu = np.zeros((3, 3), dtype=np.complex_)
        self.Ypu = np.zeros((3, 3), dtype=np.complex_)

        self.P_linopt = cp.Variable((3,timesteps), self.name + '_P')
        self.Q_linopt = cp.Variable((3,timesteps), self.name + '_Q')

class transformer(connector):
    def __init__(self,desig,timesteps):
        connector.__init__(self,timesteps)
        self.name = 'transformer_' + str(desig)
        self.id = ''

        self.w0_node = None
        self.w0_phases = list()
        self.w0_kVbase_phg = complex(0)
        self.w0_kVAbase = complex(0)
        self.w0_rpu = complex(0)
        self.w0_conn = ''
        self.w1_node = None
        self.w1_phases = list()
        self.w1_kVbase_phg = complex(0)
        self.w1_kVAbase = complex(0)
        self.w1_rpu = complex(0)
        self.w1_conn = ''

        self.xpu = complex(0)
        self.tappos = list()
        self.taprange_high = complex(0)
        self.taprange_low = complex(0)
        self.taprangepct_high = complex(0)
        self.taprangepct_low = complex(0)

        self.Zpu = np.zeros((3, 3), dtype=np.complex_)
        self.Ypu = np.zeros((3, 3), dtype=np.complex_)

        self.P_linopt = cp.Variable((3,timesteps), self.name + '_P')
        self.Q_linopt = cp.Variable((3,timesteps), self.name + '_Q')

# In[27]:

def phase2vec(letter):
    # Converts 'a','b','c' to elementary vectors e1, e2, or e3
    assert (letter == 'a' or letter == 'b' or letter == 'c'), "Bad call to phase2vec"
    vecout = np.zeros((3,1))
    if letter == 'a':
        vecout = vecout + np.array([[1],[0],[0]])
    elif letter == 'b':
        vecout = vecout + np.array([[0],[1],[0]])
    elif letter == 'c':
        vecout = vecout + np.array([[0],[0],[1]])
    return vecout

def ZtoY(Zmat):
    # Converts an impedance matrix to an admittance matrix
    # Treats '0' impedances on the diagonal as 'line not present' (i.e. temporarily assigns them Z=infinite before inverting)
    tempZ = deepcopy(Zmat)
    for idx in range(0,3):
        if Zmat[idx,idx] == 0:
            tempZ[idx,idx] = np.inf
    return np.linalg.inv(tempZ)

def fixconnections(tree,headnode):
    # Removes all upstream-facing connections from a networkx digraph
    # This will break when we start moving to mesh networks
    succlist = list()
    for inode in tree.successors(headnode):
        succlist.append(inode)
    for inode in succlist:
        if (inode, headnode) in tree.edges():
            #print(f'inode: {inode}, headnode: {headnode}')
            tree.remove_edge(inode,headnode)
        #old line causing recursive error
        #for inode2 in tree.successors(inode):
        #this next line used to be indented for for loop
        fixconnections(tree,inode)

def propogatebasesup(tree,currnode,kVbase_phg):
    # Sets the voltage bases of every node on a path upstream from a given node. Stops if it hits a transformer.
    # 'tree' should be a networkx graph object
    predlist = list()
    currnode.kVbase_phg = kVbase_phg
    currnode.Zbase = kVbase_phg*kVbase_phg*1000/currnode.kVAbase
    for inode in tree.predecessors(currnode):
        predlist.append(inode)
    #print(f'UP - currnode: {currnode.name}')
    #for inode in predlist:
        #print(f'UP - succ: {inode.name}')
    for inode in predlist:
        if isinstance(tree[inode][currnode]['connector'],transformer):
            return
        else:
            propogatebasesup(tree,inode,kVbase_phg)

def propogatebasesdown(tree,currnode,kVbase_phg):
    # Sets the voltage bases of every node on a path downtream from a given node. Stops if it hits a transformer.
    # 'tree' should be a networkx graph object
    succlist = list()
    currnode.kVbase_phg = kVbase_phg
    currnode.Zbase = kVbase_phg*kVbase_phg*1000/currnode.kVAbase
    for inode in tree.successors(currnode):
        succlist.append(inode)
    #print(f'DOWN - currnode: {currnode.name}')
    #for inode in succlist:
        #print(f'DOWN- succ: {inode.name}')
    for inode in succlist:
        propogatebasesdown(tree,inode,kVbase_phg)

def propogatetrans(tree,currnode):
    # Uses propogatebasesup and down to set appropriate voltage bases throughout a networkx graph based on transformer ratings.
    edgelist = list()
    for iedge in tree.out_edges(currnode): #2to3 out_edges_iter to out_edges
        edgelist.append(iedge)
    for iedge in edgelist:
        conn = tree[iedge[0]][iedge[1]]['connector']
        if isinstance(conn,transformer):
            if currnode == conn.w0_node:
                propogatebasesup(tree,currnode,conn.w0_kVbase_phg)
                propogatebasesdown(tree,iedge[1],conn.w1_kVbase_phg)
            elif currnode == conn.w1_node:
                propogatebasesup(tree,currnode,conn.w1_kVbase_phg)
                propogatebasesdown(tree,iedge[1],conn.w0_kVbase_phg)
    succlist = list()
    for inode in tree.successors(currnode):
        succlist.append(inode)
    for inode in succlist:
        propogatetrans(tree,inode)

# In[28]:

## DATA IMPORT FUNCTIONS

# In[29]:

# CREATING NODES AND LOAD OBJECTS

# In[30]:

# Create bus dictionary from dataframe
def busbuilder(modeldata,subkVbase_phg,subkVAbase,timesteps):
    bussheet = modeldata.parse('Bus')
    busdict=dict()

    for idx, row in bussheet.iterrows():
        indkey = row['Bus'][:len(row['Bus'])-2]
        indphase = row['Bus'][len(row['Bus'])-1]

        if indkey in busdict.keys():
            busdict[indkey].phases.append(indphase)
        else:
            busdict[indkey] = bus(indkey,subkVbase_phg,subkVAbase, timesteps)
            busdict[indkey].type = row['Type']
            busdict[indkey].phases.append(indphase)

    for key, obj in busdict.items():
        for idx2 in range(len(obj.phases)):
            if obj.phases[idx2] == 'a':
                obj.phasevec = obj.phasevec + np.array([[1],[0],[0]])
            elif obj.phases[idx2] == 'b':
                obj.phasevec = obj.phasevec + np.array([[0],[1],[0]])
            elif obj.phases[idx2] == 'c':
                obj.phasevec = obj.phasevec + np.array([[0],[0],[1]])

    return busdict

# In[31]:

# Create Vsource dictionary from dataframe
# This is a superfluous object since the present (July 2018) code assumes that there is only one Vsrc (the substation)
# So, the current code doesn't use it for anything, but if later models have multiple Vsrcs, we might find it useful
def Vsrcbuilder(modeldata, busdict):
    Vsrcsheet = modeldata.parse('Vsource 3-phase')
    Vsrcdict=dict()

    # Initiation
    for idx, row in Vsrcsheet.iterrows():
        if row['bus A']:
            indkey = row['bus A'][:len(row['bus A'])-2]
        elif row['bus B']:
            indkey = row['bus B'][:len(row['bus B'])-2]
        elif row[' bus C']:
            indkey = row['bus C'][:len(row[' bus C'])-2] # Note that there is a leading space in the Excel sheet
        Vsrcdict[indkey] = Vsrc(indkey)

        # Check phases
        if row['bus A'] and isinstance(row['bus A'],str):
            Vsrcdict[indkey].phases.append('a')
        if row['bus B'] and isinstance(row['bus B'],str):
            Vsrcdict[indkey].phases.append('b')
        if row[' bus C'] and isinstance(row[' bus C'],str): # Note that there is a leading space in the Excel sheet
            Vsrcdict[indkey].phases.append('c')

        # Set angles. This assumes that "Angle A" is the only one populated, (the only form I've seen so far)
        angle_phA = row[' Angle_a (Degree)']
        Vsrcdict[indkey].Vangvec[0,0] = angle_phA
        Vsrcdict[indkey].Vangvec[1,0] = angle_phA + 240.
        Vsrcdict[indkey].Vangvec[2,0] = angle_phA + 120.

        # Misc field, likely not useful
        Vsrcdict[indkey].id = row['ID']

        # Set voltages
        Vsrcdict[indkey].kV_phph = row['kV (ph-ph RMS)']
        Vsrcdict[indkey].Vvec_phg[0,0] = Vsrcdict[indkey].kV_phph/np.sqrt(3)
        Vsrcdict[indkey].Vvec_phg[1,0] = Vsrcdict[indkey].kV_phph/np.sqrt(3)
        Vsrcdict[indkey].Vvec_phg[2,0] = Vsrcdict[indkey].kV_phph/np.sqrt(3)

        # Append object to buslist
        busdict[indkey].Vsrcs.append(Vsrcdict[indkey])

    # Populate phase vectors
    for key, obj in Vsrcdict.items():
        for idx2 in range(len(obj.phases)):
            obj.phasevec = obj.phasevec + phase2vec(obj.phases[idx2])

    return Vsrcdict

# In[32]:

# Create shunt elements dictionary from dataframe
# Currently (July 2018) this object handles constant power capacitors only
def shuntbuilder(modeldata, busdict,timesteps):
    shuntsheet = modeldata.parse('Multiphase Shunt')
    shuntdict = dict()

    for idx, row in shuntsheet.iterrows():
        if row['Bus1'] and isinstance(row['Bus1'],str):
            indkey = row['Bus1'][:len(row['Bus1'])-2]
        elif row['Bus2'] and isinstance(row['Bus2'],str):
            indkey = row['Bus2'][:len(row['Bus2'])-2]
        elif row['Bus3'] and isinstance(row['Bus3'],str):
            indkey = row['Bus3'][:len(row['Bus3'])-2]

        shuntdict[indkey] = shunt(indkey,timesteps)

        if row['Bus1'] and isinstance(row['Bus1'],str):
            indphase = row['Bus1'][len(row['Bus1'])-1]
            shuntdict[indkey].phases.append(indphase)

        if row['Bus2'] and isinstance(row['Bus2'],str):
            indphase = row['Bus2'][len(row['Bus2'])-1]
            shuntdict[indkey].phases.append(indphase)

        if row['Bus3'] and isinstance(row['Bus3'],str):
            indphase = row['Bus3'][len(row['Bus3'])-1]
            shuntdict[indkey].phases.append(indphase)

        shuntdict[indkey].id = row['ID']
        shuntdict[indkey].node = busdict[indkey]
        shuntdict[indkey].kV_phg = row['kV (ph-gr RMS)']
# 2to3 long to int in (isinstance(row['P1(kW)'],long)
        if (row['P1(kW)']) and (not np.isnan(row['P1(kW)'])) and (isinstance(row['P1(kW)'],int) or isinstance(row['P1(kW)'],float)):
            # Note that spacings in P,Q headings are very inconsistent
            shuntdict[indkey].Pvec = shuntdict[indkey].Pvec + row['P1(kW)'] * phase2vec(shuntdict[indkey].phases[0])

        if row['P2 (kW)'] and (not np.isnan(row['P2 (kW)'])) and (isinstance(row['P2 (kW)'],int) or isinstance(row['P2 (kW)'],float)):
            shuntdict[indkey].Pvec = shuntdict[indkey].Pvec + row['P2 (kW)'] * phase2vec(shuntdict[indkey].phases[1])

        if row['P3(kW)'] and (not np.isnan(row['P3(kW)'])) and (isinstance(row['P3(kW)'],int) or isinstance(row['P3(kW)'],float)):
            shuntdict[indkey].Pvec = shuntdict[indkey].Pvec + row['P3(kW)'] * phase2vec(shuntdict[indkey].phases[2])

        if row['Q1(kVAr)'] and (not np.isnan(row['Q1(kVAr)'])) and (isinstance(row['Q1(kVAr)'],int) or isinstance(row['Q1(kVAr)'],float)):
            shuntdict[indkey].Qvec = shuntdict[indkey].Qvec + row['Q1(kVAr)'] * phase2vec(shuntdict[indkey].phases[0])

        if row['Q2 (kVAr)'] and (not np.isnan(row['Q2 (kVAr)'])) and (isinstance(row['Q2 (kVAr)'],int) or isinstance(row['Q2 (kVAr)'],float)):
            shuntdict[indkey].Qvec = shuntdict[indkey].Qvec + row['Q2 (kVAr)'] * phase2vec(shuntdict[indkey].phases[1])

        if row['Q3 (kVAr)'] and (not np.isnan(row['Q3 (kVAr)'])) and (isinstance(row['Q3 (kVAr)'],int) or isinstance(row['Q3 (kVAr)'],float)):
            shuntdict[indkey].Qvec = shuntdict[indkey].Qvec + row['Q3 (kVAr)'] * phase2vec(shuntdict[indkey].phases[2])

        if row['Status1'] and row['Status1'] == 1:
            shuntdict[indkey].statusvec = shuntdict[indkey].statusvec + phase2vec(shuntdict[indkey].phases[0])
        if row['Status2'] and row['Status2'] == 1:
            assert(len(shuntdict[indkey].phases) >= 2)
            shuntdict[indkey].statusvec = shuntdict[indkey].statusvec + phase2vec(shuntdict[indkey].phases[1])
        if row['Status3'] and row['Status3'] == 1:
            assert(len(shuntdict[indkey].phases) == 3)
            shuntdict[indkey].statusvec = shuntdict[indkey].statusvec + phase2vec(shuntdict[indkey].phases[2])

        busdict[indkey].cap.append(shuntdict[indkey])

    for key, obj in shuntdict.items():
        for idx2 in range(len(obj.phases)):
            obj.phasevec = obj.phasevec + phase2vec(obj.phases[idx2])

    return shuntdict

# In[33]:

# Create load dictionary from ePHASORsim model and Gridbright load files
def loadbuilderPQ(modeldata, busdict, loadpath, timesteps, timestepcur):

    # This creates the load objects from the ePHASORsim model, but ignores the specified values (values are set with a Gridbright load file)
    loadsheet = modeldata.parse('Multiphase Load')
    loaddict = dict()

    for idx, row in loadsheet.iterrows():
        if row['Bus1']:
            indkey = row['Bus1'][:len(row['Bus1'])-2]
            loadname = row['Bus1']
        elif row['Bus2']:
            indkey = row['Bus2'][:len(row['Bus2'])-2]
            loadname = row['Bus2']
        elif row['Bus3']:
            indkey = row['Bus3'][:len(row['Bus3'])-2]
            loadname = row['Bus3']

        loaddict[indkey] = load(indkey, timesteps)
        if row['Bus1'] and isinstance(row['Bus1'],str):
            indphase = row['Bus1'][len(row['Bus1'])-1]
            loaddict[indkey].phases.append(indphase)

        if row['Bus2'] and isinstance(row['Bus2'],str):
            indphase = row['Bus2'][len(row['Bus2'])-1]
            loaddict[indkey].phases.append(indphase)

        if row['Bus3'] and isinstance(row['Bus3'],str):
            indphase = row['Bus3'][len(row['Bus3'])-1]
            loaddict[indkey].phases.append(indphase)

        loaddict[indkey].id = row['ID']
        loaddict[indkey].node = busdict[indkey]
        loaddict[indkey].type = row['Type']
        loaddict[indkey].kV_phph = row['V (kV)']
        loaddict[indkey].bandwidth = row['Bandwidth (pu)']
        loaddict[indkey].conn = row['Conn. type']
        loaddict[indkey].constZ = row['K_z']
        loaddict[indkey].constI = row['K_i']
        loaddict[indkey].constP = row['K_p']
        loaddict[indkey].status = row['Status']

        busdict[indkey].loads.append(loaddict[indkey])

    loadfile = pd.ExcelFile(loadpath)
    loaddf = loadfile.parse('Time_Series_data')
    #[HIL] - parse out current timestep
    loaddf = loaddf[timestepcur:timestepcur+timesteps]
    loaddf.index -= timestepcur

    # Populate the load dictionary's P and Q schedules with a Gridbright load file

#JPEDIT START

    multiph = ['1','2','3'] ##generalize to 1,2,3 instead of first second third
    for key, iload in loaddict.items():
        Pkey = []
        Qkey = []
        phkey = []
        for header in loaddf.columns:
            if key in header:
                #for mph in multiph:
                if '/P' in header:
                    Pkey.append(header)
                if '/Q' in header:
                    Qkey.append(header)
        for ph in iload.phases:
            phkey.append(ph)
        for idx in range(len(phkey)):
            for ts in range(0,timesteps):  #write with dict??
                if idx+1 > len(Pkey):
                    kW = 0
                    kVar = 0
                else:
                    kW = loaddf[Pkey[idx]][ts]
                    kVAR = loaddf[Qkey[idx]][ts]

                S = kW + 1j*kVAR

                if not (S==0):
                    Z = np.conj(np.square(iload.node.kVbase_phg)*1000/S)
                else:
                    Z = 0

                if phkey[idx] == 'a':
                    iload.Psched[0,ts] = kW
                    iload.Qsched[0,ts] = kVAR

                    iload.Rsched[0,ts] = np.real(Z)
                    iload.Xsched[0,ts] = np.imag(Z)

                if phkey[idx] == 'b':
                    iload.Psched[1,ts] = kW
                    iload.Qsched[1,ts] = kVAR

                    iload.Rsched[1,ts] = np.real(Z)
                    iload.Xsched[1,ts] = np.imag(Z)

                if phkey[idx] == 'c':
                    iload.Psched[2,ts] = kW
                    iload.Qsched[2,ts] = kVAR

                    iload.Rsched[2,ts] = np.real(Z)
                    iload.Xsched[2,ts] = np.imag(Z)

#JPEDIT END - replaced edited out code, see old backup versions if this needs to be restored

    for key, iload in loaddict.items():
        for idx in range(len(iload.phases)):
            if iload.phases[idx] == 'a':
                iload.phasevec = iload.phasevec + np.array([[1],[0],[0]])
            elif iload.phases[idx] == 'b':
                iload.phasevec = iload.phasevec + np.array([[0],[1],[0]])
            elif iload.phases[idx] == 'c':
                iload.phasevec = iload.phasevec + np.array([[0],[0],[1]])

    return loaddict

# In[34]:

# Create actuator dictionary from Gridbright load file
# This interprets all 'PV_KW_' entries in the load file as controllable PV.
# If the PV is uncontrollable, it should be included as negative load in the load P and Q schedules
def actbuilder(modeldata, busdict, actpath, timesteps, timestepcur):

    actdict = dict()
    actfile = pd.ExcelFile(actpath)
    actdf = actfile.parse('Time_Series_data')
    #[HIL] - parse current timestep
    actdf = actdf[timestepcur:timestepcur+timesteps]
    actdf.index -= timestepcur

    for key,ibus in busdict.items():
        for ph in ibus.phases:
            if 'act_kVA_' + key + '_' + ph in list(actdf.columns.values):
                if not (key in actdict):
                    actdict[key] = actuator(key, timesteps)
                    actdict[key].node = busdict[key]
                    ibus.actuators.append(actdict[key])
                actdict[key].phases.append(ph)

    for key, iact in actdict.items():
        for ph in iact.phases:
            for ts in range(0,timesteps):
                actname_kVA = 'act_kVA_' + key + '_' + ph
                act = actdf[actname_kVA][ts]

                if ph == 'a':
                    iact.Psched[0,ts] = act
                    iact.Ssched[0,ts] = act
                if ph == 'b':
                    iact.Psched[1,ts] = act
                    iact.Ssched[1,ts] = act
                if ph == 'c':
                    iact.Psched[2,ts] = act
                    iact.Ssched[2,ts] = act

    for key, iact in actdict.items():
        for idx in range(len(iact.phases)):
            if iact.phases[idx] == 'a':
                iact.phasevec = iact.phasevec + np.array([[1],[0],[0]])
            elif iact.phases[idx] == 'b':
                iact.phasevec = iact.phasevec + np.array([[0],[1],[0]])
            elif iact.phases[idx] == 'c':
                iact.phasevec = iact.phasevec + np.array([[0],[0],[1]])

    return actdict

# In[35]:

# LINES AND CONNECTOR OBJECTS

# In[36]:

# Create line dictionary
# Note that this isn't set up to handle cross-phase connections: i.e. please don't connect phase A at node 1 to phase B at node 2
def linebuilder(modeldata, busdict, timesteps):
    linesheet = modeldata.parse('Multiphase Line')
    # Create line dictionary from dataframe
    linedict = dict()
    for idx, row in linesheet.iterrows():
        # node ID's
        if row['From1']:
            indkeyfrom = row['From1'][:len(row['From1'])-2]
        elif row['From2']:
            indkeyfrom = row['From2'][:len(row['From2'])-2]
        elif row['From3']:
            indkeyfrom = row['From3'][:len(row['From3'])-2]

        if row['To1']:
            indkeyto = row['To1'][:len(row['To1'])-2]
        elif row['To2']:
            indkeyto = row['To2'][:len(row['To2'])-2]
        elif row['To3']:
            indkeyto = row['To3'][:len(row['To3'])-2]

        indkey = indkeyfrom + 'to' + indkeyto
        linedict[indkey] = line(indkey, timesteps)

        busdict[indkeyfrom].edges_out.append(linedict[indkey])
        busdict[indkeyto].edges_in.append(linedict[indkey])

        linedict[indkey].id = row['ID']
        linedict[indkey].length = row['Length (length_unit)']

        linedict[indkey].from_node = busdict[indkeyfrom]
        linedict[indkey].to_node = busdict[indkeyto]

        # phases (a,b,c)
        if row['From1'] and isinstance(row['From1'],str):
            linedict[indkey].from_phases.append(row['From1'][len(row['From1'])-1])
        if row['From2'] and isinstance(row['From2'],str):
            linedict[indkey].from_phases.append(row['From2'][len(row['From2'])-1])
        if row['From3'] and isinstance(row['From3'],str):
            linedict[indkey].from_phases.append(row['From3'][len(row['From3'])-1])

        if row['To1'] and isinstance(row['To1'],str):
            linedict[indkey].to_phases.append(row['To1'][len(row['To1'])-1])
        if row['To2'] and isinstance(row['To2'],str):
            linedict[indkey].to_phases.append(row['To2'][len(row['To2'])-1])
        if row['To3'] and isinstance(row['To3'],str):
            linedict[indkey].to_phases.append(row['To3'][len(row['To3'])-1])

        for idx in range(0,len(linedict[indkey].to_phases)):
            linedict[indkey].phasevec = linedict[indkey].phasevec + phase2vec(linedict[indkey].to_phases[idx])

        # Build R, X, shunt Y matrices (shunt Y are not included in LUPFM)
        rdict = dict()
        rdict['11'] = row['r11 (ohm/length_unit)']
        rdict['21'] = row['r21 (ohm/length_unit)']
        rdict['22'] = row['r22 (ohm/length_unit)']
        rdict['31'] = row['r31 (ohm/length_unit)']
        rdict['32'] = row['r32 (ohm/length_unit)']
        rdict['33'] = row['r33 (ohm/length_unit)']
        rdict['12'] = rdict['21']
        rdict['13'] = rdict['31']
        rdict['23'] = rdict['32']

        xdict = dict()
        xdict['11'] = row['x11 (ohm/length_unit)']
        xdict['21'] = row['x21 (ohm/length_unit)']
        xdict['22'] = row['x22 (ohm/length_unit)']
        xdict['31'] = row['x31 (ohm/length_unit)']
        xdict['32'] = row['x32 (ohm/length_unit)']
        xdict['33'] = row['x33 (ohm/length_unit)']
        xdict['12'] = xdict['21']
        xdict['13'] = xdict['31']
        xdict['23'] = xdict['32']

        bdict = dict()
        bdict['11'] = row['b11 (uS/length_unit)']
        bdict['21'] = row['b21 (uS/length_unit)']
        bdict['22'] = row['b22 (uS/length_unit)']
        bdict['31'] = row['b31 (uS/length_unit)']
        bdict['32'] = row['b32 (uS/length_unit)']
        bdict['33'] = row['b33 (uS/length_unit)']
        bdict['12'] = bdict['21']
        bdict['13'] = bdict['31']
        bdict['23'] = bdict['32']

        frm_ph_lst = list(map(string.ascii_lowercase.index,linedict[indkey].from_phases))
        to_ph_lst = list(map(string.ascii_lowercase.index,linedict[indkey].to_phases))
        for fromidx in range(0, len(frm_ph_lst)):
            for toidx in range(0, len(to_ph_lst)):
                linedict[indkey].R[frm_ph_lst[fromidx], to_ph_lst[toidx]] = rdict[str(fromidx + 1) + str(toidx + 1)]
                linedict[indkey].R[to_ph_lst[toidx], frm_ph_lst[fromidx]] = rdict[str(fromidx + 1) + str(toidx + 1)]
                linedict[indkey].X[to_ph_lst[toidx], frm_ph_lst[fromidx]] = xdict[str(fromidx + 1) + str(toidx + 1)]
                linedict[indkey].X[frm_ph_lst[fromidx], to_ph_lst[toidx]] = xdict[str(fromidx + 1) + str(toidx + 1)]
        linedict[indkey].R = np.nan_to_num(np.multiply(linedict[indkey].R,linedict[indkey].length))
        linedict[indkey].X = np.nan_to_num(np.multiply(linedict[indkey].X,linedict[indkey].length))

        linedict[indkey].Z = linedict[indkey].R + 1j*linedict[indkey].X
        linedict[indkey].Y = ZtoY(linedict[indkey].Z)
        # Line per-unit quantities are set later in this script, once voltage bases have been established.

    return linedict

# In[37]:

# Create switch dictionary
def switchbuilder(modeldata, busdict, timesteps):
    switchsheet = modeldata.parse('Switch')

    switchdict = dict()
    for idx, row in switchsheet.iterrows():
        #if row['Status'] != 0: #only create node/edge if switch is closed
        indkeyfrom = row['From Bus'][:len(row['From Bus'])-2]
        indkeyto = row['To Bus'][:len(row['To Bus'])-2]

        indphasefrom = row['From Bus'][len(row['From Bus'])-1]
        indphaseto = row['To Bus'][len(row['To Bus'])-1]

        indkey = indkeyfrom + 'to' + indkeyto

        if indkey in switchdict.keys():
            switchdict[indkey].phases_from.append(indphasefrom)
            switchdict[indkey].phases_to.append(indphaseto)

        else:
            switchdict[indkey] = switch(indkey, timesteps)
            switchdict[indkey].phases_from.append(indphasefrom)
            switchdict[indkey].phases_to.append(indphaseto)

            switchdict[indkey].from_node = busdict[indkeyfrom]
            switchdict[indkey].to_node = busdict[indkeyto]
            switchdict[indkey].status.append(row['Status'])

            busdict[indkeyfrom].edges_out.append(switchdict[indkey])
            busdict[indkeyto].edges_in.append(switchdict[indkey])

    # This next loop is ugly, but it works (it's the result of fixing a bug)
    for indkey, entry in switchdict.items():
        for idx in range(0,len(switchdict[indkey].phases_to)):
            switchdict[indkey].phasevec = switchdict[indkey].phasevec + phase2vec(switchdict[indkey].phases_to[idx])

        # Build Z, Y matrices (per unit)
        assert(switchdict[indkey].from_node.Zbase == switchdict[indkey].to_node.Zbase)
        Zbase = switchdict[indkey].from_node.Zbase

        tempz = (1e-4)/Zbase # Based off of the DSS switch approximation: r1=r0=1e-4
        tempy = 1/tempz

        from_ph_lst = list(map(string.ascii_lowercase.index,switchdict[indkey].phases_from))
        to_ph_lst = list(map(string.ascii_lowercase.index,switchdict[indkey].phases_to))

        for idx in range(0, len(from_ph_lst)):
            switchdict[indkey].Z[from_ph_lst[idx], to_ph_lst[idx]] = 1e-4
            switchdict[indkey].Y[from_ph_lst[idx], to_ph_lst[idx]] = 1e4
            switchdict[indkey].Zpu[from_ph_lst[idx], to_ph_lst[idx]] = tempz
            switchdict[indkey].Ypu[from_ph_lst[idx], to_ph_lst[idx]] = tempy

    return switchdict

# In[38]:

# Create transformer dictionary from dataframe
def transbuilder(modeldata,busdict,subkVAbase,timesteps):
    transsheet = modeldata.parse('Transformer 3-phase')
    #[HIL] - NEW CODE index misalignment during parse
    if transsheet.iloc[0][0] == 'ID':
        transsheet = modeldata.parse('Transformer 3-phase', index_col=0)

    # Prep transformer column headers (This is built to handle a 2-winding transformer)
    windcols = transsheet.columns.get_loc('winding 1') - transsheet.columns.get_loc('winding 0')
    othercols = len(transsheet.columns) - transsheet.columns.get_loc('winding 1') - windcols
    for idx in range(0,windcols):
        transsheet.iloc[0][idx] = 'w0_' + transsheet.iloc[0][idx]
    for idx in range(windcols,2*windcols):
        transsheet.iloc[0][idx] = 'w1_' + transsheet.iloc[0][idx]
    transsheet.columns = transsheet.iloc[0]
    transsheet = transsheet.drop(transsheet.index[0]);

    # Create dictionary
    transdict = dict()

    for idx, row in transsheet.iterrows():
        if row['w0_bus a']:
            indkeyw0 = row['w0_bus a'][:len(row['w0_bus a'])-2]
        elif row['w0_bus b']:
            indkeyw0 = row['w0_bus b'][:len(row['w0_bus b'])-2]
        elif row['w0_bus c']:
            indkeyw0 = row['w0_bus c'][:len(row['w0_bus c'])-2]

        if row['w1_bus_a']:
            indkeyw1 = row['w1_bus_a'][:len(row['w1_bus_a'])-2]
        elif row['w1_bus_b']:
            indkeyw1 = row['w1_bus_b'][:len(row['w1_bus_b'])-2]
        elif row['w1_bus_c']:
            indkeyw1 = row['w1_bus_c'][:len(row['w1_bus_c'])-2]

        indkey = indkeyw0 + 'to' + indkeyw1

        transdict[indkey] = transformer(indkey, timesteps)
        transdict[indkey].id = idx

        busdict[indkeyw0].edges_out.append(transdict[indkey])
        busdict[indkeyw1].edges_in.append(transdict[indkey])

        if row['w0_bus a']:
            transdict[indkey].w0_phases.append('a')
        if row['w0_bus b']:
            transdict[indkey].w0_phases.append('b')
        if row['w0_bus c']:
            transdict[indkey].w0_phases.append('c')

        transdict[indkey].w0_name = indkeyw0
        transdict[indkey].w0_node = busdict[indkeyw0]

        transdict[indkey].w0_kVbase_phg = row['w0_kV (ph-ph RMS)']/np.sqrt(3)
        transdict[indkey].w0_kVAbase = row['w0_kVA_base']
        transdict[indkey].w0_rpu = row['w0_R_w0 (pu)']
        #transdict[indkey].w0_conn = row[headmap['w0_conn']]
        transdict[indkey].w0_conn = row['w0_conn'] #[HIL] - edit, error

        if row['w1_bus_a']:
            transdict[indkey].w1_phases.append('a')
        if row['w1_bus_b']:
            transdict[indkey].w1_phases.append('b')
        if row['w1_bus_c']:
            transdict[indkey].w1_phases.append('c')

        for idx in range(0,len(transdict[indkey].w1_phases)):
            transdict[indkey].phasevec = transdict[indkey].phasevec + phase2vec(transdict[indkey].w1_phases[idx])

        transdict[indkey].w1_name = indkeyw1
        transdict[indkey].w1_node = busdict[indkeyw1]

        transdict[indkey].w1_kVbase_phg = row['w1_kV (ph-ph RMS)']/np.sqrt(3)
        transdict[indkey].w1_kVAbase = row['w1_kVA_base']
        transdict[indkey].w1_rpu = row['w1_R_w1 (pu)']
        transdict[indkey].w1_conn = row['w1_conn']

        transdict[indkey].xpu = row['X (pu)']

        if row['Tap A']:
            transdict[indkey].tappos.append(row['Tap A'])
        else:
            transdict[indkey].tappos.append(0)
        if row['Tap B']:
            transdict[indkey].tappos.append(row['Tap B'])
        else:
            transdict[indkey].tappos.append(0)
        if row['Tap C']:
            transdict[indkey].tappos.append(row['Tap C'])
        else:
            transdict[indkey].tappos.append(0)

        transdict[indkey].taprange_high = row['Highest Tap']
        transdict[indkey].taprange_low = row['Lowest Tap']
        transdict[indkey].taprangepct_high = row['Max Range (%)']
        transdict[indkey].taprangepct_low = row['Min Range (%)']

        # Build Z, Y matrices
        assert(transdict[indkey].w1_kVAbase == transdict[indkey].w0_kVAbase)
        tempz = (transdict[indkey].w0_rpu + transdict[indkey].w1_rpu + 1j*transdict[indkey].xpu)*subkVAbase/transdict[indkey].w0_kVAbase
        tempy = 1/tempz

        w0_ph_lst = list(map(string.ascii_lowercase.index,transdict[indkey].w0_phases))
        w1_ph_lst = list(map(string.ascii_lowercase.index,transdict[indkey].w1_phases))

        for idx in range(0, len(w0_ph_lst)):
            transdict[indkey].Zpu[w0_ph_lst[idx], w1_ph_lst[idx]] = tempz
            transdict[indkey].Ypu[w0_ph_lst[idx], w1_ph_lst[idx]] = tempy

    return transdict

# In[39]:

## NETWORK MAP (USED TO DEFINE VOLTAGE BASES FROM TRANSFORMER CONNECTIVITY)

# In[40]:

def network_mapper(modeldata,busdict,linedict,transdict,switchdict):
    # Create networkx digraph with all connections pointing both ways
    network = nx.DiGraph()
    for key, value in busdict.items():
        network.add_node(value)
    for key, value in linedict.items():
        #print(f'key: {key}, value: {value}')
        network.add_edge(value.from_node,value.to_node,connector=value)
        network.add_edge(value.to_node,value.from_node,connector=value)
    for key, value in transdict.items():
        network.add_edge(value.w0_node,value.w1_node,connector=value)
        network.add_edge(value.w1_node,value.w0_node,connector=value)
    for key, value in switchdict.items():
        network.add_edge(value.from_node,value.to_node,connector=value)
        network.add_edge(value.to_node,value.from_node,connector=value)

    # Find slack bus, remove all upstream-facing connections with fixconnections function, and assign kV bases
    for inode in list(network):
        if inode.type == 'SLACK' or inode.type == 'Slack' or inode.type == 'slack':
            slacknode = inode

    fixconnections(network,slacknode)
    propogatetrans(network,slacknode)

    return network

# In[41]:

def set_per_unit(linedict):
    # Set the values of Zpu and Ypu matrices for lines
    for key, iconn in linedict.items():
        assert (iconn.from_node.kVbase_phg == iconn.to_node.kVbase_phg and iconn.from_node.kVAbase == iconn.to_node.kVAbase), "Base mismatch " + iconn.name
        iconn.kVbase_phg = iconn.from_node.kVbase_phg
        iconn.kVAbase = iconn.from_node.kVAbase
        iconn.Zbase = iconn.kVbase_phg*iconn.kVbase_phg*1000/iconn.kVAbase
        iconn.Zpu = (iconn.R + 1j*iconn.X)/iconn.Zbase
        iconn.Ypu = ZtoY(iconn.Zpu)

# In[42]:

# add costs for actuators
'''
def add_act_costs

'''


import sys
import traceback
from discord.ext import commands
import discord
import discord_slash

listen = commands.Cog.listener

class EventCog(commands.Cog):
    def __init__(self, bot: commands.Bot):
        self.bot = bot

    @listen()
    async def on_command_error(self, ctx, error):
        rep_guild = discord.utils.get(self.bot.guilds, id=761991504793174117)
        rep_channel = discord.utils.get(rep_guild.channels, id=868788281528160266)
        dev=discord.utils.get(self.bot.users, id=704560097610825828)
        """The event triggered when an error is raised while invoking a command.
        Parameters
        ------------
        ctx: commands.Context
            The context used for command invocation.
        error: commands.CommandError
            The Exception raised.
        """
        if hasattr(ctx.command, 'on_error'):
            return

        cog = ctx.cog
        if cog:
            if cog._get_overridden_method(cog.cog_command_error) is not None:
                return

        await self.error_checker(ctx, error, rep_guild, rep_channel, dev)

    @listen()
    async def on_slash_command_error(self, ctx, err):
        rep_guild = discord.utils.get(self.bot.guilds, id=761991504793174117)
        rep_channel = discord.utils.get(rep_guild.channels, id=868788281528160266)
        dev=discord.utils.get(self.bot.users, id=704560097610825828)
        await self.error_checker(ctx, err, rep_guild, rep_channel, dev)

    @listen()
    async def on_component_callback_error(self, ctx, err):
        rep_guild = discord.utils.get(self.bot.guilds, id=761991504793174117)
        rep_channel = discord.utils.get(rep_guild.channels, id=868788281528160266)
        dev=discord.utils.get(self.bot.users, id=704560097610825828)
        await self.error_checker(ctx, err, rep_guild, rep_channel, dev)

    @staticmethod
    async def error_checker(ctx, error, rep_guild, rep_channel, dev):
        ignored = (commands.NotOwner, discord.NotFound, commands.CommandNotFound)
        error = getattr(error, 'original', error)

        if isinstance(error, ignored):
            return

        elif isinstance(error, commands.MissingRequiredArgument):
            embed = discord.Embed(color=0xFF0000).set_author(
                name=f'Указаны не все аргументы для {ctx.command}.',
                icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
            await ctx.send(embed=embed)

        elif isinstance(error, commands.DisabledCommand):
            embed = discord.Embed(color=0xFF0000).set_author(
                name=f'Команда {ctx.command} отключена.',
                icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
            return await ctx.send(embed=embed)

        elif isinstance(error, discord.errors.Forbidden):
            embed = discord.Embed(color=0xFF0000).set_author(
                name=f'У меня недостаточно прав.',
                icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
            return await ctx.send(embed=embed)

        elif isinstance(error, commands.CheckFailure):
            print(error.__module__)
            if not isinstance(error, commands.errors.NSFWChannelRequired):
                if isinstance(error, discord.ext.commands.errors.MissingPermissions):
                    embed = discord.Embed(color=0xFF0000, ).set_author(
                        name=f'у тебя нет прав',
                        icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
                    return await ctx.send(embed=embed)

                embed = discord.Embed(color=0xFF0000).set_author(
                    name='У вас нет прав.',
                    icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
            else:
                embed = discord.Embed(color=0xFF0000).set_author(
                    name=f'Эту команду нельзя выполнить здесь. (Может быть, в NSFW канале)',
                    icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
            return await ctx.send(embed=embed)
        elif isinstance(error, commands.NoPrivateMessage):
            try:
                embed = discord.Embed(color=0xFF0000).set_author(
                    name=f'Команда {ctx.command} не может быть выполнена в ЛС.',
                    icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
                return await ctx.send(embed=embed)
            except:
                pass

        elif isinstance(error, commands.BadArgument):
            embed = discord.Embed(color=0xFF0000).set_author(
                name=f'Получен неверный аргумент для {ctx.command}.',
                icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
            await ctx.send(embed=embed)

        elif isinstance(error, commands.CommandOnCooldown):
            embed = discord.Embed(color=0xFF0000).set_author(
                name=f'Команду {ctx.command} нельзя выполнять так часто. Подождите немного.',
                icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
            return await ctx.send(embed=embed)

        # Если ничего не подходит
        embed = discord.Embed(
            color=0xF56415,
            title='ErrorHandler обнаружил ошибку!',
            description=f'Вызвано участником: {ctx.author}\nКоманда: {ctx.command}\nПодробности ошибки: ```python\n{type(error).__name__}: {error}```\n```python\n{type(error).__name__}:\n{type(error).__doc__}```'
        )
        embed.set_author(
            name='Обработка исключения.',
            icon_url='http://s1.iconbird.com/ico/2013/11/504/w128h1281385326489locked.png')
        try:
            await rep_channel.send(embed=embed)

        except:
            await dev.send(embed=embed)

        if ctx.author.id in [704560097610825828]:
            await ctx.send(f'{ctx.author.mention}, у меня произошла проблема.')
        else:
            await ctx.send('произошла ошибка! Она уже отправлена разработчикам!')

def setup(bot):
    bot.add_cog(EventCog(bot))


# File: chaos2.py
# A simple program illustrating chaotic behavior.

def main():
    print("This program illustrates a chaotic function")
    x = float(input("Enter a number between 0 and 1: "))
    y = float(input("Enter another number between 0 and 1: "))
    n = int(input("How many numbers should I print? "))

    result = {'x':[], 'y':[]}

    print('{0:^8} {1:^12} {2:^12}'.format('index', x, y))
    print('-' * 32)

    for i in range(n):
        x = 3.9 * x * (1 - x)
        result['x'].append(x)
        y = 3.9 * y * (1 - y)
        result['y'].append(y)

    for i in range(n):
        print('{0:0>2}'.format(i + 1).center(8) + '{0:^12.6f} {0:^12.6f}'.format(
              result['x'][i], result['y'][i]))

main()


"""
The purpose of this module is to provide validation of the input
provided to the functions in the :py:mod:`pytils.launchers.doctests`
module.

"""

import doctest
import inspect
import numpy as np
import os
import sys

def _dir_exists(idir):
    """Validates the *idir* directory exists.

    Args:
        *idir* (str): Relative path for the input directory.

    Returns:
        Nothing.

    Raises:
        **ValueError** if *idir* is not an existing directory.

    """
    if not os.path.isdir(idir):
        caller = inspect.stack()[1][3]
        st1 = 'Specified directory ({0}'.format(caller)
        st2 = '{!r}) does not exist.'.format(idir)
        raise ValueError('{0}::{1}'.format(st1, st2))

def _verbose(verbose):
    """Validates the *verbose* variable and raises error if necessary.

    Args:
        *verbose* (str): Verbose level where '-v' or '-V' indicate
        detailed test information is printed, and '-q' or '-Q' mean
        quiet mode where only failed tests are reported.

    Returns:
        Nothing.

    Raises:
        **ValueError** if *path* is not an existing directory.

        **ValueError** if *verbose* level is incorrectly specified.

    """
    if verbose not in ('-v', '-V', '-q', '-Q'):
        caller = inspect.stack()[1][3]
        st1 = 'Verbose level ({0}'.format(caller)
        st2 = '{!r}) incorrectly specified.'.format(verbose)
        raise ValueError('{0}::{1}'.format(st1, st2))

def _file_exists(filename):
    """Validates *filename* exists.

    Args:
        *filename* (str): Filename ...

    Returns:
        Nothing.

    Raises:
        **IOError** if *filename* is not a file.

    """
    if not type(filename) == str:
        caller = inspect.stack()[1][3]
        st1 = 'Input ({0}'.format(caller)
        st2 = '{!r}) must be a str.'.format(filename)
        raise TypeError('{0}::{1}'.format(st1, st2))
    if not os.path.isfile(filename):
        caller = inspect.stack()[1][3]
        st1 = 'File ({0}'.format(caller)
        st2 = '{!r}) does not exist.'.format(filename)
        raise IOError('{0}::{1}'.format(st1, st2))

def _not_exists(name):
    """Validates *filename* does not exists (dir or file).

    Args:
        *filename* (str): Variable tested for existence as either
        a directory or as a file.

    Returns:
        Nothing.

    Raises:
        **IOError** if *filename* already exists as file or directory.

    """
    if not type(name) == str:
        caller = inspect.stack()[1][3]
        st1 = 'Input ({0}'.format(caller)
        st2 = '{!r}) must be a str.'.format(name)
        raise TypeError('{0}::{1}'.format(st1, st2))
    if os.path.exists(name):
        caller = inspect.stack()[1][3]
        st1 = 'File or directory ({0}'.format(caller)
        st2 = '{!r}) already exists.'.format(name)
        raise IOError('{0}::{1}'.format(st1, st2))

def _positive0_int(var):
    """Validates *var* is positive int and raises error if necessary.

    Args:
        *var* (int): Input variable which is supposed to be an int.

    Returns:
        Nothing.

    Raises:
        **TypeError** if *var* is not an int.

        **ValueError** if *var* is not positive (zero included).

    """
    np_ints = (np.int8, np.int16, np.int32, np.int64)
    np_uints = (np.uint8, np.uint16, np.uint32, np.uint64)
    if not type(var) in (int, long) + np_ints + np_uints:
        caller = inspect.stack()[1][3]
        st1 = 'Variable ({0}'.format(caller)
        st2 = '{!r}) must be an int.'.format(var)
        raise TypeError('{0}::{1}'.format(st1, st2))
    if not var >= 0:
        caller = inspect.stack()[1][3]
        st1 = 'Variable ({0}'.format(caller)
        st2 = '{!r}) must be positive.'.format(var)
        raise TypeError('{0}::{1}'.format(st1, st2))

def _logfile(logfilename=None):
    """Validates *logfilename* and raises error if necessary.

    Args:
        *logfilename* (str): Name of the logfile. Default is
        None in which case logging is not performed.

    Returns:
        Nothing.

    Raises:
        **ValueError** if *logfilename* is not None or a str.

        **ValueError** if *logfilename* already exists.

    """
    if logfilename is not None:
        if not type(logfilename) == str:
            caller = inspect.stack()[1][3]
            st1 = 'Logfile ({0}'.format(caller)
            st2 = '{!r}) invalid (must be str or None).'.format(logfilename)
            raise ValueError('{0}::{1}'.format(st1, st2))
        if os.path.exists(logfilename):
            caller = inspect.stack()[1][3]
            st1 = 'Logfile ({0}'.format(caller)
            st2 = '{!r}) already exists.'.format(logfilename)
            raise ValueError('{0}::{1}'.format(st1, st2))

def _list_str(lst):
    """Validates *lst* and raises error if necessary.

    Args:
        *lst* (str): List of strings each describing the doctest of a
        given doctest file. All list items are of type str, the first
        character is W, F or S, and all items are of identical length.

    Returns:
        Nothing.

    Raises:
        **ValueError** if *lst* is not None or a str.

        **ValueError** if *lst* already exists.

    """
    if not type(lst) == list:
        caller = inspect.stack()[1][3]
        st1 = 'Input ({0}'.format(caller)
        st2 = '{!r}) must be a list.'.format(lst)
        raise ValueError('{0}::{1}'.format(st1, st2))
    if not all(isinstance(item, str) for item in lst):
        caller = inspect.stack()[1][3]
        st1 = 'Input ({0}'.format(caller)
        st2 = '{!r}) list members must all be str.'.format(lst)
        raise ValueError('{0}::{1}'.format(st1, st2))
    for item in lst:
        if len(item) != len(lst[0]) or item[0] not in ('W', 'F', 'S'):
            caller = inspect.stack()[1][3]
            st1 = 'Input list ({0}'.format(caller)
            st2 = '{!r}) have invalid members.'.format(lst)
            raise ValueError('{0}::{1}'.format(st1, st2))

def _dict_keys(idict, keylist):
    """Validates *idict* matches with specified *keylist*.

    Args:
        *idict* (dist): Input dictionary which is checked for correctness.

        *keylist* (list): A list of str keys that **must** be present in
        the *idict* dictionary.

    Returns:
        Nothing.

    Raises:
        **ValueError** if *logfilename* is not None or a str.

        **ValueError** if *logfilename* already exists.

    """
    if not type(keylist) == list:
        caller = inspect.stack()[1][3]
        st1 = 'Input ({0}'.format(caller)
        st2 = '{!r}) must be a list.'.format(keylist)
        raise TypeError('{0}::{1}'.format(st1, st2))
    if not all(isinstance(item, str) for item in keylist):
        caller = inspect.stack()[1][3]
        st1 = 'Input ({0}'.format(caller)
        st2 = '{!r}) list members must all be str.'.format(keylist)
        raise ValueError('{0}::{1}'.format(st1, st2))
    if not type(idict) == dict:
        caller = inspect.stack()[1][3]
        st1 = 'Input ({0}'.format(caller)
        st2 = '{!r}) must be a dictionary.'.format(idict)
        raise TypeError('{0}::{1}'.format(st1, st2))
    for item in keylist:
        if item not in idict.keys():
            caller = inspect.stack()[1][3]
            st1 = 'Keylist ({0}'.format(caller)
            st2 = '{!r}) contains invalid key(s).'.format(keylist)
            raise ValueError('{0}::{1}'.format(st1, st2))


'''
- [x] Split trainval, train, val, test sets
- [x] Created by LiaoSteve on 2020/11/29
- [x] Change 3 parameters:
      (1) random seed
      (2) train_percent
      (3) val_percent
'''
import os
import random

# change 3 parameters:
random.seed(15)
train_percent = 0.7 # 0 < train percent < 1
val_percent   = 0.2

test_percent = 1 - train_percent -val_percent
root = os.getcwd()
xmlfilepath = 'VOCdevkit/VOC2007/Annotations/'
txtpath = 'VOCdevkit/VOC2007/labels/'
jpegfilepath = 'VOCdevkit/VOC2007/JPEGImages/'

if not os.path.exists(xmlfilepath):
    raise RuntimeError("- [x] xml path is not exist.")
if not os.path.exists(jpegfilepath):
    raise RuntimeError("- [x] image path is not exist.")
if not os.path.exists(txtpath):
    raise RuntimeError("- [x] txt path is not exist.")

total_xml = os.listdir(xmlfilepath)
total_images = os.listdir(jpegfilepath)
total_images.sort()
random.shuffle(total_images)
total_txt = os.listdir(txtpath)

print(f'-------------------------------')
print(f'- [x] total_xml: {len(total_xml)}')
print(f'- [x] total_images: {len(total_images)}')
print(f'- [x] total_txt (note that classes.txt could exist, check this file!): {len(total_txt)}')

if not len(total_xml) == len(total_images):
    w1 = input("- [warning] number of xml and images are not the same? [y/n]")
    if w1 == 'y' or w1 =='Y':
        pass
    else:
        raise RuntimeError('check xml and image')
if not len(total_images) == len(total_txt):
    w2 = input('- [warning] number of images and txt are not the same? [y/n]')
    if w2 == 'y' or w1 =='Y':
        pass
    else:
        raise RuntimeError('check txt and image')

list = range(len(total_images))
tr = int(len(total_images) * train_percent)
va = int(len(total_images) * val_percent)
train = random.sample(list, tr) # 3825*0.7

ftrainval = open('2007_trainval.txt', 'w')
ftest = open('2007_test.txt', 'w')
ftrain = open('2007_train.txt', 'w')
fval = open('2007_val.txt', 'w')

train_num = 0
val_num = 0
test_num = 0
val_and_test_name= []

for i in list:
    name = root + '/' + jpegfilepath + total_images[i] + '\n'
    if i in train:
        ftrain.write(name)
        ftrainval.write(name)
        train_num += 1
    else:
        val_and_test_name.append(name)

list = range(len(val_and_test_name))
val= random.sample(list,va)

for i in list:
    name = val_and_test_name[i]
    if i in val:
        fval.write(name)
        ftrainval.write(name)
        val_num += 1
    else:
        ftest.write(name)
        test_num += 1

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

if not len(total_images) == (train_num+test_num+val_num):
    raise RuntimeError('ERROR')

print(f'---------- DONE ----------')
print(f'- [INFO] train:val:test: = {train_percent}:{val_percent}:{test_percent:.3f}')
print(f'- [x] trainval: {train_num + val_num}')
print(f'- [x] train: {train_num}')
print(f'- [x] val: {val_num}')
print(f'- [x] test: {test_num}')


#!/usr/bin/python3
# -*- encoding: utf-8 -*-
from HttpServer import HttpServer
from HttpClient import HttpClient
import re
import os

class App:
    def __init__(self, host='localhost', port=8080):
        callback = self.route
        self.domain_rotation = 0
        self.httpClient = None
        self.httpserver = HttpServer(callback, host, port)

    async def shutdown(self):
        print('App App shutdown')
        await self.httpserver.shutdown()

    async def listen(self):
        await self.httpserver.listen()

    def route(self, req_line={}, req_headers={}, req_body=b''):
        # staus, headers, body = self.echo_http(req_line, req_headers, req_body)
        # print('App (staus, headers, body)', staus, headers, body)
        # return staus, headers, body

        method, path, version = req_line
        path_str = path.decode()
        routes = {
            '/echo.*':                              self.echo_http,
            '/index.*':                             self.index,
            '/tile/([0-9]+)/([0-9]+)/([0-9]+).png': self.tile,
            '/':                                    self.root,
            'default':                              self.static_file,
        }
        for route_key, route_fn in routes.items():
            if route_fn and re.match('^' + route_key + '$', path_str):
                print('\nApp route match "{0}" => "{1}"'.format(route_key, path_str))
                # status, headers, body
                return route_fn(req_line, req_headers, req_body)

        route_key = 'default'
        print('\nApp route NOT match "{0}" => "{1}"'.format(route_key, path_str))
        status, headers, body = routes[route_key](req_line, req_headers, req_body)
        return status, headers, body

    def root(self, req_line, headers, body):
        print('App root')
        status = 302
        headers = {
            b'Location': b'/index.html?zoom=17&lat=-21.98046&lon=-47.88036',
        }
        method, path, version = req_line
        body = b"Hello " + method + path + version
        return status, headers, body

    def echo_http(self, req_line, headers, body):
        print('App echo_http')
        method, path, version = req_line
        if method == b'GET':
            texto = b"Hello " + path
        else:
            texto = b"Num entendi"

        staus = 200
        headers = {}
        body = texto
        return staus, headers, body

    def index(self, req_line, headers, body):
        print('App index')
        filename = 'static/index.html'
        return self.file_response(filename)

    async def tile(self, req_line, headers, body):
        method, path, version = req_line
        print('App tile', path)
        path = path.decode()
        match = re.match('/tile/([0-9]+)/([0-9]+)/([0-9]+).png', path)
        if not match:
            raise 'oops, no tile format'
        z_zoom = match.group(1)
        x_lat = match.group(2)
        y_lon = match.group(3)
        filename = await self.get_tile_file(z_zoom, x_lat, y_lon)
        return self.file_response(filename)

    def static_file(self, req_line, headers, body):
        method, path, version = req_line
        filename = 'static' + path.decode()
        return self.file_response(filename)

    def file_response(self, filename):
        if not os.path.exists(filename):
            print('App Cache miss')
            status = 404
            headers = {}
            body = b'not found'
            return status, headers, body

        status = 200
        headers = {
            b'content-type': self.get_content_type(filename)
        }
        body = b''
        with open(filename, 'br') as file:
            body += file.read()

        return status, headers, body

    def get_content_type(self, filename):
        content_type = b'text/plain; charset=UTF-8'
        if re.match('.*css$', filename):
            content_type = b'text/css; charset=UTF-8'
        if re.match('.*js$', filename):
            content_type = b'application/javascript; charset=UTF-8'
        if re.match('.*ico$', filename):
            content_type = b'image/x-icon; charset=UTF-8'
        if re.match('.*html$', filename):
            content_type = b'text/html; charset=UTF-8'
        if re.match('.*png$', filename):
            content_type = b'image/png'
        print('content_type: {0}\t{1}'.format(content_type.decode(), filename))
        return content_type

    async def get_tile_file(self, z_zoom, x_lat, y_lon):
        dirName = 'tile-cache/'+z_zoom+'/'+x_lat+'/'
        if not os.path.exists(dirName):
            os.makedirs(dirName)

        filename = dirName+y_lon+'.png'
        if not os.path.exists(filename):
            tile = await self.get_tile_web(z_zoom, x_lat, y_lon, filename)
            with open(filename, 'bw') as file:
                file.write(tile)

        return filename

    async def get_tile_web(self, z_zoom, x_lat, y_lon, filename):
        print('App get_tile_web', z_zoom, x_lat, y_lon)
        self.domain_rotation = (self.domain_rotation + 1) % 3
        domain_prefix = ['a', 'b', 'c'][self.domain_rotation]
        domain = domain_prefix + '.tile.openstreetmap.org'

        if not self.httpClient:
            self.httpClient = HttpClient(domain, 80)
        status, headers, body = await self.httpClient.send_request('GET', '/'+z_zoom+'/'+x_lat+'/'+y_lon+'.png')

        assert b'200' in status

        return body


class Empty(Exception):
	pass

class Deque:

	def __init__(self):
		self.front = 0
		self.rear = 0
		self.data = []

	def add_first(self, val):
		if self.front > self.rear:
			if self.rear == self.front-1:
				self.resize()
				self.front = len(self.data)-1
				self.data[self.front] = val
			else:
				self.front -= 1
				self.data[self.front] = val
		elif self.rear > self.front:
			if self.front == 0:
				self.resize()
				self.front = len(self.data)-1
				self.data[self.front] = val
			else:
				self.front -= 1
				self.data[self.front] = val
		else:
			self.data.append(val)
			if (len(self) == 2):
				self.front = 1
				self.rear = 0

	def add_last(self, val):
		if self.front > self.rear:
			if self.rear == self.front-1:
				self.resize()
				self.rear += 1
				self.data[self.rear] = val
			else:
				self.rear += 1
				self.data[self.rear] = val
		elif self.rear > self.front:
			if self.rear == len(self.data)-1:
				self.resize()
				self.rear += 1
				self.data[self.rear] = val
			else:
				self.rear += 1
				self.data[self.rear] = val
		else:
			self.data.append(val)
			if (len(self) == 2):
				self.rear = 1
				self.front = 0

	def delete_first(self):
		if self.is_empty():
			raise Empty("double ended queue is empty")
		number = self.data[self.front]
		self.data[self.front] = None
		self.front += 1
		if self.is_empty():
			self.front = 0
			self.rear = 0
			self.data = []
		return number

	def delete_last(self):
		if self.is_empty():
			raise Exception("double ended queue is empty")
		number = self.data[self.rear]
		self.data[self.rear] = None
		self.rear -= 1
		if self.is_empty():
			self.front = 0
			self.rear = 0
			self.data = []
		return number

	def resize(self):
		old_data = self.data[:]
		self.data = [None] * (len(self) * 2)
		if self.front > self.rear:
			first_half = old_data[self.front:]
			second_half = old_data[:self.rear+1]
			index = 0
			for elem in first_half:
				self.data[index] = elem
				index += 1
			for elem in second_half:
				self.data[index] = elem
				index += 1
			self.front = 0
			self.rear = len(old_data)-1
		elif self.rear > self.front:
			index = 0
			for elem in old_data:
				self.data[index] = elem
				index += 1
			self.front = 0
			self.rear = len(old_data)-1

	def __len__(self):
		count = 0
		for elem in self.data:
			if elem is not None:
				count += 1
		return count

	def __str__(self):
		return str(self.data)

	def is_empty(self):
		return len(self) == 0


import os#图片地址数据集转换为TensorFlow专用格式
import numpy as np
import tensorflow as tf
import cv2

def get_file(file_dir):
    images=[]
    temp=[]
    for root,sub_folders,files in os.walk(file_dir):
        '''
        os.walk(path)---返回的是一个三元组(root,dirs,files):
         root 所指的是当前正在遍历的这个文件夹的本身的地址
         dirs 是一个 list ，内容是该文件夹中所有的目录的名字(不包括子目录)
         files 同样是 list , 内容是该文件夹中所有的文件(不包括子目录)
         '''
        for name in files:
            images.append(os.path.join(root,name))
        for name in sub_folders:
            temp.append(os.path.join(root,name))
    labels=[]
    for one_folder in temp:
        n_img=len(os.listdir(one_folder)) #s.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表
        letter=one_folder.split('/')[-1] #split() 通过指定分隔符对字符串进行切片,默认为-1, 即分隔所有。
        if letter=='cat':
            labels=np.append(labels,n_img*[0])
        else:
            labels=np.append(labels,n_img*[1])

    temp=np.array([images,labels])
    temp=temp.transpose() #矩阵转置
    np.random.shuffle(temp) #随机排序

    images_list=list(temp[:,0])
    labels_list=list(temp[:,1])
    labels_list=[int(float(i)) for i in labels_list]
    return images_list,labels_list

def get_batch(image_list,label_list,img_width,img_height,batch_size,capacity):
    image=tf.cast(image_list,tf.string)
    label=tf.cast(label_list,tf.int32)

    input_queue=tf.train.slice_input_producer([image,label])

    label=input_queue[1]
    image_contents=tf.read_file(input_queue[0]) #通过图片地址读取图片
    image=tf.image.decode_jpeg(image_contents,channels=3) #解码图片成矩阵

    image=tf.image.resize_image_with_crop_or_pad(image,img_width,img_height)
    '''
    tf.image.resize_images 不能保证图像的纵横比,这样用来做抓取位姿的识别,可能受到影响
    tf.image.resize_image_with_crop_or_pad可让纵横比不变
    '''
    image=tf.image.per_image_standardization(image) #将图片标准化
    image_batch,label_batch=tf.train.batch([image,label],batch_size=batch_size,num_threads=64,capacity=capacity)
    '''
    tf.train.batch([example, label], batch_size=batch_size, capacity=capacity)：
    1.[example, label]表示样本和样本标签,这个可以是一个样本和一个样本标签
    2.batch_size是返回的一个batch样本集的样本个数
    3.num_threads是线程
    4.capacity是队列中的容量。
    '''
    label_batch=tf.reshape(label_batch,[batch_size])

    return image_batch,label_batch


from discord.ext import commands
import discord
from utils import offer_date_util
from helpers import programmes_helper
from services import offers_service

class OffersCommand(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    async def offers(self, ctx, programme_id: str = None, graph_type: str = None):
        if programme_id is not None:
            if programme_id not in programmes_helper.programmes or \
                    (graph_type is not None and graph_type != 'step'):
                raise commands.UserInputError

            await self.send_graph(ctx, programmes_helper.programmes[programme_id], graph_type == 'step')

            return

        async with self.bot.db_conn.acquire() as connection:
            offers_svc = offers_service.OffersService(connection)
            offers = await offers_svc.get_highest_ranks_with_offers()

        embed = discord.Embed(title="Highest known ranks with offers", color=0x36bee6)

        for offer in offers:
            programme = programmes_helper.programmes[offer[0]]
            rank = offer[1]
            date_str = offer_date_util.format_offer_date(offer[2])
            is_private = offer[3] is True

            embed.add_field(name=f'**{programme.icon} {programme.uni_name}\n{programme.display_name.ljust(33, " ")}**',
                            value=f'**{(("≈" + str(offers_service.round_rank(rank))) if is_private else str(rank))}**'
                                  f' on {date_str}',
                            inline=True)

        any_rounded = any(map(lambda x: x[3] is True, offers))

        embed.add_field(name='_This data has been provided by server members.' +
                             (' Some ranking numbers (as indicated '
                              'by **≈** in front of them) have been rounded to the nearest multiple of 5 '
                              'to help protect users\' privacy._' if any_rounded else '_'),
                        value='To view all commands, type `.help`\n'
                              'To add the date you\'ve received an offer, type '
                              f'`.setofferdate <day> <month> <{programmes_helper.get_ids_string()}>`',
                        inline=False)

        await ctx.send(embed=embed)

    @offers.error
    async def info_error(self, ctx, error):
        user = ctx.message.author
        if isinstance(error, commands.UserInputError):
            await ctx.send(user.mention + f' Invalid arguments. Usage: `.offers [{programmes_helper.get_ids_string()}] '
                                          f'[step]`')
        else:
            await ctx.send(user.mention + ' An unexpected error occurred')
            raise

    async def send_graph(self, ctx, programme: programmes_helper.Programme, step: bool):
        async with self.bot.db_conn.acquire() as connection:
            offers = offers_service.OffersService(connection)
            await offers.generate_graph(programme, step)
        image = discord.File(offers_service.filename)
        await ctx.send(file=image)

def setup(bot):
    bot.add_cog(OffersCommand(bot))


import turtle
turtle.bgcolor('purple')
a=turtle.Turtle()
a.pensize(6)
a.shape('circle')
a.left(90)
a.color('yellow')
a.forward(50)
a.left(90)
a.forward(25)
a.color('white')
a.left(90)
a.forward(50)
b=turtle.Turtle()
b.pensize(10)
b.shape('arrow')
b.color('green')
b.right(90)
b.forward(50)
b.left(90)
b.forward(25)
b.color('blue')
b.left(90)
b.forward(50)


import nltk
from nltk.probability import FreqDist
from nltk.tokenize import word_tokenize
import matplotlib.pyplot as plt
import numpy as np

def removeIsNotAlpha(s):
    words = nltk.word_tokenize(s)
    words=[word.lower() for word in words if word.isalpha()]
    return words

def content_fraction(text):
    stopwords = nltk.corpus.stopwords.words('english')
    content = [w for w in text if w.lower() not in stopwords]
    return content

def thongKeTop (text):
    fdist2 = FreqDist(text) #Thống kê số từ nhiều nhất
    dictOj = dict(fdist2)
    return dictOj

def sapXepDict (dictOj):
    sortedDictOj = sorted(dictOj.items(), key = lambda kv:(kv[1], kv[0]))
    return sortedDictOj

# sentence = 'This is an example sentence, that sentence is not an an an example sentence'
with open('bo_de_1.txt', encoding='utf-8') as f:
    lines = f.read()

sentenceIsAlpha = removeIsNotAlpha(lines)
# print(sentenceIsAlpha)

sent = content_fraction(sentenceIsAlpha)

# Chỉ lấy các danh từ
# Xem tất cả các pos tags: nltk.help.upenn_tagset()
pos_tag_token = nltk.pos_tag(sent)
list_pos_tag_token = []
for pos in pos_tag_token:
    if pos[1] == 'NN' or pos[1] == 'NNS' or pos[1] == 'NNP' or pos[1] == 'NNPS':
        list_pos_tag_token.append(pos[0])
    else:
        pass

dictionary = thongKeTop(list_pos_tag_token)
# print(f'Dictionary: {dictionary}')
dict1_cond = {k:v for (k,v) in dictionary.items() if v>2 if not k in {'a', 'b', 'c', 'd'}}

dict_for_airthmetic = dict1_cond.copy()
for key, value in dict_for_airthmetic.items():
    dict_for_airthmetic[key] = round(value / float(len(dict_for_airthmetic)) * 100, 2)
list_tu_vung = []
list_tan_xuat = []
list_so_lan = []
for key, value in dict_for_airthmetic.items():
    list_tu_vung.append(key)
    list_tan_xuat.append(value)
for key, value in dict1_cond.items():
    list_so_lan.append(value)
dic_for_export_csv = {}
dic_for_export_csv.update({'Tu_vung': list_tu_vung})
dic_for_export_csv.update({'So_lan': list_so_lan})
dic_for_export_csv.update({'Tan_so': list_tan_xuat})

from pandas import DataFrame
df = DataFrame(dic_for_export_csv, columns= ['Tu_vung', 'So_lan', 'Tan_so'])

export_csv = df.to_csv ('export_dataframe.csv', index = None, header=True) #Don't forget to add '.csv' at the end of the path

print (df)
print(f'\nDictionary: {dict1_cond}')

sortedDict = sapXepDict(dict1_cond)
print(f'\nDict after sorted: {sortedDict}')

listTuVungThongKeTangDan = []
for oj in sortedDict:
    listTuVungThongKeTangDan.append(oj[0])
print(f'\nTu vung thong ke tang dan: {listTuVungThongKeTangDan}')

# Bieu do
# len(sent)
# fdist1 = FreqDist(sent)
# fdist1.plot(3, cumulative=True)
# plt.show()

# import nltk

# s = "I can't do this now, because I'm so tired.  Please give me some time. @ sd  4 232"

# words = nltk.word_tokenize(s)

# words=[word.lower() for word in words if word.isalpha()]

# print(words)


from unittest import mock

from django.test import SimpleTestCase, TestCase

from django_perf_rec.db import AllDBRecorder, DBOp, DBRecorder
from tests.utils import disable_traceback, run_query

class DBOpTests(SimpleTestCase):
    def test_create(self):
        op = DBOp("myalias", "SELECT 1", None)
        assert op.alias == "myalias"
        assert op.query == "SELECT 1"
        assert op.traceback is None

    def test_equal(self):
        assert DBOp("foo", "bar", "traceback") == DBOp("foo", "bar", "traceback")

    def test_not_equal_alias(self):
        assert DBOp("foo", "bar", None) != DBOp("baz", "bar", None)

    def test_not_equal_sql(self):
        assert DBOp("foo", "bar", None) != DBOp("foo", "baz", None)

    def test_not_equal_traceback(self):
        assert DBOp("foo", "bar", "traceback") != DBOp("foo", "baz", None)

class DBRecorderTests(TestCase):
    databases = ("default", "second", "replica")

    @disable_traceback
    def test_default(self, extract_stack):
        callback = mock.Mock()
        with DBRecorder("default", callback):
            run_query("default", "SELECT 1")
        callback.assert_called_once_with(DBOp("default", "SELECT #", None))

    @disable_traceback
    def test_secondary(self, extract_stack):
        callback = mock.Mock()
        with DBRecorder("second", callback):
            run_query("second", "SELECT 1")
        callback.assert_called_once_with(DBOp("second", "SELECT #", None))

    @disable_traceback
    def test_replica(self, extract_stack):
        callback = mock.Mock()
        with DBRecorder("replica", callback):
            run_query("replica", "SELECT 1")
        callback.assert_called_once_with(DBOp("replica", "SELECT #", None))

    def test_secondary_default_not_recorded(self):
        callback = mock.Mock()
        with DBRecorder("second", callback):
            run_query("default", "SELECT 1")
        assert len(callback.mock_calls) == 0

    def test_record_traceback(self):
        callback = mock.Mock()
        with DBRecorder("default", callback):
            run_query("default", "SELECT 1")

        assert len(callback.mock_calls) == 1
        assert "django_perf_rec/db.py" in str(
            callback.call_args_list[0][0][0].traceback
        )

class AllDBRecorderTests(TestCase):
    databases = ("default", "second", "replica")

    @disable_traceback
    def test_records_all(self, extract_stack):
        callback = mock.Mock()
        with AllDBRecorder(callback):
            run_query("replica", "SELECT 1")
            run_query("default", "SELECT 2")
            run_query("second", "SELECT 3")

        assert callback.mock_calls == [
            mock.call(DBOp("replica", "SELECT #", None)),
            mock.call(DBOp("default", "SELECT #", None)),
            mock.call(DBOp("second", "SELECT #", None)),
        ]


# -*- coding: utf-8 -*-
from twisted.plugin import IPlugin
from heufybot.moduleinterface import IBotModule
from heufybot.modules.commandinterface import BotCommand
from heufybot.utils.timeutils import now, timestamp
from zope.interface import implements

class WeatherUndergroundCommand(BotCommand):
    implements(IPlugin, IBotModule)

    name = "WeatherUnderground"
    weatherBaseURL = "http://api.wunderground.com/api"

    def triggers(self):
        return ["astronomy", "forecast", "walert", "weather"]

    def load(self):
        self.help = "Commands: weather/forecast/astronomy/walert <lat> <lon>, weather/forecast/astronomy/walert " \
                    "<place>, weather/forecast/astronomy/walert <nickname>, | Get the current weather conditions, " \
                    "forecast, astronomy or weather alerts for the given latlon, place or user."
        self.commandHelp = {
            "astronomy": "astronomy <lat> <lon>, astronomy <place>, astronomy <nickname> | Get moon phase, sunrise and " \
                         "sunset times for the given latlon, place or user.",
            "forecast": "forecast <lat> <lon>, forecast <place>, forecast <nickname> | Get the forecast for the given " \
                        "latlon, place or user.",
            "walert": "walert <lat> <lon>, walert <place>, walert <nickname> | Get the weather alerts for the given " \
                      "latlon, place or user.",
            "weather": "weather <lat> <lon>, weather <place>, weather <nickname> | Get the current weather condidions " \
                       "for the given latlon, place or user."
        }
        self.apiKey = None
        if "wunderground" in self.bot.storage["api-keys"]:
            self.apiKey = self.bot.storage["api-keys"]["wunderground"]

    def execute(self, server, source, command, params, data):
        if not self.apiKey:
            self.replyPRIVMSG(server, source, "No API key found.")
            return

        # Use the user's nickname as a parameter if none were given
        if len(params) == 0:
            params.append(data["user"].nick)
            selfSearch = True
        else:
            selfSearch = False

        # Try using latlon to get the location
        try:
            lat = float(params[0])
            lon = float(params[1])
            location = self.bot.moduleHandler.runActionUntilValue("geolocation-latlon", lat, lon)
            if not location:
                self.replyPRIVMSG(server, source, "I can't determine locations at the moment. Try again later.")
                return
            if not location["success"]:
                self.replyPRIVMSG(server, source, "I don't think that's even a location in this multiverse...")
                return
            self._handleCommandWithLocation(server, source, _getFeature(command), location)
            return
        except (IndexError, ValueError):
            pass  # The user did not give a latlon, so continue using other methods

        # Try to determine the user's location from a nickname
        if self.bot.config.serverItemWithDefault(server, "use_userlocation", False):
            userLoc = self.bot.moduleHandler.runActionUntilValue("userlocation", server, source, params[0], selfSearch)
            if selfSearch:
                if not userLoc:
                    return
                elif not userLoc["success"]:
                    return
            if userLoc and userLoc["success"]:
                if "lat" in userLoc:
                    location = self.bot.moduleHandler.runActionUntilValue("geolocation-latlon", userLoc["lat"],
                                                                          userLoc["lon"])
                else:
                    location = self.bot.moduleHandler.runActionUntilValue("geolocation-place", userLoc["place"])
                if not location:
                    self.replyPRIVMSG(server, source, "I can't determine locations at the moment. Try again later.")
                    return
                if not location["success"]:
                    self.replyPRIVMSG(server, source, "I don't think that's even a location in this multiverse...")
                    return
                self._handleCommandWithLocation(server, source, _getFeature(command), location)
                return

        # Try to determine the location by the name of the place
        place = " ".join(params)
        if place.startswith("pws:") and command in ["weather", "forecast"]:
            place = place[4:]
            location = { "success": True, "pws": place, "locality": "Weather Station {}".format(place) }
        else:
            location = self.bot.moduleHandler.runActionUntilValue("geolocation-place", place)
        if not location:
            self.replyPRIVMSG(server, source, "I can't determine locations at the moment. Try again later.")
            return
        if not location["success"]:
            self.replyPRIVMSG(server, source, "I don't think that's even a location in this multiverse...")
            return
        self._handleCommandWithLocation(server, source, _getFeature(command), location)

    def _handleCommandWithLocation(self, server, source, command, location):
        apiFunction = "conditions" if command == "weather" else command
        if "pws" in location:
            url = "{}/{}/{}/q/pws:{}.json".format(self.weatherBaseURL, self.apiKey, apiFunction, location["pws"])
        else:
            url = "{}/{}/{}/q/{},{}.json".format(self.weatherBaseURL, self.apiKey, apiFunction, location["latitude"],
                                             location["longitude"])
        result = self.bot.moduleHandler.runActionUntilValue("fetch-url", url)
        output = None
        if not result:
            output = "No weather for this location could be found at this moment. Try again later."
        else:
            j = result.json()
            if "error" in j["response"]:
                output = "The Weather Underground API returned an error of type {}.".format(
                         j["response"]["error"]["type"])
            else:
                if command == "weather":
                    output = _parseWeather(j)
                elif command == "forecast":
                    output = _parseForecast(j)
                elif command == "astronomy":
                    output = _parseAstronomy(j)
                elif command == "alerts":
                    output = self._parseAlert(j)
        self.replyPRIVMSG(server, source, "Location: {} | {}".format(location["locality"], output))

    def _parseAlert(self, json):
        alerts = json["alerts"]
        if len(alerts) == 0:
            return "No weather alerts were found."
        if "wtype_meteoalarm_name" in alerts[0]:
            alertType = alerts[0]["wtype_meteoalarm_name"]
        elif "description" in alerts[0]:
            alertType = alerts[0]["description"]
        elif "type" in alerts[0]:
            alertType = alerts[0]["type"]
        else:
            alertType = "Unknown"
        if "level_meteoalarm_name" in alerts[0]:
            level = alerts[0]["level_meteoalarm_name"]
        else:
            level = "None"
        description = alerts[0]["message"].encode("utf-8", "ignore").replace("\n", " ")
        if description.endswith(">)"):
            description = description[:-2]  # Strip WUnderground weirdness.
        if len(description) > 275:
            result = self.bot.moduleHandler.runActionUntilValue("post-paste", "Weather alert", description, 10)
            if result:
                description = "{}... {}".format(description[:250], result)
        return "Type: {} | Level: {} | {}".format(alertType, level, description)

def _parseWeather(json):
    if "current_observation" not in json:
        return "No weather for this location could be found at this moment. Try again later."

    cond = json["current_observation"]
    tempC = cond["temp_c"]
    tempF = cond["temp_f"]
    feelslikeC = cond["feelslike_c"]
    feelslikeF = cond["feelslike_f"]
    description = cond["weather"]
    humidity = cond["relative_humidity"]
    winddir = cond["wind_dir"]
    windspeedMiles = cond["wind_mph"]
    windspeedMs = round(cond["wind_kph"] / 3.6, 1)
    stationID = cond["station_id"]
    feelslikeStr = ""
    if abs(float(tempC) - float(feelslikeC)) > 3.0:
        feelslikeStr = "(feels like {}°C / {}°F) ".format(feelslikeC, feelslikeF)

    if len(cond["estimated"]) > 0:
        latestUpdateStr = cond["estimated"]["description"]
    else:
        latestUpdate = (timestamp(now()) - int(cond["observation_epoch"])) / 60
        latestUpdateStr = "Latest Update: {}".format("{} minute(s) ago".format(latestUpdate) if latestUpdate > 0 \
                                                         else "just now")

    return "Temp: {}°C / {}°F {}| Weather: {} | Humidity: {} | Wind Speed: {} m/s / {} mph | " \
            "Wind Direction: {} | Station ID: {} | {}.".format(tempC, tempF, feelslikeStr, description, humidity,
                                                               windspeedMs,  windspeedMiles, winddir, stationID,
                                                               latestUpdateStr)

def _parseForecast(json):
    if "forecast" not in json:
        return "No forecast for this location could be found at this moment. Try again later."

    daysList = json["forecast"]["simpleforecast"]["forecastday"]
    formattedDays = []
    for x in range(0, len(daysList)):
        day = daysList[x]
        date = day["date"]["weekday"]
        minC = day["low"]["celsius"]
        minF = day["low"]["fahrenheit"]
        maxC = day["high"]["celsius"]
        maxF = day["high"]["fahrenheit"]
        description = day["conditions"]
        formattedDays.append("{}: {} - {}°C, {} - {}°F, {}".format(date, minC, maxC, minF, maxF, description))
    return " | ".join(formattedDays)

def _parseAstronomy(json):
    astr = json["moon_phase"]
    phase = astr["phaseofMoon"]
    sunrise = _getTimeString(astr["sunrise"]["hour"], astr["sunrise"]["minute"])
    sunset = _getTimeString(astr["sunset"]["hour"], astr["sunset"]["minute"])
    moonrise = _getTimeString(astr["moonrise"]["hour"], astr["moonrise"]["minute"])
    moonset = _getTimeString(astr["moonset"]["hour"], astr["moonset"]["minute"])

    return "Tonight's Moon Phase: {} | Sunrise: {}, Sunset: {} | Moonrise: {}, Moonset: {}".format(phase, sunrise,
                                                                                sunset, moonrise,
                                                                                moonset)

def _getTimeString(hours, minutes):
    try:
        hours = int(hours)
        hour24 = "{}:{}".format(hours, minutes)
        hour12 = "{}:{} {}".format(hours if hours < 13 else hours - 12, minutes, "AM" if hours < 13 else "PM")
        return "{} ({})".format(hour24, hour12)
    except ValueError:
        return "Unknown"

def _getFeature(command):
    if command == "walert":
        return "alerts"
    return command

weatherUndergroundCommand = WeatherUndergroundCommand()


from helpers import *
import operator
from itertools import combinations

def detect_signs(img, feature_extractor, full_model,
				 classifier, winW, winH, stride):
	'''Applies sliding window of size (winW, winH) over image to
	   detect and classify traffic signs.
	   Returns the image with labeled bounding boxes, total number of windows
	   and the coordinates of the detected signs along with their class index.
	'''
	rects = []
	font = cv2.FONT_HERSHEY_DUPLEX
	ctr = 0
	#create a copy of the image. (bounding boxes may interfere with detection)
	imgShow = np.array(img, copy=True)

	for y,x,image in sliding_window(img, stride, (winW, winH)):
		ctr += 1
		#perform required transformations and pass it to the cnn
		#to extract conv featuress
		features = pass_pipeline(image, feature_extractor)
		if image.shape[0] != image.shape[1]:
			continue
		#if the svm predicts a sign, threshold on the neural network
		#probability and add the detection to the rectangles list
		if classifier.predict(features) == 1:
			processed_img = process_image(image)
			probability_dist = full_model.predict(processed_img)[0]
			probability_dict = {x:y for x,y in enumerate(probability_dist)}
			if max(probability_dict.values()) < 0.8:
				continue
			predicted_class = max(probability_dict.items(), key=operator.itemgetter(1))[0]
			rects.append((x, y, x+winW, x+winH, predicted_class))

	#remove overlapping rectangles
	for r1, r2 in combinations(rects, 2):
		#if they have different classes, skip
		if r1[4]!=r2[4]:
			continue
		#if they have been already removed, skip
		if r1 not in rects or r2 not in rects:
			continue
		#if no overlap, skip
		if r1[0] > r2[0]+winW or r1[0]+winW < r2[0] or r1[1]+winH < r2[1] or r1[1] > r2[1]+winH:
			continue
		#remove overlapping rectangles and add the one
		#that results from merging them
		if r1 in rects:
			rects.remove(r1)
		if r2 in rects:
			rects.remove(r2)
		rects.append((min(r1[0], r2[0]), min(r1[1],r2[1]),
					  max(r1[2], r2[2]), max(r1[3],r2[3]),
					  r1[4]))
	#draw bounding boxes and add text
	for elem in rects:
		cv2.rectangle(imgShow, (elem[0],elem[1]), (elem[0]+winH, elem[1]+winW), (0,255,0), 3)
		cv2.putText(imgShow, sign_dict[elem[4]], (elem[0], elem[1]), font, 1, (0, 255, 0), 2, cv2.LINE_AA)
	return imgShow, ctr, rects

if __name__ == "__main__":
	clf = joblib.load('SVC8e-1.pkl')
	extractor = build_feature_extractor('best_model_acc_98_1.h5')
	fullmodel = load_model('best_model_acc_98_1.h5')

	img1 = plt.imread('00005.ppm')
	img2 = plt.imread('00006.ppm')
	img3 = plt.imread('00628.ppm')
	img4 = plt.imread('00871.ppm')

	imgShow, ctr, rects = detect_signs(img1, feature_extractor=extractor, full_model=fullmodel, classifier=clf,
			 			 winW=180, winH=180, stride=64)
	print('Total windows=', ctr)
	print('Total signs detected=', rects)
	plt.imshow(imgShow)
	plt.show()

	imgShow, ctr, rects = detect_signs(img2, feature_extractor=extractor, full_model=fullmodel, classifier=clf,
			 			 winW=110, winH=110, stride=64)
	print('Total windows=', ctr)
	print('Total signs detected=', rects)
	plt.imshow(imgShow)
	plt.show()

	imgShow, ctr, rects = detect_signs(img3, feature_extractor=extractor, full_model=fullmodel, classifier=clf,
			 			 winW=100, winH=100, stride=40)
	print('Total windows=', ctr)
	print('Total signs detected=', rects)
	plt.imshow(imgShow)
	plt.show()

	imgShow, ctr, rects = detect_signs(img4, feature_extractor=extractor, full_model=fullmodel, classifier=clf,
			 			 winW=48, winH=48, stride=16)
	print('Total windows=', ctr)
	print('Total signs detected=', rects)
	plt.imshow(imgShow)
	plt.show()


'''
Немного инфы:
-все пикчи кроме котов (requests + catapi), берутся из текстовых файлов с ссылками
-все бугурты - это тупо спарсенные записи со стены ВК, хранятся как словарь, подгружаем его через Pickle и выдергиваем любую инфу из записей (что можно выдергивать смотрите в документации VK API)
-Сделано спешол для https://vk.com/bugurt_thread и его канала на Discord'е
-Для запуска Бота нужен только токен, получить который можно на сайте дискорда в разделе разработчика, не забудте указать, что создаваемое приложение  - это будущий бот, а не простой аккаунт пользователя, полученный токен подставить в последнюю строку client.run()

TO DO LIST:
Статистика
Отсев пустых или слишком длинных сообщений (реклама/репосты/длиннобугурты)
Ограничение на кол-во принимаемых команд / очередь
Возможность отправки анонимок
Привелегии админам канала (например: навремя выключать бота)

P.S @kitsune#8767 зануда
'''
# -*- coding: utf-8 -*-
import pickle
import random
from random import randrange
from random import randint
import discord
import asyncio
import requests
from discord.ext import commands
description = '''Бот Согревающий'''
bot = commands.Bot(command_prefix='!', description=description)
client = discord.Client()
#Ссылки на пикчи были получены с помощью VKOpt
pepe_list = []
peka_list = []
anime_list = []
pony_list = []
with open('./data/pepe.txt') as pepe:
    pepe_list = pepe.read().splitlines()
    pepe.close()
with open('./data/anime.txt') as anime:
    anime_list = anime.read().splitlines()
    anime.close()
with open('./data/pony.txt') as pony:
    pony_list = pony.read().splitlines()
    pony.close()
with open('./data/peka.txt') as peka:
    peka_list = peka.read().splitlines()
    peka.close()
#Дамп стенки ВК из файла wall.pickle, обновить который можно через vk_wall_dump.py
with open('./data/wall.pickle', 'rb') as f:
    wall = pickle.load(f)
#Chat commands
@client.event
async def on_message(message):
    if message.author == client.user:
        return
    #!help
    if message.content.startswith('!help') or message.content.startswith('!помощь'):
        msg = ('{0.author.mention}\nКомманды которые понимает БугуртоБот:\n!bugurt, !bt, !бт - рандомный бугурт с паблоса ВК\n!cat, !кот - пикча с рандомным котом\n!a, !anime - рандомная онимэ пикча\n!pepe - лягух пепе\n!peka - рандомный пека на каждый день\n!mlp, !pony - цветные лошадки\nСпешол фор https://vk.com/bugurt_thread').format(message)
        await client.send_message(message.channel, msg)
    #!bt
    elif message.content.startswith('!bugurt') or message.content.startswith('!бугурт') or message.content.startswith('!бт') or message.content.startswith('!bt'):
        count = wall['count']
        count = int(count)
        post_id = randint(0,count)
        if wall['items']:
            bugurt = wall['items'][post_id]['text']
            likes_count = wall['items'][post_id]['likes']['count']
            if 'attachments' in wall['items'][post_id]:
                if 'photo' in wall['items'][post_id]['attachments'][0]:
                    photo = wall['items'][post_id]['attachments'][0]['photo']
                    photo_link = photo[sorted([x for x in photo.keys() if 'photo' in x], key=lambda x: int(x.split('_')[1]))[-1]]
                    msg = ('{0.author.mention}\n' + str(bugurt) + '\n' + '\nКол-во лайков у бугурта: ' + str(likes_count) + '\n' + str(photo_link)).format(message)
            else:
                msg = ('{0.author.mention}\n' + str(bugurt) + '\n' + '\nКол-во лайков у бугурта: ' + str(likes_count)).format(message)
            await client.send_message(message.channel, msg)
    #!cat
    elif message.content.startswith('!cat') or message.content.startswith('!кот') or message.content.startswith('!блохастый') or message.content.startswith('!котяйка') or message.content.startswith('!пушистый'):
        r = requests.get('http://thecatapi.com/api/images/get?format=src')
        msg = ('{0.author.mention}\n '+ r.url).format(message)
        await client.send_message(message.channel, msg)
    #!anime
    elif message.content.startswith('!anime') or message.content.startswith('!a') or message.content.startswith('!а'):
        img_link = random.choice(anime_list)
        msg = ('{0.author.mention}\n '+ img_link).format(message)
        await client.send_message(message.channel, msg)
    #!pepe
    elif message.content.startswith('!pepe') or message.content.startswith('!пепе') or message.content.startswith('!лягух'):
        img_link = random.choice(pepe_list)
        msg = ('{0.author.mention}\n '+ img_link).format(message)
        await client.send_message(message.channel, msg)
    #!peka
    elif message.content.startswith('!peka') or message.content.startswith('!пека') or message.content.startswith('!йоба'):
        img_link = random.choice(peka_list)
        msg = ('{0.author.mention}\n '+ img_link).format(message)
        await client.send_message(message.channel, msg)
    #!pony
    elif message.content.startswith('!pony') or message.content.startswith('!mlp') or message.content.startswith('!лошадка') or message.content.startswith('!кони') or message.content.startswith('!пони')or message.content.startswith('!млп'):
        img_link = random.choice(pony_list)
        msg = ('{0.author.mention}\n '+ img_link).format(message)
        await client.send_message(message.channel, msg)
    #!cp ^_^
    elif message.content.startswith('!цп') or message.content.startswith('!cp') or message.content.startswith('!цопэ'):
        msg = ('{0.author.mention}\n '+ 'https://www.youtube.com/watch?v=dQw4w9WgXcQ').format(message)
        await client.send_message(message.channel, msg)
    #!creator
    elif message.content.startswith('!creator') or message.content.startswith('!создатель'):
        msg = ('{0.author.mention}\n '+ 'https://media.giphy.com/media/o0vwzuFwCGAFO/giphy.gif\nБота запилил Hinex - https://vk.com/protector').format(message)
        await client.send_message(message.channel, msg)
#Приветствие пользователей при заходе на сервер
@client.event
async def on_member_join(member):
    server = member.server
    fmt = 'Wake Up, {0.mention}!'
    await client.send_message(server, fmt.format(member, server))

'''/////////////////////////////////////////////////////////////////'''
@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')
#Тут нужен ваш токен
client.run('')