# $Id: batch.py,v 1.63 2013/02/15 19:15:41 samn Exp $

# execfile("runone.py") # loads sim

import sys
import os
import numpy
# from modindex import *
import multiprocessing
# from Queue import Queue
from conf import writeconf

# from IPython.core.debugger import Tracer
# debug_here = Tracer()

# if __name__ != "__main__":
#   from neuron import h
#   from network import net
#   execfile("run.py")
#   #from run import loadminrundat

liseed = [1234] # ,6912,9876,6789,3219,5936]
lwseed = [4321] # ,5012,9281,8130,6143,7131]

def appline (s,fn):
  fp = open(fn,"a")
  fp.write(s)
  fp.write("\n")
  fp.close()

batchf = "mybatch.sh"
def mycomm (s, fn=batchf):
  appline(s,fn)

def mylog(s,fn="OLMbatchLong_13aug5B.log"):
  appline(s,fn)

# runs batch modulating strength of NMDA synapses at OLM cells
# loops & calls ntebatchrun.py to run the sim/save data
def ntebatch(nlevels,startnum=0):
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for i1,r1 in enumerate(x):
                #net.olm.set_r("somaNMDA",r1)
                if y < startnum:
                    print ("skipping sim num ", y)
                    y += 1
                    continue
                s = "./mod/x86_64/special -python ntebatchrun.py"
                s += " "+str(iseed)+" "+str(wseed)+" "+str(r1)
                print ("sim num = ", y, ", command = ", s)
                y += 1
                mylog(s)
                os.system(s)

# load info about batch run into an NQS. returns the NQS
def ntebatchnq(nlevels=5):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","OLMr")
    nq.strdec("simstr")
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for i1,r1 in enumerate(x):
                simstr = "11may20.05_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                simstr += "_OLMr_"+str(r1)
                nq.append(y,simstr,iseed,wseed,r1)
                y += 1
    return nq

# runs batch modulating strength of NMDA synapses at different cell types/locations
# loops & calls nmbatchrun.py to run the sim/save data
def nmbatch(nlevels,startnum=0):
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for i1,r1 in enumerate(x):
                #net.olm.set_r("somaNMDA",r1)
                for i2, r2 in enumerate(x):
                    #net.bas.set_r("somaNMDA",r2)
                    for i3, r3 in enumerate(x):
                        #net.pyr.set_r("BdendNMDA",r3)
                        for i4, r4 in enumerate(x):
                            if y < startnum:
                                print ("skipping sim num ", y)
                                y += 1
                                continue
                            s = "./mod/x86_64/special -python nmbatchrun.py"
                            s += " "+str(iseed)+" "+str(wseed)+" "+str(r1)+" "+str(r2)+" "+str(r3)+" "+str(r4)
                            print ("sim num = ", y, ", command = ", s)
                            y += 1
                            mylog(s)
                            os.system(s)
                            #net.pyr.set_r("Adend3NMDA",r4)

# runs batch modulating level of Ih conductance at PYR,BAS cells together - maintaining OLM Ih conductance
# loops & calls ihbatchrun.py to run the sim/save data
def longihbatchPYRBAS (nlevels,startnum=0,qsz=25):
    procs = []
    q = Queue(qsz)
    x,y = numpy.linspace(0,2,nlevels), 0
    iseed, wseed = liseed[0], lwseed[0]

    def myworker (scomm,num):
        os.system(scomm) #worker function, invoked in a process.

    for ih1 in x:
        for ih2 in x:
            if y < startnum:
                print ("skipping sim num ", y)
                y += 1
                continue
            s = "./mod/x86_64/special -python ihbatchrun.py"
            s += " "+str(iseed)+" "+str(wseed)+" "+str(ih1)+" "+str(ih2)+" "+str(1.0)+" 1.0"
            p = multiprocessing.Process(target=myworker,args=(s,2))
            procs.append(p)
            q.put(p,True) # put proc on q and wait for free slot
            print ("sim num = ", y, ", command = ", s)
            mylog(s)
            p.start() # maybe have to put this before placing on q
            y += 1

    for p in procs: p.join() # Wait for all worker processes to finish

# runs batch modulating level of Ih conductance at OLM cells - maintaining PYR,BAS Ih conductance
# loops & calls ihbatchrun.py to run the sim/save data
def longihbatchOLM (nlevels,startnum=0,qsz=11):
  procs = []
  q = Queue(qsz)
  x,y = numpy.linspace(0,2,nlevels), 0
  iseed, wseed = liseed[0], lwseed[0]

  def myworker (scomm,num):
    os.system(scomm) #worker function, invoked in a process.

  for ih1 in x:
    if y < startnum:
      print ("skipping sim num ", y)
      y += 1
      continue
    s = "./mod/x86_64/special -python ihbatchrun.py"
    s += " "+str(iseed)+" "+str(wseed)+" "+str(1.0)+" "+str(1.0)+" "+str(ih1)+" 1.0"
    p = multiprocessing.Process(target=myworker,args=(s,2))
    procs.append(p)
    q.put(p,True) # put proc on q and wait for free slot
    print ("sim num = ", y, ", command = ", s)
    mylog(s)
    p.start() # maybe have to put this before placing on q
    y += 1

  for p in procs: p.join() # Wait for all worker processes to finish

#
def getihsimstr (iseed,wseed,ihpyr,ihbas,iholm):
  simstr = "12nov09.09_iseed_"+str(iseed)+"_wseed_"+str(wseed)
  simstr += "_ihpyr_"+str(ihpyr)+"_ihbas_"+str(ihbas)+"_iholm_"+str(iholm)
  return simstr

# return an NQS with concatenated vectors from longihbatcPYRBAS run
# only loads data <= savenums
def longihbatchPYRBASNQ (nlevels,savenums):
    x,y = numpy.linspace(0,2,nlevels), 0
    iseed, wseed = liseed[0], lwseed[0]
    nq = h.NQS("id","simstr","iseed","wseed","ihpyr","ihbas","iholm","vlfp")
    nq.strdec("simstr")
    nq.odec("lfp")
    for ih1 in x:
        for ih2 in x:
            simstr = getihsimstr(iseed,wseed,ih1,ih2,1.0)
            fbase = "./data/lfp/" + simstr + "_"
            vlfp = catlfp(fbase,savenums)
            nq.append(y,simstr,iseed,wseed,ih1,ih2,1.0,vlfp)
            y += 1
    return nq

