#!/usr/bin/env python
import numpy as np
import math
from pylab import *
from matplotlib import pyplot as plt

def columnToList(text,colnumber):
    with open(text) as f:
        lista=[]
        for line in f:
            spl=line.split()
            lista.append(spl[colnumber])
    return lista

data = 'lanemden.dat'
xi = columnToList(data,2)
theta = columnToList(data, 0)
plot(xi,theta)
plt.xlabel(r'$\xi$')
plt.ylabel(r'$\theta$')
plt.savefig('fig4.png')
show()

Grad School/Fall 2016/AEP 4380/HWs/Final Project/Scripts/fpplot4.py


import pulse_check
import dosage_reminder
import temp_chart
import blood_vessel_overlap
user_input = ''

while user_input != 'exit':
    print("-------------------------------------")
    user_input = input("Choose the program you want to run: \n"
                       "    0: Pulse Check \n"
                       "    1: Dosage Reminder \n"
                       "    2: Temperature Chart \n"
                       "    3: Blood Vessel Overlap \n"
                       "-------------------------------------")

    if user_input == "0":
        pulse_check.check()
    elif user_input == "1":
        dosage_reminder.remind()
    elif user_input == "2":
        temp_chart.chart()
    elif user_input == "3":
        blood_vessel_overlap.examine()


# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import logging
import datetime as dt
from src.utils.utils import Rsummary
from unidecode import unidecode
from pathlib import Path

# global variable
regions = ["national", "auvergne_rhone_alpes", "bourgogne_franche_comte", "bretagne", "centre_val_de_loire",
           "grand_est", "haut_de_france", "ile_de_france", "normandie", "nouvelle_aquitaine",
           "occitanie", "paca", "pays_de_loire"]
map_regions_encoding = {region: region_encoding for region, region_encoding in
                        zip(regions, ["", "Auvergne-Rhône-Alpes_", "Bourgogne-Franche-Comté_",
                                      "Bretagne_", "Centre-Val-de-Loire_",
                                      "Grand-Est_", "Hauts-de-France_", "Ile-de-France_",
                                      "Normandie_", "Nouvelle-Aquitaine_",
                                      "Occitanie_", "PACA_", "Pays-de-la-Loire_"])}

def read_load(eco2mix_load_path):
    eco2mix_load = pd.read_csv(eco2mix_load_path, encoding='windows-1252', sep="\t", engine="python",
                               usecols=['Date', 'Heures', 'Consommation'], index_col=False)
    eco2mix_load["minutes"] = eco2mix_load["Heures"].str[3:5]
    eco2mix_load = eco2mix_load[eco2mix_load["minutes"].isin(['00', '30'])].reset_index(drop=True)
    eco2mix_load["Date"] = pd.to_datetime(eco2mix_load["Date"], utc=True, dayfirst=True)
    return eco2mix_load

def create_nat_or_reg_data_load(region):
    print('\t' + region)
    logging.info(region)
    region_encoding = map_regions_encoding[region]
    eco2mix_load_real_time = read_load(
        eco2mix_load_path="Inputs/rte/eCO2mix_RTE_" + unidecode(region_encoding) + "En-cours-TR.xls")
    eco2mix_load_consolidated = read_load(
        eco2mix_load_path="Inputs/rte/eCO2mix_RTE_" + region_encoding + "En-cours-Consolide.xls")
    nat_or_reg_data_load = pd.concat([eco2mix_load_real_time, eco2mix_load_consolidated], ignore_index=True)

    year = 2012 if region == "national" else 2013
    eco2mix_load_path_root = "Inputs/rte/conso_nat/" if region == "national" else "Inputs/rte/conso_regions/" + region + "/"
    while Path(eco2mix_load_path_root + "eCO2mix_RTE_" + region_encoding + "Annuel-Definitif_" + str(
            year) + ".xls").is_file():
        eco2mix_load_final = read_load(
            eco2mix_load_path=eco2mix_load_path_root + "eCO2mix_RTE_" + region_encoding + "Annuel-Definitif_" + str(
                year) + ".xls")
        nat_or_reg_data_load = pd.concat([nat_or_reg_data_load, eco2mix_load_final],
                                         ignore_index=True)
        year = year + 1

    nat_or_reg_data_load = nat_or_reg_data_load.rename(
        columns={"Date": "date_jour", "Heures": "heures", "Consommation": "Load"})
    nat_or_reg_data_load["date"] = nat_or_reg_data_load["date_jour"].astype(str).str[:11] + nat_or_reg_data_load[
        "heures"]
    nat_or_reg_data_load = nat_or_reg_data_load.loc[:, ["date", "Load"]]
    nat_or_reg_data_load["date"] = pd.to_datetime(nat_or_reg_data_load["date"], utc=True)
    nat_or_reg_data_load = nat_or_reg_data_load.sort_values(by='date').reset_index(drop=True)
    nat_or_reg_data_load.loc[nat_or_reg_data_load['Load'] == "ND", 'Load'] = np.nan
    nat_or_reg_data_load['Load'] = pd.to_numeric(nat_or_reg_data_load['Load'])
    return nat_or_reg_data_load

def interpolation_data_load(data, var='Load'):
    #logging.info("avant interpolation")
    #Rsummary(data[[var]])

    data_interpolated_one_na = data.copy()
    data_interpolated_one_na[var + "_lag1"] = data_interpolated_one_na[var].shift(1)
    data_interpolated_one_na[var + "_lead1"] = data_interpolated_one_na[var].shift(-1)

    data_interpolated_one_na[var + "_interpolate"] = data_interpolated_one_na[var].interpolate(method='linear', limit=1,
                                                                                limit_direction="both")

    mask_only_one_consecutive_na = (data_interpolated_one_na[var + "_lag1"].notna()) & (
        data_interpolated_one_na[var].isna()) & (data_interpolated_one_na[var + "_lead1"].notna())
    data_interpolated_one_na.loc[mask_only_one_consecutive_na, var] = data_interpolated_one_na.loc[
        mask_only_one_consecutive_na, var + '_interpolate']

    del (data_interpolated_one_na[var + "_lag1"], data_interpolated_one_na[var + "_lead1"],
         data_interpolated_one_na[var + "_interpolate"])

    #logging.info("après interpolation")
    #Rsummary(data_interpolated_one_na[[var]])

    return data_interpolated_one_na

def process_rte_raw_datas(date_start=dt.datetime(2013, 1, 1, 0, 0, 0, tzinfo=dt.timezone.utc),
                          date_end=dt.datetime(2023, 2, 1, 0, 0, 0, tzinfo=dt.timezone.utc),
                          return_data_load=False):
    """
    A function used to process the eco2mix Power-related data (*) (real-time, consolidated and final): this data
    concerns France, its 12 administrative regions and its 21 metropolitan areas.
        real-time data : real-time smart devices data + estimation when data non available
        consolidated data : rte and enedis measured data (available after one month)
        final data : rte and local distribution entities (enedis, municipalities, etc.) measured data (available after
        one year)
    The "Load" or "Load_region" extracted is the national or regional power-related french electricity consumption,
    unit of measure = MW
    (*) https://www.rte-france.com/en/eco2mix/download-indicators

    ...

    Parameters
    ----------
    date_start : datetime64[ns, tz], optional
        The beginning date of the rte dataset (default is dt.datetime(2013, 1, 1, 0, 0, 0, tzinfo=dt.timezone.utc))
    date_end : datetime64[ns, tz], optional
        The end date of the rte dataset (default is dt.datetime(2023, 12, 31, 23, 30, 0, tzinfo=dt.timezone.utc))
    return_data_load : bool, optional
        (default is False)

    Returns
    -------
    Feather file
        rte.feather
    DataFrame, optional
        rte data_load

    """
    print("Processing the electricity load data:")
    logging.info("ELECTRICITY DATA LOADING")

    data_load = pd.DataFrame()
    for region in regions:
        nat_or_reg_data_load = create_nat_or_reg_data_load(region=region)

        nat_or_reg_data_load = interpolation_data_load(nat_or_reg_data_load)

        nat_or_reg_data_load.columns = ['date', 'Load'] if region == "national" else ['date', 'Load_' + region]

        nat_or_reg_data_load = nat_or_reg_data_load[
            ((nat_or_reg_data_load['date'] >= date_start) &
             (nat_or_reg_data_load['date'] <= date_end))]

        data_load = nat_or_reg_data_load if region == "national" else data_load.merge(
            nat_or_reg_data_load, on="date", how='left')

    Rsummary(data_load)

    # save rte data
    data_load.to_feather("Outputs/rte.feather")

    if return_data_load:
        return data_load


from flask_socketio import SocketIO
from field_capture import celery
from field_capture.main import game_objects
from flask import current_app
import os

broker = os.environ.get('AMQP_BROKER')
socketio = SocketIO(message_queue=broker, async_mode='threading')

@celery.task(name="task.clock")
def game_clock(room_id, current_player_id, number_of_moves):
    app = current_app._get_current_object()
    with app.app_context():
        room_manager = game_objects.RoomManager(room_id)
        if room_manager.get_number_of_moves() == number_of_moves:
            socketio.emit('stop_game_clock', current_player_id, room=room_id)

@celery.task(name="task.message")
def async_board_message(room_id, message, color, number_of_moves):
    app = current_app._get_current_object()
    message_list = [{color:message}]
    with app.app_context():
        room_manager = game_objects.RoomManager(room_id)
        if room_manager.get_number_of_moves() == number_of_moves:
            socketio.emit('inf_board_message', message_list, room=room_id)


# 导入所需的库，例如numpy
import numpy as np

def identify_signal(preprocessed_signal):
    """
    识别预处理过的信号的类型。

    参数:
        preprocessed_signal (np.array): 预处理过的信号。

    返回:
        signal_type (str): 信号的类型，例如'AM', 'FM', 'CW', '2ASK', '2PSK', '2FSK'。
    """

    if np.max(preprocessed_signal) > 0.5:
        signal_type = 'AM'
    else:
        signal_type = 'Unknown'

    return signal_type


"""
Given two strings s and t, determine if they are isomorphic.

Two strings are isomorphic if the characters in s can be replaced to get t.

All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.

Example 1:

Input: s = "egg", t = "add"
Output: true
Example 2:

Input: s = "foo", t = "bar"
Output: false
Example 3:

Input: s = "paper", t = "title"
Output: true
Note:
You may assume both s and t have the same length.

Solution 1 : For both s and t, create hashmaps, which keep track of the indexes at which each char occurs.
             eg, abba, bbaa
                 hm1 will be {a: [0,3], b: [1,2]} and hm2 will be {a: [2,3], a: [0,1]}
                 Now get the values and sort it by the vals.
                 So it will be val1 = [[0,3], [1,2]] and val2 = [[0,1], [2,3]]
                 Now check if both are equal.
            Time complexity : O(N)
            Space complexity : O(Nlog(N)) -> since sorting is involved.

Solution 2: At each point, assume you are replacing the character at s with the character at t.
            This will work only if they are isomorphic. Hence at each point, see if you had used this character before.
            This can be done by using two hashmaps, one for s to t transformation, and one for the reverse transformation.

            Why do you need to check both ways? ab and aa case. If you check only ab to aa case, there won't be any issues
            since you will use a for both a and b, which is wrong

            Time complexity : O(N)
            Space complexity : O(N)

"""

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        if not s and not t:
            return True
        hm1 = {}
        hm2 = {}
        for i in range(len(s)):
            hm1[s[i]] = hm1.get(s[i], []) + [i]
            hm2[t[i]] = hm2.get(t[i], []) + [i]
        return sorted(hm1.values()) == sorted(hm2.values())

    def isIsomorphicBetter(self, s: str, t: str) -> bool:
        if not s and not t:
            return True
        s2t = {}
        t2s = {}
        for i in range(len(s)):
            if s[i] in s2t and s2t[s[i]] != t[i]:
                return False
            if t[i] in t2s and t2s[t[i]] != s[i]:
                return False
            s2t[s[i]] = t[i]
            t2s[t[i]] = s[i]
        return True


