from typing import Any, Dict, List, Optional, Type, Union

from knime._backend._mainloop import MainLoop

import knime._backend._gateway as kg
import knime.extension.nodes as kn
import knime.extension.parameter as kp

import knime.api.schema as ks

import knime._arrow._table as kat
import knime.api.table as kt
import importlib
import json
import logging

import traceback
import collections

from py4j.java_gateway import JavaClass
from py4j.java_collections import ListConverter
import py4j.clientserver

from knime.extension.env import _set_proxy_settings

# TODO: register extension types

class _PythonPortObject:
    def __init__(self, java_class_name):
        self._java_class_name = java_class_name

    def getJavaClassName(self) -> str:  # NOSONAR - Java naming conventions
        return self._java_class_name

    class Java:
        implements = [
            "org.knime.python3.nodes.ports.PythonPortObjects$PythonPortObject"
        ]

class _PythonTablePortObject:
    def __init__(self, java_class_name, sink):
        self._java_class_name = java_class_name
        self._sink = sink

    def getJavaClassName(self) -> str:  # NOSONAR - Java naming conventions
        return self._java_class_name

    def getPythonArrowDataSink(self):  # NOSONAR - Java naming conventions
        return self._sink

    class Java:
        implements = [
            "org.knime.python3.nodes.ports.PythonPortObjects$PurePythonTablePortObject"
        ]

class _PythonPortObjectSpec:
    def __init__(self, java_class_name, data_dict: Dict):
        self._java_class_name = java_class_name
        self._json_string_data = json.dumps(data_dict)
        self._data = data_dict

    def getJavaClassName(self) -> str:  # NOSONAR - Java naming conventions
        return self._java_class_name

    def toJsonString(self) -> str:  # NOSONAR - Java naming conventions
        return self._json_string_data

    def toString(self) -> str:  # NOSONAR - Java naming conventions
        """For debugging on the Java side"""
        return self._json_string_data

    @property
    def data(self) -> Dict:
        if self._data is None:
            # to be able to access the data dict when we're accessing a Java class
            self._data = json.loads(self.toJsonString())
        return self._data

    class Java:
        implements = [
            "org.knime.python3.nodes.ports.PythonPortObjects$PythonPortObjectSpec"
        ]

class _PythonBinaryPortObject:
    def __init__(self, java_class_name, filestore_file, spec):
        self._java_class_name = java_class_name
        self._spec = spec
        self._key = filestore_file.get_key()

    @classmethod
    def from_bytes(
        cls,
        java_class_name: str,
        filestore_file,
        data: bytes,
        spec: _PythonPortObjectSpec,
    ) -> "_PythonBinaryPortObject":
        with open(filestore_file.get_file_path(), "wb") as f:
            f.write(data)
        return cls(java_class_name, filestore_file, spec)

    def getJavaClassName(self) -> str:  # NOSONAR - Java naming conventions
        return self._java_class_name

    def getSpec(self) -> _PythonPortObjectSpec:  # NOSONAR - Java naming conventions
        return self._spec

    def getFileStoreKey(self) -> str:  # NOSONAR - Java naming conventions
        return self._key

    def toString(self) -> str:  # NOSONAR - Java naming conventions
        """For debugging on the Java side"""
        return f"PythonBinaryPortObject[spec={self._spec.toJsonString()}]"

    class Java:
        implements = [
            "org.knime.python3.nodes.ports.PythonPortObjects$PurePythonBinaryPortObject"
        ]

class _PythonConnectionPortObject:
    def __init__(self, java_class_name, spec):
        self._java_class_name = java_class_name
        self._spec = spec

    def getPid(self) -> int:  # NOSONAR - Java naming conventions
        """Used on the Java side to obtain the Python process ID"""
        import os

        return os.getpid()

    def getJavaClassName(self) -> str:  # NOSONAR - Java naming conventions
        return self._java_class_name

    def getSpec(self) -> _PythonPortObjectSpec:  # NOSONAR - Java naming conventions
        return self._spec

    def toString(self) -> str:  # NOSONAR - Java naming conventions
        """For debugging on the Java side"""
        return f"PythonConnectionPortObject[spec={self._spec.toJsonString()}]"

    class Java:
        implements = [
            "org.knime.python3.nodes.ports.PythonPortObjects$PurePythonConnectionPortObject"
        ]

class _PythonImagePortObject:
    def __init__(self, java_class_name, data):
        import base64

        if isinstance(data, str):  # string potentially representing an SVG image
            data = data.encode("utf-8")

        self._java_class_name = java_class_name
        self._img_bytes = base64.b64encode(data).decode("utf-8")

    def getJavaClassName(self) -> str:  # NOSONAR
        return self._java_class_name

    def getImageBytes(self) -> str:  # NOSONAR
        return self._img_bytes

    class Java:
        implements = [
            "org.knime.python3.nodes.ports.PythonPortObjects$PurePythonImagePortObject"
        ]

class _FlowVariablesDict(collections.UserDict):
    def __init__(self):
        super().__init__({})
        self._locked = False

    def __setitem__(self, key: str, value) -> None:
        if not isinstance(key, str):
            raise TypeError("the flow variable name must be a string")
        if self._locked and key.startswith("knime"):
            raise ValueError(
                "setting or changing a flow variable that starts with 'knime' is not allowed"
            )
        super().__setitem__(key, value)

    def __delitem__(self, _) -> None:
        raise RuntimeError("deleting flow variables is not allowed")

def _check_attr_is_available(node, attr_name):
    if not hasattr(node, attr_name) or getattr(node, attr_name) is None:
        raise ValueError(f"Attribute {attr_name} is missing in node {node}")

class _PortTypeRegistry:
    # One global dictionary for all connections
    _connection_port_data = {}

    def __init__(self, extension_id: str) -> None:
        self._extension_id = extension_id
        self._port_types_by_object_class = {}
        self._port_types_by_spec_class = {}
        self._port_types_by_id = {}

    def register_port_type(
        self,
        name: str,
        object_class: Type[kn.PortObject],
        spec_class: Type[kn.PortObjectSpec],
        id: Optional[str] = None,
    ) -> kn.PortType:
        if object_class in self._port_types_by_object_class:
            raise ValueError(
                f"There is already a port type with the provided object class '{object_class}' registered."
            )
        if spec_class in self._port_types_by_spec_class:
            raise ValueError(
                f"There is already a port type with the provided spec class '{spec_class}' registered."
            )
        if id is None:
            id = f"{self._extension_id}.{object_class.__module__}.{object_class.__qualname__}"

        if id in self._port_types_by_id:
            raise ValueError(
                f"There is already a port type with the provided id '{id}' registered."
            )

        port_type = kn.PortType(id, name, object_class, spec_class)

        self._port_types_by_object_class[object_class] = port_type
        self._port_types_by_spec_class[spec_class] = port_type
        self._port_types_by_id[id] = port_type
        return port_type

    def get_port_type_for_spec_type(
        self, spec_type: Type[kn.PortObjectSpec]
    ) -> kn.PortType:
        if spec_type in self._port_types_by_spec_class:
            return self._port_types_by_spec_class[spec_type]
        raise KeyError(f"The PortObjectSpec type {str(spec_type)} is not registered.")

    def get_port_type_for_id(self, id: str) -> kn.PortType:
        if id in self._port_types_by_id:
            return self._port_types_by_id[id]
        raise KeyError(f"No PortType for id '{id}' registered.")

    def spec_to_python(self, spec: _PythonPortObjectSpec, port: kn.Port):
        class_name = spec.getJavaClassName()
        data = json.loads(spec.toJsonString())

        def deserialize_custom_spec() -> kn.PortObjectSpec:
            incoming_port_type = self._extract_port_type_from_spec_data(data, port)
            return incoming_port_type.spec_class.deserialize(data["data"])

        if class_name == "org.knime.core.data.DataTableSpec":
            assert port.type == kn.PortType.TABLE
            return ks.Schema.deserialize(data)
        elif (
            class_name == "org.knime.python3.nodes.ports.PythonBinaryBlobPortObjectSpec"
        ):
            if port.type == kn.PortType.BINARY:
                bpos = ks.BinaryPortObjectSpec.deserialize(data)
                assert (
                    bpos.id == port.id
                ), f"Expected binary input port ID {port.id} but got {bpos.id}"
                return bpos
            else:  # custom spec
                return deserialize_custom_spec()
        elif (
            class_name
            == "org.knime.python3.nodes.ports.PythonTransientConnectionPortObjectSpec"
        ):
            assert port.type not in [kn.PortType.TABLE, kn.PortType.BINARY]
            assert issubclass(port.type.object_class, kn.ConnectionPortObject)
            return deserialize_custom_spec()

        raise TypeError("Unsupported PortObjectSpec found in Python, got " + class_name)

    def _extract_port_type_from_spec_data(
        self, data, expected_port: kn.Port
    ) -> kn.PortType:
        spec_id = data["id"]
        assert (
            spec_id in self._port_types_by_id
        ), f"There is no port type with id '{spec_id}' registered."
        incoming_port_type: kn.PortType = self._port_types_by_id[spec_id]
        if not expected_port.type.is_super_type_of(incoming_port_type):
            raise kn.InvalidParametersError(
                f"The provided input port type {incoming_port_type.name} must be the same or a sub-type of the node's input port type {expected_port.type.name}."
            )
        return incoming_port_type

    def spec_from_python(
        self, spec, port: kn.Port, node_id: str, port_idx: int
    ) -> _PythonPortObjectSpec:
        if port.type == kn.PortType.TABLE:
            if isinstance(spec, ks._ColumnarView):
                spec = spec.get()
            if isinstance(spec, ks.Column):
                spec = ks.Schema.from_columns(spec)
            assert isinstance(spec, ks.Schema)
            data = spec.serialize()
            class_name = "org.knime.core.data.DataTableSpec"
        elif port.type == kn.PortType.BINARY:
            assert isinstance(spec, ks.BinaryPortObjectSpec)
            assert (
                port.id == spec.id
            ), f"Expected binary output port ID {port.id} but got {spec.id}"

            data = spec.serialize()
            class_name = "org.knime.python3.nodes.ports.PythonBinaryBlobPortObjectSpec"
        elif port.type == kn.PortType.IMAGE:
            assert isinstance(spec, ks.ImagePortObjectSpec)
            assert any(
                spec.format == option.value for option in kn.ImageFormat
            ), f"Expected image formats are: {kn.ImageFormat.available_options()}."

            data = spec.serialize()
            class_name = "org.knime.core.node.port.image.ImagePortObjectSpec"
        else:  # custom spec
            assert (
                port.type.id in self._port_types_by_id
            ), f"There is no port type with id '{port.type.id}' registered"
            assert isinstance(
                spec, port.type.spec_class
            ), f"Expected output spec of type {port.type.spec_class} but got spec of type {type(spec)}"
            data = {"id": port.type.id, "data": spec.serialize()}

            if issubclass(port.type.object_class, kn.ConnectionPortObject):
                data["node_id"] = node_id
                data["port_idx"] = port_idx
                class_name = "org.knime.python3.nodes.ports.PythonTransientConnectionPortObjectSpec"
            else:
                class_name = (
                    "org.knime.python3.nodes.ports.PythonBinaryBlobPortObjectSpec"
                )

        return _PythonPortObjectSpec(class_name, data)

    def port_object_to_python(self, port_object: _PythonPortObject, port: kn.Port):
        class_name = port_object.getJavaClassName()

        def read_port_object_data() -> Union[Any, kn.PortObject]:
            file = port_object.getFilePath()
            with open(file, "rb") as f:
                return f.read()

        if class_name == "org.knime.core.node.BufferedDataTable":
            assert port.type == kn.PortType.TABLE
            java_source = port_object.getDataSource()
            return kat.ArrowSourceTable(kg.data_source_mapper(java_source))
        elif (
            class_name
            == "org.knime.python3.nodes.ports.PythonBinaryBlobFileStorePortObject"
        ):
            if port.type == kn.PortType.BINARY:
                return read_port_object_data()
            else:
                java_spec = port_object.getSpec()
                spec = self.spec_to_python(java_spec, port)
                incoming_port_type = self._extract_port_type_from_spec_data(
                    json.loads(java_spec.toJsonString()), port
                )
                if issubclass(incoming_port_type.object_class, kn.FilestorePortObject):
                    return incoming_port_type.object_class.read_from(
                        spec, port_object.getFilePath()
                    )
                data = read_port_object_data()
                return incoming_port_type.object_class.deserialize(spec, data)
        elif (
            class_name
            == "org.knime.python3.nodes.ports.PythonTransientConnectionPortObject"
        ):
            assert issubclass(
                port.type.object_class, kn.ConnectionPortObject
            ), f"unexpected port type {port.type}"
            spec = self.spec_to_python(port_object.getSpec(), port)

            data = json.loads(port_object.getSpec().toJsonString())
            key = f'{data["node_id"]}:{data["port_idx"]}'
            if key not in _PortTypeRegistry._connection_port_data:
                raise KeyError(
                    f'No connection data found for node {data["node_id"]}, port {data["port_idx"]}. '
                    + "Please re-execute the upstream node providing the connection."
                )

            connection_data = _PortTypeRegistry._connection_port_data[key]
            return port.type.object_class.from_connection_data(spec, connection_data)

        raise TypeError("Unsupported PortObjectSpec found in Python, got " + class_name)

    def port_object_from_python(
        self, obj, file_creator, port: kn.Port, node_id: str, port_idx: int
    ) -> _PythonPortObject:
        if port.type == kn.PortType.TABLE:
            if isinstance(obj, kt._TabularView):
                obj = obj.get()
            class_name = "org.knime.core.node.BufferedDataTable"

            java_data_sink = None
            if isinstance(obj, kat.ArrowTable):
                sink = kt._backend.create_sink()
                obj._write_to_sink(sink)
                java_data_sink = sink._java_data_sink
            elif isinstance(obj, kat.ArrowBatchOutputTable):
                java_data_sink = obj._sink._java_data_sink
            else:
                raise TypeError(
                    f"Object for port {port} should be of type Table or BatchOutputTable, but got {type(obj)}"
                )

            return _PythonTablePortObject(class_name, java_data_sink)
        elif port.type == kn.PortType.BINARY:
            if not isinstance(obj, bytes):
                tb = None
                raise TypeError(
                    f"Binary Port can only process objects of type bytes, not {type(obj)}"
                ).with_traceback(tb)

            class_name = (
                "org.knime.python3.nodes.ports.PythonBinaryBlobFileStorePortObject"
            )
            spec = _PythonPortObjectSpec(
                "org.knime.python3.nodes.ports.PythonBinaryBlobPortObjectSpec",
                {"id": port.id},
            )
            return _PythonBinaryPortObject.from_bytes(
                class_name, file_creator(), obj, spec
            )
        elif port.type == kn.PortType.IMAGE:
            class_name = "org.knime.core.node.port.image.ImagePortObject"
            return _PythonImagePortObject(class_name, obj)
        else:
            assert (
                port.type.id in self._port_types_by_id
            ), f"There is no port type with '{id}' registered"
            assert isinstance(
                obj, port.type.object_class
            ), f"Expected output object of type {port.type.object_class}, got object of type {type(obj)}"
            spec = self.spec_from_python(obj.spec, port, node_id, port_idx)

            if issubclass(port.type.object_class, kn.ConnectionPortObject):
                class_name = (
                    "org.knime.python3.nodes.ports.PythonTransientConnectionPortObject"
                )

                # We store the port object data in a global dict referenced by nodeID and portIdx
                key = f"{node_id}:{port_idx}"
                _PortTypeRegistry._connection_port_data[key] = obj.to_connection_data()
                return _PythonConnectionPortObject(class_name, spec)
            else:
                class_name = (
                    "org.knime.python3.nodes.ports.PythonBinaryBlobFileStorePortObject"
                )

                if issubclass(port.type.object_class, kn.FilestorePortObject):
                    filestore = file_creator()
                    file_path = filestore.get_file_path()
                    obj.write_to(file_path)
                    return _PythonBinaryPortObject(class_name, filestore, spec)
                else:
                    serialized = obj.serialize()
                    return _PythonBinaryPortObject.from_bytes(
                        class_name, file_creator(), serialized, spec
                    )

