from __future__ import absolute_import, division, print_function, unicode_literals

from typing import List, Dict, Tuple, Iterable, Type, Any
import fidia

# Python Standard Library Imports
# from collections import OrderedDict, Mapping
from copy import deepcopy

# Other Library Imports
# import pandas as pd

import sqlalchemy as sa
from sqlalchemy.sql import and_
from sqlalchemy.orm import relationship, reconstructor, object_session
from sqlalchemy.orm.collections import attribute_mapped_collection

# FIDIA Imports
import fidia.base_classes as bases
from ..exceptions import *
from ..utilities import fidia_classname, MultiDexDict, MappingMixin
from ..database_tools import database_transaction
from fidia.sample import SampleLikeMixin
import fidia.traits as traits
import fidia.column as fidia_column
# Other modules within this package
# from fidia.base_classes import BaseArchive

# Set up logging
import fidia.slogging as slogging
log = slogging.getLogger(__name__)
log.setLevel(slogging.WARNING)
log.enable_console_logging()

__all__ = ['Archive', 'KnownArchives', 'ArchiveDefinition']

class Archive(SampleLikeMixin, MappingMixin, bases.Archive, bases.Sample, bases.SQLAlchemyBase, bases.PersistenceBase):
    # noinspection PyUnresolvedReferences
    """An archive of data in FIDIA.

        Instances of `.Archive` class are created by calling the constructor for an
        `.ArchiveDefinition`, which defines the objects, data, and schema of the
        Archive. `.Archive` and it's sub-classes are generic across all specific
        Archives in the system.

        An `.ArchiveDefinition` can define Traits and TraitCollections, which are
        checked and registered when the corresponding archive is created. As part of
        the registration, each TraitMapping is validated. This validation checks
        each Trait's slots have been correctly filled (e.g. with another trait or a
        column of a particular type).

        An `.Archive` also behaves like a `.Sample` in that its objects can be
        looked up looked up by subscripting. So these two are equivalent:

        >>> ea = fidia.archive.example_archive.ExampleArchive(basepath=test_data_dir)  # type: fidia.Archive
        >>> sample = fidia.Sample.new_from_archive(ea)
        >>> mass = sample['Gal1'].dmu['StellarMasses'].table['StellarMasses'].stellar_mass

        and

        >>> ea = fidia.ExampleArchive(basepath=test_data_dir)
        >>> mass = ea['Gal1'].dmu['StellarMasses'].table['StellarMasses'].stellar_mass

        """

    # Set up how Archive objects will appear in the MappingDB
    __tablename__ = "archives"
    _db_id = sa.Column(sa.Integer, sa.Sequence('archive_seq'), primary_key=True)
    _db_archive_class = sa.Column(sa.String)
    _db_archive_id = sa.Column(sa.String)
    _db_calling_arguments = sa.Column(sa.PickleType)  # type: Dict[str, Any]
    # _db_contents = sa.Column(sa.PickleType)
    __mapper_args__ = {
        'polymorphic_on': '_db_archive_class',
        'polymorphic_identity': 'Archive'}

    _mappings = relationship('TraitMapping',
                             cascade="all, delete, delete-orphan"
                             )  # type: List[traits.TraitMapping]
    columns = relationship('FIDIAColumn',
                           collection_class=attribute_mapped_collection('id'),
                           cascade="all, delete, delete-orphan",
                           back_populates="_archive"
                           )  # type: Dict[str, fidia_column.FIDIAColumn]

    def __init__(self, **kwargs):
        """Pass through initializer. Initialization is handled by `ArchiveDefinition.__new__()`

        Warnings:

            This should be empty, or nearly so. It will be called when an
            Archive is reconstructed from the database (which is non-standard
            behavior for SQLAlchemy). See `Archive.__db_init__`

        """
        self._local_trait_mappings = None
        super(Archive, self).__init__()

    @reconstructor
    def __db_init__(self):
        """Initializer called when the object is reconstructed from the database."""
        super(Archive, self).__db_init__()
        # Since this archive is being recovered from the database, it must have
        # requested persistence.
        # self._db_session = Session()
        self._local_trait_mappings = None

        # Call initializers of subclasses so they can reset attributes stored in _db_calling_args
        self.__init__(**self._db_calling_arguments)

    def register_mapping(self, mapping):
        # type: (traits.TraitMapping) -> None
        """Register a new TraitMapping to this Archive."""
        self._register_mapping_locally(mapping)
        self._mappings.append(mapping)
        self._update_trait_pointers()

    def _register_mapping_locally(self, mapping):
        """Add a TraitMapping to the `_local_trait_mappings`."""
        if isinstance(mapping, traits.TraitMapping):
            mapping.validate()
            key = mapping.mapping_key
            log.debug("Registering mapping for key %s", key)
            # Check if key already exists in this database
            if key in self._local_trait_mappings:
                raise FIDIAException("Attempt to add/change an existing mapping")
            self._local_trait_mappings[key] = mapping
            # @TODO: Also link up superclasses of the provided Trait to the FIDIA level.
        else:
            raise ValueError("TraitManager can only register a TraitMapping, got %s"
                             % mapping)

    @property
    def contents(self):
        # type: () -> List[str]
        from ..astro_object import AstronomicalObject

        # Get a valid database session:
        #
        #   I'm not sure if the object_session is required, but it guarantees
        #   that we are working with the session that this archive belongs to.
        #   In theory, fidia.mappingdb_session should be the only session present.
        session = object_session(self)
        if session is None:
            session = fidia.mappingdb_session

        query = session.query(AstronomicalObject._identifier)

        query_results = query.filter_by(_db_archive_id=self._db_archive_id).all()
        # Results will contain a list of tuples, so we must get the first column out so we have a simple list.

        contents = [i[0] for i in query_results]  # type: List[str]
        return contents

    @contents.setter
    def contents(self, value):
        # type: (Iterable) -> None
        """Data Objects contained in this archive.

        Warnings
        --------

        The order of these objects is not preserved currently, because of how
        the data are stored in the persistence database. This may be valuable in
        future. In the short term, efforts have been made to make sure
        everything is checked and ensured to be done in the order of the
        contents for each instance, regardless of the original ordering.

        """
        from ..astro_object import AstronomicalObject

        # Get a valid database session:
        #
        #   I'm not sure if the object_session is required, but it guarantees
        #   that we are working with the session that this archive belongs to.
        #   In theory, fidia.mappingdb_session should be the only session present.
        session = object_session(self)
        if session is None:
            session = fidia.mappingdb_session

        # Work out what's changed
        new_contents = set(value)
        existing_contents = set(self.contents)
        to_add = new_contents.difference(existing_contents)
        to_remove = existing_contents.difference(new_contents)

        # Make those changes to the underlying Objects table in the database
        object_table = AstronomicalObject.__table__
        if len(to_add) > 0:
            session.execute(object_table.insert(),
                            [{"_identifier": i, "_db_archive_id": self._db_archive_id} for i in to_add])
        if len(to_remove) > 0:
            session.execute(object_table.delete().where(and_(object_table.c._db_archive_id == self._db_archive_id,
                                                             object_table.c._identifier in to_remove)))

    @property
    def archive_id(self):
        return self._db_archive_id

    @property
    def trait_mappings(self):
        # type: () -> Dict[Tuple[str, str], fidia.traits.TraitMapping]
        if self._local_trait_mappings is None:
            # Have not been initialized

            # Confirm that the database has loaded its data, and if not, skip initialization.
            if len(self._mappings) == 0:
                return dict()

            # Otherwise, initialize the trait_mappings from the mappings stored int he database.
            self._local_trait_mappings = MultiDexDict(2)  # type: Dict[Tuple[str, str], fidia.traits.TraitMapping]
            for mapping in self._mappings:
                self._register_mapping_locally(mapping)
            self._update_trait_pointers()
        return self._local_trait_mappings

    def get_archive_id(self, archive, id):
        # Part of the "sample-like interface
        if archive is not self:
            raise FIDIAException("Object in Archive cannot get id's for other archives.")
        else:
            return id

    def archive_for_column(self, column_id):
        # type: (str) -> fidia.Archive
        """The `.Archive` instance that that has the column id given.

        This is part of the sample-like interface for Archives.

        See Also
        --------

        `Sample.archive_for_column`

        """

        # NOTE: changes to the logic here may also need to be made in `Sample.archive_for_column`

        column_id = fidia_column.ColumnID.as_column_id(column_id)
        log.debug("Column requested: %s", column_id)
        column_type = column_id.type  # Cache locally to avoid recalculating.
        if column_type != 'full':
            # This column is not fully defined in the FIDIA sense. Either:
            #    (1) there was an error or problem in associating the column with
            #        this archive--check the execution of `replace_aliases_trait_mappings`
            #        and `expand_column_ids_in_trait_mappings` in `ArchiveDefinition.__new__`
            #    (2) the column id string does not conform to the FIDIA standard, presumably
            #        because the data access layer recognises a special column id. In this
            #        we assume that the column is associated with this Archive (what else
            #        can we do?).
            if column_type == 'non-conformant':
                # Case (2) above.
                return self
            else:
                # Case (1) above.
                raise FIDIAException("Column %s does not seem to have been correctly associated with any archive" %
                                     column_id)
        if column_id.archive_id != self.archive_id:
            log.error("Archive ID mismatch for column %s. This archive: %s, column: %s",
                      column_id, self.archive_id, column_id.archive_id)
            raise FIDIAException("Object in Archive cannot get columns from other archives.")
        return self

    def find_column(self, column_id):
        # Part of the "sample-like interface
        column_id = fidia.column.ColumnID.as_column_id(column_id)
        return self.columns[column_id]

    def validate(self, raise_exception=False):

        self._validate_mapping_column_ids(raise_exception=raise_exception)
        self._validate_all_columns_mapped(raise_exception=raise_exception)

    def _validate_mapping_column_ids(self, raise_exception=False):

        # @TODO: This is draft code and not well tested.
        # See also SubTraitMapping.check_columns and TraitMapping.check_columns

        missing_columns = []
        for mapping in self._mappings:
            missing_columns.extend(mapping.check_columns(self.columns))

        if raise_exception and len(missing_columns) > 0:
            raise ValidationError("Trait Mappings of this archive reference Columns not defined in the Archive.")
        else:
            return missing_columns

    def _validate_all_columns_mapped(self, raise_exception=False):

        # @TODO: This is draft code and not well tested.

        mapped_columns = set()
        for mapping in self._mappings:
            mapped_columns.update(mapping.referenced_column_ids)

        unmapped_columns = set(self.columns) - mapped_columns

        if raise_exception and len(unmapped_columns) > 0:
            raise ValidationError("Trait Mappings of this archive reference Columns not defined in the Archive.")
        elif len(unmapped_columns) > 0:
            return unmapped_columns
        else:
            return

    def __getattr__(self, item):
        """Backup get-attr that will handle cases like a freshly loaded archive."""
        if not item.startswith("_") and self._local_trait_mappings is None and len(self._mappings) > 0:
            self.trait_mappings
            return getattr(self, item)
        else:
            raise AttributeError("Unknown attribute %s" % item)

    def __getitem__(self, key):
        # type: (str) -> AstronomicalObject
        """Make archives able to retrieve their astro-objects in the same manner as samples."""
        # Part of the "sample-like interface

        from ..astro_object import AstronomicalObject

        if key in self.contents:
            return AstronomicalObject(self, identifier=key)
        else:
            raise NotInSample("Archive '%s' does not contain object '%s'" % (self, key))

    def __iter__(self):
        """Iterate over the objects in the sample.

        Pat of the Mapping interface (collections.abc.Mapping).

        NOTE: This could be better implemented by integrating more carefully
        with the code at `self.contents`

        """

        for i in self.contents:
            yield i

    def __len__(self):
        """Number of objects in the Archive.

        Pat of the Mapping interface (collections.abc.Mapping).

        NOTE: This could be better implemented by integrating more carefully
        with the code at `self.contents`

        """

        return len(self.contents)

    def __repr__(self):
        return "FIDIAArchive:" + self.archive_id

    def __str__(self):
        return "FIDIA Archive \"{}\"".format(self.archive_id)

    def _repr_pretty_(self, p, cycle):
        # p.text(self.__str__())
        if cycle:
            p.text(self.__str__())
        else:
            p.text("FIDIA Archive \"{}\"".format(str(self.archive_id)))
            self._sub_trait_repr_pretty(p, cycle)

