from django.test import TestCase
from django.contrib.auth import get_user_model
from django.urls import reverse

from rest_framework import status
from rest_framework.test import APIClient

from core.models import *
from recipe.serializers import RecipeSerializer, RecipeDetailSerializer

RECIPE_URL = reverse('recipe:recipe-list')

# /api/recipe/recipes
# /api/recipe/recipes/1/

def detail_url(recipe_id):
    """return recipe detail url"""
    return reverse('recipe:recipe-detail', args=[recipe_id])

def sample_tag(user, name='Main Course'):
    """Create and return sample tag"""
    return Tag.objects.create(user=user, name=name)

def sample_ingredient(user, name='Cinnamon'):
    """Create and return sample ingredient"""
    return Ingredient.objects.create(user=user, name=name)

def sample_recipe(user,**params):
    """Create and return sample recipe"""

    test_recipe = {
        'title': 'Mushroom Chicken',
        'time_minutes': 10,
        'price': 5.00
    }
    # update will create/update keys in dictionary
    test_recipe.update(params)

    return Recipe.objects.create(user=user, **test_recipe)

class PublicRecipeTests(TestCase):
    """Test publicly avaialble tags API"""
    def setup(self):
        self.client = APIClient()

    def test_auth_required(self):
        res = self.client.get(RECIPE_URL)
        self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED)

class PrivateTagsTests(TestCase):
    """Test the unauthenticated recipe API"""
    def setUp(self):
        self.user = get_user_model().objects.create_user(
            'test12@test.com',
            'testpass',
        )
        self.client = APIClient()
        self.client.force_authenticate(self.user)

    def test_retrieve_recipe(self):
        """Test retrieving a list of recipes"""
        sample_recipe(user=self.user)
        sample_recipe(user=self.user)

        res = self.client.get(RECIPE_URL)

        recipes = Recipe.objects.all().order_by('-id')
        serializer = RecipeSerializer(recipes, many=True)

        self.assertEqual(res.status_code, status.HTTP_200_OK)
        self.assertEqual(res.data, serializer.data)

    def test_recipes_limited(self):
        """Test that recipes are retrieved for user"""

        user2 = get_user_model().objects.create_user(
            'new@test.com',
            'testpass'
        )
        sample_recipe(user=user2)
        sample_recipe(user=self.user)

        res = self.client.get(RECIPE_URL)

        recipes = Recipe.objects.filter(user=self.user)
        serializer = RecipeSerializer(recipes, many=True)

        self.assertEqual(res.status_code, status.HTTP_200_OK)
        self.assertEqual(len(res.data), 1)
        self.assertEqual(res.data, serializer.data)

    def test_view_recipe_detail(self):
        """TEst viewing recipe detail"""
        recipe=sample_recipe(user=self.user)
        recipe.tags.add(sample_tag(user=self.user))
        recipe.ingredients.add(sample_ingredient(user=self.user))

        url = detail_url(recipe.id)
        res = self.client.get(url)

        serializer = RecipeDetailSerializer(recipe)

        self.assertEqual(res.data, serializer.data)

    def test_create_recipe(self):
        """Test creating recipe"""
        new_recipe = {
            'title': 'Cake',
            'time_minutes': 30,
            'price': 15.00
        }

        res = self.client.post(RECIPE_URL, new_recipe)
        self.assertEqual(res.status_code, status.HTTP_201_CREATED)

        recipe = Recipe.objects.get(id=res.data['id'])

        for key in new_recipe.keys():
            self.assertEqual(new_recipe[key], getattr(recipe, key))

    def test_create_recipe_with_tags(self):
        """Creating recipe with tags"""
        tag1 = sample_tag(user=self.user, name='Vegan')
        tag2 = sample_tag(user=self.user, name='Dessert')

        new_recipe = {
            'title': 'CheeseCake',
            'tags': [tag1.id, tag2.id],
            'time_minutes': 30,
            'price': 15.00
        }
        res = self.client.post(RECIPE_URL, new_recipe)
        self.assertEqual(res.status_code, status.HTTP_201_CREATED)

        recipe = Recipe.objects.get(id=res.data['id'])
        tags = recipe.tags.all()

        self.assertEqual(tags.count(), 2)
        self.assertIn(tag1, tags)
        self.assertIn(tag2, tags)

    def test_create_recipe_with_ingredients(self):
        """Creating recipe with ingredients"""
        ingredient1 = sample_ingredient(user=self.user, name='Shrimp')
        ingredient2 = sample_ingredient(user=self.user, name='Ginger')

        new_recipe = {
            'title': 'Prawn curry',
            'ingredients': [ingredient1.id, ingredient2.id],
            'time_minutes': 25,
            'price': 20.00
        }
        res = self.client.post(RECIPE_URL, new_recipe)

        self.assertEqual(res.status_code, status.HTTP_201_CREATED)
        recipe = Recipe.objects.get(id=res.data['id'])
        ingredients = recipe.ingredients.all()

        self.assertEqual(ingredients.count(), 2)
        self.assertIn(ingredient1, ingredients)
        self.assertIn(ingredient2, ingredients)

    def test_partial_update_recipe(self):
        """test updating recipe with patch"""
        recipe = sample_recipe(user=self.user)
        recipe.tags.add(sample_tag(user=self.user))
        new_tag = sample_tag(user=self.user, name='Curry')

        payload = {'title': 'Chicken tikka', 'tags': [new_tag.id]}
        url = detail_url(recipe.id)
        self.client.patch(url,payload)

        recipe.refresh_from_db()
        self.assertEqual(recipe.title, payload['title'])
        tags = recipe.tags.all()
        self.assertEqual(len(tags), 1)
        self.assertIn(new_tag, tags)

    def test_full_update_reciple(self):
        """Test updating a recipe with put"""
        recipe = sample_recipe(user=self.user)
        recipe.tags.add(sample_tag(user=self.user))
        payload = {
        'title': 'Spaghetti',
        'time_minutes': 15,
        'price': 10.00
        }
        url = detail_url(recipe.id)
        self.client.put(url,payload)

        recipe.refresh_from_db()
        self.assertEqual(recipe.title, payload['title'])
        self.assertEqual(recipe.time_minutes, payload['time_minutes'])
        self.assertEqual(recipe.price, payload['price'])

        tags = recipe.tags.all()
        self.assertEqual(len(tags), 0)


from typing import Any, Dict, Iterable

import pandas as pd

from fugue import DataFrame, FugueWorkflow, PandasDataFrame, out_transform, transform
from fugue.constants import FUGUE_CONF_WORKFLOW_CHECKPOINT_PATH

def test_transform():
    pdf = pd.DataFrame([[1, 10], [0, 0], [1, 1], [0, 20]], columns=["a", "b"])

    def f1(df: pd.DataFrame) -> pd.DataFrame:
        return df.sort_values("b").head(1)

    result = transform(pdf, f1, schema="*")
    assert isinstance(result, pd.DataFrame)
    assert result.values.tolist() == [[0, 0]]

    # schema: *
    def f2(df: pd.DataFrame) -> pd.DataFrame:
        return df.sort_values("b").head(1)

    result = transform(pdf, f2)
    assert isinstance(result, pd.DataFrame)
    assert result.values.tolist() == [[0, 0]]

    result = transform(pdf, f2, partition=dict(by=["a"]))
    assert isinstance(result, pd.DataFrame)
    assert sorted(result.values.tolist(), key=lambda x: x[0]) == [[0, 0], [1, 1]]
    result = transform(
        pdf, f2, partition=dict(by=["a"]), force_output_fugue_dataframe=True
    )
    assert isinstance(result, DataFrame)

    ppdf = PandasDataFrame(pdf)
    assert isinstance(transform(ppdf, f2), DataFrame)

    # schema: *
    def f3(df: pd.DataFrame, called: callable) -> pd.DataFrame:
        called()
        return df

    cb = Callback()
    result = transform(pdf, f3, callback=cb.called)
    assert 1 == cb.ct

def test_transform_from_yield(tmpdir):
    # schema: *,x:int
    def f(df: pd.DataFrame) -> pd.DataFrame:
        return df.assign(x=1)

    dag = FugueWorkflow()
    dag.df([[0]], "a:int").yield_dataframe_as("x1")
    dag.df([[1]], "b:int").yield_dataframe_as("x2")
    dag.run("", {FUGUE_CONF_WORKFLOW_CHECKPOINT_PATH: str(tmpdir)})

    result = transform(dag.yields["x1"], f)
    assert isinstance(result, DataFrame)
    assert result.as_array(type_safe=True) == [[0, 1]]

    result = transform(
        dag.yields["x2"],
        f,
        engine_conf={FUGUE_CONF_WORKFLOW_CHECKPOINT_PATH: str(tmpdir)},
    )
    assert isinstance(result, DataFrame)
    assert result.as_array(type_safe=True) == [[1, 1]]

def test_out_transform(tmpdir):
    pdf = pd.DataFrame([[1, 10], [0, 0], [1, 1], [0, 20]], columns=["a", "b"])

    class T:
        def __init__(self):
            self.n = 0

        def f(self, df: Iterable[Dict[str, Any]]) -> None:
            self.n += 1

    t = T()
    out_transform(pdf, t.f)
    assert 1 == t.n

    t = T()
    out_transform(pdf, t.f, partition=dict(by=["a"]))
    assert 2 == t.n

    dag = FugueWorkflow()
    dag.df(pdf).yield_dataframe_as("x1")
    dag.df(pdf).yield_dataframe_as("x2")
    dag.run("", {FUGUE_CONF_WORKFLOW_CHECKPOINT_PATH: str(tmpdir)})

    t = T()
    out_transform(dag.yields["x1"], t.f)
    assert 1 == t.n

    t = T()
    out_transform(
        dag.yields["x2"],
        t.f,
        partition=dict(by=["a"]),
        engine_conf={FUGUE_CONF_WORKFLOW_CHECKPOINT_PATH: str(tmpdir)},
    )
    assert 2 == t.n

    # schema: *
    def f3(df: pd.DataFrame, called: callable) -> pd.DataFrame:
        called()
        return df

    cb = Callback()
    result = out_transform(pdf, f3, callback=cb.called)
    assert 1 == cb.ct

class Callback:
    def __init__(self):
        self.ct = 0

    def called(self) -> None:
        self.ct += 1


# Configuration file for the Sphinx documentation builder.
#
root_doc = 'index'
master_doc = 'index'

# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = ''
copyright = '2022, Aurelius Atlas Enterprise'
author = 'Americo'
release = '0.1'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
    'sphinx.ext.intersphinx',
    'sphinx.ext.autosectionlabel',
    #'myst_parser',
]

source_suffix = ['.rst', '.md']
templates_path = ['_templates']
exclude_patterns = []

intersphinx_mapping = {
    'sphinx': ('https://github.com/aureliusenterprise/helm-governance/blob/main/README.md', None),
}

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
#alabaster is the other theme
html_theme = "sphinx_rtd_theme"
html_static_path = ['_static']
html_logo = '_static/logo/logo1.png'
html_favicon = '_static/favicon/fav.png'

#
#html_style = 'theme1.css'

def setup(app):
    app.add_stylesheet('theme1.css')


import pycosat
from pprint import pprint

# number of cells in sudoku
NUM_CELLS = 81

# this can be used to interate all squares subset in 3x 3
#    V      V      V
#    1 2 3  4 5 6  7 8 9
#> 1 |0 0 0| 0 0 0| 0 0 0|
#  2 |0 0 0| 0 0 0| 0 0 0|
#  3 |0 0 0| 0 0 0| 0 0 0|
#    ---------------------
#> 4 |0 0 0| 0 0 0| 0 0 0|
#  5 |0 0 0| 0 0 0| 0 0 0|
#  6 |0 0 0| 0 0 0| 0 0 0|
#    --------------------
#> 7 |0 0 0| 0 0 0| 0 0 0|
#  8 |0 0 0| 0 0 0| 0 0 0|
#  9 |0 0 0| 0 0 0| 0 0 0|
SUBSQUARE_BOUDARIES = [1, 4, 7]

