import pandas as pd
import numpy as np
import os

import caliperreader as cr

import hatchet.graphframe
from hatchet.node import Node
from hatchet.graph import Graph
from hatchet.frame import Frame
from hatchet.util.timer import Timer

class CaliperNativeReader:
    """Read in a native `.cali` file using Caliper's python reader."""

    def __init__(self, filename_or_caliperreader, native, string_attributes):
        """Read in a native cali using Caliper's python reader.

        Args:
            filename_or_caliperreader (str or CaliperReader): name of a `cali` file OR
                a CaliperReader object
            native (bool): use native metric names or user-readable metric names
            string_attributes (str or list): Adds existing string attributes from within the caliper file to the dataframe
        """
        self.filename_or_caliperreader = filename_or_caliperreader
        self.filename_ext = ""
        self.use_native_metric_names = native
        self.string_attributes = string_attributes

        self.df_nodes = {}
        self.metric_cols = []
        self.record_data_cols = []
        self.node_dicts = []
        self.callpath_to_node = {}
        self.idx_to_node = {}
        self.callpath_to_idx = {}
        self.global_nid = 0
        self.node_ordering = False

        self.default_metric = None

        self.timer = Timer()

        if isinstance(self.filename_or_caliperreader, str):
            _, self.filename_ext = os.path.splitext(filename_or_caliperreader)

        if isinstance(self.string_attributes, str):
            self.string_attributes = [self.string_attributes]

    def read_metrics(self, ctx="path"):
        all_metrics = []
        records = self.filename_or_caliperreader.records

        # read metadata from the caliper reader
        for record in records:
            node_dict = {}
            if ctx in record:
                # only parse records that have spot.channel=regionprofile or no
                # spot.channel attribute
                if (
                    "spot.channel" in record
                    and record["spot.channel"] == "regionprofile"
                ) or "spot.channel" not in record:
                    # get the node label and callpath for the record
                    if isinstance(record[ctx], list):
                        # specify how to parse cupti records
                        if "cupti.activity.kind" in record:
                            if record["cupti.activity.kind"] == "kernel":
                                node_label = record["cupti.kernel.name"]
                                node_callpath = tuple(record[ctx] + [node_label])
                            elif record["cupti.activity.kind"] == "memcpy":
                                node_label = record["cupti.activity.kind"]
                                node_callpath = tuple(record[ctx] + [node_label])
                        else:
                            node_label = record[ctx][-1]
                            node_callpath = tuple(record[ctx])
                    else:
                        node_label = record[ctx]
                        node_callpath = tuple([record[ctx]])

                    if "spot.channel" in record:
                        node_dict["spot.channel"] = record["spot.channel"]

                    # get node nid based on callpath
                    node_dict["nid"] = self.callpath_to_idx.get(node_callpath)

                    for item in record.keys():
                        if item != ctx:
                            if (
                                self.filename_or_caliperreader.attribute(
                                    item
                                ).attribute_type()
                                == "double"
                            ):
                                node_dict[item] = float(record[item])
                                if item not in self.record_data_cols:
                                    self.record_data_cols.append(item)
                            elif (
                                self.filename_or_caliperreader.attribute(
                                    item
                                ).attribute_type()
                                == "int"
                            ):
                                node_dict[item] = int(record[item])
                                if item not in self.record_data_cols:
                                    self.record_data_cols.append(item)
                            elif (
                                self.filename_or_caliperreader.attribute(
                                    item
                                ).attribute_type()
                                == "string"
                            ):
                                if item in self.string_attributes:
                                    node_dict[item] = record[item]
                                    if item not in self.record_data_cols:
                                        self.record_data_cols.append(item)

                    all_metrics.append(node_dict)

        # make list of metric columns
        for col in self.record_data_cols:
            if self.filename_or_caliperreader.attribute(col).is_value():
                self.metric_cols.append(col)

        df_metrics = pd.DataFrame.from_dict(data=all_metrics)
        df_new = df_metrics.groupby(df_metrics["nid"]).aggregate("first").reset_index()
        return df_new

    def create_graph(self, ctx="path"):
        list_roots = []

        def _create_parent(child_node, parent_callpath):
            """We may encounter a parent node in the callpath before we see it
            as a child node. In this case, we need to create a hatchet node for
            the parent.

            This function recursively creates parent nodes in a callpath
            until it reaches the already existing parent in that callpath.
            """
            parent_node = self.callpath_to_node.get(parent_callpath)

            if parent_node:
                # return if arrives at the parent
                parent_node.add_child(child_node)
                child_node.add_parent(parent_node)
                return
            else:
                # else create the parent and add parent/child

                # if root node, end recursive call to create parent nodes
                if not parent_callpath:
                    list_roots.append(child_node)

                    node_dict = dict(
                        {
                            "name": child_node.frame["name"],
                            "node": child_node,
                            "nid": self.global_nid,
                        }
                    )

                    self.idx_to_node[self.global_nid] = node_dict
                    self.global_nid += 1
                else:
                    grandparent_callpath = parent_callpath[:-1]
                    parent_name = parent_callpath[-1]

                    parent_node = Node(
                        Frame({"type": "function", "name": parent_name}), None
                    )

                    self.callpath_to_node[parent_callpath] = parent_node
                    self.callpath_to_idx[parent_callpath] = self.global_nid

                    node_dict = dict(
                        {
                            "name": parent_name,
                            "node": parent_node,
                            "nid": self.global_nid,
                        },
                    )
                    self.idx_to_node[self.global_nid] = node_dict
                    self.global_nid += 1

                    parent_node.add_child(child_node)
                    child_node.add_parent(parent_node)
                    _create_parent(parent_node, grandparent_callpath)

        parent_hnode = None
        records = self.filename_or_caliperreader.records
        order = -1

        for record in records:
            node_label = ""
            if ctx in record:
                if (
                    "spot.channel" in record
                    and record["spot.channel"] == "regionprofile"
                ) or "spot.channel" not in record:
                    # if it's a list, then it's a callpath
                    if isinstance(record[ctx], list):
                        # specify how to parse cupti records
                        if "cupti.activity.kind" in record:
                            if record["cupti.activity.kind"] == "kernel":
                                node_label = record["cupti.kernel.name"]
                                node_callpath = tuple(record[ctx] + [node_label])
                                parent_callpath = node_callpath[:-1]
                                node_type = "kernel"
                            elif record["cupti.activity.kind"] == "memcpy":
                                node_label = record["cupti.activity.kind"]
                                node_callpath = tuple(record[ctx] + [node_label])
                                parent_callpath = node_callpath[:-1]
                                node_type = "memcpy"
                            else:
                                Exception("Haven't seen this activity kind yet")
                        else:
                            node_label = record[ctx][-1]
                            node_callpath = tuple(record[ctx])
                            parent_callpath = node_callpath[:-1]
                            node_type = "function"

                        hnode = self.callpath_to_node.get(node_callpath)

                        if not hnode:
                            # set the _hatchet_nid by the node order column if it exists, else -1
                            if "min#min#aggregate.slot" in record:
                                self.node_ordering = True
                                order = record["min#min#aggregate.slot"]
                            frame = Frame({"type": node_type, "name": node_label})
                            order = int(order)
                            hnode = Node(frame, hnid=order)
                            self.callpath_to_node[node_callpath] = hnode

                            # get parent from node callpath
                            parent_hnode = self.callpath_to_node.get(parent_callpath)

                            # create parent if it doesn't exist
                            # else if parent already exists, add child-parent
                            if not parent_hnode:
                                _create_parent(hnode, parent_callpath)
                            else:
                                parent_hnode.add_child(hnode)
                                hnode.add_parent(parent_hnode)

                            self.callpath_to_idx[node_callpath] = self.global_nid
                            node_dict = dict(
                                {
                                    "name": node_label,
                                    "node": hnode,
                                    "nid": self.global_nid,
                                },
                            )
                            self.idx_to_node[self.global_nid] = node_dict
                            self.global_nid += 1

                    # if it's a string, then it's a root
                    else:
                        root_label = record[ctx]
                        root_callpath = tuple([root_label])

                        if root_callpath not in self.callpath_to_node:
                            # create the root since it doesn't exist
                            frame = Frame({"type": "function", "name": root_label})
                            graph_root = Node(frame, None)

                            # store callpaths to identify the root
                            self.callpath_to_node[root_callpath] = graph_root
                            self.callpath_to_idx[root_callpath] = self.global_nid
                            list_roots.append(graph_root)

                            node_dict = dict(
                                {
                                    "name": root_label,
                                    "node": graph_root,
                                    "nid": self.global_nid,
                                }
                            )

                            self.idx_to_node[self.global_nid] = node_dict
                            self.global_nid += 1

        return list_roots

    def _parse_metadata(self, mdata):
        """Convert Caliper Metadata values into correct Python objects.

        Args:
            mdata (dict[str: str]): metadata to convert

        Return:
            (dict[str: str]): modified metadata
        """
        parsed_mdata = {}
        for k, v in mdata.items():
            # If the value is an int, convert it to an int.
            try:
                parsed_mdata[k] = int(v)
            except ValueError:
                # If the value is a float, convert it to a float
                try:
                    parsed_mdata[k] = float(v)
                except ValueError:
                    # If the value is a list or tuple, convert it to a list or
                    # tuple
                    if v.startswith("[") and v.endswith("]"):
                        parsed_mdata[k] = [
                            elem.strip() for elem in v.strip("][").split(",")
                        ]
                    elif v.startswith("(") and v.endswith(")"):
                        parsed_mdata[k] = [
                            elem.strip() for elem in v.strip(")(").split(",")
                        ]
                    # If the value is a string, just save it as-is
                    else:
                        parsed_mdata[k] = v
        return parsed_mdata

    def read(self):
        """Read the caliper records to extract the calling context tree."""
        if isinstance(self.filename_or_caliperreader, str):
            if self.filename_ext != ".cali":
                raise ValueError("from_caliperreader() needs a .cali file")
            else:
                cali_file = self.filename_or_caliperreader
                self.filename_or_caliperreader = cr.CaliperReader()
                self.filename_or_caliperreader.read(cali_file)

        with self.timer.phase("graph construction"):
            list_roots = self.create_graph()
        self.df_nodes = pd.DataFrame(data=list(self.idx_to_node.values()))

        # create a graph object once all the nodes have been added
        graph = Graph(list_roots)
        if self.node_ordering:
            graph.node_ordering = True
        graph.enumerate_traverse()

        with self.timer.phase("read metrics"):
            df_fixed_data = self.read_metrics()

        metrics = pd.DataFrame.from_dict(data=df_fixed_data)

        # add missing intermediate nodes to the df_fixed_data dataframe
        if "mpi.rank" in df_fixed_data.columns:
            num_ranks = metrics["mpi.rank"].max() + 1
            rank_list = range(0, num_ranks)

        # create a standard dict to be used for filling all missing rows
        default_metric_dict = {}
        for idx, col in enumerate(self.record_data_cols):
            if self.filename_or_caliperreader.attribute(col).is_value():
                default_metric_dict[list(self.record_data_cols)[idx]] = 0
            else:
                default_metric_dict[list(self.record_data_cols)[idx]] = None
        default_metric_dict["nid"] = np.nan

        # create a list of dicts, one dict for each missing row
        missing_nodes = []
        for iteridx, row in self.df_nodes.iterrows():
            # check if df_nodes row exists in df_fixed_data
            metric_rows = df_fixed_data.loc[metrics["nid"] == row["nid"]]
            if "mpi.rank" not in self.metric_cols:
                if metric_rows.empty:
                    # add a single row
                    node_dict = dict(default_metric_dict)
                    missing_nodes.append(node_dict)
            else:
                if metric_rows.empty:
                    # add a row per MPI rank
                    for rank in rank_list:
                        node_dict = dict(default_metric_dict)
                        node_dict["nid"] = row["nid"]
                        node_dict["mpi.rank"] = rank
                        missing_nodes.append(node_dict)
                elif len(metric_rows) < num_ranks:
                    # add a row for each missing MPI rank
                    present_ranks = metric_rows["mpi.rank"].values
                    missing_ranks = [x for x in rank_list if x not in present_ranks]
                    for rank in missing_ranks:
                        node_dict = dict(default_metric_dict)
                        node_dict["nid"] = row["nid"]
                        node_dict["mpi.rank"] = rank
                        missing_nodes.append(node_dict)

        df_missing = pd.DataFrame.from_dict(data=missing_nodes)
        df_metrics = pd.concat([df_fixed_data, df_missing], sort=False)

        # rename columns to user-readable metric names (i.e., aliases)
        if not self.use_native_metric_names:
            for col in df_metrics.columns:
                if col == "nid":
                    continue
                alias = self.filename_or_caliperreader.attribute(col).get(
                    "attribute.alias"
                )
                if alias:
                    # update column name in metrics dataframe
                    df_metrics.rename(columns={col: alias}, inplace=True)

                    # also update list of metric columns
                    self.metric_cols = [
                        alias if item == col else item for item in self.metric_cols
                    ]

        # dict mapping old to new column names to make columns consistent with
        # other readers
        old_to_new = {
            "mpi.rank": "rank",
            "module#cali.sampler.pc": "module",
            "sum#time.duration": "time",
            "sum#avg#sum#time.duration": "time",
            "inclusive#sum#time.duration": "time (inc)",
            "sum#avg#inclusive#sum#time.duration": "time (inc)",
        }

        # change column names
        new_cols = []
        for col in df_metrics.columns:
            if col in old_to_new:
                new_cols.append(old_to_new[col])
            else:
                new_cols.append(col)
        df_metrics.columns = new_cols

        # create list of exclusive and inclusive metric columns
        exc_metrics = []
        inc_metrics = []
        for column in self.metric_cols:
            # ignore rank as an exc or inc metric
            if column == "mpi.rank":
                continue

            # add new column names to list of metrics if inc or inclusive in
            # old column names
            if "(inc)" in column or "inclusive" in column:
                if column in old_to_new:
                    column = old_to_new[column]
                inc_metrics.append(column)
            else:
                if column in old_to_new:
                    column = old_to_new[column]
                exc_metrics.append(column)

        with self.timer.phase("data frame"):
            # merge the metrics and node dataframes on the nid column
            dataframe = pd.merge(df_metrics, self.df_nodes, on="nid")
            dataframe["nid"] = dataframe["nid"].astype(pd.Int64Dtype())

            # set the index to be a MultiIndex
            indices = ["node"]
            if "rank" in dataframe.columns:
                indices.append("rank")
            dataframe.set_index(indices, inplace=True)
            dataframe.sort_index(inplace=True)

        # set the default metric
        if self.default_metric is None:
            if "time (inc)" in dataframe.columns:
                self.default_metric = "time"
            elif "avg#inclusive#sum#time.duration" in dataframe.columns:
                self.default_metric = "avg#inclusive#sum#time.duration"
            elif len(inc_metrics) > 0:
                self.default_metric = inc_metrics[0]
            elif len(exc_metrics) > 0:
                self.default_metric = exc_metrics[0]

        metadata = self.filename_or_caliperreader.globals
        parsed_metadata = self._parse_metadata(metadata)

        return hatchet.graphframe.GraphFrame(
            graph,
            dataframe,
            exc_metrics,
            inc_metrics,
            self.default_metric,
            metadata=parsed_metadata,
        )


