# Import modules
import tkinter
import tkinter.font as tkFont
from tkinter import *

# Class to create a button that changes color when hovered over
# Inherits from tkinter Button class
class HoverButton1(tkinter.Button):
    def __init__(self, **kw):
        tkinter.Button.__init__(self, **kw)
        self['bd'] = 1
        self['background'] = '#88b5fc'
        self.defaultBackground = self['background']
        self.bind('<Enter>', self.on_enter)
        self.bind('<Leave>', self.on_leave)

    def on_enter(self, e):
        self['background'] = '#4287f5'

    def on_leave(self, e):
        self['background'] = self.defaultBackground

# Hover button inheriting from HoverButton1 class
# (has a different color)
class HoverButton2(HoverButton1):
    def __init__(self, **kw):
        HoverButton1.__init__(self, **kw)
        self['background'] = '#e3abff'
        self.defaultBackground = self['background']

    def on_enter(self, e):
        self['background'] = '#d278ff'

# Hover button inheriting from HoverButton1 class
# (has a different color)
class HoverButton3(HoverButton1):
    def __init__(self, **kw):
        HoverButton1.__init__(self, **kw)
        self['background'] = '#63ff9a'
        self.defaultBackground = self['background']

    def on_enter(self, e):
        self['background'] = '#00bf43'

# GUI class
class standardCalculator:
    def __init__(self):
        # Create main window
        self.main_window = tkinter.Tk()

        # Window design/attributes
        self.main_window['background'] = '#0d0063'
        self.main_window.attributes('-alpha', 0.95)
        self.main_window.title('JCalc')
        self.main_window.minsize(250, 300)

        # Window size
        w = 350
        h = 600

        # Settings to place window in middle of screen when ran
        ws = self.main_window.winfo_screenwidth()
        hs = self.main_window.winfo_screenheight()
        x = (ws/2) - (w/2)
        y = (hs/2) - (h/2)
        self.main_window.geometry('%dx%d+%d+%d' % (w, h, x, y))

        # Font settings to be used with window widgets
        window_font1 = tkFont.Font(family = 'Bahnschrift', size = 20)
        window_font2 = tkFont.Font(family = 'Bahnschrift Light', size = 16)

        # StringVars to update expression and result labels
        self.expressionVar = tkinter.StringVar()
        self.resultVar = tkinter.StringVar()

        # Create widgets
        # Labels for expression and result
        self.expression_label = tkinter.Label(bg = '#0d0063', fg = '#f4f2ff', textvariable = self.expressionVar, font = ('Bahnschrift', 16), anchor = 'e')
        self.result_label = tkinter.Label(bg = '#0d0063', fg = '#f4f2ff', textvariable = self.resultVar, font = ('Bahnschrift', 46), anchor = 'e')

        # Digit buttons
        self.zero_btn = HoverButton1(text = '0', command = lambda: self.update_input(self.zero_btn), font = window_font1)
        self.one_btn = HoverButton1(text = '1', command = lambda: self.update_input(self.one_btn), font = window_font1)
        self.two_btn = HoverButton1(text = '2', command = lambda: self.update_input(self.two_btn), font = window_font1)
        self.three_btn = HoverButton1(text = '3', command = lambda: self.update_input(self.three_btn), font = window_font1)
        self.four_btn = HoverButton1(text = '4', command = lambda: self.update_input(self.four_btn), font = window_font1)
        self.five_btn = HoverButton1(text = '5', command = lambda: self.update_input(self.five_btn), font = window_font1)
        self.six_btn = HoverButton1(text = '6', command = lambda: self.update_input(self.six_btn), font = window_font1)
        self.seven_btn = HoverButton1(text = '7', command = lambda: self.update_input(self.seven_btn), font = window_font1)
        self.eight_btn = HoverButton1(text = '8', command = lambda: self.update_input(self.eight_btn), font = window_font1)
        self.nine_btn = HoverButton1(text = '9', command = lambda: self.update_input(self.nine_btn), font = window_font1)

        # Operation buttons
        self.add_btn = HoverButton2(text = '+', command = lambda: self.update_input(self.add_btn), font = window_font2)
        self.sub_btn = HoverButton2(text = '-', command = lambda: self.update_input(self.sub_btn), font = window_font2)
        self.mult_btn = HoverButton2(text = '*', command = lambda: self.update_input(self.mult_btn), font = window_font2)
        self.div_btn = HoverButton2(text = '/', command = lambda: self.update_input(self.div_btn), font = window_font2)
        self.eq_btn = HoverButton3(text = '=', command = self.equals, font = window_font2)
        self.dec_btn = HoverButton1(text = '.', command = lambda: self.update_input(self.dec_btn), font = window_font2)

        # Delete/Clear buttons
        self.del_btn = HoverButton3(text = 'DEL', command = self.delete_entry, font = window_font2)
        self.clear_btn = HoverButton3(text = 'C', command = self.clear, font = window_font2)

        # Configure column weights
        self.main_window.columnconfigure(0, weight = 3)
        self.main_window.columnconfigure(1, weight = 3)
        self.main_window.columnconfigure(2, weight = 3)
        self.main_window.columnconfigure(3, weight = 3)

        # Configure row weights
        self.main_window.rowconfigure(0, weight = 1)
        self.main_window.rowconfigure(1, weight = 3)
        self.main_window.rowconfigure(2, weight = 3)
        self.main_window.rowconfigure(3, weight = 3)
        self.main_window.rowconfigure(4, weight = 3)
        self.main_window.rowconfigure(5, weight = 3)
        self.main_window.rowconfigure(6, weight = 3)

        # Grid widgets
        self.expression_label.grid(row = 0, column = 0, rowspan = 1, columnspan = 4, sticky = 'NSEW')
        self.result_label.grid(row = 1, column = 0, rowspan = 1, columnspan = 4, sticky = 'NSEW')

        self.zero_btn.grid(row = 6, column = 0, sticky = 'NSEW', padx = 1, pady = 1)
        self.one_btn.grid(row = 5, column = 0, sticky = 'NSEW', padx = 1, pady = 1)
        self.two_btn.grid(row = 5, column = 1, sticky = 'NSEW', padx = 1, pady = 1)
        self.three_btn.grid(row = 5, column = 2, sticky = 'NSEW', padx = 1, pady = 1)
        self.four_btn.grid(row = 4, column = 0, sticky = 'NSEW', padx = 1, pady = 1)
        self.five_btn.grid(row = 4, column = 1, sticky = 'NSEW', padx = 1, pady = 1)
        self.six_btn.grid(row = 4, column = 2, sticky = 'NSEW', padx = 1, pady = 1)
        self.seven_btn.grid(row = 3, column = 0, sticky = 'NSEW', padx = 1, pady = 1)
        self.eight_btn.grid(row = 3, column = 1, sticky = 'NSEW', padx = 1, pady = 1)
        self.nine_btn.grid(row = 3, column = 2, sticky = 'NSEW', padx = 1, pady = 1)

        self.add_btn.grid(row = 6, column = 3, sticky = 'NSEW', padx = 1, pady = 1)
        self.sub_btn.grid(row = 5, column = 3, sticky = 'NSEW', padx = 1, pady = 1)
        self.mult_btn.grid(row = 4, column = 3, sticky = 'NSEW', padx = 1, pady = 1)
        self.div_btn.grid(row = 3, column = 3, sticky = 'NSEW', padx = 1, pady = 1)
        self.eq_btn.grid(row = 6, column = 2, sticky = 'NSEW', padx = 1, pady = 1)
        self.dec_btn.grid(row = 6, column = 1, sticky = 'NSEW', padx = 1, pady = 1)

        self.del_btn.grid(row = 2, column = 3, sticky = 'NSEW', padx = 1, pady = 1)
        self.clear_btn.grid(row = 2, column = 2, sticky = 'NSEW', padx = 1, pady = 1)

        tkinter.mainloop()

    # Function to update labels with button entries
    def update_input(self, btn):
        self.expressionVar.set(self.expressionVar.get() + btn['text'])
        self.get_result()

    # Function to attempt to get the result of the current expression and update
    # the results label
    def get_result(self):
        try:
            result = eval(self.expressionVar.get())
            # Formatting large numbers to scientific notation
            if (len(str(result)) > 10):
                result = "{:.5e}".format(result)
            self.resultVar.set(result)
        except:
            self.resultVar.set('')

    # Callback function for the 'clear' button
    def clear(self):
        self.resultVar.set('')
        self.expressionVar.set('')

    # Callback function for the 'delete' button
    def delete_entry(self):
        self.expressionVar.set(self.expressionVar.get()[:-1])
        self.get_result()

    # Callback function for the equal button
    def equals(self):
        try:
            result = eval(self.expressionVar.get())
            # Formatting large numbers to scientific notation
            if (len(str(result)) > 10):
                result = "{:.5e}".format(result)
            self.expressionVar.set(result)
            self.resultVar.set('')
        except:
            self.resultVar.set('Invalid input')

calc1 = standardCalculator()


cijfers = {
    'Peter':    2,
    'Sjaak':    4,
    'Diederik': 10,
    'Jan':      9,
    'Pieter':   8,
    'Andre':    6,
    'Ruud':     7,
    'Nigel':    10
}

for a, b in cijfers.items():
	if b > 8:
		print('{}, {}'.format(a, b))


# Problem: Creating a Frequency Counter

# Write a Python function called calculate_frequency that takes a list of words as input and returns a dictionary
# where the keys are the unique words from the list, and the values are the frequencies of those words in the list.

# {
#     "apple": 3,
#     "banana": 2,
#     "orange": 1,
#     "grape": 1
# }

listOfWords = ["orange","apple","orange","mango","mango","apple","banana","orange"]

def calculate_frequency(list):
    finalDict = {}
    for word in list:
        if word in finalDict:
            finalDict[word] += 1
        else:
            finalDict[word] = 1

    return finalDict

print(calculate_frequency(listOfWords))


from matplotlib import colors
import matplotlib.pyplot as plt

fp = open('out', 'r')
lines = list(map(lambda x: [float(y)
                            for y in x.split(':')[1:]], fp.readlines()))
lines = list(map(lambda x: [x[0], x[1]*100], lines))
for line in lines:
    print(line)

# For found

ns = [lines[x][0] for x in range(0, len(lines), 2)]
times = [lines[x][1] for x in range(0, len(lines), 2)]

ns2 = [2*lines[x][0] for x in range(0, len(lines), 2)]
times2 = [2*lines[x][1] for x in range(0, len(lines), 2)]
print(ns)
print(times)
plt.plot(ns, times)
plt.plot(ns2, times2)
plt.xlabel("number of items")
plt.ylabel("Time*100")
plt.legend(["One", "Two"])

plt.show()