from django.shortcuts import render

def homepage_view(request):
    return render(request, 'homepage.html', {
        'title': 'Django Ecommerce',
        'services': [{
            'name': 'Happy clients',
            'value': '1000+',
        }, {
            'name': 'Available products',
            'value': '2000+'
        }, {
            'name': 'Reviews',
            'value': '4.9/5'
        }]
    })


# importando a biblioteca moviepy e as biblioteca para interface grafica
from moviepy.editor import *
from tkinter import *
from tkinter import filedialog

# funcao responsavel por realizar a conversão
def convert_video():
    # abre a janela de seleção de arquivos para selecionar o video
    video_file = filedialog.askopenfilename(title = "Selecione o arquivo de vídeo", filetypes = (("mp4 files", "*.mp4"), ("all files", "*.*")))
    # abre a janela para selecionar onde salvar o arquivo de audio
    audio_file = filedialog.asksaveasfilename(title = "Salvar arquivo de audio", defaultextension=".mp3")
    # carrega o video selecionado
    video = VideoFileClip(video_file)
    # extrai o audio do video e salva em audio_file
    video.audio.write_audiofile(audio_file)

# criação da janela principal
root = Tk()
root.title("Conversor de video para mp3")
root.geometry("200x50")

# criação do botao convert
convert_button = Button(root, text="Converter", command=convert_video)
convert_button.pack()

# inicialização da janela
root.mainloop()


import numpy as np
import scipy.sparse as sp

from discretize.tests import check_derivative

from .maps import IdentityMap
from .props import BaseSimPEG
from .utils import timeIt, Zero, Identity

__all__ = ["BaseObjectiveFunction", "ComboObjectiveFunction", "L2ObjectiveFunction"]

class BaseObjectiveFunction(BaseSimPEG):
    """
    Base Objective Function

    Inherit this to build your own objective function. If building a
    regularization, have a look at
    :class:`SimPEG.regularization.BaseRegularization` as there are additional
    methods and properties tailored to regularization of a model. Similarly,
    for building a data misfit, see :class:`SimPEG.DataMisfit.BaseDataMisfit`.
    """

    map_class = IdentityMap  #: Base class of expected maps

    def __init__(
        self,
        nP=None,
        mapping=None,
        has_fields=False,
        counter=None,
        debug=False,
    ):
        self._nP = nP
        if mapping is None:
            self._mapping = mapping
        else:
            self.mapping = mapping
        self.counter = counter
        self.debug = debug
        self.has_fields = has_fields

    def __call__(self, x, f=None):
        """
        Evaluate the objective functions for a given model
        """
        raise NotImplementedError(
            "__call__ has not been implemented for {} yet".format(
                self.__class__.__name__
            )
        )

    @property
    def nP(self):
        """
        Number of model parameters expected.
        """
        if self._nP is not None:
            return self._nP
        if getattr(self, "mapping", None) is not None:
            return self.mapping.nP
        return "*"

    @property
    def _nC_residual(self):
        """
        Shape of the residual
        """
        if getattr(self, "mapping", None) is not None:
            return self.mapping.shape[0]
        else:
            return self.nP

    @property
    def mapping(self):
        """
        A `SimPEG.Maps` instance
        """
        if self._mapping is None:
            if self._nP is not None:
                self._mapping = self.map_class(nP=self.nP)
            else:
                self._mapping = self.map_class()
        return self._mapping

    @mapping.setter
    def mapping(self, value):
        if not isinstance(value, self.map_class):
            raise TypeError(
                f"Invalid mapping of class '{value.__class__.__name__}'. "
                f"It must be an instance of {self.map_class.__name__}"
            )
        self._mapping = value

    @timeIt
    def deriv(self, x, **kwargs):
        """
        First derivative of the objective function with respect to the model
        """
        raise NotImplementedError(
            "The method deriv has not been implemented for {}".format(
                self.__class__.__name__
            )
        )

    @timeIt
    def deriv2(self, x, v=None, **kwargs):
        """
        Second derivative of the objective function with respect to the model
        """
        raise NotImplementedError(
            "The method _deriv2 has not been implemented for {}".format(
                self.__class__.__name__
            )
        )

    def _test_deriv(self, x=None, num=4, plotIt=False, **kwargs):
        print("Testing {0!s} Deriv".format(self.__class__.__name__))
        if x is None:
            if self.nP == "*":
                x = np.random.randn(np.random.randint(1e2, high=1e3))
            else:
                x = np.random.randn(self.nP)

        return check_derivative(
            lambda m: [self(m), self.deriv(m)], x, num=num, plotIt=plotIt, **kwargs
        )

    def _test_deriv2(self, x=None, num=4, plotIt=False, **kwargs):
        print("Testing {0!s} Deriv2".format(self.__class__.__name__))
        if x is None:
            if self.nP == "*":
                x = np.random.randn(np.random.randint(1e2, high=1e3))
            else:
                x = np.random.randn(self.nP)

        v = x + 0.1 * np.random.rand(len(x))
        expectedOrder = kwargs.pop("expectedOrder", 1)
        return check_derivative(
            lambda m: [self.deriv(m).dot(v), self.deriv2(m, v=v)],
            x,
            num=num,
            expectedOrder=expectedOrder,
            plotIt=plotIt,
            **kwargs,
        )

    def test(self, x=None, num=4, **kwargs):
        """
        Run a convergence test on both the first and second derivatives - they
        should be second order!
        """
        deriv = self._test_deriv(x=x, num=num, **kwargs)
        deriv2 = self._test_deriv2(x=x, num=num, plotIt=False, **kwargs)
        return deriv & deriv2

    __numpy_ufunc__ = True

    def __add__(self, other):
        if isinstance(other, Zero):
            return self
        if not isinstance(other, BaseObjectiveFunction):
            raise TypeError(
                f"Cannot add type '{other.__class__.__name__}' to an objective "
                "function. Only ObjectiveFunctions can be added together."
            )
        objective_functions, multipliers = [], []
        for instance in (self, other):
            if isinstance(instance, ComboObjectiveFunction) and instance._unpack_on_add:
                objective_functions += instance.objfcts
                multipliers += instance.multipliers
            else:
                objective_functions.append(instance)
                multipliers.append(1)
        combo = ComboObjectiveFunction(
            objfcts=objective_functions, multipliers=multipliers
        )
        return combo

    def __radd__(self, other):
        return self + other

    def __mul__(self, multiplier):
        return ComboObjectiveFunction(objfcts=[self], multipliers=[multiplier])

    def __rmul__(self, multiplier):
        return self * multiplier

    def __div__(self, denominator):
        return self * (1.0 / denominator)

    def __truediv__(self, denominator):
        return self * (1.0 / denominator)

    def __rdiv__(self, denominator):
        return self * (1.0 / denominator)

