from cmath import exp
import os  # Necesario para poder usar comandos del CMD/Powershell
import json  # Necesario para manipular JSON dentro de python

graph = {}  # Diccionario donde se guardarán todos los grafos
historial = []  # Variable usada para crear la lista del archivo.json

nodo_conexiones = [] # En este diccionario se almacenaran todas las conexiones que tendrán los nodos

def validar_campo_de_texto(pregunta):
    tiene_errores = True
    while tiene_errores == True:
        print(pregunta)
        respuesta = input("escribe tu respuesta\n")
        if len(respuesta) <= 0:
            print("El campo no puede estar vacío")
            tiene_errores = True
        elif respuesta.isnumeric():
            print("El campo no puede ser un número")
            tiene_errores = True
        else:
            tiene_errores = False
            return respuesta

#Menu inicial del programa
def menu_inicio():

    while True:
        try:
            opc = int(input("\
                \n1. Inicio del programa\
                \n2. Consulta de rutas\
                \n3. Salir del programa\n"))

            if opc == 1:
                pregunta = "¿Cómo te llamas?"
                nombre = validar_campo_de_texto(pregunta)
                id_usuario = asignar_id()

                print("Bienvenido {} tu id es {} ".format(nombre, id_usuario))
                cantidad_nodos = crear_nodos()
                conectar_nodos(cantidad_nodos)

                vi = input("Digite el nodo inicial del recorrido\n").upper()
                vf = input("Digite el nodo final del recorrido\n").upper()

                ruta = list(dfs_paths(graph, vi, vf))
                ruta_larga = ruta_mas_larga(ruta)
                ruta_corta = ruta_mas_corta(ruta)
                print(ruta)
                crear_historial_json(nombre, cantidad_nodos,vi, vf, ruta, id_usuario, ruta_larga, ruta_corta)
                graph.clear()

            if opc == 2:
                print("Opción 2: Consulta de rutas")
                while True:
                    try:
                        opc2 = int(input("1. Mostrar todos los registros del JSON\
                                        \n2. Mostrar un registro por ID\
                                        \n3. Regresar\n"))
                    except ValueError:
                        print("Tienes que elegir una de las opciones enumeradas")
                    if opc2 == 1:
                        consulta_rutas_json()
                    if opc2 == 2:
                        buscar_id = int(input("¿Numero de ID a buscar?\n"))
                        mostrar_json_id(buscar_id)
                    if opc2 == 3:
                        break

            if opc == 3:
                os.system('cls')
                print("Has salido del programa")
                break

        except ValueError:
            os.system('cls')
            print("Elige una de las opciones enumeradas")

#Funcion para crear la cantidad de nodos que existirán
def crear_nodos():
    while True:
        try:
            cantidad_nodos = int(input("Digite la cantidad de nodos\n"))
            if cantidad_nodos < 2:
                os.system('cls')
                print("Tienes que agregar mas de 1 nodo")
            else:
                while True:
                    try:
                        opc = validar_campo_texto(input("¿Estás seguro que agregarás {} nodos?\
                            \n1. Si\
                            \n2.No\nRecuerda escribir Si o No\n".format(cantidad_nodos)))

                    except ValueError:
                        os.system('cls')
                        print("Tienes que digitar una de las opciones listadas")
                        continue

                    if opc == True:
                        return cantidad_nodos
                    if opc == False:
                        print("Tienes que escribir Si o No")
        except ValueError as e:
            os.system('cls')
            print("Tienes que escribir la cantidad en números")

#Función que conecta los nodos entre sí
def conectar_nodos(cantidad_nodos):
    try:
        for i in range(cantidad_nodos):
            while True:
                print("Nodo actual "+str(i+1)+" de "+str(cantidad_nodos))
                nodo = input("Digite el nombre del nodo en mayuscula "+str("    ")).upper()
                if comprobar_existencia_nodo(nodo,graph) == True:
                    print(graph)
                    print("No puedes crear el mismo nodo otra vez")
                elif comprobar_existencia_nodo(nodo,graph) == False:
                    if len(nodo) < 1:
                        print("Escribe el nombre del nodo")
                    else:
                        configurar_nodos(nodo)
                        graph.update({nodo: set(nodo_conexiones)})
                        nodo_conexiones.clear()
                        print(graph)
                        break
    except ValueError:
        print("Tienes que escribir el nodo")

#Funcion par agregar o quitar nodos en caso de equivocación
def configurar_nodos(nodo):
    while True:
        try:
            print(nodo+str(nodo_conexiones))
            rpta = int(input("Elige una de las opciones\
                \n1.Agregar conexion de nodo\
                \n2.No agregar conexion de nodo\
                \n3.Eliminar camino de nodo\n"))

            if rpta == 1:
                print(nodo+str(nodo_conexiones))
                while True:
                    try:
                        nodo_unir = input("¿Con quién conecta el nodo "+nodo+"?\n")
                        if nodo_unir == nodo:
                            print("No puedes conectar {} con el nodo {} ".format(nodo_unir, nodo))
                        elif nodo_unir in nodo_conexiones:
                            print("El nodo ya existe")
                        elif nodo_unir == "":
                            print("El campo no puede estar vacío")
                        else:
                            nodo_conexiones.append(nodo_unir)
                            break
                    except:
                        continue
            elif rpta == 2:
                 if nodo_unir == "":
                    print("El campo no puede estar vacio")
                 else:
                    break

            elif rpta == 3:
                if not nodo_conexiones:
                    print("\nLa lista está vacía\n")

                else:
                    print(nodo+str(nodo_conexiones))
                    quitar = input("Escribe el que deseas quitar\n").upper()

                    if quitar in nodo_conexiones:
                        nodo_conexiones.remove(quitar)
                        print("Se ha eliminado el nodo "+quitar+"\n")

                    else:
                        print(quitar+" no existe en el nodo ")

            else:
                print("Tienes que elegir una de las opciones listadas\n")

        except:
            print("\nEl campo no puede estar vacío\n")

#Función que devuelve el recorrido de los grafos desde su variable inicial hasta su variable final
def dfs_paths(graph, start, goal):
    # Define stack variable
    stack = [[start]]
    # Do the process while there are paths to follow
    while stack:
        path = stack.pop()
        node = path[-1]
        for next in graph[node] - set(path):
            # If a correct path is founded, then return the path with the generator
            # else write a new path and follow iterating.
            if next == goal:
                yield path + [next]
            else:
                stack.append(path + [next])

#Función que detecta cuál fue la ruta mas recorrida
def ruta_mas_larga(ruta):
    tamano_ruta = 0
    indice_en_lista_recibida = 0
    ruta_larga = []
    for diccionarios_en_lista in range(len(ruta)):
        if tamano_ruta < len(ruta[diccionarios_en_lista]):
            tamano_ruta = len(ruta[diccionarios_en_lista])
            indice_en_lista_recibida = diccionarios_en_lista
    ruta_larga = ruta[indice_en_lista_recibida]
    return ruta_larga

#Funcion que detecta cual fue la ruta menos recorrida
def ruta_mas_corta(ruta):
    tamano_ruta = 0
    indice_en_lista_recibida = 0
    ruta_corta = []
    for diccionarios_en_lista in range(len(ruta)):
        if  tamano_ruta > len(ruta[diccionarios_en_lista]):
            tamano_ruta = len(ruta[diccionarios_en_lista])
            indice_en_lista_recibida = diccionarios_en_lista
    ruta_corta = ruta[indice_en_lista_recibida]
    return ruta_corta

#Funcion que se enecarga de crear un historial en formato json
def crear_historial_json(nombre, cantidad_nodos, vi, vf, ruta, id_usuario, ruta_larga, ruta_corta):
    if existe_historial() == True:
        nuevos_datos = diccionario_datos(id_usuario, nombre, cantidad_nodos, vi, vf, ruta, ruta_larga, ruta_corta)
        with open("historial.json") as archivo_json:
            datos = json.load(archivo_json)
        datos.append(nuevos_datos)

        with open("historial.json", 'w') as archivo_json:
            json.dump(datos, archivo_json, indent=3)
            print("Se han añadido los siguientes datos al archivo " + \
                  archivo_json.name+"\n")
            print(nuevos_datos)
    else:
        with open("historial.json", 'w') as archivo_json:
            historial.append(diccionario_datos(id_usuario, nombre, cantidad_nodos, vi, vf, ruta, ruta_larga, ruta_corta))
            json.dump(historial, archivo_json, indent=3)
            print(archivo_json.name+" creado exitosamente")
            print("Se han añadido los siguientes datos al archivo " + \
                  archivo_json.name+"\n")
            print(historial)

#Funcion que consulta las rutas del archivo historial.json y las muestra en consola
def consulta_rutas_json():
    if existe_historial() == True:
        with open("historial.json") as archivo_json:
            datos = json.load(archivo_json)
        json_formateado = json.dumps(datos, indent= 3)
        return print(str(json_formateado))

#Funcion encaragda de buscar dentro del historial, un ID y mostrar los resutlados que contenga
def mostrar_json_id(id):
    if existe_historial() == True:
        with open("historial.json") as archivo_json:
            datos = json.load(archivo_json)
            try:
                v = [x for x in datos if x['Id'] == id]
                print("\n")
                if len(v) == 0:
                    print("No existe ese id")
                else:
                    print(v)
            except:
                print("No existe registro")
    else:
        print("No existe el historial.json")

#Funcion que comprueba que no se repita un nodo
def comprobar_existencia_nodo(nodo,graph):
    list = [elementos for elementos in graph.keys()]
    if nodo in list:
        return True
    else:
        return False

#Funcion encargada de leer una entrada por consola y validar que sea un texto
def validar_campo_texto(opc):
    lista_si = ['si','sí','Si','Sí','sI', 'SI', 'SÍ','sÍ']

    if opc.isnumeric():
        print("Tienes que escribir la cantidad en números")
    elif len(opc) <= 0:
        print("El campo no puede estar vacío")
    elif opc in lista_si:
        return True
    else:
        return False

#Funcion que se encarga de verificar si existe un historial en formato JSON devolviendo True sí existe o False si no existe
def existe_historial():
    try:
        with open('historial.json') as archivo:
            return True
    except FileNotFoundError as e:
        return False

#Funcion que sirve para añadir datos que se le introduzcan dentro de un diccionario
def diccionario_datos(id_usuario, nombre, cantidad_nodos, vi, vf, ruta, ruta_larga, ruta_corta):
    diccionario_nuevo = {
        'Id': id_usuario,
        'Usuario': nombre,
        'Cantidad_nodos': cantidad_nodos,
        'Nodo_vi': vi,
        'Nodo_vf': vf,
        'Rutas': ruta,
        'Ruta mas recorrida': ruta_larga,
        'Ruta menos recorrida': ruta_corta}
    return diccionario_nuevo

#Funcion que asigna ID al usuario dependiendo de la cantidad de registros que haya en el historial.json
def asignar_id():
    if existe_historial() == True:
        with open("historial.json") as archivo_json:
            datos = json.load(archivo_json)
            return len(datos) + 1
    else:
        return 1

if __name__ == "__main__":
    # Inicio del programa
    menu_inicio()


from pathlib import Path

import pandas as pd
import requests
import torch
from eyepacs import EyePACS

from EyeQ_process import process

class EyeQ(EyePACS):

    # Create EyeQ dataset class attributes
    image_extension = ".jpg"
    result_label = "quality"
    classes_names = ["Gradable", "Usable", "Ungradable"]

    def __init__(
        self,
        targ_dir: Path = "",  # also called root
        split: str = "train",
        transform=None,
        target_transform=None,
    ) -> None:
        super().__init__(targ_dir, split, transform, target_transform)

        self.__preprocess()

        self.label_csv_name = f"Label_EyeQ_{split}.csv"

        self.__download_results()

        self.df_labels = pd.read_csv(self.data_path / self.label_csv_name, sep=",")

        self.df_labels["image"] = self.df_labels["image"].apply(
            lambda S: S.strip(".jpeg")
        )

    def __download_results(
        self,
    ) -> None:
        # Download EyeQ results
        with open(self.data_path / self.label_csv_name, "wb") as f:
            request = requests.get(
                f"https://raw.githubusercontent.com/HzFu/EyeQ/master/data/{self.label_csv_name}"
            )
            print(f"Downloading Label_EyeQ_{self.split}.csv...")
            f.write(request.content)

    def __preprocess(
        self,
    ) -> None:
        image_list = [str(img) for img in self.paths]
        save_path = str(self.data_path / self.split)

        process(image_list, save_path, self.image_extension)

        self.paths = list(Path(save_path).glob("*" + self.image_extension))

