import numpy as np
import pandas as pd

import data.spatial.municipalities
import data.spatial.quarters
import data.spatial.utils
import data.spatial.zones
import data.utils

def configure(context):
    context.config("data_path")
    context.stage("data.spatial.zones")
    context.stage("data.spatial.municipalities")
    context.stage("data.spatial.quarters")
    context.stage("data.spatial.nuts")
    context.stage("data.spatial.postal_codes")

def execute(context):
    data_path = context.config("data_path")

    df = pd.DataFrame(pd.read_csv(
        "%s/statent/QUERY_FOR_2014_DEC_STATENT_LOC.csv" % data_path,
        encoding = "latin1", sep = ";"))

    df = pd.DataFrame(df[["METER_X", "METER_Y", "NOGA08", "EMPTOT"]])
    df.columns = ["x", "y", "noga", "number_employees"]
    df.loc[:, "noga"] = df["noga"].astype(np.str)
    df.loc[:, "enterprise_id"] = np.arange(len(df))

    df.loc[df["noga"].str.startswith("851"), "education_type"] = "kindergarten"
    df.loc[df["noga"].str.startswith("852"), "education_type"] = "primary"
    df.loc[df["noga"].str.startswith("853"), "education_type"] = "secondary"
    df.loc[df["noga"].str.startswith("854"), "education_type"] = "tertiary"
    df["education_type"] = df["education_type"].astype("category")

    # For now we don't do anything with the NOGA category.
    # (but need to do later for the education locations)

    # Impute zones
    df_zones = context.stage("data.spatial.zones")
    df_quarters = context.stage("data.spatial.quarters")
    df_municipalities = context.stage("data.spatial.municipalities")[0]
    df_nuts = context.stage("data.spatial.nuts")
    df_postal_codes = context.stage("data.spatial.postal_codes")

    df_spatial = pd.DataFrame(df[["enterprise_id", "x", "y"]])

    df_spatial = data.spatial.utils.to_gpd(context, df_spatial, "x", "y")
    df_spatial = df_spatial.drop(["x", "y"], axis=1)

    columns = ["enterprise_id"]

    # impute municipalities
    df_spatial = data.spatial.utils.impute(context, df_spatial, df_municipalities, "enterprise_id", "municipality_id")
    columns.extend(["municipality_id"])

    # impute quarters
    df_spatial = data.spatial.utils.impute(context, df_spatial, df_quarters, "enterprise_id", "quarter_id", fix_by_distance = False)
    columns.extend(["quarter_id"])

    # impute NUTS
    df_nuts = df_nuts[df_nuts["nuts_id"].str.contains("CH")]
    for level in df_nuts["nuts_level"].unique():
        df_spatial = data.spatial.utils.impute(context, df_spatial, df_nuts[df_nuts["nuts_level"] == level],
                                               "enterprise_id", "nuts_id", fix_by_distance=False).rename(
            {"nuts_id": ("nuts_id_level_" + str(level))}, axis=1)
        columns.extend([("nuts_id_level_" + str(level))])

    # impute postal codes
    df_spatial = data.spatial.utils.impute(context, df_spatial, df_postal_codes, "enterprise_id", "postal_code", fix_by_distance=False)
    columns.extend(["postal_code"])

    # clean up columns
    df_spatial = df_spatial[columns]

    # impute zones
    df_spatial = data.spatial.zones.impute(df_spatial, df_zones)

    assert(len(df) == len(df_spatial))
    assert(len(df_spatial) == len(df_spatial["zone_id"].dropna()))

    columns.extend(["zone_id"])

    df = pd.merge(
        df, df_spatial[columns],
        on = "enterprise_id"
    )
    df["zone_id"] = df["zone_id"].astype(np.int)

    return df


import numpy as np
import h5py
import sys
import matplotlib.pyplot as plt

class Map():
    def __init__(self, mapname):
        self.mapname = mapname
        self.field   = self.mapname.split("/")[-1]
        self.field   = self.field.split("_")[0]

    def read_map(self):
        with h5py.File(self.mapname, "r") as infile:
            self.feeds = infile["feeds"][()]
            self.freq  = infile["freq"][()]

            if np.all(self.freq == 0):
                self.freq = np.linspace(26, 34, 256)

            self.map   = infile["map"][()]
            self.nhit  = infile["nhit"][()]
            self.rms   = infile["rms"][()]

            # self.map   = infile["multisplits/map_elev"][()]
            # self.nhit  = infile["multisplits/nhit_elev"][()]
            # self.rms   = infile["multisplits/rms_elev"][()]

            # #idx = (0, 2) # Lissajous
            # idx = (1, 3)  # CES
            # self.map = self.map[idx, ...]
            # self.nhit = self.nhit[idx, ...]
            # self.rms = self.rms[idx, ...]

            # var_inv = np.where(self.nhit > 0, 1 / (self.rms ** 2), 0)

            # map = np.where(self.nhit > 0, self.map * var_inv, 0)

            # map = np.sum(map, axis = 0)

            # inv_var = np.sum(var_inv, axis = 0)

            # map = np.where(np.isnan(map / inv_var) == False, map / inv_var, 0)

            # self.map = map.copy()
            # # print(np.all(self.rms == 0))
            # # print(np.all(self.rms == 0))
            # self.nhit = np.sum(self.nhit, axis = 0).astype(np.int32)
            # self.rms = np.where(self.nhit > 0, 1 / np.sqrt(inv_var), 0)

            # #print(np.where(self.nhit != 0))
            # #fig, ax = plt.subplots(2, 2)
            # fig, ax = plt.subplots()
            # # ax[0, 0].imshow(self.nhit[0, 2, 2, 6, ...])
            # # ax[0, 1].imshow(self.nhit[1, 2, 2, 6, ...])
            # # ax[1, 0].imshow(self.nhit[2, 2, 2, 6, ...])
            # # ax[1, 1].imshow(self.nhit[3, 2, 2, 6, ...])
            # ax.imshow(self.rms[2, 2, 6, ...])
            # plt.show()
            # sys.exit()

            try:
                self.map_coadd   = infile["map_coadd"][()]
                self.nhit_coadd  = infile["nhit_coadd"][()]
                self.rms_coadd   = infile["rms_coadd"][()]
            except:
                self.map_coadd   = infile["map_beam"][()]
                self.nhit_coadd  = infile["nhit_beam"][()]
                self.rms_coadd   = infile["rms_beam"][()]

            self.mean_az = infile["mean_az"][()]
            self.mean_el = infile["mean_el"][()]
            self.n_x     = infile["n_x"][()]
            self.n_y     = infile["n_y"][()]

            try:
                self.nside   = infile["nside"][()]
                self.nsim    = infile["nsim"][()]
                self.nsplit  = infile["nsplit"][()]
                self.runID   = infile["runID"][()]
                self.patch_center = infile["patch_center"][()]
            except:
                self.nside   = 0
                self.nsim    = 0
                self.nsplit  = 0
                self.runID   = None
                self.patch_center = [None, None]

            self.time    = infile["time"][()]
            self.x       = infile["x"][()]
            self.y       = infile["y"][()]

        self.n_det, self.n_sb, self.n_freq = self.map.shape[:3]


from . import kinematics_constants as constants
import numpy as np
from scipy.spatial.transform import Rotation as R

class Node:
    '''A node in the tree data structure for storing all the possible inverse kinematics solutions.'''

    def __init__(self, angle):
        self.angle = angle
        self.children = []

    def add_child_node(self, angle):
        self.children.append(Node(angle))

    def add_child(self, child):
        self.children.append(child)

    def get_angle_combinations(self):
        '''Return all the possible combinations of joint angles for the given node and its children'''
        if not self.children:
            return [[self.angle]]
        combinations = []
        for child in self.children:
            child_combinations = child.get_angle_combinations()
            for combination in child_combinations:
                combinations.append([self.angle] + combination)
        return combinations