class _PythonNodeProxy:
    def __init__(
        self,
        node: kn.PythonNode,
        port_type_registry: _PortTypeRegistry,
        knime_parser,
        extension_version,
    ) -> None:
        _check_attr_is_available(node, "input_ports")
        _check_attr_is_available(node, "output_ports")

        self._node = node
        self._num_outports = len(node.output_ports)
        self._port_type_registry = port_type_registry
        self._knime_parser = knime_parser
        self._extension_version = extension_version

    def getDialogRepresentation(
        self,
        parameters: str,
        parameters_version: str,
        python_dialog_context,
    ):
        # parameters could be from an older version
        self.setParameters(parameters, parameters_version)

        dialog_context = kn.DialogCreationContext(
            python_dialog_context, self._get_flow_variables(), self._specs_to_python
        )

        json_forms_dict = {
            "data": kp.extract_parameters(self._node, for_dialog=True),
            "schema": kp.extract_schema(
                self._node,
                self._extension_version,  # we need the current schema for the dialog
                dialog_creation_context=dialog_context,
            ),
            "ui_schema": kp.extract_ui_schema(self._node, dialog_context),
        }

        self._parse_parameter_descriptions(json_forms_dict["schema"])

        return json.dumps(json_forms_dict)

    def _parse_parameter_descriptions(self, schema_dict):
        """
        Recursively parse "description" fields of the provided JSON dict from Markdown to HTML.

        Parsing is done in-place, no value is returned.
        """
        for key in schema_dict:
            if isinstance(schema_dict[key], dict):
                self._parse_parameter_descriptions(schema_dict[key])
            elif key == "description":
                schema_dict[key] = self._knime_parser.parse_option_description(
                    schema_dict[key]
                )

    def _specs_to_python(self, specs):
        return [
            self._port_type_registry.spec_to_python(spec, port)
            if spec is not None
            else None
            for port, spec in zip(self._node.input_ports, specs)
        ]

    def getParameters(self) -> str:
        parameters_dict = kp.extract_parameters(self._node)
        return json.dumps(parameters_dict)

    def getSchema(self, version=None) -> str:
        schema = kp.extract_schema(self._node, version)
        return json.dumps(schema)

    def setParameters(
        self,
        parameters: str,
        parameters_version: str,
    ) -> None:
        parameters_dict = json.loads(parameters)
        kp.inject_parameters(
            self._node,
            parameters_dict,
            parameters_version,
        )

    def validateParameters(self, parameters: str, saved_version: str) -> None:
        parameters_dict = json.loads(parameters)
        try:
            kp.validate_parameters(self._node, parameters_dict, saved_version)
            return None
        except BaseException as error:
            return str(error)

    def determineCompatibility(
        self, saved_version: str, current_version: str, saved_parameters: str
    ) -> None:
        saved_parameters_dict = json.loads(saved_parameters)
        kp.determine_compatability(
            self._node, saved_version, current_version, saved_parameters_dict
        )

    def initializeJavaCallback(self, java_callback: JavaClass) -> None:
        self._java_callback = java_callback

    def execute(
        self, input_objects: List[_PythonPortObject], java_exec_context
    ) -> List[_PythonPortObject]:
        _push_log_callback(lambda msg, sev: self._java_callback.log(msg, sev))

        try:
            inputs = [
                self._port_type_registry.port_object_to_python(
                    po, self._node.input_ports[idx]
                )
                for idx, po in enumerate(input_objects)
            ]

            # inject preferred_value_types as these are not part of a column's metadata
            for table in [i for i in inputs if isinstance(i, kat.ArrowSourceTable)]:
                table._inject_metadata(
                    self._java_callback.get_preferred_value_types_as_json
                )

            # prepare output table creation
            def create_python_sink():
                java_sink = self._java_callback.create_sink()
                return kg.data_sink_mapper(java_sink)

            kt._backend = kat._ArrowBackend(create_python_sink)
            kt._backend.file_store_handler = self._java_callback

            # execute
            exec_context = kn.ExecutionContext(
                java_exec_context, self._get_flow_variables()
            )

            # TODO: maybe we want to run execute on the main thread? use knime._backend._mainloop
            outputs = self._node.execute(exec_context, *inputs)

            # Return null if the execution was canceled
            if exec_context.is_canceled():
                self._java_callback.set_failure("Canceled", "", False)
                return None

            self._set_flow_variables(exec_context.flow_variables)

            if outputs is None:
                outputs = []

            if not isinstance(outputs, list) and not isinstance(outputs, tuple):
                # single outputs are fine
                outputs = [outputs]

            if (
                hasattr(self._node, "output_view")
                and self._node.output_view is not None
            ):
                out_view = outputs[-1]
                outputs = outputs[:-1]

                # write the view to the sink
                view_sink = kg.data_sink_mapper(self._java_callback.create_view_sink())
                view_sink.display(out_view)

            java_outputs = [
                self._port_type_registry.port_object_from_python(
                    obj,
                    lambda: self._java_callback.create_filestore_file(),
                    self._node.output_ports[idx],
                    java_exec_context.get_node_id(),
                    idx,
                )
                for idx, obj in enumerate(outputs)
            ]

        except Exception as ex:
            self._set_failure(ex, 0)
            return None
        finally:
            if kt._backend is not None:
                kt._backend.close()
                kt._backend = None

            _pop_log_callback()

        return ListConverter().convert(java_outputs, kg.client_server._gateway_client)

    def configure(
        self, input_specs: List[_PythonPortObjectSpec], java_config_context
    ) -> List[_PythonPortObjectSpec]:
        _push_log_callback(lambda msg, sev: self._java_callback.log(msg, sev))
        try:
            inputs = self._specs_to_python(input_specs)
            config_context = kn.ConfigurationContext(
                java_config_context, self._get_flow_variables()
            )
            kp.validate_specs(self._node, inputs)
            # TODO: maybe we want to run execute on the main thread? use knime._backend._mainloop
            outputs = self._node.configure(config_context, *inputs)
        except Exception as ex:
            self._set_failure(ex, 1)
            return None

        self._set_flow_variables(config_context.flow_variables)

        if outputs is None:
            # indicates that downstream nodes can't be configured, yet
            outputs = [None] * self._num_outports
        if not isinstance(outputs, list) and not isinstance(outputs, tuple):
            # single outputs are fine
            outputs = [outputs]

        output_specs = [
            self._port_type_registry.spec_from_python(
                spec, self._node.output_ports[i], java_config_context.get_node_id(), i
            )
            if spec is not None
            else None
            for i, spec in enumerate(outputs)
        ]
        _pop_log_callback()
        return ListConverter().convert(output_specs, kg.client_server._gateway_client)

    def _set_failure(self, ex: Exception, remove_tb_levels=0):
        # Remove levels from the traceback
        tb = ex.__traceback__
        for _ in range(remove_tb_levels):
            tb = ex.__traceback__.tb_next

        # Format the details: Traceback + Error type + Error
        details = "".join(traceback.format_exception(type(ex), value=ex, tb=tb))

        # Set the failure in the Java callback
        self._java_callback.set_failure(
            str(ex), details, isinstance(ex, kn.InvalidParametersError)
        )

    def _get_flow_variables(self):
        from py4j.java_collections import JavaArray

        java_flow_variables = self._java_callback.get_flow_variables()

        flow_variables = _FlowVariablesDict()
        for key, value in java_flow_variables.items():
            if isinstance(value, JavaArray):
                value = [x for x in value]
            flow_variables[key] = value
        flow_variables._locked = True
        return flow_variables

    def _check_flow_variables(self, flow_variables):
        LinkedHashMap = JavaClass(  # NOSONAR Java naming conventions apply.
            "java.util.LinkedHashMap", kg.client_server._gateway_client
        )
        java_flow_variables = LinkedHashMap()
        for key in flow_variables.keys():
            fv = flow_variables[key]
            try:
                java_flow_variables[key] = fv
            except AttributeError as ex:
                # py4j raises attribute errors of the form "'<type>' object has no attribute '_get_object_id'" if it
                # fails to translate Python objects to Java objects.
                raise TypeError(
                    f"Flow variable '{key}' of type '{type(fv)}' cannot be translated to a valid KNIME flow "
                    f"variable. Please remove the flow variable or change its type to something that can be translated."
                )

    def _set_flow_variables(self, flow_variables):
        self._check_flow_variables(flow_variables)

        LinkedHashMap = JavaClass(  # NOSONAR Java naming conventions apply.
            "java.util.LinkedHashMap", kg.client_server._gateway_client
        )
        java_flow_variables = LinkedHashMap()
        for key in flow_variables.keys():
            flow_variable = flow_variables[key]
            java_flow_variables[key] = flow_variable

        self._java_callback.set_flow_variables(java_flow_variables)

    class Java:
        implements = ["org.knime.python3.nodes.proxy.PythonNodeProxy"]

