from datetime import datetime
import json
from urllib.request import Request
from rest_framework.decorators import api_view
from bocr.settings import IMG_BB_URL, IMGBB_API_KEY
from django.core.files.uploadedfile import InMemoryUploadedFile
from .models import Recognition as RecognitionModel
from .serializers.recognitionSerializer import RecognizerSerializer, RecognitionSerializer
from rest_framework.status import HTTP_503_SERVICE_UNAVAILABLE
from rest_framework.exceptions import NotFound
from helper.common.decorators import responsify, jwtAuthGuardExcept
from uploads.models import Uploads
from drf_spectacular.utils import extend_schema
from recognition.serializers.paramsSerializer import RecognitionParamsSerializer, RecognitionImageUploadSerializer
from helper.common.requestSerializer import JWTAuthGuard
from uauth.models import User
from rest_framework import serializers
import requests
import base64

@extend_schema(parameters=[RecognitionParamsSerializer],
               methods=['GET'],
               responses={200: RecognitionSerializer},
               tags=['Recognition'])
@extend_schema(
    parameters=[
        JWTAuthGuard(required=False),
    ],
    request=serializers.ListSerializer(child = RecognitionImageUploadSerializer()),
    methods=['PUT'],
    responses={200: serializers.ListSerializer(child=RecognitionSerializer())},
    tags=['Recognition'])
@api_view(["GET", "PUT"])
@jwtAuthGuardExcept
@responsify
def recognition(request: Request, user=None):
    if request.method.lower() == 'put':
        finalResult = []
        images: list[InMemoryUploadedFile] = request.FILES.getlist('images')
        for img in images:
            data = {
                "image": base64.b64encode(img.read()).decode(),
            }
            response = requests.post(IMG_BB_URL,
                                     params={"key": IMGBB_API_KEY},
                                     data=data)
            response = json.loads(response.content)

            if 'status' in response and response[
                    'status'] == 200 and 'success' in response and response[
                        'success'] == True:
                url = response['data']['image']['url']

                result = RecognizerSerializer(data={"uri": url}).getResult()
                result['cAt'] = datetime.now().timestamp()

                recognitionModel = RecognitionModel.objects.filter(uri=url).first()

                recognitionModel.update_or_create(**result)

                if user:
                    userUploadModel = Uploads.objects.create(
                        uid=User.objects.filter(id = user['id']).first(), recid=recognitionModel)
                    userUploadModel.save()

                finalResult.append(result)
            else:
                return {
                    "status_code": HTTP_503_SERVICE_UNAVAILABLE,
                    "message": response['message']
                }
        return finalResult

    else:
        id = request.GET['id']
        recognition: RecognitionModel = RecognitionModel.objects.filter(
            id=id).first()

        if not recognition:
            raise NotFound('Image not found')
        result = RecognizerSerializer(data={"uri": url}).getResult()
        result = RecognitionModel.objects.filter(id=id).update(
            **result).__dict__()
        return result


import pandas as pd
import numpy as np
from pandas_datareader import data as web
import datetime as dt
import yfinance as yf
import matplotlib.pyplot as plt

start = dt.datetime(2016, 1, 2)
end = dt.datetime(2022, 8, 29)

stock_name=input("Enter the stock symbol of your firm: ")
stock_name = stock_name.upper()

stock = web.DataReader(stock_name, 'yahoo', start, end)
SMA50=pd.DataFrame()
SMA50['Adj Close']=stock['Adj Close'].rolling(50).mean()

SMA200=pd.DataFrame()
SMA200['Adj Close']=stock['Adj Close'].rolling(200).mean()

plt.figure(figsize=(15, 5))
plt.plot(stock['Adj Close'], label=stock_name)
plt.plot(SMA50['Adj Close'], label="SMA50")
plt.plot(SMA200['Adj Close'], label="SMA100")
plt.xlabel("Jan 2016- Aug 2022")
plt.ylabel("Adj Close Prices in USD")
plt.legend(loc="upper left")
plt.show()

stock_data = pd.DataFrame()
stock_data['Stock'] = stock['Adj Close']
stock_data['SMA50'] = SMA50['Adj Close']
stock_data['SMA200'] = SMA200['Adj Close']

#function to create signals for buying and selling
def signalStock(data):
    signalBuyPrice=[]
    signalSellPrice=[]
    flag = -1 #if flag is 1, a buy is recently conducted, or if flag is 0, a sell is recently conducted. Use -1 to start

    for i in range(len(data)):
        if data['SMA50'][i]> data['SMA200'][i]: #when short term SMA crosses above long term SMA, BUY
            if flag!=1:
                signalBuyPrice.append(stock_data['Stock'][i])
                signalSellPrice.append(np.nan)
                flag=1
            else:
                signalBuyPrice.append(np.nan)
                signalSellPrice.append(np.nan)
        elif data['SMA50'][i] < data['SMA200'][i]: #when short term SMA crosses above long term SMA, BUY
            if flag!=0:
                signalSellPrice.append(stock_data['Stock'][i])
                signalBuyPrice.append(np.nan)
                flag=0
            else:
                signalBuyPrice.append(np.nan)
                signalSellPrice.append(np.nan)
        else:
            signalBuyPrice.append(np.nan)
            signalSellPrice.append(np.nan)
    return(signalBuyPrice, signalSellPrice)

signal = signalStock(stock_data)

stock_data['Buy_Signal_Price'] = signal[0]
stock_data['Sell_Signal_Price']= signal[1]

plt.figure(figsize=(15,5))
plt.plot(stock_data['Stock'],label = stock_name, alpha = 0.30)
plt.plot(stock_data['SMA50'], label = 'SMA50', alpha = 0.30)
plt.plot(stock_data['SMA200'], label = 'SMA200', alpha = 0.30)
plt.xlabel("Jan 2016 - Aug 2022")
plt.ylabel("Prices in USD")
plt.scatter(stock_data.index,stock_data['Buy_Signal_Price'], label = 'Buy', marker = '^', color = 'green')
plt.scatter(stock_data.index,stock_data['Sell_Signal_Price'], label = 'Sell', marker = 'v', color = 'red')
plt.legend(loc='upper left')
plt.show()
print(stock_data)


import csv
import json
from functools import partial
from typing import Literal, Union

from ..io import universal_write_open

def to_file(
    iterable,
    path,
    delimiter=None,
    mode: Union[Literal["r", "w", "x", "a", "b", "t", "+"], str] = "wt",
    buffering=-1,
    encoding=None,
    errors=None,
    newline=None,
    compresslevel=9,
    format=None,
    check=-1,
    preset=None,
    filters=None,
    compression: Union[None, Literal["gz", "gzip", "lzma", "xz", "bz2"]] = None,
):
    """
    Saves the sequence to a file by executing str(self) which becomes str(self.to_list()). If
    delimiter is defined will instead execute self.make_string(delimiter)
    :param path: path to write file
    :param delimiter: if defined, will call make_string(delimiter) and save that to file.
    :param mode: file open mode
    :param buffering: passed to builtins.open
    :param encoding: passed to builtins.open
    :param errors: passed to builtins.open
    :param newline: passed to builtins.open
    :param compression: compression format
    :param compresslevel: passed to gzip.open
    :param format: passed to lzma.open
    :param check: passed to lzma.open
    :param preset: passed to lzma.open
    :param filters: passed to lzma.open
    """
    with universal_write_open(
        path,
        mode=mode,
        buffering=buffering,
        encoding=encoding,
        errors=errors,
        newline=newline,
        compression=compression,
        compresslevel=compresslevel,
        format=format,
        check=check,
        preset=preset,
        filters=filters,
    ) as output:
        if delimiter:
            output.write(iterable.make_string(delimiter))
        else:
            output.write(str(iterable))

def to_jsonl(
    iterable,
    path,
    mode: Union[Literal["r", "w", "x", "a", "b", "t", "+"], str] = "wb",
    compression: Union[None, Literal["gz", "gzip", "lzma", "xz", "bz2"]] = None,
    ensure_ascii=False,
):
    """
    Saves the sequence to a jsonl file. Each element is mapped using json.dumps then written
    with a newline separating each element.
    :param path: path to write file
    :param mode: mode to write in, defaults to 'w' to overwrite contents
    :param compression: compression format
    :param ensure_ascii: ensure_ascii
    """
    dumps = partial(json.dumps, ensure_ascii=ensure_ascii)
    with universal_write_open(path, mode=mode, compression=compression) as output:
        output.write((iterable.map(dumps).make_string("\n") + "\n").encode("utf-8"))

def to_json(
    iterable,
    path,
    root_array=True,
    mode: Union[Literal["r", "w", "x", "a", "b", "t", "+"], str] = "wt",
    compression: Union[None, Literal["gz", "gzip", "lzma", "xz", "bz2"]] = None,
    ensure_ascii=False,
):
    """
    Saves the sequence to a json file. If root_array is True, then the sequence will be written
    to json with an array at the root. If it is False, then the sequence will be converted from
    a sequence of (Key, Value) pairs to a dictionary so that the json root is a dictionary.
    :param path: path to write file
    :param root_array: write json root as an array or dictionary
    :param mode: file open mode
    """
    with universal_write_open(path, mode=mode, compression=compression) as output:
        if root_array:
            json.dump(list(iterable), output, ensure_ascii=ensure_ascii)
        else:
            json.dump(dict(iterable), output, ensure_ascii=ensure_ascii)

def to_csv(
    iterable,
    path,
    mode: Union[Literal["r", "w", "x", "a", "b", "t", "+"], str] = "wt",
    dialect="excel",
    compression: Union[None, Literal["gz", "gzip", "lzma", "xz", "bz2"]] = None,
    newline="",
    **fmtparams
):
    """
    Saves the sequence to a csv file. Each element should be an iterable which will be expanded
    to the elements of each row.
    :param path: path to write file
    :param mode: file open mode
    :param dialect: passed to csv.writer
    :param fmtparams: passed to csv.writer
    """

    if "b" in mode:
        newline = None

    with universal_write_open(
        path, mode=mode, compression=compression, newline=newline
    ) as output:
        csv_writer = csv.writer(output, dialect=dialect, **fmtparams)
        for row in iterable:
            csv_writer.writerow([str(element) for element in row])


from __future__ import print_function, division
import os, cv2, torch, time
from PIL import Image
import numpy as np
import utils.custom_transforms as tr
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from constants import VIEWS

# KaKR 3rd 데이터셋 전처리
def crop_boxing_img(img_name, TRAIN_IMG_PATH, TEST_IMG_PATH, df_train, df_test, margin=-4, size=(224, 224)):
    # Bbox croping function for KaKR 3rd car classification competition
    if img_name.split('_')[0] == 'train':
        PATH = TRAIN_IMG_PATH
        data = df_train
    else:
        PATH = TEST_IMG_PATH
        data = df_test

    img = Image.open(os.path.join(PATH, img_name))
    pos = data.loc[data["img_file"] == img_name, ['bbox_x1', 'bbox_y1', 'bbox_x2', 'bbox_y2']].values.reshape(-1)

    width, height = img.size
    x1 = max(0, pos[0] - margin)
    y1 = max(0, pos[1] - margin)
    x2 = min(pos[2] + margin, width)
    y2 = min(pos[3] + margin, height)

    return img.crop((x1, y1, x2, y2)).resize(size)

