import zip_util
from geopy.distance import geodesic

zip_codes = zip_util.read_zip_all()

def write_loc():
    zip_code = input("Enter a ZIP Code to lookup: ")
    if isinstance(loc(zip_code), tuple):
        print("ZIP Code", zip_code, "is in", ", ".join(loc(zip_code)[1]), "\ncoordinates:",
              " ".join(map(str, (loc(zip_code)[0]))))
        return
    else:
        print(loc(zip_code))

def loc(zip_code):
    flag = False
    for i in range(len(zip_codes) - 1):
        if zip_code == zip_codes[i][0]:
            flag = True
            zip_code_location = zip_codes[i][1:3]
            loc_name = zip_codes[i][3:5]
            return zip_code_location, loc_name
    if not flag:
        return "Invalid or unknown ZIP Code"

def zip():
    flag = False
    city_name = input("Enter a city name to lookup: ").title()
    state_name = input("Enter the state name to lookup: ").upper()
    city_name_zips = []
    for i in range(len(zip_codes) - 1):
        if city_name == zip_codes[i][3] and state_name == zip_codes[i][4]:
            flag = True
            city_name_zips.append(zip_codes[i][0])
            print("The following ZIP Code(s) found for", city_name, state_name, ":", ", "
                  .join(city_name_zips))
            break
    if not flag:
        print("No ZIP Code found for: ", city_name, state_name)

def dist():
    zip_code_1 = input("Enter the first ZIP Code: ")
    zip_code_2 = input("Enter the second ZIP Code: ")
    if isinstance(loc(zip_code_1), tuple) \
            and isinstance(loc(zip_code_2), tuple):
        coordinate_zip_code_1 = loc(zip_code_1)[0]
        coordinate_zip_code_2 = loc(zip_code_2)[0]
        distance_miles = round(geodesic(coordinate_zip_code_1, coordinate_zip_code_2).miles, 2)
        print("The distance between", zip_code_1, "and", zip_code_2, "is", distance_miles, "miles")
        return
    else:
        print("The distance between", zip_code_1, "and", zip_code_2, "cannot be determined")


import json
import string

def format_json_function(input_json_file, input_txt_file, output_file):
    print(f'*** formatting {input_json_file} ***')
    with open(input_json_file, 'r') as f:
        data = json.load(f)

    with open(input_txt_file, 'r') as f:
        transcript = f.read()
        transcript_lines = transcript.split("\n")

    text = [{"begin": "0.000", "children": [], "end": "0.000", "id": "HEAD", "language": None, "lines": []}]

    word_idx = 0

    for line_idx, line in enumerate(transcript_lines):
        words_in_line = line.split()
        for transcript_word in words_in_line:
            if word_idx >= len(data["words"]):
                print(f"Ran out of words in JSON data on line {line_idx + 1} for {input_json_file}.")
                break

            # Remove punctuation for matching
            sanitized_transcript_word = transcript_word.strip(string.punctuation).lower()
            json_word = data["words"][word_idx]["word"].lower() if "word" in data["words"][word_idx] else None

            if sanitized_transcript_word != json_word:
                print(f"Warning: Skipped '{transcript_word}' on line {line_idx + 1} for {input_json_file}.")
                continue

            json_word_has_start = "start" in data["words"][word_idx]
            next_word_has_start = word_idx + 1 < len(data["words"]) and "start" in data["words"][word_idx + 1]

            item = {
                "begin": "{:.3f}".format(data["words"][word_idx]["start"]) if json_word_has_start else "N/A",
                "children": [],
                "end": "{:.3f}".format(data["words"][word_idx + 1]["start"]) if next_word_has_start else "{:.3f}".format(data["words"][word_idx]["end"]) if json_word_has_start else "N/A",
                "id": f"f{word_idx:06}",
                "language": "eng",
                "lines": [transcript_word]
            }

            text.append(item)
            word_idx += 1

        if line_idx < len(transcript_lines) - 1:
            text.append({"lines": [], "tags": "lineBreak"})

    text.append({
        "begin": "{:.3f}".format(data["words"][-1]["end"]) if len(data["words"]) > 0 and "end" in data["words"][-1] else "N/A",
        "children": [],
        "end": "{:.3f}".format(data["words"][-1]["end"]) if len(data["words"]) > 0 and "end" in data["words"][-1] else "N/A",
        "id": "TAIL",
        "language": None,
        "lines": []
    })

    with open(output_file, 'w') as f:
        json.dump({"text": text}, f, indent=4)


from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from dotenv import load_dotenv
load_dotenv()

from src.config.api_config import ApiConfig
from src.routes.dividendos_routes import dividendos_routes
from src.routes.ativos_routes import ativos_routes
from src.routes.vendas_routes import vendas_routes

ROOT_PATH = ApiConfig.ROOT_PATH.value

api = FastAPI(
    title=ApiConfig.TITLE.value,
    description=ApiConfig.DESCRIPTION.value,
    version=ApiConfig.VERSION.value,
    terms_of_service=ApiConfig.TERMS_OF_SERVICE.value,
    contact=ApiConfig.CONTACT.value,
    license_info=ApiConfig.LICENSE_INFO.value,
    openapi_tags=ApiConfig.TAGS_METADATA.value,
    docs_url=ApiConfig.URL_DOCS_API.value,
    redoc_url=None,
    # root_path=ROOT_PATH,
)

api.add_middleware(
    CORSMiddleware,
    allow_origins=ApiConfig.CORS_ALLOW_ORIGINS.value,
    allow_credentials=True,
    allow_methods=ApiConfig.CORS_ALLOW_METHODS.value,
    allow_headers=ApiConfig.CORS_ALLOW_ORIGINS.value,
)

@api.get(ROOT_PATH, tags=["Root"])
def root():
    """Api Ativos"""
    return {
        "Status": "Ok",
        "Descrição": "Api Ativos"
    }

api.include_router(dividendos_routes, tags=["Ativos Dividendos"], prefix=ROOT_PATH)
api.include_router(vendas_routes, tags=["Ativos Lucro Vendas"], prefix=ROOT_PATH)
api.include_router(ativos_routes, tags=["Ativos Lucro Geral"], prefix=ROOT_PATH)


import numpy as np
import math
from matplotlib import pyplot as plt

class vec2:
    def __init__(self, x, y):
            self.x = x
            self.y = y

    def __add__(self, other):
        if isinstance(other, vec2):
            return vec2(self.x+other.x, self.y+other.y)
        return vec2(self.x+other, self.y+other)

    def __sub__(self, other):
        if isinstance(other, vec2):
            return vec2(self.x-other.x, self.y-other.y)
        return vec2(self.x-other, self.y-other)

    def __mul__(self, other):
        if isinstance(other, vec2):
            return vec2(self.x*other.x, self.y*other.y)
        return vec2(self.x*other, self.y*other)

    def __truediv__(self, other):
        if isinstance(other, vec2):
            return vec2(self.x/other.x, self.y/other.y)
        return vec2(self.x/other, self.y/other)

    def length(self):
        return math.hypot(self.x, self.y)

    def normalized(self):
        length = self.length()
        if not length:
            length = 1.0
        return vec2(self.x/length, self.y/length)

    def normalize(self):
        length = self.length()
        if not length:
            length = 1.0
        self.x = self.x / length
        self.y = self.y / length

    def limited(self, maxlength=1.0):
        length = self.length()
        if length > maxlength:
            return vec2(maxlength*self.x/length, maxlength*self.y/length)
        return self

def random_uniform_unit_disk():
    v = vec2(1.0, 1.0)
    while v.length() > 1.0 :
	    v = vec2(np.random.uniform(-1.0, 1.0), np.random.uniform(-1.0, 1.0))
    return v

def random_square_unit_disk():
    radius = np.random.uniform(0.0, 1.0)
    theta = np.random.uniform(0.0, 2.0 * math.pi)
    return vec2(math.cos(theta) * radius, math.sin(theta) * radius)

total_amount = 10000
spiral_arms = 4
amount_per_arm = int(total_amount / spiral_arms)
spread = 0.9

x = []
y = []
s = []
for i in range(0, spiral_arms) :
  t = 0
  dt = 1.0 / amount_per_arm
  for j in range(0, amount_per_arm) :
    size = np.random.uniform(0.2, 2.0)
    theta = (t**0.5 * 4.0 * math.pi) - 2.0 * math.pi
    radius = math.e**(0.306 * theta)
    theta = theta + i * math.pi * 0.5
    pos = vec2(math.cos(theta), math.sin(theta))
    pos = pos * radius
    offset = random_square_unit_disk() * spread
    pos = pos + offset
    x.append(pos.x)
    y.append(pos.y)
    s.append(size)
    t = t + dt

c = np.random.randint(30, 50, len(x))
plt.figure(figsize=(10,10))
plt.scatter(x, y, c=c, s=s)
axes = plt.axes()
axes.set_aspect('equal', 'datalim')
axes.set_facecolor((0.1,0.1,0.1))
plt.show()