# For not found

ns = [lines[x][0] for x in range(1, len(lines), 2)]
times = [lines[x][1] for x in range(1, len(lines), 2)]

print(ns)
print(times)
plt.plot(ns, times)
plt.xlabel("number of items")
plt.ylabel("Time*100")

plt.show()


from tkinter import *

root= Tk()

root.title("PARITY CHECKER")

label1=Label(root, text=" Enter the data:- ")
inp=Entry(root,width=50)
label1.grid(column=0,row=0,pady=20)

inp.grid(column=1, row=0)

def evenBit():
    s=inp.get()
    data=""
    if(s.count('1')%2==0):
        data=s+'0'
    else:
        data=s+'1'

    output= Label(root, text= "Data after adding parity bit --> "+data,pady=20)
    output.grid(row=3,column=0)

def oddBit():
    s=inp.get()
    data=""
    if(s.count('1')%2==0):
        data=s+'1'
    else:
        data=s+'0'

    output= Label(root, text= "Data after adding parity bit --> "+data,pady=20)
    output.grid(row=3,column=1)

btn1= Button(root, text=" Click to add even bit parity  ", command=evenBit)

btn2= Button(root, text=" Click to add odd bit parity  ", command=oddBit)

btn1.grid(row=2,column=0)
btn2.grid(row=2,column=1)

root.mainloop()


from mesa import Agent
import random

class GameAgent(Agent):
    """ An agent that is more likely to choose the mean option. """

    def __init__(self, unique_id, model, home_cell=None):
        super().__init__(unique_id, model)
        self.score = 1
        self.home_cell = home_cell
        self.spouse = None
        self.partner = None
        self.choice = None
        self.age = 0
        self.children = []
        self.dead_spouse = False
        self.health = 10

    def __str__(self):
        return f"Agent {self.unique_id}, with score {self.score}. \n Home cell: {str(self.home_cell)}, Spouse: {self.spouse.unique_id if self.spouse else None}. \n Age: {self.age}, Children: {str([[child.age, child.home_cell == self.home_cell] for child in self.children])}. \n Had spouse: {str(self.dead_spouse)}"

    def step(self):
        if self.health < 1 or self.age > 85:
            adult_at_home = [child for child in self.children if
                             ((child.age >= 18) and (child.home_cell == self.home_cell))]
            children_at_home = [child for child in self.children if child.age < 18]
            parents_at_home = [parent for parent in self.parents if parent.home_cell == self.home_cell]
            for child in self.children:
                child.parents.remove(self)
            for parent in self.parents:
                parent.children.remove(self)
            if self.spouse:
                self.spouse.dead_spouse = True
                self.spouse.spouse = None
            else:
                if len(adult_at_home) == 0:

                    if len(children_at_home) > 0:
                        for child in children_at_home:
                            self.model.schedule.remove(child)
                            self.model.grid.remove_agent(child)
                        self.children = []
                    if len(parents_at_home) == 0:
                        if self.home_cell not in self.model.unoccupied_houses:
                            self.model.unoccupied_houses.append(self.home_cell)
                        if self.home_cell in self.model.occupied_houses:
                            self.model.occupied_houses.remove(self.home_cell)
                else:
                    for child in children_at_home:
                        new_parent = random.choice(adult_at_home)
                        new_parent.children.append(child)
                        child.parents.append(new_parent)

            self.model.schedule.remove(self)
            self.model.grid.remove_agent(self)

        else:
            if self.age < 18:
                if self.model.time != "night":
                    pass
                else:
                    self.age += 1
            elif self.spouse is None and len([child for child in self.children if child.spouse is None]) == 0:
                if self.model.time == "morning":
                    self.move(mingle=True)
                elif self.model.time == "midday":
                    if self.partner:
                        self.move_in()
                elif self.model.time == "afternoon":
                    self.move(destination=self.home_cell)
                elif self.model.time == "evening":
                    if self.spouse:
                        self.reproduce()
                else:
                    self.sleep()
            else:
                if self.model.time == "morning":
                    self.move()
                elif self.model.time == "midday":
                    if self.partner:
                        self.choose_action()
                elif self.model.time == "afternoon":
                    self.move(destination=self.home_cell)
                elif self.model.time == "evening":
                    if self.spouse:
                        self.reproduce()
                else:
                    self.sleep()

    def move(self, destination=None, mingle=False):
        if destination is None:
            # Find other player to play with and move to their cell
            # If no other player, move randomly
            if mingle:
                other_players = self.model.out_minglers
            else:
                other_players = self.model.out_agents
            if len(other_players) > 0:
                other_player = random.choice(other_players)
                self.partner = other_player
                other_player.partner = self
                self.move(other_player.pos)
                other_players.remove(other_player)
            else:
                # Move to random cell
                random_cell = (
                    random.randint(1, self.model.grid.width - 2), random.randint(1, self.model.grid.height - 2))
                while not self.model.grid.is_cell_empty(random_cell):
                    random_cell = (
                        random.randint(1, self.model.grid.width - 2), random.randint(1, self.model.grid.height - 2))
                self.move(destination=random_cell)
                other_players.append(self)
        else:
            # Move to destination cell
            self.model.grid.move_agent(self, destination)
            self.pos = destination

    def reproduce(self):
        type_dict = {"mean": MeanAgent, "altruistic": AltruisticAgent, "greenbeard": GreanBeardAltruistic,
                     "imposter": ImposterGreenBeards, "spiteful_family": SpitefulFamily, "spiteful": Spiteful, "tft": TitForTat,
                     "tft_family": TitForTatFamily}
        # print("Trying for babys")
        if self.score > 10 and self.spouse.score > 10:
            # Create new agent
            if 18 < self.age < 55 and 18 < self.spouse.age < 55:
                # print("BABY!")
                num_children = random.randint(1, 2)
                for i in range(num_children):
                    child_type = random.choice([self.type, self.spouse.type])
                    self.model.num_agents += 1
                    child = type_dict[child_type](self.model.num_agents, self.model)
                    child.home_cell = self.home_cell
                    self.model.schedule.add(child)
                    self.model.grid.place_agent(child, child.home_cell)
                    self.children.append(child)
                    self.spouse.children.append(child)
                    child.parents = [self, self.spouse]
                self.score -= 10
                self.spouse.score -= 10

    def sleep(self):
        food_to_eat = self.model.harshness * (1 + sum(
            0.5 for child in self.children if child.home_cell == self.home_cell and child.age >= 18) + sum(
            0.3 for child in self.children if child.home_cell == self.home_cell and child.age < 18))
        if self.score < food_to_eat:
            self.health -= 20
            for child in self.children:
                if child.home_cell == self.home_cell:
                    child.health -= 20
        else:
            self.score -= food_to_eat
            self.health += 10
            for child in self.children:
                if child.home_cell == self.home_cell:
                    child.health += 10
        self.age += 1

    def move_in(self):
        if self.age - 5 <= self.partner.age <= self.age + 5:
            if len(self.model.unoccupied_houses) > 0:
                # Move to random unoccupied house
                self.home_cell = random.choice(self.model.unoccupied_houses)
                self.partner.home_cell = self.home_cell
                self.spouse = self.partner
                self.partner.spouse = self
                self.model.unoccupied_houses.remove(self.home_cell)
                self.model.occupied_houses.append(self.home_cell)

    def fight(self):
        # Prisoner's dilemma
        if self.choice == "cooperate":
            if self.partner.choice == "cooperate":
                self.score += 3
                self.partner.score += 3
            else:
                self.score += 0
                self.partner.score += 5
        else:
            if self.partner.choice == "cooperate":
                self.score += 5
                self.partner.score += 0
            else:
                self.score += 1
                self.partner.score += 1
        self.choice = None
        self.partner.choice = None

class MeanAgent(GameAgent):
    """ An agent that is more likely to choose the mean option. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "mean"

    def choose_action(self):
        # Choose action
        self.choice == "defect"
        if self.partner.choice:
            self.fight()

class AltruisticAgent(GameAgent):
    """ An agent that is more likely to be altruistic. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "altruistic"

    def choose_action(self):
        # Choose action
        self.choice = "cooperate"
        if self.partner.choice:
            self.fight()

class GreanBeardAltruistic(GameAgent):
    """ An agent that is more likely to be altruistic to other greenbeards."""

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "greenbeard"

    def choose_action(self):
        # Choose action

        if self.partner.type == "greenbeard" or self.partner.type == "imposter":
            self.choice = "cooperate"
        else:
            self.choice = "defect"

        if self.partner.choice:
            self.fight()

class ImposterGreenBeards(GameAgent):
    """ An agent who pretends to be a green beard to take advantage of the other greenbeard's altruism."""

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "imposter"

    def choose_action(self):
        # Choose action
        if self.partner.type == "greenbeard" or self.partner.type == "imposter":
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

class SpitefulFamily(GameAgent):
    """ An agent who pretends is altruistic, unless they have been betrayed before. At which point they (and their
    family) will defect. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "spiteful_family"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def tell_related(self, agent):
        # Tells the other agent that they have been wronged
        list_of_family = self.children + [self.partner] + self.parents + [[i for i in child.children] for child in
                                                                          self.children]
        for member in list_of_family:
            if member.type == "spiteful_family":
                member.wronged_list.append(agent)

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)
                self.tell_related(self.partner)

class Spiteful(GameAgent):
    """ An agent who pretends is altruistic, unless they have been betrayed before. At which point they will defect. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "spiteful"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)

class TitForTat(GameAgent):
    """ Classical Tit for Tat strategy. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "tft"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)
        else:
            if self.partner in self.wronged_list:
                self.wronged_list.remove(self.partner)

class TitForTatFamily(GameAgent):
    """ Classical Tit for Tat strategy. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "tft_family"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)
                self.tell_related(self.partner)
        else:
            if self.partner in self.wronged_list:
                self.wronged_list.remove(self.partner, remove=True)

    def tell_related(self, agent, remove=False):
        # Tells the other agent that they have been wronged
        list_of_family = self.children + [self.partner] + self.parents + [[i for i in child.children] for child in
                                                                          self.children]
        for member in list_of_family:
            if member.type == "tft_family":
                if remove:
                    member.wronged_list.remove(agent)
                else:
                    member.wronged_list.append(agent)


import numpy as np
# import networkx as nx
from collections import *
from itertools import *
from functools import *
import math
import re

from common.session import AdventSession

session = AdventSession(day=18, year=2020)
data = session.data.strip()
data = data.split('\n')

p1, p2 = 0, 0

def findmatch(expr, i):
    match = 0
    while i < len(expr):
        if expr[i] == '(':
            match += 1
        elif expr[i] == ')':
            match -= 1
            if match == 0:
                return i
        i += 1