class _KnimeNodeBackend(kg.EntryPoint, kn._KnimeNodeBackend):
    def __init__(self) -> None:
        super().__init__()
        self._main_loop = MainLoop()
        self._port_type_registry = None
        kn._backend = self

    def register_port_type(
        self,
        name: str,
        object_class: Type[kn.PortObject],
        spec_class: Type[kn.PortObjectSpec],
        id: Optional[str] = None,
    ):
        assert self._port_type_registry is not None, "No extension is loaded."
        return self._port_type_registry.register_port_type(
            name, object_class, spec_class, id
        )

    def get_port_type_for_spec_type(
        self, spec_type: Type[kn.PortObjectSpec]
    ) -> kn.PortType:
        return self._port_type_registry.get_port_type_for_spec_type(spec_type)

    def get_port_type_for_id(self, id: str) -> kn.PortType:
        return self._port_type_registry.get_port_type_for_id(id)

    def loadExtension(
        self, extension_id: str, extension_module: str, extension_version: str
    ) -> None:
        try:
            self._port_type_registry = _PortTypeRegistry(extension_id)
            # load the extension, so that it registers its nodes, categories and port types
            importlib.import_module(extension_module)
            kp.set_extension_version(extension_version)
            self._extension_version = extension_version
        except Exception:
            error = traceback.format_exc(limit=1, chain=True)
            raise RuntimeError(
                f"Failed to load extension {extension_id} from {extension_module} with error: {error}"
            ) from None

    def initializeJavaCallback(self, callback):
        _push_log_callback(lambda msg, sev: callback.log(msg, sev))
        _set_proxy_settings(callback)

    def retrieveCategoriesAsJson(self) -> str:
        category_dicts = [category.to_dict() for category in kn._categories]
        return json.dumps(category_dicts)

    def retrieveNodesAsJson(self) -> str:
        node_dicts = [self.resolve_node_dict(n) for n in kn._nodes.values()]
        return json.dumps(node_dicts)

    def resolve_node_dict(self, node: kn._Node):
        d = node.to_dict()
        instance = node.node_factory()
        description = self.extract_description(instance, node.name)
        return {**d, **description}

    def extract_description(self, node: kn.PythonNode, name) -> dict:
        node_doc = node.__doc__

        param_doc, tabs_used = kp.extract_parameter_descriptions(node)

        if node_doc is None:
            logging.warning(
                f"No docstring available for node {name}. Please document the node class with a docstring or set __doc__ in the init of the node."
            )
            short_description = full_description = "Missing description."
        else:
            # remove first empty line, for nicer formatted short descriptions
            if node_doc[0] == "\n":
                node_doc = node_doc[1:]
            split_description = node_doc.splitlines()
            short_description = split_description[0]
            if len(split_description) > 1:
                full_description = "\n".join(split_description[1:])
                full_description = self._knime_parser.parse_full_description(
                    full_description
                )
            else:
                full_description = "Missing description."

        # Check short description
        if not len(short_description):
            logging.warning(
                f"No short description available. Create it by placing text right next to starting docstrings."
            )

        if tabs_used:
            tabs = self._knime_parser.parse_tabs(param_doc)
            options = []
        else:
            options = self._knime_parser.parse_options(param_doc)
            tabs = []

        input_ports = self._knime_parser.parse_ports(node.input_ports)
        output_ports = self._knime_parser.parse_ports(node.output_ports)

        return {
            "short_description": short_description,
            "full_description": full_description,
            "options": options,
            "tabs": tabs,
            "input_ports": input_ports,
            "output_ports": output_ports,
        }

    def createNodeFromExtension(self, node_id: str) -> _PythonNodeProxy:
        node_info = kn._nodes[node_id]
        node = node_info.node_factory()
        return _PythonNodeProxy(
            node, self._port_type_registry, self._knime_parser, self._extension_version
        )

    @property
    def _knime_parser(self):
        # Initialize the _knime_parser once we need it. In __init__ the log callback is
        # not ready and the warning would get lost
        if not hasattr(self, "_knime_parser_instance"):
            try:
                from knime.extension._markdown import KnimeMarkdownParser

                self._knime_parser_instance = KnimeMarkdownParser()
            except ModuleNotFoundError:
                logging.warning(
                    " The 'markdown' Python package is missing from the environment: "
                    + "node descriptions will display Markdown source in plain text instead of being rich-text-formatted."
                )
                self._knime_parser_instance = FallBackMarkdownParser()

        return self._knime_parser_instance

    class Java:
        implements = ["org.knime.python3.nodes.KnimeNodeBackend"]

class KnimeLogHandler(logging.StreamHandler):
    def __init__(self, backend):
        super().__init__(self)
        self.setFormatter(logging.Formatter("%(name)s:%(message)s"))
        self._backend = backend

    def emit(self, record: logging.LogRecord):
        if _log_callback is not None:
            msg = self.format(record)

            if record.levelno >= logging.ERROR:
                severity = "error"
            elif record.levelno >= logging.WARNING:
                severity = "warn"
            elif record.levelno >= logging.INFO:
                severity = "info"
            else:
                severity = "debug"

            _log_callback(msg, severity)

class FallBackMarkdownParser:
    """
    Is used when markdown is not imported.
    """

    def __init__(self):
        pass

    def parse_full_description(self, s):
        return s

    def parse_basic(self, s):
        return s

    def parse_ports(self, ports):
        return [{"name": port.name, "description": port.description} for port in ports]

    def parse_options(self, options):
        return options

    def parse_option_description(self, option_description):
        return option_description

    def parse_tabs(self, tabs):
        return tabs

_log_callback = None
_old_log_callbacks = []

def _push_log_callback(callback):
    global _log_callback
    global _old_log_callbacks
    _old_log_callbacks.append(_log_callback)
    _log_callback = callback

def _pop_log_callback():
    global _log_callback
    global _old_log_callbacks
    callback = _old_log_callbacks.pop()
    _log_callback = callback

if __name__ == "__main__":
    backend = _KnimeNodeBackend()
    kg.connect_to_knime(backend)
    py4j.clientserver.server_connection_stopped.connect(
        lambda *args, **kwargs: backend._main_loop.exit()
    )
    # suppress py4j logs
    logging.getLogger("py4j").setLevel(logging.ERROR)
    logging.getLogger().setLevel(logging.DEBUG)
    logging.getLogger().addHandler(KnimeLogHandler(backend))

    # We enter the main loop - but never enqueue any tasks. It
    # seems as if keeping the main thread alive as long as the
    # py4j connection is established is enough / required to allow
    # other threading operations to work.
    backend._main_loop.enter()


n = int(input())
ans = 0
for i in range(0,n):
  s = 0
  for j in range(len(str(i))):
    a = str(i)
    s += int(a[j])
  if (s + i) == n:
    ans = i
    break
print(ans)


