"""
Provides functionality to interact with the database.
"""

import os

import sqlite3
from sqlite3 import Error
import numpy as np

# Path to existing database or where the database should be created
PATH_TO_DB = os.environ.get('PATH_TO_DB')

def create_connection():
    """Creates a connection to the database or creates a
    new database if it does not exist using the default path

    Returns:
        Connection: Connection to database
    """
    return create_connection_to(path_to_db=PATH_TO_DB)

def create_connection_to(path_to_db: str):
    """Creates a connection to the database or creates a
    new database if it does not exist

    Returns:
        Connection: Connection to database
    """
    conn = None
    try:
        conn = sqlite3.connect(path_to_db)
    except Error as error:
        print(error)

    return conn

def insert_abstract(conn, db_entry_abstract):
    """Inserts an abstract into the database.

    Args:
        conn (Connection): Connection to the database
        db_entry_abstract (list): List of the abstract's attributes
    """
    sql_command = ("INSERT INTO abstract(abstract_id, year, title, "
                   "content, doctype, institution) VALUES(?,?,?,?,?,?)")
    cursor = conn.cursor()
    cursor.execute(sql_command, db_entry_abstract)
    conn.commit()

def insert_written_by(conn, abstract_id: int, author_id: int):
    """Inserts an entry into the written_by relation in the database.

    Args:
        conn (Connection): Connection to the database
        abstract_id (int): Id of the abstract
        author_id (int): Id of the author
    """
    sql_command = ("INSERT INTO written_by(abstract_id, "
                   "author_id) VALUES(?,?)")
    cursor = conn.cursor()
    cursor.execute(sql_command, (abstract_id, author_id))
    conn.commit()

def insert_has_competency(conn, author_id: int,
                          competency_id: int, status: str):
    """Inserts an entry into the has_competency relation in the database.

    Args:
        conn (Connection): Connection to the database
        author_id (int): Id of the author
        competency_id (int): Id of the competency
        status (str): Status of the competency from {denied, neutral, accepted}
    """
    sql_command = ("INSERT OR IGNORE INTO has_competency"
                   "(author_id, competency_id, status) VALUES(?,?,?)")
    cursor = conn.cursor()
    cursor.execute(sql_command, (author_id, competency_id, status))
    conn.commit()

def insert_derived_from(conn, competency_id: int,
                        abstract_id: int, relevancy: float):
    """Inserts an entry into the derived_from relation in the database.

    Args:
        conn (Connection): Connection to the database
        competency_id (int): Id of the competency
        abstract_id (int): Id of the abstract
        relevancy (float): Relevancy of the competency to the abstract
    """
    sql_command = ("INSERT INTO derived_from(competency_id, "
                   "abstract_id, relevancy) VALUES(?,?,?)")
    cursor = conn.cursor()
    cursor.execute(sql_command, (competency_id, abstract_id, relevancy))
    conn.commit()

def insert_category(conn, category_id: int, category_name: str):
    """Inserts an entry into the category relation in the database.

    Args:
        conn (Connection): Connection to the database
        category_id (int): Id of the category
        category_name (str): Name of the category
    """
    sql_command = """INSERT INTO category(category_id, name) VALUES(?,?)"""
    cursor = conn.cursor()
    cursor.execute(sql_command, (category_id, category_name))
    conn.commit()

def insert_has_category(conn, category_id: int, competency_id: int):
    """Inserts an entry into the has_category relation in the database.

    Args:
        conn (Connection): Connection to the database
        category_id (int): Id of the category
        competency_id (int): Id of the competency
    """
    sql_command = """INSERT OR IGNORE INTO has_category(category_id, competency_id)
                    VALUES(?,?)"""
    cursor = conn.cursor()
    cursor.execute(sql_command, (category_id, competency_id))
    conn.commit()

def get_author_id_by_name(conn, first_name: str, last_name: str) -> int:
    """Returns the id of an author by its name or creates an id if the author's
    id has not been created yet.

    Args:
        conn (Connection): Connection to the database
        first_name (str): First name of the author
        last_name (str): Last name of the author

    Returns:
        int: Id of the author
    """
    sql_get_author_id = """SELECT author_id
                           FROM author
                           WHERE first_name = ? AND last_name = ?;"""
    sql_insert_author = """INSERT INTO author(first_name, last_name)
    VALUES(?,?)"""
    cursor = conn.cursor()
    cursor.execute(sql_get_author_id, (first_name, last_name))
    result = cursor.fetchone()
    if result is None:
        # author not in db -> needs to be created
        author_id = cursor.execute(sql_insert_author,
                                   (first_name, last_name)).lastrowid
    else:
        # fetchone returns tuple, we want only the author_id
        author_id = result[0]

    conn.commit()
    return author_id

def add_category(conn, competency_name: str) -> int:
    """Adds an entry to the category relation in the database.

    Args:
        conn (Connection): Connection to the database
        competency_name (str): Name of the competency

    Returns:
        int: Id of the competency
    """
    sql_get_competency_id = """SELECT competency_id
                               FROM competency
                               WHERE competency_name = ?"""
    sql_insert_competency = """INSERT INTO competency(competency_name)
                               VALUES(?)"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competency_id, (competency_name,))
    result = cursor.fetchone()
    if result is None:
        # Competency not in db -> needs to be created
        competency_id = cursor.execute(sql_insert_competency,
                                       (competency_name,)).lastrowid
    else:
        # Fetchone returns tuple, we want only the author_id
        competency_id = result[0]

    conn.commit()
    return competency_id

def get_all_categories(conn) -> list[int, str]:
    """Returns all entries in the category relation in the database.

    Args:
        conn (Connection): Connection to the database

    Returns:
        list: list[category_id, name]
    """
    sql_get_categories = """SELECT * FROM category;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_categories)
    result = cursor.fetchall()
    if result is None:
        return """Something went wrong. Result for the query to fetch
    all entries of the category relation is None."""
    conn.commit()
    return result

def get_all_competencies(conn) -> list[int, str]:
    """Returns all entries in the competency relation in the database.

    Args:
        conn (Connection): Connection to the database

    Returns:
        list: list[competency_id, competency_name]
    """
    sql_get_categories = """SELECT * FROM competency;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_categories)
    result = cursor.fetchall()
    if result is None:
        return 'Something went wrong.'
    conn.commit()
    return result

def get_first_available_abstract_id(conn) -> int:
    """Returns next available abstract_id meaning highest_abstract_id + 1.
    Ignoring if some abstracts have been deleted in between, so potential
    for optimization.

    Args:
        conn (Connection): Connection to the database

    Returns:
        int: next abstract id
    """
    sql_get_highest_abstract_id = """SELECT MAX(abstract_id)
                                     FROM abstract
                                  """
    cursor = conn.cursor()
    cursor.execute(sql_get_highest_abstract_id)
    highest_abstract_id = cursor.fetchone()
    if highest_abstract_id[0] is None:
        highest_abstract_id = 0
    else:
        highest_abstract_id = highest_abstract_id[0]
    next_available = highest_abstract_id + 1
    conn.commit()
    return next_available

def get_or_generate_competency_id_by_name(conn, competency_name: str) -> int:
    """Returns the id of a competency by its name or creates an id if the
    competency's id has not been created yet.

    Args:
        conn (Connection): Connection to the database
        competency_name (str): Name of the competency

    Returns:
        int: Id of the competency
    """
    sql_get_competency_id = """SELECT competency_id
                               FROM competency
                               WHERE competency_name = ?"""
    sql_insert_competency = """INSERT INTO competency(competency_name)
                               VALUES(?)"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competency_id, (competency_name,))
    result = cursor.fetchone()
    if result is None:
        # competency not in db -> needs to be created
        competency_id = cursor.execute(sql_insert_competency,
                                       (competency_name,)).lastrowid
        print("Wurde hinzugefügt mit id" + str(competency_id))
    else:
        competency_id = result[0]

    conn.commit()
    return competency_id

def get_competency_id_by_name(conn, competency_id) -> int:
    """Returns the id of a competency by its name.

    Args:
        conn (Connection): Connection to the database
        competency_id (int): Id of the competency

    Returns:
        int: Id of the competency
    """
    sql_get_competency_id = """SELECT competency_id
                            FROM competency
                            WHERE competency_name = ?"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competency_id, (competency_id,))
    competency_id = cursor.fetchone()
    conn.commit()
    return competency_id

def get_competency_name_by_id(conn, competency_id) -> str:
    """Returns the name of a competency by its id.

    Args:
        conn (Connection): Connection to the database
        competency_id (int): Id of the competency

    Returns:
        str: Name of the competency
    """
    sql_get_competency_id = """SELECT competency_name
                            FROM competency
                            WHERE competency_id = ?"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competency_id, (competency_id,))
    competeny_name = cursor.fetchone()
    return competeny_name

def get_category_name_by_id(conn, category_id: int) -> str:
    """Returns the name of a category by its id.

    Args:
        conn (Connection): Connection to the database
        category_id (int): Id of the category

    Returns:
        str: Name of the category
    """
    sql_command = """SELECT name
                     FROM category
                     WHERE category_id = ?"""
    cursor = conn.cursor()
    cursor.execute(sql_command, (category_id,))
    category_name = cursor.fetchone()
    return category_name

def get_competencies_by_category(conn, category_name: str) -> list[int, str]:
    """Returns all competencies for a given category.

    Args:
        conn (Connection): Connection to the database
        category (str): Name of the category

    Returns:
        list: list[competency_name]
    """
    sql_get_competencies = """SELECT comp.competency_name FROM competency comp
                              JOIN has_category hc ON comp.competency_id
                              = hc.competency_id JOIN category cat ON
                              hc.category_id = cat.category_id
                              WHERE cat.name = ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competencies, (category_name,))
    result = cursor.fetchall()
    if result is None:
        return 'There are no competencies for this category.'
    conn.commit()
    return result

def get_competencies_by_category_id(conn, category_id: int) -> list[int, str]:
    """Returns all competencies for a given category.

    Args:
        conn (Connection): Connection to the database
        category_id (int): Id of the category

    Returns:
        list: list[competency_id, competency_name]
    """
    sql_get_competencies = """SELECT comp.competency_id, comp.competency_name
                              FROM competency comp
                              JOIN has_category hc ON comp.competency_id
                              = hc.competency_id
                              WHERE hc.category_id = ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competencies, (category_id,))
    result = cursor.fetchall()
    if result is None:
        return 'There are no competencies for this category.'
    conn.commit()
    return result