# KaKR 3rd car classification competiton을 위한 custom dataloader
class KaKR3rdDataset(Dataset):
    def __init__(self, args, df, mode, DATA_PATH, transforms = None):
        self.args = args
        self.df = df
        self.mode = mode
        self.data_set_path = DATA_PATH
        self.data, self.labels, self.len_data, self.len_label = self.read_dataset()

        self.len = self.data.shape[0]
        self.x_data = torch.from_numpy(self.data)
        self.y_data = torch.from_numpy(self.labels)

        # 전처리를 위한 transforms 초기화
        self.transforms = transforms

    def __getitem__(self, index):
        # Grayscale 등으로 변환할 경우 이곳에서 작업할것.
        if self.mode == 'train':
            return self.transform_tr(self.x_data)
        elif self.mode == 'val':
            return self.transform_val(self.x_data)
        else:
            print("Invalid params input")
            raise NotImplementedError

    def __len__(self):
        return self.len

    def read_dataset(self):
        t = time.time()
        print('Data loading...')
        data_path = []  # data path 저장을 위한 변수
        labels = []  # 테스트 id 순서 기록
        ## 하위 데이터 path 읽기
        for dir_name, _, _ in os.walk(self.data_set_path):
            try:
                data_id = dir_name.split('/')[-1]
                int(data_id)
            except:
                pass
            else:
                data_path.append(dir_name)
                labels.append(int(data_id[0]))

        ## 데이터만 읽기
        data = []  # img저장을 위한 list
        for d_path in data_path:
            sample = np.load(d_path + '/mammo.npz')['arr_0']
            data.append(sample)
        data = np.array(data)  ## list to numpy

        print('Dataset Reading Success \n Reading time', time.time() - t, 'sec')
        print('Dataset:', data.shape, 'np.array.shape(files, views, width, height)')

        return data, labels, len(data), len(labels)  # Numpy arr과 정답 클래스

    # custom_transforms.py의 전처리 항목을 적용한 transforms.Compose 클래스 반환
    def transform_tr(self, sample):
        composed_transforms = transforms.Compose([
            tr.RandomHorizontalFlip(),
            tr.RandomScaleCrop(base_size=self.args.base_size, crop_size=self.args.crop_size),
            # tr.FixScaleCrop(crop_size=self.args.crop_size),
            tr.RandomGaussianBlur(),
            tr.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
            tr.ToTensor()])

        return composed_transforms(sample)

    def transform_val(self, sample):
        composed_transforms = transforms.Compose([
            tr.FixScaleCrop(crop_size=self.args.crop_size),
            tr.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
            tr.ToTensor()])

        return composed_transforms(sample)

# KHD Mammo dataset을 위한 데이터로더
class MammoDataset(Dataset):
    def __init__(self, args, mode, data, labels, len_data, len_label):
        self.args = args
        self.mode = mode
        self.data, self.labels, self.len_data, self.len_label = data, labels, len_data, len_label
        self.LMLO, self.RMLO, self.LCC, self.RCC = self.preprocessing(self.data)
        # self.LMLO_x_data = torch.from_numpy(self.LMLO)
        # self.RMLO_x_data = torch.from_numpy(self.RMLO)
        # self.LCC_x_data = torch.from_numpy(self.LCC)
        # self.RCC_x_data = torch.from_numpy(self.RCC)
        # self.y_data = torch.from_numpy(self.labels)
        # self.x_data_views = [self.LMLO_x_data, self.RMLO_x_data, self.LCC_x_data, self.RCC_x_data]
        self.x_data_views = [self.LMLO, self.RMLO, self.LCC, self.RCC]
        self.y_data = self.labels

        # 전처리를 위한 transforms 초기화
        self.transforms = transforms

    def __getitem__(self, index):
        if self.mode == 'train':
            return {'image': self.transform_tr(self.x_data_views), 'label': self.y_data}
        elif self.mode == 'val':
            return {'image' : self.transform_val(self.x_data_views), 'label' : self.y_data}
        else:
            print("Invalid params input")
            raise NotImplementedError

    def __len__(self):
        return self.len_data

    # custom_transforms.py의 전처리 항목을 적용한 transforms.Compose 클래스 반환
    def transform_tr(self, sample):
        composed_transforms = transforms.Compose([
            tr.RandomHorizontalFlip(),
            tr.Normalize(mean=(0, 0, 0), std=(1, 1, 1)),
            tr.ToTensor()])

        return composed_transforms(sample)

    def transform_val(self, sample):
        composed_transforms = transforms.Compose([
            tr.FixScaleCrop(crop_size=self.args.crop_size),
            tr.Normalize(mean=(0, 0, 0), std=(1, 1, 1)),
            tr.ToTensor()])

        return composed_transforms(sample)

    def clahe(self, img_arr):
        print("shape of img_arr : ", img_arr.shape) # (1800, 410, 333)
        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        PILim = Image.fromarray(img_arr) # [0,:]
        res = clahe.apply(np.array(PILim))
        return res  # Grayscale

    def postclahe(self, img):
        median_clahe = cv2.medianBlur(img, 5)
        ret, th1 = cv2.threshold(median_clahe, 127, 255, cv2.THRESH_BINARY)
        return th1  # Grayscale

    def flip_image(self, image, view, horizontal_flip):
        """
        If training mode, makes all images face right direction.
        In medical, keeps the original directions unless horizontal_flip is set.
        """
        if horizontal_flip == 'NO':
            if VIEWS.is_right(view):
                image = np.fliplr(image)
        elif horizontal_flip == 'YES':
            if VIEWS.is_left(view):
                image = np.fliplr(image)

        return image

    def preprocessing(self, data):
        print('Preprocessing start')
        # 11/30일 이슈 : 아래 LMLO의 shape를 찍어보면 (410, 333)이 나오나, clahe()로 넘긴 직후 shape를 찍어보면 (1800, 410, 333)이 나오는 버그(미해결)
        LMLO = data[:,0] # (1800, 1, 410, 333) - 범위로 인덱싱하지 않아서 생긴 문제인지 확인할것.
        print('shape of LMLO : ', LMLO.shape)
        LMLO_clahe = self.clahe(LMLO) # (410, 333)
        print('shape of LMLO_clahe : ', LMLO_clahe.shape)
        LMLO_postclahe = self.postclahe(LMLO_clahe) # (410, 333)
        print('shape of LMLO_postclahe : ', LMLO_postclahe.shape)
        final_LMLO = np.array(cv2.merge([LMLO, LMLO_clahe, LMLO_postclahe])).astype(np.float32).transpose((2, 0, 1)) # (3, 410, 333)

        RMLO = data[:,1] # (1800, 1, 410, 333)
        RMLO_clahe = self.clahe(RMLO)
        RMLO_postclahe = self.postclahe(RMLO_clahe)
        final_RMLO = np.array(cv2.merge([RMLO, RMLO_clahe, RMLO_postclahe])).astype(np.float32).transpose((2, 0, 1))  # (3, 410, 333)

        LCC = data[:,2] # (1800, 1, 410, 333)
        LCC_clahe = self.clahe(LCC)
        LCC_postclahe = self.postclahe(LCC_clahe)
        final_LCC = np.array(cv2.merge([LCC, LCC_clahe, LCC_postclahe])).astype(np.float32).transpose((2, 0, 1))  # (3, 410, 333)

        RCC = data[:,3] # (1800, 1, 410, 333)
        RCC_clahe = self.clahe(RCC)
        RCC_postclahe = self.postclahe(RCC_clahe)
        final_RCC = np.array(cv2.merge([RCC, RCC_clahe, RCC_postclahe])).astype(np.float32).transpose((2, 0, 1))  # (3, 410, 333)

        print('Preprocessing complete...')
        return final_LMLO, final_RMLO, final_LCC, final_RCC


import firebase_admin
from firebase_admin import credentials, firestore

cred = credentials.Certificate("locationapp.json")
firebase_admin.initialize_app(cred)
db = firestore.client()

def itemsInStore():
    locs = db.collection("location")
    doc = locs.stream()

    res_location = []

    for i in doc:
        location_dict = i.to_dict()
        resLoc = {'lats': location_dict["latitude"], 'long': location_dict["longitude"],
                  "VehicleID": f'{location_dict["name"]}'}

        res_location.append(resLoc)
    return res_location


def get_stroke_freq(Ax, Az, fs_a, nperseg, peak_thresh, stroke_ratio=None):
    """Determine stroke frequency to use as a cutoff for filtering

    Args
    ----
    Ax: numpy.ndarray, shape (n,)
        x-axis accelermeter data (longitudinal)
    Ay: numpy.ndarray, shape (n,)
        x-axis accelermeter data (lateral)
    Az: numpy.ndarray, shape (n,)
        z-axis accelermeter data (dorso-ventral)
    fs_a: float
        sampling frequency (i.e. number of samples per second)
    nperseg: int
        length of each segment (i.e. number of samples per frq. band in PSD
        calculation. Default to 512 (scipy.signal.welch() default is 256)
    peak_thresh: float
        PSD power level threshold. Only peaks over this threshold are returned.

    Returns
    -------
    cutoff_frq: float
        cutoff frequency of signal (Hz) to be used for low/high-pass filtering
    stroke_frq: float
        frequency of dominant wavelength in signal
    stroke_ratio: float

    Notes
    -----
    During all descents and ascents phases where mainly steady swimming occurs.
    When calculated for the whole dive it may be difficult to differentiate the
    peak at which stroking rate occurs as there are movements than
    only steady swimming

    Here the power spectra is calculated of the longitudinal and dorso-ventral
    accelerometer signals during descents and ascents to determine the dominant
    stroke frequency for each animal in each phase

    This numpy samples per f segment 512 and a sampling rate of fs_a.

    Output: S is the amount of power in each particular frequency (f)
    """

    import numpy

    from . import dsp
    from . import utils
    from .plots import plotdsp

    # Axes to be used for determining `stroke_frq`
    stroke_axes = [(0, "x", "dorsa-ventral", Ax), (2, "z", "lateral", Az)]

    # Lists for appending values from each axis
    cutoff_frqs = list()
    stroke_frqs = list()
    stroke_ratios = list()

    # Iterate over axes in `stroke_axes` list appending output to above lists
    for i, i_alph, name, data in stroke_axes:

        frqs, S, _, _ = dsp.calc_PSD_welch(data, fs_a, nperseg)

        # Find index positions of local maxima and minima in PSD
        delta = S.max() / 1000
        max_ind, min_ind = dsp.simple_peakfinder(range(len(S)), S, delta)

        max0 = max_ind[0]

        # TODO hack fix, improve later
        try:
            min_ind[0]
        except Exception:
            stroke_ratio = 0.4

        stroke_frq = frqs[max0]

        # Prompt user for `cutoff_frq` value after inspecting PSD plot
        title = "PSD - {} axis (n={}), {}".format(i_alph, i, name)
        # Plot power spectrum against frequency distribution
        plotdsp.plot_welch_peaks(frqs, S, max_ind, title=title)

        # Get user input of cutoff frequency identified off plots
        cutoff_frq = utils.recursive_input("cutoff frequency", float)

        # Append values for axis to list
        cutoff_frqs.append(cutoff_frq)
        stroke_frqs.append(stroke_frq)
        stroke_ratios.append(stroke_ratio)

    # Average values for all axes
    cutoff_frq = float(numpy.mean(cutoff_frqs))
    stroke_frq = float(numpy.mean(stroke_frqs))

    # Handle exception of manual selection when `stroke_ratio == None`
    # TODO with fix
    try:
        stroke_ratio = float(numpy.mean(stroke_ratios))
    except Exception:
        stroke_ratio = None

    return cutoff_frq, stroke_frq, stroke_ratio