import pygame,sys
from scripts.character import Character
from scripts.animations import Animations
from scripts.sword import Sword
from scripts.playerInput import PlayerInput
class Player(Character):
    def __init__(self,name,x, y,hp, width, height,collisionRects,hpBarImg=None):#init the player
        super().__init__(x, y, width, height,collisionRects)#init the character class
        self.name = name#name of the player
        self.weapons = {'sword' : Sword(x,y)}#the weapons the player has
        self.takeInputs = True#does the player take inputs
        self.attacking = False#is the player attacking
        self.dash = False#is the player dashing
        self.slide = False#is the player sliding
        self.dead = False#is the player dead
        self.input = PlayerInput(self)#the player's input
        self.slideVel = None#the velocity of the player when sliding
        self.slideAcc = None#the acceleration of the player when sliding
        self.imunityFrames = 0#the amount of frames the player is immune to damage
        self.dashAcceleration = 0.5#the acceleration of the player when dashing
        self.attackCombo = 'firstAttack'#the attack combo the player is on
        self.hpBar = self.getHpBar(hp,hpBarImg)#the hp bar of the player
        self.animations = self.getAnimations('assets/playerAnimations',run=[4,4,4,4,4],#the animations of the player
                                             idle=[1],firstAttack=[4,4,4,4,4,4],secondAttack=[5,5,4,4],
                                             thirdAttack=[5,10,4],dash=[4,5,5,5,5,5])

    @property
    def isInIngameMenu(self):#is the player in the in game menu
        return self.input.runInGameMenu

    def drawPlayerHpBar(self,gameSurface):#draw the player's hp bar
        pygame.draw.rect(gameSurface,(172,50,50),(9,9+170,self.hpBarWidth-10,self.hpBar['height']-10))#draw the red hp bar
        gameSurface.blit(self.hpBar['img'],(4,4+170))#draw the hp bar image

    def attack(self):#attack function
        if self.attackCombo =='firstAttack':#if the attack combo is the first attack
            self.triggerAttack1()#call the triggerAttack1 function
        elif self.attackCombo == 'secondAttack':#if the attack combo is the second attack
            self.triggerAttack2()#call the triggerAttack2 function
        elif self.attackCombo == 'thirdAttack':#if the attack combo is the third attack
            self.triggerAttack3()#call the triggerAttack3 function

    def triggerAttack1(self):#trigger the first attack
        self.animations.changeState('firstAttack')#change the animation state to firstAttack
        currentImg = self.animations.getCurrentImg#get the current image of the animation
        if currentImg == 'firstAttack2':#if the current image is the second image of the first attack
            self.weapons["sword"].arc = self.weapons["sword"].newBezeirArc(self.x,self.y,self.flip,'down')#create a new bezeir arc
            self.startSlide()#start the slide
        elif currentImg == 'firstAttack5':#if the current image is the fifth image of the first attack
            self.attacking = False#stop attacking
            self.attackCombo = 'secondAttack'#change the attack combo to the second attack

    def triggerAttack2(self):#trigger the second attack
        self.animations.changeState('secondAttack')#change the animation state to secondAttack
        currentImg = self.animations.getCurrentImg#get the current image of the animation
        if currentImg == 'secondAttack2':#if the current image is the second image of the second attack
            self.weapons["sword"].arc = self.weapons["sword"].newBezeirArc(self.x,self.y,self.flip,'up')#create a new bezeir arc
            self.startSlide()#start the slide
        elif currentImg == 'secondAttack3':#if the current image is the third image of the second attack
            self.attacking = False#stop attacking
            self.attackCombo = 'thirdAttack'#change the attack combo to the third attack
    def triggerAttack3(self):#trigger the third attack
        self.animations.changeState('thirdAttack')#change the animation state to thirdAttack
        currentImg = self.animations.getCurrentImg#get the current image of the animation
        if currentImg == 'thirdAttack0':#if the current image is the first image of the third attack
            self.startSlide()#start the slide
            self.weapons["sword"].arc = self.weapons["sword"].newBezeirArc(self.x,self.y,self.flip,'down')#create a new bezeir arc
        elif currentImg == 'thirdAttack2':#if the current image is the third image of the third attack
            self.attacking = False#stop attacking
            self.attackCombo = 'firstAttack'#change the attack combo to the first attack
    def triggerDash(self):#trigger the dash
        self.attacking = False#stop attacking
        if self.flip: #if the player is flipped
            self.velocity[0] = -(6 / self.dashAcceleration)#set the velocity to the dash acceleration
            self.dashAcceleration += 0.5#increase the dash acceleration
        else: #if the player is not flipped
            self.velocity[0] = (6 / self.dashAcceleration)#set the velocity to the dash acceleration
            self.dashAcceleration += 0.5#increase the dash acceleration
        self.animations.changeState('dash')#change the animation state to dash
        currentImg = self.animations.getCurrentImg#get the current image of the animation
        if currentImg == 'dash5':#if the current image is the fifth image of the dash
            self.dash = False#stop dashing
            self.dashAcceleration = 0.5#reset the dash acceleration

    def changeAnimationState(self,movement):#change the animation state
        if movement[0] == 0:self.animations.changeState('idle')#if the player is not moving change the animation state to idle
        if movement[0] > 0:self.animations.changeState('run')#if the player is moving right change the animation state to run
        if movement[0] < 0:self.animations.changeState('run')#if the player is moving left change the animation state to run

    def kill(self):#kill the player
        self.hpBar['hp'] = 100#reset the hp
        self.dead = True#set the player to dead

    def startSlide(self):#start the slide
        self.slideVel = 3#set the slide velocity
        self.slideAcc = -1#set the slide acceleration
        self.slide = True#set the slide to true

    def slideUpdate(self):#update the slide
        if self.slide:#if the player is sliding
            self.slideVel += self.slideAcc#increase the slide velocity
            if self.flip: self.x -=self.slideVel#move the player left
            else: self.x += self.slideVel#move the player right
            if self.slideVel <= 0:#if the slide velocity is less than or equal to 0
                self.slide = False#stop sliding
                self.slideVel = None#reset the slide velocity
                self.slideAcc = None#reset the slide acceleration

    def update(self,gameSurface,scroll, enemies):#update the player
        self.updateCharacter()#update the character
        self.input.update()#update the input
        if not self.attacking:#if the player is not attacking
            movement = self.move(self.collisionRects)#move the player
        if self.dash: self.triggerDash()#if the player is dashing call the triggerDash function
        elif self.attacking: #if the player is attacking
            self.attack()#call the attack function
        else: self.changeAnimationState(movement)#change the animation state

        self.slideUpdate()#update the slide
        add = 0#set the add variable to 0
        if self.animations.getCurrentImg[:-1] == 'thirdAttack':#if the current image is the third attack
            if self.flip: add = -13#set the add variable to -13
            else: add = 13#set the add variable to 13
        self.weapons['sword'].update(self.x+add,self.y,gameSurface,scroll,enemies)#update the sword add to the x position of the player so that it's in the correct postion depending on the animation

        self.draw(gameSurface,scroll,self.animations.getImg())#draw the player
        self.drawPlayerHpBar(gameSurface)#draw the player hp bar


import collections;
import json;
import fcntl;

# Config = collections.namedtuple('Config', 'blog_name blog_subname nav_list');

def load_config(config_file):
    fin = open(config_file, 'r');
    fcntl.flock(fin, fcntl.LOCK_SH);
    config = json.loads(fin.read());
    fcntl.flock(fin, fcntl.LOCK_UN);
    fin.close();

    return config;

def dump_config(config, config_file):
    s = json.dumps(config, indent = 4);
    fout = open(config_file, 'w');
    fcntl.flock(fout, fcntl.LOCK_EX);
    fout.write(s);
    fcntl.flock(fout, fcntl.LOCK_UN);
    fout.close();

# print(load_config('../data/config.cnf'));
# for test


#Name: Brendan Gee
#Date: 5/17/21
#Video Link: https://youtu.be/Q-xJ1kPw6Yo
#Honor Statement: I have not given or received any unauthorized assistance on this assignment

import random

class WarAndPeacePseudoRandomNumberGenerator():

    def __init__(self, seed=1000):
        '''initialize the object at seed 1000 default,
        open the file'''

        #initialize seed & file
        self.seed = seed
        self.infile = open('war-and-peace.txt')

    def random(self):

        #initialize result
        bitlst = []
        ct = 0
        rand = 0

        #record 32 pairs, and use comparsions to assign bits of 1 or 0
        while ct < 32:

            try:

                letter1 = self.infile.read(self.seed)[-1]
                letter2 = self.infile.read(100)[-1]

            #if the file goes over the index, restart
            except IndexError:

                self.infile = open('war-and-peace.txt')
                letter1 = self.infile.read(1)[-1]
                letter2 = self.infile.read(100)[-1]

            #can't compare letters if they are the same
            if letter1 == letter2:
                continue
            elif letter1 > letter2:
                bitlst.append(1)
            else:
                bitlst.append(0)

            ct += 1
            self.seed = 100

        #calculate rand based on the bitlst
        for i in range(len(bitlst)):

            #approaches 1, includes 0
            rand += 1/(2**(i+1))*bitlst[i]

        return rand

    def generate(self,num):
        '''generate a given number of random numbers and
        store them in a list'''
        numlst = []

        #iterate through the required # of random numbers
        for i in range(num):
            numlst.append(self.random())

        return numlst

    def open(self):
        '''opens file if not already open'''
        self.infile = open('war-and-peace.txt')

    def close(self):
        '''closes file'''

        self.infile.close()


###### NEURAL NETWORK BASED VOTING SYSTEM ########
import csv

import numpy as np
from sklearn.externals import joblib
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier

def vote(logreg, gaussian, linearsvc, Y1):
    X = np.array(list(zip(logreg, gaussian, linearsvc)))
    Y = np.array(Y1)

    x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.25)
    clf = MLPClassifier(solver='adam', alpha=1e-3, hidden_layer_sizes=(32, 16), batch_size=16, learning_rate='adaptive', learning_rate_init=0.001, verbose=True)
    clf.fit(x_train, y_train)
    print('ANN training completed')
    y_real, y_pred = y_test, clf.predict(x_test)

    joblib.dump(clf, 'models/know_ann_voter.pkl')

    print('Accuracy: {:.2f}%'.format(accuracy_score(y_real, y_pred) * 100))
    '''
    print('MaxEnt Accuracy: {:.2f}%'.format(accuracy_score(y_real, x_test.T[0]) * 100))
    print('BiRNN Accuracy: {:.2f}%'.format(accuracy_score(y_real, x_test.T[1]) * 100))
    print('SVM-GloVe Accuracy: {:.2f}%'.format(accuracy_score(y_real, x_test.T[2]) * 100))
    '''
know_labels = {'Factual':0, 'Conceptual':1, 'Procedural':2, 'Metacognitive':3}
if __name__ == '__main__':
    VOTE_SUB = 'ADA'
    questions = []
    logreg = []
    gaussian = []
    linearsvc = []
    Y1 = []
    if VOTE_SUB == 'ADA':
        with open('datasets/ADA_Exercise_Questions_Results.csv', encoding="utf-8") as csvfile:
            csvreader = csv.reader(csvfile.read().splitlines()[1:])
            for row in csvreader:
                questions.append(row[0])
                Y1.append(know_labels.get(row[1]))
                logreg.append(know_labels.get(row[2]))
                gaussian.append(know_labels.get(row[3]))
                linearsvc.append(know_labels.get(row[4]))

        vote(logreg, gaussian, linearsvc, Y1)

    if VOTE_SUB == 'Combined':
        with open('datasets/COMBINED_Exercise_Questions_Results1.csv', encoding="utf-8") as csvfile:
            csvreader = csv.reader(csvfile.read().splitlines()[1:])
            for row in csvreader:
                questions.append(row[0])
                Y1.append(know_labels.get(row[1]))
                logreg.append(know_labels.get(row[2]))
                gaussian.append(know_labels.get(row[3]))
                linearsvc.append(know_labels.get(row[4]))

        vote(logreg, gaussian, linearsvc, Y1)


for ii in range(1,6):
    figure(ii)
    clf()

# Vector of half beam width [rad]
TH = array([2,10,20])*pi/180

# Angular values for evaluating beam intensity
th = linspace(-pi/2,pi/2,1000);

# MATLAB equiv.
#for ii = 1:length(TH):
#    theta_w = TH(ii);

for theta_w in TH:
    # Line array
    # Ratio of L/\lambda
    L_bar = 0.442/theta_w
    #th = theta_w
    x = pi*L_bar*sin(th)
    bl = (sin(x)/x)**2

    # Points for annotating polar plot
    th2 = linspace(-theta_w,theta_w,7)
    x = pi*L_bar*sin(th2)
    # Hack to avoid divide by zero
    x = x + 1e-3
    bl2 = (sin(x)/x)**2

    figure(1)
    plot(th/theta_w,10*log10(bl),
         label=r'%.1f deg, $L/\lambda$=%.1f'%(theta_w*180/pi,L_bar))

    figure(3)
    polar(th,10*log10(bl),
         label=r'%.1f deg, $L/\lambda$=%.1f'%(theta_w*180/pi,L_bar))

    figure(2)
    #plot(th/theta_w,10*log10(bl))
    plot(th/theta_w,bl,
         label=r'%.1f deg, $L/\lambda$=%.1f'%(theta_w*180/pi,L_bar))

    figure(4)
    #plot(th/theta_w,10*log10(bl))
    polar(th,bl,
         label=r'%.1f deg, $L/\lambda$=%.1f'%(theta_w*180/pi,L_bar))

    figure(5)
    polar(th/theta_w*30*pi/180.0,10*log10(bl),
         label=r'%.1f deg, $L/\lambda$=%.1f'%(theta_w*180/pi,L_bar))

figure(1)
axvline(-1,color='r',linestyle='--')
axvline(1,color='r',linestyle='--')
grid(True)
xlabel(r"Normalized angle, $\theta/\theta_{w}$ [n/a]")
ylabel(r"Source level [dB]")
ylim([-20,5])
legend()
tstr = r'$\theta_w$ = %.3f rad / %.1f deg, $L/\lambda$ = %.1f'%(theta_w,
                                                               theta_w*180/pi,
                                                               L_bar)
