import numpy as np
from scipy.spatial import distance as dist
import copy
import math
import cv2
import serial
import time
from fractions import gcd
import sys
from numpy.linalg import multi_dot
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QMainWindow
from PyQt5.QtWidgets import QSizePolicy, QSlider, QRadioButton, QGridLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QObject, QThread, pyqtSignal, QSize, Qt
#import GUI_attempt

#KL25=serial.Serial('COM6',256000,timeout=1)#open serial port
# two Lists used for real time plottting of the left motor and right motor
Rmotor= []
Lmotor= []

class robotClass:
    def __init__(self, pos = [], radius = 0, team = '-no team!-', ID = '-no ID!-'):
        self.pos = pos # centre coordinates [x,y]
        self.radius = radius # calculated radius of robot (based on centre dot)
        self.team = team # team 'B'  or 'Y'
        self.angle = 999 # angle of orientation
        self.ID = ID # ID of robot on a team
        # ID markings
        self.circles = [] # [x,y,color]

    # this is a method to add a new circle for IDing the robot
    def newMarking(self, circle = [0,0,[0,0,0]]):
        self.circles.append(circle)

class ballClass:
    def __init__(self, x = 0, y = 0):
        self.pos = [x, y]

roboList = []       # holds all robots currently seen- resets every loop
roboIDmarks = []    # holds all potential robot ID marks seen ('G' or 'P')
ball = None         # holds ball position in ballClass type object
IDdRobots = []      # potentially used for previous state- probably updated every loop

param1val = 75
param2val = 15
valueMin = 125

def sampleCubicSplinesWithDerivative(points, tangents, resolution):
    '''
    Compute and sample the cubic splines for a set of input points with
    optional information about the tangent (direction AND magnitude). The
    splines are parametrized along the traverse line (piecewise linear), with
    the resolution being the step size of the parametrization parameter.
    The resulting samples have NOT an equidistant spacing.
    Arguments:      points: a list of n-dimensional points
                    tangents: a list of tangents
                    resolution: parametrization step size
    Returns:        samples
    Notes: Lists points and tangents must have equal length. In case a tangent
           is not specified for a point, just pass None. For example:
                    points = [[0,0], [1,1], [2,0]]
                    tangents = [[1,1], None, [1,-1]]
    '''
    resolution = float(resolution)
    points = np.asarray(points)
    nPoints, dim = points.shape

    # Parametrization parameter s.
    dp = np.diff(points, axis=0)                 # difference between points
    dp = np.linalg.norm(dp, axis=1)              # distance between points
    d = np.cumsum(dp)                            # cumsum along the segments
    d = np.hstack([[0],d])                       # add distance from first point
    l = d[-1]                                    # length of point sequence
    nSamples = int(l/resolution)                 # number of samples
    s,r = np.linspace(0,l,nSamples,retstep=True) # sample parameter and step

    # Bring points and (optional) tangent information into correct format.
    assert(len(points) == len(tangents))
    data = np.empty([nPoints, dim], dtype=object)
    for i,p in enumerate(points):
        t = tangents[i]
        # Either tangent is None or has the same
        # number of dimensions as the point p.
        assert(t is None or len(t)==dim)
        fuse = list(zip(p,t) if t is not None else zip(p,))
        data[i,:] = fuse

    # Compute splines per dimension separately.
    samples = np.zeros([nSamples, dim])
    for i in range(dim):
        poly = interpolate.BPoly.from_derivatives(d, data[:,i])
        samples[:,i] = poly(s)
    return samples

def colorID(hue, sat, val):
    color = 'X' # Default case, 'X' will print an error for an unrecognized element
    if(val > valueMin):
        if (hue < 128 and hue >= 90):
        #if (hue < 250 and hue >= 150):
            color = 'B' # Blue team circle
        elif (hue < 35 and hue > 25 and sat > 80):
            color = 'Y' # Yellow team circle
        elif (hue >= 128 or (hue <= 9 and sat < 120)): # Must address loop in hue
            color = 'P' # Purple ID circle
        elif (hue < 90 and hue >= 43):
            color = 'G' # Green ID circle
        elif ((hue <= 12 and hue >= 3 and sat > 40) or (hue <=35 and hue >12 and sat < 80)):
            color = 'O' # Ball!
            #print(hue,sat,val)
        #else:
        #    print("unrecognized",hue,sat,val) # good for debugging unrecognized circles
        #    cv2.waitKey(1000)
    return color

# IDcircle()
# K.C. & E.H., Nov. 24th, 2018
# This function identifies any given circle based on its color and location. Although it
# does not return anything, it assigns the circle to its appropriate global variable
# (a robot object, ID mark list or ball object).
#              (input) -> (function) -> (output)
#               [x,y,r] -> ID_circle() -> none
# v1:
# Must implement all identifying functions. closestBot() is not fully developed, and must
# be added when completed.
def IDcircle(img, circle):
    global ball # so we can assign the ball its position globally

    x=int(circle[0])
    y=int(circle[1])
    #r=int(circle[2])

    # Getting spaced pixels within the circle
    #diffx = [int(x+r/2), int(x-r/2)]
    #for idx,posx in list(enumerate(diffx)):
    #    if(posx >= len(img[0])):
    #        diffx[idx] = x
    #    elif(posx < 0):
    #        diffx[idx] = 0
    #diffy = [int(y+r/2), int(y-r/2)]
    #for idx2,posy in list(enumerate(diffy)):
    #    if(posy >= len(img)):
    #        diffy[idx2] = y
    #    elif(posy < 0):
    #        diffy[idx2] = 0
    #print("Colors",img[y,x,0],img[y,x,1],img[y,x,2])
    hue = img[y,x,0]
    sat = img[y,x,1]
    val = img[y,x,2]
    # taking the average hue, saturation and value of a circle
    #hue = sum([img[y,x,0],img[y,diffx[0],0],img[y,diffx[1],0],img[diffy[0],x,0],img[diffy[1],x,0]])/5
    #sat = sum([img[y,x,1],img[y,diffx[0],1],img[y,diffx[1],1],img[diffy[0],x,1],img[diffy[1],x,1]])/5
    #val = sum([img[y,x,2],img[y,diffx[0],2],img[y,diffx[1],2],img[diffy[0],x,2],img[diffy[1],x,2]])/5

    # getting the color of the circle with the averaged pixel
    color = colorID(hue, sat, val)
    #print(hue, sat, val,'   so the Circle is ', color)
    #cv2.waitKey(1000)

    # if its blue or (if its yellow) --> Robot center/new robot
    if (color == 'B') or (color == 'Y'):
        # passes in position [x,y], radius and color
        # where the radius is calced with: 25 radius centre in 85 radius robot so ~ 3.4 times radius
        roboList.append(robotClass([x,y],circle[2]*4,color))
        #print('Robot seen!')

    # if green or purple --> Robot ID marking
    elif (color == 'G') or (color == 'P'):
        roboIDmarks.append([x,y,color])

    # if orange --> Ball location
    elif (color == 'O'):
        ball = ballClass(x,y)

# assignIDmarks()
# E.H., Dec, 2018
# This function cycles through the globally stored roboIDmarks list and assigns them to the
# closest available robot, provided they don't already have 4 assigned
def assignIDmarks(robot):
    #if isinstance(roboList, type(None)) == 0:
        # Assign each robot its four closest marks
        #for robot in roboList:
    closestMarks = [] # indices of the closest four marks to the robot center
                                # [index in roboIDmarks, euclidean distance]
    #furthestMark = [0,0] # [index in closestMarks, euclidean distance]

    # Assign this robot its four closest marks
    #for i, mark in enumerate(list(roboIDmarks)):
    for mark in roboIDmarks:
        markDist = dist.euclidean([mark[0],mark[1]],robot.pos)

        if(markDist < robot.radius and len(robot.circles) < 4):
            robot.newMarking(mark)
            closestMarks.append(markDist)
        elif(markDist < robot.radius):
            for i, currentcircle in enumerate(list(robot.circles)):
                if markDist < closestMarks[i]:
                    robot.circles[i] = mark
                    closestMarks[i] = markDist

        # If there aren't already four marks given to the robot,
        # just give it whatever is available in order to initialize robot.circles[]
        #if len(robot.circles) < 4:
        #    if markDist < robot.radius:
        #        robot.newMarking(mark)
        #    closestMarks[i] = [i, markDist]
        #    if markDist > furthestMark[1]:
        #        furthestMark = [i, markDist]

        ## If there is a closer value than the furthest currently in robot.circles[]
        ## replace the current furthest with this new one
        #elif markDist < furthestMark[1]:
        #    if markDist < robot.radius:
        #        robot.circles[furthestMark[0]] = mark
        #    closestMarks[furthestMark[0]] = [i, markDist]

        #    furthestMark[1] = markDist

        #    # redetermine the furthest mark within the current closest marks
        #    for j, qark in enumerate(closestMarks):
        #        if qark[1] > furthestMark[1]:
        #            furthestMark = [j, qark[1]]

        #else:
            #print(robot.radius)

    # * The below code was intended to shorten the list of circles in order to
    # improve efficiency, however it had an error due to the index provided by
    # "wark[0]" being incorrect after the element in the previous iteration
    # was deleted... *
    ## Remove the marks that were assigned to a robot- this will potentially make
    ## assigning the rest of the marks much quicker with larger numbers of robots
    #for wark in closestMarks:
    #    del roboIDmarks[wark[0]]
    #else:
    #    print("No robots detected, but there are ID marks..?")

# RoboID()
# E.H., Jan, 2019
# This function reads the sorted robot.circles list and assigns an ID (robot.ID = x)
# to the robot. If the IDs are not properly sorted, this will not work
# v2:
# Has all IDs implemented
def RoboID(robot):
    #for robot in roboList:
    if len(robot.circles) == 4:
        if robot.circles[0][2] == 'P': # circle 1
            if robot.circles[1][2] == 'P': # circle 2
                if robot.circles[2][2] == 'P': # circle 3
                    if robot.circles[3][2] == 'P': # circle 4
                        robot.ID = 'ID9'
                    elif robot.circles[3][2] == 'G': # circle 4
                        robot.ID = 'ID4'
                elif robot.circles[2][2] == 'G': # circle 3
                    if robot.circles[3][2] == 'P': # circle 4
                        robot.ID = 'ID0'
                    elif robot.circles[3][2] == 'G': # circle 4
                        robot.ID = 'ID10'
            elif robot.circles[1][2] == 'G': # circle 2
                if robot.circles[2][2] == 'P': # circle 3
                    if robot.circles[3][2] == 'G': # circle 4
                        robot.ID = 'ID7'
                elif robot.circles[2][2] == 'G': # circle 3
                    if robot.circles[3][2] == 'P': # circle 4
                        robot.ID = 'ID3'
        elif robot.circles[0][2] == 'G': # circle 1
            if robot.circles[1][2] == 'P': # circle 2
                if robot.circles[2][2] == 'P': # circle 3
                    if robot.circles[3][2] == 'G': # circle 4
                        robot.ID = 'ID5'
                elif robot.circles[2][2] == 'G': # circle 3
                    if robot.circles[3][2] == 'P': # circle 4
                        robot.ID = 'ID1'
            elif robot.circles[1][2] == 'G': # circle 2
                if robot.circles[2][2] == 'P': # circle 3
                    if robot.circles[3][2] == 'P': # circle 4
                        robot.ID = 'ID11'
                    elif robot.circles[3][2] == 'G': # circle 4
                        robot.ID = 'ID6'
                elif robot.circles[2][2] == 'G': # circle 3
                    if robot.circles[3][2] == 'P': # circle 4
                        robot.ID = 'ID2'
                    elif robot.circles[3][2] == 'G': # circle 4
                        robot.ID = 'ID8'