"""lmf URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from django.contrib import admin

from . import views

urlpatterns = [
    url(r'^ckeditor/', include('ckeditor_uploader.urls')),
    url(r'^categoria_editorial', views.categoria_editorial, name='editorial'),
    url(r'^categoria_artigos', views.categoria_artigos, name='artigo'),
    url(r'^categoria_destaques', views.categoria_destaques, name='destaque'),
    url(r'^categoria_cursos', views.categoria_cursos, name='curso'),
    url(r'^page/(?P<num>[0-9]+)', views.page),
    url(r'^pesquisa', views.pesquisa, name='pesquisa'),
    url(r'^contato', views.contato, name='contato'),
    url(r'^nosso-time', views.nossotime, name='nossotime'),
    url(r'^membros-antigos', views.membros_antigos, name='membros_antigos'),
    url(r'^galeria', views.galeria, name='galeria'),
    url(r'^mail', views.enviar_email, name='email'),
    url(r'^parceiros', views.parceiros, name='parceiros'),
    url(r'^newsletter', views.newsletter, name='newsletter'),
    url(r'', views.index, name='index'),
]


import requests
import config

def get_page(group, week=''):
    if week:
        week = str(week) + '/'
    url = 'http://www.ifmo.ru/ru/schedule/0/K3140/raspisanie_zanyatiy_K3140.htm'.format(
        domain=config.domain,
        week=week,
        group=group)
    response = requests.get(url)
    web_page = response.text
    return web_page


import sys, os.path as osp, os, math, numpy as np, argparse
import torch
import torch_sparse # Not 100% sure if needed
import gc
import torch.nn as nn
import torch.nn.functional as F
import torch_geometric.transforms as T
from torch_geometric.nn import EdgeConv

class EdgeNetWithCategoriesJittable(nn.Module):
    def __init__(self, input_dim=3, hidden_dim=8, output_dim=4, n_iters=1, aggr='add',
             norm=torch.tensor([1./500., 1./500., 1./54., 1/25., 1./1000.])):
        super(EdgeNetWithCategoriesJittable, self).__init__()

        self.datanorm = nn.Parameter(norm)

        start_width = 2 * (hidden_dim + input_dim)
        middle_width = (3 * hidden_dim + 2*input_dim) // 2

        self.n_iters = n_iters

        self.inputnet =  nn.Sequential(
            nn.Linear(input_dim, 2*hidden_dim),
            nn.Tanh(),
            nn.Linear(2*hidden_dim, 2*hidden_dim),
            nn.Tanh(),
            nn.Linear(2*hidden_dim, hidden_dim),
            nn.Tanh(),
        )

        self.edgenetwork = nn.Sequential(
            nn.Linear(2*n_iters*hidden_dim, 2*hidden_dim),
            nn.ELU(),
            nn.Linear(2*hidden_dim, 2*hidden_dim),
            nn.ELU(),
            nn.Linear(2*hidden_dim, output_dim),
            nn.LogSoftmax(dim=-1),
        )

        convnn = nn.Sequential(
            nn.Linear(start_width, middle_width),
            nn.ELU(),
            #nn.Dropout(p=0.5, inplace=False),
            nn.Linear(middle_width, hidden_dim),
            nn.ELU()
        )
        self.firstnodenetwork = EdgeConv(nn=convnn, aggr=aggr).jittable()
        self.nodenetwork = nn.ModuleList()
        for i in range(n_iters - 1):
            convnn = nn.Sequential(
                nn.Linear(start_width, middle_width),
                nn.ELU(),
                #nn.Dropout(p=0.5, inplace=False),
                nn.Linear(middle_width, hidden_dim),
                nn.ELU()
            )
            self.nodenetwork.append(EdgeConv(nn=convnn, aggr=aggr).jittable())

    def forward(self, x, edge_index):
        row = edge_index[0]
        col = edge_index[1]
        x_norm = self.datanorm * x
        H = self.inputnet(x_norm)
        H = self.firstnodenetwork(torch.cat([H, x_norm], dim=-1), edge_index)
        H_cat = H
        for nodenetwork in self.nodenetwork:
            H = nodenetwork(torch.cat([H, x_norm], dim=-1), edge_index)
            H_cat = torch.cat([H, H_cat], dim=-1)
        return self.edgenetwork(torch.cat([H_cat[row],H_cat[col]],dim=-1)).squeeze(-1)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('checkpoint', type=str, help='Path to checkpoint.pt', default='model_checkpoint_EdgeNetWithCategories_264403_5b5c05404f_csharma.best.pth.tar')
    parser.add_argument('--n_iters', type=int, default=6)
    parser.add_argument('--input_dim', type=int, default=5)
    parser.add_argument('--hidden_dim', type=int, default=64)
    args = parser.parse_args()

    nonjit_model = EdgeNetWithCategoriesJittable(
        n_iters=args.n_iters,
        input_dim=args.input_dim,
        hidden_dim=args.hidden_dim
        )
    model = torch.jit.script(nonjit_model)

    pretrained_dict = torch.load(args.checkpoint, map_location=torch.device('cpu'))['model']
    model_dict = model.state_dict()

    map_pretrained_to_jitmodel = {
        'nodenetwork0.nn.0.weight' : 'firstnodenetwork.nn.0.weight',
        'nodenetwork0.nn.0.bias'   : 'firstnodenetwork.nn.0.bias',
        'nodenetwork0.nn.2.weight' : 'firstnodenetwork.nn.2.weight',
        'nodenetwork0.nn.2.bias'   : 'firstnodenetwork.nn.2.bias',
        'nodenetwork1.nn.0.weight' : 'nodenetwork.0.nn.0.weight',
        'nodenetwork1.nn.0.bias'   : 'nodenetwork.0.nn.0.bias',
        'nodenetwork1.nn.2.weight' : 'nodenetwork.0.nn.2.weight',
        'nodenetwork1.nn.2.bias'   : 'nodenetwork.0.nn.2.bias',
        'nodenetwork2.nn.0.weight' : 'nodenetwork.1.nn.0.weight',
        'nodenetwork2.nn.0.bias'   : 'nodenetwork.1.nn.0.bias',
        'nodenetwork2.nn.2.weight' : 'nodenetwork.1.nn.2.weight',
        'nodenetwork2.nn.2.bias'   : 'nodenetwork.1.nn.2.bias',
        'nodenetwork3.nn.0.weight' : 'nodenetwork.2.nn.0.weight',
        'nodenetwork3.nn.0.bias'   : 'nodenetwork.2.nn.0.bias',
        'nodenetwork3.nn.2.weight' : 'nodenetwork.2.nn.2.weight',
        'nodenetwork3.nn.2.bias'   : 'nodenetwork.2.nn.2.bias',
        'nodenetwork4.nn.0.weight' : 'nodenetwork.3.nn.0.weight',
        'nodenetwork4.nn.0.bias'   : 'nodenetwork.3.nn.0.bias',
        'nodenetwork4.nn.2.weight' : 'nodenetwork.3.nn.2.weight',
        'nodenetwork4.nn.2.bias'   : 'nodenetwork.3.nn.2.bias',
        'nodenetwork5.nn.0.weight' : 'nodenetwork.4.nn.0.weight',
        'nodenetwork5.nn.0.bias'   : 'nodenetwork.4.nn.0.bias',
        'nodenetwork5.nn.2.weight' : 'nodenetwork.4.nn.2.weight',
        'nodenetwork5.nn.2.bias'   : 'nodenetwork.4.nn.2.bias',
        }

    print('Loading checkpoint {0} into model'.format(args.checkpoint))
    for key in pretrained_dict:
        model_key = map_pretrained_to_jitmodel.get(key, key)

        if not model_key in model_dict:
            print('Skipping key {0}, not in model_dict'.format(model_key))
            continue

        if key != model_key:
            print('Mapping {0} --> {1}'.format(key, model_key))

        model_dict[model_key] = pretrained_dict[key]

    model.load_state_dict(model_dict)
    torch.jit.save(model, 'edgenetwithcats.pt')

if __name__ == '__main__':
    main()


""" This module contains the DatasetTransporter class.