def evaluate(expr):
    i = 0
    while i < len(expr) and len(expr) > 1:
        if i - 1 >= 0 and expr[i - 1].isdigit() and expr[i + 1].isdigit() and \
                not expr[i].isdigit():
            expr[i - 1:i + 2] = [str(eval(''.join(expr[i - 1:i + 2])))]
            i = 0
        elif expr[i] == '(':
            end = findmatch(expr, i)
            expr[i:end + 1] = [evaluate(expr[i + 1:end])]
            i = 0
        i += 1
    return expr[0]

def evaluate2(expr):
    for op in ('+', '*'):
        i = 0
        while i < len(expr) and len(expr) > 1:
            if i - 1 >= 0 and expr[i - 1].isdigit() and expr[i] == op and \
                    expr[i + 1].isdigit():
                expr[i - 1:i + 2] = [str(eval(''.join(expr[i - 1:i + 2])))]
                i = 0
            elif expr[i] == '(':
                end = findmatch(expr, i)
                expr[i:end + 1] = [evaluate2(expr[i + 1:end])]
                i = 0
            i += 1
    return expr[0]

for line in data:
    p1 += int(evaluate([c for c in line if c != ' ']))
    p2 += int(evaluate2([c for c in line if c != ' ']))

print(f'Part 1: {p1}')
print(f'Part 2: {p2}')

# session.submit(p1, part=1)
# session.submit(p2, part=2)

# session.submit(p1, part=2)


# -*- coding: utf-8 -*-
import os
import time

from boto3.dynamodb.conditions import Key

import settings

from db_util import DBUtil
from lambda_base import LambdaBase
from jsonschema import validate
from not_authorized_error import NotAuthorizedError
from user_util import UserUtil

class MeCommentsDelete(LambdaBase):
    def get_schema(self):
        return {
            'type': 'object',
            'properties': {
                'comment_id': settings.parameters['comment']['comment_id']
            },
            'required': ['comment_id']
        }

    def validate_params(self):
        UserUtil.verified_phone_and_email(self.event)
        validate(self.params, self.get_schema())
        comment = DBUtil.get_validated_comment(self.dynamodb, self.params['comment_id'])
        DBUtil.validate_article_existence(self.dynamodb, comment['article_id'], status='public')

    def exec_main_proc(self):
        comment_table = self.dynamodb.Table(os.environ['COMMENT_TABLE_NAME'])
        comment = comment_table.get_item(
            Key={"comment_id": self.params['comment_id']}
        )['Item']

        if not self.__is_accessable_comment(comment):
            raise NotAuthorizedError('Forbidden')

        deleted_comment_table = self.dynamodb.Table(os.environ['DELETED_COMMENT_TABLE_NAME'])
        delete_targets = self.__get_delete_targets(comment)

        with deleted_comment_table.batch_writer() as batch:
            for item in delete_targets:
                item.update({'deleted_at': int(time.time())})
                batch.put_item(Item=item)

        with comment_table.batch_writer() as batch:
            for item in delete_targets:
                batch.delete_item(Key={'comment_id': item['comment_id']})

        return {'statusCode': 200}

    def __is_accessable_comment(self, comment):
        user_id = self.event['requestContext']['authorizer']['claims']['cognito:username']

        article_info_table_name = self.dynamodb.Table(os.environ['ARTICLE_INFO_TABLE_NAME'])
        article_info = article_info_table_name.get_item(Key={"article_id": comment['article_id']})['Item']

        if article_info['user_id'] == user_id or comment['user_id'] == user_id:
            return True

        return False

    def __get_delete_targets(self, comment):
        comment_table = self.dynamodb.Table(os.environ['COMMENT_TABLE_NAME'])

        targets = [comment]

        query_params = {
            'IndexName': 'parent_id-sort_key-index',
            'KeyConditionExpression': Key('parent_id').eq(comment['comment_id'])
        }

        thread_comments = comment_table.query(**query_params)['Items']

        targets.extend(thread_comments)

        return targets


import imp
from tkinter import *

root = Tk()
root.geometry('200x300')

courselist = ['html', 'css', 'java script', 'php']
var = Variable(value=courselist)

lb = Listbox(root ,height=10, width=20, selectmode="multiple", font="Arial 20",listvariable=var, bg='mistyrose')
lb.pack()

root.mainloop()


# pylint: disable=unused-variable
# pylint: disable=unused-argument
# pylint: disable=redefined-outer-name

import json
from copy import deepcopy

import httpx
import pytest
import respx
from fastapi import FastAPI
from respx import MockRouter
from simcore_service_api_server._meta import API_VTAG
from simcore_service_api_server.core.settings import ApplicationSettings
from simcore_service_api_server.models.schemas.profiles import Profile
from starlette import status

@pytest.fixture
def mocked_webserver_service_api(app: FastAPI):
    """Mocks some responses of web-server service"""

    settings: ApplicationSettings = app.state.settings
    assert settings.API_SERVER_WEBSERVER

    # pylint: disable=not-context-manager
    with respx.mock(
        base_url=settings.API_SERVER_WEBSERVER.api_base_url,
        assert_all_called=False,
        assert_all_mocked=True,
    ) as respx_mock:
        # NOTE: webserver-api uses the same schema as api-server!
        # in-memory fake data
        me = deepcopy(Profile.Config.schema_extra["example"])

        def _get_me(request):
            return httpx.Response(status.HTTP_200_OK, json={"data": me})

        def _update_me(request: httpx.Request):
            changes = json.loads(request.content.decode(request.headers.encoding))
            me.update(changes)
            return httpx.Response(status.HTTP_200_OK, json={"data": me})

        respx_mock.get("/me", name="get_me").mock(side_effect=_get_me)
        respx_mock.put("/me", name="update_me").mock(side_effect=_update_me)

        yield respx_mock

        del me

async def test_get_profile(
    client: httpx.AsyncClient,
    auth: httpx.BasicAuth,
    mocked_webserver_service_api: MockRouter,
):
    # needs no auth
    resp = await client.get(f"/{API_VTAG}/meta")
    assert resp.status_code == status.HTTP_200_OK

    # needs auth
    resp = await client.get(f"/{API_VTAG}/me")
    assert resp.status_code == status.HTTP_401_UNAUTHORIZED
    assert not mocked_webserver_service_api["get_me"].called

    resp = await client.get(f"/{API_VTAG}/me", auth=auth)
    assert resp.status_code == status.HTTP_200_OK
    assert mocked_webserver_service_api["get_me"].called

    profile = Profile(**resp.json())
    assert profile.first_name == "James"
    assert profile.last_name == "Maxwell"

async def test_update_profile(
    client: httpx.AsyncClient,
    auth: httpx.BasicAuth,
    mocked_webserver_service_api: MockRouter,
):
    # needs auth
    resp = await client.put(
        f"/{API_VTAG}/me",
        json={"first_name": "Oliver", "last_name": "Heaviside"},
        auth=auth,
    )
    assert resp.status_code == status.HTTP_200_OK, resp.text

    profile = Profile.parse_obj(resp.json())
    assert profile.first_name == "Oliver"
    assert profile.last_name == "Heaviside"


from flask import Flask,request
from flask_restful import Resource, Api
from tensorflow import keras
import numpy as np
from flask_cors import CORS

COLUMNS = ['temp', 'wind', 'rain', 'FFMC', 'DMC', 'DC', 'ISI', 'RH', 'BUI', 'FWI']

app = Flask(__name__)
#
CORS(app)
# creating an API object
api = Api(app)

# Load model
model = keras.models.load_model('model.h5', compile=False)

#prediction api call
class predict(Resource):
    def get(self):
        # Get data
        data = np.array([[float(request.args.get(field)) for field in COLUMNS]])

        # Predict
        prediction = model.predict(data)
        prediction = float(prediction[0])

        return prediction

#
api.add_resource(predict, '/predict/')

if __name__ == '__main__':
    app.run()


"""Parse the discussion wiki and archive the data in the database."""

import re
import pathlib
from operator import ior
from functools import reduce
from string import punctuation
from database import DatabaseDiscussion
from parser_wiki import Parser, Discussion

DISCUSSION_ENTRY_PATH = "src\\queries\\discussion\\add_discussion_entry.sql"
EPISODE_ENTRY_PATH = "src\\queries\\add_episodes.sql"

FILE_PATH = "data\\wiki\\anime\\discussion_archive_edited"

PERMALINK_AND_TEXT = re.compile(
    r"(?:\|([^\|]*)\|\[[^\]]*\]\(https?:\/\/redd\.it\/(\w+)(?:\)|$)"
    r"|\[([^\]]*)\]\([^\s]*comments\/(\w+)[^\)]*(?:\)|$)"
    r"|\[([^\]]*)\]\(\/(\w+)(?:\)|$))"
)
HEADERS = re.compile(r"\|?([^\|]+)\|?")
CONTENTS_LINKS = re.compile(
    r"\[[^\]]+\]\([^|]*(?:comments|redd\.it)?\/(\w+)[^\)]*(?:\)|$)"
)
LONG_RUNNING_PARSE = re.compile(r"\[([^\]]+)\]\([^\)]*\/(\w+)\/?\)")

# Compare with parser_wiki.TableParser to see which one to keep/improve.
class TableDiscussionParser:
    """Parse discussion wiki tables."""

    @staticmethod
    def parse_table_one_header(table: list[str]) -> dict:
        """Parse a table that has a single header row.

        Contents can be in the form:
        - name | [text](link) (| repeat)
        - [name](link) (| repeat)"""
        return reduce(
            ior,
            list(
                {
                    entry[1]: entry[0]
                    for entry in PERMALINK_AND_TEXT.findall(row)
                    if entry[1]
                }
                for row in table[1:]
            ),
        )

    @staticmethod
    def parse_table_alternate_headers(table: list[str]) -> dict:
        """Parse a table that alternate headers and contents.

        Contents have the form:
        - name (| repeat)
          [text](link) (| repeat)"""
        ans = {}
        for pair in zip(table[::2], table[1::2]):
            header_row, link_row = pair
            for title, contents in zip(header_row.split("|"), link_row.split("|")):
                links = CONTENTS_LINKS.findall(contents)
                if links and links[0]:
                    ans[links[0]] = title
        return ans

    @staticmethod
    def parse_table_no_headers(table: list[str]) -> dict:
        """Parse a table that has no header.

        Contents have the form:
        - [text](link) (| repeat)"""
        return reduce(
            ior,
            list(
                {
                    entry[1]: entry[0]
                    for entry in LONG_RUNNING_PARSE.findall(row)
                    if entry[1]
                }
                for row in table
            ),
        )

