from networks.deep_ensemble_NN_model import GaussianMixtureMLP
from networks.MLP import MLP
from matplotlib import pyplot as plt
import numpy as np
import torch
from tqdm import tqdm
from torch import nn
from torch.nn import functional as F
class BSDP(torch.nn.Module):
    def __init__(self):
        super(BSDP, self).__init__()
        # initalize 5 models
        self.model0 = MLP(1,2,0)
        self.model1 = MLP(1,2,0)
        self.model2 = MLP(1,2,0)
        self.model3 = MLP(1,2,0)
        self.model4 = MLP(1,2,0)
        self.model5 = MLP(1,2,0)
        self.model6 = MLP(1,2,0)
        self.model7 = MLP(1,2,0)
        self.model8 = MLP(1,2,0)
        self.model9 = MLP(1,2,0)
        # initialize 5 prior models
        self.prior0 = MLP(1,2,0)
        self.prior1 = MLP(1,2,0)
        self.prior2 = MLP(1,2,0)
        self.prior3 = MLP(1,2,0)
        self.prior4 = MLP(1,2,0)
        self.prior5 = MLP(1,2,0)
        self.prior6 = MLP(1,2,0)
        self.prior7 = MLP(1,2,0)
        self.prior8 = MLP(1,2,0)
        self.prior9 = MLP(1,2,0)

    def forward(self, x):
        # forward pass
        out0 = self.model0(x)
        out1 = self.model1(x)
        out2 = self.model2(x)
        out3 = self.model3(x)
        out4 = self.model4(x)
        out5 = self.model5(x)
        out6 = self.model6(x)
        out7 = self.model7(x)
        out8 = self.model8(x)
        out9 = self.model9(x)
        # prior pass
        prior0 = self.prior0(x)
        prior1 = self.prior1(x)
        prior2 = self.prior2(x)
        prior3 = self.prior3(x)
        prior4 = self.prior4(x)
        prior5 = self.prior5(x)
        prior6 = self.prior6(x)
        prior7 = self.prior7(x)
        prior8 = self.prior8(x)
        prior9 = self.prior9(x)

        # return
        return out0+prior0,out1+prior1, out2+prior2, out3+prior3, out4+prior4, out5+prior5, out6+prior6, out7+prior7, out8+prior8, out9+prior9

    def diversity_init(self):
        """initalzie the networks with diversity to make the softmax output different in each member"""

        for i in tqdm(range (500)):
            s=[]
            s.append(torch.FloatTensor(128,1).uniform_(-5,5))
            data=torch.cat(s,1)

            model_index=torch.randint(0,10,(1,))
            model_p = getattr(self, 'prior' + str(model_index.item()))
            model = getattr(self, 'model' + str(model_index.item()))

            optim=torch.optim.AdamW(model_p.parameters(),lr=0.005)
            # forward
            mean = model(data)+model_p(data)
            mean_plus=model(data+0.05)+model_p(data+0.05)
            mean_minus=model(data-0.05)+model_p(data-0.05)
            # compute the second derivate
            second_derivate=(mean_plus+mean_minus-2*mean)/0.05**2

            mean = torch.softmax(mean,-1)+1e-6
            means=self(data)
            # compute the predcitions of ensemble
            means=torch.stack(means)

            with torch.no_grad():
                target=means.detach()
                model_index=torch.randint(0,10,(1,))
                target=torch.softmax(target.median(0)[0],-1)+1e-6
                # target=target-target.mean(-1).unsqueeze(-1).repeat(1,1,2)
                # target[model_index]*=100000

            # compute the loss
            optim.zero_grad()
            # loss=-F.mse_loss(mean,target)*100-means.var(0).mean()*100
            # min_distance=torch.abs(target-mean).min(0)[0]
            # loss=(torch.clamp(min_distance,0,0.5)**2).mean()*10000+(means**2).mean()
            # loss=F.mse_loss(means.var(0),target)+(means**2).mean()
            # loss=-F.mse_loss(mean,target)
            # loss=-torch.clamp((mean-target)**2,0,0.1).mean()+means.mean()**2+(torch.abs(means)**2).mean()
            kl_loss=self.KL(mean,target)
            nonlinearity_loss=-(second_derivate.abs()).mean()
            a,b,c=0.1,0,0.1
            loss=-torch.clamp(kl_loss,0,a).mean()+b*nonlinearity_loss+(means**2).mean()*c
            # loss=-torch.clamp(kl_loss,0,0.1).mean()+nonlinearity_loss
            # loss=nonlinearity_loss*10
            # optimize
            loss.backward()
            optim.step()
    def KL(self,a,b):
        return (a*torch.log(a/b)).sum(-1)
    def second_derivate(self,a):
        return torch.autograd.grad(a.sum(),a,retain_graph=True)[0]

x=torch.arange(-5,5,0.01).reshape(-1,1)

BSDP_model = BSDP()
y1=BSDP_model(x)

# plot the BSP cruve
for i in range(len(y1)):
    plt.plot(x,y1[i][:,0].detach(),label='model'+str(i+1))
    plt.ylim(-20,20)
# plt.legend(loc=2)
plt.xlabel("state")
plt.ylabel("Q(s,a=0)")
plt.savefig("imgs/BSDP/BSP_0.png",dpi=500)
plt.close()

# plot the BSP cruve
for i in range(len(y1)):
    plt.plot(x,y1[i][:,1].detach(),label='model'+str(i+1))
    plt.ylim(-20,20)
# plt.legend(loc=2)
plt.xlabel("state")
plt.ylabel("Q(s,a=1)")
plt.savefig("imgs/BSDP/BSP_1.png",dpi=500)
plt.close()

# plot the BSDP cruve
BSDP_model.diversity_init()

y1=BSDP_model(x)

# plot the BSP cruve
for i in range(len(y1)):
    plt.plot(x,y1[i][:,0].detach(),label='model'+str(i+1))
    plt.ylim(-20,20)
# plt.legend(loc=2)
plt.xlabel("state")
plt.ylabel("Q(s,a=0)")
plt.savefig("imgs/BSDP/BSDP_0_kl_bound.png",dpi=500)
plt.close()

# plot the BSP cruve
for i in range(len(y1)):
    plt.plot(x,y1[i][:,1].detach(),label='model'+str(i+1))
    plt.ylim(-20,20)
# plt.legend(loc=2)
plt.xlabel("state")
plt.ylabel("Q(s,a=1)")
plt.savefig("imgs/BSDP/BSDP_0_kl_bound.png",dpi=500)
plt.close()


__version_info__ = (0, 1, 0)
__version__ = ".".join(map(str, __version_info__))

# Documentation strings format
__docformat__ = "restructuredtext en"

# ------------------------------------------------------------------------------

# Local package
import core

# iPOPO
from pelix.ipopo.decorators import ComponentFactory, Requires, \
    Invalidate, Instantiate, Provides, Property, BindField, UnbindField
import pelix.ipopo.constants as constants
import pelix.remote

# PyQt5
import PyQt5.QtWidgets as QtWidgets

# Standard library
import logging

# ------------------------------------------------------------------------------

FRAMEWORK_INFO_FACTORY = "framework-instance-info-factory"

_logger = logging.getLogger(__name__)

# ------------------------------------------------------------------------------

@ComponentFactory("framework-instance-info-creator-factory")
@Requires('_ipopo', constants.IPOPO_SERVICE_SPECIFICATION)
@Provides(core.SVC_FRAMEWORK_INSTANCE_INFO_FACTORY)
@Instantiate("framework-instance-info-creator")
class FrameworkInstanceInfoCreator(object):
    """
    Service that instantiates FrameworkInstanceInfo components
    """
    def __init__(self):
        """
        Sets up the component
        """
        # Bundle context
        self._context = None

        # iPOPO
        self._ipopo = None

        # Instances
        self._instances = {}

    def __make_name(self, dispatcher_id):
        """
        Generates the component name, based on the dispatcher ID

        :param dispatcher_id: The ID of the dispatcher exporting the Probe
                              service
        :return: The component name
        """
        return "framework-instance-info-{0}".format(dispatcher_id or "local")

    def make(self, framework_uid):
        """
        Makes a FrameworkInstanceInfo component, using the probe service
        matching the given framework UID

        :param framework_uid: The UID of the framework exporting the Probe
                              service
        :return: The instantiated component
        :raise Exception: Something went wrong during the instantiation
        """
        if not framework_uid:
            framework_uid = None

        try:
            # Already created component
            return self._instances[framework_uid]

        except KeyError:
            # Generate a name
            name = self.__make_name(framework_uid)

            # Prepare the @Requires filter override
            properties = {}
            properties[core.PROP_PROBE_UID] = framework_uid
            if framework_uid:
                probe_filter = "({0}={1})" \
                               .format(pelix.remote.PROP_ENDPOINT_FRAMEWORK_UUID,
                                       framework_uid)
                details_filter = "({0}={1})".format(core.PROP_PROBE_UID,
                                                    framework_uid)
            else:
                probe_filter = "(!({0}=*))" \
                               .format(pelix.remote.PROP_ENDPOINT_FRAMEWORK_UUID)
                details_filter = "(!({0}=*))".format(core.PROP_PROBE_UID)

            properties[constants.IPOPO_REQUIRES_FILTERS] = {
                '_probe': probe_filter,
                '_details': details_filter,
                }

            # Instantiate the component
            component = self._ipopo.instantiate(FRAMEWORK_INFO_FACTORY,
                                                name, properties)

            self._instances[framework_uid] = component
            return component

    def delete(self, dispatcher_id):
        """
        Deletes the component associated to the given dispatcher

        :param dispatcher_id: The ID of the dispatcher exporting the Probe
                              service
        """
        if not dispatcher_id:
            dispatcher_id = None

        if dispatcher_id in self._instances:
            # Delete it
            del self._instances[dispatcher_id]
            self._ipopo.kill(self.__make_name(dispatcher_id))

    @Invalidate
    def invalidate(self, context):
        """
        Component invalidated

        :param context: Bundle context
        """
        # Clear all known instances
        for dispatcher_id in self._instances.keys():
            self.delete(dispatcher_id)

        self._instances.clear()

# ------------------------------------------------------------------------------