class Kinematics:
    '''Inverse kinematics for the NAO robot'''

    def __init__(self) -> None:
        # The thetas are stored in the order they are computed in the paper:
        # theta6, theta4, theta5, theta2, theta3, theta1
        # Here we initialise with the default standing commands
        self.left_leg_previous_joints = [0, 1.047, -0.524, 0, -0.524, 0]
        self.right_leg_previous_joints = [0, 1.047, -0.524, 0, -0.524, 0]

    @staticmethod
    def DH(a, alpha, d, theta):
        '''Return the Denavit-Hartenberg matrix for the given parameters'''
        return np.array([
            [np.cos(theta), -np.sin(theta), 0, a],
            [np.sin(theta) * np.cos(alpha), np.cos(theta) * np.cos(alpha), -np.sin(alpha), -d * np.sin(alpha)],
            [np.sin(theta) * np.sin(alpha), np.cos(theta) * np.sin(alpha), np.cos(alpha), d * np.cos(alpha)],
            [0, 0, 0, 1]
        ])

    @staticmethod
    def orientation_to_transform(orientation):
        '''Return the affine transform matrix for the given orientation'''
        T = np.eye(4)
        T[:3, :3] = R.from_euler('ZYX', orientation).as_matrix()
        return T

    @staticmethod
    def transform_to_orientation(T):
        '''Return the orientation from the given affine transform matrix'''
        roll = np.arctan2(T[2, 1], T[2, 2])
        pitch = np.arctan2(-T[2, 0], np.sqrt(T[2, 1]**2 + T[2, 2]**2))
        yaw = np.arctan2(T[1, 0], T[0, 0])
        return np.array([roll, pitch, yaw])

    @classmethod
    def position_and_orientation_to_transform(cls, position, orientation):
        '''Return the affine transform matrix for the desired position and orientation'''
        T = cls.orientation_to_transform(orientation)
        T[0:3, 3] = position
        return T

    @staticmethod
    def get_A_base_0(is_left):
        A_base_0 = np.eye(4)
        A_base_0[1, 3] = constants.HipOffsetY if is_left else -constants.HipOffsetY
        A_base_0[2, 3] = -constants.HipOffsetZ
        return A_base_0

    @classmethod
    def get_T_0_1(cls, theta_1, is_left):
        T_0_1 = cls.DH(0, -np.pi / 4 * 3 if is_left else 1, 0, theta_1 - np.pi / 2)
        return T_0_1

    @classmethod
    def get_T_1_2(cls, theta_2, is_left):
        T_1_2 = cls.DH(0, -np.pi / 2, 0, theta_2 + np.pi / 4 if is_left else -np.pi / 4)
        return T_1_2

    @classmethod
    def get_T_2_3(cls, theta_3):
        T_2_3 = cls.DH(-constants.ThighLength, 0, 0, theta_3)
        return T_2_3

    @classmethod
    def get_T_3_4(cls, theta_4):
        T_3_4 = cls.DH(-constants.ThighLength, 0, 0, theta_4)
        return T_3_4

    @classmethod
    def get_T_4_5(cls, theta_5):
        T_4_5 = cls.DH(-constants.TibiaLength, 0, 0, theta_5)
        return T_4_5

    @classmethod
    def get_T_5_6(cls, theta_6):
        T_5_6 = cls.DH(0, -np.pi / 2, 0, theta_6)
        return T_5_6

    @classmethod
    def get_Rot_zy(cls):
        Rot_zy = cls.orientation_to_transform([np.pi, -np.pi / 2, 0])
        return Rot_zy

    @staticmethod
    def get_A_6_end():
        A_6_end = np.eye(4)
        A_6_end[2, 3] = -constants.FootHeight
        return A_6_end

    @classmethod
    def forward_left_leg(cls, thetas):
        '''Return the position and orientation of the left foot for the given joint angles (forwards kinematics)'''
        A_base_0 = cls.get_A_base_0(True)
        T_0_1 = cls.get_T_0_1(thetas[0], True)
        T_1_2 = cls.get_T_1_2(thetas[1], True)
        T_2_3 = cls.get_T_2_3(thetas[2])
        T_3_4 = cls.get_T_3_4(thetas[3])
        T_4_5 = cls.get_T_4_5(thetas[4])
        T_5_6 = cls.get_T_5_6(thetas[5])
        Rot_zy = cls.get_Rot_zy()
        A_6_end = cls.get_A_6_end()
        T_base_end = A_base_0 @ T_0_1 @ T_1_2 @ T_2_3 @ T_3_4 @ T_4_5 @ T_5_6 @ Rot_zy @ A_6_end
        return np.concatenate((T_base_end[0:3, 3], cls.transform_to_orientation(T_base_end)))

    @classmethod
    def forward_right_leg(cls, thetas):
        '''Return the position and orientation of the right foot for the given joint angles (forwards kinematics)'''
        A_base_0 = cls.get_A_base_0(False)
        T_0_1 = cls.get_T_0_1(thetas[0], False)
        T_1_2 = cls.get_T_1_2(thetas[1], False)
        T_2_3 = cls.get_T_2_3(thetas[2])
        T_3_4 = cls.get_T_3_4(thetas[3])
        T_4_5 = cls.get_T_4_5(thetas[4])
        T_5_6 = cls.get_T_5_6(thetas[5])
        Rot_zy = cls.get_Rot_zy()
        A_6_end = cls.get_A_6_end()
        T_base_end = A_base_0 @ T_0_1 @ T_1_2 @ T_2_3 @ T_3_4 @ T_4_5 @ T_5_6 @ Rot_zy @ A_6_end
        return np.concatenate((T_base_end[0:3, 3], cls.transform_to_orientation(T_base_end)))

    def inverse_leg(self, x, y, z, roll, pitch, yaw, is_left):
        '''Return the joint angles for the desired position and orientation of the foot (inverse kinematics)'''
        global left_leg_previous_joints
        global right_leg_previous_joints

        # This does all the maths from the paper step-by-step (look at the paper if you are interested)
        T = self.position_and_orientation_to_transform([x, y, z], [yaw, pitch, roll])
        A_base_0 = self.get_A_base_0(is_left)
        A_6_end = self.get_A_6_end()
        T_hat = np.linalg.inv(A_base_0) @ T @ np.linalg.inv(A_6_end)
        # This angle offset depends on which leg we are doing the inverse kinematics
        plus_or_minus_pi_over_4 = np.pi / 4 if is_left else -np.pi / 4
        T_tilde = self.orientation_to_transform([0, 0, plus_or_minus_pi_over_4]) @ T_hat
        T_prime = np.linalg.inv(T_tilde)
        px_prime, py_prime, pz_prime = T_prime[0:3, 3]
        theta_6 = np.arctan(py_prime / pz_prime)
        solution_tree_root = Node(theta_6)
        d = np.linalg.norm([px_prime, py_prime, pz_prime])
        theta_4_double_prime = np.pi - np.arccos((constants.ThighLength**2 + constants.TibiaLength**2 - d**2)
                                                 / (2 * constants.ThighLength * constants.TibiaLength))
        for theta_4_test in [theta_4_double_prime, -theta_4_double_prime]:
            if constants.LKneePitchLow < theta_4_test < constants.LKneePitchHigh:
                solution_tree_root.add_child_node(theta_4_test)
        T_tilde_prime = T_tilde @ np.linalg.inv(self.get_T_5_6(theta_6) @ self.get_Rot_zy())
        T_double_prime = np.linalg.inv(T_tilde_prime)
        for theta_4_node in solution_tree_root.children:
            theta_4_test = theta_4_node.angle
            numerator = T_double_prime[1, 3] * (constants.TibiaLength + constants.ThighLength * np.cos(theta_4_test)) + \
                constants.ThighLength * T_double_prime[0, 3] * np.sin(theta_4_test)
            denominator = constants.ThighLength**2 * np.sin(theta_4_test)**2 \
                + (constants.TibiaLength + constants.ThighLength * np.cos(theta_4_test))**2
            theta_5_prime = np.arcsin(-numerator / denominator)
            for theta_5_test in [theta_5_prime, (np.pi if theta_5_prime >= 0 else -np.pi) - theta_5_prime]:
                if constants.LAnklePitchLow < theta_5_test < constants.LAnklePitchHigh:
                    theta_4_node.add_child_node(theta_5_test)
        for theta_4_node in solution_tree_root.children:
            for theta_5_node in theta_4_node.children:
                theta_4_test = theta_4_node.angle
                theta_5_test = theta_5_node.angle
                T_3_4 = self.get_T_3_4(theta_4_test)
                T_4_5 = self.get_T_4_5(theta_5_test)
                T_triple_prime = T_tilde_prime @ np.linalg.inv(T_3_4 @ T_4_5)
                theta_2_prime = np.arccos(T_triple_prime[1, 2])
                for theta_2_test in [theta_2_prime - plus_or_minus_pi_over_4, - theta_2_prime - plus_or_minus_pi_over_4]:
                    if constants.LHipRollLow < theta_2_test < constants.LHipRollHigh:
                        theta_2_node = Node(theta_2_test)
                    else:
                        continue
                    theta_3_prime = np.arcsin(T_triple_prime[1, 1] / np.sin(theta_2_test + plus_or_minus_pi_over_4))
                    theta_3 = []
                    for theta_3_test in [theta_3_prime, (np.pi if theta_3_prime >= 0 else -np.pi) - theta_3_prime]:
                        if constants.LHipPitchLow < theta_3_test < constants.LHipPitchHigh:
                            theta_3.append(theta_3_test)
                    if len(theta_3) == 0:
                        continue
                    theta_1_prime = np.arccos(T_triple_prime[0, 2] / np.sin(theta_2_test + plus_or_minus_pi_over_4))
                    theta_1 = []
                    for theta_1_test in [theta_1_prime + np.pi / 2, - theta_1_prime + np.pi / 2]:
                        if constants.LHipYawPitchLow < theta_1_test < constants.LHipYawPitchHigh:
                            theta_1.append(theta_1_test)
                    for theta_3_angle in theta_3:
                        theta_3_node = Node(theta_3_angle)
                        for theta_1_angle in theta_1:
                            theta_3_node.add_child_node(theta_1_angle)
                        theta_2_node.add_child(theta_3_node)
                    # We only add the theta_2_node if it results in a valid theta_3 and theta_1
                    theta_5_node.add_child(theta_2_node)
        # retrieve all the possible combinations of angles from the tree
        combinations = solution_tree_root.get_angle_combinations()
        combinations = [candidate for candidate in combinations if len(candidate) == 6]
        if len(combinations) == 0 or len(combinations[0]) != 6:
            print(f'WARNING: Incomputable desired end point position for the {"left" if is_left else "right"} leg:')
            print(f'x: {x}, y: {y}, z: {z}, roll: {roll}, pitch: {pitch}, yaw: {yaw}')
            best_solution = left_leg_previous_joints if is_left else right_leg_previous_joints
        elif len(combinations) != 1:
            print('Number of combination different than one:', combinations)
            # compute the distance between the different combinations and the previous joints and return the closest one
            shortest_distance = np.Inf
            best_index = -1
            for i, combination in enumerate(combinations):
                distance = np.linalg.norm(
                    np.array(left_leg_previous_joints if is_left else right_leg_previous_joints) - np.array(combination))
                if distance < shortest_distance:
                    shortest_distance = distance
                    best_index = i
            best_solution = combinations[best_index]
        else:
            best_solution = combinations[0]
        if is_left:
            left_leg_previous_joints = best_solution
        else:
            right_leg_previous_joints = best_solution
        theta_6, theta_4, theta_5, theta_2, theta_3, theta_1 = best_solution
        return theta_1, theta_2, theta_3, theta_4, theta_5, theta_6


from db import engine
from sqlmodel import Session, SQLModel, col, or_, select

from models import *

def create_db_and_tables():
    '''Initialize SQLModel ORM using imported  db engine'''
    SQLModel.metadata.create_all(engine)

def create_heroes():
    '''Add Hero instances to memory and commit through a session transaction.'''
    heroes = [
        Hero(name="Deadpond", secret_name="Dive Wilson", age=40),
        Hero(name="Spider-Boy", secret_name="Pedro Parqueador", age=25),
        Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48),
        Hero(name="Tarantula", secret_name="Natalia Roman-on", age=32),
        Hero(name="Black Lion", secret_name="Trevor Challa", age=35),
        Hero(name="Dr. Weird", secret_name="Steve Weird", age=36),
        Hero(name="Captain NA", secret_name="Esteban Rogelios", age=93)
    ]

    with Session(engine) as session:
        for hero in heroes:
            session.add(hero)
        session.commit()

def select_heroes():
    with Session(engine) as session:
        heroes = session.exec(select(Hero)
                              .where(or_(col(Hero.name) == "Black Lion", col(Hero.age) == 25))
                              #   .where(Hero.age == 48)
                              ).all()
        print(heroes)

def main():
    '''Creates required databases and ORM components.'''
    create_db_and_tables()
    create_heroes()
    select_heroes()

if __name__ == "__main__":
    main()


from setuptools import setup, find_packages
import pathlib

here = pathlib.Path(__file__).parent.resolve()

setup(
    name='Ionomap',
    version='Alpha',
    packages=[''],
    url='https://github.com/DartiLila/Ionomap',
    license='',
    author='Darti Lila',
    author_email='dartilila@gmail.com',
    description='This project aims to create a way for radio enthusiasts to find the best moment to communicate with the Internationlal space station through AM radio waves. '
)


import firebase_admin
from firebase_admin import credentials, db, firestore, auth, storage

# Fetch the service account key JSON file contents
cred = credentials.Certificate('serviceAccountKey.json')

# Initialize the app with a service account, granting admin privileges
firebase_admin.initialize_app(cred, {
    'databaseURL': 'https://seniorproject-3df90-default-rtdb.asia-southeast1.firebasedatabase.app/',
    'storageBucket': 'gs://seniorproject-3df90.appspot.com'
})

# As an admin, the app has access to read and write all data, regardless of Security Rules
realtime_database = db
firebase_firestore = firestore.client()
firebase_auth = auth
storage_bucket = storage.bucket()


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

#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Lesser General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Lesser General Public License for more details.
#
#   You should have received a copy of the GNU Lesser General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>

import struct, array, types

# Structure of SSTable file:
# * 16 bytes of header (see below in sstable class)
# * Array of offsets. Each offset points to start of the string. For the first string offset = 0.
# * One extra offset equals points to the byte right after last string+payload
# * Strings. Each string is followed by payload, to calculate size of string
#   calculate difference between current and next offsets and decrease by size of payload
#
# All numbers inside are unsigned, all counters and offsets are integers

class HeaderException(Exception):
	pass