# most digit in sudoku
NUM_DIGITS = 9

def get_cell_value(row, column, digit):
   """
     make unique id to a cell

     first number is a row
     second is a column
     third is a digit value

     Ex: the cell (1,3) and (3,1) with digit 7 there are diferentes id
         cell (1,3) = 137
         cell (3,1) = 317
   """
   return row*100+column*10+ digit

def get_base_clauses():
    """
    make all NUM_VARIABLES used in sudoku board, named by id

    Ex:
        for cell (1,1) and digit 7 can be named: 117
        for cell (2,3) and digit 5 can be named: 235
    """
    base_clauses = []

    for row in range(1, NUM_DIGITS+1):
       for column in range(1, NUM_DIGITS+1):
          clauses = []
          for digit in range(1, NUM_DIGITS+1):
             clauses.append(get_cell_value(row,column,digit))
          base_clauses.append(clauses)

    return base_clauses

def get_unique_cells_clauses():
    """
    make clauses guarantee that a cell can just appear once for sudoku board.

    to make this each cell will have the next cell with the clause:
      ~current_digit or ~next_digit

    Example:
        to cell 111 there the clauses:
        (-111,-112),(-111,-113),(-111,-114),...,(-111,-999)
    """
    unique_digits_clauses = []

    for row in range(1, NUM_DIGITS+1):
        for column in range(1,NUM_DIGITS+1):
            for digit in range(1, NUM_DIGITS+1):
                for next_digit in range(digit+1, NUM_DIGITS+1):
                    cell_id = -get_cell_value(row,column,digit)
                    next_cell_id = -get_cell_value(row,column,next_digit)
                    unique_digits_clauses.append([cell_id,next_cell_id])

    return unique_digits_clauses

def get_unique_subset_clauses(board_subset):
    """
    this guarantee that a cell appear only once in the board subset
    """
    subset_clauses = []
    subset = enumerate(board_subset)

    for index, first_tuple in enumerate(board_subset):
        for n_index, n_tuple in enumerate(board_subset):
            if index < n_index:
                for digit in range(1, NUM_DIGITS + 1):
                    clause = [-get_cell_value(
                        first_tuple[0], first_tuple[1], digit),
                        -get_cell_value(
                        n_tuple[0], n_tuple[1], digit)]
                    subset_clauses.append(clause)
    return subset_clauses

def get_row_unique_clauses():
    """
    this guarantee that a cell in row appear only once in the row
    """
    unique_clauses = []

    for row in range(1,NUM_DIGITS +1):
        subset = []
        for column in range(1, NUM_DIGITS+1):
            subset.append((row,column))
        unique_clauses.extend(get_unique_subset_clauses(subset))
    return unique_clauses

def get_columns_unique_clauses():
    """
    this guarantee that a cell in column appear only once in the columns
    """
    unique_clauses = []
    for row in range(1,NUM_DIGITS +1):
        subset = []
        for column in range(1, NUM_DIGITS+1):
            subset.append((column,row))
        unique_clauses.extend(get_unique_subset_clauses(subset))
    return unique_clauses

def get_square_unique_clauses():
    """
    this guarantee that a cell in square appear only once in the squares
    """
    subset_clauses = []

    for row in SUBSQUARE_BOUDARIES:
        for column in SUBSQUARE_BOUDARIES:
            subset = [] # make subset 3x3
            for k in range(9):
                subset.append((row+k%3,column+k//3))
            subset_clauses.extend(get_unique_subset_clauses(subset))

    return subset_clauses

def get_sudoku_clauses():
    """
    mix all defined clauses to guarantee a valid sudoku
    """
    sudoku_clauses = []
    sudoku_clauses.extend(get_base_clauses())
    sudoku_clauses.extend(get_unique_cells_clauses())
    sudoku_clauses.extend(get_row_unique_clauses())
    sudoku_clauses.extend(get_columns_unique_clauses())
    sudoku_clauses.extend(get_square_unique_clauses())

    return sudoku_clauses

def get_single_clauses(sudoku_board):
    """
    This method make a clauses that can be answer true
    to solve the sudoku board
    """
    single_clauses = []
    for row in range(1, NUM_DIGITS+1):
        for column in range(1,NUM_DIGITS+1):
            cell_value = sudoku_board[row-1][column-1]
            if cell_value:
                single_clauses.append(
                    [get_cell_value(row,column,cell_value)])

    return single_clauses

def get_cell_solution(sudoku_solution, row, column):
    """
    verify a cell id in a sudoku solution list
    """
    for digit in range(1, NUM_DIGITS+1):
        if get_cell_value(row,column,digit) in sudoku_solution:
            return digit
    return -1

def solve_sudoku(sudoku_board):
    """
    Generate a sudoku clauses, apply in a pycosat and get sudoku solution
    """
    sudoku_clauses = get_sudoku_clauses()
    single_clauses = get_single_clauses(sudoku_board)
    sudoku_clauses.extend(single_clauses)

    sudoku_solution = set(pycosat.solve(sudoku_clauses))

    for row in range(1, NUM_DIGITS+1):
        for column in range(1, NUM_DIGITS+1):
            sudoku_board[row-1][column-1] = get_cell_solution(
                sudoku_solution, row, column)
    return sudoku_board

def main():
    print ("Sudoku problem:")
    sudoku_problem = [[0, 2, 0, 0, 0, 0, 0, 0, 0],
                      [0, 0, 0, 6, 0, 0, 0, 0, 3],
                      [0, 7, 4, 0, 8, 0, 0, 0, 0],
                      [0, 0, 0, 0, 0, 3, 0, 0, 2],
                      [0, 8, 0, 0, 4, 0, 0, 1, 0],
                      [6, 0, 0, 5, 0, 0, 0, 0, 0],
                      [0, 0, 0, 0, 1, 0, 7, 8, 0],
                      [5, 0, 0, 0, 0, 9, 0, 0, 0],
                      [0, 0, 0, 0, 0, 0, 0, 4, 0]]
    pprint(sudoku_problem)

    print('\nGenerating solution:')
    sudoku_solution = solve_sudoku(sudoku_problem)
    pprint(sudoku_solution)

if __name__ == '__main__':
    main()


# HOHMANN GUI
# A GUI version of HOHMANN BASIC.
# Basic program to calculate a Hohmann transfer between two coplanar, circular orbits.
# The altitudes of the two orbits are defined by user input.

# ---------------------------------------------------
# Imports
from orbit_toolbox import hohmann, Transfer
from bodies_toolbox import Planet
from guizero import App, Text, TextBox, PushButton

# ---------------------------------------------------
# Constants
Earth_radius = Planet["Earth"]["radius"]

# ---------------------------------------------------
# Functions
def hohmann_calc():
    Hoh_1 = Transfer(1, "hohmann", "09012022")
    hohmann_result = Hoh_1.hohmann("Earth", int(h_start_input.value)+Earth_radius, int(h_end_input.value)+Earth_radius)

    result_dv1.value = hohmann_result[0]
    result_dv2.value = hohmann_result[1]
    result_dv_total.value = hohmann_result[2]
    result_t_transfer.value = hohmann_result[3]

# ---------------------------------------------------
# App

# App and grid frameworks
app = App("Hohmann GUI", layout="grid")

# Input text and boxes
h_start_text = Text(app, text="Start altitude (km): ", grid=[0, 0])
h_start_input = TextBox(app, text="Insert start altitude (km) here", width="30", grid=[2, 0])
h_end_text = Text(app, text="End altitude (km): ", grid=[0, 1])
h_end_input = TextBox(app, text="Insert end altitude (km) here", width="30", grid=[2, 1])

# Calculation button
h_start_set = PushButton(app, command=hohmann_calc, text="Calculate transfer", grid=[1, 2])

# Output text and boxes
dv1_text = Text(app, text="dv1 (km.s^-1) =", grid=[0, 3])
result_dv1 = TextBox(app, text="dv1 =", width="30", grid=[2, 3])

dv2_text = Text(app, text="dv2 (km.s^-1) =", grid=[0, 4])
result_dv2 = TextBox(app, text="dv2 =", width="30", grid=[2, 4])

dv_total_text = Text(app, text="dv_total (km.s^-1) =", grid=[0, 5])
result_dv_total = TextBox(app, text="dv_total =", width="30", grid=[2, 5])

t_transfer_text = Text(app, text="t_transfer (s) =", grid=[0, 6])
result_t_transfer = TextBox(app, text="t_transfer =", width="30", grid=[2, 6])

app.display()


import time
from roman_integer import Roman

def check_for_higher_numerals(numeral):
  if "_I_V" in numeral:
    numeral = numeral.replace("_I_V", "MMMM")
  return numeral

if __name__ == "__main__":
  start = time.time()
  roman = Roman()
  numerals = [i.strip()
              for i in open("Data/p089_roman.txt").readlines()]
  old_count = 0
  new_count = 0
  for numeral in numerals:
    old_count += len(numeral)
    int_val = roman.convert_to_integer(numeral, disp=False)
    # print(numeral, int_val)
    proper_roman = roman.convert_to_numeral(int_val, disp=False)
    corrected_roman = check_for_higher_numerals(proper_roman)
    new_count += len(corrected_roman)
  print("Default form count:", old_count)
  print("Minimal form count:", new_count)
  print("Characters saved:", old_count - new_count)
  print("Calculated in:", time.time() - start)


import sys
import fileinput
import csv
import operator
import numpy as np
import scipy.spatial.distance as sd
import pickle

#python compare_google.py [google_match-norm] [avg-$count-norm] states.p statescores$count

google = []
matrix = []

infile = sys.argv[2]

google_reader = csv.reader(open(sys.argv[1], 'rb'), delimiter=',')
matrix_reader = csv.reader(open(infile, 'rb'), delimiter=',')
states = pickle.load(open(sys.argv[3], 'rb'))
results = open(sys.argv[4], 'wb')

weeks = 52

def compute_score(m, g):
    sum = 0
    for i in range(m.shape[1]):
        sum += sd.euclidean(m[:,i],g[:,i])

    score = sum/float(m.shape[1])

    return score

#store google data
for row in google_reader:
    row = [(float(x) if x else 0) for x in row]
    google.append(np.array(row))

google = np.array(google)

for row in matrix_reader:
    row = [(float(x) if x else 0) for x in row]
    matrix.append(np.array(row))

matrix = np.array(matrix)

scores = {}
for i in range(google.shape[1]):
    scores[str(i) + ' ' + states[i]] = sd.euclidean(matrix[:,i],google[:,i])

sorted_scores = sorted(scores.iteritems(), key=operator.itemgetter(1))

for name,score in sorted_scores:
    results.write(name+':'+str(score)+'\n')

results.close()


import numpy as np
import torch

with open("pdtSEIKA.csv", "r") as f:
    f_reader = np.loadtxt(f, delimiter=',', dtype=np.float32)
    predict = f_reader
    f.close()
tensor = torch.from_numpy(np.load(r"C:\Users\cchen\PycharmProjects\LearnPyTorch/K05_excluded_xyz.npy"))  # 101778,
# 15,10,10
with open("ai__K05_SEIKA2.csv", "w") as f:
    for item, result in zip(tensor, predict):
        pos = (item[0, 0, 0], item[5, 0, 0], item[10, 0, 0])
        row = "{},{},{},{},{},{},{},{}\n".format(*pos, *result)
        f.write(row)
    f.close()


from fastapi import FastAPI
from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware
from reconocer_form import analyze_general_documents
from base_datos import crear_registro
import asyncio
app = FastAPI()

origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials = True,
    allow_methods = ["*"],
    allow_headers = ["*"]
)

class Registro(BaseModel):
    url: str

@app.get("/")
def verRegistros():
    return "registros"

@app.post("/post")
async def crearRegistro(regitsro: Registro):

    repuesta = await analyze_general_documents(regitsro.url)
    registro_guardado = await crear_registro(regitsro.url,repuesta)
    if registro_guardado:
        return repuesta
    return "no se pudo guardar"

@app.put("/post")
def crearRegistro():
    return "hola"

@app.delete("/delete")
def crearRegistro():
    return "hola"


#! /usr/bin/env python3

import sys
import json
from flask import Flask, request

app = Flask(__name__)

def is_browser(ua_string):
    return ua_string.split('/')[0].lower() == 'mozilla'

@app.route("/")
def hello():
    msg_content = "Hello World!"
    if is_browser(request.headers['User-Agent']):
        return "
{}".format(msg_content)

    else:
        response = dict()
        response["msg"] = msg_content
        return json.dumps(response)

@app.route("/name", methods=["POST"])
def greeting():
    print(request.data, file=sys.stdout)
    req = json.loads(request.data)
    req["msg"] = "Hi, {}".format(req["name"])
    return json.dumps(req)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(sys.argv[1]))