@ComponentFactory(FRAMEWORK_INFO_FACTORY)
@Requires('_details', core.SVC_DETAILS, aggregate=True, optional=True)
@Requires('_qt_loader', core.SVC_QT_LOADER)
@Provides(core.SVC_FRAMEWORK_INSTANCE_INFO)
@Property('_dispatcher_id', core.PROP_PROBE_UID)
class FrameworkInstanceInfo(object):
    """
    The framework instance info widget
    """
    def __init__(self):
        """
        Sets up the component
        """
        # The Qt service
        self._qt_loader = None

        # The details services
        self._details = None

        # Details service -> reference
        self._details_refs = {}

        # The remote service dispatcher ID
        self._dispatcher_id = None

        # Qt Tab widget
        self._widget = None

        # Details widgets
        self._details_widgets = {}

    def get_name(self):
        """
        Returns the dispatcher ID, or "Local"
        """
        return "{0}".format(self._dispatcher_id or "Local")

    def get_uid(self):
        """
        Returns the raw dispatcher ID
        """
        return self._dispatcher_id

    def get_widget(self, parent):
        """
        Makes the Qt widget that will show the framework instance information.

        This method must/will be be called from the UI thread.

        :return: A QWidget object
        """
        if self._widget:
            return self._widget

        # Make the tab bar
        self._widget = QtWidgets.QTabWidget(parent)

        # Add all known details
        for service, reference in self._details_refs.items():
            self.__add_tab(service, reference)

        return self._widget

    def clean(self, parent):
        """
        Cleans the UI elements.

        This method must/will be be called from the UI thread.
        """
        for detail_widget in self._details_widgets:
            try:
                detail_widget.clean()
            except:
                # Ignore errors
                pass

        # Clear references
        self._widget = None

    def __add_tab(self, service, reference):
        """
        Adds a tab to the UI

        This method must be be called from the UI thread.

        :param service: A details service
        :param reference: The service reference
        """
        # Prepare the widget
        widget = service.get_widget(self._widget)

        # Store it in cache
        self._details_widgets[reference] = widget

        # Add it to the UI
        self._widget.addTab(widget, service.get_name())

    def __remove_tab(self, service, reference):
        """
        Removes a tab from the UI.

        This method must be be called from the UI thread.

        :param service: A details service
        :param reference: The service reference
        """
        # Pop the widget from cache
        widget = self._details_widgets.pop(reference)

        # Look for it in the tab widget
        index = self._widget.indexOf(widget)

        if index > -1:
            # Found it
            self._widget.removeTab(index)

    @BindField('_details')
    def _bind_details(self, field, service, reference):
        """
        A details component has been bound
        """
        # Store the service reference
        self._details_refs[service] = reference

        # Use "is not None", Qt Widgets seem to be False
        if self._widget is not None:
            self._qt_loader.run_on_ui(self.__add_tab, service, reference)

    @UnbindField('_details')
    def _unbind_details(self, field, service, reference):
        """
        A details component has been unbound
        """
        try:
            if self._widget is not None:
                self._qt_loader.run_on_ui(self.__remove_tab, service,
                                          reference)
        finally:
            # Clear the service reference
            del self._details_refs[service]


from __future__ import absolute_import, division, print_function
from future import standard_library
from future.utils import integer_types, string_types

from warnings import warn

from pennsieve import log
from pennsieve.models import get_package_class

# urllib compatibility
standard_library.install_aliases()
import urllib.parse  # isort:skip

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Base class
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class APIBase(object):
    host = None
    base_uri = ""
    name = ""

    def __init__(self, session):
        """
        Base class to be used by all API components.
        """
        # api session
        self.session = session
        self._logger = log.get_logger("pennsieve.api")
        warn(
            f"Pennsieve is transitioning to the new agent. This class '{self.__class__.__name__}' will be deprecated; version=7.0.0; date=2022-11-01.",
            DeprecationWarning,
            stacklevel=2,
        )

    def _get_id(self, thing):
        """
        Get ID for object. Assumes string is already ID.
        """
        if isinstance(thing, (string_types, integer_types)):
            return thing
        elif thing is None:
            return None
        else:
            return thing.id

    def _get_int_id(self, thing):
        """
        Get internal ID for object.
        """
        if isinstance(thing, (string_types, integer_types)):
            return thing
        elif thing is None:
            return None
        else:
            return thing.int_id

    def _get_package_from_data(self, data):
        # parse json
        cls = get_package_class(data)
        pkg = cls.from_dict(data, api=self.session)

        return pkg

    def _uri(self, url_str, **kwvars):
        vals = {k: urllib.parse.quote(str(var)) for k, var in kwvars.items()}
        return url_str.format(**vals)

    def _get(self, endpoint, base=None, host=None, *args, **kwargs):
        base = self.base_uri if base is None else base
        host = self.host if host is None else host
        return self.session._call(
            "get", endpoint, host=host, base=base, *args, **kwargs
        )

    def _post(self, endpoint, base=None, host=None, *args, **kwargs):
        base = self.base_uri if base is None else base
        host = self.host if host is None else host
        return self.session._call(
            "post", endpoint, host=host, base=base, *args, **kwargs
        )

    def _put(self, endpoint, base=None, host=None, *args, **kwargs):
        base = self.base_uri if base is None else base
        host = self.host if host is None else host
        return self.session._call(
            "put", endpoint, host=host, base=base, *args, **kwargs
        )

    def _del(self, endpoint, base=None, host=None, *args, **kwargs):
        base = self.base_uri if base is None else base
        host = self.host if host is None else host
        return self.session._call(
            "delete", endpoint, host=host, base=base, *args, **kwargs
        )


from spt3g import core

import rogue
import pyrogue.gui
import argparse
import sosmurf
import sys
import yaml
import os

import pysmurf.core.devices
import pysmurf.core.server_scripts.Common as pysmurf_common
import shlex

def main():
    with open(os.path.expandvars('$OCS_CONFIG_DIR/sys_config.yml')) as f:
        cfg = yaml.safe_load(f)

    slot = int(os.environ['SLOT'])
    crate_id = cfg['crate_id']
    comm_type = cfg['comm_type']
    shelf_manager = cfg['shelf_manager']
    slot_cfg = cfg['slots'][f'SLOT[{slot}]']
    g3_dir = cfg['g3_dir']

    parser = pysmurf_common.make_parser()
    parser.add_argument(
        '--stream-port', type=int,
        default=slot_cfg.get('stream_port', 4530 + slot))
    parser.add_argument(
        '--stream-id', type=str,
        default=slot_cfg.get('stream_id', f'crate{crate_id}slot{slot}'))
    parser.add_argument(
        '--emulate', action='store_true',
        help='Run server in emulation mode'
    )

    modified_args = sosmurf.util.setup_server(cfg, slot)
    args = parser.parse_args(shlex.split(modified_args))
    pysmurf_common.process_args(args)

    print(f"Stream id: {args.stream_id}")
    os.environ['SMURFPUB_ID'] = f"STREAMER:{args.stream_id}"

    # Sets some reasonable defaults
    if not args.epics_prefix:
        if args.emulate:
            args.epics_prefix = f"smurf_emulator_s{slot}"
            args.server_port = 9000 + 2*slot
        else:
            args.epics_prefix = f"smurf_server_s{slot}"
        print(f"Using epics root {args.epics_prefix}")

    if args.config_file is None:
        args.config_file = slot_cfg.get('rogue_defaults')
        print(f"Using config_file {args.config_file}")

    if args.pcie_rssi_lane is None:
        args.pcie_rssi_lane = slot - 2
        print(f"Using pcie lane {args.pcie_rssi_lane}")

    stream_root = sosmurf.StreamBase(
        "SOStream", debug_meta=False, debug_data=False, agg_time=2.0
    )
    file_writer = sosmurf.SOFileWriter("SOFileWriter", g3_dir, file_dur=10*60)
    stream_root.add(file_writer)

    pipe = core.G3Pipeline()
    pipe.Add(stream_root.builder)
    pipe.Add(sosmurf.SessionManager.SessionManager, stream_id=args.stream_id)
    # pipe.Add(sosmurf.util.stream_dumper)
    pipe.Add(core.G3NetworkSender, hostname='*',
             port=args.stream_port, max_queue_size=1000)
    pipe.Add(file_writer.rotator)

    vgs = None
    default_meta_file = '/usr/local/src/smurf-streamer/meta_registers.yaml'
    meta_file = cfg.get('meta_register_file')
    if os.path.exists(default_meta_file):
        vgs = sosmurf.util.VariableGroups.from_file(default_meta_file)
    if meta_file is not None and vgs is not None:
        vgs.update(sosmurf.util.VariableGroups.from_file(
            os.path.expandvars(meta_file)
        ))

    pcie_kwargs = {
        'lane': args.pcie_rssi_lane, 'ip_addr': args.ip_addr,
        'dev_rssi': args.pcie_dev_rssi, 'dev_data': args.pcie_dev_data,
        'comm_type': f'{comm_type}-rssi-interleaved'
    }
    root_kwargs = {
        'config_file': args.config_file, 'server_port': args.server_port,
        'epics_prefix': args.epics_prefix, 'polling_en': args.polling_en,
        'pv_dump_file': args.pv_dump_file, 'disable_bay0': args.disable_bay0,
        'disable_bay1': args.disable_bay1, 'configure': args.configure,
        'txDevice': stream_root, 'enable_pwri2c': args.enable_em22xx,
    }
    if vgs is not None:
        root_kwargs['VariableGroups'] = vgs.data

    if comm_type == 'eth' and not args.emulate:
        root_kwargs['ip_addr'] = args.ip_addr

    if args.emulate:
        from pysmurf.core.roots.EmulationRoot import EmulationRoot
        CmbRoot = EmulationRoot
    elif comm_type == 'eth':
        from pysmurf.core.roots.CmbEth import CmbEth
        CmbRoot = CmbEth
    elif comm_type == 'pcie':
        from pysmurf.core.roots.CmbPcie import CmbPcie
        CmbRoot = CmbPcie
    else:
        raise ValueError(
            f"comm_type is {comm_type}. Must be either 'eth'' or 'pcie'.")

    if comm_type == 'pcie':
        root_kwargs.update({
            'pcie_rssi_lane': args.pcie_rssi_lane,
            'pcie_dev_rssi': args.pcie_dev_rssi,
            'pcie_dev_data': args.pcie_dev_data,
        })

    if args.emulate:
        print("Starting Emulation root")
        with EmulationRoot(**root_kwargs):
            print("got pysmurf root. Starting G3 Pipeline...", flush=True)
            pipe.Run(profile=True)
            print("Closed G3 pipeline")
    else:
        with pysmurf.core.devices.PcieCard(**pcie_kwargs):
            with CmbRoot(**root_kwargs):
                print("got pysmurf root. Starting G3 Pipeline...", flush=True)
                pipe.Run(profile=True)
                print("Closed G3 pipeline")

if __name__ == '__main__':
    main()


def get_summ(one, two, delimiter="&"):
    concatenated = f"{one}{delimiter}{two}"
    return concatenated

my_string = get_summ("Learn", "python")
print(my_string.upper())

print('-'*50)
def hello(*args, **kwargs):
    print(args)
    print(kwargs)

hello(17,18)
hello(1,2,55,66,cat='cat',dog='Russia')


"""Purpose built for Earthle. Converts a line-seperated list of comma-seperated coordinates into a JSON file.

Usage:
    coords-to-json.py -i <input_file>

Arguments:
    <input_file> (REQUIRED)  The input file to read from.

Options:
    -d <start_date> (OPTIONAL)  Start date for the coordinates in format YYYY-MM-DD. Defaults to current local date.

Output:
    A JSON file named with start and end dates of the coordinates.

Example:
    coords-to-json.py -i coords.txt -d 2022-10-05

    example output:

      {
        "date": "2022-10-05",
          "location": {
            "lat": -38.15221989407775,
            "lng": 144.37571532382444
          }
      },

"""

import argparse
import json
import re
import os
from datetime import datetime, timedelta

parser = argparse.ArgumentParser(description='Generate json object with date and coordinates for a given list of comma seperated coordinates')
parser.add_argument('input_file', type=str, help="File path to .txt file containing lines or comma seperated coords in format <lat, long>")

parser.add_argument('-d', '--date', type=str, help="Starting date as <YYYY-MM-DD>. If not provided appends previous date by 1 day", required=False)

args = parser.parse_args()

date = datetime.today().strftime('%Y-%m-%d')

if args.date:
  if not re.match(r'^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$', args.date):
    print('Invalid date format. Must be real date and must be in format YYYY-MM-DD')
    exit(1)
  else:
    date = args.date

print('Start date: ' + date)
last_date = date

try:
  infile = open(args.input_file, 'r')
  outfile = open('coords.json', 'w', encoding='utf-8')
except:
  print('Invalid file path')
  exit(1)