class ComboObjectiveFunction(BaseObjectiveFunction):
    """
    Composite for multiple objective functions

    A composite class for multiple objective functions. Each objective function
    is accompanied by a multiplier. Both objective functions and multipliers
    are stored in a list.

    Parameters
    ----------
    objfcts : list or None, optional
        List containing the objective functions that will live inside the
        composite class. If ``None``, an empty list will be created.
    multipliers : list or None, optional
        List containing the multipliers for its respective objective function
        in ``objfcts``.  If ``None``, a list full of ones with the same length
        as ``objfcts`` will be created.
    unpack_on_add : bool, optional
        Weather to unpack the multiple objective functions when adding them to
        another objective function, or to add them as a whole.

    Examples
    --------
    Build a simple combo objective function:

    >>> objective_fun_a = L2ObjectiveFunction(nP=3)
    >>> objective_fun_b = L2ObjectiveFunction(nP=3)
    >>> combo = ComboObjectiveFunction([objective_fun_a, objective_fun_b], [1, 0.5])
    >>> print(len(combo))
    2
    >>> print(combo.multipliers)
    [1, 0.5]

    Combo objective functions are also created after adding two objective functions:

    >>> combo = 2 * objective_fun_a + 3.5 * objective_fun_b
    >>> print(len(combo))
    2
    >>> print(combo.multipliers)
    [2, 3.5]

    We could add two combo objective functions as well:

    >>> objective_fun_c = L2ObjectiveFunction(nP=3)
    >>> objective_fun_d = L2ObjectiveFunction(nP=3)
    >>> combo_1 = 4.3 * objective_fun_a + 3 * objective_fun_b
    >>> combo_2 = 1.5 * objective_fun_c + 0.5 * objective_fun_d
    >>> combo = combo_1 + combo_2
    >>> print(len(combo))
    4
    >>> print(combo.multipliers)
    [4.3, 3, 1.5, 0.5]

    We can choose to not unpack the objective functions when creating the
    combo. For example:

    >>> objective_fun_a = L2ObjectiveFunction(nP=3)
    >>> objective_fun_b = L2ObjectiveFunction(nP=3)
    >>> objective_fun_c = L2ObjectiveFunction(nP=3)
    >>>
    >>> # Create a ComboObjectiveFunction that won't unpack
    >>> combo_1 = ComboObjectiveFunction(
    ...     objfcts=[objective_fun_a, objective_fun_b],
    ...     multipliers=[0.1, 1.2],
    ...     unpack_on_add=False,
    ... )
    >>> combo_2 = combo_1 + objective_fun_c
    >>> print(len(combo_2))
    2
    """

    _multiplier_types = (float, None, Zero, np.float64, int, np.integer)

    def __init__(self, objfcts=None, multipliers=None, unpack_on_add=True):
        # Define default lists if None
        if objfcts is None:
            objfcts = []
        if multipliers is None:
            multipliers = len(objfcts) * [1]

        # Validate inputs
        self._check_length_objective_funcs_multipliers(objfcts, multipliers)
        self._validate_objective_functions(objfcts)
        self._validate_multipliers(multipliers)

        # Get number of parameters (nP) from objective functions
        number_of_parameters = [f.nP for f in objfcts if f.nP != "*"]
        if number_of_parameters:
            nP = number_of_parameters[0]
        else:
            nP = None

        super().__init__(nP=nP)
        self.objfcts = objfcts
        self._multipliers = multipliers
        self._unpack_on_add = unpack_on_add

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

    def __getitem__(self, key):
        return self.multipliers[key], self.objfcts[key]

    @property
    def multipliers(self):
        """
        Multipliers for each objective function
        """
        return self._multipliers

    @multipliers.setter
    def multipliers(self, value):
        """
        Set multipliers attribute after checking if they are valid
        """
        self._validate_multipliers(value)
        self._check_length_objective_funcs_multipliers(self.objfcts, value)
        self._multipliers = value

    def __call__(self, m, f=None):
        """
        Evaluate the objective functions for a given model
        """
        fct = 0.0
        for i, phi in enumerate(self):
            multiplier, objfct = phi
            if multiplier == 0.0:  # don't evaluate the fct
                continue
            if f is not None and objfct.has_fields:
                objective_func_value = objfct(m, f=f[i])
            else:
                objective_func_value = objfct(m)
            fct += multiplier * objective_func_value
        return fct

    def deriv(self, m, f=None):
        """
        First derivative of the composite objective function is the sum of the
        derivatives of each objective function in the list, weighted by their
        respective multplier.

        :param numpy.ndarray m: model
        :param SimPEG.Fields f: Fields object (if applicable)
        """
        g = Zero()
        for i, phi in enumerate(self):
            multiplier, objfct = phi
            if multiplier == 0.0:  # don't evaluate the fct
                continue
            if f is not None and objfct.has_fields:
                aux = objfct.deriv(m, f=f[i])
            else:
                aux = objfct.deriv(m)
            if not isinstance(aux, Zero):
                g += multiplier * aux
        return g

    def deriv2(self, m, v=None, f=None):
        """
        Second derivative of the composite objective function is the sum of the
        second derivatives of each objective function in the list, weighted by
        their respective multplier.

        :param numpy.ndarray m: model
        :param numpy.ndarray v: vector we are multiplying by
        :param SimPEG.Fields f: Fields object (if applicable)
        """
        H = Zero()
        for i, phi in enumerate(self):
            multiplier, objfct = phi
            if multiplier == 0.0:  # don't evaluate the fct
                continue
            if f is not None and objfct.has_fields:
                objfct_H = objfct.deriv2(m, v, f=f[i])
            else:
                objfct_H = objfct.deriv2(m, v)
            H = H + multiplier * objfct_H
        return H

    # This assumes all objective functions have a W.
    # The base class currently does not.
    @property
    def W(self):
        """
        W matrix for the full objective function. Includes multiplying by the
        square root of alpha.
        """
        W = []
        for mult, fct in self:
            curW = np.sqrt(mult) * fct.W
            if not isinstance(curW, Zero):
                W.append(curW)
        return sp.vstack(W)

    def get_functions_of_type(self, fun_class) -> list:
        """
        Find an objective function type from a ComboObjectiveFunction class.
        """
        target = []
        if isinstance(self, fun_class):
            target += [self]
        else:
            for fct in self.objfcts:
                if isinstance(fct, ComboObjectiveFunction):
                    target += [fct.get_functions_of_type(fun_class)]
                elif isinstance(fct, fun_class):
                    target += [fct]

        return [fun for fun in target if fun]

    def _validate_objective_functions(self, objective_functions):
        """
        Validate objective functions

        Check if the objective functions have the right types, and if
        they all have the same number of parameters.
        """
        for function in objective_functions:
            if not isinstance(function, BaseObjectiveFunction):
                raise TypeError(
                    "Unrecognized objective function type "
                    f"{function.__class__.__name__} in 'objfcts'. "
                    "All objective functions must inherit from BaseObjectiveFunction."
                )
        number_of_parameters = [f.nP for f in objective_functions if f.nP != "*"]
        if number_of_parameters:
            all_equal = all(np.equal(number_of_parameters, number_of_parameters[0]))
            if not all_equal:
                np_list = [f.nP for f in objective_functions]
                raise ValueError(
                    f"Invalid number of parameters '{np_list}' found in "
                    "objective functions. Except for the ones with '*', they all "
                    "must have the same number of parameters."
                )

    def _validate_multipliers(self, multipliers):
        """
        Validate multipliers

        Check if the multipliers have the right types.
        """
        for multiplier in multipliers:
            if type(multiplier) not in self._multiplier_types:
                valid_types = ", ".join(str(t) for t in self._multiplier_types)
                raise TypeError(
                    f"Invalid multiplier '{multiplier}' of type '{type(multiplier)}'. "
                    "Objective functions can only be multiplied by " + valid_types
                )

    def _check_length_objective_funcs_multipliers(
        self, objective_functions, multipliers
    ):
        """
        Check if objective functions and multipliers have the same length
        """
        if len(objective_functions) != len(multipliers):
            raise ValueError(
                "Inconsistent number of elements between objective functions "
                f"('{len(objective_functions)}') and multipliers "
                f"('{len(multipliers)}'). They must have the same number of parameters."
            )

class L2ObjectiveFunction(BaseObjectiveFunction):
    r"""
    An L2-Objective Function

    .. math::

        \phi = \frac{1}{2}||\mathbf{W} \mathbf{m}||^2
    """

    def __init__(
        self,
        nP=None,
        mapping=None,
        W=None,
        has_fields=False,
        counter=None,
        debug=False,
    ):
        # Check if nP and shape of W are consistent
        if W is not None and nP is not None and nP != W.shape[1]:
            raise ValueError(
                f"Number of parameters nP ('{nP}') doesn't match the number of "
                f"rows ('{W.shape[1]}') of the weights matrix W."
            )
        super().__init__(
            nP=nP,
            mapping=mapping,
            has_fields=has_fields,
            debug=debug,
            counter=counter,
        )
        if W is not None and self.nP == "*":
            self._nP = W.shape[1]
        self._W = W

    @property
    def W(self):
        """
        Weighting matrix. The default if not specified is an identity.
        """
        if getattr(self, "_W", None) is None:
            if self._nC_residual != "*":
                self._W = sp.eye(self._nC_residual)
            else:
                self._W = Identity()
        return self._W

    def __call__(self, m):
        """
        Evaluate the objective functions for a given model
        """
        r = self.W * (self.mapping * m)
        return 0.5 * r.dot(r)

    def deriv(self, m):
        """
        First derivative with respect to the model

        :param numpy.ndarray m: model
        """
        return self.mapping.deriv(m).T * (self.W.T * (self.W * (self.mapping * m)))

    def deriv2(self, m, v=None):
        """
        Second derivative with respect to the model

        :param numpy.ndarray m: model
        :param numpy.ndarray v: vector to multiply by
        """
        if v is not None:
            return self.mapping.deriv(m).T * (
                self.W.T * (self.W * (self.mapping.deriv(m) * v))
            )
        W = self.W * self.mapping.deriv(m)
        return W.T * W


from .models import *
from .forms import *
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse

@login_required
def account_redirect(request):
    return redirect('account-landing', pk=request.user.pk, name=request.user.username)

def post_list(request):
    posts = Post.objects.all().order_by('-date_created')
    return render(request, 'reddit/post_list.html',  {'posts': posts})

@login_required
def post_new(request):
    context = {}
    if request.method == "POST":
        form = PostForm(request.POST,request.FILES)
        if form.is_valid():

            post = form.save(commit=False)
            post.submitter = request.user
            post.save()

            for subreddit_id in request.POST.getlist('subreddits'):
                SubRedditPost.objects.create(subreddit_id=subreddit_id, post=post)
            return redirect('post_detail', pk=post.pk)

    else:
        form = PostForm()
        context['form'] = form
    return render(request, 'reddit/post_edit.html', {'form': form, 'is_create': True})

@login_required
def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post, initial={'subreddits' : post.subreddits.all()})
    return render(request, 'reddit/post_edit.html', {'form': form, 'is_create': False})

def post_detail(request, pk):

    post = get_object_or_404(Post, pk=pk)
    return render(request, 'reddit/post_detail.html', {'post': post})

def sub_detail(request, pk):
    sub = get_object_or_404(SubReddit, pk=pk)
    return render(request, 'reddit/sub_detail.html', {'sub': sub})

@login_required
def add_comment(request, pk, parent_pk=None):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.post = post
            comment.author = request.user
            comment.parent_id = parent_pk
            comment.save()
        return redirect('post_detail', pk=post.pk)
    else:
        form = CommentForm()
    return render(request, 'reddit/add_comment.html', {'form': form})

# Create your views here.
def home_view(request):
    context = {}
    context['form'] = PostForm()
    return render( request, "base.html", context)

def display_images(request):

    if request.method == 'GET':

        # getting all the objects of hotel.
       post = Post.objects.all()
       return render((request, 'post_detail.html',
                     {'images' : post}))


def isEven(x):
    if x == 0:
        return True
    else:
        return isOdd(x-1)

def isOdd(x):
    if x == 0:
        return False
    else:
        return isEven(x-1)

print(isEven(3))
print(isOdd(3))

print(isEven(10))
print(isOdd(10))


from pages.comparisonPage.comparison_page import ComparisonPage
from utilities.status import Status
import unittest
import pytest
from ddt import ddt, data, unpack
from utilities.read_data import getCSVData

@pytest.mark.usefixtures("oneTimeSetUp", "setUp")
class ComparisonTests(unittest.TestCase):

    @pytest.fixture(autouse=True)
    def classSetup(self, oneTimeSetUp):
        self.cp = ComparisonPage(self.driver)
        self.ts = Status(self.driver)

    # Need to verify two verification points
    # 1 fails, code will not go to the next verification point
    # If assert fails, it stops current test execution and
    # moves toaceEmail() the next test method

    # @pytest.mark.run(order=1)
    # def test_comparison_package(self):
    #     self.cp.closeCookie()
    #     self.cp.GoToPackageAndTab("Stor", "Viaplay")
    #     result = self.cp.verify_comparison_title()
    #     self.ts.mark(result, "verify package title")
    #     result2 = self.cp.verify_comparison_description()
    #     self.ts.mark(result2, "Verify package description")
    #
    # @pytest.mark.run(order=2)
    # def test_comparison_package2(self):
    #     self.cp.GoToPackageAndTab("Bas","Playtjänster")
    #     result = self.cp.verify_comparison_title()
    #     self.ts.mark(result, "verify package title")
    #     result2 = self.cp.verify_comparison_description()
    #     self.ts.markFinal("Test_comparison_nave", result2, "verify package description")
    #

    @pytest.mark.run(order=2)
    def test_comparison_page(self):
        # self.cp.closeCookie()
        self.cp.GoToPackageAndTab("Stor", "Tv-kanaler")
        result = self.cp.verify_comparison_title()
        self.ts.mark(result, "verify package title")
        result2 = self.cp.verify_comparison_description()
        self.ts.mark(result2, "verify package title")
        self.cp.openAllLogos()
        self.ts.markFinal("Test_comparison_nave", result2, "verify package description")

    # @pytest.mark.run(order=1)
    # def test_comparison_page_all(self):
    #     self.cp.closeCookie()
    #     self.cp.openAllPackagesTabsAndLogos()
    #


import logging
import os

from datetime import timedelta
from hashlib import md5
from mimetypes import guess_extension
from urllib.parse import quote, unquote_plus

from django.conf import settings
from django.utils import timezone

from .browser import RequestBrowser
from .html_asset import HTMLAsset
from .url import sanitize_url
from .utils import http_date_format

logger = logging.getLogger('html_snapshot')

# https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#heuristic_caching
HEURISTIC_CACHE_THRESHOLD_PERCENT = 10
HTML_SNAPSHOT_HASH_LEN = 10

def max_filename_size():
    return os.statvfs(settings.SOSSE_HTML_SNAPSHOT_DIR).f_namemax

class CacheHit(Exception):
    def __init__(self, asset):
        self.asset = asset

class CacheMiss(Exception):
    pass

class CacheRefresh(Exception):
    def __init__(self, page):
        self.page = page