class BasePathArchive(Archive):

    __mapper_args__ = {'polymorphic_identity': 'BasePathArchive'}

    def __init__(self, **kwargs):
        """Initializer.

        Note: Normally, this initialiser would not be called when reconstructing
        form the database, but for Archives, it is. See `Archive.__db_init__`.

        """

        self.basepath = kwargs['basepath']
        super(BasePathArchive, self).__init__(**kwargs)

class DatabaseArchive(Archive):

    __mapper_args__ = {'polymorphic_identity': 'DatabaseArchive'}

    def __init__(self, **kwargs):
        """Initializer.

        Note: Normally, this initialiser would not be called when reconstructing
        form the database, but for Archives, it is. See `Archive.__db_init__`.

        """

        self.database_url = kwargs['database_url']
        super(DatabaseArchive, self).__init__(**kwargs)

def replace_aliases_trait_mappings(mappings, alias_mappings):
    for mapping in mappings:
        if isinstance(mapping, fidia.traits.TraitPropertyMapping):
            if mapping.id in alias_mappings:
                log.debug("Replacing alias %s with actual ID %s", mapping.id, alias_mappings[mapping.id])
                mapping.id = alias_mappings[mapping.id]
            else:
                continue
        else:
            log.debug("Recursing on mapping %s", mapping)
            replace_aliases_trait_mappings(mapping, alias_mappings)

def expand_column_ids_in_trait_mappings(mappings, archive_columns):
    # type: (List[Any], Dict[str, fidia_column.FIDIAColumn]) -> None
    short_to_long = None
    for mapping in mappings:
        if isinstance(mapping, fidia.traits.TraitPropertyMapping):
            mapping_column_id = fidia_column.ColumnID.as_column_id(mapping.id)
            if mapping_column_id.type == 'short':
                if short_to_long is None:
                    # Create a database of short to long IDs to make updating quick.
                    short_to_long = dict()
                    for colid in archive_columns:
                        colid = fidia_column.ColumnID.as_column_id(colid)
                        short_to_long[colid.column_type + ":" + colid.column_name] = colid
                log.debug("Replacing short ColumnID %s with full ID %s", mapping.id, short_to_long[mapping.id])
                mapping.id = short_to_long[mapping.id]
            else:
                continue
        else:
            log.debug("Recursing on mapping %s", mapping)
            expand_column_ids_in_trait_mappings(mapping, archive_columns)

class ArchiveDefinition(object):
    """A definition of the columns (data), objects, and traits (schema) making up an archive.

    This class should be subclassed to define a new Archive for use in FIDIA.
    Typically, the subclass needs to override all of the attributes.

    """

    archive_id = None
    """The ID uniquely identifying this archive (str).

    Typically, this will be
    composed of the Survey/Archive name. If individual instances of the
    archive may need to refer to different data (e.g., because it is stored
    in different directories, then the ID should contain this distinction in
    the form of a path or similar. If the data to be referred to is always
    the same (more typical) then the ID should not contain the path.

    """

    archive_type = Archive  # type: Type[Archive]
    """The class of the `.Archive` to be constructed.

    `.BasePathArchive` is the most common example, which provides a base path
    abstraction to remove details of the particular local path from the rest of
    the definition of the archive.

    """
    writable = False

    contents = []  # type: Iterable
    """An iterable containing the names of the objects to be included in this Archive.

    May be instance specific (but only if the `.archive_id` is also
    instance specific).

    """

    trait_mappings = []  # type: List[traits.TraitMapping]
    """List of TraitMapping objects defining the schemas of the data in this archive."""

    column_definitions = fidia_column.ColumnDefinitionList()  # type: Dict[str, fidia_column.ColumnDefinition]
    """List of definitions of the columns of data to be included in this archive.

    When the `.ArchiveDefinition` factory creates an instances of
    an `.Archive`, these definitions will be interpreted into actual
    references to columns of data.

    """

    is_persisted = True
    """Does FIDIA write Archive instances from this definition into the MappingDB.

    Typically only set to False for testing.

    """

    def __init__(self, **kwargs):
        # __init__ of superclasses not called.
        pass

    # noinspection PyProtectedMember
    def __new__(cls, **kwargs):
        # type: (Any) -> Archive
        from fidia import known_archives

        definition = object.__new__(cls)
        definition.__init__(**kwargs)

        # Allow an archive not to (individually) be persisted in the database
        is_persisted = kwargs.pop("persist", True) and definition.is_persisted

        # @TODO: Validate definition

        if is_persisted:
            # Check if archive already exists:
            try:
                return known_archives.by_id[definition.archive_id]
            except KeyError:
                pass

        # Archive doesn't exist, so it must be created
        archive = definition.archive_type.__new__(definition.archive_type)  # type: Archive

        # I n i t i a l i s e   t h e   A r  c h i v e
        archive.__init__(**kwargs)

        # We wrap the rest of the initialisation in a database transaction, so
        # if the archive cannot be initialised, it will not appear in the
        # database.
        with database_transaction(fidia.mappingdb_session):

            # Basics
            archive._db_archive_id = definition.archive_id
            archive.writeable = definition.writable
            archive.contents = definition.contents
            archive._db_calling_arguments = kwargs

            # TraitMappings

            #     Note: To ensure that this instance of the archive has local copies
            #     of all of the Trait Mappings and Column definitions, we make
            #     copies of the originals. This is necessary so that e.g. if they
            #     are defined on a class instead of an instance, the copies
            #     belonging to an instance are unique. Without this, SQLAlchemy will
            #     complain that individual TraitMappings are owned by multiple
            #     archives.

            archive._local_trait_mappings = MultiDexDict(2)  # type: Dict[Tuple[str, str], traits.TraitMapping]
            archive._mappings = deepcopy(definition.trait_mappings)
            for mapping in archive._mappings:
                archive._register_mapping_locally(mapping)
            archive._update_trait_pointers()

            archive._db_archive_class = fidia_classname(archive)

            # Columns
            column_definitions = deepcopy(definition.column_definitions)  # type: List[Tuple[str, fidia_column.ColumnDefinition]]

            # Associate column instances with this archive instance
            alias_mappings = dict()
            for alias, column in column_definitions:
                log.debug("Associating column %s with archive %s", column, archive)
                instance_column = column.associate(archive)
                archive.columns[instance_column.id] = instance_column
                alias_mappings[alias] = instance_column.id

            # Update any columns that have been referred to by an alias:
            replace_aliases_trait_mappings(archive._mappings, alias_mappings)

            # Update short column ids in mappings to point to local columns where possible
            expand_column_ids_in_trait_mappings(archive._mappings, archive.columns)

            # self._db_session.add(self.trait_manager)
            if is_persisted:
                fidia.mappingdb_session.add(archive)

        return archive

class KnownArchives(object):

    _instance = None

    @property
    def _query(self):
        # type: () -> sa.orm.query.Query
        return fidia.mappingdb_session.query(Archive)

    # The following __new__ function implements a Singleton.
    def __new__(cls, *args, **kwargs):
        if KnownArchives._instance is None:
            instance = object.__new__(cls)

            KnownArchives._instance = instance
        return KnownArchives._instance

    @property
    def all(self):
        # type: () -> List[Archive]
        return self._query.order_by('_db_archive_id').all()

    def remove_archive(self, archive_id):
        archive = self.by_id[archive_id]
        log.info("Deleting Archive \"%s\" from the persistence database", str(archive))

        fidia.mappingdb_session.delete(archive)

    class by_id(object):
        def __getitem__(self, item):
            # type: (str) -> Archive
            log.debug("Retrieving archive with id \"%s\"...", item)
            log.debug("Query object: %s", KnownArchives()._query)
            try:
                archive = KnownArchives()._query.filter_by(_db_archive_id=item).one()
            except:
                log.warn("Request for unknown archive %s.", item)
                raise KeyError("No archive with id '%s'" % item)
            else:
                log.debug("...archive %s found.", item)
                return archive
    by_id = by_id()


import math
import numpy as np
from scipy.special import erf
from scipy import stats
norm = stats.norm