def get_stroke_glide_indices(A_g_hf, fs_a, J, t_max):
    """Get stroke and glide indices from high-pass accelerometer data

    Args
    ----
    A_g_hf: 1-D ndarray
        Animal frame triaxial accelerometer matrix at sampling rate fs_a.

    fs_a: int
        Number of accelerometer samples per second

    J: float
        Frequency threshold for detecting a fluke stroke in m/s^2.  If J is not
        given, fluke strokes will not be located but the rotations signal (pry)
        will be computed.

    t_max: int
        Maximum duration allowable for a fluke stroke in seconds.  A fluke
        stroke is counted whenever there is a cyclic variation in the pitch
        deviation with peak-to-peak magnitude greater than +/-J and consistent
        with a fluke stroke duration of less than t_max seconds, e.g., for
        Mesoplodon choose t_max=4.

    Returns
    -------
    GL: 1-D ndarray
        Matrix containing the start time (first column) and end time (2nd
        column) of any glides (i.e., no zero crossings in t_max or more
        seconds). Times are in seconds.

    Note
    ----
    If no J or t_max is given, J=[], or t_max=[], GL returned as None
    """
    import numpy

    from . import dsp

    # Check if input array is 1-D
    if A_g_hf.ndim > 1:
        raise IndexError(
            "A_g_hf multidimensional: Glide index determination "
            "requires 1-D acceleration array as input"
        )

    # Convert t_max to number of samples
    n_max = t_max * fs_a

    # Find zero-crossing start/stops in pry(:,n), rotations around n axis.
    zc = dsp.findzc(A_g_hf, J, n_max / 2)

    # find glides - any interval between zeros crossings greater than `t_max`
    ind = numpy.where(zc[1:, 0] - zc[0:-1, 1] > n_max)[0]
    gl_ind = numpy.vstack([zc[ind, 0] - 1, zc[ind + 1, 1] + 1]).T

    # Compute mean index position of glide, Only include sections with jerk < J
    gl_mean_idx = numpy.round(numpy.mean(gl_ind, 1)).astype(int)
    gl_ind = numpy.round(gl_ind).astype(int)

    for i in range(len(gl_mean_idx)):
        col = range(gl_mean_idx[i], gl_ind[i, 0], -1)
        test = numpy.where(numpy.isnan(A_g_hf[col]))[0]
        if test.size != 0:
            gl_mean_idx[i] = numpy.nan
            gl_ind[i, 0] = numpy.nan
            gl_ind[i, 1] = numpy.nan
        else:
            over_J1 = numpy.where(abs(A_g_hf[col]) >= J)[0][0]

            gl_ind[i, 0] = gl_mean_idx[i] - over_J1 + 1

            col = range(gl_mean_idx[i], gl_ind[i, 1])

            over_J2 = numpy.where(abs(A_g_hf[col]) >= J)[0][0]

            gl_ind[i, 1] = gl_mean_idx[i] + over_J2 - 1

    GL = gl_ind
    GL = GL[numpy.where(GL[:, 1] - GL[:, 0] > n_max / 2)[0], :]

    return GL