from typing import List

from project.appliances.appliance import Appliance
from project.people.child import Child

class Room:

    def __init__(self, name: str, budget: float, members_count: int):
        self.family_name = name
        self.budget = budget
        self.members_count = members_count
        self.children: List[Child] = []
        self.expenses = 0

    @property
    def expenses(self):
        return self.__expenses

    @expenses.setter
    def expenses(self, value):
        if value < 0:
            raise ValueError("Expenses cannot be negative")

        self.__expenses = value

    def calculate_expenses(self, *args):
        total_expenses = 0

        for list_obj in args:
            for obj in list_obj:
                if isinstance(obj, Appliance):
                    total_expenses += obj.get_monthly_expense()
                else:
                    total_expenses += obj.cost * 30

        self.expenses = total_expenses

    def room_info(self):
        result_str = [
            f"{self.family_name} with {self.members_count} members."
            f" Budget: {self.budget:.2f}$, Expenses: {self.expenses:.2f}$"]

        for idx, child in enumerate(self.children):
            result_str.append(f"--- Child {idx + 1} monthly cost: {(child.cost * 30):.2f}$")

        if hasattr(self, 'appliances'):
            appliances_monthly_cost = sum([a.get_monthly_expense() for a in self.appliances])
            result_str.append(f"--- Appliances monthly cost: {appliances_monthly_cost:.2f}$")

        return '\n'.join(result_str)


import math
import numpy as np
from scipy.spatial import ConvexHull

class LOS_guidance():
    def __init__(self, params):
        self.ship_max_speed = params['ship_max_speed']
        self.ship_ax_vel_lim = params['ship_ax_vel_lim']
        self.ship_lat_acc_pos_lim = params['ship_lat_acc_pos_lim']
        self.ship_lat_acc_neg_lim = params['ship_lat_acc_neg_lim']
        self.ship_ax_acc_lim = params['ship_ax_acc_lim']
        self.T_max_thrust = params['T_max_thrust']
        self.T_min_thrust = params['T_min_thrust']

    def ship_los_guidance(self, ship_phys_status, target_pos, dt=1 / 60):

        ship_position = ship_phys_status['pose'][0]
        heading_in = ship_phys_status['pose'][1]
        ship_speed_in = np.linalg.norm(ship_phys_status['velocity'][0])
        ship_rot_spd_in = ship_phys_status['velocity'][1]

        def angle_between_vector_and_angle(vector, angle):
            # Calculate the angle between the vector and the x-axis
            vector_angle = math.atan2(vector[1], vector[0])

            # Calculate the difference between the vector angle and the given angle
            angle_diff = vector_angle - angle

            # Ensure that the angle difference is within the range (-pi, pi]
            while angle_diff > math.pi:
                angle_diff -= 2 * math.pi
            while angle_diff <= -math.pi:
                angle_diff += 2 * math.pi

            # Return the absolute value of the angle difference
            return angle_diff

        ship_heading = heading_in
        ship_rot_spd = ship_rot_spd_in
        ship_speed = 0

        distance_to_target = math.sqrt(
            (target_pos[0] - ship_position[0]) ** 2 + (target_pos[1] - ship_position[1]) ** 2)

        if not (distance_to_target >= -1 and distance_to_target <= 10000):
            angle_variance = 0

        target_angle = (target_pos - ship_position)

        angle_variance = angle_between_vector_and_angle(target_angle, ship_heading)

        rotational_mul = angle_variance

        if not (angle_variance >= -10 and angle_variance <= 10):
            angle_variance = 0

        if (angle_variance) > (math.pi / 4):
            rotational_mul = abs((math.pi / 2))
        elif (angle_variance) < -(math.pi / 2):
            rotational_mul = - abs((math.pi / 2))

        # rotational controller
        if abs(angle_variance) > 0.01 and abs(ship_rot_spd) <= abs(self.ship_ax_vel_lim):
            ship_rot_spd = -(rotational_mul / (math.pi / 2))*10
        else:
            ship_rot_spd = 0

            # translational controller
        if distance_to_target > 2:
            ship_speed = self.ship_max_speed
        elif distance_to_target >= 0.6:
            ship_speed = self.ship_max_speed/3
        elif distance_to_target >= 0.3:
            ship_speed = self.ship_max_speed/8
        else:
            ship_speed = 0
            ship_rot_spd = 0

        ship_vel = ship_speed*np.array([math.cos(heading_in), math.sin(heading_in)])

        cmd_vel = [ship_vel, ship_rot_spd]

        #print("\rangle_variance, ship_rot_spd", np.degrees(heading_in), ship_rot_spd, end="")
        #print("\rTLeft, TRight", rTLeft.TRight, end="")

        return cmd_vel