from celery import Celery
from kombu import Exchange, Queue
from celery.exceptions import Reject
from dead_letter import DeadLetterConsumer

def setup(app):
    app_exchange = Exchange('e.app', type='direct')
    app_queue = Queue(
        name='q.app',
        exchange=app_exchange,
        routing_key='app',
        queue_arguments={
        'x-dead-letter-exchange': 'e.deadletter',
        'x-dead-letter-routing-key': 'deadletter'
    })
    app.conf.task_queues = (app_queue,)
    app.conf.beat_schedule = {
        'print-every-20-seconds': {
          'task': 'tasks.print_hi',
          'schedule': 20.0,
          'args': ('Kakashi',),
          'options': {'queue': 'q.app'}
      },
    }
    # app.steps['consumer'].add(DeadLetterConsumer)

def create_app():
    app = Celery('app')
    app.autodiscover_tasks(['tasks'], force=True)
    setup(app)
    return app

app = create_app()


from unittest import mock

from django.test import TestCase

from apps.shortener.models import Shortener

class TestShortenerModels(TestCase):
    model = Shortener

    def test_shortened_str(self):
        shortener = self.model.objects.create(
            url='http://localhost', shortened='SHORT'
        )
        self.assertEqual(str(shortener), 'SHORT')

    def test_random_shortened_str(self):
        with mock.patch(
            'apps.shortener.utils.generate_shortened_code',
            return_value='VALUE',
        ):
            shortener = self.model.objects.create(
                url='http://localhost',
            )
            self.assertEqual(str(shortener), 'VALUE')


import math

import torch
import torch.nn as nn
from torch_scatter import scatter

from DataPrepareUtils import cal_msg_edge_index
from DimeModule import DimeModule
from CoulombLayer import CoulombLayer
from D3DispersionLayer import D3DispersionLayer
from PhysModule import PhysModule
from AtomToEdgeLayer import AtomToEdgeLayer
from EdgeToAtomLayer import EdgeToAtomLayer
from EmbeddingLayer import EmbeddingLayer
from MCDropout import ConcreteDropout
from BesselCalculator import bessel_expansion_raw
from BesselCalculatorFast import BesselCalculator
from utils_functions import floating_type, device, dime_edge_expansion, softplus_inverse, \
    gaussian_rbf, info_resolver, expansion_splitter, error_message, option_solver
#from tags import tags

