import json
from collections import defaultdict
import types
import inspect
from torch import _TensorBase
from viz.graphtracker import GraphData, GraphContainer, GraphOp, get_graphdata, has_graphdata

class VisualizationType:
    """Encapsulates the visualization-relevant properties of a specific object type.

    The `VisualizationEngine` outputs data schemas for different types of objects (string, number, dict, etc). Each of
    these schemas is different, as different objects need to send different data. Rather than constructing each schema
    according to some monolithic switch condition, each object's unique properties/functions are encapsulated in a
    `VisualizationType` object. For instance,

        `BOOL = VisualizationType(type_name='bool', test_fn=lambda x: type(x) is bool, is_primitive=True)`

    encapsulates the unique properties/functions for the `boolean` type. This construction ultimately allows objects of
    different types to be treated in a generic manner in code.
    """
    def __init__(self, type_name, test_fn, data_fn, str_fn=str, is_primitive=False):
        """Constructor. Fields should not be changed after instantiation, and only one instance of a `VisualizationType`
        should exist for each object type.

        Args:
            type_name (str): The string name of the object type, as understood by the client.
            test_fn (fn): A function (obj) => bool, which returns true if `obj` is of the type handled by this
                `VisualizationType` instance.
            data_fn (fn): A function (`VisualizationEngine`, obj) => (object, set), which takes an engine
                (typically passed from within an engine as `self`) and a symbol object and creates the data object.
                Assumed that `test_fn(obj) == True`.
            str_fn (fn): A function (obj) => str, which translates the given symbol object to a human-readable string.
                Assumed that `test_fn(obj) == True`.
            is_primitive (bool): True if this `VisualizationType` is primitive.
        """
        self.type_name = type_name
        self.test_fn = test_fn
        self.data_fn = data_fn
        self.str_fn = str_fn
        self.is_primitive = is_primitive
        assert is_primitive or self.data_fn is not None, 'Non-primitive types must define a data_fn.'