with infile:
  data = []
  lines = infile.readlines()
  next_date = date
  for line in lines:
    coords = line.split(',')
    if len(coords) != 2:
      print('Invalid coordinates: ' + line)
      exit(1)

    data.append({
      'date': next_date,
      'location': {
        'lat': float(coords[0].strip()),
        'lng': float(coords[1].strip())
      }
    })
    next_date = (datetime.strptime(next_date, '%Y-%m-%d') + timedelta(days=1)).strftime('%Y-%m-%d')
    last_date = next_date

  json.dump(data, outfile, ensure_ascii=False, indent=2)
  outfile.close()
  infile.close()
  last_date = (datetime.strptime(last_date, '%Y-%m-%d') - timedelta(days=1)).strftime('%Y-%m-%d')
  os.rename('coords.json', 'coords-' + date + '--' + last_date + '.json')


import os

import pickle
from math import ceil
from torch.utils.data import Dataset, DataLoader
import random
import numpy as np
from pandas import DataFrame
from pandas.io.parsers import read_csv
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
import logging
logging.basicConfig(level=logging.DEBUG)
# import tensorflow as tf
import matplotlib.pyplot as plt

def plot_sample_denormed(X, y, plot: bool=True) -> None:
    y = denormalize_pos(y)
    plot_sample(X, y, plot=plot)

def plot_sample(X, y, plot: bool=True):
    # logging.debug("labels looks like this {}".format(denormalize_pos(y)))
    n_item = len(y)
    xs: np.ndarray = y[0::2]
    ys: np.ndarray = y[1::2]
    if plot:
        img = X.reshape(96, 96)
        plt.imshow(img, cmap='gray')
        '''
            sort of scatter points
        '''
        plt.scatter(xs, ys, marker="x")

        '''
            showing picture
        '''
        plt.show()

def plot_testing_sample(X, plot: bool=True):
    # logging.debug("labels looks like this {}".format(denormalize_pos(y)))
    n_item = len(X)
    if plot:
        img = X.reshape(96, 96)
        plt.imshow(img, cmap='gray')
        '''
            showing picture
        '''
        plt.show()

def plot_sample(X, y, plot: bool=True):
    # logging.debug("labels looks like this {}".format(denormalize_pos(y)))
    n_item = len(y)
    xs: np.ndarray = y[0::2]
    ys: np.ndarray = y[1::2]
    if plot:
        img = X.reshape(96, 96)
        plt.imshow(img, cmap='gray')
        '''
            sort of scatter points
        '''
        plt.scatter(xs, ys, marker="x")

        '''
            showing picture
        '''
        plt.show()

def normalize_img(img_arr: np.ndarray) -> np.ndarray:
    X = img_arr / 255.  # scale pixel values to [0, 1]
    return X

def denormalize_img(img_arr: np.ndarray) -> np.ndarray:
    X = img_arr * 255.  # scale pixel values to [0, 255]
    return X

def normalize_pos(pos: np.ndarray) -> np.ndarray:
    X = (pos - 48) / 48
    return X

def denormalize_pos(pos: np.ndarray) -> np.ndarray:
    X = pos * 48 + 48
    return X

# class kaggle_face_dataset(Dataset):

class kaggle_face_dataset(Dataset):
    def __init__(self, data_dir: str, batch_size: int, cache: bool=True,
            cache_location: str="ds_cache", test=False):
        self.train_file = os.path.join(data_dir, 'training.csv')
        self.test_file = os.path.join(data_dir, 'test.csv')
        self.lookup_file = os.path.join(data_dir, 'IdLookupTable.csv')
        saved_file = os.path.join(cache_location, "ds_cache.pkl")
        saved_test_file = os.path.join(cache_location, "ds_test_cache.pkl")
        self.batch_size = batch_size

        if not test and cache and os.path.exists(saved_file):
            logging.debug("cached hit, reading from cache")
            with open(saved_file, 'rb') as f:
                self.X, self.y, self.X_ori, self.y_ori = pickle.load(f)
        elif test and cache and os.path.exists(saved_test_file):
            logging.debug("cached hit, reading from cache")
            with open(saved_test_file, 'rb') as f:
                self.X, self.y, self.X_ori, self.y_ori = pickle.load(f)
        else:
            self.X, self.y, self.X_ori, self.y_ori = self.load(test)

        self.n_samples = len(self.X)
        self.inds = [i for i in range(self.n_samples)]
        random.shuffle(self.inds)
        if not test and cache and not os.path.exists(saved_file):
            logging.debug("saving cache at location {}".format(saved_file))
            os.makedirs(cache_location, exist_ok=True)
            with open(saved_file, 'wb') as f:
                pickle.dump((self.X, self.y, self.X_ori, self.y_ori), f)
                logging.debug("ds saved to {}".format(saved_file))
        elif test and cache and not os.path.exists(saved_test_file):
            logging.debug("saving cache at location {}".format(saved_test_file))
            os.makedirs(cache_location, exist_ok=True)
            with open(saved_test_file, 'wb') as f:
                pickle.dump((self.X, self.y, self.X_ori, self.y_ori), f)

    def __len__(self):
        return ceil(self.n_samples/self.batch_size)

    def __get_item__(self, ind: int):
        return self.X[ind], self.y[ind]

    def __iter__(self):
        self.cur_ind = 0
        return self

    def __next__(self):
        if self.cur_ind > self.n_samples:
            return StopIteration
        to_ret_inds = self.inds[self.cur_ind: self.cur_ind+self.batch_size]
        self.cur_ind += self.batch_size

        # batch_size_ = min(self.n_samples,
        #         self.cur_ind+self.batch_size) - self.cur_ind
        reshaped_X = np.reshape(self.X[to_ret_inds],
                (-1, 1, 96, 96))
        return reshaped_X, self.y[to_ret_inds]

    def _ind_yielder(self):
        inds = [i for i in range(self.n_samples)]
        random.shuffle(inds)
        cur_ind = 0
        yield inds[cur_ind: cur_ind + self.batch_size]

    def load(self, test: bool=False, cols=None):
        fname = self.test_file if test else self.train_file
        df = read_csv(os.path.expanduser(fname))  # load pandas dataframe

        # The Image column has pixel values separated by space; convert
        # the values to numpy arrays:
        df['Image'] = df['Image'].apply(lambda im: np.fromstring(im, sep = ' '))

        if cols:  # get a subset of columns
            df = df[list(cols) + ['Image']]

        # logging.debug("num entries\n {}".format(df.count()))
        logging.debug("entry sample\n {}".format(df[:2]))
        df = df.dropna()

        X_ori = np.vstack(df['Image'].values)
        X = X_ori / 255.  # scale pixel values to [0, 1]
        X = X.astype(np.float32)

        if not test:  # only self.train_file has any target columns
            y_ori = df[df.columns[:-1]].values
            y = (y_ori - 48) / 48  # scale target coordinates to [-1, 1]
            X, y = shuffle(X, y, random_state=42)  # shuffle train data
            y = y.astype(np.float32)
        else:
            y = None
            y_ori = None

        return X, y, X_ori, y_ori


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
        len_node = 0
        cur = head
        while(cur):
            len_node+=1
            cur = cur.next
        len_cur = 0
        while(head):
            if len_cur == len_node//2:
                return head
            head = head.next
            len_cur +=1


"""
### Extract the footprints or centroids of rasters. ###
"""

# Standard library
import sys; sys.path.append("../../")
from typing import Union, Optional, List
import os

# External
from osgeo import gdal

# Internal
from buteo.raster import core_raster
from buteo.utils import (
    utils_base,
    utils_bbox,
    utils_path,
    utils_io,
    utils_projection,
)

def raster_get_footprints(
    raster: Union[str, gdal.Dataset, List[Union[str, gdal.Dataset]]],
    latlng: bool = True,
    out_path: Optional[str] = None,
    *,
    overwrite: bool = True,
    prefix: str = "",
    suffix: str = "",
    add_uuid: bool = False,
    add_timestamp: bool = False,
    out_format: str = "gpkg",
) -> Union[str, List[str], gdal.Dataset]:
    """
    Gets the footprints of a raster or a list of rasters.

    Parameters
    ----------
    raster : Union[str, List, gdal.Dataset]
        The raster(s) to be shifted.

    latlng : bool, optional
        If True, the footprints are returned in lat/lon coordinates. If False, the footprints are returned in projected coordinates., default: True

    out_path : Optional[str], optional
        The path to the output raster. If None, the raster is created in memory., default: None

    overwrite : bool, optional
        If True, the output raster will be overwritten if it already exists., default: True

    prefix : str, optional
        The prefix to be added to the output raster name., default: ""

    suffix : str, optional
        The suffix to be added to the output raster name., default: ""

    add_uuid : bool, optional
        If True, a unique identifier will be added to the output raster name., default: False

    add_timestamp : bool, optional
        If True, a timestamp will be added to the output raster name., default: False

    out_format : str, optional
        The output format of the raster. If None, the format is inferred from the output path., default: "gpkg"

    Returns
    -------
    Union[str, List[str]]
        The path(s) to the shifted raster(s).
    """
    utils_base._type_check(raster, [str, gdal.Dataset, [str, gdal.Dataset]], "raster")
    utils_base._type_check(latlng, [bool], "latlng")
    utils_base._type_check(out_path, [str, [str], None], "out_path")
    utils_base._type_check(overwrite, [bool], "overwrite")
    utils_base._type_check(prefix, [str], "prefix")
    utils_base._type_check(suffix, [str], "suffix")
    utils_base._type_check(add_uuid, [bool], "add_uuid")
    utils_base._type_check(add_timestamp, [bool], "add_timestamp")

    input_is_list = isinstance(raster, list)

    input_list = utils_io._get_input_paths(raster, "raster")
    output_list = utils_io._get_output_paths(
        input_list,
        out_path,
        overwrite=overwrite,
        prefix=prefix,
        suffix=suffix,
        add_uuid=add_uuid,
        add_timestamp=add_timestamp,
        change_ext=out_format,
    )

    utils_path._delete_if_required_list(output_list, overwrite)

    footprints = []
    for idx, in_raster in enumerate(input_list):
        metadata = core_raster._get_basic_metadata_raster(in_raster)
        name = os.path.splitext(os.path.basename(metadata["name"]))[0]

        # Projections
        projection_osr = metadata["projection_osr"]
        projection_latlng = utils_projection._get_default_projection_osr()

        # Bounding boxes
        bbox = metadata["bbox"]

        if latlng:
            footprint_geom = utils_bbox._get_bounds_from_bbox(
                bbox,
                projection_osr,
                wkt=False,
            )
            footprint = utils_bbox._get_vector_from_geom(
                footprint_geom,
                projection_osr=projection_latlng,
                out_path=output_list[idx],
                name=name,
            )
        else:
            footprint_geom = utils_bbox._get_geom_from_bbox(
                bbox,
            )
            footprint = utils_bbox._get_vector_from_geom(
                footprint_geom,
                projection_osr=projection_osr,
                out_path=output_list[idx],
                name=name,
            )

        footprints.append(footprint)

    if input_is_list:
        return footprints

    return footprints[0]


from sage.structure.unique_representation import UniqueRepresentation
from sage.categories.coxeter_groups import CoxeterGroups

from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract
from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic
from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic
from sage.graphs.graph import Graph
from sage.matrix.constructor import matrix
from sage.matrix.matrix_space import MatrixSpace
from sage.rings.all import ZZ
from sage.rings.infinity import infinity
from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField

class CoxeterMatrixGroup(FinitelyGeneratedMatrixGroup_generic, UniqueRepresentation):
    r"""
    A Coxeter group represented as a matrix group.

    Let `(W, S)` be a Coxeter system and we construct a vector space `V`
    over `\RR` with a basis of `\{ \alpha_s \}_{s \in S}` and inner product

    .. MATH::

        B(\alpha_s, \alpha_t) = -\cos\left( \frac{\pi}{m_{st}} \right)

    where we have `B(\alpha_s, \alpha_t) = -1` if `m_{st} = \infty`. Next we
    define a representation `\sigma_s : V \to V` by

    .. MATH::

        \sigma_s \lambda = \lambda - 2 B(\alpha_s, \lambda) \alpha_s.

    This representation is faithful so we can represent the Coxeter group `W`
    by the set of matrices `\sigma_s` acting on `V`.

    INPUT:

    - ``data`` -- a Coxeter matrix or graph or a Cartan type
    - ``base_ring`` -- (default: the universal cyclotomic field) the base
      ring which contains all values `\cos(\pi/m_{ij})` where `(m_{ij})_{ij}`
      is the Coxeter matrix
    - ``index_set`` -- (optional) an indexing set for the generators

    For more on creating Coxeter groups, see
    :meth:`~sage.combinat.root_system.coxeter_group.CoxeterGroup`.

    .. TODO::

        Currently the label `\infty` is implemented as `-1` in the Coxeter
        matrix.

    EXAMPLES:

    We can create Coxeter groups from Coxeter matrices::

        sage: W = CoxeterGroup([[1, 6, 3], [6, 1, 10], [3, 10, 1]])
        sage: W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [ 1  6  3]
        [ 6  1 10]
        [ 3 10  1]
        sage: W.gens()
        (
        [                 -1 -E(12)^7 + E(12)^11                   1]
        [                  0                   1                   0]
        [                  0                   0                   1],
        <BLANKLINE>
        [                  1                   0                   0]
        [-E(12)^7 + E(12)^11                  -1     E(20) - E(20)^9]
        [                  0                   0                   1],
        <BLANKLINE>
        [              1               0               0]
        [              0               1               0]
        [              1 E(20) - E(20)^9              -1]
        )
        sage: m = matrix([[1,3,3,3], [3,1,3,2], [3,3,1,2], [3,2,2,1]])
        sage: W = CoxeterGroup(m)
        sage: W.gens()
        (
        [-1  1  1  1]  [ 1  0  0  0]  [ 1  0  0  0]  [ 1  0  0  0]
        [ 0  1  0  0]  [ 1 -1  1  0]  [ 0  1  0  0]  [ 0  1  0  0]
        [ 0  0  1  0]  [ 0  0  1  0]  [ 1  1 -1  0]  [ 0  0  1  0]
        [ 0  0  0  1], [ 0  0  0  1], [ 0  0  0  1], [ 1  0  0 -1]
        )
        sage: a,b,c,d = W.gens()
        sage: (a*b*c)^3
        [ 5  1 -5  7]
        [ 5  0 -4  5]
        [ 4  1 -4  4]
        [ 0  0  0  1]
        sage: (a*b)^3
        [1 0 0 0]
        [0 1 0 0]
        [0 0 1 0]
        [0 0 0 1]
        sage: b*d == d*b
        True
        sage: a*c*a == c*a*c
        True

    We can create the matrix representation over different base rings and with
    different index sets. Note that the base ring must contain all
    `2*\cos(\pi/m_{ij})` where `(m_{ij})_{ij}` is the Coxeter matrix::

        sage: W = CoxeterGroup(m, base_ring=RR, index_set=['a','b','c','d'])
        sage: W.base_ring()
        Real Field with 53 bits of precision
        sage: W.index_set()
        ('a', 'b', 'c', 'd')

        sage: CoxeterGroup(m, base_ring=ZZ)
        Coxeter group over Integer Ring with Coxeter matrix:
        [1 3 3 3]
        [3 1 3 2]
        [3 3 1 2]
        [3 2 2 1]
        sage: CoxeterGroup([[1,4],[4,1]], base_ring=QQ)
        Traceback (most recent call last):
        ...
        TypeError: unable to convert sqrt(2) to a rational

    Using the well-known conversion between Coxeter matrices and Coxeter
    graphs, we can input a Coxeter graph. Following the standard convention,
    edges with no label (i.e. labelled by ``None``) are treated as 3::

        sage: G = Graph([(0,3,None), (1,3,15), (2,3,7), (0,1,3)])
        sage: W = CoxeterGroup(G); W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [ 1  3  2  3]
        [ 3  1  2 15]
        [ 2  2  1  7]
        [ 3 15  7  1]
        sage: G2 = W.coxeter_graph()
        sage: CoxeterGroup(G2) is W
        True

    Because there currently is no class for `\ZZ \cup \{ \infty \}`, labels
    of `\infty` are given by `-1` in the Coxeter matrix::

        sage: G = Graph([(0,1,None), (1,2,4), (0,2,oo)])
        sage: W = CoxeterGroup(G)
        sage: W.coxeter_matrix()
        [ 1  3 -1]
        [ 3  1  4]
        [-1  4  1]

    We can also create Coxeter groups from Cartan types using the
    ``implementation`` keyword::

        sage: W = CoxeterGroup(['D',5], implementation="reflection")
        sage: W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2 2 2]
        [3 1 3 2 2]
        [2 3 1 3 3]
        [2 2 3 1 2]
        [2 2 3 2 1]
        sage: W = CoxeterGroup(['H',3], implementation="reflection")
        sage: W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]
    """
    @staticmethod
    def __classcall_private__(cls, data, base_ring=None, index_set=None):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: W1 = CoxeterGroup(['A',2], implementation="reflection", base_ring=UniversalCyclotomicField())
            sage: W2 = CoxeterGroup([[1,3],[3,1]], index_set=(1,2))
            sage: W1 is W2
            True
            sage: G1 = Graph([(1,2)])
            sage: W3 = CoxeterGroup(G1)
            sage: W1 is W3
            True
            sage: G2 = Graph([(1,2,3)])
            sage: W4 = CoxeterGroup(G2)
            sage: W1 is W4
            True

        Check with `\infty` because of the hack of using `-1` to represent
        `\infty` in the Coxeter matrix::

            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
            sage: W1 = CoxeterGroup(matrix([[1, 3, 2], [3,1,-1], [2,-1,1]]))
            sage: W2 = CoxeterGroup(G)
            sage: W1 is W2
            True
            sage: CoxeterGroup(W1.coxeter_graph()) is W1
            True
        """
        if isinstance(data, CartanType_abstract):
            if index_set is None:
                index_set = data.index_set()
            data = data.coxeter_matrix()
        elif isinstance(data, Graph):
            G = data
            n = G.num_verts()

            # Setup the basis matrix as all 2 except 1 on the diagonal
            data = matrix(ZZ, [[2]*n]*n)
            for i in range(n):
                data[i, i] = ZZ.one()

            verts = G.vertices()
            for e in G.edges():
                m = e[2]
                if m is None:
                    m = 3
                elif m == infinity or m == -1:  # FIXME: Hack because there is no ZZ\cup\{\infty\}
                    m = -1
                elif m <= 1:
                    raise ValueError("invalid Coxeter graph label")
                i = verts.index(e[0])
                j = verts.index(e[1])
                data[j, i] = data[i, j] = m

            if index_set is None:
                index_set = G.vertices()
        else:
            try:
                data = matrix(data)
            except (ValueError, TypeError):
                data = CartanType(data).coxeter_matrix()
            if not data.is_symmetric():
                raise ValueError("the Coxeter matrix is not symmetric")
            if any(d != 1 for d in data.diagonal()):
                raise ValueError("the Coxeter matrix diagonal is not all 1")
            if any(val <= 1 and val != -1 for i, row in enumerate(data.rows())
                   for val in row[i+1:]):
                raise ValueError("invalid Coxeter label")

            if index_set is None:
                index_set = range(data.nrows())

        if base_ring is None:
            base_ring = UniversalCyclotomicField()
        data.set_immutable()
        return super(CoxeterMatrixGroup, cls).__classcall__(cls,
                     data, base_ring, tuple(index_set))

    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        MS = MatrixSpace(base_ring, n, sparse=True)
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2*x) + ~base_ring.gen(2*x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2)
        gens = [MS.one() + MS({(i, j): val(coxeter_matrix[i, j])
                               for j in range(n)})
                for i in range(n)]
        FinitelyGeneratedMatrixGroup_generic.__init__(self, n, base_ring,
                                                      gens,
                                                      category=CoxeterGroups())

    def _repr_(self):
        """
        Return a string representation of ``self``.

        EXAMPLES::

            sage: CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
            [1 3 2]
            [3 1 3]
            [2 3 1]
        """
        return "Coxeter group over {} with Coxeter matrix:\n{}".format(self.base_ring(), self._matrix)

    def index_set(self):
        """
        Return the index set of ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3],[3,1]])
            sage: W.index_set()
            (0, 1)
            sage: W = CoxeterGroup([[1,3],[3,1]], index_set=['x', 'y'])
            sage: W.index_set()
            ('x', 'y')
            sage: W = CoxeterGroup(['H',3])
            sage: W.index_set()
            (1, 2, 3)
        """
        return self._index_set

    def coxeter_matrix(self):
        """
        Return the Coxeter matrix of ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3],[3,1]])
            sage: W.coxeter_matrix()
            [1 3]
            [3 1]
            sage: W = CoxeterGroup(['H',3])
            sage: W.coxeter_matrix()
            [1 3 2]
            [3 1 5]
            [2 5 1]
        """
        return self._matrix

    def coxeter_graph(self):
        """
        Return the Coxeter graph of ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup(['H',3], implementation="reflection")
            sage: G = W.coxeter_graph(); G
            Graph on 3 vertices
            sage: G.edges()
            [(1, 2, None), (2, 3, 5)]
            sage: CoxeterGroup(G) is W
            True
            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
            sage: W = CoxeterGroup(G)
            sage: W.coxeter_graph() == G
            True
            sage: CoxeterGroup(W.coxeter_graph()) is W
            True
        """
        G = Graph()
        G.add_vertices(self.index_set())
        for i, row in enumerate(self._matrix.rows()):
            for j, val in enumerate(row[i+1:]):
                if val == 3:
                    G.add_edge(self._index_set[i], self._index_set[i+1+j])
                elif val > 3:
                    G.add_edge(self._index_set[i], self._index_set[i+1+j], val)
                elif val == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\}
                    G.add_edge(self._index_set[i], self._index_set[i+1+j], infinity)
        return G

    def canonical_representation(self):
        r"""
        Return the canonical faithful representation of ``self``, which
        is ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3],[3,1]])
            sage: W.canonical_representation() is W
            True
        """
        return self

    def simple_reflection(self, i):
        """
        Return the simple reflection `s_i`.

        INPUT:

        - ``i`` -- an element from the index set

        EXAMPLES::

            sage: W = CoxeterGroup(['A',3], implementation="reflection")
            sage: W.simple_reflection(1)
            [-1  1  0]
            [ 0  1  0]
            [ 0  0  1]
            sage: W.simple_reflection(2)
            [ 1  0  0]
            [ 1 -1  1]
            [ 0  0  1]
            sage: W.simple_reflection(3)
            [ 1  0  0]
            [ 0  1  0]
            [ 0  1 -1]
        """
        if not i in self._index_set:
            raise ValueError("%s is not in the index set %s" % (i, self.index_set()))
        return self.gen(self._index_set.index(i))

    class Element(MatrixGroupElement_generic):
        """
        A Coxeter group element.
        """
        def has_right_descent(self, i):
            r"""
            Return whether ``i`` is a right descent of ``self``.

            A Coxeter system `(W, S)` has a root system defined as
            `\{ w(\alpha_s) \}_{w \in W}` and we define the positive
            (resp. negative) roots `\alpha = \sum_{s \in S} c_s \alpha_s`
            by all `c_s \geq 0` (resp.`c_s \leq 0`). In particular, we note
            that if `\ell(w s) > \ell(w)` then `w(\alpha_s) > 0` and if
            `\ell(ws) < \ell(w)` then `w(\alpha_s) < 0`.
            Thus `i \in I` is a right descent if `w(\alpha_{s_i}) < 0`
            or equivalently if the matrix representing `w` has all entries
            of the `i`-th column being non-positive.

            INPUT:

            - ``i`` -- an element in the index set

            EXAMPLES::

                sage: W = CoxeterGroup(['A',3], implementation="reflection")
                sage: a,b,c = W.gens()
                sage: elt = b*a*c
                sage: map(lambda i: elt.has_right_descent(i), [1, 2, 3])
                [True, False, True]
            """
            i = self.parent()._index_set.index(i)
            col = self.matrix().column(i)
            return all(x <= 0 for x in col)

        def canonical_matrix(self):
            r"""
            Return the matrix of ``self`` in the canonical faithful
            representation, which is ``self`` as a matrix.

            EXAMPLES::

                sage: W = CoxeterGroup(['A',3], implementation="reflection")
                sage: a,b,c = W.gens()
                sage: elt = a*b*c
                sage: elt.canonical_matrix()
                [ 0  0 -1]
                [ 1  0 -1]
                [ 0  1 -1]
            """
            return self.matrix()


def isValid(s: str) -> bool:
    def checkMatch(s1, s2):
        if (s1 == '(' and s2 == ')') or (s1 == '{' and s2 == '}') or (s1 == '[' and s2 == ']'):
            return True
        else:
            return False
    openParentheses = ['(', '{', '[']
    stackParentheses = []
    for i in s:
        ans = False
        if i in openParentheses:
            stackParentheses.append(i)
        elif i not in openParentheses:
            if not stackParentheses:
                return False
            ans = checkMatch(stackParentheses[-1], i)
            if ans:
                stackParentheses.pop(-1)
            else:
                return False
    return stackParentheses == []

s = "(])"
print(isValid(s))


def find_it(seq):
    res = []
    for i in seq:
       if i not in res:
           res.append(i)
       else:
           res.remove(i)
    return res[0]

if __name__ == "__main__":
    x = find_it([20,1,-1,2,-2,3,3,5,5,1,2,4,20,4,-1,-2,5])
    print(x)


import base

EXPECTED = [
    """Hello world from user mode program!