class PhysDimeNet(nn.Module):
    """
    Combination of PhyNet and DimeNet
    For non-bonding interaction, using atom-atom interaction in PhysNet
    For bonding interaction, using directional message passing
    Final prediction is the combination of PhysNet and DimeNet

    Next time I will use **kwargs :<
    """

    def __init__(self,
                 n_atom_embedding,
                 modules,
                 bonding_type,
                 n_feature,
                 n_output,
                 n_dime_before_residual,
                 n_dime_after_residual,
                 n_output_dense,
                 n_phys_atomic_res,
                 n_phys_interaction_res,
                 n_phys_output_res,
                 n_bi_linear,
                 nh_lambda,
                 normalize,
                 shared_normalize_param,
                 activations,
                 restrain_non_bond_pred,
                 expansion_fn,
                 uncertainty_modify,
                 coulomb_charge_correct,
                 energy_shift=None,
                 energy_scale=None,
                 debug_mode=False,
                 action="E",
                 target_names=None,
                 batch_norm=False,
                 dropout=False,
                 requires_atom_prop=False,
                 get_atom_embedding=False,
                 use_qmd=False,
                 use_solvent=False,
                 **kwargs):
        """

        :param n_atom_embedding: number of atoms to embed, usually set to 95
        :param n_feature:
        :param n_output:
        :param n_dime_before_residual:
        :param n_dime_after_residual:
        :param n_output_dense:
        :param n_bi_linear: Dimension of bi-linear layer in DimeNet, also called N_tensor in paper
        :param nh_lambda: non-hierarchical penalty coefficient
        :param debug_mode:
        """
        super().__init__()
        #print("------unused keys in model-----")
        #for key in kwargs:
        #    print("{}: {}".format(key, kwargs[key]))

        #self.logger = logging.getLogger()
        self.use_qmd = use_qmd
        self.use_solvent=use_solvent
        self.requires_atom_prop = requires_atom_prop
        self.get_atom_embedding = get_atom_embedding
        #if action in tags.requires_atomic_prop:
            #self.logger.info("Overwriting self.requires_atom_prop = True because you require atomic props")
        self.requires_atom_prop = True
        # convert input into a dictionary
        self.target_names = target_names
        self.action = action
        self.coulomb_charge_correct = coulomb_charge_correct
        self.uncertainty_modify = uncertainty_modify
        self.expansion_fn = expansion_splitter(expansion_fn)

        self.activations = activations.split(' ')
        module_str_list = modules.split()
        bonding_str_list = bonding_type.split()
        # main modules, including P (PhysNet), D (DimeNet), etc.
        self.main_module_str = []
        self.main_bonding_str = []
        # post modules are either C (Coulomb) or D3 (D3 Dispersion)
        self.post_module_str = []
        self.post_bonding_str = []
        for this_module_str, this_bonding_str in zip(module_str_list, bonding_str_list):
            '''
            Separating main module and post module
            '''
            this_module_str = this_module_str.split('[')[0]
            if this_module_str in ['D', 'P', 'D-noOut', 'P-noOut']:
                self.main_module_str.append(this_module_str)
                self.main_bonding_str.append(this_bonding_str)
            elif this_module_str in ['C', 'D3']:
                self.post_module_str.append(this_module_str)
                self.post_bonding_str.append(this_bonding_str)
            else:
                error_message(this_module_str, 'module')
        self.bonding_type_keys = set(bonding_str_list)

        # whether calculate long range interaction or not
        self.contains_lr = False
        for _bonding_type in self.bonding_type_keys:
            if _bonding_type.find('L') >= 0:
                self.contains_lr = True

        module_bond_combine_str = []
        msg_bond_type = []
        for module, bond in zip(module_str_list, bonding_str_list):
            module = module.split('[')[0]
            module_bond_combine_str.append('{}_{}'.format(module, bond))
            if module == 'D':
                msg_bond_type.append(bond)
        self.module_bond_combine_str = set(module_bond_combine_str)
        # These bonds need to be expanded into message version (i.e. 3 body interaction)
        self.msg_bond_type = set(msg_bond_type)

        self.restrain_non_bond_pred = restrain_non_bond_pred
        self.shared_normalize_param = shared_normalize_param
        self.normalize = normalize
        self.n_phys_output_res = n_phys_output_res
        self.n_phys_interaction_res = n_phys_interaction_res
        self.n_phys_atomic_res = n_phys_atomic_res
        self.debug_mode = debug_mode
        self.n_output = n_output
        self.nhlambda = nh_lambda

        # A dictionary which parses an expansion combination into detailed information
        self.expansion_info_getter = {
            combination: info_resolver(self.expansion_fn[combination])
            for combination in self.module_bond_combine_str
        }

        # registering necessary parameters for some expansions if needed
        for combination in self.expansion_fn.keys():
            expansion_fn_info = self.expansion_info_getter[combination]
            if expansion_fn_info['name'] == "gaussian":
                n_rbf = expansion_fn_info['n']
                feature_dist = expansion_fn_info['dist']
                feature_dist = torch.as_tensor(feature_dist).type(floating_type)
                self.register_parameter('cutoff' + combination, torch.nn.Parameter(feature_dist, False))
                # Centers are params for Gaussian RBF expansion in PhysNet
                centers = softplus_inverse(torch.linspace(1.0, math.exp(-feature_dist), n_rbf))
                centers = torch.nn.functional.softplus(centers)
                self.register_parameter('centers' + combination, torch.nn.Parameter(centers, True))

                # Widths are params for Gaussian RBF expansion in PhysNet
                widths = [softplus_inverse((0.5 / ((1.0 - torch.exp(-feature_dist)) / n_rbf)) ** 2)] * n_rbf
                widths = torch.as_tensor(widths).type(floating_type)
                widths = torch.nn.functional.softplus(widths)
                self.register_parameter('widths' + combination, torch.nn.Parameter(widths, True))
            elif expansion_fn_info['name'] == 'defaultDime':
                n_srbf = self.expansion_info_getter[combination]['n_srbf']
                n_shbf = self.expansion_info_getter[combination]['n_shbf']
                envelop_p = self.expansion_info_getter[combination]['envelop_p']
                setattr(self, f"bessel_calculator_{n_srbf}_{n_shbf}", BesselCalculator(n_srbf, n_shbf, envelop_p))

        self.base_unit_getter = {
            'D': "edge",
            'D-noOut': "edge",
            'P': "atom",
            'P-noOut': "atom",
            'C': "atom",
            'D3': "atom"
        }

        self.dist_calculator = nn.PairwiseDistance(keepdim=True)

        if self.use_qmd: self.embedding_layer = EmbeddingLayer(n_atom_embedding, 157)
        elif self.use_solvent: self.embedding_layer = EmbeddingLayer(n_atom_embedding, 148)
        else: self.embedding_layer = EmbeddingLayer(n_atom_embedding, n_feature) # if addiing QMD features, substract from the n_feature

        previous_module = 'P'
        '''
        registering main modules
        '''
        self.main_module_list = nn.ModuleList()
        # stores extra info including module type, bonding type, etc
        self.main_module_info = []
        for i, (module_str, bonding_str) in enumerate(zip(module_str_list, bonding_str_list)):
            # contents within '[]' will be considered options
            _options = option_solver(module_str)
            module_str = module_str.split('[')[0]
            combination = module_str + "_" + bonding_str
            if module_str in ['D', 'D-noOut']:
                n_dime_rbf = self.expansion_info_getter[combination]['n']
                n_srbf = self.expansion_info_getter[combination]['n_srbf']
                n_shbf = self.expansion_info_getter[combination]['n_shbf']
                dim_sbf = n_srbf * (n_shbf + 1)
                this_module_str = DimeModule(dim_rbf=n_dime_rbf,
                                             dim_sbf=dim_sbf,
                                             dim_msg=n_feature,
                                             n_output=n_output,
                                             n_res_interaction=n_dime_before_residual,
                                             n_res_msg=n_dime_after_residual,
                                             n_dense_output=n_output_dense,
                                             dim_bi_linear=n_bi_linear,
                                             activation=self.activations[i],
                                             uncertainty_modify=uncertainty_modify)
                if self.uncertainty_modify == 'concreteDropoutModule':
                    this_module_str = ConcreteDropout(this_module_str, module_type='DimeNet')
                self.main_module_list.append(this_module_str)
                self.main_module_info.append({"module_str": module_str, "bonding_str": bonding_str,
                                              "combine_str": "{}_{}".format(module_str, bonding_str),
                                              "is_transition": False})
                if self.base_unit_getter[previous_module] == "atom":
                    self.main_module_list.append(AtomToEdgeLayer(n_dime_rbf, n_feature, self.activations[i]))
                    self.main_module_info.append({"is_transition": True})

            elif module_str in ['P', 'P-noOut']:
                this_module_str = PhysModule(F=n_feature,
                                             K=self.expansion_info_getter[combination]['n'],
                                             n_output=n_output,
                                             n_res_atomic=n_phys_atomic_res,
                                             n_res_interaction=n_phys_interaction_res,
                                             n_res_output=n_phys_output_res,
                                             activation=self.activations[i],
                                             uncertainty_modify=uncertainty_modify,
                                             n_read_out=int(_options['n_read_out']) if 'n_read_out' in _options else 0,
                                             batch_norm=batch_norm,
                                             dropout=dropout)
                if self.uncertainty_modify == 'concreteDropoutModule':
                    this_module_str = ConcreteDropout(this_module_str, module_type='PhysNet')
                self.main_module_list.append(this_module_str)
                self.main_module_info.append({"module_str": module_str, "bonding_str": bonding_str,
                                              "combine_str": "{}_{}".format(module_str, bonding_str),
                                              "is_transition": False})
                if self.base_unit_getter[previous_module] == "edge":
                    self.main_module_list.append(EdgeToAtomLayer())
                    self.main_module_info.append({"is_transition": True})
            elif module_str in ['C', 'D3']:
                pass
            else:
                error_message(module_str, 'module')
            previous_module = module_str

        # TODO Post modules to list
        for i, (module_str, bonding_str) in enumerate(zip(self.post_module_str, self.post_bonding_str)):
            if module_str == 'C':
                combination = module_str + "_" + bonding_str
                self.add_module('post_module{}'.format(i),
                                CoulombLayer(cutoff=self.expansion_info_getter[combination]['dist']))
            elif module_str == 'D3':
                self.add_module('post_module{}'.format(i), D3DispersionLayer(s6=0.5, s8=0.2130, a1=0.0, a2=6.0519))
            else:
                error_message(module_str, 'module')

        # TODO normalize to list
        if self.normalize:
            '''
            Atom-wise shift and scale, used in PhysNet
            '''
            if shared_normalize_param:
                shift_matrix = torch.zeros(95, n_output).type(floating_type)
                scale_matrix = torch.zeros(95, n_output).type(floating_type).fill_(1.0)
                if energy_shift is not None:
                    if isinstance(energy_shift, torch.Tensor):
                        if shift_matrix.shape == energy_shift.shape:
                            shift_matrix = energy_shift
                        else:
                            shift_matrix[:, :] = energy_shift.view(1, -1)
                    else:
                        shift_matrix[:, 0] = energy_shift
                if energy_scale is not None:
                    if isinstance(energy_scale, torch.Tensor):
                        if scale_matrix.shape == energy_scale.shape:
                            scale_matrix = energy_scale
                        else:
                            scale_matrix[:, :] = energy_scale.view(1, -1)
                    else:
                        scale_matrix[:, 0] = energy_scale
                shift_matrix = shift_matrix / len(self.bonding_type_keys)
                self.register_parameter('scale', torch.nn.Parameter(scale_matrix, requires_grad=True))
                self.register_parameter('shift', torch.nn.Parameter(shift_matrix, requires_grad=True))
            else:
                for key in self.bonding_type_keys:
                    shift_matrix = torch.zeros(95, n_output).type(floating_type)
                    scale_matrix = torch.zeros(95, n_output).type(floating_type).fill_(1.0)
                    if energy_shift is not None:
                        shift_matrix[:, 0] = energy_shift
                    if energy_scale is not None:
                        scale_matrix[:, 0] = energy_scale
                    shift_matrix = shift_matrix / len(self.bonding_type_keys)
                    self.register_parameter('scale{}'.format(key), torch.nn.Parameter(scale_matrix, requires_grad=True))
                    self.register_parameter('shift{}'.format(key), torch.nn.Parameter(shift_matrix, requires_grad=True))

    def freeze_prev_layers(self, freeze_extra=False):
        if freeze_extra:
            # Freeze scale, shift and Gaussian RBF parameters
            for param in self.parameters():
                param.requires_grad_(False)
        for i in range(len(self.main_module_str)):
            self.main_module_list[i].freeze_prev_layers()

    def forward(self, data):
        # torch.cuda.synchronize(device=device)
        # t0 = time.time()

        R = data.R.type(floating_type)
        Z = data.Z
        N = data.N
        '''
        Note: non_bond_edge_index is for non-bonding interactions
              bond_edge_index is for bonding interactions
        '''
        atom_mol_batch = data.atom_mol_batch
        edge_index_getter = {}
        for bonding_str in self.bonding_type_keys:
            # prepare edge index
            edge_index = getattr(data, bonding_str + '_edge_index', False)
            if edge_index is not False:
                edge_index_getter[bonding_str] = edge_index + getattr(data, bonding_str + '_edge_index_correct')
            else:
                edge_index_getter[bonding_str] = torch.cat(
                    [data[_type + '_edge_index'] + data[_type + '_edge_index_correct'] for _type in bonding_str],
                    dim=-1)

        msg_edge_index_getter = {}
        for bonding_str in self.msg_bond_type:
            # prepare msg edge index
            this_msg_edge_index = getattr(data, bonding_str + '_msg_edge_index', False)
            if this_msg_edge_index is not False:
                msg_edge_index_getter[bonding_str] = this_msg_edge_index + \
                                                     getattr(data, bonding_str + '_msg_edge_index_correct')
            else:
                msg_edge_index_getter[bonding_str] = cal_msg_edge_index(edge_index_getter[bonding_str]).to(device)

        # t0 = record_data('edge index prepare', t0)

        expansions = {}
        '''
        calculating expansion
        '''
        for combination in self.module_bond_combine_str:
            module_str = combination.split('_')[0]
            this_bond = combination.split('_')[1]
            this_expansion = self.expansion_info_getter[combination]['name']
            if module_str in ['D', 'D-noOut']:
                # DimeNet, calculate sbf and rbf
                if this_expansion == "defaultDime":
                    n_srbf = self.expansion_info_getter[combination]['n_srbf']
                    n_shbf = self.expansion_info_getter[combination]['n_shbf']
                    expansions[combination] = dime_edge_expansion(R, edge_index_getter[this_bond],
                                                                  msg_edge_index_getter[this_bond],
                                                                  self.expansion_info_getter[combination]['n'],
                                                                  self.dist_calculator,
                                                                  getattr(self, f"bessel_calculator_{n_srbf}_{n_shbf}"),
                                                                  self.expansion_info_getter[combination]['dist'],
                                                                  return_dict=True)
                else:
                    raise ValueError("Double check your expansion input!")
            elif module_str in ['P', 'P-noOut']:
                # PhysNet, calculate rbf
                if this_expansion == 'bessel':
                    this_edge_index = edge_index_getter[this_bond]
                    dist_atom = self.dist_calculator(R[this_edge_index[0, :], :], R[this_edge_index[1, :], :])
                    rbf = bessel_expansion_raw(dist_atom, self.expansion_info_getter[combination]['n'],
                                               self.expansion_info_getter[combination]['dist'])
                    expansions[combination] = {"rbf": rbf}
                elif this_expansion == 'gaussian':
                    this_edge_index = edge_index_getter[this_bond]
                    pair_dist = self.dist_calculator(R[this_edge_index[0, :], :], R[this_edge_index[1, :], :])
                    expansions[combination] = gaussian_rbf(pair_dist, getattr(self, 'centers' + combination),
                                                           getattr(self, 'widths' + combination),
                                                           getattr(self, 'cutoff' + combination),
                                                           return_dict=True)
                else:
                    error_message(this_expansion, 'expansion')
            elif (module_str == 'C') or (module_str == 'D3'):
                '''
                In this situation, we only need to calculate pair-wise distance.
                '''
                this_edge_index = edge_index_getter[this_bond]
                # TODO pair dist was calculated twice here
                expansions[combination] = {"pair_dist": self.dist_calculator(R[this_edge_index[0, :], :],
                                                                             R[this_edge_index[1, :], :])}
            else:
                # something went wrong
                error_message(module_str, 'module')

        # t0 = record_data('calculate rbf', t0)

        '''
        mji: edge diff
        vi:  node diff
        '''
        vi = self.embedding_layer(Z) # atomic number embedding
        if self.use_qmd:
            vi = torch.cat([vi, data.qmd_features], axis=-1)
        elif self.use_solvent:
            vi = torch.cat([vi, data.qmd_features, data.solvents], axis=-1)

        # t0 = record_data('diff layer', t0)

        separated_last_out = {key: None for key in self.bonding_type_keys}
        separated_out_sum = {key: 0. for key in self.bonding_type_keys}

        nh_loss = torch.zeros(1).type(floating_type).to(device)
        mji = None
        out_dict = {"vi": vi, "mji": mji}
        '''
        Going through main modules
        '''
        for info, _module in zip(self.main_module_info, self.main_module_list):

            # t0 = time.time()

            out_dict["info"] = info
            if not info["is_transition"]:
                out_dict["edge_index"] = edge_index_getter[info["bonding_str"]]
                out_dict["edge_attr"] = expansions[info["combine_str"]]
            if info["module_str"].split("-")[0] == "D":
                out_dict["msg_edge_index"] = msg_edge_index_getter[info["bonding_str"]]

            # t0 = record_data('assign values', t0)

            out_dict = _module(out_dict)

            # t0 = record_data('main modules', t0)

            if info["is_transition"] or info["module_str"].split("-")[-1] == '-noOut':
                pass
            else:
                nh_loss = nh_loss + out_dict["regularization"]
                if separated_last_out[info["bonding_str"]] is not None:
                    # Calculating non-hierarchical penalty
                    out2 = out_dict["out"] ** 2
                    last_out2 = separated_last_out[info["bonding_str"]] ** 2
                    nh_loss = nh_loss + torch.mean(out2 / (out2 + last_out2 + 1e-7)) * self.nhlambda
                separated_last_out[info["bonding_str"]] = out_dict["out"]
                separated_out_sum[info["bonding_str"]] = separated_out_sum[info["bonding_str"]] + out_dict["out"]

            # t0 = record_data('nh loss calculation', t0)

        # t0 = record_data('main modules', t0)

        if self.normalize:
            '''
            Atom-wise shifting and scale
            '''
            if self.shared_normalize_param:
                for key in self.bonding_type_keys:
                    separated_out_sum[key] = self.scale[Z, :] * separated_out_sum[key] + self.shift[Z, :]
            else:
                for key in self.bonding_type_keys:
                    separated_out_sum[key] = getattr(self, 'scale{}'.format(key))[Z, :] * separated_out_sum[key] + \
                                             getattr(self, 'shift{}'.format(key))[Z, :]

        atom_prop = 0.
        for key in self.bonding_type_keys:
            atom_prop = atom_prop + separated_out_sum[key]

        '''
        Post modules: Coulomb or D3 Dispersion layers
        '''
        for i, (module_str, bonding_str) in enumerate(zip(self.post_module_str, self.post_bonding_str)):
            this_edge_index = edge_index_getter[bonding_str]
            this_expansion = expansions["{}_{}".format(module_str, bonding_str)]
            if module_str == 'C':
                if self.coulomb_charge_correct:
                    Q = data.Q
                    coulomb_correction = self._modules["post_module{}".format(i)](atom_prop[:, -1],
                                                                                this_expansion["pair_dist"],
                                                                                this_edge_index, q_ref=Q, N=N,
                                                                                atom_mol_batch=atom_mol_batch)
                else:
                    print("one of the variables needed for gradient computation has been modified by an inplace"
                          " operation: need to be fixed here, probably in function cal_coulomb_E")
                    coulomb_correction = self._modules["post_module{}".format(i)](atom_prop[:, -1], this_expansion,
                                                                                this_edge_index)
                atom_prop[:, 0] = atom_prop[:, 0] + coulomb_correction
            elif module_str == 'D3':
                d3_correction = self._modules["post_module{}".format(i)](Z, this_expansion, this_edge_index)
                atom_prop[:, 0] = atom_prop[:, 0] + d3_correction
            else:
                error_message(module_str, 'module')

        # t0 = record_data('post modules', t0)

        if self.restrain_non_bond_pred and ('N' in self.bonding_type_keys):
            # Bonding energy should be larger than non-bonding energy
            atom_prop2 = atom_prop ** 2
            non_bond_prop2 = separated_out_sum['N'] ** 2
            nh_loss = nh_loss + torch.mean(non_bond_prop2 / (atom_prop2 + 1e-7)) * self.nhlambda

        # Total prediction is the summation of bond and non-bond prediction
        mol_pred_properties = scatter(reduce='add', src=atom_prop, index=atom_mol_batch, dim=0)

        # t0 = record_data('atom prop to molecule', t0)

        # t0 = record_data('others', t0)
        if self.debug_mode:
            if torch.abs(mol_pred_properties.detach()).max() > 1e4:
                error_message(torch.abs(mol_pred_properties.detach()).max(), 'Energy prediction')

        output = {}
        if self.action in ["E", "names_and_QD", "atomMol"]:
            mol_prop = mol_pred_properties[:, :-1]
            assert self.n_output > 1
            # the last property is considered as atomic charge prediction
            Q_pred = mol_pred_properties[:, -1]
            Q_atom = atom_prop[:, -1]
            atom_prop = atom_prop[:, :-1]
            D_atom = Q_atom.view(-1, 1) * R
            D_pred = scatter(reduce='add', src=D_atom, index=atom_mol_batch, dim=0)
            output["Q_pred"] = Q_pred
            output["D_pred"] = D_pred
            if self.requires_atom_prop:
                output["Q_atom"] = Q_atom
        else:
            mol_prop = mol_pred_properties
        output["mol_prop"] = mol_prop
        output["nh_loss"] = nh_loss

        if self.get_atom_embedding:
            out_dict['atom_mol_batch'] = atom_mol_batch
            return out_dict

        if self.requires_atom_prop:
            output["atom_prop"] = atom_prop
            output["atom_mol_batch"] = atom_mol_batch
        return output