To run this module independently, use the following command:
python src/transaction_risk_profiler/io/dataset_transporter.py
"""
import logging
from pathlib import Path

import numpy as np
import pandas as pd
from attrs import define
from attrs import field
from strictyaml import YAML

from transaction_risk_profiler.configs import settings
from transaction_risk_profiler.configs.dataset_config import DatasetCardConfig
from transaction_risk_profiler.io.dataset_utils import fetch_dataset_card
from transaction_risk_profiler.io.dataset_utils import split_data_with_id_hash

logger = logging.getLogger(__name__)

@define
class DataTransporter:
    """
    This class facilitates the transportation of data into various Python
    machine learning algorithms, eliminating the need for repeated data
    loading.
    """

    _filename: str
    _test_ratio: float = 0.2
    _holdout_ratio: float | None = 0.0
    _dataset_card_filename: str | None = None

    df: pd.DataFrame = field(init=False)
    df_train: pd.DataFrame = field(init=False)
    df_test: pd.DataFrame = field(init=False)
    df_holdout: pd.DataFrame | None = field(init=False)

    df_train_id: pd.Series = field(init=False)
    df_test_id: pd.Series = field(init=False)
    df_holdout_id: pd.Series | None = field(init=False)

    y: np.ndarray = field(init=False)
    X: np.ndarray = field(init=False)
    X_pred: np.ndarray = field(init=False)

    dataset_card: YAML | None = field(init=False)
    dataset_config: DatasetCardConfig | None = field(init=False)
    datetime_features: list[str] | None = field(init=False, factory=list)
    hash_column: str | None = field(init=False)

    def __attrs_post_init__(self):
        """Post init method."""
        if self._dataset_card_filename:
            self.load_dataset_card(self._dataset_card_filename)
            self.load_dataset_config(self.dataset_card)

        self.load_data()

    @property
    def filename(self) -> str:
        """
        Return the filename.

        Returns
        -------
        str
            The filename.
        """
        return self._filename

    @property
    def base_filename(self) -> str:
        """
        Return the base filename.

        Returns
        -------
        str
            The filename.
        """
        return self._filename.split("/")[-1].split(".")[0]

    def load_dataset_card(self, dataset_card_filename: str | None = None) -> None:
        """
        Load the dataset card.

        Parameters
        ----------
        dataset_card_filename : str
            The dataset card filename.

        Returns
        -------
        None
        """
        if dataset_card_filename or self._dataset_card_filename:
            self.dataset_card = fetch_dataset_card(
                dataset_card_filename=dataset_card_filename or self._dataset_card_filename
            )

    def load_dataset_config(self, dataset_card: YAML | None = None) -> None:
        """
        Load the dataset config.

        Parameters
        ----------
        dataset_card : YAML
            The dataset card.

        Returns
        -------
        None
        """
        if bool(dataset_card.data):
            self.dataset_card = dataset_card

        if bool(self.dataset_card.data):
            self.dataset_config = DatasetCardConfig(**self.dataset_card.data)
            self.datetime_features = self.dataset_config.datetime_features or []

    def load_full_dataset(self) -> pd.DataFrame:
        """
        Load and return the specified dataset.

        Returns
        -------
        pd.DataFrame
            The loaded dataset in the form of a pandas' DataFrame.

        Raises
        ------
        OSError If the specified dataset is not found.
        TypeError If the dataset file type is not supported.
        """
        path = Path(self.filename)
        if not path.is_file():
            raise OSError(f"Dataset {self.filename} not found.")

        if self.filename.endswith(".csv"):
            return pd.read_csv(self.filename, parse_dates=self.datetime_features)

        elif self.filename.endswith(".json"):
            return pd.read_json(self.filename)

        raise TypeError(f"Dataset file type {self.filename.split('.')[-1]} not supported.")

    def load_data(self, filename: str | None = None, hash_column: str | None = "index") -> None:
        """
        Load data from the given file into Pandas DataFrames and NumPy arrays.

        Parameters
        ----------
        filename : Optional[str]
            The path to the file containing the data.

        hash_column : str
            The column to use for hashing.

        Returns
        -------
        None
        """
        self._filename = filename or self.filename
        self.df = self.load_full_dataset()

        assert not self.df.empty, "No data was loaded, cannot proceed further."

        if not self.dataset_config:
            self.hash_column = "index"
        else:
            self.hash_column = self.dataset_config.id_column or hash_column

        if self.hash_column == "index":
            self.df.reset_index(inplace=True)

        # Unpacking the data
        self.unpack()

        if not self.dataset_config:
            columns_to_drop = []
        else:
            columns_to_drop = self.dataset_config.features_to_drop or []

        if "index" in self.df_train:
            columns_to_drop.append("index")

        self.df_train = self.df_train.reset_index(drop=True).drop(columns=columns_to_drop)
        self.df_test = self.df_test.reset_index(drop=True).drop(columns=columns_to_drop)
        if self.df_holdout is not None:
            self.df_holdout = self.df_holdout.reset_index(drop=True).drop(columns=columns_to_drop)

        # Extracting features and labels
        feature_columns = [cols for cols in self.df.columns if cols not in columns_to_drop]
        self.X = self.df_train[feature_columns].values
        self.X_pred = self.df_test[feature_columns].values
        self.y = self.df_train[self.dataset_config.target].values

    def unpack(self):
        """
        Unpack the loaded data into instance variables.

        Returns
        -------
        None
        """
        # Using split_data_with_id_hash to split data
        self.df_train, self.df_test, self.df_holdout = split_data_with_id_hash(
            self.df, self._test_ratio, self.hash_column, self._holdout_ratio
        )

        # Extracting IDs
        self.df_train_id = self.df_train[self.hash_column]
        self.df_test_id = self.df_test[self.hash_column]
        self.df_holdout_id = (
            self.df_holdout[self.hash_column] if self.df_holdout is not None else None
        )
        # self.all_features = self.df_train.columns.unique()

    def update_data(self, features: list[str]):
        """
        Update the data frames to only include the most important features.

        Parameters
        ----------
        features : List[str]
            The list of important feature names.

        Returns
        -------
        None
        """
        self.df_train = self.df_train[features]
        self.df_test = self.df_test[features]
        self.X_pred = self.df_test.values

    def save_data(
        self,
        base_filename: str | None = None,
        directory: str | None = f"{settings.PROJECT_DIRECTORY}/{settings.DATASET_DIRECTORY}",
        file_type: str | None = "json",
    ) -> None:
        """
        Save the data to the specified directory.

        Parameters
        ----------
        base_filename : str
            The base filename to save the data to.
        directory : str
            The directory to save the data to.
        file_type : str
            The file type to save the data as.
            Default to JSON.

        Returns
        -------
        None
        """
        if not base_filename:
            base_filename = self.base_filename

        if file_type not in {"json", "csv"}:
            raise TypeError(f"File type {file_type} not supported.")

        full_base_filename = f"{directory}/{base_filename}"
        if file_type == "csv":
            self.df_train.to_csv(f"{full_base_filename}_train.csv")
            self.df_test.to_csv(f"{full_base_filename}_test.csv")

            if self.df_holdout is not None:
                self.df_holdout.to_csv(f"{full_base_filename}_holdout.csv")

        self.df_train.to_json(f"{full_base_filename}_train.{file_type}")
        self.df_test.to_json(f"{full_base_filename}_test.{file_type}")

        if self.df_holdout is not None:
            self.df_holdout.to_json(f"{full_base_filename}_holdout.{file_type}")

if __name__ == "__main__":
    # from transaction_risk_profiler.io import DataTransporter

    dt = DataTransporter(
        filename=f"{settings.PROJECT_DIRECTORY}/data/transactions.json",
        test_ratio=0.2,
        holdout_ratio=0.1,
        dataset_card_filename="dataset_card.yml",
    )
    dt.save_data(file_type="csv")


# from turtle import mode
# from unittest import result
import inspect
from django.db import models
from users.models import User
from django.utils import timezone

# Create your models here.
class Anamnese(models.Model):
    id_anamnese = models.AutoField(primary_key=True)
    # pratica_corrida = models.IntegerField("pratica_corrida", null=False)
    usuario = models.OneToOneField(
        "users.User",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="usuario",
        related_name="anamnese"
    )

    pratica_corrida = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="pratica_corrida",
        related_name="pratica_corrida"
    )
    atividade_fisica = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="atividade_fisica",
        related_name="atividade_fisica"
    )
    dieta = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="dieta",
        related_name="dieta"
    )

    pratica_exercicio_academia = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="pratica_exercicio_academia",
        related_name="pratica_exercicio_academia"
    )

    pressao_arterial = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="pressao_arterial",
        related_name="pressao_arterial"
    )

    dor_muscular = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="dor_muscular",
        related_name="dor_muscular"
    )

    tem_lesao = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="tem_lesao",
        related_name="tem_lesao"
    )

    diabetes = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="diabetes",
        related_name="diabetes"
    )

    problema_coronariano = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="problema_coronariano",
        related_name="problema_coronariano"
    )

    competitividade = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="competitividade",
        related_name="competitividade"
    )

    condicao_fisica_atual = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="condicao_fisica_atual",
        related_name="condicao_fisica_atual"
    )

    aptidao_fisica_atual = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="aptidao_fisica_atual",
        related_name="aptidao_fisica_atual"
    )

    atividade_preferida = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="atividade_preferida",
        related_name="atividade_preferida"
    )

    altura = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="altura",
        related_name="altura"
    )

    peso = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="peso",
        related_name="peso"
    )

    data_criacao = models.DateTimeField("data_criacao", default=timezone.now)
    data_modificacao = models.DateTimeField("data_modificacao", auto_now=True)

    @staticmethod
    def buscar_campos_anamnese():
        resultado = []
        resultadoClassePai = []
        resultadoClasseAtual = []
        for i in inspect.getmembers(models.Model):
            if not i[0].startswith('_'):
                if not inspect.isclass(i[1]):
                    if not inspect.ismethod(i[1]) and not inspect.isfunction(i[1]):
                        resultadoClassePai.append(i[0])

        for i in inspect.getmembers(Anamnese):
             if not i[0].startswith('_') and not inspect.isclass(i[1]) and not inspect.ismethod(i[1]) and not inspect.isfunction(i[1]) and not i[0] == 'objects':
                resultadoClasseAtual.append(i[0])
        resultadoClasseAtual.sort()
        resultadoClassePai.sort()
        resultado = set(resultadoClasseAtual) - set(resultadoClassePai)
        #print(tuple(resultado))
        return resultado

    class Meta:
        verbose_name = "Anamnese"
        verbose_name_plural = "Anamneses"

class PerguntasAnamnese(models.Model):
    #anamnese = Anamnese()
    campos_anamnese = Anamnese.buscar_campos_anamnese()
    campos_anamnese_correspondente_opcoes = []
    for campo in campos_anamnese:
        campos_anamnese_correspondente_opcoes.append((campo, campo))

    id_pergunta_anamnese = models.AutoField(primary_key=True)
    texto = models.CharField("texto", max_length=150, blank=False, null=False)
    tipo = models.CharField("tipo", max_length=150, blank=False, null=False, choices=(("texto","Texto"), ("select", "Select"), ("multiselect", "Multiselect"), ("numerico", "Numérico"))) # texto, numerico, opcoes
    campo_anamnese_correspondente = models.CharField("campo_anamnese_correspondente", max_length=100, null=True, blank=False, unique=True, choices=tuple(campos_anamnese_correspondente_opcoes))
    depende_de = models.ForeignKey(
        "anamnese.OpcaoRespostaAnamnese",
        on_delete=models.RESTRICT,
        blank=True,
        null=True,
        db_column="depende_de",
        related_name="depende_de"
    )

    def __str__(self):
        return str(self.id_pergunta_anamnese) +": " + self.texto

    class Meta:
        verbose_name = "Pergunta da Anamnese"
        verbose_name_plural = "Perguntas da Anamnese"

class OpcaoRespostaAnamnese(models.Model):
    id_opcao_resposta_anamnese = models.AutoField(primary_key=True)
    id_pergunta_anamnese = models.ForeignKey(
        PerguntasAnamnese,
        on_delete=models.CASCADE,
        blank=True,
        null=True,
        db_column="id_pergunta_anamnese",
        related_name="opcoes"
    )
    texto = models.CharField("texto", max_length=150, blank=False, null=False)

    def BuscarPergunta(self):
        return PerguntasAnamnese.objects.get(id_pergunta_anamnese = self.id_pergunta_anamnese.id_pergunta_anamnese)

    def __str__(self):
        return self.BuscarPergunta().texto +": " + self.texto


from .pages.main_page import MainPage
from .pages.login_page import LoginPage
from .pages.cart_page import CartPage

import pytest

@pytest.mark.login_guest
class TestLoginFromMainPage(object):
    def test_guest_can_go_to_login_page(self, browser):
        link = "http://selenium1py.pythonanywhere.com"
        page = MainPage(browser, link)                          # initializing the Page Object, passing the driver instance and url to the constructor
        page.open()                                             # page opening
        page.go_to_login_page()                                 # executing the page method - go to the login page
        login_page = LoginPage(browser, browser.current_url)    # initializing the Page Object, passing the driver instance and url to the constructor
        login_page.should_be_login_page()                       # executing the page method - check, if it's the login page

    def test_guest_should_see_login_link(self, browser):
        link = "http://selenium1py.pythonanywhere.com/"
        page = MainPage(browser, link)
        page.open()
        page.should_be_login_link()

def test_guest_cant_see_product_in_cart_opened_from_main_page(browser):
    link = "http://selenium1py.pythonanywhere.com"
    page = MainPage(browser, link)                          # initializing the Page Object, passing the driver instance and url to the constructor
    page.open()                                             # page opening
    page.go_to_basket_page()                                # go to the basket page
    cart_page = CartPage(browser, browser.current_url)      # initializing the Page Object, passing the driver instance and url to the constructor
    cart_page.should_be_empty_cart()                        # check, if the basket is empty
    cart_page.should_be_empty_cart_text()                   # check, there is empty basket text


import socket, pickle, struct
import cv2

class Controlling:
    def __init__(self):
        try:
            self.my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.my_socket.connect(('127.0.0.1', 50000))
        except Exception as e:
            print("we couldn't connect")
            print(e)
        data = b""
        payload_size = struct.calcsize("Q")
        while True:
            while len(data) < payload_size:
                packet = self.my_socket.recv(4 * 1024)
                if not packet:
                    break
                data += packet
            packed_msg_size = data[:payload_size]
            data = data[payload_size:]
            msg_size = struct.unpack("Q", packed_msg_size)[0]
            print(msg_size)
            while len(data) < msg_size:
                data += self.my_socket.recv(4 * 1024)
            frame_data = data[:msg_size]
            data = data[msg_size:]
            frame = pickle.loads(frame_data)
            cv2.imshow("RECEIVING VIDEO", frame)
            key = cv2.waitKey(1) & 0xFF
            if key == ord('q'):
                break

h = Controlling()


from rlkit.torch.torch_rl_algorithm import TorchTrainer
import torch.optim as optim
import torch.nn as nn
import torch
import numpy as np
import rlkit.torch.pytorch_util as ptu
from rlkit.core.eval_util import create_stats_ordered_dict
from collections import OrderedDict

MEAN_MIN = -9.0
MEAN_MAX = 9.0

class S4RLTrainer(TorchTrainer):
    def __init__(self,
                 env,
                 policy,
                 qf1,
                 qf2,
                 target_qf1=None,
                 target_qf2=None,
                 vf=None,
                 discount=0.99,
                 reward_scale=1.0,
                 policy_lr=1e-3,
                 qf_lr=1e-3,
                 optimizer_class=optim.Adam,
                 soft_target_tau=1e-2,
                 # SAC
                 automatic_entropy_tuning=True,
                 target_entropy=None,
                 bc_warm_start=0,
                 num_qs=2,
                 total_training_steps=1E6,
                 # CQL
                 min_q_version=3,
                 temp=1.0,
                 min_q_weight=1.0,
                 ## sort of backup
                 max_q_backup=False,
                 deterministic_backup=True,
                 num_random=10,
                 with_lagrange=False,
                 lagrange_thresh=0.0,
                 ### augmentation type
                 s4rl=dict(type='normal', params=0.0003)
                 ):
        super().__init__()
        self.env = env
        self.obs_lower_bound = float(self.env.observation_space.low[0])
        self.obs_upper_bound = float(self.env.observation_space.high[0])
        self.policy = policy
        self.qf1 = qf1
        self.qf2 = qf2
        self.target_qf1 = target_qf1
        self.target_qf2 = target_qf2
        self.vf = vf
        self.discount = discount
        self.reward_scale = reward_scale
        self.eval_statistics = OrderedDict()
        self._need_to_update_eval_statistics = True

        # setting of loss and optimizer
        self.qf_criterion = nn.MSELoss()
        self.vf_criterion = nn.MSELoss()

        self.policy_optimizer = optimizer_class(
            self.policy.parameters(),
            lr=policy_lr,
        )
        self.qf1_optimizer = optimizer_class(
            self.qf1.parameters(),
            lr=qf_lr,
        )
        self.qf2_optimizer = optimizer_class(
            self.qf2.parameters(),
            lr=qf_lr,
        )

        self.automatic_entropy_tuning = automatic_entropy_tuning
        self.alpha=0.2 # constant alpha if not automatic tuning
        if self.automatic_entropy_tuning:
            if target_entropy:
                self.target_entropy = target_entropy
            else:
                self.target_entropy = -np.prod(self.env.action_space.shape).item()

            self.log_alpha = ptu.zeros(1, requires_grad=True)
            self.alpha_optimizer = optimizer_class(
                [self.log_alpha],
                lr=policy_lr,
            )
            self.alpha = self.log_alpha.exp()

        self.with_lagrange = with_lagrange
        if self.with_lagrange:
            self.target_action_gap = lagrange_thresh
            self.log_alpha_prime = ptu.zeros(1, requires_grad=True)
            self.alpha_prime_optimizer = optimizer_class(
                [self.log_alpha_prime],
                lr=qf_lr,
            )

        self.soft_target_tau = soft_target_tau

        self.bc_warm_start = bc_warm_start
        self.num_qs = num_qs
        self.num_random = num_random
        self.total_training_steps = total_training_steps
        self._n_train_steps_total = 0
        self.min_q_version = min_q_version
        self.min_q_weight = min_q_weight
        self.temp = temp
        self.max_q_backup = max_q_backup
        self.deterministic_backup = deterministic_backup

        self.s4rl_type = s4rl['type']
        self.s4rl_params = s4rl['params']

    def augment_states(self, states):
        if self.s4rl_type == 'normal':
            noise = torch.normal(0, self.s4rl_params, size=states.shape).to(ptu.device)
            aug_states = states + noise
        elif self.s4rl_type == 'uniform':
            # noise = (self.s4rl_params[1] - self.s4rl_params[0]) * torch.rand(size=states.shape).to(ptu.device) + self.s4rl_params[0]
            noise = torch.FloatTensor(size=states.shape).uniform_(-self.s4rl_params, self.s4rl_params).to(ptu.device)
            aug_states = states + noise
        elif self.s4rl_type == 'adv':
            # todo: adversarial augment
            # aug_states = states
            pass
        else:
            raise ValueError('Not support the augmentation:{}'.format(self.s4rl_type))

        return aug_states.clamp(self.obs_lower_bound, self.obs_upper_bound)

    def _get_tensor_values(self, obs, actions, network=None):
        action_size = actions.shape[0]
        obs_size= obs.shape[0]
        num_repeat = int (action_size / obs_size)
        obs_temp = obs.unsqueeze(1).repeat(1, num_repeat, 1).view(obs.shape[0] * num_repeat, obs.shape[1])
        preds = network(obs_temp, actions)
        preds = preds.view(obs.shape[0], num_repeat, 1)
        return preds

    def _get_policy_actions(self, obs, num_actions=1, network=None):
        obs_temp = obs.unsqueeze(1).repeat(1, num_actions, 1).view(obs.shape[0] * num_actions, obs.shape[1])
        actions_dist = network(obs_temp)
        normal_mean = actions_dist.normal_mean # no tanh()
        normal_std = actions_dist.stddev
        new_obs_actions, log_pi = actions_dist.rsample_and_logprob() # (bs*num_actions, act_dim), (bs*num_actions,)

        return new_obs_actions, normal_mean, normal_std, log_pi.view(log_pi.shape[0], 1)

    def train_from_torch(self, batch):

        rewards = batch['rewards']
        terminals = batch['terminals']
        obs = batch['observations']
        actions = batch['actions']
        next_obs = batch['next_observations']

        """
        Critic Loss
        """
        with torch.no_grad():
            next_state_action, _, _, next_state_log_pi = self._get_policy_actions(next_obs, network=self.policy)

            if not self.max_q_backup:
                if self.num_qs == 1:
                    target_q_values = self.target_qf1(self.augment_states(next_obs), next_state_action)
                else:
                    target_q_values = torch.min(
                        self.target_qf1(self.augment_states(next_obs), next_state_action),
                        self.target_qf2(self.augment_states(next_obs), next_state_action),
                    )

                if not self.deterministic_backup:
                    target_q_values = target_q_values - self.alpha * next_state_log_pi
            else:
                """when using max q backup"""
                next_actions_temp, _, _, _ = self._get_policy_actions(next_obs, num_actions=10, network=self.policy)
                target_qf1_values = self._get_tensor_values(self.augment_states(next_obs), next_actions_temp, network=self.target_qf1).max(1)[0].view(-1, 1)
                target_qf2_values = self._get_tensor_values(self.augment_states(next_obs), next_actions_temp, network=self.target_qf2).max(1)[0].view(-1, 1)
                target_q_values = torch.min(target_qf1_values, target_qf2_values)

            q_target = self.reward_scale * rewards + (1. - terminals) * self.discount * target_q_values

        q1_pred = self.qf1(self.augment_states(obs), actions)
        if self.num_qs > 1:
            q2_pred = self.qf2(self.augment_states(obs), actions)

        qf1_loss = self.qf_criterion(q1_pred, q_target)
        if self.num_qs > 1:
            qf2_loss = self.qf_criterion(q2_pred, q_target)

        # add CQL loss
        random_actions_tensor = torch.FloatTensor(q2_pred.shape[0] * self.num_random, actions.shape[-1]).uniform_(-1, 1).to(ptu.device)
        curr_actions_tensor, _, _, curr_log_pis = self._get_policy_actions(obs, num_actions=self.num_random, network=self.policy)
        curr_log_pis = curr_log_pis.view(q2_pred.shape[0], self.num_random, 1)
        next_curr_actions_tensor, _, _, next_curr_log_pis = self._get_policy_actions(next_obs, num_actions=self.num_random, network=self.policy)
        next_curr_log_pis = next_curr_log_pis.view(q2_pred.shape[0], self.num_random, 1)

        q1_rand = self._get_tensor_values(obs, random_actions_tensor, network=self.qf1)
        q2_rand = self._get_tensor_values(obs, random_actions_tensor, network=self.qf2)
        q1_curr_actions = self._get_tensor_values(obs, curr_actions_tensor.detach(), network=self.qf1)
        q2_curr_actions = self._get_tensor_values(obs, curr_actions_tensor.detach(), network=self.qf2)
        q1_next_actions = self._get_tensor_values(obs, next_curr_actions_tensor.detach(), network=self.qf1)
        q2_next_actions = self._get_tensor_values(obs, next_curr_actions_tensor.detach(), network=self.qf2)

        if self.min_q_version == 3:
            # importance sammpled version
            random_density = np.log(0.5 ** curr_actions_tensor.shape[-1])
            cat_q1 = torch.cat(
                [q1_rand - random_density, q1_next_actions - next_curr_log_pis.detach(), q1_curr_actions - curr_log_pis.detach()], 1
            )
            cat_q2 = torch.cat(
                [q2_rand - random_density, q2_next_actions - next_curr_log_pis.detach(), q2_curr_actions - curr_log_pis.detach()], 1
            )
            std_q1 = torch.std(cat_q1, dim=1)
            std_q2 = torch.std(cat_q2, dim=1)
        else:
            cat_q1 = torch.cat(
                [q1_rand, q1_pred.unsqueeze(1), q1_next_actions, q1_curr_actions], 1
            )
            cat_q2 = torch.cat(
                [q2_rand, q2_pred.unsqueeze(1), q2_next_actions, q2_curr_actions], 1
            )
            std_q1 = torch.std(cat_q1, dim=1)
            std_q2 = torch.std(cat_q2, dim=1)

        min_qf1_loss = torch.logsumexp(cat_q1 / self.temp, dim=1,).mean() * self.min_q_weight * self.temp
        min_qf2_loss = torch.logsumexp(cat_q2 / self.temp, dim=1,).mean() * self.min_q_weight * self.temp

        """Subtract the log likelihood of data"""
        min_qf1_loss = min_qf1_loss - q1_pred.mean() * self.min_q_weight
        min_qf2_loss = min_qf2_loss - q2_pred.mean() * self.min_q_weight

        if self.with_lagrange:
            alpha_prime = torch.clamp(self.log_alpha_prime.exp(), min=0.0, max=1000000.0)
            min_qf1_loss = alpha_prime * (min_qf1_loss - self.target_action_gap)
            min_qf2_loss = alpha_prime * (min_qf2_loss - self.target_action_gap)

            self.alpha_prime_optimizer.zero_grad()
            alpha_prime_loss = (-min_qf1_loss - min_qf2_loss)*0.5
            alpha_prime_loss.backward(retain_graph=True)
            self.alpha_prime_optimizer.step()

        qf1_loss = qf1_loss + min_qf1_loss
        qf2_loss = qf2_loss + min_qf2_loss

        """
        Update Critic
        """
        # Update the Q-functions iff
        if self.num_qs == 1:
            self.qf1_optimizer.zero_grad()
            qf1_loss.backward()
            self.qf1_optimizer.step()
        else:
            total_qf_loss = qf1_loss + qf2_loss
            self.qf1_optimizer.zero_grad()
            self.qf2_optimizer.zero_grad()
            total_qf_loss.backward()
            self.qf1_optimizer.step()
            self.qf2_optimizer.step()

        """
        Policy and Alpha Loss
        """
        new_obs_actions, policy_normal_mean, policy_normal_std, log_pi = self._get_policy_actions(obs,
                                                                                network=self.policy)

        if self.automatic_entropy_tuning:
            alpha_loss = -(self.log_alpha * (log_pi + self.target_entropy).detach()).mean()
            self.alpha_optimizer.zero_grad()
            alpha_loss.backward()
            self.alpha_optimizer.step()
            self.alpha = self.log_alpha.exp()

        if self.num_qs == 1:
            q_new_actions = self.qf1(obs, new_obs_actions)
        else:
            q_new_actions = torch.min(
                self.qf1(obs, new_obs_actions),
                self.qf2(obs, new_obs_actions),
            )

        policy_loss = (self.alpha*log_pi - q_new_actions).mean()

        if self._n_train_steps_total + 1 < self.bc_warm_start:
            """
            For the initial few epochs, try doing behaivoral cloning, if needed
            conventionally, there's not much difference in performance with having 20k
            gradient steps here, or not having it
            """
            policy_normal_mean = torch.clamp(policy_normal_mean, MEAN_MIN, MEAN_MAX)
            policy_log_prob = self.policy.logprob(actions, policy_normal_mean, policy_normal_std) # no gradient flow
            policy_loss = (self.alpha * log_pi - policy_log_prob).mean()

        """
        Update Policy
        """
        self.policy_optimizer.zero_grad()
        policy_loss.backward()
        self.policy_optimizer.step()

        """
        Soft Updates
        """
        ptu.soft_update_from_to(
            self.qf1, self.target_qf1, self.soft_target_tau
        )
        if self.num_qs > 1:
            ptu.soft_update_from_to(
                self.qf2, self.target_qf2, self.soft_target_tau
            )

        """
        Save some statistics for eval
        """
        if self._need_to_update_eval_statistics:
            self._need_to_update_eval_statistics = False
            """
            Eval should set this to None.
            This way, these statistics are only computed for one batch.
            """

            self.eval_statistics['QF1 Loss'] = np.mean(ptu.get_numpy(qf1_loss))
            self.eval_statistics['min QF1 Loss'] = np.mean(ptu.get_numpy(min_qf1_loss))
            if self.num_qs > 1:
                self.eval_statistics['QF2 Loss'] = np.mean(ptu.get_numpy(qf2_loss))
                self.eval_statistics['min QF2 Loss'] = np.mean(ptu.get_numpy(min_qf2_loss))

            self.eval_statistics['Std QF1 values'] = np.mean(ptu.get_numpy(std_q1))
            self.eval_statistics['Std QF2 values'] = np.mean(ptu.get_numpy(std_q2))
            self.eval_statistics.update(create_stats_ordered_dict(
                'QF1 in-distribution values',
                ptu.get_numpy(q1_curr_actions),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'QF2 in-distribution values',
                ptu.get_numpy(q2_curr_actions),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'QF1 random values',
                ptu.get_numpy(q1_rand),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'QF2 random values',
                ptu.get_numpy(q2_rand),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'QF1 next_actions values',
                ptu.get_numpy(q1_next_actions),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'QF2 next_actions values',
                ptu.get_numpy(q2_next_actions),
            ))

            self.eval_statistics['Policy Loss'] = np.mean(ptu.get_numpy(
                policy_loss
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'Q1 Predictions',
                ptu.get_numpy(q1_pred),
            ))
            if self.num_qs > 1:
                self.eval_statistics.update(create_stats_ordered_dict(
                    'Q2 Predictions',
                    ptu.get_numpy(q2_pred),
                ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'Q Targets',
                ptu.get_numpy(q_target),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'Log Pis',
                ptu.get_numpy(log_pi),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'Policy mu',
                ptu.get_numpy(policy_normal_mean),
            ))
            self.eval_statistics.update(create_stats_ordered_dict(
                'Policy std',
                ptu.get_numpy(policy_normal_std),
            ))

            if self.automatic_entropy_tuning:
                self.eval_statistics['Alpha'] = self.alpha.item()
                self.eval_statistics['Alpha Loss'] = alpha_loss.item()

            if self.with_lagrange:
                self.eval_statistics['Alpha_prime'] = alpha_prime.item()
                self.eval_statistics['min_q1_loss'] = ptu.get_numpy(min_qf1_loss).mean()
                self.eval_statistics['min_q2_loss'] = ptu.get_numpy(min_qf2_loss).mean()
                self.eval_statistics['threshold action gap'] = self.target_action_gap
                self.eval_statistics['alpha prime loss'] = alpha_prime_loss.item()

        self._n_train_steps_total += 1

    def get_diagnostics(self):
        stats = super().get_diagnostics()
        stats.update(self.eval_statistics)
        return stats

    def end_epoch(self, epoch):
        self._need_to_update_eval_statistics = True

    @property
    def networks(self):
        nets = [
            self.policy,
            self.qf1,
            self.qf2,
            self.target_qf1,
            self.target_qf2,
        ]
        return nets

    def get_snapshot(self):
        return dict(
            policy=self.policy,
            qf1=self.qf1,
            qf2=self.qf2,
            target_qf1=self.target_qf1,
            target_qf2=self.target_qf2,
        )


import argparse
import collections
import torch
import numpy as np
import data_loader.data_loaders as module_data
import model.loss as module_loss
import model.metric as module_metric
import model.model as module_arch
from parse_config import ConfigParser
from trainer import Trainer
from utils import prepare_device

# fix random seeds for reproducibility
SEED = 123
torch.manual_seed(SEED)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
np.random.seed(SEED)

def main(config):
    logger = config.get_logger('train')

    # setup data_loader instances
    data_loader = config.init_obj('data_loader', module_data)
    valid_data_loader = data_loader.split_validation()

    # build model architecture, then print to console
    model = config.init_obj('arch', module_arch)
    logger.info(model)

    # prepare for (multi-device) GPU training
    device, device_ids = prepare_device(config['n_gpu'])
    model = model.to(device)
    if len(device_ids) > 1:
        model = torch.nn.DataParallel(model, device_ids=device_ids)

    # get function handles of loss and metrics
    # getattr built in func
    # config['loss'] is a string that corresponds to the name of the loss function you want to use in module_loss
    criterion = getattr(module_loss, config['loss'])
    # config['metrics'] is a list of strings where each string is the name of a metric function you want to use
    # getattr to fetch each metric function from module_metric by name.
    metrics = [getattr(module_metric, met) for met in config['metrics']]

    # build optimizer, learning rate scheduler. delete every lines containing lr_scheduler for disabling scheduler
    # lambda function that takes a parameter p and returns True if this parameter requires gradient computation (i.e., it's a parameter that the optimizer will update), otherwise False.
    # model.parameters() a method from the PyTorch nn.Module class, which model is an instance of. It returns an iterator over all the parameters (weights and biases) of the model.
    trainable_params = filter(lambda p: p.requires_grad, model.parameters())
    # uses PyTorch module that contains various optimization algorithms with parameters of the model that the optimizer will update
    optimizer = config.init_obj('optimizer', torch.optim, trainable_params)
    # use lr_scheduler so that it adjusts the learning rate based on the number of epochs or other criteria
    lr_scheduler = config.init_obj('lr_scheduler', torch.optim.lr_scheduler, optimizer)
    # uses Trainer Class from trainer.py with defined variables
    trainer = Trainer(model, criterion, metrics, optimizer,
                      config=config,
                      device=device,
                      data_loader=data_loader,
                      valid_data_loader=valid_data_loader,
                      lr_scheduler=lr_scheduler)

    trainer.train()

if __name__ == '__main__':
    # This line creates a new ArgumentParser object, which will be used to parse command-line arguments.
    # description parameter provides a text that will be displayed when the help message of the program is requested.
    # optional, otherwise defaults to none
    args = argparse.ArgumentParser(description='PyTorch Template')
    args.add_argument('-c', '--config', default=None, type=str,
                      help='config file path (default: None)')
    args.add_argument('-r', '--resume', default=None, type=str,
                      help='path to latest checkpoint (default: None)')
    args.add_argument('-d', '--device', default=None, type=str,
                      help='indices of GPUs to enable (default: all)')

    # custom cli options to modify configuration from default values given in json file
    # a template for creating a simple object that can hold three pieces of information: flags, type, and target
    CustomArgs = collections.namedtuple('CustomArgs', 'flags type target')
    # a list of these CustomArgs objects. Each one represents a different setting you can change from the terminal
    # are optional and will override defaults configs if used. otherwise, uses original config file
    options = [
        CustomArgs(['--lr', '--learning_rate'], type=float, target='optimizer;args;lr'),
        CustomArgs(['--bs', '--batch_size'], type=int, target='data_loader;args;batch_size')
    ]
    # this object reads the default settings from a file (like config.json) and then looks at the arguments you've passed in. If you've used any of the flags defined in options, it will replace the default settings with the values you've provided
    # NOTE: config var define here
    config = ConfigParser.from_args(args, options)
    # main function of the script, using the configuration that has been potentially modified by your command-line arguments
    main(config)
    # call function ex: python train.py --lr 0.01 --bs 32


import datetime
import itertools
import argparse
import sys

_sample_srt_entries = """
1
00:00:25,080 --> 00:00:29,580
jaraco.media.srt presents