def get_competencies_by_author_id(conn, author_id: int) -> list[int, str]:
    """Returns all competencies for a given author.

    Args:
        conn (Connection): Connection to the database
        author_id (int): Id of the author

    Returns:
        list: list[competency_id, competency_name, status]
    """
    sql_get_competencies = """SELECT hc.competency_id, comp.competency_name,
                              hc.status FROM has_competency hc
                              JOIN competency comp ON
                              comp.competency_id = hc.competency_id
                              WHERE hc.author_id = ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competencies, (author_id,))
    result = cursor.fetchall()
    if result is None:
        return 'There are no competencies for this author.'
    conn.commit()
    return result

def get_competencies_by_abstract_id(conn, abstract_id: int) -> list[int, str]:
    """Returns all competencies for a given abstract.

    Args:
        conn (Connection): Connection to the database
        abstract_id (int): Id of the abstract

    Returns:
        list: List[competency_id, competency_name, relevancy]
    """
    sql_get_competencies = """SELECT df.competency_id, comp.competency_name,
                              df.relevancy FROM derived_from df
                              JOIN competency comp ON
                              comp.competency_id = df.competency_id
                              WHERE df.abstract_id = ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_competencies, (abstract_id,))
    result = cursor.fetchall()
    if result is None:
        return 'There are no competencies for this author.'
    conn.commit()
    return result

def get_abstract_by_id(conn,
                       abstract_id: int) -> list[int, int, str, str, str, str]:
    """Returns an abstract (consisting of all its attributes) by its id.

    Args:
        conn (Connection): Connection to the database
        abstract_id (int): Id of the abstract

    Returns:
        list: List[abstract_id, year, title, content, doctype, institution]
    """
    sql_get_abstract = """SELECT * FROM abstract
                          WHERE abstract_id = ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_abstract, (abstract_id,))
    result = cursor.fetchone()
    if result is None:
        return 'There exists no abstract with the given id.'
    conn.commit()
    return result

def get_authors_by_abstract(conn, abstract_id: int) -> list[int, str, str]:
    """Returns all authors of a given abstract.

    Args:
        conn (Connection): Connection to the database
        abstract_id (int): Id of the abstract

    Returns:
        list: List[author_id, first_name, last_name]
    """
    sql_get_abstract = """SELECT auth.author_id, auth.first_name,
                          auth.last_name FROM abstract abs
                          JOIN written_by wb
                          ON wb.abstract_id = abs.abstract_id
                          JOIN author auth ON wb.author_id = auth.author_id
                          WHERE abs.abstract_id = ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_abstract, (abstract_id,))
    result = cursor.fetchall()
    if result is None:
        return 'There exists no author with the given abstract id.'
    conn.commit()
    return result

def get_authors_with_competency(conn,
                                competency: str) -> list[
                                    int, str, str, int, str]:
    """Returns all authors with a given competency and the status of the
    competency.

    Args:
        conn (Connection): Connection to the database
        competency_name (str): Name of the competency

    Returns:
        list: list[author_id, first_name, last_name, relevancy, status]
    """
    sql_get_authors = """SELECT auth.author_id, auth.first_name,
                         auth.last_name,
                         df.relevancy, hc.status
                         FROM author auth JOIN has_competency hc
                         ON auth.author_id = hc.author_id JOIN competency comp
                         ON hc.competency_id = comp.competency_id JOIN
                         derived_from df
                         ON comp.competency_id = df.competency_id
                         WHERE comp.competency_name = ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_authors, (competency,))
    result = cursor.fetchall()
    if result is None:
        return 'There are no people with this competency.'
    conn.commit()
    return result

def get_authors_by_competency_id(conn,
                                 competency_id: int) -> list[
                                    int, str, str, float, str]:
    """Returns all authors with a given competency with its
    relevancy and status.

    Args:
        conn (Connection): Connection to the database
        competency_id (int): Id of the competency

    Returns:
        list: List[author_id, first_name, last_name, abstract_id, relevancy, status]
    """
    sql_get_authors = """SELECT auth.author_id, auth.first_name,
                         auth.last_name, df.abstract_id, df.relevancy, status
                         FROM author auth JOIN has_competency hc
                         ON auth.author_id = hc.author_id
                         LEFT JOIN derived_from df
                         ON df.competency_id = hc.competency_id
                         JOIN written_by wb ON wb.author_id = auth.author_id
                         AND wb.abstract_id = df.abstract_id
                         WHERE hc.competency_id= ?;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_authors, (competency_id,))
    result = cursor.fetchall()
    if result is None:
        return 'There are no people with this competency.'
    conn.commit()
    return result

def get_abstracts_by_author(conn, author_first_name: str,
                            author_last_name: str) -> list[
                                int, int, str, str, str]:
    """Returns all abstracts of a given author.

    Args:
        conn (Connectino): Connection to the database
        author_first_name (str): First name of the author
        author_last_name (str): Last name of the author

    Returns:
        list: list[abstract_id, year, title, content, institution]
    """
    sql_get_abstracts = """SELECT abs.abstract_id, abs.year, abs.title,
                           abs.content, abs.institution
                           FROM abstract abs JOIN
                           written_by wb ON abs.abstract_id
                           = wb.abstract_id JOIN author auth
                           ON wb.author_id = auth.author_id
                           WHERE auth.first_name = ? AND
                           auth.last_name = ?;"""

    cursor = conn.cursor()
    cursor.execute(sql_get_abstracts, (author_first_name, author_last_name))
    result = cursor.fetchall()
    if result is None:
        return 'There are no abstracts from this author.'
    conn.commit()
    return result

def get_abstracts_with_competency(conn, competency_id: int,
                                  author_id: int) -> list[int]:
    """Returns all abstracts_ids of the abstracts that proof that an author has
    a given competency.

    Args:
        conn (Connection): Connection to the database
        competency_id (int): Id of the competency
        author_id (int): Id of the author

    Returns:
        list: list[abstract_id]
    """
    sql_get_abstracts_with_competency = """SELECT wb.abstract_id
                                           FROM derived_from df
                                           JOIN written_by wb
                                           ON df.abstract_id = wb.abstract_id
                                           WHERE df.competency_id = ?
                                           AND wb.author_id = ?
                                           """
    cursor = conn.cursor()
    cursor.execute(sql_get_abstracts_with_competency,
                   (competency_id, author_id))
    abstracts = cursor.fetchall()
    conn.commit()
    return abstracts

def get_ranking_score(conn, author_id, competency_id) -> int:
    """Returns the ranking score of a given competency for a given author.

    Args:
        conn (Connection): Connection to the database
        author_id (int): Id of the author
        competency_id (int): Id of the competency

    Returns:
        _type_: _description_
    """
    FAILURE_DEFAULT = -1
    sql_get_relevancies = """SELECT relevancy
                             FROM derived_from df JOIN
                             written_by wb ON df.abstract_id = wb.abstract_id
                             WHERE competency_id = ? AND
                             author_id = ?
                            """
    cursor = conn.cursor()
    # getting all relevancies of the author and competency from the ML model
    cursor.execute(sql_get_relevancies, (competency_id, author_id))
    relevancies = cursor.fetchall()
    if relevancies is None or -1 in relevancies:    # no relevancies or dummy relevancies
        return FAILURE_DEFAULT
    conn.commit()

    # getting the author name from the database
    author_first_name, author_last_name = get_author_name(conn, author_id)
    if author_first_name is None and author_last_name is None:
        return FAILURE_DEFAULT

    # getting all abstracts by the author
    abstracts_by_author = get_abstracts_by_author(conn, author_first_name,
                                                  author_last_name)
    if abstracts_by_author == 'There are no abstracts from this author.':
        return FAILURE_DEFAULT
    total_abstracts = len(abstracts_by_author)  # amount of abstracts

    # getting the abstracts of the author that show the competency
    abstracts_with_competency = get_abstracts_with_competency(conn,
                                                              competency_id,
                                                              author_id)
    if abstracts_with_competency == []:
        return FAILURE_DEFAULT
    amount_abstracts_with_competency = len(abstracts_with_competency)

    proportion_competency = amount_abstracts_with_competency / total_abstracts
    mean_relevancy = np.mean(relevancies)

    # no bonus if 1/1 abstract shows competency
    if amount_abstracts_with_competency != 1 and total_abstracts != 1:
        bonus = proportion_competency * (1 - mean_relevancy)
    else:
        bonus = 0

    # calculation of relevancy: relevancy mean plus bonus for proportion with the competency
    ranking_score = mean_relevancy + bonus
    ranking_score = round(ranking_score*100) / 100

    return ranking_score

def get_author_name(conn, author_id: int) -> list[str, str]:
    """Returns the name of an author.

    Args:
        conn (Connection): Connection to the database
        author_id (int): Id of the author

    Returns:
        list: [first_name, last_name]
    """
    sql_get_author_name = """SELECT first_name, last_name
                             FROM author
                             WHERE author_id = ?
                            """
    cursor = conn.cursor()
    cursor.execute(sql_get_author_name, [author_id])

    author = cursor.fetchone()
    if author is None:
        return None, None
    conn.commit()
    return author

def get_all_authors(conn) -> list[int, str, str]:
    """Returns all entries in the author relation in the database.

    Args:
        conn (Connection): Connection to the database

    Returns:
        list: list[author_id, first_name, last_name]
    """
    sql_get_authors = """SELECT * FROM author;"""
    cursor = conn.cursor()
    cursor.execute(sql_get_authors)
    result = cursor.fetchall()
    if result is None:
        return ("Something went wrong. Result for the query to fetch",
                "all entries of the author relation is None.")
    conn.commit()
    return result

def change_status(conn, author_id: int, competency_id: int,
                  competency_status: str) -> list[str]:
    """Changes given competency status in database of author with competency

    Args:
        conn (Connection): Connection to the database
        author_id: author where it should be changed
        competency_id: for which competency the status should be changed
    """
    sql_change_status = """ UPDATE has_competency
                            SET status = ?
                            WHERE author_id = ? AND
                            competency_id = ?
                        """
    cursor = conn.cursor()
    cursor.execute(sql_change_status,
                   (competency_status, author_id, competency_id))
    cursor.fetchall()
    conn.commit()
    result = ["success"]
    return result

def get_author_id_by_full_name(conn, full_name: str) -> int:
    """Returns the id of an author by its name or creates an id if the author's
    id has not been created yet.

    Args:
        conn (Connection): Connection to the database
        full_name (str): Full name of the author

    Returns:
        int: Id of the author
    """
    sql_get_author_id_by_full_name = """SELECT author_id
                                        FROM author
                                        WHERE first_name || ' ' || last_name =
                                        '{}'""".format(full_name)
    cursor = conn.cursor()
    cursor.execute(sql_get_author_id_by_full_name)
    result = cursor.fetchone()
    conn.commit()
    return result


# import the necessary packages
from pytesseract import Output
import pytesseract
import cv2
from imutils.video import VideoStream

