#!/usr/bin/env python3

import os
import random
import signal
import socket
import struct
import sys
import threading
import time
from datetime import datetime
from datetime import timedelta

Z = 2
W = 3
X = 3
T = 1
M = 3
# Packet_type

REG_REQ = 0xa0
REG_ACK = 0xa1
REG_NACK = 0xa2
REG_REJ = 0xa3
REG_INFO = 0xa4
INFO_ACK = 0xa5
INFO_NACK = 0xa6
INFO_REJ = 0xa7
ALIVE_NACK = 0xb1
ALIVE_REJ = 0xb2
SEND_DATA = 0xc0
DATA_ACK = 0xc1
DATA_NACK = 0xc2
DATA_REJ = 0xc3
SET_DATA = 0xc4
GET_DATA = 0xc5

# Client-server state

DISCONNECTED = 0xf0
NOT_REGISTERED = 0xf1
WAIT_ACK_REG = 0xf2
WAIT_INFO = 0xf3
WAIT_ACK_INFO = 0xf4
REGISTERED = 0xf5
SEND_ALIVE = 0xf6
ALIVE = 0xb0

class Server:
    def __init__(self):
        self.id = None
        self.port_UDP = None
        self.port_TCP = None

class Clients:
    def __init__(self):
        self.id = None
        self.ip = None
        self.id_comm = None
        self.all_elements = None
        self.element_and_value = [[]]
        self.status = None
        self.udp_port = None
        self.tcp_port = None
        self.udp_socket = None
        self.consecutive_alive = 0
        self.receive_alive = False
        self.first_alive_recv = False

class Socket:
    def __init__(self):
        self.udp_socket = None
        self.tcp_socket = None
        self.connection_socket = None

# GLobal Functions
allowed_client = []
debug_mode = False
sock = Socket()
server_inf = Server()

# ----------------------------SOCKETS------------------------------------------#
def udp_socket():
    # Funcio que obra socket amb el port UDP de les dades del servidor
    global server_inf
    global sock
    sock = Socket()
    sock.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.udp_socket.bind(("", server_inf.port_UDP))

def client_udp_socket(client):
    # Funcio que obra socket amb el port UDP aleatori per intercambiar el REG_INFO amb el client

    global server_inf
    client.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    client.udp_socket.bind(("", 0))
    ip, port = client.udp_socket.getsockname()

    if (debug_mode == True):
        print_message("Port UDP : " + str(port) + " obert al client: " + client.id)

    return port

def tcp_socket():
    # Funcio que obra socket amb el port TCP del servidor
    global sock
    global server_inf
    sock.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.tcp_socket.bind(("", server_inf.port_TCP))
    sock.tcp_socket.listen(5)

def client_tcp_socket(client):
    # Funcio que obra socket amb el port TCP rebut del client
    client.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_address = (client.ip, int(client.tcp_port))
    client.tcp_socket.connect(client_address)
    print_message("Iniciant protocol TCP al port: " + str(client.tcp_port) + " per al client: " + client.id)

# -----------------------------REGISTER && ALIVE FUNCTIONS------------------------------------------#
def udp_loop():
    """ Funcio que continuament esta rebent els paquets UDP dels diferents clients
    connectats.Per cada paquet es crea un fil que tractara el paquet segons el seu tipus.
    Per aqui s'haurien de rebre sol REG_REQ i ALIVES """
    global sock
    while (1):
        try:
            sock.udp_socket.settimeout(2)
            recieved_pck_udp, client_ip, client_port = receive_udp_packet(84, sock.udp_socket)
            pack_ack = threading.Thread(target=register_loop, args=(recieved_pck_udp, client_ip, client_port))
            pack_ack.start()
        except socket.error as socketerror:
            """Com a altres funcions, he decidit optar per utilitzar el .settimeout()
            que retorna una exepcio en cas de no rebre res en el temps esmentat.En el nostre cas
            la manera de tractar el error es ignorarlo, ya que rebem una excepcio per cada paquet no rebut"""
            error = "ignore"

def register_loop(recieved_pck_udp, client_ip, client_port):
    """ Funcio cridada per UDP_loop(), tracta cada tipus de paquet(REG_REQ i ALIVE),
    cridant les seves respectives funcions de tractament """
    pack_type = recieved_pck_udp[0]
    if pack_type == REG_REQ:
        register_reg(recieved_pck_udp, client_ip, client_port)
    if pack_type == ALIVE:
        alive_phase(recieved_pck_udp)

def register_reg(received_package, client_ip, client_udp_port):
    """Tracta els paquets REG_REQ que rep, en cas de ser ivalids enviem REG_REJ.
    Si es valid i el client esta en DISCONNECTED,
    pasarem de fase per completar el registre del client"""

    global sock
    client_id_transm = received_package[1].decode().split("\x00")[0]
    client_id_comm = received_package[2].decode().split("\x00")[0]
    client_dades = received_package[3].decode(errors="ignore").split("\x00")[0]
    if not client_id_and_id_comm_valid(client_id_transm, client_id_comm) and len(client_dades) > 0:
        print_message("ERROR -> Paquet del client: " + client_id_transm + " no valid, enviant REG_REJ....")
        send_pck = reg_rej_pack_maker("Dades incorrectes")
        sock.udp_socket.sendto(send_pck, (client_ip, client_udp_port))
        return

    valid_client = get_client_by_Id(client_id_transm)
    valid_client.ip = client_ip
    valid_client.id_comm = client_id_comm
    valid_client.udp_port = client_udp_port

    if valid_client.status == DISCONNECTED:
        reg_ack_phase(valid_client)
    else:
        """En cas de barrejar estats i rebre un reg_req en un estat incorrecte,
        tornem el client a DISCONNECTED"""

        print_message("Rebut paquet REG_REQ en estat diferent a Disconnected")
        change_status(valid_client.id, DISCONNECTED)

def reg_ack_phase(valid_client):
    """Tractament complet del REG_REQ"""
    global sock
    # Creo id_comm i nou port per on iniciarem l'intercanvi del REG_INFO
    rand_num = random.randint(1111111111, 9999999999)
    valid_client.id_comm = str(rand_num)

    # Obrim socket per rebre el REG_INFO
    port_aleatori = client_udp_socket(valid_client)

    # Envio REG_ACK amb el port creat anteriorment
    send_pck = reg_ack_pack_maker(rand_num, port_aleatori)
    send_udp_packet(valid_client, send_pck)
    change_status(valid_client.id, WAIT_INFO)

    """Aqui obtenim el REG_INFO amb el socket obert anteriorment,
    i li afegim un temps Z * T per rebrel"""
    try:
        valid_client.udp_socket.settimeout(Z * T)
        reg_info, client_ip, client_port = receive_udp_packet(84, valid_client.udp_socket)
    except socket.error as socketerror:
        print_message("Paquet REG_INFO no rebut")
        valid_client.udp_socket.close()
        change_status(valid_client.id, DISCONNECTED)
        return
    valid_client.udp_socket.close()
    # Tanquem socket i tractem el REG_INFO

    pack_type = reg_info[0]
    client_id_comm = reg_info[2].decode().split("\x00")[0]
    client_dades = reg_info[3].decode(errors="ignore").split("\x00")[0]

    # Tractament del REG_INFO
    if pack_type == REG_INFO and client_ip == valid_client.ip and client_id_comm == valid_client.id_comm \
            and len(client_dades) > 10 and valid_client.status == WAIT_INFO:

        set_reg_client_data(valid_client, client_dades)
        send_info_ack = info_ack_pack_maker(valid_client.id_comm)
        send_udp_packet(valid_client, send_info_ack)
        change_status(valid_client.id, REGISTERED)

        # Si completem registre, obrim fil del controlador periodic de comunicació amb el client (wait_alive())
        alive_timeout = datetime.now() + timedelta(seconds=3)
        alive_treatment = threading.Thread(target=wait_alives, args=(valid_client.id, alive_timeout))
        alive_treatment.start()
        return
    else:
        print_message("Paquet REG_INFO incorrecte")
        send_info_nack = info_nack_pack_maker("Dades incorrectes", valid_client.id_comm)
        send_udp_packet(valid_client, send_info_nack)
        change_status(valid_client.id, DISCONNECTED)
        return