class VisualizationEngine:
    """Encapsulates the translation of Python variable symbols into visualization schema. It is stateful, so it may
    implement caching in the future to improve performance.
    """
    def __init__(self):
        """Constructor. Initializes symbol cache to store and efficient serve generated data schemas and references.
        See "Symbol cache keys" section for more details.
        """
        self.cache = defaultdict(dict)

    # ==================================================================================================================
    # Symbol cache.
    # -------------
    # The `VisualizationEngine` cache is of the form {symbol_id -> {key -> value}}. Each `symbol_id` is mapped to a dict
    # of stored information, the keys for which are defined below.
    # ==================================================================================================================

    # Key for a symbol's shell representation, which is a dict of the form:
    # {
    #   'type': The type of the symbol; this matches the `VisualizationType.type_name` field and must be understood by
    #           the client. Any change to the type_name must be reflected in the client.
    #   'str': A string representation of the symbol that can be showed in the client, particularly in the variable list
    #           and when the object has not been expanded.
    #   'name': A string name, possibly null, for the object, to be shown in the client.
    #   'data': Either the value of the object (for primitives) or None (for non-primitives). When the client seeks
    #           to "fill" a schema shell, they will have to request that data from the debugger first. See
    #           VIZ-SCHEMA.js for more info about what these data objects will look like.
    # }
    SHELL = 'shell'

    # Key for a symbol's data schema. Undefined (not in the dict) until `get_symbol_data` has populated it. This lazy
    # population prevents extraneous work of generating a symbol's data schema (often a highly nested structure) until
    # it is specifically requested.
    DATA = 'data'

    # Key for a `set` of IDs for all symbols referenced in this symbol's data schema. Each symbol ID is a string of the
    # form "{REF_PREFIX}{id}", where id is a unique number for the symbol. Undefined (not in the dict) until
    # `get_symbol_data` has populated it.
    REFS = 'refs'

    # Key for this symbol's Python object handle, so that the object can manipulated and indexed when requested.
    OBJ = 'obj'

    # Key for this symbol's `VisualizationType` instance. There exists only one `VisualizationType` for each type, so
    # two symbols of the same type reference the same `VisualizationType`.
    TYPE_INFO = 'type-info'

    # ==================================================================================================================
    # Schema generation.
    # ------------------
    # Create the `VisualizationType` objects to represent each symbol type and write the logic which translates
    # Python objects into visualization schema dicts.
    # ==================================================================================================================

    # Data generation functions.
    # --------------------------
    # These type-specific functions generate the `data, refs` for a symbol object.

    def _generate_data_primitive(self, obj):
        """Data generation function for primitives."""
        refs = set()
        return {
            self.VIEWER_KEY: {
                'contents': self._sanitize_for_data_object(obj, refs),
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs),
        }, refs

    def _generate_data_tensor(self, obj):
        """Data generation function for tensors."""
        refs = set()
        return {
            self.VIEWER_KEY: {
                # This is deliberately not datafied to prevent the lists from being turned into references.
                'contents': obj.cpu().numpy().tolist(),
                'size': list(obj.size()),
                'type': self._sanitize_for_data_object(self.TENSOR_TYPES[obj.type()], refs),
                'maxmag': obj.abs().max(),
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs)
        }, refs

    def _generate_data_graphdata(self, obj):
        """Data generation function for graph data nodes."""
        refs = set()
        # We consider both `GraphData` instances and objects which have associated `GraphData` instances to be
        # graphdata for schema purposes, so we need to figure out which one `obj` is
        try:
            graphdata_obj = get_graphdata(obj)
        except AttributeError:
            graphdata_obj = obj
            obj = graphdata_obj.obj
        return {
            self.VIEWER_KEY: {
                'creatorop': self._sanitize_for_data_object(graphdata_obj.creator_op, refs),
                'creatorpos': self._sanitize_for_data_object(graphdata_obj.creator_pos, refs),
                'kvpairs': {
                    self._sanitize_for_data_object(key, refs): self._sanitize_for_data_object(value, refs)
                    for key, value in graphdata_obj.get_visualization_dict().items()
                }
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs)
        }, refs

    def _generate_data_graphcontainer(self, obj):
        """Data generation function for graph containers."""
        refs = set()
        return {
            self.VIEWER_KEY: {
                'contents': [self._sanitize_for_data_object(op, refs) for op in obj.contents],
                'container': self._sanitize_for_data_object(obj.container, refs),
                'temporalstep': self._sanitize_for_data_object(obj.temporal_step, refs),
                'height': self._sanitize_for_data_object(obj.height, refs),
                'functionname': self._sanitize_for_data_object(obj.fn_name, refs),
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs)
        }, refs

    def _generate_data_graphop(self, obj):
        """Data generation function for graph op nodes."""
        refs = set()
        print(obj.args)
        d = {
            self.VIEWER_KEY: {
                'function': self._sanitize_for_data_object(obj.fn, refs),
                'args': [[self._sanitize_for_data_object(arg[0], refs),
                          self._sanitize_for_data_object(arg[1], refs) if not isinstance(arg[1], list) else
                          [self._sanitize_for_data_object(arg_item, refs) for arg_item in arg[1]]] if len(arg) > 1 else
                         [self._sanitize_for_data_object(arg[0], refs)]
                         for arg in obj.args],
                'kwargs': [[self._sanitize_for_data_object(arg[0], refs),
                          self._sanitize_for_data_object(arg[1], refs) if not isinstance(arg[1], list) else
                          [self._sanitize_for_data_object(arg_item, refs) for arg_item in arg[1]]] if len(arg) > 1 else
                         [self._sanitize_for_data_object(arg[0], refs)]
                         for arg in obj.kwargs],
                'container': self._sanitize_for_data_object(obj.container, refs),
                'functionname': self._sanitize_for_data_object(obj.fn_name, refs),
                'outputs': [self._sanitize_for_data_object(output, refs) for output in obj.outputs],
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs)
        }
        print(d)
        return d, refs

    def _generate_data_dict(self, obj):
        """Data generation function for dicts."""
        contents = dict()
        refs = set()
        for key, value in obj.items():
            contents[self._sanitize_for_data_object(key, refs)] = self._sanitize_for_data_object(value, refs)
        return {
            self.VIEWER_KEY: {
                'contents': contents,
                'length': self._sanitize_for_data_object(len(obj), refs),
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs),
        }, refs

    def _generate_data_sequence(self, obj):
        """Data generation function for sequential objects (list, tuple, set)."""
        contents = list()
        refs = set()
        for item in obj:
            contents.append(self._sanitize_for_data_object(item, refs))
        return {
            self.VIEWER_KEY: {
                'contents': contents,
                'length': self._sanitize_for_data_object(len(obj), refs),
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs),
        }, refs

    def _generate_data_function(self, obj):
        """Data generation function for functions."""
        refs = set()
        viewer_data = {
            'filename': self._sanitize_for_data_object(obj.__code__.co_filename, refs),
            'lineno': self._sanitize_for_data_object(obj.__code__.co_firstlineno, refs),
        }
        argnames = obj.__code__.co_varnames
        default_arg_values = obj.__defaults__
        if default_arg_values is not None:
            viewer_data['args'] = argnames[:-len(default_arg_values)]
            viewer_data['kwargs'] = {
                self._sanitize_for_data_object(argname, refs): self._sanitize_for_data_object(value, refs)
                for argname, value in zip(argnames[-len(default_arg_values)], default_arg_values)
            }
        else:
            viewer_data['args'] = []
            viewer_data['kwargs'] = {}
        return {
            self.VIEWER_KEY: viewer_data,
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs)
        }, refs

    def _generate_data_module(self, obj):
        """Data generation function for modules."""
        refs = set()
        contents = self._get_data_object_attributes(obj, refs, exclude_fns=False)
        return {
            self.VIEWER_KEY: {
                'contents': contents,
            },
            self.ATTRIBUTES_KEY: contents,
        }, refs

    def _generate_data_class(self, obj):
        """Data generation function for classes."""
        contents = {
            'staticfields': dict(),
            'functions': dict(),
        }
        refs = set()
        for attr in dir(obj):
            value = getattr(obj, attr)
            if self.FUNCTION.test_fn(value):
                contents['functions'][self._sanitize_for_data_object(attr, refs)] = \
                    self._sanitize_for_data_object(value, refs)
            else:
                contents['staticfields'][self._sanitize_for_data_object(attr, refs)] = \
                    self._sanitize_for_data_object(value, refs)
        return {
            self.VIEWER_KEY: {
                'contents': contents,
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs, exclude_fns=False)
        }, refs

    def _generate_data_instance(self, obj):
        """Data generation function for object instances which do not fall into other categories."""
        instance_class = type(obj)
        instance_class_attrs = dir(instance_class)
        contents = dict()
        refs = set()
        for attr in dir(obj):
            value = getattr(obj, attr)
            try:
                if not self.FUNCTION.test_fn(value) and (
                                attr not in instance_class_attrs or getattr(instance_class, attr, None) != value):
                    contents[self._sanitize_for_data_object(attr, refs)] = \
                        self._sanitize_for_data_object(getattr(obj, attr), refs)
            except TypeError:
                contents[self._sanitize_for_data_object(attr, refs)] = \
                    self._sanitize_for_data_object(getattr(obj, attr), refs)
        return {
            self.VIEWER_KEY: {
                'contents': contents,
            },
            self.ATTRIBUTES_KEY: self._get_data_object_attributes(obj, refs)
        }, refs

    # `VisualizationType` objects.
    # ----------------------------
    NUMBER          = VisualizationType('number', test_fn=lambda obj: isinstance(obj, (float, int)),
                                        data_fn=_generate_data_primitive, is_primitive=True)
    STRING          = VisualizationType('string', test_fn=lambda obj: isinstance(obj, str),
                                        data_fn=_generate_data_primitive,
                                        str_fn=lambda obj: '"{}"'.format(obj),
                                        is_primitive=True)
    BOOL            = VisualizationType('bool', test_fn=lambda obj: isinstance(obj, bool),
                                        data_fn=_generate_data_primitive, is_primitive=True)
    NONE            = VisualizationType('none', test_fn=lambda obj: obj is None,
                                        data_fn=_generate_data_primitive, is_primitive=True)
    TENSOR          = VisualizationType('tensor', test_fn=lambda obj: isinstance(obj, _TensorBase),
                                        str_fn=lambda obj: 'tensor <{}>{}'.format(VisualizationEngine.TENSOR_TYPES
                                                                                [obj.type()], list(obj.size())),
                                        data_fn=_generate_data_tensor)
    GRAPH_DATA      = VisualizationType('graphdata',
                                        test_fn=lambda obj: isinstance(obj, GraphData) or has_graphdata(obj),
                                        str_fn=lambda obj: VisualizationEngine._get_type_info_obj(obj, ['graphdata'])
                                        .str_fn(obj),
                                        data_fn=_generate_data_graphdata)
    GRAPH_CONTAINER = VisualizationType('graphcontainer', test_fn=lambda obj: isinstance(obj, GraphContainer),
                                        str_fn=lambda obj: 'graphcontainer[{}]'.format(len(obj.contents)),
                                        data_fn=_generate_data_graphcontainer)
    GRAPH_OP        = VisualizationType('graphop', test_fn=lambda obj: isinstance(obj, GraphOp),
                                        str_fn=lambda obj: 'graphop <{}>'.format(obj.name),
                                        data_fn=_generate_data_graphop)
    DICT            = VisualizationType('dict', test_fn=lambda obj: isinstance(obj, dict),
                                        str_fn=lambda obj: 'dict[{}]'.format(len(obj)),
                                        data_fn=_generate_data_dict)
    LIST            = VisualizationType('list', test_fn=lambda obj: isinstance(obj, list),
                                        str_fn=lambda obj: 'list[{}]'.format(len(obj)),
                                        data_fn=_generate_data_sequence)
    SET             = VisualizationType('set', test_fn=lambda obj: isinstance(obj, set),
                                        str_fn=lambda obj: 'set[{}]'.format(len(obj)),
                                        data_fn=_generate_data_sequence)
    TUPLE           = VisualizationType('tuple', test_fn=lambda obj: isinstance(obj, tuple),
                                        str_fn=lambda obj: 'tuple[{}]'.format(len(obj)),
                                        data_fn=_generate_data_sequence)
    FUNCTION        = VisualizationType('fn', test_fn=lambda obj: isinstance(obj, (types.FunctionType, types.MethodType,
                                                                                types.BuiltinFunctionType,
                                                                                types.BuiltinFunctionType,
                                                                                type(all.__call__))),
                                        str_fn=lambda obj: 'function {}{}'.format(obj.__name__, '()'
                                        if inspect.isbuiltin(obj) else str(inspect.signature(obj))),
                                        data_fn=_generate_data_function)
    MODULE          = VisualizationType('module', test_fn=inspect.ismodule,
                                        str_fn=lambda obj: 'module <{}>'.format(obj.__name__),
                                        data_fn=_generate_data_module)
    CLASS           = VisualizationType('class', test_fn=inspect.isclass,
                                        str_fn=lambda obj: 'class <{}>'.format(obj.__name__),
                                        data_fn=_generate_data_class)
    INSTANCE        = VisualizationType('obj', test_fn=lambda obj: True,
                                        str_fn=lambda obj: '<{}>'.format(obj.__class__.__name__, str(obj)),
                                        data_fn=_generate_data_instance)

    # A list of all `VisualizationType` objects, in the order in which type should be tested. For example, the
    # INSTANCE should be last, as it returns `True` on any object and is the most general type. `BOOL` should be
    # before `NUMBER`, as bool is a subclass of number. `GRAPH_DATA` should be first, as it can wrap any type and
    # will be mistaken for those types.
    TYPES = [GRAPH_DATA, GRAPH_CONTAINER, GRAPH_OP, NONE, BOOL, NUMBER, STRING, TENSOR, DICT, LIST, SET, TUPLE, MODULE,
             FUNCTION, CLASS, INSTANCE]

    # Utility functions for data generation.
    # --------------------------------------

    def _get_data_object_attributes(self, obj, refs, exclude_fns=True):
        """Creates the dict containing a symbol's attributes to be sent in the symbol's data object.

        Each symbol is a single Python object, which has attributes beyond those used for visualization.
        For completeness, the debugger surfaces these key-value pairs of these attributes. Those
        pairs are generated here and escaped for safe communication with the client.

        Args:
            obj (object): Python object whose attributes dict should be generated.
            refs (set): A set to save new symbol ID reference strings created during generation.
            exclude_fns (bool): Exclude functions (both instance and static) if `True`.

        Returns:

        """
        attributes = dict()
        for attr in dir(obj):
            # There are some functions, like torch.Tensor.data, which exist just to throw errors. Testing these
            # fields will throw the errors. We should consume them and keep moving if so.
            try:
                if exclude_fns and self.FUNCTION.test_fn(getattr(obj, attr)):
                    continue
            except RuntimeError:
                continue
            attributes[self._sanitize_for_data_object(attr, refs)] = \
                self._sanitize_for_data_object(getattr(obj, attr), refs)
        return attributes

    def _is_primitive(self, obj):
        """Returns `True` if `obj` is primitive, as defined by the engine's `VisualizationType` objects."""
        for type_info in self.TYPES:
            if type_info.test_fn(obj):
                return type_info.is_primitive
        return False

    def _escape_str(self, s):
        # TODO: We need to have a system for escaping strings, to ensure that strings starting with REF_PREFIX are not
        # considered references mistakenly.
        """Reformats a string to eliminate ambiguity between strings and symbol ID references."""
        return s

    def _sanitize_for_data_object(self, key_or_value, refs):
        """Takes in a Python object and returns a version which is safe to use in a data object.

        _sanitize_for_data_object translates any key or value which needs to be in a symbol's data object into a JSON-safe version.
        Everything put into a symbol's data object must be data-fied first. For primitives, this does nothing but
        escapes strings so that they are not confused with symbol references. For non-primitive objects, a symbol ID
        reference string which refers to the input object is returned.

        Non-primitive objects are added to the cache, so that the returned symbol ID is associated with that object
        for future use.

        Args:
            key_or_value (object): An object to make safe for inclusion in the data object.
            refs (set): A set to save new symbol ID reference strings created during generation.

        Returns:
            (str or int or float): Serializable-safe representation of obj, possibly as a symbol ID reference.
        """
        if self._is_primitive(key_or_value):
            return self._escape_str(key_or_value) if self.STRING.test_fn(key_or_value) else key_or_value
        else:
            symbol_id = self._get_symbol_id(key_or_value)
            self.cache[symbol_id][self.OBJ] = key_or_value
            refs.add(symbol_id)
            return self.REF_PREFIX + symbol_id

    # Schema constants.
    # -----------------
    # Shared knowledge between the `VisualizationEngine`. These strings describe the fields in the data representation
    # that will be consumed by the front-end client. Any changes on either side will need to be reflected in the other.

    # Prefix to append to strings to identify them as symbol ID references. The `VisualizationEngine`
    # must communicate in a way the client can understand, but the Python -> JSON string conversion introduces
    # sources of potential confusion. It is not clear whether a string in a schema's 'data' field is a symbol ID
    # reference or an actual string object, so some escaping must be done to remove ambiguity.
    # TODO: Come up with a better system for this that can't be tricked
    REF_PREFIX = '@id:'

    # Key for a symbol data object's viewer dict (key-value pairs used by data viewers to render the object).
    # This dict follows the schema outlined in VIZ-SCHEMA.js.
    VIEWER_KEY = 'viewer'

    # Key for a symbol data object's attributes dict (key-value pairs to show in client's variable list. These
    # attributes often encompass more information than will be displayed in a viewer.
    # This dict follows the schema outlined in VIZ-SCHEMA.js.
    ATTRIBUTES_KEY = 'attributes'

    # We convey the data type of a tensor in a generic way to remove dependency on the tensor's implementation. We
    # need a way to look up the Python object's type to get the data type string the client will understand.
    TENSOR_TYPES = {
        'torch.HalfTensor': 'float16',
        'torch.FloatTensor': 'float32',
        'torch.DoubleTensor': 'float64',
        'torch.ByteTensor': 'uint8',
        'torch.CharTensor': 'int8',
        'torch.ShortTensor': 'int16',
        'torch.IntTensor': 'int32',
        'torch.LongTensor': 'int64',
        'torch.cuda.HalfTensor': 'float16',
        'torch.cuda.FloatTensor': 'float32',
        'torch.cuda.DoubleTensor': 'float64',
        'torch.cuda.ByteTensor': 'uint8',
        'torch.cuda.CharTensor': 'int8',
        'torch.cuda.ShortTensor': 'int16',
        'torch.cuda.IntTensor': 'int32',
        'torch.cuda.LongTensor': 'int64',
    }

    # ==================================================================================================================
    # Utility functions for public methods.
    # ==================================================================================================================

    def _get_symbol_id(self, obj):
        """Returns the symbol ID (a string unique for the object's lifetime) of a given object.

        As currently implemented, IDs are only guaranteed to be unique within a single snapshot of the namespace. At the
        next breakpoint, an object may have died and a new object reclaimed the ID (really implemented as just a base
        memory address).

        Args:
            obj (object): A Python object to be identified.

        Returns:
            (str): symbol ID.
        """
        return str(id(obj))

    def _get_type_info_symbol(self, symbol_id):
        """Returns the `VisualizationType` object associated with a particular symbol ID.

        If the symbol ID has not yet been associated with a `VisualizationType` object in the cache, the association is made
        here. Otherwise, the cached value is returned.
        Args:
            symbol_id (str): ID for a symbol, as defined by `self._get_symbol_id()`.

        Returns:
            (VisualizationType): the `VisualizationType` object associated with the symbol's type.
        """
        if symbol_id not in self.cache:
            raise KeyError('Symbol id {} not found in cache.'.format(symbol_id))
        if self.TYPE_INFO not in self.cache[symbol_id]:
            obj = self.cache[symbol_id][self.OBJ]
            self.cache[symbol_id][self.TYPE_INFO] = self._get_type_info_obj(obj)
        return self.cache[symbol_id][self.TYPE_INFO]

    @staticmethod
    def _get_type_info_obj(obj, exclude_types=None):
        """Returns the `VisualizationType` object associated with a given object.

        Does not perform any caching; if the object is associated with a symbol ID in the symbol table,
        `get_type_info_symbol()` should be used.
        Args:
            obj (object): an object of unknown visualization type.
            exclude_types (list or None): a list of visualization type names that may not be returned.

        Returns:
            (VisualizationType): the `VisualizationType` object associated with the object's type.
        """
        for type_info in VisualizationEngine.TYPES:
            if (exclude_types is None or type_info.type_name not in exclude_types) and type_info.test_fn(obj):
                return type_info

    def _load_symbol_data(self, symbol_id):
        """Builds the data object for a symbol.

        Used in `get_symbol_data` to build a symbol's data object if none was already cached. This function does not
        cache its output and will not check the cache before generating.

        Args:
            symbol_id (str): A string ID for the requested symbol, as defined by self._get_symbol_id.

        Returns:
            (object): The symbol's data object.
        """
        symbol_type_info = self._get_type_info_symbol(symbol_id)
        symbol_obj = self.cache[symbol_id][self.OBJ]
        return symbol_type_info.data_fn(self, symbol_obj)

    # ==================================================================================================================
    # Public functions.
    # -----------------
    # The functions which generate visualization-ready content about objects in the Python program. Typically,
    # a user will first acquire the "shell" of a symbol, its lightweight representation that encapsulates its basic
    # properties. If interested in visualizing the symbol fully, the user will then request its data, a dictionary
    # which exposes more data-heavy properties of the object needed for visualization, as well as debugging-useful
    # attributes of the Python object itself.
    # ==================================================================================================================

    def get_symbol_shell(self, symbol_id, name=None):
        """Builds the lightweight shell dict representation of a given symbol for visualization.

        The shell dict (described in "Symbol cache" above and in VIZ-SCHEMA.js) is used to store lightweight information
        about an object. Except for primitives, the data of the object are not generally reflected in the shell
        representation (though some may be present in the 'str' field).

        The function assumes that `symbol_id` exists already within the `cache` (added via `get_symbol_data()` or
        or `_get_namespace_shells()`) and that `cache[symbol_id][OBJ]` points to the symbol's associated Python
        object. If the shell has already been cached, it is simply returned; otherwise, this function will fill the
        cache[symbol_id][SHELL] field.

        The returned dict is a Python object, which needs conversion via `to_json()` for sending to a Javascript server.

        Args:
            symbol_id (str): A unique identifier for the symbol, as defined by `_get_symbol_id()`.
            name (str): Optional, a name for the symbol if defined, e.g. "myVar".

        Returns:
            (dict): The symbol's shell dict.
        """
        if symbol_id not in self.cache:
            raise KeyError('Symbol id {} not found in cache.'.format(symbol_id))
        if self.OBJ not in self.cache[symbol_id]:
            raise KeyError('No object reference found for symbol {}'.format(symbol_id))
        if self.SHELL not in self.cache[symbol_id]:
            symbol_type_info = self._get_type_info_symbol(symbol_id)
            symbol_obj = self.cache[symbol_id][self.OBJ]
            self.cache[symbol_id][self.SHELL] = {
                'type': symbol_type_info.type_name,
                'str': symbol_type_info.str_fn(symbol_obj),
                'name': name,
                'data': None,
            }
        return self.cache[symbol_id][self.SHELL]

    def get_namespace_shells(self, namespace):
        """Get lightweight shell representations for all objects defined in the given namespace dict.

        This function should generally be used when the state of the runtime has changed. The cache is updated to
        associate the objects in the given namespace with their symbol IDs. Future implementations may
        retain information from step to step, but currently the cache is wiped when this function is called to
        prevent accidental ID collisions between destroyed objects and new objects with the same ID.

        Args:
            namespace (dict): A mapping of string names to Python objects.

        Returns:
            (dict): A dict mapping symbol ID strings to shell dictionaries (see get_symbol_shell and above
                documentation for more info).
        """
        self.reset_cache()
        namespace_shells = dict()
        for obj_name, obj in namespace.items():
            symbol_id = self._get_symbol_id(obj)
            self.cache[symbol_id][self.OBJ] = obj
            namespace_shells[self.REF_PREFIX + symbol_id] = self.get_symbol_shell(symbol_id, name=obj_name)
            if self._is_primitive(obj):
                data_obj, new_shells = self.get_symbol_data(symbol_id)
                self.cache[symbol_id][self.SHELL]['data'] = data_obj
                namespace_shells.update(new_shells)
        return namespace_shells

    def get_symbol_data(self, symbol_id):
        """Returns the symbol data object for a particular symbol, as well as the shells of any referenced symbols.

        The data object encapsulates all potentially useful information about a symbol. For a dict, this would
        be its contents; for a class, this might be its static fields and functions. Regardless, the data object
        should be serializable, such that it can be sent via socket to clients, who can decide how to process the
        given information.

        This function requires a shell to have already been generated for symbol_id and stored at
        cache[symbol_id][SHELL]. It uses, and fills if empty, cache[symbol_id][DATA] and cache[symbol_id][REFS]. REFS
        stores all symbol IDs referenced by the data object, and the shells of each such symbol are returned along
        with the data object.

        Args:
            symbol_id (str): The requested symbol's ID, as defined by self._get_symbol_id.

        Returns:
            (object): A serializable representation of the given symbol.
            (dict): A dict mapping symbol IDs (particuarly, those found in the data object) to shells.
        """
        if self.SHELL not in self.cache[symbol_id]:
            raise KeyError('Attempted to load data for {} before shell loaded.'.format(symbol_id))
        if self.DATA not in self.cache[symbol_id]:
            self.cache[symbol_id][self.DATA], self.cache[symbol_id][self.REFS] = self._load_symbol_data(symbol_id)
        shells = dict()
        for ref in self.cache[symbol_id][self.REFS]:
            shells[self.REF_PREFIX + ref] = self.get_symbol_shell(ref)
        return self.cache[symbol_id][self.DATA], shells

    def to_json(self, obj):
        """Converts a visualization dict to its corresponding JSON string.

        `obj` can be any output of the engine's exposed calls -- in particular, it can be either a symbol's shell or a
        symbol's data object. There is currently no difference in behavior, but for some more complex types (like
        Tensors) it may be required.

        See comment on generate for explanation of decomposition. to_json is a method of `VisualizationEngine` so that
        it can exploit the internal cache for object referencing if need be, as well as understand the engine's
        string escaping protocol. It should be called on the same engine where the dict was created.

        Args:
            obj (object): A Python object output by the `VisualizationEngine`.

        Returns:
            (str): The JSON representation of the input object.
        """
        return json.dumps(obj)

    def reset_cache(self):
        """Clear the cache completely, resetting the engine to its starting state."""
        self.cache.clear()