from math import e

from scipy.stats import norm
cnd = norm.cdf

# Related third party imports
import numpy

def d1(S,K,t,r,sigma):  # see Hull, page 292

    sigma_squared = sigma*sigma
    numerator = numpy.log( S/float(K) ) + ( r + sigma_squared/2.) * t
    denominator = sigma * numpy.sqrt(t)

    return numerator/denominator

def d2(S,K,t,r,sigma):  # see Hull, page 292
    return d1(S, K, t, r, sigma) - sigma*numpy.sqrt(t)

def delta(flag, S, K, t, r, sigma):

    d_1 = d1(S, K, t, r, sigma)

    if flag == 'p':
        return cnd(d_1) - 1.0
    else:
        return cnd(d_1)


import sys
import threading
import gc
import types
from contextlib import contextmanager
from enum import Enum
from typing import Optional, Callable

from blinker import Signal

from streamlit import config
from streamlit import magic
from streamlit import source_util
from streamlit import util
from streamlit.error_util import handle_uncaught_app_exception
from streamlit.in_memory_file_manager import in_memory_file_manager
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
from streamlit.script_run_context import ScriptRunContext, add_script_run_ctx
from streamlit.script_run_context import get_script_run_ctx
from streamlit.script_request_queue import ScriptRequest, ScriptRequestQueue, RerunData
from streamlit.session_data import SessionData
from streamlit.state import (
    SessionState,
    SCRIPT_RUN_WITHOUT_ERRORS_KEY,
)
from streamlit.logger import get_logger
from streamlit.proto.ClientState_pb2 import ClientState