# angle()
# E.H., Jan, 2019
# This function determines the angle of a passed robot using the IDs assigned to the robot
# by observing relative positions of said IDs. The angle determined is assigned to the robot
# at the end of the function, and reassignIDs() is called at the end to allow for identification
# of the robot.
#              (input) -> (function) -> (output)
#               ID marks -> angle() -> robot.angle
def angle(robot):
    topIDs = [] # i.e. the two circles on the flat end of the robot
    bottomIDs = []
    theta1 = 999 # An impossible number for if statements later
    theta2 = 999

    # Uses the cosine law to figure out the angle every possible combo of ID circles makes
    # with the center of the robot (team ID), assigning to top or bottom IDs based on this angle
    for ii in range(len(robot.circles)-1):
        for jj in range(ii + 1, len(robot.circles)):
            temp1 = robot.circles[ii]
            temp2 = robot.circles[jj]

            # Determining distance between the different IDs
            a = dist.euclidean([temp1[0],temp1[1]],robot.pos) # Distance from ID 1 to centre
            b = dist.euclidean([temp2[0],temp2[1]],robot.pos) # Distance from ID 2 to centre
            c = dist.euclidean([temp1[0],temp1[1]],[temp2[0],temp2[1]]) # Distance from ID 1 to ID 2
            try:
                theta = math.degrees(math.acos((c**2 - b**2 - a**2)/(-2.0 * a * b))) #CRASHES ON RARE OCCASIONS
            except:
                print('Theta Error')
            if theta > 100 and theta < 130: # Ideally 114.84 degrees
                topIDs.append(temp1)
                topIDs.append(temp2)

            if theta > 45 and theta < 75: # Ideally 65.16 degrees
                bottomIDs.append(temp1)
                bottomIDs.append(temp2)

            # the other ID pairs will be either ~180 or ~90 degrees

    # Takes the top two IDs and their average position, creating a vector to that point from the
    # center of the robot which the robot's angle can be derived from
    if len(topIDs) == 2:
        xMean = (topIDs[0][0] + topIDs[1][0])/2
        yMean = (topIDs[0][1] + topIDs[1][1])/2

        xDiff = xMean - robot.pos[0]
        yDiff = yMean - robot.pos[1]
        # Angle points in the direction the robot is facing
        theta1 = math.degrees(math.atan2(yDiff,xDiff))
    #else:
        #print("top went wrong...")

    # Takes the bottom two IDs and their average position, creating a vector from that point to
    # the center of the robot which the robot's angle can be derived from
    # (this is the opposite direction from the other one so the angle will be the same)
    if len(bottomIDs) == 2:
        xMean2 = (bottomIDs[0][0] + bottomIDs[1][0])/2
        yMean2 = (bottomIDs[0][1] + bottomIDs[1][1])/2

        xDiff2 = robot.pos[0] - xMean2
        yDiff2 = robot.pos[1] - yMean2
        # Negative for both of these to get an angle that is front facing
        theta2 = math.degrees(math.atan2(yDiff2,xDiff2))
    #else:
    #    print("bottom is wrong")

    # Averages the vectors to get a better approx of the true angle
    if theta2 != 999 and theta1 != 999:
        xMean = (math.cos(math.radians(theta1)) + math.cos(math.radians(theta2)))/2
        yMean = (math.sin(math.radians(theta1)) + math.sin(math.radians(theta2)))/2
        theta = math.degrees(math.atan2(yMean,xMean))
        robot.angle = theta

    # If one of the vector calcs failed, just take the one that worked
    elif theta2 != 999 and theta1 == 999:
        theta = theta2
        robot.angle = theta
    elif theta2 == 999 and theta1 != 999:
        theta = theta1
        robot.angle = theta
    else:
        return "ERROR"

    reassignIDs(robot,topIDs,bottomIDs)

# reassignIDs()
# E.H., Jan, 2019
# This function reassigns the IDs found in a robot depending on the angle the robot
# is facing. It is helpful to draw out a visualization of this to understand why
# certain angles are associated with certain indices in robot.circles
#              (input) -> (function) -> (output)
#              angle -> reassignIDs() -> robot.circles (sorted)
def reassignIDs(robot,topIDs,bottomIDs):
    # Reassignment of IDs only works if all four have been recognized
    if len(robot.circles) == 4 and len(topIDs) == 2 and len(bottomIDs) == 2:
        # I suggest drawing this out if you're having a hard time visualizing it-
        # see the design document for further detail on which ID is which
        if robot.angle <= 45 and robot.angle >= -45:
            if topIDs[0][1] > topIDs[1][1]:
                robot.circles[0] = topIDs[1]
                robot.circles[1] = topIDs[0]
            else:
                robot.circles[0] = topIDs[0]
                robot.circles[1] = topIDs[1]
            if bottomIDs[0][1] > bottomIDs[1][1]:
                robot.circles[2] = bottomIDs[1]
                robot.circles[3] = bottomIDs[0]
            else:
                robot.circles[2] = bottomIDs[0]
                robot.circles[3] = bottomIDs[1]
        if robot.angle < 135 and robot.angle > 45:
            if topIDs[0][0] > topIDs[1][0]:
                robot.circles[0] = topIDs[0]
                robot.circles[1] = topIDs[1]
            else:
                robot.circles[0] = topIDs[1]
                robot.circles[1] = topIDs[0]
            if bottomIDs[0][0] > bottomIDs[1][0]:
                robot.circles[2] = bottomIDs[0]
                robot.circles[3] = bottomIDs[1]
            else:
                robot.circles[2] = bottomIDs[1]
                robot.circles[3] = bottomIDs[0]
        if robot.angle < -45 and robot.angle > -135:
            if topIDs[0][0] > topIDs[1][0]:
                robot.circles[0] = topIDs[1]
                robot.circles[1] = topIDs[0]
            else:
                robot.circles[0] = topIDs[0]
                robot.circles[1] = topIDs[1]
            if bottomIDs[0][0] > bottomIDs[1][0]:
                robot.circles[2] = bottomIDs[1]
                robot.circles[3] = bottomIDs[0]
            else:
                robot.circles[2] = bottomIDs[0]
                robot.circles[3] = bottomIDs[1]
        if robot.angle <= -135 or robot.angle >= 135:  # must be "or", as sign swaps at 180
            if topIDs[0][1] > topIDs[1][1]:
                robot.circles[0] = topIDs[0]
                robot.circles[1] = topIDs[1]
            else:
                robot.circles[0] = topIDs[1]
                robot.circles[1] = topIDs[0]
            if bottomIDs[0][1] > bottomIDs[1][1]:
                robot.circles[2] = bottomIDs[0]
                robot.circles[3] = bottomIDs[1]
            else:
                robot.circles[2] = bottomIDs[1]
                robot.circles[3] = bottomIDs[0]
    return

# stoprobot()
# E.H., Mar, 2019
# This function will stop any robots passed into it by issuing stop commands to
# the specified robot. Alternatively, if 'all' is passed in, it will stop all robots.
def stoprobot(ID):
    packet = bytearray()
    if(ID == 'all'): # Send stop commands to all robots
        for robot in range(0,12):
            packet.append(0xFF) # start bit
            packet.append(robot)  #Robot ID
            packet.append(0)
            packet.append(0)
            packet.append(0)
            packet.append(0)
            packet.append(0)
            packet.append(0xFF) # stop bit
            KL25.write(packet)
            packet = bytearray()
    elif(ID >= 0 and ID <= 11): # Only accept valid IDs
        packet.append(0xFF) # start bit
        packet.append(ID)  #Robot ID
        packet.append(0)
        packet.append(0)
        packet.append(0)
        packet.append(0)
        packet.append(0)
        packet.append(0xFF) # stop bit
        KL25.write(packet)

## PD controller Parametters
error1=0
error_prior1=0
error2=0
error_prior2=0

#Motor Speed Parameters
VrMax = 800
VlMax = VrMax
VrMin = 0x15
VlMin = VrMin

## The dt variable should be variable based on the number of frame rates obtained by the CV system.
####### This frame rate should be calculated. #########
dt=1/10
derivative1=0
L=18                #Robot Diameter
R=3.5               #Wheel Radius
dirR=0
dirL=0
umax=575            #Max input for position control
u2max= 220
kp= 0.65

flag =  0
kd=0.5

temp1=0
temp2=0
test = 0
counter = 0