with open("day04_input.txt") as f:
    sections = f.readlines()

def section_contains_other(section1, section2):
    endpoints1 = section1.split("-")
    endpoints2 = section2.split("-")
    is_overlapping = int(endpoints1[0]) >= int(endpoints2[0]) and int(endpoints1[1]) <= int(endpoints2[1]) or \
                     int(endpoints2[0]) >= int(endpoints1[0]) and int(endpoints2[1]) <= int(endpoints1[1])
    return is_overlapping

def expand_section(section):
    expanded = set()
    endpoints = section.split("-")
    start = int(endpoints[0])
    end = int(endpoints[1])
    for i in range(start, end+1):
        expanded.add(i)
    return expanded

def containment_count(sections_list):
    total = 0
    for line in sections_list:
        parts = line.strip().split(",")
        overlaps = section_contains_other(parts[0], parts[1])
        if overlaps:
            total += 1
    return total

def overlap_count(sections_list):
    total = 0
    for line in sections_list:
        parts = line.strip().split(",")
        section1 = expand_section(parts[0])
        section2 = expand_section(parts[1])
        overlap = section1.intersection(section2)
        if len(overlap) > 0:
            total += 1
    return total

# puzzle 1
print(containment_count(sections))

# puzzle 2
print(overlap_count(sections))


"""
Nicholas Alderman
Countries Project - uses countriesClass
"""

import countriesClass as cc

search = cc.countrySearch('https://en.wikipedia.org/wiki/List_of_sovereign_states')

in1 = input("Enter the first letter of desired country, or type in name of country: ")
if (len(in1) == 1):
    search.letterSearchClass(in1)
    print(search.searchDf)
    name = input("Enter the index of desired country, or type in name of country: ")
    search.getNameClass(int(name))
else:
    in2 = search.df[search.df['Country'].str.match(in1)].reset_index()
    in3 = str(in2.iloc[0][1])
    search.getNameClass(in3)
search.processResultClass()

search.saveImageClass()


import os
import sys
import subprocess
import shutil

"""
    功能:
        1. 拷贝python的proto到go的对应目录之下
        2. 生成python的源码 - import .
        3. 生成go的源码
"""

class cd:
    def __init__(self, newPath):
        self.newPath = os.path.expanduser(newPath)

    def __enter__(self):
        self.savedPath = os.getcwd()
        os.chdir(self.newPath)

    def __exit__(self, etype, value, traceback):
        os.chdir(self.savedPath)

def replace_file(file_name):
    """
    添加 import .
    """
    new_file_name = f"{file_name}-bak"
    modify_times = 0  # 统计修改次数
    f1 = open(file_name, 'r', encoding='utf-8')  # 以“r”(只读)模式打开旧文件
    f2 = open(new_file_name, 'w', encoding='utf-8')  # 以“w”(写)模式打开或创建新文件（写模式下，文件存在则重写文件，文件不存在则创建文件）
    for lines in f1:  # 循环读
        if lines.startswith("import") and not lines.startswith("import grpc"):
            lines = f"from . {lines}"
            modify_times += 1  # 每修改一次就自增一次
        f2.write(lines)  # 将修改后的内容后的内容写入新文件
    print(f'{file_name} 文件修改的次数：', modify_times)  # 9
    f1.close()  # 关闭文件f1
    f2.close()  # 关闭文件f2(同时打开多个文件时，先打开的先关闭，后打开的后关闭)
    os.replace(new_file_name, file_name)  # 修改(替换)文件名

def proto_file_list(path):
    """
        返回这个文件夹 里的 proto文件
    """
    flist = []
    lsdir = os.listdir(path)        # 列举python proto目录的的文件名
    dirs = [i for i in lsdir if os.path.isdir(os.path.join(path, i))]   # 判断是否是 文件夹
    if dirs:
        for i in dirs:
            proto_file_list(os.path.join(path, i))                      # 递归调用
    files = [i for i in lsdir if os.path.isfile(os.path.join(path, i))] # 判断是否是 文件
    for file in files:
        if file.endswith(".proto"):     # 如果后缀名是 proto
            flist.append(file)
    return flist

def copy_from_py_to_go(src_dir, dst_dir):
    """
        src_dir 文件 复制到 dst_dir
    """
    proto_files = proto_file_list(src_dir)
    for proto_file in proto_files:
        try:
            shutil.copy(f"{src_dir}/{proto_file}", dst_dir)
        except IOError as e:
            print("Unable to copy file. %s" % e)
        except:
            print("Unexpected error:", sys.exc_info())

def generated_pyfile_list(path):
    """
        返回 生成后此文件夹中 py文件
    """
    flist = []
    lsdir = os.listdir(path)    # 列举python proto目录的的文件名
    dirs = [i for i in lsdir if os.path.isdir(os.path.join(path, i))]   # 筛选出 此文件下所有的 文件夹
    if dirs:
        for i in dirs:
            proto_file_list(os.path.join(path, i))          # 返回这个文件夹 里的 proto文件
    files = [i for i in lsdir if os.path.isfile(os.path.join(path, i))] # 判断是否是 文件
    for file in files:
        if file.endswith(".py"):        # 找到 .py文件
            flist.append(file)
    return flist

class ProtoGenerator:
    def __init__(self, python_dir, go_dir):
        self.python_dir = python_dir
        self.go_dir = go_dir

    def generate(self):
        with cd(self.python_dir["proto_file"]):
            files = proto_file_list(self.python_dir["proto_file"])
            subprocess.call(f"workon {self.python_dir['python_environment']}", shell=True)  # 启动的进程 然后执行 命令

            for file in files:
                command = f"python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. {file}"
                subprocess.call(command, shell=True)

            # 查询生成的py文件并添加上 from .
            py_files = generated_pyfile_list(self.python_dir["proto_file"])
            for file_name in py_files:
                replace_file(file_name)

        with cd(self.go_dir["proto_file"]):
            files = proto_file_list(self.go_dir["proto_file"])
            if self.go_dir['go_environment']:
                param = f" -I {self.go_dir['go_environment']}"
            else:
                param = ""
            for file in files:
                command = fr"protoc -I {self.go_dir['proto_file']} {param} --go_out=. --go-grpc_out=. {file}"
                subprocess.call(command)