Test hello_world OK!""",
    """Test power OK!""",
    """string from data section
strinstring from stack section
strin
Test write1 OK!""",
]

TEMP = [
    """Test write0 OK!""",
    """Test hello_world OK!""",
    """Test write1 OK!""",
]

NOT_EXPECTED = [
    "FAIL: T.T",
]

if __name__ == '__main__':
    base.test(EXPECTED + TEMP, NOT_EXPECTED)


# 1295. Find Numbers with Even Number of Digits

# Given an array nums of integers, return how many of them contain an even number of digits.

# Example 1:
# Input: nums = [12,345,2,6,7896]
# Output: 2
# Explanation:
# 12 contains 2 digits (even number of digits).
# 345 contains 3 digits (odd number of digits).
# 2 contains 1 digit (odd number of digits).
# 6 contains 1 digit (odd number of digits).
# 7896 contains 4 digits (even number of digits).
# Therefore only 12 and 7896 contain an even number of digits.

# Example 2:
# Input: nums = [555,901,482,1771]
# Output: 1
# Explanation:
# Only 1771 contains an even number of digits.

# Constraints:
# 1 <= nums.length <= 500
# 1 <= nums[i] <= 10^5

class Solution1():
    def findNumbers(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        count = 0
        for num in nums:
            if self.digitCount(num) % 2 == 0:
                count += 1
        return count

    def digitCount(self, num):
        count = 0
        while(num > 0):
            num = num // 10
            count += 1
        return count

class Solution2():
    def findNumbers(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        count = 0
        for num in nums:
            if len(str(num)) % 2 == 0:
                count += 1
        return count


import threading;

def forward(no):
	if no != 0:
		forward(no-1);
		print(no);

def reverse(no):
	if no != 0:
		print(no);
		reverse(no-1);

def main():
	thread1 = threading.Thread(target = forward, args = (50,));
	thread2 = threading.Thread(target = reverse, args = (50,));

	thread1.start();
	thread1.join();
	print("*"*50);
	thread2.start();

if __name__ == '__main__':
	main();


#%%
import os
import numpy as np
import random

# Genetic algorithm
def ga_selection(pop_size = 10, population = [], variable_num = 5, fitness = [], mutation_ratio = 0.1):
    # Parents selection (max k)
    parent_size = pop_size//2 # Keep half of the initial population
    temp_1 = population.copy()
    temp_2 = fitness.copy()
    parent = []
    for seq in range(parent_size):
        min_id = temp_2.index(min(temp_2))
        parent.append(temp_1[min_id])
        del(temp_2[min_id])
        del(temp_1[min_id])

    # Crossover
    offspring = parent.copy()
    mating_seq = random.sample(range(0, pop_size), parent_size) # randomly select half of pop_size to crossover
    for seq in range(parent_size):
        mating_rule = np.random.randint(2, size=variable_num) # 1 -> keep, 0 -> swap
        child = parent[seq] * mating_rule + population[mating_seq[seq]] * abs(mating_rule - 1)
        offspring.append(child.tolist())

    # Mutation
    mutation_num = int(len(offspring) * len(offspring[0]) * mutation_ratio) # Randomly select num of position to mutate
    mutation_pos = []
    while len(mutation_pos) < mutation_num:
        temp = [random.randint(0, pop_size-1), random.randint(0, variable_num-1)]
        if temp not in mutation_pos:
            mutation_pos.append(temp)
    for pos in mutation_pos:
        mute_x = random.randint(0, variable_num-1)
        while mute_x == offspring[pos[0]][pos[1]]:
            mute_x = random.randint(0, variable_num-1)
        else:
            offspring[pos[0]][pos[1]] = mute_x
    return offspring

print('Library loaded')

# %%
# Load data
n_variables = 5
n_h_sub = 5
n_h_adhesive = 5
n_h_die = 5
n_cte_emc = 5
n_h_emc = 5
with open('./full_scan_5d.csv') as f:
    full_scan = np.loadtxt(f, delimiter=',')
full_scan[:, 0] = (full_scan[:, 0]-200)/30  # h_die
full_scan[:, 1] = (full_scan[:, 1]-20)/5    # h_adhesive
full_scan[:, 2] = (full_scan[:, 2]-200)/25  # h_sub
full_scan[:, 3] = (full_scan[:, 3]-550)/100 # h_emc
full_scan[:, 4] = (full_scan[:, 4]-8)/1     # cte_emc
print('Initial data loaded')

pop_size = 10
rand_pick = full_scan[random.sample(range(0, len(result)), pop_size)]
init_pop = rand_pick[:, 0:-1].tolist()
init_fit = abs(rand_pick[:, -1]).tolist()
# %%
generation_num = 10
for generation in range(generation_num):
    offspring = ga_selection(pop_size = pop_size, population = init_pop, variable_num = n_variables, fitness = init_fit, mutation_ratio = 0.1)
    offspring_fit = []
    for child in offspring:
        offspring_fit.append(abs(full_scan[int(child[2] + child[1]*n_h_sub + child[0]*n_h_sub*n_h_adhesive + \
            child[4]*n_h_sub*n_h_adhesive*n_h_die + child[3]*n_h_sub*n_h_adhesive*n_h_die*n_cte_emc)][-1]))
    init_pop = offspring
    init_fit = offspring_fit
    #np.savetxt('C:/SUSTech-Postdoc/SDIM-Projects/Warpage/Genetic_Algorithm/Generation_' + str(generation + 1) + '.csv', \
     #   np.hstack((np.array(init_pop), np.array(init_fit)[:, None])), delimiter=',')

# %%
parent_size = pop_size//2
temp = init_pop.copy()
parent = []
for seq in range(parent_size):
    min_id = init_fit.index(min(init_fit))
    parent.append(temp[min_id])
    del(init_fit[min_id])
    del(temp[min_id])

# %%
offspring = parent.copy()
mating_seq = random.sample(range(0, pop_size), parent_size)
for seq in range(parent_size):
    mating_rule = np.random.randint(2, size=5)
    child = parent[seq] * mating_rule + init_pop[mating_seq[seq]] * abs(mating_rule - 1)
    offspring.append(child.tolist())

# %%


import os
import dj_database_url
import environ
from pathlib import Path

env = environ.Env()
environ.Env.read_env()

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = env('SECRET_KEY')

DEBUG = env('DEBUG')

ALLOWED_HOSTS = ['thevinylproject.herokuapp.com',
                 '127.0.0.1']

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'crispy_forms',
    'thebrain',
    'cart',
    'staff',
    'storages',
]

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL')
NOTIFY_EMAIL = os.environ.get('NOTIFY_EMAIL')

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'vinylmainfolder.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "templates")],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'vinylmainfolder.wsgi.application'

# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
if 'DATABASE_URL' in os.environ:
    DATABASES = {
        'default': dj_database_url.parse(os.environ.get('DATABASE_URL'))
    }
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }

# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
]
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = 'none'
LOGIN_REDIRECT_URL = '/'
SITE_ID = 1
CRISPY_TEMPLATE_PACK = 'bootstrap4'

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_TZ = True
USE_I18N = True
USE_L10N = True
USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
STATIC_ROOT = os.path.join(BASE_DIR, "static_root")
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
# MEDIA_URL = [os.path.join(BASE_DIR, "media")]

PAYPAL_CLIENT_ID = os.environ.get('PAYPAL_SANDBOX_CLIENT_ID')
PAYPAL_SECRET_KEY = os.environ.get('PAYPAL_SANDBOX_SECRET_KEY')

DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL')
NOTIFY_EMAIL = os.environ.get('NOTIFY_EMAIL')

if DEBUG is False:
    SESSION_COOKIE_SECURE = True
    SECURE_BROWSER_XSS_FILTER = True
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SECURE_HSTS_INCLUDE_SUBDOMAINS = True
    SECURE_HSTS_SECONDS = 31536000
    # SECURE_SSL_HOST = ['www.vinylproject.co.uk']
    SECURE_REDIRECT_EXEMPT = []
    SECURE_SSL_REDIRECT = True
    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

    ALLOWED_HOSTS = ['db-vinylproject.herokuapp.com',
                     '127.0.0.1', '.vinylproject.co.uk', 'www.vinylproject.co.uk']

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': '',
            'USER': '',
            'PASSWORD': '',
            'HOST': '',
            'PORT': '',
        }
    }

# REMEMBER TO REACTIVATE AWS S3 WHEN DEPLOYING
AWS_STORAGE_BUCKET_NAME = 'vinylproject'
AWS_S3_REGION_NAME = 'eu-west-2'
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_S3_CUSTOM_DOMAIN = 'vinylproject.s3.amazonaws.com'
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = False

STATICFILES_STORAGE = 'custom_storages.StaticStorage'
STATICFILES_LOCATION = 'static/'
DEFAULT_FILE_STORAGE = 'custom_storages.MediaStorage'
MEDIAFILES_LOCATION = 'media'

STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{STATICFILES_LOCATION}/'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIAFILES_LOCATION}/'


import bpy
from collections import defaultdict
from bpy.types import Operator
import bmesh
import mathutils
import math
from bpy.props import (
    BoolProperty,
    IntProperty,
    EnumProperty,
)

if bpy.app.version >= (3, 0, 0):
    from . import function_wrapper_3_0 as function_wrapper
elif bpy.app.version >= (2, 90, 0):
    from . import function_wrapper_2_9 as function_wrapper
else:
    from . import function_wrapper_2_8 as function_wrapper

class Seams_To_SewingPattern(Operator):
    bl_idname = "object.seams_to_sewingpattern"
    bl_label = "Seams to Sewing Pattern"
    bl_description = (
        "Converts a manifold mesh with seams into a swewing pattern for cloth"
        " simulation"
    )
    bl_options = {'REGISTER', 'UNDO'}

    do_unwrap: EnumProperty(
        name="Unwrap",
        description=(
            "Perform an unwrap before unfolding. Identical to UV > Unwrap"
        ),
        items=(
            ('ANGLE_BASED', "Angle based", ""),
            ('CONFORMAL', "Conformal", ""),
            ('KEEP', "Keep existing (advanced)", ""),
        ),
        default='ANGLE_BASED',
    )
    keep_original: BoolProperty(
        name="Work on duplicate",
        description=(
            "Creates a duplicate of the selected object and operates on that"
            " instead. This keeps your original object intact."
        ),
        default=True,
    )
    use_remesh: BoolProperty(
        name="Remesh",
        description="Use Boundary Aligned Remesh to remesh",
        default=True,
    )
    apply_modifiers: BoolProperty(
        name="Apply modifiers",
        description="Applies all modifiers before operating.",
        default=True,
    )
    target_tris: IntProperty(
        name="Target number of triangles",
        description="Actual number of triangle migh be a bit off",
        default=5000,
    )

    def invoke(self, context, event):
        wm = context.window_manager
        return wm.invoke_props_dialog(self, width=250)

    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.label(
            text="Unfolds this mesh by cutting along seams.", icon='INFO'
        )
        layout.separator()
        layout.row()
        layout.row()
        row = layout.row()
        row.prop(self, "do_unwrap")
        if(self.do_unwrap == 'KEEP'):
            row = layout.row()
            row.alignment = 'EXPAND'
            row.label(
                text="Ensure your seams match your UV's!", icon='EDGESEL'
            )

        layout.row()
        row = layout.row()
        row.prop(self, "keep_original")
        row = layout.row()
        row.prop(self, "apply_modifiers")
        row = layout.row()
        row.prop(self, "use_remesh")
        row = layout.row()
        row.prop(self, "target_tris")
        row.enabled = self.use_remesh
        layout.row()

    def execute(self, context):
        if self.keep_original:
            # Duplicate selection to keep original.
            src_obj = bpy.context.active_object
            obj = src_obj.copy()
            obj.data = src_obj.data.copy()
            obj.animation_data_clear()
            bpy.context.collection.objects.link(obj)

            obj.select_set(True)
            src_obj.select_set(False)
            bpy.context.view_layer.objects.active = obj

        if self.apply_modifiers:
            bpy.ops.object.convert(target='MESH')
            obj = bpy.context.active_object

        wm = bpy.context.window_manager
        bpy.ops.object.mode_set(mode='EDIT')

        obj = bpy.context.edit_object
        me = obj.data

        bpy.ops.mesh.select_mode(type="EDGE")

        bpy.ops.mesh.select_all(action='SELECT')
        if (self.do_unwrap != 'KEEP'):
            bpy.ops.uv.unwrap(method=self.do_unwrap, margin=0.02)
        bpy.ops.mesh.select_all(action='DESELECT')

        bm = bmesh.from_edit_mesh(me)

        obj["S2S_InitialVolume"] = bm.calc_volume()

        function_wrapper.do_update_edit_mesh(me)

        # Calculate edge length based on a surface of equilateral triangles.

        if (self.use_remesh):
            current_area = sum(f.calc_area() for f in bm.faces)
            target_triangle_count = self.target_tris
            area_per_triangle = current_area / target_triangle_count

            max_edge_length = math.sqrt(area_per_triangle/(math.sqrt(3)/4))

            # A bias to compensate for stretching.
            self.ensure_edgelength(max_edge_length * 0.8, bm, wm)

        warn_any_seam = False

        for e in bm.edges:
            if e.seam:
                e.select = True
                warn_any_seam = True

        if not warn_any_seam:
            self.report(
                {'ERROR'},
                (
                    'There are no seams in this mesh. Please add seams where'
                    ' you want to cut the model.'
                )
            )
            return {'CANCELLED'}

        function_wrapper.do_bevel()

        #####
        '''
        error now because I need to fix the fact that fanning edges dont exist
        anymore maybe by finding ngons instead?
        or removing doubled afer
        '''
        #####

        # fix fanning seams
        degenerate_edges = list()
        for f in list(filter(lambda f: (f.select), bm.faces)):
            is_degenerate = False
            for v in f.verts:
                vert_degenerate = True
                for e in v.link_edges:
                    if e.seam:
                        vert_degenerate = False
                if vert_degenerate:
                    is_degenerate = True

            for e in f.edges:
                if e.is_boundary:
                    is_degenerate = False

            if is_degenerate:
                for e in f.edges:
                    degenerate_edges.append(e)

        bmesh.ops.collapse(bm, edges=degenerate_edges, uvs=True)

        bpy.ops.mesh.delete(type='ONLY_FACE')

        bpy.ops.mesh.select_mode(type="FACE")
        faceGroups = []

        # isolate all face islands, and UV unwrap each island

        faces = set(bm.faces[:])
        wm.progress_begin(0, 99)
        progress_max = len(faces)
        progress = 0
        while faces:
            bpy.ops.mesh.select_all(action='DESELECT')
            face = faces.pop()
            face.select = True
            bpy.ops.mesh.select_linked()
            selected_faces = {f for f in faces if f.select}
            selected_faces.add(face)  # this or bm.faces above?
            faceGroups.append(selected_faces)
            faces -= selected_faces

            progress += len(selected_faces)
            wm.progress_update((progress / progress_max))

        uv_layer = bm.loops.layers.uv.active

        progress = 0

        area_before = 0
        area_after = 0

        for g in faceGroups:
            progress += 1
            wm.progress_update((progress / len(faceGroups)))
            bpy.ops.mesh.select_mode(type='FACE')
            bpy.ops.mesh.select_all(action='DESELECT')
            average_position = mathutils.Vector((0, 0, 0))
            facenum = 0

            # calculate the area, average position

            for f in g:
                f.select = True
                area_before += f.calc_area()
                average_position += f.calc_center_median()
                facenum += 1

            average_position /= facenum

            average_tangent = mathutils.Vector((0, 0, 0))
            average_bitangent = mathutils.Vector((0, 0, 0))

            # calculate a rough tangent and a bitangent

            average_uv_position = mathutils.Vector((0, 0))
            uv_position_samples = 0

            for face in g:
                for loop in face.loops:
                    uv = loop[uv_layer].uv
                    uv_position_samples += 1
                    average_uv_position += uv
                    delta = loop.vert.co - average_position
                    average_tangent += delta * (uv.x - 0.5)
                    average_bitangent += delta * (uv.y - 0.5)

            # reorient the tangent and bitangent

            average_uv_position /= uv_position_samples
            average_tangent = average_tangent.normalized()
            average_bitangent = average_bitangent.normalized()
            average_normal = average_tangent.cross(
                average_bitangent
            ).normalized()
            halfvector = average_bitangent + average_tangent
            halfvector /= 2
            halfvector.normalize()
            # straighten out half vector
            halfvector = average_normal.cross(halfvector)
            halfvector = average_normal.cross(halfvector)
            cw = mathutils.Matrix.Rotation(
                math.radians(45.0), 4, average_normal
            )
            ccw = mathutils.Matrix.Rotation(
                math.radians(-45.0), 4, average_normal
            )

            average_tangent = mathutils.Vector(halfvector)
            average_tangent.rotate(ccw)

            average_bitangent = mathutils.Vector(halfvector)
            average_bitangent.rotate(cw)

            # offset each face island by their UV value, using the tangent and
            # bitangent

            for face in g:
                for loop in face.loops:
                    uv = loop[uv_layer].uv
                    vert = loop.vert
                    pos = mathutils.Vector((0, 0, 0))
                    pos += average_position
                    pos += average_tangent * -(uv.x - average_uv_position.x)
                    pos += average_bitangent * -(uv.y - average_uv_position.y)
                    # arbitrary - should probably depend on object scale?
                    pos += average_normal * 0.3
                    vert.co = pos

            function_wrapper.do_update_edit_mesh(me)
            area_after += sum(f.calc_area() for f in g)

        # done

        area_ratio = math.sqrt(area_before / area_after)
        bpy.ops.mesh.select_all(action='SELECT')
        previous_pivot = bpy.context.scene.tool_settings.transform_pivot_point
        bpy.context.scene.tool_settings.transform_pivot_point = (
            'INDIVIDUAL_ORIGINS'
        )
        bpy.ops.transform.resize(value=(area_ratio, area_ratio, area_ratio))
        bpy.context.scene.tool_settings.transform_pivot_point = previous_pivot

        obj["S2S_UVtoWORLDscale"] = area_ratio

        function_wrapper.do_update_edit_mesh(me)
        bpy.ops.mesh.select_all(action='SELECT')

        bpy.ops.mesh.remove_doubles(threshold=0.0004, use_unselected=False)

        if (self.use_remesh):
            bpy.ops.mesh.dissolve_limited(angle_limit=0.01)
            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
            bpy.ops.remesh.boundary_aligned_remesh(
                edge_length=max_edge_length, iterations=10, reproject=False
            )

        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

        wm.progress_end()

        # fix 2.9 wm.progress problem
        bpy.context.window.cursor_set('NONE')
        bpy.context.window.cursor_set('DEFAULT')

        return{'FINISHED'}

    def ensure_edgelength(self, max_length, mesh, wm):
        seam_edges = list(filter(lambda e: e.seam, mesh.edges))
        edge_groups = defaultdict(list)
        for e in seam_edges:
            edge_groups[math.floor(e.calc_length() / max_length)].append(e)

        wm.progress_begin(0, 99)
        progress = 0

        # A little weird, but by grouping the edges by number of required cuts,
        # subdivide_edges() can work a lot more effecient

        for eg in edge_groups.values():
            edge_length = eg[0].calc_length()
            wm.progress_update((progress / len(edge_groups)))
            bmesh.ops.subdivide_edges(
                mesh, edges=eg, cuts=math.floor(edge_length / max_length)
            )

        bmesh.ops.triangulate(
            mesh, faces=mesh.faces, quad_method='BEAUTY', ngon_method='BEAUTY'
        )
        # done


from ROOT import TCanvas, TH1D, TH2D, TLegend, TPad
import ROOT
ROOT.gStyle.SetOptStat(0)
ROOT.gStyle.SetPalette(1)
ROOT.gROOT.LoadMacro("AtlasStyle.C")
ROOT.gROOT.LoadMacro("AtlasLabels.C")
ROOT.SetAtlasStyle()

ROOT.xAOD.Init().isSuccess()

c1 = TCanvas('c1',' ' , 1000, 1000)
c1.Draw()

h1 = TH2D('h1', 'Combined vs Segement Tagged', 5, -0.5, 4.5, 5, -0.5, 4.5)
h0 = TH1D('h0', 'Number of 0 Charge Quads', 60, 0, 30)
h2 = TH1D('h2', 'Number of +-2 Charge Quads', 60, 0, 30)
h4 = TH1D('h4', 'Number of +-4 Charge Quads', 60, 0, 30)

f = ROOT.TFile.Open('root://eosatlas.cern.ch//eos/atlas/user/d/daits/mc16_13TeV/DAOD_BPHY4/mc16.999031.P8BEG_23lo_ggX18p4_Upsilon1Smumu_4mu_3pt2.deriv.DAOD_BPHY4.e8304_a875_r10724_r10726_p3712_pUM999999/DAOD_BPHY4.999031._000001.pool.root.1')
t = ROOT.xAOD.MakeTransientTree(f, 'CollectionTree')

nEntries = t.GetEntries()

n0Quad = 0 #set values to 0 BEFORE event so it can add to the value after each event instead of resetting to 0 every event
n2Quad = 0
n4Quad = 0

for event in xrange(nEntries):
    t.GetEntry(event)

    bphy4_muon_lookup = { muon.auxdataConst('int')('BPHY4MuonIndex'): muon
                          for muon in t.Muons if muon.auxdataConst('int')('BPHY4MuonIndex') != -1 } #Python dicitonary that gives the muon object given the BPHY4MuonIndex value

    for quad in t.BPHY4Quads:
        tCharge = 0
        value = quad.auxdataConst('string')('CombinationCode') #accesses the muon decorator CombinationCode
        value2 = quad.auxdataConst('string')('ChargeCode') #accesses the muon decorator ChargeCode
        value3 = quad.auxdata('float')('QUAD_mass')

        for c in value2:
            if c == '+': #adds 1 to tCharge for every + character
                tCharge += 1
            elif c == '-': #subtracts 1 from tCharge for every - character
                tCharge -= 1

    if tCharge == 0: #must be outside of 'for c' loop so it can define tCharge once for each quad
        n0Quad += 1
        h0.Fill(value3/1000)
    elif tCharge == -2 or tCharge == +2:
        n2Quad += 1
        h2.Fill(value3/1000)
    elif tCharge == -4 or tCharge == +4:
        n4Quad += 1
        h4.Fill(value3/1000)

        #nComb = 0
        #nSegTag = 0
        if len(value) == 4:
            for c in value: #seperates string into each character
                muon = bphy4_muon_lookup[int(c)] #converts characters to strings and indexes object Muon
                print(muon.muonType()) #call the type of muon: combined or segment

                #if muon.muonType() == 0:
                    #nComb += 1
                #elif muon.muonType() == 2:
                    #nSegTag += 1
               # else:
                   # print(muon.muonType())
            #h1.Fill(nComb, nSegTag)

            #print(nComb)

t = (n0Quad, n2Quad, n4Quad)
tQuad = float(sum(t))
frac0 = n0Quad/tQuad
frac2 = n2Quad/tQuad
frac4 = n4Quad/tQuad

#print frac0, frac2, frac4
#print n4Quad

h0.SetLineColor(ROOT.kBlue)
h2.SetLineColor(ROOT.kRed)
h4.SetLineColor(ROOT.kGreen)
h0.GetXaxis().SetTitle('Charge Quad Mass [GeV]')
leg = TLegend(0.63, 0.60, 0.78, 0.75)
leg.AddEntry(h0, 'Charge 0', 'l')
leg.AddEntry(h2, 'Charge 2', 'l')
leg.AddEntry(h4, 'Charge 4', 'l')
h0.Draw()
h2.Draw('same')
h4.Draw('same')
leg.Draw()
c1.SaveAs('chargeQuadmass.png')

h1.GetXaxis().SetTitle('# of Combined Muons')
h1.GetYaxis().SetTitle('# of Segment Tagged Muons')
#h1.Draw('COLZ')
#h1.Print('all')

#c1.SaveAs('Com_SegTag.png')

ROOT.xAOD.ClearTransientTrees()
f.Close()


from unittest import TestCase

from kibana_prometheus_exporter.kibana_collector import Metrics

class TestMetrics(TestCase):
    def setUp(self) -> None:
        self.metrics_dict = {
            "last_updated": "2019-04-02T03:56:41.078Z",
            "collection_interval_in_millis": 15000,
            "process": {
                "memory": {
                    "heap": {"total_in_bytes": 175874048, "used_in_bytes": 157139288, "size_limit": 1526909922},
                    "resident_set_size_in_bytes": 285655040,
                },
                "event_loop_delay": 0.08109402656555176,
                "pid": 18595,
                "uptime_in_millis": 2494490,
            },
            "os": {
                "load": {"1m": 0.16357421875, "5m": 0.13720703125, "15m": 0.13037109375},
                "memory": {"total_in_bytes": 8257908736, "free_in_bytes": 193777664, "used_in_bytes": 8064131072},
                "uptime_in_millis": 1212738000,
                "platform": "linux",
                "platformRelease": "linux-4.15.0-1034-aws",
                "distro": "Ubuntu Linux",
                "distroRelease": "Ubuntu Linux-18.04",
                "cgroup": {
                    "cpuacct": {"control_group": "/system.slice/kibana.service", "usage_nanos": 24967412414},
                    "cpu": {
                        "control_group": "/system.slice/kibana.service",
                        "cfs_period_micros": 100000,
                        "cfs_quota_micros": -1,
                        "stat": {
                            "number_of_elapsed_periods": 0,
                            "number_of_times_throttled": 0,
                            "time_throttled_nanos": 0,
                        },
                    },
                },
            },
            "response_times": {"avg_in_millis": 2.3333333333333335, "max_in_millis": 3},
            "requests": {"disconnects": 0, "statusCodes": {}, "total": 3, "status_codes": {"302": 3}},
            "concurrent_connections": 0,
        }

    def test_all_metrics_have_timestamps(self):
        metrics = Metrics(self.metrics_dict)
        for metric in metrics:
            for sample in metric.samples:
                self.assertIsNotNone(sample.timestamp, sample)


from JumpScale import j

descr = """
Stops a vmachine if it's abusing node's resources, and moves it to slower storage
"""

name = "vm_stop_for_abusive_usage"
category = "cloudbroker"
organization = "cloudscalers"
author = "zains@codescalers.com"
license = "bsd"
version = "1.0"
queue = "hypervisor"

def action(machineId, nodeId):
    # shutdown the vmachine
    from CloudscalerLibcloud.utils.libvirtutil import LibvirtUtil
    connection = LibvirtUtil()
    connection.shutdown(nodeId)

    # move the vmachine to slower storage
    import os
    src = j.system.fs.joinPaths('/mnt', 'vmstor', 'vm-%s' % machineId)
    dest = j.system.fs.joinPaths('/mnt', 'vmstor2', 'vm-%s' % machineId)
    if not j.system.fs.exists(dest):
        j.system.fs.moveDir(src, dest)
        os.symlink(dest, src)


from flask import *
import os

main = Blueprint('main', __name__, template_folder='templates')

@main.route('/', methods=['GET', 'POST'])
def main_route():
	validFormats = set(['png', 'jpg', 'bmp', 'gif'])
	# if (request.form.get("op") == "img_search"):
	#   	picFile = request.files.get("pic")
	#   	if picFile:
	#   		filename = picFile.filename
	#   		extension = filename[-3:]
	#   		# make sure the file is of a valid picture format
	#   		if extension.lower() not in validFormats and filename[-4:].lower() not in ['tiff', 'jpeg']:
	#   			abort(404)
	#        	# save the uploaded image so we can send it to the model
	#        	curPath = os.path.dirname(__file__)
	#        	relPath = "static/images"
	#        	imagesFolder = os.path.abspath(os.path.join(curPath, os.pardir, relPath))
	#        	picFile.save(os.path.join(imagesFolder, filename))
	#        	# Send the file to the trained model
	#        	# model.recognize(filename)
	#        	# returns JSON data to search by
	#        	# store into set/list/just use the json object and grab the values for each key maybe
	#        		#call container imageInfo
	#        	#redirectURL = "http://www.wayfair.com/keyword.php?keyword="
	#        	redirectURL = "http://www.wayfair.com/keyword.php?keyword=blue+lamp"
	#        	# redirectURL += str(imageInfo[0]);
	#        	# for attr in imageInfo[1:]:
	#        	# 	redirectURL += ("+" + str(attr))
	#        	print redirectURL
	#        	return redirect(redirectURL)

	return render_template("index.html")


#  import data.json
#  convert into jsonle format

import json
import os

def convert(file_name):
    with open(file_name, 'r') as JSON_file:
        data = json.load(JSON_file)
        with open('data' + '.txt', 'w') as output:
            for item in data:
                item['completion'] = str(item['completion']) + '###'
                # dump
                output.write(json.dumps
                (item))
                output.write('\n')
                # output.write(item['prompt'] + ':' + item['completion'] + '\n')
    # os.remove(file_name)
    print("Converted {} to {}.json".format(file_name, file_name))
# get current directory
currentDirection = os.getcwd()
jsonfile = currentDirection + '\\data.json'
convert(jsonfile)


from tAssist import *
from VEnv import VEnv

Main = 'genome.txt'
Genome = ReadGenome(Main)
class Agent:
    def __init__(self, name, envShape, body):
        # AGENT DETAILS
        self.Name = name
        self.width, self.height = envShape
        self.body, self.head = body, body[0]
        self.Network = NeuralNetwork(Genome)  #
        self.hypotenuse = Divide(Add(envShape), math.sqrt(2))  # Longest possible distance

        # ACTIVITY DETAILS
        self.orientation = [-1, 0]
        self.stamina, self.holdStamina = 1, 1
        self.angles = [0, 15, 30, 45, 60, 75,
                       90, 105, 120, 135, 150,
                       -150, -135, -120, -105,
                       -90, -75, -60, -45, -30, -15]  # Octagon

        # MEMORY
        self.Snake = {self.Name: -0.20000}
        self.Food, self.Boundary = -0.1, -0.3

    def Update(self, body, stamina):
        self.stamina = stamina
        self.body, self.head = body, body[0]

    def CheckBoard(self, YXAbs, Board):
        Food, Snakes = Board['food'], Board['snakes']
        if YXAbs in Food:
            return self.Food
        for name in Snakes:
            if YXAbs in Snakes[name]:
                return self.Snake[name]
        return None

    def Move(self, Board: dict) -> str:
        # NETWORK:
        NeuralInput = self.See(Board) + [self.stamina, self.holdStamina]
        self.Network.ForwardPass(NeuralInput)

        # STAMINA:
        self.holdStamina = self.stamina

        # MOVEMENTS:
        confidence = RoundList(self.Network.ReadOutput())
        if confidence == [0, 1]:
            self.orientation = RoundList(RotMat(90, self.orientation))  # ClockWise: 90 deg
        elif confidence == [1, 0]:
            self.orientation = RoundList(RotMat(-90, self.orientation))  # ClockWise: -90 deg

        if self.orientation == [1, 0]:
            return 'up'  # Forward/Repeat: 0 deg
        elif self.orientation == [0, 1]:
            return 'right'  # ClockWise: 90 deg
        elif self.orientation == [0, -1]:
            return 'left'  # ClockWise: -90 deg
        elif self.orientation == [-1, 0]:
            return 'down'  # ClockWise: 180 deg

        return response

    def See(self, Board: dict) -> list:
        # Searches VEnvironment for:
        vFeat, vDist = [], []  # Features and Their distance
        YPov, XPov = self.head

        for theta in self.angles:
            y, x = YPov, XPov  # ...
            route = RotMat(theta, self.orientation)  # ...
            y, x = Add([y, route[0]]), Add([x, route[1]])  # ...
            YAbs, XAbs = Round(y), Round(x)  # Look in 21 directions
            while True:
                dist = abs(YPov - YAbs) + abs(XAbs - XPov)
                if not 0 <= YAbs < self.height or not 0 <= XAbs < self.width:
                    vDist.append(Divide(dist, self.hypotenuse))
                    vFeat.append(self.Boundary)
                    break
                tile = self.CheckBoard([YAbs, XAbs], Board)
                if tile:
                    vDist.append(Divide(dist, self.hypotenuse))
                    vFeat.append(tile)
                    break
                y, x = Add([y, route[0]]), Add([x, route[1]])  # ...
                YAbs, XAbs = Round(y), Round(x)  # and Keep looking

        return vFeat + vDist


def can_chain(dominoes):
    if len(dominoes) == 0:
        return []
    return chain([], dominoes, len(dominoes))

def chain(snake, pile, expected_length):
    options = pile if len(snake) == 0 else [i for i in pile if i[0] == snake[-1][1] or i[1] == snake[-1][1]]
    for item in options:
        next_item = item if len(snake) == 0 or item[0] == snake[-1][1] else tuple((item[1], item[0]))
        new_snake = snake + [next_item]
        if is_completed(new_snake, expected_length):
            return new_snake
        i = pile.index(item)
        new_pile = pile[1:] if i == 0 else pile[:-1] if i == len(pile) - 1 else pile[:i] + pile[i + 1:]
        final_snake = chain(new_snake, new_pile, expected_length)
        if final_snake is not None and is_completed(final_snake, expected_length):
            return final_snake

def is_completed(snake, expected_length):
    return len(snake) == expected_length and snake[0][0] == snake[-1][1]


"""