from streamlit.uploaded_file_manager import UploadedFileManager

LOGGER = get_logger(__name__)

class ScriptRunnerEvent(Enum):
    # The script started running.
    SCRIPT_STARTED = "SCRIPT_STARTED"

    # The script run stopped because of a compile error.
    SCRIPT_STOPPED_WITH_COMPILE_ERROR = "SCRIPT_STOPPED_WITH_COMPILE_ERROR"

    # The script run stopped because it ran to completion, or was
    # interrupted by the user.
    SCRIPT_STOPPED_WITH_SUCCESS = "SCRIPT_STOPPED_WITH_SUCCESS"

    # The ScriptRunner is done processing the ScriptEventQueue and
    # is shut down.
    SHUTDOWN = "SHUTDOWN"

"""
Note [Threading]
There are two kinds of threads in Streamlit, the main thread and script threads.
The main thread is started by invoking the Streamlit CLI, and bootstraps the
framework and runs the Tornado webserver.
A script thread is created by a ScriptRunner when it starts. The script thread
is where the ScriptRunner executes, including running the user script itself,
processing messages to/from the frontend, and all the Streamlit library function
calls in the user script.
It is possible for the user script to spawn its own threads, which could call
Streamlit functions. We restrict the ScriptRunner's execution control to the
script thread. Calling Streamlit functions from other threads is unlikely to
work correctly due to lack of ScriptRunContext, so we may add a guard against
it in the future.
"""

class ScriptRunner:
    def __init__(
        self,
        session_id: str,
        session_data: SessionData,
        enqueue_forward_msg: Callable[[ForwardMsg], None],
        client_state: ClientState,
        request_queue: ScriptRequestQueue,
        session_state: SessionState,
        uploaded_file_mgr: UploadedFileManager,
    ):
        """Initialize the ScriptRunner.

        (The ScriptRunner won't start executing until start() is called.)

        Parameters
        ----------
        session_id : str
            The AppSession's id.

        session_data : SessionData
            The AppSession's session data.

        enqueue_forward_msg : Callable
            Function to call to send a ForwardMsg to the frontend.
            (When not running a unit test, this will be the enqueue function
            of the AppSession instance that created this ScriptRunner.)

        client_state : ClientState
            The current state from the client (widgets and query params).

        request_queue : ScriptRequestQueue
            The queue that the AppSession is publishing ScriptRequests to.
            ScriptRunner will continue running until the queue is empty,
            and then shut down.

        uploaded_file_mgr : UploadedFileManager
            The File manager to store the data uploaded by the file_uploader widget.

        """
        self._session_id = session_id
        self._session_data = session_data
        self._enqueue_forward_msg = enqueue_forward_msg
        self._request_queue = request_queue
        self._uploaded_file_mgr = uploaded_file_mgr

        self._client_state = client_state
        self._session_state: SessionState = session_state
        self._session_state.set_widgets_from_proto(client_state.widget_states)

        self.on_event = Signal(
            doc="""Emitted when a ScriptRunnerEvent occurs.

            This signal is *not* emitted on the same thread that the
            ScriptRunner was created on.

            Parameters
            ----------
            event : ScriptRunnerEvent

            exception : BaseException | None
                Our compile error. Set only for the
                SCRIPT_STOPPED_WITH_COMPILE_ERROR event.

            widget_states : streamlit.proto.WidgetStates_pb2.WidgetStates | None
                The ScriptRunner's final WidgetStates. Set only for the
                SHUTDOWN event.
            """
        )

        # Set to true when we process a SHUTDOWN request
        self._shutdown_requested = False

        # Set to true while we're executing. Used by
        # _maybe_handle_execution_control_request.
        self._execing = False

        # This is initialized in start()
        self._script_thread: Optional[threading.Thread] = None

    def __repr__(self) -> str:
        return util.repr_(self)

    def start(self) -> None:
        """Start a new thread to process the ScriptEventQueue.

        This must be called only once.

        """
        if self._script_thread is not None:
            raise Exception("ScriptRunner was already started")

        self._script_thread = threading.Thread(
            target=self._run_script_thread,
            name="ScriptRunner.scriptThread",
        )
        self._script_thread.start()

    def _get_script_run_ctx(self) -> ScriptRunContext:
        """Get the ScriptRunContext for the current thread.

        Returns
        -------
        ScriptRunContext
            The ScriptRunContext for the current thread.

        Raises
        ------
        AssertionError
            If called outside of a ScriptRunner thread.
        RuntimeError
            If there is no ScriptRunContext for the current thread.

        """
        assert self._is_in_script_thread()

        ctx = get_script_run_ctx()
        if ctx is None:
            # This should never be possible on the script_runner thread.
            raise RuntimeError(
                "ScriptRunner thread has a null ScriptRunContext. Something has gone very wrong!"
            )
        return ctx

    def _run_script_thread(self) -> None:
        """The entry point for the script thread.

        Processes the ScriptRequestQueue, which will at least contain the RERUN
        request that will trigger the first script-run.

        When the ScriptRequestQueue is empty, or when a SHUTDOWN request is
        dequeued, this function will exit and its thread will terminate.
        """
        assert self._is_in_script_thread()

        LOGGER.debug("Beginning script thread")

        # Create and attach the thread's ScriptRunContext
        ctx = ScriptRunContext(
            session_id=self._session_id,
            enqueue=self._enqueue,
            query_string=self._client_state.query_string,
            session_state=self._session_state,
            uploaded_file_mgr=self._uploaded_file_mgr,
        )
        add_script_run_ctx(threading.current_thread(), ctx)

        while not self._shutdown_requested and self._request_queue.has_request:
            request, data = self._request_queue.dequeue()
            if request == ScriptRequest.STOP:
                LOGGER.debug("Ignoring STOP request while not running")
            elif request == ScriptRequest.SHUTDOWN:
                LOGGER.debug("Shutting down")
                self._shutdown_requested = True
            elif request == ScriptRequest.RERUN:
                self._run_script(data)
            else:
                raise RuntimeError("Unrecognized ScriptRequest: %s" % request)

        # Send a SHUTDOWN event before exiting. This includes the widget values
        # as they existed after our last successful script run, which the
        # AppSession will pass on to the next ScriptRunner that gets
        # created.
        client_state = ClientState()
        client_state.query_string = ctx.query_string
        widget_states = self._session_state.as_widget_states()
        client_state.widget_states.widgets.extend(widget_states)
        self.on_event.send(ScriptRunnerEvent.SHUTDOWN, client_state=client_state)

    def _is_in_script_thread(self) -> bool:
        """True if the calling function is running in the script thread"""
        return self._script_thread == threading.current_thread()

    def _enqueue(self, msg: ForwardMsg) -> None:
        """Enqueue a ForwardMsg to our browser queue.
        This private function is called by ScriptRunContext only.

        It may be called from the script thread OR the main thread.
        """
        # Whenever we enqueue a ForwardMsg, we also handle any pending
        # execution control request. This means that a script can be
        # cleanly interrupted and stopped inside most `st.foo` calls.
        #
        # (If "runner.installTracer" is true, then we'll actually be
        # handling these requests in a callback called after every Python
        # instruction instead.)
        if not config.get_option("runner.installTracer"):
            self._maybe_handle_execution_control_request()

        # Pass the message up to our associated AppSession.
        self._enqueue_forward_msg(msg)

    def _maybe_handle_execution_control_request(self) -> None:
        if not self._is_in_script_thread():
            # We can only handle execution_control_request if we're on the
            # script execution thread. However, it's possible for deltas to
            # be enqueued (and, therefore, for this function to be called)
            # in separate threads, so we check for that here.
            return

        if not self._execing:
            # If the _execing flag is not set, we're not actually inside
            # an exec() call. This happens when our script exec() completes,
            # we change our state to STOPPED, and a statechange-listener
            # enqueues a new ForwardEvent
            return

        # Pop the next request from our queue.
        request, data = self._request_queue.dequeue()
        if request is None:
            return

        LOGGER.debug("Received ScriptRequest: %s", request)
        if request == ScriptRequest.STOP:
            raise StopException()
        elif request == ScriptRequest.SHUTDOWN:
            self._shutdown_requested = True
            raise StopException()
        elif request == ScriptRequest.RERUN:
            raise RerunException(data)
        else:
            raise RuntimeError("Unrecognized ScriptRequest: %s" % request)

    def _install_tracer(self) -> None:
        """Install function that runs before each line of the script."""

        def trace_calls(frame, event, arg):
            self._maybe_handle_execution_control_request()
            return trace_calls

        # Python interpreters are not required to implement sys.settrace.
        if hasattr(sys, "settrace"):
            sys.settrace(trace_calls)

    @contextmanager
    def _set_execing_flag(self):
        """A context for setting the ScriptRunner._execing flag.

        Used by _maybe_handle_execution_control_request to ensure that
        we only handle requests while we're inside an exec() call
        """
        if self._execing:
            raise RuntimeError("Nested set_execing_flag call")
        self._execing = True
        try:
            yield
        finally:
            self._execing = False

    def _run_script(self, rerun_data: RerunData) -> None:
        """Run our script.

        Parameters
        ----------
        rerun_data: RerunData
            The RerunData to use.

        """
        assert self._is_in_script_thread()

        LOGGER.debug("Running script %s", rerun_data)

        # Reset DeltaGenerators, widgets, media files.
        in_memory_file_manager.clear_session_files()

        ctx = self._get_script_run_ctx()
        ctx.reset(query_string=rerun_data.query_string)

        self.on_event.send(ScriptRunnerEvent.SCRIPT_STARTED)

        # Compile the script. Any errors thrown here will be surfaced
        # to the user via a modal dialog in the frontend, and won't result
        # in their previous script elements disappearing.

        try:
            with source_util.open_python_file(self._session_data.main_script_path) as f:
                filebody = f.read()

            if config.get_option("runner.magicEnabled"):
                filebody = magic.add_magic(
                    filebody, self._session_data.main_script_path
                )

            code = compile(
                filebody,
                # Pass in the file path so it can show up in exceptions.
                self._session_data.main_script_path,
                # We're compiling entire blocks of Python, so we need "exec"
                # mode (as opposed to "eval" or "single").
                mode="exec",
                # Don't inherit any flags or "future" statements.
                flags=0,
                dont_inherit=1,
                # Use the default optimization options.
                optimize=-1,
            )

        except BaseException as e:
            # We got a compile error. Send an error event and bail immediately.
            LOGGER.debug("Fatal script error: %s" % e)
            self._session_state[SCRIPT_RUN_WITHOUT_ERRORS_KEY] = False
            self.on_event.send(
                ScriptRunnerEvent.SCRIPT_STOPPED_WITH_COMPILE_ERROR, exception=e
            )
            return

        # If we get here, we've successfully compiled our script. The next step
        # is to run it. Errors thrown during execution will be shown to the
        # user as ExceptionElements.

        if config.get_option("runner.installTracer"):
            self._install_tracer()

        # This will be set to a RerunData instance if our execution
        # is interrupted by a RerunException.
        rerun_with_data = None

        try:
            # Create fake module. This gives us a name global namespace to
            # execute the code in.
            module = _new_module("__main__")

            # Install the fake module as the __main__ module. This allows
            # the pickle module to work inside the user's code, since it now
            # can know the module where the pickled objects stem from.
            # IMPORTANT: This means we can't use "if __name__ == '__main__'" in
            # our code, as it will point to the wrong module!!!
            sys.modules["__main__"] = module

            # Add special variables to the module's globals dict.
            # Note: The following is a requirement for the CodeHasher to
            # work correctly. The CodeHasher is scoped to
            # files contained in the directory of __main__.__file__, which we
            # assume is the main script directory.
            module.__dict__["__file__"] = self._session_data.main_script_path

            with modified_sys_path(self._session_data), self._set_execing_flag():
                # Run callbacks for widgets whose values have changed.
                if rerun_data.widget_states is not None:
                    # Update the WidgetManager with the new widget_states.
                    # The old states, used to skip callbacks if values
                    # haven't changed, are also preserved in the
                    # WidgetManager.
                    self._session_state.compact_state()
                    self._session_state.set_widgets_from_proto(rerun_data.widget_states)

                    self._session_state.call_callbacks()

                ctx.on_script_start()
                exec(code, module.__dict__)
                self._session_state[SCRIPT_RUN_WITHOUT_ERRORS_KEY] = True
        except RerunException as e:
            rerun_with_data = e.rerun_data

        except StopException:
            pass

        except BaseException as e:
            self._session_state[SCRIPT_RUN_WITHOUT_ERRORS_KEY] = False
            handle_uncaught_app_exception(e)

        finally:
            self._on_script_finished(ctx)

        # Use _log_if_error() to make sure we never ever ever stop running the
        # script without meaning to.
        _log_if_error(_clean_problem_modules)

        if rerun_with_data is not None:
            self._run_script(rerun_with_data)

    def _on_script_finished(self, ctx: ScriptRunContext) -> None:
        """Called when our script finishes executing, even if it finished
        early with an exception. We perform post-run cleanup here.
        """
        self._session_state.reset_triggers()
        self._session_state.cull_nonexistent(ctx.widget_ids_this_run)
        # Signal that the script has finished. (We use SCRIPT_STOPPED_WITH_SUCCESS
        # even if we were stopped with an exception.)
        self.on_event.send(ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS)
        # Delete expired files now that the script has run and files in use
        # are marked as active.
        in_memory_file_manager.del_expired_files()

        # Force garbage collection to run, to help avoid memory use building up
        # This is usually not an issue, but sometimes GC takes time to kick in and
        # causes apps to go over resource limits, and forcing it to run between
        # script runs is low cost, since we aren't doing much work anyway.
        if config.get_option("runner.postScriptGC"):
            gc.collect(2)