class ParserDiscussion(Parser):
    """Parser for episode discussion wiki pages."""

    def parse_file(self) -> None:
        """Parse the contents."""
        if self.year in {2011, 2012, 2013, 2014, 2015, 2016}:
            self.parse_file_1(delimiter="* ")
        elif self.year in {2017, 2018, 2019, 2021, 2022}:
            self.parse_file_1(delimiter="**")
        elif self.year in {2020}:
            self.parse_file_1(delimiter="###")
        elif self.name == "long_running_anime":
            self.parse_file_1(delimiter="###")

    def parse_file_1(self, delimiter: str) -> None:
        """Parse the contents.

        Use the formatting for discussion archives years from 2011 to 2014."""
        while not self.out_of_bounds:
            if self.current_line.startswith(delimiter):
                self.parse_entry(delimiter=delimiter)
            else:
                self.next_line()

    def parse_entry(self, delimiter: str) -> None:
        """Parse a discussion entry."""
        series_name = self.remove_formatting(self.current_line[2:])
        # print(self.year, series_name)
        discussion = Discussion(name=series_name, year=self.year)
        self.next_line()
        while (not self.out_of_bounds) and (
            not self.current_line.startswith(delimiter)
        ):
            if self.current_line.count("|") >= 1:
                if self.current_line.lstrip(punctuation + " ").startswith("Case"):
                    while self.current_line.count("|") >= 1:
                        for pair in PERMALINK_AND_TEXT.findall(self.current_line):
                            title, post_id = (x for x in pair if x)
                            discussion.episodes[post_id] = title.strip()
                        self.next_line()
                else:
                    if self.name == "long_running_anime":
                        table_parser = TableDiscussionParser.parse_table_no_headers
                    elif self.current_line.lstrip(punctuation + " ").startswith("Ep."):
                        table_parser = (
                            TableDiscussionParser.parse_table_alternate_headers
                        )
                    else:
                        table_parser = TableDiscussionParser.parse_table_one_header
                    table = self.read_table()
                    discussion.episodes |= table_parser(table)
            else:
                for pair in PERMALINK_AND_TEXT.findall(self.current_line):
                    title, post_id = (x for x in pair if x)
                    discussion.episodes[post_id] = title.strip()
                self.next_line()
        if discussion.episodes:
            self.create_entry(discussion=discussion)

    def create_entry(self, discussion: Discussion) -> None:
        """Create a db entry."""
        self._db.begin()
        try:
            with open(DISCUSSION_ENTRY_PATH, encoding="utf8") as f:
                self._db.q.execute(f.read(), discussion.info)
            series_id = self._db.last_row_id
            with open(EPISODE_ENTRY_PATH, encoding="utf8") as f:
                query = f.read()
            for post_id, episode in discussion.episodes.items():
                # print(self.year, series_id, discussion.name, post_id, episode)
                self._db.q.execute(
                    query, (series_id, post_id or None, self.remove_formatting(episode))
                )
            self._db.commit()
        except Exception as e:
            print(f"Exception: {e}")
            print(
                f"{self.year} - {series_id} - {discussion.name} - {post_id} - {episode}"
            )
            self._db.rollback()

    @property
    def year(self) -> int:
        """Return the year included in the file name."""
        file_name = pathlib.Path(self._file_path).stem
        try:
            return int(file_name)
        except ValueError:
            return None

    @property
    def name(self) -> str:
        """Return the file name."""
        return pathlib.Path(self._file_path).stem

    @staticmethod
    def parse_table() -> None:
        pass

if __name__ == "__main__":
    # Episode discussions year 2011-2022
    for y in range(2011, 2023):
        print(f"Processing year {y}")
        parser = ParserDiscussion(
            f"{FILE_PATH}\\{y}.md", DatabaseDiscussion(path="data\\discussion.sqlite")
        )
        parser.parse_file()
    # Episode discussions long running anime
    parser = ParserDiscussion(
        f"{FILE_PATH}\\long_running_anime.md",
        DatabaseDiscussion(path="data\\discussion.sqlite"),
    )
    parser.parse_file()


import setuptools                               # Must be before Cython import

import Emma

with open("README.md", "r") as fp:
    long_description = fp.read()

try:
    from Cython.Compiler import Options
    from Cython.Build import cythonize
    Options.docstrings = True
    Options.fast_fail = True

    extensions = cythonize(
        [
            setuptools.Extension("Emma.emma_libs.memoryMap", sources=["Emma/emma_libs/memoryMap.py"]),
            setuptools.Extension("Emma.emma_libs.memoryEntry", sources=["Emma/emma_libs/memoryEntry.py"])
        ]
    )
except ImportError:
    extensions = None

setuptools.setup(
    name="pypiemma",
    version=Emma.EMMA_VERSION,
    license="GPLv3+",
    description="Emma Memory and Mapfile Analyser (Emma) | Conduct static (i.e. worst case) memory consumption \
    analyses based on arbitrary linker map files. It produces extensive .csv files which are easy to filter and \
    post-process. Optionally .html and markdown reports as well as neat figures help you visualising your results.",
    long_description=long_description,
    long_description_content_type="text/markdown",
    maintainer="The Emma Authors",
    maintainer_email="emma-dev@googlegroups.com",
    url="https://github.com/bmwcarit/Emma",
    zip_safe=False,                                             # Needed for Cython
    packages=setuptools.find_namespace_packages(),              # Recursively find package files (i.e. sub-folders, ...)
    python_requires=Emma.PYTHON_REQ_VERSION,
    install_requires=["Pygments",
                      "Markdown",
                      "matplotlib",
                      "pandas",
                      "pypiscout>=2.0",
                      "graphviz",
                      "svgwrite"
                      ],
    extras_require={"dev":                                      # Install dev version via `pip3 install pypiemma[dev]`
                        ["gprof2dot",
                         "pylint",
                         "mkdocs>=1.1.2",                       # There was a break in the config files: https://squidfunk.github.io/mkdocs-material/releases/5/
                         "mkdocs-material>=5.2.1"               # There was a break in the config files: https://squidfunk.github.io/mkdocs-material/releases/5/
                         ],
                    },
    entry_points={                                              # Make Emma available as independent scripts
        "console_scripts": [
            "emma=Emma.emma:runEmma",
            "emma_vis=Emma.emma_vis:runEmmaVis",
            "emma_deltas=Emma.emma_vis:runEmmaDeltas"
        ],
    },
    ext_modules=extensions,                                     # Needed for Cython
    keywords=[
        "memory-analysis",
        "mapfile",
        "memory-analyzer",
        "embedded",
        "ghs",
        "gcc",
        "mcu",
        "linker",
        "visualization",
        "reports",
        "csv",
        "python",
        "categorisation",
        "memory-consumption",
        "mapfile-analyser"
        ],
    classifiers=[
        "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
        "Programming Language :: Python :: 3",
        "Operating System :: OS Independent",
        "Development Status :: 5 - Production/Stable",
        "Environment :: Console",
        "Topic :: Scientific/Engineering :: Visualization",
        "Topic :: Software Development",
        "Topic :: Software Development :: Embedded Systems",
        "Topic :: Software Development :: Quality Assurance",
    ],
)


import os
from django.core.files.storage import FileSystemStorage

try:
    FileNotFoundError
except:
    FileNotFoundError = IOError

class BaseStorage(FileSystemStorage):
    def _open(self, name, mode='rb'):
        try:
            return super(BaseStorage, self)._open(name, mode)
        except FileNotFoundError:
            if 'w' in mode: # if writing, make sure the parent structure exists
                self._ensure_directory(name)

            try:
                try:
                    f = self._get(name)
                except IOError:
                    # if the underlying file doesn't exist, no matter.
                    pass
                else:
                    # if it does, write the contents locally
                    self._write(f, name)

            except Exception:
                pass
        return super(BaseStorage, self)._open(name, mode)

    def _exists_locally(self, name):
        return super(BaseStorage, self).exists(name)

    def exists(self, name):
        if self._exists_locally(name):
            return True
        return self._exists_upstream(name)

    def _ensure_directory(self, name):
        dirname = os.path.dirname(self.path(name))
        if not os.path.exists(dirname):
            os.makedirs(dirname)

    def _write(self, filelike, name):
        self._ensure_directory(name)
        f = open(self.path(name), mode='wb')
        f.write(filelike.read())

    def _fetch_local(self, name, force=False):
        if self._exists_locally(name) and not force:
            return

        return self._write(self._get(name), name)


""" Outlnies the methods to be used for the signUp app. """
from django.shortcuts import render, redirect
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.contrib.sites.shortcuts import get_current_site
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
from django.contrib.auth.models import Group
from accounts.models import CustomUser
from signUp import forms
from signUp.tokens import account_activation_token

def activate(request, uidb64, token):
    """ Activates a new user account with their id being their primary key.

    Args:
        request: The HTTP request submitted by the user.
        uidb64: A unique ID for the user's email.
        token: A object to help identify the user.

    Returns:
        redirect: 'login': Redirects the user to the login page once their,
            account has been validated.
    """
    # User = CustomUser.objects.get

    try:
        user = CustomUser.objects.get(pk=id)
        user.is_user = True
        user.save()

    except:
        user = None

    # If the user exists and has a valid token, save the account
    if user is not None and account_activation_token.check_token(user, token):
        user.is_user = True
        user.save()

    return redirect('login')

def activate_email(request, user, to_email) -> None:
    """ Formulates the message that gets sent in the activation email and
    sends the email to the user.

    Args:
        request: The HTTP request submitted by the user.

        user: user: The user object representing the user who is having their
            email validated.

        to_email: (str): The user's email, given as a string for ease of
            processing.
    """
    mail_subject = "Activate your user account"

    # Converts the message to be sent to the user into a string
    message = render_to_string(
        "signUp/template_activate_user.html",
        {"user": user.username,
         "domain": get_current_site(request).domain,
         "uid": urlsafe_base64_encode(force_bytes(user.pk)),
         "token": account_activation_token.make_token(user),
         "protocol": 'https' if request.is_secure() else "http"
         }
    )
    email = EmailMessage(mail_subject, message, to=[to_email])
    email.send()

def signup(request):
    """ Displays the sign up page (GET request) and takes the data from the
    sign up form, validates it and creates a new user, displaying any error
    messages if necessary.

    Args:
        request: The HTTP request submitted by the user.

    Returns:
        render: Signup page is shown to the user if they enter the wrong
            details.

        redirect: (leaderboard): The user is redirected to the leaderboard
            page if they have submitted a valid form.
    """
    if request.method == "POST":

        form = forms.SignUpForm(request.POST)

        # If the data entered into the form is valid save the details and
        # create a new user, otherwise throw the relevant error message
        if form.is_valid():
            user = form.save(commit=False)
            user.is_user = False
            user.save()
            user_group = Group.objects.get(name='user')
            user_group.user_set.add(user)
            activate_email(request, user, form.cleaned_data.get('email'))
            return redirect('leaderboard')

    else:
        # GET request case
        form = forms.SignUpForm()

    return render(request, 'registration/signup.html', {'form': form})