def split_glides(n_samples, dur, fs_a, GL, min_dur=None):
    """Get start/stop indices of each `dur` length sub-glide for glides in GL

    Args
    ----
    dur: int
        Desired duration of glides
    GL: ndarray, (n, 2)
        Matrix containing the start time (first column) and end time
        (2nd column) of any glides.Times are in seconds.
    min_dur: int, default (bool False)
        Minimum number of seconds for sub-glide. Default value is `False`, which
        makes `min_dur` equal to `dur`, ignoring sub-glides smaller than `dur`.

    Attributes
    ----------
    gl_ind_diff: ndarray, (n,3)
        GL, with additional column of difference between the first two columns

    Returns
    -------
    SGL: ndarray, (n, 2)
        Matrix containing the start time (first column) and end time (2nd
        column) of the generated sub-glides. All glides must have duration equal
        to the given dur value.Times are in seconds.
    """
    import numpy

    # Convert `dur` in seconds to duration in number of samples `ndur`
    ndur = dur * fs_a

    # If minimum duration not passed, set to `min_dur` to skip slices < `dur`
    if not min_dur:
        min_ndur = dur * fs_a
    else:
        min_ndur = min_dur * fs_a

    # `GL` plus column for total duration of glide, seconds
    gl_ind_diff = numpy.vstack((GL.T, GL[:, 1] - GL[:, 0])).T

    # Split all glides in `GL`
    SGL_started = False
    for i in range(len(GL)):
        gl_ndur = gl_ind_diff[i, 2]

        # Split into sub glides if longer than duration
        if abs(gl_ndur) > ndur:

            # Make list of index lengths to start of each sub-glide
            n_sgl = int(gl_ndur // ndur)
            sgl_ndur = numpy.ones(n_sgl) * ndur
            sgl_start = numpy.arange(n_sgl) * (ndur + 1)

            # Add remainder as a sub-glide, skips if `min_ndur` not passed
            if gl_ndur % ndur > min_ndur:
                last_ndur = numpy.floor(gl_ndur % ndur)
                sgl_ndur = numpy.hstack([sgl_ndur, last_ndur])

                last_start = (len(sgl_start) * ndur) + ndur
                sgl_start = numpy.hstack([sgl_start, last_start])

            # Get start and end index positions for each sub-glide
            for k in range(len(sgl_start)):

                # starting at original glide start...
                # sgl_start_ind: add index increments of ndur+1 for next start idx
                next_start_ind = (gl_ind_diff[i, 0] + sgl_start[k]).astype(int)

                # end_glide: add `ndur` to that to get ending idx
                next_end_ind = (next_start_ind + sgl_ndur[k]).astype(int)

                # If first iteration, set equal to first set of indices
                if SGL_started is False:
                    sgl_start_ind = next_start_ind
                    sgl_end_ind = next_end_ind
                    SGL_started = True
                else:
                    # Concatenate 1D arrays together, shape (n,)
                    sgl_start_ind = numpy.hstack((sgl_start_ind, next_start_ind))
                    sgl_end_ind = numpy.hstack((sgl_end_ind, next_end_ind))

    # Stack and transpose indices into shape (n, 2)
    SGL = numpy.vstack((sgl_start_ind, sgl_end_ind)).T

    # Filter out sub-glides that fall outside of sensor data indices
    SGL = SGL[(SGL[:, 0] >= 0) & (SGL[:, 1] < n_samples)]

    # check that all sub-glides have a duration of `ndur` seconds
    sgl_ndur = SGL[:, 1] - SGL[:, 0]

    # If sub-glide `min_ndur` set, make sure all above `min_ndur`, below `ndur`
    if min_dur:
        assert numpy.all((sgl_ndur <= ndur) & (sgl_ndur >= min_ndur))
    # Else make sure all sample number durations equal to `ndur`
    else:
        assert numpy.all(sgl_ndur == ndur)

    # Create `data_sgl_mask`
    data_sgl_mask = numpy.zeros(n_samples, dtype=bool)
    for start, stop in SGL.astype(int):
        data_sgl_mask[start:stop] = True

    return SGL, data_sgl_mask

def calc_glide_des_asc(
    depths,
    pitch_lf,
    roll_lf,
    heading_lf,
    swim_speed,
    dives,
    SGL,
    pitch_lf_deg,
    temperature,
    Dsw,
):
    """Calculate glide ascent and descent summary data

    Args
    ----
    SGL: numpy.ndarray, shape (n,2)
        start and end index positions for sub-glides

    Returns
    -------
    sgls: pandas.DataFrame
        Sub-glide summary information defined by `SGL` start/stop indices

        *Columns*:

        * dive_phase
        * dive_id
        * dive_min_depth
        * dive_max_depth
        * dive_duration
        * start_idx
        * stop_idx
        * duration
        * mean_depth
        * total_depth_change
        * abs_depth_change
        * mean_speed
        * total_speed_change
        * mean_pitch
        * mean_sin_pitch
        * SD_pitch
        * mean_temp
        * mean_swdensity
        * mean_a
        * R2_speed_vs_time
        * SE_speed_vs_time
        * mean_pitch_circ
        * pitch_concentration
        * mean_roll_circ
        * roll_concentration
        * mean_heading_circ
        * heading_concentration

    """
    import scipy.stats
    import numpy
    import pandas

    keys = [
        "dive_phase",
        "dive_id",
        "dive_min_depth",
        "dive_max_depth",
        "dive_duration",
        "start_idx",
        "stop_idx",
        "duration",
        "mean_depth",
        "total_depth_change",
        "abs_depth_change",
        "mean_speed",
        "total_speed_change",
        "mean_pitch",
        "mean_sin_pitch",
        "SD_pitch",
        "mean_temp",
        "mean_swdensity",
        "mean_a",
        "R2_speed_vs_time",
        "SE_speed_vs_time",
        "mean_pitch_circ",
        "pitch_concentration",
        "mean_roll_circ",
        "roll_concentration",
        "mean_heading_circ",
        "heading_concentration",
    ]

    # Create empty pandas dataframe for summary values
    sgls = pandas.DataFrame(index=range(len(SGL)), columns=keys)

    for i in range(len(SGL)):
        start_idx = SGL[i, 0]
        stop_idx = SGL[i, 1]

        # sub-glide start point in seconds
        sgls["start_idx"][i] = start_idx

        # sub-glide end point in seconds
        sgls["stop_idx"][i] = stop_idx

        # sub-glide duration
        sgls["duration"][i] = SGL[i, 1] - SGL[i, 0]

        # mean depth(m)during sub-glide
        sgls["mean_depth"][i] = numpy.mean(depths[start_idx:stop_idx])

        # total depth(m)change during sub-glide
        sgl_depth_diffs = numpy.diff(depths[start_idx:stop_idx])
        sgls["total_depth_change"][i] = numpy.sum(abs(sgl_depth_diffs))

        # depth(m)change from start to end of sub-glide
        sgls["abs_depth_change"][i] = abs(depths[start_idx] - depths[stop_idx])

        # mean swim speed during the sub-glide, only given if pitch>30 degrees
        sgls["mean_speed"][i] = numpy.nanmean(swim_speed[start_idx:stop_idx])

        # total speed change during sub-glide
        sgl_speed_diffs = numpy.diff(swim_speed[start_idx:stop_idx])
        sgls["total_speed_change"][i] = numpy.nansum(abs(sgl_speed_diffs))

        # mean pitch during the sub-glide
        sgls["mean_pitch"][i] = numpy.mean(pitch_lf_deg[start_idx:stop_idx])

        # mean sin pitch during the sub-glide
        sin_pitch = numpy.sin(numpy.mean(pitch_lf_deg[start_idx:stop_idx]))
        sgls["mean_sin_pitch"][i] = sin_pitch

        # SD of pitch during the sub-glide
        # TODO just use original radian array, not deg
        #      make sure "original" is radians ;)
        sd_pitch = numpy.std(pitch_lf_deg[start_idx:stop_idx]) * 180 / numpy.pi
        sgls["SD_pitch"][i] = sd_pitch

        # mean temperature during the sub-glide
        sgls["mean_temp"][i] = numpy.mean(temperature[start_idx:stop_idx])

        # mean seawater density (kg/m^3) during the sub-glide
        sgls["mean_swdensity"][i] = numpy.mean(Dsw[start_idx:stop_idx])

        try:
            # Perform linear regression on sub-glide data subset
            xpoly = numpy.arange(start_idx, stop_idx).astype(int)
            ypoly = swim_speed[start_idx:stop_idx]

            # slope, intercept, r-value, p-value, standard error
            m, c, r, p, std_err = scipy.stats.linregress(xpoly, ypoly)

            # mean acceleration during the sub-glide
            sgls["mean_a"][i] = m

            # R2-value for the regression swim speed vs. time during the
            # sub-glide
            sgls["R2_speed_vs_time"][i] = r ** 2

            # SE of the gradient for the regression swim speed vs. time during
            # the sub-glide
            sgls["SE_speed_vs_time"][i] = std_err

        except Exception:
            # mean acceleration during the sub-glide
            sgls["mean_a"][i] = numpy.nan

            # R2-value for the regression swim speed vs. time during the
            # sub-glide
            sgls["R2_speed_vs_time"][i] = numpy.nan

            # SE of the gradient for the regression swim speed vs. time during
            # the sub-glide
            sgls["SE_speed_vs_time"][i] = numpy.nan

        # TODO this does not take into account the positive depths, flipping
        # descents to ascents
        sgl_signs = numpy.sign(sgl_depth_diffs)
        if all(sgl_signs == -1):
            sgls["dive_phase"][i] = "descent"
        elif all(sgl_signs == 1):
            sgls["dive_phase"][i] = "ascent"
        elif any(sgl_signs == -1) & any(sgl_signs == 1):
            sgls["dive_phase"][i] = "mixed"

        # Get indices of dive in which glide occurred
        dive_ind = numpy.where(
            (dives["start_idx"] < start_idx) & (dives["stop_idx"] > stop_idx)
        )[0]

        # TODO Hack way of pulling the information from first column of dives
        if dive_ind.size == 0:
            dive_inf = pandas.DataFrame.copy(dives.iloc[0])
            dive_inf[:] = numpy.nan
        else:
            dive_inf = dives.iloc[dive_ind].iloc[0]

        # Dive number in which the sub-glide recorded
        sgls["dive_id"][i] = dive_inf["dive_id"]

        # Minimum dive depth (m) of the dive
        sgls["dive_min_depth"][i] = dive_inf["depth_min"]

        # Maximum dive depth (m) of the dive
        sgls["dive_max_depth"][i] = dive_inf["depth_max"]

        # Dive duration (s) of the dive
        sgls["dive_duration"][i] = dive_inf["dive_dur"]

        # Mean pitch(deg) calculated using circular statistics
        pitch_circmean = scipy.stats.circmean(pitch_lf[start_idx:stop_idx])
        sgls["mean_pitch_circ"][i] = pitch_circmean

        # Measure of concentration (r) of pitch during the sub-glide (i.e. 0
        # for random direction, 1 for unidirectional)
        pitch_circvar = scipy.stats.circvar(pitch_lf[start_idx:stop_idx])
        sgls["pitch_concentration"][i] = 1 - pitch_circvar

        # Mean roll (deg) calculated using circular statistics
        roll_circmean = scipy.stats.circmean(roll_lf[start_idx:stop_idx])
        sgls["mean_roll_circ"][i] = roll_circmean

        # Measure of concentration (r) of roll during the sub-glide
        roll_circvar = scipy.stats.circvar(roll_lf[start_idx:stop_idx])
        sgls["roll_concentration"][i] = 1 - roll_circvar

        # Mean heading (deg) calculated using circular statistics
        heading_circmean = scipy.stats.circmean(heading_lf[start_idx:stop_idx])
        sgls["mean_heading_circ"][i] = heading_circmean

        # Measure of concentration (r) of heading during the sub-glide
        heading_circvar = scipy.stats.circvar(heading_lf[start_idx:stop_idx])
        sgls["heading_concentration"][i] = 1 - heading_circvar

    return sgls

def calc_glide_ratios(dives, des, asc, glide_mask, depths, pitch_lf):
    """Calculate summary information on glides during dive ascent/descents

    Args
    ----
    dives: (n,10)
        Numpy record array with summary information of dives in sensor data
    des: ndarray
        Boolean mask of descents over sensor data
    asc: ndarray
        Boolean mask of descents over sensor data
    glid_mask: ndarray
        Boolean mask of glides over sensor data
    depths: ndarray
        Depth values at each sensor sampling
    pitch_lf: ndarray
        Pitch in radians over the low frequency signals of acceleration

    Returns
    -------
    gl_ratio: pandas.DataFrame
        Dataframe of summary information of glides during dive descent/ascents

        *Columns*:

        * des_duration
        * des_gl_duration
        * des_gl_ratio
        * des_mean_pitch
        * des_rate
        * asc_duration
        * asc_gl_duration
        * asc_gl_ratio
        * asc_mean_pitch
        * asc_rate
    """
    import numpy
    import pandas

    # Create empty `pandas.DataFrame` for storing data, init with `nan`s
    cols = [
        "des_duration",
        "des_gl_duration",
        "des_gl_ratio",
        "des_mean_pitch",
        "des_rate",
        "asc_duration",
        "asc_gl_duration",
        "asc_gl_ratio",
        "asc_mean_pitch",
        "asc_rate",
    ]

    gl_ratio = pandas.DataFrame(index=range(len(dives)), columns=cols)

    # For each dive with start/stop indices in `dives`
    for i in range(len(dives)):
        # Get indices for descent and ascent phase of dive `i`
        start_idx = dives["start_idx"][i]
        stop_idx = dives["stop_idx"][i]
        des_ind = numpy.where(des[start_idx:stop_idx])[0]
        asc_ind = numpy.where(asc[start_idx:stop_idx])[0]

        # DESCENT
        # total duration of the descent phase (s)
        gl_ratio["des_duration"][i] = len(des_ind)

        # total glide duration during the descent phase (s)
        des_glides = numpy.where(glide_mask[des_ind])[0]
        gl_ratio["des_gl_duration"][i] = len(des_glides)

        if len(des_ind) == 0:
            gl_ratio["des_gl_ratio"][i] = 0
            gl_ratio["des_rate"][i] = 0
        else:
            # glide ratio during the descent phase
            des_gl_ratio = gl_ratio["des_gl_duration"][i] / len(des_ind)
            gl_ratio["des_gl_ratio"][i] = des_gl_ratio

            # descent rate (m/sample)
            max_depth_des = depths[des_ind].max()
            gl_ratio["des_rate"][i] = max_depth_des / len(des_ind)

        # mean pitch during the descent phase(degrees)
        des_mean_pitch = numpy.mean(numpy.rad2deg(pitch_lf[des_ind]))
        gl_ratio["des_mean_pitch"][i] = des_mean_pitch

        # ASCENT
        # total duration of the ascent phase (s)
        gl_ratio["asc_duration"][i] = len(asc_ind)

        # total glide duration during the ascent phase (s)
        asc_glides = numpy.where(glide_mask[asc_ind])[0]
        gl_ratio["asc_gl_duration"][i] = len(asc_glides)

        if len(asc_ind) == 0:
            gl_ratio["asc_gl_ratio"][i] = 0
            gl_ratio["asc_rate"][i] = 0
        else:
            # glide ratio during the ascent phase
            asc_gl_ratio = gl_ratio["asc_gl_duration"][i] / len(asc_ind)
            gl_ratio["asc_gl_ratio"][i] = asc_gl_ratio

            # ascent rate (m/sample)
            max_depth_asc = depths[asc_ind].max()
            gl_ratio["asc_rate"][i] = max_depth_asc / len(asc_ind)

        # mean pitch during the ascent phase(degrees)
        asc_mean_pitch = numpy.mean(numpy.rad2deg(pitch_lf[asc_ind]))
        gl_ratio["asc_mean_pitch"][i] = asc_mean_pitch

    return gl_ratio


import pygame
from pygame import Rect
import os
from sprite_sheets import crea_llista_imatges
from conf import mides_pantalla

ll_im_Door_U1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_U.png")), 4)
ll_im_Door_D1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_D.png")), 4)
ll_im_Door_R1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_R.png")), 4)
ll_im_Door_L1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_L.png")), 4)

ll_im_Enter_door_U1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes",'Enter_door_U.png')),10)
ll_im_Enter_door_D1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Enter_door_D.png")), 10)

ll_im_Exit_door_U1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Exit_door_U.png")), 9)
ll_im_Exit_door_D1 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Exit_door_D.png")), 9)

ll_im_Door_U2 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_U_2.png")), 4)
ll_im_Door_D2 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_D_2.png")), 4)
ll_im_Door_R2 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_R_2.png")), 4)
ll_im_Door_L2 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Door_L_2.png")), 4)

ll_im_Enter_door_U2 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes",'Enter_door_U_2.png')),10)
ll_im_Enter_door_D2 = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Enter_door_D_2.png")), 10)

ll_ascensor = crea_llista_imatges(pygame.image.load(os.path.join("imatges","portes","Elevator.png")), 4)

ll_im_Door_D1.reverse()
ll_im_Door_D2.reverse()
ll_im_Door_R1.reverse()
ll_im_Door_R2.reverse()
ll_im_Enter_door_D1.reverse()
ll_im_Enter_door_D2.reverse()
ll_im_Exit_door_D1.reverse()

ll_orient = ['U', 'R', 'D', 'L']
d_portes1 = {'Door':{'U':ll_im_Door_U1,'D':ll_im_Door_D1,'R':ll_im_Door_R1,'L':ll_im_Door_L1},\
            'Enter':{'U':ll_im_Enter_door_U1,'D':ll_im_Enter_door_D1},\
            'Exit':{'D':ll_im_Exit_door_D1,'U':ll_im_Exit_door_U1}}
d_portes2 = {'Door':{'U':ll_im_Door_U2,'D':ll_im_Door_D2,'R':ll_im_Door_R2,'L':ll_im_Door_L2},\
            'Enter':{'U':ll_im_Enter_door_U2,'D':ll_im_Enter_door_D2},\
            'Exit':{}}
class Porta(pygame.sprite.Sprite):
    '''
    Tipus Door = canvi de sala
    Tipus Exit = sortida exterior
    tipus Enter = entrada interior
    tipus Elevator = ascensor
    estats = [tancada, oberta, animacio]

    '''
    def __init__(self, orientacio, tipus, lvl, topleft=0, panel=0):
        super().__init__()
        if tipus == 'ascensor':
            # Animacio
            self.fps = 500
            self.llista_im = ll_ascensor
            self.image = self.llista_im[0]
            self.rect = topleft

        else:
            # Asignacio d'imatges segons tipus
            if lvl == 1:
                try:
                    self.llista_im = d_portes1[tipus][orientacio]
                except KeyError:
                    raise ValueError('Falta posar al diccionari del modul portas la llista amb els frames de la porta')
            elif lvl == 2:
                try:
                    self.llista_im = d_portes2[tipus][orientacio]
                except KeyError:
                    raise ValueError('Falta posar al diccionari del modul portas la llista amb els frames de la porta')
            # Animacio
            if tipus == 'Door':
                self.fps = 100
            elif tipus == 'Enter' or tipus == 'Exit':
                self.fps = 50
            # Atributs rects
            self.image = self.llista_im[0]
            self.rect = self.image.get_rect()
            self.rect.topleft = topleft #per a la sala principal = (75+6*70,0)
        self.tipus = tipus
        self.estat = 'tancada'
        self.orientacio = orientacio
        # Imatge (la image esta amb el rect)
        self.count = 0
        # Atributs de temps
        self.t_animacio = pygame.time.get_ticks()

    def update(self):
        delta = pygame.time.get_ticks() - self.t_animacio
        if self.count == len(self.llista_im)-1:
            self.image = self.llista_im[len(self.llista_im)-1]
        elif delta >= self.fps:
            self.t_animacio = pygame.time.get_ticks()
            self.count = self.count + 1
            self.image = self.llista_im[self.count]

class Mando_de_control(pygame.sprite.Sprite):
    def __init__(self, porta):
        super().__init__()
        self.porta = porta
        self.rect = Rect(porta.rect.right+1, porta.rect.top, porta.rect.width, porta.rect.height)


from tabulate import tabulate
import math
import numpy as np

class Printer:
    @staticmethod
    # Печать матрицы
    def printMatrix(A):
       for i in range (len(A)):
          for j in range ( len(A[i]) ):
              print ( "{:4f}".format(A[i][j]), end = " " )
          print ()

    @staticmethod
    # Печать таблицы решения на "крупной" сетке 6х6
    def print_grid(U, N, M):
        table = []
        header = ['x/t']
        h = 1 / N
        tau = 0.1 / M
        hx = math.ceil(N / 5)
        ht = math.ceil(M / 5)
        Us = np.zeros((6, 6))
        for i in range(6):
            for k in range(6):
                Us[i][k] = U[i * hx, k * ht]

        for k in range(6):
            header.append(k * ht * tau)

        for i in range(6):
            line = []
            line.append(i * hx * h)
            for k in range(6):
                line.append(Us[i][k])
            table.append(line)
        print(tabulate(table, headers=header, tablefmt="pipe"))


r"""This module contains functionality related to ``curl`` commands.

It provides methods for creating/executing ``curl`` commands which mimic
the ``requests`` signatures.

This module has been mainly designed to be used in the ``Api`` module for
logging purposes.

The ``curl`` module could be also used as stand alone:

Example:

>>> import xyzspaces.curl as curl
>>> command = curl.get(url='https://xkcd.com/552/info.0.json')
['curl', '--request', 'GET', 'https://xkcd.com/552/info.0.json']
>>> curl.execute(command)
b'{"month": "3", "num": 552, "link": "", "year": "2009", "news": "", "safe_title": "Correlation", "transcript": "[[A man is talking to a woman]]\\nMan: I used to think correlation implied causation.\\nMan: Then I took a statistics class.  Now I don\'t.\\nWoman: Sounds like the class helped.\\nMan: Well, maybe.\\n{{Title text: Correlation doesn\'t imply causation, but it does waggle its eyebrows suggestively and gesture furtively while mouthing \'look over there\'.}}", "alt": "Correlation doesn\'t imply causation, but it does waggle its eyebrows suggestively and gesture furtively while mouthing \'look over there\'.", "img": "https://imgs.xkcd.com/comics/correlation.png", "title": "Correlation", "day": "6"}'  # noqa: E501
[...]
"""

import subprocess as sp
from json import dumps as json_dumps
from typing import List, Mapping, Optional
from urllib.parse import urlencode

from requests.models import Response

def get(url, params=None, **kwargs) -> List[str]:
    """Run ``curl`` ``GET`` mimicking the ``requests.get()`` signature.

    This completes a ``curl`` ``GET`` command.

    :param url: The URL of the server including the path.
    :param params: The query string params.
    :param kwargs: Further keyword arguments that should match those expected
        by :mod:`requests`.
    :return: The ``List[str]`` representation of the ``curl`` ``GET`` command.

    Example:

    >>> import xyzspaces.curl as curl
    >>> curl.get(url="https://xkcd.com/552/info.0.json")
    ['curl', '--request', 'GET', 'ttps://xkcd.com/552/info.0.json']
    """
    return command(url, "get", params, **kwargs)

def put(url, data=None, **kwargs) -> List[str]:
    """Run ``curl`` ``PUT`` command mimicking the ``requests.put()`` signature.

    This completes a ``curl`` ``PUT`` command.

    :param url: The URL of the server including the path for the new object.
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like object.
    :param kwargs: Further keyword arguments that should match those expected
        by :mod:`requests`.
    :return: The ``List[str]`` representation of the ``curl`` ``PUT`` command.
    """
    return command(url, "put", data=data, **kwargs)

def patch(url, data=None, **kwargs) -> List[str]:
    """Run ``curl`` ``PATCH`` command mimicking the ``requests.patch()`` signature.

    This completes a ``curl`` ``PATCH`` command.

    :param url: The URL of the server including the path for the new object.
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like object.
    :param kwargs: Further keyword arguments that should match those expected
        by :mod:`requests`.
    :return: The ``List[str]`` representation of the ``curl`` ``PATCH`` command.
    """
    return command(url, "patch", data=data, **kwargs)

def post(url, data=None, json=None, **kwargs) -> List[str]:
    """Run ``curl`` ``POST`` command mimicking the ``requests.post()`` signature.

    This completes a ``curl`` ``POST`` command.

    :param url: The URL of the server including the path for the new object.
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like object.
    :param json: (optional) json data.
    :param kwargs: Further keyword arguments that should match those expected
        by :mod:`requests`.
    :return: The ``List[str]`` representation of the ``curl`` ``POST`` command.
    """
    return command(url, "post", data=data, json=json, **kwargs)

def delete(url, **kwargs) -> List[str]:
    """Run ``curl`` ``DELETE`` command mimicking the ``requests.delete()`` signature.

    This completes a ``curl`` ``DELETE`` command.

    :param url: The URL of the server including the path.
    :param kwargs: Further keyword arguments that should match those expected
        by :mod:`requests`.
    :return: The ``List[str]`` representation of the ``curl`` ``DELETE`` command.
    """
    return command(url, "delete", **kwargs)

def command(
    url: str,
    method: str,
    params: Optional[dict] = None,
    **kwargs: Optional[Mapping],
) -> List[str]:
    """Return a ``curl`` command equivalent from the params for :mod:`requests`.

    This builds and returns a list of strings representing a ``curl`` command
    that can be directly passed to functions like
    :func:`subprocess.check_output`. When joined with blanks into a single
    string it can also be used for logging or pasting to a terminal.

    To be used like :func:`requests.get`, passing the same params
    for headers, cookies, etc. So the function signature is similar to
    :func:`requests.get`, with additional ``method`` parameter.

    :param url: The URL of the server including the path.
    :param method: The HTTP method name, e.g. "GET", "PUT", etc.
    :param params: The query string params.
    :param kwargs: Further keyword arguments that should match those expected
        by :mod:`requests`.
    :return: The generated ``curl`` command (a list of strings).

    Example:

    >>> import xyzspaces.curl as curl
    >>> curl.command(method="get", url="https://xkcd.com/552/info.0.json")
    ['curl', '--request', 'GET', 'https://xkcd.com/552/info.0.json']
    """
    command = ["curl", "--request", method.upper()]

    if params:
        url += "?" + urlencode(params)

    command += [url]

    cookies = kwargs.get("cookies")
    if cookies:
        command += ' --cookie "%s"' % ";".join(f"{k}={v}" for k, v in cookies.items())

    headers = kwargs.get("headers")
    if headers:
        for k, v in headers.items():
            command += ["--header", f"{k}: {v}"]

    json = kwargs.get("json")
    if json:
        if headers and "Content-Type" not in headers:
            command += ["--header", "Content-Type: application/json"]
        command += ["--data", json_dumps(json)]

    data = kwargs.get("data")
    if data:
        if headers and "Content-Type" not in headers:
            command += [
                "--header",
                "Content-Type: application/x-www-form-urlencoded",
            ]
        command += ["--data", "&".join(f"{k}={v}" for k, v in data.items())]

    proxies = kwargs.get("proxies")
    if proxies:
        for _, v in proxies.items():
            command += ["--proxy", v]

    return command

def execute(command: List[str]) -> Response:
    r"""Execute a ``command`` and create the ``requests.models.Response`` object.

    The Python's ``subprocess`` module will be used for the executing a ``command``.

    In the ``requests.models.Response`` object will be initialized following attributes:
    _content: The response data from the ``stdout``
    status_code: Simplified conversion from the ``subprocess.CompletedProcess.returncode``
    to ``HTTP`` ones 200 ~ 0, 500 ~ >0.

    :param command: The ``curl`` to be executed in the ``List[str]`` type.
    :return: The generated ``requests.models.Response`` object.

    Example:

    >>> import xyzspaces.curl as curl
    >>> command = curl.get(url='https://xkcd.com/552/info.0.json')
    ['curl', '--request', 'GET', 'ttps://xkcd.com/552/info.0.json']
    >>> curl.execute(command)
    b'{"month": "3", "num": 552, "link": "", "year": "2009", "news": "", "safe_title": "Correlation", "transcript": "[[A man is talking to a woman]]\\nMan: I used to think correlation implied causation.\\nMan: Then I took a statistics class.  Now I don\'t.\\nWoman: Sounds like the class helped.\\nMan: Well, maybe.\\n{{Title text: Correlation doesn\'t imply causation, but it does waggle its eyebrows suggestively and gesture furtively while mouthing \'look over there\'.}}", "alt": "Correlation doesn\'t imply causation, but it does waggle its eyebrows suggestively and gesture furtively while mouthing \'look over there\'.", "img": "https://imgs.xkcd.com/comics/correlation.png", "title": "Correlation", "day": "6"}'  # noqa: E501
    [...]
    """
    CurlResponse = type(
        "CurlResponse",
        (Response,),
        {"setcontent": lambda self, content: setattr(self, "_content", content)},
    )
    response = CurlResponse()
    try:
        cp = sp.run(
            command,
            stdin=sp.PIPE,
            stdout=sp.PIPE,
            stderr=sp.PIPE,
            close_fds=True,
        )
        response.status_code = 200 if cp.returncode == 0 else 500
        response.setcontent(cp.stdout)
    except:  # noqa: E722
        response.status_code = 500

    return response


import json

json_file = open('Task.json').read()
data = json.loads(json_file)

def clean_data():
    id_list = []
    name_list = []
    age_list = []
    member_list = []
    people_surname_list = []
    familiy_surname_list = []
    parents_list = []
    has_kids_list = []
    temp_kids_list = []
    kids_list = []
    kids_num_list = []
    temp_list = []
    for people in data['people']:
        for info in people:
            names = people[info]['name']
            surnames = people[info]['surname']
            age = people[info]['age']
            member = people[info]['family_member']
            name_list.append(names)
            age_list.append(age)
            member_list.append(member)
            people_surname_list.append(surnames)
    for family in data['families']:
        for info in family:
            id_list.append(info)
            for details in family[info]:
                surnames = family[info]['surname']
                has_kids = family[info]['has_kids']
                parents = family[info]['parents']
                kids = family[info]['kids']
                kids_num = family[info]['kids_num']
            familiy_surname_list.append(surnames)
            temp_list.append(parents)
            has_kids_list.append(has_kids)
            temp_kids_list.append(kids)
            kids_num_list.append(kids_num)
    for i in temp_list:
        for x in i:
            parents_list.append(x)
    for kid in temp_kids_list[0]:
        kids_list.append(kid)

    # This checks if the first 3 digits in the id field of families is indeed 999
    id_status = False
    for id in id_list:
        if '999' in id:
            id_status = True
            print("The number 999 is the beginning of the id in this list")
        else:
            print("The number 999 is not part of the id related to the families list\n")
    print()

    # This check wheter the names have a numerical correspondent as the surnames
    if len(name_list) == len(people_surname_list):
        print("All the people have a corresponding surname to their name ", "\n" " number of names:", len(name_list), "\n" " number of surnames:", len(people_surname_list), "\n")
    else:
        print("The number of names does not correspond to the number of surnames" + " number of names: ", len(name_list), " number of surnames: ", len(people_surname_list), "\n")

    # This checks whetter there are ages that correspond to the age of teenagers and if it equals to the number of children available
    teens = 0
    for i in age_list:
        if i < 18:
            teens+=1
        else:
            continue
    if len(kids_list) == teens:
        print("The number of teens corresponds to the list of children, age wise","\n" " Kids count:", len(kids_list), "\n Ammount of teens by age:", teens, "\n")
    else:
        print("The ages and the ammount of teens do not correspond","\n" " Kids count:", len(kids_list), "\n Ammount of teens by age:", teens, "\n")

    # This checks if the ammount of parents corresponds to the actual number of parents
    grownups = 0
    for i in age_list:
        if i >= 18:
            grownups+=1
        else:
            continue
    if len(parents_list) == grownups:
        print("The number of parents corresponds to the number of grownups by age\n", "The number of parents:", len(parents_list), "\n The ammount of grownups by age:", grownups, "\n")
    else:
        print("The number of parents DOES NOT correspond to the number of grownups by age\n", "The number of parents:", len(parents_list), "\n The ammount of grownups by age:", grownups, "\n")

    # This code checks wheter the ammount of family members corresponds to the number of kids and grownups in the list
    temp_members_kids = 0
    temp_members_parents = 0
    for mem in member_list:
        if mem == 'kid':
            temp_members_kids+=1
        elif mem == 'parent':
            temp_members_parents+=1
        else:
            continue
    if temp_members_kids == teens:
        print("Kid family member corresponds to the ammount of kids in general\n", "The ammount of kids:", teens, "\n The members that are kids:", temp_members_kids, "\n")
    else:
        print("Kid family member DOES NOT correspond to the ammount of kids in general\n", "The ammount of kids:", teens, "\n The members that are kids:", temp_members_kids, "\n")
    if temp_members_parents == grownups:
        print("Grownups family member corresponds to the ammount of parents in general\n", "The ammount of parents:", grownups, "\n The members that are parents:", temp_members_parents, "\n")
    else:
        print("Grownups family member DOES NOT correspond to the ammount of parents in general\n", "The ammount of parents:", grownups, "\n The members that are parents:", temp_members_parents, "\n")

    # This checks wheter the surnames match from people list and families list
    shemesh = 0
    yakir = 0
    for surname in people_surname_list:
        if surname == familiy_surname_list[0]:
            shemesh+=1
        elif surname == familiy_surname_list[1]:
            yakir+=1
        else:
            print("the surnames dont match")
    if shemesh > 0 | yakir > 0:
        print("There are matching surnames between the people dictionary and the families dictionary\n", "The ammount of shemeshes:",shemesh, "\n The ammount of yakirs:",yakir, "\n")

    #This checks if the ammount of people is correct
    if shemesh + yakir == len(name_list) & shemesh + yakir == len(people_surname_list) & shemesh + yakir == len(member_list):
        print("The ammount of people is the correct between multiple lists", "\n")
    else:
        print("The ammount of people is DIFFERENT between surname, member and name lists", "\n")

    # This checks the ammount of children in the list
    if len(kids_list) == kids_num_list[0]:
        print("There is a matching number of kids between lists\n there are:", len(kids_list), "kids ", "\n and the ammount of kids on the kids num list:", kids_num_list[0], "\n")
    else:
        print("The number of kids does not match")

    # This checks if yakir family has indeed 0 children
    if temp_kids_list[1] == None:
        print("Yakir family has 0 children\n the number of kids is:",kids_num_list[1], "\n the value for kids in list is:", temp_kids_list[1], "\n")

    # This checks whetter shemesh family has kids or not and what is the ammount of them
    if len(temp_kids_list[0]) == len(kids_num_list):
        print("Shemesh family has the same ammount of kids between lists\n", "The ammount of kids is:", len(temp_kids_list[0]),"\n The ammount of kids in list:", kids_num_list[0], "\n")
    else:
        print("The ammount of kids is not matching")

clean_data()


# -*- coding: utf-8 -*-
"""
Created on Tue Nov  3 10:45:30 2020

@author: Family
"""

import cv2 #OpenCV
import numpy as np
import matplotlib.pyplot as plt

A = cv2.imread('images/A.jpg')
B = cv2.imread('images/B.jpg')

#Operaciones básicas
pxX = np.size(A, axis=0) #W
pxY = np.size(A, axis=1) #H
pxXY = np.size(A, axis=None)

sumaA = np.sum(A) #SumaA
sumaB = np.sum(B) #SumaB
minimo = np.min(A) #Mínimo

maximo = np.max(A) #Máximo
ARGmaximo = np.argmax(A)
ARGmin = np.argmin(A)
prom = np.mean(A) #Promedio
var = np.var(A) #Varianza
de = np.sqrt(var) #Desviación estándar

#Operaciones avanzadas
#cv2.imshow('Img-Original',img1)

hsv = cv2.cvtColor(A,cv2.COLOR_BGR2HSV)
#cv2.imshow('Img-HSV', hsv)

I = cv2.cvtColor(A,cv2.COLOR_BGR2GRAY)
#cv2.imshow('Img-GRAY', I)
#umbral1 = 50
umbral2,_ = cv2.threshold(I,0,255,cv2.THRESH_OTSU)
binaria = np.uint8((I<umbral2)+255)
#cv2.imshow('Img-Binary', binaria)
output = cv2.connectedComponentsWithStats(umbral2,4,cv2.CV_32F)
cantObj = output[0] # Objects quantity


import concurrent.futures
import datetime as dt
import logging
import random
import time
import uuid

from lockable import Lock

def test_load_one(caplog):
    caplog.set_level(logging.DEBUG, logger='lockable.lock')
    caplog.set_level(logging.DEBUG, logger='lockable.client')
    caplog.set_level(logging.DEBUG, logger=__name__)

    with Lock(
            lock_name=uuid.uuid4(),
            heartbeat_sleep_period=dt.timedelta(milliseconds=100),
            acquire_sleep_period=dt.timedelta(milliseconds=100)
            ):
        time.sleep(dt.timedelta(milliseconds=500).total_seconds())

def test_load(caplog):
    caplog.set_level(logging.DEBUG, logger='lockable.lock')
    caplog.set_level(logging.DEBUG, logger='lockable.client')
    caplog.set_level(logging.DEBUG, logger=__name__)

    random.seed(a=1337)
    min_delay_ms = 0
    max_delay_ms = 1000
    min_duration_ms = 0
    max_duration_ms = 1500
    N = 400
    M = 4

    lock_names = [uuid.uuid4() for _ in range(M)]
    local_locks = {l: False for l in lock_names}
    processes = []
    for _ in range(N):
        delay_ms = random.randrange(min_delay_ms, max_delay_ms)
        delay = dt.timedelta(milliseconds=delay_ms)
        duration_ms = random.randrange(min_duration_ms, max_duration_ms)
        duration = dt.timedelta(milliseconds=duration_ms)
        lock_name = random.choice(lock_names)
        process = Process(delay, duration, lock_name, local_locks)
        processes.append(process)

    executor = concurrent.futures.ThreadPoolExecutor(max_workers=N)
    tasks = []
    for process in processes:
        future = executor.submit(process.run)
        tasks.append((process, future))
    assert all(_[1].result() is None for _ in tasks)

class Process:
    def __init__(self, delay, duration, lock_name, local_locks):
        self._delay = delay
        self._duration = duration
        self._lock_name = lock_name
        self._local_locks = local_locks

    def run(self):
        try:
            time.sleep(self._delay.total_seconds())
            with Lock(
                    self._lock_name,
                    heartbeat_sleep_period=dt.timedelta(milliseconds=100),
                    acquire_sleep_period=dt.timedelta(milliseconds=100)
                    ):
                assert self._local_locks[self._lock_name] is False
                self._local_locks[self._lock_name] = True
                time.sleep(self._duration.total_seconds())
                assert self._local_locks[self._lock_name] is True
                self._local_locks[self._lock_name] = False
        except Exception as e:
            return e

    def __repr__(self):
        return f'Process({repr(self._delay)}, {repr(self._duration)}, {repr(self._lock_name)})'


import torch

import os
import pickle
import random

def model_near_native_ranks(model, scores, top_n=20):
    model_scores_dict = scores

    pcomplexes = list(model_scores_dict.keys())
    pcomplexes.sort()

    total_top_20_decoys = 0
    total_hq_decoys = 0

    total_complexes = 0

    near_native_ranks = []

    dock_sw_path = "/s/jawar/b/nobackup/yash/protein-ranking/data/docking_softwares"

    for pcomplex_name in pcomplexes:
        pcomplex_ranks = []

        is_valid_pcomplex = True
        for dock_sw in model_scores_dict[pcomplex_name]:
            if(dock_sw == "natives"):
                continue

            dockq_path = os.path.join(dock_sw_path, dock_sw, "dockq")
            dockq_prot_path = os.path.join(dockq_path, pcomplex_name + ".pkl")
            dockq_dict = None
            with open(dockq_prot_path, "rb") as f:
                dockq_dict = pickle.load(f)

            pcomplex_decoys = list(model_scores_dict[pcomplex_name][dock_sw].items())

            if model.ranking:
                pcomplex_decoys.sort(key=lambda tup:tup[1], reverse=False)
            else:
                pcomplex_decoys.sort(key=lambda tup:tup[1], reverse=True)

            pcomplex_decoys_dockq = [dockq_dict[decoy_name][0] for decoy_name, score in pcomplex_decoys]

            for i, value in enumerate(pcomplex_decoys):
                decoy_name, decoy_score = value
                if(pcomplex_decoys_dockq[i] > 0.65):
                    pcomplex_ranks.append((i+1, pcomplex_decoys_dockq[i]))
                    break
                if(i == len(pcomplex_decoys)-1):
                    is_valid_pcomplex = False

        if(len(pcomplex_ranks) > 0):
            pcomplex_ranks.sort(key=lambda tup:tup[1], reverse=True)
            near_native_ranks.append(pcomplex_ranks[0][0])

        if(not is_valid_pcomplex):
            total_complexes += 1

    model_ranks = [rank for rank in near_native_ranks if(rank != None)]

    top_n_present = 0
    for rank in model_ranks:
        if(rank<=top_n):
            top_n_present += 1

    return top_n_present, total_complexes

def model_native_ranks(model, scores, top_n=20):

    model_scores_dict = scores

    pcomplexes = list(model_scores_dict.keys())
    pcomplexes.sort()

    native_ranks = []

    dock_sw_path = "/s/jawar/b/nobackup/yash/protein-ranking/data/docking_softwares"

    # pcomplexes = ['1ktz', '1s1q', '1sv0', '1u0s', '1veu', '1xb2', '2dvw', '2fhz', '2r17', '3c9a', '3k74', '3viq', '4e05', '4hwi', '4je3', '4kc3', '4yjz', '5a1n', '5bv0', '5doi']

    for pcomplex_name in pcomplexes:
        pcomplex_decoys = []

        max_dockq_docksw_val = -1
        max_dockq_docksw_cat = None
        for dock_sw in model_scores_dict[pcomplex_name]:
            if(dock_sw == "natives"):
                continue

            dockq_path = os.path.join(dock_sw_path, dock_sw, "dockq")
            dockq_prot_path = os.path.join(dockq_path, pcomplex_name + ".pkl")
            dockq_dict = None
            with open(dockq_prot_path, "rb") as f:
                dockq_dict = pickle.load(f)

            decoys_scores = model_scores_dict[pcomplex_name][dock_sw].items()

            pcomplex_decoys_dockq = [dockq_dict[decoy_name][0] for decoy_name, score in decoys_scores]

            max_pcomplex_decoys_dockq = max(pcomplex_decoys_dockq)
            if(max_pcomplex_decoys_dockq > max_dockq_docksw_val):
                max_dockq_docksw_val = max_pcomplex_decoys_dockq
                max_dockq_docksw_cat = dock_sw

        if(max_dockq_docksw_val > 0.65):
            pcomplex_decoys += model_scores_dict[pcomplex_name][max_dockq_docksw_cat].items()
            pcomplex_decoys += model_scores_dict[pcomplex_name]["natives"].items()

            if model.ranking:
                pcomplex_decoys.sort(key=lambda tup:tup[1], reverse=False)
            else:
                pcomplex_decoys.sort(key=lambda tup:tup[1], reverse=True)

            for i, value in enumerate(pcomplex_decoys):
                decoy_name, decoy_dockq = value
                if(decoy_name.endswith("_b.pdb")):
                    native_ranks.append(i)
                    break

    top_20 = 0
    for native_rank in native_ranks:
        if(native_rank <= top_n):
            top_20 += 1

    return top_20, len(native_ranks)

def model_near_native_enrichment(model, scores, top_n=20):
    model_scores_dict = scores

    pcomplexes = list(model_scores_dict.keys())
    pcomplexes.sort()

    near_native_ranks = []

    dock_sw_path = "/s/jawar/b/nobackup/yash/protein-ranking/data/docking_softwares"

    enrichment = []

    for _ in range(1000):
        enrichment_pcomplex = []
        for pcomplex_name in pcomplexes:
            enrichment_dock = []
            for dock_sw in model_scores_dict[pcomplex_name]:

                model_count = 0
                random_count = 0

                if(dock_sw == "natives"):
                    continue

                dockq_path = os.path.join(dock_sw_path, dock_sw, "dockq")
                dockq_prot_path = os.path.join(dockq_path, pcomplex_name + ".pkl")
                dockq_dict = None
                with open(dockq_prot_path, "rb") as f:
                    dockq_dict = pickle.load(f)

                pcomplex_decoys = list(model_scores_dict[pcomplex_name][dock_sw].items())

                pcomplex_decoys_len = len(pcomplex_decoys)

                pcomplex_decoys_dockq = [dockq_dict[decoy_name][0] for decoy_name, score in pcomplex_decoys]

                for i in range(len(pcomplex_decoys)):
                    decoy_name = pcomplex_decoys[i][0]
                    pcomplex_decoys[i] = list(pcomplex_decoys[i])
                    pcomplex_decoys[i].append(dockq_dict[decoy_name][0])

                pcomplex_decoys_rand = list(pcomplex_decoys)
                random.shuffle(pcomplex_decoys_rand)

                if model.ranking:
                    pcomplex_decoys.sort(key=lambda tup:tup[1], reverse=False)
                else:
                    pcomplex_decoys.sort(key=lambda tup:tup[1], reverse=True)

                good_quality_complex = False

                for i in range(pcomplex_decoys_len):
                    if(pcomplex_decoys[i][2] > 0.25):
                        good_quality_complex = True
                    if(i<=top_n and pcomplex_decoys[i][2] > 0.25):
                        model_count += 1
                    if(i<=top_n and pcomplex_decoys_rand[i][2] > 0.25):
                        random_count += 1

                if(random_count == 0):
                    random_count = 1

                if(good_quality_complex):
                    enrichment_dock.append(model_count/random_count)
            if(len(enrichment_dock)>0):
                enrichment_pcomplex.append(sum(enrichment_dock)/len(enrichment_dock))

        if(len(enrichment_pcomplex)):
            enrichment.append(sum(enrichment_pcomplex)/len(enrichment_pcomplex))

    return sum(enrichment)/len(enrichment)

def test(model, device, test_loader, epoch, two_graph_class_names, top_n=20, dataset_cat="VALID", logger=None):
    model.eval()
    test_loss = 0
    mini_batches = 0

    model_scores = {}

    with torch.no_grad():
        for batch_idx, local_batch in enumerate(test_loader):
            mini_batch_target = []
            mini_batch_output = []

            for i, item in enumerate(local_batch):

                if(item["vertices"].size()[0] == 0):
                    if(logger is not None):
                        logger.error(item["name"])
                    else:
                        print("Error: " + str(item["name"]))
                    continue

                # Move graph to GPU.
                prot_name, dock_sw, decoy_name = item["name"]
                vertices = item["vertices"].to(device)
                nh_indices = item["nh_indices"].to(device)
                int_indices = item["int_indices"].to(device)
                nh_edges = item["nh_edges"].to(device)
                int_edges = item["int_edges"].to(device)
                is_int = item["is_int"].to(device)

                model_input = None
                if(model.conv1.__class__.__name__ in two_graph_class_names):
                    model_input = (vertices, vertices, nh_indices, int_indices, nh_edges, int_edges, is_int)
                else:
                    model_input = (vertices, nh_indices, int_indices, nh_edges, int_edges, is_int)

                output = model(model_input)

                try:
                    model_scores[prot_name]
                except:
                    model_scores[prot_name] = {}

                try:
                    model_scores[prot_name][dock_sw]
                except:
                    model_scores[prot_name][dock_sw] = {}

                if(model.multi_label):
                    model_scores[prot_name][dock_sw][decoy_name] = output[0][0].item()
                else:
                    model_scores[prot_name][dock_sw][decoy_name] = output.item()

        if(dataset_cat != "CUSTOM"):
            top_n_near_native_present, total_near_native_complexes = model_near_native_ranks(model, model_scores, top_n=20)
            top_n_native_present, total_native_complexes = model_native_ranks(model, model_scores, top_n=20)
            enrichment_near_native = model_near_native_enrichment(model, model_scores, top_n=20)

            return model_scores, top_n_near_native_present, top_n_native_present, enrichment_near_native
        else:
            return model_scores


"""
This example shows how to use itertools.islice to cut down on the number
of iteration that a loop does...

It also shows how to write your own islice implementation....
"""

from itertools import islice

def simple_islice(iterable, size: int):
    for i, x in enumerate(iterable):
        if i == size:
            break
        yield x

def main():
    # This is the most basic example: getting only the first n elements
    # from an iterable. When islice gets one argument its meaning is "stop".
    for i in islice(range(10), 5):
        print(i)
    # start and stop
    for i in islice(range(10), 2, 7):
        print(i)
    # start, stop and step
    for i in islice(range(10), 4, 14, 2):
        print(i)
    for i in simple_islice(range(10), 5):
        print(i)
    for i in simple_islice(range(10), 10):
        print(i)
    for i in simple_islice(range(10), 11):
        print(i)

main()


import sys
sys.path.extend([
    "./",
])
import numpy as np
import os
import optuna
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
import copy
import random

import pandas as pd
from itertools import product
from src.general_utils import util_path
from src.general_utils import util_toy

# For aspect ratio 4:3.
sns.set_context("paper")
sns.set_theme(style="ticks")

if __name__ == '__main__':

    report_dir = './reports/'
    exp_name = 'toy_gans_num_real_samples__100000-grid_size__5-step__2-std_dev__0.05'
    report_dir = os.path.join(report_dir, exp_name)
    util_path.create_dir(report_dir)

    # Parameters for the data
    grid_size = 5
    min_mux =4
    max_mux = min_mux + 2 * (grid_size - 1)
    min_muy = 4
    max_muy = min_muy + 2 * (grid_size - 1)
    num_real_tot = 10000
    num_synth_gan = 500
    mu_real = [(min_mux + 2 * i, min_muy + 2 * j) for i in range(grid_size) for j in range(grid_size)]

    std_real = 0.05
    n_trials = 300

    # Create real datasets.
    data_real_list, data_real = util_toy.generate_data(num_real_tot, mu_real, std_real)
    fig = plt.figure()
    plt.scatter(data_real[:, 0], data_real[:, 1], alpha=0.5, s=1, color='blue')
    plt.grid(True)
    plt.tight_layout()
    fig.savefig(os.path.join(report_dir, 'real_data.png'))
    #plt.show()

    # Load all the toy GANs on the disk.
    epoch_to_load = 'final'
    folders_list =  os.listdir(report_dir)
    data_synthetic_list = []
    for fname in folders_list:
        samples_dir = os.path.join(report_dir, fname)
        # Check if directory.
        if not os.path.isdir(samples_dir):
            continue
        if 'ensemble_search' in samples_dir:
            continue
         # Load final samples.
        samples = np.load(os.path.join(samples_dir, f'generated_samples_epoch_{epoch_to_load}.npy'))
        # Shuffle
        np.random.shuffle(samples)
        # Select the first num_synth_gan samples.
        samples = samples[:num_synth_gan]
        data_synthetic_list.append(samples)

    # Flatten the list.
    data_synthetic = np.vstack(data_synthetic_list)

    # Plot synthetic data.
    fig = plt.figure()
    plt.scatter(data_synthetic[:, 0], data_synthetic[:, 1], alpha=0.5, s=1, color='blue')
    plt.grid(True)
    plt.tight_layout()
    fig.savefig(os.path.join(report_dir, 'synthetic_data.png'))
    #plt.show()
    for idx, samples_synth in enumerate(data_synthetic_list):
        fig = plt.figure()
        plt.scatter(samples_synth[:, 0], samples_synth[:, 1], alpha=0.5, s=1, color='blue')
        plt.grid(True)
        plt.tight_layout()
        fig.savefig(os.path.join(report_dir, f'synthetic_data_{idx}.png'))
        #plt.show()

    n_classes = 10
    seed_class = 42
    class_choice = 'random'  # 'random' or 'kmeans'
    os.path.join(report_dir, f'toy-seed_class__{seed_class}-n_classes__{n_classes}/')
    util_path.create_dir(report_dir)

    # Generate classes.
    if class_choice == 'random':
        np.random.seed(seed_class)
        random.seed(seed_class)
        random_class = np.array([[np.random.uniform(min_mux, max_mux), np.random.uniform(min_muy, max_muy)] for _ in range(n_classes)])
    elif class_choice == 'kmeans':
        from sklearn.cluster import KMeans
        kmeans = KMeans(n_clusters=n_classes, random_state=seed_class, n_init='auto').fit(data_real)
        centroids = kmeans.cluster_centers_
        random_class = copy.deepcopy(centroids)
    else:
        raise NotImplementedError

    # Assign label to each point according to its vicinity to a class.
    # Real.
    distances_real = np.linalg.norm(data_real[:, np.newaxis] - random_class, axis=2)
    labels_real = np.argmin(distances_real, axis=1)

    # Synthetic.
    distances_synth = np.linalg.norm(data_synthetic[:, np.newaxis] - random_class, axis=2)
    labels_synth = np.argmin(distances_synth, axis=1)

    # Visualize the space according to the label.
    fig = plt.figure()
    plt.scatter(data_real[:, 0], data_real[:, 1], c=labels_real, marker='o', s=1, alpha=0.4, label='Points')
    plt.scatter(random_class[:, 0], random_class[:, 1], c=np.unique(labels_real), marker='*', s=50, label='Classes')
    plt.grid(True)
    plt.tight_layout()
    fig.savefig(os.path.join(report_dir, 'real_data_label.png'))
    #plt.show()

    fig = plt.figure()
    plt.scatter(data_synthetic[:, 0], data_synthetic[:, 1], c=labels_synth, marker='o', s=1, alpha=0.4, label='Points')
    plt.scatter(random_class[:, 0], random_class[:, 1], c=np.unique(labels_synth), marker='*', s=50, label='Classes')
    plt.grid(True)
    plt.tight_layout()
    fig.savefig(os.path.join(report_dir, 'synthetic_data_label.png'))
    #plt.show()

    # Create dataset.
    X_real = copy.deepcopy(data_real.reshape(-1, 2))
    y_real = copy.deepcopy(labels_real.reshape(-1, 1))
    X_naive = copy.deepcopy(data_synthetic)
    y_naive = copy.deepcopy(labels_synth.reshape(-1, 1))
    # Create y_gauss.
    y_gauss = []
    for center_idx, samples_real in enumerate(data_real_list):
        y_gauss.append(np.repeat(center_idx, len(samples_real)))
    y_gauss = np.hstack(y_gauss)
    y_gauss = y_gauss.reshape(-1, 1)

    # Concate y_real and y_gauss and save to xlsx.
    y_strat = np.hstack([y_real, y_gauss])
    df_strat = pd.DataFrame(y_strat)
    df_strat['strat'] = df_strat[0].astype(str) + '-' + df_strat[1].astype(str)

    # Split the training set.
    X_train_real, X_test_real, y_train_real, y_test_real = train_test_split(X_real, y_real, test_size=0.2,  stratify=df_strat, random_state=42, shuffle=True)

    # Create a dataframe for the results.
    if os.path.exists(os.path.join(report_dir, 'history.xlsx')):
        history = pd.read_excel(os.path.join(report_dir, 'history.xlsx'))
    else:
        history = pd.DataFrame(columns=['seed_class', 'n_classes', 'n_obj', 'obj_name', 'aggregation', 'exp_name', 'n_gan_ens', 'accuracy', 'precision', 'recall', 'specificity', 'f1-score', 'g-mean',  'rec_modes', 'high_quality_samples'])

    # Real.
    clf = DecisionTreeClassifier()
    clf.fit(X_train_real, y_train_real)
    y_pred = clf.predict(X_test_real)
    clf_acc, clf_prec, clf_rec, clf_spec, clf_f1, clf_gmean = compute_metrics(y_test_real, y_pred, aggregation='mean')
    history = history.append({
        'seed_class': seed_class,
        'n_classes': n_classes,
        'n_obj': 'NA',
        'obj_name': 'NA',
        'aggregation': 'NA',
        'exp_name': 'baseline',
        'n_gan_ens': 'NA',
        'accuracy': clf_acc,
        'precision': clf_prec,
        'recall': clf_rec,
        'specificity': clf_spec,
        'f1-score': clf_f1,
        'g-mean': clf_gmean,
        'rec_modes': 'NA',
        'high_quality_samples': 'NA'
    }, ignore_index=True)

    # Naive.
    clf = DecisionTreeClassifier()
    clf.fit(X_naive, y_naive)
    y_pred = clf.predict(X_test_real)
    clf_acc, clf_prec, clf_rec, clf_spec, clf_f1, clf_gmean = util_toy.compute_metrics(y_test_real, y_pred, aggregation='mean')
    rec_modes = util_toy.recovered_mode(data=X_naive, mu_ref=mu_real, thres= 3 * std_real)
    high_quality_samples = util_toy.frac_points(data=X_naive, mu_ref=mu_real, thres=3 * std_real)
    history = history.append({
        'seed_class': seed_class,
        'n_classes': n_classes,
        'n_obj': 'NA',
        'obj_name': 'NA',
        'aggregation': 'NA',
        'exp_name': 'naive',
        'n_gan_ens': len(data_synthetic_list),
        'accuracy': clf_acc,
        'precision': clf_prec,
        'recall': clf_rec,
        'specificity': clf_spec,
        'f1-score': clf_f1,
        'g-mean': clf_gmean,
        'rec_modes': rec_modes,
        'high_quality_samples': high_quality_samples
    }, ignore_index=True)

    # Single Gaussians.
    mean_acc = []
    mean_precision = []
    mean_recall = []
    mean_specificity = []
    mean_f1_score = []
    mean_gmean = []

    mean_rec_modes = []
    mean_high_quality_samples = []
    for idx in range(len(data_synthetic_list)):
        X = X_naive[idx * num_synth_gan: (idx + 1) * num_synth_gan]
        y = y_naive[idx * num_synth_gan: (idx + 1) * num_synth_gan]
        clf = DecisionTreeClassifier()
        clf.fit(X, y)
        y_pred = clf.predict(X_test_real)
        clf_acc, clf_prec, clf_rec, clf_spec, clf_f1, clf_gmean = util_toy.compute_metrics(y_test_real, y_pred, aggregation='mean')
        mean_acc.append(clf_acc)
        mean_precision.append(clf_prec)
        mean_recall.append(clf_rec)
        mean_specificity.append(clf_spec)
        mean_f1_score.append(clf_f1)
        mean_gmean.append(clf_gmean)
        mean_rec_modes.append(util_toy.recovered_mode(data=X, mu_ref=mu_real, thres=3 * std_real))
        mean_high_quality_samples.append(util_toy.frac_points(data=X, mu_ref=mu_real, thres=3 * std_real))

    history = history.append({
        'seed_class': seed_class,
        'n_classes': n_classes,
        'n_obj': 'NA',
        'obj_name': 'NA',
        'aggregation': 'NA',
        'exp_name': 'mean gan',
        'n_gan_ens': 'NA',
        'accuracy': np.mean(mean_acc),
        'precision': np.mean(mean_precision),
        'recall': np.mean(mean_recall),
        'specificity': np.mean(mean_specificity),
        'f1-score': np.mean(mean_f1_score),
        'g-mean': np.mean(mean_gmean),
        'rec_modes': np.mean(mean_rec_modes),
        'high_quality_samples': np.mean(mean_high_quality_samples)

    }, ignore_index=True)

    # Ensemble search.
    name_obj_list =   ['pr_inter', 'pr_intra', 'dc_inter', 'dc_intra', 'fid_inter', 'fid_intra', 'pr_inter__pr_intra', 'dc_inter__dc_intra', 'fid_inter__fid_intra'] # ['pr_inter', 'pr_intra', 'pr_inter__pr_intra', 'dc_inter', 'dc_intra', 'dc_inter__dc_intra', 'fid_inter', 'fid_intra', 'fid_inter__fid_intra']
    aggregation = ['inter', 'intra', 'ratio', 'NA']

    opts = list(product(name_obj_list, aggregation))

    for name_obj, aggregation in opts:

        n_obj = len(name_obj.split('__'))
        if n_obj > 1:
            obj_first_position = name_obj.split('___')[0]
            assert 'inter' in obj_first_position
            if aggregation == 'NA':
                continue
        else:
            if aggregation != 'NA':
                continue

        directions = []
        for i in range(n_obj):
            if 'pr_inter' in name_obj:
                directions.append('maximize')
            elif 'pr_intra' in name_obj:
                directions.append('minimize')
            elif 'dc_inter' in name_obj:
                directions.append('maximize')
            elif 'dc_intra' in name_obj:
                directions.append('minimize')
            elif 'fid_inter' in name_obj:
                directions.append('minimize')
            elif 'fid_intra' in name_obj:
                directions.append('maximize')
            elif 'size' in name_obj:
                directions.append('minimize')
            else:
                raise NotImplementedError

        ensemble_dir = os.path.join(report_dir,f'ensemble_search-n_obj__{n_obj}-name_obj__{name_obj}-aggregation__{aggregation}-n_trials__{n_trials}')
        util_path.create_dir(ensemble_dir)

        study = optuna.create_study(directions=directions, sampler=optuna.samplers.TPESampler(multivariate=True))

        func = lambda trial: util_toy.obj_optuna(
            trial=trial,
            samples_real=data_real_list,
            samples_naive_list=data_synthetic_list,
            n_obj=n_obj,
            name_obj=name_obj,
        )
        study.optimize(func, n_trials=n_trials)
        df = study.trials_dataframe(attrs=('number', 'value', 'params', 'state'))

        # Drop not complete trials and save to disk.
        df = df[df['state'] == "COMPLETE"]
        df.reset_index(inplace=True, drop=True)
        df.to_excel(os.path.join(ensemble_dir, 'optuna_study.xlsx'), index=False)

        if n_obj==1:
            # Best trials analysis.
            if name_obj == 'pr_inter':
                best_trials = max(study.best_trials, key=lambda t: t.values[0])
            elif name_obj == 'pr_intra':
                best_trials = min(study.best_trials, key=lambda t: t.values[0])
            elif name_obj == 'dc_inter':
                best_trials = max(study.best_trials, key=lambda t: t.values[0])
            elif name_obj == 'dc_intra':
                best_trials = min(study.best_trials, key=lambda t: t.values[0])
            elif name_obj == 'fid_inter':
                best_trials = min(study.best_trials, key=lambda t: t.values[0])
            elif name_obj == 'fid_intra':
                best_trials = max(study.best_trials, key=lambda t: t.values[0])
            else:
                raise NotImplementedError

            with open(os.path.join(ensemble_dir, f"best_trials.txt"), 'w') as f:
                f.write(f"\nNumber: {best_trials.number}")
                f.write(f"\nParams: {best_trials.params}")
                f.write(f"\nValues: {best_trials.values}")

            best_trials_gans = [x for x in best_trials.params if best_trials.params[x] == 1]

            best_trials_gans_indexes = sorted([int(x.split('G')[-1]) for x in best_trials_gans])
            best_trials_gans = [f'G{x}' for x in best_trials_gans_indexes]
            sel_idx = [0] * len(data_synthetic_list)
            for idx in best_trials_gans_indexes:
                sel_idx[idx] = 1

        elif n_obj > 1:
            best_trials = copy.deepcopy(study.best_trials)
            # Selet only best trials.
            best_trials_number = [trial.number for trial in best_trials]
            best_trials_df = df[df['number'].isin(best_trials_number)]

            if aggregation == 'inter':
                best_trials_df['cost'] = copy.deepcopy(best_trials_df['values_0'])
            elif aggregation == 'intra':
                best_trials_df['cost'] = copy.deepcopy(best_trials_df['values_1'])
            elif aggregation == 'ratio':
                best_trials_df['cost'] = best_trials_df['values_0'] / best_trials_df['values_1']

            if 'pr' in name_obj or 'dc' in name_obj:
                best_trials_cost = best_trials_df[best_trials_df['cost'] == best_trials_df['cost'].max()].iloc[0]
            elif 'fid' in name_obj:
                best_trials_cost = best_trials_df[best_trials_df['cost'] == best_trials_df['cost'].min()].iloc[0]
            else:
                raise NotImplementedError

            # Save to disk.
            best_trials_df.reset_index(inplace=True, drop=True)
            best_trials_df.to_excel(os.path.join(ensemble_dir, 'optuna_study_best.xlsx'), index=False)

            best_trials_gans = best_trials_cost[best_trials_cost == 1]
            best_trials_gans = list(best_trials_gans.index)
            # Remove 'number' from the list.
            best_trials_gans = [x for x in best_trials_gans if x != 'number']
            with open(os.path.join(ensemble_dir, f"best_gans.txt"), 'w') as f:
                f.write(f"\n{best_trials_gans}")

            best_trials_gans_indexes = sorted([int(x.split('G')[-1]) for x in best_trials_gans])
            best_trials_gans = [f'G{x}' for x in best_trials_gans_indexes]
            sel_idx = [0] * len(data_synthetic_list)
            for idx in best_trials_gans_indexes:
                sel_idx[idx] = 1
        else:
            raise NotImplementedError

        # Create ensemble dataset.
        data_ensemble_list = [data_synthetic_list[i] for i in range(len(data_synthetic_list)) if sel_idx[i] == 1]
        data_ensemble = np.vstack(data_ensemble_list)

        # Label the data.
        distances_ensemble = np.linalg.norm(data_ensemble[:, np.newaxis] - random_class, axis=2)
        labels_ensemble = np.argmin(distances_ensemble, axis=1)

        # Create the training dataset.
        X_ens = copy.deepcopy(data_ensemble.reshape(-1, 2))
        y_ens = copy.deepcopy(labels_ensemble.reshape(-1, 1))

        # Ensemble.
        clf = DecisionTreeClassifier()
        clf.fit(X_ens, y_ens)
        y_pred = clf.predict(X_test_real)
        clf_acc, clf_prec, clf_rec, clf_spec, clf_f1, clf_gmean = util_toy.compute_metrics(y_test_real, y_pred, aggregation='mean')
        rec_modes = util_toy.recovered_mode(data=X_ens, mu_ref=mu_real, thres=3 * std_real)
        high_quality_samples = util_toy.frac_points(data=X_ens, mu_ref=mu_real, thres=3 * std_real)
        history = history.append({
            'seed_class': seed_class,
            'n_classes': n_classes,
            'n_obj': n_obj,
            'obj_name': name_obj,
            'aggregation': aggregation,
            'exp_name': 'ensemble',
            'n_gan_ens': len(data_ensemble_list),
            'accuracy': clf_acc,
            'precision': clf_prec,
            'recall': clf_rec,
            'specificity': clf_spec,
            'f1-score': clf_f1,
            'g-mean': clf_gmean,
            'rec_modes': rec_modes,
            'high_quality_samples': high_quality_samples
        }, ignore_index=True)

        # Save to the disk.
        history.to_excel(os.path.join(report_dir, 'history.xlsx'), index=False)

    print('May the force be with you.')


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

"""The setup script."""

from setuptools import setup, find_packages

with open('README.md') as readme_file:
    readme = readme_file.read()

with open('CHANGELOG.md') as changelog_file:
    changelog = changelog_file.read()

# Core requirements for end-users
requirements = [
    'squid-py==0.2.11'
]

# Required packages for developers
dev_requirements = [
    'jupytext==0.8.5', # For conversion of IPython scripts to Jupyter
    'bumpversion',
    #'pkginfo',
    'twine',
    #'watchdog',
]

# Extra requirements for setup
setup_requirements = []

# Requirements for testing
test_requirements = [
    'tox',
    'pytest',
]

docs_requirements = [
    'Sphinx',
    'sphinx-rtd-theme',
]

setup(
    author="leucothia",
    author_email='devops@oceanprotocol.com',
    classifiers=[
        'Development Status :: 2 - Pre-Alpha',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        'Natural Language :: English',
        'Programming Language :: Python :: 3.7',
    ],
    description="Data Science interface to the Ocean Protocol stack",
    extras_require={
        'test': test_requirements,
        'dev': dev_requirements + test_requirements + docs_requirements,
    },
    install_requires=requirements,
    license="Apache Software License 2.0",
    long_description=readme,
    long_description_content_type='text/markdown',
    include_package_data=True,
    keywords='mantaray',
    name='mantaray',
    packages=find_packages(include=['mantaray']),
    setup_requires=setup_requirements,
    test_suite='tests',
    tests_require=test_requirements,
    url='https://github.com/oceanprotocol/mantaray',
    version='0.0.1',
    zip_safe=False,
)