class ScriptControlException(BaseException):
    """Base exception for ScriptRunner."""

    pass

class StopException(ScriptControlException):
    """Silently stop the execution of the user's script."""

    pass

class RerunException(ScriptControlException):
    """Silently stop and rerun the user's script."""

    def __init__(self, rerun_data: RerunData):
        """Construct a RerunException

        Parameters
        ----------
        rerun_data : RerunData
            The RerunData that should be used to rerun the script
        """
        self.rerun_data = rerun_data

    def __repr__(self) -> str:
        return util.repr_(self)

def _clean_problem_modules() -> None:
    """Some modules are stateful, so we have to clear their state."""

    if "keras" in sys.modules:
        try:
            keras = sys.modules["keras"]
            keras.backend.clear_session()
        except:
            pass

    if "matplotlib.pyplot" in sys.modules:
        try:
            plt = sys.modules["matplotlib.pyplot"]
            plt.close("all")
        except:
            pass

def _new_module(name: str) -> types.ModuleType:
    """Create a new module with the given name."""
    return types.ModuleType(name)

# Code modified from IPython (BSD license)
# Source: https://github.com/ipython/ipython/blob/master/IPython/utils/syspathcontext.py#L42
class modified_sys_path:
    """A context for prepending a directory to sys.path for a second."""

    def __init__(self, session_data: SessionData):
        self._session_data = session_data
        self._added_path = False

    def __repr__(self) -> str:
        return util.repr_(self)

    def __enter__(self):
        if self._session_data.main_script_path not in sys.path:
            sys.path.insert(0, self._session_data.main_script_path)
            self._added_path = True

    def __exit__(self, type, value, traceback):
        if self._added_path:
            try:
                sys.path.remove(self._session_data.main_script_path)
            except ValueError:
                pass

        # Returning False causes any exceptions to be re-raised.
        return False

# The reason this is not a decorator is because we want to make it clear at the
# calling location that this function is being used.
def _log_if_error(fn: Callable[[], None]) -> None:
    try:
        fn()
    except Exception as e:
        LOGGER.warning(e)


import vpinn
import json
import inspect
import warnings
from abc import ABC, abstractmethod

class Problem(ABC):
    def __init__(self, device='cpu'):
        self.device = device
        self.ref_data = None

    # @abstractmethod
    # def pde(self, X, U):
    #     pass
    def load_ref_data(self, path):
        self.ref_data = path

    def run(self, load=None, task_id = 0, queue=None, lr=1e-3, logevery=100, plotevery=2000, args=None):
        if (hasattr(self, 'geom') == False and hasattr(self, 'geomtime') == False):
            raise TypeError('Invalid geom or geomtime.')

        if (hasattr(self, 'pde') == False):
            raise TypeError('PDE is not defined.')

        if (hasattr(self, 'outdim') == False):
            warnings.warn("Outdim of the PDE equation is not defined, the program views it as 1 defaultly.", UserWarning)
            self.outdim = 1

        if args:
            self.arg_map = args.to_json()
        else:
            try:
                with open('src/config/default_arg.json', 'r') as f:
                    self.arg_map = json.load(f)
            except Exception as e:
                print("Exception when analyzing config: ", str(e))

        self.solver = vpinn.solver.PDE(self.geom if hasattr(self, 'geom') else self.geomtime, self.pde, self.constrain if hasattr(self, 'constrain') else None)

        if self.__class__.__name__ in self.arg_map:

            # User defined arguments are found.
            func_params = inspect.signature(self.solver.model).parameters
            required_params = {k: self.arg_map[self.__class__.__name__][k] for k in func_params if k in self.arg_map[self.__class__.__name__]}
            if hasattr(self, 'inverse'):
                required_params['inverse'] = getattr(self, 'inverse')
            if hasattr(self, 'u_ref'):
                required_params['ref'] = getattr(self, 'u_ref')

            self.solver.model(**required_params, device=self.device, load=load)
            # params = {k: self.arg_map[k] for k in ('layer_size', 'neuron_type', 'grid_num', 'coef', 'Q', 'test_fcn_num', 'inverse', 'ref', 'ifsave')}
            # self.solver.model(**params, device=self.device, load=load)
            self.net = self.solver.train(self.__class__.__name__, epoch_num=self.arg_map[self.__class__.__name__]['epoch_num'], task_id=task_id, queue=queue, lr=lr, logevery=logevery, plotevery=plotevery)
            return self.net

        else:
            # Use default arguments.
            self.solver.model(
            layer_size=[int(len(self.bbox) / 2), 20, 20, 20, self.outdim],
            neuron_type='tanh',
            grid_num=[4] * int(len(self.bbox) / 2),
            coef= [1] * len(self.constrain) if hasattr(self, 'constrain') else 0,
            Q=10,
            device=self.device,
            test_fcn_num=5,
            load=load,
            inverse=getattr(self, 'inverse') if hasattr(self, 'inverse') else False,
            ref=getattr(self, 'u_ref') if hasattr(self, 'u_ref') else False,
            ifsave=getattr(self, 'ifsave') if hasattr(self, 'ifsave') else False)

            self.net = self.solver.train(self.__class__.__name__, epoch_num=20000, task_id=task_id, queue=queue, lr=lr, logevery=logevery, plotevery=plotevery)
            return self.net[-1]

    def plot(self):
        if self.__class__.__name__ in self.arg_map:
            # User defined arguments are found.
            func_params = inspect.signature(self.solver.plot).parameters
            required_params = {}
            for k in func_params:
                if k in self.arg_map[self.__class__.__name__]:
                    value = self.arg_map[self.__class__.__name__][k]
                    if isinstance(value, str):
                        value = value.replace('self.', '', 1) if value.startswith('self.') else value

                    if isinstance(value, str) and hasattr(self, value):
                        required_params[k] = getattr(self, value)
                    else:
                        required_params[k] = value
            if hasattr(self, 'inverse') and getattr(self, 'inverse') and hasattr(self, 'a_ref'):
                required_params['u_ref'] = getattr(self, 'a_ref')
            elif hasattr(self, 'u_ref'):
                required_params['u_ref'] = getattr(self, 'u_ref')

            if self.ref_data:
                required_params['data'] = self.ref_data

            if hasattr(self, 'scale'):
                required_params['scale'] = getattr(self, 'scale')

            if ('u_ref' in required_params)== False and ('data' in required_params) == False:
                print('No plot argument is given.')
                return
        else :
            raise TypeError('No plot config is defined.')
        return self.solver.plot(**required_params)