if __name__ == "__main__":
    # goods的proto生成
    python_dir = {
        "proto_file": r"C:\Users\16255\Desktop\Python_Microservice\python-projects\mxshop_srvs\goods_srv\proto",
        "python_environment": "mxshop_srv"      # python的虚拟环境
    }
    go_dir = {
         "proto_file": r"C:\Users\16255\Desktop\Python_Microservice\go-projects\mxshop-api\goods-web\proto",
         "go_environment": r"C:\Users\16255\AppData\Local\JetBrains\GoLand2022.1\protoeditor"       # 如果不需要 就 换成空字符串
    }

    # 将py目录下的文件夹拷贝到go目录下
    copy_from_py_to_go(python_dir["proto_file"], go_dir["proto_file"])

    # 生成对应的py源码和go源码
    gen = ProtoGenerator(python_dir, go_dir)
    gen.generate()


import itertools
import random
from collections import defaultdict
from typing import List, Dict, Iterable

from splendor_ai import constants
from splendor_ai.entities.card import Card, CARD_VECTOR_SIZE
from splendor_ai.entities.gem_color import GemColor
from splendor_ai.entities.noble import Noble, NOBLE_VECTOR_SIZE

class Board:
    def __init__(self, num_players: int, cards: List[Card] = constants.FULL_DECK,
                 nobles: List[Noble] = constants.NOBLES):
        self.num_players = num_players
        num_nobles = num_players + 1
        nobles_selection = nobles.copy()
        random.shuffle(nobles_selection)
        self.nobles = nobles_selection[:num_nobles]

        cards_selection = cards.copy()
        random.shuffle(cards_selection)
        self.decks = defaultdict(list)
        for card in cards:
            self.decks[card.level].append(card)

        players_to_coins = {4: 7, 3: 5, 2: 4}
        num_coins = players_to_coins[num_players]

        self.coins = {
            GemColor.WHITE: num_coins,
            GemColor.RED: num_coins,
            GemColor.GREEN: num_coins,
            GemColor.BLUE: num_coins,
            GemColor.BLACK: num_coins,
            GemColor.JOKER: 5
        }

    @property
    def cards(self) -> Iterable[Card]:
        return itertools.chain(self.decks[1], self.decks[2], self.decks[3])

    @property
    def vectorized_state(self) -> List[int]:
        # vectorize the cards in the decks and in case deck is empty
        # append vectors of 0's
        vectorized_cards_level_1 = []
        vectorized_cards_level_2 = []
        vectorized_cards_level_3 = []
        for card in self.decks[1][:4]:
            vectorized_cards_level_1 += card.vectorized_state
        for card in self.decks[2][:4]:
            vectorized_cards_level_2 += card.vectorized_state
        for card in self.decks[3][:4]:
            vectorized_cards_level_3 += card.vectorized_state
        vectorized_cards_level_1 += [0] * CARD_VECTOR_SIZE * (4 - len(self.decks[1][:4]))
        vectorized_cards_level_2 += [0] * CARD_VECTOR_SIZE * (4 - len(self.decks[2][:4]))
        vectorized_cards_level_3 += [0] * CARD_VECTOR_SIZE * (4 - len(self.decks[3][:4]))

        # vectorize nobles
        vectorized_nobles = []
        for noble in self.nobles:
            vectorized_nobles += noble.vectorized_state
        vectorized_nobles += [0] * NOBLE_VECTOR_SIZE * (self.num_players + 1 - len(self.nobles))

        return [self.coins[GemColor.WHITE], self.coins[GemColor.RED], self.coins[GemColor.BLUE],
                self.coins[GemColor.GREEN], self.coins[GemColor.BLACK], self.coins[GemColor.JOKER]
                ] + vectorized_cards_level_1 + vectorized_cards_level_2 + vectorized_cards_level_3 + vectorized_nobles

    @property
    def open_cards(self) -> Iterable[Card]:
        return itertools.chain(self.decks[1][:4], self.decks[2][:4], self.decks[3][:4])


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

import re
import random
import logging
from abc import abstractmethod

EXAM_GOODS_CODE_MATCH_LENGTH = 4

ExamCondition = ['报关单号', '进出口岸', '运输方式', '提单号', '标记唛码及备注', '集装箱号', '商品编码', '布控要求', '布控理由', '备注']

ExamModeCodes = {
    '核对品名': '01', '核对规格': '02', '核对数量': '03', '核对重量': '04', '核对件数': '05', '核对唛头': '06', '是否侵权': '07',
    '核产终地': '08', '核对归类': '09', '核对新旧': '10', '核对价格': '11', '取样送检': '12', '检查车体': '13', '检查箱体': '14', '是否夹藏': '15'}

LocalModeCodes = {'简易抽查': '16', '常规抽查': '17', '重点抽查': '18', '机动查验': '19', '复验': '20', 'X光机检查': '21', '三个一': '22',
                  '核对品牌': '23', 'H986': '24', 'FS6000': '25', '核对体积': '26'}

ExamMethod = {'A': 'A', 'B': 'B', 'B1': 'B1', 'B2': 'B2', 'B3': 'B3', 'C': 'C', 'J': 'J', 'X': 'X'}

MachineExamCode = {'84159090', '841510', '841810', '841820', '841830', '841840', '841850', '852871', '852872', '851420',
                   '851821', '851822', '851829', '851410', '851420', '732111', '732112', '732119', '732181', '853922',
                   '853950', '940510', '940520', '940530', '940540', '401110', '401120', '401140', '401180', '401190',
                   '08039000', '08043000', '08105000', '08106000', '08054000', '08061000', '02064900', '02032900',
                   '02071421', '02071422', '470710', '470720', '470730'}

def is_starts_within(set_A, set_B):
    for a in set_A:
        found = False
        for b in set_B:
            if a.startswith(b):
                found = True
                break
        if not found:
            return False
    return True

class Classifier(object):
    @abstractmethod
    def classify(self, inputs):
        pass

class IOPortClassifier(Classifier):
    def __init__(self):
        self.name = '进出口岸'

    def classify(self, inputs: dict):
        if inputs['进出口岸'] == '南沙海关南沙港区监管点':
            if not inputs['集装箱号']:
                return '3'
            if inputs['标记唛码及备注'].find("散货码头") != -1:
                return '2'
            else:
                return '1'
        else:
            return '3'

class RequirementClassifier(Classifier):
    def __init__(self):
        self.name = '布控指令类型'

    def classify(self, inputs: dict):
        if inputs['布控要求'] == '查验单货是否相符':
            return '2'
        else:
            return '1'

class GoodsClassifier(Classifier):
    def __init__(self):
        self.name = '商品编码'

    def classify(self, inputs: dict):
        goods = frozenset(map(lambda a: a[:EXAM_GOODS_CODE_MATCH_LENGTH], inputs['商品编码']))
        if len(goods) == 1 and '4707' in goods:  # 废纸
                return '4'

        if inputs['标记唛码及备注'].find('危') != -1 or is_starts_within(goods, {
                '0801', '0802', '0803', '0804', '0805', '0806', '0807', '0808', '0809', '0810', '0813'
                }) or is_starts_within(goods, {'02', '03', '04', '05'}):  # 危险品 or 冻品 or 水果
            return '3'
        elif inputs['标记唛码及备注'].find('拼柜') != -1 or len(goods) > 3:
            return '2'
        elif len(goods) <= 3 and inputs['标记唛码及备注'].find('拼柜') == -1:
            return '1'
        else:
            return '0'

class GoodsClassifier2(Classifier):
    def __init__(self):
        self.name = '机检直放列表'

    def classify(self, inputs: dict):
        goods = inputs['商品编码']
        if is_starts_within(goods, MachineExamCode):
            return '1'
        else:
            return '0'

class CommandClassifier(Classifier):
    def __init__(self):
        self.name = '指令类型'

    def classify(self, inputs: dict):
        reqs = frozenset(filter(None, map(lambda a: a.strip(), re.split(r"[,，]", inputs['布控要求']))))

        if reqs.isdisjoint({'检查箱体', '核对重量', '是否夹藏'}):
            return '2'
        else:
            return '1'

class ExamPolicy(object):

    def __init__(self):
        self.classifiers = [IOPortClassifier(), RequirementClassifier(), GoodsClassifier(), CommandClassifier(),
                            GoodsClassifier2()]
        self.logger = logging.getLogger("ExamPolicy")

    def dense_layer(self, conditions, classification):
        reqs = set(filter(None, map(lambda a: a.strip(), re.split(r"[,，]", conditions['布控要求'])))).difference({'查验单货是否相符'})
        if not reqs.issubset(ExamModeCodes.keys()):
            return None

        if classification.startswith('1111'):
            self.logger.info("判断结果: 5166, 具体布控要求, 商品编码3项或以下，不拼柜，不含3项指令 | 机检")
            ret = {
                'ExamModeCodes': reqs,
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'}
            }

        elif classification.startswith('1112'):
            self.logger.info("判断结果: 5166, 具体布控要求, 商品编码3项或以下，不拼柜，含3项指令之一 | 人工抽查")
            ret = {
                'ExamModeCodes': reqs,
                'LocalModeCodes': {'常规抽查'},
                'ExamMethod': {'B'}
            }

        elif classification.startswith('112'):
            self.logger.info("判断结果: 5166, 具体布控要求, 商品编码3项以上，或拼柜，含3项指令之一 | 人工抽查")
            ret = {
                'ExamModeCodes': reqs,
                'LocalModeCodes': {'常规抽查'},
                'ExamMethod': {'B'}
            }

        elif classification.startswith('113'):  # 危险品 冻品 水果
            self.logger.info("判断结果: 5166, 具体布控要求, 危险品冻品水果 | 机检")
            ret = {
                'ExamModeCodes': reqs,
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'}
            }

        elif classification.startswith('114'):  # 废纸
            self.logger.info("判断结果: 5166, 具体布控要求, 废纸 | 机检，非随机选箱")
            ret = {
                'ExamModeCodes': reqs.union({'核对品名'}),
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'},
                'Extra': {'NoRandomContainer'}
            }

        elif re.fullmatch('121.1', classification) is not None:
            self.logger.info("判断结果: 5166, 无具体指令, 商品编码3项或以下，不拼柜，直放列表内 | 机检，核对品名、核对重量、检查箱体、是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '是否夹藏', '核对品名', '检查箱体'},
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'}
            }

        elif re.fullmatch('121.0', classification) is not None:
            self.logger.info("判断结果: 5166, 无具体指令, 商品编码3项或以下，不拼柜，非直放列表内 | 机检，核对重量、检查箱体、是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '是否夹藏', '检查箱体'},
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'}
            }

        elif classification.startswith('122'):
            self.logger.info("判断结果: 5166, 无具体指令, 商品编码3项以上，或拼柜，非直放列表内 | 人工抽查，核对品名、核对重量、是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '是否夹藏', '核对品名'},
                'LocalModeCodes': {'常规抽查'},
                'ExamMethod': {'B'}
            }

        elif re.fullmatch('123.1', classification) is not None:  # 属于机检直放目录
            self.logger.info("判断结果: 5166, 无具体指令, 危险品水果冻品，直放列表内 | 机检，核对品名、核对重量、检查箱体、是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '是否夹藏', '核对品名', '检查箱体'},
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'}
            }

        elif re.fullmatch('123.0', classification) is not None:
            self.logger.info("判断结果: 5166, 无具体指令, 危险品水果冻品，非直放列表内 | 机检，核对重量、检查箱体、是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '是否夹藏', '检查箱体'},
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'}
            }

        elif re.fullmatch('124.1', classification) is not None:  # 属于机检直放目录
            self.logger.info("判断结果: 5166, 无具体指令, 废纸, 直放列表内 | 机检，核对品名、核对重量、检查箱体、是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '是否夹藏', '核对品名', '检查箱体'},
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'},
                'Extra': {'NoRandomContainer'}
            }

        elif re.fullmatch('124.0', classification) is not None:
            self.logger.info("判断结果: 5166, 无具体指令, 废纸，非直放列表内 | 机检，核对重量、检查箱体、是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '是否夹藏', '检查箱体'},
                'LocalModeCodes': {'FS6000'},
                'ExamMethod': {'J'},
                'Extra': {'NoRandomContainer'}
            }

        elif classification.startswith('21'):
            self.logger.info("判断结果: 5166散货码头, 具体布控要求 | 人工抽查")
            ret = {
                'ExamModeCodes': reqs,
                'LocalModeCodes': {'常规抽查'},
                'ExamMethod': {'B'}
            }

        elif classification.startswith('22'):
            self.logger.info("判断结果: 5166散货码头, 无具体指令 | 人工抽查，核对重量, 核对品名, 核对规格")
            ret = {
                'ExamModeCodes': {'核对重量', '核对品名', '核对规格'},
                'LocalModeCodes': {'常规抽查'},
                'ExamMethod': {'B'}
            }

        elif classification.startswith('31'):
            self.logger.info("判断结果: 5165, 具体布控要求 | 人工抽查")
            ret = {
                'ExamModeCodes': reqs,
                'LocalModeCodes': {'常规抽查'},
                'ExamMethod': {'B'}
            }

        elif classification.startswith('32'):
            self.logger.info("判断结果: 5165, 无具体指令 | 人工抽查，核对重量, 核对品名, 是否夹藏")
            ret = {
                'ExamModeCodes': {'核对重量', '核对品名', '是否夹藏'},
                'LocalModeCodes': {'常规抽查'},
                'ExamMethod': {'B'}
            }

        else:
            self.logger.info("判断结果: 无法判断")
            return None

        if conditions['备注'].find('重量') != -1:
            ret['ExamModeCodes'].add('核对重量')

        if conditions['布控理由'].find('不少于三项') != -1:
            remaining = ['检查箱体', '核对重量', '是否夹藏']
            random.shuffle(remaining)

            while len(ret['ExamModeCodes']) < 3:
                cmd = remaining.pop()
                ret['ExamModeCodes'].add(cmd)

        if (len(reqs) > 5 and 'B' in ret['ExamMethod']) or conditions['布控理由'].find("失信") != -1:
            ret['ExamMethod'].discard('B2')
            ret['ExamMethod'].add('B3')
            ret['LocalModeCodes'].discard('常规抽查')
            ret['LocalModeCodes'].add('重点抽查')

        return ret

    def evaluate(self, inputs):
        classification = ''.join([c.classify(inputs) for c in self.classifiers])
        self.logger.debug("Classified result: {0}".format(classification))
        outputs = self.dense_layer(inputs, classification)
        return outputs