cap = cv2.VideoCapture(cv2.CAP_DSHOW + 1) # 0 if your pc doesn't have a webcam, probably 1 if it does
def mainLoop():
    print("new loop\n\r")
    # Declaring global variables so they can be cleared every loop
    global roboList, roboIDmarks, circles, ball, IDdRobots

    global error1,error_prior1,error2,error_prior2,dt,derivative1,L,R,dirR,dirL,umax,u2max,kp
    global flag,kd,VrMax,VlMax,temp1,temp2,test,counter

    #Mikes Global Variables
    global points
    global tangents

    #cap = cv2.VideoCapture(cv2.CAP_DSHOW + 0) # 0 if your pc doesn't have a webcam, probably 1 if it does
    # https://stackoverflow.com/questions/52043671/opencv-capturing-imagem-with-black-side-bars
    # MSMF doesn't like being scaled up apparently, so switch from it (default) to DirectShow
    # so we can scale up the resolution read from the camera

    # Scaling up from 640x480 to HD 1280x720
    #cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    #cap.set(cv2.CAP_PROP_FRAME_HEIGHT,720)
    #cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    #cap.set(cv2.CAP_PROP_FRAME_HEIGHT,720)

    #while(True):
    #  while(KL25.inWaiting()==0):

    ret,frame = cap.read() # reading the video capture into a dummy var and frame

    #cv2.waitKey(50)

    # Reinitializing robot data (prevents buildup of data accross frames)
    roboList = []
    roboIDmarks= []
    circles = []
    ball = None

    #Mike's Added Value Parameters
    points = []
    tangents = []
    resolution = 0.2

    # Histogram equalization for colors (haven't tested with this)
    #img_yuv = cv2.cvtColor(ii, cv2.COLOR_BGR2YUV)

    ### equalize the histogram of the Y channel
    #img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])

    ### convert the YUV image back to RGB format
    #frame_yuv = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)

    # blurring image for less errant circles and better color recognition later
    # d = 5 as that is the recommended nearest neighbour for real time
    # sigmaColor = 150 to produce large blending effect
    # sigmaSpace is limited by d, so I suspect it doesn't matter
    blurred_img = cv2.bilateralFilter(frame,8,150,150)

    # HSV color space conversion
    hsv= cv2.cvtColor(blurred_img,cv2.COLOR_BGR2HSV)

    # Color masking, not necessary due to blurring, but might be worth looking into further
    #lower_rangeG = np.array([0,0,0]) # Hue, Saturation, Value mask lower limit
    #upper_rangeG = np.array([180,255,255]) # " , " , " " upper limit

    #mask = cv2.inRange(hsv, lower_rangeG, upper_rangeG) # mask for original frame with only good color
    #result = cv2.bitwise_and(blurred_img,blurred_img,mask=mask)
    result = blurred_img

    #cv2.imshow("blurred image",result)

    hsv_out_gray= cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)

    #cv2.imshow("houghin",hsv_out_gray)

    # Some notes on the HoughCircles function:
    #  Utilizes edge detection to draw tangent lines, recognizing a circle where perpendicular lines to tangents
    #  meet, depending on the intensity of the intersecting tangent lines.
    #  param1: higher threshold for Canny edge detection (lower is half of this)
    #  param2: accumulator threshold for circle center detection- i.e. the lower it is, the less circular an object
    #          needs to be to be recognized as a circle
    #  minDist: Specifies minimum distance between circles (the 4th input to the function)
    #
    # from documentation: cv2.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) → circles
    circles = cv2.HoughCircles(hsv_out_gray,cv2.HOUGH_GRADIENT,1,minDist=5,param1=param1val,param2=param2val,minRadius=1,maxRadius=15)

    cv2.waitKey(1) # cv2.waitKey() is required to display images- waits 1 millisecond here

    img = copy.deepcopy(frame) # Sometimes if you copy stuff in Python, changes made to a copied variable end up in original
                                # which necessitates a deepcopy

    if isinstance(circles, type(None)) == 0:
        for circle in circles[0,:]:
            IDcircle(hsv, circle) # ID all the circles recognized by color
            # draw the outer circle
            cv2.circle(img,(circle[0],circle[1]),circle[2],(0,255,0),2)
            # draw the center of the circle
            cv2.circle(img,(circle[0],circle[1]),2,(0,0,255),3)

        if isinstance(ball, type(None)) == 0:
            # Draw a blue circle on the ball
            cv2.circle(img,(ball.pos[0],ball.pos[1]),10,(200,0,0),5)
            cv2.putText(img, str(ball.pos), (ball.pos[0]+20,ball.pos[1]+20), cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)

        if (isinstance(roboIDmarks, type(None)) == 0) & (isinstance(roboList, type(None)) == 0):
            for robot in roboList:
                assignIDmarks(robot) # Assign the ID marks observed to their appropriate robot
                angle(robot)         # Determine angle of robots seen
                RoboID(robot)        # Give robots seen an ID

                # Draw the robot circles seen robot by robot
                # Draw a black circle on the centre of the robot
                cv2.circle(img,(robot.pos[0],robot.pos[1]),10,(0,0,0),3)
                #if isinstance(robot.angle, type(None)) == 0:
                #    # Display the robot's angle
                #    cv2.putText(img, str(round(robot.angle,1)), (robot.pos[0]+ 100, robot.pos[1] + 130),
                #                cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)
                #    # Display the robot's position
                #    cv2.putText(img, str(robot.pos), (robot.pos[0]+ 100, robot.pos[1] + 100),
                #                cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)
                #    # Display the robot's ID
                #    cv2.putText(img, robot.ID, (robot.pos[0]+ 100, robot.pos[1] + 70),
                #                cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)
                #    # Display the robot's Team
                #    cv2.putText(img, robot.team, (robot.pos[0]+ 100, robot.pos[1] + 40),
                #                cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)
                for mark in robot.circles:
                    # Draw a black circle on every ID mark
                    cv2.circle(img,(mark[0],mark[1]),10,(0,0,0),3)
        flag = 0 # go ahead and print "no circles detected" again

    elif(flag == 0):
        #print("no circles detected")
        flag = 1 # don't print this again

    # Display drawn on frame and original frame
    #cv2.imshow('circles on stream',img)
    cv2.imshow('original stream',frame)

    #if cv2.waitKey(1) & 0xFF == ord('\r'): # if enter is pressed, stop running
    #    break

    # when the ball does not get detected
    if (isinstance(ball, type(None)) != 0):
        ball = ballClass(temp1,temp2)

    #This if statement is simply for initialization, there has to be a better way of doing this
    if(counter == 0):
        #Mike's added value stuff Initialization
        points = []
        tangents = []
        resolution = 0.2
        points.append([rob.pos[0],rob.pos[1]]) #Robot Position
        points.append([ball.pos[0],ball.pos[1]]) #Ball Position
        points.append([600,220]) #Net Position

        #Finding the angle at which the robot approaches
        approach_x = (points[2][0] - points[1][0])
        approach_y = (points[2][1] - points[1][1])
        common_divisor = abs(gcd(approach_x,approach_y)) #Absolute value of the greatest common divisor
        approach_x = approach_x/common_divisor #Divide by common divisor
        approach_y = approach_y/common_divisor #Divide by common divisor

        #Tangents for alligning robot with ball and net
        tangents.append([math.tan(45*np.pi/180),1]) #Robot position, Slope converted from radians, this value is whatever angle the robot is currently facing
        tangents.append([approach_x, approach_y]) #Ball position
        tangents.append([approach_x, approach_y]) #Net position

    packet = bytearray()                    # ** Should this be within the for loop below?
    #packet.append(0xff)
    #packet.append(0x01)  #id
    #packet.append(0x30)  #mtr1
    #packet.append(0x01)  #dir1
    #packet.append(0x30)  #mtr2
    #packet.append(0x01)  #dir2
    #packet.append(0x01)  #kick
    #packet.append(0xff)

    #KL25.write(packet)
    #data = KL25.read(4) #Reading and Printing slows down the system incredibly, do not use for the demonstration
    #print(data.decode('ISO-8859-1')) #Reading and Printing slows down the system incredibly, do not use for the demonstration

    for rob in roboList:
        if(rob.ID != '-no ID!-') & (isinstance(roboList, type(None)) == 0):
            robotsID = int(''.join(filter(str.isdigit,rob.ID))) # extracting integer ID number from rob.ID
            # if the robot has a radius larger than the distance between it and the edge of the frame
            # skip over this robot
            if(rob.radius < (rob.pos - len(img)) or rob.radius < (rob.pos - len(img[0]))):
                stoprobot(robotsID)
                continue
            else:
                if(abs(abs(rob.angle)-180)>20 and counter>5):
                    if (abs(rob.angle-test) >=200 and counter > 5):
                        rob.angle=test#something is wrong with the angle measurement

                else:
                    if (abs(abs( rob.angle)-abs(test)) >=50 and counter>5 ):
                        rob.angle=test#something is wrong with the angle measurement
                test=rob.angle
                #print("rob.angle",rob.angle)
                # Display the robot's angle
                cv2.putText(img, str(round(rob.angle,1)), (rob.pos[0]+ 100, rob.pos[1] + 130),
                            cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)
                # Display the robot's position
                cv2.putText(img, str(rob.pos), (rob.pos[0]+ 100, rob.pos[1] + 100),
                            cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)
                # Display the robot's ID
                cv2.putText(img, rob.ID, (rob.pos[0]+ 100, rob.pos[1] + 70),
                            cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)
                # Display the robot's Team
                cv2.putText(img, rob.team, (rob.pos[0]+ 100, rob.pos[1] + 40),
                            cv2.FONT_HERSHEY_DUPLEX, 1, (255,255,255), 3)

                #Mike's Added Value Stuff
                points.append([rob.pos[0],rob.pos[1]]) #Robot Position
                points.append([ball.pos[0],ball.pos[1]]) #Ball Position
                points.append([600,220]) #Net Position

                #Finding the angle at which the robot approaches
                approach_x = (points[2][0] - points[1][0])
                approach_y = (points[2][1] - points[1][1])
                common_divisor = abs(gcd(approach_x,approach_y)) #Absolute value of the greatest common divisor
                approach_x = approach_x/common_divisor #Divide by common divisor
                approach_y = approach_y/common_divisor #Divide by common divisor

                # Interpolate with different tangent lengths, but equal direction.
                scale = 0.1 #Tunable Parameter, the closer to 0 the tighter the spline
                tangents_new = np.dot(tangents, scale*np.eye(2))
                samples_new = np.float32(sampleCubicSplinesWithDerivative(points, tangents_new, resolution))

                #Find the slope to the next point
                next_point_x =  np.float32(samples_new[round(len(samples_new)/10)][0] - points[0][0]) #Change in x between the robot and next point
                next_point_y =  np.float32(samples_new[round(len(samples_new)/10)][1] - points[0][1]) #Change in y between the robot and next point
                tangents[0][0] = math.atan2(next_point_y,next_point_x) #This value is the angle in radians that the robot must face for its path
                tangents[0][1] = 1
                tangents[1][0] = approach_x #x slope
                tangents[1][1] = approach_y #y slope
                tangents[2][0] = approach_x #x slope
                tangents[2][1] = approach_y #y slope

                points = np.asarray(points)
                tangents = np.asarray(tangents)
                trajectory = math.degrees(tangents[0][0]) #Angle in degrees

                #Printing Mike's Stuff
                print(samples_new[round(len(samples_new)/10)][0]) #X position with resolution of 10, if this is not good enough divide into smaller pieces perhaps
                print(samples_new[round(len(samples_new)/10)][1]) #X position with resolution of 10, if this is not good enough divide into smaller pieces perhaps
                print(trajectory) #Angle output in degrees

                #Display splines on the live feed & plot
                #path_plot = plt.scatter(samples3[:,0], samples3[:,1], marker='o', label='samples3')
                k = 0
                for k in range(0,len(samples3)):
                    cv2.circle(img, (samples3[k,0], samples3[k,1]), 1, (0, 255, 255),5)

                #image1 = path_plot.imshow(grab_frame(cap))
                plt.ion()
                plt.show()

                ####### Angle Control
                if rob.angle == 999:
                    rob.angle=test

                #error2=math.degrees((math.atan2(ball.pos[1]-rob.pos[1],ball.pos[0]-rob.pos[0])))-rob.angle
                error2=math.degrees((math.atan2(next_point_y-rob.pos[1],next_point_x-rob.pos[0])))-rob.angle #error2 for Mike's Added Value

                #regulate the angle to reduce ambiguity
                if (abs(error2)<180):
                        error2=error2
                elif (np.sign(error2)==-1):
                        error2=error2+360
                elif (np.sign(error2)==1):
                        error2=error2-360
                else:
                        print("done")
                print("error2",error2)

                derivative2=(error2-error_prior2) #Shouldn't this be divided by a dt?
                error_prior2=error2
                u2=  (kp*error2)   +   (kd*derivative2)
                print("u2",u2)

			    #Error In Position
                ####### Position Control #######
                temp1=ball.pos[0]
                temp2=ball.pos[1]
                #error1 = ((ball.pos[0]-rob.pos[0])**2+(ball.pos[1]-rob.pos[1])**2)**0.5
                error1 = ((next_point_x-rob.pos[0])**2+(next_point_y-rob.pos[1])**2)**0.5 #error1 for Mike's Added value

                derivative1=(error1-error_prior1)
                error_prior1=error1
                print("error1:",error1)
                u1=  ( kp*error1 )   +  ( kd*derivative1 )

                # Assigning the direction of motors based on the wheel velocities sign
                if (error2>=-15 and error2<=15):
                    error2=error2
                    dirR=1
                    dirL=1
                else:
                    if np.sign(error2)==-1:
                        dirR=0
                        dirL=1
                    elif np.sign(error2)==1:
                        dirR=1
                        dirL=0

                ## Setting limits to the inputs
                if(u1 > umax):
                    u1=umax
                if(u1 < -umax):
                    u1 = -umax
                #u2=0
                if(u2 > u2max):
                    u2=u2max
                if(u2 < -u2max):
                    u2 = -u2max

                # Assigning Individual Wheel velocities
                u1=0 #Should this be here?
                vr=u1+u2
                vl=u1-u2

                # Remove the sign in motor velocities
                Vr = abs(int(vr))
                Vl = abs(int(vl))

                # Assign the motor velocities to 0-256 range to send through 8bit UART
                VrHex = int((Vr - VrMin)*255/ (VrMax - VrMin))
                VlHex = int((Vl - VlMin)*255/ (VlMax - VlMin))

                if (abs(error1) < 10 and abs(error2) <5):
                    kick= 0x01
                else:
                    kick = 0
                if (error1<50):
                    VrHex=0x0
                    VlHex=0x0

                print("VlHex:",VlHex)
                print("VrHex:",VrHex)
                counter = counter + 1
                packet.append(0xFF)
                packet.append(0x01)  #Robot ID
                packet.append(VrHex) #VrHex
                packet.append(dirR)  #dirR
                packet.append(VlHex) #VlHex
                packet.append(dirL)  #dirL
                packet.append(kick)  #kick
                packet.append(0xFF)
                KL25.write(packet)
                #data = KL25.read(4)
                #print(data.decode('ISO-8859-1'))

    cv2.imshow('circles on stream',img)