class BSOPM_Class:

  def disc_function(self, FV, r, T):
    PV = FV * np.exp(-r*T)
    return PV

  def bs_d1_d2(self,St,r,t,K,call,sig):
    d1 = np.log(St/K)
    d1 += ( sig*sig/2 + r)*t
    with np.errstate(divide='ignore',invalid='ignore'):
        d1/=sig * t**0.5
    d2=d1-sig * t**0.5
    return d1,d2

  def cdf_approx(self,dn,call):
    if call:
      Ndn = (0.50 * (1.0 + erf(dn / math.sqrt(2.0))))
    else:
      Ndn = (0.50 * (1.0 + erf(-dn / math.sqrt(2.0))))
    return Ndn

  def bs_delta(self,d1,d2,call):
    Nd1 = self.cdf_approx(dn=d1,call=call)
    Nd2 = self.cdf_approx(dn=d2,call=call)
    return Nd1,Nd2

  def bs_gamma(self,d1,St,sig,t):
    gamma = norm.pdf(d1)
    with np.errstate(divide='ignore',invalid='ignore'):
        gamma /= (St*sig*np.sqrt(t))
    return gamma

  def bs_price(self,St,r,t,K,call,Nd1,Nd2,T):
    pvk = self.disc_function(K,r, T-t)
    if call:
      price = St*Nd1-pvk*Nd2
    else:
      price = pvk * Nd2 - St * Nd1
    if (abs(St-pvk)<=0.0000000000001)and(T-t<=0.0000000000001):
      price= 0 #expires at-the-money aka worthless
    return price

  def opt_payoff(self, ST, K, call=True):
    if call == True:
      payoff=np.maximum(ST-K,0)
    else:
      payoff=np.maximum(K-ST,0)
    return payoff

  def __init__(self,S0,r,sigma,t,T,K,call=True):
    self.S0 = S0
    self.r = r
    self.sigma = sigma
    self.T  = T
    self.K = K
    self.call = call
    self.t = t

    self.d1,self.d2=self.bs_d1_d2(St=self.S0,r=self.r,t=self.T-self.t,K=self.K,call=self.call,sig=self.sigma)
    self.Nd1,self.Nd2=self.bs_delta(d1=self.d1,d2=self.d2,call=self.call)
    self.delta=self.Nd1
    self.gammas = self.bs_gamma(d1=self.d1,St=self.S0,sig=self.sigma,t=self.T-self.t)
    self.price = self.bs_price(St=self.S0,r=self.r,t=self.t,K=self.K,call=self.call,Nd1=self.Nd1,Nd2=self.Nd2,T=self.T)
    self.payoff = self.opt_payoff(self.S0,self.K,self.call)


import heapq

import config
import logbot

log = logbot.getlogger("ASTAR")

class PathNode(object):
    def __init__(self, coords, cost=1):
        self.coords = coords
        self.cost = cost
        self.g = 0
        self.h = 0
        self.f = 0
        self.step = 0
        self._parent = None
        self.hash = hash(self.coords)

    def __str__(self):
        return "%s:%s:g%s:h%s:f%s" % \
            (str(self.coords), self.cost, self.g, self.h, self.f)

    def __repr__(self):
        return self.__str__()

    def __lt__(self, other):
        return self.f < other.f

    def __eq__(self, other):
        return self.hash == other.__hash__()

    def __hash__(self):
        return self.hash

    def __getitem__(self, i):
        return self.coords[i]

    @property
    def parent(self):
        return self._parent

    @parent.setter
    def parent(self, p):
        self._parent = p
        self.step = p.step + 1

    def set_score(self, g, h):
        self.g = g
        self.h = h
        self.f = g + h

class Path(object):
    def __init__(self, goal=None):
        self.goal = goal
        self.nodes = []
        self.reconstruct_path(self.goal)
        self.step_index = len(self.nodes)

    def __str__(self):
        return "Path nodes %s" % [str(n) for n in self.nodes]

    def reconstruct_path(self, current):
        self.nodes.append(current)
        while current.parent is not None:
            self.nodes.append(current.parent)
            current = current.parent

    def __iter__(self):
        self.iter_index = len(self.nodes)
        return self

    def next(self):
        self.iter_index -= 1
        if self.iter_index < 0:
            raise StopIteration()
        return self.nodes[self.iter_index]

    def has_next(self):
        return self.step_index > 0

    def next_step(self):
        self.step_index -= 1
        if self.step_index < 0:
            raise Exception("Path consumed")
        return self.nodes[self.step_index]

class AStar(object):
    def __init__(self, navgrid, start, goal, max_cost=config.PATHFIND_LIMIT):
        self.navgrid = navgrid
        self.succesors = self.navgrid.graph.get_succ
        self.get_node = self.navgrid.graph.get_node
        self.start_node = PathNode(start)
        self.goal_node = PathNode(goal)
        self.max_cost = max_cost
        self.path = None
        self.closed_set = set()
        self.open_heap = [self.start_node]
        self.open_set = set([self.start_node])
        self.start_node.set_score(
            0, self.heuristic_cost_estimate(self.start_node, self.goal_node))

    def reconstruct_path(self, current):
        nodes = []
        nodes.append(current)
        while current.parent is not None:
            nodes.append(current.parent)
            current = current.parent
        nodes.reverse()
        return nodes

    def get_edge_cost(self, node_from, node_to):
        return self.navgrid.graph.get_edge(node_from.coords, node_to.coords)

    def neighbours(self, start):
        for node, cost in self.succesors(start.coords):
            if node not in self.closed_set:
                yield PathNode(node, cost=cost)

    def heuristic_cost_estimate(self, start, goal):
        h_diagonal = min(abs(start[0] - goal[0]), abs(start[2] - goal[2]))
        h_straight = (abs(start[0] - goal[0]) + abs(start[2] - goal[2]))
        h = config.COST_DIAGONAL * h_diagonal + \
            config.COST_DIRECT * (h_straight - 2 * h_diagonal)
        return h

    def next(self):
        if not self.open_set:
            log.err("Did not find path between %s and %s" % (self.start_node.coords, self.goal_node.coords))
            raise StopIteration()
        x = heapq.heappop(self.open_heap)
        if x == self.goal_node:
            self.path = Path(goal=x)
            raise StopIteration()
        self.open_set.remove(x)
        self.closed_set.add(x)
        for y in self.neighbours(x):
            if y in self.closed_set:
                continue
            tentative_g_core = x.g + self.get_edge_cost(x, y)
            if y not in self.open_set or tentative_g_core < y.g:
                y.set_score(tentative_g_core,
                            self.heuristic_cost_estimate(y, self.goal_node))
                y.parent = x
                if y not in self.open_set:
                    heapq.heappush(self.open_heap, y)
                    self.open_set.add(y)
                if y.step > self.max_cost:
                    log.err("Finding path over limit between %s and %s" % (self.start_node.coords, self.goal_node.coords))
                    raise StopIteration()


from threading import Thread

from . import tm_tc_internal_handler
import time

class TMTCRedeployHandler(Thread):
    """
    This thread is started by external tm-tc subscriber to handle re-deploying of
    TMTC service (by creating internal kicker and setting/resetting internal oper-data).
    """

    def __init__(self, username, nodes, operation, log):
        Thread.__init__(self)
        self.username = username
        self.nodes = nodes
        self.operation = operation
        self.log = log

    def run(self):
        username = self.username
        operation = self.operation
        nodes = self.nodes
        self.log.info("TMTCRedeployHandler: operation {} on nodes {}".
                      format(operation, nodes))
        if operation == "created" or operation == "updated":
            # New nodes
            if len(nodes) > 0:
                # Toggle oper-data for external plan to run
                for node in nodes:
                    tm_tc_internal_handler.reset_oper_data(node[0], node[1], self.log)
                time.sleep(2)
                for node in nodes:
                    tm_tc_internal_handler.set_oper_data(node[0], node[1], None, self.log)
        elif operation == "deleted":
            # Deleted nodes
            for node in nodes:
                # Reset oper-data for external plan to run
                tm_tc_internal_handler.reset_oper_data(node[0], node[1], self.log)


import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression, RidgeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.metrics import accuracy_score
import pickle

# Step 1: Load the dataset
df = pd.read_csv('Pose.csv')

# Step 2: Split the dataset into features (X) and target (y)
X = df.drop('class', axis=1)
y = df['class']

# Step 3: Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1234)

# Step 4: Define the pipelines for different models
pipelines = {
    'lr': make_pipeline(StandardScaler(), LogisticRegression()),
    'rc': make_pipeline(StandardScaler(), RidgeClassifier()),
    'rf': make_pipeline(StandardScaler(), RandomForestClassifier()),
    'gb': make_pipeline(StandardScaler(), GradientBoostingClassifier()),
}

# Step 5: Train the models and store them in a dictionary
fit_models = {}
for algo, pipeline in pipelines.items():
    model = pipeline.fit(X_train, y_train)
    fit_models[algo] = model

# Step 6: Print accuracy scores for each model
for algo, model in fit_models.items():
    yhat = model.predict(X_test)
    print(algo, accuracy_score(y_test, yhat))

# Step 7: Save the trained Random Forest model using pickle
with open('body_language.pkl', 'wb') as f:
    pickle.dump(fit_models['rf'], f)


import torch
import torch.nn as nn
import torch.nn.functional as F

from itertools import chain

class GaussianActorCriticNet(nn.Module):

    def __init__(self, state_size, action_size, shared_layers, actor_layers, critic_layers, std_init=0):
        super(GaussianActorCriticNet, self).__init__()

        self.shared_network = GaussianActorCriticNet._create_shared_network(state_size, shared_layers)
        shared_output_size = state_size if len(shared_layers) == 0 else shared_layers[-1]

        self.actor_network = GaussianActorCriticNet._create_actor_network(shared_output_size, actor_layers, action_size)
        self.critic_network = GaussianActorCriticNet._create_critic_network(shared_output_size, critic_layers)

        self.std = nn.Parameter(torch.ones(action_size) * std_init)

    @staticmethod
    def _create_shared_network(state_size, shared_layers):
        iterator = chain([state_size], shared_layers)

        last_size = None
        args = []
        for layer_size in iterator:
            if last_size is not None:
                args.append(nn.Linear(last_size, layer_size))
                args.append(nn.ReLU())
            last_size = layer_size

        return nn.Sequential(*args)

    @staticmethod
    def _create_actor_network(input_size, actor_layers, action_size):
        iterator = chain([input_size], actor_layers, [action_size])

        last_size = None
        args = []
        for layer_size in iterator:
            if last_size is not None:
                args.append(nn.Linear(last_size, layer_size))
                args.append(nn.ReLU())
            last_size = layer_size

        # Replace last ReLU layer with tanh
        del args[-1]
        args.append(nn.Tanh())

        return nn.Sequential(*args)

    @staticmethod
    def _create_critic_network(input_size, critic_layers):
        iterator = chain([input_size], critic_layers, [1])

        last_size = None
        args = []
        for layer_size in iterator:
            if last_size is not None:
                args.append(nn.Linear(last_size, layer_size))
                args.append(nn.ReLU())
            last_size = layer_size

        # Remove last ReLU layer
        del args[-1]

        return nn.Sequential(*args)

    def forward(self, states, action=None, std_scale=1.0):
        shared_output = self.shared_network(states)
        mu = self.actor_network(shared_output)
        value = self.critic_network(shared_output)

        distribution = torch.distributions.Normal(mu, std_scale * F.softplus(self.std))
        if action is None:
            action = distribution.sample() if std_scale > 0 else mu

        log_prob = distribution.log_prob(action)
        entropy = distribution.entropy().sum(-1).unsqueeze(-1)

        return {
            'v': value.squeeze(1),
            'action': action,
            'log_prob': log_prob,
            'entropy': entropy
        }