tstr = 'Line array beam pattern at different beam widths'
title(tstr)
xlim([-4,4])

figure(2)
axvline(-1,color='r',linestyle='--')
axvline(1,color='r',linestyle='--')
grid(True)
xlabel(r"Normalized angle, $\theta/\theta_{w}$ [n/a]")
ylabel(r"Source level [n/a]")
legend()
title(tstr)
xlim([-4,4])

figure(3)
xlim([-pi/2,pi/2])
xlim(45.0*pi/180*array([-1, 1]))
ylim([-20,3])
gca().set_theta_zero_location("N")
legend(loc='lower right',bbox_to_anchor=(0.2,0.1))
ylabel('dB')
yticks([-20, -15, -10, -5, -3, 0, 3])
xticks(arange(-40,50,10)*pi/180.0)

figure(4)
xlim([-pi/2,pi/2])
xlim(45.0*pi/180*array([-1, 1]))
#ylim([-20,5])
gca().set_theta_zero_location("N")
legend(loc='lower right',bbox_to_anchor=(0.2,0.1))
ylabel('Ratio [n/a]')
yticks([0, 0.25, 0.5, 0.75, 1.0])
xticks(arange(-40,50,10)*pi/180.0)

figure(5)
xlim([-pi/2,pi/2])
xlim(60.0*pi/180*array([-1, 1]))
ylim([-15,3])
gca().set_theta_zero_location("N")
#legend(loc='lower right',bbox_to_anchor=(0.2,0.1))
ylabel('dB')
yticks([-3,0])
xt = array([-30, 0, 30])*pi/180
xticks(xt,[r'$-\theta_w$',r'$0$',r'$\theta_w$'])

polar(th2/theta_w*30*pi/180.0,10*log10(bl2),'ro')
show()


import math
import sys

#  Function to find the minimum weight Hamiltonian Cycle
def tsp_util(graph,  n,  path,  path_size,  path_cost,  visited,  ans) :
    curr = path[n - 1]
    if (path_size == n and graph[curr][0] > 0) :
        ans = min(ans,path_cost + graph[curr][0])
        return  ans

    for i in range(0, n):
        if (visited[i] == False and graph[curr][i] > 0) :
            visited[i] = True
            path[path_size] = i
            ans = tsp_util(graph, n, path, path_size + 1, path_cost + graph[curr][i], visited, ans)
            visited[i] = False
    return  ans

def tsp(graph,  n) :
    visited = [False] * n
    path = [0] * n
    visited[0] = True
    ans = tsp_util(graph, n, path, 1, 0, visited, sys.maxsize)
    return  ans

# Testing Code
n = 4
graph = [[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]]
print("TSP path cost:", tsp(graph, n))

"""
TSP path cost: 65
"""


import os
from tqdm import tqdm
import logging
import jsonlines

from retrieving.retrieval_module import get_retrieval_module
from utils import Arguments, set_seed, print_args
from utils.time_log import TimeMeasure
from evaluation.metrics import Metrics

logger = logging.getLogger(__name__)

def main():
    parser = Arguments()
    parser.add_model_parameters()
    parser.add_retrieval_module_parameters()

    parser.add_argument("--checkpoint_path", type=str, required=True)
    parser.add_argument("--query_file", type=str, required=True,
                        help="query file is jsonl file")
    parser.add_argument("--document_name", type=str, required=True)
    parser.add_argument("--faiss_depth", type=int, default=1)
    parser.add_argument("--batch_size", type=int, default=32)
    args = parser.parse()

    print_args(args, logger)
    set_seed(args.seed)

    logging.basicConfig(
        format="%(asctime)s - %(levelname)s - %(name)s -   %(message)s",
        datefmt="%m/%d/%Y %H:%M:%S",
        level=logging.INFO,
    )

    # Load retrieving Model and files
    logger.info("[Load retrieval_module]===========")
    retrieval = get_retrieval_module(args)

    document_path = os.path.join(args.index_dir, f"{args.document_name}.bin")
    if os.path.exists(document_path):
        retrieval.load_document(document_path)
    else:
        logger.info(f"Wrong document name")
        exit(0)

    qas = []
    with jsonlines.open(args.query_file, "r") as f:
        for line in f:
            qas.append(line)

    # Evaluate
    time_measure = TimeMeasure(logger)
    metric = Metrics(mrr_depths={10, 50, 100},
                     success_depths={10, 50, 100},
                     recall_depths={10, 50, 100})

    with time_measure as tm:
        tm.set_prefix("[Do Evaluate]===========: ")

        q_id = 0
        for offset in tqdm(range(0, len(qas), args.batch_size)):
            endpos = min(offset + args.batch_size, len(qas))
            batch = qas[offset: endpos]

            queries = [b['query'] for b in batch]
            _, pids = retrieval.retrieval(queries, args.document_name,
                                          faiss_depth=args.faiss_depth, verbose=args.retrieval_verbose)

            for i in range(len(batch)):
                metric.add(q_id, pids[i], batch[i]['answers'])
                q_id += 1

        metric.print_metrics()

if __name__ == "__main__":
    main()


"""
FILE: skeleton_parser.py
------------------
Author: Firas Abuzaid (fabuzaid@stanford.edu)
Author: Perth Charernwattanagul (puch@stanford.edu)
Modified: 04/21/2014

Skeleton parser for CS564 programming project 1. Has useful imports and
functions for parsing, including:

1) Directory handling -- the parser takes a list of eBay json files
and opens each file inside of a loop. You just need to fill in the rest.
2) Dollar value conversions -- the json files store dollar value amounts in
a string like $3,453.23 -- we provide a function to convert it to a string
like XXXXX.xx.
3) Date/time conversions -- the json files store dates/ times in the form
Mon-DD-YY HH:MM:SS -- we wrote a function (transformDttm) that converts to the
for YYYY-MM-DD HH:MM:SS, which will sort chronologically in SQL.

Your job is to implement the parseJson function, which is invoked on each file by
the main function. We create the initial Python dictionary object of items for
you; the rest is up to you!
Happy parsing!
"""

import sys
from json import loads
from re import sub

columnSeparator = "|"

itemTable = ""
catTable = ""
sellerTable = ""
bidderTable = ""
bidTable = ""

# Dictionary of months used for date transformation
MONTHS = {'Jan':'01','Feb':'02','Mar':'03','Apr':'04','May':'05','Jun':'06',\
        'Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'}

"""
Returns true if a file ends in .json
"""
def isJson(f):
    return len(f) > 5 and f[-5:] == '.json'

"""
Converts month to a number, e.g. 'Dec' to '12'
"""
def transformMonth(mon):
    if mon in MONTHS:
        return MONTHS[mon]
    else:
        return mon

"""
Transforms a timestamp from Mon-DD-YY HH:MM:SS to YYYY-MM-DD HH:MM:SS
"""
def transformDttm(dttm):
    dttm = dttm.strip().split(' ')
    dt = dttm[0].split('-')
    date = '20' + dt[2] + '-'
    date += transformMonth(dt[0]) + '-' + dt[1]
    return date + ' ' + dttm[1]

"""
Transform a dollar value amount from a string like $3,453.23 to XXXXX.xx
"""

def transformDollar(money):
    if money == None or len(money) == 0:
        return money
    return sub(r'[^\d.]', '', money)

"""
Parses a single json file. Currently, there's a loop that iterates over each
item in the data set. Your job is to extend this functionality to create all
of the necessary SQL tables for your database.
"""

def parse_items(item):
    line = ""

    if 'ItemID'in item and item['ItemID'] != None:
        item['ItemID']= item['ItemID'].replace('"', '""')
        line += item['ItemID']
        line = line + columnSeparator
    else :
        line = line + 'null'
        line = line + columnSeparator

    if 'Name' in item and item['Name'] != None:
        item['Name']= item['Name'].replace('"', '""')
        line += '\"' + item['Name'] + '\"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Currently' in item and item['Currently'] != None:
        item['Currently']= item['Currently'].replace('"', '""')
        line += '\"' + transformDollar(item['Currently']) + '\"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Buy_Price' in item and item['Buy_Price'] != None:
        item['Buy_Price']= item['Buy_Price'].replace('"', '""')
        line += '\"' + transformDollar(item['Buy_Price']) + '\"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'First_Bid' in item and item['First_Bid'] != None:
        item['First_Bid']= item['First_Bid'].replace('"', '""')
        line += '"' + transformDollar(item['First_Bid']) + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Number_of_Bids' in item and item['Number_of_Bids'] != None:
        item['Number_of_Bids']= item['Number_of_Bids'].replace('"', '""')
        line += item['Number_of_Bids']
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Started' in item and item['Started'] != None:
        item['Started']= item['Started'].replace('"', '""')
        line += '"' + transformDttm(item['Started']) + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Ends' in item and item['Ends'] != None:
        item['Ends']= item['Ends'].replace('"', '""')
        line += '"' + transformDttm(item['Ends']) + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Description' in item and item['Description'] != None:
        item['Description'] = item['Description'].replace('\"', '""')
        line += '"' + item['Description'] + '"'
        line += columnSeparator
    else:
        line += 'null'
        line += columnSeparator

    if 'Seller' in item and item['Seller'] != None:
        item['Seller']['UserID']= item['Seller']['UserID'].replace('"', '""')
        line += '"' + item['Seller']['UserID'] + '"'

    else:
        line += 'null'

    line += '\n'
    return line

def categoryTable(item):
    line = ""
    if 'ItemID' in item and item['ItemID'] != None :
        if('Category' in item and item['Category'] != None):
            i = 0
            for ele in item['Category']:
                line += item['ItemID']
                line += columnSeparator
                item['Category'][i] = item['Category'][i].replace('"', '""')
                line += '"' + item['Category'][i] + '"'
                line += '\n'
                i += 1
        else:
            for i in item['Category']:
                line += item['ItemID']
                line += columnSeparator
                line += 'null'
                line += '\n'
    return line

def sTable(item):
    line = ""
    if 'Seller' in item and item['Seller'] != None:
        line += '"' + item['Seller']['UserID'] + '"'
        line += columnSeparator
        if 'Location' in item and item['Location'] != None:
            item['Location']= item['Location'].replace('"', '""')
            line += '"' + item['Location'] + '"'
        else:
            line += 'null'
        line += columnSeparator
        if 'Country' in item and item['Country'] != None:
            item['Country']= item['Country'].replace('"', '""')
            line += '"' + item['Country'] + '"'
        else:
            line += 'null'
        line += columnSeparator
        if 'Rating' in item['Seller'] and item['Seller']['Rating'] != None:
            line += item['Seller']['Rating']
        else:
            line += 'null'
        line += '\n'
    return line