class sstable:

	# Internal data buffer
	buffer = ""

	# Header format:
	# 8 bytes: magic
	# 2 bytes: version
	# 2 bytes: size of extra structure
	# 4 bytes: number of strings inside
	header_fmt = "8sHHI"
	header_magic = "YPySSTbl"
	header_version = 1
	header_payload_size = 0
	header_count = 0
	header_strings_start = 0

	# Indexes
	# Just plain array of unsigned integers
	index = array.array("I")

	def __init__(self, buffer=None):
		self.index = array.array("I")
		self.header_count = 0
		self.header_payload_size = 0
		self.header_strings_start = 0
		self.buffer = ""

		if type(buffer) == types.StringType:
			self.buffer = buffer

	def init(self, payload_size):
		# Put header and one extra index indicates size=0 into buffer
		self.buffer = struct.pack(self.header_fmt + "I", self.header_magic, self.header_version, payload_size, 0, 0)

		self.index = array.array("I")
		self.index.insert(0, 0)
		self.header_count = 0
		self.header_payload_size = payload_size
		self.header_strings_start = struct.calcsize(self.header_fmt) + self.index.itemsize

	def load(self, buffer=None):
		if type(buffer) == types.StringType:
			self.buffer = buffer

		position = 0
		header = struct.unpack_from(self.header_fmt, self.buffer, position)
		position += struct.calcsize(self.header_fmt)

		# Compare magic and version
		if header[0] != self.header_magic:
			raise HeaderException('Incorrect header magic')

		if header[1] != self.header_version:
			raise HeaderException('Incorrect header version')

		self.header_payload_size = header[2]
		self.header_count = header[3]

		# Load indexes
		# There is one extra index at the end that stores total length
		self.index.fromstring(self.buffer[position:(position + (self.header_count+1) * self.index.itemsize)])

		self.header_strings_start = position + (self.header_count+1) * self.index.itemsize

	def search(self, key):
		# Use binary search 'cause strings are sorted
		# There is one extra index at the end that stores total length
		min = 0
		max = self.header_count-1

		while min <= max:
			mid = int((min + max) / 2)

			# Get offset and calculate length of the record
			length = self.index[mid+1] - self.index[mid]
			offset = self.index[mid]

			# Each record consists of key and fixed-size payload
			record = self.buffer[(self.header_strings_start + offset):(self.header_strings_start + offset + length)]
			string = record[:length-self.header_payload_size]
			payload = record[length-self.header_payload_size:]

			if string == key:
				return (mid, key, payload)

			if key > string:
				min = mid+1
			else:
				max = mid-1
		raise KeyError("Key doesn't exist")

	def insert(self, key, payload, rewrite=False):

		if len(payload) != self.header_payload_size:
			raise KeyError("Incorrect payload size")

		# Use binary search 'cause strings are sorted
		# There is one extra index at the end that stores total length
		mid = 0
		min = 0
		max = self.header_count-1
		string = ""

		while min <= max:
			mid = int((min + max) / 2)

			length = self.index[mid+1] - self.index[mid]
			offset = self.index[mid]

			# Each record consists of key and fixed-size payload
			record = self.buffer[(self.header_strings_start + offset):(self.header_strings_start + offset + length)]
			string = record[:length-self.header_payload_size]

			if string == key:
				break

			if key > string:
				min = mid+1
			else:
				max = mid-1

		idx = mid
		if string == key:
			if not rewrite:
				raise KeyError("Duplicate key")
			new_buf = self.buffer[:(self.header_strings_start + offset + length - self.header_payload_size)] \
				+ payload + self.buffer[(self.header_strings_start + offset + length):]
			self.buffer = new_buf
		else:
			if key > string:
				idx += 1

			# If it is a first record
			if self.header_count == 0:
				idx = 0

			# New record should be added at position idx
			# all offsets from this position to the end should be increased with record length
			offset = self.index[idx]
			length = len(key) + self.header_payload_size

			self.index.insert(idx, offset)
			self.header_count += 1
			for i in xrange(idx+1, self.header_count+1):
				self.index[i] += length

			# Create header
			new_buf = struct.pack(self.header_fmt, self.header_magic, self.header_version, self.header_payload_size, self.header_count)
			# Create new buffer
			new_buf += self.index.tostring() + self.buffer[self.header_strings_start:(self.header_strings_start + offset)] \
				+ key + payload + self.buffer[(self.header_strings_start + offset):]
			self.buffer = new_buf
			self.header_strings_start += self.index.itemsize

	def delete(self, key):
		res = self.search(key)
		if not res:
			raise KeyError("key doesn't exist")

		idx = res[0]
		offset = self.index[idx]
		length = len(key) + self.header_payload_size

		# Remove idx from array
		# all offsets from this position to the end should be decreased with record length
		self.index.pop(idx)
		self.header_count -= 1
		for i in xrange(idx, self.header_count+1):
			self.index[i] -= length

		# Create header
		new_buf = struct.pack(self.header_fmt, self.header_magic, self.header_version, self.header_payload_size, self.header_count)

		# Create new buffer
		new_buf += self.index.tostring() + self.buffer[self.header_strings_start:(self.header_strings_start + offset)] \
			+ self.buffer[(self.header_strings_start + offset + length):]
		self.buffer = new_buf
		self.header_strings_start -= self.index.itemsize

	def save(self):
		return self.buffer


import time
import board
import busio

VS1053_BANK_DEFAULT = 0x00
VS1053_BANK_DRUMS1 = 0x78
VS1053_BANK_DRUMS2 = 0x7F
VS1053_BANK_MELODY = 0x79
MIDI_NOTE_ON = 0x90
MIDI_NOTE_OFF = 0x80
MIDI_CHAN_MSG = 0xB0
MIDI_CHAN_BANK = 0x00
MIDI_CHAN_VOLUME = 0x07
MIDI_CHAN_PAN = 0x0A
MIDI_CHAN_PROGRAM = 0xC0

uart = busio.UART(board.TX, board.RX, baudrate=31250)

def note_on(channel, note, vel):
    uart.write(bytearray([MIDI_NOTE_ON | channel, note, vel]))

def note_off(channel, note):
    uart.write(bytearray([MIDI_NOTE_OFF | channel, note, 0]))

def set_channel_bank(channel, bank):
    uart.write(bytearray([MIDI_CHAN_MSG | channel, MIDI_CHAN_BANK, bank]))

def set_channel_volume(channel, vol):
    uart.write(bytearray([MIDI_CHAN_MSG | channel, MIDI_CHAN_VOLUME, vol]))

def set_channel_instrument(channel, num):
    uart.write(bytearray([MIDI_CHAN_PROGRAM | channel]))
    time.sleep(0.01)
    uart.write(bytearray([num]))
    time.sleep(0.01)

def set_channel_pan(channel, pan):
    uart.write(bytearray([MIDI_CHAN_MSG | channel, MIDI_CHAN_PAN, pan]))

# Set up a piano instrument on channel 0
set_channel_bank(0, VS1053_BANK_MELODY)
set_channel_volume(0, 127)
set_channel_instrument(0, 0)  # piano

# Play Do Re Mi
note_on(0, 60, 127)
time.sleep(0.5)
note_off(0, 60)

note_on(0, 62, 127)
time.sleep(0.5)
note_off(0, 62)

note_on(0, 64, 127)
time.sleep(0.5)
note_off(0, 64)

time.sleep(1)

# Play a major scale on all 127 instruments!
# See the datasheet page 32 for a list of instruments:
# https://cdn-shop.adafruit.com/datasheets/vs1053.pdf
scale = [60, 62, 64, 65, 67, 69, 71, 72]
for instrument in range(127):
    print("instrument: " + str(instrument))
    set_channel_instrument(0, instrument)
    for note_num in scale:
        note_on(0, note_num, 127)
        time.sleep(0.1)
    time.sleep(1)
    for note_num in scale:
        note_off(0, note_num)
    time.sleep(0.5)


""" Urls for the eshop app """

from django.conf.urls import url
from django.views.generic import TemplateView

from . import views

__author__ = 'Sathi, Aupourbau Koumar'
__copyright__ = 'Copyright 2018, Maison Mahdil'

# URLs
urlpatterns = [
    url(
        r'^panier/$',
        views.CartView.as_view(),
        name='cart'
    ),
    url(
        r'^notification/$',
        views.payment_notification,
        name='notification'
    ),
    url(
        r'^cart/count/$',
        views.ItemCountView.as_view(),
        name='item_count'
    ),
    url(
        r'^cart/item/remove$',
        views.RemoveCartItemAPIView.as_view(),
        name='cartitem_remove_api'
    ),
    url(
        r'^check-out/$',
        views.CheckoutView.as_view(),
        name='checkout'
    ),
    url(
        r'^check-out/adresse/$',
        views.AddressSelectFormView.as_view(),
        name='order_address'
    ),
    url(
        r'^check-out/adresse/ajouter/$',
        views.UserAddressCreateView.as_view(),
        name='user_address_create'
    ),
    url(
        r'^commandes/(?P<pk>\d+)/$',
        views.order_detail,
        name='order_detail'
    ),
    url(
        r'^commandes/paiement/$',
        views.Payment,
        name='payment'
    ),
    url(
        r'^check-out/final/$',
        views.CheckoutFinalView.as_view(),
        name='checkout_final'
    ),
    url(
        r'^orders/payment/after/',  # Linked to external payment module
        views.CheckoutFinalView.as_view(),
        name='payment_after'
    ),
    url(
        r'^order/confirmation/$',
        TemplateView.as_view(template_name='eshop/email/order_confirmation_mail.html')
    ),
    url(
        r'^order/invoice/$',
        TemplateView.as_view(template_name='eshop/invoice.html')
    ),

    # API
    url(
        r'^api/cart/$',
        views.CartAPIView.as_view(),
        name='cart_api'
    ),
]


from re import S
import pandas

squirrel_data = pandas.read_csv("./data/2018_Central_Park_Squirrel_Census_-_Squirrel_Data.csv")
# print(squirrel_data)

grey_squirrels_count = len(squirrel_data[squirrel_data["Primary Fur Color"] == "Grey"])
cinnamon_squirrels_count = len(squirrel_data[squirrel_data["Primary Fur Color"] == "Cinnamon"])
black_squirrels_count = len(squirrel_data[squirrel_data["Primary Fur Color"] == "Black"])

print(f"Cinnamon squirrel count: {grey_squirrels_count}")
print(f"Cinnamon squirrel count: {cinnamon_squirrels_count}")
print(f"Black squirrel count: {black_squirrels_count}")

data_dict = {
    "Fur Color": ["Gray", "Cinnamon", "Black"],
    "Count": [grey_squirrels_count, cinnamon_squirrels_count, black_squirrels_count]
}

data_frame = pandas.DataFrame(data_dict)
data_frame.to_csv("./data/squirrel_count.csv")


# -*- coding: utf-8 -*-
"""
Created on Wed Sep  7 11:17:07 2016

@author: agentsmith
"""

import numpy as np
import pandas as pd
import time
from fill_dataframe import fill_dataframe

def apply_fill_dataframe(data_process, variable_to_fill):
    """
        Cette fonction remplit le DataFrame passé en entrée et produit 2 outputs : Un DataFrame représentant la présence des héros dans une partie
        et un DataFrame représentant les statistiques des deux équipes d'une partie
        args : "data_process" le résultat de la fonction "data_process" contenue dans "data_process.py" qui contient les données
               "variable_to_fill" indique les features qui devront être construite dans la fonction "fill_dataframe" contenue dans "fill_dataframe.py"
    """

    time_before = time.time()

    # On récupère la liste des données issues de MongoDB
    data = data_process["Results"]["Data"]
    # On récupère la liste des héros
    heroes = data_process["Results"]["HeroesList"]
    # On récupère le DataFrame que l'on va modifier
    df = data_process["Results"]["DataFrame"]
    # Sur chacune des lignes du DataFrame on applique la fonction "fill_dataframe" contenue dans "fill_dataframe.py"
    df_apply_result = df.apply(fill_dataframe, axis=1, args=(variable_to_fill, data, heroes,)).drop("index", 1)

    # Index des valeurs manquantes dans le DataFrame construit
    nan_index_list = []
    for i in range(0, len(df_apply_result)):
        if(True in pd.isnull(df_apply_result.iloc[i, :].values)):
            nan_index_list.append(i)
    if(len(nan_index_list) > 0):
        print("############ WARNING #####################\n############ EXISTENCE DE NAN ############")
    else:
        print("############ PAS DE NAN ############")

    # Split du DataFrame précédent en 2 et supression des colonnes non utiles qui ont servies à construire les autres colonnes utiles
    if(variable_to_fill in ["Custom", "Custom2"]):

        # 1) DataFrame représentant la présence des héros dans chaque équipe
        dataframe_heroes_presences_columns = [elt for elt in df_apply_result.columns if ("_TeamPick" in elt)] + ["Victoire"]
        dataframe_heroes_presences = df_apply_result.loc[:, dataframe_heroes_presences_columns]

        # 2) DataFrame représentant les statistiques des deux équipes
        if(variable_to_fill == "Custom"):
            dataframe_team_stats_columns = ["Radiant_Golds", "Radiant_Hero_Damage", "Radiant_Xp", "Radiant_Hero_Healing", "Radiant_Levels", "Radiant_Denies", "Radiant_Kda", "Dire_Golds", "Dire_Hero_Damage", "Dire_Xp", "Dire_Hero_Healing", "Dire_Levels", "Dire_Denies", "Dire_Kda", "Victoire"]
            dataframe_team_stats = df_apply_result.loc[:, dataframe_team_stats_columns]

            time_after = time.time()
            time_elapsed = (time_after - time_before) / 60.0

            print("###################################")
            print("TimeProcessInMinutes ---> : {}".format(time_elapsed))
            print("###################################")

            return {"TimeProcessInMinutes": time_elapsed, "Results": {"Presences": dataframe_heroes_presences, "TeamsStats": dataframe_team_stats}}

        elif(variable_to_fill == "Custom2"):
            # Récupération des colonnes et construction du DataFrame
            DfHeroesPresencesColumns = [eltcolumn for eltcolumn in df_apply_result.columns if ("TeamPick" in eltcolumn)] + ["Victoire"]
            DfHeroesPresences = df_apply_result.loc[:, DfHeroesPresencesColumns]
            # Récupération des colonnes et construction du DataFrame
            dataframe_team_stats_classif_columns = [eltcolumn for eltcolumn in df_apply_result.columns if (("_Denies" not in eltcolumn) & ("_Items" not in eltcolumn) & ("_Hero_Name" not in eltcolumn) & ("TeamPick" not in eltcolumn) & (("Radiant_Hero_" in eltcolumn) or ("Dire_Hero_" in eltcolumn)))] + ["Victoire", "TimeDuration"]
            dataframe_team_statsClassif = df_apply_result.loc[:, dataframe_team_stats_classif_columns]
            # Récupération des colonnes et construction du DataFrame
            dataframe_team_stats_global_columns = [eltcolumn for eltcolumn in df_apply_result.columns if (("TeamPick" not in eltcolumn) & (("Radiant_" in eltcolumn) or ("Dire_" in eltcolumn)))] + ["Victoire", "TimeDuration"]
            dataframe_stats_global_and_heroes = df_apply_result.loc[:, list(np.unique(dataframe_team_stats_classif_columns + dataframe_team_stats_global_columns))]

            time_after = time.time()
            time_elapsed = (time_after - time_before) / 60.0

            print("###################################")
            print("TimeProcessInMinutes ---> : {}".format(time_elapsed))
            print("###################################")

            return {"TimeProcessInMinutes": time_elapsed, "Results": {"Presences": DfHeroesPresences, "TeamsStats": dataframe_team_statsClassif, "Global": dataframe_stats_global_and_heroes}}

        return {"TimeProcessInMinutes": time_elapsed, "Results": df_apply_result}