class HTMLCache():
    # https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#expires_or_max-age
    @staticmethod
    def _max_age_check(asset, max_file_size):
        if (asset.max_age and asset.last_modified) or asset.etag:
            if asset.max_age and asset.last_modified and asset.last_modified + timedelta(seconds=asset.max_age) >= timezone.now():
                logger.debug('cache hit, max_age')
                raise CacheHit(asset)
            else:
                logger.debug('cache miss, max_age, %s + %s > %s', asset.last_modified, asset.max_age, timezone.now())

                # https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#validation
                if not asset.has_cache_control:
                    logger.debug('cache miss, max_age, no cache control')
                    raise CacheMiss()

                headers = {
                    'Accept': '*/*',
                    'If-Modified-Since': http_date_format(asset.download_date)
                }

                if asset.etag:
                    headers['If-None-Match'] = asset.etag

                page = RequestBrowser.get(asset.url,
                                          check_status=True,
                                          max_file_size=max_file_size,
                                          headers=headers)

                if page.status_code == 304:
                    # http not modified
                    logger.debug('cache hit, max_age, cache control, not modified')
                    raise CacheHit(asset)

                logger.debug('cache refresh, max_age, cache control, refresh')
                raise CacheRefresh(page)

    # https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#heuristic_caching
    @staticmethod
    def _heuristic_check(asset):
        if asset.download_date and asset.last_modified:
            dt = asset.download_date - asset.last_modified
            dt = (dt.total_seconds() * HEURISTIC_CACHE_THRESHOLD_PERCENT) / 100
            dt = timedelta(seconds=dt)
            if asset.download_date + dt > timezone.now():
                logger.debug('cache hit, heuristic_caching')
                raise CacheHit(asset)
            else:
                logger.debug('cache miss, heuristic_caching, %s + %s < %s', asset.download_date, dt, timezone.now())
                raise CacheMiss()

    @staticmethod
    def _cache_check(url, max_file_size):
        asset = HTMLAsset.objects.filter(url=url).order_by('download_date').last()

        if not asset:
            logger.debug('cache miss, asset does not exist')
            raise CacheMiss()

        if asset.download_date is None:
            logger.debug('cache miss, force refresh')
            raise CacheMiss()

        HTMLCache._max_age_check(asset, max_file_size)
        HTMLCache._heuristic_check(asset)
        logger.debug('cache miss, cache outdated')
        raise CacheMiss()

    @staticmethod
    def download(url, max_file_size):
        try:
            HTMLCache._cache_check(url, max_file_size)
        except CacheHit as e:
            e.asset.increment_ref()
            raise
        except CacheRefresh as e:
            return e.page
        except CacheMiss:
            pass

        page = RequestBrowser.get(url,
                                  check_status=True,
                                  max_file_size=max_file_size,
                                  headers={'Accept': '*/*'})
        return page

    @staticmethod
    def create_cache_entry(url, filename, page=None):
        asset, created = HTMLAsset.objects.get_or_create(url=url, filename=filename)

        if created:
            asset.init_ref_count()

        asset.increment_ref()

        if page:
            asset.update_from_page(page)

        return asset

    @staticmethod
    def write_asset(url, content, page, extension=None, mimetype=None):
        assert isinstance(content, bytes)

        logger.debug('html_write_asset for %s', url)
        _hash = md5(content).hexdigest()[:HTML_SNAPSHOT_HASH_LEN]

        # Build the extension using mimetypes, because the appropriate extension
        # is required by Nginx when the file is served statically
        if extension is None:
            assert mimetype is not None
            extension = guess_extension(mimetype)
            if extension is None:
                _, ext = url.rsplit('.', 1)
                if '?' in ext:
                    ext, _ = ext.split('?', 1)

                if '/' in ext:
                    extension = '.bin'
                else:
                    extension = f'.{ext}'

        url = sanitize_url(url)
        filename_url = HTMLCache.html_filename(url, _hash, extension)
        dest = os.path.join(settings.SOSSE_HTML_SNAPSHOT_DIR, filename_url)
        dest_dir, _ = dest.rsplit('/', 1)
        os.makedirs(dest_dir, 0o755, exist_ok=True)

        with open(dest, 'wb') as fd:
            fd.write(content)

        return HTMLCache.create_cache_entry(url, filename_url, page)

    @staticmethod
    def html_filename(url, _hash, extension):
        assert extension.startswith('.')

        # replace http:// by http:/
        url = url.replace('//', '/')

        # Unquote before requoting
        url = unquote_plus(url)
        # Replace % by , to prevent interpration of the escape by nginx
        url = quote(url).replace('%', ',')

        # Make sure the filename is not longer than supported by the filesystem
        parts = url.split('/')
        _parts = []
        for no, part in enumerate(parts):
            if no == len(parts) - 1:
                max_len = max_filename_size() - HTML_SNAPSHOT_HASH_LEN - len(extension) - 1
                if len(part) > max_len:
                    part = part[:max_len]
                part = f'{part}_{_hash}{extension}'
            else:
                if len(part) > max_filename_size():
                    part = part[:max_filename_size() - HTML_SNAPSHOT_HASH_LEN - 1]
                    part = f'{part}_{_hash}'

            _parts.append(part)
        return '/'.join(_parts)


import array
import random
import math

import pyglet

from .resources import get_image, TILE_WIDTH, HALF_FONT_INFO
from .util import pushed_matrix, UP, DOWN, LEFT, RIGHT
from .caterpillar import Caterpillar
from .coccoon import Cocoon
from .level import load_level_to_grid
from . import tiles

SPEED = 2

class Grid:
    def __init__(self, state, egg=None, level=0, ui=None):
        self.state = state
        self.ui = ui
        self.egg = egg
        self.width = 31
        self.height = 17
        self.tiles = {}
        self.caterpillar = None
        self.caterpillar_opacity = 255
        self.sprites = {}
        self.eol_tiles = []
        self.batch = pyglet.graphics.Batch()
        self.score_batch = pyglet.graphics.Batch()
        self.displayed_score = 0
        self.t = 0
        self.gameover_t = None
        self.total_score = 0
        self.score_labels = []
        self.cocoon = None
        self.done = False
        self.background = pyglet.image.TileableTexture. create_for_image(
            get_image('tile', 0, 0, 2, 2)
        )
        self.level = int(level)
        self.autogrow_flowers = True
        self.collected_sprites = {}
        if level == 0:
            self.add_caterpillar()
            self.init_level0()
        else:
            load_level_to_grid(level, self)

        self.main_score_label = pyglet.text.Label(
            f'',
            **HALF_FONT_INFO.label_args(),
            anchor_x='right',
            anchor_y='baseline',
            align='center',
            batch=self.score_batch,
            x=(self.width - .5) * TILE_WIDTH,
            y=(self.height - .5) * TILE_WIDTH + HALF_FONT_INFO.baseline,
        )
        self.gameover_label = pyglet.text.Label(
            f'',
            **HALF_FONT_INFO.label_args(),
            anchor_x='left',
            anchor_y='baseline',
            align='center',
            batch=self.score_batch,
            color=(255, 255, 255, 255),
            x=-.5 * TILE_WIDTH,
            y=(self.height - .5) * TILE_WIDTH + HALF_FONT_INFO.baseline,
        )
        if not self.level:
            self.gameover_label.text = 'Crash to form a cocoon.'.upper()

        self.t = 1
        if self.caterpillar is None:
            self.add_caterpillar()
        #self.add_cocoon(self.caterpillar) ## debug

    def add_caterpillar(self, x=None, y=None, direction=(1, 0)):
        self.caterpillar = Caterpillar(
            self, self.egg or self.state.choose_egg(),
            x=x, y=y, direction=direction,
        )

    def init_level0(self):
        for x in range(self.width):
            for y in range(self.height):
                if random.randrange(7) < 2:
                    self[x, y] = 'grass'

        for x, y in (0, 2), (11, 5), (17, 5):
            self[x, y] = 'flower'

        head_x, head_y = self.caterpillar.segments[-1].xy
        self[head_x - 1, head_y] = None
        self[head_x + 0, head_y] = None
        self[head_x + 1, head_y] = 'grass'
        self[head_x + 2, head_y] = 'grass'
        self[head_x + 2, head_y].grow_flower()
        self[head_x + 3, head_y] = None
        self[head_x + 0, head_y - 1] = 'grass'
        self[head_x + 0, head_y + 1] = 'grass'

        for i, d in enumerate((
            #RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT,
            #RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT,
            #DOWN, LEFT, UP,
            #DOWN, DOWN, LEFT, LEFT, UP, UP, LEFT, LEFT, LEFT, LEFT, DOWN, DOWN,
            #RIGHT, RIGHT, DOWN, DOWN, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN,
            #RIGHT, RIGHT, UP, UP, RIGHT, RIGHT, #DOWN, DOWN, RIGHT, RIGHT, RIGHT, RIGHT,
            #UP, UP, LEFT, LEFT, UP, UP, RIGHT, RIGHT, UP, UP, UP, #LEFT
            #UP, UP, UP, *[LEFT]*10, *[DOWN]*1, *[RIGHT]*7, DOWN
        )):
            self.caterpillar.turn(d)
            self.caterpillar.step(force_eat=i>2)

    def add_a_flower(self, grass_only=False):
        if not self.autogrow_flowers:
            return False
        if grass_only == False:
            if self.add_a_flower(grass_only=True):
                return True
        xs = list(range(self.width))
        ys = list(range(self.width))
        random.shuffle(xs)
        random.shuffle(ys)
        caterpillar_xys = set(s.xy for s in self.caterpillar.segments)
        for x in xs:
            for y in ys:
                if (x, y) in caterpillar_xys:
                    continue
                tile = self.tiles.get((x, y))
                if tile is None:
                    if not grass_only:
                        self[x, y] = 'flower'
                        return True
                elif tile.grow_flower():
                    return True

    def draw(self):
        with pushed_matrix():
            pyglet.gl.glTranslatef(TILE_WIDTH/2, TILE_WIDTH/2, 1)
            pyglet.gl.glScalef(1/2, 1/2, 1)
            self.background.blit_tiled(
                0, 0, 0,
                self.width * TILE_WIDTH * 2, self.height * TILE_WIDTH * 2,
            )
            pyglet.gl.glScalef(2, 2, 1)
            pyglet.gl.glTranslatef(TILE_WIDTH/2, TILE_WIDTH/2, 0)
            self.batch.draw()
            self.caterpillar.draw()
            if self.cocoon:
                self.cocoon.draw()
            self.score_batch.draw()

    def tick(self, dt):
        self.t += dt
        self.caterpillar.tick(dt * SPEED)
        if self.cocoon:
            self.cocoon.tick(dt)
        self.eol_tiles = [tile for tile in self.eol_tiles if tile.tick(dt)]
        for tile in self.tiles.values():
            tile.tick(dt)
        if self.score_labels:
            new_score_labels = []
            for label in self.score_labels:
                t = self.t - label._caterpillar_start_t
                label.x = (label._caterpillar_x) * TILE_WIDTH
                label.y = (label._caterpillar_y + t + t**2*2) * TILE_WIDTH
                label.color = (*label._caterpillar_color, int(abs(1 - t)**.5 * 255))
                if t < 1:
                    new_score_labels.append(label)
                else:
                    label.delete()
            self.score_labels = new_score_labels
        if self.displayed_score != self.total_score:
            diff = (self.total_score - self.displayed_score)
            if diff < 1:
                self.displayed_score = self.total_score
            else:
                self.displayed_score += (self.total_score - self.displayed_score) * 0.1
                if diff > 1000:
                    self.displayed_score += 111
                if diff > 100:
                    self.displayed_score += 11
                elif diff > 10:
                    self.displayed_score += 1
                elif diff > 0:
                    self.displayed_score += 0.5
                else:
                    self.displayed_score -= 0.5
            if self.displayed_score:
                self.main_score_label.text = str(int(self.displayed_score))
            else:
                self.main_score_label.text = ''
        if self.gameover_t is not None:
            gt = (self.t - self.gameover_t)
            n = 30
            b = int(min(255-n, (255-n) * gt))
            o = int(math.sin(gt * math.tau / 2) * n)
            self.gameover_label.color = (
                b-o, b-o, b-o, 255
            )

    def handle_command(self, command):
        if command == 'up':
            self.caterpillar.turn(UP)
        elif command == 'down':
            self.caterpillar.turn(DOWN)
        elif command == 'left':
            self.caterpillar.turn(LEFT)
        elif command == 'right':
            self.caterpillar.turn(RIGHT)
        elif command == 'end' and self.ui:
            self.ui.activate()
            return True

    def __getitem__(self, x_y):
        x, y = x_y
        if x < 0 or y < 0 or x >= self.width or y >= self.height:
            return tiles.edge
        return self.tiles.get(x_y, tiles.empty)

    def __setitem__(self, x_y, item):
        eol_tile = self.tiles.pop(x_y, None)
        if eol_tile:
            self.eol_tiles.append(eol_tile)
            eol_tile.delete()
        x, y = x_y
        if x < 0 or y < 0 or x >= self.width or y >= self.height:
            return
        if item is not None:
            if isinstance(item, str):
                item = tiles.new(item, self, x, y)
            self.tiles[x_y] = item

    def add_cocoon(self, caterpillar):
        self.cocoon = Cocoon(self, caterpillar)

    def score(self, amount, x, y):
        self.total_score += amount
        if self.total_score <= 0:
            self.total_score = 0
        self.main_score_label.text = str(self.total_score)
        if not (0 < amount < 5):
            label = self.add_label(f'{amount:+1}', x, y)
            if amount > 0:
                label._caterpillar_color = 250, 255, 200
            else:
                label._caterpillar_color = 255, 230, 200

    def add_label(self, label, x, y):
        label = pyglet.text.Label(
            label,
            **HALF_FONT_INFO.label_args(),
            anchor_x='center',
            anchor_y='baseline',
            align='center',
            batch=self.score_batch,
            x=x * TILE_WIDTH,
            y=y * TILE_WIDTH,
        )
        self.score_labels.append(label)
        label._caterpillar_start_t = self.t
        label._caterpillar_x = x
        label._caterpillar_y = y
        label._caterpillar_color = 255, 255, 255
        return label

    def signal_done(self):
        if self.done:
            return True
        self.shot = pyglet.image.get_buffer_manager().get_color_buffer().get_texture()
        self.state.level_completed(
            self.level, self.total_score, self.caterpillar.collected_items,
            self.cocoon.butterfly,
        )
        if self.ui:
            self.ui.activate(self.shot)

    def signal_game_over(self, message):
        self.gameover_label.text = f'{message}    Press esc to exit.'.upper()
        self.gameover_t = self.t

    def update_collected(self, caterpillar):
        for item in caterpillar.collected_items.difference(self.collected_sprites):
            for i in range(100):
                for sprite in self.collected_sprites.values():
                    if sprite._caterpillar_i == i:
                        break
                else:
                    break
            sprite = pyglet.sprite.Sprite(
                get_image(item),
                x=(self.width-1/4) * TILE_WIDTH,
                y=(self.height - 3/4 - i/2) * TILE_WIDTH,
                batch=self.score_batch,
            )
            sprite._caterpillar_i = i
            sprite.scale = 1/4
            self.collected_sprites[item] = sprite
        for name, sprite in list(self.collected_sprites.items()):
            if name not in caterpillar.collected_items:
                sprite.delete()
                del self.collected_sprites[name]