n = 0
currentText = ""
pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files/Tesseract-OCR/tesseract'
TESSDATA_PREFIX = 'C:/Program Files/Tesseract-OCR/tessdata'
vs = VideoStream(src=0).start()
while True:
        #load the input image, convert it from BGR to RGB channel ordering,
        # and use Tesseract to localize each area of text in the input image
        image = vs.read()
        rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        results = pytesseract.image_to_data(rgb, output_type=Output.DICT, lang="eng")

        # loop over each of the individual text localizations
        for i in range(0, len(results["text"])):
                # extract the bounding box coordinates of the text region from
                # the current result
                x = results["left"][i]
                y = results["top"][i]
                w = results["width"][i]
                h = results["height"][i]
                # extract the OCR text itself along with the confidence of the
                # text localization
                text = results["text"][i]
                conf = int(results["conf"][i])

                # filter out weak confidence text localizations
                if conf > 1:
                        # display the confidence and text to our terminal
                        print("Confidence: {}".format(conf))
                        print("Text: {}".format(text))
                        print("")
                        # strip out non-ASCII text so we can draw the text on the image
                        # using OpenCV, then draw a bounding box around the text along
                        # with the text itself
                        text = "".join([c if ord(c) < 128 else "" for c in text]).strip()
                        cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
                        cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
                                1.2, (0, 0, 255), 3)
                        if(text == currentText and text != ""):
                                n = n + 1
        if (n > 3):
                print(text)
                break
        currentText = text
        # show the output image
        cv2.imshow("Image", image)
        cv2.waitKey(15)
cv2.destroyAllWindows()


# Jason van Raamsdonk
# program to print the second highest element of an inputted my_array
# first input is the array size, second to n inputs are the array elements

if __name__ == '__main__':
    n = int(input())
    arr = list(map(int, input().split()))

    current = min(arr)

    for i in range(0, n):
        if arr[i] > current and arr[i] < max(arr):
            current = arr[i]

    print(current)
    # print(max(arr))


import random
import string
import threading

class Game:
    def __init__(self, questions_list):
        self.status = 'not_started'
        self.current_question = -1
        self.question_status = -1
        self.question_counter = -1
        self.reading_duration = -1
        self.thinking_duration = -1
        self.reading_timer = -1
        self.thinking_timer = -1
        self.waiting_timer = -1
        self.questions_list = questions_list

        self.game_thread = None

        self.history = {
            'team1id' : {
                    'team_id'   : 'asox023qe32nsdfsq', #some random string
                    'team_name' : 'The Bilzebobs',
                    'record'   : {'q1_id' : 0, 'q2_id' : 1, 'q3_id': 1, 'q4_id':0},
                    'answers'  : {
                        'q1_id' : { 'raspuns': 'iarba verde', 'team_member': 'vasilika'},
                        'q2_id' : { 'raspuns': 'gagarin',     'team_member': 'vasilika'},
                        'q3_id' : { 'raspuns': 'tsoi jiv',    'team_member': 'vasilika'},
                        'q4_id' : { 'raspuns': 'ligma',       'team_member': 'vasilika'},
                    },
                    'scor' : 0
                }
        }

        self.rankings = {
            'team1' : [0,0,1,0,1,0,0,1,0,1,0,-1,-1,-1,-1,-1],
            'team2' : [0,1,9,1,1,0,0,1,0,1,0,-1,-1,-1,-1,-1],
            'team3' : [0,0,1,1,1,1,0,1,0,1,0,-1,-1,-1,-1,-1],
            'team4' : [0,0,1,0,1,0,1,1,0,1,1,-1,-1,-1,-1,-1],
            'team5' : [0,0,1,0,1,0,0,1,0,1,0,-1,-1,-1,-1,-1]
        }

        self.verification_queue = []

    def get_random_string(self, length):
        letters = string.ascii_lowercase
        result_str = ''.join(random.choice(letters) for i in range(length))

        return result_str

    def getStatus(self, team_id):
        return {
            'status'                  : self.status,
            'question_counter'        : self.question_counter,
            'question_status'         : self.question_status,
            'reading_duration'        : self.reading_duration,
            'reading_timer'           : self.reading_timer,
            'thinking_duration'       : self.thinking_duration,
            'thinking_timer'          : self.thinking_timer,
            'waiting_timer'           : self.waiting_timer,
            'team_history'            : self.history[team_id]
        }

    def revise(self,teamId, questionId, check):
        self.history[teamId]['record'][qiestionId] = check

    def updateRankings(self):
        questionset_structure = [{'q1'},{'q2a','q2b'},{'q3'},{'q4'},{'q5'}]
        tmp_rankings = {}
        for teamId in self.history:
            tmp_rankings[teamId] = [-1 for i in range(len(self.questions_list))]
        for qno, qstruct in enumerate(questionset_structure):
            for teamId in self.rankings:
                teamAnsweredCorrectly = True
                teamHasntAnsweredYet  = False
                for questionid in qstruct:
                    if(self.rankings[teamId]['record'][questionId] == -1):
                        teamHasntAnsweredYet = True
                    if(self.rankings[teamId]['record'][questionId] == 0):
                        teamAnsweredCorrectly = False
                if(teamHasntAnsweredYet):
                    rankings[teamId][qno] = -1
                else:
                    rankings[teamId][qno] = int(teamAnsweredCorrectly)

    def getRankings(self):
        return self.rankings

    def start(self):
        self.status            = 'ongoing'
        self.question_counter  = 0
        self.question_status   = 'reading'
        self.current_question  = self.questions_list[self.question_counter]
        self.reading_duration  = self.current_question['reading_duration']
        self.thinking_duration = self.current_question['thinking_duration']

        self.reading_timer     = 0
        self.thinking_timer    = 0
        self.waiting_timer     = 0

        self.game_thread = threading.Thread(target=self.loop, args=(self))
        self.game_thread.start()

    def verify(self,submission):
        teamId     = submission['teamId']
        questionId = submission['questionId']
        check      = submission['check']
        self.history[teamId]['record'][questionId] = check

    def getNextUnverified(self):
        return self.verification_queue[-1]

    def submitAnswer(self,teamId,teamMember,questionId, answer):
        self.rankings[teamId]['answers'][questionId]['answer'] = answer
        self.rankings[teamId]['answers'][questionId]['team_member'] = team_member
        self.verification_queue.append({'teamId':teamId,'questionId':questionId,'answer':answer})

    def nextQuestion(self):
        self.question_counter  = self.question_counter + 1

        if(self.question_counter>=len(self.questions_list)):
            self.status = 'finished'

        self.current_question  = self.questions_list[self.question_counter]

        self.question_status   = 'reading'
        self.reading_timer     = 0
        self.thinking_timer    = 0
        self.waiting_timer     = 0
        self.reading_duration  = self.questions_list[self.question_counter]['reading_duration']
        self.thinking_duration = self.questions_list[self.question_counter]['reading_duration']

    def loop(self):
        print("I'M IN THE LOOP!")
        while True:
            if(self.question_status == 'reading'):
                print("Question is being read")
                if(self.reading_timer < self.current_question['reading_duration']):
                    self.reading_timer = self.reading_timer + 1
                else:
                    self.question_status = 'thinking'
                    self.thinking_timer = 0

            elif(self.question_status == 'thinking'):
                print("people are thinking")
                if(self.thinking_timer < self.current_question['thinking_duration']):
                    self.thinking_timer = self.thinking_timer + 1
                else:
                    self.question_status = 'waiting_for_answers'
                    self.waiting_timer = 0

            elif(self.question_status == 'waiting_for_answers'):
                print("waiting for answers")
                if(self.waiting_timer < 10):
                    self.waiting_timer = self.waiting_timer + 1
                else:
                    self.nextQuestion()

            elif(self.status == 'finished'):
                print("GAME IS FINISHED")
                return

            print(self.getStatus())
            time.sleep(1)

    def registerTeam(self,team_name):
        for team_id, team_object in self.history.items():
            if(team_object['team_name'] == team_name):
                return {'status' :-1,'message': 'team with this name already exists'}

        team_id = self.get_random_string(5)
        while(team_id in self.history):
            team_id = get_random_string(5)

        self.history[team_id] = {
            'team_id'   : team_id,
            'team_name' : team_name,
            'record'    : [0 for q in self.questions_list],
            'answers'   : {},
            'score'     : 0
        }

        self.rankings[team_id] = [0 for q in self.questions_list]

        return {'success':1, 'team_id':team_id}


import numpy
from collections import defaultdict

def epsilon_greedy_policy(env, S, Q, epsilon):
    """Act epsilon greedily with respect to action-value funtion Q in state S.

    env is an OpenAI gym environment.
    S is state where the agent is.
    Q is action-value function.
    epsilon is probability of taking random action.
    """
    if numpy.random.rand() < epsilon:
        return env.action_space.sample()
    # else choose action which maximize Q in S
    return numpy.argmax([Q[S, A] for A in range(env.action_space.n)])

def sarsa(env, n_episodes, gamma=1.0, alpha=0.5, epsilon=0.1):
    """Sarsa algorithm.

    Return action-value function for optimal epsilon-greedy policy for an
    environment.

    env is an OpenAI gym environment.
    n_episodes is number of episodes to run.
    gamma is an discount factor.
    alpha is an learning rate.
    epsilon is probability of selecting random action.
    """
    # rather than store Q as table use dictionary (default value is 0)
    Q = defaultdict(float)
    for _ in range(n_episodes):
        # reset environment
        S = env.reset()
        # choose epsilon-greedy action with respect to Q
        A = epsilon_greedy_policy(env, S, Q, epsilon)
        while True:
            S_prime, R, done, _ = env.step(A)
            A_prime = epsilon_greedy_policy(env, S_prime, Q, epsilon)
            # temporal-difference update
            Q[S, A] += alpha * (R + gamma * Q[S_prime, A_prime] - Q[S, A])
            S, A = S_prime, A_prime
            if done:
                break
    return Q

def q_learning(env, n_episodes, gamma=1.0, alpha=0.5, epsilon=0.1):
    """Q-learning algorithm.

    Return optimal action value function Q. It is off-policy
    temporal-difference method.

    env is an OpenAI gym environment.
    n_episodes is number of episodes to run.
    gamma is an discount factor.
    alpha is an learning rate.
    epsilon is probability of selecting random action.
    """
    # rather than store Q as table use dictionary (default value is 0)
    Q = defaultdict(float)
    for _ in range(n_episodes):
        S = env.reset()
        while True:
            # select epsilon-greedy action
            A = epsilon_greedy_policy(env, S, Q, epsilon)
            S_prime, R, done, _ = env.step(A)
            # Q update
            max_Q = numpy.max(
                    [Q[S_prime, A] for A in range(env.action_space.n)]
                    )
            Q[S, A] += alpha * (R + gamma * max_Q - Q[S, A])
            S = S_prime
            if done:
                break
    return Q

def get_policy(env, Q):
    """Return greedy policy with respect to action-value function Q.

    env is an OpenAI environment.
    Q is action-value function.
    """
    policy = numpy.zeros((env.height, env.width), numpy.int)
    for i in range(env.height):
        for j in range(env.width):
            S = i, j
            policy[S] = numpy.argmax(
                    [Q[S, A] for A in range(env.action_space.n)]
                    )
    return policy