def bTable(item):
    line = ""

    if 'Bids' in item and item['Bids'] != None:
        for bidder in item['Bids']:
            #print(bidder)
            bidder['Bid']['Bidder']['UserID']= bidder['Bid']['Bidder']['UserID'].replace('"', '""')
            line += '\"' + bidder['Bid']['Bidder']['UserID'] + '\"'
            line += columnSeparator
            if 'Location' in bidder['Bid']['Bidder'] and bidder['Bid']['Bidder']['Location'] != None:
                bidder['Bid']['Bidder']['Location']= bidder['Bid']['Bidder']['Location'].replace('"', '""')
                line += '"' + bidder['Bid']['Bidder']['Location'] + '"'
            else:
                line += 'null'

            line += columnSeparator

            if 'Country' in bidder['Bid']['Bidder'] and bidder['Bid']['Bidder']['Country'] != None:
                bidder['Bid']['Bidder']['Country']= bidder['Bid']['Bidder']['Country'].replace('"', '""')
                line += '"' + bidder['Bid']['Bidder']['Country'] + '"'
            else:
                line += 'null'

            line += columnSeparator

            if 'Rating' in bidder['Bid']['Bidder'] and bidder['Bid']['Bidder']['Rating'] != None:
                line += bidder['Bid']['Bidder']['Rating']
            else:
                line += 'null'

            line += '\n'
    return line

def parse_bid(item):
    line = ""
    if 'Bids' in item and item['Bids'] != None:
        for bid_i in item['Bids']:
            line += item['ItemID']
            line += columnSeparator

            line += '"' + bid_i['Bid']['Bidder']['UserID'] + '"'
            line += columnSeparator

            if bid_i['Bid']['Time'] != None:

                line += '"' + transformDttm(bid_i['Bid']['Time']) + '"'
            else:
                line += 'null'
            line += columnSeparator
            if bid_i['Bid']['Amount'] != None:
                bid_i['Bid']['Amount']= bid_i['Bid']['Amount'].replace('"', '""')
                line += '"' + transformDollar(bid_i['Bid']['Amount']) + '"'
            else: line += 'null'
            line += '\n'

    return line

def parseJson(json_file):
    global itemTable, catTable, bidderTable, bidTable, sellerTable
    with open(json_file, 'r') as f:
        items = loads(f.read())['Items'] # creates a Python dictionary of Items for the supplied json file

        for item in items:
            """
            TODO: traverse the items dictionary to extract information from the
            given `json_file' and generate the necessary .dat files to generate
            the SQL tables based on your relation design
            """

            itemTable += parse_items(item)
            catTable += categoryTable(item)
            bidderTable += bTable(item)
            sellerTable += sTable(item)
            bidTable += parse_bid(item)

def output():
    f1 = open("itemTable.dat", "a")
    f2 = open("categoryTable.dat", "a")
    f3 = open("bidderTable.dat", "a")
    f4 = open("bidTable.dat", "a")
    f5 = open("sellerTable.dat", "a")
    f1.write(itemTable)
    f2.write(catTable)
    f3.write(bidderTable)
    f4.write(bidTable)
    f5.write(sellerTable)
    f1.close()
    f2.close()
    f3.close()
    f4.close()
    f5.close()

"""
Loops through each json files provided on the command line and passes each file
to the parser
"""
def main(argv):
    if len(argv) < 2:
        print >> sys.stderr, 'Usage: python skeleton_json_parser.py <path to json files>'
        sys.exit(1)
    # loops over all .json files in the argument
    for f in argv[1:]:
        if isJson(f):
            parseJson(f)
            print("Success parsing " + f)
    output()

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


class Apartment:
	"""docstring for Apartment"""
	def __init__(self, aptNumber, numOfBaths, numOfBedrooms, rent):

		self.setRent(rent)
		self.setApartmentNumber(aptNumber)
		self.setNumberOfBathrooms(numOfBaths)
		self.setNumberOfBedrooms(numOfBedrooms)

	def setRent(self,rent):
		try:
			self.rent = float(rent)
			if self.rent < 0.0:
				raise Exception
		except Exception:
			self.rent = 0.0
	def setApartmentNumber(self,aptNumber):
		try:
			self.aptNumber = int(aptNumber)
			if self.aptNumber < 0:
				raise Exception
		except Exception:
			self.aptNumber = 0
	def setNumberOfBathrooms(self,numOfBaths):
		try:
			self.numOfBaths = int(numOfBaths)
			if self.numOfBaths < 0:
				raise Exception
		except Exception:
			self.numOfBaths = 0

	def setNumberOfBedrooms(self,numOfBedrooms):
		try:
			self.numOfBedrooms = int(numOfBedrooms)
			if self.numOfBedrooms < 0:
				raise Exception
		except Exception:
			self.numOfBedrooms = 0

	def getRent(self):
		return self.rent
	def getApartmentNumber(self):
		return self.aptNumber
	def getNumberOfBathrooms(self):
		return self.numOfBaths
	def getNumberOfBedrooms(self):
		return self.numOfBedrooms

def getApartmentData(fileName):
	data = []
	try:
		logFile = open(fileName,'r')
	except Exception:
		# logFile = open('dateLog', 'ab')
		print('Data not formatted properly')
	for line in logFile.readlines():
		y = line
		data.append(y.strip('\n').split(','))
	logFile.close()
	return data

w = getApartmentData('ApartmentData.txt')

allApartments = []
for i in w:
	allApartments.append(Apartment(i[0],i[1],i[2],i[3]))

def userApartmentWants(wantAptlst):
	apartmentsFound = []
	for aa in range(len(allApartments)):
		if wantAptlst[0] <= allApartments[aa].numOfBedrooms and wantAptlst[1] <= allApartments[aa].numOfBaths and wantAptlst[2] >= allApartments[aa].rent:
			apartmentsFound.append(allApartments[aa])
	return apartmentsFound

def mainMenu(option):
	if option is '1':
		newaptnum = input('Enter new Apartment Number\n')
		newaptbeds = input('Enter new Apartment Number of bedrooms\n')
		newaptbaths = input('Enter new Apartment Number of bathrooms\n')
		newaptrent = input('Enter new Apartment Rent\n')
		allApartments.append(Apartment(newaptnum,newaptbaths,newaptbeds,newaptrent))
	elif option is '2':
		while True:
			try:
				minaptbeds = int(input('Enter min Apartment Number of bedrooms\n'))
				if minaptbeds < 0:
					continue
				else:
					break
			except Exception:
				continue

		while True:
			try:
				minaptbaths = int(input('Enter min Apartment Number of bathrooms\n'))
				if minaptbaths < 0:
					continue
				else:
					break
			except Exception:
				continue

		while True:
			try:
				maxaptrent = float(input('Enter max Apartment Rent\n'))
				if maxaptrent < 0:
					continue
				else:
					break
			except Exception:
				continue
		return [minaptbeds,minaptbaths,maxaptrent]

x = input('Select 1 for new Apartment or 2 for finding Apartments\n')
if x is '1':
	mainMenu('1')
elif x is '2':
	apartmentCriteria = mainMenu('2')
	selectedaparts = userApartmentWants(apartmentCriteria)
else:
	print('not a valid menu choice')
if len(selectedaparts) > 0:
	print('Number: ', '\t', 'Rent: ', '\t', 'Bedrooms: ', '\t', 'Bathrooms: ')
	for n in range(len(selectedaparts)):
		print(selectedaparts[n].aptNumber,'\t\t',  '{:5.2f}'.format(selectedaparts[n].rent),'\t\t', selectedaparts[n].numOfBedrooms, '\t\t', selectedaparts[n].numOfBaths)


import typing as t
import datetime
import pandas as pd
import calendar as cal
from commodutil import forwards
from pylim import lim
from pylim import limutils
from pylim import limqueryutils as lqu

def quarterly(symbol: str, quarter: int = 1, start_year=datetime.date.today().year,
              end_year=datetime.date.today().year + 2, start_date=t.Optional[datetime.date]):
    """
    Given a symbol or formula, calculate the quarterly average and return as a series of yearly timeseries
    :param symbol:
    :param quarter:
    :param start_year:
    :param end_year:
    :return:
    """
    cmap = {1: ['F', 'G', 'H'], 2: ['J', 'K', 'M'], 3: ['N', 'Q', 'U'], 4: ['V', 'X', 'Z']}

    if quarter == 0:  # calc Q1,Q2,Q3,Q4
        df = lim.contracts(symbol, start_year=start_year, end_year=end_year, start_date=start_date)
        dfs = []
        for qtr in cmap:  # filter columns for each quarter
            d = df[[x for x in df.columns if x[-1] in cmap[qtr]]]
            d = limutils.convert_lim_contracts_to_datetime(d)
            d = limutils.pivots_contract_by_year(d)
            d = d.rename(columns={x: 'Q%s_%s' % (qtr, x) for x in d.columns})  # eg Q12020
            dfs.append(d)
        return pd.concat(dfs, 1)
    else:
        return calendar(symbol, start_year=start_year, end_year=end_year, months=cmap[quarter], start_date=start_date)

def calendar(symbol, start_year=datetime.date.today().year, end_year=datetime.date.today().year + 2,
             months: t.Optional[t.Tuple[str, ...]] = None,
             start_date: t.Optional[datetime.date] = None):
    """
    Given a symbol or formula, calculate the calendar (yearly) average and return as a series of yearly timeseries
    :param months:
    :param symbol:
    :param quarter:
    :param start_year:
    :param end_year:
    :return:
    """
    df = lim.contracts(symbol, start_year=start_year, end_year=end_year, months=months, start_date=start_date)
    df = limutils.convert_lim_contracts_to_datetime(df)
    return limutils.pivots_contract_by_year(df)

def spread(symbol: str, x: t.Tuple[int, str], y: t.Tuple[int, str], z: t.Optional[t.Tuple[int, str]] = None,
           start_year: datetime.date.today().year = None, end_year: datetime.date.today().year = None,
           start_date: t.Optional[datetime.date] = None) -> pd.DataFrame:
    contracts = lim.contracts(symbol, start_year=start_year, end_year=end_year, months=[x, y, z],
                                 start_date=start_date)
    contracts = limutils.convert_lim_contracts_to_datetime(contracts)

    if z is not None:
        if (isinstance(x, int) or x.isnumeric()) and (isinstance(y, int) or y.isnumeric()) and (isinstance(z, int) or z.isnumeric()):
            return forwards.fly(contracts, int(x), int(y), int(z))

    if (isinstance(x, int) or x.isnumeric()) and (isinstance(y, int) or y.isnumeric()):
        return forwards.time_spreads_monthly(contracts, x, y)

    if isinstance(x, str) and isinstance(y, str):
        x, y = x.upper(), y.upper()
        if x.startswith('Q') and y.startswith('Q'):
            return forwards.time_spreads_quarterly(contracts, x, y)

        if x.startswith('CAL') and y.startswith('CAL'):
            return forwards.cal_spreads(forwards.cal_contracts(contracts))

def fly(symbol: str, x: t.Tuple[int, str], y: t.Tuple[int, str], z: t.Optional[t.Tuple[int, str]],
        start_year: t.Optional[datetime.date] = None,
        end_year=None, start_date: t.Optional[datetime.date] = None):
    return spread(symbol, x, y, z, start_year=start_year, end_year=end_year, start_date=start_date)

def multi_spread(symbol, spreads, start_year: datetime.date.today().year = None,
                 end_year: datetime.date.today().year = None,
                 start_date: t.Optional[datetime.date] = None) -> pd.DataFrame:
    contracts = lim.contracts(symbol, start_year=start_year, end_year=end_year, start_date=start_date)
    contracts = limutils.convert_lim_contracts_to_datetime(contracts)

    dfs = []
    for spread in spreads:
        r = forwards.time_spreads_monthly(contracts, spread[0], spread[1])
        r = r.rename(
            columns={x: '%s%s_%s' % (cal.month_abbr[spread[0]], cal.month_abbr[spread[1]], x) for x in r.columns})
        dfs.append(r)

    res = pd.concat(dfs, 1)
    return res


import time
import ipdb
import pickle
from agents.reinforcement_agent import *