# ****************************************************************************
#
# This file is part of the yasmine editing tool.
#
# yasmine (Yet Another Station Metadata INformation Editor), a tool to
# create and edit station metadata information in FDSN stationXML format,
# is a common development of IRIS and RESIF.
# Development and addition of new features is shared and agreed between * IRIS and RESIF.
#
#
# Version 1.0 of the software was funded by SAGE, a major facility fully
# funded by the National Science Foundation (EAR-1261681-SAGE),
# development done by ISTI and led by IRIS Data Services.
# Version 2.0 of the software was funded by CNRS and development led by * RESIF.
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version. *
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License (GNU-LGPL) for more details. *
# You should have received a copy of the GNU Lesser General Public
# License along with this software. If not, see
# <https://www.gnu.org/licenses/>
#
#
# 2019/10/07 : version 2.0.0 initial commit
#
# ****************************************************************************/

class NrlKeyCreator:

    def create_keys(self, sensors, dataloggers):
        return self.get_level_info(sensors), self.get_level_info(dataloggers)

    def get_level_info(self, level):
        data = []
        if not isinstance(level, tuple):
            try:
                for level_key in level.keys():
                    child = level[level_key]
                    if not isinstance(child, tuple):
                        data.append({
                            'text': level._question,
                            'key': level_key,
                            'leaf': False,
                            'children': self.get_level_info(level[level_key])
                        })
                    else:
                        data.append({
                            'key': level_key,
                            'text': child[0],
                            'leaf': True
                        })
            except:  # @IgnorePep8
                pass
        return data


colors = ["black", "white", "red", "pink", "yellow", "green", "aqua"]

black = '||black||'
white = '||white||'
red = '||red||'
pink = '||pink||'
yellow = '||yellow||'
green = '||green||'
lightgreen = '||#00ff00||'
aqua = '||aqua||'
blue = '||#3A96DD||'
reset = '||#BBBBBB||'
bg_white = "||bg.white||"


DOF = 7
import numpy as np
import pandas as pd
from scipy.spatial.transform import Rotation
from omni.isaac.core.utils.stage import add_reference_to_stage
from omni.isaac.core import World
from omni.isaac.core.utils.types import ArticulationAction
# from omni.isaac.franka.franka import Franka
from omni.isaac.manipulators.grippers import ParallelGripper
from omni.isaac.manipulators import SingleManipulator
from omni.isaac.core.objects import DynamicCuboid
import lula
import math_type_define.dyros_math as DyrosMath
import math

np.set_printoptions(precision=3, suppress=True)