from ParseShiftData_v1 import *
import glob
from asammdf import MDF
import os

mdfs = glob.glob("MDFs/*")

APS = "HEV_AccelPdlVal"
eng_rpm = "HEV_EngSpdVal"
BPS = "IEB_StrkDpthPcVal"
tr_class = "LHTCU_ShftTrgtClsSta"
cur_gear = "HTCU_CurrGearSta"
target_gear = "HTCU_TrgtGearSta"
wheel_spd = "WHL_SpdFLVal"
accel = "YRS_LongAccelVal"
mot_spd = "NTU"  # tm_in_spd 와 같음
tm_out_spd = "NAB"
tm_delta_acc = "ntug_SyncFilt"
shift_phase = "esa_Phase"

tm_disc_signals = (cur_gear, target_gear, tr_class)
tm_cont_signals = (APS, eng_rpm, BPS, wheel_spd, mot_spd, tm_out_spd, tm_delta_acc)
# tm_cont_signals = (APS, eng_rpm, BPS, wheel_spd, mot_spd, tm_out_spd)

for mdf in mdfs:

    file_name_, file_extension = os.path.splitext(mdf)

    try:
        if file_extension == ".dat" or file_extension == ".mf4":
            input_mdf = MDF(mdf)
            file_name = file_name_.split("\\")[-1]
            ParseShiftData(input_mdf, tm_disc_signals, tm_cont_signals, file_name)
        else:
            pass
    except Exception as e:
        print(e)


import pytest
from ezdxf.lldxf.tagger import internal_tag_compiler
from ezdxf.document import Drawing
from ezdxf import DXFValueError, decode_base64

def test_dxfversion_1():
    doc = Drawing.from_tags(internal_tag_compiler(TEST_HEADER))
    assert "AC1009" == doc.dxfversion

@pytest.fixture(scope="module")
def dwg_r12():
    return Drawing.new("AC1009")

def test_dxfversion_2(dwg_r12):
    assert "AC1009" == dwg_r12.dxfversion

def test_acad_release(dwg_r12):
    assert "R12" == dwg_r12.acad_release

def test_get_layer(dwg_r12):
    layer = dwg_r12.layers.get("0")
    assert "0" == layer.dxf.name

def test_error_getting_not_existing_layer(dwg_r12):
    with pytest.raises(DXFValueError):
        layer = dwg_r12.layers.get("TEST_NOT_EXISTING_LAYER")

def test_create_layer(dwg_r12):
    layer = dwg_r12.layers.new("TEST_NEW_LAYER")
    assert "TEST_NEW_LAYER" == layer.dxf.name

def test_error_adding_existing_layer(dwg_r12):
    with pytest.raises(DXFValueError):
        layer = dwg_r12.layers.new("0")

def test_has_layer(dwg_r12):
    assert "0" in dwg_r12.layers

def test_has_not_layer(dwg_r12):
    assert "TEST_LAYER_NOT_EXISTS" not in dwg_r12.layers

def test_removing_layer(dwg_r12):
    dwg_r12.layers.new("TEST_NEW_LAYER_2")
    assert "TEST_NEW_LAYER_2" in dwg_r12.layers
    dwg_r12.layers.remove("TEST_NEW_LAYER_2")
    assert "TEST_NEW_LAYER_2" not in dwg_r12.layers

def test_error_removing_not_existing_layer(dwg_r12):
    with pytest.raises(DXFValueError):
        dwg_r12.layers.remove("TEST_LAYER_NOT_EXISTS")

@pytest.fixture(scope="module")
def dwg_r2000():
    return Drawing.new("AC1015")

def test_r2000_dxfversion(dwg_r2000):
    assert "AC1015" == dwg_r2000.dxfversion

def test_r2000_acad_release(dwg_r2000):
    assert "R2000" == dwg_r2000.acad_release

@pytest.fixture
def min_r12():
    return Drawing.from_tags(internal_tag_compiler(MINIMALISTIC_DXF12))

def test_min_r12_header_section(min_r12):
    assert hasattr(min_r12, "header")
    assert min_r12.header["$ACADVER"] == "AC1009"
    assert min_r12.header["$DWGCODEPAGE"] == "ANSI_1252"

def test_min_r12_layers_table(min_r12):
    assert hasattr(min_r12, "layers")
    assert len(min_r12.layers) == 2
    assert "0" in min_r12.layers
    assert "Defpoints" in min_r12.layers

def test_min_r12_styles_table(min_r12):
    assert hasattr(min_r12, "styles")
    assert len(min_r12.styles) == 1
    assert "Standard" in min_r12.styles

def test_min_r12_linetypes_table(min_r12):
    assert hasattr(min_r12, "linetypes")
    assert len(min_r12.linetypes) == 3
    assert "continuous" in min_r12.linetypes
    assert "ByLayer" in min_r12.linetypes
    assert "ByBlock" in min_r12.linetypes

def test_min_r12_blocks_section(min_r12):
    assert hasattr(min_r12, "blocks")
    assert len(min_r12.blocks) == 2
    assert "*Model_Space" in min_r12.blocks
    assert "*Paper_Space" in min_r12.blocks

def test_min_r12_entity_section(min_r12):
    assert hasattr(min_r12, "entities")
    assert len(min_r12.entities) == 0

def test_chain_layout_and_block(dwg_r12, dwg_r2000):
    for dwg in (dwg_r12, dwg_r2000):
        msp = dwg.modelspace()
        line_msp = msp.add_line((0, 0), (1, 1))
        blk = dwg.blocks.new("TEST_CHAIN")
        line_blk = blk.add_line((0, 0), (1, 1))

        handles = list(e.dxf.handle for e in dwg.chain_layouts_and_blocks())
        # check for unique handles
        assert len(handles) == len(set(handles))

        check = {line_msp.dxf.handle, line_blk.dxf.handle}
        assert check.intersection(handles) == check

def test_base64_encoding_r12(dwg_r12):
    data = dwg_r12.encode_base64()
    doc = decode_base64(data)
    assert doc.acad_release == "R12"

def test_base64_encoding_r2000(dwg_r2000):
    data = dwg_r2000.encode_base64()
    doc = decode_base64(data)
    assert doc.acad_release == "R2000"

def test_set_drawing_units(dwg_r12):
    dwg_r12.units = 6
    assert dwg_r12.header["$INSUNITS"] == 6
    dwg_r12.units = 5
    assert dwg_r12.header["$INSUNITS"] == 5

MINIMALISTIC_DXF12 = """  0
SECTION
  2
ENTITIES
  0
ENDSEC
  0
EOF
"""

TEST_HEADER = """  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1009
  9
$DWGCODEPAGE
  3
ANSI_1252
  9
$HANDSEED
  5
FF
  0
ENDSEC
  0
SECTION
  2
ENTITIES
  0
ENDSEC
  0
EOF
"""

TESTCOPY = """  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  9
$TDUPDATE
 40
0.
  9
$HANDSEED
  5
FF
  0
ENDSEC
  0
SECTION
  2
OBJECTS
  0
ENDSEC
  0
SECTION
  2
FANTASYSECTION
  1
everything should be copied
  0
ENDSEC
  0
SECTION
  2
ALPHASECTION
  1
everything should be copied
  0
ENDSEC
  0
SECTION
  2
OMEGASECTION
  1
everything should be copied
  0
ENDSEC
  0
EOF
"""


filename_cats = 'cats.txt'
filename_dogs = 'dogs.txt'

try:
	with open(filename_cats, 'r') as file_object:
		cats_lines = file_object.readlines()
		for line in cats_lines:
			print(line.rstrip())

	print("\n")

	with open(filename_dogs, 'r') as file_object:
		dogs_lines = file_object.readlines()
		for line in dogs_lines:
			print(line.rstrip())

except FileNotFoundError:
	print("Oops! One of your file paths appears to be incorrect.",
		"Go back and make sure that your files are pathed correctly!")

crashcourse/crash_course_learning_section/ch 10 -  read and write to file/crash_course_ch10_cats and dogs_read_file.py


import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style

class PlotData:
    def __init__(self, subplot_lines, subplot_columns):
        self.fig = plt.figure()
        n = subplot_lines*subplot_columns
        self.ax = [self.fig.add_subplot(subplot_lines, subplot_columns, i+1) for i in range(n)]

        self.reset(n)

    def reset(self, subplots):
        self.x = [[[]] for _ in range(subplots)]
        self.y = [[[]] for _ in range(subplots)]
        self.data_series = [{} for _ in range(subplots)]
        self.titles = [None for _ in range(subplots)]
        self.legends = [[] for _ in range(subplots)]
        self.ylabels = [None for _ in range(subplots)]
        self.xlabels = [None for _ in range(subplots)]

    def config_subplot(self, i, title=None, legend=None, xlabel=None, ylabel=None):
        self.titles[i-1] = title
        self.legends[i-1] = legend
        self.xlabels[i-1] = xlabel
        self.ylabels[i-1] = ylabel

        if legend is not None:
            for lg in legend:
                self.data_series[i-1][lg] = len(self.data_series[i-1])
                self.x[i-1].append([])
                self.y[i-1].append([])
        else:
            self.legends[i-1] = []

    def add_data(self, subplot, series, x, y):
        if not series in self.data_series[subplot-1]:
            self.data_series[subplot-1][series] = len(self.data_series[subplot-1])
            self.x[subplot-1].append([])
            self.y[subplot-1].append([])
            self.legends[subplot-1].append(series)

        s = self.data_series[subplot-1][series]
        self.x[subplot-1][s].append(x)
        self.y[subplot-1][s].append(y)

    def plot(self):
        for i,sp in enumerate(self.ax):
            series = len(self.x[i])
            for ser in range(series):
                sp.plot(self.x[i][ser], self.y[i][ser])
            sp.grid(b=True)

            if self.titles[i] is not None:
                sp.set_title(self.titles[i])
            if self.legends[i] is not None:
                sp.legend(self.legends[i])
            if self.xlabels[i] is not None:
                sp.set_xlabel(self.xlabels[i])
            if self.ylabels[i] is not None:
                sp.set_ylabel(self.ylabels[i])


import sys
sys.stdin = open("수 정렬하기.txt")

N = int(input())
number = []
ans = []
for z in range(N):
    num = int(sys.stdin.readline())
    number.append(num)

number.sort()

for z in range(N):
    ans.append(str(number[z]))

print('\n'.join(ans))

알고리즘문제/수 정렬하기2.py


import sys
sys.stdin = open("input_5203.txt","r")

def babyjin(player):
    for i in range(8):  #연속된 숫자 3개 이상
        if player[i] and player[i + 1] and player[i + 2]:
            return True

    for j in range(10):  #같은 숫자 3개 이상
        if player[j] == 3:
            return True

    return False