if __name__ == "__main__":

    from torchvision import transforms

    data_transform = transforms.Compose(
        [
            # Resize and Crop the images to 640x640
            transforms.Resize(EyeQ.image_size),
            transforms.CenterCrop(EyeQ.image_size),
            # Turn the image into a torch.Tensor
            transforms.ToTensor(),  # this also converts all pixel values from 0 to 255 to be between 0.0 and 1.0
            transforms.Normalize(EyeQ.mean, EyeQ.std),
        ]
    )

    # Setup path to data folder
    data_path = Path("~/.torchvision/")
    image_path = data_path / "eyeq"

    split = "train"

    dataset = EyeQ(image_path, split=split, transform=data_transform)  # train_data
    n = len(dataset)
    print(f"EyeQ, split {split}, has {n} samples.")

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

    import matplotlib.pyplot as plt
    import torchvision

    def display_image(
        dataset: torchvision.datasets.VisionDataset, targ_sample: int
    ) -> None:
        targ_image, targ_label = dataset[targ_sample][0], dataset[targ_sample][1]

        # Adjust image tensor shape for plotting (rearrange the order of dimensions)
        # [color_channels, height, width] -> [height, width, color_channels]
        targ_image_adjust = (
            targ_image.permute(1, 2, 0) if torch.is_tensor(targ_image) else targ_image
        )

        # Setup plot
        plt.imshow(targ_image_adjust)
        plt.axis("off")
        title = f"class: {EyeQ.classes_names[targ_label]}"
        if torch.is_tensor(targ_image_adjust):
            title = title + f"\nshape: {targ_image_adjust.shape}"
        plt.title(title)

        # Plot the adjusted sample
        plt.show()

    display_image(dataset, 2)  # 13_left

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

    from torch.utils.data import DataLoader

    train_dataloader_custom = DataLoader(
        dataset=dataset,  # use custom created train Dataset
        batch_size=1,  # how many samples per batch?
        num_workers=0,  # how many subprocesses to use for data loading? (higher = more)
        shuffle=True,  # shuffle the data?
    )

    # Get image and label from custom DataLoader
    img_custom = None
    while img_custom is None:
        try:
            img_custom, label_custom = next(iter(train_dataloader_custom))
        except (StopIteration, TypeError):
            break
        except:
            pass

    # Batch size will now be 1, try changing the batch_size parameter above and see what happens
    print(
        f"Image shape: {img_custom.shape} -> [batch_size, color_channels, height, width]"
    )
    print(f"Label shape: {label_custom.shape}")


from channels.generic.websocket import AsyncWebsocketConsumer
import json
from django.forms.models import model_to_dict
from server.serializers.chatroom_serializer import ChatroomSerializer
from server.models import Chatroom, Organization, User, AbstractMessage, chatroom_model
from server.utils.json_util import jsonify
from channels.db import database_sync_to_async
from bson import ObjectId
from copy import deepcopy as deepcopy
import datetime
import time

@database_sync_to_async
def save_to_database(group_name, sender, messageType, message):
    try:
        chatroom = Chatroom.objects.get(room_name=group_name)
    except:
        user = group_name.split("_")[1]
        org = group_name.split("_")[2]

        print(user, org)
        user = model_to_dict(User.objects.get(_id=ObjectId(user)))
        org = model_to_dict(Organization.objects.get(_id=ObjectId(org)))
        data = jsonify({"room_name": group_name, "user":user, "organization":org, "message":[]})
        serializer = ChatroomSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            chatroom = Chatroom.objects.get(room_name=group_name)
        else:
            print(serializer.errors)

    new_message = {"sender":sender, "messageType":messageType, "message":message, "createAt":datetime.datetime.fromtimestamp(time.time())}

    chatroom.message.append(new_message)

    chatroom.save()

    # data = model_to_dict(chatroom)

    # serializer = ChatroomSerializer(data=data)
    # if serializer.is_valid():
    #     serializer.save()
    # else:
    #     serializer.errors()

"""
Route 를 통하여 Consumer에 접근

urls -> views
routing -> consumers
"""

class ChatRoomConsumer(AsyncWebsocketConsumer):
    # Start connection
    async def connect(self):  # calling it will return coroutine(?) object
        """
        enabling web socket activity
        """

        # extract room name
        self.room_name = self.scope["url_route"]["kwargs"]["room_name"]

        # setup group room name
        self.room_group_name = "chat_%s" % self.room_name

        # Construct group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name,  # contains pointer to the channel layer isntance & name to reach the consumer
        )

        # Accept socket connection
        await self.accept()

        # need a broker --> config.settings CHANNEL_LAYERS

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name,
        )

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json["message"]
        username = text_data_json["username"]

        await self.channel_layer.group_send(
            self.room_group_name,
            {"type": "chatroom_message", "message": message, "username": username},
        )

    async def chatroom_message(self, event):
        message = event["message"]
        username = event["username"]
        messageType = event["type"]

        await self.send(
            text_data=json.dumps({"username": username, "message": message})
        )
        await save_to_database(self.room_group_name, username, messageType, message)


import itertools

# 括弧列が正しいかどうかの必要十分条件は以下
# ・'('と')'の数が等しい
# ・すべてのi (1 <= i <= N)に対して左からi番目までの時点で'('の数が')'よりも多い

def check_pair(i):
    if i[0] != '(':
        return False
    right = 0
    left = 0
    for x in i:
        if x == '(':
            left += 1
        else:
            right += 1
        if left < right:
            return False
    return True

N = int(input())
P = itertools.product('()', repeat = N)
for i in P:
    if check_pair(i) and i.count('(') == i.count(')'):
        print(*i, sep='')


from __future__ import print_function
import sys
import time
from random import random
from operator import add

from pyspark import SparkContext

if __name__ == "__main__":
    sc = SparkContext(appName="PythonPi")
    partitions = int(sys.argv[1]) if len(sys.argv) > 1 else 2
    n = 100000 * partitions

    def f(_):
        x = random() * 2 - 1
        y = random() * 2 - 1
        return 1 if x ** 2 + y ** 2 < 1 else 0

    start = time.time()
    print("iterations: %d" % n)
    count = sc.parallelize(range(1, n + 1), partitions).map(f).reduce(add)
    print("exec time %f" % (time.time()-start))
    print("Pi is roughly %f" % (4.0 * count / n))

    sc.stop()


from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = r"""
---
module: droplet_action_snapshot

short_description: Take a snapshot of a Droplet

version_added: 0.3.0

description:
  - Take a snapshot of a Droplet.
  - View the API documentation at U(https://docs.digitalocean.com/reference/api/api-reference/#tag/Droplet-Actions).

author: Mark Mercado (@mamercad)

requirements:
  - pydo >= 0.1.3
  - azure-core >= 1.26.1

options:
  droplet_id:
    description:
      - A unique identifier for a Droplet instance.
      - If provided, C(name) and C(region) are ignore.
    type: int
    required: false
  name:
    description:
      - The name of the Droplet to act on.
      - If provided, must be unique and given with C(region).
    type: str
    required: false
  region:
    description:
      - The name of the Droplet to act on.
      - Required with C(name).
    type: str
    required: false
  snapshot_name:
    description:
      - The name to give the new snapshot of the Droplet.
    type: str
    required: false

extends_documentation_fragment:
  - digitalocean.cloud.common.documentation
"""

EXAMPLES = r"""
- name: Snapshot a Droplet
  digitalocean.cloud.droplet_action_snapshot:
    token: "{{ token }}"
    state: present
    name: my-droplet
    region: nyc3
    snapshot_name: my-droplet-snapshot
"""

RETURN = r"""
action:
  description: DigitalOcean snapshot action information.
  returned: always
  type: dict
  sample:
    id: 36804636
    status: completed
    type: create
    started_at: '2020-11-14T16:29:21Z'
    completed_at: '2020-11-14T16:30:06Z'
    resource_id: 3164444
    resource_type: droplet
    region:
      name: New York 3
      slug: nyc3
      features:
        - private_networking
        - backups
        - ipv6
        - metadata
        - install_agent
        - storage
        - image_transfer
      available: true
      sizes:
        - s-1vcpu-1gb
        - s-1vcpu-2gb
        - s-1vcpu-3gb
        - s-2vcpu-2gb
        - s-3vcpu-1gb
        - s-2vcpu-4gb
        - s-4vcpu-8gb
        - s-6vcpu-16gb
        - s-8vcpu-32gb
        - s-12vcpu-48gb
        - s-16vcpu-64gb
        - s-20vcpu-96gb
        - s-24vcpu-128gb
        - s-32vcpu-192g
    region_slug: string
error:
  description: DigitalOcean API error.
  returned: failure
  type: dict
  sample:
    Message: Informational error message.
    Reason: Unauthorized
    Status Code: 401
msg:
  description: DigitalOcean action information.
  returned: always
  type: str
  sample:
    - No Droplet with ID 336851565
    - No Droplet with name test-droplet-1 in nyc3
    - Droplet test-droplet-1 (336851565) in nyc3 would be sent action 'snapshot'
    - Droplet test-droplet-1 (336851565) in nyc3 sent action 'snapshot'
    - Droplet test-droplet-1 (336851565) in nyc3 sent action 'snapshot' and it has not completed, status is 'in-progress'
"""

import time
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.digitalocean.cloud.plugins.module_utils.common import (
    DigitalOceanCommonModule,
    DigitalOceanOptions,
    DigitalOceanFunctions,
    DigitalOceanConstants,
)

class DropletActionSnapshot(DigitalOceanCommonModule):
    def __init__(self, module):
        super().__init__(module)
        self.timeout = module.params.get("timeout")
        self.droplet_id = module.params.get("droplet_id")
        self.name = module.params.get("name")
        self.region = module.params.get("region")
        self.type = "snapshot"
        self.snapshot_name = module.params.get("snapshot_name")
        self.droplet = self.find_droplet()
        if self.state == "present":
            self.present()

    def find_droplet(self):
        if self.droplet_id:
            try:
                droplet = self.client.droplets.get(droplet_id=self.droplet_id)[
                    "droplet"
                ]
                if droplet:
                    return droplet
                self.module.fail_json(
                    changed=False,
                    msg=f"No Droplet with ID {self.droplet_id}",
                    action=[],
                )
            except DigitalOceanCommonModule.HttpResponseError as err:
                error = {
                    "Message": err.error.message,
                    "Status Code": err.status_code,
                    "Reason": err.reason,
                }
                self.module.fail_json(
                    changed=False, msg=error.get("Message"), error=error, action=[]
                )
        elif self.name and self.region:
            droplets = DigitalOceanFunctions.get_droplet_by_name_in_region(
                module=self.module,
                client=self.client,
                region=self.region,
                name=self.name,
            )
            if len(droplets) == 0:
                self.module.fail_json(
                    changed=False,
                    msg=f"No Droplet named {self.name} in {self.region}",
                    action=[],
                )
            elif len(droplets) > 1:
                self.module.fail_json(
                    changed=False,
                    msg=f"Multiple Droplets ({len(droplets)}) named {self.name} found in {self.region}",
                    action=[],
                )
            return droplets[0]

        self.module.fail_json(
            changed=False,
            msg="Should not reach this",
            action=[],
        )

    def get_action_by_id(self, action_id):
        try:
            action = self.client.actions.get(action_id=action_id)["action"]
            return action
        except DigitalOceanCommonModule.HttpResponseError as err:
            error = {
                "Message": err.error.message,
                "Status Code": err.status_code,
                "Reason": err.reason,
            }
            self.module.fail_json(
                changed=False, msg=error.get("Message"), error=error, action=[]
            )

    def snapshot(self):
        try:
            body = {
                "type": self.type,
                "name": self.snapshot_name,
            }
            action = self.client.droplet_actions.post(
                droplet_id=self.droplet["id"], body=body
            )["action"]

            end_time = time.monotonic() + self.timeout
            while time.monotonic() < end_time and action["status"] != "completed":
                time.sleep(DigitalOceanConstants.SLEEP)
                action = self.get_action_by_id(action_id=action["id"])

            if action["status"] != "completed":
                self.module.fail_json(
                    changed=True,
                    msg=(
                        f"Droplet {self.droplet['name']} ({self.droplet['id']}) in {self.droplet['region']['slug']}"
                        f" sent action '{self.type}' and it has not completed, status is '{action['status']}'"
                    ),
                    action=action,
                )

            self.module.exit_json(
                changed=True,
                msg=f"Droplet {self.droplet['name']} ({self.droplet['id']}) in {self.droplet['region']['slug']} sent action '{self.type}'",
                action=action,
            )
        except DigitalOceanCommonModule.HttpResponseError as err:
            error = {
                "Message": err.error.message,
                "Status Code": err.status_code,
                "Reason": err.reason,
            }
            self.module.fail_json(
                changed=False, msg=error.get("Message"), error=error, action=[]
            )

    def present(self):
        if self.module.check_mode:
            self.module.exit_json(
                changed=True,
                msg=f"Droplet {self.droplet['name']} ({self.droplet['id']}) in {self.droplet['region']['slug']} would be sent action '{self.type}'",
            )

        self.snapshot()