def run():
    app = QApplication(sys.argv)
    window = roboGUI()
    window.show()
    sys.exit(app.exec_())

breakpointthing = None
class Worker(QObject):
    finished = pyqtSignal()

    def __init__(self):
        super(Worker, self).__init__()
        self.working = True

    def work(self):
        while(self.working):
            sys.settrace = breakpointthing
            mainLoop()
        stoprobot('all') # when stop button pressed, stop robots

class roboGUI(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(roboGUI,self).__init__()
        self.window = QWidget(self)
        self.setCentralWidget(self.window)
        self.resize(400,100)
        self.setWindowTitle("roboGUI")
        self.layout = QVBoxLayout()

        self.buttons = QHBoxLayout()

        self.startButton = QPushButton("START",self)
        #self.startButton.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Expanding)
        #self.startButton.resize(self.startButton.minimumSizeHint())
        self.startButton.setMinimumSize(self.startButton.minimumSizeHint())
        self.startButton.setMinimumHeight(80)
        self.buttons.addWidget(self.startButton)
        self.stopButton = QPushButton("STOP",self)
        #self.stopButton.setSizePolicy(QSizePolicy.Preferred,QSizePolicy.Expanding)
        self.stopButton.setMinimumSize(self.stopButton.minimumSizeHint())
        self.stopButton.setMinimumHeight(80)
        self.buttons.addWidget(self.stopButton)

        self.layout.addLayout(self.buttons)

        self.sliders = QHBoxLayout()
        self.slidersleft = QVBoxLayout()
        self.slidersright = QGridLayout()

        self.param1text = QHBoxLayout()
        self.param1title = QLabel("Parameter 1")
        self.param1value = QLabel(str(param1val))
        self.param1slider = QSlider(Qt.Horizontal)
        self.param1slider.setMinimum(1)
        self.param1slider.setMaximum(250)
        self.param1slider.setValue(param1val)
        self.param1slider.setTickInterval(1)
        self.param1text.addWidget(self.param1title)
        self.param1text.addWidget(self.param1value)
        self.slidersleft.addLayout(self.param1text)
        self.slidersleft.addWidget(self.param1slider)

        self.param2text = QHBoxLayout()
        self.param2title = QLabel("Parameter 2")
        self.param2value = QLabel(str(param2val))
        self.param2slider = QSlider(Qt.Horizontal)
        self.param2slider.setMinimum(1)
        self.param2slider.setMaximum(50)
        self.param2slider.setValue(param2val)
        self.param2slider.setTickInterval(1)
        self.param2text.addWidget(self.param2title)
        self.param2text.addWidget(self.param2value)
        self.slidersleft.addLayout(self.param2text)
        self.slidersleft.addWidget(self.param2slider)

        self.valuetext = QHBoxLayout()
        self.valuetitle = QLabel("Minimum Value for Color")
        self.valuevalue = QLabel(str(valueMin))
        self.valueslider = QSlider(Qt.Horizontal)
        self.valueslider.setMinimum(0)
        self.valueslider.setMaximum(255)
        self.valueslider.setValue(valueMin)
        self.valueslider.setTickInterval(1)
        self.valueslider.setSizePolicy(QSizePolicy.Preferred,QSizePolicy.Fixed)
        self.valuetext.addWidget(self.valuetitle)
        self.valuetext.addWidget(self.valuevalue)
        self.slidersleft.addLayout(self.valuetext)
        self.slidersleft.addWidget(self.valueslider)

        self.kptext = QHBoxLayout()
        self.kptitle = QLabel("Kp Value:")
        self.kpvalue = QLabel(str(kp))
        self.kpvalue.setFixedWidth(30)
        self.kptext.addWidget(self.kptitle)
        self.kptext.addWidget(self.kpvalue)
        self.kpslider = QSlider(Qt.Vertical)
        self.kpslider.setMinimum(0)
        self.kpslider.setMaximum(500)
        self.kpslider.setValue(kp)
        self.kpslider.setTickInterval(5)
        self.kpslider.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Expanding)

        self.kdtext = QHBoxLayout()
        self.kdtitle = QLabel("Kd Value:")
        self.kdvalue = QLabel(str(kd))
        self.kdvalue.setFixedWidth(30)
        self.kdtext.addWidget(self.kdtitle)
        self.kdtext.addWidget(self.kdvalue)
        self.kdslider = QSlider(Qt.Vertical)
        self.kdslider.setMinimum(0)
        self.kdslider.setMaximum(500)
        self.kdslider.setValue(kd)
        self.kdslider.setTickInterval(5)
        self.kdslider.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Expanding)

        self.slidersright.addLayout(self.kptext,0,0)
        self.slidersright.addLayout(self.kdtext,0,1)
        self.slidersright.addWidget(self.kpslider,1,0)
        self.slidersright.addWidget(self.kdslider,1,1)

        self.sliders.addLayout(self.slidersleft)
        self.sliders.addLayout(self.slidersright)
        self.layout.addLayout(self.sliders)

        self.window.setLayout(self.layout)
        self.window.setSizePolicy(QSizePolicy.Preferred,QSizePolicy.Expanding)

        self.thread = None
        self.worker = None

        self.param1slider.valueChanged[int].connect(self.changedValue_param1)
        self.param2slider.valueChanged[int].connect(self.changedValue_param2)
        self.valueslider.valueChanged[int].connect(self.changedValue_valueMin)
        self.kpslider.valueChanged[int].connect(self.changedValue_kp)
        self.kdslider.valueChanged[int].connect(self.changedValue_kd)
        self.startButton.clicked.connect(self.startLoop)

    def startLoop(self):
        breakpointthing = sys.gettrace()
        self.thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)

        self.thread.started.connect(self.worker.work)
        self.stopButton.clicked.connect(self.stopLoop)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.worker.finished.connect(self.thread.deleteLater)

        self.thread.start()

    def stopLoop(self):
        self.worker.working = False

    def changedValue_param1(self, value):
        global param1val
        param1val = value
        self.param1value.setText(str(param1val))
    def changedValue_param2(self, value):
        global param2val
        param2val = value
        self.param2value.setText(str(param2val))
    def changedValue_valueMin(self, value):
        global valueMin
        valueMin = value
        self.valuevalue.setText(str(valueMin))
    def changedValue_kp(self, value):
        global kp
        kp = value/100
        self.kpvalue.setText(str(kp))
    def changedValue_kd(self, value):
        global kd
        kd = value/100
        self.kdvalue.setText(str(kd))

    sys._excepthook = sys.excepthook
    def exception_hook(exctype, value, traceback):
      #  print(exctype, value, traceback)
        sys._excepthook(exctype, value, traceback)
        sys.exit(1)
    sys.excepthook = exception_hook

if __name__== "__main__":
    run()
    cv2.destroyAllWindows()


import cv2
import numpy as np

faceClassif = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

img = cv2.imread('imagen_input.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = faceClassif.detectMultiScale(gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30,30),
maxSize=(200,200))

for(x,y,w,h) in faces:
   cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

cv2.imshow('img', img)

cv2.waitKey(0)
cv2.destroyAllWindows()


from marshmallow import Schema, post_load, validates_schema, ValidationError
from marshmallow.fields import String, Integer, Dict, Nested
from src.database import get_db
from src.models.questions_model import QuestionModel
from src.models.questionTypes_model import QuestionTypeModel

class QuestionLoaderSchema(Schema):
    id = Integer()
    order = Integer()
    question = String()
    options = Dict()
    type = String()
    subQuestions = Nested("self", many=True)

    @validates_schema
    def validate_schema(self, data):
        if data.get("id") is not None:

            if data.get("question") is None:
                raise ValidationError(
                    "you must provide the text for the question to create the question",
                    "question"
                )

            if data.get("type") is None:
                raise ValidationError(
                    "you must provide the type of the question",
                    "type"
                )

            if (
                data.get("type") is not None
                and (data["type"] == "matrix" or data["type"] == "ranking")
                and data.get("subQuestions") is None):
                raise ValidationError(
                    "you must provide at least one sub question for matrix and ranking type questions",
                    "subQuestions"
                )

    @post_load
    def load_question(self, data):
        session = get_db()
        if data.get("id") is not None:
            question = session.query(QuestionModel).filter_by(id=data["id"]).one_or_none()
            if question is None:
                raise ValidationError(
                    f"The id {data[id]} for the question you have provided does not exist",
                    "id"
                    )
        else:
            question = QuestionModel()

        if data.get("question") is not None:
            question.question = data["question"]
        if data.get("type") is not None:
            type = session.query(QuestionTypeModel).filter_by(
                type=data['type']
            ).one_or_none()
            if type is None:
                raise ValidationError("The type " + data.get("type") + "is not supported")
            else:
                question.type = type

        if data.get("options") is not None:
            question.options = data["options"]

        if data.get("subQuestions") is not None:
            if question.type.type != "matrix" and question.type.type != "ranking":
                raise ValidationError("Only matrix and ranking type questions may have sub questions")
            for sub in question.subQuestions:
                if sub not in data["subQuestions"]:
                    sub.status = "deactive"
            for sub in data['subQuestions']:
                if sub['object'] not in question.subQuestions:
                    question.subQuestions.append(sub['object'])
                elif sub.status == "deactive":
                    sub.status = "active"

            for sub in data['subQuestions']:
                if sub.get('order') is not None:
                    question.set_item_order(sub['order'], sub['object'])

        elif (
            question.type.type == "matrix"
            or question.type.type == "ranking"
            ):
            for sub in question.subQuestions:
                if sub.status == "active":
                    sub.status == "deactive"
            question.status = "deactive"

        # handle the case of matrix and ranking questions
        # the sub questions of these types need the parent questionKey as a prefix
        if (question.questionKey is None and
            question.type.type == "matrix" and
            question.type.type == "ranking"):
            for sub in question.subQuestions:
                if sub.questionKey is None:
                    sub.set_prefix(question.questionKey)

        deserialized_return = {
            "object":question
        }

        if data.get("order") is not None:
            deserialized_return['order'] = data['order']

        return deserialized_return


class Solution:
    def longestCommonSubsequence(self, txt1: str, txt2: str) -> int:
        short, long = [
            len(txt1), len(txt2)
        ] if len(txt1) < len(txt2) else [len(txt2), len(txt1)]

        if len(txt1) > len(txt2):
            txt1, txt2 = txt2, txt1
        dp = [["" for _ in range(long + 1)] for _ in range(short + 1)]
        # print("dp->", dp, "text1->", text1, "text2->", text2)
        # dp[i][j] == dp[i-1][j] or dp[i][j-1] or dp[i-1][j-1] + text1[i]
        max_len = 0
        for i in range(0, short):
            j = 0
            while j < long:
                if i == 0 and j >= 0:
                    if txt1[i] == txt2[j]:
                        dp[i][j] = txt1[i]
                        max_len = max(max_len, len(dp[i][j]))
                        print("A:{0}->{1}".format(i, j), "dp[i][j]", dp[i][j])
                if txt1[i] == txt2[j]:
                    dp[i][j] = dp[i - 1][j - 1] + txt2[j]
                    max_len = max(max_len, len(dp[i][j]))
                    print("B:{0}->{1}".format(i, j), "dp[i][j]", dp[i][j])
                else:
                    if len(dp[i - 1][j]) >= len(dp[i][j - 1]):
                        dp[i][j] = dp[i - 1][j]
                    else:
                        dp[i][j] = dp[i][j - 1]
                    max_len = max(max_len, len(dp[i][j]))
                    print("C:{0}->{1}".format(i, j), "dp[i][j]", dp[i][j])
                j += 1
        # print(dp)

        return max_len