t = int(input())
for tc in range(1, t+1):
    lst = list(map(int, input().split()))
    player1 = [0] * 10  #숫자는 0~9
    player2 = [0] * 10
    win = 0
    for i in range(12):
        if i % 2 == 0:   #짝수
            player1[lst[i]] += 1
            if babyjin(player1):
                win = 1
                break

        else:
            player2[lst[i]] += 1
            if babyjin(player2):
                win = 2
                break

    print('#{} {}'.format(tc, win))


# problem from leetcode with Maura
import unittest
from unittest.case import TestCase

def findCenter(edges):
        seen = {}

        for edge in edges:
            for num in edge:
                if num in seen:
                    seen[num] += 1
                else:
                    seen[num] = 1
        for key in seen:
            if seen[key] > 1:
                return key

class Test(unittest.TestCase):

    def test_small_graph(self):
        edges = [[1, 2], [2, 3], [4, 2]]
        result = findCenter(edges)
        expected = 2
        self.assertEqual(result, expected)

    def test_med_graph(self):
        edges = [[1, 4], [2, 4], [3, 4], [5, 4], [6, 4]]
        result = findCenter(edges)
        expected = 4
        self.assertEqual(result, expected)

    def test_lg_graph(self):
        edges = [[1, 6], [2, 6], [3, 6], [4, 6], [5, 6], [7, 6], [8, 6], [9, 6]]
        result = findCenter(edges)
        expected = 6
        self.assertEqual(result, expected)

unittest.main(verbosity=2)


def desafio_do_maior_numero():
    """
    Está função calcula o maior número dentro de uma sequência de números
    fornecidos pelo usuário que termina a sequência com o número zero printando
    o maior número da sequência.
    :return:
    """
    l1 = []
    num = input().split(" ")
    for i in range(0, len(num)):
        if num[i] == "0":
            break
        else:
            num[i] = int(num[i])
            l1.append(num[i])
    l1.sort()
    if len(l1) > 0:
        print(max(l1))
    else:
        print(0)

desafio_do_maior_numero()


from model.planetary_system import PlanetaryWeather

class DayWeather:

    _weather_string_map = {
        PlanetaryWeather.NORMAL_SEASON: 'normal',
        PlanetaryWeather.DROUGHT_SEASON: 'sequia',
        PlanetaryWeather.OTP_SEASON: 'condiciones optimas de temperatura y presion',
        PlanetaryWeather.WET_SEASON: 'lluvioso'
    }

    def __init__(self, day, weather):
        self.day = day
        self.weather = weather

    @property
    def weather_string(self):
        return self._weather_string_map.get(self.weather)


# Se você correr 10 quilômetros em 42 minutos e 42 segundos, qual é o seu passo médio?
# Passo médio = tempo por milha em minutos e segundos.
# Qual é a sua velocidade média em milhas por hora?
# 10 quilômetros = 6 milhas = 2562 segundos
tempo = 2562 / 6
minuto = tempo // 60
segundo = tempo % 60
print(f'O tempo por milha é de {minuto} minutos e {segundo} segundos')


from math import sqrt, ceil, floor
import random
import itertools
import functools
import operator
import collections
from fractions import Fraction

def subsequences(iterable, length):
    '''
    >>> [''.join(seq) for seq in subsequences("Hello world!", 10)]
    ['Hello worl', 'ello world', 'llo world!']
    '''
    yield from zip(*[iterable[start:] for start in range(length)])

def product(iterable):
    '''
    >>> product([3, 3, 5])
    45
    '''
    return functools.reduce(operator.mul, iterable, 1)

def prime_sieve(n):
    '''
    >>> g = prime_sieve(100)
    >>> [next(g) for _ in range(5)]
    [2, 3, 5, 7, 11]
    '''
    sieve = [True] * int(n+1) # this is not identical to a list comprehension!
    sieve[0] = sieve[1] = False
    for p in (p for p, is_prime in enumerate(sieve) if is_prime):
        if p**2 < n: sieve[2*p::p] = [False] * int(n/p-1)
        yield p

@functools.lru_cache(maxsize=None)
def is_prime(n, k=5):
    '''
    Miller-Rabin probabilistic primality test.
    Credit to Anuvrat Singh for original

    A return value of False means n is certainly not prime.
    A return value of True means n is very likely a prime.
    Larger k means more rigorous testing.

    >>> is_prime(32416190071)
    True
    '''
    # some obvious cases
    if n <= 1:      return False
    if n == 2:      return True
    if n % 2 == 0:  return False

    # find combination that fulfills: n-1 == d * 2**s
    s = next(s for s in range(n-1) if (n-1)/2**s%2)
    d = (n-1) // 2**s

    # if base a is witness to n, n is definitely composite
    def witness(a, d, n, s):
        A =  pow(a, d, n) == 1
        B = (pow(a, 2 ** i * d, n) == n - 1 for i in range(s))
        return not A and not any(B)

    # check for witnesses based on rigor criterion
    sample = (random.randrange(2, n) for i in range(k))
    return not any(witness(a, d, n, s) for a in sample)

def convergents(chain):
    '''
    >>> g = convergents([1, 2])
    >>> [next(g) for _ in range(4)][1:]
    [Fraction(3, 2), Fraction(7, 5), Fraction(17, 12)]
    '''
    first, *rest = chain
    repeating = itertools.cycle(rest)
    f = Fraction(first)
    m = next(repeating)
    fn = Fraction(1 + f*m, m)
    for m in repeating:
        yield f
        n = f.numerator   + m * fn.numerator
        d = f.denominator + m * fn.denominator
        f, fn = fn, Fraction(n, d)

def cfrac(S):
    '''
    >>> cfrac(7)
    [2, 1, 1, 1, 4]
    '''
    alist = []
    seen = set()
    m = m0 = 0
    d = d0 = 1
    a = a0 = floor(sqrt(S))
    if a0**2 == S: return [a0]
    while (m, d, a) not in seen:
        seen.update({(m, d, a)})
        alist.append(a)
        m = d*a - m
        d = ( S - m**2 ) // d
        a = ( a0 + m ) // d
    return alist

if __name__ == '__main__':
    import doctest
    doctest.testmod()


import tensorflow as tf

def make_pipe(pref, fst_slab, nth_slab, dropout, config, reducer, m, h, fcname = "FC", fczname = "FCZ", default_reuse = None):
    main = tf.layers.dropout(
        tf.nn.relu(
            tf.layers.dense(
                fst_slab(),
                h,
                name = (fcname + pref),
                reuse = default_reuse,
                kernel_initializer=tf.contrib.layers.variance_scaling_initializer()
            )),
            dropout
    )

    outns = list()
    reuse=default_reuse
    for n in range(m):
        print(nth_slab(n).shape)
        outns.append(
            tf.layers.dropout(
                tf.nn.relu(
                    tf.layers.dense(
                        nth_slab(n),
                        h,
                        name = (fczname + pref),
                        reuse = reuse,
                        kernel_initializer=tf.contrib.layers.variance_scaling_initializer()
                    )),
                dropout
            )
        )
        reuse=True
    pool = reducer(outns, pref)
    #print(pool.shape)
    return (main, pool)


import numpy as np
from scipy import signal

# Below is a implementation of "Lucas-Kanade Optical Flow algorithm"

# input 2 images as sequence, output sparse motion field (U, V)
# window_size is the size that assume to have "convservation of pixels"
# i.e. the total strength of pixels don't change in that windows,
# which is a good approximation when scale of motion is small related to the window size.

# window_size >= 3 is better. (too large will cause computation slow)
def SparseMoField(I1, I2, window_size, tau=1e-2):

    kernel_x = np.array([[-1., 1.],
                        [-1., 1.]])
    kernel_y = np.array([[-1., -1.],
                        [1., 1.]])
    kernel_t = np.array([[1., 1.],
                         [1., 1.]])#*.25

    w = (int)(window_size/2)  # window_size is odd, all the pixels with offset in between [-w, w] are inside the window
    I1 = I1 / 255. # normalize pixels
    I2 = I2 / 255. # normalize pixels

    # for each point, calculate I_x, I_y, I_t
    mode = 'same'
    fx = signal.convolve2d(I1, kernel_x, boundary='symm', mode=mode)
    fy = signal.convolve2d(I1, kernel_y, boundary='symm', mode=mode)
    ft = signal.convolve2d(I2, kernel_t, boundary='symm', mode=mode) + \
        signal.convolve2d(I1, -kernel_t, boundary='symm', mode=mode)
    U = np.zeros(I1.shape)
    V = np.zeros(I1.shape)

    # within window window_size * window_size
    for i in range(w, I1.shape[0]-w):
        for j in range(w, I1.shape[1]-w):
            if(I1[i, j] == 1):
                Ix = fx[i-w:i+w+1, j-w:j+w+1].flatten()
                Iy = fy[i-w:i+w+1, j-w:j+w+1].flatten()
                It = ft[i-w:i+w+1, j-w:j+w+1].flatten()

                b = np.reshape(It, (It.shape[0],1)) # get b here
                A = np.vstack((Ix, Iy)).T # get A here

                # if threshold τ is larger than the smallest eigenvalue of A'A, get velocity
                if np.min(abs(np.linalg.eigvals(np.matmul(A.T, A)))) >= tau:
                    nu = np.matmul(np.linalg.pinv(A), b) # get velocity here. pinv(A) means pseudo inverse = (A'A)^(-1) A'
                    U[i,j] = nu[0]
                    V[i,j] = nu[1]

    return (U,V)