import time
import pandas as pd

CITY_DATA = {'chicago': 'chicago.csv',
             'new york city': 'new_york_city.csv',
             'washington': 'washington.csv'}

def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply
                      no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no
                   day filter
    """
    print('Hello! Let\'s explore some US bikeshare data!')
    # TO DO: get user input for city (chicago, new york city, washington).
    # HINT: Use a while loop to handle invalid inputs
    city = ''
    month = ''
    day = ''
    filter_opt = ''
    while True:
        try:
            input_city = input(
                "\nWould you like to see data for Chicago, New york city or "
                "Washington?\n").lower()
            if input_city in ['chicago', 'new york city', 'washington']:
                city = input_city
                break
        except KeyboardInterrupt:
            print('\nNo input taken\n')
        finally:
            print('\nAttempted Input\n')
    # TO DO: get user input for month (all, january, february, ... , june)
    while True:
        try:
            input_filter = input(
                '\nWould you like to filter the data by month ,day,'
                'both or not at all？Type \'none\' for no time filter.\n').lower()
            if input_filter == 'none':
                day = 'all'
                month = 'all'
                filter_opt = 'none'
                break
            elif input_filter == 'both':
                filter_opt = 'both'
                while True:
                    try:
                        input_month = input(
                            '\nWhich month? January, February, March, April, '
                            'May or June?\n').lower()
                        if input_month in ['january', 'february', 'march',
                                           'april', 'may', 'june']:
                            month = input_month
                            while True:
                                try:
                                    input_day = input(
                                        '\nWhich day? Monday, Tuesday, Wednesday,'
                                        ' Thursday, Friday, Saturday or Sunday?\n').lower()
                                    if input_day in ['monday', 'tuesday',
                                                     'wednesday', 'thursday',
                                                     'friday', 'saturday',
                                                     'sunday']:
                                        day = input_day
                                        break
                                except KeyboardInterrupt:
                                    print('\nNo input taken\n')
                                finally:
                                    print('\nAttempted Input\n')
                            break
                    except KeyboardInterrupt:
                        print('\nNo input taken\n')
                    finally:
                        print('\nAttempted Input\n')
                break
            elif input_filter == 'month':
                filter_opt = 'month'
                while True:
                    try:
                        input_month = input(
                            '\nWhich month? January, February, March, April, '
                            'May or June?\n').lower()
                        if input_month in ['january', 'february', 'march',
                                           'april', 'may', 'june']:
                            month = input_month
                            day = 'all'
                            break
                    except KeyboardInterrupt:
                        print('\nNo input taken\n')
                    finally:
                        print('\nAttempted Input\n')
                break
            elif input_filter == 'day':
                filter_opt = 'day'
# TO DO: get user input for day of week (all, monday, tuesday, ... sunday)
                while True:
                    try:
                        input_day = input(
                            '\nWhich day? Monday, Tuesday, Wednesday, Thursday,'
                            'Friday, Saturday or Sunday?\n').lower()
                        if input_day in ['monday', 'tuesday', 'wednesday',
                                         'thursday', 'friday', 'saturday',
                                         'sunday']:
                            day = input_day
                            month = 'all'
                            break
                    except KeyboardInterrupt:
                        print('\nNo input taken\n')
                    finally:
                        print('\nAttempted Input\n')
                break
        except KeyboardInterrupt:
            print('\nNo input taken\n')
        finally:
            print('\nAttempted Input\n')

    print('-' * 40)
    return city, month, day, filter_opt

def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day
    if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply
                     no month filter
        (str) day - name of the day of week to filter by, or "all" to apply
                    no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """

    # load data file into a dataframe
    df = pd.DataFrame(pd.read_csv(CITY_DATA[city]))
    # convert the Start Time column to datetime
    df['Start Time'] = pd.to_datetime(df['Start Time'])
    # extract month and day of week from Start Time to create new columns
    df['Month'] = df['Start Time'].dt.month
    df['Day_of_week'] = df['Start Time'].dt.weekday_name
    # filter by month if applicable
    if month != 'all':
        # use the index of the months list to get the corresponding int
        months = ['january', 'february', 'march', 'april', 'may', 'june']
        month = months.index(month) + 1
        # filter by month to create the new dataframe
        df = df[df['Month'] == month]
    # filter by day of week if applicable
    if day != 'all':
        # filter by day of week to create the new dataframe
        df = df[df['Day_of_week'] == day.title()]
    return df

def time_stats(df, filter_opt):
    """Displays statistics on the most frequent times of travel."""

    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()

    # TO DO: display the most common month
    df_month = df[['Month', 'Start Time']].groupby('Month')[
        'Start Time'].size().reset_index(name='Count')\
        .sort_values(['Count'], ascending=False)
    common_month_list = df_month[df_month['Count'] == df_month['Count'].max()][['Month', 'Count']].values.tolist()
    if common_month_list:
        for item in common_month_list:
            print('\nMost common month : {}, Count : {}, Filter: {}.'
                  .format(item[0], item[1], filter_opt))
    else:
        print('\nNo Most common month data to share.')
    # TO DO: display the most common day of week
    df_day = df[['Day_of_week', 'Start Time']].groupby('Day_of_week')[
        'Start Time'].size().reset_index(name='Count')\
        .sort_values(['Count'], ascending=False)
    common_day_list = df_day[df_day['Count'] == df_day['Count'].max()][['Day_of_week', 'Count']].values.tolist()
    if common_day_list:
        for item in common_day_list:
            print('\nMost common day : {}, Count : {}, Filter: {}.'
                  .format(item[0], item[1], filter_opt))
    else:
        print('\nNo Most common day data to share.')

    # TO DO: display the most common start hour
    df['Start Hour'] = df['Start Time'].dt.hour
    df_hour = df[['Start Hour', 'Start Time']].groupby('Start Hour')[
        'Start Time'].size().reset_index(name='Count')\
        .sort_values(['Count'], ascending=False)
    common_hour_list = df_hour[df_hour['Count'] == df_hour['Count'].max()][['Start Hour', 'Count']].values.tolist()
    if common_hour_list:
        for item in common_hour_list:
            print('\nMost common hour : {}, Count : {}, Filter: {}.'
                  .format(item[0], item[1], filter_opt))
    else:
        print('\nNo Most common hour data to share.')

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-' * 40)

def station_stats(df, filter_opt):
    """Displays statistics on the most popular stations and trip."""

    print('\nCalculating The Most Popular Stations and Trip...\n')
    start_time = time.time()

    # TO DO: display most commonly used start station
    df_start = df[['Start Station', 'Start Time']].groupby('Start Station')[
        'Start Time'].size().reset_index(name='Count')\
        .sort_values(['Count'], ascending=False)
    common_start_list = df_start[df_start['Count'] == df_start['Count'].max()][['Start Station', 'Count']].values.tolist()
    if common_start_list:
        for item in common_start_list:
            print('\nMost commonly used start station '
                  ': {}, Count : {}, Filter: {}.'
                  .format(item[0], item[1], filter_opt))
    else:
        print('\nNO Most commonly used start station data to share.')

    # TO DO: display most commonly used end station
    df_end = df[['End Station', 'Start Time']].groupby('End Station')[
        'Start Time'].size().reset_index(name='Count')\
        .sort_values(['Count'], ascending=False)
    common_end_list = df_end[df_end['Count'] == df_end['Count'].max()][['End Station', 'Count']].values.tolist()
    if common_end_list:
        for item in common_end_list:
            print('\nMost commonly used end station '
                  ': {}, Count : {}, Filter: {}.'
                  .format(item[0], item[1], filter_opt))
    else:
        print('\nNO Most commonly used end station data to share.')

    # TO DO: display most frequent combination of start station
    # and end station trip
    df_start_end = df[['Start Station', 'End Station', 'Start Time']].groupby(
        ['Start Station', 'End Station'])['Start Time'].size().sort_values(
        ascending=False).reset_index(name='Count')
    start_end_list = df_start_end[df_start_end['Count'] ==
                                  df_start_end['Count'].max()][['Start Station', 'End Station', 'Count']].values.tolist()
    if start_end_list:
        for item in start_end_list:
            print('\nMost frequent combination of start station and end station :')
            print('\nStart Station :{}, End Station :{}, Count : {}, '
                  'Filter: {}.'
                  .format(item[0], item[1], item[2], filter_opt))
    else:
        print('\nNO Most frequent start and end station data to share.')

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-' * 40)

def trip_duration_stats(df, filter_opt):
    """Displays statistics on the total and average trip duration."""

    print('\nCalculating Trip Duration...\n')
    start_time = time.time()

    # TO DO: display total travel time
    df = df.fillna(0)
    total_duration = df['Trip Duration'].sum()
    count = df.shape[0]
    print('\nTotal duration : {} ,Count : {} , Filter : {} .'
          .format(total_duration, count, filter_opt))
    # TO DO: display mean travel time
    average_duration = df['Trip Duration'].mean()
    print('\nAvg duration : {} ,Count : {} , Filter : {} .'
          .format(average_duration, count, filter_opt))
    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-' * 40)

def user_stats(df, filter_opt):
    """Displays statistics on bikeshare users."""

    print('\nCalculating User Stats...\n')
    start_time = time.time()

    # TO DO: Display counts of user types

    df_user_counts = df[['User Type', 'Start Time']].groupby('User Type')['Start Time'].size().reset_index(name='Count').sort_values(['Count'], ascending=False)
    user_counts_list = df_user_counts.values.tolist()
    if user_counts_list:
        for item in user_counts_list:
            print('\nUser Type :{}, Count :{}, Filter : {} .'
                  .format(item[0], item[1], filter_opt))
    else:
        print('\nNO user type counts data to share.')

    # TO DO: Display counts of gender
    if 'Gender' in df:
        df_gender_counts= df[['Gender', 'Start Time']].groupby('Gender')[
            'Start Time'].size().reset_index(name='Count').sort_values(['Count'], ascending=False)
        gender_counts_list = df_gender_counts.values.tolist()
        if gender_counts_list:
            for item in gender_counts_list:
                print('\nGender Type :{}, Count :{}, Filter : {} .'
                      .format(item[0], item[1], filter_opt))
        else:
            print('\nNO user gender counts data to share.')
    else:
        print('\nNO user gender counts data to share.')

    # TO DO: Display earliest, most recent, and most common year of birth
    if 'Birth Year' in df:
        if False in df['Birth Year'].isnull().values.tolist():
            earliest_year = df['Birth Year'].min()
            recent_year = df['Birth Year'].max()
            common_year = df['Birth Year'].mode().iloc[0]
            print('\nEarliest birth year : {} , Most recent birth year : {} , '
                  'Most common birth year : {} .'
                  .format(earliest_year, recent_year, common_year))
        else:
            print('\nNo birth year data to share .')
    else:
        print('\nNo birth year data to share .')
    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-' * 40)