if __name__ == '__main__':
    so = Solution()
    text1 = "abcde"
    text2 = "ace"
    res = so.longestCommonSubsequence(text1, text2)
    print(res)


import struct
from unittest import TestCase

from host.modules.connection import Connection

class TestConnection(TestCase):

    def test_create_request(self):
        conn = Connection("127.0.0.1", 65432)

        # first request
        req1 = conn.create_request("Test")
        assert struct.unpack(">H", req1[:2])[0] == len("Test")
        assert req1[2:].decode() == "Test"

        # second request
        req2 = conn.create_request("start_vm 102")
        assert struct.unpack(">H", req2[:2])[0] == len("start_vm 102")
        assert req2[2:].decode() == "start_vm 102"

    def test_connect_to_socket(self):
        conn = Connection("127.0.0.1", 65432)
        conn.connect_to_socket()
        conn.disconnect_from_socket()

    def test_send_request(self):
        conn = Connection("127.0.0.1", 65432)
        conn.send_request("Test")
        conn.send_request("start_vm 102")


import logging

# https://www.programcreek.com/python/example/192/logging.Formatter
# https://stackoverflow.com/questions/533048
def get_logger(logger_name, level_name=logging.DEBUG, create_file=False,
               log_file_name='harvest.log'):
    """
    create a new logger
    :param logger_name: string, logs logger name
    :param level_name: string, log printing level
    :param create_file: bool, whether log in to a file
    :param log_file_name: string, log file's name
    :return: a logger
    """
    # create logger for prd_ci
    log = logging.getLogger(logger_name)
    log.setLevel(level_name)
    # create formatter and add it to the handlers
    formatter = logging.Formatter(
        fmt='[%(asctime)s,%(msecs)d][%(filename)s:%(lineno)d][%(name)s][%(levelname)s] %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S')
    if create_file:
        # create file handler for logger.
        fh = logging.FileHandler(log_file_name)
        fh.setLevel(level=level_name)
        fh.setFormatter(formatter)
        # add handlers to logger.
        log.addHandler(fh)
    # reate console handler for logger.
    ch = logging.StreamHandler()
    ch.setLevel(level=level_name)
    ch.setFormatter(formatter)
    # while log.handlers:
    #     log.handlers.pop()
    log.addHandler(ch)
    return log


import argparse
import webbrowser

def search_googlemap():
    parser = argparse.ArgumentParser()
    parser.add_argument('addr', help='The address for google map to search', type=str)
    args = parser.parse_args()

    webbrowser.open('https://www.google.com/maps/place/' + args.addr)

if __name__ == '__main__':
    search_googlemap()


import paho.mqtt.client as mqtt
import time
import random
import struct

# initialize random number generator
random.seed()

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))

# Create a MQTT client and register a callback
# for connect events
client = mqtt.Client()
client.on_connect = on_connect

# Connect to a broker
client.connect("localhost", port=1883, keepalive=60)

# Start a background loop that handles all
# communication with the MQTT broker
client.loop_start()

# send a random value every second
while True:
    time.sleep(1)
    id = 0x28ff5d5c5b5a5950
    rnd = random.randint(-128, 127)
    print(str(rnd))
    # to pack data into a "C struct" (i.e. bytes object)
    # use the struct package. The first argument is
    # a format string describing the data format
    # and then all the data that should be packed into
    # it. In this case we have ! = network byte order
    # Q = unsigned 8 bytes, b = signed 1 byte
    data = struct.pack("!Qb", id, rnd)

    # publish the data to the topic some/topic
    # using the packed struct as payload and
    # MQTT QoS set to 1
    client.publish("some/topic", payload=data, qos=1)


from argparse import ArgumentParser
from itertools import tee
from os import listdir
from os.path import getsize, exists
from shutil import move

def pairwise(iterable):
    "s -> (s0, s1), (s1, s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

def create_empty_file(self, file_name):
    open(file_name, 'w').close()

SIZE_5MB = 5e6
MAX_LOG_FILES_COUNT = 5

class LogRotator(object):

    def __init__(self, prefix, suffix):
        self.prefix = prefix
        self.suffix = suffix

    def __str__(self):
        return  self.__make_file_name("x")

    def __make_file_name(self, file_number):
        return "{}{}.{}".format(self.prefix, file_number, self.suffix)

    def rotate(self):
        current_log = self.__make_file_name("")
        if getsize(current_log) < SIZE_5MB:
            return

        files = [
            self.__make_file_name(x)
            for x in range(1, MAX_LOG_FILES_COUNT + 1)]

        for f in files:
            if not exists(f):
                create_empty_file(f)

        for older, newer in pairwise(reversed([current_log] + files)):
            move(newer, older)

        create_empty_file(current_log)

if __name__ == '__main__':
    parser = ArgumentParser(description="Rotate log files")
    parser.add_argument("-prefix", help="log file prefix")
    parser.add_argument("-suffix", help="log file suffix")

    args = parser.parse_args()

    logRotator = LogRotator(args.prefix, args.suffix)
    logRotator.rotate()


from error import InputError, AccessError
from other import clear, existing_email, valid_email, valid_user_id
from other import existing_handle, authenticate_token
from data import data

import jwt
import urllib
from PIL import Image

def user_profile(token, u_id):
    """
    Function that returns the profile of the
    user with the given u_id as a dictionary.

    Parameters:
    	token (str): Used to validate the users login session

    Return:
    	{
            user: {
        		u_id (int): Unique identification number of target
        		email (str): email address of target
        		name_first (str): first name of target
        		name_last (str): last name of target
        		handle_str (str): Not sure what this is used for
            },
    	}
    """
    valid_user_id(u_id)
    authenticate_token(token)

    return {
    	'user': data.users[u_id].user_details()
    }

def user_profile_setname(token, name_first, name_last):
    """
    Changes and sets users first and last name.
    Parameters:
        token(str): A string that validates the users actions while
    				 they are logged in
        name_first(str): The new first name of user
        name_last(string): The new last name of user

    Returns: None
    """
    # raise InputError if any of the inputs is empty
    if token == '':
        raise InputError("token input left empty")
    if name_first == '':
        raise InputError("name_first left empty")
    if name_last == '':
        raise InputError("name_last left empty")

    # raise InputError if any of the inputs is an invalid type
    if not isinstance(token, str):
        raise AccessError("token of wrong data type")
    if not isinstance(name_first, str):
        raise InputError("name_first of wrong data type")
    if not isinstance(name_last, str):
        raise InputError("name_last of wrong data type")

    # name_first is not between 1 and 50 characters or
    # name_last is not between 1 and 50 characters
    if (len(name_first) > 50 or len(name_first) < 1):
        raise InputError("name_first length is out of range")
    if (len(name_last) > 50 or len(name_last) < 1):
        raise InputError("name_last length is out of range")

    # check that token is authorised
    tok = authenticate_token(token)

    user = data.users[tok]

    user.name_first = name_first
    user.name_last = name_last
    return {
    }

def user_profile_setemail(token, email):
    """
    Changes and sets user's email.
    Parameters:
        token(str): A string that validates the users actions while
    				 They are logged in
        email(str): The new email of the user
    Returns: None
    """
    # raise InputError if any of the inputs is empty
    if token == '':
        raise InputError("token input left empty")
    if email == '':
        raise InputError("email input left empty")

    # raise InputError if any of the inputs is an invalid type
    if not isinstance(token, str):
        raise AccessError("token of wrong data type.")
    if not isinstance(email, str):
        raise InputError("email of wrong data type.")

    # Checks that email is in valid format
    valid_email(email)
    # Checks that email is not being used by another user
    existing_email(email)

    # check that token is authorised
    tok = authenticate_token(token)

    user = data.users[tok]
    user.email = email
    return {
    }

def user_profile_sethandle(token, handle_str):
    """
    Changes and sets user's handle_str.
    Parameters:
        token(str): A string that validates the users actions while
    				they are logged in
        handle_str(str): The handle the user wants to change to

    Returns: None
    """
    # raise InputError if any of the inputs is empty
    if token == '':
        raise InputError("Token input left empty")
    if handle_str == '':
        raise InputError("Handle_str input left empty")

    # raise InputError if any of the inputs is an invalid type
    if not isinstance(token, str):
        raise AccessError("Invalid Token")
    if not isinstance(handle_str, str):
        raise InputError("Invalid Email")

    # raises an error if the handle is not of the required length
    if len(handle_str) < 3:
        raise InputError("handle string too short")
    elif len(handle_str) > 20:
        raise InputError("handle string too long")

    # check that token is authorised
    tok = authenticate_token(token)
    # check that handle_str is not being used by another user
    existing_handle(handle_str)

    user = data.users[tok]
    user.handle_str = handle_str
    return {
    }

def user_profile_uploadphoto(token, img_url, x_start, y_start, x_end, y_end, host_url):
    """
    Upoloads a photo for the users profile.

    Parameters:
        token(str): A string that validates the users actions while
    				they are logged in
        img_url(str): URL of an image on the internet
        x_start(int): x position to start cropping
        y_start(int): y position to start cropping
        x_end(int): x position to end cropping
        y_end(int): y position to end cropping

    Returns: {}
    """
    # check that token is authorised
    user_id = authenticate_token(token)

    path = "src/static/profile_img_for_" + str(user_id) + ".jpg"
    # get image
    try:
        urllib.request.urlretrieve(img_url, path)
    except:
        raise InputError("invalid url")

    img = Image.open(path)
    width, height = img.size

    if x_start < 0 or x_start > width:
        raise InputError("Invalid x_start")
    elif y_start < 0 or y_start > height:
        raise InputError("Invalid y_start")
    elif x_end > width or x_end < x_start:
        raise InputError("Invalid x_end")
    elif y_end > height or y_end < y_start:
        raise InputError("Invalid x_end")

    if img.format != "JPEG":
        raise InputError("not a JPEG file")

    img_cropped = img.crop((x_start, y_start, x_end, y_end))
    img_cropped.save(path)

    data.users[user_id].update_profile_img_url(host_url + path)

    return {}


import os,matplotlib.pyplot as plt, numpy as np, datetime as dtm
from scipy.optimize import curve_fit
from npat.reactions import isotope
from npat.spectroscopy.spectrum import spectrum
from npat.misc.plotter import plotter