import torch, vtk
import numpy as np
import h5py
from vtk_utils import *
import os
from scipy.stats import zscore

path = 'Twin_Transformers'
folder_name = '/media/shawey/SSD8T/GyraSulci_Motor/'+path+'/figs'
weis = os.listdir(folder_name)

filename = "/media/shawey/SSD8T/GyraSulci_Motor/H5_vtk/100408.h5"
f1 = h5py.File(filename,'r+')

roi = f1['roi']
len(roi[roi[:] == True])

reco_subs = []
for wei in weis:
    print(wei)
    sub_id = wei.split('_')[0]
    if sub_id in reco_subs:
        continue
    reco_subs.append(sub_id)
    ws = [sub_id + '_gyri_weight.pkl',sub_id + '_sulci_weight.pkl' ]
    #write this signal
    for w in ws:
        part = w.split('_')[1]
        scalars = []
        labels = []
        #w1 = torch.load(folder_name+"/" + w).cpu().numpy()  #122317_gyri_weight.pkl
        #w1 = zscore(w1)      #!!! WITH OR WITHOUT zscore
        temp = torch.load(folder_name+"/" + w,torch.device("cpu")).t()
        w1 = zscore(temp)[:59412,:]
        w1 = np.transpose(w1)
        for i in range(100):
            signal = np.zeros(64984)
            signal[roi[:] == True] = w1[i][:59412]

            #write this signal
            scalars.append(signal)
            labels.append("label{}".format(i))

        rewrite_scalars("/media/shawey/SSD8T/GyraSulci_Motor/InflatedSurface/InflatedSurface.vtk", \
                    "/media/shawey/SSD8T/GyraSulci_Motor/"+path+"/generated_vtks/"+\
                                sub_id+"_"+part+"_zscore.vtk",new_scalars=scalars,new_scalar_names=labels)
    #break


import errno
import os
import re
import threading
import unittest

try:
    from unittest import mock
except ImportError:
    import mock

import ptracer

eperm_mock = mock.Mock(
    side_effect=OSError(errno.EPERM, 'Operation not permitted'))

class TestPtracer(unittest.TestCase):
    @mock.patch('ptracer.ptrace.attach_and_wait', eperm_mock)
    def test_ptracer__fail_01(self):
        with self.assertRaisesRegexp(ptracer.PtracerError,
                                     'Operation not permitted'):
            with ptracer.context(lambda s: None):
                f = open('/dev/zero', 'r')
                f.close()

    @mock.patch('ptracer.ptrace.syscall', eperm_mock)
    def test_ptracer__fail_02(self):
        with self.assertRaisesRegexp(ptracer.PtracerError,
                                     'Operation not permitted'):
            with ptracer.context(lambda s: None):
                f = open('/dev/zero', 'r')
                f.close()

    @mock.patch('ptracer.ptrace.syscall_exit', eperm_mock)
    def test_ptracer__fail_03(self):
        with self.assertRaisesRegexp(ptracer.PtracerError,
                                     'Operation not permitted'):
            with ptracer.context(lambda s: None):
                f = open('/dev/zero', 'r')
                f.close()

    @mock.patch('ptracer.ptrace.ptrace.getsiginfo', eperm_mock)
    def test_ptracer__fail_04(self):
        with self.assertRaisesRegexp(ptracer.PtracerError,
                                     'Operation not permitted'):
            with ptracer.context(lambda s: None):
                f = open('/dev/zero', 'r')
                f.close()

    def test_ptracer_basic(self):
        syscalls = []

        with ptracer.context(syscalls.append):
            f = open('/dev/zero', 'r')
            f.close()

        self.assertGreater(len(syscalls), 0)

    def test_ptracer_filter_01(self):
        syscalls = []

        def _trace(pattern):
            syscalls[:] = []

            with ptracer.context(syscalls.append, filter=pattern):
                f = open('/dev/null', 'w')
                f.close()
                f = open('/dev/zero', 'r')
                f.close()
                try:
                    open('/dev/nonexistent', 'r')
                except IOError:
                    pass

        _trace([
            ptracer.SysCallPattern(name=re.compile('op.*'))
        ])

        self.assertEqual(len(syscalls), 3)

        _trace([
            ptracer.SysCallPattern(
                name=re.compile('openat'),
                args=[
                    None,
                    b'/dev/null'
                ]
            )
        ])

        self.assertEqual(len(syscalls), 1)

        _trace([
            ptracer.SysCallPattern(
                name=re.compile('openat'),
                args=[
                    None,
                    b'/dev/null'
                ]
            )
        ])

        self.assertEqual(len(syscalls), 1)

        _trace([
            ptracer.SysCallPattern(
                name=re.compile('openat'),
                args=[
                    None,
                    re.compile(b'.*/null'),
                ]
            )
        ])

        self.assertEqual(len(syscalls), 1)

        _trace([
            ptracer.SysCallPattern(
                name=re.compile('openat'),
                args=[
                    None,
                    None,
                    lambda arg: arg.value & os.O_WRONLY
                ]
            )
        ])

        self.assertEqual(len(syscalls), 1)

        _trace([
            ptracer.SysCallPattern(
                name=re.compile('op.*'),
                result=lambda res: res.value < 0
            )
        ])

        self.assertEqual(len(syscalls), 1)

    def test_ptracer_threading(self):
        syscalls = []

        def _thread():
            f = open('/dev/zero', 'r')
            f.close()

        flt = ptracer.SysCallPattern(
            name='openat',
            args=[
                None,
                b'/dev/zero'
            ]
        )

        with ptracer.context(syscalls.append, filter=flt):
            thread = threading.Thread(target=_thread)
            thread.start()
            thread.join()

        self.assertEqual(len(syscalls), 1)


import sqlalchemy
from fastapi import Depends
from sqlalchemy.orm import Session
from src.data_layer.bot_io import OrderInput
from src.data_layer.db_connector import get_db
from src.models.order import OrderModel
from fastapi import APIRouter
router = APIRouter()

@router.post("/order")
def get_order_by_hospital_id(hospital_id: str, db: Session = Depends(get_db)):
    """
    Create order by hospital ID, items and emergency
    """
    # Create OrderModel per item
    order_item_list = []
    for item in order.items:
        order = {"user_id": order.user_id,
                 "to_hospital_id": order.to_hospital_id,
                 "item_id": item.id,
                 "emergency": order.emergency}
        order_item_list.extend([OrderModel(**order) for i in range(item.quantity)])

    for order_model in order_item_list:
        # Commit to DB
        db.add(order_model)
        db.commit()
        db.refresh(order_model)
    return order_item_list

@router.post("/order")
def create_order(order: OrderInput, db: Session = Depends(get_db)):
    """
    Create order by hospital ID, items and emergency
    """
    # Create OrderModel per item
    order_item_list = []
    for item in order.items:
        order = {"user_id": order.user_id,
                 "to_hospital_id": order.to_hospital_id,
                 "item_id": item.id,
                 "emergency": order.emergency}
        order_item_list.extend([OrderModel(**order) for i in range(item.quantity)])

    for order_model in order_item_list:
        # Commit to DB
        db.add(order_model)
        db.commit()
        db.refresh(order_model)
    return order_item_list

@router.put("/order")
def put_one_order(order_model: OrderInput, db: Session = Depends(get_db)):
    """
    Update one order
    It reads parameters from the request field and update finds the entry and update it
    :param order_model: OrderModel class that contains requested field to update
    :param db: DB session
    :return: Updated order
    """
    try:
        # Get audio_format by ID
        order_to_put = db.query(OrderModel).filter(OrderModel.id == order_model.id).one()

        # Update model class variable for requested fields
        for var, value in vars(order_model).items():
            setattr(order_to_put, var, value) if value else None

        # Commit to DB
        db.add(order_to_put)
        db.commit()
        db.refresh(order_to_put)
        return {"id": str(order_to_put.id), "processed": order_to_put.processed, "approved": order_to_put.approved}
    except sqlalchemy.orm.exc.NoResultFound:
        raise Exception(f"{order_model.id} does not exist")


import torch
from torch.utils.data import Dataset, DataLoader, SequentialSampler, RandomSampler
from utils_MTL import (str2bool,
                       init_seed,
                       load_json_data,
                       get_pretrained_tokenizer,
                       get_pretrained_model,
                       get_optimizer_and_scheduler)
from tokenizer_correct_baselines import SPTokenizer
from dataset_MTL import MTLDataset
from model_MTL import MultiTaskLearner
from trainer_MTL import iteration, predict_detection, predict_correction, predict_beam1
import os
import re, ast
import argparse