def main():
    while True:
        city, month, day, filter_opt = get_filters()
        df = load_data(city, month, day)

        time_stats(df, filter_opt)
        station_stats(df, filter_opt)
        trip_duration_stats(df, filter_opt)
        user_stats(df, filter_opt)

        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break

if __name__ == "__main__":
    main()


# Game 1 : Made by Me

# print("Welcome to my computer quiz!")

# playing = (input("Do you wanna play the game? "))

# if playing.capitalize() == ("Yes"):
#     NameOfTheGame = input("Enter the name of the game you wanna play: ")
#     print(f"Opening {NameOfTheGame} .....")
# else:
#     print("Come sometime else bitch ЁЯШЭ")

# Game 2 :

print("Welcome to my computer quiz!")

playing = (input("Do you wanna play the game? "))

if playing.lower() != "yes":
    quit()

print("OKay! Let's play :)")
score = 0
incorrect = 0

answer = input("What does CPU stand for?: ")

if answer == "central processing unit":
    print("Correct !")
    score += 1
else:
    print("Wrong bitch ЁЯдк")
    incorrect +=1

answer = input("What does GPU stand for?: ")

if answer == "graphics processing unit":
    print("Correct !")
    score += 1
else:
    print("Wrong bitch ЁЯдк")
    incorrect +=1

answer = input("What does RAM stand for?: ")

if answer == "random access memory":
    print("Correct !")
    score += 1
else:
    print("Wrong bitch ЁЯдк")
    incorrect +=1

answer = input("What does SSD stand for?: ")

if answer == "solid state drive":
    print("Correct !")
    score += 1
else:
    print("Wrong bitch ЁЯдк")
    incorrect +=1

print(f"Your score is {score} out of {score + incorrect}")


import re
import dateutil.parser

class DateRegex:
    def __init__(
        self,
        pattern,
    ):
        self.pattern = pattern

    def convert(
        self,
        date_string,
    ):
        match = re.search(
            pattern=self.pattern,
            string=date_string,
            flags=re.IGNORECASE,
        )

        if not match or not match.groups():
            return None

        try:
            year = match.group('year')
            month = match.group('month')
            day = match.group('day')
        except Exception:
            return None

        try:
            date_object = dateutil.parser.parse(
                timestr='{day} {month} {year}'.format(
                    day=day,
                    month=month,
                    year=year,
                ),
                dayfirst=True,
            )

            return date_object.replace(
                tzinfo=None,
            )
        except:
            return None

class DateGeneric:
    def __init__(
        self,
    ):
        pass

    def convert(
        self,
        date_string,
    ):
        try:
            date_object = dateutil.parser.parse(
                timestr=date_string,
                fuzzy=True,
            )

            return date_object.replace(
                tzinfo=None,
            )
        except:
            return None

class Dummy:
    def __init__(
        self,
    ):
        pass

    def convert(
        self,
        original_string,
    ):
        return original_string


from __future__ import annotations

import copy
from typing import Optional, Dict

from dlgo.gotypes import Player, Point
from dlgo import zobrist
from dlgo.scoring import compute_game_result
from dlgo.utils import MoveAge

__all__ = [
    'Board',
    'GameState',
    'Move',
]

neighbor_tables = {}
corner_tables = {}

def init_neighbor_table(dim: (int, int)):
    rows, cols = dim
    new_table = {}
    for r in range(1, rows + 1):
        for c in range(1, cols + 1):
            p = Point(row=r, col=c)
            full_neighbors = p.neighbors()
            true_neighbors = [
                n for n in full_neighbors
                if 1 <= n.row <= rows and 1 < n.col <= cols]
            new_table[p] = true_neighbors
    neighbor_tables[dim] = new_table

def init_corner_table(dim: (int, int)):
    rows, cols = dim
    new_table = {}
    for r in range(1, rows + 1):
        for c in range(1, cols + 1):
            p = Point(row=r, col=c)
            full_corners = [
                Point(row=p.row - 1, col=p.col - 1),
                Point(row=p.row - 1, col=p.col + 1),
                Point(row=p.row + 1, col=p.col - 1),
                Point(row=p.row + 1, col=p.col + 1),
            ]
            true_corner = [
                n for n in full_corners
                if 1 <= n.row <= rows and 1 <= n.col <= cols]
            new_table[p] = true_corner
    corner_tables[dim] = new_table

class IllegalMoveError(Exception):
    pass

class GoString:
    def __init__(self, color, stones, liberties):
        self.color = color
        self.stones = frozenset(stones)
        self.liberties = frozenset(liberties)

    def without_liberty(self, point):
        new_liberties = self.liberties - {point}
        return GoString(self.color, self.stones, new_liberties)

    def with_liberty(self, point: Point):
        new_liberties = self.liberties | {point}
        return GoString(self.color, self.stones, new_liberties)

    def merged_with(self, go_string: GoString) -> GoString:
        assert go_string.color == self.color
        combined_stones = self.stones | go_string.stones
        return GoString(self.color, combined_stones,
                        (self.liberties | go_string.liberties) - combined_stones)

    @property
    def num_liberties(self) -> int:
        return len(self.liberties)

    def __eq__(self, other) -> bool:
        return all([
            isinstance(other, GoString),
            self.color == other.color,
            self.stones == other.stones,
            self.liberties == other.liberties
        ])

    def __repr__(self) -> str:
        return f"GoString({self.color}, {self.stones}, {self.liberties})"

    def __deepcopy__(self, memodict={}):
        return GoString(self.color, self.stones, copy.deepcopy(self.liberties))

class Board:
    def __init__(self, num_rows: int, num_cols: int):
        self.num_rows = num_rows
        self.num_cols = num_cols
        self._grid: Dict[Point, Optional[GoString]] = {}
        self._hash = zobrist.EMPTY_BOARD

        global neighbor_tables
        dim = (num_rows, num_cols)
        if dim not in neighbor_tables:
            init_neighbor_table(dim)
        if dim not in corner_tables:
            init_corner_table(dim)

        self.neighbor_table = neighbor_tables[dim]
        self.corner_table = corner_tables[dim]
        self.move_ages = MoveAge(self)

    def neighbors(self, point: Point):
        return self.neighbor_table[point]

    def corners(self, point: Point):
        return self.corner_table[point]

    def place_stone(self, player: Player, point: Point):
        assert self.is_on_grid(point)
        if self._grid.get(point) is not None:
            print(f"Illegal play on {point}")
        assert self._grid.get(point) is None

        adjacent_same_color = []
        adjacent_opposite_color = []
        liberties = []
        self.move_ages.increment_all()
        self.move_ages.add(point)
        for neighbor in self.neighbor_table[point]:
            neighbor_string = self._grid.get(neighbor)
            if neighbor_string is None:
                liberties.append(neighbor)
            elif neighbor_string.color == player:
                if neighbor_string not in adjacent_same_color:
                    adjacent_same_color.append(neighbor_string)
            else:
                if neighbor_string not in adjacent_opposite_color:
                    adjacent_opposite_color.append(neighbor_string)

        new_string = GoString(player, [point], liberties)

        for same_color_string in adjacent_same_color:
            new_string = new_string.merged_with(same_color_string)
        for new_string_point in new_string.stones:
            self._grid[new_string_point] = new_string

        self._hash ^= zobrist.HASH_CODE[point, None]
        self._hash ^= zobrist.HASH_CODE[point, player]

        for other_color_string in adjacent_opposite_color:
            replacement = other_color_string.without_liberty(point)
            if replacement.num_liberties:
                self._replace_string(other_color_string.without_liberty(point))
            else:
                self._remove_string(other_color_string)

    def is_on_grid(self, point: Point) -> bool:
        return 1 <= point.row <= self.num_rows and 1 <= point.col <= self.num_cols

    def get(self, point: Point) -> Optional[Player]:
        string = self._grid.get(point)
        if string is None:
            return None
        return string.color

    def get_go_string(self, point: Point) -> Optional[GoString]:
        string = self._grid.get(point)
        if string is None:
            return None
        return string

    def zobrist_hash(self) -> int:
        return self._hash

    def _replace_string(self, new_string: GoString):
        for point in new_string.stones:
            self._grid[point] = new_string

    def _remove_string(self, string: GoString):
        for point in string.stones:
            self.move_ages.reset_age(point)
            for neighbor in self.neighbor_table[point]:
                neighbor_string = self._grid.get(neighbor)
                if neighbor_string is None:
                    continue
                if neighbor_string is not string:
                    self._replace_string(neighbor_string.with_liberty(point))
            self._grid[point] = None

            self._hash ^= zobrist.HASH_CODE[point, string.color]
            self._hash ^= zobrist.HASH_CODE[point, None]

    def is_self_capture(self, player: Player, point: Point) -> bool:
        friendly_strings = []
        for neighbor in self.neighbor_table[point]:
            neighbor_string = self._grid.get(neighbor)
            if neighbor_string is None:
                return False
            elif neighbor_string.color == player:
                friendly_strings.append(neighbor_string)
            else:
                if neighbor_string.num_liberties == 1:
                    return False
        if all(neighbor.num_liberties == 1 for neighbor in friendly_strings):
            return True

        return False

    def will_capture(self, player: Player, point: Point) -> bool:
        for neighbor in self.neighbor_table[point]:
            neighbor_string = self._grid.get(neighbor)
            if neighbor_string is None:
                continue
            elif neighbor_string.color == player:
                continue
            else:
                if neighbor_string.num_liberties == 1:
                    return True

        return False

    def __eq__(self, other):
        return isinstance(other, Board) and \
                self.num_rows == other.num_rows and \
                self.num_cols == other.num_cols and \
                self._hash() == other._hash()

    def __deepcopy__(self, memodict={}):
        copied = Board(self.num_rows, self.num_cols)
        copied._grid = copy.copy(self._grid)
        copied._hash = self._hash
        return copied