import logging
import os
from tempfile import TemporaryDirectory
from typing import Optional

from .base import BaseExecutor

logger = logging.getLogger(__name__)

class ExpTemporaryDirectory(TemporaryDirectory):
    # Python's TemporaryDirectory cleanup shutil.rmtree wrapper does not handle
    # git read-only dirs cleanly in Windows on Python <3.8, so we use our own
    # remove(). See:
    # https://github.com/iterative/dvc/pull/5425
    # https://bugs.python.org/issue26660

    @classmethod
    def _rmtree(cls, name):
        from dvc.utils.fs import remove

        remove(name)

    def cleanup(self):
        if self._finalizer.detach():
            self._rmtree(self.name)

class BaseLocalExecutor(BaseExecutor):
    """Base local machine executor."""

    @property
    def git_url(self) -> str:
        root_dir = os.path.abspath(self.root_dir)
        if os.name == "nt":
            root_dir = root_dir.replace(os.sep, "/")
        return f"file://{root_dir}"

class TempDirExecutor(BaseLocalExecutor):
    """Temp directory experiment executor."""

    # Temp dir executors should warn if untracked files exist (to help with
    # debugging user code), and suppress other DVC hints (like `git add`
    # suggestions) that are not applicable outside of workspace runs
    WARN_UNTRACKED = True
    QUIET = True

    def __init__(
        self,
        *args,
        tmp_dir: Optional[str] = None,
        cache_dir: Optional[str] = None,
        **kwargs,
    ):
        self._tmp_dir = ExpTemporaryDirectory(dir=tmp_dir)
        kwargs["root_dir"] = self._tmp_dir.name
        super().__init__(*args, **kwargs)
        if cache_dir:
            self._config(cache_dir)
        logger.debug("Init temp dir executor in dir '%s'", self._tmp_dir)

    def _config(self, cache_dir):
        local_config = os.path.join(self.dvc_dir, "config.local")
        logger.debug("Writing experiments local config '%s'", local_config)
        with open(local_config, "w") as fobj:
            fobj.write(f"[cache]\n    dir = {cache_dir}")

    def cleanup(self):
        super().cleanup()
        logger.debug("Removing tmpdir '%s'", self._tmp_dir)
        self._tmp_dir.cleanup()


from import_sql import *
from tkinter import *
from tkinter.ttk import *
from tkinter.scrolledtext import *

ketnoi = getConnection()
dulieu = ketnoi.cursor()

# Tạo giao diện
qlnv = Tk()
qlnv.title("Quản lý nhân viên")
qlnv.geometry("575x425")

# Tiêu đề
top = Label(qlnv, text = "CHƯƠNG TRÌNH QUẢN LÝ NHÂN VIÊN", font=("Times New Roman","12"))
top.grid(column = 2, row = 1)

#Tên
name = Label(qlnv, text = "Tên")
name.grid(column = 1, row = 2)
giatri1 = StringVar()
name_box = Entry(qlnv, width = 25, textvariable = giatri1)
name_box.grid(column = 2, row = 2)

#Tuổi
age = Label(qlnv, text = "Tuổi")
age.grid(column = 1, row = 3)
giatri2 = IntVar()
age_box = Entry(qlnv, width = 25, textvariable = giatri2)
age_box.grid(column = 2, row = 3)

#Quê
country = Label(qlnv, text = "Quê quán")
country.grid(column = 1, row = 4)
giatri3 = StringVar()
country_box = Entry(qlnv, width = 25, textvariable = giatri3)
country_box.grid(column = 2, row = 4)

#Chức vụ
title = Label(qlnv, text = "Chức vụ")
title.grid(column = 1, row = 5)
giatri4 = StringVar()
title_box = Combobox(qlnv, values = ["NV", "TP", "GD"], textvariable=giatri4)
title_box.grid(column = 2, row = 5)

#Số ngày làm
workday = Label(qlnv, text = "Số ngày làm")
workday.grid(column = 1, row = 6)
giatri5 = IntVar()
workday_box = Entry(qlnv, width = 25, textvariable = giatri5)
workday_box.grid(column = 2, row = 6)

#Màn hình hiển thị
screen = ScrolledText(qlnv, width = 40, height = 10)
screen.grid(column = 2, row = 10)
screen['state'] = 'disabled'

#Kiểm tra kết nối
def kiemtraketnoi():
    test = ketnoi.is_connected()
    if test == True:
        success = Label(qlnv, text = "Connect Successful")
        success.grid(column = 2, row = 8)
        success.after(1000, success.destroy)
test_connection = Button(qlnv, text = "Kiểm tra kết nối", command = kiemtraketnoi)
test_connection.grid(column = 2, row = 11)

#Thêm nhân viên
def them():
    dulieu.execute("INSERT INTO `nhanvien`(`Name`,Age,Country,Chucvu,Songaylam) VALUES ('{}',{},'{}','{}',{})".format(giatri1.get(),giatri2.get(),giatri3.get(),giatri4.get(),giatri5.get()))
    ketnoi.commit()
    for giatri in (giatri1, giatri2, giatri3, giatri4, giatri5):
        giatri.set("")
    success = Label(qlnv, text = "Đã thêm")
    success.grid(column = 3, row = 9)
    success.after(1000, success.destroy)

nut_them = Button(qlnv, text = "Thêm nhân viên", command = them)
nut_them.grid(column =1, row = 7)

#Hiển thị nhân viên
def hienthi():
    screen['state'] = 'normal'
    dulieu.execute("SELECT * FROM quan_ly_nhan_vien.nhanvien")
    text = dulieu.fetchall()
    screen.insert("1.0", text)
    nutthaotac = Button(qlnv, text = "Xóa màn hình", command = lambda: [screen.delete("1.0", END), nutthaotac.destroy()])
    nutthaotac.grid(column = 3, row = 10)

nut_hien_thi = Button(qlnv, text = "Hiển thị nhân viên", command = hienthi)
nut_hien_thi.grid(column = 2, row = 7)

#Sửa nhân viên
def sua():
    sua1 = Label(qlnv, text="ID của nhân viên cần sửa")
    sua1.grid(column = 1, row = 10)
    id = IntVar()
    id_box = Entry(qlnv, width = 25, textvariable = id)
    id_box.grid(column = 2, row = 10)
    def thaotac():
        dulieu.execute("UPDATE quan_ly_nhan_vien.nhanvien SET `Name` = '{}', Age = {}, Country = '{}', Chucvu = '{}', Songaylam = {} WHERE ID = {}".format(giatri1.get(), giatri2.get(), giatri3.get(), giatri4.get(), giatri5.get(), id.get()))
        ketnoi.commit()
        success = Label(qlnv, text="Đã sửa")
        success.grid(column = 3, row =8)
        success.after(1000,success.destroy)
        sua1.after(1000,sua1.destroy)
        id_box.after(1100,id_box.destroy)
        for giatri in (giatri1, giatri2, giatri3, giatri4, giatri5):
            giatri.set("")
    nutthaotac1 = Button(qlnv, text = "Sửa", command = lambda: [thaotac(),nutthaotac1.destroy()])
    nutthaotac1.grid(column = 3, row = 10)

sua_hv = Button(qlnv, text = "Sửa nhân viên", command = sua).grid(column = 2, row = 9)

#Xóa nhân viên
def xoa():
    xoa1 = Label(qlnv, text ="ID của nhân viên cần xóa")
    xoa1.grid(column = 1, row =10)
    id=IntVar()
    id_box = Entry(qlnv, width = 25, textvariable = id)
    id_box.grid(column  = 2, row = 10)
    def thaotac():
        dulieu.execute("DELETE from quan_ly_nhan_vien.nhanvien WHERE ID = {}".format(id.get()))
        ketnoi.commit()
        success = Label(qlnv, text = "Đã xóa")
        success.grid(column = 3, row = 8)
        success.after(1000, success.destroy)
        xoa1.after(1000, xoa1.destroy)
        id_box.after(1100, id_box.destroy)
    nutthaotac2 = Button(qlnv, text = "Xóa", command = lambda: [thaotac(), nutthaotac2.destroy()])
    nutthaotac2.grid(column = 3, row = 10)

xoa_hv = Button(qlnv, text = "Xóa nhân viên", command = xoa).grid(column = 1, row = 9)

qlnv.mainloop()
ketnoi.close()


import random
word_list=["apple","banana","cherry","orange","cucumber"]
print(word_list)

class Hangman:
    def __init__(self,word_list):
        self.word=random.choice(word_list)
        print(self.word)
        self.word_guessed=["_"]*len(self.word)
        print(self.word_guessed)
        self.num_letters=len(self.word)
        self.num_lives=5
        # self.word_list
        self.list_of_guesses=[]

    def check_guess(self, guess):
        guess=guess.lower()
        if guess in self.word:
            print("Good guess! {} is in the word.".format(guess))
            indx=""
            for count, i in enumerate(self.word):
                if i==guess:
                    indx=count
                    self.word_guessed[count]=i
                    self.num_letters-=1
            print(indx)
            print(self.num_letters)
            print(self.word_guessed)
        else:
            self.num_lives-=1
            print("Sorry, {} is not in the word. Try again.".format(guess))
            print("You have {} lives left.".format(self.num_lives))

    def ask_for_input(self):
        while True:
            guess=input("Please guess a letter: ")
            if len(guess)!=1 or type(guess)!=str:
                print("Invalid letter. Please, enter a single alphabetical character.")
            elif guess in self.list_of_guesses:
                print("You already tried that letter!")
            else:
                self.check_guess(guess)
                self.list_of_guesses.append(guess)

game1=Hangman(word_list)
game1.ask_for_input()


__version__     = '0.1'
__package__     = 'ILog'
__summary__     = "IRC Logging"
__author__      = 'Pedro Algarvio'
__email__       = 'ufs@ufsoft.org'
__license__     = 'BSD'
__url__         = 'https://hg.ufsoft.org/ILog'
__description__ = __doc__

import sys
from types import ModuleType

sys.modules['ilog.application'] = application = ModuleType( 'application' )
sys.modules['ilog.notification'] = notification = ModuleType( 'notification' )


# birthday/utils.py
# Импортируем модуль для работы с датами.
from datetime import date

def calculate_birthday_countdown(birthday):
    today = date.today()
    this_year_birthday = get_birthday_for_year(birthday, today.year)
    if this_year_birthday < today:
        next_birthday = get_birthday_for_year(birthday, today.year + 1)
    else:
        next_birthday = this_year_birthday
    birthday_countdown = (next_birthday - today).days
    return birthday_countdown

def get_birthday_for_year(birthday, year):
    """
    Получает дату дня рождения для конкретного года.

    Ошибка ValueError возможна только в случае
    с високосными годами и ДР 29 февраля.
    В этом случае приравниваем дату ДР к 1 марта.
    """
    try:
        # Пробуем заменить год в дате рождения на переданный в функцию.
        calculated_birthday = birthday.replace(year=year)
    # Если возникла ошибка, значит, день рождения 29 февраля
    # и подставляемый год не является високосным.
    except ValueError:
        # В этом случае устанавливаем ДР 1 марта.
        calculated_birthday = date(year=year, month=3, day=1)
    return calculated_birthday


import itertools

def check(l) -> bool:

    for i in range(1, N, 1):
        # 完全一致はダメ
        if l[i-1] == l[i] :
            return False

        count = 0
        for j in range(M):
            if l[i-1][j] != l[i][j]:
                count += 1
        if count > 1:
            return False

    return True