def main():
    argument_spec = DigitalOceanOptions.argument_spec()
    argument_spec.update(
        droplet_id=dict(type="int", required=False),
        name=dict(type="str", required=False),
        region=dict(type="str", required=False),
        snapshot_name=dict(type="str", required=False),
    )
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_one_of=[("droplet_id", "name")],
        mutually_exclusive=[("droplet_id", "name")],
        required_together=[("name", "region")],
    )
    DropletActionSnapshot(module)

if __name__ == "__main__":
    main()


import inspect
import logging
import csv
from openpyxl import Workbook, load_workbook

class Utils():
    def __init__(self):
        self.log_level = logging.DEBUG

    def set_log_level(self, log_level):
        self.log_level = log_level

    # Return logger object for logging test information
    def custom_logger(self):
        # Set to class name, helps with troubleshooting when looking at automation log
        logger_name = inspect.stack()[1][3]
        # logger creation
        logger = logging.getLogger(logger_name)
        logger.setLevel(self.log_level)
        # create handler
        file_handler = logging.FileHandler("..\\Reports\\automation.log", mode="a")
        # create formatter and add to handler
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s : %(message)s',
                                      datefmt="%m/%d/%Y %I:%M:%S %p")
        file_handler.setFormatter(formatter)
        # add console handler to logger
        logger.addHandler(file_handler)
        return logger

    @staticmethod
    def read_data_from_excel(file_name, sheet):
        data_list = []
        work_book = load_workbook(filename=file_name)
        sheet = work_book[sheet]
        row_ct = sheet.max_row
        col_ct = sheet.max_column

        for i in range(2, row_ct + 1):
            row = []
            for j in range(1, col_ct + 1):
                row.append(sheet.cell(row=i, column=j).value)
            data_list.append(row)
        print(data_list)
        return data_list

    @staticmethod
    def read_data_from_csv(file_name):
        data_list = []
        # Open CSV file
        csv_data = open(file_name, "r")
        # Create CSV reader
        reader = csv.reader(csv_data)
        # Skip first line
        next(reader)
        # Add CSV data to data_list
        for row in reader:
            data_list.append(row)
        return data_list


from django.test import TestCase
from django.contrib.auth.models import User
from account.models import Lab
from resource_inventory.models import (
    Scenario,
    Installer,
    Opsys,
    ConfigBundle,
    OPNFVConfig,
    OPNFVRole,
    Image,
    HostProfile,
    GenericResourceBundle,
    GenericResource,
    GenericHost,
    HostConfiguration
)

class ConfigUtil():
    count = 0

    @staticmethod
    def makeScenario():
        return Scenario.objects.create(name="testScenario")

    @staticmethod
    def makeInstaller():
        inst = Installer.objects.create(name="testInstaller")
        inst.sup_scenarios = [ConfigUtil.makeScenario()]
        return inst

    @staticmethod
    def makeOpsys():
        os = Opsys.objects.create(name="test Operating System")
        os.sup_installers = [ConfigUtil.makeInstaller()]
        return os

    @staticmethod
    def makeConfigBundle():
        user = User.objects.create(username="test_user" + str(ConfigUtil.count))
        ConfigUtil.count += 1
        return ConfigBundle.objects.create(owner=user)

    @staticmethod
    def makeOPNFVConfig():
        installer = ConfigUtil.makeInstaller()
        scenario = ConfigUtil.makeScenario()
        bundle = ConfigUtil.makeConfigBundle()
        return OPNFVConfig.objects.create(
            installer=installer,
            scenario=scenario,
            bundle=bundle
        )

    @staticmethod
    def makeOPNFVRole():
        return OPNFVRole.objects.create(
            name="Test role",
            description="This is a test role"
        )

    @staticmethod
    def makeImage():
        owner = User.objects.create(username="another test user")
        lab_user = User.objects.create(username="labUserForTests")
        lab = Lab.objects.create(
            lab_user=lab_user,
            name="this is lab for testing",
            contact_email="email@mail.com",
            contact_phone="123-4567"
        )

        return Image.objects.create(
            cobbler_id="profile1",
            from_lab=lab,
            name="an image for testing",
            owner=owner
        )

    @staticmethod
    def makeGenericHost():
        profile = HostProfile.objects.create(
            host_type=0,
            name="test lab for config bundle",
            description="this is a test profile"
        )
        user = User.objects.create(username="test sample user 12")
        bundle = GenericResourceBundle.objects.create(
            name="Generic bundle for config tests",
            xml="",
            owner=user,
            description=""
        )

        resource = GenericResource.objects.create(
            bundle=bundle,
            name="a test generic resource"
        )

        return GenericHost.objects.create(
            profile=profile,
            resource=resource
        )

    @staticmethod
    def makeHostConfiguration():
        host = ConfigUtil.makeGenericHost()
        image = ConfigUtil.makeImage()
        bundle = ConfigUtil.makeConfigBundle()
        opnfvRole = ConfigUtil.makeOPNFVRole()
        return HostConfiguration.objects.create(
            host=host,
            image=image,
            bundle=bundle,
            opnfvRole=opnfvRole
        )

class ScenarioTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeScenario())

class InstallerTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeInstaller())

class OperatingSystemTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeOpsys())

class ConfigBundleTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeConfigBundle())

class OPNFVConfigTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeOPNFVConfig())

class OPNFVRoleTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeOPNFVRole())

class HostConfigurationTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeHostConfiguration())

class ImageTestCase(TestCase):

    def test_save(self):
        self.assertTrue(ConfigUtil.makeImage())


from __future__ import annotations

import os
from dataclasses import dataclass

import tornado.web

from marimo import _loggers
from marimo._server import sessions
from marimo._server.api import status
from marimo._server.api.validated_handler import ValidatedHandler
from marimo._server.utils import canonicalize_filename
from marimo._utils.parse_dataclass import parse_raw

LOGGER = _loggers.marimo_logger()

@dataclass
class Rename:
    filename: str

class RenameHandler(ValidatedHandler):
    """Rename the current app."""

    @sessions.requires_edit
    def post(self) -> None:
        mgr = sessions.get_manager()
        args = parse_raw(self.request.body, Rename)
        filename = args.filename
        LOGGER.debug("Renaming from %s to %s", mgr.filename, filename)
        if filename is not None:
            filename = canonicalize_filename(filename)

        if filename == mgr.filename:
            # no-op
            pass
        elif filename is None:
            mgr.rename(filename)
        elif os.path.exists(filename):
            raise tornado.web.HTTPError(
                status.HTTPStatus.METHOD_NOT_ALLOWED,
                reason="File {0} already exists".format(filename),
            )
        elif mgr.filename is None:
            try:
                # create a file named `filename`
                with open(filename, "w") as _:
                    pass
            except Exception as err:
                raise tornado.web.HTTPError(
                    status.HTTPStatus.SERVER_ERROR,
                    reason="Failed to create file {0}".format(filename),
                ) from err
            mgr.rename(filename)
        else:
            try:
                os.rename(mgr.filename, filename)
            except Exception as err:
                raise tornado.web.HTTPError(
                    status.HTTPStatus.SERVER_ERROR,
                    reason="Failed to rename from {0} to {1}".format(
                        mgr.filename, filename
                    ),
                ) from err
            mgr.rename(filename)


from contextlib import contextmanager
from django.core.management.base import BaseCommand
from os.path import basename
from time import time
import boto3
import crowdcount.models.paths as ccp
import requests

class Command(BaseCommand):
    def handle(self, *args, **kwargs):
        now = int(time())
        source = "https://cdn.shakeshack.com/camera.jpg?{}".format(now)
        destination = ccp.output("shakeshack-{}.jpg".format(now))

        with _fetch_image(source) as data:
            if len(data) > 0:
                _upload(data, "shakeshack/{}".format(basename(destination)))

@contextmanager
def _fetch_image(source):
    response = requests.get(source, stream=True)

    # Throw an error for bad status codes
    response.raise_for_status()
    yield response.content

def _upload(data, key):
    print("Uploading {}...".format(key))
    s3 = boto3.resource('s3')
    s3.Bucket('dev.counting-company.com').put_object(Key=key, Body=data)


import json
a={
 "shopping_list":
        {
            "chaco":"15",
            "Biscuits":"50",
            "Diary_milk":"30",
            "ice_cream":"20",
        }
}
user=input("enter the name"":")
user1=int(input("enter the number"))
for i in a:
    if a[i][user]==a[i][user]:
        c=a[i][user]
        e=int(c)
        s=e-user1
        d={}
        dic={}
    for key in a :
        for value in a[key]:
            d[value]=a[key][value]
            if value==user:
                d[value]=s
                dic[key]=d
# print(dic)
with open("pavani.json","w")as f:
    json.dump(dic,f,indent=4)
# file = open("pavani.json", "w")
# json.dump(dic, file, indent = 6)
# file.close()


# ----------------- Losses, Initialization & Training ----------------- #

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import tikzplotlib
import torch
from torch.optim import lr_scheduler
from tqdm import tqdm

from data import get_target_samples
from data import latent_data
from data import target_data
from sinkhorn_loss import sinkhorn_loss
from visualize import visualize_training

matplotlib.use("pgf")
matplotlib.rcParams.update({
    "pgf.texsystem": "xelatex",
    'font.family': 'serif',
    'text.usetex': True,
    'pgf.rcfonts': False,
})

# LOSSES #

def discriminator_loss(disc, true_samples, gen_samples, param):
    """
    Calculate discriminator loss for NSGAN and WGAN with regularization techniques.
    Note that the discriminator maximizes the value function, such that it minimizes the
    negative value function (minimizing the loss).
    :param disc: Discriminator instance
    :param true_samples: samples from target distribution
    :param gen_samples: samples from current Generator
    :param param: AttrDict with additional parameters
    :return: discriminator loss
    """

    gen_samples = gen_samples.detach()

    if param.gan_type == "nsgan" or param.gan_type == "vanilla":
        # D maximizes: phi(D(0)) + phi(1-D(G(1))) with phi = log
        return - (torch.mean(torch.log(disc(true_samples))) + torch.mean(torch.log(1 - disc(gen_samples))))

    elif param.gan_type == "wgan":
        # --- Gradient & Lipschitz Penalties --- #
        # 1. Sampling Technique
        n_grad_samples = 1  # number of samples to approximate expectation over penalty distribution
        # x_hat = target_data(param)[0:n_grad_samples]  # sample from target distribution
        x_hat = gen_samples[0:n_grad_samples]  # x_hat from gen_samples
        x_hat.requires_grad_(True)

        # 2. Calculate Gradient
        grad = torch.autograd.grad(
            inputs=x_hat,
            outputs=disc(x_hat),
            grad_outputs=torch.ones_like(disc(x_hat)),
            create_graph=True
        )

        # 3. Calculate penalties
        # 3.1 Gradient Penalty (simple GP)
        if param.regularizer == 'gp':
            penalty = torch.norm(grad[0]) ** 2
        # 3.2 Gradient Penalty for Wasserstein GAN (WGAN-GP)
        if param.regularizer == 'wgan-gp':
            penalty = (torch.norm(torch.mean(grad[0])) - 1) ** 2
        # 3.3 Lipschitz Penalty for Wasserstein GAN (WGAN-LP)
        if param.regularizer == 'wgan-lp':
            penalty = (torch.max(torch.zeros(1), torch.norm(torch.mean(grad[0])) - 1)) ** 2
        # D maximizes: phi(D(true_samples)) + phi(1-D(G(noise))) with phi = id
        if param.regularizer == 'off':
            return - (torch.mean(disc(true_samples)) - torch.mean(disc(gen_samples)))
        else:
            return - (torch.mean(disc(true_samples)) - torch.mean(disc(gen_samples))) + param.pen_weight * penalty

    else:
        raise ValueError("gan_type should be 'nsgan', 'vanilla' or 'wgan'.")

def generator_loss(disc, gen, noise, param):
    """
    Calculate generator loss according to generalized GAN loss.
    :param disc: Discriminator instance
    :param gen: Generator instance
    :param noise: samples from latent distribution
    :param param: AttrDict with additional parameters
    :return: generator loss
    """

    if param.gan_type == "wgan":
        # G minimizes: phi(1-D(G(1))) with phi = id
        return - torch.mean(disc(gen(noise)))

    elif param.gan_type == "nsgan":
        # G minimizes: - phi(D(G(1))) with phi = log
        return - torch.mean(torch.log(disc(gen(noise))))

    elif param.gan_type == "vanilla":
        # G minimizes: - phi(1-D(G(1))) with phi = log
        return torch.mean(torch.log(1 - disc(gen(noise))))

    else:
        raise ValueError("gan_type should be 'nsgan', 'vanilla' or 'wgan'.")