# runs batch modulating level of Ih conductance at PYR,BAS cells together - maintaining OLM Ih conductance
# loops & calls ihbatchrun.py to run the sim/save data
def ihbatchPYRBAS (nlevels,startnum=0):
    x = numpy.linspace(0,2,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for r1 in x:
                for r2 in x:
                    if r1 == 1.0 and r2 == 1.0:
                        continue # already ran all at baseline
                    elif r1 != r2:
                        continue # only running where they're equal
                    else:
                        xl = [[r1, r2, 1.0]]
                    #elif r1 == r2:
                    #    continue # already ran same values of r1,r2
                    for xll in xl:
                        if y < startnum:
                            print ("skipping sim num ", y)
                            y += 1
                            continue
                        s = "./mod/x86_64/special -python ihbatchrun.py"
                        s += " "+str(iseed)+" "+str(wseed)+" "+str(xll[0])+" "+str(xll[1])+" "+str(xll[2])
                        print ("sim num = ", y, ", command = ", s)
                        y += 1
                        mylog(s)
                        os.system(s)
                        # mycomm(s)

# load info about batch run into an NQS. returns the NQS
def ihbatchPYRBASnq (nlevels):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","ihpyr","ihbas","iholm")
    nq.strdec("simstr")
    x = numpy.linspace(0,2,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for r1 in x:
                for r2 in x:
                    if r1 == 1.0 and r2 == 1.0:
                        continue # already ran all at baseline
                    else:
                        xl = [[r1, r2, 1.0]]
                    for xll in xl:
                        simstr = "12nov09.09_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                        simstr += "_ihpyr_"+str(xll[0])+"_ihbas_"+str(xll[1])+"_iholm_"+str(xll[2])
                        nq.append(y,simstr,iseed,wseed,xll[0],xll[1],xll[2])
                        y += 1
    return nq

# runs batch modulating level of ih conductance
# loops & calls ihbatchrun.py to run the sim/save data
def ihbatch (nlevels,startnum=0):
  x = numpy.linspace(0,2,nlevels)
  y = 0
  for iseed in liseed:
    for wseed in lwseed:
      for r1 in x:
        if r1 == 1.0:
          xl = [[1.0, 1.0, 1.0]] # skip dups
        else:
          xl = [[r1, r1, r1], [r1, 1.0, 1.0], [1.0, r1, 1.0], [1.0, 1.0, r1] ]
        for xll in xl:
          if y < startnum:
            print ("skipping sim num ", y)
            y += 1
            continue
          s = "./mod/x86_64/special -python ihbatchrun.py"
          s += " "+str(iseed)+" "+str(wseed)+" "+str(xll[0])+" "+str(xll[1])+" "+str(xll[2])
          print ("sim num = ", y, ", command = ", s)
          y += 1
          mylog(s)
          os.system(s)

# load info about batch run into an NQS. returns the NQS
def ihbatchnq(nlevels):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","ihpyr","ihbas","iholm")
    nq.strdec("simstr")
    x = numpy.linspace(0,2,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for r1 in x:
                if r1 == 1.0:
                    xl = [[1.0, 1.0, 1.0]] # skip dups
                else:
                    xl = [[r1, r1, r1], [r1, 1.0, 1.0], [1.0, r1, 1.0], [1.0, 1.0, r1] ]
                for xll in xl:
                    simstr = "12nov09.09_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                    simstr += "_ihpyr_"+str(xll[0])+"_ihbas_"+str(xll[1])+"_iholm_"+str(xll[2])
                    nq.append(y,simstr,iseed,wseed,xll[0],xll[1],xll[2])
                    y += 1
    return nq

# load info about batch run into an NQS. returns the NQS (batch from 13aug1)
def newihbatchnq (nlevels):
  nq = h.NQS("id","simstr","iseed","wseed","ihpyr","ihbas","iholm")
  nq.strdec("simstr")
  x = numpy.linspace(0,2,nlevels)
  y = 0
  liseed = [1234]; lwseed = [4321];
  for iseed in liseed:
    for wseed in lwseed:
      for r1 in x:
        if r1 == 1.0:
          xl = [[1.0, 1.0, 1.0]] # skip dups
        else:
          xl = [[r1, r1, r1], [r1, 1.0, 1.0], [1.0, r1, 1.0], [1.0, 1.0, r1] ]
        for xll in xl:
          simstr = "13aug1_iseed_"+str(iseed)+"_wseed_"+str(wseed)
          simstr += "_ihpyr_"+str(xll[0])+"_ihbas_"+str(xll[1])+"_iholm_"+str(xll[2])
          nq.append(y,simstr,iseed,wseed,xll[0],xll[1],xll[2])
          y += 1
      for r1 in x:
        for r2 in x:
          if r1 == 1.0 and r2 == 1.0:
            continue # already ran all at baseline
          elif r1 != r2:
            continue
          else:
            xl = [[r1, r2, 1.0]]
            for xll in xl:
              simstr = "13aug1_iseed_"+str(iseed)+"_wseed_"+str(wseed)
              simstr += "_ihpyr_"+str(xll[0])+"_ihbas_"+str(xll[1])+"_iholm_"+str(xll[2])
              nq.append(y,simstr,iseed,wseed,xll[0],xll[1],xll[2])
              y += 1
  return nq

# load info about batch run into an NQS. returns the NQS
def nmbatchnq(nlevels):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","OLMr","BASr","PYRBr","PYRAr")
    nq.strdec("simstr")
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for i1,r1 in enumerate(x):
                for i2, r2 in enumerate(x):
                    for i3, r3 in enumerate(x):
                        for i4, r4 in enumerate(x):
                            simstr = "11jun22.02_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                            simstr += "_OLMr_"+str(r1)+"_BASr_"+str(r2)+"_PYRBr_"+str(r3)+"_PYRAr_"+str(r4)
                            nq.append(y,simstr,iseed,wseed,r1,r2,r3,r4)
                            y += 1
    return nq

def testit ():
#    global h,net,loadminrundat
#    from neuron import h
#    from network import net
#    from run import loadminrundat
    print (h,net,loadminrundat)

# get cross-frequency coupling arrays  - vlfp is a vector
def getcfc (vlfp):
  v1 = h.Vector()
  v1.copy(vlfp) # (vlfp,nsamp,vlfp.size()-1-nsamp)
  v1.sub(v1.mean())
  sampr = 1e3 / h.dt
  from_t = 1
  to_t = int( vlfp.size() / sampr - 1 )
  phaseFreq,ampFreq,modArr = varModIndArr(v1, sampr, from_t, to_t, 4, 12, 25, 55, 1 , 1, 1)
  return phaseFreq, ampFreq, modArr

# run CFC analysis on LFPs in nqb - save output to text files
def addCFCcol (nqb,datadir="./data/"):
    global h
    nqb.tog("DB")
    if nqb.fi("fcfc") == -1:
        nqb.resize("fcfc")
        nqb.strdec("fcfc")
        nqb.pad()
    for i in range(int(nqb.v[0].size())):
        print ("up to " + str(i) + " out of " + str(nqb.v[0].size()))
        simstr = nqb.get("simstr",i).s
        fcfc = "./data/cfc/" + simstr + "_cfc.txt"
        if os.path.exists(fcfc):
            print ("skipping ", fcfc, " already done.")
            nqb.set("fcfc",i,fcfc)
            continue
        loadminrundat(simstr,datadir)
        phaseFreq, ampFreq, modArr = getcfc(net.vlfp)
        if i == 0:
            numpy.savetxt("./data/cfc/phaseFreq.txt",phaseFreq)
            numpy.savetxt("./data/cfc/ampFreq.txt",ampFreq)
        numpy.savetxt(fcfc,modArr)
        nqb.set("fcfc",i,fcfc)

# add a column to nqb with power spectra from h.matpmtm.
# skipms is milliseconds of signal to skip from beginning and end of LFP
# ty determines method to use for calculating power spectrum
def addnqpcol(nqb,skipms=200,ty=0,datadir="./data/"):
    global h
    nqb.tog("DB")
    if nqb.fi("nqp") == -1:
        nqb.resize("nqp")
        nqb.odec("nqp")
        nqb.pad()
    hasvlfp = False
    if nqb.fi("vlfp") != -1: hasvlfp = True
    v1=h.Vector()
    nsamp = skipms / h.dt # number of samples to skip from start,end
    for i in range(int(nqb.v[0].size())):
        print ("up to " + str(i) + " out of " + str(nqb.v[0].size()))
        if hasvlfp:
            v1.copy(nqb.get("vlfp",i).o[0])
        else:
            loadminrundat(nqb.get("simstr",i).s,datadir)
            v1.copy(net.vlfp,nsamp,net.vlfp.size()-1-nsamp)
        v1.sub(v1.mean())
        if ty==0:
            nqp=h.matpmtm(v1,1e3/h.dt)
        elif ty==1:
            nqp=h.pypmtm(v1,1e3/h.dt)
        elif ty==2:
            nqp=h.pypsd(v1,1e3/h.dt)
        else:
            nqp=h.nrnpsd(v1,1e3/h.dt)
        nqb.set("nqp",i,nqp)
        h.nqsdel(nqp)

# add columns to nqb with synchrony of each population (uses cvpsync in stats.hoc)
# skipms is milliseconds of signal to skip from beginning and end of sim
def addCVpcol (nqb,skipms=200,simdur=8e3,datadir="./data/"):
    nqb.tog("DB")
    if nqb.fi("pyrCVp") == -1:
        for s in ["pyrCVp","basCVp","olmCVp","pyrbasCVp","pyrolmCVp","basolmCVp","allCVp"]: nqb.resize(s)
        nqb.pad()
    cdx = int(nqb.fi("pyrCVp")) # column index
    for i in range(int(nqb.v[0].size())):
        print ("up to " + str(i) + " out of " + str(nqb.v[0].size()))
        loadminrundat(nqb.get("simstr",i).s,datadir)
        net.snq.verbose=0
        idx = cdx
        for ty in range(7):
            cvp = 0
            if ty <= 2: # PYR then BAS then OLM
                if net.snq.select("ty",ty,"t","[]",skipms,simdur-skipms) > 0:
                    cvp = h.cvpsync(net.snq.getcol("t"),net.cells[ty].n)
            elif ty == 3: # PYR + BAS
                if net.snq.select("ty","!=",2,"t","[]",skipms,simdur-skipms) > 0:
                    cvp = h.cvpsync(net.snq.getcol("t"),net.cells[0].n+net.cells[1].n)
            elif ty == 4: # PYR + OLM
                if net.snq.select("ty","!=",1,"t","[]",skipms,simdur-skipms) > 0:
                    cvp = h.cvpsync(net.snq.getcol("t"),net.cells[0].n+net.cells[2].n)
            elif ty == 5: # BAS + OLM
                if net.snq.select("ty","!=",0,"t","[]",skipms,simdur-skipms) > 0:
                    cvp = h.cvpsync(net.snq.getcol("t"),net.cells[1].n+net.cells[2].n)
            elif ty == 6: # ALL
                if net.snq.select("t","[]",skipms,simdur-skipms) > 0:
                    cvp = h.cvpsync(net.snq.getcol("t"),net.cells[0].n+net.cells[1].n+net.cells[2].n)
            nqb.v[idx].x[i] = cvp
            idx += 1
        net.snq.verbose=1

# add columns to nqb with frequency of each population
# skipms is milliseconds of signal to skip from beginning and end of sim
def addHzcol (nqb,skipms=200,simdur=8e3,datadir="./data/"):
    nqb.tog("DB")
    if nqb.fi("pyrHz") == -1:
        for s in ["pyrHz", "basHz", "olmHz"]: nqb.resize(s)
        nqb.pad()
    cdx = int(nqb.fi("pyrHz")) # column index
    for i in range(int(nqb.v[0].size())):
        print ("up to " + str(i) + " out of " + str(nqb.v[0].size()))
        loadminrundat(nqb.get("simstr",i).s,datadir)
        net.snq.verbose=0
        idx = cdx
        for ty in range(3):
            nspks = net.snq.select("ty",ty,"t","[]",skipms,simdur-skipms)
            hz = 1e3 * nspks / ( (simdur-2*skipms) * net.cells[ty].n ) # to hz
            nqb.v[idx].x[i] = hz
            idx += 1
        net.snq.verbose=1

# runs a batch of sims of form baseline/washin/washout . during washin, OLM NMDA is turned off.
# at washout, it's turned back on.
def washbatch(nlevels,startnum=0):
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for r1 in x:
                if y < startnum:
                    print ("skipping sim num ", y)
                    y += 1
                    continue
                s = "./mod/x86_64/special -python washbatchrun.py"
                s += " "+str(iseed)+" "+str(wseed)+" "+str(r1)
                print ("sim num = ", y, ", command = ", s)
                y += 1
                mylog(s,"washbatch_10dec13.14.log")
                os.system(s)

# load info about washbatch run into an NQS. returns the NQS
def washbatchnq(nlevels):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","OLMr")
    nq.strdec("simstr")
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for r1 in x:
                simstr = "10dec14.10dec13.14_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                simstr += "_washOLMr_"+str(r1)
                nq.append(y,simstr,iseed,wseed,r1)
                y += 1
    return nq

# addwashnqpcol -- add a column to nqb from washbatchnq with power spectra from h.matpmtm.
def addwashnqpcol(nqb):
    from neuron import h
#    from network import net
#    from run import loadminrundat
    nqb.tog("DB")
    if nqb.fi("nqpbase") == -1:
        nqb.resize("nqpbase") # baseline power spectra
        nqb.odec("nqpbase")
        nqb.resize("nqpwin")  # washin power spectra
        nqb.odec("nqpwin")
        nqb.resize("nqpwout") # washout power spectra
        nqb.odec("nqpwout")
        nqb.pad()
    cdx = int(nqb.fi("nqpbase")) # column id
    vec=h.Vector()
    dt = h.dt # time interval
    sampr = 1e3/dt # sampling rate
    vsidx = [2e3/dt,4e3/dt,6e3/dt] # start times for different periods
    veidx = [4e3/dt,6e3/dt,8e3/dt] # end times for different periods
    for i in range(int(nqb.v[0].size())):
        simstr = nqb.get("simstr",i).s
        print ("up to " + str(i) + " out of " + str(nqb.v[0].size()))
        print ("\tsim = " , simstr)
        loadminrundat(simstr) # load the sim data
        j = cdx # j has column index into nqb
        for k in range(len(vsidx)):
            print ("interval=",k,vsidx[k],veidx[k])
            vec.resize(0)
            vec.copy(net.vlfp,vsidx[k],veidx[k]) # copy relevant portion of LFP
            vec.sub(vec.mean())       # remove mean
            nqp=h.matpmtm(vec,sampr)  # get the power spectra
            nqb.set(nqb.s[j].s,i,nqp) # save nqp in correct row,column of nqb
            h.nqsdel(nqp) # free memory
            j += 1 # increment column index

# runs a batch of sims where BAS cells are turned off
def basbatch(startnum=0):
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            if y < startnum:
                print ("skipping sim num ", y)
                y += 1
                continue
            s = "./mod/x86_64/special -python basbatchrun.py"
            s += " "+str(iseed)+" "+str(wseed)
            print ("sim num = ", y, ", command = ", s)
            y += 1
            mylog(s,"basbatch_10dec13.14.log")
            os.system(s)

# load info about basbatch run into an NQS. returns the NQS
def basbatchnq():
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed")
    nq.strdec("simstr")
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            simstr = "10dec15.10dec13.14_iseed_"+str(iseed)+"_wseed_"+str(wseed)
            simstr += "_BASoff_"
            nq.append(y,simstr,iseed,wseed)
            y += 1
    return nq

# runs a batch of sims where OLM NMDA is off and different levels of current injection
# into the OLM cells is applied. calls currinjbatchrun.py to run sim & save data.
def currinjbatch(nlevels,startnum=0):
    x = numpy.linspace(10,50,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for i1,r1 in enumerate(x):
                if y < startnum:
                    print ("skipping sim num ", y)
                    y += 1
                    continue
                s = "./mod/x86_64/special -python currinjbatchrun.py"
                s += " "+str(iseed)+" "+str(wseed)+" "+str(r1)
                print ("sim num = ", y, ", command = ", s)
                y += 1
                mylog(s,"currinjbatch_10dec13.14.log")
                os.system(s)

# load info about currinjbatch run into an NQS. returns the NQS
def currinjbatchnq(nlevels):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","incOLMInj")
    nq.strdec("simstr")
    x = numpy.linspace(10,50,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for ic in x:
                simstr = "10dec14.10dec13.14_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                simstr += "_incOLMInj_"+str(ic)
                nq.append(y,simstr,iseed,wseed,ic)
                y += 1
    return nq

# runs a batch of sims with 3 periods: baseline, washin, current injection (to replace washout)
# during washin, ALL OLM NMDA is off. during current injection different levels of current injection
# are sent into the OLM cells instead of washout. calls washinjbatchrun.py to run sim & save data.
def washinjbatch(nlevels,startnum=0):
    x = numpy.linspace(0,50,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for i1,r1 in enumerate(x):
                if y < startnum:
                    print ("skipping sim num ", y)
                    y += 1
                    continue
                s = "./mod/x86_64/special -python washinjbatchrun.py"
                s += " "+str(iseed)+" "+str(wseed)+" "+str(r1)
                print ("sim num = ", y, ", command = ", s)
                y += 1
                mylog(s,"washinjbatch_10dec15.06.log")
                os.system(s)

# load info about washinjbatch run into an NQS. returns the NQS
def washinjbatchnq(nlevels):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","incOLMInj")
    nq.strdec("simstr")
    x = numpy.linspace(0,50,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for ic in x:
                simstr = "10dec16.10dec15.06_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                simstr += "_washincOLMInj_"+str(ic*1e-3)
                nq.append(y,simstr,iseed,wseed,ic)
                y += 1
    return nq

# runs a batch of sims varying the MSGain (medial septal weight gain)
# msbatchrun.py to run sim & save data.
def msbatch(nlevels,startnum=0):
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for i1,r1 in enumerate(x):
                if y < startnum:
                    print ("skipping sim num ", y)
                    y += 1
                    continue
                s = "./mod/x86_64/special -python msbatchrun.py"
                s += " "+str(iseed)+" "+str(wseed)+" "+str(r1)
                print ("sim num = ", y, ", command = ", s)
                y += 1
                mylog(s,"msbatch_11mar28.12.log")
                os.system(s)

# load info about msbatch run into an NQS. returns the NQS
def msbatchnq(nlevels=5):
    from neuron import h
    nq = h.NQS("id","simstr","iseed","wseed","msgain")
    nq.strdec("simstr")
    x = numpy.linspace(0,1,nlevels)
    y = 0
    for iseed in liseed:
        for wseed in lwseed:
            for msgain in x:
                simstr = "11mar28.12_iseed_"+str(iseed)+"_wseed_"+str(wseed)
                simstr += "_msgain_"+str(msgain)
                nq.append(y,simstr,iseed,wseed,msgain)
                y += 1
    return nq

# # append line s to filepath fn
# def appline (s,fn):
#   '''append line s to filepath fn'''
#   fp = open(fn,"a"); fp.write(s + "\n"); fp.close()

# append to the lists
def NewParam (lsec,lopt,lval,sec,opt,val):
  '''append to the lists of params'''
  lsec.append(sec); lopt.append(opt); lval.append(val)

# check that the batch dir exists
def checkdir (d):
  '''check that the batch dir exists'''
  try:
    if not os.path.exists(d): os.mkdir(d)
    return True
  except:
    print ("could not create directory :" + d)
    return False

# run a batch using multiprocessing
#  based on http://www.bryceboe.com/2011/01/28/the-python-multiprocessing-queue-and-large-objects/
# obtained from /u/samn/ca1d/batch.py
def batchRun (whichParams,blog,skip=[],qsz=10,bdir="./batchconfigFiles"):
  '''run a batch using multiprocessing'''
  if not checkdir(bdir): return False
  jobs = multiprocessing.Queue()
  lsec,lopt,lval,lconfigfilestr = whichParams()

  def myworker (jobs):
    while True:
      scomm = jobs.get()
      if scomm == None: break
      print ("worker starting : " , scomm)
      os.system(scomm) #worker function, invoked in a process.

  for i in range(len(lsec)):
    if i in skip: continue
    cfgname = os.path.join(bdir, lconfigfilestr[i] + ".cfg")
    writeconf(cfgname,sec=lsec[i],opt=lopt[i],val=lval[i])
    cmd = "python runone.py " + cfgname
    print (cmd, type(cmd))
    appline(cmd,blog)
    jobs.put(cmd)
  workers = []
  for i in range(qsz):
    jobs.put(None)
    tmp = multiprocessing.Process(target=myworker, args=(jobs,))
    tmp.start()
    workers.append(tmp)
  for worker in workers: worker.join()
  return jobs.empty()

# main...
if __name__ == "__main__":
    na = len(sys.argv) # number of args
    print (sys.argv)
    if na < 2:
        print ("Usage: python batch.py type[0=nmbatch,1=washbatch,2=currinjbatch,3=basbatch,4=washinj,5=msbatch,6=ntebatch,7=ihbatch],[nlevels,startnum]")
        sys.exit(1)

    ty = int(sys.argv[1])

    print ("hello!!! ty is : " + str(ty))

    if ty == 0:
        print ("nmbatch")
        bru = nmbatch
    elif ty == 1:
        print ("washbatch")
        bru = washbatch
    elif ty == 2:
        print ("currinjbatch")
        bru = currinjbatch
    elif ty == 3:
        print ("basbatch")
        if na > 2:
            startnum = int(sys.argv[2])
            basbatch(startnum)
        else:
            basbatch()
        sys.exit(0)
    elif ty == 4:
        print ("washinj")
        bru = washinjbatch
    elif ty == 5:
        print ("msbatch")
        bru = msbatch
    elif ty == 6:
        print ("ntebatch")
        bru = ntebatch
    elif ty == 7:
        print ("ihbatch")
        bru = ihbatch
    elif ty == 8:
        print ("ihbatchPYRBAS")
        bru = ihbatchPYRBAS
    elif ty == 9:
        print ("longihbatchPYRBAS")
        bru = longihbatchPYRBAS
    elif ty == 10:
        print ("longihbatchOLM")
        bru = longihbatchOLM
    else:
        print (str(ty) + "is an unknown batch type!")
        sys.exit(1)

    nlevels = int(sys.argv[2])
    if na > 3:
        startnum = int(sys.argv[3])
        bru(nlevels,startnum)
    else:
        bru(nlevels)

    sys.exit(0)


from selenium.webdriver.common.keys import Keys
from selenium import webdriver
from bs4 import BeautifulSoup
import selenium
import time

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("user-data-dir=selenium")
prefs = {"profile.default_content_setting_values.notifications" : 2}
chrome_options.add_experimental_option("prefs",prefs)
driver = webdriver.Chrome(chrome_options=chrome_options)

driver.get("https://www.humanbenchmark.com/tests/reactiontime")

time.sleep(5)

click = driver.find_element_by_xpath('//*[@id="root"]/div/div[4]/div[1]')
click.click()

while True:

    click = driver.find_element_by_xpath('//*[@id="root"]/div/div[4]/div[1]')

    if 'Click!' in click.text:

        click.click()

        time.sleep(2)

        click.click()


# coding: UTF-8
from __future__ import unicode_literals

from os import path, remove

from openpyxl import load_workbook
import pytest

from xlsx_to_nosql import XlsxReader, XlsxWriter

@pytest.yield_fixture
def workbook():
    reader = XlsxReader(filepath='src/tests/test-data/content.xlsx')
    XlsxWriter(db=reader.db, filename='src/tests/test-data/output.xlsx')
    workbook = load_workbook(
        path.join('src/tests/test-data/output.xlsx'), read_only=True
    )
    yield workbook
    remove('src/tests/test-data/output.xlsx')

def test_to_xlsx(workbook):
    assert set(workbook.sheetnames) == set(['Books', 'Films'])

    books = workbook['Books']
    books_one = {
        'A': 'Book',
        'B': 'Author',
        'C': 'Publication date',
        'D': 'ISBN',
    }
    books_two = {
        'A': 'Northern Lights',
        'B': 'Philip Pullman',
        'C': '1995-07-01T00:00:00+00:00',
        'D': '0-590-54178-1',
    }

    ss_books_rows = books.rows
    ss_books_one = ss_books_rows.next()
    ss_books_two = ss_books_rows.next()

    assert len(ss_books_one) == 4
    for cell in ss_books_one:
        assert cell.value == books_one[cell.column]

    assert len(ss_books_two) == 4
    for cell in ss_books_two:
        assert cell.value == books_two[cell.column]

    films = workbook['Films']
    films_one = {
        'A': 'Film',
        'B': 'Directed by',
        'C': 'Starring',
        'D': 'Release date',
        'E': 'Running time',
        'F': 'Box office',
    }
    films_two = {
        'A': 'Interstellar',
        'B': 'Christopher Nolan',
        'C': 'Matthew McConaughey, Anne Hathaway',
        'D': '2014-10-26T00:00:00+00:00',
        'E': 169,
        'F': 672700000,
    }

    ss_films_rows = films.rows
    ss_films_one = ss_films_rows.next()
    ss_films_two = ss_films_rows.next()

    assert len(ss_films_one) == 6
    for cell in ss_films_one:
        assert cell.value == films_one[cell.column]

    assert len(ss_films_two) == 6
    for cell in ss_films_two:
        assert cell.value == films_two[cell.column]


TESTE = True
VALOR = 0
VALOR = int(input("Digite um  número inteiro"))
n = VALOR - 1

while(n >= 2):
    if(VALOR % n == 0):
        TESTE = False
        n = 0
    n = n - 1
if(TESTE):
    print("primo")
else:
    print("não primo")


import numpy as np
import matplotlib.pyplot as plt
import bisect

# Base class for all noisy signals
# Not to be used directly. Use the derived classes instead
#
class NoiseSignal(object):
    """
    Generic noisy signal
    """

    def __init__(self, initial_seed=1234, resolution=1.0, time_unit=1e-9):
        self.resolution_factor = resolution
        self.amplitude = 1.0
        self.random_seed = initial_seed
        self.is_init = False
        self.interpolation_settings()
        self.time_unit=time_unit
        self.time_units_per_sec = 1/time_unit

        # This base random seed is used to create the individual seeds used to generate each instance of the noise
        self.seed_generator = np.random.RandomState(self.random_seed)

    def __repr__(self):
        return "NoiseSignal(resolution_factor={0}, amplitude={1}, seed={2}".format(self.resolution_factor, self.amplitude, self.random_seed)
    def __str__(self):
        return "NoiseSignal(resolution_factor={0}, amplitude={1}, seed={2}".format(self.resolution_factor, self.amplitude, self.random_seed)
    def __getitem__(self, key):
        if self.do_interpolation:
            return self.eval_interpolated(key)
        else:
            return self.eval(key)

    def reset(self):
        self.seed_generator = np.random.RandomState(self.random_seed)

    def get_new_seed(self):
        return self.seed_generator.randint(np.iinfo(np.int32).max)

    def interpolation_settings(self, do_interpolation=False, resolution_factor=1.0, itime=10.0):
        # enable flag
        self.do_interpolation = do_interpolation
        # resolution of samples from the signal
        self.interpolation_resolution = resolution_factor
        # window to interpolate over
        self.interpolation_time = itime

    def eval_interpolated(self, t):
        if self.do_interpolation:
            time_steps, data_samples = self.get_sample_data(t)
            ival = np.interp(t, time_steps, data_samples)*self.amplitude
            return ival
        else:
            return self.eval(t)

class NoiseSignalRandomWalk(NoiseSignal):
    '''
    Creates a random walk function, starting at 0, over a specified time interval.
    Create the object, configure it, then init. Do more inits or next_intervals as necessary
    '''
    def __str__(self):
        return "NoiseSignalRandomWalk(resolution_factor={0}, amplitude={1}, seed={2}".format(self.resolution_factor, self.amplitude, self.random_seed)

    def configure_noise(self, amplitude, resolution_factor, total_time):
        '''total_time will remain constant after configuration, but the times and points will get data appended to
        each time you call init or next_interval.
        amplitude: the step size of each walk; the value at a given time is the last time's value plus or minus this amplitude
        resolution: how many values per time_unit
        '''
        self.amplitude = amplitude
        self.resolution_factor = resolution_factor
        self.total_time = total_time #number of time_units per .init() call
        self.points = []
        self.times = []
        self.num_points = int(self.total_time*self.resolution_factor)
        self.next_interval_start_time = 0

    def init(self, random_seed=None):
        '''
        Starts a random walk from zero, up to total_time with num_points in between.
        '''
        if random_seed==None:
            random_seed = self.get_new_seed()
        rand_switch = np.random.RandomState(random_seed)
        num_points = self.num_points
        binaries = [0] + [self.amplitude if rand_switch.randint(2)==1 else -1*self.amplitude for i in range(num_points-1)]
        points = [0]*num_points
        points[0] = 0
        for i in range(1, num_points):
            points[i] = points[i-1] + binaries[i]
        self.points += points
        step = (self.total_time - 0)/self.num_points
        if len(self.times) == 0:
            self.times += [i*step for i in range(num_points)]  #array of times from 0 to total_time, units of time_unit
            self.next_interval_start_time = num_points*step
        else:
            self.times += [self.next_interval_start_time+i*step for i in range(num_points)]
            self.next_interval_start_time = self.next_interval_start_time + num_points*step
        self.is_init = True
        return random_seed

    def eval(self, t):
        '''Returns noise value at time t (specified in time_unit) in units of time_unit'''
        if t>self.total_time:
            raise ValueError("NoiseSignalNormal(): Requested time greater than total simulation time")
        if t<0:
            raise ValueError("NoiseSignalNormal(): Requested time < 0")

        tidx = int(t*self.resolution_factor)
        return self.points[tidx]

    def get_sample_data(self):
        '''returns a tuple with a time list and associated noise values at each time point'''
        times = self.times #returns all the calculated times, including any .next_intervals() you may do
        vals = self.points
        return times, vals

    def next_interval(self,random_seed=None):
        '''Does self.init again, but starts where the last init ended, not from zero.
        Will will add total_time amount of time to self.time (a total of num_points added)
        '''
        if random_seed==None:
            random_seed = self.get_new_seed()
        rand_switch = np.random.RandomState(random_seed)
        num_points = int(self.total_time * self.resolution_factor)
        binaries = [self.amplitude if rand_switch.randint(2)==1 else -1*self.amplitude for i in range(num_points)]
        points = [0]*num_points
        points[0] = binaries[0] + self.points[len(self.points) -1]
        for i in range(1, num_points):
            points[i] = points[i-1] + binaries[i]
        self.points += points
        step = (self.total_time - 0)/self.num_points
        self.times += [self.next_interval_start_time+i*step for i in range(num_points)]
        self.next_interval_start_time = self.next_interval_start_time + num_points*step
        return random_seed

    def plot_noise_signal(self):
        if self.is_init == False:
            raise ValueError("Must be initialized first!")
        marker = '.'
        linewidth = 1
        markersize = 1

        t, n = self.get_sample_data()
        plt.plot(t,n, marker=marker, linewidth=linewidth, markersize=markersize)
        plt.grid()
        plt.title("Random Walk Noise\n$\pm${} per step, {:.1f}(x{:.1e}s) per step".format(self.amplitude, self.total_time/self.num_points, self.time_unit) )
        plt.ylabel("Arbitrary Units")
        plt.xlabel("Time, in units of {:.1e} seconds".format(self.time_unit))
        plt.show()

class NoiseSignalSine(NoiseSignal):
    '''
    Creates a noise signal composed of a summation of sine waves over a specified time interval.
    create the object, configure it, then do an init and you're good to go. Do a next_interval or another init if necessary
    '''
    def __str__(self):
        return "NoiseSignalSine(resolution_factor={0}, seed={1}".format(self.resolution_factor, self.random_seed)

    def configure_noise(self, resolution_factor, freq_list, amp_list, phase_list, total_time):
        '''
        resolution factor: how many points per time_unit
        freq_list: a list or tuple of the all the desired frequencies, in Hz
        amp_list: a list or tuple of the amplitudes for all frequencies
        phase_list: a list or tuple of the phases of all the waves (all lists should be the same length)
        total_time: total # of time_units you want to cover per .init call
        '''
        self.resolution_factor = resolution_factor
        self.total_time = total_time #number of time_units per .init() call
        self.list_of_point_lists = []
        self.summed_points = []
        self.times = []
        self.num_points = int(self.total_time*self.resolution_factor)
        self.step = self.total_time/self.num_points #the time interval between time points, in units of time_units
        self.next_interval_start_time = 0
        self.freq_list = freq_list
        self.amp_list = amp_list
        self.phase_list = phase_list

    def init(self):
        times = [i*self.step for i in range(0,self.num_points+1)] #step = totaltime/numpoints, numpoits = int(totaltime*resfactor)
        #print(times)
        list_of_point_lists = [0]*len(self.freq_list)
        for i in range(len(self.freq_list)):
            '''find values for each frequency, then sum them up later'''
            freq = self.freq_list[i]
            amp = self.amp_list[i]
            phase = self.phase_list[i]
            value_list = []
            for t in times:
                val = amp*np.sin(2*np.pi*freq*t*self.time_unit + phase)
                value_list.append(val)
            list_of_point_lists[i] = value_list
        self.list_of_point_lists = list_of_point_lists
        #each frequency's list is done, now add them all together in one list
        summed_vals = [0]*len(times)
        for t_index in range(len(times)):
            for wave_index in range(len(self.list_of_point_lists)):
                summed_vals[t_index] += self.list_of_point_lists[wave_index][t_index]
        #print(summed_vals)
        self.summed_points += summed_vals
        #add these lines at the end of the init call
        self.times += times
        self.next_interval_start_time = self.times[-1] + self.step

    def get_sample_data(self):
        '''returns a tuple with a time list and associated noise values at each time point'''
        times = self.times #returns all the calculated times, including any .next_intervals() you may do
        vals = self.summed_points #returns the summed sine wave for each point in self.times
        return times, vals

    def add_random_noise(self, sigma):
        '''add normally distributed noise to the overall summed_values
        Specify the std deviation, sigma, of the noise, which centers on zero'''
        for i in range(len(self.summed_points)):
            self.summed_points[i] += np.random.normal(0,sigma)

    def next_interval(self):
        times = [self.next_interval_start_time+i*self.step for i in range(self.num_points)]
        #print(times)
        for i in range(len(self.freq_list)):
            '''find values for each frequency, then su mthem up later'''
            freq = self.freq_list[i]
            amp = self.amp_list[i]
            phase = self.phase_list[i]
            value_list = []
            for t in times:
                val = amp*np.sin(2*np.pi*freq*t*self.time_unit + phase)
                value_list.append(val)
            self.list_of_point_lists[i].extend(value_list)

        #each frequency's list is done, now add them all together in one list
        summed_vals = [0]*len(times)
        for t_index in range(len(times)):
            for wave_index in range(len(self.list_of_point_lists)):
                summed_vals[t_index] += self.list_of_point_lists[wave_index][t_index]
        #print(summed_vals)
        self.summed_points += summed_vals
        #add these lines at the end of the init call
        self.times += times
        self.next_interval_start_time = self.times[-1] + self.step
        #print("After next interval, end time is {}".format(self.times[-1]))

    def plot_noise_signal(self, show_components=True):
        '''Shows a plot of the individual waves, and a plot of the summed wave, if components = True'''

        times = self.times
        summed = self.summed_points
        components = self.list_of_point_lists
        marker ='.'
        linewidth=1
        markersize = 1
        if show_components == True:
            for wave_index in range(len(components)):
                wave= components[wave_index]
                freq = self.freq_list[wave_index]
                plt.plot(times, wave, label="{:.2f} Hz".format(freq), marker=marker, linewidth=linewidth, markersize=markersize)
            plt.grid()
            plt.xlabel("Time in selected units ({:.0e} s)".format(self.time_unit))
            plt.ylabel("Amplitude, a.u.")
            plt.legend()
            plt.title("Component Waves")
            plt.show()

        plt.plot(times, summed, marker=marker, linewidth=linewidth,markersize=markersize)
        plt.grid()
        plt.xlabel("Time in selected units ({:.0e} s)".format(self.time_unit))
        plt.ylabel("Amplitude, a.u.")
        plt.title("Sinusoidal Noise Signal")
        plt.show()

    def eval(self, t):
        if t>self.total_time:
            print("Bad time is {}".format(t))
            raise ValueError("NoiseSignalSine(): Requested time greater than total simulation time")
        if t<0:
            raise ValueError("NoiseSignalSine(): Requested time < 0")

        tidx = int(t*self.resolution_factor)
        #print("time t is {}".format(t))
        #print("tindex is {}".format(tidx))
        #print("total time is {}".format(self.total_time))
        return self.summed_points[tidx]

class NoiseSignalNormal(NoiseSignal):

    def __str__(self):
        return "NoiseSignalNormal(resolution_factor={0}, amplitude={1}, seed={2}, mean{3}, variance{4})".format(self.resolution_factor, self.amplitude, self.random_seed, self.mean, self.variance)
    def __repr__(self):
        if self.is_init:
            str_val = "normal_deviants = [ "
            for ii in range(len(self.points)):
                str_val += "{0} ".format(self.points[ii])
            str_val += "]"

            return str_val
        else:
            return "normal_deviants = []"

    def plot_amplitudes(self):
        times = [ti/self.resolution_factor for ti in range(int(self.total_time*self.resolution_factor))]
        plt.plot(times, [sv*self.amplitude for sv in self.points])
        plt.show()

    def configure_noise(self, amplitude, mean, variance, resolution_factor, total_time):
        self.mean = mean
        self.variance = variance
        self.amplitude = amplitude
        self.resolution_factor = resolution_factor
        self.std_dev = np.sqrt(variance)
        self.total_time = total_time

    def init(self, random_seed=None):
        if random_seed==None:
            random_seed = self.get_new_seed()
        rand_switch = np.random.RandomState(random_seed)
        num_points = int(self.total_time * self.resolution_factor)

        self.points = [self.std_dev*rand_switch.randn() + self.mean for ii in range(num_points)]
        self.is_init = True

        return random_seed

    def eval(self, t):
        if t>self.total_time:
            raise ValueError("NoiseSignalNormal(): Requested time greater than total simulation time")
        if t<0:
            raise ValueError("NoiseSignalNormal(): Requested time < 0")

        tidx = int(t*self.resolution_factor)
        return self.points[tidx]*self.amplitude

    def get_sample_data(self, t):
        lidx = int(np.floor(t*self.resolution_factor))
        ltime = lidx/self.resolution_factor
        uidx = int(np.ceil(t*self.resolution_factor))
        utime = uidx/self.resolution_factor

        sample_times = [ltime]
        sample_vals = [self.points[lidx]]
        if uidx<len(self.points):
            sample_times += [utime]
            sample_vals += [self.points[uidx]]

        while (lidx>0 or (uidx+1)<len(self.points)) and ((len(sample_times)<2) or (utime-ltime)<self.interpolation_time):
            if lidx>0:
                lidx -= 1
                ltime = lidx/self.resolution_factor
                sample_vals = [self.points[lidx]] + sample_vals
                sample_times = [ltime] + sample_times
            if (uidx+1)<len(self.points):
                uidx += 1
                utime = uidx/self.resolution_factor
                sample_vals += [self.points[uidx]]
                sample_times += [utime]

        if len(sample_times)<2:
            raise ValueError("Cannot find enough sample data")

        return sample_times, sample_vals

class NoiseSignalTelegraph(NoiseSignal):

    def __str__(self):
        return "NoiseSignalTelegraph(resolution_factor={0}, amplitude={1}, seed={2}, exponent={3}, total_fluctuators={4}, start_freq={5}, stop_freq={6}, total_time={7})".format(self.resolution_factor, self.amplitude, self.random_seed, self.exponent, self.total_fluctuators, self.start_freq, self.stop_freq, self.total_time)
    def __repr__(self):
        if self.is_init:
            str_val = "flux_switch_times = [ "
            for ii in range(len(self.switching_times)):
                str_val += "{0}:{1} ".format(self.switching_times[ii],self.amplitude_sums[ii])
            str_val += "]"
        else:
            return "flux_switch_times = []"

        return str_val

    def plot_amplitudes(self):
        prev_time = -1
        switch_times = []
        switch_amps = []
        for ii in range(len(self.switching_times)):
            sw_time = self.switching_times[ii]
            sw_sum = self.amplitude*self.amplitude_sums[ii]

            if prev_time >= 0:
                switch_times += [sw_time]
                switch_amps += [prev_amp]
            switch_times += [sw_time]
            switch_amps += [sw_sum]
            prev_time = sw_time
            prev_amp = sw_sum

        plt.plot(switch_times, switch_amps)
        plt.show()

    def plot_noise_signal(self):
        if self.is_init != True:
            raise ValueError("Noise signal must first be initialized!")
        num_points = int(self.total_time/self.resolution_factor)
        step = self.total_time/num_points
        times = [i*step for i in range(num_points)] #step = totaltime/numpoints, numpoits = int(totaltime*resfactor)
        vals = []
        for t in times:
            vals.append(self[t])
        plt.plot(times, vals,marker='.',linewidth=1)
        plt.xlabel("Time in time_unit")
        plt.ylabel("Noise, arb. units")
        plt.title("Telegraph Noise\nFrom {} Hz to {} Hz".format(self.start_freq, self.stop_freq))
        plt.grid()
        plt.show()

    def configure_noise(self, exponent, amplitude, total_fluctuators, start_freq, stop_freq, total_time):
        self.exponent = float(exponent)
        self.amplitude = float(amplitude / (2.0 * np.pi))
        self.total_fluctuators = total_fluctuators
        self.start_freq = float(start_freq)
        self.stop_freq = float(stop_freq)
        self.total_time = float(total_time)
        self.create_fluctuators()

    # create structures needed for noise generator
    def create_fluctuators(self):

        freq_area = np.log(self.stop_freq/self.start_freq)/((self.total_fluctuators-1))
        freq_fact = np.exp(freq_area)

        if ( self.exponent<0.0 or self.exponent>2.0 ):
            raise ValueError("Invalid exponent for Telegraph noise, should be > 0.0 and <= 2.0")

        self.freq_points = [self.start_freq*np.power(freq_fact,ii) for ii in range(self.total_fluctuators+1)]
        if self.exponent==1.0:
            self.freq_amps = [np.sqrt(2.0 * (np.log(self.freq_points[ii+1])-np.log(self.freq_points[ii]))) for ii in range(self.total_fluctuators)]
        else:
            self.freq_amps = [np.sqrt(1.0/(1.0-self.exponent) * (np.power(self.freq_points[ii+1],1.0-self.exponent) - np.power(self.freq_points[ii],1.0-self.exponent))) for ii in range(self.total_fluctuators)]
        del self.freq_points[self.total_fluctuators]

    # initialize a new set of fluctuators
    def init(self, random_seed=None):
        if random_seed==None:
            random_seed = self.get_new_seed()
        self.rand_switch = np.random.RandomState(random_seed)

        # initialize the state of each fluctuator (+-1.0)
        self.f_state = [1.0 if self.rand_switch.randint(2)==0 else -1.0 for ii in range(self.total_fluctuators)]

        # initialize the switching time for each fluctuator
        # next switching time is exponentially distributed, so we can
        # generate a uniform rv and transform it to an exponential rv.
        # also convert from seconds to nanoseconds (1 s = 10^9 ns) and start at a random point in the interval [0,1]
        self.f_next_switch = [(self.time_units_per_sec)*self.rand_switch.uniform()*(-np.log(1-self.rand_switch.uniform())/self.freq_points[ii]) for ii in range(self.total_fluctuators)]

        # create an array of switching times (for any fluctuator) and the sum of all the fluctuators at that time
        #
        self.amplitude_sums = [sum(self.f_state[ii]*self.freq_amps[ii] for ii in range(self.total_fluctuators))]
        self.switching_times = [0.0]

        tval = 0.0;
        while ( tval < self.total_time ):
            # find the fluctuator that is to switch next
            next_switch_idx = self.f_next_switch.index(min(self.f_next_switch))
            tval = self.f_next_switch[next_switch_idx]

            # update the switching time for this fluctuator
            self.f_next_switch[next_switch_idx] += self.time_units_per_sec*(-np.log(1-self.rand_switch.uniform())/self.freq_points[next_switch_idx])

            # update the state of this fluctuator
            self.f_state[next_switch_idx] *= -1.0

            # add the switching time and new sum to the lists
            self.switching_times += [tval]
            self.amplitude_sums += [self.amplitude_sums[len(self.amplitude_sums)-1] + self.f_state[next_switch_idx]*2.0*self.freq_amps[next_switch_idx]]

        self.is_init = True
        return random_seed

    # move to a new interval of time, i.e., continue the 1/f signal without re-initializing
    def next_interval(self):

        self.f_next_switch = [next_switch-self.total_time for next_switch in self.f_next_switch]

        self.amplitude_sums = [sum(self.f_state[ii]*self.freq_amps[ii] for ii in range(self.total_fluctuators))]
        self.switching_times = [0.0]

        tval = 0.0;
        while ( tval < self.total_time):
            # find the fluctuator that is to switch next
            next_switch_idx = self.f_next_switch.index(min(self.f_next_switch))
            tval = self.f_next_switch[next_switch_idx]

            # update the switching time for this fluctuator
            self.f_next_switch[next_switch_idx] += self.time_units_per_sec*(-np.log(1-self.rand_switch.uniform())/self.freq_points[next_switch_idx])

            # update the state of this fluctuator
            self.f_state[next_switch_idx] *= -1.0

            # add the switching time and new sum to the lists
            self.switching_times += [tval]
            self.amplitude_sums += [self.amplitude_sums[len(self.amplitude_sums)-1] + self.f_state[next_switch_idx]*2.0*self.freq_amps[next_switch_idx]]

    # return the value of the noise at the indicated time
    def eval(self, t):
        tdx = bisect.bisect_left(self.switching_times, t)
        if ( tdx >= len(self.switching_times) ):
             tdx -= 1

        if tdx==0:
            e_val = self.amplitude_sums[0]*self.amplitude
        else:
            e_val = self.amplitude_sums[tdx-1]*self.amplitude
        return e_val

    def get_sample_data(self, t):
        uidx = 0
        while uidx<len(self.switching_times) and self.switching_times[uidx]<t:
            uidx += 1

        if uidx>0:
            lidx = uidx - 1
        else:
            lidx = 0

        ltime = self.switching_times[lidx]
        utime = self.switching_times[uidx]
        sample_times = [ltime]
        sample_vals = [self.amplitude_sums[lidx]]
        if not ltime == utime:
            sample_times += [utime]
            sample_vals += [self.amplitude_sums[uidx]]

        while (lidx>0 or (uidx+1)<len(self.switching_times)) and ((len(sample_times)<2) or (utime-ltime)<self.interpolation_time):
            if lidx>0:
                lidx -= 1
                ltime = self.switching_times[lidx]
                sample_vals = [self.amplitude_sums[lidx]] + sample_vals
                sample_times = [ltime] + sample_times
            if (uidx+1)<len(self.switching_times):
                uidx += 1
                utime = self.switching_times[uidx]
                sample_vals += [self.amplitude_sums[uidx]]
                sample_times += [utime]

        if len(sample_times)<2:
            raise ValueError("Cannot find enough sample data")

        return sample_times, sample_vals

if __name__=='__main__':
    total_time = 1000
    time_unit = 1e-3

    sig = NoiseSignalTelegraph(initial_seed=1234, time_unit=time_unit, resolution=1)
    sig.configure_noise(exponent=1, amplitude=1, total_fluctuators=40, start_freq=0.1, stop_freq=5, total_time=total_time)
    sig.init()
    sig.plot_noise_signal()

    amp = 1
    res = 1
    freq_list = (2,5, 8) #Hz
    amp_list = (0.1, 0.06, 0.04) #arb. units
    phase_list = (0,0,0)
    sig = NoiseSignalRandomWalk(initial_seed = 1, time_unit=time_unit)
    sig.configure_noise(amp, res, total_time)
    sig.init()
    sig.plot_noise_signal()

    sine = NoiseSignalSine(time_unit = 1e-3)
    sine.configure_noise(resolution_factor=0.1, freq_list=freq_list, amp_list=amp_list, phase_list=phase_list, total_time=1000)
    sine.init()
    sine.next_interval()
    sine.plot_noise_signal(True)


class Human(object):
    # 静态字段
    live = True

    def __init__(self, name):
        # 普通字段
        self.name = name

man = Human('Adam')
woman = Human('Eve')

# 有静态字段,live属性
print(Human.__dict__)
# 有普通字段,name属性
print(man.__dict__)

# 实例可以使用普通字段也可以使用静态字段
man.name
man.live = False
# 查看实例属性
man.__dict__ #普通字段有live变量
man.live
woman.live

# 类可以使用静态字段
Human.live
woman.live = False
woman.live
woman.__dict__

# 可以为类添加静态字段
Human.newattr = 1
dir(Human)
dir(woman)
# woman.__dir__()
Human.__dict__

# 内置类型不能增加属性和方法
setattr(list, 'newattr', 'value')
# TypeError
# 可以使用这种方法增加属性和方法
setattr(Human, 'age', 20)
me = Human('zhang san')
dir(Human)
dir(me)
me.age

# 显示object类的所有子类
print( ().__class__.__bases__[0].__subclasses__() )


# REFERENCE: https://aws.plainenglish.io/setup-celery-5-0-and-aws-sqs-with-django-125be52262fc
from .tasks import run_job

def post(self, request):
    p = request.data.get('product') #return in dict
    product = Product(title=p['title'], description=p['description'], price=p['price'])
    product.save()
    # Call celery task to update status
    run_job(product.id)
    return Response({"success":"true", "message": "Product '{}' created successfully".format(p['title'])})


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

import sys,time

def progressbar():

    j = "#"

    for i in range(1, 61):

        j += "#"

        sys.stdout.write(str(int((float(i)/60)*100)) + "%||" + "#" * i  + "->" + "\r")

        sys.stdout.flush()

        time.sleep(0.01)

if __name__ == "__main__":

    progressbar()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import asyncio
import logging

import mock
from fbnet.command_runner.command_session import CommandSession

from .mock_session import MockCommandSession
from .mocks import MockService
from .testutil import AsyncTestCase, async_test

log = logging.getLogger()

class CommandSessionTest(AsyncTestCase):
    def setUp(self):
        super().setUp()

        self.mock_options = {}
        self.mocks = MockService(self.mock_options, self._loop)

        test_device = self.mock_device("test-dev-1")
        self.devinfo = self._run_loop(self.mocks.device_db.get(test_device))[0]

        self.options = {
            "client_ip": "10.10.10.10",
            "client_port": 1010,
            "open_timeout": 10,
        }
        handler = mock.Mock()
        self.session = MockCommandSession(
            self.mock_options, handler, self.devinfo, self.options, loop=self._loop
        )
        self.session_id = self.session.id
        self.key = (
            self.session.id,
            self.options["client_ip"],
            self.options["client_port"],
        )

    def tearDown(self):
        try:
            q_session = self._get_session()
            self._run_loop(q_session.close())
        except Exception:
            # session already closed in the test
            pass
        self.mocks.tearDown()
        super().tearDown()

    def mock_device(self, name, console=None, command_prompts=None):
        return mock.Mock(
            hostname=name, console=console, command_prompts=command_prompts
        )

    def _get_session(self):
        """
        helper method the get session from cache
        """
        return CommandSession.get(
            self.session_id, self.options["client_ip"], self.options["client_port"]
        )

    def test_create(self):
        self.assertFalse(self.session._connected)
        self.assertIn(self.key, CommandSession._ALL_SESSIONS)

    def test_get(self):
        q_session = self._get_session()
        self.assertEqual(self.session, q_session)

    @async_test
    async def test_connect(self):
        # Session is initially not connected
        self.assertFalse(self.session._connected)

        await self.session.connect()
        await self.session.wait_until_connected()

        self.assertTrue(self.session._connected)

    @async_test
    async def test_delay_connect(self):
        # Session is initially not connected
        self.assertFalse(self.session._connected)

        self.session.set_option("connect_delay", 0.1)
        # Initiate the connection and wait for connect
        await self.session.connect()
        await self.session.wait_until_connected(0.2)

        self.assertTrue(self.session._connected)

    @async_test
    async def test_connect_timeout(self):
        # Session is initially not connected
        self.assertFalse(self.session._connected)

        self.session.set_option("connect_delay", 0.2)
        # Initiate the connection and wait for connect
        with self.assertRaises(asyncio.TimeoutError):
            await self.session.connect()
            await self.session.wait_until_connected(0.1)

        self.assertFalse(self.session._connected)

    @async_test
    async def test_setup_success(self):
        device = self.mock_device("test-dev-1")
        devinfo = await self.mocks.device_db.get(device)

        self.options["open_timeout"] = 2
        self.mock_options["prompt_delay"] = 0

        handler = mock.Mock()
        session = MockCommandSession(
            self.mock_options, handler, devinfo, self.options, loop=self._loop
        )
        # Session is initially not connected
        self.assertFalse(session._connected)

        await session.setup()
        self.assertTrue(session._connected)

    @async_test
    async def test_setup_prompt_timeout(self):
        device = self.mock_device("test-dev-1")
        devinfo = await self.mocks.device_db.get(device)

        self.options["open_timeout"] = 2
        self.mock_options["prompt_delay"] = 3

        handler = mock.Mock()
        session = MockCommandSession(
            self.mock_options, handler, devinfo, self.options, loop=self._loop
        )
        # Session is initially not connected
        self.assertFalse(session._connected)

        # Initiate the connection and wait for connect
        with self.assertRaises(asyncio.TimeoutError):
            await session.setup()

    @async_test
    async def test_setup_command_timeout(self):
        device = self.mock_device("test-dev-1")
        devinfo = await self.mocks.device_db.get(device)

        self.options["open_timeout"] = 2

        # force a delay in setup commands
        self.mock_options["command_delay"] = 3

        handler = mock.Mock()
        session = MockCommandSession(
            self.mock_options, handler, devinfo, self.options, loop=self._loop
        )
        # Session is initially not connected
        self.assertFalse(session._connected)

        # Initiate the connection and wait for connect
        with self.assertRaises(asyncio.TimeoutError):
            await session.setup()

    @async_test
    async def test_close(self):
        q_session = self._get_session()
        self.assertEqual(self.session, q_session)

        await self.session.close()

        with self.assertRaises(KeyError):
            q_session = self._get_session()

    @async_test
    async def test_run_command(self):
        with self.assertRaises(RuntimeError) as rexc:
            await self.session.run_command(b"test\n")

        self.assertEqual(rexc.exception.args[0], "Not Connected")

        # Initiate the connection and wait for connect
        await self.session.connect()
        await self.session.wait_until_connected()
        await self.session.wait_prompt()

        res = await self.session.run_command(b"test1\n")
        self.assertEqual(res, b"$ test1\nMock response for test1")

    @async_test
    async def test_run_command_timeout_prompt(self):

        # Initiate the connection and wait for connect
        await self.session.connect()
        await self.session.wait_until_connected()
        await self.session.wait_prompt()

        with self.assertRaises(RuntimeError) as rexc:
            await self.session.run_command(b"command timeout\n", 1)

        self.assertEqual(rexc.exception.args[0], "Command Response Timeout")
        self.assertEqual(
            rexc.exception.args[1],
            b"command timeout\nMock response for command timeout",
        )


import cv2
import os
from tqdm import tqdm
'''
Watch the videos via opencv, and save every <interval> frame.
'''
source_path = '/home/tk/Desktop/20190919record'
video_list = []
for root, dirs, files in os.walk(source_path):
    for i in files:
        if i.endswith('.dav'):
            video_list.append(os.path.join(root,i))

for videopath in tqdm(video_list):
    video_size = os.path.getsize(videopath)/(1000*1000)
    if video_size > 600:
        interval = 400
    else:
        interval = 200
    outputpath = os.path.join('data',videopath.split('/')[-1][:-4])
    try:
        os.mkdir(outputpath)
    except:
        pass
    cap = cv2.VideoCapture(videopath)
    time = 0
    while True:
        ret, frame = cap.read()
        if ret:
            time += 1
            if "PTZ" not in videopath:
                frame = frame[::-1,:,:]
                h,w = frame.shape[:2]
                sections = []
                for row in range(2):
                    for col in range(4):
                        sections.append(frame[row*(h//2):row*(h//2)+h//2,col*(w//4):col*(w//4)+w//4,:])

                for i in range(8):
                    cv2.namedWindow('frame_{}'.format(i), 0)
                    cv2.resizeWindow('frame_{}'.format(i), 502, 450);
                    cv2.imshow('frame_{}'.format(i), sections[i])
            #     if time%25==0:
            #         cv2.imwrite('data/videoframe/{}_{:d}.jpg'.format(time,i), sections[i])
            else:
                cv2.imshow('frame', frame)

            if time%interval ==0:
                cv2.imwrite(os.path.join(outputpath,'{:d}.jpg'.format(time//interval)), frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        else:
            break
    print('Captures of video {} has been saved in {}'.format(videopath.split('/')[-1],outputpath))

cap.release()
cv2.destroyAllWindows()


class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        """
        It's O(n) Algotithm, using DP

        and O(n^2) will exceed the time limits

        f[k, i] represents the max profit up until prices[i] (Note: NOT ending with prices[i]) using at most k transactions.
        f[k, i] = max(f[k, i-1], prices[i] - prices[j] + f[k-1, j]) { j in range of [0, i-1] }
                  = max(f[k, i-1], prices[i] + max(f[k-1, j] - prices[j]))
        f[0, i] = 0; 0 times transation makes 0 profit
        f[k, 0] = 0; if there is only one price data point you can't make any money no matter how many times you can trade
        the key insight is that you don't need to caculate the max(f[k-1, j] - prices[j])) every time, because it can be updated gradually when loop
        """
        if not prices:
            return 0
        n = len(prices)
        K = 2
        f=[[ 0 for col in range(n)] for row in range(K+1)] #don't use *

        for k in range(1,K+1):
            tmpMax = f[k-1][0] - prices[0]
            for i in range(1,n):
                tmpMax = max(tmpMax,f[k-1][i]-prices[i])
                f[k][i] = max(f[k][i-1], prices[i] + tmpMax) #do not forget f[k][i-1]!!!
        return f[K][n-1]


#
# @lc app=leetcode.cn id=30 lang=python
#
# [30] 串联所有单词的子串
#
# https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/description/
#
# algorithms
# Hard (27.30%)
# Likes:    201
# Dislikes: 0
# Total Accepted:    21.2K
# Total Submissions: 73.8K
# Testcase Example:  '"barfoothefoobarman"\n["foo","bar"]'
#
# 给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
#
# 注意子串要与 words 中的单词完全匹配，中间不能有其他字符，但不需要考虑 words 中单词串联的顺序。
#
#
#
# 示例 1：
#
# 输入：
#  s = "barfoothefoobarman",
#  words = ["foo","bar"]
# 输出：[0,9]
# 解释：
# 从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
# 输出的顺序不重要, [9,0] 也是有效答案。
#
#
# 示例 2：
#
# 输入：
#  s = "wordgoodgoodgoodbestword",
#  words = ["word","good","best","word"]
# 输出：[]
#
#
#

# @lc code=start
class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        # from collections import Counter
        # if s == '' or len(words) == 0:
        #     return []
        # single_length = len(words[0])
        # all_length = len(words)*single_length

        # all_words = Counter(words[0])
        # for i in range(1,len(words)):
        #     all_words+=Counter(words[i])

        # def subfind(s,words):
        #     if len(s) == 0:
        #         return True
        #     # s的长度等于words中所有的长度
        #     for i in range(len(words)):
        #         if s[:single_length] == words[i]:
        #             if subfind(s[single_length:],words[:i]+words[i+1:]):
        #                 return True
        #     return False
        # result = []
        # for i in range(len(s)-all_length+1):
        #     if True:
        #         if subfind(s[i:i+all_length],words) == True:
        #             result.append(i)
        # return result

        # 巧妙啊
        from collections import Counter
        if not s or not words:return []
        one_word = len(words[0])
        all_len = len(words) * one_word
        n = len(s)
        words = Counter(words)
        res = []
        for i in range(0, n - all_len + 1):
            tmp = s[i:i+all_len]
            c_tmp = []
            # 人家这里是充分利用了长度相等，直接把词且分开，然后统计短语数量
            for j in range(0, all_len, one_word):
                c_tmp.append(tmp[j:j+one_word])
            if Counter(c_tmp) == words:
                res.append(i)
        return res

# @lc code=end
s = "barfoothefoobarman"
words = ["foo","bar"]

# s = 'a'
# words = []

solu = Solution()
print(solu.findSubstring(s,words))

30.串联所有单词的子串.py

30.串联所有单词的子串.py


import datetime
import pygal
from pygal.style import DarkStyle
from time import sleep
import random

TIMESTORAGE = []
for x in range(0,9):
    TIMESTORAGE.append(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    sleep(10)
    print("time added")

TEMPSTORAGE_1 = []
TEMPSTORAGE_2 = []
TEMPSTORAGE_3 = []
TEMPSTORAGE_4 = []

HUMIDSTORAGE_1 = []
HUMIDSTORAGE_2 = []
HUMIDSTORAGE_3 = []
HUMIDSTORAGE_4 = []

for x in range(0,10):

    TEMPSTORAGE_1.append(random.randrange(20,31))
    TEMPSTORAGE_2.append(random.randrange(20,31))
    TEMPSTORAGE_3.append(random.randrange(20,31))
    TEMPSTORAGE_4.append(random.randrange(20,31))

    HUMIDSTORAGE_1.append(random.randrange(50,91))
    HUMIDSTORAGE_2.append(random.randrange(50,91))
    HUMIDSTORAGE_3.append(random.randrange(50,91))
    HUMIDSTORAGE_4.append(random.randrange(50,91))

TEMP_CHART = pygal.Line(style=DarkStyle, width=1600, height=800, range=(0, 31))
TEMP_CHART.title = 'Temperature Chart for the Last Hour'
TEMP_CHART.x_labels = map(str, TIMESTORAGE)
TEMP_CHART.add('Sensor 1', TEMPSTORAGE_1)
TEMP_CHART.add('Sensor 2', TEMPSTORAGE_2)
TEMP_CHART.add('Sensor 3', TEMPSTORAGE_3)
TEMP_CHART.add('Sensor 4', TEMPSTORAGE_4)
TEMP_CHART.render_to_png('/home/aegon/Documents/STEM-Greenhouse/demotempchart.png')

HUMID_CHART = pygal.Line(style=DarkStyle, width=1600, height=800, range=(20, 91))
HUMID_CHART.title = 'Humidity Chart for the Last Hour'
HUMID_CHART.x_labels = map(str, TIMESTORAGE)
HUMID_CHART.add('Sensor 1', HUMIDSTORAGE_1)
HUMID_CHART.add('Sensor 2', HUMIDSTORAGE_2)
HUMID_CHART.add('Sensor 3', HUMIDSTORAGE_3)
HUMID_CHART.add('Sensor 4', HUMIDSTORAGE_4)
HUMID_CHART.render_to_png('/home/aegon/Documents/STEM-Greenhouse/demohumidchart.png')


from random import randint

from sympy.matrices import (
    Matrix,
    zeros,
)

from hekn.ciphertext import (
    AugmentedCiphertext,
    Ciphertext,
)
from hekn.keys import (
    ExtendedPublicKey,
    ExtendedSecretKey,
    PublicKey,
    SecretKey,
)

class HEkN:
    """
    Homomorphic encryption over Integers.

    Args:
        security (int):
            Security parameter in bits.
        dimensions (int):
            Dimension of the ciphertext.
            The higher the value, the more secure the system is.
        entropy (float):
            Entropy of the messages to be decrypted.
    """

    def __init__(self, security: int, dimensions: int, entropy: float):
        self._security = security
        self._dimensions = dimensions

        if dimensions == 1:
            self._secret_key = SecretKey(security=security, entropy=entropy)
            self._public_key = PublicKey(secret_key=self._secret_key)
        else:
            self._secret_key = ExtendedSecretKey(
                security=security,
                entropy=entropy,
                dimension=dimensions,
            )
            self._public_key = ExtendedPublicKey(secret_key=self._secret_key)

    def encrypt(self, message: int) -> Ciphertext:
        ciphertext = (
            (message + self._secret_key.p * randint(1, self._secret_key.q))
            % self._public_key.pq
        )
        ciphertext = Matrix(1, self._dimensions, lambda i, j: ciphertext)

        if self._dimensions == 1:
            return Ciphertext(
                ciphertext=ciphertext,
                public_key=self._public_key,
            )

        ciphertext = self._extended_encryption(ciphertext=ciphertext)
        return AugmentedCiphertext(
            ciphertext=ciphertext,
            public_key=self._public_key,
        )

    def _extended_encryption(self, ciphertext: Matrix) -> Matrix:
        encryption_matrix = self._secret_key.encryption_matrix

        extended_part = zeros(rows=1, cols=self._dimensions)
        for i in range(1, self._dimensions):
            noise = randint(0, self._public_key.pq)
            extended_part += encryption_matrix.row(i).applyfunc(
                lambda element: element * noise
            )

        return (ciphertext + extended_part).applyfunc(
            lambda element: element % self._public_key.pq
        )

    def decrypt(self, ciphertext: Ciphertext) -> int:
        if self._dimensions == 1:
            return ciphertext.raw[0] % self._secret_key.p

        decryption_vector = self._secret_key.decryption_vector
        message = decryption_vector.dot(ciphertext.raw) % self._secret_key.p
        return message

if __name__ == "__main__":
    hom = HEkN(security=128, dimensions=1, entropy=32)

    c1 = hom.encrypt(message=8)
    c2 = hom.encrypt(message=8)

    c3 = c1 + c2
    c4 = c1 * c2

    m = hom.decrypt(ciphertext=c3)
    m2 = hom.decrypt(ciphertext=c4)

    print(m)
    print(m2)


class LinkedNode:
    def __init__(self, elem, next_=None):
        self.elem = elem
        self.next = next_

class LinkedListUnderflow(ValueError):
    pass

class LinkedList:
    def __init__(self):
        self._head = None

    def is_empty(self):
        return self._head is None

    def prepend(self, elem):
        self._head = LinkedNode(elem, self._head)

    def pop(self):
        if self._head is None:
            raise LinkedListUnderflow('in pop')
        e = self._head.elem
        self._head = self._head.next
        return e

    def append(self, elem):
        if self._head is None:
            self._head = LinkedNode(elem)
            return
        p = self._head
        while p.next is not None:
            p = p.next
        p.next = LinkedNode(elem)

    def pop_last(self):
        if self._head is None:
            raise LinkedListUnderflow('in pop_last')
        p = self._head
        if p.next is None:
            e = p.elem
            self._head = None
            return e
        while p.next.next is not None:
            p = p.next
        e = p.next.elem
        p.next = None
        return e

    def find(self, predicate):
        p = self._head
        while p is not None:
            if predicate(p.elem):
                return p.elem
            p = p.next

    def filter(self, predicate):
        p = self._head
        while p is not None:
            if predicate(p.elem):
                yield p.elem
            p = p.next

    def print_all(self):
        p = self._head
        while p is not None:
            print(p.elem, end='')
            if p.next is not None:
                print(', ', end='')
            p = p.next
        print('')

    def for_each(self, process):
        p = self._head
        while p is not None:
            process(p.elem)
            p = p.next

    def elements(self):
        p = self._head
        while p is not None:
            yield p.elem
            p = p.next

def predicate_judge(x):
    if 5 <= x <= 15:
        return True
    else:
        return False

def process_add_one(x):
    print(x + 10)

def test():
    l1 = LinkedList()
    for i in range(5):
        l1.prepend(i)
    for i in range(5, 10):
        l1.append(i)
    l1.print_all()
    print(l1.find(predicate_judge))
    print(l1.pop())
    l1.print_all()
    print(l1.pop_last())
    l1.print_all()
    l1.for_each(process_add_one)
    l1.print_all()
    for x in l1.elements():
        print(x, end=' ')
    print('')
    for x in l1.filter(predicate_judge):
        print(x, end=' ')
    print('')

if __name__ == '__main__':
    test()