if __name__ == '__main__':
    os.environ['TOKENIZERS_PARALLELISM'] = 'false'  # Disabling parallelism to avoid deadlocks
    torch.multiprocessing.set_start_method('spawn')  # to use CUDA with multiprocessing

    parser = argparse.ArgumentParser()

    parser.add_argument('--device', type=str,
                        default=torch.device('cuda' if torch.cuda.is_available() else 'cpu'))
    parser.add_argument('--data_path', type=str, default='/HDD/seunguk/KGECdataset/kgec_kowiki_0907')
    parser.add_argument('--model_path', type=str)
    parser.add_argument('--with_pretrained', type=str2bool, default='true')
    #parser.add_argument('--tokenizer_path', type=str, default='/home/seunguk/KGEC/0821/correct_baselines/tokenizer/')
    parser.add_argument('--vocab_size', type=int, default=30000)
    #parser.add_argument('--vocab_with', type=str, choices=['bpe', 'char'])
    parser.add_argument('--save_path', type=str)

    parser.add_argument('--seed', type=int, default=42)
    parser.add_argument('--num_workers', type=int, default=10)
    parser.add_argument('--max_tokens_per_sent', type=int, default=64)

    #parser.add_argument('--batch_size', type=int)
    parser.add_argument('--beam_size', type=int)

    print('========== Loading All Parse Arguments\n')
    args = parser.parse_args()
    init_seed(args.seed)

    print('========== Loading Tokenizer\n')
    #tokenizer = SPTokenizer(args)
    tokenizer = get_pretrained_tokenizer(args.model_path)
    pad_num = tokenizer('[PAD]', add_special_tokens=False)['input_ids'][0]

    args.vocab_size = tokenizer.vocab_size

    # get best epoch
    def only_text(text):
        text = re.sub(r'[=:\n.,]+', '', text)
        text = re.sub(r'[0-9]+', '', text)
        text = re.sub(r'[\[\]]', '', text)
        return text.strip()

    with open(args.save_path+'_result.txt', 'r') as f:
        result = f.readlines()
    result_ = [only_text(t) for t in result]
    valid_epoch_loss = result[result_.index('Valid Epoch Loss')]

    def preprocess_result(text):
        text = re.sub(r'[a-zA-Z]+', '', text)
        text = re.sub(r'[=:\n]+', '', text)
        text = text.strip()

        array = ast.literal_eval(text)
        return array
    valid_epoch_loss = preprocess_result(valid_epoch_loss)
    best_epoch = valid_epoch_loss.index(min(valid_epoch_loss))

    print(f'========== Loading Test Dataset & DataLoader\n')
    test_data = load_json_data(args.data_path+'test.json')
    test_dataset = MTLDataset(args, test_data, tokenizer)
    test_loader = DataLoader(test_dataset, batch_size=1,
                             sampler=RandomSampler(test_dataset), num_workers=args.num_workers)

    print(f'beam size: {args.beam_size}')
    #test_word_metrics, test_char_metrics = predict(args, tokenizer, best_epoch, test_dataset)
    predict_beam1(args, tokenizer, best_epoch, test_loader)


from openpyxl.styles import NamedStyle, Font, Border, Side, Alignment, PatternFill
from openpyxl.formatting.rule import ColorScaleRule

# 薄緑（主にheader用)
style_00 = NamedStyle(name="style_00",
                      font=Font(bold=True, size=10.5),
                      fill=PatternFill(patternType='solid', start_color='E6EDDD', end_color='E6EDDD'),
                      border=Border(left=Side(border_style='thin', color='000000'),
                                    right=Side(border_style='thin',color='000000'),
                                    top=Side(border_style='thin',color='000000'),
                                    bottom=Side(border_style='thin', color='000000')),
                      alignment=Alignment(horizontal='center',
                                          vertical = 'center'))

# グレー（主にindex用)
style_01 = NamedStyle(name="style_01",
                      font=Font(bold=True, size=10.5),
                      fill=PatternFill(patternType='solid', start_color='F2F2F2', end_color='F2F2F2'),
                      border=Border(left=Side(border_style='thin', color='000000'),
                                    right=Side(border_style='thin',color='000000'),
                                    top=Side(border_style='thin',color='000000'),
                                    bottom=Side(border_style='thin', color='000000')),
                      alignment=Alignment(horizontal='center',
                                          vertical = 'center'))

# 塗りつぶしなし（主にcell用)
style_02 = NamedStyle(name="style_02",
                      font=Font(bold=False, size=10.5),
                      border=Border(left=Side(border_style='thin', color='000000'),
                                    right=Side(border_style='thin',color='000000'),
                                    top=Side(border_style='thin',color='000000'),
                                    bottom=Side(border_style='thin', color='000000')),
                      alignment=Alignment(horizontal='center',
                                          vertical = 'center'))

# 淡赤（主に強調したいcell用)
style_03 = NamedStyle(name="style_03",
                      border=Border(left=Side(border_style=None),
                                    right=Side(border_style=None),
                                    top=Side(border_style=None),
                                    bottom=Side(border_style=None)),
                      font=Font(bold=True, size=10.5),
                      fill=PatternFill(patternType='solid', start_color='EEDDDC', end_color='EEDDDC'),
                      alignment=Alignment(horizontal='center',
                                          vertical = 'center'))

# 淡青（主に強調したいcell用)
style_04 = NamedStyle(name="style_04",
                      border=Border(left=Side(border_style=None),
                                    right=Side(border_style=None),
                                    top=Side(border_style=None),
                                    bottom=Side(border_style=None)),
                      font=Font(bold=True, size=10.5),
                      fill=PatternFill(patternType='solid', start_color='DEE6F0', end_color='DEE6F0'),
                      alignment=Alignment(horizontal='center',
                                          vertical = 'center'))

# 淡緑（主に強調したいcell用)
style_05 = NamedStyle(name="style_05",
                      border=Border(left=Side(border_style=None),
                                    right=Side(border_style=None),
                                    top=Side(border_style=None),
                                    bottom=Side(border_style=None)),
                      font=Font(bold=True, size=10.5),
                      fill=PatternFill(patternType='solid', start_color='E6EDDD', end_color='E6EDDD'),
                      alignment=Alignment(horizontal='center',
                                          vertical = 'center'))

# グラデーション（緑）
colorscale_00 = ColorScaleRule(start_type='min',
                               start_color='e5f5f9',
                               end_type='max',
                               end_color='2ca25f')

# グラデーション（赤）
colorscale_01 = ColorScaleRule(start_type='min',
                               start_color='fff7ec',
                               end_type='max',
                               end_color='990000')

# グラデーション（青->赤）
colorscale_02 = ColorScaleRule(start_type='num',
                               start_value=-1,
                               start_color='0571b0',
                               mid_type='num',
                               mid_value=0,
                               mid_color='f7f7f7',
                               end_type='num',
                               end_value=1,
                               end_color='ca0020')


class Solution:
    def findKthBit(self, n: int, k: int) -> str:

        s = "0"
        # print(str(int(not int(s1))))

        def getBinary(s,n):

            if n == 0:
                return s
            invertedS = [str(int(not int(bit))) for bit in s]
            reversedInvertedS = "".join(invertedS[::-1])
            newStringBit = s + "1" + reversedInvertedS

            return getBinary(newStringBit,n-1)
        Sth = getBinary(s,n)

        return Sth[k-1]


# -*- coding: utf-8 -*-

import cv2
import numpy as np
from PIL import Image
import glob
import os
from tqdm import tqdm

def color_map(N=256, normalized=False):
    def bitget(byteval, idx):
        return ((byteval & (1 << idx)) != 0)

    dtype = 'float32' if normalized else 'uint8'
    cmap = np.zeros((N, 3), dtype=dtype)
    for i in range(N):
        r = g = b = 0
        c = i
        for j in range(8):
            r = r | (bitget(c, 0) << 7-j)
            g = g | (bitget(c, 1) << 7-j)
            b = b | (bitget(c, 2) << 7-j)
            c = c >> 3

        cmap[i] = np.array([r, g, b])

    cmap = cmap/255 if normalized else cmap
    return cmap

def im2index(im,rgb2idx):
    """
    turn a 3 channel RGB image to 1 channel index image
    """
    assert len(im.shape) == 3
    height, width, ch = im.shape
    assert ch == 3
    m_lable = np.zeros((height, width, 1), dtype=np.uint8)
    for w in range(width):
        for h in range(height):
            b, g, r = im[h, w, :]
            m_lable[h, w, :] = rgb2idx[(r, g, b)]
    return np.squeeze(m_lable)

def convert(source_filename,target_filename,cmap,rgb2idx):
    """
    convert a RGB format image to P
    """
    palette=list(cmap.reshape(-1))
    cv_img_rgb=cv2.imread(source_filename)
    idx_img=im2index(cv_img_rgb,rgb2idx)
#    print(np.unique(idx_img))
    pil_img=Image.fromarray(idx_img,mode='P')
    pil_img.putpalette(palette)
    pil_img.save(target_filename)

if __name__ == '__main__':
    src_files=glob.glob('test/comp6_test_cls/*.png')
    target_dir='test/comp6_test_cls_voc'
    des_files=[os.path.join(target_dir,os.path.basename(f)) for f in src_files]

    print(src_files[0:3])
    print(des_files[0:3])

    cmap=color_map()
    rgb2idx={tuple(v):idx for idx,v in enumerate(cmap)}
    for src,des in tqdm(zip(src_files,des_files)):
        convert(src,des,cmap,rgb2idx)


from . import app
from twilio.twiml.messaging_response import MessagingResponse
from .models import Question
from flask import url_for, request, session

@app.route('/question/<question_id>')
def question(question_id):
    question = Question.query.get(question_id)
    session['question_id'] = question.id
    return sms_twiml(question)

def is_sms_request():
    return 'MessageSid' in request.values.keys()

def sms_twiml(question):
    response = MessagingResponse()
    response.message(question.content)
    #response.message(SMS_INSTRUCTIONS[question.kind])
    return str(response)

SMS_INSTRUCTIONS = {
        Question.TEXT: 'Please type your answer',
        Question.BOOLEAN: 'Please type yes or no (or y or n)',
        Question.NUMERIC: 'Please type a number between one and seven'
}


from datetime import timedelta

from feast import FeatureView, Field
from feast.types import Float64, String

import pandas as pd

from entities import properties_entity
from data_sources import properties_source

properties_fv = FeatureView(
    name="properties_fv",
    entities=[properties_entity],
    ttl=timedelta(days=36500),
    schema=[
        Field(name="area", dtype=Float64, description="Area of the property"),
        Field(name="width", dtype=Float64, description="Width of the property"),
        Field(name="length", dtype=Float64, description="Length of the property"),
        Field(name="num_bedrooms", dtype=Float64, description="Number of bedrooms in the property"),
        Field(name="num_bathrooms", dtype=Float64, description="Number of bathrooms in the property"),
        Field(name="district", dtype=String, description="The property located district name"),
        Field(name="city", dtype=String, description="The property located city name"),
        Field(name="legal_document", dtype=String, description="The legal document of the property"),
    ],
    source=properties_source,
    tags={},
    owner="phancaothng@gmail.com"
)