def init_weights(net):
    """
    Small subroutine to initalize weights following Xavier_Uniform.
    :param net: Network (either Discriminator or Generator instance)
    :return:
    """
    if type(net) == torch.nn.Linear:
        # use xavier_uniform (aka Glorot) initialization with scaling parameter gain
        torch.nn.init.xavier_uniform_(net.weight, gain=1.5)

# Define the training loop
def trainer(disc, gen, disc_optimizer, gen_optimizer, param):
    """
    Train a GAN with given agents and optimizers according to the specified arguments in param.
    This function requires the two functions target_data and latent_data to sample data from,
    as well as the functions disc_loss and gen_loss to calculate the losses.
    :parameter:
        - disc : Discriminator instance
        - gen : Generator instance
        - disc_optimizer : torch.optimizer
            Optimizer for the Discriminator
        - gen_optimizer : torch.optimizer
            Optimizer for the Generator
        - param : AttrDict
            Dictionary containing additional parameters, e.g., target_dim, gan_type and n_epochs
    """

    # Prepare lists for training & visualization #
    gen_losses = []
    disc_losses = []
    W_dist = []
    decision_boundaries = []

    # prepare trajectory positions for visualization #
    if param.target_dim == "dirac":
        trajectory_points = np.array([gen.params().theta, disc.params().psi])
    elif param.target_dim == "1D" and param.disc_depth == 1:
        trajectory_points = np.array([gen.params().theta,
                                      disc.params().psi,
                                      gen.params().bias,
                                      disc.params().bias])
    elif param.target_dim == "1D" and param.disc_depth == 2:
        trajectory_points = None

    elif param.target_dim == "2D":
        trajectory_points = None

    # initialize LR Scheduler (if applicable, specify as desired) #
    if param.schedule_lr:
        # MultiStepLR
        # lr_steps = [i / 10 * param.n_epochs for i in range(1, 10)]
        # disc_scheduler = lr_scheduler.MultiStepLR(disc_optimizer, milestones=lr_steps, gamma=1.)
        # gen_scheduler = lr_scheduler.MultiStepLR(gen_optimizer, milestones=lr_steps, gamma=0.99)
        # LambdaLR
        lambda_disc = lambda epoch: np.max([1 - epoch / param.n_epochs, 1 / 500])
        lambda_gen = lambda epoch: np.max([1 - epoch / param.n_epochs, 1 / 1000])
        disc_scheduler = lr_scheduler.LambdaLR(gen_optimizer, lambda_disc)
        gen_scheduler = lr_scheduler.LambdaLR(gen_optimizer, lambda_gen)

    # create target dataset #
    dataset = target_data(param, n_samples=param.dataset_size)

    # --- The Training Loop --- #
    for epoch in tqdm(range(param.n_epochs + 1)):
        for _ in range(param.n_disc_train):
            # --- Sample from target and latent distribution --- #
            true_samples = get_target_samples(param, dataset)
            noise = latent_data(param)
            gen_samples = gen(noise)
            if param.gan_type == "dirac" and param.dirac_noise == True:
                gen_samples += 1. * torch.randn_like(gen_samples, device=param.device)

            # --- Update discriminator --- #
            # Zero out the gradients before backpropagation
            disc_optimizer.zero_grad()
            # calculate discriminator loss
            disc_loss = discriminator_loss(disc, true_samples=true_samples, gen_samples=gen_samples, param=param)
            # Backpropagation
            disc_loss.backward(retain_graph=True)
            # Gradient Update
            disc_optimizer.step()

        # --- Update the generator --- #
        # Zero out the gradients before backpropagation
        gen_optimizer.zero_grad()
        # Calculate discriminator loss
        gen_loss = generator_loss(disc, gen, noise=noise, param=param)
        # Backpropagation
        gen_loss.backward(retain_graph=True)
        # Gradient Update
        gen_optimizer.step()  # Does the update

        # --- LR Schedule --- #
        if param.schedule_lr:
            disc_scheduler.step()
            gen_scheduler.step()

        # --- Save losses and Wasserstein Distance for visualization --- #
        if epoch % param.n_epochs_loss == 0:
            disc_losses.append(disc_loss.data.numpy())
            gen_losses.append(gen_loss.data.numpy())
            W_dist.append(sinkhorn_loss(true_samples, gen_samples, n=param.batch_size))

        # --- Visualize the current state --- #
        if epoch % param.n_epochs_pic == 0:
            # Save current point of trajectory #
            if param.target_dim == "dirac":
                coordinates = np.array([gen.params().theta, disc.params().psi])
                trajectory_points = np.vstack((trajectory_points, coordinates))
            if param.target_dim == "1D" and param.disc_depth == 1:
                coordinates = np.array([gen.params().theta,
                                        disc.params().psi,
                                        gen.params().bias,
                                        disc.params().bias])
                trajectory_points = np.vstack((trajectory_points, coordinates))

            # Save current decision boundaries #
            if param.target_dim == "1D" and param.disc_depth == 2:
                w = torch.reshape(disc.disc[0].weight, [param.n_hidden, ]).detach()
                b = disc.disc[0].bias.detach()
                decision_boundary = (- b / w).tolist()
                decision_boundaries.append(decision_boundary)

            # Visualize the training #
            visualize_training(gen, disc, epoch=epoch, true_samples=true_samples, gen_samples=gen_samples, param=param,
                               W_dist=W_dist, disc_losses=disc_losses, gen_losses=gen_losses,
                               trajectory_points=trajectory_points, decision_boundaries=decision_boundaries)

    # --- After training: Plot and save Loss and Wasserstein Distance --- #
    # Losses
    plt.plot([param.n_epochs_loss * i for i in range(len(gen_losses))], gen_losses,
             color='red', label="Generator Loss")
    plt.plot([param.n_epochs_loss * i for i in range(len(disc_losses))], disc_losses,
             color='orange', label="Discriminator Loss")
    # if param.schedule_lr:
    #    plt.vlines(lr_steps, -5, 5, color='gray', alpha=0.4)
    plt.legend()
    plt.title(f"Loss: {param.gan_type}")
    # Save and close the figure
    plt.savefig(f"{param.save_dir}/0_Loss.png", dpi=200)
    plt.clf()

    # Wasserstein Distance
    plt.plot([param.n_epochs_loss * i for i in range(len(W_dist))], W_dist, color='blue', label="Wasserstein Distance")
    # plt.ylabel(r"$\widehat{W}_1(\mathbb{P},\mathbb{Q})$")
    plt.xlabel("epochs")
    # Save and close the figure
    plt.savefig(f"{param.save_dir}/W_Distance.png")
    tikzplotlib.save(f"{param.save_dir}/W_Distance.tex")
    plt.clf()

    return (W_dist)


from kafka import KafkaProducer

def enviar_mensagem(mensagem, topico):
    print(mensagem)
    # configuração do producer
    producer = KafkaProducer(bootstrap_servers='10.255.255.115:9092')

    # envio da mensagem
    producer.send(topico, mensagem)


import json

htv_data = [
    {
        "brand": "Siser",
        "style": "Easyweed",
        "name_hex_combos": [
            ("White", "#E3DFDC"),
            ("Silver", "#959EA3"),
            ("Gray", "#73797B"),
            ("Charcoal", "#484C56"),
            ("Black", "#26282B"),
            ("Brown", "#3B302D"),
            ("Dark Maroon", "#4A3844"),
            ("Maroon", "#4B2536"),
            ("Burgundy", "#660F2C"),
            ("Red", "#921323"),
            ("Bright Red", "#A42526"),
            ("Hibiscus", "#B43F3E"),
            ("Cardinal", "#71222D"),
            ("Texas Orange", "#9B331D"),
            ("Orange", "#BE401A"),
            ("Orange Soda", "#C14C01"),
            ("Mustard", "#A6740D"),
            ("Sun", "#CE8601"),
            ("Yellow", "#E09F01"),
            ("Lemon", "#D9C301"),
            ("Gold", "#A58840"),
            ("Vegas Gold", "#AE9D70"),
            ("Cream", "#D9C48F"),
            ("Light Apricot", "#D6B389"),
            ("Cashew", "#B49575"),
            ("Tan", "#B49575"),
            ("Latte", "#B49575"),
            ("Hazelnut", "#9B715A"),
            ("Chocolate", "#624D40"),
            ("Mocha", "#513729"),
            ("Lime", "#82B019"),
            ("Green Apple", "#588B40"),
            ("Green", "#265541"),
            ("Cadette Green", "#556A4C"),
            ("Sage", "#9FB48D"),
            ("Green Olive", "#657050"),
            ("Dark Green", "#364543"),
            ("Retro Mint", "#60B8AC"),
            ("Turquoise", "#36505D"),
            ("Powder Blue", "#9CB2B8"),
            ("Sky Blue", "#2B649A"),
            ("Pale Blue", "#8BAEC6"),
            ("Periwinkle", "#9BA3C1"),
            ("Royal Blue", "#394979"),
            ("Navy Blue", "#3D4249"),
            ("Purple", "#3F3A4E"),
            ("Wicked Purple", "#5B4C6C"),
            ("Lilac", "#AB89A0"),
            ("Passion Pink", "#D32365"),
            ("Pink", "#B14560"),
            ("Bubblegum", "#C9758D"),
            ("Flamingo", "#D8868C"),
            ("Melon", "#CC695A"),
            ("Pale Peach", "#D6A782"),
            ("Light Pink", "#D8978B"),
            ("Fluorescent Pink", "#FE157C"),
            ("Fluorescent Raspberry", "#EE0369"),
            ("Fluorescent Coral", "#E81A2D"),
            ("Fluorescent Orange", "#FE5001"),
            ("Fluorescent Yellow", "#D4DE01"),
            ("Fluorescent Green", "#28BC0D"),
            ("Fluorescent Blue", "#05549D"),
        ],
    },
    {
        "brand": "Siser",
        "style": "Glitter",
        "name_hex_combos": [
            ("White", "#D3D6C4"),
            ("Red", "#BD2537"),
        ],
    },
]

# Initialize empty array and primary key counter
fixture_data = []
pk = 1

# Iterate over outer htv_data array
for item in htv_data:
    brand = item["brand"]
    style = item["style"]

    # Iterate over name/hex combinations for current brand and style
    for name, hex_code in item["name_hex_combos"]:
        fixture_record = {
            "model": "api.HTVColor",
            "pk": pk,
            "fields": {
                "brand": brand,
                "style": style,
                "name": name,
                "hex_code": hex_code,
            },
        }
        fixture_data.append(fixture_record)
        pk += 1

# Write fixture_data to the fixture file
fixture_file_path = "api/fixtures/htv_colors_fixture.json"
with open(fixture_file_path, "w") as fixture_file:
    json.dump(fixture_data, fixture_file, indent=2)


from enum import Enum

# ---------------------------------- #
#    NaturalStatTrick data classes   #
# ---------------------------------- #
class nst_sit(Enum):
    ALL_STRENGTHS = 'all'
    EVEN_STRENGTH = 'ev'
    FULL_STRENGTH = '5v5'
    FULL_ADJUSTED = 'sva' # Score and venue adjusted
    POWERPLAY = 'pp'
    FIVE_ON_FOUR_PP = '5v4'
    PENALTYKILL = 'pk'
    FOUR_ON_FIVE_PK = '4v5'
    WITH_EMPTY_NET = 'enf'
    AGAINST_EMPTY_NET = 'ena'

class nst_score(Enum):
    ALL_SCORES = 'all'
    TIED = 'tied'
    LEADING = 'u'
    TRAILING = 'd'
    WITHIN_ONE = 'w1'
    UP_ONE = 'u1'
    DOWN_ONE = 'd1'

class nst_rate(Enum):
    RATES = 'y'
    COUNTS = 'n'

class nst_loc(Enum):
    HOME_AND_AWAY = 'B'
    HOME = 'H'
    AWAY = 'A'

class nst_gpf(Enum):
    FULL_SEASON = '410'
    LAST_TEN = '10'

# ------------------------------- #
#    LeftWingLock data classes    #
# ------------------------------- #
class lwl_strengths(Enum):
    EV = 'EV'
    PP = 'PP'
    PK = 'SH'

class lwl_gametypes(Enum):
    GAMEDAY = 'GD'
    MOST_RECENT = '1'
    LAST_3 = '3'

# -------------------------------- #
#    DraftkingsAPI data classes    #
# -------------------------------- #
CLASSIC_IDS = (1, 72, 122, 98, 70, 94, 125, 21)
SHOWDOWN_IDS = []

# -------------------------- #
#    NHL_API data classes    #
# -------------------------- #

# ---------------- #
#    Odds sites    #
# ---------------- #
US_SITES = ('pointsbetus', 'betonlineag', 'bookmaker', 'mybookieag', 'intertops', 'betfair', 'lowvig')
UK_SITES = ('mybookieag', 'betfair', 'willhill', 'paddypower')
EU_SITES = ('betonlineag', 'bookmaker', 'mybookieag', 'intertops', 'betfair', 'pinnacle')