class ArmController:
    def __init__(self, hz: float, world: World, pkg_path: str)->None:
        self.hz = hz
        self.world = world
        self.tick = 0
        self.play_time = 0.0
        self.control_mode = "none"
        self.is_mode_changed = False
        self.pkg_path = pkg_path
        self.file_names = ["Circle", "Square", "Eight"]
        self.is_teleop = False
        self.initDimension()
        self.initModel()
        self.initCube()
        self.initFile()

    def initDimension(self)->None:
        self.q_init = np.zeros(DOF)
        self.q = np.zeros(DOF)
        self.q_desired = np.zeros(DOF)
        self.qd_init = np.zeros(DOF)
        self.qd = np.zeros(DOF)
        self.torque = np.zeros(DOF)
        self.torque_desired = np.zeros(DOF)
        self.j = np.zeros((6, DOF))
        self.j_qd = np.zeros((6,DOF))
        self.pose_init = np.zeros((4,4))
        self.pose = np.zeros((4,4))
        self.pose_desired = np.zeros((4,4))
        self.pose_qd = np.zeros((4,4))
        self.gripper_pose_init = np.zeros(2)
        self.gripper_pose_desired = np.zeros(2)
        self.gripper_pose = np.zeros(2)
        self.action = ArticulationAction()
        self.event_index = 0
        self.gripper_mode = False

    def initModel(self)->None:
        model_path = self.pkg_path + "/model"
        # self.franka = self.world.scene.add(Franka(prim_path="/World/panda", name="franka_robot",
        #                                           end_effector_prim_name="panda_hand",
        #                                           gripper_dof_names = ["panda_finger_joint1", "panda_finger_joint2"],
        #                                           gripper_open_position = np.array([0.05, 0.05]),
        #                                           gripper_closed_position = np.array([0.0, 0.0]),))
        self.gripper = ParallelGripper(
            # end_effector_prim_path="/World/panda/panda_rightfinger",
            end_effector_prim_path="/World/panda/panda_hand",
            joint_prim_names=["panda_finger_joint1", "panda_finger_joint2"],
            joint_opened_positions=np.array([0.05, 0.05]),
            joint_closed_positions=np.array([0.0, 0.0]),
            action_deltas=np.array([0.05, 0.05]),
        )
        self.franka = self.world.scene.add(SingleManipulator(prim_path="/World/panda",
                                                             name="franka_robot",
                                                            #  end_effector_prim_name="panda_rightfinger",
                                                             end_effector_prim_name="panda_hand",
                                                             gripper=self.gripper))

        self.franka_controller = self.franka.get_articulation_controller()
        self.kinematic = lula.RobotDescription.kinematics(lula.load_robot(robot_description_file=model_path + "/panda_robot_description.yaml",
                                                             robot_urdf=model_path + "/panda_arm_hand.urdf"))
        joints_default_positions = np.zeros(9)
        joints_default_positions[3] = -math.pi/2
        joints_default_positions[5] = math.pi/2
        joints_default_positions[6] = math.pi/4

        # self.franka.set_joints_default_state(positions=joints_default_positions)
        self.franka.gripper.set_default_state(self.franka.gripper.joint_opened_positions)

    def initCube(self)->None:
        self.cube = self.world.scene.add(DynamicCuboid(prim_path="/World/cube",
                                                       name="Cube",
                                                       position=np.array([0.55, 0, 0.1]),
                                                       scale=np.array([0.04, 0.04, 0.04]),
                                                       color=np.array([0, 0, 1.0]),
                                                       mass=0.04))

    def initFile(self)->None:
        for i in range(len(self.file_names)):
            file_path = self.pkg_path + "/data/" + self.file_names[i] + ".txt"
            globals()['self.file_'+str(i)] = open(file_path, "w")

    def printState(self)->None:
        if( self.world.current_time_step_index % 50 == 0 ):
            print("---------------------------------")
            print("Time : ")
            print(round(self.play_time, 2))
            print("\nposition : ")
            print(self.pose[:3, 3].T)
            print("\norientation : ")
            print(self.pose[:3,:3])
            print("\njacobian : ")
            print(self.j)
            print("\ntorque : ")
            print(self.torque)
            print("\ngripper position : ")
            print(self.gripper_pose_desired)
            print(self.gripper_pose)
            print("\nFT data from tips : ")
            print(self.ft_data)

            print("---------------------------------")
            print("\n\n")

    def moveJointPosition(self, target_q: np.array, duration: float)->None:
        self.q_desired = DyrosMath.cubicVector(self.play_time, self.control_start_time, self.control_start_time+duration,
                                               self.q_init, target_q, np.zeros(7), np.zeros(7))

    def getTrajData(self, file_name:str)->np.array:
        traj_data = pd.read_table(self.pkg_path+"/trajectory"+file_name, sep=" ", header=None)
        traj_data = traj_data.to_numpy()

        x_traj = np.zeros(traj_data.shape[0])
        y_traj = traj_data[:, 1]
        z_traj = traj_data[:, 2]

        vx_traj = np.zeros(traj_data.shape[0])
        vy_traj = traj_data[:, 3]
        vz_traj = traj_data[:, 4]

        traj = np.column_stack((x_traj, y_traj))
        traj = np.column_stack((traj, z_traj))
        traj = np.column_stack((traj, vx_traj))
        traj = np.column_stack((traj, vy_traj))
        traj = np.column_stack((traj, vz_traj))
        return traj

    def CLIK(self, target_pose: np.array = None, duration: float = None, traj_data: np.array = np.zeros(1), traj_type: str = None)->None:
        x_desired = np.zeros(3)  # position
        rotation_desired = np.zeros((3,3)) # rotation
        xd_desired = np.zeros(6) # v, w

        # --------------------------------- Cubic Spline -----------------------------------------------
        if np.all(traj_data == 0):
            for i in range(0,3):
                x_desired[i] = DyrosMath.cubic(self.play_time, self.control_start_time, self.control_start_time+duration,
                                               self.pose_init[i,3], target_pose[i,3], 0, 0)
                xd_desired[i] = DyrosMath.cubicDot(self.play_time, self.control_start_time, self.control_start_time+duration,
                                                   self.pose_init[i,3], target_pose[i,3], 0, 0)
            rotation_desired = DyrosMath.rotationCubic(self.play_time, self.control_start_time, self.control_start_time+duration,
                                                       self.pose_init[:3,:3], target_pose[:3,:3])
            xd_desired[3:] = DyrosMath.rotationCubicDot(self.play_time, self.control_start_time, self.control_start_time+duration,
                                                        np.zeros(3), np.zeros(3), self.pose_init[:3,:3], target_pose[:3,:3])
        # -----------------------------------------------------------------------------------------------

        # ---------------------------------- Traj from .txt -------------------------------------------
        else:
            index = self.tick - self.tick_init

            if(index < 0):
                x_desired = self.pose_init[:3,3]
                rotation_desired = self.pose_init[:3,:3]
                xd_desired = np.zeros(6)
            elif(index >= traj_data.shape[0]):
                x_desired = np.array([traj_data[-1,0]+self.pose_init[0, 3],
                                      traj_data[-1,1]+self.pose_init[1, 3],
                                      traj_data[-1,2]+self.pose_init[2, 3]])
                rotation_desired = self.pose_init[:3,:3]
                xd_desired = np.zeros(6)
            else:
                x_desired = np.array([traj_data[index,0]+self.pose_init[0, 3],
                                      traj_data[index,1]+self.pose_init[1, 3],
                                      traj_data[index,2]+self.pose_init[2, 3]])
                rotation_desired = self.pose_init[:3,:3]
                xd_desired = np.array([traj_data[index,3], traj_data[index,4], traj_data[index,5], 0, 0, 0])
        # -----------------------------------------------------------------------------------------------

        x_error = np.zeros(6)
        x_error[:3] = x_desired - self.pose_qd[:3,3]
        x_error[3:] = DyrosMath.getPhi(self.pose_qd[:3,:3], rotation_desired)

        kp = np.zeros((6,6))
        np.fill_diagonal(kp, val=[50, 50, 50, 10, 10, 10])

        pseudo_j_inv = np.dot( self.j_qd.T, np.linalg.inv( np.dot(self.j_qd, self.j_qd.T) ) )
        qd_desired = np.dot(pseudo_j_inv, xd_desired + np.dot(kp, x_error) )
        self.q_desired = self.q_desired + qd_desired/self.hz

        # target_gripper = np.array([-0.005, -0.005])
        # self.setGripperPosition(target_gripper, 1)

        if traj_type == "CLIK Circle":
            self.record(0, traj_data.shape[0]/self.hz)
        elif traj_type == "CLIK Square":
            self.record(1, traj_data.shape[0]/self.hz)
        elif traj_type == "CLIK Eight":
            self.record(2, traj_data.shape[0]/self.hz)

    def setGripperPosition(self, target_position:np.array, duration:float)->None:
        self.gripper_pose_desired = DyrosMath.cubicVector(self.play_time, self.control_start_time, self.control_start_time+duration,
                                                     self.gripper_pose_init, target_position, np.zeros(2), np.zeros(2))

    def setGripperForce(self, target_force:np.array)->None:
        self.gripper_force_desired = target_force

    def setGripperOpen(self)->None:
        self.gripper_mode = True
        # self.gripper_pose_desired = self.gripper_pose + np.array([0.05, 0.05])
        self.gripper_pose_desired = np.array([0.04, 0.04])

    def setGripperClose(self)->None:
        self.gripper_mode = True
        # self.gripper_pose_desired = self.gripper_pose - np.array([0.05, 0.05])
        self.gripper_pose_desired = np.array([0.0, 0.0])

    def UpdateData(self)->None:
        self.q = self.franka.get_joint_positions()[:7]
        self.qd = self.franka.get_joint_velocities()[:7]
        self.torque = self.franka.get_applied_joint_efforts()[:7]
        self.gripper_pose = self.franka.gripper.get_joint_positions()

    def initPosition(self)->None:
        self.q_init = self.q
        self.q_desired = self.q_init
        self.gripper_pose_init = self.gripper_pose
        self.gripper_pose_desired = self.gripper_pose_init

    def setMode(self, mode:str)->None:
        self.is_mode_changed = True
        self.control_mode = mode
        print("Current mode (changed) : "+self.control_mode)

    def setTeleMode(self, mode:str)->None:
        self.is_telemode_changed = True
        self.tele_mode = mode

    def compute(self)->None:
        self.q = self.franka.get_joint_positions()[:7]
        self.j = self.kinematic.jacobian(cspace_position=self.q.astype(np.float64), frame="panda_hand")
        self.j_qd = self.kinematic.jacobian(cspace_position=self.q_desired.astype(np.float64), frame="panda_hand")
        self.pose = self.kinematic.pose(cspace_position=self.q.astype(np.float64), frame="panda_hand").matrix()
        self.pose_qd = self.kinematic.pose(cspace_position=self.q_desired.astype(np.float64), frame="panda_hand").matrix()
        self.vel = np.dot(self.j, self.qd)

        if(self.is_mode_changed):
            self.is_mode_changed = False
            self.control_start_time = self.play_time
            self.q_init = self.q
            self.qd_init = self.qd
            self.pose_init = self.pose
            self.gripper_pose_init = self.gripper_pose
            self.tick_init = self.tick
            self.gripper_mode = False
            if(self.control_mode != "pick_up"):
                self.event_index = 0

        if(self.control_mode == "joint_ctrl_init"):
            target_q = np.array([0.0, 0.0, 0.0, -math.pi/2, 0.0, math.pi/2, math.pi/4])
            self.moveJointPosition(target_q, 1)

        elif(self.control_mode == "CLIK Circle"):
            self.CLIK(traj_data=self.getTrajData("/circle.txt"), traj_type=self.control_mode)

        elif(self.control_mode == "CLIK Square"):
            self.CLIK(traj_data=self.getTrajData("/square.txt"), traj_type=self.control_mode)

        elif(self.control_mode == "CLIK Eight"):
            self.CLIK(traj_data=self.getTrajData("/eight.txt"), traj_type=self.control_mode)

        elif(self.control_mode == "gripper_open"):
            # target_gripper = np.array([0.04, 0.04])
            # self.setGripperPosition(target_gripper, 1)
            self.setGripperOpen()

        elif(self.control_mode == "gripper_close"):
            # target_gripper = np.array([0.0, 0.0])
            # self.setGripperPosition(target_gripper, 1)
            self.setGripperClose()

        elif(self.control_mode == "pick_up"):
            duration_set = np.array([1.0, 2.0, 1.0, 4.0]) # Open Gripper, Go to Cube, Close Gripper, Back to initial pose

            if self.event_index == 0:
                self.pose_desired = self.pose_init.copy()
                self.setGripperOpen()
            elif self.event_index == 1:
                cube_position, cubic_ori = self.cube.get_world_pose()
                ori_tool = Rotation.from_quat(cubic_ori)
                cubic_orientation = ori_tool.as_matrix()
                gripper_offset = np.array([0, 0.005, 0.095])
                desired_pose = np.zeros((4, 4))
                desired_pose[:3, :3] = cubic_orientation
                desired_pose[:3, 3] = cube_position + gripper_offset
                self.CLIK(target_pose = desired_pose, duration = duration_set[1])
            elif self.event_index == 2:
                self.setGripperClose()
            elif self.event_index == 3:
                self.CLIK(target_pose = self.pose_desired, duration = duration_set[3])

            if self.event_index in range(0,4):
                if self.play_time > self.control_start_time + duration_set[self.event_index]:
                    self.is_mode_changed = True
                    self.event_index += 1

        self.printState()
        self.play_time = self.world.current_time
        self.tick = self.world.current_time_step_index

    def teleoperation(self)->None:
        self.q = self.franka.get_joint_positions()[:7]
        self.j = self.kinematic.jacobian(cspace_position=self.q.astype(np.float64), frame="panda_hand")
        self.j_qd = self.kinematic.jacobian(cspace_position=self.q_desired.astype(np.float64), frame="panda_hand")
        self.pose = self.kinematic.pose(cspace_position=self.q.astype(np.float64), frame="panda_hand").matrix()
        self.pose_qd = self.kinematic.pose(cspace_position=self.q_desired.astype(np.float64), frame="panda_hand").matrix()
        self.vel = np.dot(self.j, self.qd)

        if(self.is_telemode_changed):
            self.is_telemode_changed = False

        pseudo_j_inv = np.dot( self.j_qd.T, np.linalg.inv( np.dot(self.j_qd, self.j_qd.T) ) )
        qd_desired = np.zeros(7)
        if(self.tele_mode == "move_forward"):
            qd_desired = np.dot(pseudo_j_inv, np.array([0.2, 0, 0, 0, 0, 0]))
        elif(self.tele_mode == "move_backward"):
            qd_desired = np.dot(pseudo_j_inv, np.array([-0.2, 0, 0, 0, 0, 0]))
        elif(self.tele_mode == "move_left"):
            qd_desired = np.dot(pseudo_j_inv, np.array([0, 0.2, 0, 0, 0, 0]))
        elif(self.tele_mode == "move_right"):
            qd_desired = np.dot(pseudo_j_inv, np.array([0, -0.2, 0, 0, 0, 0]))
        elif(self.tele_mode == "move_upward"):
            qd_desired = np.dot(pseudo_j_inv, np.array([0, 0, 0.2, 0, 0, 0]))
        elif(self.tele_mode == "move_downward"):
            qd_desired = np.dot(pseudo_j_inv, np.array([0, 0, -0.2, 0, 0, 0]))
        self.q_desired = self.q_desired + qd_desired/self.hz

        self.printState()
        self.play_time = self.world.current_time
        self.tick = self.world.current_time_step_index

    def getPosition(self)->np.array:
        return self.q

    def getGripperPosition(self)->np.array:
        return self.gripper

    def write(self)->None:
        # self.franka.set_joint_positions(positions=np.concatenate((self.q_desired, self.gripper_desired), axis=0))
        if self.gripper_mode == True:
            self.action = ArticulationAction(joint_positions=self.gripper_pose_desired, joint_indices=np.array([7,8]))
        else:
            self.action = ArticulationAction(joint_positions=self.q_desired, joint_indices=np.arange(0, 7, 1))
        self.franka_controller.apply_action(self.action)

    def setFTdata(self, ft_data:np.array)->None:
        self.ft_data = ft_data

    def isTeleop(self)->bool:
        return self.is_teleop

    def setTeleopMode(self, teleop_mode:bool)->None:
        self.is_teleop = teleop_mode

    def record(self, file_name_index:int, duration:float):
        if self.play_time < self.control_start_time + duration + 1.0:
            data = str(self.play_time-self.control_start_time) + " " + str(self.ft_data[0,:]*1000)[1:-1] + " " + str(self.ft_data[1,:]*1000)[1:-1]
            globals()["self.file_"+str(file_name_index)].write(data + "\n" )

    def closeFile(self)->None:
        for i in range(len(self.file_names)):
            globals()['self.file_'+str(i)].close()