class calibration(object):
	def __init__(self,calibration_spectra=[],experiment_spectra=[],db=None,db_connection=None,db_name=None,db_path=None):
		self.cspec,self.espec = calibration_spectra,experiment_spectra
		self.rescal,self.R,self.alpha = 0.05,0.2,0.9
		self.engcal = [0.4,0.0]
		self.init_eff()
		self.clr = plotter().pallate()
		if (db is not None and db_connection is not None) or (db_name is not None):
			self.init_db(db=db,db_connection=db_connection,db_name=db_name,db_path=db_path)
		else:
			self.db,self.db_connection = None,None
	def init_eff(self):
		self.effcal,self.unc_effcal = [0.04,-1.7,4.1],[[0.04,0,0],[0,0.17,0],[0,0,0.41]]
		self.disteff = False
		if len(self.cspec)>0:
			if all(['dist' in s.meta for s in self.cspec]):
				self.effcal = {d:[0.04,-1.7,4.1] for d in list(set([s.meta['dist'] for s in self.cspec]))}
				self.unc_effcal = {d:[[0.04,0,0],[0,0.17,0],[0,0,0.41]] for d in list(set([s.meta['dist'] for s in self.cspec]))}
				self.disteff = True
	def init_db(self,db=None,db_connection=None,db_name=None,db_path=None):
		sp = spectrum(read_maestro=False)
		sp.init_db(db=db,db_connection=db_connection,db_name=db_name,db_path=db_path)
		self.db,self.db_connection = sp.db,sp.db_connection
	def map_efficiency(self,energy,a,b,c):
		if type(energy) in [int,float,np.float64]:
			return np.exp(a*np.log(energy)**2+b*np.log(energy)+c)
		return [np.exp(a*np.log(e)**2+b*np.log(e)+c) for e in energy]
	def map_unc_efficiency(self,energy,eff,unc_eff):
		u = unc_eff
		if type(energy) in [int,float,np.float64]:
			return np.sqrt(np.log(energy)**4*u[0][0]+2.0*np.log(energy)**3*u[0][1]+2.0*np.log(energy)**2*u[0][2]+np.log(energy)**2*u[1][1]+2.0*np.log(energy)*u[1][2]+u[2][2])*self.map_efficiency(energy,*eff)
		return [np.sqrt(np.log(energy[n])**4*u[0][0]+2.0*np.log(energy[n])**3*u[0][1]+2.0*np.log(energy[n])**2*u[0][2]+np.log(energy[n])**2*u[1][1]+2.0*np.log(energy[n])*u[1][2]+u[2][2])*e for n,e in enumerate(self.map_efficiency(energy,*eff))]
	def append_spec(self,filename='',directory='',meta={},cal=True):
		sp = spectrum(filename,directory)
		sp.update_params(meta=meta)
		sp.write_maestro()
		if cal:
			self.cspec.append(sp)
			self.init_eff()
		else:
			self.espec.append(sp)
	def guess_calibration(self):
		res,m,b = [],[],[]
		for sp in self.cspec:
			sp.auto_calibrate()
			res.append(sp.rescal)
			m.append(sp.engcal[0])
			b.append(sp.engcal[1])
		self.rescal,self.engcal = np.average(res),[np.average(m),np.average(b)]
		self.apply_calibration(spectra=self.cspec,write=False)
	def apply_calibration(self,spectra=None,write=True):
		if spectra is not None:
			for sp in spectra:
				sp.update_params(meta={'res':self.rescal,'R':self.R,'alpha':self.alpha})
				sp.update_params(engcal=self.engcal)
				if 'dist' in sp.meta:
					sp.update_params(effcal=self.effcal[sp.meta['dist']])
					sp.update_params(meta={'unc_eff':self.unc_effcal[sp.meta['dist']]})
				else:
					sp.update_params(effcal=self.effcal)
					sp.update_params(meta={'unc_eff':self.unc_effcal})
				if write:
					sp.write_maestro()
		else:
			self.apply_calibration(spectra=self.cspec,write=write)
			self.apply_calibration(spectra=self.espec,write=write)
	def calc_engcal(self,peaks):
		self.engcal_data = []
		for pk in [p for pk in peaks for p in pk['pks']]:
			if np.sqrt(pk['unc'][1][1])<0.05*pk['fit'][1] and np.sqrt(pk['unc'][1][1])<25.0/self.engcal[0]:
				self.engcal_data.append([pk['fit'][1],pk['E'],self.engcal[0]*np.sqrt(pk['unc'][1][1])])
		fit,unc = curve_fit(lambda x,m,b:[m*i+b for i in x],[i[0] for i in self.engcal_data],[i[1] for i in self.engcal_data],p0=self.engcal,sigma=[i[2] for i in self.engcal_data])
		self.engcal = fit.tolist()
	def calc_effcal(self,peaks):
		self.effcal_data = {d:[] for d in self.effcal} if self.disteff else []
		for fl in peaks:
			lm,unc_lm = isotope(fl['pks'][0]['istp']).decay_const(unc=True)
			A0,t_d,t_m = fl['meta']['A0'],(fl['start_time']-dtm.datetime.strptime(fl['meta']['ref_date'],'%m/%d/%Y %H:%M:%S')).total_seconds(),fl['real_time']
			for pk in fl['pks']:
				eff = pk['N']*lm/(A0*(1.0-np.exp(-lm*t_m))*np.exp(-lm*t_d)*0.01*pk['I']*pk['eff_corr'])
				unc_eff = np.sqrt((eff/pk['N'])**2*(pk['N']+pk['unc_N']**2)+(eff/A0)**2*(0.01*A0)**2+(eff/lm)**2*unc_lm**2+((eff/pk['I'])**2*pk['unc_I']**2))
				if unc_eff<eff:
					if self.disteff:
						self.effcal_data[fl['meta']['dist']].append([pk['E'],eff,unc_eff])
					else:
						self.effcal_data.append([pk['E'],eff,unc_eff])
		if self.disteff:
			for dist in self.effcal_data:
				fit,unc = curve_fit(self.map_efficiency,[i[0] for i in self.effcal_data[dist]],[i[1] for i in self.effcal_data[dist]],p0=self.effcal[dist],sigma=[i[2] for i in self.effcal_data[dist]])
				self.effcal[dist],self.unc_effcal[dist] = fit.tolist(),unc.tolist()
		else:
			fit,unc = curve_fit(self.map_efficiency,[i[0] for i in self.effcal_data],[i[1] for i in self.effcal_data],p0=self.effcal,sigma=[i[2] for i in self.effcal_data])
			self.effcal,self.unc_effcal = fit.tolist(),unc.tolist()
	def calc_rescal(self,peaks):
		self.rescal_data = []
		for pk in [p for pk in peaks for p in pk['pks']]:
			if np.sqrt(pk['unc'][2][2])<pk['fit'][2]:
				self.rescal_data.append([np.sqrt(pk['fit'][1]),pk['fit'][2],np.sqrt(pk['unc'][2][2])])
		fit,unc = curve_fit(lambda x,r:[r*i for i in x],[i[0] for i in self.rescal_data],[i[1] for i in self.rescal_data],p0=[self.rescal],sigma=[i[2] for i in self.rescal_data])
		self.rescal = fit[0]
	def calc_pk_params(self,peaks):
		self.R_data,self.alpha_data = [],[]
		for pk in [p for pk in peaks for p in pk['pks']]:
			if np.sqrt(pk['unc'][3][3])<pk['fit'][3]:
				self.R_data.append([pk['fit'][3],pk['E'],np.sqrt(pk['unc'][3][3]),pk['N']])
			if np.sqrt(pk['unc'][4][4])<pk['fit'][4]:
				self.alpha_data.append([pk['fit'][4],pk['E'],np.sqrt(pk['unc'][4][4]),pk['N']])
		self.R = np.average([i[0] for i in self.R_data],weights=[i[3] for i in self.R_data]) if len(self.R_data)>0 else self.R
		self.alpha = np.average([i[0] for i in self.alpha_data],weights=[i[3] for i in self.alpha_data]) if len(self.alpha_data)>0 else self.alpha
	def calibrate(self,save=False):
		self.guess_calibration()
		peaks = [{'meta':sp.meta,'pks':sp.get_fmt_pks(True),'start_time':sp.start_time,'real_time':sp.real_time} for sp in self.cspec]
		self.calc_engcal(peaks)
		self.calc_effcal(peaks)
		self.calc_rescal(peaks)
		self.calc_pk_params(peaks)
		self.apply_calibration(spectra=self.cspec)
		if save and self.db is not None and self.db_connection is not None:
			for sp in self.cspec:
				sp.init_db(db=self.db,db_connection=self.db_connection)
				sp.write_db(calibrate=True)
	def save_all_plots(self,directory='./',extension=['png','pdf']):
		directory = directory if directory.endswith('/') else directory+'/'
		extension = extension if type(extension)==list else [extension]
		for ext in extension:
			if not os.path.exists(directory):
				os.system('mkdir '+directory)
			if not os.path.exists(directory+'/peak_fits'):
				os.system('mkdir '+directory+'/peak_fits')
			self.plot_peak_fits(saveas=[directory+'peak_fits/'+sp.filename.split('/')[-1].split('.')[0]+'.'+ext for sp in self.cspec])
			self.plot_energy_calibration(saveas=directory+'engcal.'+ext)
			self.plot_efficiency_calibration(saveas=directory+'effcal.'+ext)
			self.plot_resolution_calibration(saveas=directory+'rescal.'+ext)
			self.plot_pk_param_calibration(saveas=directory+'pk_param_cal.'+ext)
	def show_all_plots(self):
		self.plot_peak_fits()
		self.plot_energy_calibration()
		self.plot_efficiency_calibration()
		self.plot_resolution_calibration()
		self.plot_pk_param_calibration()
	def plot_peak_fits(self,saveas=[],subpeak=False):
		for n,sp in enumerate(self.cspec):
			sp.plot_spectrum(wfit=True,subpeak=subpeak,saveas=(saveas[n] if n<len(saveas) else None))
	def plot_energy_calibration(self,saveas=None):
		f,ax = plt.subplots(2,sharex=True,gridspec_kw = {'height_ratios':[3, 2]})
		ax[0].errorbar([i[0] for i in self.engcal_data],[i[1] for i in self.engcal_data],yerr=[i[2] for i in self.engcal_data],ls='None',marker='o',color=self.clr['k'])
		idx_range = np.arange(min([i[0] for i in self.engcal_data]),max([i[0] for i in self.engcal_data]),0.5)
		ax[0].plot(idx_range,[self.engcal[0]*i+self.engcal[1] for i in idx_range],lw=1.8,color=self.clr['gy'])
		ax[1].plot(idx_range,np.zeros(len(idx_range)),ls='--',lw=1.8,color=self.clr['gy'])
		ax[1].errorbar([i[0] for i in self.engcal_data],[i[1]-self.engcal[0]*i[0]-self.engcal[1] for i in self.engcal_data],yerr=[i[2] for i in self.engcal_data],ls='None',marker='o',color=self.clr['k'])
		ax[1].set_xlabel('Bin Number (a.u.)')
		ax[0].set_ylabel('Energy (keV)')
		ax[1].set_ylabel('Residual (keV)')
		f.tight_layout()
		if saveas is None:
			plt.show()
		else:
			f.savefig(saveas)
			plt.close()
	def plot_efficiency_calibration(self,saveas=None):
		f,ax = plt.subplots()
		if self.disteff:
			E_range = np.arange(min([i[0] for dist in self.effcal_data for i in self.effcal_data[dist]]),max([i[0] for dist in self.effcal_data for i in self.effcal_data[dist]]),0.5)
			for dist in self.effcal_data:
				ax.errorbar([i[0] for i in self.effcal_data[dist]],[i[1] for i in self.effcal_data[dist]],yerr=[i[2] for i in self.effcal_data[dist]],ls='None',marker='o',color=self.clr['k'])
				eff = np.array(self.map_efficiency(E_range,*self.effcal[dist]))
				ax.plot(E_range,eff,lw=1.8,color=self.clr['gy'])
				ax.fill_between(E_range,eff+np.array(self.map_unc_efficiency(E_range,self.effcal[dist],self.unc_effcal[dist])),eff-np.array(self.map_unc_efficiency(E_range,self.effcal[dist],self.unc_effcal[dist])),color=self.clr['gy'],alpha=0.5)
		else:
			ax.errorbar([i[0] for i in self.effcal_data],[i[1] for i in self.effcal_data],yerr=[i[2] for i in self.effcal_data],ls='None',marker='o',color=self.clr['k'])
			E_range = np.arange(min([i[0] for i in self.effcal_data]),max([i[0] for i in self.effcal_data]),0.5)
			eff = np.array(self.map_efficiency(E_range,*self.effcal))
			ax.plot(E_range,eff,lw=1.8,color=self.clr['gy'])
			ax.fill_between(E_range,eff+np.array(self.map_unc_efficiency(E_range,self.effcal,self.unc_effcal)),eff-np.array(self.map_unc_efficiency(E_range,self.effcal,self.unc_effcal)),color=self.clr['gy'],alpha=0.5)
		ax.set_xlabel('Energy (keV)')
		ax.set_ylabel('Efficiency (a.u.)')
		ax.set_yscale('log')
		f.tight_layout()
		if saveas is None:
			plt.show()
		else:
			f.savefig(saveas)
			plt.close()
	def plot_resolution_calibration(self,saveas=None):
		f,ax = plt.subplots()
		ax.errorbar([i[0] for i in self.rescal_data],[i[1] for i in self.rescal_data],yerr=[i[2] for i in self.rescal_data],ls='None',marker='o',color=self.clr['k'])
		idx_range = np.arange(min([i[0] for i in self.rescal_data]),max([i[0] for i in self.rescal_data]),0.1)
		ax.plot(idx_range,[self.rescal*i for i in idx_range],lw=1.8,color=self.clr['gy'])
		ax.set_xlabel(r'Bin Number$^{1/2}$ (a.u.)')
		ax.set_ylabel('Peak Width (a.u.)')
		f.tight_layout()
		if saveas is None:
			plt.show()
		else:
			f.savefig(saveas)
			plt.close()
	def plot_pk_param_calibration(self,saveas=None):
		f,ax = plt.subplots(2,sharex=True)
		ax[0].errorbar([i[1] for i in self.R_data],[i[0] for i in self.R_data],yerr=[i[2] for i in self.R_data],ls='None',marker='o',color=self.clr['k'])
		E_range = np.arange(min([i[1] for dat in [self.R_data,self.alpha_data] for i in dat]),max([i[1] for dat in [self.R_data,self.alpha_data] for i in dat]),0.5)
		ax[0].plot(E_range,[self.R for i in E_range],ls='--',lw=1.8,color=self.clr['gy'])
		ax[1].errorbar([i[1] for i in self.alpha_data],[i[0] for i in self.alpha_data],yerr=[i[2] for i in self.alpha_data],ls='None',marker='o',color=self.clr['k'])
		ax[1].plot(E_range,[self.alpha for i in E_range],ls='--',lw=1.8,color=self.clr['gy'])
		ax[0].set_ylabel('R (a.u.)')
		ax[1].set_ylabel(r'$\alpha$ (a.u.)')
		ax[1].set_xlabel('Energy (keV)')
		f.tight_layout()
		if saveas is None:
			plt.show()
		else:
			f.savefig(saveas)
			plt.close()