N, M = map(int, input().split())
list_S = []
for _ in range(N):
    list_S.append(input())

for a in itertools.permutations(list_S, N):
    # 1つでも列があれば良い
    if check(a):
        print("Yes")
        break
else:
    print("No")


from __future__ import absolute_import

import os

from yaml.parser import ParserError
import six

from oslo_config import cfg
from st2common import log as logging
from st2common.constants.meta import ALLOWED_EXTS
from st2common.constants.meta import PARSER_FUNCS
from st2common.constants.pack import MANIFEST_FILE_NAME

if six.PY2:
    from io import open

__all__ = ["ContentPackLoader", "MetaLoader", "OverrideLoader"]

LOG = logging.getLogger(__name__)

class ContentPackLoader(object):
    """
    Class for loading pack and pack content information from directories on disk.
    """

    # TODO: Rename "get_content" methods since they don't actually return
    # content - they just return a path

    ALLOWED_CONTENT_TYPES = [
        "triggers",
        "sensors",
        "actions",
        "rules",
        "aliases",
        "policies",
    ]

    def get_packs(self, base_dirs):
        """
        Retrieve a list of packs in the provided directories.

        :return: Dictionary where the key is pack name and the value is full path to the pack
                 directory.
        :rtype: ``dict``
        """
        if not isinstance(base_dirs, list):
            raise TypeError(
                "The base dirs has a value that is not a list"
                f" (was {type(base_dirs)})."
            )

        result = {}
        for base_dir in base_dirs:
            if not os.path.isdir(base_dir):
                raise ValueError('Directory "%s" doesn\'t exist' % (base_dir))

            packs_in_dir = self._get_packs_from_dir(base_dir=base_dir)
            result.update(packs_in_dir)

        return result

    def get_content(self, base_dirs, content_type):
        """
        Retrieve content from the provided directories.

        Provided directories are searched from left to right. If a pack with the same name exists
        in multiple directories, first pack which is found wins.

        :param base_dirs: Directories to look into.
        :type base_dirs: ``list``

        :param content_type: Content type to look for (sensors, actions, rules).
        :type content_type: ``str``

        :rtype: ``dict``
        """
        if not isinstance(base_dirs, list):
            raise TypeError(
                "The base dirs has a value that is not a list"
                f" (was {type(base_dirs)})."
            )

        if content_type not in self.ALLOWED_CONTENT_TYPES:
            raise ValueError("Unsupported content_type: %s" % (content_type))

        content = {}
        pack_to_dir_map = {}
        for base_dir in base_dirs:
            if not os.path.isdir(base_dir):
                raise ValueError('Directory "%s" doesn\'t exist' % (base_dir))

            dir_content = self._get_content_from_dir(
                base_dir=base_dir, content_type=content_type
            )

            # Check for duplicate packs
            for pack_name, pack_content in six.iteritems(dir_content):
                if pack_name in content:
                    pack_dir = pack_to_dir_map[pack_name]
                    LOG.warning(
                        'Pack "%s" already found in "%s", ignoring content from "%s"'
                        % (pack_name, pack_dir, base_dir)
                    )
                else:
                    content[pack_name] = pack_content
                    pack_to_dir_map[pack_name] = base_dir

        return content

    def get_content_from_pack(self, pack_dir, content_type):
        """
        Retrieve content from the provided pack directory.

        :param pack_dir: Path to the pack directory.
        :type pack_dir: ``str``

        :param content_type: Content type to look for (sensors, actions, rules).
        :type content_type: ``str``

        :rtype: ``str``
        """
        if content_type not in self.ALLOWED_CONTENT_TYPES:
            raise ValueError("Unsupported content_type: %s" % (content_type))

        if not os.path.isdir(pack_dir):
            raise ValueError('Directory "%s" doesn\'t exist' % (pack_dir))

        content = self._get_content_from_pack_dir(
            pack_dir=pack_dir, content_type=content_type
        )
        return content

    def _get_packs_from_dir(self, base_dir):
        result = {}
        for pack_name in os.listdir(base_dir):
            pack_dir = os.path.join(base_dir, pack_name)
            pack_manifest_file = os.path.join(pack_dir, MANIFEST_FILE_NAME)

            if os.path.isdir(pack_dir) and os.path.isfile(pack_manifest_file):
                result[pack_name] = pack_dir

        return result

    def _get_content_from_dir(self, base_dir, content_type):
        content = {}
        for pack in os.listdir(base_dir):
            # TODO: Use function from util which escapes the name
            pack_dir = os.path.join(base_dir, pack)

            # Ignore missing or non directories
            try:
                pack_content = self._get_content_from_pack_dir(
                    pack_dir=pack_dir, content_type=content_type
                )
            except ValueError:
                continue
            else:
                content[pack] = pack_content

        return content

    def _get_content_from_pack_dir(self, pack_dir, content_type):
        content_types = dict(
            triggers=self._get_triggers,
            sensors=self._get_sensors,
            actions=self._get_actions,
            rules=self._get_rules,
            aliases=self._get_aliases,
            policies=self._get_policies,
        )

        get_func = content_types.get(content_type)

        if get_func is None:
            raise ValueError("Invalid content_type: %s" % (content_type))

        if not os.path.isdir(pack_dir):
            raise ValueError('Directory "%s" doesn\'t exist' % (pack_dir))

        pack_content = get_func(pack_dir=pack_dir)
        return pack_content

    def _get_triggers(self, pack_dir):
        return self._get_folder(pack_dir=pack_dir, content_type="triggers")

    def _get_sensors(self, pack_dir):
        return self._get_folder(pack_dir=pack_dir, content_type="sensors")

    def _get_actions(self, pack_dir):
        return self._get_folder(pack_dir=pack_dir, content_type="actions")

    def _get_rules(self, pack_dir):
        return self._get_folder(pack_dir=pack_dir, content_type="rules")

    def _get_aliases(self, pack_dir):
        return self._get_folder(pack_dir=pack_dir, content_type="aliases")

    def _get_policies(self, pack_dir):
        return self._get_folder(pack_dir=pack_dir, content_type="policies")

    def _get_folder(self, pack_dir, content_type):
        path = os.path.join(pack_dir, content_type)
        if not os.path.isdir(path):
            return None
        return path

class MetaLoader(object):
    """
    Class for loading and parsing pack and resource metadata files.
    """

    def load(self, file_path, expected_type=None):
        """
        Loads content from file_path if file_path's extension
        is one of allowed ones (See ALLOWED_EXTS).

        Throws UnsupportedMetaException on disallowed filetypes.
        Throws ValueError on malformed meta.

        :param file_path: Absolute path to the file to load content from.
        :type file_path: ``str``

        :param expected_type: Expected type for the loaded and parsed content (optional).
        :type expected_type: ``object``

        :rtype: ``dict``
        """
        file_name, file_ext = os.path.splitext(file_path)

        if file_ext not in ALLOWED_EXTS:
            raise Exception(
                "Unsupported meta type %s, file %s. Allowed: %s"
                % (file_ext, file_path, ALLOWED_EXTS)
            )

        result = self._load(PARSER_FUNCS[file_ext], file_path)

        if expected_type and not isinstance(result, expected_type):
            actual_type = type(result).__name__
            error = 'Expected "%s", got "%s"' % (expected_type.__name__, actual_type)
            raise ValueError(error)

        return result

    def _load(self, parser_func, file_path):
        with open(file_path, "r", encoding="utf-8") as fd:
            try:
                return parser_func(fd)
            except ValueError:
                LOG.exception("Failed loading content from %s.", file_path)
                raise
            except ParserError:
                LOG.exception("Failed loading content from %s.", file_path)
                raise

class OverrideLoader(object):
    """
    Class for loading pack override data
    """

    # Mapping of permitted override types to resource name
    ALLOWED_OVERRIDE_TYPES = {
        "sensors": "class_name",
        "actions": "name",
        "rules": "name",
        "aliases": "name",
    }

    ALLOWED_OVERRIDE_NAMES = [
        "enabled",
    ]

    DEFAULT_OVERRIDE_VALUES = {"enabled": True}

    def override(self, pack_name, resource_type, content):

        """
        Loads override content for pack, and updates content

        :param pack_name: Name of pack
        :type pack_name: ``str``
        :param resource_type: Type of resource loading
        :type type: ``str``
        :param content: Content as loaded from meta information
        :type content: ``object``
        :return: Whether data was overridden
        :rtype: ``bool``
        """
        orig_content = content.copy()
        if resource_type not in self.ALLOWED_OVERRIDE_TYPES.keys():
            raise ValueError(
                f"Invalid override type of {resource_type} attempted for pack {pack_name}"
            )

        override_dir = os.path.join(cfg.CONF.system.base_path, "overrides")
        # Apply global overrides
        global_file = os.path.join(override_dir, "_global.yaml")
        self._apply_override_file(global_file, pack_name, resource_type, content, True)

        # Apply pack overrides
        override_file = os.path.join(override_dir, f"{pack_name}.yaml")
        self._apply_override_file(
            override_file, pack_name, resource_type, content, False
        )
        if content == orig_content:
            overridden = False
        else:
            # Need to account for defaults that might not have been set
            for key in self.ALLOWED_OVERRIDE_NAMES:
                if key not in orig_content.keys() and key in content.keys():
                    orig_content[key] = self.DEFAULT_OVERRIDE_VALUES[key]
            if content == orig_content:
                overridden = False
            else:
                overridden = True
        return overridden

    def _apply_override_file(
        self, override_file, pack_name, resource_type, content, global_file
    ):

        """
        Loads override content from override file

        :param override_file: Override filename
        :type override_file: ``str``
        :param pack_name: Name of pack
        :type pack_name: ``str``
        :param resource_type: Type of resource loading
        :type type: ``str``
        :param content: Content as loaded from meta information
        :type content: ``object``
        """

        if not os.path.exists(override_file):
            # No override file for pack
            LOG.debug(f"No override file {override_file} found")
            return

        # Read override file
        file_name, file_ext = os.path.splitext(override_file)
        overrides = self._load(PARSER_FUNCS[file_ext], override_file)
        # Apply overrides
        if resource_type in overrides:
            type_override = overrides[resource_type]
            name = content[self.ALLOWED_OVERRIDE_TYPES[resource_type]]
            if "defaults" in type_override:
                for key in type_override["defaults"]:
                    if key in self.ALLOWED_OVERRIDE_NAMES:
                        content[key] = type_override["defaults"][key]
                        LOG.debug(
                            f"Overridden {resource_type} {pack_name}.{name} {key} to default value of {content[key]} from {override_file}"
                        )
                    else:
                        raise ValueError(
                            f"Override attempted with invalid default key {key} in pack {pack_name}"
                        )

            if global_file:
                # No exceptions required in global content file
                return

            if "exceptions" in type_override:
                if name in type_override["exceptions"]:
                    for key in type_override["exceptions"][name]:
                        if key in self.ALLOWED_OVERRIDE_NAMES:
                            content[key] = type_override["exceptions"][name][key]
                            LOG.debug(
                                f"Overridden {resource_type} {pack_name}.{name} {key} to exception value of {content[key]} from {override_file}"
                            )
                        else:
                            raise ValueError(
                                f"Override attempted with invalid exceptions key {key} in pack {pack_name}"
                            )

    def _load(self, parser_func, file_path):
        with open(file_path, "r", encoding="utf-8") as fd:
            try:
                return parser_func(fd)
            except ValueError:
                LOG.exception("Failed loading content from %s.", file_path)
                raise
            except ParserError:
                LOG.exception("Failed loading content from %s.", file_path)
                raise


"""Core objects."""

__copyright__ = "Copyright (C) 2014 Ivan D Vasin"
__docformat__ = "restructuredtext"

from collections import Mapping as _Mapping
import httplib as _http

# 1xx informational -----------------------------------------------------------

CONTINUE = 100

SWITCHING_PROTOCOLS = 101

PROCESSING = 102

INFORMATIONAL_STATUSES = (CONTINUE, SWITCHING_PROTOCOLS, PROCESSING)

# 2xx success -----------------------------------------------------------------

OK = 200

CREATED = 201

ACCEPTED = 202

NON_AUTHORITATIVE_INFORMATION = 203

NO_CONTENT = 204

RESET_CONTENT = 205

PARTIAL_CONTENT = 206

MULTI_STATUS = 207