# ---------------------------------------- #
#    All Team Ids, Names, Abbreviations    #
# ---------------------------------------- #

# --------- #
#    NHL    #
# --------- #
NHL_TEAMS = {
    'NJD': {
     'dk_abbreviation': 'NJ',
     'dk_team_id': 4964,
     'nhl_id': 1,
     'name': 'New Jersey Devils',
     'secondary_name': 'New Jersey Devils',
     'slug': 'new-jersey-devils',
     'nhl_abbreviation': 'NJD',
     'nst_abbreviation': 'N.J',
    },
    'NYI': {
     'dk_abbreviation': 'NYI',
     'dk_team_id': 4965,
     'nhl_id': 2,
     'name': 'New York Islanders',
     'secondary_name': 'New York Islanders',
     'slug': 'new-york-islanders',
     'nhl_abbreviation': 'NYI',
     'nst_abbreviation': 'NYI',
    },
    'NYR': {
     'dk_abbreviation': 'NYR',
     'dk_team_id': 4966,
     'nhl_id': 3,
     'name': 'New York Rangers',
     'secondary_name': 'New York Rangers',
     'slug': 'new-york-rangers',
     'nhl_abbreviation': 'NYR',
     'nst_abbreviation': 'NYR',
    },
    'PHI': {
     'dk_abbreviation': 'PHI',
     'dk_team_id': 4968,
     'nhl_id': 4,
     'name': 'Philadelphia Flyers',
     'secondary_name': 'Philadelphia Flyers',
     'slug': 'philadelphia-flyers',
     'nhl_abbreviation': 'PHI',
     'nst_abbreviation': 'PHI',
    },
    'PIT': {
     'dk_abbreviation': 'PIT',
     'dk_team_id': 4969,
     'nhl_id': 5,
     'name': 'Pittsburgh Penguins',
     'secondary_name': 'Pittsburgh Penguins',
     'slug': 'pittsburgh-penguins',
     'nhl_abbreviation': 'PIT',
     'nst_abbreviation': 'PIT',
    },
    'BOS': {
     'dk_abbreviation': 'BOS',
     'dk_team_id': 4954,
     'nhl_id': 6,
     'name': 'Boston Bruins',
     'secondary_name': 'Boston Bruins',
     'slug': 'boston-bruins',
     'nhl_abbreviation': 'BOS',
     'nst_abbreviation': 'BOS',
    },
    'BUF': {
     'dk_abbreviation': 'BUF',
     'dk_team_id': 4955,
     'nhl_id': 7,
     'name': 'Buffalo Sabres',
     'secondary_name': 'Buffalo Sabres',
     'slug': 'buffalo-sabres',
     'nhl_abbreviation': 'BUF',
     'nst_abbreviation': 'BUF',
    },
    'MTL': {
     'dk_abbreviation': 'MON',
     'dk_team_id': 4963,
     'nhl_id': 8,
     'name': 'Montréal Canadiens',
     'secondary_name': 'Montreal Canadiens',
     'slug': 'montreal-canadiens',
     'nhl_abbreviation': 'MTL',
     'nst_abbreviation': 'MTL',
    },
    'OTT': {
     'dk_abbreviation': 'OTT',
     'dk_team_id': 4967,
     'nhl_id': 9,
     'name': 'Ottawa Senators',
     'secondary_name': 'Ottawa Senators',
     'slug': 'ottawa-senators',
     'nhl_abbreviation': 'OTT',
     'nst_abbreviation': 'OTT',
    },
    'TOR': {
     'dk_abbreviation': 'TOR',
     'dk_team_id': 4974,
     'nhl_id': 10,
     'name': 'Toronto Maple Leafs',
     'secondary_name': 'Toronto Maple Leafs',
     'slug': 'toronto-maple-leafs',
     'nhl_abbreviation': 'TOR',
     'nst_abbreviation': 'TOR',
    },
    'CAR': {
     'dk_abbreviation': 'CAR',
     'dk_team_id': 4960,
     'nhl_id': 12,
     'name': 'Carolina Hurricanes',
     'secondary_name': 'Carolina Hurricanes',
     'slug': 'carolina-hurricanes',
     'nhl_abbreviation': 'CAR',
     'nst_abbreviation': 'CAR',
    },
    'FLA': {
     'dk_abbreviation': 'FLA',
     'dk_team_id': 4979,
     'nhl_id': 13,
     'name': 'Florida Panthers',
     'secondary_name': 'Florida Panthers',
     'slug': 'florida-panthers',
     'nhl_abbreviation': 'FLA',
     'nst_abbreviation': 'FLA',
    },
    'TBL': {
     'dk_abbreviation': 'TB',
     'dk_team_id': 4973,
     'nhl_id': 14,
     'name': 'Tampa Bay Lightning',
     'secondary_name': 'Tampa Bay Lightning',
     'slug': 'tampa-bay-lightning',
     'nhl_abbreviation': 'TBL',
     'nst_abbreviation': 'T.B',
    },
    'WSH': {
     'dk_abbreviation': 'WAS',
     'dk_team_id': 4976,
     'nhl_id': 15,
     'name': 'Washington Capitals',
     'secondary_name': 'Washington Capitals',
     'slug': 'washington-capitals',
     'nhl_abbreviation': 'WSH',
     'nst_abbreviation': 'WSH',
    },
    'CHI': {
     'dk_abbreviation': 'CHI',
     'dk_team_id': 4957,
     'nhl_id': 16,
     'name': 'Chicago Blackhawks',
     'secondary_name': 'Chicago Blackhawks',
     'slug': 'chicago-blackhawks',
     'nhl_abbreviation': 'CHI',
     'nst_abbreviation': 'CHI',
    },
    'DET': {
     'dk_abbreviation': 'DET',
     'dk_team_id': 4958,
     'nhl_id': 17,
     'name': 'Detroit Red Wings',
     'secondary_name': 'Detroit Red Wings',
     'slug': 'detroit-red-wings',
     'nhl_abbreviation': 'DET',
     'nst_abbreviation': 'DET',
    },
    'NSH': {
     'dk_abbreviation': 'NSH',
     'dk_team_id': 4980,
     'nhl_id': 18,
     'name': 'Nashville Predators',
     'secondary_name': 'Nashville Predators',
     'slug': 'nashville-predators',
     'nhl_abbreviation': 'NSH',
     'nst_abbreviation': 'NSH',
    },
    'STL': {
     'dk_abbreviation': 'STL',
     'dk_team_id': 4972,
     'nhl_id': 19,
     'name': 'St. Louis Blues',
     'secondary_name': 'St Louis Blues',
     'slug': 'st-louis-blues',
     'nhl_abbreviation': 'STL',
     'nst_abbreviation': 'STL',
    },
    'CGY': {
     'dk_abbreviation': 'CGY',
     'dk_team_id': 4956,
     'nhl_id': 20,
     'name': 'Calgary Flames',
     'secondary_name': 'Calgary Flames',
     'slug': 'calgary-flames',
     'nhl_abbreviation': 'CGY',
     'nst_abbreviation': 'CGY',
    },
    'COL': {
     'dk_abbreviation': 'COL',
     'dk_team_id': 4970,
     'nhl_id': 21,
     'name': 'Colorado Avalanche',
     'secondary_name': 'Colorado Avalanche',
     'slug': 'colorado-avalanche',
     'nhl_abbreviation': 'COL',
     'nst_abbreviation': 'COL',
    },
    'EDM': {
     'dk_abbreviation': 'EDM',
     'dk_team_id': 4959,
     'nhl_id': 22,
     'name': 'Edmonton Oilers',
     'secondary_name': 'Edmonton Oilers',
     'slug': 'edmonton-oilers',
     'nhl_abbreviation': 'EDM',
     'nst_abbreviation': 'EDM',
    },
    'VAN': {
     'dk_abbreviation': 'VAN',
     'dk_team_id': 4975,
     'nhl_id': 23,
     'name': 'Vancouver Canucks',
     'secondary_name': 'Vancouver Canucks',
     'slug': 'vancouver-canucks',
     'nhl_abbreviation': 'VAN',
     'nst_abbreviation': 'VAN',
    },
    'ANA': {
     'dk_abbreviation': 'ANH',
     'dk_team_id': 4978,
     'nhl_id': 24,
     'name': 'Anaheim Ducks',
     'secondary_name': 'Anaheim Ducks',
     'slug': 'anaheim-ducks',
     'nhl_abbreviation': 'ANA',
     'nst_abbreviation': 'ANA',
    },
    'DAL': {
     'dk_abbreviation': 'DAL',
     'dk_team_id': 4962,
     'nhl_id': 25,
     'name': 'Dallas Stars',
     'secondary_name': 'Dallas Stars',
     'slug': 'dallas-stars',
     'nhl_abbreviation': 'DAL',
     'nst_abbreviation': 'DAL',
    },
    'LAK': {
     'dk_abbreviation': 'LA',
     'dk_team_id': 4961,
     'nhl_id': 26,
     'name': 'Los Angeles Kings',
     'secondary_name': 'Los Angeles Kings',
     'slug': 'los-angeles-kings',
     'nhl_abbreviation': 'LAK',
     'nst_abbreviation': 'L.A',
    },
    'SJS': {
     'dk_abbreviation': 'SJ',
     'dk_team_id': 4971,
     'nhl_id': 28,
     'name': 'San Jose Sharks',
     'secondary_name': 'San Jose Sharks',
     'slug': 'san-jose-sharks',
     'nhl_abbreviation': 'SJS',
     'nst_abbreviation': 'S.J',
    },
    'CBJ': {
     'dk_abbreviation': 'CLS',
     'dk_team_id': 4982,
     'nhl_id': 29,
     'name': 'Columbus Blue Jackets',
     'secondary_name': 'Columbus Blue Jackets',
     'slug': 'columbus-blue-jackets',
     'nhl_abbreviation': 'CBJ',
     'nst_abbreviation': 'CBJ',
    },
    'MIN': {
     'dk_abbreviation': 'MIN',
     'dk_team_id': 4983,
     'nhl_id': 30,
     'name': 'Minnesota Wild',
     'secondary_name': 'Minnesota Wild',
     'slug': 'minnesota-wild',
     'nhl_abbreviation': 'MIN',
     'nst_abbreviation': 'MIN',
    },
    'WPG': {
     'dk_abbreviation': 'WPG',
     'dk_team_id': 4981,
     'nhl_id': 52,
     'name': 'Winnipeg Jets',
     'secondary_name': 'Winnipeg Jets',
     'slug': 'winnipeg-jets',
     'nhl_abbreviation': 'WPG',
     'nst_abbreviation': 'WPG',
    },
    'ARI': {
     'dk_abbreviation': 'ARI',
     'dk_team_id': 4977,
     'nhl_id': 53,
     'name': 'Arizona Coyotes',
     'secondary_name': 'Arizona Coyotes',
     'slug': 'arizona-coyotes',
     'nhl_abbreviation': 'ARI',
     'nst_abbreviation': 'ARI',
    },
    'VGK': {
     'dk_abbreviation': 'VGK',
     'dk_team_id': 58462,
     'nhl_id': 54,
     'name': 'Vegas Golden Knights',
     'secondary_name': 'Vegas Golden Knights',
     'slug': 'vegas-golden-knights',
     'nhl_abbreviation': 'VGK',
     'nst_abbreviation': 'VGK',
    }
}

# ------------------------------- #
# ------------------------------- #