from xai.brain.wordbase.nouns._sovereign import _SOVEREIGN

#calss header
class _SOVEREIGNS(_SOVEREIGN, ):
	def __init__(self,):
		_SOVEREIGN.__init__(self)
		self.name = "SOVEREIGNS"
		self.specie = 'nouns'
		self.basic = "sovereign"
		self.jsondata = {}


import pygame
import random

screen_width,screen_height = 800,600
screen = pygame.display.set_mode([screen_width, screen_height])
font_small = 35

red = (200,0,0)
green = (0,200,0)
bright_green = (0,255,0)
bright_red = (255,0,0)
black = (0,0,0)
white = (255,255,255)
display_width,display_height = 800,600

def text_objects(text,font,color=white):
	textSurf = font.render(text,True,color)
	return textSurf,textSurf.get_rect()

def message_display(msg,place,color=(255,255,255)):
	largeText = pygame.font.Font('freesansbold.ttf',35)
	#textRect is rect that contains it
	textSurf,textRect = text_objects(msg,largeText,color)
	#center text
	textRect.center = (place[0],place[1])
	screen.blit(textSurf,textRect)
	pygame.display.update()

def button(msg,x,y,width,height,acolor,icolor,action=None):
	"""  """
	mouse = pygame.mouse.get_pos()
	click = pygame.mouse.get_pressed()
	mx,my = mouse[0],mouse[1]
	if (x+width >=mx >= x ) and (y+height >=my > y):
		pygame.draw.rect(screen,red,(x,y,width,height))
		pygame.display.update()
		if click[0]==1 and action:
			action()
			return False
	else:
		pygame.draw.rect(screen,green,(x,y,width,height))

	smallText = pygame.font.Font("freesansbold.ttf",20)

	textSurf,textRect = text_objects(msg,smallText)

	textRect.center = ((x+width/2),(y+height/2))
	screen.blit(textSurf,textRect)
	pygame.display.update()
	return True

def lines(lx,ly,lw,h,color):
	pygame.draw.rect(screen,color,[lx,ly,lw,h])

def displayArray(a,j=0):
	for i in range(len(a)):
		if i==j:
			lines(100+i*2,50,2,a[i]*5,(255,0,0))
		elif i%2==0:
			lines(100+i*2,50,2,a[i]*5,(0,55,244))
		else:
			lines(100+i*2,50,2,a[i]*5,(0,255,0))
	pygame.display.update()


from typing import List

def maximalSquare(matrix: List[List[str]]) -> int:
    num_row = len(matrix)
    num_col = len(matrix[0])
    #matrix_d = [[0 for i in range(num_col)] for k in range(num_row)]
    """
    for i in range(num_row):
        matrix_d[i][0]=matrix[i][0]
    for i in range(num_col):
        matrix_d[0][i] = matrix[0][i]
    """
    matrix_d = [[0 if matrix[i][j]=="0" else 1 for j in range(num_col)]for i in range(num_row)]
    for i in range(1,num_row):
        for j in range(1,num_col):
            if matrix[i][j] == '1':
                matrix_d[i][j]=min(matrix_d[i-1][j-1],matrix_d[i-1][j],matrix_d[i][j-1])+1
            else:
                matrix_d[i][j]=0
    num_max=0
    for i in range(num_row):
        for j in range(num_col):
            if matrix_d[i][j]>num_max:
                num_max=matrix_d[i][j]
    return num_max*num_max

#a=[["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
#a=[[1,0,1,0,0],[1,0,1,1,1]]
a=[["1"]]

res=maximalSquare(a)
print(res)


import datetime
import time
import math
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from timeSeqRingBuffer import TimeSeqRingBuffer
from ringbuf import RingBuffer
from weatherDataRingBuffer import weatherDataRingBuffer

class WeatherDataCalc(object):
    def __init__(self, gustAvgTimeSpan = 3, windGuestReportingInterval = 60, reportingInterval = 6):
        """initialization"""
        self.lastWindGustOutputTimestamp = time.time()
        self.wind_gust_5min = 0
        self.rainDayData = {'date': None, 'total': 0.0 }
        self.rainData = []
        self.wind_gust_buffer = TimeSeqRingBuffer(size_max=3, default_value=0.0, dtype=float)
        self.wind_speed_buffer = RingBuffer(size_max=600, default_value=0.0, dtype=float) # Wind speed 10min moving average
        self.wind_dir_buffer = RingBuffer(size_max=600, default_value=0.0, dtype=float)  # Wind dir 10min moving average
        self.temp_outdoor_buf = RingBuffer(size_max=reportingInterval, default_value=0.0, dtype=float)
        self.weather_data_buf = weatherDataRingBuffer(size_max=reportingInterval, vectorsize=5, default_value=0.0, dtype=float)
        self.gustAvgTimeSpan = gustAvgTimeSpan
        self.windGuestReportingInterval = windGuestReportingInterval

    def calcOutdoorTemp(self, outdoorTemp):
        self.temp_outdoor_buf.append(outdoorTemp)
        return self.temp_outdoor_buf.avg()

    def calcGust(self, wind_speed_mph, wind_dir, weatherData):
        """Calculate gust"""
        timestamp = time.time()

        # Store wind speed
        self.wind_speed_buffer.append(wind_speed_mph)

        # Get avg wind speed
        avg_wind_speed = self.wind_speed_buffer.avg()
        weatherData[ 'wind_speed_mph' ] = "%.2f" % avg_wind_speed

        # Store wind direction in rad
        self.wind_dir_buffer.append(np.radians(wind_dir))

        # Calculate avg wind direction
        sa = sum(self.wind_speed_buffer.partial * np.sin(self.wind_dir_buffer.partial)) / self.wind_dir_buffer.size
        ca = sum(self.wind_speed_buffer.partial * np.cos(self.wind_dir_buffer.partial)) / self.wind_dir_buffer.size
        avg_a = np.degrees(np.arctan2(sa, ca))
        if avg_a < 0:
            avg_a = avg_a + 360.0

        weatherData['wind_dir'] = "%.2f" % avg_a

        if wind_speed_mph > avg_wind_speed:
            self.wind_gust_buffer.append(wind_speed_mph, timestamp)
            if self.wind_gust_buffer.timespan() < self.gustAvgTimeSpan and self.wind_gust_5min < self.wind_gust_buffer.avg():
               self.wind_gust_5min = self.wind_gust_buffer.avg()
            if self.lastWindGustOutputTimestamp + self.windGuestReportingInterval < timestamp:
                if self.wind_gust_5min > 0.0:
                    weatherData[ 'windgustmph' ] = "%.2f" % self.wind_gust_5min
                    print('Reporting Wind_gust_5min=', self.wind_gust_5min)
                self.wind_gust_5min = 0.0
                self.lastWindGustOutputTimestamp = timestamp

    def calcRainData(self, totalRainIn):
        currentDate = datetime.date.today()
        rainToday = 0.0
        rainLast60 = 0.0

        # If today's date isn't the same as the recorded date
        if currentDate != self.rainDayData["date"]:
            self.rainDayData["total"] = totalRainIn # Set the recorded total
            self.rainDayData["date"] = currentDate # Set the recorded date
        # Get the rain today by subtracting the recorded total from the
        # always-increasing totalRainIn
        rainToday = totalRainIn - self.rainDayData["total"]

        # get a current time and store this along with the value
        currentTime = datetime.datetime.now()
        self.rainData.append({"date":currentTime, "total":totalRainIn})
        # get rid of values that are more than 60 min away from this value
        while (currentTime - self.rainData[0]["date"]).total_seconds() / 60 > 60:
            del(self.rainData[0])
        # get the total over the last 60
        start60RainTotal = self.rainData[0]["total"]
        rainLast60 = totalRainIn - start60RainTotal
        return rainLast60, rainToday

    def calcDewPointF(self, temperatureC, humidityPercent):
        # From the Arden-Buck adjusted Magnus formula via Wikipedia
        a = 6.1121
        b = 18.678
        c = 257.14
        d = 234.5
        try:
            gamma = math.log(humidityPercent/100 * math.exp( (b - temperatureC / d) * (temperatureC / (c + temperatureC)) ) )
            return ((c*gamma)/(b - gamma)) * 1.8 + 32
        except(ValueError, e):
            return 0

    def addSensorDataToBuffer(self, outdoorTemp, humidityPercent, dewPoint, indoorTemp, pressure):
        # type: (float, float, float, float) -> object

        outdoorTemp = 32 + 1.8 * outdoorTemp  # convert degrees C to degrees F
        pressure = 0.029529 * pressure  # convert barometric pressure from pascals to inches
        indoorTemp = 32 + 1.8 * indoorTemp
        dewPoint = 32 + 1.8 * dewPoint
        self.weather_data_buf.append([outdoorTemp, humidityPercent, indoorTemp, pressure, dewPoint])

    def getMeanSensorData(self):
        a = self.weather_data_buf.avg()
        outdoorTemp = a[0]
        humidityPercent = a[1]
        indoorTemp = a[2]
        pressure = a[3]
        dewPoint = a[4]
        return outdoorTemp, humidityPercent, indoorTemp, pressure, dewPoint