@author: Cody Smith | codysmith.contact@gmail.com
https://github.com/codysmith-tech
https://www.linkedin.com/in/codysmithprofile/

"""

import matplotlib.pyplot as plt
import plotly.express as px
import os
import shutil
import webbrowser

def html_scatter_plot(data, labels, title, path):
    """
    Creates interactive HTML scatter plots from DataFrames.

    Parameters
    ----------
    data : DataFrame
        DF containg data to be scatter plotted

    labels : dict
        Dictionary of x and y axis labels

    title : string
        Title of graph

    path : string
        Path to save to

    Returns
    -------
    None.

    """
    fig = px.scatter(x = data.index, y = data,
                     labels = labels,
                     title = title)
    fig.write_html(path)

def plot_data(working_directory, all_data, nov_mean_binary, dec_mean_binary, jan_mean_binary):
    """
    Plots all data into raw radiation plots and binary radiation plots.

    Parameters
    ----------
    working_directory : string
        The directory that contains your the scripts
        for this project, including this one.

    all_data : list
        A list of DataFrames containing all data.

    nov_mean_binary : DataFrame
        The average binary data for all years of November.

    dec_mean_binary : DataFrame
        The average binary data for all years of December.

    jan_mean_binary : DataFrame
        The average binary data for all years of January.

    Returns
    -------
    None.

    """

    #Turning off anaconda plots
    plt.ioff()

    #Making directories
    if os.path.isdir(working_directory + '\\graphs\\') == True:
        shutil.rmtree(working_directory + '\\graphs')

    os.mkdir(working_directory + '\\graphs\\')

    os.mkdir(working_directory + '\\graphs\\radiation-graphs')
    os.mkdir(working_directory + '\\graphs\\radiation-graphs\\november-radiation-graphs')
    os.mkdir(working_directory + '\\graphs\\radiation-graphs\\december-radiation-graphs')
    os.mkdir(working_directory + '\\graphs\\radiation-graphs\\january-radiation-graphs')

    os.mkdir(working_directory + '\\graphs\\binary-graphs')
    os.mkdir(working_directory + '\\graphs\\binary-graphs\\november-binary-graphs')
    os.mkdir(working_directory + '\\graphs\\binary-graphs\\december-binary-graphs')
    os.mkdir(working_directory + '\\graphs\\binary-graphs\\january-binary-graphs')

    for i in range(len(all_data)):

        year = 1978

        for j in range(len(all_data[i])):

            year = year + 1

            #Graphing raw radiation
            plt.figure()
            plt.scatter(all_data[i][j].index, all_data[i][j][0], s=1)
            plt.xlabel('Time (3 Minute Intervals)')
            plt.ylabel('Direct Solar Radiation (W/m^2)')

            #Setting title & saving raw radiation plots
            if i == 0:
                plt.title(f'November {year} Direct Radiation')
                plt.savefig(working_directory + '\\graphs\\radiation-graphs\\november-radiation-graphs\\' + f'nov_{year}_radiation.png', dpi=300)

            elif i == 1:
                plt.title(f'December {year} Direct Radiation')
                plt.savefig(working_directory + '\\graphs\\radiation-graphs\\december-radiation-graphs\\' + f'dec_{year}_radiation.png', dpi=300)

            else:
                plt.title(f'January {year} Direct Radiation')
                plt.savefig(working_directory + '\\graphs\\radiation-graphs\\january-radiation-graphs\\' + f'jan_{year}_radiation.png', dpi=300)

            plt.close()

            #Graphing binary
            plt.figure()
            plt.scatter(all_data[i][j].index, all_data[i][j][1], s=1)
            plt.xlabel('Time (3 Minute Intervals)')
            plt.ylabel('Binary Radiation')

            #Setting title & saving binary radiation plots
            if i == 0:
                plt.title(f'November {year} Binary Radiation')
                plt.savefig(working_directory + '\\graphs\\binary-graphs\\november-binary-graphs\\' + f'nov_{year}_binary.png', dpi=300)

            elif i == 1:
                plt.title(f'December {year} Binary Radiation')
                plt.savefig(working_directory + '\\graphs\\binary-graphs\\december-binary-graphs\\' + f'dec_{year}_binary.png', dpi=300)

            else:
                plt.title(f'January {year} Binary Radiation')
                plt.savefig(working_directory + '\\graphs\\binary-graphs\\january-binary-graphs\\' + f'jan_{year}_binary.png', dpi=300)

            plt.close()

    #Plotting average binary radiation for each month
    #November
    html_scatter_plot(nov_mean_binary,
                      labels = dict(x='Time (3 Minute Intervals)',y='Binary Radiation'),
                      title = 'Average November Binary Radiation',
                      path = working_directory + '\\graphs\\' + 'nov_avg_binary.html'
                      )

    #December
    html_scatter_plot(dec_mean_binary,
                      labels = dict(x='Time (3 Minute Intervals)',y='Binary Radiation'),
                      title = 'Average December Binary Radiation',
                      path = working_directory + '\\graphs\\' + 'dec_avg_binary.html'
                      )

    #January
    html_scatter_plot(jan_mean_binary,
                      labels = dict(x='Time (3 Minute Intervals)',y='Binary Radiation'),
                      title = 'Average January Binary Radiation',
                      path = working_directory + '\\graphs\\' + 'jan_avg_binary.html'
                      )

    #Opening plots
    new = 2 #Opens in new tab if possible

    nov_url = "file://" + working_directory + "\\graphs\\nov_avg_binary.html"
    dec_url = "file://" + working_directory + "\\graphs\\dec_avg_binary.html"
    jan_url = "file://" + working_directory + "\\graphs\\jan_avg_binary.html"

    webbrowser.open(nov_url, new=new)
    webbrowser.open(dec_url, new=new)
    webbrowser.open(jan_url, new=new)


from odoo import Command
from odoo.addons.test_mail_sms.tests.test_sms_management import TestSMSActionsCommon
from odoo.tests.common import HttpCase, JsonRpcException
from odoo.tools import mute_logger

class TestSmsController(HttpCase, TestSMSActionsCommon):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.sms_processing, cls.sms_sent = cls.env['sms.sms'].create([
            {
                'body': 'A test about pending state',
                'number': '10',
                'mail_message_id': cls.msg.id,
                'uuid': '8db55b6a9ec6443ca1d69af3ab500e27',
                'state': 'process',
            }, {
                'mail_message_id': cls.msg.id,
                'body': 'A test about sent state',
                'number': '20',
                'uuid': '8505e6f439d4472690c7955de9b210a4',
                'state': 'sent',
            },
        ])
        cls.notification_processing, cls.notification_pending = cls.env['mail.notification'].create([
            {
                'mail_message_id': cls.msg.id,
                'notification_type': 'sms',
                'notification_status': 'process',
                'sms_id_int': cls.sms_processing.id,
                'sms_tracker_ids': [Command.create({'sms_uuid': cls.sms_processing.uuid})],
            }, {
                'mail_message_id': cls.msg.id,
                'notification_type': 'sms',
                'notification_status': 'pending',
                'sms_id_int': cls.sms_sent.id,
                'sms_tracker_ids': [Command.create({'sms_uuid': cls.sms_sent.uuid})],
            },
        ])
        cls.sms_sent.unlink()  # as it would normally be.

    @mute_logger("odoo.addons.base.models.ir_http")
    def test_webhook_update_notification_from_processing_to_pending(self):
        self.assertTrue(self.sms_processing)
        statuses = [{'sms_status': 'sent', 'uuids': [self.sms_processing.uuid]}]
        self.assertEqual(self._make_webhook_jsonrpc_request(statuses), 'OK')
        self.assertTrue(self.sms_processing.to_delete)
        self.assertEqual(self.notification_processing.notification_status, 'pending')

    @mute_logger('odoo.addons.base.models.ir_http')
    def test_webhook_update_notification_from_pending_to_bounced(self):
        statuses = [{'sms_status': 'invalid_destination', 'uuids': [self.notification_pending.sms_tracker_ids.sms_uuid]}]
        self.assertEqual(self._make_webhook_jsonrpc_request(statuses), 'OK')
        self.assertEqual(self.notification_pending.notification_status, 'bounce')

    @mute_logger('odoo.addons.base.models.ir_http')
    def test_webhook_update_notification_from_pending_to_delivered(self):
        statuses = [{'sms_status': 'delivered', 'uuids': [self.notification_pending.sms_tracker_ids.sms_uuid]}]
        self.assertEqual(self._make_webhook_jsonrpc_request(statuses), 'OK')
        self.assertEqual(self.notification_pending.notification_status, 'sent')

    @mute_logger('odoo.addons.base.models.ir_http')
    def test_webhook_update_notification_from_pending_to_failed(self):
        statuses = [{'sms_status': 'not_delivered', 'uuids': [self.notification_pending.sms_tracker_ids.sms_uuid]}]
        self.assertEqual(self._make_webhook_jsonrpc_request(statuses), 'OK')
        self.assertEqual(self.notification_pending.notification_status, 'exception')
        self.assertEqual(self.notification_pending.failure_type, 'sms_not_delivered')

    @mute_logger('odoo.addons.base.models.ir_http')
    def test_webhook_update_notification_multiple_statuses(self):
        statuses = [
            {'sms_status': 'sent', 'uuids': [self.notification_processing.sms_tracker_ids.sms_uuid]},
            {'sms_status': 'delivered', 'uuids': [self.notification_pending.sms_tracker_ids.sms_uuid]}
        ]
        self.assertEqual(self._make_webhook_jsonrpc_request(statuses), 'OK')
        self.assertTrue(self.sms_processing.to_delete)
        self.assertEqual(self.notification_processing.notification_status, 'pending')
        self.assertEqual(self.notification_pending.notification_status, 'sent')

    @mute_logger('odoo.addons.base.models.ir_http', 'odoo.addons.sms.controllers.main', 'odoo.http')
    def test_webhook_update_raises_with_wrong_event_data(self):
        statuses = [{'sms_status': 'delivered', 'uuids': ['not a uuid']}]
        with self.assertRaises(JsonRpcException):
            self._make_webhook_jsonrpc_request(statuses)

    @mute_logger('odoo.addons.base.models.ir_http')
    def test_webhook_update_succeeds_with_non_existent_uuids(self):
        statuses = [{'sms_status': 'delivered', 'uuids': ['00000000000000000000000000000000']}]
        self.assertEqual(self._make_webhook_jsonrpc_request(statuses), 'OK')

    @mute_logger('odoo.addons.base.models.ir_http')
    def test_webhook_update_succeeds_with_unknown_status(self):
        statuses = [{'sms_status': 'something_new', 'uuids': [self.notification_pending.sms_tracker_ids.sms_uuid]}]
        self.assertEqual(self._make_webhook_jsonrpc_request(statuses), 'OK')
        self.assertEqual(self.notification_pending.notification_status, 'exception')