EMPTY_ACTIONS = np.zeros(len(POSSIBLE_MOVES))
TARGET_NET_UPDATE_FREQUENCY = 30000
SAVE_NET_FREQUENCY = 500
EGREEDY_EPSILON = 0.9
N_INITIAL_RANDOM_MOVES = 50000
BATCH_SIZE = 8

class QAgent(Agent):
    def __init__(self, model_name, saved_model_file=None, watch=False):
        super().__init__(model_name, saved_model_file=saved_model_file, watch=watch)
        self.target_model = self.model.copy()
        self.exploiting_turn = bool(random.getrandbits(1))
        self.total_moves_performed = 0
        self.total_games_played = 0
        self.recent_q_values = deque([], N_ROLLING_AVG)
        self.watching = watch

    def choose_action(self, board):
        if self.watching:
            time.sleep(0.1)
        if self.__should_exploit():
            state = Board.copy_state(board, board.tetronimo)
            q_values = self.model.predict(state, EMPTY_ACTIONS)
            self.recent_q_values.append(np.max(q_values))
            return np.argmax(q_values)
        return random.choice(POSSIBLE_MOVES)

    def game_over(self, total_reward):
        self.total_games_played += 1
        if self.watching:
            self.model = self.load_model(self.saved_model_file)
            self.__update_target_model()

    def on_episode_end(self, reward, episode_length):
        self.state_printer.print(self.states_t1[self.current_pos - 1])

    def on_move_end(self):
        self.total_moves_performed += 1
        if self.watching:
            self.state_printer.print(self.states_t1[self.current_pos - 1])
        else:
            self.__experience_replay()
            if self.total_moves_performed % TARGET_NET_UPDATE_FREQUENCY == 0:
                self.__update_target_model()
            if self.total_moves_performed % SAVE_NET_FREQUENCY == 0:
                self.__save_model()

    def __should_exploit(self):
        if (not self.watching) and (self.total_moves_performed < N_INITIAL_RANDOM_MOVES):
            return False
        return random.random() < EGREEDY_EPSILON

    def __max_populated_buffer_index(self):
        return min(self.total_moves_performed, BUFFER_SIZE)

    def __experience_replay(self):
        indexes = np.random.randint(0, self.__max_populated_buffer_index(), BATCH_SIZE)
        states, actions, target_q_values = self.__training_data_for_indexes(indexes)
        self.model.train(states, actions, target_q_values, 1)

    def __update_target_model(self):
        self.target_model = self.model.copy()

    def __save_model(self):
        sys.setrecursionlimit(5000)
        pickle.dump(self.model,
            open('output/model.p', 'wb'),
            protocol=pickle.HIGHEST_PROTOCOL)
        sys.setrecursionlimit(1000)

    def __training_data_for_indexes(self, indexes):
        states = self.states_t0[indexes]
        actions = self.actions_by_index(indexes)
        rewards = self.rewards[indexes]
        states_t1 = self.states_t1[indexes]
        targets = list()
        for i in range(0, states.shape[0]):
            action = actions[i]
            current_targets = self.model.predict(states[i], EMPTY_ACTIONS)
            next_q_values = self.model.predict(states_t1[i], EMPTY_ACTIONS)
            next_target_q_values = self.target_model.predict(states_t1[i], EMPTY_ACTIONS)
            # Double DQN
            current_targets[np.where(action == 1)] = \
                rewards[i] + DISCOUNT*(next_target_q_values[np.argmax(next_q_values)])
            targets.append(current_targets)
        targets = np.array(targets)
        return (states, actions, targets)


from queue import PriorityQueue

def solution(food_times, k):
    answer = 0

    #우선 순위 큐를 생성
    que = PriorityQueue()

    #딕셔너리 타입으로 재정의
    for i in len(food_times):
        que.put((food_times[i],i+1))

    #음식 시간의 총합
    food_total_sum = sum(food_times)

    #k보다 음식의 시간이 작으면 -1 반환
    if food_total_sum <= k:
        return -1

    else:
        while True:
            shortest_time = que.get()[0]

            #가장 짧은 음식시간의 사이클을 돌 수 있는지 확인
            if k > shortest_time*len(food_times):
                #시간을 줄여주고
                k -= shortest_time*len(food_times)

            #돌은만큼 빼주기
            for i in que:
                que[i][0] -= shortest_time

            if shortest_time > k:
                break

    return answer

이것이 코테다/그리디/무지의 먹방 라이브/sol_python.py


# -*- coding: UTF-8 -*-
from flask_socketio import SocketIO
from server3.utility import json_utility
from server3.constants import REDIS_SERVER

socketio = SocketIO(message_queue=REDIS_SERVER)

epoch = 0

def emit_notification(message, created_receivers):
    for receiver in created_receivers:
        receiver_user = receiver.user
        message.is_read = False
        message.receiver_id = [receiver.id]
        if message.user:
            message.user_ID = message.user.user_ID
            message.username = message.user.username
        if message.user_request:
            message.user_request_title = message.user_request.title
            message.user_request_type = message.user_request.type
            message.request_user_ID = message.user_request.user.user_ID
            message.request_username = message.user_request.user.username
        if message.project:
            message.project_name = message.project.name
            message.project_display_name = message.project.display_name
            message.project_type = message.project.type
            message.project_id = message.project.id
            message.is_tutorial = message.project.is_tutorial
            message.project_collaborators = [c.to_mongo() for c in
                                             message.project.collaborators]
        if message.answer and message.answer.user_request:
            message.user_request_title = message.answer.user_request.title
            message.user_request_type = message.answer.user_request.type
            message.user_request = message.answer.user_request
        # task
        if message.task:
            message.task_type = message.task.task_type
            message.sponsor = message.task.sponsor.user_ID
            message.task_title = message.task_type + '-' + str(message.task.id)
            message.display_name = message.project.display_name
        # print(22222, message.project)
        msg = json_utility.convert_to_json(
            {'receiver_id': receiver.id,
             'message': message.to_mongo(),
             })
        # print('notification', msg, receiver_user.user_ID)
        socketio.emit('notification', msg,
                      namespace='/log/%s' % receiver_user.user_ID)

def emit_refresh_event(message, user_ID):
    # print(message, user_ID)
    socketio.emit('refresh', message,
                  namespace=f'/log/{user_ID}')

def emit_world_message(world):
    if hasattr(world, "sender") and world.sender:
        world.sender_user_ID = world.sender.user_ID
    else:
        world.sender_user_ID = "system"

    world_message = json_utility.convert_to_json(world.to_mongo())
    socketio.emit('world', world_message, namespace='/log')

def emit_create_project(user_ID, state, source_project, display_name,
                        project_type, rand_num_str=None):
    msg = json_utility.convert_to_json(
        {
            'user_ID': user_ID,
            'state': state,
            'source_project': source_project,
            'project_name': display_name,
            'project_type': project_type,
            'rand_num_str': rand_num_str,
        })
    socketio.emit('create_project', msg,
                  namespace='/log/%s' % user_ID)

def emit_deploy_project(user_ID, project_id, state, version):
    msg = json_utility.convert_to_json(
        {
            'user_ID': user_ID,
            'project_id': project_id,
            'state': state,
            'version': version,
        })
    socketio.emit('deploy_project', msg,
                  namespace='/log/%s' % user_ID)

def send_ping():
    socketio.emit('ping event', '', namespace='/ping_pong')


# https://leetcode.com/problems/count-and-say/
# leetcode 38
# easy

def countAndSay(n):
    current = None
    for _ in range(n):
        current = say(current)
    return current

def say(n):
    if n is None:
        return "1"
    else:
        res, crnt, amt = "", n[0], 1
        for item in n[1:]:
            if item == crnt:
                amt += 1
            else:
                res += f"{amt}{crnt}"
                crnt, amt = item, 1
        res += f"{amt}{crnt}"
        return res


#!/usr/bin/python3
#Given a folder with ecoding, instances and list of instances run IDLV for each instances and
#    run all encodings and save the running time

import sys
import os
import numpy as np
import datetime

import annotator
import runner

PID = os.getpid()
WARNING_PERC = 30

def extractStats(dir, encoding_means):
    stats = []
    warnings = []
    if 0 not in encoding_means:
        print("ERROR default encoding not in %s" % dir)
        return stats

    problem = runner.getLast(dir)
    base_time = encoding_means[0]
    for e in encoding_means:
        p = ((base_time - encoding_means[e]) / base_time) * 100
        if p > WARNING_PERC:
            warnings.append("%s\t%s\t%s\t%s" % (problem, e, str(encoding_means[e]), str(p)))
        stats.append("%s\t%s\t%s\t%s" % (problem, e, str(encoding_means[e]), str(p)))

    return (stats, warnings)

def main(directory):
    print("Start extract stats")
    directoies = []
    for dir in os.listdir(directory):
        directoies.append(directory+dir)

    dir_out = {}
    for dir in directoies:
        dir_out[dir] =  dir +"/" + annotator.checkDir(dir)

    fileOut = open("result_"+str(datetime.date.today())+"_"+str(PID),"w")
    fileSum = open("result_summary"+str(datetime.date.today())+"_"+str(PID),"w")
    fileOut.write("Problem\tencoding\ttime(s)\t%\n")
    for dir in dir_out:
        do = dir_out[dir]
        file = open(do+"/"+runner.RESULTFILE, "r")
        encoding_times = {}
        for line in file:
            num = int(line.split("\t")[0].split(".")[-1])
            if num not in encoding_times:
                encoding_times[num] = []
            encoding_times[num].append(float(line.split("\t")[2]))
        encoding_means = {}
        for k in encoding_times:
            encoding_means[k] = np.mean(encoding_times[k])

        s, w = extractStats(dir, encoding_means)
        for l in s:
            fileOut.write(l+"\n")
        file.close()
        for l in w:
            fileSum.write(l+"\n")
    fileOut.close()
    fileSum.close()

if __name__ == "__main__":
    folder = sys.argv[1]
    if folder[-1] != '/':
        folder += '/'
    main(folder)


# coding: utf-8

from __future__ import absolute_import
from datetime import date, datetime  # noqa: F401

from typing import List, Dict  # noqa: F401

from swagger_server.models.base_model_ import Model
from swagger_server import util