def alive_phase(recv_pack):
    """Funcio que tracta els paquets ALIVES rebuts per l'UDP_loop.
    La variable self.first_alive_recv controla que el primer paquet s'hagui rebut,
    i la self.receive_alive serveix per sincronitzar l'estat amb el fil wait_alives,
    per saber si rep ALIVES en el temps demanat"""

    client_id_transm = recv_pack[1].decode().split("\x00")[0]
    client_id_comm = recv_pack[2].decode().split("\x00")[0]
    client_dades = recv_pack[3].decode("latin-1").split("\x00")[0]
    alive_client = get_client_by_Id(client_id_transm)

    if alive_client.status == REGISTERED or alive_client.status == SEND_ALIVE:
        if alive_client.id_comm == client_id_comm and len(client_dades) == 0:
            if alive_client.status == REGISTERED:
                alive_client.first_alive_recv = True
            alive_client.receive_alive = True
            alive_pck = alive_pack_maker(alive_client.id, alive_client.id_comm)
            send_udp_packet(alive_client, alive_pck)
            return
        elif alive_client.status == REGISTERED:
            print("INFO -> 1r Alive no valid: ", alive_client.id)
            alive_rej_pck = alive_rej_pack_maker(alive_client.id, alive_client.id_comm)
            send_udp_packet(alive_client, alive_rej_pck)
            change_status(alive_client.id, DISCONNECTED)
            return
        else:
            print("SERVER -> ALIVE no valid ")
            alive_rej_pck = alive_rej_pack_maker(alive_client.id, alive_client.id_comm)
            send_udp_packet(alive_client, alive_rej_pck)
            change_status(alive_client.id, DISCONNECTED)
            return
    else:
        print("SERVER -> ALIVE del client: " + client_id_transm + " no acceptat, client no esta REGISTERED o SEND_ALIVE ")
        return

def wait_alives(client_id, alive_timeout):
    """Aquesta funcio controla la comunicacio periodica del client.
    Com hem esmentat anteriorment, self.receive_alive controla si el paquet es rep en el minim de temps,
    si no es rep es suma 1 a ALIVES consecutius no rebuts( alive_client.consecutive_alive ).
    Als tres ALIVES no rebuts, client pasa a DISCONNECTED"""

    alive_client = get_client_by_Id(client_id)
    if alive_client.status == REGISTERED:
        """Controlem si el primer paquet s'ha rebut,
        si no es rep client es pasa a DISCONNECTED"""
        received_first_packet = False
        while datetime.now() < alive_timeout:
            if alive_client.first_alive_recv == True and alive_client.receive_alive:
                received_first_packet = True
                change_status(client_id, SEND_ALIVE)
                break
        if not received_first_packet:
            print_message("Primer Paquet ALIVE ha arribat a temps")
            change_status(client_id, DISCONNECTED)
            return

    while alive_client.status == SEND_ALIVE:
        send_alive_timeout = datetime.now() + timedelta(seconds=2)
        alive_client.receive_alive = False
        received_alive = False
        while datetime.now() < send_alive_timeout:
            if alive_client.receive_alive:
                alive_client.consecutive_alive = 0
                received_alive = True
        if not received_alive:
            alive_client.consecutive_alive += 1

        if alive_client.consecutive_alive == 3:
            print("No s'han rebut 3 ALIVE consecutius del client: ", alive_client.id)
            alive_client.consecutive_alive = 0
            change_status(client_id, DISCONNECTED)
            return

# -----------------------------TCP && SET/GET FUNCTIONS------------------------------------------#
def tcp_loop():
    """ Funcio que continuament esta rebent els paquets TCP dels diferents clients
    connectats. Per cada paquet es crea un fil que tractara el paquet.
    Per aqui s'haurien de rebre SEND_DATA"""
    global sock
    while 1:
        try:
            sock.tcp_socket.settimeout(3)
            private_socket, (client_ip, client_port) = sock.tcp_socket.accept()
            received_pck_tcp = receive_tcp_packet(127, private_socket)

            if received_pck_tcp:
                pack_procedure = threading.Thread(target=tcp_pack_procedure, args=(received_pck_tcp, private_socket))
                pack_procedure.start()
        except socket.error as socket_error:
            socket_error = "error"

def tcp_pack_procedure(packet, sockets):
    """ Funcio feta fil per TCP_LOOP(), tracta els SEND_DATA.
    SI rebes algun tipus de paquet incorrecte no el tractaria"""

    client_id = packet[1].decode().split("\x00")[0]
    if packet[0] == SEND_DATA:
        send_data_procedure(packet, sockets)

# -----------------------------SEND && RECEIVE UDP/TCP------------------------------------------#
def send_udp_packet(client, packet):
    #Funcio per enviar paquets amb UDP
    sock.udp_socket.sendto(packet, (client.ip, client.udp_port))

    received_package_unpacked = struct.unpack('B11s11s61s', packet)
    pack_type = received_package_unpacked[0]
    client_id_transm = received_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = received_package_unpacked[2].decode().split("\x00")[0]
    client_dades = received_package_unpacked[3].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("UDP PACKET Send -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Dades: " + client_dades)

def receive_udp_packet(num_bytes, sockets):
    #Funcio per rebre paquets amb UDP
    global sock
    global debug_mode
    received_pck_udp, (client_ip, client_port) = sockets.recvfrom(num_bytes)
    received_package_unpacked = struct.unpack('B11s11s61s', received_pck_udp)
    pack_type = received_package_unpacked[0]
    client_id_transm = received_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = received_package_unpacked[2].decode().split("\x00")[0]
    client_dades = received_package_unpacked[3].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("UDP PACKET Recv -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Dades: " + client_dades)
    return received_package_unpacked, client_ip, client_port

def receive_tcp_packet(num_bytes, sockets):
    #Funcio per rebre paquets amb TCP
    global sock
    global debug_mode
    recieved_pck_tcp = sockets.recv(num_bytes)

    if recieved_pck_tcp == b'':
        print("Paquet TCP no arribat")
        return False

    received_package_unpacked = struct.unpack('B11s11s8s16s80s', recieved_pck_tcp)
    pack_type = received_package_unpacked[0]
    client_id_transm = received_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = received_package_unpacked[2].decode().split("\x00")[0]
    client_element = received_package_unpacked[3].decode().split("\x00")[0]
    client_valor = received_package_unpacked[4].decode(errors="ignore").split("\x00")[0]
    client_info = received_package_unpacked[5].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("TCP PACKET Recv -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Element: " + client_element + ", " +
                      "valor: " + client_valor + ", " +
                      "info: " + client_info)
    return received_package_unpacked

def send_tcp_packet(packet, sockets):
    #Funcio per enviar paquets amb TCP
    global sock
    global debug_mode

    sockets.sendall(packet)

    send_package_unpacked = struct.unpack('B11s11s8s16s80s', packet)
    pack_type = packet[0]
    client_id_transm = send_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = send_package_unpacked[2].decode().split("\x00")[0]
    client_element = send_package_unpacked[3].decode().split("\x00")[0]
    client_valor = send_package_unpacked[4].decode(errors="ignore").split("\x00")[0]
    client_info = send_package_unpacked[5].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("TCP PACKET Send -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Element: " + client_element + ", " +
                      "valor: " + client_valor + ", " +
                      "info: " + client_info)
    return

# -----------------------------ERROR CONTROL && PACKET MAKERS------------------------------------------#
"""En aquesta seccio trobarem tots el paquets
que revisen els condicionals de les funcions
o constructors de paquets per enviar durant
el proces de registre o paquets per enviar amb TCP"""

def client_id_and_id_comm_valid(client_id, client_id_comm):
    if get_client_by_Id(client_id):
        return client_id_comm == "0000000000"
    return False

def random_comm_and_id_valid(client, client_id_comm, client_id):
    if client.id_comm == client_id_comm:
        return client_id == client.ip
    return False

def reg_ack_pack_maker(random_comm, client_port):
    reg_ack_pck = struct.pack('B11s11s61s', REG_ACK, bytes(server_inf.id, 'ascii'), bytes(str(random_comm), 'ascii'),
                              bytes(str(client_port), 'ascii'))
    return reg_ack_pck

