#    15-112: Principles of Programming and Computer Science
#    HW07 Programming: Term Project (Tetris)
#    Name      : Umaymah Imran
#    AndrewID  : uimran

#    File Created:
#    Modification History:
#    Start             End
#    2/11 11:46pm     3/11 3:14am
#    3/11 12:01pm     3/11 4:11pm
#    3/11 10:21pm     4/11 1:39am
#    4/11 9:44pm      4/11 11:32pm
#    7/11 5:13pm      7/11 8:21pm
#    8/11 10:45am     8/11 2:37pm
#    9/11 11:56pm     10/11 2:53am
#    10/11 4:07am     10/11 5:52am
#    10/11 2:43pm     10/11 6:17pm
#    11/11 3:12pm     11/11 6:21pm
#    13/11 02:41pm    13/11 04:22pm
#    14/11 06:19pm    14/11 07:56pm
#    17/11 09:48am    17/11 12:43pm
#    17/11 07:32pm    17/11 09:18pm
#    18/11 08:54pm    18/11 10:02pm
#    19/11 11:39pm    20/11 01:34am
#    20/11 05:19pm    20/11 08:16pm
#    21/11 12:04pm    21/11 01:23pm
#    21/11 04:04pm    21/11 08:57pm
#    21/11 09:26pm    22/11 02:56am
#    23/11 08:18pm    24/11 12:12am
#    24/11 03:44am    24/11 05:20am
#    25/11 08:00pm    26/11 05:50am
#    26/11 07:52pm    26/11 10:19pm
#    26/11 10:31pm    27/11 12:45am
#    27/11 10:28am    27/11 11:22am
#    27/11 03:12pm    27/11 07:35pm
#    27/11 09:11pm    27/11 11:08pm
#    28/11 12:00pm    28/11 12:45pm
# import the necessary libraries
import pygame
import random

#############################################FUNCTION DEFINITIONS#######################################################
# Taken references and help from the following links:
# https://www.youtube.com/watch?v=Ign-VmKmz9g
# https://pythonprogramming.net/
# https://github.com/DanielSlater/PyGamePlayer/blob/master/games/tetris.py
# https://github.com/yash-iiith/Tetris-Game-in-Python-without-Pygame-/blob/master/tetris.py
# https://inventwithpython.com/pygame/chapter7.html
# https://gist.github.com/silvasur/565419/d9de6a84e7da000797ac681976442073045c74a4
# https://www.pygame.org/docs/ref/event.html
# https://github.com/matachi/python-tetris/blob/master/main.py
# http://www.discoveryplayground.com/computer-programming-for-kids/rgb-colors/
# Image for main screen taken from: https://www.ubisoft.com/en-us/game/tetris-ultimate
# Sound for collision from: http://soundbible.com/1742-Anvil-Impact-1x.html
# Sound for removal of rows: http://soundbible.com/1891-Flyby.html
# Sound for main screen: https://downloads.khinsider.com/game-soundtracks/album/tetris-gameboy-rip-/tetris-gameboy-01.mp3

# Code taken from: https://pythonprogramming.net/pygame-start-menu-tutorial/
# function(text_objects) is used to centre align the text of a button
def text_objects(text, font):
    textSurface = font.render(text, True, cyan)
    return textSurface, textSurface.get_rect()