ALREADY_REPORTED = 208

IM_USED = 226

SUCCESS_STATUSES = (OK, CREATED, ACCEPTED, NON_AUTHORITATIVE_INFORMATION,
                    NO_CONTENT, RESET_CONTENT, PARTIAL_CONTENT, MULTI_STATUS,
                    ALREADY_REPORTED, IM_USED)

# 3xx redirection -------------------------------------------------------------

MULTIPLE_CHOICES = 300

MOVED_PERMANENTLY = 301

FOUND = 302

SEE_OTHER = 303

NOT_MODIFIED = 304

USE_PROXY = 305

SWITCH_PROXY = 306

TEMPORARY_REDIRECT = 307

PERMANENT_REDIRECT = 308

REDIRECTION_STATUSES = (MULTIPLE_CHOICES, MOVED_PERMANENTLY, FOUND, SEE_OTHER,
                        NOT_MODIFIED, USE_PROXY, SWITCH_PROXY,
                        TEMPORARY_REDIRECT, PERMANENT_REDIRECT)

# 4xx client error ------------------------------------------------------------

BAD_REQUEST = 400

UNAUTHORIZED = 401

PAYMENT_REQUIRED = 402

FORBIDDEN = 403

NOT_FOUND = 404

METHOD_NOT_ALLOWED = 405

NOT_ACCEPTABLE = 406

PROXY_AUTHENTICATION_REQUIRED = 407

REQUEST_TIMEOUT = 408

CONFLICT = 409

GONE = 410

LENGTH_REQUIRED = 411

PRECONDITION_FAILED = 412

REQUEST_ENTITY_TOO_LARGE = 413

REQUEST_URI_TOO_LONG = 414

UNSUPPORTED_MEDIA_TYPE = 415

REQUESTED_RANGE_NOT_SATISFIABLE = 416

EXPECTATION_FAILED = 417

IM_A_TEAPOT = 418

ENHANCE_YOUR_CALM = 420

UNPROCESSABLE_ENTITY = 422

LOCKED = 423

FAILED_DEPENDENCY = 424

METHOD_FAILURE = 424

UNORDERED_COLLECTION = 425

UPGRADE_REQUIRED = 426

PRECONDITION_REQUIRED = 428

TOO_MANY_REQUESTS = 429

REQUEST_HEADER_FIELDS_TOO_LARGE = 431

NO_RESPONSE = 444

RETRY_WITH = 449

BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450

CLIENT_CLOSED_REQUEST = 499

CLIENT_ERROR_STATUSES = (BAD_REQUEST,
                         UNAUTHORIZED,
                         PAYMENT_REQUIRED,
                         FORBIDDEN,
                         NOT_FOUND,
                         METHOD_NOT_ALLOWED,
                         NOT_ACCEPTABLE,
                         PROXY_AUTHENTICATION_REQUIRED,
                         REQUEST_TIMEOUT,
                         CONFLICT,
                         GONE,
                         LENGTH_REQUIRED,
                         PRECONDITION_FAILED,
                         REQUEST_ENTITY_TOO_LARGE,
                         REQUEST_URI_TOO_LONG,
                         UNSUPPORTED_MEDIA_TYPE,
                         REQUESTED_RANGE_NOT_SATISFIABLE,
                         EXPECTATION_FAILED,
                         IM_A_TEAPOT,
                         ENHANCE_YOUR_CALM,
                         UNPROCESSABLE_ENTITY,
                         LOCKED,
                         FAILED_DEPENDENCY,
                         METHOD_FAILURE,
                         UNORDERED_COLLECTION,
                         UPGRADE_REQUIRED,
                         PRECONDITION_REQUIRED,
                         TOO_MANY_REQUESTS,
                         REQUEST_HEADER_FIELDS_TOO_LARGE,
                         NO_RESPONSE,
                         RETRY_WITH,
                         BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS,
                         CLIENT_CLOSED_REQUEST,
                         )

# 5xx server error ------------------------------------------------------------

INTERNAL_SERVER_ERROR = 500

NOT_IMPLEMENTED = 501

BAD_GATEWAY = 502

SERVICE_UNAVAILABLE = 503

GATEWAY_TIMEOUT = 504

HTTP_VERSION_NOT_SUPPORTED = 505

VARIANT_ALSO_NEGOTIATES = 506

INSUFFICIENT_STORAGE = 507

LOOP_DETECTED = 508

BANDWIDTH_LIMIT_EXCEEDED = 509

NOT_EXTENDED = 510

NETWORK_AUTHENTICATION_REQUIRED = 511

NETWORK_READ_TIMEOUT_ERROR = 598

NETWORK_CONNECT_TIMEOUT_ERROR = 599

SERVER_ERROR_STATUSES = (INTERNAL_SERVER_ERROR,
                         NOT_IMPLEMENTED,
                         BAD_GATEWAY,
                         SERVICE_UNAVAILABLE,
                         GATEWAY_TIMEOUT,
                         HTTP_VERSION_NOT_SUPPORTED,
                         VARIANT_ALSO_NEGOTIATES,
                         INSUFFICIENT_STORAGE,
                         LOOP_DETECTED,
                         BANDWIDTH_LIMIT_EXCEEDED,
                         NOT_EXTENDED,
                         NETWORK_AUTHENTICATION_REQUIRED,
                         NETWORK_READ_TIMEOUT_ERROR,
                         NETWORK_CONNECT_TIMEOUT_ERROR,
                         )

class _StatusMessages(_Mapping):

    def __new__(cls):
        if cls._inst is None:
            cls._inst = super(_StatusMessages, cls).__new__(cls)
        return cls._inst

    def __init__(self):
        self._keys = set(_http.responses.keys() + self._responses.keys())

    def __getitem__(self, code):
        try:
            return _http.responses[code]
        except KeyError:
            return self._responses[code]

    def __iter__(self):
        return iter(self._keys)

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

    _inst = None

    _responses = {PROCESSING: 'Processing',
                  MULTI_STATUS: 'Multi-Status',
                  ALREADY_REPORTED: 'Already Reported',
                  IM_USED: 'IM Used',
                  PERMANENT_REDIRECT: 'Permanent Redirect',
                  IM_A_TEAPOT: 'I\'m a teapot',
                  ENHANCE_YOUR_CALM: 'Enhance Your Calm',
                  UNPROCESSABLE_ENTITY: 'Unprocessable Entity',
                  LOCKED: 'Locked',
                  FAILED_DEPENDENCY: 'Failed Dependency',
                  UNORDERED_COLLECTION: 'Unordered Collection',
                  UPGRADE_REQUIRED: 'Upgrade Required',
                  PRECONDITION_REQUIRED: 'Precondition Required',
                  TOO_MANY_REQUESTS: 'Too Many Requests',
                  REQUEST_HEADER_FIELDS_TOO_LARGE:
                      'Request Header Fields Too Large',
                  NO_RESPONSE: 'No Response',
                  RETRY_WITH: 'Retry With',
                  BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS:
                      'Blocked by Windows Parental Controls',
                  CLIENT_CLOSED_REQUEST: 'Client Closed Request',
                  VARIANT_ALSO_NEGOTIATES: 'Variant Also Negotiates',
                  INSUFFICIENT_STORAGE: 'Insufficient Storage',
                  LOOP_DETECTED: 'Loop Detected',
                  BANDWIDTH_LIMIT_EXCEEDED: 'Bandwidth Limit Exceeded',
                  NOT_EXTENDED: 'Not Extended',
                  NETWORK_AUTHENTICATION_REQUIRED:
                      'Network Authentication Required',
                  NETWORK_READ_TIMEOUT_ERROR: 'Network read timeout error',
                  NETWORK_CONNECT_TIMEOUT_ERROR:
                      'Network connect timeout error',
                  }

status_messages = _StatusMessages()

def status_str(code):
    try:
        message = status_messages[code]
    except KeyError:
        return str(code)
    else:
        return '{} ({})'.format(message, code)

def statuscode_def_source(code):
    if code in (OK, CREATED, ACCEPTED, NO_CONTENT, MULTIPLE_CHOICES,
                MOVED_PERMANENTLY, FOUND, NOT_MODIFIED, BAD_REQUEST,
                UNAUTHORIZED, FORBIDDEN, NOT_FOUND, INTERNAL_SERVER_ERROR,
                NOT_IMPLEMENTED, BAD_GATEWAY, SERVICE_UNAVAILABLE):
        return 'HTTP/1.0 (RFC 1945)'
    elif code in (VARIANT_ALSO_NEGOTIATES,):
        return 'Transparent Content Negotiation in HTTP (RFC 2295)'
    elif code in (IM_A_TEAPOT,):
        return 'HTCPCP (RFC 2324)'
    elif code in (NOT_EXTENDED,):
        return 'An HTTP Extension Framework (RFC 2774)'
    elif code in (PROCESSING, MULTI_STATUS, UNPROCESSABLE_ENTITY, LOCKED,
                  FAILED_DEPENDENCY, INSUFFICIENT_STORAGE):
        return 'WebDAV (RFC 4918)'
    elif code in (CONTINUE, SWITCHING_PROTOCOLS, NON_AUTHORITATIVE_INFORMATION,
                  RESET_CONTENT, PARTIAL_CONTENT, SEE_OTHER, USE_PROXY,
                  SWITCH_PROXY, TEMPORARY_REDIRECT, PAYMENT_REQUIRED,
                  METHOD_NOT_ALLOWED, NOT_ACCEPTABLE,
                  PROXY_AUTHENTICATION_REQUIRED, REQUEST_TIMEOUT, CONFLICT,
                  GONE, LENGTH_REQUIRED, PRECONDITION_FAILED,
                  REQUEST_ENTITY_TOO_LARGE, REQUEST_URI_TOO_LONG,
                  UNSUPPORTED_MEDIA_TYPE, REQUESTED_RANGE_NOT_SATISFIABLE,
                  EXPECTATION_FAILED, GATEWAY_TIMEOUT,
                  HTTP_VERSION_NOT_SUPPORTED):
        return 'HTTP/1.1 (RFC 2616)'
    elif code in (UPGRADE_REQUIRED,):
        return 'Upgrading to TLS Within HTTP/1.1 (RFC 2817)'
    elif code in (IM_USED,):
        return 'Delta encoding in HTTP (RFC 3229)'
    elif code in (ALREADY_REPORTED, LOOP_DETECTED):
        return 'WebDAV BIND (RFC 5842)'
    elif code in (PRECONDITION_REQUIRED, TOO_MANY_REQUESTS,
                  REQUEST_HEADER_FIELDS_TOO_LARGE,
                  NETWORK_AUTHENTICATION_REQUIRED):
        return 'Additional HTTP Status Codes (RFC 6585)'
    elif code in (PERMANENT_REDIRECT, UNORDERED_COLLECTION):
        return 'Internet-Draft'
    elif code in (BANDWIDTH_LIMIT_EXCEEDED,):
        return 'Apache bw/limited extension'
    elif code in (RETRY_WITH, BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS,
                  NETWORK_READ_TIMEOUT_ERROR, NETWORK_CONNECT_TIMEOUT_ERROR):
        return 'Microsoft'
    elif code in (NO_RESPONSE, CLIENT_CLOSED_REQUEST):
        return 'nginx'
    elif code in (ENHANCE_YOUR_CALM,):
        return 'Twitter'

statuscodes = status_messages.keys()


import math
from random import random, randint, seed
from math import fmod, sin, pi
from time import sleep, time
from colorsys import hsv_to_rgb, rgb_to_hsv, rgb_to_hsv
import undulating_effect

import gradient
import palette
import effect

"""
Vertexes:

0 - top
1 - tree 0
2 - tree 1 (tree + 1 clockwise)
3 - tree 2 (tree + 2 clockwise)

Segments:
3 - top -> tree 0
1 - top -> tree 1
0 - top -> tree 2
4 - tree 0 -> tree 1
5 - tree 1 -> tree 2
2 - tree 2 -> tree 0

"""