# --------- #
#    NBA    #
# --------- #
NBA_TEAMS = {
  'ATL': {
    'tricode': 'ATL',
    'urlName': 'hawks',
    'teamShortName': 'Atlanta',
    'abbreviation': 'ATL',
    'dk_abbreviation': 'ATL',
    'name': 'Atlanta Hawks',
    'secondary_name': 'Atlanta Hawks',
    'nba_id': '1610612737',
    'dk_team_id': 0
  },
  'BOS': {
    'tricode': 'BOS',
    'urlName': 'celtics',
    'teamShortName': 'Boston',
    'abbreviation': 'BOS',
    'dk_abbreviation': 'BOS',
    'name': 'Boston Celtics',
    'secondary_name': 'Boston Celtics',
    'nba_id': '1610612738',
    'dk_team_id': 0
  },
  'BKN': {
    'tricode': 'BKN',
    'urlName': 'nets',
    'teamShortName': 'Brooklyn',
    'abbreviation': 'BKN',
    'dk_abbreviation': 'BKN',
    'name': 'Brooklyn Nets',
    'secondary_name': 'Brooklyn Nets',
    'nba_id': '1610612751',
    'dk_team_id': 0
  },
  'CHA': {
    'tricode': 'CHA',
    'urlName': 'hornets',
    'teamShortName': 'Charlotte',
    'abbreviation': 'CHA',
    'dk_abbreviation': 'CHA',
    'name': 'Charlotte Hornets',
    'secondary_name': 'Charlotte Hornets',
    'nba_id': '1610612766',
    'dk_team_id': 0
  },
  'CHI': {
    'tricode': 'CHI',
    'urlName': 'bulls',
    'teamShortName': 'Chicago',
    'abbreviation': 'CHI',
    'dk_abbreviation': 'CHI',
    'name': 'Chicago Bulls',
    'secondary_name': 'Chicago Bulls',
    'nba_id': '1610612741',
    'dk_team_id': 0
  },
  'CLE': {
    'tricode': 'CLE',
    'urlName': 'cavaliers',
    'teamShortName': 'Cleveland',
    'abbreviation': 'CLE',
    'dk_abbreviation': 'CLE',
    'name': 'Cleveland Cavaliers',
    'secondary_name': 'Cleveland Cavaliers',
    'nba_id': '1610612739',
    'dk_team_id': 0
  },
  'DAL': {
    'tricode': 'DAL',
    'urlName': 'mavericks',
    'teamShortName': 'Dallas',
    'abbreviation': 'DAL',
    'dk_abbreviation': 'DAL',
    'name': 'Dallas Mavericks',
    'secondary_name': 'Dallas Mavericks',
    'nba_id': '1610612742',
    'dk_team_id': 0
  },
  'DEN': {
    'tricode': 'DEN',
    'urlName': 'nuggets',
    'teamShortName': 'Denver',
    'abbreviation': 'DEN',
    'dk_abbreviation': 'DEN',
    'name': 'Denver Nuggets',
    'secondary_name': 'Denver Nuggets',
    'nba_id': '1610612743',
    'dk_team_id': 0
  },
  'DET': {
    'tricode': 'DET',
    'urlName': 'pistons',
    'teamShortName': 'Detroit',
    'abbreviation': 'DET',
    'dk_abbreviation': 'DET',
    'name': 'Detroit Pistons',
    'secondary_name': 'Detroit Pistons',
    'nba_id': '1610612765',
    'dk_team_id': 0
  },
  'GSW': {
    'tricode': 'GSW',
    'urlName': 'warriors',
    'teamShortName': 'Golden State',
    'abbreviation': 'GSW',
    'dk_abbreviation': 'GS',
    'name': 'Golden State Warriors',
    'secondary_name': 'Golden State Warriors',
    'nba_id': '1610612744',
    'dk_team_id': 0
  },
  'HOU': {
    'tricode': 'HOU',
    'urlName': 'rockets',
    'teamShortName': 'Houston',
    'abbreviation': 'HOU',
    'dk_abbreviation': 'HOU',
    'name': 'Houston Rockets',
    'secondary_name': 'Houston Rockets',
    'nba_id': '1610612745',
    'dk_team_id': 0
  },
  'IND': {
    'tricode': 'IND',
    'urlName': 'pacers',
    'teamShortName': 'Indiana',
    'abbreviation': 'IND',
    'dk_abbreviation': 'IND',
    'name': 'Indiana Pacers',
    'secondary_name': 'Indiana Pacers',
    'nba_id': '1610612754',
    'dk_team_id': 0
  },
  'LAC': {
    'tricode': 'LAC',
    'urlName': 'clippers',
    'teamShortName': 'LA Clippers',
    'abbreviation': 'LAC',
    'dk_abbreviation': 'LAC',
    'name': 'LA Clippers',
    'secondary_name': 'Los Angeles Clippers',
    'nba_id': '1610612746',
    'dk_team_id': 0
  },
  'LAL': {
    'tricode': 'LAL',
    'urlName': 'lakers',
    'teamShortName': 'L.A. Lakers',
    'abbreviation': 'LAL',
    'dk_abbreviation': 'LAL',
    'name': 'Los Angeles Lakers',
    'secondary_name': 'Los Angeles Lakers',
    'nba_id': '1610612747',
    'dk_team_id': 0
  },
  'MEM': {
    'tricode': 'MEM',
    'urlName': 'grizzlies',
    'teamShortName': 'Memphis',
    'abbreviation': 'MEM',
    'dk_abbreviation': 'MEM',
    'name': 'Memphis Grizzlies',
    'secondary_name': 'Memphis Grizzlies',
    'nba_id': '1610612763',
    'dk_team_id': 0
  },
  'MIA': {
    'tricode': 'MIA',
    'urlName': 'heat',
    'teamShortName': 'Miami',
    'abbreviation': 'MIA',
    'dk_abbreviation': 'MIA',
    'name': 'Miami Heat',
    'secondary_name': 'Miami Heat',
    'nba_id': '1610612748',
    'dk_team_id': 0
  },
  'MIL': {
    'tricode': 'MIL',
    'urlName': 'bucks',
    'teamShortName': 'Milwaukee',
    'abbreviation': 'MIL',
    'dk_abbreviation': 'MIL',
    'name': 'Milwaukee Bucks',
    'secondary_name': 'Milwaukee Bucks',
    'nba_id': '1610612749',
    'dk_team_id': 0
  },
  'MIN': {
    'tricode': 'MIN',
    'urlName': 'timberwolves',
    'teamShortName': 'Minnesota',
    'abbreviation': 'MIN',
    'dk_abbreviation': 'MIN',
    'name': 'Minnesota Timberwolves',
    'secondary_name': 'Minnesota Timberwolves',
    'nba_id': '1610612750',
    'dk_team_id': 0
  },
  'NOP': {
    'tricode': 'NOP',
    'urlName': 'pelicans',
    'teamShortName': 'New Orleans',
    'abbreviation': 'NOP',
    'dk_abbreviation': 'NOP',
    'name': 'New Orleans Pelicans',
    'secondary_name': 'New Orleans Pelicans',
    'nba_id': '1610612740',
    'dk_team_id': 0
  },
  'NYK': {
    'tricode': 'NYK',
    'urlName': 'knicks',
    'teamShortName': 'New York',
    'abbreviation': 'NYK',
    'dk_abbreviation': 'NYK',
    'name': 'New York Knicks',
    'secondary_name': 'New York Knicks',
    'nba_id': '1610612752',
    'dk_team_id': 0
  },
  'OKC': {
    'tricode': 'OKC',
    'urlName': 'thunder',
    'teamShortName': 'Oklahoma City',
    'abbreviation': 'OKC',
    'dk_abbreviation': 'OKC',
    'name': 'Oklahoma City Thunder',
    'secondary_name': 'Oklahoma City Thunder',
    'nba_id': '1610612760',
    'dk_team_id': 0
  },
  'ORL': {
    'tricode': 'ORL',
    'urlName': 'magic',
    'teamShortName': 'Orlando',
    'abbreviation': 'ORL',
    'dk_abbreviation': 'ORL',
    'name': 'Orlando Magic',
    'secondary_name': 'Orlando Magic',
    'nba_id': '1610612753',
    'dk_team_id': 0
  },
  'PHI': {
    'tricode': 'PHI',
    'urlName': 'sixers',
    'teamShortName': 'Philadelphia',
    'abbreviation': 'PHI',
    'dk_abbreviation': 'PHI',
    'name': 'Philadelphia 76ers',
    'secondary_name': 'Philadelphia 76ers',
    'nba_id': '1610612755',
    'dk_team_id': 0
  },
  'PHX': {
    'tricode': 'PHX',
    'urlName': 'suns',
    'teamShortName': 'Phoenix',
    'abbreviation': 'PHX',
    'dk_abbreviation': 'PHO',
    'name': 'Phoenix Suns',
    'secondary_name': 'Phoenix Suns',
    'nba_id': '1610612756',
    'dk_team_id': 0
  },
  'POR': {
    'tricode': 'POR',
    'urlName': 'blazers',
    'teamShortName': 'Portland',
    'abbreviation': 'POR',
    'dk_abbreviation': 'POR',
    'name': 'Portland Trail Blazers',
    'secondary_name': 'Portland Trail Blazers',
    'nba_id': '1610612757',
    'dk_team_id': 0
  },
  'SAC': {
    'tricode': 'SAC',
    'urlName': 'kings',
    'teamShortName': 'Sacramento',
    'abbreviation': 'SAC',
    'dk_abbreviation': 'SAC',
    'name': 'Sacramento Kings',
    'secondary_name': 'Sacramento Kings',
    'nba_id': '1610612758',
    'dk_team_id': 0
  },
  'SAS': {
    'tricode': 'SAS',
    'urlName': 'spurs',
    'teamShortName': 'San Antonio',
    'abbreviation': 'SAS',
    'dk_abbreviation': 'SA',
    'name': 'San Antonio Spurs',
    'secondary_name': 'San Antonio Spurs',
    'nba_id': '1610612759',
    'dk_team_id': 0
  },
  'TOR': {
    'tricode': 'TOR',
    'urlName': 'raptors',
    'teamShortName': 'Toronto',
    'abbreviation': 'TOR',
    'dk_abbreviation': 'TOR',
    'name': 'Toronto Raptors',
    'secondary_name': 'Toronto Raptors',
    'nba_id': '1610612761',
    'dk_team_id': 0
  },
  'UTA': {
    'tricode': 'UTA',
    'urlName': 'jazz',
    'teamShortName': 'Utah',
    'abbreviation': 'UTA',
    'dk_abbreviation': 'UTA',
    'name': 'Utah Jazz',
    'secondary_name': 'Utah Jazz',
    'nba_id': '1610612762',
    'dk_team_id': 0
  },
  'WAS': {
    'tricode': 'WAS',
    'urlName': 'wizards',
    'teamShortName': 'Washington',
    'abbreviation': 'WAS',
    'dk_abbreviation': 'WAS',
    'name': 'Washington Wizards',
    'secondary_name': 'Washington Wizards',
    'nba_id': '1610612764',
    'dk_team_id': 0
  }
}

# --------- #
#    MLB    #
# --------- #
MLB_TEAMS = {

}