#! /usr/bin/env python3

from math import log10
import itertools
import sys
import multiprocessing as mp
import subprocess
import csv
import numpy

def cut(edc_cut_path, graph_info, phi, default_strategy, min_balance):
    """Run 'edc-cut', assert balanced cut is returned, and return the graph
    parameters and the balance.

    """
    graph_string, graph_params, graph_edges = graph_info
    result = subprocess.run([edc_cut_path, f'-phi={phi}', f'-balanced_cut_strategy={not(default_strategy)}', f'-min_balance={min_balance}'],
                            input=graph_string,
                            text=True,
                            check=True,
                            timeout=480,
                            stdout=subprocess.PIPE)
    if result.returncode != 0:
        print(f'Failed cut: {result.stdout}')
        exit(1)
    else:
        lines = result.stdout.split('\n')
        resultType = lines[0].split()[0]
        volA,volB = list(map(int, lines[0].split()[2:4]))
        assert volA + volB == 2 * graph_edges

        if resultType != 'balanced_cut':
            print(f'Cut resulted in: {resultType} with params {graph_params}')
            exit(1)
        xlen, *xs = list(map(int, lines[1].split()))
        assert xlen == len(xs)
        ylen, *ys = list(map(int, lines[2].split()))
        assert ylen == len(ys)

        balance = min(volA, volB) / (volA + volB)
        return (graph_params, graph_edges, default_strategy, min_balance, balance)

if __name__ == '__main__':
    if len(sys.argv) != 6:
        print('Expected five arguments')
        exit(1)
    _, _, edc_cut_path, seed, gen_graph, output_file = sys.argv

    graph_params = [{
        'name': 'clique-path',
        'n': 20,
        'k': k,
    } for k in [i*50 for i in range(1,20)]]

    def graphParamsToString(p):
        ps = [p['name'], str(p['n']), str(p['k'])]
        if 'r' in p:
            ps.append(str(p['r']))
        if 'p' in p:
            ps.append(str(p['p']))
        return '-'.join(ps)

    # contains tuples (graph_string, parameters for generating graph, edges in graph)
    graphs = []
    for ps in graph_params:
        cmd = [
            f'./{gen_graph}', f'--seed={seed}', ps['name'],
            '-n={}'.format(ps['n']), '-k={}'.format(ps['k'])
        ]
        result = subprocess.run(cmd,
                                text=True,
                                check=True,
                                timeout=60,
                                stdout=subprocess.PIPE)
        if result.returncode != 0:
            print('Generating graph with type {} failed'.format(ps['name']))
            exit(1)
        lines = result.stdout.strip().split('\n')
        m = int(lines[0].split()[1])
        assert (len(lines) == m + 1)
        graphs.append((result.stdout, ps, m))

    with mp.Pool() as pool:
        jobs = []
        for g in graphs:
            for phi in [0.001]:
                for balance in [0, 0.25, 0.45]:
                    for _ in range(8):
                        jobs.append((edc_cut_path, g, phi, True, balance))
                        jobs.append((edc_cut_path, g, phi, False, balance))
        result = pool.starmap(cut, jobs, chunksize=1)

    with open(output_file, 'w') as f:
        writer = csv.DictWriter(f,
                                fieldnames=[
                                    'graph',
                                    'edges',
                                    'default_strategy',
                                    'min_balance',
                                    'balance',
                                ])
        writer.writeheader()

        for p, edges, default_strategy, min_balance, balance in result:
            writer.writerow({
                'graph': graphParamsToString(p),
                'edges': edges,
                'default_strategy': 'Default' if default_strategy else 'Balanced',
                'min_balance': min_balance,
                'balance': balance,
            })


import utime
from machine import Pin, CAN, ADC
import machine
import config
import uasyncio as asyncio
from utilities import *

machine.freq(240000000)
import gc
gc.collect()

can = CanMgr(0,
            tx=config.config['can_tx'],
            rx=config.config['can_rx'],
            extframe=True,
            mode=CAN.NORMAL,
            baudrate=250000,
            slp_pin=config.config['can_slp']
            )

hbt_led = Pin(5, Pin.OUT)

async def do_hbt():
    while True:
        hbt_led.value(not hbt_led.value())
        await asyncio.sleep_ms(500)

_board = __import__('boards.' + config.config['board'])
board = getattr(_board, config.config['board'])

loop = asyncio.get_event_loop()

loop.create_task(do_hbt())
loop.create_task(can.chk())

loop.run_forever()


from django.urls import path
from . import views

urlpatterns = [
    path('test', views.test, name='test'),
    path('users', views.ListClinicianUser.as_view()),
    path('authenticate/clinicians', views.login_as_clinician, name='login_as_clinician'),
    path('authenticate/instructors', views.login_as_instructor, name='login_as_instructor'),
    path('authenticate/patients', views.login_as_patient, name='login_as_patient')
]


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
import backend.validators

class Migration(migrations.Migration):

    dependencies = [
        ('backend', '0005_auto_20160822_1251'),
    ]

    operations = [
        migrations.AddField(
            model_name='busroute',
            name='toBase',
            field=models.FileField(validators=[backend.validators.validate_file_extension], upload_to='routes', help_text='Parada Uees-Base de ruta en formato "json".', blank=True),
        ),
        migrations.AddField(
            model_name='busroute',
            name='toUees',
            field=models.FileField(validators=[backend.validators.validate_file_extension], upload_to='routes', help_text='Parada Base-Uees de ruta en formato "json".', blank=True),
        ),
    ]


import math
import pandas_datareader as web
import colorama # pip install colorama

def progress_bar(progress, total, color=colorama.Fore.YELLOW):
    percent = 100 * (progress / float(total))
    bar = '█' * int(percent) + '-' * (100 - int(percent))
    print(color + f"\r|{bar}| {percent:.2f}%", end ="\r")
    if progress == total:
        print(colorama.Fore.GREEN + f"\r|{bar}| {percent:.2f}%", end ="\r")

tickers = ["APPL", "FB", "NVDA", "WFC"]
clossing_prices = []

progress_bar(0,len(tickers))
for index, ticker in enumerate(tickers):
    last_price = web.DataReader(ticker, "yahoo").iloc[-1]['Close']
    clossing_prices.append(last_price)
    progress_bar(index + 1,len(tickers))

 # only for testing
numbers =[x * 5 for x in range(2000, 3000)]
result = []

for i, x in enumerate(numbers):
    result.append(math.factorial(x))
    progress_bar(i + 1, len(numbers))

print(colorama.Fore.RESET)


import math
import paddle
from paddle import nn
import paddle.nn.functional as F

def myphi(x,m):
    x = x * m
    return 1-x**2/math.factorial(2)+x**4/math.factorial(4)-x**6/math.factorial(6) + \
            x**8/math.factorial(8) - x**9/math.factorial(9)

class AngleLinear(nn.Layer):
    def __init__(self, in_features, out_features, m = 4, phiflag=True):
        super(AngleLinear, self).__init__()
        self.in_features = in_features
        self.out_features = out_features
        # self.weight = paddle.zeros(shape=)
        data_pd = paddle.nn.functional.normalize(paddle.uniform(shape=[in_features, out_features], min=-1, max=1), p=2, axis=1, epsilon=1e-5)
        data_pd_mul = paddle.multiply(data_pd, paddle.to_tensor([1e5]))
        self.weight = paddle.create_parameter(shape=[in_features, out_features], dtype="float16",
                                              default_initializer=paddle.nn.initializer.Assign(value=data_pd_mul))
        self.phiflag = phiflag
        self.m = m
        self.mlambda = [
            lambda x: x**0,
            lambda x: x**1,
            lambda x: 2*x**2-1,
            lambda x: 4*x**3-3*x,
            lambda x: 8*x**4-8*x**2+1,
            lambda x: 16*x**5-20*x**3+5*x
        ]

    def forward(self, input):
        x = input   # size=(B,F)    F is feature len
        w = self.weight # size=(F,Classnum) F=in_features Classnum=out_features
        w = F.normalize(w, p=2, axis=1, epsilon=1e-5)
        ww = paddle.multiply(w, paddle.to_tensor([1e5]))
        xlen = x.pow(2).sum(1).pow(0.5)  # size=B
        wlen = ww.pow(2).sum(0).pow(0.5)  # size=Classnum
        cos_theta = x.mm(ww)  # size=(B,Classnum)
        cos_theta = cos_theta / paddle.reshape(xlen, shape=[-1, 1]) / paddle.reshape(wlen, shape=[1, -1])
        cos_theta = cos_theta.clip(-1, 1)

        if self.phiflag:
            cos_m_theta = self.mlambda[self.m](cos_theta)
            theta = paddle.acos(cos_theta)
            # theta = Variable(cos_theta.data.acos())
            k = (self.m*theta/3.14159265).floor()
            n_one = k*0.0 - 1
            phi_theta = (n_one**k) * cos_m_theta - 2*k
        else:
            theta = cos_theta.acos()
            phi_theta = myphi(theta,self.m)
            phi_theta = phi_theta.clip(-1*self.m, 1)

        cos_theta = cos_theta * paddle.reshape(xlen, shape=(-1,1))
        phi_theta = phi_theta * paddle.reshape(xlen, shape=(-1,1))
        output = (cos_theta,phi_theta)
        return output # size=(B,Classnum,2)