2
00:00:29,590 --> 00:00:33,660
An SRT Subtitle Parser

3
00:00:38,370 --> 00:00:47,870
Copyright ©2009-2010 Jason R. Coombs
Licensed for redistribution under the MIT license.

""".lstrip()

class SubEntry:
    r"""
    An SRT subtitle entry parser and manager.
    To get the SubEntry entries from an SRT file, just call get_entries
    on a filename or file-like object.

    >>> import io
    >>> sample = io.StringIO(_sample_srt_entries)
    >>> entries = SubEntry.get_entries(sample)

    Entries is now a generator which will parse the entries as they're
    requested. If you have enough memory to load them all in, then you
    can load them into a list or tuple.
    >>> entries = list(entries)

    >>> len(entries)
    3
    >>> entries[0].text
    ['jaraco.media.srt presents\n']
    >>> entries[1].start.seconds
    29
    >>> entries[1].start.microseconds
    590000

    Then, you can adjust when the entries occur. For example, this adds
    one second to the start and end times for the last subtitle.
    >>> entries[2] += datetime.timedelta(seconds=1)

    Finally, you can easily re-serialize the entries.
    >>> str(entries[2])
    '3\n00:00:39,370 --> 00:00:48,870\nCopyright... MIT license.\n'
    """

    time_sep = ' --> '

    def __init__(self, index, start, stop, text):
        self.__dict__.update(vars())
        del self.__dict__['self']

    @staticmethod
    def get_entries(file):
        if isinstance(file, str):
            file = open(file)
        while True:
            try:
                yield SubEntry.get_entry(file)
            except StopIteration:
                return

    @staticmethod
    def get_entry(items):
        items = iter(items)
        index = int(next(items))
        start, stop = SubEntry.parse_span(next(items))

        def is_not_blank(s):
            return bool(s.strip())

        text = list(itertools.takewhile(is_not_blank, items))
        return SubEntry(index, start, stop, text)

    @staticmethod
    def parse_span(span_string):
        times = span_string.split(SubEntry.time_sep)
        return map(SubEntry.parse_time, times)

    @staticmethod
    def parse_time(time_string):
        hr, min, sec = time_string.split(':')
        sec, msec = sec.split(',')
        return datetime.timedelta(
            hours=int(hr),
            minutes=int(min),
            seconds=int(sec),
            milliseconds=int(msec),
        )

    def __sub__(self, difference):
        "Subtract a time difference from the start and stop values"
        start = self.start - difference
        stop = self.stop - difference
        entry = SubEntry(self.index, start, stop, self.text)
        return entry

    def __add__(self, addition):
        "Add a time value to the start and stop values"
        start = self.start + addition
        stop = self.stop + addition
        entry = SubEntry(self.index, start, stop, self.text)
        return entry

    def format_span(self):
        times = map(self.format_time, [self.start, self.stop])
        return self.time_sep.join(times)

    @staticmethod
    def format_time(time):
        # python makes us construct a datetime object in order to get the desired
        #  time object in order to use strftime

        # pick some abitrary date
        dt = datetime.datetime(2000, 1, 1)
        # add our timedelta
        dt += time
        # extract the time
        time = dt.time()
        time_string = time.strftime('%H:%M:%S,%f')
        # strip the microseconds
        time_string = time_string[:-3]
        return time_string

    def __str__(self):
        items = [
            str(self.index),
            self.format_span(),
            ''.join(self.text),
        ]
        return '\n'.join(items)

    @staticmethod
    def write_entries(file, entries):
        if isinstance(file, str):
            file = open(file, 'w')
        for entry in entries:
            file.write(str(entry))
            file.write('\n')

    @staticmethod
    def adjust_entries(entries, adjustment):
        for entry in entries:
            yield entry + adjustment

class AdjustCommand:
    @classmethod
    def get_args(cls):
        parser = argparse.ArgumentParser()
        parser.add_argument(
            'delta', type=lambda s: datetime.timedelta(seconds=float(s))
        )
        parser.add_argument('-s', '--start-entry', default=0, type=int)
        parser.add_argument('-e', '--end-entry', type=int)
        return parser.parse_args()

    @classmethod
    def run(cls):
        args = cls.get_args()
        entries = SubEntry.get_entries(sys.stdin)
        start_entries = itertools.islice(entries, args.start_entry)
        if args.end_entry:
            # since start_entries may already have been consumed, adjust the
            #  end to account for those items.
            args.end_entry = args.end_entry - args.start_entry
        adjust_entries = itertools.islice(entries, args.end_entry)
        adjust_entries = (entry + args.delta for entry in adjust_entries)
        rest = entries

        adjusted_entries = itertools.chain(start_entries, adjust_entries, rest)

        SubEntry.write_entries(sys.stdout, adjusted_entries)


import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager

app = Flask(__name__, template_folder="template", static_folder="static")
app.config["SECRET_KEY"] = "otakuanime"
basedir = os.path.abspath(os.path.dirname(__file__))
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + \
    os.path.join(basedir, "db.sqlite")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

db = SQLAlchemy(app)
Migrate(app, db)

@app.before_first_request
def create_table():
    from Project.model import User
    return db.create_all()

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"


import os
import modal

LOCAL = False

if LOCAL == False:
    stub = modal.Stub("wine_daily")
    image = modal.Image.debian_slim().pip_install(["hopsworks", "scipy"])

    @stub.function(
        image=image,
        schedule=modal.Period(days=1),
        secret=modal.Secret.from_name("wine"),
    )
    def f():
        g()

def calculate_probabilities(dataframe):
    """
    for every column, we calculate the pdf (probability distribution function)
    so that when generating a random wine, we can use these pdfs to randomly select
    the values of each column
    """
    import scipy

    print("calculating probabilities")

    mu = dataframe["alcohol"].mean()
    sig = dataframe["alcohol"].std()
    dataframe["p_alcohol"] = dataframe["alcohol"].apply(
        lambda x: abs(scipy.stats.norm(mu, sig).pdf(x))
        if x > mu
        else abs(1 - scipy.stats.norm(mu, sig).pdf(x))
    )

    mu = dataframe["chlorides"].mean()
    sig = dataframe["chlorides"].std()
    dataframe["p_chlorides"] = dataframe["chlorides"].apply(
        lambda x: abs(scipy.stats.norm(mu, sig).pdf(x))
        if x > mu
        else abs(1 - scipy.stats.norm(mu, sig).pdf(x))
    )

    mu = dataframe["volatile_acidity"].mean()
    sig = dataframe["volatile_acidity"].std()
    dataframe["p_volatile_acidity"] = dataframe["volatile_acidity"].apply(
        lambda x: abs(scipy.stats.norm(mu, sig).pdf(x))
        if x > mu
        else abs(1 - scipy.stats.norm(mu, sig).pdf(x))
    )

    mu = dataframe["density"].mean()
    sig = dataframe["density"].std()
    dataframe["p_density"] = dataframe["density"].apply(
        lambda x: abs(scipy.stats.norm(mu, sig).pdf(x))
        if x > mu
        else abs(1 - scipy.stats.norm(mu, sig).pdf(x))
    )

    return dataframe

def get_random_wine(dataframe):
    """
    Returns a DataFrame containing one random wine
    """
    import pandas as pd
    import random

    print("getting a random wine")

    random_quality = random.randint(4, 8)
    random_quality_str = str(random_quality)
    filtered = dataframe.query("quality==" + random_quality_str).reset_index(drop=True)

    wine_df = pd.DataFrame(
        {
            "alcohol": random.choices(
                filtered["alcohol"], weights=filtered["p_alcohol"]
            ),
            "chlorides": random.choices(
                filtered["chlorides"], weights=filtered["p_chlorides"]
            ),
            "volatile_acidity": random.choices(
                filtered["volatile_acidity"], weights=filtered["p_volatile_acidity"]
            ),
            "density": random.choices(
                filtered["density"], weights=filtered["p_density"]
            ),
        }
    )
    wine_df["quality"] = random_quality
    print(
        "generated random wine with quality:",
        random_quality,
        " and alcohol:",
        wine_df["alcohol"],
        "and chlorides:",
        wine_df["chlorides"],
        "and volatile_acidity:",
        wine_df["volatile_acidity"],
        "and density:",
        wine_df["density"],
    )
    return wine_df

def g():
    import hopsworks
    import pandas as pd

    project = hopsworks.login()
    fs = project.get_feature_store()

    wine_fg = fs.get_feature_group(name="wine", version=1)
    wine_df = pd.DataFrame(wine_fg.read())

    wine_df = calculate_probabilities(wine_df)

    wine_entry_df = get_random_wine(wine_df)
    print("inserted wine_entry has quality: ", wine_entry_df.quality)

    wine_fg.insert(wine_entry_df)

if __name__ == "__main__":
    if LOCAL == True:
        g()
    else:
        stub.deploy("wine_daily")
        with stub.run():
            f()


import streamlit as st
from PIL import Image
import cv2
import pytesseract
import pandas as pd
from pymongo import MongoClient
import boto3

client=MongoClient('localhost',27017)
db=client['HugsforBugs']
c=db['alpr']

def image(img): # to read image in pixel format
    return Image.open(img)

def readText():
    results=[]
    imageSource=open('test.jpg','rb')
    client=boto3.client('textract')
    response=client.detect_document_text(Document={'Bytes':imageSource.read()})
    for item in response['Blocks']:
        if item['BlockType']=='LINE':
            lp=item['Text']
            results.append(lp)
    try:
        lens=[]
        print(results)
        for i in results:
            lens.append(len(i))
        return (results[lens.index(max(lens))])
    except:
        return None

def app():
    st.header('ALPR Training')
    img_file=st.file_uploader('Upload Image', type=['png','jpg','jpeg'])

    if img_file is not None: # when someone uploads a file
        file_details={} # to store the details of file
        file_details['type']=img_file.type
        file_details['size']=img_file.size
        file_details['name']=img_file.name
        st.write(file_details)
        st.image(image(img_file)) # show image on web app

        with open('test.jpg','wb') as f: # save the image
            f.write(img_file.getbuffer())

        vehicleno=readText()
        st.success(vehicleno)
        ownername=st.text_input('Enter Owner Name')
        address=st.text_input('Enter Address')
        mobileno=st.text_input('Enter MobileNo')
        if st.button('Register Vehicle'):
            k={}
            k['vehicleno']=vehicleno
            k['ownername']=ownername
            k['address']=address
            k['mobileno']=mobileno
            c.insert_one(k)
            st.success('Vehicle Data Registerd')


# -*- coding: utf-8 -*-
'''
    Defines the directive lineref-code-block and role lref.

    lineref-code-block allows defining labels enclosed in :: for lines
    of the code block. Labels can include alphanumeric characters,
    underscore (_), and hyphen (-). Usage as with Sphinx directive code-block:

    .. lineref-code-block:: python
        :linenos:

        def example():
          :label-name:var = something
          return var

    The role lref makes it possible to link to labels defined in
    lineref-code-block blocks:

    :lref:`optional link text <label-name>`
'''
import re

from docutils import nodes

from sphinx.directives.code import CodeBlock
from sphinx.util import logging
from sphinx.locale import __

logger = logging.getLogger(__name__)

class codeblock_lineref(nodes.General, nodes.Element):
    pass

def visit_codeblock_lineref_node(self, node):
    # Pretty much copied from the codeblock visitor
    # except for the addition of line anchors.
    lineanchors = node['lineanchor_id']
    node = node[0]
    lang = node.get('language', 'default')
    linenos = node.get('linenos', False)
    highlight_args = node.get('highlight_args', {})
    highlight_args['force'] = node.get('force', False)
    opts = self.config.highlight_options.get(lang, {})

    if linenos and self.config.html_codeblock_linenos_style:
        linenos = self.config.html_codeblock_linenos_style

    highlighted = self.highlighter.highlight_block(
        node.rawsource, lang, opts=opts, linenos=linenos, lineanchors=lineanchors,
        location=node, **highlight_args
    )
    starttag = self.starttag(node, 'div', suffix='',
                             CLASS='highlight-%s notranslate' % lang)
    self.body.append(starttag + highlighted + '</div>\n')
    raise nodes.SkipNode

def depart_codeblock_lineref_node(self, node):
    pass

def process_line(block, line, labelpattern, anchor):
    env = block.state.document.settings.env
    parts = re.split(r'(:[\w-]+:)', line)
    newline = []
    for string in parts:
        if labelpattern.match(string):
            label = string.strip(':')
            if label in env.code_line_labels:
                logger.warning(
                    __('Line reference labels should be unique: ' +
                          'label "{}" has already been defined'.format(label)),
                    location=block.state_machine.get_source_and_line(
                        block.lineno)
                    )
                continue
            # Save the label and row numebr to env so that they are
            # available later in visit_codeblock_lineref_node
            env.code_line_labels[label] = anchor
        elif string:
            # The processed line will include everything but the labels
            newline.append(string)
    return ('').join(newline)

class LineRefCodeBlock(CodeBlock):
    '''
    Directive for code blocks that can include line labels that
    can be referenced to with the lref-role.
    '''

    def run(self):
        newlines = []
        env = self.state.document.settings.env
        # Random id for the code block is used in the line anchors
        randomid = str(env.new_serialno('lineref_codeblock'))
        labelpattern = re.compile(r':[\w-]+:')
        if not hasattr(env, 'code_line_labels'):
            env.code_line_labels = {}
        linecount = 0
        for line in self.content:
            linecount += 1
            anchor = randomid + '-' + str(linecount)
            newline = process_line(self, line, labelpattern, anchor)
            newlines.append(newline)
        self.content = newlines
        originals = CodeBlock.run(self)
        node = codeblock_lineref()
        node.extend(originals)
        node['lineanchor_id'] = randomid
        return [node]

def lineref_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
    """
    Link to a line label in lineref-codeblock.

    Reference a label defined in a lineref-code-block.
    """

    env = inliner.document.settings.env
    location = (env.docname, lineno)

    linktext = text.partition('<')[0].strip()
    labelmatch = re.search(r'<([\w-]+)>', text)
    label = ''
    if not labelmatch:
        logger.warning(
            __('Missing label: the role lref requires a label and optional link text ' +
                  'in the form :lref:`link text <label>`'),
            location=location
        )
        return [], []

    label = labelmatch.group(1)

    if not label in env.code_line_labels:
        logger.warning(
            __('Unknown label "{}"'.format(label)),
            location=location
        )
        return [nodes.reference(rawtext, label, refuri='', **options)],[]

    anchor = env.code_line_labels[label]
    lineno = anchor.split('-')[1]
    parens = False
    if not linktext:
        # Default link text is (line X)
        linktext = 'line ' + lineno
        parens = True
    linknode = nodes.reference(rawtext, str(linktext), refuri='#'+anchor,
                                **options)
    linknode['classes'].append('codeblock-lineref')

    if parens:
        return [nodes.Text('('), linknode, nodes.Text(')')], []
    else:
         return [linknode], []

def _reset_env_code_line_labels(app):
    env = app.builder.env
    if hasattr(env, 'code_line_labels'):
        del env.code_line_labels

def setup(app):
    app.add_directive('lineref-code-block', LineRefCodeBlock)
    app.add_node(codeblock_lineref,
                 html=(visit_codeblock_lineref_node, depart_codeblock_lineref_node),
                 latex=(visit_codeblock_lineref_node, depart_codeblock_lineref_node),
                 text=(visit_codeblock_lineref_node, depart_codeblock_lineref_node))
    app.add_role('lref', lineref_role)

    app.connect("builder-inited", _reset_env_code_line_labels)


from sqlalchemy import delete, insert, select, update
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from ..database import Like, Media, Tweet, User
from ..exeptions import BackendExeption
from ..services_overal import get_user_by_api_key

async def get_tweet(session: AsyncSession, tweet_id: int):
    q = await session.execute(
        select(Tweet)
        .options(selectinload(Tweet.author))
        .options(selectinload(Tweet.likes).options(selectinload(Like.user)))
        .options(selectinload(Tweet.media))
        .where(Tweet.id == tweet_id)
    )
    tweet = q.scalars().one_or_none()
    if not tweet:
        raise BackendExeption(
            error_type="NO TWEET", error_message="No tweet with such id"
        )
    return tweet

async def get_tweets(session: AsyncSession, api_key: str):
    await get_user_by_api_key(session=session, api_key=api_key)

    q = await session.execute(
        select(Tweet)
        .options(selectinload(Tweet.author))
        .options(selectinload(Tweet.likes).options(selectinload(Like.user)))
        .options(selectinload(Tweet.media))
        .where(Tweet.author.has(User.api_key == api_key))
    )

    tweets = q.scalars().all()

    return {"result": True, "tweets": tweets}

async def post_tweet(
    session: AsyncSession, api_key: str, tweet_data: str
) -> int:
    user = await get_user_by_api_key(session=session, api_key=api_key)

    insert_tweet_query = await session.execute(
        insert(Tweet).values(
            content=tweet_data,
            user_id=user.id,
        )
    )
    new_tweet_id = insert_tweet_query.inserted_primary_key[0]
    await session.commit()

    return new_tweet_id

async def insert_media_to_tweet(
    session: AsyncSession, tweet_id: int, tweet_medias: list
):
    for media_id in tweet_medias:
        await session.execute(
            update(Media).where(Media.id == media_id).values(tweet_id=tweet_id)
        )
        await session.commit()

async def delete_tweet(session: AsyncSession, api_key: str, tweet_id: int):
    user = await get_user_by_api_key(session=session, api_key=api_key)
    await get_tweet(session=session, tweet_id=tweet_id)

    q1 = await session.execute(
        select(Tweet.user_id).where(Tweet.id == tweet_id)
    )
    author_id = q1.scalars().one_or_none()
    if author_id != user.id:
        raise BackendExeption(
            error_type="NO ACCSESS",
            error_message="Tweet belongs to other user",
        )

    await session.execute(
        delete(Tweet).where(Tweet.id == tweet_id, Tweet.user_id == user.id)
    )
    await session.commit()

async def post_like_to_tweet(
    session: AsyncSession, api_key: str, tweet_id: int
):
    user = await get_user_by_api_key(session=session, api_key=api_key)
    await get_tweet(session=session, tweet_id=tweet_id)

    try:
        insert_like_query = await session.execute(
            insert(Like).values(
                tweet_id=tweet_id,
                user_id=user.id,
            )
        )
        new_like_id = insert_like_query.inserted_primary_key[0]
        await session.commit()
    except IntegrityError:
        raise BackendExeption(
            error_type="BAD LIKE", error_message="Such like already exists"
        )

    return new_like_id

async def delete_like_to_tweet(
    session: AsyncSession, api_key: str, tweet_id: int
):
    user = await get_user_by_api_key(session=session, api_key=api_key)
    tweet = await get_tweet(session=session, tweet_id=tweet_id)
    q = await session.execute(
        select(Like)
        .where(Like.user_id == user.id)
        .where(Like.tweet_id == tweet.id)
    )
    like = q.scalars().one_or_none()
    if not like:
        raise BackendExeption(
            error_type="BAD LIKE DELETE",
            error_message="No like for tweet from user",
        )

    await session.execute(
        delete(Like).where(Like.tweet_id == tweet_id, Like.user_id == user.id)
    )
    await session.commit()


from robotic_arm.config import LOGGING_LEVEL

def init_logger():
    import logging

    logger = logging.getLogger()
    logger.setLevel(level=LOGGING_LEVEL)

    # BEGIN Disable some logs from 3-rd party libraries
    com_logger = logging.getLogger("comtypes")
    com_logger.setLevel(logging.WARNING)
    websockets_logger = logging.getLogger("websockets")
    websockets_logger.setLevel(logging.WARNING)
    matplotlib_logger = logging.getLogger("matplotlib")
    matplotlib_logger.setLevel(logging.WARNING)
    # END Disable some logs from 3-rd party libraries

    file_handler = logging.FileHandler("robotic-arm.log")
    file_handler.setLevel(LOGGING_LEVEL)
    console_handler = logging.StreamHandler()
    console_handler.setLevel(LOGGING_LEVEL)
    file_handler.setFormatter(logging.Formatter('%(asctime)s [%(name)s]@%(threadName)s|%(levelname)s: %(message)s'))
    console_handler.setFormatter(logging.Formatter('%(asctime)s [%(name)s]@%(threadName)s|%(levelname)s: %(message)s'))
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)


"""
solution of adv_2021_18
"""
import json
import math
import itertools

def _to_hashable(in_data):
    if isinstance(in_data, int):
        res = in_data
    else:
        assert len(in_data) == 2
        res = tuple(_to_hashable(_) for _ in in_data)
    return res

def parse_input(in_str):
    """
    parses the string input into a list of expressions/Snailfish numbers
    """

    def proc_single_line(in_line):
        res = json.loads(in_line)
        res = _to_hashable(res)
        return res

    return [proc_single_line(_) for _ in in_str.splitlines()]

def get_node(in_data, in_path):
    """
    returns the node in in_data described by in_path
    """
    assert isinstance(in_path, tuple)
    if not in_path:
        res = in_data
    else:
        res = get_node(in_data[in_path[0]], in_path[1:])
    return res

def find_path_do_expl_pair(in_data):
    """
    returns the path to the first exploding pair (if any)
    """

    def is_atom(in_node):
        return (
            isinstance(in_node, tuple)
            and isinstance(in_node[0], int)
            and isinstance(in_node[1], int)
        )

    def inner(in_path):
        cur_node = get_node(in_data, in_path)
        if is_atom(cur_node):
            res = in_path if len(in_path) >= 4 else None
        elif isinstance(cur_node, int):
            res = None
        else:
            res = inner(in_path + (0,))
            if res is None:
                res = inner(in_path + (1,))
        return res

    return inner(tuple())

def _extend_path(in_data, in_start_path, in_dir):
    assert in_dir in {0, 1}
    res = in_start_path
    while not isinstance(get_node(in_data, res), int):
        res += (in_dir,)
    return res

def find_last(in_data, in_value):
    """
    returns the index of last occurence of in_value in in_data
    """
    assert in_value in in_data
    res = len(in_data) - 1
    while in_data[res] != in_value:
        res -= 1
    assert in_data[res] == in_value
    return res

def _find_first_path(in_data, in_path_to_expl, in_dir_a, in_dir_b):
    res = None
    if in_dir_a in in_path_to_expl:
        last_ind = find_last(in_path_to_expl, in_dir_a)
        res = in_path_to_expl[0:last_ind] + (in_dir_b,)
        res = _extend_path(in_data, res, in_dir_a)
    return res

def find_path_to_first_left(in_data, in_path_to_expl):
    """
    returns the path to the first number on the left from the given path
    """
    res = _find_first_path(in_data, in_path_to_expl, 1, 0)
    assert res is None or res < in_path_to_expl
    return res

def find_path_to_first_right(in_data, in_path_to_expl):
    """
    returns the path to the first number on the right from the given path
    """
    res = _find_first_path(in_data, in_path_to_expl, 0, 1)
    assert res is None or in_path_to_expl < res
    return res

def find_path_to_split(in_data):
    """
    returns the path to the first number to split
    """

    def inner(in_path):
        cur_node = get_node(in_data, in_path)
        if isinstance(cur_node, int):
            res = in_path if cur_node >= 10 else None
        else:
            res = inner(in_path + (0,))
            if res is None:
                res = inner(in_path + (1,))
        return res

    return inner(tuple())

def get_updated(in_data, in_update_dict):
    """
    Returns the data after changed described in in_update_dict.
    keys in in_update_dict ar paths to the numbers.
    values in in_update_dict are the new values of these numbers
    """

    def inner(in_path):
        if in_path in in_update_dict:
            res = in_update_dict[in_path]
        else:
            cur_node = get_node(in_data, in_path)
            if isinstance(cur_node, int):
                res = cur_node
            else:
                res = (inner(in_path + (0,)), inner(in_path + (1,)))
        return res

    return inner(tuple())

def explode(in_data):
    """returns in_data after single explode"""
    path_to_explode = find_path_do_expl_pair(in_data)
    first_left_path = find_path_to_first_left(in_data, path_to_explode)
    first_right_path = find_path_to_first_right(in_data, path_to_explode)
    exploding_node = get_node(in_data, path_to_explode)
    update_dict = {path_to_explode: 0}
    if first_left_path is not None:
        update_dict[first_left_path] = (
            get_node(in_data, first_left_path) + exploding_node[0]
        )
    if first_right_path is not None:
        update_dict[first_right_path] = (
            get_node(in_data, first_right_path) + exploding_node[1]
        )
    assert len(update_dict) >= 2
    return get_updated(in_data, update_dict)

def make_split(in_data):
    """returns in_data after single split"""
    path_to_split = find_path_to_split(in_data)
    res = in_data
    if path_to_split is not None:
        splited_value = get_node(in_data, path_to_split)
        assert splited_value >= 10
        update_dict = {
            path_to_split: (splited_value // 2, math.ceil(splited_value / 2))
        }
        res = get_updated(in_data, update_dict)
    return res

def simplify(in_data):
    """performs a full reduction of in_data"""

    def single_simplify(in_data):
        tmp_val = in_data
        if find_path_do_expl_pair(in_data) is not None:
            tmp_val = explode(in_data)
        elif find_path_to_split(in_data) is not None:
            tmp_val = make_split(in_data)
        return tmp_val, in_data != tmp_val

    tmp_res, has_changed = single_simplify(in_data)
    while has_changed:
        tmp_res, has_changed = single_simplify(tmp_res)
    return tmp_res

def add_values(in_val_a, in_val_b):
    """returns the simplified result of adding two Snailfish numbers"""
    return simplify((in_val_a, in_val_b))

def add_all(in_value_list):
    """returns the sum of all Snailfish numbers in in_value_list"""
    sum_value = in_value_list[0]
    for _ in in_value_list[1:]:
        sum_value = add_values(sum_value, _)
    return sum_value

def magnitude(in_data):
    """returns the magnitude of in_data"""

    def proc_single(in_x):
        if isinstance(in_x, int):
            res = in_x
        else:
            res = magnitude(in_x)
        return res

    return 3 * proc_single(in_data[0]) + 2 * proc_single(in_data[1])

def solve_a(in_str):
    """solution function for part a"""
    return magnitude(add_all(parse_input(in_str)))

def solve_b(in_str):
    """solution function for part b"""
    return max(
        max(magnitude(add_values(a, b)), magnitude(add_values(b, a)))
        for (a, b) in itertools.combinations(parse_input(in_str), 2)
    )


import sys
import csv
import numpy as np
from fractions import Fraction
def SpamCheck(emailInput,dataset):
    Number_of_spam_emails=1500
    Number_of_real_emails=3672
    fraction_of_spam_emails=1500/5712
    fraction_of_real_emails=3672/5712
    spamProbabilities=[]
    hamProbabilities=[]
    my_file = open(emailInput, "r")
    content = my_file.read()
    content_list1 = content.rstrip("\n")

    content_list = content_list1.split(" ")

#    print(content_list)
    num=0
    with open(dataset) as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        line_count = 0
        for row in csv_reader:
            if num>=1:

                if(row[len(row)-1] in content_list):
                    spamProbabilities.append(float(Fraction(row[0])))
                    hamProbabilities.append(float(Fraction(row[1])))
#                    print(row[len(row)-1] +"in")
                if(row[len(row)-1] not in content_list):
                    spamProbabilities.append(1-float(Fraction(row[0])))
                    hamProbabilities.append(1-float(Fraction(row[1])))
#                    print(row[len(row)-1]+"not in")

            num=num+1

#        print(spamProbabilities)
#        print(hamProbabilities)
        probabilitySpam=np.prod(spamProbabilities)
        probabilityHam=np.prod(hamProbabilities)
        Calculation=(fraction_of_spam_emails*probabilitySpam)/((fraction_of_spam_emails*probabilitySpam)+(fraction_of_real_emails*probabilityHam))
        if(Calculation<0.5):
            print("The probability that the email is spam is "+str(Calculation)+"thus it is highly likely that is is a legitimate email")
        else:
            print("The probability that the email is spam is "+str(Calculation)+" thus it is highly likely that is is a spam email")

    return None

EmailInput=sys.argv[1]
Dataset=sys.argv[2]
#print(EmailInput)
#print(Dataset)
SpamCheck(EmailInput,Dataset)


##
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style

style.use('fivethirtyeight')

filename = 'Test4.csv'

data = pd.read_csv(filename, index_col=0)

df = data.head(5)

df = df.set_index(["HOUR"])

sd = df.reindex(columns=['DIFF','DIFF1'])

db = sd.diff(axis=1)

db.plot(kind = 'bar')

plt.show()

print(sd)


import os
from configparser import RawConfigParser

from yaml import CLoader, load_all

from app.repository import RepositoryConfiguration

class ScannerConfiguration:
    """
    This class contains all the relevant scanning logic for looking
    through and parsing repositories.
    """

    def __init__(self, scanner_config: RawConfigParser):
        self.repositories = []
        self.scanner_config = scanner_config

        for section in self.scanner_config:
            if self.scanner_config[section].name == 'DEFAULT':
                # Ignore default section always
                continue
            self.__append_repositories(section)

    def __append_repositories(self, section):
        section_name = self.scanner_config[section].name
        section_under_append = self.scanner_config[section]
        try:
            git_url = section_under_append['git_url']
            csv_files = section_under_append['scan_files'].split(',')
            binding_urls = section_under_append['remote_urls'].split(',')
            prefer_url = section_under_append['ignore_git_if_url_found']
            self.repositories.append(RepositoryConfiguration(section_name, git_url, csv_files, binding_urls, prefer_url))
        except KeyError:
            print("Invalid section provided, ignoring")

def find_all(name, path) -> list:
    """
    This method returns a list of the fully qualified path
    of all files that match the path provided by the given name.
    :param name: name of the file to query for
    :param path: the path to use for file querying
    :return: the list of files found from the search by name
    """
    result = []
    for root, dirs, files in os.walk(path):
        if name in files:
            result.append(os.path.join(root, name))
    return result

def search_files(target_repository: RepositoryConfiguration) -> list:
    """
    Walk through configured repository and retrieve a list of files
    that meet the configured filter
    :param target_repository: repository object containing config data
    :return: list of files found within repository
    """
    retrieved_files = []

    for search_file in target_repository.files:
        for retrieved_file in find_all(search_file, target_repository.name):
            if retrieved_file not in retrieved_files:
                retrieved_files.append(retrieved_file)
    return retrieved_files

def parse_yaml(path):
    # TODO - update this to higher quality
    with open(path, 'r') as file:
        try:
            # Convert generator to list
            return list(load_all(file, CLoader))
        except Exception as e:
            print(f"Something went wrong parsing {path}::ERROR::{e}")

def parse_stream_bindings(parsed_file):
    # TODO - merge binding functions together
    try:
        binding_dicts = parsed_file['spring']['cloud']['stream']['bindings']
        for binding_dict in list(binding_dicts.items()):
            return binding_dict
    except KeyError:
        # If we get a KeyError, this file doesn't have spring.cloud.stream.bindings, so we ignore it
        # TODO - need to refactor how this is processed by checking existence before retrieval
        pass

def parse_kafka_stream_bindings(parsed_file):
    # TODO - merge binding functions together
    try:
        binding_dicts = parsed_file['spring']['cloud']['stream']['kafka']['bindings']
        for binding_dict in list(binding_dicts.items()):
            return binding_dict
    except KeyError:
        # If we get a keyerror, this file doesn't have spring.cloud.stream.bindings, so we ignore it
        # TODO - need to refactor how this is processed by checking existence before retrieval
        pass

def get_bindings(parsed_files) -> (list, list):
    """
    Retrieve lists of supported bindings
    :param parsed_files: incoming files to parse for bindings
    :return: spring-cloud-stream bindings, kafka-stream bindings
    """
    cloud_stream_bindings = []
    kafka_stream_bindings = []

    if parsed_files is None:
        return [], []
    for parsed_file in parsed_files:
        cloud_stream_bindings.append(parse_stream_bindings(parsed_file))
        kafka_stream_bindings.append(parse_kafka_stream_bindings(parsed_file))

    return cloud_stream_bindings, kafka_stream_bindings


from aiogram import types
from aiogram.dispatcher.filters.builtin import CommandStart
from keyboards.default.default_btn import menu_btn
from aiogram.types import InlineKeyboardButton,InlineKeyboardMarkup
from aiogram.types import CallbackQuery
from loader import dp, db
from data.data import data

@dp.message_handler(CommandStart())
async def bot_start(message: types.Message):

    user_id = int(message.from_user.id)
    all_user_id =[user[0] for user in db.select_all_users()]

    if user_id not in all_user_id:
        txt = "🇺🇿 Iltimos tilni tanlang!\n"
        txt += "🇺🇸 Please select a language!\n"
        txt += "🇷🇺 Пожалуйста, выберите язык!"
        # Inline Keyboard create
        btn_lang = InlineKeyboardMarkup(row_width=3)
        btn_lang.insert(InlineKeyboardButton(text="🇺🇿 Uz", callback_data="uz"))
        btn_lang.insert(InlineKeyboardButton(text="🇺🇸 Eng", callback_data="eng"))
        btn_lang.insert(InlineKeyboardButton(text="🇷🇺 Ru", callback_data="ru"))
        await message.answer(txt, reply_markup=btn_lang)
    else:
        lang = db.select_user(user_id=user_id)[2]
        index = data["lang"].index(lang)
        menu = data["menu"][index]
        await message.answer(menu, reply_markup=menu_btn(index))

@dp.callback_query_handler(lambda c: c.data in ["uz","eng","ru"])
async def process_callback_language(call: CallbackQuery):
    await call.answer()
    await call.message.delete()
    await call.answer(cache_time=60)

    lang = call.data
    index = data["lang"].index(lang)
    user_id = int(call.from_user.id)
    all_user_id = [user[0] for user in db.select_all_users()]

    if user_id not in all_user_id:
        # insert data to DB
        db.add_user(
                user_id=user_id,
                full_name=str(call.from_user.full_name),
                language=lang
            )
        til_tanlandi = data["til_tanlandi"][index]
        menu = data["menu"][index]

        await call.message.answer(til_tanlandi)
        await call.message.answer(menu, reply_markup=menu_btn(index))
    else:
        user_lang = db.select_all_users()[2]
        index = data["lang"].index(user_lang)
        allaqachon_til = data["allaqachon_til"][index]

        await call.message.answer(allaqachon_til)