class Move:
    def __init__(self, point: Optional[Point] = None, is_pass: bool = False,
                 is_resign: bool = False):
        assert (point is not None) ^ is_pass ^ is_resign
        self.point = point
        self.is_play = (self.point is not None)
        self.is_pass = is_pass
        self.is_resign = is_resign

    @classmethod
    def play(cls, point) -> Move:
        return Move(point=point)

    @classmethod
    def pass_turn(cls) -> Move:
        return Move(is_pass=True)

    @classmethod
    def resign(cls) -> Move:
        return Move(is_resign=True)

    def __str__(self):
        if self.is_pass:
            return 'pass'
        if self.is_resign:
            return 'resign'
        return f"(r {self.point.row}, c {self.point.col}"

    def __hash__(self):
        return hash((
            self.is_play,
            self.is_pass,
            self.is_resign,
            self.point))

    def __eq__(self, other):
        return (
            self.is_play,
            self.is_pass,
            self.is_resign,
            self.point) == (
            other.is_play,
            other.is_pass,
            other.is_resign,
            other.point)

class GameState:
    def __init__(self, board: Board, next_player: Player, previous: Optional[GameState],
                 move: Optional[Move]):
        self.board = board
        self.next_player = next_player
        self.previous_state = previous
        if not self.previous_state:
            self.previous_states = frozenset()
        else:
            self.previous_states = frozenset(
                previous.previous_states | {(previous.next_player, previous.board.zobrist_hash())}
            )
        self.last_move = move

    def apply_move(self, move: Move) -> GameState:
        if move.is_play:
            next_board = copy.deepcopy(self.board)
            next_board.place_stone(self.next_player, move.point)
        else:
            next_board = self.board
        return GameState(next_board, self.next_player.other, self, move)

    @classmethod
    def new_game(cls, board_size) -> GameState:
        if isinstance(board_size, int):
            board_size = (board_size, board_size)
        board = Board(*board_size)
        return GameState(board, Player.black, None, None)

    def is_over(self) -> bool:
        if self.last_move is None:
            return False

        if self.last_move.is_resign:
            return True

        second_last_move = self.previous_state.last_move
        if second_last_move is None:
            return False

        return self.last_move.is_pass and second_last_move.is_pass

    def is_move_self_capture(self, player: Player, move: Move) -> bool:
        if not move.is_play:
            return False
        return self.board.is_self_capture(player, move.point)

    @property
    def situation(self) -> (Player, Board):
        return self.next_player, self.board

    def does_move_violate_ko(self, player: Player, move: Move) -> bool:
        if not move.is_play:
            return False

        if not self.board.will_capture(player, move.point):
            return False

        next_board = copy.deepcopy(self.board)
        next_board.place_stone(player, move.point)
        next_situation = (player.other, next_board.zobrist_hash())
        return next_situation in self.previous_states

    def is_valid_move(self, move: Move) -> bool:
        if self.is_over():
            return False

        if move.is_pass or move.is_resign:
            return True

        return self.board.get(move.point) is None and \
               not self.is_move_self_capture(self.next_player, move) and \
               not self.does_move_violate_ko(self.next_player, move)

    def legal_moves(self) -> [Move]:
        if self.is_over():
            return []

        moves = []
        for row in range(1, self.board.num_rows + 1):
            for col in range(1, self.board.num_cols + 1):
                move = Move.play(Point(row, col))
                if self.is_valid_move(move):
                    moves.append(move)
        # These two moves are always legal.
        moves.append(Move.pass_turn())
        moves.append(Move.resign())

        return moves

    def winner(self):
        if not self.is_over():
            return None

        if self.last_move.is_resign:
            return self.next_player
        game_result = compute_game_result(self)
        return game_result.winner


'''
An example run script using custom pre- and post-actions.
'''
from bueno.public import container
from bueno.public import experiment
from bueno.public import logger

def pre_action(**kwargs):
    '''
    Actions performed before running the experiment (setup).
    '''
    logger.emlog('# Entering pre_action')

def post_action(**kwargs):
    '''
    Actions performed after running the experiment (analysis).
    '''
    logger.emlog('# Entering post_action')

    cmd = kwargs.pop('command')     # Command string
    out = kwargs.pop('output')      # Output gathered from example-app
    stm = kwargs.pop('start_time')  # Timing values
    etm = kwargs.pop('end_time')
    tet = kwargs.pop('exectime')

    logger.log(f'Command: {cmd}')
    logger.log(f'Start time: {stm}')
    logger.log(f'End time: {etm}')
    logger.log(f'Total Execution Time (s): {tet}\n')

    # It is possible to process the many outputs of the example application.
    lines = [x.rstrip() for x in out]
    for i, line in enumerate(lines):
        # Scan application output for "Data" tag.
        if line.startswith('Data'):
            data = line.split(': ')[1]
            logger.log(f' >> Data {i} is {data}')
            continue

def main(argv):
    experiment.name('custom-actions')
    container.run(
        './example-application.sh',  # Application invocation.
        preaction=pre_action,        # Set pre-action callback function.
        postaction=post_action       # Set post-action callback function.
    )


# TESTOS DE CREACIO/REGISTRE
from classes.models import Class
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase

class ClassRegistrationAPIViewTestCase(APITestCase):
    def test_one_bad_file_classes(self):
        """
        Test to verify that a post call with category
        """
        url = reverse('classes-list')
        act_data = {'activity': 'Bad_test',
                    'videoclass': None,
                    'trainer': 'Ex',
                    'workarea': 'T'}
        response = self.client.post(url, act_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)
        self.assertEqual(Class.objects.count(), 0)


import torch
import copy
from torch.quantization.quantize import add_observer_

_RELU_BRANCH = {'son':None,'can_be_fused':True}
_BN_BRANCH = {'son': {torch.nn.ReLU:_RELU_BRANCH},'can_be_fused':True}
_NN_BRANCH = {'son': {torch.nn.ReLU:_RELU_BRANCH},'can_be_fused':False}
_CONV_BRANCH = {'son': {torch.nn.BatchNorm2d:_BN_BRANCH,torch.nn.ReLU:_RELU_BRANCH},'can_be_fused':False}
_FUSETREE = {'son':{torch.nn.Conv2d:_CONV_BRANCH,torch.nn.Linear:_NN_BRANCH},'can_be_fused':False}
# FuseTree = {torch.nn.Conv2d:{torch.nn.ReLU:None,torch.nn.BatchNorm2d:{torch.nn.ReLU:None}},torch.nn.Linear:{torch.nn.ReLU:None}}

def fuse_module(module, inplace = False):
    if not inplace:
        module = copy.deepcopy(module)
    _fuse_module_helper(module)
    return module

def _fuse_module_helper(module):
    names = []
    tmpTree = _FUSETREE
    for name,child in module.named_children():
        if type(child) in tmpTree['son']:
            tmpTree = tmpTree['son'][type(child)]
            names.append(name)
        else:
            _fuse_module_helper(child)
            if tmpTree['can_be_fused']:
                torch.quantization.fuse_modules(module,names,inplace=True)
                names = []
                tmpTree = _FUSETREE
    if tmpTree['can_be_fused']:
        torch.quantization.fuse_modules(module,names,inplace=True)

# QCONFIGS = {} #use class method
# def propagate_qconfig(module,qconfig=None,inplace=False):
#     if not inplace:
#         module = copy.deepcopy(module)
#     module.qconfig = QCONFIGS[getattr(module,'qconfig',qconfig)]
#     if module.config is None:
#         raise Exception('not qconfig passed in or set in module')
#     for name, child in module.named_children():
#         propagate_qconfig(child,qconfig)
#
# def prepare(model,inplace=False):
#     assert hasattr(model,'qconfig')
#     propagate_qconfig(model,qconfig=model.qconfig,inplace=inplace)
#     add_observer_(model)
#     return model


# coding: utf-8

from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from builtins import *  # pylint:disable=redefined-builtin,unused-wildcard-import,wildcard-import,wrong-import-order

from collections import deque

import cv2

from .config import ConfigurationError, get_config
from .imgutils import (_frame_repr, _image_region, _ImageFromUser, _load_image,
                       pixel_bounding_box, crop, limit_time)
from .logging import debug, draw_on, ImageLogger
from .types import Region, UITestFailure

def detect_motion(timeout_secs=10, noise_threshold=None, mask=None,
                  region=Region.ALL, frames=None):
    """Generator that yields a sequence of one `MotionResult` for each frame
    processed from the device-under-test's video stream.

    The `MotionResult` indicates whether any motion was detected -- that is,
    any difference between two consecutive frames.

    Use it in a ``for`` loop like this::

        for motionresult in stbt.detect_motion():
            ...

    In most cases you should use `wait_for_motion` instead.

    :type timeout_secs: int or float or None
    :param timeout_secs:
        A timeout in seconds. After this timeout the iterator will be exhausted.
        Thas is, a ``for`` loop like ``for m in detect_motion(timeout_secs=10)``
        will terminate after 10 seconds. If ``timeout_secs`` is ``None`` then
        the iterator will yield frames forever. Note that you can stop
        iterating (for example with ``break``) at any time.

    :param float noise_threshold:
        The amount of noise to ignore. This is only useful with noisy analogue
        video sources. Valid values range from 0 (all differences are
        considered noise; a value of 0 will never report motion) to 1.0 (any
        difference is considered motion).

        This defaults to 0.84. You can override the global default value by
        setting ``noise_threshold`` in the ``[motion]`` section of
        :ref:`.stbt.conf`.

    :type mask: str or `numpy.ndarray`
    :param mask:
        A black & white image that specifies which part of the image to search
        for motion. White pixels select the area to analyse; black pixels select
        the area to ignore. The mask must be the same size as the video frame.

        This can be a string (a filename that will be resolved as per
        `load_image`) or a single-channel image in OpenCV format.

    :type region: `Region`
    :param region:
        Only analyze the specified region of the video frame.

        If you specify both ``region`` and ``mask``, the mask must be the same
        size as the region.

    :type frames: Iterator[stbt.Frame]
    :param frames: An iterable of video-frames to analyse. Defaults to
        ``stbt.frames()``.

    | Added in v28: The ``region`` parameter.
    | Added in v29: The ``frames`` parameter.
    """
    if frames is None:
        import stbt
        frames = stbt.frames()

    frames = limit_time(frames, timeout_secs)  # pylint: disable=redefined-variable-type

    if noise_threshold is None:
        noise_threshold = get_config(
            'motion', 'noise_threshold', type_=float)

    debug("Searching for motion")

    if mask is None:
        mask = _ImageFromUser(None, None, None)
    else:
        mask = _load_image(mask, cv2.IMREAD_GRAYSCALE)
        debug("Using mask %s" % mask.friendly_name)

    try:
        frame = next(frames)
    except StopIteration:
        return

    region = Region.intersect(_image_region(frame), region)

    previous_frame_gray = cv2.cvtColor(crop(frame, region),
                                       cv2.COLOR_BGR2GRAY)
    if (mask.image is not None and
            mask.image.shape[:2] != previous_frame_gray.shape[:2]):
        raise ValueError(
            "The dimensions of the mask '%s' %s don't match the "
            "video frame %s" % (
                mask.friendly_name, mask.image.shape,
                previous_frame_gray.shape))

    for frame in frames:
        imglog = ImageLogger("detect_motion", region=region)
        imglog.imwrite("source", frame)
        imglog.set(roi=region, noise_threshold=noise_threshold)

        frame_gray = cv2.cvtColor(crop(frame, region), cv2.COLOR_BGR2GRAY)
        imglog.imwrite("gray", frame_gray)
        imglog.imwrite("previous_frame_gray", previous_frame_gray)

        absdiff = cv2.absdiff(frame_gray, previous_frame_gray)
        previous_frame_gray = frame_gray
        imglog.imwrite("absdiff", absdiff)

        if mask.image is not None:
            absdiff = cv2.bitwise_and(absdiff, mask.image)
            imglog.imwrite("mask", mask.image)
            imglog.imwrite("absdiff_masked", absdiff)

        _, thresholded = cv2.threshold(
            absdiff, int((1 - noise_threshold) * 255), 255,
            cv2.THRESH_BINARY)
        eroded = cv2.erode(
            thresholded,
            cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)))
        imglog.imwrite("absdiff_threshold", thresholded)
        imglog.imwrite("absdiff_threshold_erode", eroded)

        out_region = pixel_bounding_box(eroded)
        if out_region:
            # Undo cv2.erode above:
            out_region = out_region.extend(x=-1, y=-1)
            # Undo crop:
            out_region = out_region.translate(region.x, region.y)

        motion = bool(out_region)

        result = MotionResult(getattr(frame, "time", None), motion,
                              out_region, frame)
        draw_on(frame, result, label="detect_motion()")
        debug("%s found: %s" % (
            "Motion" if motion else "No motion", str(result)))
        _log_motion_image_debug(imglog, result)
        yield result