class MECTrafficServiceCreationResponse(Model):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """

    def __init__(self, request_id: str=None):  # noqa: E501
        """MECTrafficServiceCreationResponse - a model defined in Swagger

        :param request_id: The request_id of this MECTrafficServiceCreationResponse.  # noqa: E501
        :type request_id: str
        """
        self.swagger_types = {
            'request_id': str
        }

        self.attribute_map = {
            'request_id': 'RequestId'
        }

        self._request_id = request_id

    @classmethod
    def from_dict(cls, dikt) -> 'MECTrafficServiceCreationResponse':
        """Returns the dict as a model

        :param dikt: A dict.
        :type: dict
        :return: The MECTrafficServiceCreationResponse of this MECTrafficServiceCreationResponse.  # noqa: E501
        :rtype: MECTrafficServiceCreationResponse
        """
        return util.deserialize_model(dikt, cls)

    @property
    def request_id(self) -> str:
        """Gets the request_id of this MECTrafficServiceCreationResponse.

        Request identifier assigned by the MEC plugin. This will be used for future queries or service deletion requests.  # noqa: E501

        :return: The request_id of this MECTrafficServiceCreationResponse.
        :rtype: str
        """
        return self._request_id

    @request_id.setter
    def request_id(self, request_id: str):
        """Sets the request_id of this MECTrafficServiceCreationResponse.

        Request identifier assigned by the MEC plugin. This will be used for future queries or service deletion requests.  # noqa: E501

        :param request_id: The request_id of this MECTrafficServiceCreationResponse.
        :type request_id: str
        """
        if request_id is None:
            raise ValueError("Invalid value for `request_id`, must not be `None`")  # noqa: E501

        self._request_id = request_id


import pandas as pd
import streamlit as st
import datetime
from deta import Deta

st.set_page_config(page_title="Received Items", page_icon="ðŸ‘‘")

deta = Deta(st.secrets["key_number"])
db = deta.Base("Receieve")
db1 = deta.Base("Stone")
all_items = db.fetch().items
n1 = db1.fetch().items

jn = st.number_input('Enter job number', value=1, step=1)
genre = st.radio("What kind of Receieve",('Partial', 'Full'))

today = datetime.date.today()
day=int(today.strftime("%d"))
m=int(today.strftime("%m"))
y=int(today.strftime("%Y"))

df = pd.DataFrame(n1)
stones = df['Stone name'].values.tolist()

if genre == 'Full':
      flag = 0
      for j in all_items:
            if j['Job No'] == jn:
                flag = 1
                if str(j['Status']) == 'P':
                      st.write('')
                      st.header('Details')
                      st.write('')
                      st.write('Recieved Status : Partially Recieved')
                      st.write('Recieved On  : ',str(j['Receieve Date']))
                      st.write('')
                      st.header('Update details')
                      st.write('')

                      with st.form("Full1"):
                            d1 = st.date_input('Receive Date', datetime.date(y, m, day))
                            cmts1 = st.text_input('Comments', '')
                            d11 = d1.strftime("%m/%d/%Y")
                            submit_button = st.form_submit_button(label='Submit')

                      if submit_button:
                            keydata = str(j['key'])
                            db.update({"Receieve Date": d11, "Comments_Full" : cmts1, "Status":'F'},keydata,)
                            st.write("Data updated !")

                elif str(j['Status']) == 'F':
                      st.write('Item was already confirmed to be received, veiw full details on homepage')

                elif str(j['Status']) == 'N':
                      st.write('')
                      st.header('Enter details')
                      st.write('')
                      with st.form("Full2"):
                            d1 = st.date_input('Receieve Date', datetime.date(y, m, day))
                            cmts1 = st.text_input('Comments', '')
                            d11 = d1.strftime("%m/%d/%Y")
                            submit_button = st.form_submit_button(label='Submit')
                      if submit_button:
                            keydata = str(j['key'])
                            db.update({"Receieve Date": d11, "Comments_Full" : cmts1, "Status":'F'},keydata,)
                            st.write("Data submitted !")

      if flag == 0 :
            st.write('Data not found !')

if genre == 'Partial' :
      flag = 0
      for j in all_items:
            if j['Job No'] == jn:
                flag = 1
                if str(j['Status']) == 'N':
                      num_rows = st.slider('Number of different stones', min_value=0,max_value=10,value=1)
                      with st.form("Part1"):
                            c1, c2 = st.columns(2)
                            with c1:
                                  d1 = st.date_input('Receive Date', datetime.date(y, m, day))
                            with c2:
                                  amt1 = st.number_input('Amount', value=0, step=1)
                            stone = [None] * num_rows
                            pc = [None] * num_rows

                            def add_row(row):
                                  with c1:
                                      stone[row] = st.selectbox('Stones', stones, key=f'stone{row}')
                                  with c2:
                                      pc[row] = st.number_input('PCs', step=1, key=f'pcs{row}')

                            for r in range(num_rows):
                                  add_row(r)
                            cmts1 = st.text_input('Comments', '')
                            submit_button = st.form_submit_button(label='Submit')

                      if submit_button:
                             d11 = d1.strftime("%m/%d/%Y")
                             keydata = str(j['key'])
                             db.update({"Status":'P',"Receieve Date": d11, "Comments" : cmts1, "Receieve Amount" : amt1, "Stones": stone, "PCs":pc},keydata,)
                             st.write("Data submitted !")

                if str(j['Status']) == 'F':
                        st.write("This items is already fully receieved !")

                if str(j['Status']) == 'P':
                        st.write("This items is already partially receieved !")

      if flag == 0 :
            st.write('Data not found !')


# coding:utf-8
"""
    爬取百度贴吧的HTML内容
"""
from urllib import request,parse
import urllib
import os

def loadPage(url, filename):
    """
        作用：根据URL发送请求，获取服务器响应文件
        :param url: 需要爬取的URL地址
        :filename: 处理的文件名
    """
    print("正在下载" + filename)
    ua_headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36",
    }
    request = urllib.request.Request(url, headers=ua_headers)
    return urllib.request.urlopen(request).read()

def writePage(html, filename):
    """
        作用：将HTML内容写入到本地
        :param html: 服务器相应文件内容
    """
    print("正在保存" + filename)
    # 文件写入
    with open(filename, 'bw') as f:
        f.write(html)
    print("-" * 33)

def tiebaSpider(url, beginPage, endPage):
    """
        作用：贴吧爬虫调度器，负责组合处理每个页面的URL
        :param url: 贴吧URL前部分
        :param beginPage: 起始页
        :param endPage: 结束页
    """
    beginPage = int(beginPage)
    endPage = int(endPage)
    for page in range(beginPage, endPage+1):
        pn = (page - 1) * 50
        filename = "第" + str(page) + "页.html"
        fullurl = url + "&pn=" + str(pn)
        # print(fullurl)
        html = loadPage(fullurl, filename)
        # print(html)
        writePage(html, getDesktopPath()+ "\\" + filename)

def getDesktopPath():
    """
        作用：获取当前桌面路径
    """
    return os.path.join(os.path.expanduser("~"), 'Desktop')

if __name__ == "__main__":
    kw = input("请输入要爬取的贴吧名：")
    beginPage = input("请输入起始页：")
    endPage = input("请输入结束页：")

    url = "http://tieba.baidu.com/f?"
    key = parse.urlencode({"kw":kw})
    fullurl = url + key
    tiebaSpider(url, beginPage, endPage)


import math
import torch

from torch import nn
from typing import Tuple

def init_param(module: nn.Module, gain: float = 1.) -> nn.Module:
    """
    Init the input neural network's linear layers Y = AX + B according to
        1.) A is orthogonal with gain
        2.) B = 0

    Parameters
    ----------
    module: nn.Module
        input neural network
    gain: float

    Returns
    -------
    module: nn.Module
        initialized neural network
    """
    nn.init.orthogonal_(module.weight.data, gain=gain)
    nn.init.constant_(module.bias.data, 0)
    return module

def build_mlp(
        input_dim: int,
        output_dim: int,
        hidden_units: tuple = (64, 64),
        hidden_activation: nn.Module = nn.Tanh(),
        init: bool = False,
        output_activation: nn.Module = None,
        gain: float = 1.
) -> nn.Module:
    """
    Build a MLP network

    Parameters
    ----------
    input_dim: int
        dimension of the input of the neural network
    output_dim: int
        dimension of the output of the neural network
    hidden_units: tuple
        hidden units of the neural network
    hidden_activation: nn.Module
        activation function of the hidden layers
    init: bool
        whether to init the neural network to be orthogonal weighted
    output_activation: nn.Module
        activation function of the output layer
    gain: float
        gain for the init function

    Returns
    -------
    nn: nn.Module
        MLP net
    """
    layers = []
    units = input_dim
    for next_units in hidden_units:
        if init:
            layers.append(init_param(nn.Linear(units, next_units), gain=gain))
        else:
            layers.append(nn.Linear(units, next_units))
        layers.append(hidden_activation)
        units = next_units
    if init:
        layers.append(init_param(nn.Linear(units, output_dim), gain=gain))
    else:
        layers.append(nn.Linear(units, output_dim))
    if output_activation is not None:
        layers.append(output_activation)
    return nn.Sequential(*layers)

def build_param_list(
        input_dim: int,
        output_dim: int,
        device: torch.device,
        hidden_units: tuple = (64, 64),
        requires_grad: bool = True
) -> Tuple[list, list]:
    """
    Build parameter list of the neural network

    Parameters
    ----------
    input_dim: int
        dimension of the input of the neural network
    output_dim: int
        dimension of the output of the neural network
    device: torch.device
        cpu or cuda
    hidden_units: tuple
        hidden units of the neural network
    requires_grad: bool
        whether the parameters need to be trained

    Returns
    -------
    weights: a list of torch.Tensor
        weights of each layer of the neural network
    biases: a list of torch.Tensor
        biases of each layer of the neural network
    """
    weights = []
    biases = []
    units = input_dim
    for next_units in hidden_units:
        weights.append(torch.zeros(next_units, units, requires_grad=requires_grad).to(device))
        biases.append(torch.zeros(next_units, requires_grad=requires_grad).to(device))
        units = next_units
    weights.append(torch.zeros(output_dim, units, requires_grad=requires_grad).to(device))
    biases.append(torch.zeros(output_dim, requires_grad=requires_grad).to(device))
    return weights, biases

def calculate_log_pi(log_stds: torch.Tensor, noises: torch.Tensor, actions: torch.Tensor) -> torch.Tensor:
    """
    Calculate log(\pi(a|s)) given log(std) of the distribution, noises, and actions to take

    Parameters
    ----------
    log_stds: torch.Tensor
        log(std) of the distribution
    noises: torch.Tensor
        noises added to the action
    actions: torch.Tensor
        actions to take

    Returns
    -------
    log_pi: torch.Tensor
        log(\pi(a|s))
    """
    gaussian_log_probs = (-0.5 * noises.pow(2) - log_stds).sum(
        dim=-1, keepdim=True) - 0.5 * math.log(2 * math.pi) * log_stds.size(-1)

    return gaussian_log_probs - torch.log(
        1 - actions.pow(2) + 1e-6).sum(dim=-1, keepdim=True)

def reparameterize(means: torch.Tensor, log_stds: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
    """
    Get action and its log_pi according to mean and log_std

    Parameters
    ----------
    means: torch.Tensor
        mean value of the action
    log_stds: torch.Tensor
        log(std) of the action

    Returns
    -------
    actions: torch.Tensor
        actions to take
    log_pi: torch.Tensor
        log_pi of the actions
    """
    noises = torch.randn_like(means)
    us = means + noises * log_stds.exp()
    actions = torch.tanh(us)
    return actions, calculate_log_pi(log_stds, noises, actions)

def atanh(x: torch.Tensor) -> torch.Tensor:
    """
    Return atanh of the input. Modified torch.atanh in case the output is nan.

    Parameters
    ----------
    x: torch.Tensor
        input

    Returns
    -------
    y: torch.Tensor
        atanh(x)
    """
    return 0.5 * (torch.log(1 + x + 1e-6) - torch.log(1 - x + 1e-6))

def evaluate_log_pi(means: torch.Tensor, log_stds: torch.Tensor, actions: torch.Tensor) -> torch.Tensor:
    """
    Evaluate the log(\pi(a|s)) of the given action

    Parameters
    ----------
    means: torch.Tensor
        mean value of the action distribution
    log_stds: torch.Tensor
        log(std) of the action distribution
    actions: torch.Tensor
        actions taken

    Returns
    -------
    log_pi: : torch.Tensor
        log(\pi(a|s))
    """
    noises = (atanh(actions) - means) / (log_stds.exp() + 1e-8)
    return calculate_log_pi(log_stds, noises, actions)