"""Definition of Model Switching Planners and Switching Heuristics"""

import tensorflow as tf
from interact_drive.world import CarWorld
from interact_drive.car import Car, PlannerCar
from interact_drive.planner.car_planner import CarPlanner
from interact_drive.simulation_utils import batched_next_car_state
import pickle
import time
import numpy as np
import os

class SwitchPlanner(CarPlanner):
    """
    Parent class for all the trajectory finders for a car,
    that are capable of model switching.
    """

    def __init__(self, model_class, world: CarWorld, car: Car,
                 meta_planner, planner_specific_args = dict()):
        '''
        model_class: Planner class being used (e.g. NaivePlanner)
        meta_planner: Metaplanner making use of this (e.g. ModelSwitcher instance)
        planner_specific_args: Contains switch heuristic rules as well as parameters
            for underlying trajectory optimization model.
        '''
        super().__init__(world, car)

        # Reference to meta planner (i.e. meta planner)
        self.meta_planner = meta_planner

        # Collect switch heuristic rule
        heuristic_expressions = planner_specific_args.pop("heuristic_expressions") \
                                if "heuristic_expressions" in planner_specific_args else dict()

        # Initialize trajectory optimization model
        self.model = model_class(world, car, **planner_specific_args)

        # Initialize switch heuristics
        self.heuristics = dict()

        #Indicates if heuristic graph set up prior to last run
        self.heuristic_graph_set_up = True

    def setup_switch_heuristics(planners):
        '''
        Accepts a list of switch planners representing the complexity
        ladder being used.  The first model is the least expensive
        and the last model is the most expensive.

        Setups switch heuristics to switch between the ladder of planners.
        '''
        for i in range(len(planners)):
            h_dict = planners[i].heuristics
            alt_down = planners[i - 1].model if i > 0 else None
            h_dict["down"] = SwitchHeuristic(planners[i], "down", alt_model = alt_down)

            alt_up = planners[-1].model if i < (len(planners) - 1) else None
            h_dict["up"] = SwitchHeuristic(planners[i], "up", alt_model = alt_up)

    def generate_plan(self, init_state = None):
        # Trajectory optimize plan, voiding iterations involving graph setup
        self.model.compute("plan", init_state, void_graph_setup = True)

        return self.model.split_robot_control

    def switch_indicator(self):
        '''
        Should Return

        -1: Switch to one lower computation model.
        0: Stay with current model.
        1: Switch to highest computation model.
        '''

        # Will be flipped to False if any heuristic involves graph setup
        self.heuristic_graph_set_up = True

        indicator = 0

        if (self.heuristics["up"].should_switch()):
            indicator = 1
        elif (self.heuristics["down"].should_switch()):
            indicator = -1

        return indicator

    def reset_planner(self):
        # Reset planner by reinitializing optimizer and heuristics
        self.model.initialize_optimizer()
        for heuristic in self.heuristics.values():
            heuristic.heuristic_reset()

class SwitchHeuristic():

    # Default hyperparameters are stored as default command line arguments
    # Meta mdp reward is R - lambd * (comp time)
    lambd = None

    # Empirical values for the compuational times of various models
    comp_times = dict()

    # We wait cooldown timesteps before revaluating a heuristic (depending on switch direction)
    cooldowns = dict()

    # Trust radius we consider for estimating optimal control change given an alternate model
    trust_radius = None

    cached_values = dict()
    last_computed = dict()
    computation_log = []

    def __init__(self, switch_planner, direction, alt_model):
        '''
        swtitch_planner: The SwitchPlanner that is using this heuristic.
        direction: 'up' or 'down'. ('up' indicates this heuristics determines when we
                    should switch to a more complex model)
        alt_model: Alternative model to switch to (right below for down, top most for
                   up).  None if no alternate model in which case this heuristic never
                   activates.
        '''
        self.switch_planner = switch_planner
        self.direction = direction
        self.alt_model = alt_model

        # For easy access
        self.verbose = self.switch_planner.world.verbose

        # Time step of last computing heuristic
        self.last_computed = None

        # Number of components to control
        self.NC = self.switch_planner.model.NC

        # Potential areas of model improvement
        self.ladder_potential = self.switch_planner.meta_planner.ladder_potential
        self.influence_potential = "influence_prediction" in self.ladder_potential

    def should_switch(self):
        '''
        Returns if we should switch or not using switch heuristics,
        potentially differing due to cooldown.  If no alternate model
        always return False.
        '''
        if (self.alt_model is None):
            return False

        sp = self.switch_planner

        cooldown = SwitchHeuristic.cooldowns[self.direction]
        time_step = sp.world.get_time_step()
        if (self.last_computed is None or time_step >= (self.last_computed + cooldown)):

            evaluation = self.estimated_meta_tradeoff()
            if (sp.heuristic_graph_set_up):
                self.last_computed = time_step

            return evaluation

        return False

    # SWITCHING HEURISTIC DEFINITIONS

    def estimated_meta_tradeoff(self):
        '''
        Estimates the metatradeoff for the current state and model, given the
        alternate model based on the direction this heuristic is setup for.

        The metareward is low level reward - lambd * computational time.
        The meta tradeoff is positive when a different model achieves a better
        combination of low level reward and computation time.
        '''

        sp = self.switch_planner
        time_step = sp.world.get_time_step()
        switch_key = f"{sp.model.name}_{self.alt_model.name}"

        if (self.direction == "up"):
            # Approximate best model with observation.
            control_prediction = sp.world.cars[sp.model.hi].control_log[-1]
            if (self.influence_potential):
                self.verify_grad_cache()
                influence_prediction = SwitchHeuristic.cached_values["grads"]["dhc_rc"]
        else:
            # Get predictions from model directly below.
            self.alt_model.compute("control_prediction", sp.world.last_state, void_graph_setup = True)
            control_prediction = self.alt_model.control_prediction[:self.NC]
            SwitchHeuristic.register_computation(time_step, f"{self.alt_model.name}_ctrl_pred")

            if (self.influence_potential):
                self.alt_model.compute("influence_prediction", sp.world.last_state, void_graph_setup = True)
                influence_prediction = self.alt_model.influence_prediction[:self.NC, :self.NC]
                SwitchHeuristic.register_computation(time_step, f"{self.alt_model.name}_inf_pred")

            if (not self.alt_model.graph_set_up):
                sp.heuristic_graph_set_up = False

        influence_prediction = influence_prediction if self.influence_potential else None
        control_change = self.estimate_control_change(control_prediction, influence_prediction)
        reward_change = self.estimate_reward_change(control_change)

        cur_model_time = SwitchHeuristic.comp_times[sp.model.name]
        alt_model_time = SwitchHeuristic.comp_times[self.alt_model.name]
        time_change = alt_model_time - cur_model_time

        meta_tradeoff = reward_change - SwitchHeuristic.lambd * time_change

        if (not sp.heuristic_graph_set_up):
            # We've finished setting up the graph at this point so simply return
            return None

        SwitchHeuristic.register_computation(time_step, switch_key, meta_tradeoff)

        # Display and return decision!
        if (self.verbose):
            model_name = self.switch_planner.model.name
            print(f"{model_name} {self.direction} Meta Tradeoff: {meta_tradeoff:.1e}")
        return meta_tradeoff > 0

    # Core Heuristic Functionality

    def estimate_control_change(self, control_prediction, influence_prediction = None):
        '''
        Estimates the change in robot control if an alternate model was used.
        The alternate model would have offered control_prediction and
        influence_prediction had it been used to plan for the previous timestep.

        Estimates control change by using a second-order taylor expansion of the reward
        centerd around the observed robot control and human control at the previous
        timestep.  The optimal control change (d) is the optimizer for the below expression
        R(d) = 0.5 * dT * A * d + B * d + C
        where A, B, C are computed based on gradients evaluated at the observed
        state and controls, as well as the provided control and influence prediction.

        The optimal d is -A^-1 * B.
        '''
        sp = self.switch_planner
        time_step = sp.world.get_time_step()
        self.verify_grad_cache()
        grads = SwitchHeuristic.cached_values["grads"]

        # Convert model predictions into components for taylor expansion
        dhc_rc = influence_prediction
        hc_diff = control_prediction - sp.world.cars[sp.model.hi].control_log[-1]

        # Compute A matrix (and it's inverse)
        drr_rc_rc = grads['drr_rc_rc']
        drr_rc_hc = grads['drr_rc_hc']
        if (dhc_rc is not None):
            drr_hc_hc = grads['drr_hc_hc']
            cross_term = (drr_rc_hc @ dhc_rc)
            A = drr_rc_rc + cross_term + cross_term.T + (dhc_rc.T @ drr_hc_hc @ dhc_rc)
        else:
            A = drr_rc_rc

        # Compute B vector
        drr_rc = grads['drr_rc']
        if (dhc_rc is not None):
            drr_hc = grads['drr_hc']
            B = drr_rc + (dhc_rc.T @ drr_hc) + (drr_rc_hc @ hc_diff) + (dhc_rc.T @ drr_hc_hc @ hc_diff)
        else:
            B = drr_rc + (drr_rc_hc @ hc_diff)

        return SwitchHeuristic.constrained_optimum(A, B)

    def estimate_reward_change(self, control_change):
        '''
        Estimates change in reward compared to what was garnered in the previous time
        step.  Accounts for how the robot's control_change may influence the human's
        control.  Note that in reality the robot's control cannot affect the human's
        control at the same timestep, but this allows to better approximate what will
        happen next timestep.
        '''
        sp = self.switch_planner
        time_step = sp.world.get_time_step()
        self.verify_grad_cache()

        rc = sp.world.cars[sp.model.ri].control_log[-1]
        hc = sp.world.cars[sp.model.hi].control_log[-1]

        reward_key = "reward"
        if (SwitchHeuristic.last_computed.get("reward", -1) != time_step):
            reward = sp.world.cars[sp.model.ri].reward_fn(tf.stack(sp.world.state), rc).numpy()
            SwitchHeuristic.register_computation(time_step, reward_key, reward)
        else:
            reward = SwitchHeuristic.cached_values["reward"]

        # Identify where new controls take you and evaluate alternate reward
        controls = []
        for i in range(len(sp.world.cars)):
            if (i == sp.model.ri):
                controls.append(rc + control_change)
            elif (i == sp.model.hi):
                controls.append(hc + SwitchHeuristic.cached_values["grads"]["dhc_rc"] @ control_change)
            else:
                controls.append(tf.constant([0.] * self.NC))
        controls = tf.stack(controls)
        alt_world_state = batched_next_car_state(tf.stack(sp.world.last_state), controls, sp.world.dt)

        alt_reward = sp.world.cars[sp.model.ri].reward_fn(alt_world_state, rc + control_change).numpy()

        return alt_reward - reward

    # Helper Functions

    def constrained_optimum(A, B, tol = 0.05):
        '''
        Returns the d that optimizes
        R(d) = 0.5 * dT * A * d + B * d + C
        subject to the constraint that ||d||_2 <= trust_radius.

        A is assumed to be symmetric.  Tolerance is a considered as
        a proportion of the trust radius.
        '''
        # A = U @ diag(S) @ UT
        S, U = np.linalg.eig(A)
        UT_nB = U.T @ -B

        tr = SwitchHeuristic.trust_radius
        tr_tolerance = tr * tol

        min_ev, max_ev = np.min(S), np.max(S)
        if (max_ev < 0):
            unconstrained_optima = UT_nB / S
            if (np.linalg.norm(unconstrained_optima) <= SwitchHeuristic.trust_radius):
                return U @ unconstrained_optima

        # Critical scalar that maps vector to UTB to trust radius
        critical_ev = (np.linalg.norm(UT_nB) / tr)

        # Binary search for lambda within tolerance
        lm_min = max(0, max_ev, min_ev + critical_ev)
        lm_max = max_ev + critical_ev
        while (True):
            lm_mid = (lm_min + lm_max) / 2
            optima = UT_nB / (S - lm_mid)
            optima_norm = np.linalg.norm(optima)
            if (np.abs(optima_norm - tr) < tr_tolerance):
                return U @ optima
            if (optima_norm > tr):
                lm_min = lm_mid
            else:
                lm_max = lm_mid

    def verify_grad_cache(self):
        # Recomputes and caches grads if current is outdated.
        grad_key = "grads"
        sp = self.switch_planner
        time_step = sp.world.get_time_step()

        if (SwitchHeuristic.last_computed.get(grad_key, -1) != time_step):
            np_grad_dict = sp.grad_computer.get_np_grads(self.influence_potential)
            if (not sp.grad_computer.graph_set_up):
                sp.heuristic_graph_set_up = False
            SwitchHeuristic.register_computation(time_step, grad_key, np_grad_dict)

    # Bookeeping and Parameter Maintenance

    def register_computation(time_step, computation_key, computation_value = None):
        # Caches computation and registers what computation was done in the log
        if (computation_value is not None):
            SwitchHeuristic.cached_values[computation_key] = computation_value
        SwitchHeuristic.last_computed[computation_key] = time_step

        if (time_step > len(SwitchHeuristic.computation_log)):
            SwitchHeuristic.computation_log += [""] * (time_step - len(SwitchHeuristic.computation_log))
            SwitchHeuristic.computation_log[-1] = computation_key
        else:
            SwitchHeuristic.computation_log[-1] += f"; {computation_key}"

    def update_parameters(heuristic_customization):
        # Updates general heuristic parameters
        SwitchHeuristic.lambd = heuristic_customization.get('lambda', SwitchHeuristic.lambd)
        SwitchHeuristic.comp_times.update(heuristic_customization.get('comp_times', dict()))
        SwitchHeuristic.cooldowns.update(heuristic_customization.get('cooldowns', dict()))
        SwitchHeuristic.trust_radius = heuristic_customization.get('trust_radius', SwitchHeuristic.trust_radius)

    def heuristic_reset(self):
        # Resets specific heuristic
        self.last_computed = None

    def general_reset():
        # Resets shared data structures
        SwitchHeuristic.last_computed = dict()
        SwitchHeuristic.cached_values = dict()
        SwitchHeuristic.computation_log = []