# --------- #
#    NFL    #
# --------- #
NFL_TEAMS = {
  'TEN': {
        'nfl': 'TEN',
        'dk': 'TEN',
        'dk_id': 336,
        'nfl_team_id': 2100,
        'pfr': 'OTI',
        'pff': 31,
        'pfflabel': 'TEN',
        'fo': 'TEN',
        'full': 'Tennessee Titans',
        'location': 'Tennessee',
        'short_location': 'Tennessee',
        'nickname': 'Titans',
        'slug': 'tennessee-titans'
  },
  'IND': {
          'nfl': 'IND',
          'dk': 'IND',
          'dk_id': 338,
          'nfl_team_id': 2200,
          'pfr': 'CLT',
          'pff': 14,
          'pfflabel': 'IND',
          'fo': 'IND',
          'full': 'Indianapolis Colts',
          'location': 'Indianapolis',
          'short_location': 'Indianapolis',
          'nickname': 'Colts',
          'slug': 'indianapolis-colts'
  },
  'ARI': {
          'nfl': 'ARI',
          'dk': 'ARI',
          'dk_id': 355,
          'nfl_team_id': 3800,
          'pfr': 'CRD',
          'pff': 1,
          'pfflabel': 'ARZ',
          'fo': 'ARI',
          'full': 'Arizona Cardinals',
          'location': 'Arizona',
          'short_location': 'Arizona',
          'nickname': 'Cardinals',
          'slug': 'arizona-cardinals'
  },
  'NE': {
          'nfl': 'NE',
          'dk': 'NE',
          'dk_id': 348,
          'nfl_team_id': 3200,
          'pfr': 'NWE',
          'pff': 19,
          'pfflabel': 'NE',
          'fo': 'NE',
          'full': 'New England Patriots',
          'location': 'New England',
          'short_location': 'New England',
          'nickname': 'Patriots',
          'slug': 'new-england-patriots'
  },
  'CLE': {
          'nfl': 'CLE',
          'dk': 'CLE',
          'dk_id': 329,
          'nfl_team_id': 1050,
          'pfr': 'CLE',
          'pff': 8,
          'pfflabel': 'CLV',
          'fo': 'CLE',
          'full': 'Cleveland Browns',
          'location': 'Cleveland',
          'short_location': 'Cleveland',
          'nickname': 'Browns',
          'slug': 'cleveland-browns'
  },
  'JAX': {
          'nfl': 'JAC',
          'dk': 'JAX',
          'dk_id': 365,
          'nfl_team_id': 2250,
          'pfr': 'JAX',
          'pff': 15,
          'pfflabel': 'JAX',
          'fo': 'JAX',
          'full': 'Jacksonville Jaguars',
          'location': 'Jacksonville',
          'short_location': 'Jacksonville',
          'nickname': 'Jaguars',
          'slug': 'jacksonville-jaguars'
  },
  'MIA': {
          'nfl': 'MIA',
          'dk': 'MIA',
          'dk_id': 345,
          'nfl_team_id': 2700,
          'pfr': 'MIA',
          'pff': 17,
          'pfflabel': 'MIA',
          'fo': 'MIA',
          'full': 'Miami Dolphins',
          'location': 'Miami',
          'short_location': 'Miami',
          'nickname': 'Dolphins',
          'slug': 'miami-dolphins'
  },
  'NYJ': {
          'nfl': 'NYJ',
          'dk': 'NYJ',
          'dk_id': 352,
          'nfl_team_id': 3430,
          'pfr': 'NYJ',
          'pff': 22,
          'pfflabel': 'NYJ',
          'fo': 'NYJ',
          'full': 'New York Jets',
          'location': 'New York Jets',
          'short_location': 'NY Jets',
          'nickname': 'Jets',
          'slug': 'new-york-jets'
  },
  'LV': {
          'nfl': 'LV',
          'dk': 'LV',
          'dk_id': 341,
          'nfl_team_id': 2520,
          'pfr': 'VEG',
          'pff': 23,
          'pfflabel': 'LV',
          'fo': 'LV',
          'full': 'Las Vegas Raiders',
          'location': 'Las Vegas',
          'short_location': 'Las Vegas',
          'nickname': 'Raiders',
          'slug': 'las-vegas-raiders'
  },
  'ATL': {
          'nfl': 'ATL',
          'dk': 'ATL',
          'dk_id': 323,
          'nfl_team_id': 200,
          'pfr': 'ATL',
          'pff': 2,
          'pfflabel': 'ATL',
          'fo': 'ATL',
          'full': 'Atlanta Falcons',
          'location': 'Atlanta',
          'short_location': 'Atlanta',
          'nickname': 'Falcons',
          'slug': 'atlanta-falcons'
  },
  'NYG': {
          'nfl': 'NYG',
          'dk': 'NYG',
          'dk_id': 351,
          'nfl_team_id': 3410,
          'pfr': 'NYG',
          'pff': 21,
          'pfflabel': 'NYG',
          'fo': 'NYG',
          'full': 'New York Giants',
          'location': 'New York Giants',
          'short_location': 'NY Giants',
          'nickname': 'Giants',
          'slug': 'new-york-giants'
  },
  'CIN': {
          'nfl': 'CIN',
          'dk': 'CIN',
          'dk_id': 327,
          'nfl_team_id': 920,
          'pfr': 'CIN',
          'pff': 7,
          'pfflabel': 'CIN',
          'fo': 'CIN',
          'full': 'Cincinnati Bengals',
          'location': 'Cincinnati',
          'short_location': 'Cincinnati',
          'nickname': 'Bengals',
          'slug': 'cincinnati-bengals'
  },
  'LAC': {
          'nfl': 'LAC',
          'dk': 'LAC',
          'dk_id': 357,
          'nfl_team_id': 4400,
          'pfr': 'SDG',
          'pff': 27,
          'pfflabel': 'LAC',
          'fo': 'LAC',
          'full': 'Los Angeles Chargers',
          'location': 'Los Angeles Chargers',
          'short_location': 'LA Chargers',
          'nickname': 'Chargers',
          'slug': 'los-angeles-chargers'
  },
  'BUF': {
          'nfl': 'BUF',
          'dk': 'BUF',
          'dk_id': 324,
          'nfl_team_id': 610,
          'pfr': 'BUF',
          'pff': 4,
          'pfflabel': 'BUF',
          'fo': 'BUF',
          'full': 'Buffalo Bills',
          'location': 'Buffalo',
          'short_location': 'Buffalo',
          'nickname': 'Bills',
          'slug': 'buffalo-bills'
  },
  'CAR': {
          'nfl': 'CAR',
          'dk': 'CAR',
          'dk_id': 364,
          'nfl_team_id': 750,
          'pfr': 'CAR',
          'pff': 5,
          'pfflabel': 'CAR',
          'fo': 'CAR',
          'full': 'Carolina Panthers',
          'location': 'Carolina',
          'short_location': 'Carolina',
          'nickname': 'Panthers',
          'slug': 'carolina-panthers'
  },
  'MIN': {
          'nfl': 'MIN',
          'dk': 'MIN',
          'dk_id': 347,
          'nfl_team_id': 3000,
          'pfr': 'MIN',
          'pff': 18,
          'pfflabel': 'MIN',
          'fo': 'MIN',
          'full': 'Minnesota Vikings',
          'location': 'Minnesota',
          'short_location': 'Minnesota',
          'nickname': 'Vikings',
          'slug': 'minnesota-vikings'
  },
  'NO': {
          'nfl': 'NO',
          'dk': 'NO',
          'dk_id': 350,
          'nfl_team_id': 3300,
          'pfr': 'NOR',
          'pff': 20,
          'pfflabel': 'NO',
          'fo': 'NO',
          'full': 'New Orleans Saints',
          'location': 'New Orleans',
          'short_location': 'New Orleans',
          'nickname': 'Saints',
          'slug': 'new-orleans-saints'
  },
  'DEN': {
          'nfl': 'DEN',
          'dk': 'DEN',
          'dk_id': 332,
          'nfl_team_id': 1400,
          'pfr': 'DEN',
          'pff': 10,
          'pfflabel': 'DEN',
          'fo': 'DEN',
          'full': 'Denver Broncos',
          'location': 'Denver',
          'short_location': 'Denver',
          'nickname': 'Broncos',
          'slug': 'denver-broncos'
  },
  'SF': {
          'nfl': 'SF',
          'dk': 'SF',
          'dk_id': 359,
          'nfl_team_id': 4500,
          'pfr': 'SFO',
          'pff': 28,
          'pfflabel': 'SF',
          'fo': 'SF',
          'full': 'San Francisco 49ers',
          'location': 'San Francisco',
          'short_location': 'San Francisco',
          'nickname': '49ers',
          'slug': 'san-francisco-49ers'
  },
  'KC': {
          'nfl': 'KC',
          'dk': 'KC',
          'dk_id': 339,
          'nfl_team_id': 2310,
          'pfr': 'KAN',
          'pff': 16,
          'pfflabel': 'KC',
          'fo': 'KC',
          'full': 'Kansas City Chiefs',
          'location': 'Kansas City',
          'short_location': 'Kansas City',
          'nickname': 'Chiefs',
          'slug': 'kansas-city-chiefs'
  },
  'TB': {
          'nfl': 'TB',
          'dk': 'TB',
          'dk_id': 362,
          'nfl_team_id': 4900,
          'pfr': 'TAM',
          'pff': 30,
          'pfflabel': 'TB',
          'fo': 'TB',
          'full': 'Tampa Bay Buccaneers',
          'location': 'Tampa Bay',
          'short_location': 'Tampa Bay',
          'nickname': 'Buccaneers',
          'slug': 'tampa-bay-buccaneers'
  },
  'BAL': {
          'nfl': 'BAL',
          'dk': 'BAL',
          'dk_id': 366,
          'nfl_team_id': 325,
          'pfr': 'RAV',
          'pff': 3,
          'pfflabel': 'BLT',
          'fo': 'BAL',
          'full': 'Baltimore Ravens',
          'location': 'Baltimore',
          'short_location': 'Baltimore',
          'nickname': 'Ravens',
          'slug': 'baltimore-ravens'
  },
  'PIT': {
          'nfl': 'PIT',
          'dk': 'PIT',
          'dk_id': 356,
          'nfl_team_id': 3900,
          'pfr': 'PIT',
          'pff': 25,
          'pfflabel': 'PIT',
          'fo': 'PIT',
          'full': 'Pittsburgh Steelers',
          'location': 'Pittsburgh',
          'short_location': 'Pittsburgh',
          'nickname': 'Steelers',
          'slug': 'pittsburgh-steelers'
  },
  'WAS': {
          'nfl': 'WAS',
          'dk': 'WAS',
          'dk_id': 363,
          'nfl_team_id': 5110,
          'pfr': 'WAS',
          'pff': 32,
          'pfflabel': 'WAS',
          'fo': 'WAS',
          'full': 'Washington Football Team',
          'location': 'Washington',
          'short_location': 'Washington',
          'nickname': 'Football Team',
          'slug': 'washington-football-team'
  },
  'CHI': {
          'nfl': 'CHI',
          'dk': 'CHI',
          'dk_id': 326,
          'nfl_team_id': 810,
          'pfr': 'CHI',
          'pff': 6,
          'pfflabel': 'CHI',
          'fo': 'CHI',
          'full': 'Chicago Bears',
          'location': 'Chicago',
          'short_location': 'Chicago',
          'nickname': 'Bears',
          'slug': 'chicago-bears'
  },
  'GB': {
          'nfl': 'GB',
          'dk': 'GB',
          'dk_id': 335,
          'nfl_team_id': 1800,
          'pfr': 'GNB',
          'pff': 12,
          'pfflabel': 'GB',
          'fo': 'GB',
          'full': 'Green Bay Packers',
          'location': 'Green Bay',
          'short_location': 'Green Bay',
          'nickname': 'Packers',
          'slug': 'green-bay-packers'
  },
  'PHI': {
          'nfl': 'PHI',
          'dk': 'PHI',
          'dk_id': 354,
          'nfl_team_id': 3700,
          'pfr': 'PHI',
          'pff': 24,
          'pfflabel': 'PHI',
          'fo': 'PHI',
          'full': 'Philadelphia Eagles',
          'location': 'Philadelphia',
          'short_location': 'Philadelphia',
          'nickname': 'Eagles',
          'slug': 'philadelphia-eagles'
  },
  'HOU': {
          'nfl': 'HOU',
          'dk': 'HOU',
          'dk_id': 325,
          'nfl_team_id': 2120,
          'pfr': 'HTX',
          'pff': 13,
          'pfflabel': 'HST',
          'fo': 'HOU',
          'full': 'Houston Texans',
          'location': 'Houston',
          'short_location': 'Houston',
          'nickname': 'Texans',
          'slug': 'houston-texans'
  },
  'DET': {
          'nfl': 'DET',
          'dk': 'DET',
          'dk_id': 334,
          'nfl_team_id': 1540,
          'pfr': 'DET',
          'pff': 11,
          'pfflabel': 'DET',
          'fo': 'DET',
          'full': 'Detroit Lions',
          'location': 'Detroit',
          'short_location': 'Detroit',
          'nickname': 'Lions',
          'slug': 'detroit-lions'
  },
  'DAL': {
          'nfl': 'DAL',
          'dk': 'DAL',
          'dk_id': 331,
          'nfl_team_id': 1200,
          'pfr': 'DAL',
          'pff': 9,
          'pfflabel': 'DAL',
          'fo': 'DAL',
          'full': 'Dallas Cowboys',
          'location': 'Dallas',
          'short_location': 'Dallas',
          'nickname': 'Cowboys',
          'slug': 'dallas-cowboys'
  },
  'SEA': {
          'nfl': 'SEA',
          'dk': 'SEA',
          'dk_id': 361,
          'nfl_team_id': 4600,
          'pfr': 'SEA',
          'pff': 29,
          'pfflabel': 'SEA',
          'fo': 'SEA',
          'full': 'Seattle Seahawks',
          'location': 'Seattle',
          'short_location': 'Seattle',
          'nickname': 'Seahawks',
          'slug': 'seattle-seahawks'
  },
  'LAR': {
          'nfl': 'LA',
          'dk': 'LAR',
          'dk_id': 343,
          'nfl_team_id': 2510,
          'pfr': 'RAM',
          'pff': 26,
          'pfflabel': 'LA',
          'fo': 'LAR',
          'full': 'Los Angeles Rams',
          'location': 'Los Angeles Rams',
          'short_location': 'LA Rams',
          'nickname': 'Rams',
          'slug': 'los-angeles-rams'
  }
}

# ----------------------------------------- #
#          Sports IDs, keys, names          #
#  Keys are named by 'title' from odds API  #
# ----------------------------------------- #
SPORTS = {
    'NFL':{
        'dk_id': 1,
        'dk_name': 'NFL',
        'odds_key': 'americanfootball_nfl',
        'sport_data': NFL_TEAMS
    },
    'NHL':{
        'dk_id': 3,
        'dk_name': 'NHL',
        'odds_key': 'icehockey_nhl',
        'sport_data': NHL_TEAMS
    },
    'NBA':{
        'dk_id': 4,
        'dk_name': 'NBA',
        'odds_key': 'basketball_nba',
        'sport_data': NBA_TEAMS
    },
    'MLB':{
        'dk_id': 2,
        'dk_name': 'MLB',
        'odds_key': 'baseball_mlb',
        'sport_data': MLB_TEAMS
    },
    'GOLF':{
        'dk_id': 13,
        'dk_name': 'GOLF'
    },
    'EPL':{
        'dk_id': 12,
        'dk_name': 'SOC',
        'odds_key': 'soccer_epl'
    },
    'NCAAF':{
        'dk_id': 5,
        'dk_name': 'CFB',
        'odds_key': 'americanfootball_ncaaf'
    },
    'NCAAB':{
        'dk_id': 6,
        'dk_name': 'CBB',
        'odds_key': 'basketball_ncaab'
    },
    'MMA':{
        'dk_id': 9,
        'dk_name': 'MMA',
        'odds_key': 'mma_mixed_martial_arts'
    }
}