class LOS_VO_guidance():

    def __init__(self, params):

        self.ship_max_speed = params['ship_max_speed']
        self.ship_ax_vel_lim = params['ship_ax_vel_lim']
        self.ship_lat_acc_pos_lim = params['ship_lat_acc_pos_lim']
        self.ship_lat_acc_neg_lim = params['ship_lat_acc_neg_lim']
        self.ship_ax_acc_lim = params['ship_ax_acc_lim']
        self.T_max_thrust = params['T_max_thrust']
        self.T_min_thrust = params['T_min_thrust']
        self.detection_range = 10
        self.spd_visual_multiplier = 2.5

        self.los = LOS_guidance(params)
        self.vo_polygons = []

        #parameters

    def ship_los_vo_guidance(self, phys_status, output_polygon, target_pos, sensor_data, dt=1 / 60):
        #   First, this receives a database of ships in the world. the database is a dictionary
        #   if there are no obstacles in range, it pursues the target using Line-of-sight guidance law
        #   if there are VO cones in sight, it tries to evade the obstacle by maintaining speed and turning.
        #   it prefers angles closer to the target.
        #   if no trajectory is valid, it tries to decelerate to half the maximum speed
        #   if there is still no trajectory, it tries to stop.

        #setting up variables
        self.phys_status = phys_status  # updates phys status
        self.output_polygon = output_polygon
        self.sensor_data = sensor_data  # get sensor_data
        self.vo_lines = []
        self.vo_circles = []  # position and radius
        self.vo_cones = []
        self.vo_polygons = []
        ship_position = phys_status['pose'][0]
        heading_in = phys_status['pose'][1]
        ship_speed_in = np.linalg.norm(phys_status['velocity'][0])
        ship_rot_spd_in = phys_status['velocity'][1]
        ship_heading = heading_in
        ship_rot_spd = ship_rot_spd_in
        ship_speed = 0

        # recieving and processing the data
        self.filtered_objects_angle = self.sensor_simulator()  # process the data
        self.vo_cone_generator() #generates VO cone

        # target_information
        distance_to_target = math.sqrt((target_pos[0] - ship_position[0]) ** 2 + (target_pos[1] - ship_position[1]) ** 2)
        target_vector = (target_pos - ship_position)
        target_angle = self.regularize_angle(math.atan2(target_vector[1], target_vector[0]))

        # search for valid angle
        target_speed = 2.0
        self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
        angle_rad = math.radians(3*self.index_with_lowest_number(self.angle_opacity))
        angle_variance = self.regularize_angle(angle_rad - ship_heading)
        if abs(angle_variance) > math.pi * (1 / 8):
            target_speed = 1.5
            self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
            angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
            angle_variance = self.regularize_angle(angle_rad - ship_heading)

            if abs(angle_variance) > math.pi * (1.5 / 8):
                target_speed = 1.0
                self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
                angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
                angle_variance = self.regularize_angle(angle_rad - ship_heading)

                if abs(angle_variance) > math.pi * (1 / 4):
                    target_speed = 0.5
                    self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
                    angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
                    angle_variance = self.regularize_angle(angle_rad - ship_heading)

                    if abs(angle_variance) > math.pi * (5 / 8):
                        target_speed = -0.5
                        self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
                        angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
                        angle_variance = self.regularize_angle(angle_rad - ship_heading)

        for theta in range(0,120):
            point = np.array(
                [self.spd_visual_multiplier*target_speed * math.cos(math.radians(theta*3)), self.spd_visual_multiplier*target_speed * math.sin(math.radians(theta*3))])

            if self.angle_opacity[theta] < 1:  #np.percentile(self.angle_opacity,10):
                self.vo_circles.append([self.phys_status["pose"][0]+point,0.05, (0,255,50), 1])

        self.vo_lines.append([self.phys_status["pose"][0],[self.phys_status["pose"][0][0]+self.spd_visual_multiplier*target_speed*math.cos(angle_rad),self.phys_status["pose"][0][1]+self.spd_visual_multiplier*target_speed*math.sin(angle_rad)],(0,255,0)])

        rotational_mul = angle_variance

        if target_speed < 0:
            rotational_mul = - rotational_mul

        if not (angle_variance >= -10 and angle_variance <= 10):
            angle_variance = 0

        if (angle_variance) > (math.pi / 2):
            rotational_mul = abs((math.pi / 2))
        elif (angle_variance) < -(math.pi / 2):
            rotational_mul = - abs((math.pi / 2))

        # rotational controller
        if abs(angle_variance) > 0.01 and abs(ship_rot_spd) <= abs(self.ship_ax_vel_lim):
            ship_rot_spd = -(rotational_mul / (math.pi / 2))*10
        else:
            ship_rot_spd = 0

        # translational controller
        if distance_to_target > 2:
            ship_speed = target_speed
        elif distance_to_target >= 0.6:
            ship_speed = target_speed/3
        elif distance_to_target >= 0.3:
            ship_speed = target_speed/8
        else:
            ship_speed = 0
            ship_rot_spd = 0

        ship_vel = ship_speed*np.array([math.cos(heading_in), math.sin(heading_in)])
        cmd_vel = [ship_vel, ship_rot_spd]

        return cmd_vel

    def vo_cone_generator(self):
        ship_pos = self.phys_status["pose"][0]
        ship_vel = self.phys_status["velocity"][0]
        ship_spd = abs(np.linalg.norm(self.phys_status["velocity"][0]))

        #vessel velocity indicator
        self.vo_lines.append([ship_pos,ship_pos+ship_vel*self.spd_visual_multiplier, (0, 0, 255)])

        circle_color = (200, 200, 200, 255)
        line_width = 1
        circle = [ship_pos, self.detection_range, circle_color, line_width]  # object circle position
        self.vo_circles.append(circle)  # circle representing collision distance of the object

        if self.filtered_objects_angle != None:
            for key, object in self.filtered_objects_angle.items():

                object_pos = object[0].phys_status["pose"][0]  # absolute object position
                object_vel = object[0].phys_status["velocity"][0]  # absolute object velocity
                #object_radius = object[1] + object[2]  # object VO_circle radius
                circle_color = (200, 0, 0, 255)
                line_width = 1
                #circle = [object_pos, object_radius, circle_color, line_width]  # object circle position
                #self.vo_circles.append(circle)  # circle representing collision distance of the object
                pos_diff = object_pos - ship_pos

                object_distance = object[3]  # distance from the object to the circle

                rel_spd = np.linalg.norm(object[0].phys_status["velocity"][0]-ship_vel)

                if object_distance < 0.1:  # for avoiding divide by zero error
                    object_distance = 0.1

                start_rad = object[1]
                end_rad = object[2]

                object_velocity = object[0].phys_status["velocity"][0]

                #self.vo_cones.append([ship_pos, [start_rad, end_rad], object_distance*math.cos(tangent_angle)])

                self.vo_cones.append([ship_pos+object_velocity*self.spd_visual_multiplier, [start_rad, end_rad], object_distance])

            #print(math.degrees(self.filtered_objects))
        pass

    def vo_theta_opacity(self, target_angle, spd_to_search):

        # when search spd = max_spd
        spd_to_search
        angle_opacity = np.linspace(start=0, stop=120, num=120, endpoint=False)

        for theta in range(0,120):

            delta_angle = target_angle - math.radians(theta*3)

            while delta_angle >= 1 * math.pi:
                delta_angle = delta_angle - 2 * math.pi
            while delta_angle <= -1 * math.pi:
                delta_angle = delta_angle + 2 * math.pi

            angle_diff_opacity = (abs(delta_angle/(math.pi)))*(30/80)

            angle_opacity[theta] = angle_diff_opacity

        for vo_cone in self.vo_cones:
            for theta in range(0, 120):
                point = np.array([self.spd_visual_multiplier*spd_to_search*math.cos(math.radians(theta*3)), self.spd_visual_multiplier**spd_to_search*math.sin(math.radians(theta*3))])

                opacity = self.vo_cone_collision_detector(point + self.phys_status["pose"][0], vo_cone)

                if opacity > 1/5:
                    opacity = 100

                if opacity <1/10:
                    opacity = 0

                angle_opacity[theta] = angle_opacity[theta]+(opacity**2)*10

        return angle_opacity

    def sensor_simulator_legacy(self):
        # receives dict(self.ships_database, **self.obstacle_database), which consists of dictionaries of objects(ship or obstacle).
        # extracts only {key, polygon} tuples using a for loop
        # then it filters only the keys of which its polygon is inside the detection range.
        # then it outputs {key: [polygon, phys_status]}  to a dictionary.
        ship_pose = self.phys_status["pose"]
        ship_polygon = self.output_polygon
        objects_database = self.sensor_data
        origin_point = ship_pose[0]

        if not(objects_database):
            return

        filtered_objects = {}

        #print(objects_database)

        for key, object in objects_database.items():
            # calculate distance between origin and closest point of polygon

            # print(key)
            object_pose = object.phys_status["pose"]
            object_vector = (object_pose[0] - ship_pose[0])
            object_distance = (np.linalg.norm(object_vector))
            #print(key, object_vector)

            # check if polygon is within detection range
            if object_distance <= self.detection_range:
                # gets object polygonal information
                poly_points = object.output_polygon
                # if there are no polygons, return nothing
                if poly_points == None:
                    return

                #print(poly_points)
                (max_angle, min_angle) = self.get_min_max_angles(poly_points)
                FOV = (max_angle - min_angle)

                while FOV > 1 * math.pi:
                    FOV = 2 * math.pi - FOV
                while FOV <= 0:
                    FOV += 2 * math.pi

                object_radius = (object_distance * math.tan(FOV / 2))
                self_radius = (self.get_largest_inner_product(ship_polygon, object_vector))/2

                filtered_objects[key] = [object, object_radius, self_radius ]
                #print(" key, FOV object_radius self_radius  : ", object_distance, math.degrees(FOV), object_radius, self_radius)
        return filtered_objects

    def sensor_simulator(self):
        # receives dict(self.ships_database, **self.obstacle_database), which consists of dictionaries of objects(ship or obstacle).
        # extracts only {key, polygon} tuples using a for loop
        # then it filters only the keys of which its polygon is inside the detection range.
        # then it outputs {key: [polygon, phys_status]}  to a dictionary.
        ship_pose = self.phys_status["pose"]
        ship_polygon = self.output_polygon
        objects_database = self.sensor_data
        origin_point = ship_pose[0]

        if not (objects_database):
            return

        filtered_objects_angle = {}

        # print(objects_database)

        for key, object in objects_database.items():
            # calculate distance between origin and closest point of polygon

            # print(key)
            object_pose = object.phys_status["pose"]
            object_vector = (object_pose[0] - ship_pose[0])

            if object_pose[0][1] == ship_pose[0][1] and object_pose[0][0] == ship_pose[0][0]:
                continue
            object_distance = (np.linalg.norm(object_vector))
            # print(key, object_vector)

            # check if polygon is within detection range
            if object_distance > self.detection_range*1.1:
                continue

                # print(poly_points)
            N = self.inflate_obstacles(object)
            if N == None:
                continue
            [max_angle_point, min_angle_point], [start_angle, end_angle], self.outer_polygon,closest_distance = N

            self.vo_lines.append([self.phys_status["pose"][0], max_angle_point,(255, 153, 251)])
            self.vo_lines.append([self.phys_status["pose"][0], min_angle_point,(255, 153, 251)])
            if closest_distance <= self.detection_range:

                filtered_objects_angle[key] = [object, start_angle, end_angle, closest_distance]
                # print(" key, FOV object_radius self_radius  : ", object_distance, math.degrees(FOV), object_radius, self_radius)
        return filtered_objects_angle

    def get_min_max_angles(self,polygon):
        # Select the first point as the origin
        origin = self.phys_status["pose"][0]

        # Calculate the angle for each point relative to the origin
        angles = []
        for point in polygon:
            x, y = point[0] - origin[0], point[1] - origin[1]
            angle = math.atan2(y, x)
            if angle < 0:
                while angle < 0:
                    angle += 2 * math.pi

            if angle > 2 * math.pi:
                while angle > 2:
                    angle -= 2 * math.pi
            angles.append(angle)

        # Return the maximum and minimum angles
        max_angle = max(angles)
        min_angle = min(angles)

        #print("\n",math.degrees(max_angle), math.degrees(min_angle),end="")
        #print("\n", polygon, end="")

        return (max_angle, min_angle)

    def inflate_obstacles(self,object):
        # Select the first point as the origin
        origin = self.phys_status["pose"][0]
        ship_polygon = self.output_polygon
        if object.output_polygon == None:
            return

        # Calculate the angle for each point relative to the origin
        object_vector = (object.phys_status["pose"][0] - self.phys_status["pose"][0])
        avg_angle = math.atan2(object_vector[1],object_vector[0])
        if avg_angle < 0:
            while avg_angle < 0:
                avg_angle += 2 * math.pi
        if avg_angle > 2 * math.pi:
            while avg_angle > 2:
                avg_angle -= 2 * math.pi
        #centers the ship polygon
        ship_polygon_centered = []
        for point in self.output_polygon:
            ship_polygon_centered.append((point - self.phys_status["pose"][0])*2)

        inflated_points = []
        for point in object.output_polygon:
            for point2 in ship_polygon_centered:
                inflated_point = point + point2
                inflated_points.append(inflated_point)

        hull = ConvexHull(inflated_points)
        outer_polygon = [inflated_points[i] for i in hull.vertices]

        self.vo_polygons.append(outer_polygon)

        angles = []
        for point in outer_polygon:
            x, y = point[0] - origin[0], point[1] - origin[1]
            angle = math.atan2(y, x)

            if angle < 0:
                while angle < 0:
                    angle += 2 * math.pi

            if angle > 2 * math.pi:
                while angle > 2 * math.pi:
                    angle -= 2 * math.pi

            delta_angle = angle-avg_angle

            if delta_angle < - math.pi:
                while delta_angle < -math.pi:
                    delta_angle += 2 * math.pi

            if delta_angle > math.pi:
                while delta_angle > math.pi:
                    delta_angle -= 2 * math.pi

            angles.append(delta_angle)

        # Return the maximum and minimum angles
        max_angle = max(angles)
        min_angle = min(angles)

        max_angle_index = angles.index(max_angle)
        min_angle_index = angles.index(min_angle)

        max_angle = min(max(angles), math.pi*(3/4))+math.pi/20
        min_angle = max(min(angles), -math.pi*(3/4))-math.pi/20

        max_angle_point = outer_polygon[max_angle_index]
        min_angle_point = outer_polygon[min_angle_index]

        closest_point = self.closest_point_to_polygon(origin, outer_polygon)

        self.vo_circles.append([closest_point[0], 0.1, (236, 232, 26), 1])

        if closest_point[1] == -1:
            closest_distance = 1
        else:
            closest_distance = np.linalg.norm(origin - closest_point[0])

        return ([max_angle_point,min_angle_point],[avg_angle+min_angle,avg_angle+max_angle],outer_polygon,closest_distance)

    def get_largest_inner_product(self,polygon, B):
        # Rotate B by pi/2
        B_rotated = np.array([-B[1], B[0]])

        # Normalize B_rotated
        A = B_rotated / np.linalg.norm(B_rotated)

        max_inner_product = -float('inf')

        for i, point1 in enumerate(polygon):
            for j, point2 in enumerate(polygon[i + 1:], i + 1):
                # Calculate the line vector between point1 and point2
                line_vector = np.array(point2) - np.array(point1)

                # Calculate the inner product of line_vector and A
                inner_product = np.dot(line_vector / np.linalg.norm(line_vector), A)

                # Update the max inner product if applicable
                if inner_product > max_inner_product:
                    max_inner_product = inner_product

        # Return the largest inner product
        return max_inner_product

    def tangent_lines(self, circle, origin):
        # Unpack circle coordinates and radius
        x_c, y_c = circle[0]
        r = circle[1]

        # Unpack origin coordinates
        x_o, y_o = origin

        # Calculate the distance between the origin and the center of the circle
        d = math.sqrt((x_c - x_o) ** 2 + (y_c - y_o) ** 2)

        # Check if the origin is inside the circle
        if d < r:
            print("Error: origin is inside the circle.")
            return None

        # Calculate the angle between the origin and the center of the circle
        theta = math.atan2(y_c - y_o, x_c - x_o)

        # Calculate the distance from the origin to the tangent point
        a = math.sqrt(d ** 2 - r ** 2)

        # Calculate the angles of the tangent lines
        alpha = math.asin(r / d)
        beta = theta - alpha
        gamma = theta + alpha

        # Return the two angles of the tangent lines
        return beta, gamma

    def vo_cone_collision_detector(self, point, cone):
        """
        Determines whether a point is inside a circle section
        """
        origin, [start_angle, end_angle], radius = cone

        if radius < 0.5:
            radius = 1

        # Calculate angle of point relative to circle origin
        point_angle = math.atan2(point[1] - origin[1], point[0] - origin[0])

        start_angle = self.regularize_angle(start_angle)
        end_angle = self.regularize_angle(end_angle)
        point_angle = self.regularize_angle(point_angle)

        if end_angle >= start_angle:
            result = point_angle >= start_angle and point_angle <= end_angle
            inside_angle = end_angle - start_angle

        elif end_angle <= start_angle: # 0도 넘어갈 때
            result = point_angle >= start_angle or point_angle <= end_angle
            inside_angle = end_angle + 2*math.pi - start_angle

        if result == True:
            time_till_collision = radius / (math.dist(point, origin)/5)

            print(1)

            if radius < 4:
                return 1

            if inside_angle > math.pi:
                return 1

            return 1/time_till_collision
        if result == False:
            return 0

    def angle_between_vector_and_angle(self, vector, angle):
        # Calculate the angle between the vector and the x-axis
        vector_angle = math.atan2(vector[1], vector[0])

        # Calculate the difference between the vector angle and the given angle
        angle_diff = vector_angle - angle

        # Ensure that the angle difference is within the range (-pi, pi]

        angle_diff = self.regularize_angle(angle_diff)

        # Return the absolute value of the angle difference
        return angle_diff

    def index_with_lowest_number(self, numbers):
        """
        Returns the index of the lowest number in a list
        """
        lowest_index = 0
        for i in range(1, len(numbers)):
            if numbers[i] < numbers[lowest_index]:
                lowest_index = i
        return lowest_index

    def regularize_angle(self,angle):
        while angle > math.pi:
            angle -= 2 * math.pi
        while angle <= -math.pi:
            angle += 2 * math.pi

        return angle

    def point_polygon_distance(self, point, polygon):
        if isinstance(point, np.ndarray):
            point = tuple(point)

        polygon_vertices = polygon
        # Create a list of tuples containing the x,y coordinates of the polygon vertices
        polygon = [(x, y) for (x, y) in polygon_vertices]

        # Find the closest point on the polygon boundary to the target point
        closest_point = None
        min_distance = float('inf')
        for i in range(len(polygon)):
            x1, y1 = polygon[i]
            x2, y2 = polygon[(i + 1) % len(polygon)]
            dx = x2 - x1
            dy = y2 - y1
            dot = ((point[0] - x1) * dx + (point[1] - y1) * dy) / (dx ** 2 + dy ** 2)
            closest_x = float(x1) + dot * dx
            closest_y = float(y1) + dot * dy
            distance = math.sqrt((point[0] - closest_x) ** 2 + (point[1] - closest_y) ** 2)
            if distance < min_distance:
                min_distance = distance
                closest_point = (closest_x, closest_y)

                print(distance)

        # If the point is inside the polygon, return a negative distance
        if self.is_inside_polygon(point, polygon_vertices):
            return 0
        else:
            return min_distance

    def closest_point_to_polygon(self, point, polygon_vertices):
        # Convert numpy array to tuple if necessary
        if isinstance(point, np.ndarray):
            point = tuple(point)

        # Find the closest point on the polygon boundary to the target point
        closest_point = None
        min_distance = float('inf')

        polygon_vertices2 = self.subdivide_polygon(polygon_vertices)

        for i in range(len(polygon_vertices2)):

            (closest_x, closest_y) = polygon_vertices2[i]

            distance = np.sqrt((point[0] - closest_x) ** 2 + (point[1] - closest_y) ** 2)
            if distance < min_distance:
                min_distance = distance

                closest_point = np.array([closest_x, closest_y])

        if self.is_inside_polygon(point, polygon_vertices):
            return [closest_point, -1]
        else:
            return [closest_point, 1]

    def is_inside_polygon(self, point, polygon_vertices):
        # Create a list of tuples containing the x,y coordinates of the polygon vertices
        polygon = [(x, y) for x, y in polygon_vertices]

        # Use the winding number algorithm to check if the point is inside the polygon
        wn = 0
        for i in range(len(polygon)):
            x1, y1 = polygon[i]
            x2, y2 = polygon[(i + 1) % len(polygon)]
            if y1 <= point[1]:
                if y2 > point[1]:
                    if (point[0] - x1) * (y2 - y1) > (x2 - x1) * (point[1] - y1):
                        wn += 1
            else:
                if y2 <= point[1]:
                    if (point[0] - x1) * (y2 - y1) < (x2 - x1) * (point[1] - y1):
                        wn -= 1
        return wn != 0

    def subdivide_polygon(self, polygon, n=20):
        """Subdivides a polygon and divides each edge into n segments."""
        new_polygon = []

        # Iterate over the edges of the polygon
        for i in range(len(polygon)):
            # Add the current vertex to the new polygon
            new_polygon.append(polygon[i])

            # Calculate the difference vector between the current and next vertex
            diff = [polygon[(i + 1) % len(polygon)][j] - polygon[i][j] for j in range(len(polygon[0]))]

            # Calculate the size of each segment along the current edge
            segment_size = [diff[j] / n for j in range(len(diff))]

            # Iterate over the segments of the current edge
            for j in range(1, n):
                # Calculate the coordinates of the new vertex
                x_new = polygon[i][0] + j * segment_size[0]
                y_new = polygon[i][1] + j * segment_size[1]
                new_vertex = [x_new, y_new]

                # Add the new vertex to the new polygon
                new_polygon.append(new_vertex)

        return new_polygon