class VertexEffect(effect.Effect):

    def __init__(self, led_art, name):
        effect.Effect.__init__(self, led_art, name)
        self.palettes = []
        self.point_distance = .25
        self.hue = random()
        self.hue_increment = .005

    def setup(self, num_leds):
        self.num_leds = num_leds

    def set_color(self, color):
        pass

    def make_palettes(self, hues):
        ''' pass in 4 hues in vertex order '''

        return [                                # segment
            [ (0.0, hues[0]), (1.0, hues[3]) ], # 0
            [ (0.0, hues[0]), (1.0, hues[2]) ], # 1
            [ (0.0, hues[1]), (1.0, hues[3]) ], # 2
            [ (0.0, hues[0]), (1.0, hues[1]) ], # 3
            [ (0.0, hues[1]), (1.0, hues[2]) ], # 4
            [ (0.0, hues[2]), (1.0, hues[3]) ], # 5
        ]

    def create_analogous_palette(self, hue):
        s = random() / 2.0
        return (palette.make_hsv(hue),
                palette.make_hsv(fmod(hue - s + 1.0, 1.0)),
                palette.make_hsv(fmod(hue - (s * 2) + 1.0, 1.0)),
                palette.make_hsv(fmod(hue + s, 1.0)))

    def loop(self):

        hues = self.create_analogous_palette(self.hue)
        palettes = self.make_palettes(hues)
        for i, pal in enumerate(palettes):
            strip = 1 << i
            try:
                g = gradient.Gradient(self.num_leds, pal)
                g.render(self.led_art, 1 << i)
            except ValueError as err:
                pass

        self.led_art.show()

        self.hue += self.hue_increment
        sleep(5)


from math import pi, sin

import matplotlib.pyplot as plt
import numpy as np

nmax = 1000 # pocet kroku
ax = 1 # amplituda x
ay = 2 # amplituda y
az = 1 # amplituda z
fx = 5 # frekvence x
fy = 3 # frekvence y
fz = 2 # frekvence z
phx = 0 # faze x
phy = 0 # faze y
phz = 0 # faze z
tmin = 0 # startovaci cas
tmax = 2*pi # koncovy cas
#filename = 'Lissajous.dat'
xdata=np.zeros(nmax+1)
ydata=np.zeros(nmax+1)
zdata=np.zeros(nmax+1)

#f = open(filename,'w')
for n in range(0,nmax+1):
    t = tmin + n*(tmax-tmin)/nmax
    x = ax*sin(fx*t+phx)
    y = ay*sin(fy*t+phy)
    z = az*sin(fz*t)+phz
    xdata[n]=x
    ydata[n]=y
    zdata[n]=z
    #print(f'{x:8.4f} {y:8.4f} {z:8.4f}', file=f)
ax = plt.figure().add_subplot(projection='3d')
ax.plot(xdata,ydata,zdata,label='Lissajous')
ax.legend()
plt.show()
#f.close()


'''''
@author: zobov

Example:
    Fire a custom event through VideoSDK or Room

API Version: 4.1.0+

'''

import config
import pyVideoSDK
from pyVideoSDK.methods import Methods
from pyVideoSDK.consts import EVENT, METHOD_RESPONSE
import pyVideoSDK.consts as C
from pprint import pprint

print(__doc__)

sdk = pyVideoSDK.open_session(ip = config.IP, port = config.PORT, pin = config.PIN, debug = config.DEBUG)
methods = Methods(sdk)

@sdk.handler(EVENT[C.EV_appStateChanged])
@sdk.handler(METHOD_RESPONSE[C.M_getAppState])
def on_state_change(response):
    print(f'    Application state is {response["appState"]}')

@sdk.handler(METHOD_RESPONSE[C.M_fireMyEvent])
def on_fire_my_event_result(response):
    print("    Method call result:")
    pprint(response)

@sdk.handler(EVENT[C.EV_myEvent])
def on_my_event(response):
    print("    Event:")
    pprint(response)

if __name__ == '__main__':
    methods.fireMyEvent("hello_world_event")
    sdk.run()


#from django.db import models
#from django.db import connection
from django.db import connections

# Create your models here.
# class OBD_Trips_enh:
#   idVehicle = models.AutoField(primary_key=True)
#   idTrip = models.AutoField(primary_key=True)
#   ranking = models.DecimalField

# class OBD_CarData:
#   idData =
#   idVehicle = models.Model(primary_key=true)
#   lat = models.Model()
#   lon = models.Model()

# Gets all trips with ranking >= ranking (in the db)
def getTripsByRanking(ranking):
	cursor = connections['db7x'].cursor()
	cursor.execute("select a.idTrips, a.idVehicles from OBD_Trips_enh a where a.ranking > %s", [ranking])
	desc = cursor.description
	return [
		dict(zip([col[0] for col in desc], row))
		for row in castLongToInt(cursor.fetchall())
	]

# Return a dict in the form {"lats": [], "longs": []} with
# all gps coords from the trip identified by idTrips, idVehicles
def getAllGPSCoordsByTrip(idTrips, idVehicles):
	cursor = connections['db7x'].cursor()
	cursor.execute("select Latitude, Longitude from OBD_CarData where idTrips = %s and idVehicles = %s", [idTrips, idVehicles])
	desc = cursor.description
	return [
		dict(zip([col[0] for col in desc], row))
		for row in cursor.fetchall()
	]

def cleanTrailingLs(dbData):
	result = []
	for (lat, lon) in dbData:
		newLat = lat
		newLon = lon
		if lat.endswith('L'):
			newlat = lat[:len(lat)-1]
		if lon.endswith('L'):
			newlon = lon[:len(lon)-1]
		result.append((newLat, newLon))
	return result

def castLongToInt(dbData):
	result = []
	for (first, second) in dbData:
		result.append((int(first), int(second)))
	return result


from pydantic import BaseModel
from textblob import TextBlob

INPUT_EXAMPLE = {"text": "Wow, this is awesome!"}

class TextblobSubjectivityModel(BaseModel):
    text: str

    class Config:
        schema_extra = {"example": INPUT_EXAMPLE}

def setall(d, keys, value):
    for k in keys:
        d[k] = value

MAX_SCORE = 100
MIN_SCORE = 0

OUTCOMES = {}
setall(OUTCOMES, range(80, MAX_SCORE + 1), "subjective")
setall(OUTCOMES, range(60, 80), "rather subjective")
setall(OUTCOMES, range(40, 60), "neutral")
setall(OUTCOMES, range(20, 40), "rather objective")
setall(OUTCOMES, range(MIN_SCORE, 20), "objective")

def get_mapping_subjectivity(score):
    if score < MIN_SCORE:
        return OUTCOMES[MIN_SCORE]
    return OUTCOMES[int(score)]

def textblob_subjectivity(request: TextblobSubjectivityModel):
    """Calculate subjectivity of a text."""
    blob = TextBlob(request.text)

    return {"subjectivity": get_mapping_subjectivity(blob.sentiment.subjectivity * 100)}


from typing import List
import heapq

class Solution:
    def getOrder(self, tasks: List[List[int]]) -> List[int]:
        n = len(tasks)
        ans = [0 for _ in range(n)]
        pq = []
        sortedTasks = []

        for i in range(n):
            sortedTasks.append((tasks[i][0], tasks[i][1], i))

        sortedTasks.sort()
        heapq.heapify(pq)

        taskIndex = 0
        ansIndex = 0
        currentTime = 0

        while taskIndex < n or len(pq) > 0:
            if len(pq) == 0 and currentTime < sortedTasks[taskIndex][0]:
                currentTime = sortedTasks[taskIndex][0]
            while taskIndex < n and currentTime >= sortedTasks[taskIndex][0]:
                heapq.heappush(pq, (sortedTasks[taskIndex][1], sortedTasks[taskIndex][2]))
                taskIndex += 1
            tup = heapq.heappop(pq)
            processingTime = tup[0]
            index = tup[1]
            currentTime += processingTime
            ans[ansIndex] = index
            ansIndex += 1

        return ans

if __name__ == '__main__':
    T = int(input())
    for i in range(T):
        n = int(input())
        tasks = []
        for j in range(n):
            a = int(input())
            b = int(input())
            tasks.append([a, b])

        solution = Solution()
        print(solution.getOrder(tasks))


from django.shortcuts import render
from datetime import datetime, timedelta

from .forms import CobrancaAdicionalForm

def cobranca_adicional(request):
    total = None
    if request.method == 'POST':
        form = CobrancaAdicionalForm(request.POST)
        if form.is_valid():
            valor_hora = form.cleaned_data['valor_hora']
            hora_inicial = form.cleaned_data['hora_inicial']
            hora_final = form.cleaned_data['hora_final']

            inicio = datetime.combine(datetime.today(), hora_inicial)
            fim = datetime.combine(datetime.today(), hora_final)

            diff = fim - inicio

            print(diff)

            total_minutos = diff.total_seconds() / 60
            print(total_minutos)
            print(type(total_minutos))
            total = int(valor_hora) * (total_minutos / 60)
            print(valor_hora)
            print(type(int(valor_hora)))
    else:
        form = CobrancaAdicionalForm()

    context = {'form': form, 'total': total}
    return render(request, 'cobranca_adicional.html', context)


import torch
from torch.utils.data import Dataset
import torchvision
from torchvision import datasets
import torchvision.models as models
import matplotlib.pyplot as plt
import os
import pandas as pd
from torchvision.io import read_image
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from datetime import datetime
import time
import argparse
import numpy as np
import random as rand
from functools import partial
from typing import Any, cast, Dict, List, Optional, Union
import torch
import torch.nn as nn
import torch.multiprocessing as mp
from torch.multiprocessing import set_start_method

#from ..transforms._presets import ImageClassification
#from ..utils import _log_api_usage_once
#from ._api import register_model, Weights, WeightsEnum
#from ._meta import _IMAGENET_CATEGORIES
#from ._utils import _ovewrite_named_param, handle_legacy_interface

# training an Epoch Function
# change to not use global variables

# after epoch 50, stopped, restarted with eight decay 0.005
# and with batch size 128
# change this back and run from las in VGGModelStates to continue

class VGG16(nn.Module):
    def __init__(self, num_classes=1000):
        super(VGG16, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU())
        self.layer2 = nn.Sequential(
            nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size = 2, stride = 2))
        self.layer3 = nn.Sequential(
            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU())
        self.layer4 = nn.Sequential(
            nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size = 2, stride = 2))
        self.layer5 = nn.Sequential(
            nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU())
        self.layer6 = nn.Sequential(
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU())
        self.layer7 = nn.Sequential(
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size = 2, stride = 2))
        self.layer8 = nn.Sequential(
            nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU())
        self.layer9 = nn.Sequential(
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU())
        self.layer10 = nn.Sequential(
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size = 2, stride = 2))
        self.layer11 = nn.Sequential(
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU())
        self.layer12 = nn.Sequential(
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU())
        self.layer13 = nn.Sequential(
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size = 2, stride = 2))
        self.fc = nn.Sequential(
            nn.Dropout(0.5),
            nn.Linear(7*7*512, 4096),
            nn.ReLU())
        self.fc1 = nn.Sequential(
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU())
        self.fc2= nn.Sequential(
            nn.Linear(4096, num_classes))

    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = self.layer5(out)
        out = self.layer6(out)
        out = self.layer7(out)
        out = self.layer8(out)
        out = self.layer9(out)
        out = self.layer10(out)
        out = self.layer11(out)
        out = self.layer12(out)
        out = self.layer13(out)
        out = out.reshape(out.size(0), -1)
        out = self.fc(out)
        out = self.fc1(out)
        out = self.fc2(out)
        return out

def set_optimizer(learn_r, momen=0.9, weight_d=0.0005):
    # Choosing Optimizer and Loss Function, default lr=0.001, momentum=0.9
    optim_internal = torch.optim.SGD(model.parameters(), lr=learn_r, momentum=momen, weight_decay= weight_d)
    return optim_internal