#!/usr/bin/env python3

import sys

from bluetooth.ble import GATTRequester

# GATTRequester(addr, do_connect=True, device="hci0")
req = GATTRequester("DC:99:65:B8:F1:F6", False)

# connect(wait=False,channel_type="public",security_level="low", psm=0, mtu=0)
print("connecting...")
req.connect(True, channel_type="random")
print("ok")
val = req.read_by_uuid("00002a00-0000-1000-8000-00805f9b34fb")
print(val)

# req.write_cmd(0x13, bytes([0xa]))
# print("write done")


#
# @lc app=leetcode.cn id=82 lang=python3
#
# [82] 删除排序链表中的重复元素 II
#
# https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/description/
#
# algorithms
# Medium (48.49%)
# Likes:    328
# Dislikes: 0
# Total Accepted:    57.1K
# Total Submissions: 117.6K
# Testcase Example:  '[1,2,3,3,4,4,5]'
#
# 给定一个排序链表，删除所有含有重复数字的节点，只保留原始链表中 没有重复出现 的数字。
#
# 示例 1:
#
# 输入: 1->2->3->3->4->4->5
# 输出: 1->2->5
#
#
# 示例 2:
#
# 输入: 1->1->1->2->3
# 输出: 2->3
#
#

# @lc code=start
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head

        dummy = ListNode(float('inf'))
        dummy.next = head
        slow,fast = dummy,head.next

        while fast:
            if slow.next.val != fast.val:
                slow = slow.next
                fast = fast.next
            else:
                while fast and slow.next.val == fast.val:
                    fast = fast.next

                slow.next = fast
                fast = fast.next  if fast else None

        return dummy.next


bekertMozgas = []
def Penzmozgas():
    for i in range(12): bekertMozgas.append(int(input()))

def Bankszamla(mozgas):
    egyenleg = 0
    for i in range(len(mozgas)):
        if i != 0: egyenleg -= 2000 # januar kivetel
        egyenleg += mozgas[i]
        if egyenleg < 0: egyenleg = int(egyenleg * 1.1) # negativ
        elif egyenleg > 0: egyenleg = int(egyenleg * 1.05) # pozitiv
    return egyenleg

def SzamlaNelkul(mozgas):
    egyenleg = 0
    for i in mozgas: egyenleg += i
    return egyenleg

Penzmozgas()
print(Bankszamla(bekertMozgas[:]))
print(SzamlaNelkul(bekertMozgas[:]))


from openerp import fields, models, api, _
import openerp.addons.decimal_precision as dp

class account_invoice_line(models.Model):
    _inherit = 'account.invoice.line'

    second_quantity = fields.\
        Float('Second Quantity',
              digits= dp.get_precision('Product Unit of Measure'))
    second_uom_id = fields.Many2one('product.uom', 'Second UoM')

    @api.onchange('second_uom_id')
    def on_change_second_uom_id(self):
        uom_obj = self.env['product.uom']
        if self.uos_id and self.second_uom_id and not self.second_quantity:
            self.second_quantity = uom_obj.\
                _compute_qty(self.uos_id.id, self.quantity,
                             self.second_uom_id.id)

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:


import subprocess
import os
import time
def kill_all_tmux(group_name):
    with open(f'{group_name}-sessions','r') as f:
        for line in f:
            session_name = line.strip()
            subprocess.run(f"tmux kill-session -t {session_name}",shell=True)

def view_all_logs(group_name):
    log_names = []
    with open(f'{group_name}-tmux-logs','r') as f:
        for line in f:
            log_name = line.strip()
            log_names.append(log_name)
            # subprocess.run(f"tmux attach -t {log_name}",shell=True)
    while True:
        command=''
        for log_name in log_names:
            command += f'echo "{log_name}\n"; tail -n 7 {log_name}; printf "\n\n";'
            # os.system(f'tail -n 5 {log_name}')
            # print('\n'*2)
        # clear screen and rerun command in endless loop
        os.system(command)
        time.sleep(2)
        os.system('clear')
def get_method_model_alias(session_name):
    methods_and_alias = {
                'scorecam':'s',
               'relevancecam':'r',
               'gradcam':'g',
               'gradcampp':'gpp',
               'gpnn-gradcam':'gg',
               'gpnn-gradcampp':'ggpp',
               'gpnn-relevancecam':'gr',
               'gpnn-gradcam-uniform':'ggu',
               'cameras':'c',
               'layercam':'l',
    }
    models_and_alias = {
            'vgg16':'16',
              'resnet50':'50',
    }
    # detect which method in session_name:
    #-------------------------------------------------------------
    import itertools
    methods = methods_and_alias.keys()
    method_alias = methods_and_alias.values()
    models = models_and_alias.keys()
    model_alias = models_and_alias.values()
    method_model_combinations = itertools.product(methods,models)
    alias_combinations = itertools.product(method_alias,model_alias)
    found = None
    alias_found = None
    for mm,alias in zip(method_model_combinations,alias_combinations):
        # method,model = mm
        # if method in session_name and model in session_name:
        #     return method,model
        mm = '-'.join(mm)
        alias = ''.join(alias)
        # print(mm,session_name)
        if mm in session_name:
            # assert found == None
            if found !=None:
                if len(mm) < len(found):
                    continue
            found = mm
            alias_found = alias
    # import ipdb;ipdb.set_trace()
    return alias_found
    #-------------------------------------------------------------

def create_alias(session_name):
    # print(f"alias {session_name}='tmux attach -t {session_name}'")
    alias = ''
    if 'pascal' in session_name:
        alias += 'p'
    if session_name.startswith('t-metrics'):
        # session_name = session_name[2:]
        # def get_metrics_alias(session_name):
        alias = 'm'
        if 'chattopadhyay' in session_name:
            alias += 'c'
        elif 'perturbation' in session_name:
            alias += 'p'
        mm_alias = get_method_model_alias(session_name)
        alias += mm_alias

    else:
        mm_alias = get_method_model_alias(session_name)
        alias += mm_alias
    print(alias)
    return alias
def create_aliases(group_name):
    sessions_filename = f'{group_name}-sessions'
    alias_commands= []
    with open (sessions_filename,'r') as f:
        for line in f:
            session_name = line.strip()
            alias = create_alias(session_name)
            alias_command = f"export {alias}={session_name}\n"
            alias_commands.append(alias_command)
            # print(f"alias {session_name}='tmux attach -t {session_name}'")
    # assert False
    with open(f"{group_name}-aliases",'w') as f:
        for c in alias_commands:
            f.write(c)

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--kill', action='store_true',default=False)
parser.add_argument('--view', action='store_true',default=False)
parser.add_argument('--alias', action='store_true',default=False)
parser.add_argument('--group', type=str, default=None)
args = parser.parse_args()
if args.kill:
    kill_all_tmux(args.group)
if args.view:
    view_all_logs(args.group)
if args.alias:
    create_aliases(args.group)


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

import os
import re
import time
import logging
import pdfkit
import requests
from bs4 import BeautifulSoup
from PyPDF2 import PdfFileMerger
import os.path
import shutil
from datetime import date

html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
{content}
</body>
</html>