# -*- coding: utf-8 -*-
import random
import time
import requests
from lxml import etree
from group import comment
from config import doubanurl
from util import doubanutil
from baiconfig import headers

if __name__ == "__main__":
    group_id = "699571"
    group_url = "https://www.douban.com/group/"+group_id+"/"
    r = requests.get(group_url, cookies=doubanutil.get_cookies(), headers=headers)
    group_topics_html = etree.HTML(r.text)
    group_topics = group_topics_html.xpath("//table[@class='olt']/tr[@class='']/td[@class='title']/a/@href")
    group_topics = group_topics[3:]
    print(group_topics)
    # print (r.text)
    for topic_url in group_topics:
        comment_topic_url = topic_url + "/add_comment"
        list_data = []
        list_data2 = []
        with open("D:\\douban\\DoubanAuto-master\\DoubanAuto-master\\data\\reponse.txt", "r", encoding="utf-8") as fr:
            list_data = fr.readlines()
            for i in list_data:
                temp_line = i.strip()  # 去除每行的\n
                list_data2.append(temp_line)
        print(list_data2)
        random_index = random.randint(0, len(list_data2) - 1)
        print(random_index)
        print(list_data2[random_index])

        comment_str = list_data2[random_index]
        print("顶帖:"+topic_url)
        comment_dict = comment.make_comment_dict(topic_url, comment_str)
        comment.comment_topic(comment_topic_url, comment_dict)
        random_sleep = random.randint(10, 50)
        time.sleep(random_sleep)


def count(array):
    #your code here
    keep = {}
    chars = []
    for i in array:
        if i not in chars:
            chars.append(i)
            keep[i] = array.count(i)
    return keep

print(count('hello'))


#!/usr/bin/python

NAME = 'Example'
ORDER = 0
VALID = False # upadte with True
TYPE = 'common_application'
KEY = 'example'
ICON = 'close.png'
OWNER = 'Subin Gopi'
COMMENTS = 'example application'
VERSION = '0.0.0'
MODIFIED = 'April 28, 2020'

import sys

from PySide2 import QtGui
from PySide2 import QtCore
from PySide2 import QtWidgets

class Window(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Window)

        self.setObjectName('widget_example')
        self.resize(300, 100)
        self.setWindowTitle("Example Application")

        self.verticallayout = QtWidgets.QVBoxLayout(self)
        self.verticallayout.setObjectName("verticallayout")
        self.button = QtWidgets.QPushButton(self)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
        self.button.setSizePolicy(sizePolicy)
        self.button.setObjectName("button")
        self.button.setText('Close')
        self.verticallayout.addWidget(self.button)
        self.button.clicked.connect(self.close)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = Window(parent=None)
    window.show()
    sys.exit(app.exec_())


#######################
# Leetcode 547. 朋友圈
#######################
from typing import List

class Solution:
    def findCircleNum(self, M: List[List[int]]) -> int:
        n = len(M)
        if n == 0: return 0
        p = [[0] for i in range(n)]
        def find(a):
            if p[a] != a:
                p[a] = find(p[a])
            return p[a]
        def union(a, b):
            p[find(b)] = find(a)
            return find(b)
        for a in range(n):
            for b in range(a):
                if M[a][b]:
                    union(a, b)
        for i in range(n):
            find(i)
        return len(set(p))
if __name__ == "__main__":
    n = [["1", "1"," 0"],
         ["1", "1", "0"],
         ["0", "0", "1"]]
    S = Solution()
    print(S.findCircleNum(n))


##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Basic File interfaces.

$Id$
"""
__docformat__ = 'restructuredtext'

from zope.schema import BytesLine, Bytes
from zope.interface import Interface
from zope.app.file.i18n import ZopeMessageFactory as _

class IFile(Interface):

    contentType = BytesLine(
        title = _(u'Content Type'),
        description=_(u'The content type identifies the type of data.'),
        default='',
        required=False,
        missing_value=''
        )

    data = Bytes(
        title=_(u'Data'),
        description=_(u'The actual content of the object.'),
        default='',
        missing_value='',
        required=False,
        )

    def getSize():
        """Return the byte-size of the data of the object."""

class IImage(IFile):
    """This interface defines an Image that can be displayed.
    """

    def getImageSize():
        """Return a tuple (x, y) that describes the dimensions of
        the object.
        """


#!/usr/bin/file/python

import pygame, precode, sys, random, time, math
from random import randint
from precode import *
from pygame import *
from Classes import *

pygame.init()

class Simulator():
    def __init__(self):
        # makes a canvas
        self.screen = pygame.display.set_mode([screen_x, screen_y])
        # sets window caption
        pygame.display.set_caption("BOID SIMULATOR")

        for boid in range(numBoids):
            # appends as many boids to the list as defined in numBoids
            boidList.append(Boids(random.randint(0, screen_x), random.randint(0, screen_y)))
            # print(len(boidList))
        for obst in range(numObst):
                obstList.append(Obstacles(random.randint(0, screen_x), random.randint(0, screen_y)))
        # for hoik in range(numHoik):
        #     hoikList.append(Hoik(random.randint(0, screen_x), random.randint(0, screen_y)))

    def run(self):
        # instantiates the hoik at the given coordinates
        hoik = Hoik(200,200)

        # the while loop initializes the different methods
        while 1:

            clock.tick(120)

            # for i,boid in enumerate(boidList):
            #     print(i, boid.x, boid.y)
            hoik.draw(self.screen)
            hoik.move()

            for boid in boidList:
                boid.draw(self.screen)
                boid.move()

            for obst in obstList:
                obst.draw(self.screen)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()

                pygame.event.pump()
                keys = pygame.key.get_pressed()
                if keys [pygame.K_ESCAPE]:
                    sys.exit()

            pygame.display.flip()
            """VIKTIG AT SCREEN FILL ER ETTER DISPLAY.FLIP, IKKE FOER!"""
            self.screen.fill(white)

if __name__ == '__main__':
    boids = Simulator()
    boids.run()


# PROJECT EULER PROBLEM 31 - Coin Sums

COINS = [200,100,50,20,10,5,2,1]
LEN_COINS = len(COINS)

target_amount = 200

def countCoinCombos(coin_list,amount):
    coin = coin_list[0]
    new_coin_list = coin_list[1:]
    n = 0
    count = 0 # count of combinations of coins
    coin_amount = 0
    while coin_amount <= amount:
        #out_str = ''
        #for q in range(LEN_COINS-len(new_coin_list)-1):
        #    out_str += "\t"
        #out_str += "{} x {}".format(coin,n)
        new_amount = amount - coin_amount
        if new_amount == 0:
            count += 1
            #print(out_str)
        elif new_amount > 0:
            if len(new_coin_list) != 0:
                #print(out_str)
                count += countCoinCombos(new_coin_list,new_amount)
        n += 1
        coin_amount = n*coin
    return(count)

print(countCoinCombos(COINS,target_amount))


import time
from selenium import webdriver

#open chrome
chrome = "C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe"
driver = webdriver.Chrome(chrome)
driver.implicitly_wait(10)

#open the target url
driver.get('https://www.51job.com/')
ele = driver.find_element_by_id('kwdselectid')
ele.clear()
ele.send_keys('python')
res = driver.find_element_by_css_selector('body > div.content > div > div.fltr.radius_5 > div > button').click()
info = driver.find_elements_by_css_selector('#resultList div[class=el]')
print(info)

# driver.quit()


#Longest Increasing Subsequence
#LGIS

from re import findall

f = open('rosalind_lgis.txt','r')

#extract n and sequence from file
for i, line in enumerate(f):
    if i == 0:
        n = int(line.rstrip())
    else:
        P = findall('(\d+)',line)
P = list(map(int, P)) #convert to ints
Q = [2, 6, 3, 4, 1, 2, 9, 5, 8] #testing

def build_S(perm):
    S = [perm[0]] #initialize S
    for i in perm[1:]:
        if i > S[-1]:
            S.append(i)
        else:
            #find smallest val in S >= i
            repl = min([x for x in S if x >= i])
            #replace that value with i
            S[S.index(repl)] = i
    I = [] #initialize list of indices of vals in S
    for j in S:
        I.append(perm.index(j))
    return S,I

def build_parent(S,I,perm):
    pass

#http://stackoverflow.com/questions/2631726/how-to-determine-the-longest-increasing-subsequence-using-dynamic-programming


import sublime, sublimeplugin, functools, re
from subprocess import STARTUPINFO, PIPE, Popen, STARTF_USESHOWWINDOW
from sublime import Region

##
# PHP Linter
# Lints automatically on file save, requires 'php' in the PATH env var
#
# @author Jordi Boggiano <j.boggiano@seld.be>
##

class phpLint(sublimeplugin.Plugin):
    def onPostSave(self, view):
        if view.fileName()[-4:] != '.php': return
        view.eraseRegions('phpLint')
        startupinfo = STARTUPINFO()
        startupinfo.dwFlags |= STARTF_USESHOWWINDOW
        file = Popen('php -l "'+view.fileName()+'"', stdout=PIPE, startupinfo=startupinfo).stdout

        if file.readline()[0:2] != 'No':
            sublime.setTimeout(functools.partial(self.updateStatus, view, file.readline().strip()), 100)

    def updateStatus(self, view, text):
        match = re.search('line (\d+)', text)
        if match is None or len(match.groups()) < 1: return
        sel = view.sel()
        point = view.textPoint(int(match.group(1))-1, 0)
        highlight = [view.line(point-1), view.line(point)]
        region = Region(point, point)

        view.show(point)
        sel.clear()
        sel.add(region)

        view.addRegions('phpLint', highlight, "identifier", sublime.DRAW_OUTLINED)

        sublime.statusMessage('<!> '+text);


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

from distutils.core import setup

__author__ = 'Jeremies Perez Morata jeremiespm <AT> gmail <DOT> com'

setup(name='pydiv',
      version='0.1',
      description='Python DIVs-like API over PyGame',
      author='Jeremies Perez Morata',
      author_email='jeremiespm@gmail.com',
      url='http://github.com/jeremies/pydiv',
      license="GPL (v3 or later)",
      long_description=open('README').read(),
      packages=['pydiv'],
      install_requires=[
        "pygame >= 1.9.1",
      ],
      classifiers=["Programming Language :: Python",
                   "Inteded Audience :: Developers",
                   "Topic :: Games/Entertainment"],
      keywords="div pygame game development",
     )


__author__ = 'dwang'
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re

from LoginClass import Login
from SearchClass import Search

class Search3(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://10.10.10.193/workspace/1/login.aspx"
        self.verificationErrors = []
        self.accept_next_alert = True

    def test_login_search_function(self):
        driver = self.driver
        driver.get(self.base_url)

        login = Login(self.driver, "admin", "admin", 0)
        login.check_box()
        time.sleep(1)
        search = Search(self.driver, "bj")
        search.search()

        #driver.find_element_by_link_text("Logout").click()

    def is_element_present(self, how, what):
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException as e: return False
        return True

    def is_alert_present(self):
        try: self.driver.switch_to.alert()
        except NoAlertPresentException as e: return False
        return True

    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to.alert()
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True

    def tearDown(self):
        #self.driver.quit()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()