# -*- coding: utf-8 -*-

# those error codes shall be transformed into exceptions, where applicable

NO_ERROR = 0

# ERROR_INI_FILE_NOT_EXISTS = 1
ERROR_LR_FILE_NOT_EXISTS = 2
ERROR_SIG_FILE_NOT_EXISTS = 3
ERROR_SG_FILE_NOT_EXISTS = 4
INVALID_MEASUREMENT_ID = 5
ERROR_LOG_DIR_NOT_EXISTS = 6
USE_CASE_NOT_IMPLEMENTED = 7
PRODUCT_NOT_IMPLEMENTED = 8
DB_ERROR = 9
NC_OPEN_ERROR = 10
CAL_RANGE_HIGHER_THAN_VALID = 11
# NO_LR_VAR = 'Cannot find variable Lidar_Ratio in lr file'
NO_VALID_POINTS_FOR_CAL = 13
CANNOT_CREATE_MERGED_SIG = 14
# DIFF_VERT_RES = 15
NOISE_OF_FR_TOO_LARGE_FOR_MERGE = 16
NO_PRODUCT_OPTIONS_IN_DB = 17
DIFF_SCAN_ANGLES = 18
MISSING_EXT_SUBPROFILE = 19
ITER_BSC_NOT_CONV = 20
ERR_NOT_ENOUGH_SG_COEFFICIENTS = 21
UNKNOWN_EXCEPTION = 22
# ERR_RUNTIME_EXCEPTION = 22
ERR_INVALID_NB_OF_MC_ITERATIONS = 23
ERR_NO_MC_OPTIONS_FOR_KLETT = 24
NO_STABLE_SOLUTION_FOR_KLETT = 25
MISSING_CHANNEL_ID_IN_NCFILE = 26
NEGATIVE_CALIBRATION_VALUE = 27
WRONG_ELPP_VERSION = 28
MULTIPLE_DEPOL_NOT_YET_IMPLEMENTED = 29
CANNOT_FIND_CORRECT_CHANNEL_IDX_IN_FILE = 30
ZERO_DETECTION_LIMIT = 31
WRONG_COMMAND_LINE_PARAM = 41
DIFFERENT_CLOUD_MASK_EXISTS = 42
DIFFERENT_HEADER_EXISTS = 43
DIFFERENT_BSC_OPTIONS_IN_MEASUREMENT = 44
NO_MC_OPTIONS_IN_DB = 45
NO_BSC_CAL_OPTIONS_IN_DB = 46
NO_OVL_FILE_IN_DB = 47
COULD_NOT_FIND_CALIBR_WINDOW = 48
DIFFERENT_WL_IN_EXT_AND_BSC_FOR_LR = 49
INTEGRATION_FAILED = 50
NOT_ENOUGH_MC_SAMPLES = 51
NO_PRODUCTS_GENERATED = 52
NEG_BSC_FOR_LIDAR_CONSTANT = 53
NO_PARAMS_FOR_DEPOL_UNCERTAINTY_IN_DB = 60
NO_BSC_FOR_LIDAR_CONSTANT = 61
NO_MWL_PRODUCT_DEFINED = 62
# ===============================================
# error codes which occur only during development
# ===============================================

# Raised if the requested data are not found in data storage
DATA_NOT_IN_STORAGE = 100
# Raised on attempt to add more than one override to class registry
CLASS_REGISTRY_TOO_MAY_OVERRIDES = 101
# Raised on attempt to normalize a signal by number of laser shots several times
REPEATED_ATTEMPT_TO_NORMALZE_BY_SHOTS = 102
# Raised on attempt to correct a signal for molecular transmission several times
REPEATED_ATTEMPT_TO_CORRECT_MOL_TRANSM = 103


"""
✘ Commands Available -

• `{i}fullpromote <reply user/ username>`
 Promote User With All rights
"""

import asyncio

from telethon.errors import BadRequestError
from telethon.errors.rpcerrorlist import ChatNotModifiedError, UserIdInvalidError
from telethon.tl.functions.channels import DeleteUserHistoryRequest, EditAdminRequest
from telethon.tl.functions.channels import ExportMessageLinkRequest as ExpLink
from telethon.tl.functions.messages import SetHistoryTTLRequest
from telethon.tl.types import Chat, ChatAdminRights, InputMessagesFilterPinned

from . import *

@ultroid_cmd(
    pattern="fullpromote ?(.*)",
    admins_only=True,
)
async def prmte(ult):
    xx = await eor(ult, get_string("com_1"))
    await ult.get_chat()
    user, rank = await get_user_info(ult)
    if not rank:
        rank = "••Aᴅᴍɪɴ••"
    if not user:
        return await xx.edit("`Reply to a user to promote him with all rights!`")
    try:
        await ult.client(
            EditAdminRequest(
                ult.chat_id,
                user.id,
                ChatAdminRights(
                    add_admins=True,
                    invite_users=True,
                    change_info=True,
                    ban_users=True,
                    delete_messages=True,
                    pin_messages=True,
                    manage_call=True,
                ),
                rank,
            ),
        )
        await xx.edit(
            f"**{inline_mention(user)}** `is now an admin with full rights in` **{ult.chat.title}** `with title` **{rank}**.",
        )
    except BadRequestError:
        return await xx.edit("`I don't have the right to promote you.`")
    await asyncio.sleep(5)
    await xx.delete()


import logging

from odoo import api, fields, models, _

from odoo.exceptions import UserError, MissingError

_logger = logging.getLogger(__name__)

class ProcurementGroup(models.Model):
    _inherit = 'procurement.group'

    @api.model
    def _run_scheduler_tasks(self, use_new_cursor=False, company_id=False):
        # Check confirmed moves in MO or pickings
        self.sudo()._try_mts_moves_without_orderpoint(
            use_new_cursor=use_new_cursor, company_id=company_id
        )
        super(ProcurementGroup, self)._run_scheduler_tasks(
            use_new_cursor=use_new_cursor, company_id=company_id
        )

    @api.model
    def _try_mts_moves_without_orderpoint(
        self, use_new_cursor=False, company_id=False
    ):
        if company_id and self.env.user.company_id.id != company_id:
            # To ensure that the company_id is taken into account for
            # all the processes triggered by this method
            # i.e. If a PO is generated by the run of the procurements the
            # sequence to use is the one for the specified company not the
            # one of the user's company
            self = self.with_context(
                company_id=company_id, force_company=company_id
            )
        # Find and select only valid moves
        moves_to_reorder = self._get_mts_moves_to_reorder()
        for product_id in moves_to_reorder.mapped('product_id'):
            try:
                with self._cr.savepoint():
                    self._action_cannot_reorder_product(product_id)
            except UserError as error:
                self.env['stock.rule']._log_next_activity(
                    product_id, error.name
                )
        if use_new_cursor:
            self._cr.commit()

    @api.model
    def _get_mts_moves_to_reorder(self):
        # Search all active pickings
        picking_ids = self.env['stock.picking'].search(
            [('state', 'in', ('waiting', 'confirmed', 'assigned'))]
        )
        # Select only valid moves
        picking_res = self._filter_mts_picking_moves_to_reorder(picking_ids)

        # Search all active manufacturing orders
        production_ids = self.env['mrp.production'].search(
            [('state', 'not in', ('done', 'cancel'))]
        )
        # Select only valid moves
        production_res = self._filter_mts_production_moves_to_reorder(
            production_ids
        )
        return picking_res + production_res

    @api.model
    def _filter_mts_picking_moves_to_reorder(self, picking_ids):
        return picking_ids.mapped('move_lines').filtered(
            lambda x: \
            x.state in ('confirmed') and \
            x.procure_method == 'make_to_stock' and \
            x.product_id.nbr_reordering_rules == 0 and \
            x.location_id == self.env.ref('stock.stock_location_stock') and \
            x.created_purchase_line_id.id == False and \
            x.created_production_id.id == False and \
            x.orderpoint_created_production_ids.ids == [] and \
            x.orderpoint_created_purchase_line_ids.ids == []
        )

    @api.model
    def _filter_mts_production_moves_to_reorder(self, production_ids):
        return production_ids.mapped('move_raw_ids').filtered(
            lambda x: \
            x.state in ('confirmed') and \
            x.procure_method == 'make_to_stock' and \
            x.product_id.nbr_reordering_rules == 0 and \
            x.location_id == self.env.ref('stock.stock_location_stock') and \
            x.created_purchase_line_id.id == False and \
            x.created_production_id.id == False and \
            x.orderpoint_created_production_ids.ids == [] and \
            x.orderpoint_created_purchase_line_ids.ids == []
        )

    @api.model
    def _action_cannot_reorder_product(self, product_id):
        product_id.ensure_one()
        error_msg = _('Not enough stock and no minimum orderpoint rule')
        raise UserError(error_msg)


import json
import datetime
import requests
from common.logger import warning, debug

def attribute_test(test: dict, attributes: list, kind: type) -> None:
    buf = []
    try:
        for i in attributes:
            buf.append(i)
            test = test[i]
    except KeyError:
        warning('fatal error, key ' + '.'.join(buf) + ' not exist')
        exit(1)
    if type(test) != kind:
        warning('fatal error, type of ' + '.'.join(buf) + ' unexpected')
        exit(1)

def date_varify(test: dict) -> None:
    try:
        datetime.datetime.strptime(test['utils']['date'], '%Y-%m-%d')
    except ValueError as e:
        warning('fatal error, date parse failed: ' + str(e))
        exit(1)

def update_id(info: dict) -> None:
    debug('start update app id, open id, user id, lover id')
    request = requests.post('https://tree.welove520.com/v2/game/tree/getInfo', data={
        'access_token': config['auth']['token']
    })
    if 'token无效' in request.text:
        warning('fatal error, invalid token')
        exit(1)
    debug(request.text + '\n')
    parse = json.loads(request.text)
    info['auth']['app_id'] = parse['lover_qq_open_id']
    info['auth']['open_id'] = parse['qq_open_id']
    info['auth']['user_id'] = parse['cocos_user_id']
    info['auth']['lover_id'] = parse['cocos_lover_id']

def love_days() -> int:
    return (datetime.datetime.now() - datetime.datetime.strptime(config['utils']['date'], '%Y-%m-%d')).days + 1

try:
    with open('common/config.json', 'r', encoding='utf-8') as file:
        config = json.loads(file.read())