# Code modified but orginially taken from: https://pythonprogramming.net/pygame-start-menu-tutorial/
# function(button) is used to create a button on the screen. It takes the text for the button, its x and y coordinates,
# its width and height, and calls the specified action(function) when the button is clicked
def button(msg, x, y, w, h, on, off, action=None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()

    if x + w > mouse[0] > x and y + h > mouse[1] > y:
        pygame.draw.rect(screen, off, (x, y, w, h))
        if click[0] == 1 and action != None:
            action()
    else:
        pygame.draw.rect(screen, on, (x, y, w, h))

    if msg == "Back" or (msg == "Quit" and gameover == False) or msg == "Sound":
        smallText = pygame.font.Font("freesansbold.ttf", 14)
    else:
        smallText = pygame.font.Font("freesansbold.ttf", 20)

    textSurf, textRect = text_objects(msg, smallText)
    textRect.center = ((x + (w / 2)), (y + (h / 2)))
    screen.blit(textSurf, textRect)

# Code taken from:https://stackoverflow.com/questions/28005641/how-to-add-a-background-image-into-pygame
# class Background is used to set an image as the background of a screen
class Background(pygame.sprite.Sprite):
    def __init__(self, image_file, location):
        pygame.sprite.Sprite.__init__(self)  # call Sprite initializer
        self.image = pygame.image.load(image_file)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location

# function(quitgame) exits the pygame window when clicked on 'X'
def quitgame():
    pygame.quit()
    quit()

# function(board) returns a 2D list 'board' in which each item in the list represents a row, and each element in the row
# represents a column. It takes the number of rows and columns as parameters. Each row is intialized as [0,0,0....,n],
# where n represents the number of columns. At the end, an extra row with [1,1,1,....,n] is intialized - this is to
# detect when a block touches the bottom of the board (by using the function collision_occured)
def new_board(rows, cols):
    board = []
    for i in range(rows):
        row = []
        for j in range(cols):
            row.append(0)
        board.append(row)
    extra_row = []
    for k in range(cols):
        extra_row.append(1)
    board.append(extra_row)
    return board

# function(collision_occured) takes the board, the shape definition, the sxth col and the syth row as inputs (sx and sy
# are the x and y positions of the shape). Using this, it determines when the shape has collided with either the edges,
# with the button of the board or with another shape
def collision_occured(board, shape, shape_x, shape_y):
    i = 0  # i and j are  variables for the while loop in order to go through the indexes of the item (shape in
    j = 0  # case of i and row in case of j) specified

    # The following code segment goes through each row of a shape and accesses each column of the shape and compares it to the
    # value in the board. If the value at the board is 0, collision has not occured. If it's any value between 1-7, and the shape
    # touches it, then collision has occured and the shape stops
    while i < len(shape):
        row = shape[i]
        while j < len(row):
            col = row[j]
            try:
                if col and board[i + shape_y][j + shape_x]:
                    return True

            except IndexError:
                return True
            j += 1 #increment j by 1
        i += 1 #increment i by 1
        j = 0 #initialize j to 0 as next row will start
    return False

def collision_occured_bottom(board, shape, shape_x, shape_y):
    i = 0  # i and j are  variables for the while loop in order to go through the indexes of the item (shape in
    j = 0  # case of i and row in case of j) specified

    # The following code segment goes through each row of a shape and accesses each column of the shape and compares it to the
    # value in the board. If the value at the board is 0, collision has not occured. If it's any value between 1-7, and the shape
    # touches it, then collision has occured and the shape stops
    while i < len(shape):
        row = shape[i]
        while j < len(row):
            col = row[j]
            try:
                if col and board[i + shape_y+1][j + shape_x]:
                    return True

            except IndexError:
                return True
            j += 1 #increment j by 1
        i += 1 #increment i by 1
        j = 0 #initialize j to 0 as next row will start
    return False

# function(place_shape) adds the the digits 1-7 to the board when the shape is placed in it and returns the updated version of the
# board. It takes the current board, the shape that is moving down, the x (column) and y (row) location of the shape and mute (so
# that the functionality for the 'Sound' button can be controlled)
def place_shape(board, shape, shape_x, shape_y , mute):
    i = 0  # i and j are  variables for the while loop in order to go through the indexes of the item (shape in
    j = 0  # case of i and row in case of j) specified

    # The following code segment goes through each row of a shape and accesses each column of the shape and adds it to the specific
    # location of the board where the shape settles. If mute is False, then the sound to identify the collision/settlement of the
    # shape will play
    while i < len(shape):
        row = shape[i]
        while j < len(row):
            if shape[i][j]:
                board[i+shape_y-1][shape_x+j] = shape[i][j]
                if not mute:
                    pygame.mixer.Channel(0).play(pygame.mixer.Sound('collision.wav')) # sound plays in the same channel as main sound
            j += 1 #increment j by 1
        i += 1 #increment i by 1
        j = 0 #initialize j to 0 as next row will start
    return board

# function (remove_row) removes complete, non-zero horizontal rows from the board. This function returns the number of lines removed,
# the updated version of the board (the rows above the removed row(s) move down and row(s) with 0s are initialized at the top in their
# place) and the updated myscore (as score increases with removal of lines).
def remove_row(board, myscore, lines, mute):
    rows_removed = 0 # keeps track of the zero rows removed, this is required for updating myscore
    zero_rows = [] #zero_rows are the newly initialized rows that will be appended to the board when row(s) is/are removed
    update = [] #update holds the final return value of the function
    score_inc = 40 # score_inc is the variable that stores the value with which rows_removed is to be multipled (for updating myscore)
    # By starting from the top most row, the following loop iterates through each row and loops for non-zero rows. Since the bottom
    # most row of the board is [1,1,1,....1], the loop will disregard that row.
    for i in range(len(board) - 2, -1, -1):
        if 0 not in board[i]:
            if not mute:
                pygame.mixer.Channel(1).play(pygame.mixer.Sound('remove_row.wav')) #when the row is removed, a 'swish' sound is played
            del board[i]
            rows_removed += 1

    myscore += rows_removed * score_inc #myscore updates
    lines += rows_removed #updates number of lines that have been removed so far

    #This loop adds as many zero rows as non-zero rows were removed
    for j in range(0, rows_removed):
        zero_rows += [[0 for i in range(0, cols)]]

    board = zero_rows + board #adds the zero rows to top most of current board

    #stores the updated values for the board, myscore and line in the 'updated' list
    update.append(board)
    update.append(myscore)
    update.append(lines)
    return update

# function (shape_rotation) will change the orientation of the shape every time the 'up' arrow key is pressed. It takes the board, the
# description of the current shape and its x (column) and y (row) locations as input. If, by pressing the 'up' key a collision is occuring,
# the shape will not rotate and will remain as it is. Otherwise, the function returns the new shape description, causing the shape to
# rotate at 90 degrees with each key press of 'up'.
def shape_rotation(board,current_shape_desc,shape_x,shape_y):
    new_shape = []

    # The following code segment changes the row and column wise description of the shape. In other words, it tranposes the 2D matrix (which
    # is the shape of the object)
    for y in range(len(current_shape_desc[0]) - 1, -1, -1):
        l = []
        for x in range(len(current_shape_desc)):
            l.append(current_shape_desc[x][y])
        new_shape.append(l)

    # The new shape will return if there is no collision on all four sides of the shape
    if not collision_occured(board, new_shape, shape_x, shape_y):
        return new_shape

    # Otherwise, the current shape description will be returned as it is
    return current_shape_desc

# function(new_shape) initializes the properties of a shape. It generates a random shape from the list All_shapes.
# It then returns the details of the shape, which are stored in a dictionary, that is, the shape's color and description
def new_shape(All_shapes):
    properties_current_shape = [random.choice(All_shapes)] #shapes are randomly generated
    item = properties_current_shape[0]
    return item

# function (initialize_game) is used to restart the game if the Back button on the Game Play screen is pressed and then if the player
# returns to the game OR to restart the game at the time of game over
def initialize_game():
    # The following variables are globalized to change and store the change in their state, by setting all variables to their initial values
    global board
    global current_shape_desc
    global current_shape_col
    global next_predicted_shape
    global shape_x
    global shape_y
    global mute
    global pause
    global fileopen
    global rules
    global start
    global started
    global back
    global home
    global collide
    global gameover
    global hscore
    global myscore
    global lines
    global p_count

    p_count = 25
    mute = False
    pause = False
    fileopen = True
    rules = False
    start = True
    started = False
    back = False
    home = False
    running = True
    collide = False
    gameover = False
    hscore = False
    myscore = 0
    lines = 0
    initial_shape = new_shape(All_shapes)
    current_shape_desc = initial_shape["shape"]
    current_shape_col = initial_shape["color"]
    next_predicted_shape = new_shape(All_shapes)
    shape_x = 4
    shape_y = 0
    board = new_board(rows, cols)

    file = 'maintheme.mp3'  # the main sound being played in the background
    pygame.init()
    pygame.mixer.init()
    pygame.mixer.music.load(file)
    pygame.mixer.music.play(-1)
    pygame.mixer.music.set_volume(0.5)

#function(check_top) checks if there is any non-zero number in the first row of the
#board. If there is, it will return False, otherwise it'll return True
def check_top (board):
    if not 0 in board[0]:
        return False
    return True

# Definitions of all colors used
black = (0, 0, 0)
white = (255, 255, 255)
darkblue = (72, 61, 139)
cyan = (224, 255, 255)
blue = (25, 25, 112)
staleblue = (72, 61, 139)
med_blue = (25, 25, 112)
red = (178, 34, 34)
yellow = (230, 200, 48)
green = (34, 139, 34)
purple = (130, 50, 204)
orange = (210, 105, 30)
pink = (176, 48, 96)

# The shapes and their colors that I'm using. The arrangement of each shape can be imagined as this one for the simple
# square (where * represents a number):
# [[*,*]
#  [*,*]]
All_shapes = [{"shape": [[1, 1], [1, 1]], "color": yellow}, {"shape": [[0, 5, 0], [5, 5, 5]], "color": med_blue},
              {"shape": [[0, 2, 2], [2, 2, 0]], "color": green}, {"shape": [[7, 7, 0], [0, 7, 7]], "color": red},
              {"shape": [[3, 0, 0], [3, 3, 3]], "color": purple}, {"shape": [[0, 0, 6], [6, 6, 6]], "color": pink},
              {"shape": [[4, 4, 4, 4]], "color": orange}]

# The dictionary color_shape_mapping assigns colors to each digit value (which signifies a specific shape)
color_shape_mapping = {"1": yellow, "5": med_blue, "2": green, "7": red, "3": purple, "6": pink, "4": orange}

# INITIALIZING THE FOLLOWING VARIABLES

mute = False # if 'Sound' is pressed then mute is True and the sounds discontinue, otherwise it is set to False by default and sound plays

pause = False # pause determines whether or not the game is in pause state

fileopen = True # fileopen is the file for storing the high score. It is open by default so that it can be updated when required (run-time)

rules = False # rules is for determining the state of the RULES screen. If it's false, then the screen for Rules is not open (vice-versa)

start = False # start is for determining the state of the START screen. If it's false, then the screen for Start is not open (vice-versa)

started = False # started is for indicating that the game has started.

back = False # back is for determining the states of the back button and for determining the required screens

home = True # home is for determining the state of the HOME/MAIN screen. If it's false, then the screen for Home is not open (vice-versa)

running = True # running is for the game loop

collide = False # collide is False by default, it becomes True if the shapes reach the top-most part of the board

gameover = False # if the shapes reach the top-most part of the board, the game is over

hscore = False # hscore determines the state of the high score. If it's True, the High Score of the game will update

play_music = True # play_music controls the background music

myscore = 0 # intially, the score is set to 0. It only increases if you press the down key or if complete non-zero rows are removed

lines = 0 # lines stores the number of non-zero rows removed

p_count = 25 # p_count is the pixel size of the box for drawing the shapes

tempo = 0 # tempo is used allow the shape to shift a bit after it hits a surface

# The first shape and the shape after that are determined
initial_shape = new_shape(All_shapes)
current_shape_desc = initial_shape["shape"]
current_shape_col = initial_shape["color"]
next_predicted_shape = new_shape(All_shapes)

# shape_x: xth column from where the shape drops
# shape_y: yth row from where the shape drops
shape_x = 4
shape_y = 0

# the board has a total of 20 rows and 10 columns
rows = 20
cols = 10

board = new_board(rows, cols)  # initialize the board for the gameplay

###################################################MAIN CODE############################################################
pygame.init()  # initializes all imported pygame modules
clock = pygame.time.Clock()  # clock is used to track and control the framerate of the game

# BackGround_MainScreen sets the background image for the main screen
BackGround_MainScreen = Background('TetrisMain.jpg', [0, 0])

# window_size is the height and width for the screen
window_size = (400, 500)

# screen initializes screen ans its size
screen = pygame.display.set_mode(window_size)

# sets the title for the window
pygame.display.set_caption('Tetris')

# applies changes to screen
screen.blit(BackGround_MainScreen.image, BackGround_MainScreen.rect)

# The following is an event type to appear on the event queue after every 1000 milliseconds
pygame.time.set_timer(pygame.USEREVENT + 1, 1000)

if play_music:
    file = 'maintheme.mp3' # the main sound being played in the background
    pygame.init()
    pygame.mixer.init()
    pygame.mixer.music.load(file)
    pygame.mixer.music.play(-1)
    pygame.mixer.music.set_volume(0.5)

# While the game is running, the following events can possibly occur. Based on what event is
# true, carry out the neccesary steps
while running:
    for event in pygame.event.get():

        # pygame.QUIT: allows to quit the window when clicked on 'X' in the top right corner
        if event.type == pygame.QUIT:
            running = False

        # pygame.MOUSEBUTTONDOWN: detects a click on the screen
        elif event.type == pygame.MOUSEBUTTONDOWN:

            # get the coordinates on the x and y axis when you click on the screen
            x, y = pygame.mouse.get_pos()

            # the following conditions specify the range of click for x and y coordinates in order to
            # activate a particular button

            if (x > 130 and x < 310 and y > 280 and y < 330) and (start == False and rules == False):
                # after clicking on the button "START", the conditional statement for 'start' is made
                # true and therefore, executed
                click = pygame.mouse.get_pressed()
                initialize_game()
                if click[0] == 1:
                    start = True
                    rules = False
                    back = True
                    home = False

            elif (x > 130 and x < 310 and y > 340 and y < 390) and (start == False and rules == False):
                # after clicking on the button "RULES", 'rules' is made true and the conditional statement for
                # it are executed
                click = pygame.mouse.get_pressed()

                if click[0] == 1:
                    rules = True
                    back = True
                    home = False

            elif (x > 130 and x < 310 and y > 400 and y < 450) and (start == False and rules == False):
                # after clicking on the button "QUIT", the function(quitgame) is called
                click = pygame.mouse.get_pressed()

            elif (x > 0 and x < 80 and y > 0 and y < 30) and back == True:
                # when you click on the button "RULES", a screen with an image of the rules for the game
                # appear with a "BACK" button in the top left corner. By clicking on this back button,
                # the user is lead to the home screen again
                rules = False
                back = False
                home = True

            elif (x > 170 and x < 270 and y > 315 and y < 350) and gameover == True:
                # after clicking on the button "RESTART", in gameover, the states of the following variables change:
                start = True
                gameover = False
                rules = False
                home = False

            elif (x > 170 and x < 270 and y > 360 and y < 395) and gameover == True:
                # after clicking on the button "RULES", in gameover, the states of the following variables change:
                gameover = False
                rules = True
                start = False
                home = False

            elif (x > 300 and x < 360 and y > 390 and y < 415) and start == True:
                # after clicking on the button "Sound", in game play, the sound is stopped (or played) - depending on
                # its previous state:
                mute = not mute
                if mute:
                    pygame.mixer.music.pause()
                else:
                    pygame.mixer.music.unpause()

            elif (x > 300 and x < 360 and y > 420 and y < 445) and (start == True and back == True):
                # after clicking on the button "Back", in game play, the states of the following variables change and
                # the player is directed to the main screen:
                click = pygame.mouse.get_pressed()
                if click[0] == 1:
                    start = False
                    rules = False
                    back = False
                    home = True

            elif (x > 300 and x < 360 and y > 450 and y < 475) and start == True:
                # after clicking on the button "Quit", in game play, the program exits:
                click = pygame.mouse.get_pressed()
                quitgame()

        # pygame.KEYDOWN: detects if a key is pressed
        elif event.type == pygame.KEYDOWN and start == True:

            # the following show the initialization of the variables 'down' (holding the value when the
            # down arrow key is pressed), 'right' (holding the value when the right arrow key is pressed),
            # 'left' (holding the value when the left arrow key is pressed)
            down = pygame.key.get_pressed()[pygame.K_DOWN]
            left = pygame.key.get_pressed()[pygame.K_LEFT]
            right = pygame.key.get_pressed()[pygame.K_RIGHT]
            up = pygame.key.get_pressed()[pygame.K_UP]
            paused = pygame.key.get_pressed()[pygame.K_p]
            # restricts the movement towards the left if there is already a shape lying on that side. otherwise,
            # it decreases the value of the x-axis by 1 block
            if left and not collision_occured(board, current_shape_desc, shape_x - 1, shape_y):
                if shape_x > 0:
                    shape_x -= 1

            # restricts the movement towards the right if there is already a shape lying on that side. otherwise,
            # it increases the value of the x-axis by 1 block
            elif right and not collision_occured(board, current_shape_desc, shape_x + 1, shape_y):
                if shape_x < 9:
                    shape_x += 1

            # restricts the rotation of the shape if there is already a shape/boundary on a side. otherwise,
            # returns the rotated shape
            elif up and not collision_occured(board, current_shape_desc, shape_x, shape_y):
                current_shape_desc = shape_rotation(board, current_shape_desc, shape_x, shape_y)

            # if the down key is pressed, the value of the y-axis increments by 1 block
            elif down and not collision_occured(board, current_shape_desc, shape_x, shape_y + 1):
                    shape_y += 1
                    myscore += 1
                    if collision_occured_bottom(board, current_shape_desc, shape_x, shape_y):
                        tempo = 100

            # if the 'P' key is pressed, the opposite of the present state of the game pause is returned
            elif paused:
                pause = not pause

        # pygame.USEREVENT +1: allows the block to automatically move downwards after one click, since it keeps
        # decrementing the value of the y-axis. It also updates the board by returning the new board if the rows
        # are removed and the corresponding change in myscore and lines removed.
        elif event.type == pygame.USEREVENT+1:

            if start:
                shape_y += 1
                update = remove_row(board, myscore, lines, mute)
                board = update[0]
                myscore = update[1]
                lines = update[2]

    # checking if the game is paused, if yes, then game stays within this loop until unpaused
    while pause:

        # displays the message that the game is paused
        largeText = pygame.font.Font("freesansbold.ttf", 60)
        msg = "Paused"
        textSurf, textRect = text_objects(msg, largeText)
        textRect.center = (190, 235)
        screen.blit(textSurf, textRect)

        for event in pygame.event.get():

            # pygame.QUIT: allows to quit the window when clicked on 'X' in the top right corner
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            # pygame.KEYDOWN: detects if a key is pressed
            elif event.type == pygame.KEYDOWN and start == True:
                paused = pygame.key.get_pressed()[pygame.K_p]
                # unpause the game if its paused, and so exits this loop
                if paused:
                    pause = not pause

            # pygame.MOUSEBUTTONDOWN: detects a click on the screen
            elif event.type == pygame.MOUSEBUTTONDOWN:

                # get the coordinates on the x and y axis when you click on the screen
                x, y = pygame.mouse.get_pos()
                if (x > 300 and x < 360 and y > 420 and y < 445) and (start == True):
                    # after clicking on the button "Back", in game play, the states of the following variables change and
                    # the player is directed to the main screen:
                    click = pygame.mouse.get_pressed()
                    if click[0] == 1:
                        start = False
                        rules = False
                        back = False
                        home = True
                        pause = False

                if (x > 300 and x < 360 and y > 390 and y < 415) and (start == True):
                    # after clicking on the button "Sound", in game play, the sound is stopped (or played) - depending on
                    # its previous state:
                    click = pygame.mouse.get_pressed()
                    if click[0] == 1:
                        mute = not mute
                        if mute:
                            pygame.mixer.music.pause()
                        else:
                            pygame.mixer.music.unpause()

        button("Sound", 300, 390, 60, 25, blue, staleblue)
        button("Back", 300, 420, 60, 25, blue, staleblue)
        button("Quit", 300, 450, 60, 25, blue, staleblue, quitgame)

        # update screen
        pygame.display.update()
        clock.tick(20)

    # if any of the HOME, RULES or START screens is activated (or True), the subsequent if-condition will be executed

    # 'home' is the bool variable for the main screen. If it is true, the following code is executed. The home screen
    # first appears when the game is started
    if home:

        # shows the display including the background and necessary buttons
        screen.blit(BackGround_MainScreen.image, [0, 0])
        button("START", 110, 280, 180, 50, blue, staleblue)
        button("RULES", 110, 340, 180, 50, blue, staleblue)
        button("QUIT", 110, 400, 180, 50, blue, staleblue, quitgame)

    # 'rules' is the bool variable for the rules screen. If it is true, the following code is executed. The rule screen
    # appears when the button "RULES" is clicked
    elif rules:
        rule = Background("rules.png", [0, 0])
        screen.blit(rule.image, [0, 0])
        button("BACK", 0, 0, 80, 30, blue, staleblue)

    # 'start' is the bool variable for the game play screen. If it is true, the following code is executed. The start
    # (or game play) screen appears when the button "START" is clicked
    elif start:
        # window initializes the total size for the game play window. In this, we will be using the first 250 pixels
        # (from left to right) for the tetris game play and the remaining 150 pixels to draw the side panel (which includes
        # the score, next piece, lines)

        window = (400, 500)

        # updates the screen
        screen = pygame.display.set_mode(window)
        background = pygame.Surface(window)
        screen.blit(background, (0, 0))

        # font1 & font2 are font types and their sizes to use for headings on the side panel
        font1 = pygame.font.Font("freesansbold.ttf", 20)
        font2 = pygame.font.Font("freesansbold.ttf", 16)

        # draw a rectangular panel on the right side
        pygame.draw.rect(screen, darkblue, (250, 0, 150, 500))

        # add the heading 'Next:' to the rectangular panel with the upcoming shape
        text = font1.render("Next:", 1, white)
        screen.blit(text, (260, 100))

        # Draw the black box in which the next piece should appear
        pygame.draw.rect(screen, black, (265, 140, 120, 95))

        # add the heading 'Lines:' to the rectangular panel with the updated removed lines
        text = font2.render("Lines: " + str(lines), 1, white)
        screen.blit(text, (260, 280))

        # add the heading 'Score:' to the rectangular panel with the updated current score
        text = font2.render("Score: " + str(myscore), 1, white)
        screen.blit(text, (260, 310))

        f = open("high_score.txt", 'r') # opens the file to read the current high score value
        line = f.read()
        highscore = line.strip()
        highscore = int(highscore)

        if myscore > highscore: # if the highscore value is less than the current myscore, then the current
            highscore = myscore # score becomes the high score

        # add the heading 'High Score:' to the rectangular panel with the updated high score
        text = font2.render("High Score: " + str(highscore), 1, white)
        screen.blit(text, (260, 340))

        # draw a white line b/w the gameplay screen and the rectangular panel
        pygame.draw.line(screen, white, (250, 0), (250, 500))

        # initialize buttons on the right panel to activate sound, pause the game, or to quit the game
        button("Sound", 300, 390, 60, 25, blue, staleblue)
        button("Back", 300, 420, 60, 25, blue, staleblue)
        button("Quit", 300, 450, 60, 25, blue, staleblue)

        # the following segment draws the block as it moves downwards (from top to bottom)
        y, x = 0, 0
        for row in current_shape_desc:
            for col in row:
                if col:
                    # to draw the shape
                    pygame.draw.rect(screen, current_shape_col, pygame.Rect((shape_x + x) * p_count, (shape_y + y) * p_count, 25, 25), 0)

                    # to draw the outline of the shape
                    pygame.draw.rect(screen, black, pygame.Rect((shape_x + x) * p_count, (shape_y + y) * p_count, 25, 25), 1)
                x += 1
            y += 1
            x = 0

        # draw the next predicted shape and align the next shape in the black rectangular box (below Next) according
        # to the shape dimensions
        # In this code segment, the digits being added to x and y represent the column and row from where the shape
        # should be started for drawing
        y, x = 0, 0
        for row in next_predicted_shape["shape"]:
            for col in row:
                if col:
                    if 1 in row: # if the shape is a square

                        # to draw the shape
                        pygame.draw.rect(screen, next_predicted_shape["color"],
                                         pygame.Rect((12 + x) * p_count, (6.5 + y) * p_count, 25, 25), 0)

                        # to draw the outline of the shape
                        pygame.draw.rect(screen, black,
                                         pygame.Rect((12 + x) * p_count, (6.5 + y) * p_count, 25, 25), 1)

                    elif 4 in row: #if the shape is a straight line

                        # to draw the shape
                        pygame.draw.rect(screen, next_predicted_shape["color"],
                                         pygame.Rect((11 + x) * p_count, (7 + y) * p_count, 25, 25), 0)
                        # to draw the outline of the shape
                        pygame.draw.rect(screen, black,
                                         pygame.Rect((11 + x) * p_count, (7 + y) * p_count, 25, 25), 1)

                    else: #any other shape

                        # to draw the shape
                        pygame.draw.rect(screen, next_predicted_shape["color"],
                                         pygame.Rect((11.5 + x) * p_count, (6.5 + y) * p_count, 25, 25), 0)

                        # to draw the outline of the shape
                        pygame.draw.rect(screen, black,
                                         pygame.Rect((11.5 + x) * p_count, (6.5 + y) * p_count, 25, 25), 1)
                x += 1
            y += 1
            x = 0

        # if collision occurs at the maximum top of the screen, it indicates the end of the game
        if collision_occured(board, current_shape_desc, 4, 0) :
            if check_top (board):
                collide = True
                pygame.time.delay(2000)
                start = False
                gameover = True
                file = 'gameover.wav'  # the sound in the background being played
                pygame.mixer.music.stop()
                pygame.mixer.music.load(file)
                pygame.mixer.music.play()
                pygame.mixer.music.set_volume(0.5)

        # otherwise, the game continues
        if collide == False:
            if collision_occured_bottom(board, current_shape_desc, shape_x, shape_y):
                if tempo<10:
                    tempo = tempo+1
                else:
                    tempo=0
                    place_shape(board, current_shape_desc, shape_x, shape_y+1, mute)
                    shape_x = 4
                    shape_y = 0
                    next_shape = next_predicted_shape
                    next_predicted_shape = new_shape(All_shapes)
                    current_shape_col = next_shape["color"]
                    current_shape_desc = next_shape["shape"]

            # the following segment draws the block at the bottom of the board when it is settled
            y, x = 0, 0
            for row in board:
                for col in row:
                    if col:

                        color = color_shape_mapping[str(col)]

                        # to draw the shape
                        pygame.draw.rect(screen, color, pygame.Rect(x * p_count, y * p_count, 25, 25), 0)

                        # to draw the outline of the shape
                        pygame.draw.rect(screen, black, pygame.Rect(x * p_count, y * p_count, 25, 25), 1)
                    x += 1
                y += 1
                x = 0

    # 'gameover' is the bool variable for the gameover screen. If it is true, the following code is executed. The gameover screen
    # first appears when the collision occurs at the top most portion of the board
    elif gameover:
        # sets screen to black
        screen.fill(black)

        # initialize fonts
        font3 = pygame.font.Font("freesansbold.ttf", 40)
        font4 = pygame.font.Font("freesansbold.ttf", 20)

        # open the file that scores the high score for read and write
        hisc = open("high_score.txt", 'r+')

        #first read the high score
        line = hisc.read()
        highscore = line.strip()
        highscore = int(highscore)

        #if the highscore is less than the current score, update the highscore value in the file
        #by overwriting the current highscore value
        if fileopen:
            if myscore > highscore:
                hisc.seek(0)
                hisc.truncate()
                fileopen = False
                myscore = str(myscore)
                hisc.write(myscore)
                highscore = int(myscore)
                hscore = True
            hisc.close()

        # if there was a new high score, then show the message of New High Score to user with the current score
        if hscore:
            text = font4.render("New High Score!", 1, white)
            screen.blit(text, (120, 230))
            text = font4.render("Score: " + str(myscore), 1, white)
            screen.blit(text, (150, 260))

        #otherwise, just show the user their ending score
        else:
            text = font4.render("Score: " + str(myscore), 1, white)
            screen.blit(text, (150, 260))

        # add the heading to the Gameover screen
        text = font3.render("Game Over", 1, white)
        screen.blit(text, (80, 160))

        # add buttons to the gameover screen:

        # restart the game:
        button("RESTART", 110, 300, 180, 50, blue, staleblue)

        # go to rules:
        button("RULES", 110, 360, 180, 50, blue, staleblue)

        # quit the game:
        button("QUIT", 110, 420, 180, 50, blue, staleblue, quitgame)

    # update the screen
    clock.tick(30)
    pygame.display.update()

pygame.quit()


# Binary Search

from collections import List

class Solution:
    def maxLength(self, ribbons: List[int], k: int) -> int:

        low, high = 1, max(ribbons)

        while low <= high:

            mid = low + (high - low) // 2

            # add number of ribons that can be made
            num_cuts = sum(ribbon//mid for ribbon in ribbons)
            print(num_cuts, mid)
            # 3 5
            # 2 7
            # 2 6

            # keep searching for a possibly larger size that can make k
            if num_cuts >= k:
                low = mid + 1
            else:
                high = mid - 1

        return low - 1


from sdv.model import (
    DataPointBoolean,
    DataPointFloat,
    DataPointInt8,
    DataPointUint8,
    DataPointUint16,
    Model,
)

from sdv_model.Cabin.Seat.Airbag import Airbag
from sdv_model.Cabin.Seat.Backrest import Backrest
from sdv_model.Cabin.Seat.Headrest import Headrest
from sdv_model.Cabin.Seat.Occupant import Occupant
from sdv_model.Cabin.Seat.Seating import Seating
from sdv_model.Cabin.Seat.Switch import Switch

class Seat(Model):
    """Seat model.

    Attributes
    ----------
    IsOccupied: sensor
        Does the seat have a passenger in it.

    Occupant: branch
        Occupant data.

    IsBelted: sensor
        Is the belt engaged.

    Heating: actuator
        Seat cooling / heating. 0 = off. -100 = max cold. +100 = max heat.

        Value range: [-100, 100]
        Unit: percent
    Massage: actuator
        Seat massage level. 0 = off. 100 = max massage.

        Value range: [0, 100]
        Unit: percent
    Position: actuator
        Seat position on vehicle x-axis. Position is relative to the frontmost position supported by the seat. 0 = Frontmost position supported.

        Value range: [0, ]
        Unit: mm
    Height: actuator
        Seat position on vehicle z-axis. Position is relative within available movable range of the seating. 0 = Lowermost position supported.

        Value range: [0, ]
        Unit: mm
    Tilt: actuator
        Tilting of seat relative to vehicle z-axis. 0 = seating is flat, seat and vehicle z-axis are parallel. Positive degrees = seat tilted backwards, seat z-axis is tilted backward.

        Unit: degrees
    Backrest: branch
        Describes signals related to the backrest of the seat.

    Seating: branch
        Describes signals related to the seating/base of the seat.

        Seating is here considered as the part of the seat that supports the thighs. Additional cushions (if any) for support of lower legs is not covered by this branch.

    Headrest: branch
        Headrest settings.

    Airbag: branch
        Airbag signals.

    Switch: branch
        Seat switch signals

    """

    def __init__(self, name, parent):
        """Create a new Seat model."""
        super().__init__(parent)
        self.name = name

        self.IsOccupied = DataPointBoolean("IsOccupied", self)
        self.Occupant = Occupant("Occupant", self)
        self.IsBelted = DataPointBoolean("IsBelted", self)
        self.Heating = DataPointInt8("Heating", self)
        self.Massage = DataPointUint8("Massage", self)
        self.Position = DataPointUint16("Position", self)
        self.Height = DataPointUint16("Height", self)
        self.Tilt = DataPointFloat("Tilt", self)
        self.Backrest = Backrest("Backrest", self)
        self.Seating = Seating("Seating", self)
        self.Headrest = Headrest("Headrest", self)
        self.Airbag = Airbag("Airbag", self)
        self.Switch = Switch("Switch", self)


import cv2
import numpy as np
import rect

image = cv2.imread('test-images/page.jpg')

# Resizing will make results better. Why?????
image = cv2.resize(image, (1500, 880))

orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
kernel = np.ones((3, 3), np.uint8)
dilated = cv2.dilate(blurred, kernel, iterations=1)
edged = cv2.Canny(dilated, 0, 50)
orig_edged = edged.copy()

# find the contours in the edged image, keeping only the
# largest ones, and initialize the screen contour
_, contours, _ = cv2.findContours(edged, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)
print(cv2.contourArea(contours[0]))
cv2.drawContours(image, [contours[0]], -1, (0, 255, 0), 2)

#x,y,w,h = cv2.boundingRect(contours[0])
#cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),0)

# get approximate contour
for c in contours:
    p = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * p, True)

    # If there are 4 sides. (Can it be improved here???)
    if len(approx) == 4:
        target = approx
        break

# mapping target points to 800x800 quadrilateral
approx = rect.rectify(target)
pts2 = np.float32([[0,0],[800,0],[800,800],[0,800]])

M = cv2.getPerspectiveTransform(approx,pts2)
dst = cv2.warpPerspective(orig,M,(800,800))

cv2.drawContours(image, [target], -1, (0, 255, 0), 2)
dst = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)