def train_one_epoch(epoch_index, train_loader, input_model, optim, loss_func, prof):#, Q):#, prof):
    start_time = time.time()
    running_loss = 0.
    last_loss = 0.
    time_1000 = 0.
    step_time = 0.
    # Here, we use enumerate(training_loader) instead of
    # iter(training_loader) so that we can track the batch
    # index and do some intra-epoch reporting
    # pointers not loading, still uses cpu to load up images
    # loading up images is single threaded
    # optimize image loading
    # use profilier ot see if gpu bound
    prof.start()
    for i, data in enumerate(train_loader):
        #if i == 0:
        #    prof.start()
        # Every data instance is an input + label pair
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)

        # Zero gradients every batch, set_to_none=True reduces time
        optim.zero_grad(set_to_none=True)

        # Make predictions for this batch
        outputs = input_model(inputs)

        # Compute the loss and its gradients
        loss_start = time.time()
        loss = loss_func(outputs, labels)
        loss.backward()
        optim_start = time.time()
        loss_time = optim_start - loss_start
        #print('Time for loss function:',loss_time)
        # Adjust learning weights
        optim.step()
        optim_stop = time.time()

        step_time += optim_stop - optim_start
        #print('Time for optimizer:',step_time)
        # Gather data and report
        # save weight matrix, turn off, run again and compare, are they the same
        # also compare a few batches later
        # check to make sure
        # accre??
        running_loss += loss.item()
        #prof.step()
        #prof.stop()
        #print(prof.key_averages())
        if i % 1000 == 999:
            last_loss = running_loss / 1000 # loss per batch
            print('  batch {} || loss: {} || Timestamp: {}'.format(i + 1, last_loss, datetime.now()))
            #tb_x = epoch_index * len(train_loader) + i + 1
            #tb_writer.add_scalar('Loss/train', last_loss, tb_x)
            running_loss = 0.
            #if i == 999:
                #prof.stop()
                #print(prof.key_averages())
    scheduler.step()
    end_time = time.time()
    epoch_time = end_time - start_time
    #prof.stop()
    #print(prof.key_averages())
    #Q.put(last_loss, epoch_time, step_time)
    return last_loss, epoch_time, step_time

if __name__ == "__main__":

    parser = argparse.ArgumentParser(
        description="Train VGG16 Network"
    )
    parser.add_argument(
        "--batch_size",
        "-b",
        type=int,
        default=128,
        help="batch size for the images passing through networks",
    )
    parser.add_argument(
        "--data_dir",
        "-d",
        type=str,
        help="directory of the images data",
        default="/data/ImageNet/",
    )
    parser.add_argument(
        "--img_trans_train",
        "-itr",
        type=str,
        help="functions desired for training transforms",
        default="ToTensor, Resize-256, RandomCrop-224"
    )
    parser.add_argument(
        "--img_trans_test",
        "-ite",
        type=str,
        help="functions desired for testing transforms",
        default="ToTensor, Resize-256, CenterCrop-224"
    )
    parser.add_argument(
        "--learning_rate",
        "-lr",
        type=float,
        help="initial learning rate for training",
        default=0.01
    )
    parser.add_argument(
        "--momentum",
        "-mom",
        type=float,
        help="momentum for training",
        default=0.9
    )
    parser.add_argument(
        "--seed",
        "-s",
        type=int,
        help="momentum for training",
        default=0
    )
    parser.add_argument(
        "--num_epochs",
        "-ne",
        type=int,
        help="number of epochs to run",
        default=74
    )
    parser.add_argument(
        "--from_trained",
        "-ft",
        type=str,
        help="model to train from"
    )
    args = parser.parse_args()

    # on restart after epoch 25, lr=1.0000000000000002e-08

    # use_deterministic makes all operations deterministic, not just backends behavior
    torch.use_deterministic_algorithms(mode=True)

    # causes cuDNN to deterministically select an algorithm
    torch.backends.cudnn.benchmark = False

    # setting seeds for types of functions
    random_seed = args.seed
    torch.manual_seed(random_seed)
    rand.seed(random_seed)
    np.random.seed(random_seed)

    # Creating Image Transformations

    # Cropping and seeding for randomization / image order
    # GPU variability harder to control
    # getting GPU determinabiolity in pytorch (harder)

    # make flags for implementation (maybe turn off initially)
    '''''
    trans_list_train = args.img_trans_train.split(', ')
    for trans in trans_list_train:
        trans.replace(' ', '')
    trans_train = ['torchvision.transforms.' + x for x in trans_list_train]

    trans_list_test = args.img_trans_test.split(', ')
    for trans in trans_list_test:
        trans.replace(' ', '')
    print('\n\n\n')
    print(trans_list_test)
    print('\n\n\n')

    transforms_training = exec('torchvision.transforms.Compose([' + ', '.join(trans_train) + '])')
    transforms_testing = exec('torchvision.transforms.Compose([' + ', '.join(trans_test) + '])')
    print('\n\n\n')
    print(transforms_testing)
    print('\n\n\n')
    '''''
# run through several epochs with profiler
# fancy pca color shift is what paper uses
    transforms_training = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor(),
    #torchvision.transforms.ColorJitter(),
    #torchvision.transforms.RandomAffine(),
    #torchvision.transforms.RandomPerspective(),
    torchvision.transforms.Resize((256,256)),
    torchvision.transforms.RandomCrop((224,224)),
    #torchvision.transforms.RandomVerticalFlip(),
    #torchvision.transforms.RandomHorizontalFlip(),
    ])

    transforms_testing = torchvision.transforms.Compose([
        torchvision.transforms.ToTensor(),
        torchvision.transforms.Resize((256,256)),
        torchvision.transforms.CenterCrop((224,224))
    ])

    # Creating Datasets
    # try number of workers or device to cuda
    # prefetching!!, etc
    # working on future batches as GPU runs
    # leverage parallelizing
    # want to see accuracy
    # similar accuracy as in paper
    # two types, exactly correct or within top 5 guesses
    # need ot make it to go much faster

    # same or valid average pooling
    # see if truly deterministic

    training_dataset = datasets.ImageFolder(root= args.data_dir + 'train', transform= transforms_training)
    test_dataset = datasets.ImageFolder(root= args.data_dir + 'sortedVal', transform= transforms_testing)

    # Creating Data Loaders
    training_loader = torch.utils.data.DataLoader(training_dataset, batch_size=args.batch_size, shuffle=True, num_workers = 14, pin_memory=True)
    test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=args.batch_size, shuffle=False, num_workers = 14)

    # Choosing device as GPU
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    # initializing epoch number
    epoch_number = 0

    # initializing VGG16 model
    model = VGG16()
    # using GPUs
    model = torch.nn.DataParallel(model, device_ids=[0,1])
    model = model.to(device)

    torch.autocast('cpu', enabled=False)
    # lr=0.001, momentum=0.9
    # lr=0.0001 after 19 epochs
    # lr=0.00001 after 29

    learning_rate = args.learning_rate

    # Chosing Optimier and Loss Function
    optimizer = set_optimizer(learning_rate)
    scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=10)
    #torch.optim.SGD(model.parameters(), lr=args.learning_rate, momentum=args.momentum, weight_decay= 0.005)

    # make sure the cross entropy is same for binary / categorical
    loss_fn = torch.nn.CrossEntropyLoss()
    loss_fn = loss_fn.to(device)
    #torch.use_autocast = False
    # Loading VGG model
    if args.from_trained:
        print('Using Pretrained Model State')
        pretrain_name = args.from_trained
        model.load_state_dict(torch.load(pretrain_name))
        epoch_idx = pretrain_name.find('_ep-')
        print('\n\n\nEpoch idx:', epoch_idx)
        print(pretrain_name[epoch_idx+4:epoch_idx+6])
        epoch_number = int(pretrain_name[epoch_idx+4:epoch_idx+6]) + 1
        print('\nEpoch Number:', epoch_number)

    # Initializing epochs, vloss and timimg
    EPOCHS = args.num_epochs - epoch_number
    print('Total Epochs Remaining:', EPOCHS)
    timestamp = datetime.now().strftime('%Y/%m/%d_%H:%M:%S')
    i = 0
    argStr= []
    prev_accuracy=0
    for key, value in vars(args).items():
    # do stuff
        argStr.append(f'ag-{str(key)}<{str(value)}')
    '_'.join(argStr)
    print(argStr)
    # inject information about paramerters, make title all the parameters
    # or can write a header into the file, concatenate afterward
    # make sure you are saving exact params into file
    writer = SummaryWriter('runs/vgg16-ImageNet_trainer_ts-{}_{}'.format(timestamp, argStr))
    best_vloss = 1_000_000.

    # Running loop for training
    prof = torch.profiler.profile(
           activities=[torch.profiler.ProfilerActivity.CPU, torch.profiler.ProfilerActivity.CUDA],
            #schedule=torch.profiler.schedule(wait=1, warmup=1, active=1),
            on_trace_ready=torch.profiler.tensorboard_trace_handler('./prof_logs/VGG16'),
            #record_shapes=True,
            #profile_memory=True,
            #with_stack=True,
            #with_flops=True,
            #with_modules=True
            )
    for epoch in range(EPOCHS):
        total_start_time = datetime.now()
        print('EPOCH {} | {}:'.format(epoch_number + 1, datetime.now()))

        # Make sure gradient tracking is on, and do a pass over the data
        model.train(True)
        #model.share_memory()
        train_processes = []
        num_processes = 16
        #set_start_method('spawn')
        #Que = mp.Queue()
        #for rank in range(num_processes):
        #p = mp.spawn(train_one_epoch, args=(epoch_number, training_loader, model, optimizer, loss_fn, Que))
        avg_loss, epoch_time, step_time = train_one_epoch(epoch_number, training_loader, model, optimizer, loss_fn, prof)
        #p.start()
            #train_processes.append(p)
        #sfor p in train_processes:
        #p.join()
        #avg_loss, epoch_time, step_time = Que.get()
        running_vloss = 0.0
        top1_correct_total = 0.0
        top5_correct_total = 0.0
        total_samples = 0.0
        # Set the model to evaluation mode, disabling dropout and using population
        # statistics for batch normalization.
        # want to know about model.eval()
        # diabling dropout? == Yes
        model.eval()

        # Disable gradient computation and reduce memory consumption.
        with torch.no_grad():
            for i, vdata in enumerate(test_loader):
                vinputs, vlabels = vdata
                vinputs, vlabels = vinputs.to(device), vlabels.to(device)
                voutputs = model(vinputs)
                vloss = loss_fn(voutputs, vlabels)
                running_vloss += vloss
                top1_correct_total += (voutputs.argmax(1) == vlabels).sum().item()
                top5pred = torch.topk(voutputs, 5)
                for pred in top5pred:
                    top5_correct_total += (pred == vlabels).sum().item()
                total_samples += vlabels.size(0)
        avg_vloss = running_vloss / (i + 1)
        accuracy1 = top1_correct_total / total_samples
        accuracy5 = top5_correct_total / total_samples
        print('LOSS: train {} valid {}'.format(avg_loss, avg_vloss))
        print('Top1 Accuracy:', accuracy1)
        print('Top5 Accuracy:', accuracy5)
        '''''
        if (accuracy1 <= prev_accuracy):
            learning_rate = learning_rate / 10
            optimizer = set_optimizer(learning_rate)
            print(f'-------------\nUpdating Optimizer to use lr={learning_rate}\n-------------')
        '''''
        # Log the running loss averaged per batch
        # for both training and validation
        try:
            current_lr = scheduler.getlr()
        except:
            current_lr = 0

        writer.add_scalars('Training , Validation Loss, Learning Rate, Accuracies',
                        { 'Training' : avg_loss, 'Validation' : avg_vloss, 'LearningRate' : current_lr, 'AccuracyTop1' : accuracy1, 'AccuracyTop5' : accuracy5, 'Epoch Time': epoch_time},
                        epoch_number + 1)
        writer.flush()

        # Track best performance, and save the model's state
        # figure out how big model is
        # is it viable to save every model??
        # just save the weights?
        # want to be able to track performance over epoch / time
        # saving epoch is useful in case computer crashes
        # saving just weights wouldnt retain state of training
        if avg_vloss < best_vloss:
            best_vloss = avg_vloss
            vloss_better = True
        else:
            vloss_better = False
        timestamp = datetime.now()
        total_end_time = datetime.now()
        total_time = total_start_time - total_end_time
        model_path = '/data/brustdm/model_imp/VGG16ModelStates(Newer)/model_ts-{}_ep-{}_et-{}_tt-{}_st-{}_bv-{}_a1-{}_a5-{}'.format(timestamp, epoch_number, epoch_time, total_time, step_time, vloss_better, accuracy1, accuracy5)
        torch.save(model.state_dict(), model_path)
        prev_accuracy = accuracy1
        epoch_number += 1

    # note how long training step takes and epoch takes
    # ballpark it should take around a week to train
    # 3 seconds per step over time is quite a lot
    # mem/ cpu/ gpu, maximize use of all 3 at all times
    # must have bottleneck but get the best as possible
    # small models usually cpu bottleneck
    # possible to use both GPUs to train one model

    # definitely look at accuracy, what matters for replication

    # pytorch profiling tools, blocks that show bottlenecks (tensorflow version)
    # same, one batch , one step, one epoch
    # experimental new vscode, makes notebooks faster
    # notebooks better for presentation only

    # copilot?

    # implement topk!!!!