except IOError:
    warning('fatal error, config file failed to open')
    exit(1)
except json.decoder.JSONDecodeError:
    warning('fatal error, json file failed to parse')
    exit(1)

attribute_test(config, ['auth', 'token'], str)
attribute_test(config, ['utils', 'date'], str)
attribute_test(config, ['enable'], dict)
date_varify(config)
update_id(config)
debug('config init succeed\n')


import os, time, logging

import numpy as np
import cv2
import tensorflow as tf

# TF object detection imports
from object_detection.utils import ops as utils_ops
from object_detection.utils import label_map_util
'''

Custom object detection wrapper functions

'''

from object_detection.utils import visualization_utils as vis_util

# Custom imports
from config import *

# patch tf1 into `utils.ops`
utils_ops.tf = tf.compat.v1
# Patch the location of gfile
tf.gfile = tf.io.gfile

###############################################################################

def load_detection_model(model_name):
    model_dir = 'object_detection/models/'+ model_name + '/saved_model'
    model = tf.saved_model.load(str(model_dir))
    model = model.signatures['serving_default']
    # List of the strings that is used to add correct label for each box.
    category_index = label_map_util.create_category_index_from_labelmap(PATH_TO_LABELS, use_display_name=True)
    return model, category_index

def run_inference_for_single_image(model, image):
    image = np.asarray(image)
    # The input needs to be a tensor, convert it using `tf.convert_to_tensor`.
    input_tensor = tf.convert_to_tensor(image)
    # The model expects a batch of images, so add an axis with `tf.newaxis`.
    input_tensor = input_tensor[tf.newaxis,...]

    # Run inference
    output_dict = model(input_tensor)

    # All outputs are batches tensors.
    # Convert to numpy arrays, and take index [0] to remove the batch dimension.
    # We're only interested in the first num_detections.
    num_detections = int(output_dict.pop('num_detections'))
    output_dict = {key:value[0, :num_detections].numpy()
                   for key,value in output_dict.items()}
    output_dict['num_detections'] = num_detections

    # detection_classes should be ints.
    output_dict['detection_classes'] = output_dict['detection_classes'].astype(np.int64)

    # Handle models with masks:
    if 'detection_masks' in output_dict:
      # Reframe the the bbox mask to the image size.
      detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks(output_dict['detection_masks'],
                                                                            output_dict['detection_boxes'],
                                                                            image.shape[0],
                                                                            image.shape[1])
      detection_masks_reframed = tf.cast(detection_masks_reframed > 0.5,
                                         tf.uint8)
      output_dict['detection_masks_reframed'] = detection_masks_reframed.numpy()

    return output_dict


from tkinter import *

def main():
	window = Window()
	window.mainloop()

class Window(Tk):
	def __init__(self):
		super().__init__()
		# object attributes
		self.title_text = "Config Dictionary"
		self.width = 275
		self.height = 200
		# configure
		self.title(self.title_text)
		self.config(width = self.width, height = self.height)
		# get list of attributes that can be config'ed
		self.print_config_list()

	def print_config_list(self):
		config_dict = self.config()

		for key, value_set in config_dict.items():
			print(f"{key} : {value_set}")

if __name__ == "__main__":
	main()

"""
config's attribute dictionary for tkinter.Tk (window):
{
	'bd': ('bd', '-borderwidth'),
	'borderwidth': ('borderwidth', 'borderWidth', 'BorderWidth', <string object: '0'>, 0),
	'class': ('class', 'class', 'Class', 'Toplevel', 'Tk'),
	'menu': ('menu', 'menu', 'Menu', '', ''),
	'relief': ('relief', 'relief', 'Relief', <string object: 'flat'>, 'flat'),
	'screen': ('screen', 'screen', 'Screen', '', ''),
	'use': ('use', 'use', 'Use', '', ''),
	'background': ('background', 'background', 'Background', <string object: 'SystemButtonFace'>, 'SystemButtonFace'),
	'bg': ('bg', '-background'),
	'colormap': ('colormap', 'colormap', 'Colormap', '', ''),
	'container': ('container', 'container', 'Container', 0, 0),
	'cursor': ('cursor', 'cursor', 'Cursor', '', ''),
	'height': ('height', 'height', 'Height', <string object: '0'>, 0),
	'highlightbackground': ('highlightbackground', 'highlightBackground', 'HighlightBackground', <string object: 'SystemButtonFace'>, 'SystemButtonFace'),
	'highlightcolor': ('highlightcolor', 'highlightColor', 'HighlightColor', <string object: 'SystemWindowFrame'>, 'SystemWindowFrame'),
	'highlightthickness': ('highlightthickness', 'highlightThickness', 'HighlightThickness', <string object: '0'>, 0),
	'padx': ('padx', 'padX', 'Pad', <string object: '0'>, <string object: '0'>),
	'pady': ('pady', 'padY', 'Pad', <string object: '0'>, <string object: '0'>),
	'takefocus': ('takefocus', 'takeFocus', 'TakeFocus', '0', '0'),
	'visual': ('visual', 'visual', 'Visual', '', ''),
	'width': ('width', 'width', 'Width', <string object: '0'>, 0)
}
"""


#!/usr/bin/env python3

# Input:
#   24 bit vectors, number of vectors is 200000 (not too big!!!)
#
# The general idea:
#  We need to put vectors with Hamming distance <=2 (i.e. <=2 bits are different) in same cluster
#  To do that, we first find all duplicates for [x x 1 1 1 1 1 1 ... 1 1] mask, meaning first 2 bits
#  can be any value, but the rest of the bits must match.
#  All matching vectors are our first cluster.
#  Then we check all [x 1 x 1 1 1 ... 1 1 1]. All matches are the seconf cluster.
#  And so on.
#  There is a total of 24*23 combinations of 24 bit mask with 2 dont-cares
#  Also, we re-arrange the dataset by ciolumns (column==bit), so applying a mask of [x x 1 1 ... 1 1]
#  means that we take columnd 2,3,...,23 and find duplicates across rows.
#
#  There is a total of 24*23 choices of 22 columns out of 24.
#  Each choice of columns creates a set of N vectors, each 22bit.
#  We just sort the set, O(N*log(N)), then linearly scan and drop dupicates O(N)
#  We repeat this process for all possible selection of 22 out of 24 columns ==> 400*O(N*log(N))
#
#
# Example:
# input [0 1 0 1 0 1 0 1 0 1]
#       [0 1 0 1 0 1 0 1 1 0]
#       [0 1 0 1 0 1 0 1 1 1]
#

import sys
import time
import numpy

# select all columns except for i and j
def matrix_subset(M, i, j, columns_n):
    # assert that 0 <= i < j < num_of_columns(M)
    assert((i >= 0) and (i < j) and (j < columns_n))

    # columns between 0 and i, i+1 to j, j+1 to end, excluding i and j
    # any of the three regions can be empty
    columns = list(range(0,i)) + list(range(i+1,j)) + list(range(j+1,columns_n))

    return M[:,columns]

def merge_clusters(cluster_sizes, cluster_ids, mergeto, mergefrom):
    cluster_sizes[mergeto] += cluster_sizes[mergefrom]
    cluster_sizes[mergefrom] = 0
    cluster_ids[mergefrom] = mergeto

def get_cluster_id(cluster_ids, i):
    while cluster_ids[i] != i:
        i = cluster_ids[i]
    return i

t0 = time.time()
def print_with_timestamp(message):
    global t0
    t1 = time.time()
    print(t1 - t0, 'sec', message)
    t0 = t1

def calc_clusters(nodes_n, bits_n, nodes, debug_on):
    # transpose the matrix, columns of nodes are rows of M
    M = numpy.mat(nodes)

    # initially all clusters are of size 1 and the id is the index
    # as the algorithm progresses, linked lists are formed, similar to PCI caps list
    # For example, if nodes 0, 5, 7 belong to same cluster the arrays *might* look as follows:
    #   cluster_sizes = [ 3, 1, 1, 1, 1, 1, 1, 1, 1 ]
    #   cluster_ids   = [ 0, 1, 2, 3, 4, 0, 6, 5, 8 ]
    #       where cluster_ids[7] == 5, cluster_ids[5] == 0 and cluster_ids[0] == 0. '0' is cluster leader
    cluster_ids = [x for x in range(len(nodes))]
    cluster_sizes = len(nodes)*[1]

    print_with_timestamp('dataset ready')

    for i in range(0,bits_n-1):
        for j in range(i+1,bits_n):
            print_with_timestamp('i ' + str(i) + ', j ' + str(j))

            # select all bit columns except for i and j, and always select the last column of indices
            # sort by rows (0 == x axis)
            M_subset = matrix_subset(M, i, j, bits_n+1).tolist()
            #print(M_subset)
            M_subset.sort()

            if debug_on:
                print('pre ids', cluster_ids, ', sizes', cluster_sizes)

            # find duplicates in nodes_subset, they correspond to hamming<=2 clusters in 'nodes'
            # mark all clusters in the original 'nodes'
            node0 = M_subset[0]
            idx0 = get_cluster_id(cluster_ids, node0[-1])
            for node in M_subset[1:]:
                # compare row to row, ignore the last element - the index
                idx = get_cluster_id(cluster_ids, node[-1])
                if node0[0:-1] == node[0:-1]:
                    # TODO: cluster of size 1 is a frequent case, may deserve a special treatment
                    if idx == idx0:
                        pass # this node is already in 'idx0' cluster, nothing to do
                    else:
                        if cluster_sizes[idx0] > cluster_sizes[idx]:
                            mergeto, mergefrom = idx0, idx   # merge two clusters
                        else:
                            mergeto, mergefrom = idx, idx0   # merge two clusters
                            node0 = node
                            idx0 = idx
                        #print('merging', mergeto, '<<', mergefrom)
                        merge_clusters(cluster_sizes, cluster_ids, mergeto, mergefrom)
                else:
                    node0 = node
                    idx0 = idx

            if debug_on:
                print('post ids', cluster_ids, ', sizes', cluster_sizes)

    return len(cluster_sizes) - cluster_sizes.count(0)