# using thresholding on warped image to get scanned effect (If Required)
ret,th1 = cv2.threshold(dst,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(dst,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(dst,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)
ret2,th4 = cv2.threshold(dst,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# cv2.imshow("Original.jpg", orig)
# cv2.imshow("Original Gray.jpg", gray)
# cv2.imshow("Original Blurred.jpg", blurred)
cv2.imshow("Original Edged.jpg", orig_edged)
cv2.imshow("Outline.jpg", image)
# cv2.imshow("Thresh Binary.jpg", th1)
# cv2.imshow("Thresh mean.jpg", th2)
# cv2.imshow("Thresh gauss.jpg", th3)
# cv2.imshow("Otsu's.jpg", th4)
cv2.imshow("dst.jpg", dst)

# other thresholding methods
"""
ret,thresh1 = cv2.threshold(dst,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(dst,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(dst,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(dst,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(dst,127,255,cv2.THRESH_TOZERO_INV)

cv2.imshow("Thresh Binary", thresh1)
cv2.imshow("Thresh Binary_INV", thresh2)
cv2.imshow("Thresh Trunch", thresh3)
cv2.imshow("Thresh TOZERO", thresh4)
cv2.imshow("Thresh TOZERO_INV", thresh5)
"""

cv2.waitKey(0)
cv2.destroyAllWindows()


import pygame,sys
from esTxt import textt
def options():
    altura = 600
    largura = 1230
    mainClock = pygame.time.Clock()
    screen = pygame.display.set_mode((largura,altura), 0, 32)
    es=textt("opt",(225,225,225),screen,40,400)
    running = True
    while running:
        screen.fill((0,0,0))
        es.draw_text1()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    running = False
        pygame.display.update()
        mainClock.tick(60)


import pandas as pd
import json
import time
import os
import re
import random
import requests
from urllib import parse

class DuckSearch:

    def __init__(self, settings):
        self.domain = 'https://duckduckgo.com'
        self.language = settings.get('DDGlanguage', 'en-us')
        self.headers = {
            'User-Agent': settings.get('DDGuser-agent', ''),
            'Cache-Control': 'no-cache'
        }

    def search(self, searchItem):
        self.message = ''
        self.term = searchItem.get('term')
        self._blacklist = searchItem.get('blacklist', [])
        return self._processQuery(), self.message

    def _get_response(self):
        query = parse.quote(self.term)
        url = f'{self.domain}/local.js?q={query}&cb=DDG.duckbar.add_local&tg=maps_places&l={self.language}&sf=low'
        req =requests.get(url, headers=self.headers)
        m = re.search(r'DDG.duckbar.add_local\((.*)\)', req.text)
        if m:
            vqd = list(json.loads(m.group(1))['vqd'].values())[0]
            if vqd:
                url = f'{self.domain}/d.js?q={query}&t=D&l=wt-wt&s=0&a=hk&ss_mkt=us&vqd={vqd}&p_ent=&ex=-1&sp=0'
                time.sleep(random.uniform(1,3))
                self.response = requests.get(url, headers=self.headers).text
            else:
                self.response = ''
        else:
            self.response = ''
        time.sleep(6)

    def _parse_response(self):
        columns = ['date', 'seqno', 'query', 'title', 'snippet', 'url_se', 'pagemap']
        m = re.search(r"DDG\.pageLayout\.load\('d',(\[.*\])\)", self.response)
        if m:
            result = pd.DataFrame(json.loads(m.group(1)))[['u', 't', 'a']]
            if 'l' in result.columns:
                res0 = pd.DataFrame()
                for r in result.loc[result[['l']].any(axis=1), 'l']:
                    resnew = pd.DataFrame([{'u': x['targetUrl'], 't': x['text'], 'a': x['snippet']} for x in r])
                    res0 = pd.concat([res0, resnew])
                result = pd.concat([res0, result]).reset_index(drop=True)
            result.columns = ['url_se', 'title', 'snippet']
            result['seqno'] = result.index + 1
            result['date'] = time.strftime('%Y%m%d')
            result['query'] = self.term
            result['pagemap'] = '' # return this column because of compatibility with googlsearch.py
            return result[pd.notnull(result.url_se)][columns]
        else:
            self.message = 'Expected javascript file (d.js) not found.'
            return pd.DataFrame(columns=columns)

    def excludedSites(self):
        exclude = ' '.join(['-site:' + url for url in self._blacklist])
        return exclude

    def _processQuery(self):
        exclude = self.excludedSites()
        if exclude:
            self.term = self.term.replace(' ', '+') + ' ' + exclude
        self._get_response()
        return self._parse_response()


import os
#import cv2
import math
import time
import csv
import random
import numpy as np
import scipy.io as scio
import PIL.Image as Image
#from sklearn.metrics import confusion_matrix, roc_curve, average_precision_score, auc, f1_score

import argparse
parse = argparse.ArgumentParser('Train_Unimodal')
parse.add_argument('--gpu',type=str,default='0')
parse.add_argument('--patient_csv',type=str)
parse.add_argument('--path_lib',type=str,default='./weights/features/')
parse.add_argument('--omic_lib',type=str,default='./DATA/OMIC/')
parse.add_argument('--output_file',type=str,default='./weights/Fusion/')
parse.add_argument('--model_type',type=str,default='last')
parse.add_argument('--cross',type=int)  #int, 0-4, select from 5-fold
parse.add_argument('--modality',type=str) #'path'/'omic
parse.add_argument('--max_epoch',type=int)
parse.add_argument('--step_size',type=int)
parse.add_argument('--batch_size',type=int)
parse.add_argument('--lr',type=float)
args = parse.parse_args()

os.environ['CUDA_VISIBLE_DEVICES']=args.gpu

import torch
import torch.nn as nn
import torch.optim as opt
from torch.optim import lr_scheduler
from torch.autograd import Variable
from torchvision import transforms,models
import torch.nn.functional as F
from torch.utils.data import Dataset
from torch_geometric.data import Data

from model.SNN_model import define_net, define_optimizer
from model.GCN import GraphNet
from evaluation import calculate_metrics

cross = args.cross
modality = args.modality

train_cross = [cross%5,(cross+1)%5,(cross+2)%5]
val_cross = [(cross+3)%5]

csv_file = args.patient_csv
path_lib = os.path.join(args.path_lib, 'cross'+str(cross))
omic_lib = args.omic_lib
output_file = os.path.join(args.output_file, 'cross'+str(cross), modality+'_coatt')

path_coatt_feature = os.path.join(args.output_file, 'cross'+str(cross), 'coatt_feature/path')
omic_coatt_feature = os.path.join(args.output_file, 'cross'+str(cross), 'coatt_feature/omic')

load_coatt_path_name = os.path.join(args.output_file, 'cross'+str(cross), 'path/checkpoint_last.pth')
load_coatt_omic_name = os.path.join(args.output_file, 'cross'+str(cross), 'omic/checkpoint_last.pth')
load_model_test = os.path.join(output_file, 'checkpoint_'+args.model_type+'.pth')

lr = args.lr
max_epoch = args.max_epoch
step_size = args.step_size

#-----------------------------------------------------------------------------------------------#
# loss
class CrossEntropyLoss(nn.Module):
    def __init__(self):
        super(CrossEntropyLoss,self).__init__()

    def forward(self,y_pred, target):
        loss_function = nn.CrossEntropyLoss()
        loss = loss_function(y_pred, target)
        return loss

#-----------------------------------------------------------------------------------------------#
# data loader
class DataSet(Dataset):
    def __init__(self, cross_list, pathfile=path_lib, omicfile=omic_lib, pathcoattfile=path_coatt_feature, omiccoattfile=omic_coatt_feature):
        # list patient & label
        self.paths = []
        self.path_paths = []
        self.omics = []
        self.omic_paths = []
        self.targets = []

        csv_names = ['LUAD-', 'LUSC-']
        fold_names = ['TCGA-LUAD', 'TCGA-LUSC']

        for i in range(2):
            for j in cross_list:
                csv_path = os.path.join(csv_file, csv_names[i]+str(j)+'.csv')
                with open(csv_path) as f:
                    rows = csv.reader(f, delimiter = ',')
                    for row in rows:
                        uid = row[0]
                        label = i

                        path_fold = os.path.join(pathfile, fold_names[i], uid)
                        omic_path = os.path.join(omicfile, fold_names[i], uid+'.mat')
                        omic_fea_path = os.path.join(omic_coatt_feature, uid+'.mat')

                        if not os.path.exists(omic_path):
                            print('File ERROR! :', omic_path)
                            continue

                        if not os.path.exists(path_fold):
                            print('File ERROR! :', path_fold)
                            continue

                        imgs = os.listdir(path_fold)
                        for img in imgs:
                            path_path = os.path.join(path_fold, img)
                            path_fea_path = os.path.join(path_coatt_feature, uid, img)

                            if not os.path.exists(path_path):
                                print('File ERROR! :', path_path)
                            else:
                                self.paths.append(path_path)
                                self.path_paths.append(path_fea_path)
                                self.omics.append(omic_path)
                                self.omic_paths.append(omic_fea_path)
                                self.targets.append(int(label))

    def __len__(self):
        return len(self.targets)

    def __getitem__(self,index):
        path_path = self.paths[index]
        path_fea_path = self.path_paths[index]
        omic_path = self.omics[index]
        omic_fea_path = self.omic_paths[index]

        # open path
        data_mat_path = scio.loadmat(path_path)
        path_features = torch.from_numpy(data_mat_path['feature'])
        #roi_seq = features.unsqueeze(0)
        edge_index = torch.from_numpy(data_mat_path['edge'])
        path_fea = torch.from_numpy(scio.loadmat(path_fea_path)['path_feature'])

        # open omic
        data_mat_omic = scio.loadmat(omic_path)
        omic_raw = torch.from_numpy(data_mat_omic['raw'])
        omic_fea = torch.from_numpy(scio.loadmat(omic_fea_path)['omic_feature'])

        target = np.array([self.targets[index]])

        return path_features, edge_index, omic_raw, torch.from_numpy(target), path_fea, omic_fea

#-----------------------------------------------------------------------------------------------#
# get coatt feature
def inference(model_coattn, modal):
    print('-----------------inference coattention feature-----------------------')
    model_coattn.eval()

    # metrics
    pred_epoch, true_epoch = None, None

    types = ['TCGA-LUAD', 'TCGA-LUSC']

    for i in range(2):
        uids = os.listdir(os.path.join(path_lib, types[i]))
        path_path = os.path.join(path_lib, types[i])
        omic_path = os.path.join(omic_lib, types[i])

        for uid in uids:
            if modal == 'omic':
                mat_path = os.path.join(omic_path, uid+'.mat')
                if not os.path.exists(mat_path):
                    continue
                data_mat_omic = scio.loadmat(mat_path)
                omic_raw = torch.from_numpy(data_mat_omic['raw'])
                omic_raw = omic_raw.to(torch.float32).cuda()
                target = np.array([i])

                att_features, _, out = model_coattn(x = omic_raw)
                att_features = att_features.cpu().detach().numpy()
                if not os.path.exists(omic_coatt_feature):
                    os.makedirs(omic_coatt_feature)
                scio.savemat(os.path.join(omic_coatt_feature,uid+'.mat'), {'omic_feature':att_features})

                out = nn.Softmax(dim=1)(out)
                pred_cpu = out.cpu().detach().numpy()
                true_cpu = target
                pred_epoch = np.concatenate((pred_epoch, pred_cpu), axis=0) if (pred_epoch is not None) else pred_cpu.copy()
                true_epoch = np.concatenate((true_epoch, true_cpu), axis=0) if (true_epoch is not None) else true_cpu.copy()

                acc, AUC, AP, f1score, sen, spe = calculate_metrics(pred_epoch, true_epoch)
                print("\r[omic] acc:{:.4f}, AUC:{:.4f}, AP:{:.4f}, f1:{:.4f}".format(acc, AUC, AP, f1score), end='')

            if modal == 'path':
                if not os.path.exists(os.path.join(path_path, uid)):
                    continue
                imgs = os.listdir(os.path.join(path_path, uid))
                for img in imgs:
                    mat_path = os.path.join(path_path, uid, img)
                    data_mat_path = scio.loadmat(mat_path)
                    path_features = torch.from_numpy(data_mat_path['feature']).cuda()
                    edge_index = torch.from_numpy(data_mat_path['edge']) .cuda()
                    data = Data(x=path_features, edge_index=edge_index)
                    target = np.array([i])

                    att_features, _, out = model_coattn(data=data)
                    att_features = att_features.cpu().detach().numpy()
                    if not os.path.exists(os.path.join(path_coatt_feature, uid)):
                        os.makedirs(os.path.join(path_coatt_feature, uid))
                    scio.savemat(os.path.join(path_coatt_feature, uid, img), {'path_feature':att_features})

                    out = nn.Softmax(dim=1)(out)
                    pred_cpu = out.cpu().detach().numpy()
                    true_cpu = target
                    pred_epoch = np.concatenate((pred_epoch, pred_cpu), axis=0) if (pred_epoch is not None) else pred_cpu.copy()
                    true_epoch = np.concatenate((true_epoch, true_cpu), axis=0) if (true_epoch is not None) else true_cpu.copy()

                    acc, AUC, AP, f1score, sen, spe = calculate_metrics(pred_epoch, true_epoch)
                    print("\r[path] acc:{:.4f}, AUC:{:.4f}, AP:{:.4f}, f1:{:.4f}".format(acc, AUC, AP, f1score), end='')

#-----------------------------------------------------------------------------------------------#
# train
def train_step(data_set, mode, epoch, criterion, net, optim):
    if mode == 'test':
        net.eval()
    else:
        net.train()
        print(30*'-', '\n[epoch', epoch+1,'] Learning Rate:{}'.format(optim.param_groups[0]['lr']))

    running_loss = 0.
    consume_time = 0.

    data_len = data_set.__len__()
    data_shuffle = random.sample(range(data_len),data_len)
    step = 0
    for i in data_shuffle:
        now = time.time()
        path_features, edge_index, omic_raws, targets, path_fea, omic_fea = data_set.__getitem__(i)
        path_features, edge_index = path_features.cuda(), edge_index.cuda()
        omic_raws = omic_raws.to(torch.float32).cuda()
        targets = targets.cuda()
        path_fea, omic_fea = path_fea.cuda(), omic_fea.cuda()

        data = Data(x=path_features, edge_index=edge_index)

        if mode != 'train':
            with torch.no_grad():
                if modality == 'path':
                    _, _, out = net(data, omic_fea, 1)
                    loss = criterion(out, targets)

                elif modality == 'omic':
                    _, _, out = net(path_fea, omic_raws, 1)
                    loss = criterion(out, targets)

        else:
            optim.zero_grad()

            if modality == 'path':
                _, _, out = net(data, omic_fea, 1)
                loss = criterion(out, targets)

            elif modality == 'omic':
                _, _, out = net(path_fea, omic_raws, 1)
                loss = criterion(out, targets)

            loss.backward()
            optim.step()

        # loss
        running_loss = (running_loss*step+loss.item())/(step+1)

        if mode != 'train':
            print("\r[Validation] Step {}/{}, loss:{:.5f}".\
                  format(step, data_len, running_loss), end='')
        else:
            print('\r[Train] Step {}/{}, loss:{:.5f}'.\
                  format(step, data_len, running_loss), end='')
        consume_time += time.time() - now
        step += 1

    print(' ')

    return running_loss, consume_time/step

#-----------------------------------------------------------------------------------------------#
# train main
def pretrain_unimodal_coattention(max_epoch=max_epoch, ModelSet = '', save_csv = True, save_best_model = True, save_last_model = True, \
                                  isload = False, load_model_name=''):
    torch.cuda.manual_seed_all(0)
    torch.manual_seed(0)
    random.seed(0)

    # get coatt feature
    if not os.path.exists(path_coatt_feature):
        model = GraphNet(feature_length=128, nhid=256)
        model.cuda()
        pretrained=torch.load(load_coatt_path_name)
        model.load_state_dict(pretrained['state_dict'])
        print('coattn path model load successfully: ',load_coatt_path_name)
        inference(model, 'path')
        del model
    if not os.path.exists(omic_coatt_feature):
        model = define_net()
        model.cuda()
        pretrained=torch.load(load_coatt_omic_name)
        model.load_state_dict(pretrained['state_dict'])
        print('coattn omic model load successfully: ',load_coatt_omic_name)
        inference(model, 'omic')
        del model

    # define net
    if modality == 'omic':
        model = define_net()
        model.cuda()
        optimizer = define_optimizer(model=model, lr=lr)
        #scheduler = define_scheduler(optimizer)
        scheduler = lr_scheduler.StepLR(optimizer,step_size=args.step_size,gamma=0.5)
    elif modality == 'path':
        model = GraphNet(feature_length=128, nhid=256)
        model.cuda()
        optimizer = opt.Adam(model.parameters(), lr=lr, weight_decay=1e-4)
        scheduler = lr_scheduler.StepLR(optimizer,step_size=args.step_size,gamma=0.5)

    criterion = CrossEntropyLoss().cuda()

    start_epoch = 0
    lowest_loss = float('Inf')  # 寻找最小loss

    train_set = DataSet(train_cross)
    val_set = DataSet(val_cross)

    for epoch in range(start_epoch, max_epoch):
        # train dataset
        running_loss, consume_time = \
            train_step(train_set, 'train', epoch, criterion, model, optimizer)

        scheduler.step()

        # validation dataset
        val_loss, consume_time = \
            train_step(val_set, 'test', epoch, criterion, model, optimizer)

        # save best model
        print('')
        if val_loss < lowest_loss:
            print('Val_loss is lower than previous {:.5f}. The new best model saved. '.format(lowest_loss))
            lowest_loss = val_loss
            #obj = {'state_dict': model.state_dict()}

            #torch.save(obj, os.path.join(ModelSet,'checkpoint_best.pth'))
            #print('Current loss < initial loss, best model save......')
            print('Current loss < initial loss......')
        else:
            print('Val_loss_all is not improved from {:.5f}. '.format(lowest_loss))

    # save model
    obj = {'state_dict': model.state_dict()}

    torch.save(obj, os.path.join(ModelSet,'checkpoint_last.pth'))
    print('Last model saved. ')

if __name__ == "__main__":
    if not os.path.exists(output_file):
        os.makedirs(output_file)
    print('-----------------start pretrain unimodal-----------------------')
    print('cross: ', cross)
    print('pretrain modality: ', modality)

    pretrain_unimodal_coattention(ModelSet = output_file)


import time
import pytest

from botocore.exceptions import ClientError
from botocore.stub import ANY

import service_linked_roles

@pytest.mark.parametrize(
    "error_code, stop_on_method",
    [
        (None, None),
        ("TestException", "stub_create_service_linked_role"),
        ("TestException", "stub_list_attached_role_policies"),
        ("TestException", "stub_get_policy"),
        ("TestException", "stub_get_policy_version"),
        ("TestException", "stub_delete_service_linked_role"),
    ],
)
def test_create_service_linked_role(
    make_stubber, stub_runner, monkeypatch, error_code, stop_on_method
):
    iam_stubber = make_stubber(service_linked_roles.iam.meta.client)

    service_name = "test-service-name"
    role_name = "test-role"
    policy = {"test-policy": "arn:aws:iam::111122223333:policy/test-policy"}
    policy_ver_id = "test-version"
    task_id = "test-task"

    inputs = [service_name, "y"]
    monkeypatch.setattr("builtins.input", lambda x: inputs.pop(0))
    monkeypatch.setattr(time, "sleep", lambda x: None)

    with stub_runner(error_code, stop_on_method) as runner:
        runner.add(
            iam_stubber.stub_create_service_linked_role, service_name, ANY, role_name
        )
        runner.add(iam_stubber.stub_list_attached_role_policies, role_name, policy)
        runner.add(iam_stubber.stub_get_policy, policy["test-policy"], policy_ver_id)
        runner.add(
            iam_stubber.stub_get_policy_version,
            policy["test-policy"],
            policy_ver_id,
            "test-document",
        )
        runner.add(iam_stubber.stub_delete_service_linked_role, role_name, task_id)
        runner.add(
            iam_stubber.stub_get_service_linked_role_deletion_status,
            task_id,
            "IN_PROGRESS",
        )
        runner.add(
            iam_stubber.stub_get_service_linked_role_deletion_status,
            task_id,
            "SUCCEEDED",
        )

    if error_code is None:
        service_linked_roles.usage_demo()
    else:
        with pytest.raises(ClientError) as exc_info:
            service_linked_roles.usage_demo()
        assert exc_info.value.response["Error"]["Code"] == error_code


import urllib.request
import shutil
import requests
import xlsxwriter
import random
import re

from pymongo import MongoClient
client = MongoClient()
db = client.chrome
collect = db.polyA

mcursor = collect.find({'organism':'Homo sapiens'})

TotalConsmRNA = {}
RegionConsmRNA = {}

ConsGene = {}
RegionConsGene = {}

TotalmRNA = {}
TotalGene = {}

REGION_START = 22
REGION_END = 33

for record in mcursor:
	gene = record["gene_id"]
	if record["gene_id"] in TotalGene:
		TotalGene[gene] += 1
	else:
		TotalGene[gene] = 1
	for mrna in record["mrna"]:
		if mrna in TotalmRNA:
			TotalmRNA[mrna] += 1
		else:
			TotalmRNA[mrna] = 1
	for URS in record["URS"]:
		pos = URS["downstream_rel_pos"]
		if "conserved" in URS:
			gene = record["gene_id"]
			if record["gene_id"] in ConsGene:
				ConsGene[gene] += 1
			else:
				ConsGene[gene] = 1
			for mrna in record["mrna"]:
				if mrna in TotalConsmRNA:
					TotalConsmRNA[mrna] += 1
				else:
					TotalConsmRNA[mrna] = 1
			break
	for URS in record["URS"]:
		pos = URS["downstream_rel_pos"]
		if "conserved" in URS:
			if pos <= REGION_END and pos >= REGION_START:
				gene = record["gene_id"]
				if record["gene_id"] in RegionConsGene:
					RegionConsGene[gene] += 1
				else:
					RegionConsGene[gene] = 1
				for mrna in record["mrna"]:
					if mrna in RegionConsmRNA:
						RegionConsmRNA[mrna] += 1
					else:
						RegionConsmRNA[mrna] = 1
				break
print ("Total mRNA w/ Cons URS : " + str(len(TotalConsmRNA)))
print ("mRNA w/ Cons URS in Region (" + str(REGION_START) + "-"+ str(REGION_END) + ") nt : "+ str(len(RegionConsmRNA)))
print ("Total genes w/ Cons URS : " + str(len(ConsGene)))
print ("genes w/ Cons URS in Region (" + str(REGION_START) + "-"+ str(REGION_END) + ") nt : "+ str(len(RegionConsGene)))
print ("Total mRNA we have polyA data for: " + str(len(TotalmRNA)))
print ("Total genes we have polyA data for: " + str(len(TotalGene)))


"""Tutor shared region nav bar."""

import re
from time import sleep

from pypom import Region
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By

from utils.tutor import TutorException
from utils.utilities import Utility, go_to_, go_to_external_

class Menu(Region):
    """A Tutor nav bar menu."""

    _toggle_locator = (By.CSS_SELECTOR, 'button')

    def toggle(self):
        """Open or close a nav menu."""
        Utility.scroll_top(self.driver)
        menu = self.find_element(*self._toggle_locator)
        Utility.click_option(self.driver, element=menu)
        sleep(0.15)
        return self

    @property
    def is_open(self):
        """Return True if the menu is open."""
        return 'show' in self.root.get_attribute('class')

    def _select(self, locator, destination=None, external=False, file=False):
        """Select a menu option."""
        # Open the menu if it isn't already
        if not self.is_open:
            self.toggle()
        target = self.find_element(*locator)
        url = target.get_attribute('href')
        if external:
            # Go to the external site and wait for load;
            # pass the destination URL in case the external
            # site fails to load
            Utility.switch_to(self.driver, element=target)
            if file:
                # The target is a file for download so skip
                # the wait for page load
                return
            return go_to_external_(destination(self.driver), url)
        # Go to the internal site and wait for load; pass
        # the Page base URL (attached to the Page, not the
        # parent Region) so Page.open() can work
        Utility.click_option(self.driver, element=target)
        if destination:
            return go_to_(destination(self.driver, self.page.page.base_url))

class TutorNav(Region):
    """Tutor nav bar region for logged in users."""

    _root_locator = (By.CSS_SELECTOR, '.tutor-navbar')

    # Main buttons on the nav
    _openstax_logo_locator = (By.CSS_SELECTOR, '.ui-brand-logo')
    _help_menu_locator = (By.CSS_SELECTOR, '.support-menu')
    _student_payment_locator = (By.CSS_SELECTOR, '.student-pay-now')
    _action_menu_locator = (By.CSS_SELECTOR, '.actions-menu')
    _account_menu_locator = (By.CSS_SELECTOR, '.user-menu')

    @property
    def logo(self):
        """Return the OpenStax Tutor Beta logo."""
        return self.find_element(*self._openstax_logo_locator)

    def go_to_dashboard(self):
        """Click on the OpenStax Tutor Beta logo."""
        Utility.click_option(self.driver, element=self.logo)
        sleep(0.5)
        if 'dashboard' in self.driver.current_url:
            # The user has multiple courses and ends up at
            # the course picker page
            from pages.tutor.dashboard import Dashboard
            return go_to_(Dashboard(self.driver, self.page.base_url))
        # The student has a single course and ends up on
        # their This Week course view
        from pages.tutor.course import Course
        return go_to_(Course(self.driver, self.page.base_url))

    @property
    def help(self):
        """Access the 'Help' menu."""
        root = self.find_element(*self._help_dropdown_locator)
        return self.Help(self, root)

    @property
    def student_access(self):
        """Access the student payment information."""
        try:
            root = self.find_element(*self._student_payment_locator)
            return self.Payment(self, root)
        except WebDriverException:
            raise TutorException('No active trial')

    @property
    def menu(self):
        """Access the action menu."""
        root = self.find_element(*self._action_menu_locator)
        return self.Action(self, root)

    @property
    def user(self):
        """Access the user menu."""
        root = self.find_element(*self._account_menu_locator)
        return self.User(self, root)

    class Help(Menu):
        """The Help options."""

        _page_tips_locator = (
            By.CSS_SELECTOR, '.page-tips')
        _help_articles_locator = (
            By.CSS_SELECTOR, '.-help-link:first-child')
        _getting_started_locator = (
            By.CSS_SELECTOR, '.support-document-link')
        _best_practices_locator = (
            By.CSS_SELECTOR, '.best-practices-guide')
        _accessibility_statement_locator = (
            By.CSS_SELECTOR, '[href*=accessibility]')
        _chat_support_enabled_locator = (
            By.CSS_SELECTOR, '.chat.enabled')
        _chat_support_disabled_locator = (
            By.CSS_SELECTOR, '.chat.disabled span')

        def view_page_tips(self):
            """Trigger the current page's user tips."""
            self._select(locator=self._page_tips_locator)
            return self.page.page.page_tips()

        def view_help_articles(self):
            """Select the Help Articles menu option."""
            from pages.salesforce.home import Salesforce
            return self._select(locator=self._page_tips_locator,
                                destination=Salesforce,
                                external=True)

        @property
        def guide_url(self):
            """Return the Getting Started guide URL."""
            return (self.find_element(*self._getting_started_locator)
                    .get_attribute('href'))

        def view_getting_started_guide(self):
            """Download the Getting Started guide."""
            return self._select(locator=self._getting_started_locator,
                                external=True,
                                file=True)

        def verify_getting_started_guide(self, user_type='student'):
            """Test the guide URL."""
            url = self.guide_url
            filename = url.split('/')[-1]
            assert(user_type in filename), (
                'Wrong user guide (expected {user} to be in {filename})'
                .format(user=user_type, filename=filename))
            return Utility.test_url_and_warn(url=url,
                                             message='Getting Started guide',
                                             driver=self.driver)

        @property
        def best_practices_url(self):
            """Return the Best Practices guide URL."""
            return (self.find_element(*self._best_practices_locator)
                    .get_attribute('href'))

        def view_best_practices_guide(self):
            """Download the Best Practices guide."""
            return self._select(locator=self._best_practices_locator,
                                external=True,
                                file=True)

        def verify_best_practices_guide(self):
            """Test the guide URL."""
            return Utility.test_url_and_warn(url=self.best_practices_url,
                                             message='Best Practices guide',
                                             driver=self.driver)

        def view_accessibility_statement(self):
            """View the Accessibility Statement."""
            from pages.tutor.accessibility import Accessibility
            return self._select(locator=self._accessibility_statement_locator,
                                destination=Accessibility)

        @property
        def chat_available(self):
            """Return True if the customer support chat is available."""
            chat_enabled = self.find_element(
                *self._chat_support_enabled_locator)
            return self.driver.execute_script(
                'return arguments[0].style.display != "none";', chat_enabled)

        @property
        def chat_unavailable(self):
            """Return the chat offline message."""
            if not self.chat_available:
                return (self.find_element(*self._chat_support_disabled_locator)
                        .text)
            raise TutorException('Chat is currently available')

        def chat_with_support(self):
            """Begin a customer support chat session."""
            if self.chat_available:
                from pages.tutor.chat import Chat
                self._select(locator=self._chat_support_enabled_locator,
                             destination=Chat,
                             external=True)
            raise TutorException('Chat is not currently available')

    class Payment(Region):
        """Student trial and payment messaging."""

        _pay_now_locator = (By.CSS_SELECTOR, '.btn-primary')

        @property
        def status(self):
            """Return the trial status message."""
            return self.root.text

        @property
        def days_remaining(self):
            """Return the number of days remaining in the student trial."""
            status = self.status
            days = re.findall(r"\d+", status)
            assert(days), 'No number found ({0})'.format(status)
            return int(days[0])

        def pay_now(self):
            """Click the 'Pay now' button."""
            button = self.find_element(*self._pay_now_locator)
            Utility.click_option(self.driver, element=button)
            from regions.tutor.purchase import Purchase
            return Purchase(self.page.page)

    class Action(Menu):
        """User action options."""

        _my_courses_locator = (
            By.CSS_SELECTOR, '[data-item=myCourses]')
        _dashboard_locator = (
            By.CSS_SELECTOR, '[data-item=dashboard]')
        _browse_the_book_locator = (
            By.CSS_SELECTOR, '[name=browseBook]')
        _scores_locator = (
            By.CSS_SELECTOR, '[data-item=viewScores]')
        _performance_forecast_locator = (
            By.CSS_SELECTOR, '[data-item=viewPerformanceGuide]')
        _change_student_id_locator = (
            By.CSS_SELECTOR, 'data-item=changeStudentId]')
        _question_library_locator = (
            By.CSS_SELECTOR, '[data-item=viewQuestionsLibrary]')
        _course_settings_locator = (
            By.CSS_SELECTOR, '[data-item=courseSettings]')
        _course_roster_locator = (
            By.CSS_SELECTOR, '[data-item=courseRoster]')
        _create_a_course_locator = (
            By.CSS_SELECTOR, '[data-item=createNewCourse]')
        _copy_this_course_locator = (
            By.CSS_SELECTOR, '[data-item=cloneCourse]')
        _manage_payments_locator = (
            By.CSS_SELECTOR, '[data-item=managePayments]')
        _customer_service_locator = (
            By.CSS_SELECTOR, '[data-item=customer_service]')
        _admin_console_locator = (
            By.CSS_SELECTOR, '[data-item=admin]')
        _qa_dashboard_locator = (
            By.CSS_SELECTOR, '[data-item=QADashboard]')
        _content_analyst_locator = (
            By.CSS_SELECTOR, '[data-item=qaHome]')

        def view_my_courses(self):
            """Go to My Courses.

            See TutorNav.go_to_dashboard()
            Most users will be taken to the course picker.
            Students with one course will be taken to their course page.
            """
            self._select(locator=self._my_courses_locator)
            sleep(0.5)
            if 'dashboard' in self.driver.current_url:
                from pages.tutor.dashboard import Dashboard
                return go_to_(Dashboard(self.driver, self.page.page.base_url))
            from pages.tutor.course import Course
            return go_to_(Course(self.driver, self.page.page.base_url))

        def view_dashboard(self):
            """Go to the Dashboard.

            Instructors will be taken to the calendar.
            Students will be taken to their course page.
            """
            self._select(locator=self._dashboard_locator)
            sleep(0.5)
            if 'month' in self.driver.current_url:
                from pages.tutor.course import Calendar as Course
            else:
                from pages.tutor.course import Course
            return go_to_(Course(self.driver, self.page.page.base_url))

        def browse_the_book(self):
            """Open the book's reference view."""
            from pages.tutor.reference import Reference
            return self._select(locator=self._browse_the_book_locator,
                                destination=Reference,
                                external=True)

        def view_student_scores(self):
            """View the scores table."""
            from pages.tutor.scores import Scores
            return self._select(locator=self._scores_locator,
                                destination=Scores)

        def view_the_performance_forecast(self):
            """View the performance forecast."""
            from pages.tutor.performance import PerformanceForecast
            return self._select(locator=self._performance_forecast_locator,
                                destination=PerformanceForecast)

        def change_student_id(self):
            """Go to the ID change page."""
            from pages.tutor.student_id import ChangeID
            return self._select(locator=self._change_student_id_locator,
                                destination=ChangeID)

        def view_the_question_library(self):
            """Go to the ."""
            from pages.tutor.question_library import QuestionLibrary
            return self._select(locator=self._question_library_locator,
                                destination=QuestionLibrary)

        def view_the_course_settings(self):
            """Go to the course settings."""
            from pages.tutor.settings import CourseSettings
            return self._select(locator=self._course_settings_locator,
                                destination=CourseSettings)

        def view_the_course_roster(self):
            """Go to the course roster."""
            from pages.tutor.roster import CourseRoster
            return self._select(locator=self._course_roster_locator,
                                destination=CourseRoster)

        def create_a_course(self):
            """Go to course creation."""
            from pages.tutor.course_creation import CreateCourse
            return self._select(locator=self._create_a_course_locator,
                                destination=CreateCourse)

        def copy_this_course(self):
            """Clone the current course."""
            from pages.tutor.course_creation import CloneCourse
            return self._select(locator=self.self._create_a_course_locator,
                                destination=CloneCourse)

        def manage_payments(self):
            """Manage payments."""
            from pages.tutor.payments import PaymentManagement
            return self._select(locator=self._manage_payments_locator,
                                destination=PaymentManagement)

        def view_the_customer_service_board(self):
            """Open the customer service console."""
            from pages.tutor.admin import CustomerService
            return self._select(locator=self._customer_service_locator,
                                destination=CustomerService)

        def view_the_admin_console(self):
            """Go to the administrator's console."""
            from pages.tutor.admin import AdminConsole
            return self._select(locator=self._admin_console_locator,
                                destination=AdminConsole)

        def view_the_qa_dashboard(self):
            """Go to the QA dashboard."""
            from pages.tutor.qa import QAConsole
            return self._select(locator=self._qa_dashboard_locator,
                                destination=QAConsole)

        def view_the_content_analyst_board(self):
            """Go to the content analyst console."""
            from pages.tutor.content import ContentAnalystConsole
            return self._select(locator=self._content_analyst_locator,
                                destination=ContentAnalystConsole)

    class User(Menu):
        """User account information."""

        _initials_locator = (By.CSS_SELECTOR, '.initials')
        _my_account_locator = (By.CSS_SELECTOR, '[href$=profile]')
        _log_out_locator = (By.CSS_SELECTOR, '.logout')

        @property
        def initials(self):
            """Return the user's initials displayed in the user menu dot.

            Initials are case sensitive matching Accounts.
            """
            return self.find_element(*self._initials_locator).text.strip()

        def view_my_account(self):
            """View the user's profile on Accounts."""
            from pages.accounts.profile import Profile
            return self._select(locator=self._my_account_locator,
                                destination=Profile,
                                external=True)

        def log_out(self):
            """Log the current user out of Tutor."""
            from pages.tutor.home import TutorHome
            return self._select(locator=self._log_out_locator,
                                destination=TutorHome)


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

# functions parameters
N = 8  # Number of particles
timesteps = 1000 # Number of functions time steps
dt = 1e-1  # Timestep
alpha = 0.5  # cubic coupling
beta = 0.1  # quartic coupling

# for dt, timesteps in zip([1, 5*1e-1, 1e-1, 5*1e-2, 1e-2, 5*1e-3, 1e-3, 5*1e-4, 1e-4, 5*1e-5, 1e-5], 5*np.array([1e1, 1e2/2, 1e2, 1e3/2, 1e3, 1e4/2, 1e4, 1e5/2, 1e5, 1e6/2, 1e6]).astype(int)):
qs, ps = functions.integration(N, timesteps, dt, alpha, beta)
energy = functions.energy(ps, qs, alpha, beta)
mean_energy = np.mean(energy)
max_energy = np.max(energy)
print(dt, timesteps, np.round((energy[0]-mean_energy)/mean_energy*100, 5),"%")

#------------------------------------------
# Energy(t) plot
fig, ax = plt.subplots(1, 1, figsize=(9, 7))

# ax.plot(range(timesteps),(energy - mean_energy)/mean_energy)
ax.plot(range(timesteps + 1), np.concatenate((np.array([0]), energy)))

# ax.set_xlim(0, N-1)
# ax.set_ylim(-1.1, 1.1)
ax.set_xlabel('t')
ax.set_ylabel(r'E-$\overline{E}$')
ax.grid(True, alpha=0.25, linestyle="--")
plt.tight_layout()

plt.show()


import web
import random
import serialsend

urls = (
        '/', 'index',
        )
render = web.template.render('templates/', base='layout')

'''
used to display a simple form using HTML5
x-webkit-speech. post data is then sent
to serialsend.py which acts as a middleman between
python and the micro-controller.
'''
class index():
    def GET(self):
        title = 'Index Here!'
        return render.index(title)

    def POST(self):
        p = web.input()
        serialsend.input(p.talk)

if __name__ == "__main__":
   app = web.application(urls, globals())
   app.internalerror = web.debugerror
   app.run()


import operator

from typing import Union, Tuple, Callable, TypeVar
from numbers import Number
from decimal import Decimal, ROUND_DOWN
from functools import total_ordering

from tensortrade.core.exceptions import (
    InvalidNegativeQuantity,
    IncompatibleInstrumentOperation,
    InvalidNonNumericQuantity,
    QuantityOpPathMismatch
)

T = TypeVar("T")

@total_ordering
class Quantity:
    """A size of a financial instrument for use in trading.

    Parameters
    ----------
    instrument : `Instrument`
        The unit of the quantity.
    size : `Decimal`
        The number of units of the instrument.
    path_id : str, optional
        The path order_id that this quantity is allocated for and associated
        with.

    Raises
    ------
    InvalidNegativeQuantity
        Raised if the `size` of the quantity being created is negative.
    """

    def __init__(self, instrument: 'Instrument', size: Decimal, path_id: str = None):
        if size < 0:
            if abs(size) > Decimal(10)**(-instrument.precision):
                raise InvalidNegativeQuantity(float(size))
            else:
                size = 0

        self.instrument = instrument
        self.size = size if isinstance(size, Decimal) else Decimal(size)
        self.path_id = path_id

    @property
    def is_locked(self) -> bool:
        """If quantity is locked for an order. (bool, read-only)"""
        return bool(self.path_id)

    def lock_for(self, path_id: str) -> "Quantity":
        """Locks a quantity for an `Order` identified associated with `path_id`.

        Parameters
        ----------
        path_id : str
            The identification of the order path.

        Returns
        -------
        `Quantity`
            A locked quantity for an order path.
        """
        return Quantity(self.instrument, self.size, path_id)

    def convert(self, exchange_pair: "ExchangePair") -> "Quantity":
        """Converts the quantity into the value of another instrument based
        on its exchange rate from an exchange.

        Parameters
        ----------
        exchange_pair : `ExchangePair`
            The exchange pair to use for getting the quoted price to perform
            the conversion.

        Returns
        -------
        `Quantity`
            The value of the current quantity in terms of the quote instrument.
        """
        if self.instrument == exchange_pair.pair.base:
            instrument = exchange_pair.pair.quote
            converted_size = self.size / exchange_pair.price
        else:
            instrument = exchange_pair.pair.base
            converted_size = self.size * exchange_pair.price
        return Quantity(instrument, converted_size, self.path_id)

    def free(self) -> "Quantity":
        """Gets the free version of this quantity.

        Returns
        -------
        `Quantity`
            The free version of the quantity.
        """
        return Quantity(self.instrument, self.size)

    def quantize(self) -> "Quantity":
        """Computes the quantization of current quantity in terms of the instrument's
        precision.

        Returns
        -------
        `Quantity`
            The quantized quantity.
        """
        return Quantity(self.instrument,
                        self.size.quantize(Decimal(10)**-self.instrument.precision),
                        self.path_id)

    def as_float(self) -> float:
        """Gets the size as a `float`.

        Returns
        -------
        float
            The size as a floating point number.
        """
        return float(self.size)

    def contain(self, exchange_pair: "ExchangePair"):
        """Contains the size of the quantity to be compatible with the settings
        of a given exchange.

        Parameters
        ----------
        exchange_pair : `ExchangePair`
            The exchange pair containing the exchange the quantity must be
            compatible with.

        Returns
        -------
        `Quantity`
            A quantity compatible with the given exchange.
        """
        options = exchange_pair.exchange.options
        price = exchange_pair.price

        if exchange_pair.pair.base == self.instrument:
            size = self.size
            return Quantity(self.instrument, min(size, options.max_trade_size), self.path_id)

        size = self.size * price
        if size < options.max_trade_size:
            return Quantity(self.instrument, self.size, self.path_id)

        max_trade_size = Decimal(options.max_trade_size)
        contained_size = max_trade_size / price
        contained_size = contained_size.quantize(Decimal(10)**-self.instrument.precision, rounding=ROUND_DOWN)
        return Quantity(self.instrument, contained_size, self.path_id)

    @staticmethod
    def validate(left: "Union[Quantity, Number]",
                 right: "Union[Quantity, Number]") -> "Tuple[Quantity, Quantity]":
        """Validates the given left and right arguments of a numeric or boolean
        operation.

        Parameters
        ----------
        left : `Union[Quantity, Number]`
            The left argument of an operation.
        right : `Union[Quantity, Number]`
            The right argument of an operation.

        Returns
        -------
        `Tuple[Quantity, Quantity]`
            The validated quantity arguments to use in a numeric or boolean
            operation.

        Raises
        ------
        IncompatibleInstrumentOperation
            Raised if the instruments left and right quantities are not equal.
        QuantityOpPathMismatch
            Raised if
                - One argument is locked and the other argument is not.
                - Both arguments are locked quantities with unequal path_ids.
        InvalidNonNumericQuantity
            Raised if either argument is a non-numeric object.
        Exception
            If the operation is not valid.
        """
        if isinstance(left, Quantity) and isinstance(right, Quantity):
            if left.instrument != right.instrument:
                raise IncompatibleInstrumentOperation(left, right)

            if (left.path_id and right.path_id) and (left.path_id != right.path_id):
                raise QuantityOpPathMismatch(left.path_id, right.path_id)

            elif left.path_id and not right.path_id:
                right.path_id = left.path_id

            elif not left.path_id and right.path_id:
                left.path_id = right.path_id

            return left, right

        elif isinstance(left, Number) and isinstance(right, Quantity):
            left = Quantity(right.instrument, left, right.path_id)
            return left, right

        elif isinstance(left, Quantity) and isinstance(right, Number):
            right = Quantity(left.instrument, right, left.path_id)
            return left, right

        elif isinstance(left, Quantity):
            raise InvalidNonNumericQuantity(right)

        elif isinstance(right, Quantity):
            raise InvalidNonNumericQuantity(left)

        raise Exception(f"Invalid quantity operation arguments: {left} and {right}")

    @staticmethod
    def _bool_op(left: "Union[Quantity, Number]",
                 right: "Union[Quantity,Number]",
                 op: "Callable[[T, T], bool]") -> bool:
        """Performs a generic boolean operation on two quantities.

        Parameters
        ----------
        left : `Union[Quantity, Number]`
            The left argument of the operation.
        right : `Union[Quantity, Number]`
            The right argument of the operation.
        op : `Callable[[T, T], bool]`
            The boolean operation to be used.

        Returns
        -------
        bool
            The result of performing `op` on with `left` and `right`.
        """
        left, right = Quantity.validate(left, right)
        boolean = op(left.size, right.size)
        return boolean

    @staticmethod
    def _math_op(left: "Union[Quantity, Number]",
                 right: "Union[Quantity, Number]",
                 op: "Callable[[T, T], T]") -> "Quantity":
        """Performs a generic numeric operation on two quantities.

        Parameters
        ----------
        left : `Union[Quantity, Number]`
            The left argument of the operation.
        right : `Union[Quantity, Number]`
            The right argument of the operation.
        op : `Callable[[T, T], bool]`
            The numeric operation to be used.

        Returns
        -------
        `Quantity`
            The result of performing `op` on with `left` and `right`.
        """
        left, right = Quantity.validate(left, right)
        size = op(left.size, right.size)
        return Quantity(left.instrument, size, left.path_id)

    def __add__(self, other: "Quantity") -> "Quantity":
        return Quantity._math_op(self, other, operator.add)

    def __sub__(self, other: "Union[Quantity, Number]") -> "Quantity":
        return Quantity._math_op(self, other, operator.sub)

    def __iadd__(self, other: "Union[Quantity, Number]") -> "Quantity":
        return Quantity._math_op(self, other, operator.iadd)

    def __isub__(self, other: "Union[Quantity, Number]") -> "Quantity":
        return Quantity._math_op(self, other, operator.isub)

    def __mul__(self, other: "Union[Quantity, Number]") -> "Quantity":
        return Quantity._math_op(self, other, operator.mul)

    def __rmul__(self, other: "Union[Quantity, Number]") -> "Quantity":
        return Quantity.__mul__(self, other)

    def __lt__(self, other: "Union[Quantity, Number]") -> bool:
        return Quantity._bool_op(self, other, operator.lt)

    def __eq__(self, other: "Union[Quantity, Number]") -> bool:
        return Quantity._bool_op(self, other, operator.eq)

    def __ne__(self, other: "Union[Quantity, Number]") -> bool:
        return Quantity._bool_op(self, other, operator.ne)

    def __neg__(self) -> bool:
        return operator.neg(self.size)

    def __str__(self) -> str:
        s = "{0:." + str(self.instrument.precision) + "f}" + " {1}"
        s = s.format(self.size, self.instrument.symbol)
        return s

    def __repr__(self) -> str:
        return str(self)