import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

NUM_TRIALS = 2000
BANDIT_MEANS = [1, 2, 3]

class Bandit():
    def __init__(self, true_mean):
        self.true_mean = true_mean
        self.tau = 1
        self.N = 0
        self.sum_x = 0
        self.m = 0
        self.lbda = 1

    def pull(self):
        return np.random.normal(loc=self.true_mean, scale=(1/self.tau)**0.5)

    def update(self, x):
        self.N += 1.0
        self.sum_x += x
        self.lbda += self.tau
        self.m = self.tau*self.sum_x/self.lbda

    def sample(self):
        return np.random.normal(loc=self.m, scale=(1/self.lbda)**0.5)

def experiment():
    bandits = [Bandit(p) for p in BANDIT_MEANS]
    rewards = np.zeros(NUM_TRIALS)

    for i in range(NUM_TRIALS):
        index = np.argmax([b.sample() for b in bandits])
        bandit = bandits[index]
        r = bandit.pull()
        bandit.update(r)
        rewards[i] = r

    print("--------- RESULTS e-GREEDY ---------")
    for i, b in enumerate(bandits):
        dist = np.random.normal(loc=b.m, scale=(1/b.lbda)**0.5, size=1000)
        print(f"Mean estimate for bandit {i+1}: {np.median(dist):.3f}")

    print(f"\nTotal reward: {rewards.sum():.2f}")
    print(f"Overall win rate: {rewards.sum()/NUM_TRIALS:.2f}")

    cumulative_rewards = rewards.cumsum()
    win_rates = cumulative_rewards/(np.arange(NUM_TRIALS)+1)
    _, (ax1, ax2) = plt.subplots(1,2,figsize=(10,5))
    ax1.set_title("Mean Reward")
    ax1.plot(win_rates, label="Mean Reward")
    ax1.plot(np.ones(NUM_TRIALS)*np.max(BANDIT_MEANS), color="red", label="Known Mean Reward")
    ax2.set_title("Bandit Choice")
    ax2.bar(["Bandit "+str(i+1) for i in range(len(bandits))], [b.N/NUM_TRIALS for b in bandits])
    ax1.legend()
    plt.show()

    _, ax = plt.subplots(1,1,figsize=(10,5))
    ax.set_title("Posterior Distributions")
    df_bandits = pd.DataFrame({"Bandit "+str(i+1):np.random.normal(loc=b.m, scale=(1/b.lbda)**0.5, size=1000) for i, b in enumerate(bandits)})
    for col in df_bandits.columns:
        sns.distplot(df_bandits[col], hist=False, label=col, ax=ax)
    ax.set_xlabel("Mean Reward")
    ax.legend()
    plt.show()

if __name__ == "__main__":
   experiment()


from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from products.models import DLC
from decimal import Decimal
from cart.utils import get_cart_items

@login_required(login_url='/accounts/login')
def view_cart(request):
    cart = request.session.get('cart', {})
    context = get_cart_items(cart)
    return render(request, "cart/view_cart.html", context)

def add_to_cart(request):
    id = request.POST['id']
    quantity = int(request.POST['quantity'])

    cart = request.session.get('cart', {})
    cart[id] = cart.get(id, 0) + quantity

    request.session['cart'] = cart

    return redirect('get_dlc')

def delete_product(request, id):
    cart = request.session.get('cart', {})
    del cart[id]
    request.session['cart'] = cart
    return redirect('view_cart')


import os
import json
import yaml
import umap
import numpy as np

# Path to the directory containing the JSON files
dir_path = 'scenarios_embeddings/paraphrase-MiniLM-L6-v2'
output_filename = 'scenarios_embeddings/paraphrase-MiniLM-L6-v2.correlation-projection.json'
meta_dir_path = 'scenarios_metadata'

# List all the JSON files in the directory
file_list = os.listdir(dir_path)

# Initialize an empty array to store the embeddings
data = np.empty((len(file_list),384))
scenarios = []

# Loop through each file
for i, filename in enumerate(file_list):
    file_path = os.path.join(dir_path, filename)

    # Load the JSON file and extract the embedding array
    with open(file_path, 'r') as f:
        embedding = np.array(json.load(f), dtype=float)
        data[i] = embedding
        scenarios.append(filename.replace('scenario_', '').replace('.json', ''))

umap_embeddings = umap.UMAP(n_neighbors=20,
                            n_components=2,
                            min_dist=0.1,
                            metric='correlation').fit_transform(data)

embeddings = umap_embeddings.tolist()
projection = {scenarios[i]: embeddings[i] for i in range(len(scenarios))}

with open(output_filename, 'w') as f:
    json.dump(projection, f)


from flask import Flask, request, jsonify, render_template
import os
import dialogflow
import requests
import json
import time
#import pusher
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)

# initialize Pusher

@app.route('/')
def index():
    return render_template('index.html')

@app.route("/receive_message", methods=['GET', 'POST'])
def message_reply():
    print (request.values)
    body = request.values.get('Body', None) #https://www.twilio.com/docs/sms/tutorials/how-to-receive-and-reply-python
    project_id = os.getenv('DIALOGFLOW_PROJECT_ID')
    session_id = request.values.get('From', None)
    fulfillment_text = detect_intent_texts(project_id, session_id, body, 'en')

    resp = MessagingResponse()

    resp.message(fulfillment_text)
    time.sleep(0.5)
    return str(resp)

@app.route('/get_movie_detail', methods=['POST'])
def get_movie_detail():
    data = request.get_json(silent=True)

    try:
        movie = data['queryResult']['parameters']['movie']
        api_key = os.getenv('OMDB_API_KEY')

        movie_detail = requests.get('http://www.omdbapi.com/?t={0}&apikey={1}'.format(movie, api_key)).content
        movie_detail = json.loads(movie_detail)

        response =  """
            Title : {0}
            Released: {1}
            Actors: {2}
            Plot: {3}
        """.format(movie_detail['Title'], movie_detail['Released'], movie_detail['Actors'], movie_detail['Plot'])
    except:
        response = "Could not get movie detail at the moment, please try again"

    reply = { "fulfillmentText": response }

    return jsonify(reply)

def detect_intent_texts(project_id, session_id, text, language_code):
    session_client = dialogflow.SessionsClient()
    session = session_client.session_path(project_id, session_id)

    if text:
        text_input = dialogflow.types.TextInput(
            text=text, language_code=language_code)
        query_input = dialogflow.types.QueryInput(text=text_input)
        response = session_client.detect_intent(
            session=session, query_input=query_input)

        return response.query_result.fulfillment_text

@app.route('/send_message', methods=['POST'])
def send_message():
    try:
        socketId = request.form['socketId']
    except KeyError:
        socketId = ''

    message = request.form['message']
    project_id = os.getenv('DIALOGFLOW_PROJECT_ID')
    fulfillment_text = detect_intent_texts(project_id, "unique", message, 'en')
    response_text = { "message":  fulfillment_text }

    return jsonify(response_text)

# run Flask app
if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8000, debug=True, threaded=True)


# nnmware(c)2012-2020

from __future__ import unicode_literals

from django.contrib import admin
from django.utils.translation import gettext as _

from nnmware.apps.address.models import City, Region, Country, TourismCategory, Tourism, StationMetro, Institution
from nnmware.core.admin import TypeBaseAdmin

@admin.register(City)
class CityAdmin(admin.ModelAdmin):
    list_display = ('name', 'region', 'country', 'slug', 'longitude', 'latitude')
    search_fields = ('name',)
    fieldsets = (
        (_("City"), {"fields": [("name", "slug"), ('description',), ('country', 'region', 'time_offset'),
                                ('longitude', 'latitude'), ('name_add', 'position', 'enabled')]}),
        (_("English"), {"classes": ("collapse",), "fields": [("name_en", "name_add_en"), ("description_en",)]})
    )

@admin.register(Region)
class RegionAdmin(admin.ModelAdmin):
    list_display = ('__str__',)
    search_fields = ('name',)
    fieldsets = (
        (_("Region"), {"fields": [("name", "slug", 'country'), ('description',), ('name_add', 'position', 'enabled')]}),
        (_("English"), {"classes": ("collapse",), "fields": [("name_en", "name_add_en"), ("description_en",)]})
    )

@admin.register(Country)
class CountryAdmin(admin.ModelAdmin):
    list_display = ('__str__', 'slug')
    search_fields = ('name',)
    fieldsets = (
        (_("Country"), {"fields": [("name", "slug"), ('description',), ('name_add', 'position', 'enabled')]}),
        (_("English"), {"classes": ("collapse",), "fields": [("name_en", "name_add_en"), ("description_en",)]})
    )

@admin.register(TourismCategory)
class TourismCategoryAdmin(admin.ModelAdmin):
    list_display = ('name', 'name_en')
    search_fields = ('name',)
    fieldsets = (
        (_("Tourism place category"), {"fields": [("name",), ('description',)]}),
        (_("Addons"), {"fields": [('enabled', ), ('icon',)]}),
        (_("English"), {"classes": ("collapse",), "fields": [("name_en",), ("description_en",)]})
    )

@admin.register(Tourism)
class TourismAdmin(admin.ModelAdmin):
    list_display = ('name', 'category', 'country', 'city', 'address')
    search_fields = ('name',)
    fieldsets = (
        (_("Tourism place category"), {"fields": [("name", 'address'), ('category',), ('description',)]}),
        (_("Addons"), {"fields": [('enabled', 'country', 'city')]}),
        (_("English"), {"classes": ("collapse",), "fields": [("name_en", ), ("description_en", )]})
    )

@admin.register(StationMetro)
class StationMetroAdmin(admin.ModelAdmin):
    list_display = ('name',)
    search_fields = ('name',)
    fieldsets = (
        (_("Station of metro"), {"fields": [("name", 'address'), ('description',)]}),
        (_("Addons"), {"fields": [('enabled', 'country', 'city')]}),
        (_("English"), {"classes": ("collapse",), "fields": [("name_en",), ("description_en",)]})
    )

@admin.register(Institution)
class InstitutionAdmin(TypeBaseAdmin):
    fieldsets = (
        (_("Institution"), {"fields": [('name', 'position'), ('city', 'country')]}),
    )