def main():
    if len(sys.argv) != 2:
        print('USAGE:', sys.argv[0], '<input file>')
        return -1

    # step 1: read the input
    with open(sys.argv[1]) as f:
        line = f.readline().split()
        nodes_n, bits_n = int(line[0]), int(line[1])
        nodes = []
        index = 0
        for line in f:
            nodes.append([int(x) for x in line.split()] + [index])
            index += 1

    print_with_timestamp('done reading input, nodes_n ' + str(nodes_n))
    assert(nodes_n == len(nodes))
    assert(bits_n + 1 == len(nodes[0])) # the last element is not a bit, but the index of the array

    n = calc_clusters(nodes_n, bits_n, nodes, False)
    print('clusters', n)
    return 0

if __name__ == '__main__':
    sys.exit(main())


#!/usr/bin/env python3
import os
import traceback

## Not sure what this was originally intended for.  Leaving for now.  BLF
# for key, val in gemsModules.deprecated.delegator.settings.subEntities:
#     if val in gemsModules.deprecated.delegator.settings.deprecated:
#         pass
# prototype: need to build import statement
# from gemsModules.deprecated.deprecated_20221212. + val + import

from gemsModules.deprecated.sequence import io as sequenceio
from gemsModules.deprecated.sequence import receiver_tasks

from gemsModules.deprecated.common.loggingConfig import loggers, createLogger
from gemsModules.deprecated.common.logic import writeStringToFile
if loggers.get(__name__):
    pass
else:
    log = createLogger(__name__)

# @brief The main way Delegator interacts with this module. Request handling.
#   @param Transaction receivedTransactrion
def receive(receivedTransaction: sequenceio.Transaction) -> sequenceio.Transaction:
    log.info("sequence.receive() was called:\n")
    # log.debug("The received transaction contains this incoming string: ")
    # log.debug(receivedTransaction.incoming_string)
    # log.debug("request dict: ")
    # log.debug(receivedTransaction.request_dict)

    # ## Initialize the transaction
    from pydantic import ValidationError
    thisTransaction = sequenceio.Transaction(receivedTransaction.incoming_string)
    try:
        thisTransaction.populate_transaction_in()
    except ValidationError as e:
        log.error(e)
        log.error(traceback.format_exc())
        thisTransaction.generateCommonParserNotice(
            noticeBrief='JsonParseEror',
            additionalInfo={'hint': str(e)})
        return thisTransaction
    try:
        thisTransaction.initialize_transaction_out_from_transaction_in()
        # For convenience, make a short alias for the entity in the transaction_in
        if thisTransaction.transaction_out.timestamp is None:
            from datetime import datetime
            thisTransaction.transaction_out.timestamp=datetime.now().strftime("%Y-%m-%d_%H:%M:%S")
        thisSequenceEntity = thisTransaction.transaction_out.entity
    except Exception as error:
        log.error(
            "There was a problem initializing the outgoing transaction : " + str(error))
        log.error(traceback.format_exc())
        raise  # not sure if this will work as desired - BLFoley 2023-03-15
               # it might be necessary to generate a transaction to return and
               # populate it with an error message.

    ## If there is a sequence, ensure that it is valid
    the_sequence = receiver_tasks.get_sequence(thisSequenceEntity)
    if the_sequence is not None:
        from gemsModules.deprecated.sequence import build
        #Ok Oliver, here we should try/catch:
        try:
            carbBuilder = build.getCbBuilderForSequence(the_sequence)
        except Exception as error:
            log.debug("Just about to call generateCommonParserNotice with the outgoing project.  The transaction_out is :   ")
            log.debug(thisTransaction.transaction_out.json(indent=2))
            thisTransaction.generateCommonParserNotice(noticeBrief='InvalidInputPayload', exitMessage=str(error))
            thisTransaction.build_outgoing_string()
            return thisTransaction # do this or no?  # if the process has altered this Transaction, then yes
        log.debug("Sequence is valid.")
    # If there are no explicit services
    if thisSequenceEntity.services == []:
        log.debug("'services' was not present in the request. Do the default.")
        thisTransaction = receiver_tasks.doDefaultService(thisTransaction)
        return thisTransaction

    # ## Initialize the project
    try:
        need_new_project = receiver_tasks.we_should_start_new_project(thisTransaction)
        if need_new_project:
            log.debug("We need a new project.  Starting a new one.")
            from gemsModules.deprecated.project import io as projectio
            thisProject = projectio.CbProject()

        # log.debug("Initializing the non-filesystem-writing parts of the outgoing project")
        if thisTransaction.transaction_in.project is not None:
            if thisTransaction.transaction_in.project.filesystem_path is not None:
                thisProject.setFilesystemPath(thisTransaction.transaction_in.project.filesystem_path, noClobber=False)
        else:
            thisProject.setFilesystemPath()
        log.debug("About to load the version info")
        thisProject.loadVersionsFileInfo()
        thisTransaction.transaction_out.project=thisProject.copy(deep=True)

        need_filesystem_writes = receiver_tasks.we_need_filesystem_writes(thisSequenceEntity)
        log.debug("Initializing the filesystem parts of the outgoing project, if any")
        if need_filesystem_writes:
            # ## TODO - this will probably fail if more than one service needs filesystem
            # ##        access ~AND~ each service needs a different location.
            # ##        Project generation / filling needs to be put down into the
            # ##        services.  The new design will facilitate this fix.
            return_value = receiver_tasks.set_up_filesystem_for_writing(thisTransaction)
            if return_value != 0:
                thisTransaction.generateCommonParserNotice(
                    noticeBrief='GemsError',
                    additionalInfo={'Message': 'Something went wrong while setting up the filesystem.'})

    except Exception as error:
        log.error(
            "There was a problem initializing the outgoing project: " + str(error))
        log.error(traceback.format_exc())
        raise Exception
    # log.debug("Just initialized the outgoing project.  The transaction_out is :   ")
    # log.debug(thisTransaction.transaction_out.json(indent=2))

    ###################################################################
    #
    # these are for logging/debugging and can go if they get heavy
    #
    log.debug("The entity type is : " + thisSequenceEntity.entityType)
    # log.debug("The services are: ")
    # log.debug(thisSequenceEntity.services)
    vals = thisSequenceEntity.services.values()
    for j in vals:
        if 'Build3DStructure' in j.typename:
            log.debug("Found a build 3d request.")
        elif 'Evaluate' in j.typename:
            log.debug("Found an evaluation request.")
        elif 'Validate' in j.typename:
            log.debug("Found a validation request.")
        elif 'Status' in j.typename:
            log.debug("Found a status request.")
        elif 'Marco' in j.typename:
            log.debug("Found a marco request.")
        else:
            log.debug("Found an unknown service: '" + str(j.typename))
    # log.debug("The Seqence Entity's inputs looks like:")
    # log.debug(thisSequenceEntity.inputs)
    # log.debug("The Seqence Entity's inputs.Sequence looks like:")
    # log.debug(thisSequenceEntity.inputs.sequence.payload)
    ###################################################################

    # for each explicit service:
    for currentService in thisSequenceEntity.services:
        log.debug("service, currentService: " + str(currentService))
        thisService = thisSequenceEntity.services[currentService]

        if 'Evaluate' in thisService.typename:
            log.debug("Evaluate service requested from sequence entity.")

            try:

                thisTransaction.evaluateCondensedSequence()

            except Exception as error:

                log.error(
                    "There was a problem evaluating the condensed sequence: " + str(error))
                log.error(traceback.format_exc())
                noticeMsg="There was a problem evaluating the condensed sequence. Was a default build attempted? "
                thisTransaction.generateCommonParserNotice(
                    noticeBrief='InvalidInputPayload',
                    additionalInfo={'hint': noticeMsg})
        elif 'Build3DStructure' in thisService.typename:
            log.debug("Build3DStructure service requested from sequence entity.")
            # Sequence was validated above.  Should not be needed again.
            # An evaluation is needed for checking other things.
            try:
                thisTransaction.evaluateCondensedSequence()
                thisTransaction.setIsEvaluationForBuild(True)
                thisTransaction.manageSequenceBuild3DStructureRequest()
            except Exception as error:
                log.error(
                    "There was a problem with manageSequenceBuild3DStructureRequest(): " + str(error))
                raise error
        elif "Validate" in thisService.typename:
            # this should be able to become part of previous validation, but leaving in for now
            log.debug("Validate service requested from sequence entity.")
            try:
                thisTransaction.evaluateCondensedSequence(validateOnly=True)
            except Exception as error:
                log.error(
                    "There was a problem validating the condensed sequence: " + str(error))
                thisTransaction.generateCommonParserNotice(
                    noticeBrief='InvalidInputPayload')
        elif "Status" in thisService.typename:
            # this should be able to become part of previous validation, but leaving in for now
            log.debug("Status service requested from sequence entity.")
            try:
                thisTransaction = receiver_tasks.do_status(thisTransaction)
            except Exception as error:
                log.error(
                    "There was a problem getting status for sequence: " + str(error))
                thisTransaction.generateCommonParserNotice(
                    noticeBrief='InvalidInputPayload')
        elif "Marco" in thisService.typename:
            # this should be able to become part of previous validation, but leaving in for now
            log.debug("Marco service requested from sequence entity.")
            try:
                thisTransaction = receiver_tasks.do_marco(thisTransaction)
            except Exception as error:
                log.error(
                    "There was a problem running marco for sequence: " + str(error))
                thisTransaction.generateCommonParserNotice(
                    noticeBrief='InvalidInputPayload')
        else:
            log.error("got to the else, so something is wrong")
            thisTransaction.generateCommonParserNotice(
                noticeBrief='ServiceNotKnownToEntity')

    # prepares the transaction for return to the requestor, success or fail.
    # NOTE!!! This uses the child method in sequence.io - a better method!
    thisTransaction.build_outgoing_string()
    if need_filesystem_writes:
        thisProject=thisTransaction.transaction_out.project
        outgoingResponse = thisTransaction.transaction_out.json(indent=2, by_alias=True)
        outgoingPath = os.path.join(thisProject.logs_dir, "response.json")
        log.debug("Writing the outgoing response to: " + outgoingPath)
        writeStringToFile(outgoingResponse, outgoingPath)
    return thisTransaction

def main():
    log.info("main() was called.\n")

if __name__ == "__main__":
    main()


from fastapi import APIRouter, WebSocket
from ..wallets import router as walletRouter

router = APIRouter(
    tags=['Websocket endpoints'],
    responses={
        404: {"description": "Resource does not exist"}
    },

)

router.include_router(
    router=walletRouter,
    prefix='/wallets',

)

@router.websocket('/')
async def ping(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message text was: {data}")