"""

def get_url_list():
    response = requests.get("http://vitalik.ca//")
    soup = BeautifulSoup(response.content, "html.parser")
    urls = []
    for v in soup.find_all(class_="post-link"):
        url = "http://vitalik.ca/" + v.get('href')
        urls.append(url)
    return urls

def parse_url_to_html(url, name):
    try:
        response = requests.get(url)
        soup = BeautifulSoup(response.content, 'html.parser')

        inner = soup.find_all(class_="markdown-body")
        if inner.__len__() == 0:
            return False

        body = inner[0]

        body.find("div", {"id": "color-mode-switch"}).decompose()

        for img in body.find_all("img"):
            img_style = img.get("style")
            style = "display: block; margin-left: auto; margin-right: auto;"
            if img_style is not None:
                style += img_style
            img['style'] = style

        html = str(body)

        pattern = "(<img .*?src=\")(.*?)(\")"
        def func(m):
            return m.group(0).replace("../../../..", "https://vitalik.ca")
        html = re.compile(pattern).sub(func, html)

        html = html_template.format(content=html)
        with open(name, 'wb') as f:
            f.write(html.encode())
        return True

    except Exception as e:
        logging.error("parse error ", exc_info=True)

def save_pdf(htmls, file_name):
    options = {
        'page-size': 'A4',
        'margin-top': '0.75in',
        'margin-right': '0.75in',
        'margin-bottom': '0.75in',
        'margin-left': '0.75in',
        'encoding': "UTF-8",
        'custom-header': [
            ('Accept-Encoding', 'gzip')
        ],
        'cookie': [
            ('cookie-name1', 'cookie-value1'),
            ('cookie-name2', 'cookie-value2'),
        ],
        'minimum-font-size': 14,
    }
    try:
        pdfkit.from_file(htmls, file_name, options=options)
    except Exception as e:
        logging.error("covert error ", exc_info=True)

def main():
    shutil.rmtree("html") if os.path.exists("html") else None
    os.mkdir("html") if not os.path.exists("html") else None
    shutil.rmtree("pdf") if os.path.exists("pdf") else None
    os.mkdir("pdf") if not os.path.exists("pdf") else None

    start = time.time()
    urls = get_url_list()
    wrongUrl = []
    for index, url in enumerate(urls):
        name = str(index) + ".html"
        name = os.path.join("html", name)
        res = parse_url_to_html(url, name)
        if res is False:
            wrongUrl.append(str(index))
        print(u"download " + str(index) + ' html')

    htmls = []
    pdfs = []
    print("wrongUrl", wrongUrl)
    for i in range(0, urls.__len__()):
        if str(i) in wrongUrl:
            continue
        htmlName = str(i) + ".html"
        htmlName = os.path.join("html", htmlName)
        name = str(i) + '.pdf'
        name = os.path.join("pdf", name)
        htmls.append(htmlName)
        pdfs.append(name)

        save_pdf(htmlName, name)
        print(u"covert " + str(i) + ' html')

    merger = PdfFileMerger()
    for pdf in pdfs:
        merger.append(open(pdf, 'rb'))
        print(u"merge " + str(i) + ' pdf')

    todays_date = date.today()
    #name = "vitalik-blog-" + str(todays_date) + ".pdf"
    name = "vitalik-blog.pdf"
    output = open(name, "wb")
    merger.write(output)

    print(u"success")

    # for html in htmls:
    #     os.remove(html)
    #     print(u"delete " + html)

    # for pdf in pdfs:
    #     os.remove(pdf)
    #     print(u"delete " + pdf)

    total_time = time.time() - start
    print(u"total spend：%f second" % total_time)

if __name__ == '__main__':
    main()


#Altere o programa anterior, intercalando 3 vetores de 10 elementos cada

pri = []
seg = []
ter = []
for e in range(30):
    if e < 10:
        num = int(input(f'{e+1}º valor do primeiro vetor: '))
        pri.append(num)
    elif 10<= e < 20:
        num = int(input(f'{e-9}º valor do segundo vetor: '))
        seg.append(num)
    else:
        num = int(input(f'{e-19}º valor do terceiro vetor: '))
        ter.append(num)

for i, v in enumerate(pri):
    print(f'{v},{seg[i]},{ter[i]},', end='')


from durable.lang import *
import datetime
import random
import sys

with statechart('fraud0'):
    with state('start'):
        to('standby')

    with state('standby'):
        @to('metering')
        @when_all(m.amount > 100)
        def start_metering(c):
            c.start_timer('velocity', 30)

    with state('metering'):
        @to('fraud')
        @when_all(m.amount > 100, count(2))
        def report_fraud(c):
            print('fraud0 detected')

        @to('standby')
        @when_all(timeout('velocity'))
        def clear_fraud(c):
            print('fraud0 cleared')

    state('fraud')

    @when_start
    def start(host):
        host.post('fraud0', {'id': 1, 'sid': 1, 'amount': 200})
        host.post('fraud0', {'id': 2, 'sid': 1, 'amount': 200})
        host.post('fraud0', {'id': 3, 'sid': 1, 'amount': 200})

with ruleset('fraud1'):
    @when_all(c.first << m.t == 'purchase',
              c.second << m.location != c.first.location)
    def detected(c):
        print ('fraud1 detected {0}, {1}'.format(c.first.location, c.second.location))

    @when_start
    def start(host):
        host.post('fraud1', {'id': 1, 'sid': 1, 't': 'purchase', 'location': 'US'})
        host.post('fraud1', {'id': 2, 'sid': 1, 't': 'purchase', 'location': 'CA'})

with ruleset('fraud2'):
    @when_all(c.first << m.amount > 10,
              c.second << m.amount > c.first.amount * 2)
    def detected(c):
        print('fraud2 detected {0}, {1}'.format(c.first.amount, c.second.amount))

    @when_start
    def start(host):
        host.post('fraud2', {'id': 1, 'sid': 1, 'amount': 50})
        host.post('fraud2', {'id': 2, 'sid': 1, 'amount': 150})

with ruleset('fraud3'):
    @when_all(c.first << m.amount > 100,
              c.second << m.amount > c.first.amount,
              c.third << m.amount > c.second.amount,
              c.fourth << m.amount > (c.first.amount + c.second.amount + c.third.amount) / 3)
    def detected(c):
        print('fraud3 detected -> {0}'.format(c.first.amount))
        print('                -> {0}'.format(c.second.amount))
        print('                -> {0}'.format(c.third.amount))
        print('                -> {0}'.format(c.fourth.amount))

    @when_start
    def start(host):
        host.post('fraud3', {'id': 1, 'sid': 1, 'amount': 101})
        host.post('fraud3', {'id': 2, 'sid': 1, 'amount': 102})
        host.post('fraud3', {'id': 3, 'sid': 1, 'amount': 103})
        host.post('fraud3', {'id': 4, 'sid': 1, 'amount': 104})

with ruleset('fraud4'):
    @when_all(pri(3), m.amount < 300)
    def first_detect(c):
        print('fraud4 first detect {0}'.format(c.m.amount))

    @when_all(pri(2), m.amount < 200)
    def second_detect(c):
        print('fraud4 second detect {0}'.format(c.m.amount))

    @when_all(pri(1), m.amount < 100)
    def third_detect(c):
        print('fraud4 third detect {0}'.format(c.m.amount))

    @when_start
    def start(host):
        host.post('fraud4', {'id': 1, 'sid': 1, 'amount': 50})
        host.post('fraud4', {'id': 2, 'sid': 1, 'amount': 150})
        host.post('fraud4', {'id': 3, 'sid': 1, 'amount': 250})

with ruleset('fraud5'):
    @when_all(c.first << m.t == 'purchase',
              c.second << m.location != c.first.location,
              count(2))
    def detected(c):
        print ('fraud5 detected {0}, {1}'.format(c.m[0].first.location, c.m[0].second.location))
        print ('               {0}, {1}'.format(c.m[1].first.location, c.m[1].second.location))

    @when_start
    def start(host):
        host.assert_fact('fraud5', {'id': 1, 'sid': 1, 't': 'purchase', 'location': 'US'})
        host.assert_fact('fraud5', {'id': 2, 'sid': 1, 't': 'purchase', 'location': 'CA'})

with ruleset('fraud6'):
    @when_all(pri(3), count(3), m.amount < 300)
    def first_detect(c):
        print('fraud6 first detect ->{0}'.format(c.m[0].amount))
        print('                    ->{0}'.format(c.m[1].amount))
        print('                    ->{0}'.format(c.m[2].amount))

    @when_all(pri(2), count(2), m.amount < 200)
    def second_detect(c):
        print('fraud6 second detect ->{0}'.format(c.m[0].amount))
        print('                     ->{0}'.format(c.m[1].amount))

    @when_all(pri(1), m.amount < 100)
    def third_detect(c):
        print('fraud6 third detect ->{0}'.format(c.m.amount))

    @when_start
    def start(host):
        host.assert_fact('fraud6', {'id': 1, 'sid': 1, 'amount': 50})
        host.assert_fact('fraud6', {'id': 2, 'sid': 1, 'amount': 150})
        host.assert_fact('fraud6', {'id': 3, 'sid': 1, 'amount': 250})

with ruleset('fraud7'):
    @when_all(c.first << m.t == 'deposit',
              none(m.t == 'balance'),
              c.third << m.t == 'withrawal',
              c.fourth << m.t == 'chargeback')
    def detected(c):
        print('fraud7 detected {0}, {1}, {2}'.format(c.first.t, c.third.t, c.fourth.t))

    @when_start
    def start(host):
        host.post('fraud7', {'id': 1, 'sid': 1, 't': 'deposit'})
        host.post('fraud7', {'id': 2, 'sid': 1, 't': 'withrawal'})
        host.post('fraud7', {'id': 3, 'sid': 1, 't': 'chargeback'})
        host.assert_fact('fraud7', {'id': 4, 'sid': 1, 't': 'balance'})
        host.post('fraud7', {'id': 5, 'sid': 1, 't': 'deposit'})
        host.post('fraud7', {'id': 6, 'sid': 1, 't': 'withrawal'})
        host.post('fraud7', {'id': 7, 'sid': 1, 't': 'chargeback'})
        host.retract_fact('fraud7', {'id': 4, 'sid': 1, 't': 'balance'})

with ruleset('a0'):
    @when_all((m.subject == 'go') | (m.subject == 'approve') | (m.subject == 'ok'))
    def approved(c):
        print ('a0 approved ->{0}'.format(c.m.subject))

    @when_start
    def start(host):
        host.post('a0', {'id': 1, 'sid': 1, 'subject': 'approve'})
        host.post('a0', {'id': 2, 'sid': 2, 'subject': 'go'})
        host.post('a0', {'id': 3, 'sid': 3, 'subject': 'ok'})

with ruleset('a1'):
    @when_all((m.subject == 'approve') & (m.amount > 1000))
    def denied(c):
        print ('a1 denied from: {0}'.format(c.s.sid))
        c.s.status = 'done'

    @when_all((m.subject == 'approve') & (m.amount <= 1000))
    def request(c):
        print ('a1 request approval from: {0}'.format(c.s.sid))
        c.s.status = 'pending'

    @when_all(m.subject == 'approved', s.status == 'pending')
    def second_request(c):
        print ('a1 second request approval from: {0}'.format(c.s.sid))
        c.s.status = 'approved'

    @when_all(s.status == 'approved')
    def approved(c):
        print ('a1 approved from: {0}'.format(c.s.sid))
        c.s.status = 'done'

    @when_all(m.subject == 'denied')
    def denied(c):
        print ('a1 denied from: {0}'.format(c.s.sid))
        c.s.status = 'done'

    @when_start
    def start(host):
        host.post('a1', {'id': 1, 'sid': 1, 'subject': 'approve', 'amount': 100})
        host.post('a1', {'id': 2, 'sid': 1, 'subject': 'approved'})
        host.post('a1', {'id': 3, 'sid': 2, 'subject': 'approve', 'amount': 100})
        host.post('a1', {'id': 4, 'sid': 2, 'subject': 'denied'})
        host.post('a1', {'id': 5, 'sid': 3, 'subject': 'approve', 'amount': 10000})

with statechart('a2'):
    with state('input'):
        @to('denied')
        @when_all((m.subject == 'approve') & (m.amount > 1000))
        def denied(c):
            print ('a2 denied from: {0}'.format(c.s.sid))

        @to('pending')
        @when_all((m.subject == 'approve') & (m.amount <= 1000))
        def request(c):
            print ('a2 request approval from: {0}'.format(c.s.sid))

    with state('pending'):
        @to('pending')
        @when_all(m.subject == 'approved')
        def second_request(c):
            print ('a2 second request approval from: {0}'.format(c.s.sid))
            c.s.status = 'approved'

        @to('approved')
        @when_all(s.status == 'approved')
        def approved(c):
            print ('a2 approved from: {0}'.format(c.s.sid))

        @to('denied')
        @when_all(m.subject == 'denied')
        def denied(c):
            print ('a2 denied from: {0}'.format(c.s.sid))

    state('denied')
    state('approved')
    @when_start
    def start(host):
        host.post('a2', {'id': 1, 'sid': 1, 'subject': 'approve', 'amount': 100})
        host.post('a2', {'id': 2, 'sid': 1, 'subject': 'approved'})
        host.post('a2', {'id': 3, 'sid': 2, 'subject': 'approve', 'amount': 100})
        host.post('a2', {'id': 4, 'sid': 2, 'subject': 'denied'})
        host.post('a2', {'id': 5, 'sid': 3, 'subject': 'approve', 'amount': 10000})

with flowchart('a3'):
    with stage('input'):
        to('request').when_all((m.subject == 'approve') & (m.amount <= 1000))
        to('deny').when_all((m.subject == 'approve') & (m.amount > 1000))

    with stage('request'):
        @run
        def request(c):
            print ('a3 request approval from: {0}'.format(c.s.sid))
            if c.s.status:
                c.s.status = 'approved'
            else:
                c.s.status = 'pending'

        to('approve').when_all(s.status == 'approved')
        to('deny').when_all(m.subject == 'denied')
        to('request').when_all(m.subject == 'approved')

    with stage('approve'):
        @run
        def approved(c):
            print ('a3 approved from: {0}'.format(c.s.sid))

    with stage('deny'):
        @run
        def denied(c):
            print ('a3 denied from: {0}'.format(c.s.sid))

    @when_start
    def start(host):
        host.post('a3', {'id': 1, 'sid': 1, 'subject': 'approve', 'amount': 100})
        host.post('a3', {'id': 2, 'sid': 1, 'subject': 'approved'})
        host.post('a3', {'id': 3, 'sid': 2, 'subject': 'approve', 'amount': 100})
        host.post('a3', {'id': 4, 'sid': 2, 'subject': 'denied'})
        host.post('a3', {'id': 5, 'sid': 3, 'subject': 'approve', 'amount': 10000})

with ruleset('a4'):
    @when_any(all(m.subject == 'approve', m.amount == 1000),
              all(m.subject == 'jumbo', m.amount == 10000))
    def action(c):
        print ('a4 action {0}'.format(c.s.sid))

    @when_start
    def start(host):
        host.post('a4', {'id': 1, 'sid': 1, 'subject': 'approve'})
        host.post('a4', {'id': 2, 'sid': 1, 'amount': 1000})
        host.post('a4', {'id': 3, 'sid': 2, 'subject': 'jumbo'})
        host.post('a4', {'id': 4, 'sid': 2, 'amount': 10000})

with ruleset('a5'):
    @when_all(any(m.subject == 'approve', m.subject == 'jumbo'),
              any(m.amount == 100, m.amount == 10000))
    def action(c):
        print ('a5 action {0}'.format(c.s.sid))

    @when_start
    def start(host):
        host.post('a5', {'id': 1, 'sid': 1, 'subject': 'approve'})
        host.post('a5', {'id': 2, 'sid': 1, 'amount': 100})
        host.post('a5', {'id': 3, 'sid': 2, 'subject': 'jumbo'})
        host.post('a5', {'id': 4, 'sid': 2, 'amount': 10000})

with statechart('a6'):
    with state('work'):
        with state('enter'):
            @to('process')
            @when_all(m.subject == 'enter')
            def continue_process(c):
                print('a6 continue_process')

        with state('process'):
            @to('process')
            @when_all(m.subject == 'continue')
            def continue_process(c):
                print('a6 processing')

        @to('work')
        @when_all(m.subject == 'reset')
        def reset(c):
            print('a6 resetting')

        @to('canceled')
        @when_all(m.subject == 'cancel')
        def cancel(c):
            print('a6 canceling')

    state('canceled')
    @when_start
    def start(host):
        host.post('a6', {'id': 1, 'sid': 1, 'subject': 'enter'})
        host.post('a6', {'id': 2, 'sid': 1, 'subject': 'continue'})
        host.post('a6', {'id': 3, 'sid': 1, 'subject': 'continue'})

with ruleset('a7'):
    @when_all(m.amount < c.s.max_amount)
    def approved(c):
        print ('a7 approved {0}'.format(c.m.amount))

    @when_start
    def start(host):
        host.patch_state('a7', {'sid': 1, 'max_amount': 100})
        host.post('a7', {'id': 1, 'sid': 1, 'amount': 10})
        host.post('a7', {'id': 2, 'sid': 1, 'amount': 100})

with ruleset('a8'):
    @when_all((m.amount < c.s.max_amount) & (m.amount > c.s.id('global').min_amount))
    def approved(c):
        print ('a8 approved {0}'.format(c.m.amount))

    @when_start
    def start(host):
        host.patch_state('a8', {'sid': 1, 'max_amount': 500})
        host.patch_state('a8', {'sid': 'global', 'min_amount': 300})
        host.post('a8', {'id': 1, 'sid': 1, 'amount': 400})
        host.post('a8', {'id': 2, 'sid': 1, 'amount': 1600})

with ruleset('a9'):
    @when_all(m.amount < c.s.max_amount * 2)
    def approved(c):
        print ('a9 approved {0}'.format(c.m.amount))

    @when_start
    def start(host):
        host.patch_state('a9', {'sid': 1, 'max_amount': 100})
        host.post('a9', {'id': 1, 'sid': 1, 'amount': 100})
        host.post('a9', {'id': 2, 'sid': 1, 'amount': 300})

with ruleset('a10'):
    @when_all(m.amount < c.s.max_amount + c.s.id('global').max_amount)
    def approved(c):
        print ('a10 approved {0}'.format(c.m.amount))

    @when_start
    def start(host):
        host.patch_state('a10', {'sid': 1, 'max_amount': 500})
        host.patch_state('a10', {'sid': 'global', 'max_amount': 300})
        host.post('a10', {'id': 1, 'sid': 1, 'amount': 400})
        host.post('a10', {'id': 2, 'sid': 1, 'amount': 900})

with ruleset('a11'):
    @when_all((m.subject == 'approve') & (m.amount == 100), count(3))
    def approved(c):
        print ('a11 approved ->{0}'.format(c.m[0].amount))
        print ('             ->{0}'.format(c.m[1].amount))
        print ('             ->{0}'.format(c.m[2].amount))

    @when_start
    def start(host):
        host.post_batch('a11', [{'id': 1, 'sid': 1, 'subject': 'approve', 'amount': 100},
                               {'id': 2, 'sid': 1, 'subject': 'approve', 'amount': 100},
                               {'id': 3, 'sid': 1, 'subject': 'approve', 'amount': 100},
                               {'id': 4, 'sid': 1, 'subject': 'approve', 'amount': 100},
                               {'id': 5, 'sid': 1, 'subject': 'approve', 'amount': 100},
                               {'id': 6, 'sid': 1, 'subject': 'approve', 'amount': 100}])

with ruleset('a12'):
    @when_any(m.subject == 'approve', m.subject == 'approved', count(2))
    def approved(c):
        print ('a12 approved ->{0}'.format(c.m[0].m_0.subject))
        print ('             ->{0}'.format(c.m[1].m_0.subject))

    @when_start
    def start(host):
        host.post_batch('a12', [{'id': 1, 'sid': 1, 'subject': 'approve'},
                                {'id': 2, 'sid': 1, 'subject': 'approve'},
                                {'id': 3, 'sid': 1, 'subject': 'approve'},
                                {'id': 4, 'sid': 1, 'subject': 'approve'}])

with ruleset('t0'):
    @when_all(timeout('my_timer') | (s.count == 0))
    def start_timer(c):
        c.s.count += 1
        c.post('t0', {'id': c.s.count, 'sid': 1, 't': 'purchase'})
        c.start_timer('my_timer', random.randint(1, 3))

    @when_all(span(5), m.t == 'purchase')
    def pulse(c):
        print('t0 pulse -> {0}'.format(len(c.m)))

    @when_start
    def start(host):
        host.patch_state('t0', {'sid': 1, 'count': 0})

with ruleset('t1'):
    @when_all(m.start == 'yes')
    def start_timer(c):
        c.s.start = datetime.datetime.now().strftime('%I:%M:%S%p')
        c.start_timer('my_timer', 5)

    @when_all(timeout('my_timer'))
    def end_timer(c):
        print('t1 started @%s' % c.s.start)
        print('t1 ended @%s' % datetime.datetime.now().strftime('%I:%M:%S%p'))

    @when_start
    def start(host):
        host.post('t1', {'id': 1, 'sid': 1, 'start': 'yes'})

run_all()


#!/usr/bin/python3

import os
import sys
import subprocess
import argparse
import re

active_tunnels="/etc/ssh-sessions/active_tunnels"
ssh_history="/etc/ssh-sessions/ssh_command_history"
#clear buffer
stringToExecute = []

#count arguments and start after 1
n = len(sys.argv)
#print ("Total arguments passed:", n)
if (len(sys.argv) < 2):
    print ("You did not enter enough options for a command. Listing active tunnels:")
    subprocess.run(['cat', active_tunnels])
    sys.exit(1)
else:
    for i in range (1, n):
        stringToExecute.append(sys.argv[i])

#uncomment to debug commands
#print (stringToExecute)
stringToExecute.insert(0,'ssh')
if not '-fN' in stringToExecute:
    stringToExecute.append('-fN')

#if no options are included close down.

#string to log
cmd_string = subprocess.list2cmdline(stringToExecute)

#execute command
try:
    cmd_results = subprocess.run(stringToExecute, check=True)
    success = True
    #log command
except subprocess.CalledProcessError as e:
    output = e.output
    success = False
    #log output

def determine_ctl_cmd(stringToExecute):
    for string in stringToExecute:
        if string == ('-O'):
            i = stringToExecute.index(string)
            try:
                if (stringToExecute[i+1] == 'forward'):
                    return 'forward'
                elif (stringToExecute[i+1] == 'cancel'):
                    return 'cancel'
                else:
                    return False
            except IndexError:
                    return False

def check_for_active_connection(local_ip, local_port, remote_host, remote_port):
    #check to see if tunnel exists
    with open(active_tunnels, "r") as f:
        for line in f:
            if local_port in line:
                if local_ip in line:
                    if remote_host in line:
                        if remote_port in line:
                            return line
                        else:
                            continue
        return False

def add_tunnel_to_active_list(cmd_string):
    with open(active_tunnels, "a") as f:
        text=cmd_string + "\n"
        f.write(text)
    print (text, " written to active tunnels")

def remove_tunnel_from_active(cmd_string):
    with open(active_tunnels, "r+") as f:
        d = f.readlines()
        f.seek(0)
        for i in d:
            if i != cmd_string:
                f.write(i)
        f.truncate()

    print ("Removed ", cmd_string," from active tunnels")

def add_cmd_to_history(cmd_string):
    with open(ssh_history, "a") as f:
        f.write(cmd_string + "\n")

def index_containing_substring(the_list, substring):
    for i, s in enumerate(stringToExecute):
        if substring in s:
            return i
    return -1

def parse_tunnel(option):
    options = []
    i = index_containing_substring(stringToExecute, option)
    #print ("Options to parse: ", option)
   # print ("Index of stringToExecute: ",i)
   # print (stringToExecute[i])
    if (stringToExecute[i] == option):
        i+=1
        options = stringToExecute[i].split(':')
        #print ("If Options: ", options)
    else:
        options=stringToExecute[i].split(':')
        options[0] = re.sub(option, '', options[0])
        #print ("Else Options: ", options)

    return options

def forward_tunnel(option):
    tunnel_options = parse_tunnel(option)
        #SSH -L localhost:localport:remotehost:remoteport
    if (len(tunnel_options) < 4):
        tunnel_options.insert(0,"127.0.0.1")

    local_ip = tunnel_options[0]
    local_port = tunnel_options[1]
    remote_host = tunnel_options[2]
    remote_port = tunnel_options[3]

    tunnel_active=check_for_active_connection(local_ip, local_port, remote_host, remote_port)
    cmd=determine_ctl_cmd(stringToExecute)

   # print ("Tunnel exists: ", tunnel_active)

    #print ("Command: ", cmd)
    if (cmd == 'forward'):
        if (tunnel_active == False):
            add_tunnel_to_active_list(cmd_string)
        else:
            print ("Tunnel already exists")
    elif (cmd == 'cancel'):
        if (tunnel_active == False):
            print ("Tunnel does not exists to cancel")
        else:
            print ("Tunnel line is: ", tunnel_active)
            remove_tunnel_from_active(tunnel_active)
    else:
        print ("Was that command correct? No '-O' cmd_ctrl option found")
        exit()

def remote_tunnel(option):
    tunnel_options = parse_tunnel(option)
        #SSH -L localhost:localport:remotehost:remoteport
    if (len(tunnel_options) < 4):
        tunnel_options.insert(0,"0.0.0.0")

    remote_host = tunnel_options[0]
    remote_port = tunnel_options[1]
    local_ip = tunnel_options[2]
    local_port = tunnel_options[3]

    return remote_host, remote_port, local_ip, local_port

def dynamic_tunnel(option):
    #SSH -D proxy
    dynamic_proxy_port = parse_tunnel(option)
    return dynamic_proxy_port

if (success):
    #print(cmd_results)
    print ("Command logged: ", cmd_string)
    add_cmd_to_history(cmd_string)
    #forward tunnels
    if any('-L' in s for s in stringToExecute):
       forward_tunnel('-L')
    #remote tunnels
    elif any('-R' in s for s in stringToExecute):
        remote_tunnel('-R')
    #dynamic tunnels
    elif any('-D' in s for s in stringToExecute):
        dynamic_tunnel('-D')


import random

diamonds = ["AD", "2D", "3D", "4D", "5D", "6D",
            "7D", "8D", "9D", "10D", "JD", "QD", "KD"]

hand = []

while diamonds:
    choice = input("Hit Enter to draw a card or press Q+Enter to quit: ")
    # short-hand for giving the user more variety so as not be tied to the shift key
    if choice in ("Q", "q"):
        break
    # drawing a random item from the list of diamonds
    new_card = random.choice(diamonds)
    # removing the card that was drawn from the list of diamonds
    diamonds.remove(new_card)
    print(f"The deck now constists of: {diamonds}.")
    hand.append(new_card)  # adding the card that was drawn to the hand
    print(f"You currently have {hand} in your hand.")
# this will quit once there are no more cards to draw.
if not diamonds:
    print("There are no more cards to pick.")


# 1
import time

def countdown(count):
    while (count >= 0):
     count -= 1
     time.sleep(1)

countdown(2)
print("Times up!")

# 2

import pygame as py
py.init()
clock = py.time.Clock()

start_time = py.time.get_ticks()
print("started at:",start_time)

for i in range(0,30): #wait 1 second
    clock.tick(30)

end_time = py.time.get_ticks()
print("finished at:",end_time)

time_taken = end_time-start_time
print("time taken:",time_taken)

# 3
import pygame
from pygame.locals import *
def main():
    key = 0
    pygame.init()

    self = pygame.time.Clock()

    surface_sz = 480

    main_surface = pygame.display.set_mode((surface_sz, surface_sz))

    small_rect = (300, 200, 150, 90)
    some_color = (255, 0, 0)

    while True:
        ev = pygame.event.poll()

        if ev.type == pygame.QUIT:
            break;
        elif ev.type == KEYUP:
            if ev.key == K_SPACE:       #Sets the key to be used
                key += 1                #Updates counter for number of keypresses
                while ev.type == KEYUP:
                    self.tick_busy_loop()
                    test = (self.get_time()/1000.0)
                    print("number: ", key, "duration: ", test)
                    ev = pygame.event.poll()

main()


#!/usr/bin/env python
'''
Fit histogram templates for diphoton analysis
'''
years = [2016, 2017, 2018]
# "gg" fakes are used for real photon contamination estimates
datasets = ["gg", "data"]
fake_types = ["average", "jetht", "doublemuon"]
regions = ["BB", "BE"]
regions_alternate = ["barrel", "endcap"]
for year in years:
    for dataset in datasets:
        for fake_type in fake_types:
            arguments = dataset + " " + str(year) +  " " + fake_type
            print("getFakePrediction.exe " + arguments)

for year in years:
    for region in regions:
            arguments = region + " " + str(year)
            print("makeHistograms.exe " + arguments)

for year in years:
    arguments = str(year)
    samples = {"old", "new"}
    for sample in samples:
        print("makeDatacards.exe " + arguments + " " + sample)

for year in years:
    for region in regions_alternate:
        arguments = region + " " + str(year)
        print("datadriven.exe " + arguments)

for year in years:
    for region in regions_alternate:
        arguments = region + " " + str(year)
        print("basicplots.exe " + arguments)


# Construct input layer from features
inputs = constant(bill_amounts, float32)

# Define first dense layer
dense1 = keras.layers.Dense(3, activation='relu')(inputs)

# Define second dense layer
dense2 = keras.layers.Dense(2, activation='relu')(dense1)

# Define output layer
outputs = keras.layers.Dense(1, activation='sigmoid')(dense2)

# Print error for first five examples
error = default[:5] - outputs.numpy()[:5]
print(error)


# File:       example_PICMUS.py
# Author:     Dongwoon Hyun (dongwoon.hyun@stanford.edu)
# Created on: 2020-03-12
import os
import torch
import matplotlib.pyplot as plt
import numpy as np
from cubdl.das_torch import DAS_PW
from datasets.PWDataLoaders import load_data, get_filelist
from cubdl.PixelGrid import make_pixel_grid

device = torch.device("cuda:0")
# Find all the CUBDL Task 1 Data
# Optional other data subsets:
#   "all", "phantom", "invivo", "postcubdl", "simulation", "task1"
filelist = get_filelist(data_type="task1")

for data_source in filelist:
    for acq in filelist[data_source]:
        P, xlims, zlims = load_data(data_source, acq)

        # Define pixel grid limits (assume y == 0)
        wvln = P.c / P.fc
        dx = wvln / 2.5
        dz = dx  # Use square pixels
        grid = make_pixel_grid(xlims, zlims, dx, dz)
        fnum = 1

        # Make data torch tensors
        x = (P.idata, P.qdata)

        # Make 75-angle image
        dasN = DAS_PW(P, grid, rxfnum=fnum)
        idasN, qdasN = dasN(x)
        idasN, qdasN = idasN.detach().cpu().numpy(), qdasN.detach().cpu().numpy()
        iqN = idasN + 1j * qdasN
        bimgN = 20 * np.log10(np.abs(iqN))  # Log-compress
        bimgN -= np.amax(bimgN)  # Normalize by max value

        # Make 1-angle image
        idx = len(P.angles) // 2  # Choose center angle
        das1 = DAS_PW(P, grid, idx, rxfnum=fnum)
        idas1, qdas1 = das1(x)
        idas1, qdas1 = idas1.detach().cpu().numpy(), qdas1.detach().cpu().numpy()
        iq1 = idas1 + 1j * qdas1
        bimg1 = 20 * np.log10(np.abs(iq1))  # Log-compress
        bimg1 -= np.amax(bimg1)  # Normalize by max value

        # Display images via matplotlib
        extent = [xlims[0] * 1e3, xlims[1] * 1e3, zlims[1] * 1e3, zlims[0] * 1e3]
        plt.clf()
        plt.subplot(121)
        plt.imshow(bimg1, vmin=-60, cmap="gray", extent=extent, origin="upper")
        plt.title("1 angle")
        plt.subplot(122)
        plt.imshow(bimgN, vmin=-60, cmap="gray", extent=extent, origin="upper")
        plt.title("%d angles" % len(P.angles))
        plt.suptitle("%s%03d (c = %d m/s)" % (data_source, acq, np.round(P.c)))
        plt.pause(0.01)

        # Check to make sure save directory exists, if not, create it
        savedir = os.path.join("datasets", "test_pw_images", data_source)
        if not os.path.exists(savedir):
            os.makedirs(savedir)

        print(os.path.join("datasets", "test_pw_images", data_source, "%s%03d.jpg" % (data_source, acq)))
        plt.savefig(
            os.path.join(savedir, "%s%03d.jpg" % (data_source, acq))
        )


#!/bin/env python
# encoding=utf8

import os
import sys
import glob
from xml.dom import minidom
import pyproj

def project_coordinate(epsg, x, y):
    p = pyproj.Proj(init=epsg)
    lat, lon = p(x, y, inverse=True)
    return lat, lon

class Reader():
    def __init__(self, filename):
        #self._filename = filename
        self._coords = []
        self._buildings = []
        self._addresses = []
        self._texture_coords = []
        self._imageURI = ''
        self.parse(filename)

    def parse(self, filename):
        self._filename = filename
        with open(self._filename, 'rb') as f:
            ls = f.read()
            doc = minidom.parseString(ls)
            self._parse_building(doc)
            self._parse_address(doc)
            self._parse_appearance(doc)

    def _parse_appearance(self, root):
        for node_imageURI in root.getElementsByTagName('app:imageURI'):
            self._imageURI = node_imageURI.childNodes[0].nodeValue.strip()
        for node_textureCoordinates in root.getElementsByTagName('app:textureCoordinates'):
            ring_id = node_textureCoordinates.getAttribute("ring")[1:]
            texture_coords = []
            pss = node_textureCoordinates.childNodes[0].nodeValue.strip().split()
            for i in range(len(pss)//2):
                x = pss[i*2]
                y = pss[i*2+1]
                x,y = float(x), float(y)
                texture_coords.append((x, y))
            if texture_coords:
                self._texture_coords.append((ring_id, texture_coords))

    def _parse_building(self, root):
        #node_building = root.getElementsByTagName('bldg:Building')[0]
        for node_linearRing in root.getElementsByTagName('gml:LinearRing'):
            linearRing_id = node_linearRing.getAttribute("gml:id")
            #gml:exterior''
            node_posList = node_linearRing.getElementsByTagName('gml:posList')[0]
            building_coords = []
            for pos in node_posList.childNodes[0].nodeValue.splitlines():
                if pos:
                    x,y,z = pos.split()
                    x,y,z = float(x), float(y), float(z)
                    lon, lat = x, y
                    lon, lat = project_coordinate("EPSG:3414", x, y)
                    self._coords.append((lon, lat, z))
                    building_coords.append((lon, lat, z))
            if building_coords:
                self._buildings.append((linearRing_id, building_coords))

    def _parse_address(self, root):
        for node_pos in root.getElementsByTagName('gml:pos'):
            x,y,z = node_pos.childNodes[0].nodeValue.split()
            x,y,z = float(x), float(y), float(z)
            lat, lon = project_coordinate("EPSG:3414", x, y)
            self._addresses.append((lat, lon, z))

    def get_coords(self):
        return self._coords

    def get_buildings(self):
        return self._buildings

    def get_addresses(self):
        return self._addresses

    def get_texture_coords(self, polygon_id=None):
        if not polygon_id:
            return self._texture_coords
        else:
            for target_id, texture_coords in self._texture_coords:
                if target_id == polygon_id:
                    return texture_coords
            return None

    def get_imageURI(self):
        return self._imageURI