import os
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse, reverse_lazy
from django.views.generic.edit import CreateView, UpdateView
from django.views.generic.list import ListView

from Venter import upload_to_google_drive
from Venter.models import Category, Profile

from Venter.forms import CSVForm, ProfileForm, UserForm
from .manipulate_csv import EditCsv

def upload_csv_file(request):
    """
    View logic for uploading CSV file by a logged in user.

    For POST request-------
        1) The POST data, uploaded csv file and a request parameter are being sent to CSVForm as arguments
        2) If form.is_valid() returns true, the user is assigned to the uploaded_by field
        3) csv_form is saved and currently returns a simple httpresponse inplace of prediction results
    For GET request-------
        The csv_form is rendered in the template
    """
    if request.method == 'POST':
        csv_form = CSVForm(request.POST, request.FILES, request=request)
        if csv_form.is_valid():
            file_uploaded = csv_form.save(commit=False)
            file_uploaded.uploaded_by = request.user
            csv_form.save()
            return HttpResponse("
Your csv file was uploaded, redirect user to prediction page (pie charts, tables..)
")
        else:
            return render(request, './Venter/upload_file.html', {'csv_form': csv_form})
    elif request.method == 'GET':
        csv_form = CSVForm(request=request)
        return render(request, './Venter/upload_file.html', {'csv_form': csv_form})

def handle_user_selected_data(request):
    """This function is used to handle the selected categories by the user"""
    if not request.user.is_authenticated:
        # Authentication security check
        return redirect(settings.LOGIN_REDIRECT_URL)
    else:
        rows = request.session['Rows']
        correct_category = []
        company = request.session['company']
        if request.method == 'POST':
            file_name = request.session['filename']
            user_name = request.user.username
            for i in range(rows):
                # We are getting a list of values because the select tag was multiple select
                selected_category = request.POST.getlist(
                    'select_category' + str(i) + '[]')
                if request.POST['other_category' + str(i)]:
                    # To get a better picture of what we are getting try to print "request.POST.['other_category' + str(i)]", request.POST['other_category' + str(i)
                    # others_list=request.POST['other_category' + str(i)]
                    # for element in others_list:
                    #     print(element)
                    #     tuple = (selected_category,element)
                    tuple = (selected_category,
                             request.POST['other_category' + str(i)])
                    # print(request.POST['other_category' + str(i)])
                    # print(tuple)
                    # So here the correct_category will be needing a touple so the data will be like:
                    # [(selected_category1, selected_category2), (other_category1, other_category2)] This will be the output of the multi select
                    correct_category.append(tuple)
                else:
                    # So here the correct_category will be needing a touple so the data will be like:
                    # [(selected_category1, selected_category2)] This will be the output of the multi select
                    correct_category.append(selected_category)
        csv = EditCsv(file_name, user_name, company)
        csv.write_file(correct_category)
        if request.POST['radio'] != "no":
            # If the user want to send the file to Google Drive
            path_folder = request.user.username + "/CSV/output/"
            path_file = 'MEDIA/' + request.user.username + \
                "/CSV/output/" + request.session['filename']
            path_file_diff = 'MEDIA/' + request.user.username + "/CSV/output/Difference of " + request.session[
                'filename']
            upload_to_google_drive.upload_to_drive(path_folder,
                                                   'results of ' +
                                                   request.session['filename'],
                                                   "Difference of " +
                                                   request.session['filename'],
                                                   path_file,
                                                   path_file_diff)
    return redirect("/download")

def file_download(request):
    if not request.user.is_authenticated:
        return redirect(settings.LOGIN_REDIRECT_URL)
    else:
        # Refer to the source: https://stackoverflow.com/questions/36392510/django-download-a-file/36394206
        path = os.path.join(settings.MEDIA_ROOT, request.user.username,
                            "CSV", "output", request.session['filename'])
        with open(path, 'rb') as csv:
            response = HttpResponse(
                csv.read())  # Try using HttpStream instead of this. This method will create problem with large numbers of rows like 25k+
            response['Content-Type'] = 'application/force-download'
            response['Content-Disposition'] = 'attachment;filename=results of ' + \
                request.session['filename']
        return response

def handle_uploaded_file(f, username, filename):
    """Just a precautionary step if signals.py doesn't work for any reason."""

    data_directory_root = settings.MEDIA_ROOT
    path = os.path.join(data_directory_root, username,
                        "CSV", "input", filename)
    path_input = os.path.join(data_directory_root, username, "CSV", "input")
    path_output = os.path.join(data_directory_root, username, "CSV", "output")

    if not os.path.exists(path_input):
        os.makedirs(path_input)

    if not os.path.exists(path_output):
        os.makedirs(path_output)

    with open(path, 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

def user_logout(request):
    logout(request)
    return redirect(settings.LOGIN_REDIRECT_URL)

class CategoryListView(LoginRequiredMixin, ListView):
    """
    Arguments------
        1) ListView: View to display the category list for the organisation to which the logged in user belongs
        2) LoginRequiredMixin: Request to update profile details by non-authenticated users, will throw an HTTP 404 error

    Functions------
        1) get_queryset(): Returns a new QuerySet filtering categories based on the organisation name passed in the parameter.
    """
    model = Category

    def get_queryset(self):
        return Category.objects.filter(organisation_name=self.request.user.profile.organisation_name)

class UpdateProfileView(LoginRequiredMixin, UpdateView):
    """
    Arguments------
        1) UpdateView: View to update the user profile details for the logged in user
        2) LoginRequiredMixin: Request to update profile details by non-authenticated users, will throw an HTTP 404 error
    """
    model = Profile
    success_url = reverse_lazy('home')

    def post(self, request, *args, **kwargs):
        user_form = UserForm(request.POST, instance=request.user)
        profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
        if user_form.is_valid() and profile_form.is_valid(): # pylint: disable = R1705
            user_form.save()
            profile_form.save()
            messages.success(request, 'Your profile was successfully updated!')
            return HttpResponseRedirect(reverse_lazy('home'))
        else:
            messages.error(request, 'Please correct the error below.')

    def get(self, request, *args, **kwargs):
        user_form = UserForm(instance=request.user)
        profile_form = ProfileForm(instance=request.user.profile)
        return render(request, './Venter/update_profile.html', {'user_form': user_form, 'profile_form': profile_form})

class CreateProfileView(CreateView):
    """
    Arguments------
        1) CreateView: View to create the user profile for a new user.
    Note------
        profile_form.save(commit=False) returns an instance of Profile that hasn't yet been saved to the database.
        The profile.save() returns an instance of Profile that has been saved to the database.
        This occurs only after the profile is created for a new user with the 'profile.user = user'
    """
    model = Profile

    def post(self, request, *args, **kwargs):
        user_form = UserForm(request.POST)
        profile_form = ProfileForm(request.POST, request.FILES)
        if user_form.is_valid() and profile_form.is_valid():
            user = user_form.save()
            profile = profile_form.save(commit=False)
            profile.user = user
            profile.save()
            return HttpResponseRedirect(reverse('home', args=[]))
        else:
            messages.warning(
                request, 'Something went wrong in Venter, please try again')
            return HttpResponse("
NO Profile created
")

    def get(self, request, *args, **kwargs):
        user_form = UserForm()
        profile_form = ProfileForm()
        return render(request, './Venter/registration.html', {'user_form': user_form, 'profile_form': profile_form})


from vizasm.analysis.asm.cpu.AsmRegEx import AsmRegEx

class AsmRegEx_arm(AsmRegEx):
    '''
    Contains regular expressions (mostly in verbose mode) used for analyzing the assembler file on the arm architecture.

    Parameters
    ----------
    RE_IVAR
        match e.g. "IVAR_0x291c"

    RE_CLASSREF
        match e.g. "@bind__OBJC_CLASS_$_UIScreen"

    RE_IMP_SYMBOLSTUB
        match e.g "imp___symbolstub1__objc_msgSend"

    RE_IMP_NL_SYMBOL_PTR
        match e.g. "@imp___nl_symbol_ptr__objc_retain"

    RE_ASSINGMENT_SPLIT
        match e.g.  "ldr        r8, [sp], #0x4" or
                    "ldr        r1, [r0] " or
                    "cvtss2sd   xmm2, xmm2"

    RE_OFFSET_ADDRESSING
        match .e.g "[sp, #0x8]"

    RE_CALL_INSTRUCTION
        match e.g. "blx        imp___symbolstub1__objc_msgSend"

    RE_ADD
        match e.g. "add r7, sp, #0xc" or
                   "add        r7, sp" or
                   "add        r7, #0xc"

    RE_REGISTER
        match e.g. "ro"

    RE_ANNOTATED_SUPERCALL
         match e.g. "; call to super: 0xbb4e"
    '''

    RE_IMP_STUBS_GR_IMP_SYMBOLSTUB = 'imp_symbolstub'
    RE_IMP_SYMBOLSTUB = r'''
 (?:imp[_]{3}symbolstub1[_]{2,})  # imp___symbolstub1__
 (?P<%s>.*)                      # objc_msgSend
 ''' % RE_IMP_STUBS_GR_IMP_SYMBOLSTUB

    # @imp___nl_symbol_ptr__objc_retain
    RE_IMP_NL_SYMBOL_PTR_GR_NAME = 'name'
    RE_IMP_NL_SYMBOL_PTR = '''
    @imp[_]{3}nl[_]symbol[_]ptr[_]{2} # @imp___nl_symbol_ptr__
    (?P<%s>\S+)                       # objc_retain
    ''' % RE_IMP_NL_SYMBOL_PTR_GR_NAME

    RE_CLASSREF_GR_CLASSREF = 'classref'
    RE_CLASSREF = '''
    @bind[_]{2}OBJC[_]CLASS[_][$][_] # @bind__OBJC_CLASS_$_
    (?P<%s>\S+)                      # UIScreen
    ''' % RE_CLASSREF_GR_CLASSREF

    RE_ASSINGMENT_SPLIT_GR_OP = 'op'
    RE_ASSINGMENT_SPLIT_GR_VAL1 = 'val1'
    RE_ASSINGMENT_SPLIT_GR_VAL2 = 'val2'
    #  ldr        r8, [sp], #0x4
    RE_ASSINGMENT_SPLIT = r'''
 (?P<%s>(add|mov|ldr|.*cvt|st(m|r)).*?)    # ldr
 \s+
 (?P<%s>.*?)                                # r8
 ,\s*                                       # ,
 =?                                         # optional "=" for ldr
 (?P<%s>.*)                                 # [sp], #0x4
 ''' % (RE_ASSINGMENT_SPLIT_GR_OP, RE_ASSINGMENT_SPLIT_GR_VAL1, RE_ASSINGMENT_SPLIT_GR_VAL2)

    RE_CALL_INSTRUCTION_GR_CALLED = 'called'
    RE_CALL_INSTRUCTION = '''
    blx?             # bl or blx
    \s*              # whitespace
    (?P<%s>\S+)      # called
    ''' % RE_CALL_INSTRUCTION_GR_CALLED

    RE_IVAR_GR_NAME = 'ivar_addr'
    RE_IVAR = r'''
 IVAR[_]      # IVAR_
 (?P<%s>\S+)  # 0x291c
 ''' % (RE_IVAR_GR_NAME)

    # [ro]
    RE_REGISTER_GR_NAME = 'name'
    RE_REGISTER = '''
    \[?               # "[" is optional
    (?P<%s>
     (
      [^]]             # no ]
      \S               # no whitespace
     )+                # match all but whitespace and ]
    )
    \]?               # "]" is optional
    ''' % (RE_REGISTER_GR_NAME)

    # [sp, #0x8]
    RE_OFFSET_ADDRESSING_GR_BASE_REGISTER = 'base_register'
    RE_OFFSET_ADDRESSING_GR_OFFSET = 'offset'
    RE_OFFSET_ADDRESSING = '''
    \[             # [
    (?P<%s>\w+)    # sp
    (
    ,\s*           # ,
    [#]?           # #
    (?P<%s>\w+)    # 0x8
    )?
    \]             # ]
    ''' % (RE_OFFSET_ADDRESSING_GR_BASE_REGISTER, RE_OFFSET_ADDRESSING_GR_OFFSET)

    RE_ADD_GR_DEST = 'dest'
    RE_ADD_GR_OPERAND1 = 'operand1'
    RE_ADD_GR_OPERAND2 = 'operand2'
    # add        r7, sp, #0xc
    RE_ADD = '''
    add\w*         # add
    \s+            # whitespace
    (?P<%s>\w+)    # r7
    ,              # ,
    \s*            # whitespace
    (?P<%s>\#?\w+) # sp
    (
    ,\s*           # , whitespace
    (?P<%s>\#?\w+) # #0xc
    )*
    ''' % (RE_ADD_GR_DEST, RE_ADD_GR_OPERAND1, RE_ADD_GR_OPERAND2)

    # ; call to super: 0xbb4e
    RE_ANNOTATED_SUPERCALL_GR_SUPERREF_ADDR = 'superref_addr'
    RE_ANNOTATED_SUPERCALL = '''
    call\s+to\s+super[:]\s+        # "; call to super:"
    (?P<%s>0x\w+)                  # 0xbb4e
    ''' % (RE_ANNOTATED_SUPERCALL_GR_SUPERREF_ADDR)

    RE_STACK_PUSH_GR_REGISTERS = 'registers'
    @staticmethod
    def compiled_re_stack_push_via_stm(stack_pointer, asmline):
        ''' Read a stack push via "stm" like e.g. "stm.w      sp, {r3, r11}"
        and return the re match object.
        Use `RE_STACK_PUSH_GR_REGISTERS` to get the list<str> of pushed registers '''

        RE_STACK_PUSH = '''
        stm.*?                # stm
        \s*                   # whitespace
        %s                    # stack pointer
        ,\s*                  # ,
        [{]                   # {
        (?P<%s>.*)            # r3, r11
        [}]                   # }
        ''' % (stack_pointer, AsmRegEx_arm.RE_STACK_PUSH_GR_REGISTERS)
        stack_push_match = AsmRegEx_arm.compiled_vre(RE_STACK_PUSH).search(asmline)
        if stack_push_match is not None:
            return stack_push_match
        return None

    RE_STACK_GR_STACK_POINTER = 'stack_pointer'
    RE_STACK_GR_ADDRESS = 'stack_address'
    RE_STACK_GR_OFFSET = 'stack_offset'
    @staticmethod
    def compiled_re_stack(stack_pointer_name, frame_pointer_name):
        '''
        Return a compiled regular expression that matches  e.g. "[sp, #0x8]" or "[sp], #0x4"
        Use `RE_STACK_GR_ADDRESS` group key to get the stack address.

        Parameters
        ----------
        stack_pointer_name: string
            the name of stack pointer register (e.g. "sp")
        '''
        RE_STACK = r'''
         \[                              # [
         (?P<%s>%s|%s)                   # stack pointer name or frame pointer name
         (
                 (
                 \]
                 ,\s+                            # ,
                 [#]                             # #
                 (?P<%s>0x\w+)                   # 0x8
                 )
             |                                   # or
                 (
                 ,\s+                            # ,
                 [#]
                 (?P<%s>0x\w+)                   # #0x8
                 \]                              # ]
                 )
            |
                \]                              # ]
         )

        ''' % (AsmRegEx_arm.RE_STACK_GR_STACK_POINTER, stack_pointer_name, frame_pointer_name, AsmRegEx_arm.RE_STACK_GR_OFFSET, AsmRegEx_arm.RE_STACK_GR_ADDRESS)
        return AsmRegEx.compiled_vre(RE_STACK)

    @staticmethod
    def stack_pointer_sub(stack_pointer_str, asmline):
        '''
        Read a line like e.g. "sub        sp, #0x14"
        and return the value that is being subtracted from the stack pointer as string.
        None if did not match.
        '''

        RE_SP_SUB_GR_SUBTRACTED = 'subtracted'
        RE_SP_SUB = '''
        sub\w*
        \s*
        %s,
        \s*
        \#(?P<%s>\w+)
        ''' % (stack_pointer_str, RE_SP_SUB_GR_SUBTRACTED)

        re_sp_sub_match = AsmRegEx_arm.compiled_vre(RE_SP_SUB).search(asmline)
        if re_sp_sub_match is not None:
            return re_sp_sub_match.group(RE_SP_SUB_GR_SUBTRACTED)
        return None


"""Create category

Revision ID: bc8fb2b5aaaa
Revises: cf3388347129
Create Date: 2023-05-06 09:44:36.431462

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'bc8fb2b5aaaa'
down_revision = 'cf3388347129'
branch_labels = None
depends_on = None

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('category',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=50), nullable=True),
    sa.Column('icon', sa.String(length=50), nullable=True),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('create_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
    sa.Column('update_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
    sa.PrimaryKeyConstraint('id'),
    sa.UniqueConstraint('name')
    )
    op.create_index(op.f('ix_category_id'), 'category', ['id'], unique=False)
    # ### end Alembic commands ###

def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index(op.f('ix_category_id'), table_name='category')
    op.drop_table('category')
    # ### end Alembic commands ###


# vim set fileencoding=utf-8
from setuptools import setup

with open('README.rst') as f:
    long_description = f.read()
setup(
    name = 'AnthraxEplasty',
    version = '0.0.3',
    author = 'Szymon Pyżalski',
    author_email = 'zefciu <szymon@pythonista.net>',
    description = 'Anthrax - generating forms from Elephantoplasty objects',
    url = 'http://github.com/zefciu/Anthrax',
    keywords = 'form web orm database',
    long_description = long_description,

    install_requires = ['anthrax', 'Elephantoplasty'],
    tests_require = ['nose>=1.0', 'nose-cov>=1.0'],
    test_suite = 'nose.collector',
    package_dir = {'': 'src'},
    namespace_packages = ['anthrax'],
    packages = [
        'anthrax', 'anthrax.eplasty'
    ],
    classifiers = [
        'Development Status :: 1 - Planning',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: BSD License',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.2',
        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
    ],
    entry_points = """[anthrax.reflector]
eplasty = anthrax.eplasty.reflector:EplastyReflector
[anthrax.field_mixins]
eplasty_unique = anthrax.eplasty.field:UniqueMixin
""",
)


import pickle
import os
import sys
import numpy as np
import json_tricks as json
import cv2
import torch
import copy
import random
import torchvision.transforms as transforms
from glob import glob
from tqdm import tqdm
from PIL import Image
from natsort import natsorted
import matplotlib.pyplot as plt
from scipy.spatial.transform import Rotation as R
from torch.utils.data import Dataset
from utils.dataset_helper import get_affine_transform,affine_transform
from core.utils.helper_functions import load_matfile

class InfantDataSet(Dataset):
    def __init__(self, root,pose_root,subjects,path=None, transform=transforms.ToTensor(),is_train=True):
        """
            root: the root of data, eg: '/vol/biodata/data/human3.6m/training'
            pose_root: the root of 2d pose;
            subjects: subjects=['EMT4', 'EMT7', 'EMT38', 'EMT36', 'EMT31', 'EMT43',
                        'EMT5', 'EMT9', 'EMT47', 'EMT45', 'EMT29', 'EMT42',
                        'EMT23', 'EMT41', 'EMT37', 'EMT48', 'EMT44', 'EMT46',
                        'EMT20', 'EMT34', 'EMT11', 'EMT30', 'EMT39', 'EMT35',
                        'EMT14']
            transforms: torchvision.transforms to resize and crop frame to (256,256)
        """

        self.root = root
        self.pose_root=pose_root
        self.indices = np.array([3, 2, 9, 8, 4, 1, 10, 7, 13, 12, 15, 14, 5, 0, 11, 6])
        self.subjects=subjects
        # load dataset
        self.sequences = []
        self.transform=transform
        self.is_train=is_train
        self.dataset=None
        if path != None:
            self.load_seq(path)
        else:
            for subject in tqdm(self.subjects): # actor is in the form of 'S1','S5'
                if not os.path.isdir(os.path.join(root, subject)):
                    print(subject,"not exists")
                    continue
                frames = natsorted(os.listdir(os.path.join(root, subject)))
                frame_nums = [int(x[6:-4]) for x in frames]
                frame_nums=np.array(sorted(frame_nums))-1
                pred_path=os.path.join(pose_root,subject+'.pickle')
                if not os.path.exists(pred_path):
                    print(pred_path,"not exists")
                    continue
                with open(pred_path, "rb") as file:
                    pickle_file = pickle.load(file)
                for frame in frames:
                    frame_num=self.find_index(frame,pickle_file)
                    frame2=random.sample(frames, 1)[0]
                    seq={'subject': subject,
                         'bbox':pickle_file[frame_num]['bounding_box'],
                         'center': pickle_file[frame_num]['center'],
                         'scale': pickle_file[frame_num]['scale'],
                         'frame_num':frame_num,
                         'frame1':pickle_file[frame_num]['frame_id'],
                         'frame2': frame2,
                         'pose_2d':pickle_file[frame_num]['predicted_keypoints']
                        }
                    self.sequences.append(seq)

    def get_single(self, sequence):
        bbox=sequence['bbox']
        center=sequence['center']
        scale=np.asarray([sequence['scale'],sequence['scale']])
        image_size=(256,256)
        frame1_path=os.path.join(self.root,sequence['subject'],sequence['frame1'])
        frame2_path=os.path.join(self.root,sequence['subject'],sequence['frame2'])
        pose_2d=sequence['pose_2d'][self.indices]
        frame1=Image.open(frame1_path)
        frame2=Image.open(frame2_path)
        trans = get_affine_transform(center, scale, 0, image_size)
        frame1=cv2.warpAffine(np.array(frame1), trans, (int(image_size[0]), int(image_size[1])), flags=cv2.INTER_LINEAR)
        frame2=cv2.warpAffine(np.array(frame2), trans, (int(image_size[0]), int(image_size[1])), flags=cv2.INTER_LINEAR)
        frame1_tensor=self.transform(frame1)
        frame2_tensor=self.transform(frame2)
        pose2d_tensor=torch.FloatTensor(pose_2d)
        return frame1_tensor,frame2_tensor,pose2d_tensor

    def find_index(self,s,file):
        j=None
        for i in range(len(file)):
            if s == file[i]['frame_id']:
                j=i
                return j

    def get_sequences(self):
        return self.sequences

    def save_seq(self,path):
        if not os.path.exists(path):
            os.makedirs(path)
        seq=self.__dict__['sequences']
        torch.save(seq, os.path.join(path,'sequences.tar'))
        print("saved successfully!")

    def load_seq(self,path):
        seq_load=torch.load(path)
        self.sequences=seq_load
        print("load successfully!")

    def __getitem__(self, index):
        seq=self.sequences[index]
        return  self.get_single(seq)

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

class Infant3DPose(Dataset):
    def __init__(self, path,load_path=None):
        self.path = path
        self.indices = np.array([15, 14, 10, 6, 3, 0, 11, 7, 4, 1, 12, 8, 5, 2, 13, 9])
        self.keypoints = ['hips', 'shoulders', 'knees', 'elbows', 'ankles', 'wrists', 'feet', 'hands']
        self.sequences=[]
        if load_path != None:
            self.load_seq(load_path)
        else:
            self.sequences=self.get_sequences()

    def save_seq(self,path):
        if not os.path.exists(path):
            os.makedirs(path)
        seq=self.__dict__['sequences']
        torch.save(seq, os.path.join(path,'pose3d_sequences.tar'))
        print("saved successfully!")

    def load_seq(self,path):
        seq_load=torch.load(path)
        self.sequences=seq_load
        print("load successfully!")

    def get_sequences(self):
        spatial_indices = np.array([1, 2, 0])
        sequences = []
        files = glob(os.path.join(self.path, '*.mat'))
        sequences=[]
        for file in tqdm(files):
            # subj = os.path.splitext(os.path.split(file)[-1])[0]
            data, timestamps = load_matfile(file)
            # only xyz
            data = data[:, 0:3]
            data = data.transpose((0, 2, 1))
            # tracker data is 120 Hz, camera is 30 Hz, so factor is 4
            tracker_data = data
            for i in range(len(tracker_data)):
                pose = tracker_data[i]
                # change keypoint order and spatial orientation
                pose = pose[self.indices]
                pose = pose[..., spatial_indices]
                pose = self.align(pose)
                first = pose
                pelvis = first[0] + (first[1] - first[0]) / 2
                pose -= pelvis
                pose = self.normalize(pose)
                pose1 = np.copy(pose)
                pose1[..., 1] = pose[..., 2]
                pose1[..., 2] = pose[..., 1]
                sequences.append(pose1)
        return sequences

    def normalize(self, points):
        first = points
        # normalize to unit cube -1 to 1
        max_ = np.abs(first.max())
        min_ = np.abs(first.min())
        if max_ >= min_:
            points /= max_
        else:
            points /= min_
        return points

    def get_angle(self, vec1, vec2):
        inv = vec1 @ vec2 / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
        return np.arccos(inv)

    def align(self, sequence):
        """remove y component of hip line,
        align pelvis-neck line with z axis"""
        points = sequence
        hip_line = points[0] - points[1]
        pelvis = points[0] + (points[1] - points[0]) / 2
        neck = points[2] + (points[3] - points[2]) / 2
        pelvis_neck_line = neck - pelvis

        # pelvis neck
        rot_axis1 = np.array([0, 0, 1])
        angle = self.get_angle(pelvis_neck_line, rot_axis1)
        cross_prod = np.cross(pelvis_neck_line, rot_axis1)
        cross_prod /= np.linalg.norm(cross_prod)
        R1 = R.from_rotvec(angle * cross_prod)
        points = R1.apply(points)
        # hip
        hip_line = points[0] - points[1]
        rot_axis2 = np.array([1, 0])
        angle = self.get_angle(hip_line[0:2], rot_axis2)
        cross_prod = np.cross(hip_line[0:2], rot_axis2)
        cross_prod /= np.linalg.norm(cross_prod)
        R2 = R.from_rotvec(angle * np.array([0, 0, cross_prod]))
        points=R2.apply(points)
        rot = R.from_rotvec(np.array([0., 0., np.pi]))
        points=rot.apply(points)
        return points

    def __getitem__(self, idx):
        pose = np.array(self.sequences[idx])
#         p1 = np.copy(pose)
#         p1[..., 1] = pose[..., 2]
#         p1[..., 2] = pose[..., 1]
        pose_tensor=torch.FloatTensor(pose)

        return pose_tensor

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


# 给你一个正整数 n ，返回 2 和 n 的最小公倍数（正整数）。

class Solution(object):
    def smallestEvenMultiple(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n % 2 != 0:
            return 2 * n

        else:
            return n

n = 5

a = Solution()
print(a.smallestEvenMultiple(n))


import sys

import mock
import six

from okonomiyaki.errors import InvalidMetadataField
from ..python_implementation import PythonABI, PythonImplementation

from hypothesis import given
from hypothesis.strategies import sampled_from

if sys.version_info < (2, 7):
    import unittest2 as unittest
else:
    import unittest

class TestPythonImplementation(unittest.TestCase):

    @given(sampled_from((
        ('2', '7', 'cp27'), ('3', '8', 'cp38'),
        ('4', '15', 'cp415'), ('3', '11', 'cp311'))))
    def test_creation(self, version):
        # Given
        kind = 'cpython'
        major, minor, r_tag = version

        # When
        tag = PythonImplementation(kind, major, minor)

        # Then
        self.assertEqual(tag.abbreviated_implementation, 'cp')
        self.assertEqual(str(tag), r_tag)
        self.assertIsInstance(six.text_type(tag), six.text_type)

    def test_from_running_python(self):
        # When
        with mock.patch(
                "okonomiyaki.platforms.python_implementation."
                "_abbreviated_implementation",
                return_value="cp"):
            with mock.patch("sys.version_info", (2, 7, 9, 'final', 0)):
                py = PythonImplementation.from_running_python()

        # Then
        self.assertEqual(py.pep425_tag, u"cp27")

        # When
        with mock.patch("sys.pypy_version_info", "pypy 1.9", create=True):
            with mock.patch("sys.version_info", (2, 7, 9, 'final', 0)):
                py = PythonImplementation.from_running_python()

        # Then
        self.assertEqual(py.pep425_tag, u"pp27")

        # When
        with mock.patch("sys.platform", "java 1.7", create=True):
            with mock.patch("sys.version_info", (2, 7, 9, 'final', 0)):
                py = PythonImplementation.from_running_python()

        # Then
        self.assertEqual(py.pep425_tag, u"jy27")

        # When
        with mock.patch("sys.platform", "cli", create=True):
            with mock.patch("sys.version_info", (2, 7, 9, 'final', 0)):
                py = PythonImplementation.from_running_python()

        # Then
        self.assertEqual(py.pep425_tag, u"ip27")

    @given(sampled_from((
        ("cpython", "cp"), ("python", "py"),
        ("pypy", "pp"), ("dummy", "dummy"))))
    def test_abbreviations(self, kinds):
        # Given
        major = 2
        minor = 7
        kind, r_abbreviated = kinds

        # When
        tag = PythonImplementation(kind, major, minor)

        # Then
        self.assertEqual(tag.abbreviated_implementation, r_abbreviated)

    @given(sampled_from((
        (2, 7, 'cp27'), (3, 8, 'cp38'),
        (3, 4, 'cpython34'), (4, 5, 'cp4_5'),
        (24, 7, 'cp24_7'),
        (4, 15, 'cp415'), (3, 11, 'cp311'))))
    def test_from_string(self, data):
        # Given
        major, minor, tag_string = data

        # When
        tag = PythonImplementation.from_string(tag_string)

        # Then
        self.assertEqual(tag.kind, "cpython")
        self.assertEqual(tag.major, major)
        if minor is not None:
            self.assertEqual(tag.minor, minor)

    @given(sampled_from(('cp2', 'py3', 'cp', 'pp4567')))
    def test_from_string_errors(self, data):
        # When/Then
        message = r"^Invalid value for metadata field 'python_tag': '{}'$"
        with self.assertRaisesRegexp(
                InvalidMetadataField, message.format(data)):
            PythonImplementation.from_string(data)

class TestPythonABI(unittest.TestCase):

    def test_pep425_tag_string_none(self):
        # Given
        abi_tag = None

        # When
        abi_tag_string = PythonABI.pep425_tag_string(abi_tag)

        # Then
        self.assertEqual(abi_tag_string, u"none")
        self.assertIsInstance(abi_tag_string, six.text_type)

    def test_pep425_tag_string(self):
        # Given
        abi_tag = PythonABI(u"cp27mu")

        # When
        abi_tag_string = PythonABI.pep425_tag_string(abi_tag)

        # Then
        self.assertEqual(abi_tag_string, u"cp27mu")
        self.assertIsInstance(abi_tag_string, six.text_type)


import sys
import argparse
import tensorflow as tf
from keras.models import Model, load_model
from keras.layers import TimeDistributed, Conv1D, Dense, Embedding, Input, Dropout, LSTM, Bidirectional, MaxPooling1D, \
    Flatten, concatenate
from keras.initializers import RandomUniform
from keras.callbacks import EarlyStopping
from keras.callbacks import ModelCheckpoint
from keras.utils import plot_model
from keras.models import load_model
from hyperopt import Trials, STATUS_OK, tpe
from hyperas import optim
from hyperas.distributions import choice, uniform, randint
from util.util import *

def data():
    train_df = get_train_data()
    #found = train_df['ner']
    #hasValue = [True if 'VALUE' in x else False for i, x in enumerate(found)]
    #train_df = train_df[np.array(hasValue)]
    print(train_df.shape)

    train_data, case2Idx, caseEmbeddings, word2Idx, wordEmbeddings, \
    char2Idx, label2Idx, sentences_maxlen, words_maxlen = prepare_data(train_df)

    val_df = get_val_data()
    print(val_df.shape)

    val_data = embed_sentences(add_char_information_in(tag_data(val_df)), INFOBOX_CLASS, PROPERTY_NAME)

    X_train, Y_train = split_data(train_data)
    X_val, Y_val = split_data(val_data)

    return X_train, Y_train, X_val, Y_val, caseEmbeddings, wordEmbeddings, label2Idx, char2Idx, sentences_maxlen, words_maxlen

def model(X_train, Y_train, X_val, Y_val, caseEmbeddings, wordEmbeddings, label2Idx, char2Idx, sentences_maxlen,
          words_maxlen):
    temp = []
    for item in Y_train[0]:
        flatten = [i for sublist in item for i in sublist]
        for i in flatten:
            temp.append(i)

    temp = np.asarray(temp)
    print('labels', np.unique(np.ravel(temp, order='C')))

    # word-level input
    words_input = Input(shape=(None,), dtype='int32', name='Words_input')
    words = Embedding(input_dim=wordEmbeddings.shape[0], output_dim=wordEmbeddings.shape[1],
                      weights=[wordEmbeddings], trainable=False)(words_input)

    # case-info input
    casing_input = Input(shape=(None,), dtype='int32', name='Casing_input')
    casing = Embedding(input_dim=caseEmbeddings.shape[0], output_dim=caseEmbeddings.shape[1],
                       weights=[caseEmbeddings], trainable=False)(casing_input)

    # character input
    character_input = Input(shape=(None, words_maxlen,), name="Character_input")
    embed_char_out = TimeDistributed(
        Embedding(input_dim=len(char2Idx), output_dim=50,
                  embeddings_initializer=RandomUniform(minval=-0.5, maxval=0.5)),
        name="Character_embedding")(character_input)

    dropout = Dropout(0.5)(embed_char_out)

    # CNN
    conv1d_out = TimeDistributed(
        Conv1D(kernel_size={{choice([3, 5])}}, filters=10,
               padding='same', activation='tanh', strides=1),
        name="Convolution")(dropout)
    maxpool_out = TimeDistributed(MaxPooling1D({{choice([10, 25, 50])}}), name="Maxpool")(conv1d_out)
    char = TimeDistributed(Flatten(), name="Flatten")(maxpool_out)
    char = Dropout(0.5)(char)

    # concat & BLSTM
    output = concatenate([words, casing, char])

    output = Bidirectional(LSTM({{choice([100, 200, 300])}},
                                return_sequences=True,
                                dropout=0.5,  # on input to each LSTM block
                                recurrent_dropout=0.25  # on recurrent input signal
                                ), name="BLSTM")(output)

    output = TimeDistributed(Dense(len(label2Idx), activation='softmax'), name="Softmax_layer")(output)

    # set up model
    model = Model(inputs=[words_input, casing_input, character_input], outputs=[output])

    model.compile(loss='sparse_categorical_crossentropy',
                  optimizer='nadam', metrics=['accuracy'])

    model.summary()

    train_batch, train_batch_len = createBatches2CNN_BLSTM(X_train, Y_train)
    val_batch, val_batch_len = createBatches2CNN_BLSTM(X_val, Y_val)

    model.fit_generator(iterate_minibatches_CNN_BLSTM(train_batch, train_batch_len),
                        steps_per_epoch=len(train_batch),
                        # class_weight=class_weight_vect,
                        epochs=10, verbose=2, validation_steps=len(val_batch),
                        validation_data=iterate_minibatches_CNN_BLSTM(val_batch, val_batch_len))

    # score, acc = model.evaluate(X_val, Y_val, verbose=0)
    score, acc = model.evaluate_generator(generator=iterate_minibatches_CNN_BLSTM(val_batch, val_batch_len), steps=len(val_batch),
                                          verbose=0)
    print('Test accuracy:', acc)
    return {'loss': -acc, 'status': STATUS_OK, 'model': model}

if __name__ == "__main__":

    best_run, best_model = optim.minimize(model=model,
                                          data=data,
                                          algo=tpe.suggest,
                                          max_evals=5,
                                          trials=Trials(),
                                          functions=[createBatches2CNN_BLSTM, iterate_minibatches_CNN_BLSTM])

    plot_model(best_model, to_file='models/' + PROPERTY_NAME + '-CNN_BLSTM_best_model.png', show_shapes=True, show_layer_names=True)
    best_model.save('models/'+INFOBOX_CLASS+'/dl/' + PROPERTY_NAME + '-CNN_BLSTM_best_model.h5')

    print("Best performing model chosen hyper-parameters:")
    print(best_run)

    model = load_model('models/'+INFOBOX_CLASS+'/dl/' + PROPERTY_NAME + '-CNN_BLSTM_best_model.h5')

    test_df = get_test_data()
    print(test_df.shape)

    test_data = embed_sentences(add_char_information_in(tag_data(test_df)), INFOBOX_CLASS, PROPERTY_NAME)

    X_test, Y_test = split_data(test_data)

    temp = []
    for item in Y_test[0]:
        flatten = [i for sublist in item for i in sublist]
        for i in flatten:
            temp.append(i)

    temp = np.asarray(temp)
    print('labels', np.unique(np.ravel(temp, order='C')))

    test_batch, test_batch_len = createBatches2CNN_BLSTM(X_test, Y_test)

    print("Evalutation of best performing model:")
    score, acc = model.evaluate_generator(generator=iterate_minibatches_CNN_BLSTM(test_batch, test_batch_len),
                                          steps=len(test_batch), verbose=0)
    print("acc on test: ", acc)


import numpy as np
import pandas as pd
import config
import sys
import tensorflow as tf

from keras import Sequential
from keras.layers import Dense
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

from service.Preprocess import Preprocess
from service.FeatureEngineer import FeatureEngineer

class TaxiFaresPredictionNYC:

    def __init__(self):
        self.df = None
        self.x = None
        self.y = None
        self.x_train = None
        self.y_test = None
        self.x_test = None
        self.y_train = None
        self.df_prescaled = None
        self.f_engineer = None
        self.model = Sequential()
        self.preprocessObj = Preprocess()

    def feature_engineer(self):
        self.f_engineer = FeatureEngineer(self.df)
        self.f_engineer.create_date_columns()
        self.f_engineer.create_dist_column()
        self.f_engineer.create_airport_dist_features()

    def preprocess(self):
        self.preprocessObj.remove_missing_values()
        self.preprocessObj.remove_fare_amount_outliers()
        self.preprocessObj.replace_passenger_count_outliers()
        self.preprocessObj.remove_lat_long_outliers()
        self.df = self.preprocessObj.get_dataset()

        self.feature_engineer()

        self.df = self.f_engineer.get_dataset()

        self.df_prescaled = self.df.copy()

        self.df = self.preprocessObj.scale()

        self.x = self.df.loc[:, self.df.columns != 'fare_amount']
        self.y = self.df.fare_amount

        self.x_train, self.x_test, self.y_train, self.y_test = train_test_split(self.x, self.y, test_size=0.2)

    def create(self):
        self.model.add(Dense(128, activation='relu', input_dim=self.x_train.shape[1]))
        self.model.add(Dense(64, activation='relu'))
        self.model.add(Dense(32, activation='relu'))
        self.model.add(Dense(8, activation='relu'))
        self.model.add(Dense(1))

    def compile(self):
        self.model.compile(loss='mse', optimizer='adam', metrics=['mse'])
        self.model.fit(self.x_train, self.y_train, epochs=1)

    def predict(self):
        train_predict = self.model.predict(self.x_train)
        train_mrs_error = np.sqrt(mean_squared_error(self.y_train, train_predict))
        print("Train RMSE: {:0.2f}".format(train_mrs_error))

        test_predict = self.model.predict(self.x_test)
        test_mrs_error = np.sqrt(mean_squared_error(self.y_test, test_predict))
        print("Test RMSE: {:0.2f}".format(test_mrs_error))

    def get_dataset(self):
        return self.df


from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, SelectField
from wtforms.validators import InputRequired, Optional

sizes = ['XS','S', 'M', 'L', 'XL']
ratings = [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5,
           6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0]

class AddCupcakeForm(FlaskForm):
    """Form for adding cupcakes"""

    flavor = StringField("Flavor", validators=[InputRequired(message="Flavor cannot be blank")])
    size = SelectField("Size", choices=[(size, size) for size in sizes], validators=[InputRequired(message="Size cannot be blank")])
    rating = SelectField("Rating", coerce=float, choices=[(rating, rating) for rating in ratings], validators=[InputRequired(message="Rating cannot be blank")])
    image = StringField("Image Link", validators=[Optional()])


from random import random
import bisect

def get_new_state(current_state, transitions):
    transition_map = dict()
    for source, target, probability in transitions:
        if source not in transition_map:
            transition_map[source] = ([], [])
        if not transition_map[source][0]:
            transition_map[source][0].append(probability)
        else:
            prev = transition_map[source][0][-1]
            transition_map[source][0].append(probability + prev)
        transition_map[source][1].append(target)
    r = random()
    index = bisect.bisect(transition_map[current_state][0], r)
    print(transition_map)
    return transition_map[current_state][1][index]

def markov(start, transitions):
    current_state = start
    states = dict()
    for t in transitions:
        states[t[0]] = 0
    for i in range(5000):
        states[current_state] += 1
        current_state = get_new_state(current_state, transitions)
    return states

def main():
    visited = (markov('a', [
        ('a', 'a', 0.9),
        ('a', 'b', 0.075),
        ('a', 'c', 0.025),
        ('b', 'a', 0.15),
        ('b', 'b', 0.8),
        ('b', 'c', 0.05),
        ('c', 'a', 0.25),
        ('c', 'b', 0.25),
        ('c', 'c', 0.5)
    ]))
    assert visited['a'] > visited['b']
    assert visited['a'] > visited['c']
    assert visited['b'] > visited['c']

if __name__ == '__main__':
    main()


# Import the utils
import math
import sys
import os
sys.path.append(os.path.abspath('../QUtils'))
from qutils import pprint, graph

# Import the QISKit SDK
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit import execute

# Create a Quantum Register with 2 qubits.
q = QuantumRegister(3)
# Create a Classical Register with 2 bits.
c = ClassicalRegister(3)
# Create a Quantum Circuit
qc = QuantumCircuit(q, c)

# move the qubits into a superpostion such that when they have an H gate and a Measure
# applied they are equally likely to collapse to 0 or 1
qc.h(q)
qc.s(q)

pi = math.pi
# add the gates to get the normal distribution
"""
# makes 111 less likely
qc.crz(-0.3*pi, q[2], q[1])
qc.crz(-0.3*pi, q[1], q[0])

# some how encourages 100
qc.x(q[2])
qc.crz(-0.4*pi, q[0], q[1])
qc.crz(-0.4*pi, q[1], q[2])
qc.crz(-0.4*pi, q[0], q[2])
qc.x(q[2])

"""

# THE 2 QUBIT CIRCUIT
# I don't get why but this bumps up the ends and drops the middle
# aka the exact opposite of what we want
#qc.crz(-0.5*pi, q[1], q[0])
#qc.crz(-0.5*pi, q[0], q[1])

# this then flips it the right way up
#qc.rz(pi, q[0])

# ATTEMPT AT 3 QUBIT CIRCUIT - kinda works?
# ups 011 and 100, but also 000 and 111
qc.crz(-0.5*pi, q[1], q[0])
qc.crz(-0.5*pi, q[0], q[1])
qc.crz(-0.5*pi, q[2], q[1])
qc.rz(pi, q[2])

qc.h(q)
# Add a Measure gate to see the state.
qc.measure(q, c)
# Compile and run the Quantum circuit on a simulator backend
job_sim = execute(qc, "local_qasm_simulator", shots=7000)
sim_result = job_sim.result()

# Show the results
print("simulation: ", sim_result)
# Returns a dict
pprint(sim_result.get_counts(qc))
graph(sim_result.get_counts(qc))