2021S - Digital Image Processing/term-project/motion-approach/sparse_motion_field.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Core scripts for the OrcaNet package.
"""

import os
import toml
import warnings
import time
from datetime import timedelta
import keras as ks

import orcanet.backend as backend
from orcanet.utilities.visualization import update_summary_plot
from orcanet.in_out import IOHandler
from orcanet.history import HistoryHandler
from orcanet.utilities.nn_utilities import load_zero_center_data, get_auto_label_modifier
import orcanet.logging as olog

class Organizer:
    """
    Core class for working with networks in OrcaNet.

    Attributes
    ----------
    cfg : Configuration
        Contains all configurable options.
    io : orcanet.in_out.IOHandler
        Utility functions for accessing the info in cfg.
    history : orcanet.in_out.HistoryHandler
        For reading and plotting data from the log files created
        during training.

    """
    def __init__(self, output_folder,
                 list_file=None,
                 config_file=None,
                 tf_log_level=None):
        """
        Set the attributes of the Configuration object.

        Instead of using a config_file, the attributes of orga.cfg can
        also be changed directly, e.g. by calling orga.cfg.batchsize.

        Parameters
        ----------
        output_folder : str
            Name of the folder of this model in which everything will be saved,
            e.g., the summary.txt log file is located in here.
            Will be used to load saved files or to save new ones.
        list_file : str, optional
            Path to a toml list file with pathes to all the h5 files that should
            be used for training and validation.
            Will be used to extract samples and labels.
        config_file : str, optional
            Path to a toml config file with settings that are used instead of
            the default ones.
        tf_log_level : int/str
            Sets the TensorFlow CPP_MIN_LOG_LEVEL environment variable.
            0 = all messages are logged (default behavior).
            1 = INFO messages are not printed.
            2 = INFO and WARNING messages are not printed.
            3 = INFO, WARNING, and ERROR messages are not printed.

        """
        if tf_log_level is not None:
            os.environ['TF_CPP_MIN_LOG_LEVEL'] = str(tf_log_level)

        self.cfg = Configuration(output_folder, list_file, config_file)
        self.io = IOHandler(self.cfg)
        self.history = HistoryHandler(output_folder)

        self.xs_mean = None
        self._auto_label_modifier = None
        self._stored_model = None

    def train_and_validate(self, model=None, epochs=None):
        """
        Train a model and validate according to schedule.

        The various settings of this process can be controlled with the
        attributes of orca.cfg.
        The model will be trained on the given data, saved and validated.
        Logfiles of the training are saved in the output folder.
        Plots showing the training and validation history, as well as
        the weights and activations of the network are generated in
        the plots subfolder after every validation.
        The training can be resumed by executing this function again.

        Parameters
        ----------
        model : ks.models.Model or str, optional
            Compiled keras model to use for training. Required for the first
            epoch (the start of training).
            Can also be the path to a saved keras model, which will be laoded.
            If model is None, the most recent saved model will be
            loaded automatically to continue the training.
        epochs : int, optional
            How many epochs should be trained by running this function.
            None for infinite.

        Returns
        -------
        model : ks.models.Model
            The trained keras model.

        """
        latest_epoch = self.io.get_latest_epoch()

        model = self._get_model(model, logging=False)
        self._stored_model = model

        # check if the validation is missing for the latest fileno
        if latest_epoch is not None:
            state = self.history.get_state()[-1]
            if state["is_validated"] is False and self.val_is_due(latest_epoch):
                self.validate()

        next_epoch = self.io.get_next_epoch(latest_epoch)
        n_train_files = self.io.get_no_of_files("train")

        trained_epochs = 0
        while epochs is None or trained_epochs < epochs:
            # Train on remaining files
            for file_no in range(next_epoch[1], n_train_files + 1):
                curr_epoch = (next_epoch[0], file_no)
                self.train(model)
                if self.val_is_due(curr_epoch):
                    self.validate()

            next_epoch = (next_epoch[0] + 1, 1)
            trained_epochs += 1

        self._stored_model = None
        return model

    def train(self, model=None):
        """
        Trains a model on the next file.

        The progress of the training is also logged and plotted.

        Parameters
        ----------
        model : ks.models.Model or str, optional
            Compiled keras model to use for training. Required for the first
            epoch (the start of training).
            Can also be the path to a saved keras model, which will be laoded.
            If model is None, the most recent saved model will be
            loaded automatically to continue the training.

        Returns
        -------
        history : dict
            The history of the training on this file. A record of training
            loss values and metrics values.

        """
        # Create folder structure
        self.io.get_subfolder(create=True)
        latest_epoch = self.io.get_latest_epoch()

        model = self._get_model(model, logging=True)

        self._set_up(model, logging=True)

        # epoch about to be trained
        next_epoch = self.io.get_next_epoch(latest_epoch)
        next_epoch_float = self.io.get_epoch_float(*next_epoch)

        if latest_epoch is None:
            self.io.check_connections(model)
            olog.log_start_training(self)

        model_path = self.io.get_model_path(*next_epoch)
        model_path_local = self.io.get_model_path(*next_epoch, local=True)
        if os.path.isfile(model_path):
            raise FileExistsError(
                "Can not train model in epoch {} file {}, this model has "
                "already been saved!".format(*next_epoch))

        smry_logger = olog.SummaryLogger(self, model)

        lr = self.io.get_learning_rate(next_epoch)
        ks.backend.set_value(model.optimizer.lr, lr)

        files_dict = self.io.get_file("train", next_epoch[1])

        line = "Training in epoch {} on file {}/{}".format(
            next_epoch[0], next_epoch[1], self.io.get_no_of_files("train"))
        self.io.print_log(line)
        self.io.print_log("-" * len(line))
        self.io.print_log("Learning rate is at {}".format(
            ks.backend.get_value(model.optimizer.lr)))
        self.io.print_log('Inputs and files:')
        for input_name, input_file in files_dict.items():
            self.io.print_log("   {}: \t{}".format(input_name,
                                                   os.path.basename(
                                                       input_file)))

        start_time = time.time()
        history = backend.train_model(self, model, next_epoch, batch_logger=True)
        elapsed_s = int(time.time() - start_time)

        model.save(model_path)
        smry_logger.write_line(next_epoch_float, lr, history_train=history)

        self.io.print_log('Training results:')
        for metric_name, loss in history.items():
            self.io.print_log("   {}: \t{}".format(metric_name, loss))
        self.io.print_log("Elapsed time: {}".format(timedelta(seconds=elapsed_s)))
        self.io.print_log("Saved model to: {}\n".format(model_path_local))

        update_summary_plot(self)
        if self.cfg.cleanup_models:
            self.cleanup_models()

        return history

    def validate(self, make_weight_plots=True):
        """
        Validate the most recent saved model on all validation files.

        Will also log the progress, as well as update the summary plot and
        plot weights and activations of the model.

        Returns
        -------
        history : dict
            The history of the validation on all files. A record of validation
            loss values and metrics values.
        make_weight_plots : bool
            If true, generate and save plots of the activations and weights of
            the network to the 'plots/' subfolder.

        """
        latest_epoch = self.io.get_latest_epoch()
        if latest_epoch is None:
            raise ValueError("Can not validate: No saved model found")
        if self.history.get_state()[-1]["is_validated"] is True:
            raise ValueError("Can not validate in epoch {} file {}: "
                             "Has already been validated".format(*latest_epoch))

        if self._stored_model is None:
            model = self.load_saved_model(*latest_epoch)
        else:
            model = self._stored_model

        self._set_up(model, logging=True)

        epoch_float = self.io.get_epoch_float(*latest_epoch)
        smry_logger = olog.SummaryLogger(self, model)

        olog.log_start_validation(self)

        start_time = time.time()
        history = backend.validate_model(self, model)
        elapsed_s = int(time.time() - start_time)

        self.io.print_log('Validation results:')
        for metric_name, loss in history.items():
            self.io.print_log(f"   {metric_name}: \t{loss}")
        self.io.print_log(f"Elapsed time: {timedelta(seconds=elapsed_s)}\n")
        smry_logger.write_line(epoch_float, "n/a", history_val=history)

        update_summary_plot(self)
        if make_weight_plots:
            backend.save_actv_wghts_plot(
                self, model, latest_epoch, samples=self.cfg.batchsize)

        if self.cfg.cleanup_models:
            self.cleanup_models()

        return history

    def predict(self, epoch=None, fileno=None, concatenate=False):
        """
        Make a prediction if it does not exist yet, and return its filepath.

        Load the model with the lowest validation loss, let it predict on
        all samples of the validation set
        in the toml list, and save this prediction together with all the
        y_values as a h5 file in the predictions subfolder.

        Parameters
        ----------
        epoch : int, optional
            Epoch of a model to load.
        fileno : int, optional
            File number of a model to load.
        concatenate : bool
            Whether the prediction files should also be concatenated.

        Returns
        -------
        pred_filename : List
            List to the paths of all created prediction files.
            If concatenate = True, the list always only contains the
            path to the concatenated prediction file.

        """
        if fileno is None and epoch is None:
            epoch, fileno = self.history.get_best_epoch_fileno()
            print(f"Automatically set epoch to epoch {epoch} file {fileno}.")
        elif fileno is None or epoch is None:
            raise ValueError(
                "Either both or none of epoch and fileno must be None")

        is_pred_done = self._check_if_pred_already_done(epoch, fileno)
        if is_pred_done:
            print("Prediction has already been done.")
            pred_filepaths = self.io.get_pred_files_list(epoch, fileno)

        else:
            model = self.load_saved_model(epoch, fileno, logging=False)
            self._set_up(model)

            start_time = time.time()
            backend.make_model_prediction(self, model, epoch, fileno)
            elapsed_s = int(time.time() - start_time)
            print('Finished predicting on all validation files.')
            print("Elapsed time: {}\n".format(timedelta(seconds=elapsed_s)))

            pred_filepaths = self.io.get_pred_files_list(epoch, fileno)

        # concatenate all prediction files if wished
        concatenated_folder = self.io.get_subfolder("predictions") + '/concatenated'
        n_val_files = self.io.get_no_of_files("val")
        if concatenate is True and n_val_files > 1:
            if not os.path.isdir(concatenated_folder):
                print('Concatenating all prediction files to a single one.')
                pred_filename_conc = self.io.concatenate_pred_files(concatenated_folder)
                pred_filepaths = [pred_filename_conc]
            else:
                # omit directories if there are any in the concatenated folder
                fname_conc_file_list = list(file for file in os.listdir(concatenated_folder)
                                            if os.path.isfile(os.path.join(concatenated_folder,
                                                                           file)))
                pred_filepaths = [concatenated_folder + '/' + fname_conc_file_list[0]]

        return pred_filepaths

    def inference(self, epoch=None, fileno=None):
        """
        Make an inference and return the filepaths.

        Load the model with the lowest validation loss, let
        it predict on all samples of the inference set
        in the toml list, and save this prediction as a h5 file in the
        predictions subfolder. y values will only be added if they are in
        the input file, so this can be used on un-labelled data as well.

        Parameters
        ----------
        epoch : int, optional
            Epoch of a model to load.
        fileno : int, optional
            File number of a model to load.

        Returns
        -------
        filenames : list
            List to the paths of all created output files.

        """
        if fileno is None and epoch is None:
            epoch, fileno = self.history.get_best_epoch_fileno()
            print("Automatically set epoch to epoch {} file {}.".format(epoch, fileno))
        elif fileno is None or epoch is None:
            raise ValueError(
                "Either both or none of epoch and fileno must be None")

        model = self.load_saved_model(epoch, fileno, logging=False)
        self._set_up(model)

        filenames = []
        for files_dict in self.io.yield_files("inference"):
            # output filename is based on name of file in first input
            first_filename = os.path.basename(list(files_dict.values())[0])
            output_filename = "model_epoch_{}_file_{}_on_{}".format(
                epoch, fileno, first_filename)

            output_path = os.path.join(self.io.get_subfolder("predictions"),
                                       output_filename)
            filenames.append(output_path)
            if os.path.exists(output_path):
                warnings.warn("Warning: {} exists already, skipping "
                              "file".format(output_filename))
                continue

            start_time = time.time()
            backend.h5_inference(
                self, model, files_dict, output_path, use_def_label=False)
            elapsed_s = int(time.time() - start_time)
            print('Finished on file {} in {}'.format(
                first_filename, timedelta(seconds=elapsed_s)))

        return filenames

    def cleanup_models(self):
        """
        Delete all models except for the the most recent one (to continue
        training), and the ones with the highest and lowest loss/metrics.

        """
        all_epochs = self.io.get_all_epochs()
        epochs_to_keep = {self.io.get_latest_epoch(), }
        try:
            for metric in self.history.get_metrics():
                epochs_to_keep.add(
                    self.history.get_best_epoch_fileno(
                        metric=f"val_{metric}", mini=True))
                epochs_to_keep.add(
                    self.history.get_best_epoch_fileno(
                        metric=f"val_{metric}", mini=False))
        except ValueError:
            # no best epoch exists
            pass

        for epoch in epochs_to_keep:
            if epoch not in all_epochs:
                warnings.warn(
                    f"ERROR: keeping_epoch {epoch} not in available epochs {all_epochs}, "
                    f"skipping clean-up of models!")
                return

        print("\nClean-up saved models:")
        for epoch in all_epochs:
            model_path = self.io.get_model_path(epoch[0], epoch[1])
            model_name = os.path.basename(model_path)
            if epoch in epochs_to_keep:
                print("Keeping model {}".format(model_name))
            else:
                print("Deleting model {}".format(model_name))
                os.remove(model_path)

    def _check_if_pred_already_done(self, epoch, fileno):
        """
        Checks if the prediction has already been done before.
        (-> predicted on all validation files)

        Returns
        -------
        pred_done : bool
            Boolean flag to specify if the prediction has
            already been fully done or not.

        """
        latest_pred_file_no = self.io.get_latest_prediction_file_no(epoch, fileno)
        total_no_of_val_files = self.io.get_no_of_files('val')

        if latest_pred_file_no is None:
            pred_done = False
        elif latest_pred_file_no == total_no_of_val_files:
            return True
        else:
            pred_done = False

        return pred_done

    def get_xs_mean(self, logging=False):
        """
        Set and return the zero center image for each list input.

        Requires the cfg.zero_center_folder to be set. If no existing
        image for the given input files is found in the folder, it will
        be calculated and saved by averaging over all samples in the
        train dataset.

        Parameters
        ----------
        logging : bool
            If true, the execution of this function will be logged into the
            full summary in the output folder if called for the first time.

        Returns
        -------
        dict
            Dict of numpy arrays that contains the mean_image of the x dataset
            (1 array per list input).
            Example format:
            { "input_A" : ndarray, "input_B" : ndarray }

        """
        if self.xs_mean is None:
            if self.cfg.zero_center_folder is None:
                raise ValueError("Can not calculate zero center: "
                                 "No zero center folder given")
            self.xs_mean = load_zero_center_data(self, logging=logging)
        return self.xs_mean

    def load_saved_model(self, epoch, fileno, logging=False):
        """
        Load a saved model.

        Parameters
        ----------
        epoch : int
            Epoch of the saved model.
        fileno : int
            Fileno of the saved model.
        logging : bool
            If True, will log this function call into the log.txt file.

        Returns
        -------
        model : keras model

        """
        path_of_model = self.io.get_model_path(epoch, fileno)
        path_loc = self.io.get_model_path(epoch, fileno, local=True)
        self.io.print_log("Loading saved model: " + path_loc, logging=logging)
        model = ks.models.load_model(
            path_of_model, custom_objects=self.cfg.custom_objects)
        return model

    def _get_model(self, model, logging=False):
        """ Load most recent saved model or use user model. """
        latest_epoch = self.io.get_latest_epoch()

        if latest_epoch is None:
            # new training, log info about model
            if model is None:
                raise ValueError("You need to provide a compiled keras model "
                                 "for the start of the training! (You gave None)")

            elif isinstance(model, str):
                # path to a saved model
                self.io.print_log("Loading model from " + model, logging=logging)
                model = ks.models.load_model(model)

            if logging:
                self._save_as_json(model)
                model.summary(print_fn=self.io.print_log)

                try:
                    plots_folder = self.io.get_subfolder("plots", create=True)
                    ks.utils.plot_model(model, plots_folder + "/model_plot.png")
                except OSError as e:
                    warnings.warn("Can not plot model: " + str(e))

        else:
            # resuming training, load model if it is not given
            if model is None:
                model = self.load_saved_model(*latest_epoch, logging=logging)

            elif isinstance(model, str):
                # path to a saved model
                self.io.print_log("Loading model from " + model, logging=logging)
                model = ks.models.load_model(model)

        return model

    def _save_as_json(self, model):
        """ Save the architecture of a model as json to fixed path. """
        json_filename = "model_arch.json"

        json_string = model.to_json(indent=1)
        model_folder = self.io.get_subfolder("saved_models", create=True)
        with open(os.path.join(model_folder, json_filename), "w") as f:
            f.write(json_string)

    def _set_up(self, model, logging=False):
        """ Necessary setup for training, validating and predicting. """
        if self.cfg.get_list_file() is None:
            raise ValueError("No files specified. Need to load a toml "
                             "list file with pathes to h5 files first.")

        if self.cfg.label_modifier is None:
            self._auto_label_modifier = get_auto_label_modifier(model)

        if self.cfg.zero_center_folder is not None:
            self.get_xs_mean(logging)

    def val_is_due(self, epoch=None):
        """
        True if validation is due on given epoch according to schedule.
        Does not check if it has been done already.

        """
        if epoch is None:
            epoch = self.io.get_latest_epoch()
        n_train_files = self.io.get_no_of_files("train")
        val_sched = (epoch[1] == n_train_files) or \
                    (self.cfg.validate_interval is not None and
                     epoch[1] % self.cfg.validate_interval == 0)
        return val_sched

class Configuration(object):
    """
    Contains all the configurable options in the OrcaNet scripts.

    All of these public attributes (the ones without a
    leading underscore) can be changed either directly or with a
    .toml config file via the method update_config().

    Attributes
    ----------
    batchsize : int
        Batchsize that will be used for the training and validation of
        the network.
    callback_train : keras callback or list or None
        Callback or list of callbacks to use during training.
    class_weight : dict or None
        class_weigth argument of fit_generator:
        Optional dictionary mapping class indices (integers) to a weight
        (float) value, used for weighting the loss function (during
        training only). This can be useful to tell the model to
        "pay more attention" to samples from an under-represented class.
    cleanup_models : bool
        If true, will only keep the best (in terms of val loss) and the most
        recent from all saved models in order to save disk space.
    custom_objects : dict or None
        Optional dictionary mapping names (strings) to custom classes or
        functions to be considered by keras during deserialization of models.
    dataset_modifier : function or None
        For orga.predict: Function that determines which datasets get created
        in the resulting h5 file. If none, every output layer will get one
        dataset each for both the label and the prediction, and one dataset
        containing the y_values from the validation files.
    key_x_values : str
        The name of the datagroup in the h5 input files which contains
        the samples for the network.
    key_y_values : str
        The name of the datagroup in the h5 input files which contains
        the info for the labels.
    label_modifier : function or None
        Operation to be performed on batches of y_values read from the input
        files before they are fed into the model as labels. If None is given,
        all y_values with the same name as the output layers will be passed
        to the model as a dict, with the keys being the dtype names.
    learning_rate : float, tuple, function or str
        The learning rate for the training.
        If it is a float: The learning rate will be constantly this value.
        If it is a tuple of two floats: The first float gives the learning rate
        in epoch 1 file 1, and the second float gives the decrease of the
        learning rate per file (e.g. 0.1 for 10% decrease per file).
        If it is a function: Takes as an input the epoch and the
        file number (in this order), and returns the learning rate.
        If it is a str: Path to a csv file inside the main folder, containing
        3 columns with the epoch, fileno, and the value the lr will be set
        to when reaching this epoch/fileno.
    max_queue_size : int
        max_queue_size option of the keras training and evaluation generator
        methods. How many batches get preloaded
        from the generator.
    n_events : None or int
        For testing purposes. If not the whole .h5 file should be used for
        training, define the number of samples.
    sample_modifier : function or None
        Operation to be performed on batches of x_values read from the input
        files before they are fed into the model as samples.
    shuffle_train : bool
        If true, the order in which batches are read out from the files during
        training are randomized each time they are read out.
    train_logger_display : int
        How many batches should be averaged for one line in the training log files.
    train_logger_flush : int
        After how many lines the training log file should be flushed (updated on
        the disk). -1 for flush at the end of the file only.
    output_folder : str
        Name of the folder of this model in which everything will be saved,
        e.g., the summary.txt log file is located in here.
    use_scratch_ssd : bool
        Only working at HPC Erlangen: Declares if the input files should be
        copied to the node-local SSD scratch space.
    validate_interval : int or None
        Validate the model after this many training files have been trained on
        in an epoch. There will always be a validation at the end of an epoch.
        None for only validate at the end of an epoch.
        Example: validate_interval=3 --> Validate after file 3, 6, 9, ...
    verbose_train : int
        verbose option of keras.model.fit_generator.
        0 = silent, 1 = progress bar, 2 = one line per epoch.
    verbose_val : int
        verbose option of evaluate_generator.
        0 = silent, 1 = progress bar.
    zero_center_folder : None or str
        Path to a folder in which zero centering images are stored.
        If this path is set, zero centering images for the given dataset will
        either be calculated and saved automatically at the start of the
        training, or loaded if they have been saved before.

    """
    # TODO add a clober script that properly deletes models + logfiles
    def __init__(self, output_folder, list_file=None, config_file=None, **kwargs):
        """
        Set the attributes of the Configuration object.

        Values are loaded from the given files, if provided. Otherwise, default
        values are used.

        Parameters
        ----------
        output_folder : str
            Name of the folder of this model in which everything will be saved,
            e.g., the summary.txt log file is located in here.
        list_file : str or None
            Path to a toml list file with pathes to all the h5 files that should
            be used for training and validation.
        config_file : str or None
            Path to a toml config file with attributes that are used instead of
            the default ones.
        kwargs
            Overwrites the values given in the config file.

        """
        self.batchsize = 64
        self.learning_rate = 0.001

        self.zero_center_folder = None
        self.validate_interval = None
        self.cleanup_models = False
        self.class_weight = None

        self.sample_modifier = None
        self.dataset_modifier = None
        self.label_modifier = None

        self.key_x_values = "x"
        self.key_y_values = "y"
        self.custom_objects = None
        self.shuffle_train = False

        self.callback_train = None
        self.use_scratch_ssd = False
        self.verbose_train = 1
        self.verbose_val = 0

        self.n_events = None
        self.max_queue_size = 10
        self.train_logger_display = 100
        self.train_logger_flush = -1

        self._default_values = dict(self.__dict__)

        # Main folder:
        if output_folder[-1] == "/":
            self.output_folder = output_folder
        else:
            self.output_folder = output_folder+"/"

        # Private attributes:
        self._files_dict = {
            "train": None,
            "val": None,
            "inference": None,
        }
        self._list_file = None

        # Load the optionally given list and config files.
        if list_file is not None:
            self.import_list_file(list_file)
        if config_file is not None:
            self.update_config(config_file)

        # set given kwargs:
        for key, val in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, val)
            else:
                raise AttributeError(
                    "Unknown attribute {}".format(key))

    def import_list_file(self, list_file):
        """
        Import the filepaths of the h5 files from a toml list file.

        Parameters
        ----------
        list_file : str
            Path to the toml list file.

        """
        if self._list_file is not None:
            raise ValueError("Can not load list file: Has already been loaded! "
                             "({})".format(self._list_file))

        file_content = toml.load(list_file)

        name_mapping = {
            "train_files": "train",
            "validation_files": "val",
            "inference_files": "inference",
        }

        for toml_name, files_dict_name in name_mapping.items():
            files = self._extract_filepaths(file_content, toml_name)
            self._files_dict[files_dict_name] = files or None

        self._list_file = list_file

    @staticmethod
    def _extract_filepaths(file_content, which):
        """
        Get train/val/inf filepaths for different inputs from a toml readout.
        Makes sure that all input have the same number of files.

        """
        allowed_which = ["train_files", "validation_files", "inference_files"]
        assert which in allowed_which

        files = {}
        n_files = []
        for input_key, input_values in file_content.items():
            for key in input_values.keys():
                if key not in allowed_which:
                    raise NameError(
                        f"Unknown argument '{key}' in toml file: "
                        f"Must be either of {allowed_which}")

            if which in input_values:
                files_input = tuple(input_values[which])
                files[input_key] = files_input
                n_files.append(len(files_input))

        if n_files and n_files.count(n_files[0]) != len(n_files):
            raise ValueError(
                "Input with different number of {} in toml list".format(which))

        return files

    def update_config(self, config_file):
        """
        Update the default cfg parameters with values from a toml config file.

        Parameters
        ----------
        config_file : str
            Path to a toml config file.

        """
        user_values = toml.load(config_file)["config"]
        for key in user_values:
            if hasattr(self, key):
                setattr(self, key, user_values[key])
            else:
                raise AttributeError(
                    "Unknown attribute {} in config file ".format(key))

    def get_list_file(self):
        """
        Returns the path to the list file that was used to set the training
        and validation files. None if no list file has been used.

        """
        return self._list_file

    def get_files(self, which):
        """
        Get the training or validation file paths for each list input set.

        Parameters
        ----------
        which : str
            Either "train", "val" or "inference".

        Returns
        -------
        dict
            A dict containing the paths to the training or validation files on
            which the model will be trained on. Example for the format for
            two input sets with two files each:
                    {
                     "input_A" : ('path/to/set_A_file_1.h5', 'path/to/set_A_file_2.h5'),
                     "input_B" : ('path/to/set_B_file_1.h5', 'path/to/set_B_file_2.h5'),
                    }

        """
        if which not in self._files_dict.keys():
            raise NameError("Unknown fileset name ", which)
        if self._files_dict[which] is None:
            raise AttributeError("No {} files have been specified!".format(which))
        return self._files_dict[which]

    @property
    def default_values(self):
        """ The default values for all settings. """
        return self._default_values

    @property
    def key_samples(self):
        """ Backward compatibility """
        return self.key_x_values

    @property
    def key_labels(self):
        """ Backward compatibility """
        return self.key_y_values


# 预测图片存放位置
PREDICT_IMG_DATA_PATH = './experiments/experiment1/data/images'

CLASSES = ['background',
           'aeroplane', 'bicycle', 'bird', 'boat',
           'bottle', 'bus', 'car', 'cat', 'chair',
           'cow', 'diningtable', 'dog', 'horse',
           'motorbike', 'person', 'pottedplant',
           'sheep', 'sofa', 'train', 'tvmonitor']
# 是否需要将结果写入txt
TXT_RESULT_WANTED = False

# txt结果保存路径
TXT_RESULT_PATH = './experiments/experiment1/result/txt_result'

# 是否可视化结果
IS_VISIBLE = True

# 结果可视化图保存路径
IMAGE_RESULT_PATH = './experiments/experiment1/result/image_result'

# 模型参数保存路径
CHECKPOINTS_PATH = './experiments/experiment1/checkpoints'

# 训练迭代轮数
MAX_EPOCH = 5

# 图片归一化后的最大高度与宽度

RESIZED_IMAGE_SIZE = [600,800]
# 训练集中较难识别的目标是否参与训练
USE_DIFFICULT = False

# anchor的放大倍数，原始尺寸为16*16
ANCHOR_SCALES = [8, 16, 32]

# anchor的长宽比
ANCHOR_RATIOS = [0.5, 1.0, 2.0]

# 分类阶段输入的rois数目
BATCH_SIZE = 128

# 非背景比例
FG_FRACTION = 0.25

# 训练时，若当前ROI对应的概率大于0.5，认为它是前景
FG_THRESH = 0.5

# 类别确认阈值
CONF_THRESH = 0.7

# 区域检测阈值
NMS_THRESH = 0.3


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas.plotting import scatter_matrix
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
import seaborn as sns

column_names = ['X','Y','month','day','FFMC','DMC','DC','ISI','temp','RH', 'wind', 'rain', 'area']
dataset = pd.read_csv('forestfires.csv', names=column_names)

print(dataset.head())
dataset['Log-area'] = np.log10(dataset['area']+1)
print(dataset.describe())

### Univariate plots ###
#box and whisker plots
dataset.plot(kind='box', subplots=True, layout=(5,3), sharex=False, sharey=False)
#histogram
dataset.hist(bins = 50)

fig, axs = plt.subplots(1, 2, sharey=True, tight_layout=True)

# We can set the number of bins with the `bins` kwarg

axs[0].hist(dataset['area'], bins=40)

axs[0].set_title("Area")
axs[1].hist(dataset['Log-area'], bins=40)
plt.title("Log(Area + 1)")

### Multivariate plots ###
scatter_matrix(dataset)
sns.pairplot(dataset[["Log-area", "temp", "wind", "rain"]], diag_kind="kde")
plt.show()

for i in dataset.describe().columns[:-2]:
    dataset.plot.scatter(i, 'Log-area', grid=True)

plt.show()
plt.close()


def required(self, decorated_function=None, scopes=None,
                 **decorator_kwargs):
        """Decorator to require OAuth2 credentials for a view.

        If credentials are not available for the current user, then they will
        be redirected to the authorization flow. Once complete, the user will
        be redirected back to the original page.
        """

        def curry_wrapper(wrapped_function):
            @wraps(wrapped_function)
            def required_wrapper(*args, **kwargs):
                return_url = decorator_kwargs.pop('return_url', request.url)

                requested_scopes = set(self.scopes)
                if scopes is not None:
                    requested_scopes |= set(scopes)
                if self.has_credentials():
                    requested_scopes |= self.credentials.scopes

                requested_scopes = list(requested_scopes)

                # Does the user have credentials and does the credentials have
                # all of the needed scopes?
                if (self.has_credentials() and
                        self.credentials.has_scopes(requested_scopes)):
                    return wrapped_function(*args, **kwargs)
                # Otherwise, redirect to authorization
                else:
                    auth_url = self.authorize_url(
                        return_url,
                        scopes=requested_scopes,
                        **decorator_kwargs)

                    return redirect(auth_url)

            return required_wrapper

        if decorated_function:
            return curry_wrapper(decorated_function)
        else:
            return curry_wrapper


from fastapi import FastAPI
import os
import openai
from pydantic import BaseModel
from dotenv import load_dotenv

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = FastAPI()

class Details(BaseModel):
    report_description_url: str
    messages: list[dict[str, str]]

@app.get("/")
def root():
    return {'hello': "world"}

@app.post("/v1/assistants/response")
def assistant_response(details: Details):
    # https://www.expertmarketresearch.com/reports/detergent-grade-enzymes-market-asia-pacific

    rd_url = details.report_description_url
    messages = details.messages

    system_messages = [
        {"role": "system", "content": "You are a John."},
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "system", "content": "Be precise in answers."},
        {"role": "system", "content": f"Analyse {rd_url}"},
        {"role": "system", "content": "Competitors and key players are synonymous"},
        {"role": "system", "content": "often informing that this is only an overview."},
        {"role": "system", "content": "often informing that Complete and more Elaborate details are in full report."},
        {"role": "system", "content": "often remind full report contains more in-depth information."},
    ]
    messages = system_messages + messages
    response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=messages,
    )

    return {
        "status": "201",
        "response": {
            "role": "assistant",
            "content": response.choices[0].message.content, # type: ignore
        }
    }


n = int(input())
lst = []
# 입력값을 받아준다.
for _ in range(n):
    num = int(input())
    lst.append(num)
# 각 사람이 예상한 등수를 오름차순으로 정렬한다.
lst.sort()

# 랭크를 사람의 수만큼 만든다.(1등부터 N등까지 동석차 없이 등수를 매겨야)
rank = [i for i in range(1, n + 1)]

# 불만도 계산하기 위한 변수
complain = 0

# 랭크에서 각 사람이 예상한 등수를 빼면 불만도에 최소를 구할수있다.
# 문제에서 불만도는 A와 B의 차이 (|A - B|)로 수치화
for i in range(n):
    # 1-0 = 1, 1-1 = 0, 2-1 = 1, 4-3 = 1 5-5= 0 => 누적값 3
    complain += abs(rank[i] - lst[i])

print(complain)


import sys
from collections import defaultdict
sys.setrecursionlimit(10**6)
input = sys.stdin.readline

n, m = map(int, input().split())
cnt = 0
move = [(1, 0), (-1, 0), (0, 1), (0, -1)]
visited = [[0] * m for _ in range(n)]
maps = []
for _ in range(n):
    tmp = list(map(int, input().split()))
    cnt += tmp.count(1)
    maps.append(tmp)

def check(x, y, t):
    for dx, dy in move:
        nx = x + dx
        ny = y + dy

        if 0 <= nx < n and 0 <= ny < m:
            if visited[nx][ny] != t:
                if maps[nx][ny] == 1:
                    c[nx, ny] += 1
                    if c[nx, ny] == 2:
                        arr.add((nx, ny))
                else:
                    visited[nx][ny] = t
                    check(nx, ny, t)

ans = t = 0
while cnt:
    arr = set()
    c = defaultdict(int)
    t += 1
    visited[0][0] = t
    check(0, 0, t)
    cnt -= len(arr)
    for x, y in arr:
        maps[x][y] = 0

    ans += 1

print(ans)