import os
from flask import Flask, Blueprint, jsonify, request, render_template, redirect, url_for, flash, jsonify
from flask.ext.sqlalchemy import SQLAlchemy

root = os.path.abspath(os.path.dirname(__file__))
abt = Blueprint('abt', __name__,
    template_folder=os.path.join(root, 'templates'),
    static_folder=os.path.join(root, 'static'),
    url_prefix='/abt'
)

@abt.route('/')
def index():
    return 'insert beautiful UI here'

def getStats(Test, Experiment):
    result = {'tests' : []}
    for test in Test.query.all():
        test_res = {'test_name' : test.name, 'experiments': []}
        experiments = Experiment.query.filter_by(test_id = test.test_id).all()
        for exp in experiments:
            if exp.convert > 0.0:
                convert_rate =((exp.convert*1.0)/exp.participation)*100
            else:
                convert_rate = "inf"
            test_res['experiments'].append({'experiment': exp.experiment, 'participation': exp.participation, 'converts': exp.convert, 'convert_rate': convert_rate})

        result['tests'].append(test_res)
    return jsonify(result)

def mostConverts(Test, Experiment):
    result = {'tests' : []}
    for test in Test.query.all():
        test_res = {'test name' : test.name, 'winner': None, 'max convert rate': 0}
        experiments = Experiment.query.filter_by(test_id = test.test_id).all()
        max_convert_rate = 0.0
        best_exp_res = {}
        for exp in experiments:
            if exp.convert > 0.0:
                convert_rate =((exp.convert*1.0)/exp.participation)*100
            else:
                continue
            if convert_rate > max_convert_rate:
                max_convert_rate = convert_rate
                best_exp_res = {'experiment': exp.experiment, 'participation': exp.participation, 'converts': exp.convert, 'convert_rate': convert_rate}
        test_res['max convert rate'] = max_convert_rate
        test_res['winner'] = best_exp_res
        result['tests'].append(test_res)

    return jsonify(result)


from typing import List, Tuple

def weighted_interval_scheduling(jobs: List[Tuple[int, int, int]]) -> int:
    # sort jobs by finish time
    jobs.sort(key=lambda x: x[1])

    n = len(jobs)
    dp = [0] * n
    dp[0] = jobs[0][2]

    for i in range(1, n):
        # find the latest job that doesn't conflict with the current job
        j = i - 1
        while j >= 0 and jobs[j][1] > jobs[i][0]:
            j -= 1

        # include the current job or not
        include = jobs[i][2]
        if j >= 0:
            include += dp[j]

        dp[i] = max(include, dp[i - 1])

    return dp[-1]

if __name__ == '__main__':
    num_tests = int(input())
    for _ in range(num_tests):
        n = int(input())
        jobs = []
        for _ in range(n):
            i, j, k = map(int, input().split())
            jobs.append((i, j, k))
        print(weighted_interval_scheduling(jobs))


from datetime import datetime
from datetime import timedelta
from celery.schedules import crontab
from IGitt.Interfaces.Actions import MergeRequestActions
from IGitt.Interfaces.MergeRequest import MergeRequest, MergeRequestStates
from IGitt.Interfaces.Repository import Repository

from gitmate.utils import lock_igitt_object
from gitmate_hooks.utils import ResponderRegistrar

@ResponderRegistrar.scheduled_responder(
    'pr_stale_reminder', crontab(minute='0', hour='6,18'), is_active=True)
def add_stale_label_to_merge_requests(
        repo: Repository,
        pr_expire_limit: int = 'Expiry limit in no. of day for pull requests',
        stale_label: str = 'Label to be used for marking stale'
):
    """
    Assigns the chosen label to pull requests which haven't been updated in a
    certain period of time.
    """
    minimum_pr_update_time = (datetime.now() -
                              timedelta(days=pr_expire_limit)).date()
    for pr in repo.search_mrs(
            updated_before=minimum_pr_update_time,
            state=MergeRequestStates.OPEN,
    ):
        with lock_igitt_object('label mr', pr):
            if stale_label not in pr.labels:
                pr.labels = pr.labels | {stale_label}

@ResponderRegistrar.responder(
    'pr_stale_reminder',
    MergeRequestActions.LABELED,
    MergeRequestActions.UNLABELED,
    MergeRequestActions.REOPENED,
    MergeRequestActions.SYNCHRONIZED,
    MergeRequestActions.COMMENTED,
    MergeRequestActions.MERGED
)
def remove_stale_label_from_merge_requests(
        pr: MergeRequest,
        *args,
        stale_label: str = 'Label to be used for marking stale'
):
    """
    Unassigns the chosen label from pull requests when they are updated again.
    """
    if len(args) > 0 and args[0] == stale_label:
        # LABELED and UNLABELED events return the label used, skip action if
        # the label was ``stale_label``
        return

    with lock_igitt_object('label mr', pr):
        pr.labels = pr.labels - {stale_label}


from support_functions.chaos_won_first_stage import array_for_diagonal
import constants.const as con

def make_column(ar: list, col: int) -> list:
    """Make a column under index col from ar"""
    return [ar[i][col] for i in range(con.BOARD_COLS)]

def second_stage(ar: list) -> bool:
    """Check if all lines are blocked for Order"""
    for i in range(con.BOARD_ROWS):
        for j in range(con.BOARD_COLS):
            element = ar[i][j]
            if element == 0:
                continue
            lines = make_array_for_element(ar, i, j)
            for line in lines:
                if check_single_line(line, element):
                    return False
    return True

def check_length(diagonal: list) -> bool:
    """Return True if diagonal has 5 or more elements, else False"""
    return len(diagonal) >= 5

def make_full_desc_diagonal(ar: list, row: int, col: int) -> list:
    """Make a full descending diagonals which contains an element [row][col]"""
    decider = min(row, col)
    new_row = row
    new_col = col
    for _ in range(decider):
        new_row -= 1
        new_col -= 1
    return array_for_diagonal(ar, new_row, new_col, 'right')

def make_full_asc_diagonal(ar: list, row: int, col: int) -> list:
    """Make a full ascending diagonals which contains an element [row][col]"""
    decider = min(row, con.BOARD_COLS - 1 - col)
    new_row = row
    new_col = col
    for _ in range(decider):
        new_row -= 1
        new_col += 1
    return array_for_diagonal(ar, new_row, new_col, 'left')

def make_array_for_element(ar: list, i: int, j: int) -> list:
    """Make a list of lines containing element ar[i][j]"""
    lines = []
    row = ar[i]
    col = make_column(ar, j)
    lines.append(row)
    lines.append(col)
    desc_diagonal = make_full_desc_diagonal(ar, i, j)
    asc_diagonal = make_full_asc_diagonal(ar, i, j)
    if check_length(desc_diagonal):
        lines.append(desc_diagonal)
    if check_length(asc_diagonal):
        lines.append(asc_diagonal)
    return lines

def check_single_line(line: list, element: int) -> bool:
    """
    Check if in the line there is a chance to get 5 elements(element) in a row
    """
    sublines = []
    opposite_el = element % 2 + 1
    if len(line) == 6:
        sublines = [line[0:5], line[1:6]]
        # 6 in a row doesn't count as a win for Order, so the line is blocked
        if line[0] == line[5] and line[0] != 0:
            return False
    else:
        sublines.append(line)
    found_opposite = False
    # if subline has an opposite element - the line is blocked
    for subline in sublines:
        for sign in subline:
            if sign == opposite_el:
                found_opposite = True
        if not found_opposite:
            return True
        found_opposite = False
    return False