#


# coding=utf-8
from __future__ import absolute_import

import torch
from torch import nn
from torch.autograd import Variable
# import numpy as np

class AHardPair(nn.Module):
    def __init__(self, alpha=40, beta=20):
        super(AHardPair, self).__init__()
        self.alpha = alpha
        self.beta = beta

    def forward(self, inputs, targets):
        n = inputs.size(0)
        # Compute pairwise distance
        dist_mat = euclidean_dist(inputs)
        targets = targets.cuda()
        # split the positive and negative pairs
        eyes_ = Variable(torch.eye(n, n)).cuda()
        # eyes_ = Variable(torch.eye(n, n))
        pos_mask = targets.expand(n, n).eq(targets.expand(n, n).t())
        neg_mask = eyes_.eq(eyes_) - pos_mask
        pos_mask = pos_mask - eyes_.eq(1)

        pos_dist = torch.masked_select(dist_mat, pos_mask)
        neg_dist = torch.masked_select(dist_mat, neg_mask)

        num_instances = len(pos_dist)//n + 1
        num_neg_instances = n - num_instances

        pos_dist = pos_dist.resize(len(pos_dist)//(num_instances-1), num_instances-1)
        neg_dist = neg_dist.resize(
            len(neg_dist) // num_neg_instances, num_neg_instances)

        loss = list()
        acc_num = 0

        for i, pos_pair in enumerate(pos_dist):
            pos_pair = pos_dist[i]
            neg_pair = neg_dist[i]

            pos_logit = torch.sum(torch.exp(self.alpha*(1 - pos_pair)))
            neg_logit = torch.sum(torch.exp(self.alpha*(1 - neg_pair)))
            a_lr = 1 - (pos_logit/(pos_logit + neg_logit)).data[0]

            if i % 37 == 0:
                print(3 * '#', '%.2f' % a_lr)

            pos_loss = torch.log(torch.sum(torch.exp(self.beta * (pos_pair - 0.8))))
            neg_loss = torch.log(torch.sum(torch.exp(self.beta * (1.1 - neg_pair))))

            loss_ = a_lr*(pos_loss + neg_loss)
            loss.append(loss_)

        # transverse all the valid triplets then average
        loss = torch.mean(torch.cat(loss))

        accuracy = float(acc_num)/n
        neg_d = torch.mean(neg_dist).data[0]
        pos_d = torch.mean(pos_dist).data[0]

        return loss, accuracy, pos_d, neg_d

def euclidean_dist(inputs_):
    n = inputs_.size(0)
    dist = torch.pow(inputs_, 2).sum(dim=1, keepdim=True).expand(n, n)
    dist = dist + dist.t()
    dist.addmm_(1, -2, inputs_, inputs_.t())
    # for numerical stability
    dist = dist.clamp(min=1e-12).sqrt()
    return dist

def main():
    data_size = 32
    input_dim = 3
    output_dim = 2
    num_class = 4
    # margin = 0.5
    x = Variable(torch.rand(data_size, input_dim), requires_grad=False)
    w = Variable(torch.rand(input_dim, output_dim), requires_grad=True)
    inputs = x.mm(w)
    y_ = 8*list(range(num_class))
    targets = Variable(torch.IntTensor(y_))

    print(AHardPair(alpha=40, beta=10)(inputs, targets))

if __name__ == '__main__':
    main()
    print('Congratulations to you!')


from sklearn import decomposition
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler

class customPCA:
    def __init__(self,X,crc_proba,n_components=2,scale=False):
        self.X = X
        self.crc_proba = crc_proba
        self.scale = scale

    def PCA(self,n_components=2):
        pca = decomposition.PCA(n_components=n_components,random_state=0)

        if self.scale:
            scalled = StandardScaler().fit_transform(self.X)
            pca.fit(scalled)
        else:
            pca.fit(self.X)
        return pca

    def PCA_scores(self):
        pca = self.PCA()
        if self.scale:
            scores = pca.transform(StandardScaler().fit_transform(self.X))
        else:
            scores = pca.transform(self.X)

        scores_df = pd.DataFrame(scores,columns=['PC1','PC2'],index=self.X.index)

        return scores_df

    def cumulative_explained_variance(self):
        """
        Return cumulative explained variance of PC1 and PC2
        """
        pca = self.PCA()
        explained_variance = pca.explained_variance_ratio_
        cumulative_variance = np.cumsum(np.round(explained_variance, decimals=3))

        pc_df = pd.DataFrame(['PC1', 'PC2'], columns=['PC'])
        explained_variance_df = pd.DataFrame(explained_variance, columns=['Explained Variance'])
        cumulative_variance_df = pd.DataFrame(cumulative_variance, columns=['Cumulative Variance'])

        explained_cumulative_var = pd.concat([pc_df, explained_variance_df, cumulative_variance_df], axis=1)

        return explained_cumulative_var


import numpy as np
from scipy import optimize
from scipy.interpolate import Rbf, InterpolatedUnivariateSpline
import matplotlib.pyplot as plt
import time

class cftiming:
    def __init__(self):
        self.gain = 0.5
        self.delay = 1000 # delay 1000 ps
        self.method = 'tomas'

    def normalizeY(self, points):
        scale = points[np.argmax(np.abs(points))]
        return np.multiply(points, 1.0/scale)

    def crossFinder(self, y):
        jmin = y.argmin()
        jmax = y.argmax()
        x = np.where(np.diff(np.sign(y)))[0]
        arr1 = np.where(x<jmax)
        if len(arr1[0]) == 0: return -2
        arr1 = arr1[0][-1]
        return int(x[arr1])

    def simulateCFT(self, xs, ys, dt):
        frac = self.gain
        f = InterpolatedUnivariateSpline(xs, ys)
        def simCFT( x):
            return f(x-self.delayInterval*dt)-frac*f(x)
        return simCFT

    def getCFTiming(self, t, y):
        y = self.normalizeY(y)
        dt = t[1]-t[0]
        self.delayInterval = int(self.delay/dt)
        ntrun =int(np.floor(2000/dt))
        ymax = np.amax(y)
        halfy = np.where(y > ymax*self.gain*0.9)[0]
        t0 = halfy[0]
        t1 = halfy[-1]+self.delayInterval
        f = self.simulateCFT(t, y, dt)
        yy = f(t[ntrun:-ntrun])
        yys = yy[t0-ntrun:t1-ntrun]
        if len(yys) == 0 : print(len(yy), [t0-ntrun,t1-ntrun])
        x0 = self.crossFinder(yys)
        if x0 < 0 : return -1
        inte = [t[t0+x0-1], t[t0+x0+1]]
        if self.method == 'tomas':
            try:
                cft = optimize.toms748(f, inte[0],inte[1])
            except:
                print(inte)
                raise ValueError('failed to get CFT')
            #cft = optimize.newton(lambda x : f(x), x0=(inte[0]+inte[1])/2)
        elif self.method == 'linear':
            x1 = inte[0]
            x2 = inte[1]
            k = (f(x2)-f(x1))/(x2-x1)
            cft = x1-f(x1)/k
        return cft

    def debug(self, t, y):
        y = self.normalizeY(y)
        dt = t[1]-t[0]
        ntrun =int(np.floor(2000/dt))
        ymax = np.amax(y)
        halfy = np.where(y > ymax*self.gain*0.9)[0]
        t0 = halfy[0]
        t1 = halfy[-1]+self.delayInterval
        f = self.simulateCFT(t, y, dt)
        yy = f(t[ntrun:-ntrun])
        yys = yy[t0-ntrun:t1-ntrun]
        plt.plot(t[t0-100:t1+100], f(t[t0-100:t1+100]))
        plt.plot(t[t0:t1], f(t[t0:t1]))
        plt.show()

    def getStrange(self, dt):
        print(np.argmax(np.abs(dt)), np.amax(np.abs(dt)))

def gaussian(x, mean, sig, amp):
    return amp*exp(-(x-mean)**2/sig**2)


from pathlib import Path
from argparse import ArgumentParser

import numpy as np

from pymo.parsers import BVHParser
from pymo.writers import BVHWriter
from sklearn.pipeline import Pipeline
import joblib as jl
from tqdm import tqdm
import logging

from pymo.preprocessing import MocapParameterizer, ConstantsRemover, Numpyfier, RootTransformer

def generate_pipeline(data_path: Path, pipeline_dir: Path):
    bvh_parser = BVHParser()
    data = []
    bvh_names = list(data_path.glob('*.bvh')) if data_path.is_dir() else [data_path]
    for bvh_path in bvh_names:
        logging.info(bvh_path)
        data.append(bvh_parser.parse(str(bvh_path)))

    if not pipeline_dir.exists():
        pipeline_dir.mkdir()

    pipeline_path = pipeline_dir / 'data_pip.sav'
    data_pipe = Pipeline([
        ('root', RootTransformer('hip_centric')),
        ('exp', MocapParameterizer('expmap')),
        ('cnst', ConstantsRemover()),
        ('np', Numpyfier())
    ])
    logging.info('Fitting pipeline...')
    data_pipe.fit(data)
    logging.info('Saving pipeline...')
    jl.dump(data_pipe, str(pipeline_path))

def bvh2features(data_path: Path, dst_dir: Path, pipeline_dir: Path):
    bvh_parser = BVHParser()

    pipeline_path = pipeline_dir / 'data_pip.sav'
    assert pipeline_path.exists()

    logging.info('Loading pipeline...')
    data_pipe = jl.load(str(pipeline_path))  # type: Pipeline

    logging.info('Transforming data...')
    bvh_names = list(data_path.glob('*.bvh')) if data_path.is_dir() else [data_path]
    dst_dir = Path(dst_dir)
    if not dst_dir.exists():
        dst_dir.mkdir()

    for bvh_path in tqdm(bvh_names):
        data = bvh_parser.parse(str(bvh_path))
        out_data = data_pipe.transform([data])[0]
        logging.info(f'Output shape: {out_data.shape}')

        dst_path = dst_dir / bvh_path.name.replace('.bvh', '.npy')
        logging.info(dst_path)
        np.save(str(dst_path), out_data)

def features2bvh(data_path: Path, dst_dir: Path, pipeline_dir: Path):
    logging.info('Loading pipeline...')
    pipeline_path = Path(pipeline_dir) / 'data_pip.sav'
    pipeline = jl.load(str(pipeline_path))  # type: Pipeline

    data_path = Path(data_path)
    recordings = list(data_path.glob('*.npy')) if data_path.is_dir() else [data_path]

    data = []
    for recording in recordings:
        features = np.load(str(recording))
        logging.info(f"{recording} motion features shape: {features.shape}")
        data.append(features)

    logging.info("Transforming data...")
    bvh_data = pipeline.inverse_transform(data)

    dst_dir = Path(dst_dir)
    if not dst_dir.exists(): dst_dir.mkdir()
    bvh_writer = BVHWriter()
    logging.info("Saving bvh...")
    for i, recording in enumerate(recordings):
        dst_path = dst_dir / recording.name.replace('.npy', '.bvh')
        logging.info(dst_path)
        with open(str(dst_path), 'w') as f:
            bvh_writer.write(bvh_data[i], f)

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    arg_parser = ArgumentParser()
    arg_parser.add_argument('--src', help='Path to data folder')
    arg_parser.add_argument('--dst', help='Path to folder to store results')
    arg_parser.add_argument('--pipeline_dir', default='./pipe', help='Pth to save pipeline')
    arg_parser.add_argument('--mode', choices=['bvh2npy', 'npy2bvh', 'pipeline'], help='Modes of processing',
                            default='bvh2npy')
    args = arg_parser.parse_args()

    if args.mode == 'pipeline':
        generate_pipeline(Path(args.src), Path(args.pipeline_dir))
    elif args.mode == 'npy2bvh':
        features2bvh(Path(args.src), Path(args.dst), Path(args.pipeline_dir))
    elif args.mode == 'bvh2npy':
        bvh2features(Path(args.src), Path(args.dst), Path(args.pipeline_dir))
    else:
        logging.warning(f'Unsupported mode: {args.mode}')


import argparse
import re

def main():
    parser = argparse.ArgumentParser(prog="2sq.py")

    parser.add_argument(
        "input", type=str, help="Input File Name"
    )
    parser.add_argument(
        "--output", type=str, help="Output file name"
    )

    args = parser.parse_args()

    with open(args.input, "r") as file:
        filedata = file.read()

    pattern = re.compile(r"R__\S+")
    filename = pattern.findall(args.input)[0]

    filedata = filedata.replace("'", "''")

    with open(f"{filename if args.output is None else args.output}", "w", encoding="cp1252") as file:
        file.write(filedata)

if __name__ == "__main__":
    main()