def wait_for_motion(
        timeout_secs=10, consecutive_frames=None,
        noise_threshold=None, mask=None, region=Region.ALL, frames=None):
    """Search for motion in the device-under-test's video stream.

    "Motion" is difference in pixel values between two consecutive frames.

    :type timeout_secs: int or float or None
    :param timeout_secs:
        A timeout in seconds. This function will raise `MotionTimeout` if no
        motion is detected within this time.

    :type consecutive_frames: int or str
    :param consecutive_frames:
        Considers the video stream to have motion if there were differences
        between the specified number of consecutive frames. This can be:

        * a positive integer value, or
        * a string in the form "x/y", where "x" is the number of frames with
          motion detected out of a sliding window of "y" frames.

        This defaults to "10/20". You can override the global default value by
        setting ``consecutive_frames`` in the ``[motion]`` section of
        :ref:`.stbt.conf`.

    :param float noise_threshold: See `detect_motion`.

    :param mask: See `detect_motion`.

    :param region: See `detect_motion`.

    :param frames: See `detect_motion`.

    :returns: `MotionResult` when motion is detected. The MotionResult's
        ``time`` and ``frame`` attributes correspond to the first frame in
        which motion was detected.
    :raises: `MotionTimeout` if no motion is detected after ``timeout_secs``
        seconds.

    | Added in v28: The ``region`` parameter.
    | Added in v29: The ``frames`` parameter.
    """
    if frames is None:
        import stbt
        frames = stbt.frames()

    if consecutive_frames is None:
        consecutive_frames = get_config('motion', 'consecutive_frames')

    consecutive_frames = str(consecutive_frames)
    if '/' in consecutive_frames:
        motion_frames = int(consecutive_frames.split('/')[0])
        considered_frames = int(consecutive_frames.split('/')[1])
    else:
        motion_frames = int(consecutive_frames)
        considered_frames = int(consecutive_frames)

    if motion_frames > considered_frames:
        raise ConfigurationError(
            "`motion_frames` exceeds `considered_frames`")

    debug("Waiting for %d out of %d frames with motion" % (
        motion_frames, considered_frames))

    if mask is None:
        mask = _ImageFromUser(None, None, None)
    else:
        mask = _load_image(mask, cv2.IMREAD_GRAYSCALE)
        debug("Using mask %s" % mask.friendly_name)

    matches = deque(maxlen=considered_frames)
    motion_count = 0
    last_frame = None
    for res in detect_motion(
            timeout_secs, noise_threshold, mask, region, frames):
        motion_count += bool(res)
        if len(matches) == matches.maxlen:
            motion_count -= bool(matches.popleft())
        matches.append(res)
        if motion_count >= motion_frames:
            debug("Motion detected.")
            # We want to return the first True motion result as this is when
            # the motion actually started.
            for result in matches:
                if result:
                    return result
            assert False, ("Logic error in wait_for_motion: This code "
                           "should never be reached")
        last_frame = res.frame

    raise MotionTimeout(last_frame, mask.friendly_name, timeout_secs)

class MotionResult(object):
    """The result from `detect_motion` and `wait_for_motion`.

    :ivar float time: The time at which the video-frame was captured, in
        seconds since 1970-01-01T00:00Z. This timestamp can be compared with
        system time (``time.time()``).

    :ivar bool motion: True if motion was found. This is the same as evaluating
        ``MotionResult`` as a bool. That is, ``if result:`` will behave the
        same as ``if result.motion:``.

    :ivar Region region: Bounding box where the motion was found, or ``None``
        if no motion was found.

    :ivar Frame frame: The video frame in which motion was (or wasn't) found.

    Added in v28: The ``frame`` attribute.
    """
    _fields = ("time", "motion", "region", "frame")

    def __init__(self, time, motion, region, frame):
        self.time = time
        self.motion = motion
        self.region = region
        self.frame = frame

    def __bool__(self):
        return self.motion

    def __repr__(self):
        return (
            "MotionResult(time=%s, motion=%r, region=%r, frame=%s)" % (
                "None" if self.time is None else "%.3f" % self.time,
                self.motion, self.region, _frame_repr(self.frame)))

class MotionTimeout(UITestFailure):
    """Exception raised by `wait_for_motion`.

    :ivar Frame screenshot: The last video frame that `wait_for_motion` checked
        before timing out.

    :vartype mask: str or None
    :ivar mask: Filename of the mask that was used, if any.

    :vartype timeout_secs: int or float
    :ivar timeout_secs: Number of seconds that motion was searched for.
    """
    def __init__(self, screenshot, mask, timeout_secs):
        super(MotionTimeout, self).__init__()
        self.screenshot = screenshot
        self.mask = mask
        self.timeout_secs = timeout_secs

    def __str__(self):
        return "Didn't find motion%s within %g seconds." % (
            " (with mask '%s')" % self.mask if self.mask else "",
            self.timeout_secs)

def _log_motion_image_debug(imglog, result):
    if not imglog.enabled:
        return

    template = u"""\

          detect_motion:
          {{ "Found" if result.motion else "Didn't find" }} motion

        {{ annotated_image(result) }}

ROI Gray:

Previous frame ROI Gray:

Absolute difference:

        {% if "mask" in images %}

Mask:

Absolute difference – masked:

        {% endif %}

Threshold (noise_threshold={{noise_threshold}}):

Eroded:

    """

    imglog.html(template, result=result)


'''
Created on May 12, 2015

@author: wohlhart
'''
from tnetcore.layers.base import LayerParams, Layer
from tnetcore.util import readCfgIntNoneListParam, readCfgIntParam  # @UnresolvedImport
import theano.tensor as T
import numpy

class CatLayerParams(LayerParams):
    '''
    Concatenation Layer Parameters
    '''
    yaml_tag = u'!CatLayerParams'

    def __init__(self, inputDim=None,axis=1):
        '''
        '''
        super(CatLayerParams,self).__init__(inputDim=inputDim,outputDim=None)

        self.LayerClass = CatLayer

        self._inputDim = inputDim
        self._axis = axis
        self.update()

    def initFromConfig(self,cfg,sectionKey):
        super(CatLayerParams,self).initFromConfig(cfg,sectionKey)
        self._inputDim = readCfgIntNoneListParam(cfg,sectionKey,'inputDim',self._inputDim)
        self._axis = readCfgIntParam(cfg,sectionKey,'axis',self._axis)
        self.update()

    @property
    def axis(self):
        return self._axis

    @axis.setter
    def axis(self,value):
        self._axis = value
        self.update()

    def update(self):
        '''
        calc outputDim
        '''
        if (self._axis is None) or (self._inputDim is None):
            return

        #assert len(self._inputDim) > 1 and len(self._inputDim[0]) > 1, "CatLayer needs more than one input"
        self.checkInputDim(expectMultipleInputs=True)

        # inputDim is a list of inputDims. check if they agree along the non-cat-axes
        inDim = numpy.array(self._inputDim)
        #print("self._inputDim {}".format(self._inputDim))
        #print("inDim {}".format(inDim))
        assert inDim.shape[1] == 4, "Wrong inputDim shape {}; each row must have 4 entries (bs,nchan,h,w)".format(inDim.shape)
        numInputs = inDim.shape[0]
        nonCatAxes = numpy.setdiff1d(numpy.arange(inDim.shape[1]),[self._axis])
        numEqual = numpy.sum(inDim == inDim[0],axis=0)
        assert all(numEqual[nonCatAxes] == numInputs), "the axes along which not to concatenate must be equal, but are (axis={})\n{}".format(self._axis,inDim)

        # outDim is inDim for all non-cat-axes and sum over inDims for the cat axis
        outDim = inDim[0]
        outDim[self._axis] = sum(inDim[:,self._axis])
        self._outputDim = list(outDim)

        self.checkOutputDim()

    def debugPrint(self,indent=0):

        iStr = " "*indent
        print("CatLayer:")

        print(iStr + "inputs =          {}".format(self._inputs))
        print(iStr + "inputDim =        {}".format(self._inputDim))
        print(iStr + "axis =        {}".format(self._axis))
        print(iStr + "outputDim =       {}".format(self._outputDim))

    def __getstate__(self):
        state = super(CatLayerParams,self).__getstate__()
        state['axis'] = self._axis
        return state

    def __setstate__(self,state):
        super(CatLayerParams,self).__setstate__(state)
        self._axis = state['axis']
        self.update()

class CatLayer(Layer):
    """
    Concatenation Layer
    """

    def __init__(self, rng, inputVar, cfgParams, copyLayer=None, layerNum=None):
        """
        :type rng: numpy.random.RandomState
        :param rng: a random number generator used to initialize weights

        :type inputVar: theano.tensor.dtensor4
        :param inputVar: symbolic image tensor, of shape image_shape

        :type cfgParams: ConvLayerParams
        """
        self.cfgParams = cfgParams

        axis  = cfgParams.axis

        self.inputVar = inputVar

        self.output = T.concatenate(inputVar, axis)

        # store parameters of this layer; has none
        self.params = []
        self.weights = []