def info_ack_pack_maker(id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', INFO_ACK, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(server_inf.port_TCP), 'ascii'))
    return reg_ack_pck

def reg_rej_pack_maker(motiu):
    reg_ack_pck = struct.pack('B11s11s61s', REG_REJ, bytes(server_inf.id, 'ascii'), bytes("0000000000", 'ascii'),
                              bytes(motiu, 'ascii'))
    return reg_ack_pck

def info_nack_pack_maker(motiu, id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', INFO_NACK, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(motiu, 'ascii'))
    return reg_ack_pck

def alive_pack_maker(client_id, id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', ALIVE, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(client_id, 'ascii'))
    return reg_ack_pck

def alive_rej_pack_maker(client_id, id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', ALIVE_REJ, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(client_id, 'ascii'))
    return reg_ack_pck

def data_ack_pack_maker(client_id, id_comm, element, valor):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', DATA_ACK, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(element), 'ascii'), bytes(str(valor), 'ascii'), bytes(client_id, 'ascii'))
    return reg_ack_pck

def data_rej_pack_maker(motiu):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', DATA_REJ, bytes(server_inf.id, 'ascii'), bytes("", 'ascii'),
                              bytes("", 'ascii'), bytes("", 'ascii'), bytes(motiu, 'ascii'))
    return reg_ack_pck

def set_data_maker(client_id, id_comm, element, valor):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', SET_DATA, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(element), 'ascii'), bytes(str(valor), 'ascii'), bytes(client_id, 'ascii'))
    return reg_ack_pck

def get_data_pack_maker(client_id, id_comm, element):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', GET_DATA, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(element), 'ascii'), bytes("", 'ascii'), bytes(client_id, 'ascii'))
    return reg_ack_pck

def element_exist(client, element):
    token = client.all_elements.split(";")

    for true_element in token:
        if element == true_element:
            return True
    return False

# -----------------------------TCP DATA TREATMENT------------------------------------------#
def send_data_procedure(data_pack, socket):
    """Tracta els SEND_DATA rebuts via TCP pel port del client.
    Si tot es correcte la funcio data_maker crea i guarda els diferents canvies en els elements en un "client_id".data"""
    client_id = data_pack[1].decode().split("\x00")[0]
    client_id_comm = data_pack[2].decode().split("\x00")[0]
    client_element = data_pack[3].decode().split("\x00")[0]
    client_valor = data_pack[4].decode("latin-1").split("\x00")[0]

    data_client = get_client_by_Id(client_id)
    if not data_client:
        for clients in allowed_client:
            if clients.id_comm == client_id_comm:
                send_package = data_rej_pack_maker("ID del client incorrecte")
                socket.send(send_package)
                change_status(clients.id, DISCONNECTED)
        return

    if client_id_comm == data_client.id_comm and element_exist(data_client, client_element):
        data_maker(client_id, str_status(data_pack[0]), client_element, client_valor, 0)
        send_package = data_ack_pack_maker(client_id, client_id_comm, client_element, client_valor)
        socket.send(send_package)
        return
    else:
        send_package = data_rej_pack_maker("Dades del dispositiu incorrectes")
        socket.send(send_package)
        change_status(client_id, DISCONNECTED)
        return

def set_call(argument):
    """Tracta la comanda set del servidor. Si rep resposta, pasa a la funcio set_get_rec_procedure que tractara el paquet rebut.
    Si no rep resposta es considera com que el client ha perdut contacte i es pasa a DISCONNECTED"""

    if len(argument.split(" ")) != 4:
        print("Us de la comanda: set <identificador_dispositiu> <identificador_element> <nou_valor>")
        return
    client_id = argument.split(" ")[1]
    element = argument.split(" ")[2]
    valor_element = argument.split(" ")[3]
    client = get_client_by_Id(client_id)

    if client is not False and element_exist(client, element):
        if element.split("-")[2] == "I":
            client_tcp_socket(client)
            send_pck = set_data_maker(client_id, client.id_comm, element, valor_element)
            send_tcp_packet(send_pck, client.tcp_socket)

            try:
                client.tcp_socket.settimeout(M)
                recv_packet = receive_tcp_packet(127, client.tcp_socket)
                if not recv_packet:
                    return
                set_get_rec_procedure(recv_packet, client, element, SET_DATA)
                client.tcp_socket.close()
                return

            except socket.error as socketerror:
                """Tractem l'excepcio del .settimeout com a resposta no rebuda
                i canviem client a DISCONNECTED"""

                client.tcp_socket.close()
                print_message("Resposta al SET_DATA no rebuda")
                change_status(client_id, DISCONNECTED)
                return
        print_message("L'element anomenat: " + element + " és un sensor i no permet establir el seu valor")
        return
    else:
        print_message("SET_DATA no realitzat: Dades incorrectes o estat diferent a SEND_ALIVE")
    print("Us de la comanda: set <identificador_dispositiu> <identificador_element> <nou_valor>")

def get_call(argument):
    """Tracta la comanda get del servidor. Si rep resposta, pasa a la funcio set_get_rec_procedure que tractara el paquet rebut.
    Si no rep resposta es considera com que el client ha perdut contacte i es pasa a DISCONNECTED"""

    if len(argument.split(" ")) != 3:
        print("Us de la comanda: get <identificador_dispositiu> <identificador_element>")
        return

    client_id = argument.split(" ")[1]
    element = argument.split(" ")[2]

    client = get_client_by_Id(client_id)

    if client is not False and client.status == SEND_ALIVE and element_exist(client, element):

        client_tcp_socket(client)
        send_pck = get_data_pack_maker(client.id, client.id_comm, element)
        send_tcp_packet(send_pck, client.tcp_socket)

        try:
            client.tcp_socket.settimeout(M)
            recv_packet = receive_tcp_packet(127, client.tcp_socket)
            if not recv_packet:
                return
            set_get_rec_procedure(recv_packet, client, element, GET_DATA)
            client.tcp_socket.close()
            return

        except socket.error as socketerror:
            #Mateixa explicacio que el set_call
            client.tcp_socket.close()
            print_message("Resposta al GET_DATA no rebuda")
            change_status(client_id, DISCONNECTED)
            return
    else:
        print_message("GET_DATA no realitzat: Dades incorrectes o estat diferent a SEND_ALIVE")
    print("Us de la comanda: get <identificador_dispositiu> <identificador_element>")

def set_get_rec_procedure(recv_packet, client, element, procedure_type):
    """Tracta els tres tipus de resposta de set i get (DATA_ACK, DATA_NACK, DATA_REJ)"""
    pack_type = recv_packet[0]
    client_id = recv_packet[1].decode().split("\x00")[0]
    client_id_comm = recv_packet[2].decode().split("\x00")[0]
    element_recv = recv_packet[3].decode().split("\x00")[0]
    valor = recv_packet[4].decode(errors="ignore").split("\x00")[0]
    client_info = recv_packet[5].decode(errors="ignore").split("\x00")[0]

    if client.id == client_id and client.id_comm == client_id_comm and element == element_recv:
        if pack_type == DATA_ACK:
            data_maker(client_id, str_status(procedure_type), element, valor, client_info)
            print_message("Operacio: " + str_status(procedure_type) + " correcte, element :" + element + " actualitzat")
        elif pack_type == DATA_NACK:
            print_message(
                "Operacio: " + str_status(procedure_type) + " fallida, element :" + element + " no actualitzat")
        elif pack_type == DATA_REJ:
            change_status(client_id, DISCONNECTED)
        return
    else:
        print_message("SERVER -> Paquet : " + str_status(pack_type) + " no valid. No s'han actualitzat les dades")
        return

# -----------------------------SAVE_FILES AND GLOBAL FUNCTIONS------------------------------------------#

def data_maker(client_id, pack_type, element, value, time_from_client):
    """Crea .data i guarda totes les actualitzacions
    dels element rebuts per send (client), set i get"""

    name_file = str(client_id) + ".data"
    file = open(name_file, "a+")
    file.read()

    if len(value) == 0:
        value = "NO-VALUE"

    current_time = time.strftime("%Y-%m-%d;%H:%M:%S", time.localtime(time.time()))
    if time_from_client != 0:
        current_time = time_from_client
    file.write(current_time + ";" + pack_type + ";" + element + ";" + value)
    file.write('\n')
    file.close()

    print_message("Paquet : " + pack_type + " rebut, " + " Element: " + element + " actualitzat")
    return

def set_reg_client_data(client, data):
    """Guarda la info rebuda per REG_INFO"""
    token = data.split(",")
    client.tcp_port = token[0]
    client.all_elements = token[1]

def arg_treatment(argv):
    """Tracta tots els arguments rebuts al executar el codi via terminal"""

    config_file = None
    allowed_clients = None
    for i in range(len(argv)):
        if argv[i] == "-d":
            global debug_mode
            debug_mode = True
            print_message("Debug mode activat")
        elif argv[i] == "-c" and len(argv) > i + 1:
            try:
                config_file = open(argv[i + 1], 'r')
            except IOError:
                print_message("Error al obrir la configuració del server, utilitzant server.cfg per defecte")
        elif argv[i] == "-u" and len(argv) > i + 1:
            try:
                allowed_clients = open(argv[i + 1], 'r')
            except IOError:
                print_message("Error al obrir la base de dades, utilitzant bbdd_dev.dat per defecte")
    if debug_mode:
        print_message("Llegint configuracions...")

    if config_file is None:
        try:
            config_file = open("server.cfg", 'r')
        except IOError:
            print_message("Error al obrir client.cfg ")
            exit(1)

    if allowed_clients is None:
        try:
            allowed_clients = open("bbdd_dev.dat", 'r')
        except IOError:
            print_message("Error al obrir la base de dades dels clients amb permisos")
            exit(1)

    save_client_database(allowed_clients)
    save_config(config_file)
    if debug_mode:
        print_message("LLegint configuracions i permisos")

def print_message(message):
    #Print missatges amb hora al inici del missatge
    current_time = time.strftime("%H:%M:%S", time.localtime(time.time()))
    print(str(current_time) + " MSG: " + message)
    sys.stdout.flush()

def save_client_database(database_file):
    """Guarda tota la configuracio dels clients
    de la base de dades rebuda com argument"""
    global allowed_client
    num_clients = 0
    for line in database_file:
        if line != "\n":
            token = line.split("\n")[0].split(" ")[0]
            client = Clients()
            client.id = token
            client.status = DISCONNECTED
            client.ip = client.ip
            client.all_elements = client.all_elements
            client.id_comm = client.id_comm
            allowed_client.append(client)
            num_clients += 1
    database_file.close()

def save_config(config_file):
    """Guarda la configuracio del archiu .cfg del servidor"""
    global server_inf

    for line in config_file:
        if line != "\n":
            argument = line.split("\n")[0].split(" ")
            if argument[0] == "Id":
                server_inf.id = argument[2]
            elif argument[0] == "UDP-port":
                server_inf.port_UDP = int(argument[2])
            elif argument[0] == "TCP-port":
                server_inf.port_TCP = int(argument[2])
    config_file.close()

def client_list():
    """Mostra per terminal la llista de clients, amb l'estat, ip, id_comm i elements de cadascun"""
    if allowed_client:
        print("    ID     -     IP      -  ID.COMM   -    ESTAT     -        ELEMENTS        -")
        print("-----------|-------------|------------|--------------|-------------------------")
        for client in allowed_client:
            print(client.id, "-", str(9 * " " if client.ip is None else client.ip),
                  "  -", str(10 * " " if client.id_comm is None else client.id_comm),
                  "-", str_status(client.status), str((11 - len(str_status(client.status))) * " "), "-",
                  str(10 * " " if client.all_elements is None else client.all_elements))

def str_status(status):
    """Segons el tipus de paquet/ estat del client rebut el torna en forma de string.
    Si rep un tipus incorrecte, retorna ERR_TYPE"""
    if status == DISCONNECTED:
        return "DISCONNECTED"
    elif status == NOT_REGISTERED:
        return "NOT_REGISTERED"
    elif status == WAIT_ACK_REG:
        return "WAIT_ACK_REG"
    elif status == WAIT_INFO:
        return "WAIT_INFO"
    elif status == WAIT_ACK_INFO:
        return "WAIT_ACK_INFO"
    elif status == REGISTERED:
        return "REGISTERED"
    elif status == SEND_ALIVE:
        return "SEND_ALIVE"
    elif status == ALIVE:
        return "ALIVE"
    elif status == REG_ACK:
        return "REG_ACK"
    elif status == REG_REQ:
        return "REG_REQ"
    elif status == REG_NACK:
        return "REG_NACK"
    elif status == REG_REJ:
        return "REG_REJ"
    elif status == REG_INFO:
        return "REG_INFO"
    elif status == INFO_ACK:
        return "INFO_ACK"
    elif status == INFO_NACK:
        return "INFO_NACK"
    elif status == INFO_REJ:
        return "INFO_REJ"
    elif status == ALIVE_NACK:
        return "ALIVE_NACK"
    elif status == ALIVE_REJ:
        return "ALIVE_REJ"
    elif status == SEND_DATA:
        return "SEND_DATA"
    elif status == DATA_ACK:
        return "DATA_ACK"
    elif status == DATA_NACK:
        return "DATA_NACK"
    elif status == DATA_REJ:
        return "DATA_REJ"
    elif status == SET_DATA:
        return "SET_DATA"
    elif status == GET_DATA:
        return "GET_DATA"
    else:
        return "ERR_TYPE"

def command_treatment():
    """Tracta les comandes rebudes per terminal"""
    global sock
    try:
        while True:
            line = sys.stdin.readline().strip('\n')
            command = line.split(" ")[0]
            if command == "list":
                client_list()
            elif command == "get":
                get_call(line)
            elif command == "set":
                set_call(line)
            elif command == "quit":
                """Tanquem tots els sockets oberts i enviem senyal SIGTERM als fils per matarlos
                i poder iniciar el server una altra vegada sense rebre errors dels sockets"""

                print_message("Tancant server...")
                sock.udp_socket.close()
                sock.tcp_socket.close()
                os.kill(os.getpid(), signal.SIGTERM)
            else:
                print_message("ERROR! Comanda no trobada: " + command)
    except(KeyboardInterrupt, SystemExit):
        return

def get_client_by_Id(id_transm):
    """Retorna el client segons una id donada"""
    global allowed_client

    for client in allowed_client:
        if client.id == id_transm:
            return client
    return False

def change_status(client_id, new_state):
    """Canvia el estat del client donat al estat rebut com argument"""
    client = get_client_by_Id(client_id)
    client.status = new_state

    print_message("SERVER -> Client " + client_id + " cambia al estat: "
                  + str_status(new_state))

# -----------------------------MAIN FUNCTION------------------------------------------#
def main():
    global sock
    global allowed_client
    try:
        #Lleguim arguments
        arg_treatment(sys.argv)
        #Creem fil que tractara comandes
        command_thread = threading.Thread(target=command_treatment)
        command_thread.daemon = True
        command_thread.start()
        #Obrim sockets TCP i UDP
        udp_socket()
        tcp_socket()
        #Obrim els UDP_loop i TCP_loop per tractar els paquets dels clients
        udp_connection = threading.Thread(target=udp_loop)
        udp_connection.start()
        tcp_connection = threading.Thread(target=tcp_loop)
        tcp_connection.start()

    except(KeyboardInterrupt, SystemExit):
        #En cas d'error a l'hora dexecutar el programa tancarem tots els sockets
        print_message("Error al executar el servidor, tancant...")
        sock.udp_socket.close()
        sock.tcp_socket.close()
        exit(1)

if __name__ == "__main__":
    main()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Module to run a Nextflow pipeline and get output
"""
import os
import subprocess

ABSDIR = os.path.realpath(".")

# location for execution of pipeline
NXF_DIR = os.path.join(ABSDIR, "nxf")

# nextflow script to execute
NXF_SCRIPT = os.path.join(ABSDIR, "main.nf")

# main pipeline output log file
NXF_LOG = os.path.join(NXF_DIR, ".nextflow.log")

NXF_WORK = os.path.join(NXF_DIR, "work")

NXF_OUTPUT = os.path.join(ABSDIR, "output")

NXF_INPUT = os.path.join(ABSDIR, "input")

# env variables
NXF_ANSI_LOG = 'false'

env = {
'NXF_ANSI_LOG': NXF_ANSI_LOG,
'NXF_WORK': NXF_WORK,
}

config = {
'NXF_DIR': NXF_DIR,
'NXF_SCRIPT': NXF_SCRIPT,
'NXF_LOG': NXF_LOG,
'NXF_OUTPUT': NXF_OUTPUT,
'NXF_INPUT': NXF_INPUT
}

class Nextflow(object):
    """
    Object class to configure and run a Nextflow pipeline
    """
    def __init__(self, config, env = env):
        self.config = config
        self.env = env

    def set_command(self):
        """
        CLI command to run
        """
        nxf_command = [
        'nextflow',
        '-log', self.config['NXF_LOG'],
        'run', self.config['NXF_SCRIPT'],
        '--outputDir', self.config['NXF_OUTPUT'],
        '--inputDir', self.config['NXF_INPUT']
        ]
        self.command = nxf_command

    def get_process(self, command):
        """
        Create Python subprocess object to run the CLI command
        """
        process = subprocess.Popen(command,
            env = dict(os.environ,
                NXF_ANSI_LOG = self.env['NXF_ANSI_LOG'],
                NXF_WORK = self.env['NXF_WORK']
                ),
            universal_newlines = True,
            stdout = subprocess.PIPE,
            stderr = subprocess.PIPE)
        return(process)

    def run(self):
        """
        Generate CLI command based on config and run it in Python subprocess
        """
        self.set_command()
        process = self.get_process(self.command)
        proc_stdout, proc_stderr = process.communicate()
        self.returncode = process.returncode
        self.stdout = proc_stdout
        self.stderr = proc_stderr

def main():
    """
    Example of how to run Nextflow from Python script
    """
    n = Nextflow(config = config)
    n.run()
    print(n.returncode)
    print(n.stdout)
    print(n.stderr)

if __name__ == '__main__':
    main()


a = input("Enter the name of the file: ")
def function(b):
    """
    This is a function for taking input from the file
    """
    f = open(b)
    content = f.read()
    f.close()
    return content
c = function(a)
print(c)


from django.urls import path
from PrincipalApp import views
from django.contrib.auth.decorators import login_required

app_name = 'Merlin'
urlpatterns = [
   path('',  views.Index.as_view(), name='Index'),
   path('ListCategoria/',views.ListCategoria.as_view(), name='ListCategoria'),
   path('RegistrarCategoria/',views.CreateCategoria.as_view(), name='RegistrarCategoria'),
   path('EditarCategoria/<int:pk>',views.UpdateCategoria.as_view(), name='EditarCategoria'),

    path('RegistrarPregunta/',views.CreatePregunta.as_view(), name='RegistrarPregunta'),
   path('ListPregunta/',views.ListPregunta.as_view(), name='ListPregunta'),

]


from celery.schedules import crontab

import djcelery

djcelery.setup_loader()

BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"
CELERY_DISABLE_RATE_LIMITS = False

CELERYBEAT_SCHEDULE = {
    'delete-every-day': {
        'task': 'apps.blog.tasks.hashtag_task',
        'schedule': crontab(minute=0, hour=0) # Every day at midnight
    },
}


import numpy as np
import argparse
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "Path to the image")
args = vars(ap.parse_args())

image = cv2.imread(args["image"])
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Original", image)

lap = cv2.Laplacian(image, cv2.CV_64F)
lap = np.uint8(np.absolute(lap))
cv2.imshow("Laplacian", lap)
cv2.waitKey(0)


from . import views
from django.urls import path

"""
    Url paths extended from from django.urls
    BUG: enabling app_name causes a django.urls.exceptions.NoReverseMatch error 500.
"""
app_name = 'blog'
urlpatterns = [
    path('blog/', views.PostList.as_view(), name='blog'),
    path("blog/<slug:slug>/", views.post_detail, name="post_detail")
]


class Node:
    def __init__(self, data, reference=None):
        self.data = data
        self.reference = reference

node1 = Node(5)
print(node1.data)

node2 = Node(11)
node1.reference = node2
print(node1.reference)

class LinkedList:
    def __init__(self, head=None):
        self.head = head

    def print_linked_list(self):
        if self.head is None:
            print( 'The linked list is empty')
        else:
            c_node = self.head
            while c_node is not None:
                print(c_node.data)
                c_node = c_node.reference

    def add_to_start(self, data):
        n_node = Node(data)
        n_node.reference = self.head
        self.head = n_node

    def add_item(self, data):
        new_n = Node(data)
        if self.head is None:
            self.head = new_n
        else:

            last_n = self.head

            while last_n.reference:
                last_n = last_n.reference
            last_n.reference = new_n

        # Accepts a value. Creates a node with that value, and adds the node to the end of the linked list.

# linked_list1 = LinkedList()

# linked_list1.add_to_start(82)
# linked_list1.add_to_start(55)

# linked_list1.print_linked_list()

mylist = LinkedList()

mylist.add_item(5)
mylist.add_item(10)
mylist.add_item(15)

mylist.print_linked_list()


import pandas as pd

# Завантажте XLSX файл
xlsx_file = '.xlsx'  # Замініть на шлях до вашого XLSX файлу

# Зчитайте XLSX файл
data = pd.read_excel(xlsx_file)

# Збережіть дані у файл CSV
csv_file = '.csv'  # Замініть на ім'я, під яким ви хочете зберегти файл CSV
data.to_csv(csv_file, index=False)


import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit
from helpers import *

class CdcmainlibPlugin(plugins.SingletonPlugin):
    plugins.implements(plugins.IConfigurer)
    plugins.implements(plugins.ITemplateHelpers)

    # IConfigurer

    def update_config(self, config_):
        toolkit.add_template_directory(config_, 'templates')
        toolkit.add_public_directory(config_, 'public')
        toolkit.add_resource('fanstatic', 'cdcmainlib')

    def get_helpers(self):
        # define in the helpers.py
        return { 'getLangLabel' : getLangLabel, \
                 'getLen' : getLen, \
                 'strReplace' : strReplace, \
                 'checkChineseTag' : checkChineseTag, \
                 'checkLangTag' : checkLangTag, \
                 'getLicenseLabel' : getLicenseLabel, \
                 'parsePostRequestBodyAsList' : parsePostRequestBodyAsList, \
                 'getPostRequestParamValue' : getPostRequestParamValue, \
                 'getAccInfo' : getAccInfo, \
                 'getReq2OrgList' : getReq2OrgList, \
                 'getUserState' : getUserState, \
                 'setUserState' : setUserState, \
                 'getUserOrgan' : getUserOrgan, \
                 'getSysTime' : getSysTime, \
                 'transTime' : transTime, \
                 'retGroupList' : retGroupList, \
                 'getGroupStr' : getGroupStr, \
                 'getOrganizationStr' : getOrganizationStr, \
                 'getGroupOrOrganizationLangStr' : getGroupOrOrganizationLangStr, \
                 'getPSQLInfo' : getPSQLInfo \
               }


from node import Node

numbers = []
def setup():
  with open("input.txt") as f:
    global numbers
    numbers = f.readlines()[0].strip().split(' ')

def main():
  i = 0
  while(i < len(numbers)):
    rootNode = Node(numbers[i], numbers[i + 1])
    i += 2
    i = loopChildNodes(rootNode, i)

  print('metadata sum', rootNode.getMetadataSum())
  print('root node value', rootNode.getNodeValue())

def loopChildNodes(node, numIndex):
  for n in range(node.childCount):
    childNode = Node(numbers[numIndex], numbers[numIndex + 1])
    node.children.append(childNode)
    numIndex += 2

    if childNode.childCount == 0:
      numIndex = addMetaData(childNode, numIndex)
    else:
      numIndex = loopChildNodes(childNode, numIndex)

  numIndex = addMetaData(node, numIndex)
  return numIndex

def addMetaData(node, numIndex):
  for m in range(node.metadataCount):
    node.metadata.append(int(numbers[numIndex]))
    numIndex += 1

  return numIndex

if __name__ == '__main__':
  setup()
  main()


from math import fabs
from platform import platform
from tkinter.tix import Tree
import pygame
import os
import random
import time

class Setting:
    window_width = 750
    window_height = 900
    frames = 60
    path_file = os.path.dirname(os.path.abspath(__file__))
    image_path = os.path.join(path_file, "Images")
    sound_path = os.path.join(path_file, "Sounds")
    score = "score.txt"
    title = "Spiel mit Sprung"
    jump_speed = 0
    punkte = 0
    gravity = 0.2
    upscroll = False
    hit = False
    loose = False
    count_plat = 0
    max_plat = 25
    scale_x = 125
    scale_y = 15
    play_music = True
    score = 0
    highscore = 0

class Button:
    def __init__(self, image, pos, text_input, font, base_color, hovering_color):
        self.image = image
        self.x_pos = pos[0]
        self.y_pos = pos[1]
        self.font = font
        self.base_color, self.hovering_color = base_color, hovering_color
        self.text_input = text_input
        self.text = self.font.render(self.text_input, True, self.base_color)
        if self.image is None:
            self.image = self.text
        self.rect = self.image.get_rect(center=(self.x_pos, self.y_pos))
        self.text_rect = self.text.get_rect(center=(self.x_pos, self.y_pos))

    def update(self, screen):
        if self.image is not None:
            screen.blit(self.image, self.rect)
        screen.blit(self.text, self.text_rect)

    def checkForInput(self, position):
        if position[0] in range(self.rect.left, self.rect.right) and position[1] in range(self.rect.top, self.rect.bottom):
            return True
        return False

    def changeColor(self, position):
        if position[0] in range(self.rect.left, self.rect.right) and position[1] in range(self.rect.top, self.rect.bottom):
            self.text = self.font.render(
                self.text_input, True, self.hovering_color)
        else:
            self.text = self.font.render(
                self.text_input, True, self.base_color)

class Background:
    def __init__(self, filename="background.png") -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, filename)).convert()
        self.image = pygame.transform.scale(
            self.image, (Setting.window_width, Setting.window_height))

    def draw(self, screen):
        screen.blit(self.image, (0, 0))

    def update(self):
        pass

class First_Plat(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = Setting.window_width//2
        self.rect.centery = Setting.window_height

    def update(self):

        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat += 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class Movingp(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.xspeed = 1 or -1
        self.xmove = self.xspeed
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)

    def update(self):

        if self.rect.right == Setting.window_width:
            self.xmove = self.xspeed * -1
        if self.rect.left == 0:
            self.xmove = self.xspeed * 1

        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        self.rect.move_ip((self.xmove, 0))
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class Plattform(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)

    def update(self):
        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class BreakingPlat(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)

    def update(self):
        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class BreakingPlat_move(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)
        self.xspeed = 1 or -1
        self.xmove = self.xspeed

    def update(self):
        if self.rect.right == Setting.window_width:
            self.xmove = self.xspeed * -1
        if self.rect.left == 0:
            self.xmove = self.xspeed * 1

        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        self.rect.move_ip((self.xmove, 0))
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class Spieler(pygame.sprite.Sprite):
    def __init__(self) -> None:
        super().__init__()
        self.image_org = pygame.image.load(os.path.join(
            Setting.image_path, "jumper.png")).convert_alpha()
        self.image = self.image_org
        self.rect = self.image.get_rect()
        self.radius = self.rect.width // 2
        self.imageindex = 0
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = Setting.window_width // 2
        self.rect.centery = Setting.window_height // 2
        self.speed = 0
        self.x_movement = 0

    def update(self):

        if Setting.hit == False:
            Setting.jump_speed += Setting.gravity
        if Setting.hit == True:
            Setting.jump_speed = -13
            Setting.hit = False
        if self.rect.left >= Setting.window_width:
            self.rect.centerx = 0
        if self.rect.right < 0:
            self.rect.centerx = Setting.window_width
        self.rect.move_ip((self.x_movement, Setting.jump_speed))

    def draw(self, screen):
        screen.blit(self.image, self.rect)

    def left(self):
        self.x_movement = -5
        self.image = pygame.transform.flip(self.image_org, True, False)

    def right(self):
        self.x_movement = 5
        self.image = self.image_org

    def check_pos(self):
        if self.rect.top <= 0:
            Setting.upscroll = True
        else:
            Setting.upscroll = False

    def loose(self):
        if self.rect.top >= Setting.window_height:
            Setting.loose = True

class Game(object):
    def __init__(self) -> None:
        super().__init__()
        os.environ['SDL_VIDEO_WINDOW_POS'] = "50,30"

        pygame.init()
        pygame.display.set_caption(Setting.title)
        self.screen = pygame.display.set_mode(
            (Setting.window_width, Setting.window_height))
        self.clock = pygame.time.Clock()
        self.running = False
        self.counter = 0
        self.duration = 120
        self.spieler = Spieler()
        self.first = pygame.sprite.Group()
        self.breakingp = pygame.sprite.Group()
        self.all_obstacles = pygame.sprite.Group()
        self.font = pygame.font.Font(pygame.font.get_default_font(), 24)
        self.breakingp_move = pygame.sprite.Group()
        self.all_obstacles.add(Plattform("platform.png"))
        self.sound()
        self.background = Background()
        self.score = 0

    def get_font(size):  # Returns Press-Start-2P in the desired size
        return pygame.font.Font("assets/font.ttf", size)

    def draw(self, screen):
        screen.blit(self.image, (0, 0))

    def sound(self):
        self.volume = 0.4
        self.jump_sound = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "Jump.mp3"))
        self.background_music = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "background.mp3"))
        self.background_music = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "background.mp3"))
        self.break_sound = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "break.mp3"))
        self.background_music.set_volume(self.volume)
        self.jump_sound.set_volume(self.volume)
        self.break_sound.set_volume(self.volume)
        self.background_music.play(-1)

    def mute(self):
        if Setting.play_music == False:
            self.volume = 0
            self.background_music.set_volume(self.volume)

    def unmute(self):
        if Setting.play_music == True:
            self.volume = 0.5
            self.background_music.set_volume(self.volume)

    def scores(self):
        while True:
            OPTIONS_MOUSE_POS = pygame.mouse.get_pos()

            self.screen.blit(self.background.image, (0, 0))
            OPTIONS_TEXT = self.font.render(
                "Highscore", True, "Black")
            OPTIONS_RECT = OPTIONS_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height//5))

            NOWW_TEXT = self.font.render(
                "Letzter Score", True, "Black")
            NOWW_RECT = OPTIONS_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height/2.5))

            SCORE_TEXT = self.font.render(
                str(Setting.highscore), True, "Black")
            SCORE_RECT = SCORE_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height//4))

            NOW_TEXT = self.font.render(str(Setting.punkte), True, "Black")
            NOW_RECT = SCORE_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height//2))

            OPTIONS_BACK = Button(image=None, pos=(640, 850),
                                  text_input="BACK", font=self.font, base_color="Black", hovering_color="Green")

            PLAY = Button(image=None, pos=(Setting.window_width/2, 850),
                          text_input="PLAY", font=self.font, base_color="Black", hovering_color="Green")

            OPTIONS_BACK.changeColor(OPTIONS_MOUSE_POS)
            OPTIONS_BACK.update(self.screen)
            PLAY.changeColor(OPTIONS_MOUSE_POS)
            PLAY.update(self.screen)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        self.run()

                if event.type == pygame.MOUSEBUTTONDOWN:
                    if OPTIONS_BACK.checkForInput(OPTIONS_MOUSE_POS):
                        self.main_menu()
                    if PLAY.checkForInput(OPTIONS_MOUSE_POS):
                        self.run()
                        break

            self.screen.blit(OPTIONS_TEXT, OPTIONS_RECT)
            self.screen.blit(SCORE_TEXT, SCORE_RECT)
            self.screen.blit(NOWW_TEXT, NOWW_RECT)
            self.screen.blit(NOW_TEXT, NOW_RECT)
            pygame.display.flip()

            pygame.display.update()

    def main_menu(self):
        while True:

            self.screen.blit(self.background.image, (0, 0))

            MENU_MOUSE_POS = pygame.mouse.get_pos()

            MENU_TEXT = self.font.render("MAIN MENU", True, "Black")
            MENU_RECT = MENU_TEXT.get_rect(
                center=(Setting.window_width // 2, 100))

            PLAY_BUTTON = Button(image=None, pos=(Setting.window_width // 2, 250),
                                 text_input="Play", font=self.font, base_color="Black", hovering_color="White")
            OPTIONS_BUTTON = Button(image=None, pos=(Setting.window_width // 2, 400),
                                    text_input="Score", font=self.font, base_color="Black", hovering_color="White")
            QUIT_BUTTON = Button(image=None, pos=(Setting.window_width // 2, 550),
                                 text_input="Quit", font=self.font, base_color="Black", hovering_color="White")
            if Setting.play_music == True:
                VOLUME_BUTTON = Button(image=pygame.image.load(os.path.join(
                    Setting.image_path, "play.png")), pos=(Setting.window_width // 2, 800),
                    text_input="-", font=self.font, base_color="Black", hovering_color="Green")
            if Setting.play_music == False:
                VOLUME_BUTTON = Button(image=pygame.image.load(os.path.join(
                    Setting.image_path, "mute.png")), pos=(Setting.window_width // 2, 800),
                    text_input="-", font=self.font, base_color="Black", hovering_color="Green")

            self.screen.blit(MENU_TEXT, MENU_RECT)

            for button in [PLAY_BUTTON, OPTIONS_BUTTON, QUIT_BUTTON, VOLUME_BUTTON]:
                button.changeColor(MENU_MOUSE_POS)
                button.update(self.screen)

            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if PLAY_BUTTON.checkForInput(MENU_MOUSE_POS):
                        self.run()

                    if OPTIONS_BUTTON.checkForInput(MENU_MOUSE_POS):
                        self.scores()
                    if VOLUME_BUTTON.checkForInput(MENU_MOUSE_POS):
                        if Setting.play_music == True:
                            Setting.play_music = False
                            self.mute()

                            pygame.mixer.music.pause()
                        elif Setting.play_music == False:
                            Setting.play_music = True
                            self.unmute()

                            pygame.mixer.music.unpause()
                    if QUIT_BUTTON.checkForInput(MENU_MOUSE_POS):
                        pygame.quit()

            pygame.display.update()
            pygame.display.flip()

    def groupcollide(self):
        if pygame.sprite.spritecollide(self.spieler, self.all_obstacles, False):
            Setting.hit = True
            self.jump_sound.play()
        elif pygame.sprite.spritecollide(self.spieler, self.first, False):
            Setting.hit = True
            self.jump_sound.play()
        elif pygame.sprite.spritecollide(self.spieler, self.breakingp, True):
            Setting.hit = True
            self.break_sound.play()
        elif pygame.sprite.spritecollide(self.spieler, self.breakingp_move, True):
            Setting.hit = True
            self.break_sound.play()
        else:
            Setting.hit = False

    def reset(self):
        self.spieler.rect.x = Setting.window_width // 2
        self.spieler.rect.y = Setting.window_height // 2
        Setting.jump_speed = 0
        self.spieler.x_movement = 0
        self.screen.blit(self.background.image, (0, 0))
        Setting.loose = False
        self.all_obstacles.empty()
        self.breakingp_move.empty()
        self.breakingp.empty()
        self.first.add(First_Plat("platform.png"))
        Setting.count_plat =  0
        self.running= True

    def highscore(self):
        if Setting.punkte >= Setting.highscore:
            Setting.highscore = Setting.punkte
        else:
            pass

    def read_score(self):
        self.file = open("score.txt", "r")
        self.read = self.file.read()
        Setting.highscore = int(self.read)
        self.file.close()
        return self.score

    def write_score(self):
        self.file = open("score.txt", "w")
        if Setting.score > Setting.highscore:

            self.file.write(str(Setting.score))
            self.file.close()
        else:
            self.file.close()

    def run(self):
        self.reset()
        Setting.punkte = 0
        self.screen.blit(self.background.image, (0, 0))

        while self.running:
            self.clock.tick(Setting.frames)

            # Eventverarbeitung
            self.watch_for_events()
            # Update
            self.all_obstacles.update()
            self.spieler.update()
            self.first.update()
            self.breakingp.update()
            self.breakingp_move.update()

            # Bildschirmausgabe
            self.background.draw(self.screen)
            self.all_obstacles.draw(self.screen)
            self.spieler.draw(self.screen)
            self.first.draw(self.screen)
            self.breakingp.draw(self.screen)
            self.breakingp_move.draw(self.screen)
            text_surface_modus = self.font.render(
                "Punktzahl: {0}".format(Setting.punkte), True, (0, 0, 0))
            self.screen.blit(text_surface_modus, dest=(
                10, Setting.window_height-900))

            self.groupcollide()
            self.more()
            self.spieler.check_pos()
            self.spieler.loose()
            self.end()
            self.mute()
            self.unmute()
            pygame.display.flip()

    def watch_for_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
            elif self.running == True:
                if event.type == pygame.KEYDOWN:

                    if event.key == pygame.K_LEFT:
                        self.spieler.left()
                    elif event.key == pygame.K_RIGHT:
                        self.spieler.right()

    def end(self):
        if Setting.loose == True:
            self.highscore()
            #self.write_score()
            self.scores()

    def more(self):
        self.spawnrate = 5
        self.counter += 1
        if self.counter >= self.duration:
            if Setting.count_plat <= Setting.max_plat:
                if Setting.punkte >= 15:
                    for i in range(1):

                        if Setting.punkte >= 15:
                            self.all_obstacles.add(Movingp("platform_move.png"))
                            Setting.count_plat += 1
                            self.counter = 0
                        if Setting.punkte >= 30:
                            self.breakingp.add(BreakingPlat("platform_break.png"))
                            Setting.count_plat += 1
                            self.counter = 0
                        if Setting.punkte >= 40:
                            self.breakingp_move.add(BreakingPlat_move("platform_break_move.png"))
                            Setting.count_plat += 1
                            self.counter = 0

                else:
                    for i in range(2):
                        self.all_obstacles.add(Plattform("platform.png"))
                        self.counter = 0
                        Setting.count_plat += 1

if __name__ == "__main__":
    game = Game()
    game.main_menu()

################################

                #       #

            #               #
            ###############

#################################
# Menu with help from yt https://www.youtube.com/watch?v=GMBqjxcKogA&ab_channel=BaralTech
# Jumper Graphic from https://favpng.com/png_view/doodle-vector-doodle-jump-kinect-video-game-iphone-png/UVAWVSjC
# Jump Sound https://www.youtube.com/watch?v=cxPQ2vk-oDk&ab_channel=LatifKhan
# Breaking Sound https://www.youtube.com/watch?v=5kdSouOn09M&ab_channel=Music%26SoundsEffectLibrary
# Hintergrundmusik https://www.youtube.com/watch?v=MF_zoKQysfI&ab_channel=AudioLibrary%E2%80%94Musicforcontentcreator


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def sortedArrayToBST(self, nums: list[int]) -> TreeNode:
        # Helper function to construct a balanced BST from a sorted array
        def constructBST(left, right):
            if left > right:
                return None
            # Find the middle element of the current subarray
            mid = left + (right - left) // 2
            # Create a new TreeNode with the middle element as the value
            root = TreeNode(nums[mid])
            # Recursively construct the left and right subtrees
            root.left = constructBST(left, mid - 1)
            root.right = constructBST(mid + 1, right)
            return root

        # Call the helper function starting from the entire array
        return constructBST(0, len(nums) - 1)

def print_tree(root):
    """
    Print the binary tree structure in a visual format.
    """
    if not root:
        return "[]"

    result = []
    queue = [root]

    while queue:
        node = queue.pop(0)

        if node:
            result.append(str(node.val))
            queue.append(node.left)
            queue.append(node.right)
        else:
            result.append("null")

    # Remove trailing null values
    while result[-1] == "null":
        result.pop()

    return "[" + ",".join(result) + "]"

# Test case 1
# Input: nums = [-10,-3,0,5,9]
# Output: [0,-3,9,-10,null,5]
sol = Solution()
nums1 = [-10, -3, 0, 5, 9]
root1 = sol.sortedArrayToBST(nums1)
print(print_tree(root1))  # Output: [0,-3,9,-10,null,5]

# Test case 2
# Input: nums = [1,3]
# Output: [3,1]
sol = Solution()
nums2 = [1, 3]
root2 = sol.sortedArrayToBST(nums2)
print(print_tree(root2))  # Output: [3,1]

Tree/108. Convert Sorted Array to Binary Search Tree.py


import torch
from torch import nn

class CenterPivotConv4d(nn.Module):
    """
    CenterPivot 4D conv

    Args:
        in_channels (`int`):
            Number of input channels.
        out_channels (`int`):
            Number of output channels.
        kernel_size (`list or tuple`):
            Numbers for kernel size.
        stride (`list or tuple`):
            Numbers for stride.
        padding (`list or tuple`):
            Numbers for padding.
        bias (`bool`):
            Whether to add bias for conv layer.
    """
    def __init__(self, in_channels, out_channels, kernel_size, stride, padding, bias=True):
        super().__init__()

        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size[:2], stride=stride[:2],
                               bias=bias, padding=padding[:2])
        self.conv2 = nn.Conv2d(in_channels, out_channels, kernel_size[2:], stride=stride[2:],
                               bias=bias, padding=padding[2:])

        self.stride34 = stride[2:]
        self.kernel_size = kernel_size
        self.stride = stride
        self.padding = padding
        self.idx_initialized = False
        self.idx_initialized_2 = False

    def prune(self, ct):
        bsz, ch, ha, wa, hb, wb = ct.size()
        idxh = torch.arange(start=0, end=hb, step=self.stride[2:][0], device=ct.device)
        idxw = torch.arange(start=0, end=wb, step=self.stride[2:][1], device=ct.device)
        self.len_h = len(idxh)
        self.len_w = len(idxw)
        self.idx = (idxw.repeat(self.len_h, 1) + idxh.repeat(self.len_w, 1).t() * wb).view(-1)
        self.idx_initialized = True
        ct_pruned = ct.view(bsz, ch, ha, wa, -1).index_select(4, self.idx).view(bsz, ch, ha, wa, self.len_h, self.len_w)

        return ct_pruned

    def prune_out2(self, ct):
        bsz, ch, ha, wa, hb, wb = ct.size()
        idxh = torch.arange(start=0, end=ha, step=self.stride[:2][0], device=ct.device)
        idxw = torch.arange(start=0, end=wa, step=self.stride[:2][1], device=ct.device)
        self.len_h = len(idxh)
        self.len_w = len(idxw)
        self.idx = (idxw.repeat(self.len_h, 1) + idxh.repeat(self.len_w, 1).t() * wa).view(-1)
        self.idx_initialized_2 = True
        ct_pruned = ct.view(bsz, ch, -1, hb, wb).permute(0, 1, 3, 4, 2).index_select(4, self.idx).\
            permute(0, 1, 4, 2, 3).view(bsz, ch, self.len_h, self.len_w, hb, wb)

        return ct_pruned

    def forward(self, x):
        if self.stride[2:][-1] > 1:
            out1 = self.prune(x)
        else:
            out1 = x
        bsz, inch, ha, wa, hb, wb = out1.size()
        out1 = out1.permute(0, 4, 5, 1, 2, 3).contiguous().view(-1, inch, ha, wa)
        out1 = self.conv1(out1)
        outch, o_ha, o_wa = out1.size(-3), out1.size(-2), out1.size(-1)
        out1 = out1.view(bsz, hb, wb, outch, o_ha, o_wa).permute(0, 3, 4, 5, 1, 2).contiguous()

        if self.stride[:2][-1] > 1:
            out2 = self.prune_out2(x)
        else:
            out2 = x
        bsz, inch, ha, wa, hb, wb = out2.size()
        out2 = out2.permute(0, 2, 3, 1, 4, 5).contiguous().view(-1, inch, hb, wb)
        out2 = self.conv2(out2)
        outch, o_hb, o_wb = out2.size(-3), out2.size(-2), out2.size(-1)
        out2 = out2.view(bsz, ha, wa, outch, o_hb, o_wb).permute(0, 3, 1, 2, 4, 5).contiguous()
        if out1.size()[-2:] != out2.size()[-2:] and self.padding[-2:] == (0, 0):
            out1 = out1.view(bsz, outch, o_ha, o_wa, -1).sum(dim=-1)
            out2 = out2.squeeze()
        y = out1 + out2
        return y


#!/usr/bin/env python3
import operator
from functools import reduce
from pathlib import Path

def part1(contents):
    visible_trees_counter = 0
    grid = [[x for x in row] for row in contents.split("\n")]
    n, m = len(grid), len(grid[0])
    for i in range(n):
        for j in range(m):
            if i not in (0, n - 1) and j not in (0, m - 1):
                # inner
                visible_trees_counter += any(
                    (
                        all(grid[i][j] > grid[k][j] for k in range(0, i)),
                        all(grid[i][j] > grid[k][j] for k in range(i + 1, n)),
                        all(grid[i][j] > grid[i][k] for k in range(0, j)),
                        all(grid[i][j] > grid[i][k] for k in range(j + 1, m)),
                    )
                )
            else:
                # edge
                visible_trees_counter += 1

    print(f"Part1: {visible_trees_counter}")

def part2(contents):
    max_scenic_score = 0
    grid = [[x for x in row] for row in contents.split("\n")]
    n, m = len(grid), len(grid[0])
    for i in range(n):
        for j in range(m):
            # we do not review edges: multiply by 0 - no sense
            if i not in (0, n - 1) and j not in (0, m - 1):
                counters = [0, 0, 0, 0]  # left, top, right, botton

                # move left
                k = j - 1
                while k > -1:
                    counters[0] += 1
                    if grid[i][k] >= grid[i][j]:
                        break
                    k -= 1

                # move top
                k = i - 1
                while k > -1:
                    counters[1] += 1
                    if grid[k][j] >= grid[i][j]:
                        break
                    k -= 1

                # move right
                k = j + 1
                while k < m:
                    counters[2] += 1
                    if grid[i][k] >= grid[i][j]:
                        break
                    k += 1

                # move down
                k = i + 1
                while k < n:
                    counters[3] += 1
                    if grid[k][j] >= grid[i][j]:
                        break
                    k += 1

                # print(
                #     f"elem: {grid[i][j]} ; counters: {counters} ;; {reduce(operator.mul, counters, 1)}"
                # )
                max_scenic_score = max(
                    max_scenic_score, reduce(operator.mul, counters, 1)
                )

    print(f"Part2: {max_scenic_score}")

if __name__ == "__main__":
    contents = Path("input.txt").read_text().strip()
    part1(contents)
    part2(contents)


# URL do Enunciado
# https://www.beecrowd.com.br/judge/pt/custom-problems/view/1759

anoatual = int(input())
anoinic = 2006
aument = 1.015
salinc = 1000
saltotal = aument*salinc
if anoatual>=anoinic:
    while anoinic<anoatual:
        saltotal = saltotal*(aument+0.01)
        anoinic = anoinic+1
        aument = aument+0.01
    print("Salário atual: R$%.2f" %(saltotal))
else:
    print("O ano informado deverá ser > 2005!")


# Ce programme permet de déterminer lequel de deux nombres flottants entrés
# par l’utilisatrice ou l’utilisateur est le plus petit

# akbarimehdi 20210926

_val1=int(input("Veuillez entrer le premier nombre: "));
_val2=int(input("Veuillez entrer le second nombre: "));
if(_val1>_val2):
    print("Le plus petit nombre est ",_val2);
elif(_val2>_val1):
    print("Le plus petit nombre est ",_val1);
else:
    print("Les nombres sont egaux");


import os
replacement = "to 2 decimal places"
for dname, dirs, files in os.walk("/mnt/e/local git/astudio/maths/equations"):
    for fname in files:
        fpath = os.path.join(dname, fname)
        with open(fpath) as f:
            s = f.read()
        s = s.replace("to 2 decimal places", replacement)
        with open(fpath, "w") as f:
            f.write(s)