"""Sensor Graph main object."""

from collections import deque
import logging
import struct
from pkg_resources import iter_entry_points
from toposort import toposort_flatten
from iotile.core.exceptions import ArgumentError
from iotile.core.hw.reports import IOTileReading
from iotile.core.utilities.hash_algorithms import KNOWN_HASH_ALGORITHMS
from .node_descriptor import parse_node_descriptor
from .slot import SlotIdentifier
from .stream import DataStream
from .known_constants import config_fast_tick_secs, config_tick1_secs, config_tick2_secs, known_metadata
from .exceptions import NodeConnectionError, ProcessingFunctionError, ResourceUsageError

class SensorGraph:
    """A graph based data processing engine.

    Args:
        sensor_log (SensorLog): The sensor log where we should store our
            data
        model (DeviceModel): The device model to use for limiting our
            available resources
        enforce_limits (bool): Enforce the sensor graph size limits imposed
            by the chosen device model.  This can be useful for getting early
            failures on sensor graphs that cannot work on a given device model.
            Defaults to False.
    """

    def __init__(self, sensor_log, model=None, enforce_limits=False):
        self.roots = []
        self.nodes = []
        self.streamers = []

        self.constant_database = {}
        self.metadata_database = {}
        self.config_database = {}

        self.checksums = None

        self.sensor_log = sensor_log
        self.model = model

        self._manually_triggered_streamers = set()
        self._logger = logging.getLogger(__name__)

        if enforce_limits:
            if model is None:
                raise ArgumentError("You must pass a device model if you set enforce_limits=True")

            self._max_nodes = model.get(u'max_nodes')
            self._max_streamers = model.get(u'max_streamers')
        else:
            self._max_nodes = None
            self._max_streamers = None

    def clear(self):
        """Clear all nodes from this sensor_graph.

        This function is equivalent to just creating a new SensorGraph() object
        from scratch.  It does not clear any data from the SensorLog, however.
        """

        self.roots = []
        self.nodes = []
        self.streamers = []

        self.constant_database = {}
        self.metadata_database = {}
        self.config_database = {}

    def add_node(self, node_descriptor):
        """Add a node to the sensor graph based on the description given.

        The node_descriptor must follow the sensor graph DSL and describe
        a node whose input nodes already exist.

        Args:
            node_descriptor (str): A description of the node to be added
                including its inputs, triggering conditions, processing function
                and output stream.
        """

        if self._max_nodes is not None and len(self.nodes) >= self._max_nodes:
            raise ResourceUsageError("Maximum number of nodes exceeded", max_nodes=self._max_nodes)

        node, inputs, processor = parse_node_descriptor(node_descriptor, self.model)

        in_root = False

        for i, input_data in enumerate(inputs):
            selector, trigger = input_data

            walker = self.sensor_log.create_walker(selector)

            # Constant walkers begin life initialized to 0 so they always read correctly
            if walker.selector.inexhaustible:
                walker.reading = IOTileReading(0xFFFFFFFF, walker.selector.as_stream(), 0)

            node.connect_input(i, walker, trigger)

            if selector.input and not in_root:
                self.roots.append(node)
                in_root = True  # Make sure we only add to root list once
            else:
                found = False
                for other in self.nodes:
                    if selector.matches(other.stream):
                        other.connect_output(node)
                        found = True

                if not found and selector.buffered:
                    raise NodeConnectionError("Node has input that refers to another node that has not been created yet", node_descriptor=node_descriptor, input_selector=str(selector), input_index=i)

        # Also make sure we add this node's output to any other existing node's inputs
        # this is important for constant nodes that may be written from multiple places
        # FIXME: Make sure when we emit nodes, they are topologically sorted
        for other_node in self.nodes:
            for selector, trigger in other_node.inputs:
                if selector.matches(node.stream):
                    node.connect_output(other_node)

        # Find and load the processing function for this node
        func = self.find_processing_function(processor)
        if func is None:
            raise ProcessingFunctionError("Could not find processing function in installed packages", func_name=processor)

        node.set_func(processor, func)
        self.nodes.append(node)

    def add_config(self, slot, config_id, config_type, value):
        """Add a config variable assignment to this sensor graph.

        Args:
            slot (SlotIdentifier): The slot identifier that this config
                variable is assigned to.
            config_id (int): The 16-bit id of this config_id
            config_type (str): The type of the config variable, currently
                supported are fixed width integer types, strings and binary
                blobs.
            value (str|int|bytes): The value to assign to the config variable.
        """

        if slot not in self.config_database:
            self.config_database[slot] = {}

        self.config_database[slot][config_id] = (config_type, value)

    def add_streamer(self, streamer):
        """Add a streamer to this sensor graph.

        Args:
            streamer (DataStreamer): The streamer we want to add
        """

        if self._max_streamers is not None and len(self.streamers) >= self._max_streamers:
            raise ResourceUsageError("Maximum number of streamers exceeded", max_streamers=self._max_streamers)

        streamer.link_to_storage(self.sensor_log)
        streamer.index = len(self.streamers)

        self.streamers.append(streamer)

    def add_constant(self, stream, value):
        """Store a constant value for use in this sensor graph.

        Constant assignments occur after all sensor graph nodes have been
        allocated since they must be propogated to all appropriate virtual
        stream walkers.

        Args:
            stream (DataStream): The constant stream to assign the value to
            value (int): The value to assign.
        """

        if stream in self.constant_database:
            raise ArgumentError("Attempted to set the same constant twice", stream=stream, old_value=self.constant_database[stream], new_value=value)

        self.constant_database[stream] = value

    def add_metadata(self, name, value):
        """Attach a piece of metadata to this sensorgraph.

        Metadata is not used during the simulation of a sensorgraph but allows
        it to convey additional context that may be used during code
        generation.  For example, associating an `app_tag` with a sensorgraph
        allows the snippet code generator to set that app_tag on a device when
        programming the sensorgraph.

        Arg:
            name (str): The name of the metadata that we wish to associate with this
                sensorgraph.
            value (object): The value we wish to store.
        """

        if name in self.metadata_database:
            raise ArgumentError("Attempted to set the same metadata value twice", name=name, old_value=self.metadata_database[name], new_value=value)

        self.metadata_database[name] = value

    def initialize_remaining_constants(self, value=0):
        """Ensure that all constant streams referenced in the sensor graph have a value.

        Constant streams that are automatically created by the compiler are initialized
        as part of the compilation process but it's possible that the user references
        other constant streams but never assigns them an explicit initial value.  This
        function will initialize them all to a default value (0 if not passed) and
        return the streams that were so initialized.

        Args:
            value (int): Optional value to use to initialize all uninitialized constants.
                Defaults to 0 if not passed.

        Returns:
            list(DataStream): A list of all of the constant streams that were not previously
                initialized and were initialized to the given value in this function.
        """

        remaining = []

        for node, _inputs, _outputs in self.iterate_bfs():
            streams = node.input_streams() + [node.stream]

            for stream in streams:
                if stream.stream_type is not DataStream.ConstantType:
                    continue

                if stream not in self.constant_database:
                    self.add_constant(stream, value)
                    remaining.append(stream)

        return remaining

    def load_constants(self):
        """Load all constants into their respective streams.

        All previous calls to add_constant stored a constant value that
        should be associated with virtual stream walkers.  This function
        actually calls push_stream in order to push all of the constant
        values to their walkers.
        """

        for stream, value in self.constant_database.items():
            self.sensor_log.push(stream, IOTileReading(0, stream.encode(), value))

    def get_config(self, slot, config_id):
        """Get a config variable assignment previously set on this sensor graph.

        Args:
            slot (SlotIdentifier): The slot that we are setting this config variable
                on.
            config_id (int): The 16-bit config variable identifier.

        Returns:
            (str, str|int): Returns a tuple with the type of the config variable and
                the value that is being set.

        Raises:
            ArgumentError: If the config variable is not currently set on the specified
                slot.
        """

        if slot not in self.config_database:
            raise ArgumentError("No config variables have been set on specified slot", slot=slot)

        if config_id not in self.config_database[slot]:
            raise ArgumentError("Config variable has not been set on specified slot", slot=slot, config_id=config_id)

        return self.config_database[slot][config_id]

    def is_output(self, stream):
        """Check if a stream is a sensor graph output.

        Return:
            bool
        """

        for streamer in self.streamers:
            if streamer.selector.matches(stream):
                return True

        return False

    def get_tick(self, name):
        """Check the config variables to see if there is a configurable tick.

        Sensor Graph has a built-in 10 second tick that is sent every 10
        seconds to allow for triggering timed events.  There is a second
        'user' tick that is generated internally by the sensorgraph compiler
        and used for fast operations and finally there are several field
        configurable ticks that can be used for setting up configurable
        timers.

        This is done by setting a config variable on the controller with the
        desired tick interval, which is then interpreted by this function.

        The appropriate config_id to use is listed in `known_constants.py`

        Returns:
            int: 0 if the tick is disabled, otherwise the number of seconds
                between each tick
        """

        name_map = {
            'fast': config_fast_tick_secs,
            'user1': config_tick1_secs,
            'user2': config_tick2_secs
        }

        config = name_map.get(name)
        if config is None:
            raise ArgumentError("Unknown tick requested", name=name)

        slot = SlotIdentifier.FromString('controller')

        try:
            var = self.get_config(slot, config)
            return var[1]
        except ArgumentError:
            return 0

    def _parse_configs_ignorelist(self):
        """Parses the string containing configs to ignore into a list of tuples

        Returns:
            list(tuple): A list of config variable entries that are formatted
                as tuples (slot, config_id)
        """

        configs_ignorelist = []
        slot = SlotIdentifier.FromString('controller')

        configs_ignorelist_string = self.metadata_database['hash_configs_ignorelist']
        configs_ignorelist_address = self.metadata_database['hash_configs_ignorelist_address']
        configs_ignorelist_type, _ = self.get_config(slot, configs_ignorelist_address)
        self.add_config(slot, configs_ignorelist_address, configs_ignorelist_type, configs_ignorelist_string)

        if configs_ignorelist_string[0] != '{' and configs_ignorelist_string[-1] != '}':
            configs_ignorelist_string = '{' + configs_ignorelist_string + '}'

        configs_ignorelist_dict = eval(configs_ignorelist_string)

        for target, config_ids in configs_ignorelist_dict.items():
            slot = SlotIdentifier.FromString(target)

            for config_id in config_ids:
                configs_ignorelist.append((slot, config_id))

        return configs_ignorelist

    def add_checksum(self, force_checksum=False):
        """Check metadata if sensorgraph's checksum needs to be added.

        The sensorgraph must contain all the meta tags required to calculate the
        checksum.

        hash_address: Address where calculated checksum will be flashed.
        hash_algorihm: Algorithm to use to calculate checksums, only "sha256"
            and "crc32_0x104C11DB7" are currently supported.
        hash_algorithm_address: Address where the algorithm specifier is
            flashed. This is used so the programmer knows which algorithm to use
            to debug the device.
        hash_configs_ignorelist: Dict of config variables to exclude during the
            calculation of checksum. This MUST contain the 'hash_address'.
            The ignore list must be formatted like so...
                meta hash_configs_ignorelist = "'controller':[0xcafe,0xdead],'slot 1':[0xbabe]";
            This entry should be formatted as a stringified dictionary.
        hash_configs_ignorelist_address: Address where the ignore list is
            flashed. This is used so the programmer knows which config variables
            to exclude in the calculation of the device's checksums.
        """

        if force_checksum:
            pass
        elif 'hash_address' not in self.metadata_database or\
            'hash_algorithm' not in self.metadata_database or\
            'hash_algorithm_address' not in self.metadata_database or\
            'hash_configs_ignorelist' not in self.metadata_database or\
            'hash_configs_ignorelist_address' not in self.metadata_database:
            return

        slot = SlotIdentifier.FromString('controller')

        if not force_checksum:
            hash_address = self.metadata_database['hash_address']
            algorithm = self.metadata_database['hash_algorithm']
            algorithm_address = self.metadata_database['hash_algorithm_address']

            algorithm_config_type, _ = self.get_config(slot, algorithm_address)
            self.add_config(slot, algorithm_address, algorithm_config_type, algorithm)

            configs_ignorelist = self._parse_configs_ignorelist()
        else:
            algorithm = "sha256"
            configs_ignorelist = []

        hash_algorithm = KNOWN_HASH_ALGORITHMS[algorithm]

        nodes_checksum = hash_algorithm.calculate(hash_algorithm.algorithm,
                                                  self.get_nodes_binary())
        self._logger.debug("nodes_checksum: %s", nodes_checksum)
        streamers_checksum = hash_algorithm.calculate(hash_algorithm.algorithm,
                                                  self.get_streamers_binary())
        self._logger.debug("streamers_checksum: %s", streamers_checksum)
        configs_checksum = hash_algorithm.calculate(hash_algorithm.algorithm,
                                                  self.get_config_database_binary(ignore_configs=configs_ignorelist))
        self._logger.debug("configs_checksum: %s", configs_checksum)
        constants_checksum = hash_algorithm.calculate(hash_algorithm.algorithm,
                                                  self.get_constant_database_binary())
        self._logger.debug("constants_checksum: %s", constants_checksum)
        metadata_checksum = hash_algorithm.calculate(hash_algorithm.algorithm,
                                                  self.get_metadata_database_binary())
        self._logger.debug("metadata_checksum: %s", metadata_checksum)

        # The order of building the following string is important for other
        # applications to calculate the proper checksum
        combined_checksum_string = nodes_checksum + streamers_checksum +\
                                   configs_checksum + constants_checksum +\
                                   metadata_checksum
        combined_checksum_bytes = bytes(combined_checksum_string, 'utf-8')
        device_checksum = hash_algorithm.calculate(hash_algorithm.algorithm,
                                                   combined_checksum_bytes)
        self._logger.debug("device_checksum: %s", device_checksum)

        self.checksums = {
            "nodes": nodes_checksum,
            "streamers": streamers_checksum,
            "configs": configs_checksum,
            "constants": constants_checksum,
            "metadata": metadata_checksum,
            "device": device_checksum
        }

        if not force_checksum:
            hash_config_type, _ = self.get_config(slot, hash_address)
            self.add_config(slot, hash_address, hash_config_type, device_checksum)

    def process_input(self, stream, value, rpc_executor):
        """Process an input through this sensor graph.

        The tick information in value should be correct and is transfered
        to all results produced by nodes acting on this tick.

        Args:
            stream (DataStream): The stream the input is part of
            value (IOTileReading): The value to process
            rpc_executor (RPCExecutor): An object capable of executing RPCs
                in case we need to do that.
        """

        self.sensor_log.push(stream, value)

        # FIXME: This should be specified in our device model
        if stream.important:
            associated_output = stream.associated_stream()
            self.sensor_log.push(associated_output, value)

        to_check = deque([x for x in self.roots])

        while len(to_check) > 0:
            node = to_check.popleft()
            if node.triggered():
                try:
                    results = node.process(rpc_executor, self.mark_streamer)
                    for result in results:
                        result.raw_time = value.raw_time
                        self.sensor_log.push(node.stream, result)
                except:
                    self._logger.exception("Unhandled exception in graph node processing function for node %s", str(node))

                # If we generated any outputs, notify our downstream nodes
                # so that they are also checked to see if they should run.
                if len(results) > 0:
                    to_check.extend(node.outputs)

    def mark_streamer(self, index):
        """Manually mark a streamer that should trigger.

        The next time check_streamers is called, the given streamer will be
        manually marked that it should trigger, which will cause it to trigger
        unless it has no data.

        Args:
            index (int): The index of the streamer that we should mark as
                manually triggered.

        Raises:
            ArgumentError: If the streamer index is invalid.
        """

        self._logger.debug("Marking streamer %d manually", index)
        if index >= len(self.streamers):
            raise ArgumentError("Invalid streamer index", index=index, num_streamers=len(self.streamers))

        self._manually_triggered_streamers.add(index)

    def check_streamers(self, blacklist=None):
        """Check if any streamers are ready to produce a report.

        You can limit what streamers are checked by passing a set-like
        object into blacklist.

        This method is the primary way to see when you should poll a given
        streamer for its next report.

        Note, this function is not idempotent.  If a streamer is marked as
        manual and it is triggered from a node rule inside the sensor_graph,
        that trigger will only last as long as the next call to
        check_streamers() so you need to explicitly build a report on all
        ready streamers before calling check_streamers again.

        Args:
            blacklist (set): Optional set of streamer indices that should
                not be checked right now.

        Returns:
            list of DataStreamer: A list of the ready streamers.
        """

        ready = []
        selected = set()

        for i, streamer in enumerate(self.streamers):
            if blacklist is not None and i in blacklist:
                continue

            if i in selected:
                continue

            marked = False
            if i in self._manually_triggered_streamers:
                marked = True
                self._manually_triggered_streamers.remove(i)

            if streamer.triggered(marked):
                self._logger.debug("Streamer %d triggered, manual=%s", i, marked)
                ready.append(streamer)
                selected.add(i)

                # Handle streamers triggered with another
                for j, streamer2 in enumerate(self.streamers[i:]):
                    if streamer2.with_other == i and j not in selected and streamer2.triggered(True):
                        self._logger.debug("Streamer %d triggered due to with-other on %d", j, i)
                        ready.append(streamer2)
                        selected.add(j)

        return ready

    def iterate_bfs(self):
        """Generator that yields node, [inputs], [outputs] in breadth first order.

        This generator will iterate over all nodes in the sensor graph, yielding
        a 3 tuple for each node with a list of all of the nodes connected to its
        inputs and all of the nodes connected to its output.

        Returns:
            (SGNode, list(SGNode), list(SGNode)): A tuple for each node in the graph
        """

        working_set = deque(self.roots)
        seen = []

        while len(working_set) > 0:
            curr = working_set.popleft()

            # Now build input and output node lists for this node
            inputs = []
            for walker, _ in curr.inputs:
                for other in seen:
                    if walker.matches(other.stream) and other not in inputs:
                        inputs.append(other)

            outputs = [x for x in curr.outputs]
            yield curr, inputs, outputs

            working_set.extend(curr.outputs)
            seen.append(curr)

    def sort_nodes(self):
        """Topologically sort all of our nodes.

        Topologically sorting our nodes makes nodes that are inputs to other
        nodes come first in the list of nodes.  This is important to do before
        programming a sensorgraph into an embedded device whose engine assumes
        a topologically sorted graph.

        The sorting is done in place on self.nodes
        """

        node_map = {id(node): i for i, node in enumerate(self.nodes)}
        node_deps = {}

        for node, inputs, _outputs in self.iterate_bfs():
            node_index = node_map[id(node)]

            deps = {node_map[id(x)] for x in inputs}
            node_deps[node_index] = deps

        # Now that we have our dependency tree properly built, topologically
        # sort the nodes and reorder them.
        node_order = toposort_flatten(node_deps)
        self.nodes = [self.nodes[x] for x in node_order]

        #Check root nodes all topographically sorted to the beginning
        for root in self.roots:
            if root not in self.nodes[0:len(self.roots)]:
                raise NodeConnectionError("Inputs not sorted in the beginning", node=str(root), node_position=self.nodes.index(root))

    @classmethod
    def find_processing_function(cls, name):
        """Find a processing function by name.

        This function searches through installed processing functions
        using pkg_resources.

        Args:
            name (str): The name of the function we're looking for

        Returns:
            callable: The processing function
        """

        for entry in iter_entry_points(u'iotile.sg_processor', name):
            return entry.load()

    def dump_roots(self):
        """Dump all the root nodes in this sensor graph as a list of strings."""

        return [str(x) for x in self.roots]

    def dump_nodes(self):
        """Dump all of the nodes in this sensor graph as a list of strings."""

        return [str(x) for x in self.nodes]

    def dump_streamers(self):
        """Dump all of the streamers in this sensor graph as a list of strings."""

        return [str(streamer) for streamer in self.streamers]

    def dump_constant_database(self):
        """Dump all of the constants in this sensor graph as a list of strings."""

        constant_dump = []

        for stream, value in sorted(self.constant_database.items(), key=lambda x: x[0].encode()):
            constant_dump.append("'{}' {}".format(stream, value))

        return constant_dump

    def dump_metadata_database(self):
        """Dump all of the metadata in this sensor graph as a list of strings."""

        metadata_dump = []

        for metadata, value in sorted(self.metadata_database.items(), key=lambda x: x[0].encode()):
            metadata_dump.append("{}: {}".format(metadata, value))

        return metadata_dump

    def dump_config_database(self, dump_config_type=True, ignore_configs=[]):
        """Dump all of the config variables in this sensor graph as a list of strings."""

        config_dump = []
        for slot, conf_vars in sorted(self.config_database.items(), key=lambda x: x[0].encode()):
            for conf_var, conf_def in sorted(conf_vars.items(), key=lambda x: x[0]):
                conf_type, conf_val = conf_def
                conf_val_bytes = _convert_to_bytearray(conf_type, conf_val)

                if _is_ignored_config(ignore_configs, slot, conf_var):
                    self._logger.debug("Ignoring '%s:%s' in checksum calculation",
                                       slot, conf_var)
                    continue

                if dump_config_type:
                    config_dump.append("'{}' {} {} {}".format(slot, conf_var,
                                                              conf_type,
                                                              conf_val_bytes))
                else:
                    config_dump.append("'{}' {} {}".format(slot, conf_var,
                                                              conf_val_bytes))

        return config_dump

    def get_nodes_binary(self):
        """Returns the binary representation of all the nodes"""

        from .node_descriptor import create_binary_descriptor
        binary_representation = bytearray()

        for node in self.dump_nodes():
            binary_representation += create_binary_descriptor(node)

        return binary_representation

    def get_streamers_binary(self):
        """Returns the binary representation of all the streamers"""

        from .streamer_descriptor import parse_string_descriptor, create_binary_descriptor
        binary_representation = bytearray()

        for streamer in self.dump_streamers():
            streamer_obj = parse_string_descriptor(streamer)
            binary_representation += create_binary_descriptor(streamer_obj)

        return binary_representation

    def get_constant_database_binary(self):
        """Returns the binary representation of all the constant streams"""

        binary_representation = bytearray()

        for constant in self.dump_constant_database():
            binary_representation += bytes(constant, 'utf-8')

        return binary_representation

    def get_metadata_database_binary(self):
        """Returns the binary representation of the KNOWN metadata variables"""

        binary_representation = bytearray()

        for metadata in self.dump_metadata_database():
            entry, _ = metadata.split(': ')

            if entry in known_metadata:
                binary_representation += bytes(metadata, 'utf-8')

        return binary_representation

    def get_config_database_binary(self, ignore_configs=[]):
        """Returns the binary representation of all the config variables"""

        binary_representation = bytearray()

        for config in self.dump_config_database(dump_config_type=False,
                                                ignore_configs=ignore_configs):
            binary_representation += bytes(config, 'utf-8')

        return binary_representation

def _is_ignored_config(ignore_configs, slot, config_var):
    """Checks if an entry is in the list of variables to ignore"""

    for ignore_config in ignore_configs:
        if slot == ignore_config[0] and config_var == ignore_config[1]:
            return True

    return False

def _convert_to_bytearray(type_name, value):
    """Convert a typed value to a binary array"""

    int_types = {'uint8_t': 'B', 'int8_t': 'b', 'uint16_t': 'H', 'int16_t': 'h', 'uint32_t': 'L', 'int32_t': 'l'}

    type_name = type_name.lower()

    is_array = False
    if type_name[-2:] == '[]':
        if value[0] != '[' or value[-1] != ']':
            raise ArgumentError("Array value improperly formated, must be a stringified list")
        is_array = True
        type_name = type_name[:-2]

    if type_name not in int_types and type_name not in ['string', 'binary']:
        raise ArgumentError('Type must be a known integer type, integer type array, string', known_integers=int_types.keys(), actual_type=type_name)

    if type_name == 'string':
        #value should be passed as a string
        bytevalue = bytearray(value, 'utf-8')
    elif type_name == 'binary':
        bytevalue = bytearray(value)
    elif is_array:
        value = [int(n,0) for n in value[1:-1].split(',')]
        bytevalue = bytearray(struct.pack("<%s" % (int_types[type_name]*len(value)), *value))
    else:
        bytevalue = bytearray(struct.pack("<%s" % int_types[type_name], value))

    return bytevalue


"""
This script summarized DE results using mash model.
"""
import pandas as pd
import session_info
from pyhere import here
from gtfparse import read_gtf
from functools import lru_cache

@lru_cache()
def get_annotation(feature):
    config = {
        "genes": here("input/text_files_counts/_m/caudate/gene_annotation.tsv"),
        "transcripts": here("input/text_files_counts/_m/caudate/tx_annotation.tsv"),
        "exons": here("input/text_files_counts/_m/caudate/exon_annotation.tsv"),
        "junctions": here("input/text_files_counts/_m/caudate/jxn_annotation.tsv"),
    }
    return pd.read_csv(config[feature], sep='\t')\
             .loc[:, ["names", "seqnames", "start", "end", "Symbol", "gencodeID"]]\
             .rename(columns=str.lower)

@lru_cache()
def get_gtf():
    gtf_file = "/dcl02/lieber/apaquola/genome/human/gencode25/gtf.CHR/"+\
        "_m/gencode.v25.annotation.gtf"
    return read_gtf(gtf_file)

def gene_annotation():
    gtf = get_gtf()[get_gtf()["feature"] == "transcript"]
    return gtf[["transcript_id", "gene_id", "gene_name", "gene_type",
                "seqname", "start", "end", "strand"]]

@lru_cache()
def get_mash_degs(feature, tissue, fdr):
    if tissue == "Dentate Gyrus":
        new_tissue = "dentateGyrus"
    else:
        new_tissue = tissue.lower()
    df = pd.DataFrame()
    for perm in range(1,11):
        fname = f"../../_m/{feature}/mash_lfsr_perm_{perm:{'0'}{2}}.txt"
        df0 = pd.read_csv(fname,sep='\t').loc[:, ["feature_id", new_tissue]]
        df0["permutation"] = perm
        df = pd.concat([df, df0], axis=0)
    return df[(df[new_tissue] < fdr)].rename(columns={new_tissue: "lfsr"})

@lru_cache()
def get_mash_es(feature, tissue):
    if tissue == "Dentate Gyrus":
        new_tissue = "dentateGyrus"
    else:
        new_tissue = tissue.lower()
    df = pd.DataFrame()
    for perm in range(1,11):
        fname = f"../../_m/{feature}/mash_effectsize_perm_{perm:{'0'}{2}}.txt"
        df0 = pd.read_csv(fname,sep='\t').loc[:, ["feature_id", new_tissue]]
        df0["permutation"] = perm
        df = pd.concat([df, df0], axis=0)
    return df.rename(columns={new_tissue: "posterior_mean"})

@lru_cache()
def median_values(feature, tissue):
    return get_mash_degs(feature, tissue, 1)\
        .merge(get_mash_es(feature, tissue), on=["feature_id", "permutation"])\
        .groupby(["feature_id"]).median().drop(["permutation"], axis=1)\
        .reset_index()

@lru_cache()
def filter_fdr(feature, tissue, fdr):
    df = median_values(feature, tissue)
    return df[(df["lfsr"] < fdr)].copy()

@lru_cache()
def annotate_degs(feature, tissue, fdr):
    return filter_fdr(feature, tissue, fdr)\
        .merge(get_annotation(feature), left_on="feature_id", right_on="names")\
        .drop(["names"], axis=1)

@lru_cache()
def extract_features(tissue, fdr):
    # Gene annotation
    gtf_annot = gene_annotation()
    annot_gene = gtf_annot.loc[:, ["gene_id", "gene_type"]].drop_duplicates()
    annot_tx   = gtf_annot.loc[:, ["transcript_id", "gene_id", "gene_type"]]
    # Extract DE from mash model
    genes = annotate_degs("genes", tissue, fdr)\
        .merge(annot_gene, left_on="gencodeid", right_on="gene_id", how="left")\
        .drop("gencodeid", axis=1)
    trans = annotate_degs("transcripts", tissue, fdr)\
        .merge(annot_tx, left_on="feature_id", right_on="transcript_id", how="left")\
        .drop(["gencodeid", "transcript_id"], axis=1)
    exons = annotate_degs("exons", tissue, fdr)\
        .merge(annot_gene, left_on="gencodeid", right_on="gene_id", how="left")\
        .drop("gencodeid", axis=1)
    juncs = annotate_degs("junctions", tissue, fdr)\
        .merge(annot_gene, left_on="gencodeid", right_on="gene_id", how="left")\
        .drop("gencodeid", axis=1)
    return genes, trans, exons, juncs

def print_summary(tissue, fdr=0.05):
    genes, trans, exons, juncs = extract_features(tissue, fdr)
    if tissue == "Caudate":
        w_mode = "w"
    else:
        w_mode = "a"
    statement = "Significant DE (lfsr < 0.05) in %s" % tissue
    with open("summarize_results.log", mode=w_mode) as f:
        print(statement, file=f)
        for variable in ["feature_id", "gene_id"]:
            print(variable, file=f)
            gg = len(set(genes[variable]))
            tt = len(set(trans[variable]))
            ee = len(set(exons[variable]))
            jj = len(set(juncs[variable]))
            print("\nGene:\t\t%d\nTranscript:\t%d\nExon:\t\t%d\nJunction:\t%d\n" %
                  (gg, tt, ee, jj), file=f)

def get_DEGs_result_by_tissue(tissue, fdr=0.05):
    genes, trans, exons, juncs = extract_features(tissue, fdr)
    genes["feature_type"] = "Gene"
    trans["feature_type"] = "Transcript"
    exons["feature_type"] = "Exon"
    juncs["feature_type"] = "Junction"
    df = pd.concat([genes, trans, exons, juncs])
    df["feature_type"] = df.feature_type\
                           .astype("category")\
                           .cat.reorder_categories(["Gene", "Transcript", "Exon", "Junction"])
    df["region"] = tissue
    return df

def main():
    bigdata1 = []; bigdata2 = [];
    for tissue in ["Caudate", "Dentate Gyrus", "DLPFC", "Hippocampus"]:
        print_summary(tissue)
        data1 = get_DEGs_result_by_tissue(tissue)
        data2 = get_DEGs_result_by_tissue(tissue, 1)
        bigdata1.append(data1); bigdata2.append(data2)
    df1 = pd.concat(bigdata1); df2 = pd.concat(bigdata2)
    # Summary
    with open("effect_sizes.log", mode="w") as f:
        print("feature_id size:", file=f)
        print(df1.loc[:, ["region", "feature_type", "posterior_mean"]]\
              .groupby(["region", "feature_type"]).describe().to_string(), file=f)
    print("\nSummary:")
    gene = df1[(df1["feature_type"] == "Gene")].drop_duplicates(subset="gene_id")
    print(gene.shape)
    print(gene.groupby("gene_type").size())
    # Output
    cols = ["region", "feature_id", "gene_id", "symbol", "seqnames", "start", "end",
            "lfsr", "posterior_mean", "feature_type"]
    df1.sort_values(["region", "feature_type", "lfsr", "posterior_mean"]).loc[:, cols]\
       .to_csv("BrainSeq_ancestry_binary_4features_4regions.txt.gz",sep='\t', index=False)
    df2.sort_values(["region", "feature_type", "lfsr", "posterior_mean"]).loc[:, cols]\
       .to_csv("BrainSeq_ancestry_binary_4features_4regions_allFeatures.txt.gz",
               sep='\t', index=False)
    # Session infomation
    session_info.show()

if __name__ == "__main__":
    main()


# -*- coding: utf-8 -*-
from dateutil import tz
import datetime
from django.contrib.auth.models import User, Group
from django.db import models
from django.db.models import Min
from django.utils.timezone import utc
from academy.models import Profile

class Attendance(models.Model):
    profile = models.ForeignKey(Profile)
    image = models.ImageField(upload_to="attendance/attendance", blank=True)
    datetime = models.DateTimeField(auto_now=True)
    date = models.DateField(auto_now=True, null=True, blank=True)

    class Meta:
        ordering = ['-datetime']

    def __unicode__(self):
        datetime = self.datetime.astimezone(tz.tzlocal())
        username = self.profile.user.username if self.profile.user else "No username"
        return str(datetime.date().isoformat()) + " " + str(datetime.time().isoformat()) + " " + username + " (" + self.get_status() + ")"

    def get_status(self):
        import datetime
        result = ""
        first_attendance = Attendance.objects.filter(profile=self.profile, date=self.date).earliest('datetime')
        is_first = first_attendance == self
        current_datetime = self.datetime.astimezone(tz.tzlocal())
        first_datetime = first_attendance.datetime.astimezone(tz.tzlocal())

        try:
            attend_time = self.profile.attendancemanager.get_attend_time()
            leave_time = self.profile.attendancemanager.get_leave_time()
        except:
            attend_time = first_datetime.time()
            leave_time = (datetime.datetime(2000, 1, 1, attend_time.hour, attend_time.minute, attend_time.second) + datetime.timedelta(hours=1)).time()

        if is_first and current_datetime.time() <= attend_time:
            result = u"출석했습니다."
        elif is_first and current_datetime.time() > attend_time:
            result = u"출석했습니다."
        elif not is_first and current_datetime.time() < leave_time:
            result = u"출석했습니다."
        elif not is_first and current_datetime.time() >= leave_time:
            result = u"출석했습니다."

        return result

class AttendanceManager(models.Model):
    profile = models.OneToOneField(Profile, null=True)
    group = models.OneToOneField(Group, blank=True, null=True)
    policy = models.ForeignKey("AttendancePolicy", blank=True, null=True)
    nfc_id = models.CharField(max_length=50, blank=True, null=True)
    # phone_id = models.CharField(max_length=50, blank=True, null=True)

    def __unicode__(self):
        profile_name = self.profile.__unicode__() if self.profile else "No Profile"
        return profile_name + " --- " + (self.nfc_id if self.nfc_id else "no nfc card")

    def set_nfc(self, nfc_id, force_set=False):
        #TODO academy specific

        message = ""
        success = False
        if not nfc_id:
            message += "&카드 UID를 확인하세요."
        if self.nfc_id and self.nfc_id != nfc_id:
            message += "&이미 카드를 가지고 있습니다."
        if self.nfc_id and self.nfc_id == nfc_id:
            message += "&해당 카드에 이미 등록되어 있습니다."
        if not self.nfc_id and AttendanceManager.objects.filter(nfc_id=nfc_id).exists():
            message += "&타인이 해당 카드에 등록되어 있습니다."
        if force_set or (not self.nfc_id and not AttendanceManager.objects.filter(nfc_id=nfc_id).exists()):
            AttendanceManager.objects.filter(nfc_id=nfc_id).update(nfc_id=None)
            self.nfc_id = nfc_id
            self.save()
            success = True
            message += "&등록 되었습니다."
        return success, message

    #
    # def set_phone(self, phone_id, force_set=False):
    #
    #     message = ""
    #     success = False
    #     if not phone_id:
    #         message += "&휴대폰 단말기 ID를 확인하세요."
    #     if phone_id:
    #         self.phone_id = phone_id
    #         self.save()
    #         success = True
    #         message += self.profile.student.name + "& 학생의 출석 알람을 받아보실 수 있습니다."
    #     return success, message
    #
    def get_stu_id(self, nfc):
        user = self.user
        while user:
            if user.nfc == nfc:
                return user.id
            else:
                return 0

    def get_attend_time(self):
        return self.policy.attend_time

    def get_leave_time(self):
        return self.policy.leave_time

class AttendancePolicy(models.Model):
    attend_time = models.TimeField()
    leave_time = models.TimeField()

    def __unicode__(self):
        return str(self.attend_time) + "/" + str(self.leave_time)

import signals


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

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.listview import ListView

class basitListeUyg(App):

    def build(self):
        duzen=BoxLayout()

        programlama_dilleri=["Perl", "PHP", "Pure", "Python", "Rebol",
                             "Rexx", "Ruby", "Scheme", "Tcl"]

        liste = ListView(item_strings=programlama_dilleri)

        duzen.add_widget(Label(text="Programlama Dilleri"))
        duzen.add_widget(liste)

        return duzen

basitListeUyg().run()


import cv2
import mediapipe as mp
import time

wcam, hcam = 680, 480
cap = cv2.VideoCapture(0)
cap.set(3, wcam)
cap.set(4, hcam)
ptime = 0

mpDraw = mp.solutions.drawing_utils
mpFaceMesh = mp.solutions.face_mesh
faceMesh = mpFaceMesh.FaceMesh(max_num_faces=2)
drawspecs= mpDraw.DrawingSpec(thickness = 1, circle_radius = 2)

while True:
    success, img = cap.read()
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    results = faceMesh.process(img)
    print(results)

    if results.multi_face_landmarks:
        for landmarks in results.multi_face_landmarks:
            mpDraw.draw_landmarks(img, landmarks, mpFaceMesh.FACE_CONNECTIONS,drawspecs,drawspecs)

    ctime = time.time()
    fps =1/(ctime-ptime)
    ptime = ctime
    cv2.putText(img, f'FPS: {str(int(fps))}', (10,70), cv2.FONT_HERSHEY_PLAIN,3,(255,0,255),3)
    cv2.imshow("image", img)
    cv2.waitKey(1)


# Lifted heavily from Mustard Mine, and may have some unnecessary guff
import base64
import collections
import datetime
import functools
import json
import os
import sys
import threading
import time
import pytz
from pprint import pprint, pformat
# Hack: Get gevent to do its monkeypatching as early as possible.
# I have no idea what this is actually doing, but if you let the
# patching happen automatically, it happens too late, and we get
# RecursionErrors and such. There's a helpful warning on startup.
from gevent import monkey; monkey.patch_all(subprocess=True)
from flask import Flask, request, redirect, session, url_for, g, render_template, jsonify, Response, Markup
from authlib.integrations.requests_client import OAuth2Session
import requests

try:
	import config
except ImportError:
	# Construct a config object out of the environment
	import config_sample as config
	failed = []
	# Hack: Some systems like to give us a DATABASE_URL instead of a DATABASE_URI
	if "DATABASE_URL" in os.environ: os.environ["DATABASE_URI"] = os.environ["DATABASE_URL"]
	for var in dir(config):
		if var.startswith("__"): continue # Ignore dunders
		if var in os.environ: setattr(config, var, os.environ[var])
		else: failed.append(var)
	if failed:
		print("Required config variables %s not found - see config_sample.py" % ", ".join(failed), file=sys.stderr)
		sys.exit(1)
	sys.modules["config"] = config # Make the config vars available elsewhere

import database
app = Flask(__name__)
app.secret_key = config.SESSION_SECRET or base64.b64encode(os.urandom(12))

# Override Flask's forcing of Location headers to be absolute, since it
# gets stuff flat-out wrong. Also, the spec now says that relative
# headers are fine (and even when the spec said that the Location should
# to be absolute, everyone accepted relative URIs).
if os.environ.get("OVERRIDE_REDIRECT_HTTPS"):
	from werkzeug.middleware.proxy_fix import ProxyFix
	app.wsgi_app = ProxyFix(app.wsgi_app) # Grab info from Forwarded headers
	_redirect = redirect
	def redirect(*a, **kw):
		resp = _redirect(*a, **kw)
		resp.autocorrect_location_header = False
		return resp
	_url_for = url_for
	def url_for(*a, **kw): return _url_for(*a, **kw).replace("http://", "https://")

REQUIRED_SCOPES = "channel:read:subscriptions channel_subscriptions" # Ensure that these are sorted

class TwitchDataError(Exception):
	def __init__(self, error):
		self.__dict__.update(error)
		super().__init__(error["message"])

def query(endpoint, *, token, method="GET", params=None, data=None, auto_refresh=True):
	# If this is called outside of a Flask request context, be sure to provide
	# the auth token, and set auto_refresh to False.
	# TODO: Tidy up all this mess of auth patterns. It'll probably be easiest
	# to migrate everything to Helix first, and then probably everything will
	# use Bearer or App authentication.
	if token is None:
		auth = None
	elif token == "oauth":
		auth = "OAuth " + session["twitch_token"]
	elif token == "bearer":
		auth = "Bearer " + session["twitch_token"]
	elif token == "app":
		r = requests.post("https://id.twitch.tv/oauth2/token", data={
			"grant_type": "client_credentials",
			"client_id": config.CLIENT_ID, "client_secret": config.CLIENT_SECRET,
		})
		r.raise_for_status()
		data = r.json()
		auth = "Bearer " + data["access_token"]
		# TODO: Save the token so long as it's valid
		# expires = int(time.time()) + data["expires_in"] - 120
	else:
		auth = "OAuth " + token

	if not endpoint.startswith(("kraken/", "helix/")): raise ValueError("Need explicit selection of API (helix or kraken)")
	r = requests.request(method, "https://api.twitch.tv/" + endpoint,
		params=params, data=data, headers={
		"Accept": "application/vnd.twitchtv.v5+json",
		"Client-ID": config.CLIENT_ID,
		"Authorization": auth,
	})
	if auto_refresh and r.status_code == 401 and r.json()["message"] == "invalid oauth token":
		r = requests.post("https://id.twitch.tv/oauth2/token", data={
			"grant_type": "refresh_token",
			"refresh_token": session["twitch_refresh_token"],
			"client_id": config.CLIENT_ID, "client_secret": config.CLIENT_SECRET,
		})
		r.raise_for_status()
		resp = r.json()
		session["twitch_token"] = resp["access_token"]
		session["twitch_refresh_token"] = resp["refresh_token"]

		# Recurse for simplicity. Do NOT pass the original token, and be sure to
		# prevent infinite loops by disabling auto-refresh. Otherwise, pass-through.
		# (But DO pass the token-passing mode.)
		return query(endpoint, token="bearer" if token == "bearer" else "oauth",
			method=method, params=params, data=data, auto_refresh=False)
	if r.status_code == 403:
		# TODO: What if it *isn't* of this form??
		raise TwitchDataError(json.loads(r.json()["message"]))
	r.raise_for_status()
	if r.status_code == 204: return {}
	return r.json()

@app.route("/")
def mainpage():
	dest = os.environ.get("REDIRECT_TO_OTHER")
	if dest: return redirect(dest)
	# NOTE: If we've *reduced* the required scopes, this will still force a re-login.
	# However, it'll be an easy login, as Twitch will recognize the existing auth.
	if "twitch_token" not in session or session.get("twitch_auth_scopes") != REQUIRED_SCOPES:
		return render_template("login.html")
	user = session["twitch_user"]
	return render_template("index.html",
		username=user["display_name"], subscribers=database.list_subscribers(user["_id"]),
	)

@app.route("/logout")
def logout():
	session.pop("twitch_token", None)
	session.pop("twitch_user", None)
	return redirect(url_for("mainpage"))

@app.route("/login")
def login():
	twitch = OAuth2Session(config.CLIENT_ID, config.CLIENT_SECRET,
		scope=REQUIRED_SCOPES)
	uri, state = twitch.create_authorization_url("https://id.twitch.tv/oauth2/authorize",
		redirect_uri=os.environ.get("OVERRIDE_REDIRECT_URI") or url_for("authorized", _external=True))
	session["login_state"] = state
	return redirect(uri)

@app.route("/login/authorized")
def authorized():
	if "error" in request.args:
		# User cancelled the auth flow - discard auth (most likely there won't be any)
		session.pop("twitch_token", None)
		return redirect(url_for("mainpage"))
	twitch = OAuth2Session(config.CLIENT_ID, config.CLIENT_SECRET,
		state=session["login_state"])
	resp = twitch.fetch_access_token("https://id.twitch.tv/oauth2/token",
		code=request.args["code"],
		# For some bizarre reason, we need to pass this information along.
		client_id=config.CLIENT_ID, client_secret=config.CLIENT_SECRET,
		redirect_uri=os.environ.get("OVERRIDE_REDIRECT_URI") or url_for("authorized", _external=True))
	if "access_token" not in resp:
		# Something went wrong with the retrieval. No idea what or why,
		# so I'm doing a cop-out and just dumping to console.
		print("Unable to log in", file=sys.stderr)
		pprint(resp, stream=sys.stderr)
		print("Returning generic failure.", file=sys.stderr)
		raise Exception
	session["twitch_token"] = resp["access_token"]
	session["twitch_refresh_token"] = resp["refresh_token"]
	session["twitch_auth_scopes"] = " ".join(sorted(resp["scope"]))
	# kraken_user = query("kraken/user", token="oauth")
	# The Kraken response includes fields not in Helix, including created_at,
	# and email (though Helix gives us the latter if we add an OAuth scope).
	user = query("helix/users", token="bearer")["data"][0]
	user["_id"] = user["id"] # For now, everything looks for _id. Existing logins don't have user["id"].
	database.login_user(user["_id"], session["twitch_token"])
	session["twitch_user"] = user
	return redirect(url_for("mainpage"))

@app.route("/upload", methods=["POST"])
def upload_files():
	twitchid = session["twitch_user"]["_id"]
	for f in request.files.getlist("csv"):
		print("Loading", f.filename)
		database.bulk_load_subs(twitchid, f.read().decode("UTF-8"))
	return redirect(url_for("mainpage"))

# TODO: JSON API endpoints for uploading a CSV, and forcing a recheck

# Hack. TODO: Have a UI to do this
@app.route("/ping-api")
def ping_api():
	id = session["twitch_user"]["_id"]
	'''
	params = {"limit": 100, "offset": 0}
	subs = []
	while True:
		data = query("kraken/channels/%s/subscriptions" % id, token="oauth", params=params)
		if not data["subscriptions"]: break
		subs.extend(data["subscriptions"])
		params["offset"] += params["limit"]
	database.update_subs_from_api(id, subs)
	'''
	data = query("helix/subscriptions", token="bearer", params={"broadcaster_id": id})
	# TODO: Paginate the results
	return "<pre>" + pformat(data) + "</pre>"

if __name__ == "__main__":
	import logging
	logging.basicConfig(level=logging.INFO)
	# Load us up using gunicorn, configured via the Procfile
	with open("Procfile") as f: cmd = f.read().strip().replace("web: ", "")
	if "PORT" not in os.environ: os.environ["PORT"] = "5000" # hack - pick a different default port
	sys.argv = cmd.split(" ")[1:] # TODO: Split more smartly
	from gunicorn.app.wsgiapp import run; run()
else:
	# Worker startup. This is the place to put any actual initialization work
	# as it won't be done on master startup.
	pass


import matplotlib
import matplotlib.pyplot as plt
import xlrd

file = u'./data.xlsx'
xlrd.open_workbook(file)
data = xlrd.open_workbook(file)
table = data.sheet_by_name(u'data')  # 获得表格
x = table.col_values(0)
x.pop(0)
y1=table.col_values(1)
y1.pop(0)
y2=table.col_values(2)
y2.pop(0)
y3=table.col_values(3)
y3.pop(0)
y4=table.col_values(4)
y4.pop(0)

plt.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False

plt.figure(12)
plt.subplot(221)
plt.xlabel('地铁站数量')
plt.ylabel('值')
plt.plot(range(len(y1)), y2, 'bo-',label="gdp/亿元")
plt.xticks(range(len(y1)), y1, rotation=45)
plt.grid(True)
plt.legend(bbox_to_anchor=(1.0, 1), loc=1, borderaxespad=0.)

plt.subplot(222)
plt.xlabel('地铁站数量')
plt.ylabel('值')
plt.plot(range(len(y1)), y3, 'go-',label="增长/百分比")
plt.xticks(range(len(y1)), y1, rotation=45)
plt.grid(True)
plt.legend(bbox_to_anchor=(1.0, 1), loc=1, borderaxespad=0.)

plt.subplot(212)
plt.xlabel('地铁站数量')
plt.ylabel('值')
plt.plot(range(len(y1)), y4, 'yo-',label="人口/万人")
plt.xticks(range(len(y1)), y1, rotation=45)
plt.grid(True)
plt.legend(bbox_to_anchor=(1.0, 1), loc=1, borderaxespad=0.)

plt.show()


import torch
import math
import numpy as np

# def dct1d(x, half_shift=None):
#     N = x.shape[-1]
#     if half_shift == None:
#         half_shift = torch.stack([torch.tensor(-1j * math.pi * k / (2 * N)).exp() for k in range(N + 1)]).to(x.device)[None]
#     x_ext = torch.cat([x, x.flip(-1)], -1)
#     z = torch.fft.rfft(x_ext, norm='ortho') * half_shift
#     return z.real

# def dct2d(x, half_shift_x, half_shift_y):
#     Nx, Ny = x.shape[-2], x.shape[-1]
#     if half_shift_x == None:
#         half_shift_x = torch.stack([torch.tensor(-1j * math.pi * k / (2 * Nx)).exp()
#             for k in range(2* Nx)]).to(x.device)[None, None, :, None]
#     if half_shift_y == None:
#         half_shift_y = torch.stack([torch.tensor(-1j * math.pi * k / (2 * Ny)).exp()
#             for k in range(Ny + 1)]).to(x.device)[None, None, None]

#     x_ext = torch.cat([x, x.flip(-1)], -1)
#     x_ext = torch.cat([x_ext, x_ext.flip(-2)], -2)

#     x_ext = torch.cat([x, x.flip(-1)], -1)
#     z = torch.fft.rfft2(x_ext, norm='ortho') * half_shift_x * half_shift_y

#     return z.real

def dct1d(x, norm=None):

    x_shape = x.shape
    N = x_shape[-1]
    x = x.contiguous().view(-1, N)

    v = torch.cat([x[:, ::2], x[:, 1::2].flip([1])], dim=1)

    Vc = torch.view_as_real(torch.fft.fft(v, dim=1))  # add this line

    k = - torch.arange(N, dtype=x.dtype, device=x.device)[None, :] * np.pi / (2 * N)
    W_r = torch.cos(k)
    W_i = torch.sin(k)

    V = Vc[:, :, 0] * W_r - Vc[:, :, 1] * W_i

    if norm == 'ortho':
        V[:, 0] /= np.sqrt(N) * 2
        V[:, 1:] /= np.sqrt(N / 2) * 2

    V = 2 * V.view(*x_shape)

    return V

def idct1d(X, norm=None):

    x_shape = X.shape
    N = x_shape[-1]

    X_v = X.contiguous().view(-1, x_shape[-1]) / 2

    if norm == 'ortho':
        X_v[:, 0] *= np.sqrt(N) * 2
        X_v[:, 1:] *= np.sqrt(N / 2) * 2

    k = torch.arange(x_shape[-1], dtype=X.dtype, device=X.device)[None, :] * np.pi / (2 * N)
    W_r = torch.cos(k)
    W_i = torch.sin(k)

    V_t_r = X_v
    V_t_i = torch.cat([X_v[:, :1] * 0, -X_v.flip([1])[:, :-1]], dim=1)

    V_r = V_t_r * W_r - V_t_i * W_i
    V_i = V_t_r * W_i + V_t_i * W_r

    V = torch.cat([V_r.unsqueeze(2), V_i.unsqueeze(2)], dim=2)

    # v = torch.irfft(V, 1, onesided=False)                             # comment this line
    v= torch.fft.irfft(torch.view_as_complex(V), n=V.shape[1], dim=1)   # add this line

    x = v.new_zeros(v.shape)
    x[:, ::2] += v[:, :N - (N // 2)]
    x[:, 1::2] += v.flip([1])[:, :N // 2]

    return x.view(*x_shape)

def dct2d(x, norm=None):
    """
    2-dimentional Discrete Cosine Transform, Type II (a.k.a. the DCT)
    For the meaning of the parameter `norm`, see:
    https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.fftpack.dct.html
    :param x: the input signal
    :param norm: the normalization, None or 'ortho'
    :return: the DCT-II of the signal over the last 2 dimensions
    """
    X1 = dct1d(x, norm=norm)
    X2 = dct1d(X1.transpose(-1, -2), norm=norm)
    return X2.transpose(-1, -2)

def idct2d(X, norm=None):
    """
    The inverse to 2D DCT-II, which is a scaled Discrete Cosine Transform, Type III
    Our definition of idct is that idct_2d(dct_2d(x)) == x
    For the meaning of the parameter `norm`, see:
    https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.fftpack.dct.html
    :param X: the input signal
    :param norm: the normalization, None or 'ortho'
    :return: the DCT-II of the signal over the last 2 dimensions
    """
    x1 = idct1d(X, norm=norm)
    x2 = idct1d(x1.transpose(-1, -2), norm=norm)
    return x2.transpose(-1, -2)


from utils.timestamp_converter import TimestampConverter

class MarketSituation:
    def __init__(self, csv_row=None, kafka_row=None):
        self.amount = None
        self.merchant_id = None
        self.offer_id = None
        self.price = None
        self.prime = None
        self.product_id = None
        self.quality = None
        self.shipping_time_prime = None
        self.shipping_time_standard = None
        self.timestamp = None
        self.timestamp_object = None
        self.triggering_merchant_id = None
        self.uid = None

        if csv_row:
            self.from_csv(csv_row)
        elif kafka_row:
            self.from_kafka(kafka_row)

    def from_csv(self, csv_row):
        self.amount = csv_row[0]
        self.merchant_id = csv_row[1]
        self.offer_id = csv_row[2]
        self.price = csv_row[3]
        self.prime = csv_row[4]
        self.product_id = csv_row[5]
        self.quality = csv_row[6]
        self.shipping_time_prime = csv_row[7]
        self.shipping_time_standard = csv_row[8]
        self.timestamp = csv_row[9]
        self.timestamp_object = TimestampConverter.from_string(self.timestamp)
        self.triggering_merchant_id = csv_row[10]
        self.uid = csv_row[11]

    def from_kafka(self, kafka_row):
        self.amount = kafka_row[1]
        self.merchant_id = kafka_row[2]
        self.offer_id = kafka_row[3]
        self.price = kafka_row[4]
        self.prime = kafka_row[5]
        self.product_id = kafka_row[6]
        self.quality = kafka_row[7]
        self.shipping_time_prime = kafka_row[8]
        self.shipping_time_standard = kafka_row[9]
        self.timestamp = kafka_row[10]
        self.timestamp_object = TimestampConverter.from_string(self.timestamp)
        self.triggering_merchant_id = kafka_row[11]


from pathlib import Path
from numpy.lib.twodim_base import diag
from numpy.ma.core import count
import parse
import numpy as np

data_folder = Path(".").resolve()

def parse_data(data):
    lines = []
    line_parse = parse.compile("{},{} -> {},{}")
    for line in data.split("\n"):
        lines.append([int(d) for d in line_parse.parse(line).fixed])
    return np.array(lines, dtype=int)

def count_overlap_points(lines, include_diag):
    grid = np.zeros((np.max(lines[:, [0, 2]]) + 1, np.max(lines[:, [1, 3]]) + 1), dtype=int)

    horisontal = np.equal(lines[:, 1], lines[:, 3])
    hor_rows = lines[horisontal]
    for row in hor_rows:
        row_lim = np.sort(row[[0, 2]])
        row_lim[1] += 1
        grid[row[1], row_lim[0] : row_lim[1]] += 1

    vertical = np.equal(lines[:, 0], lines[:, 2])
    ver_rows = lines[vertical]
    for row in ver_rows:
        row_lim = np.sort(row[[1, 3]])
        row_lim[1] += 1
        grid[row_lim[0] : row_lim[1], row[0]] += 1

    if include_diag:
        diag_rows = lines[np.logical_not(np.logical_or(horisontal, vertical))]
        for row in diag_rows:
            ind = np.argsort(row[[0, 2]])
            x = row[[0, 2]][ind]
            y = row[[1, 3]][ind]
            slope = 1 if y[1] > y[0] else -1
            for i in range(1 + x[1] - x[0]):
                grid[y[0] + i * slope, x[0] + i] += 1

    return np.sum(grid >= 2)

def main():
    data = data_folder.joinpath("input.txt").read_text()
    data = parse_data(data)

    print("Part 1")
    n_overlap = count_overlap_points(data, False)
    print(f"At least two lines overlap in {n_overlap} points when not including diagonal lines")
    print()

    print("Part 2")
    n_overlap = count_overlap_points(data, True)
    print(f"At least two lines overlap in {n_overlap} points when including diagonal lines")
    print()

if __name__ == "__main__":
    main()


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

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html

from pyramid.config import Configurator
from TechLurker.models import RedditData, PyjobData, SecurityNewsData, TechRepublicData
import os

def main():
    """ This functon returns a Pyramid WSGI application."""
    settings = {}
    settings['sqlalchemy.url'] = os.environ['DATABASE_URL']
    config = Configurator(settings=settings)
    config.include('TechLurker.models')
    SessionFactory = config.registry["dbsession_factory"]
    session = SessionFactory()
    return session

class AddTablePipeline(object):
    def __init__(self, url):
        """."""
        self.url = url

    def process_item(self, item, spider):
        """."""
        if 'score' in item.keys():  # Reddit data
            record = RedditData(title=item['title'],
                                content=' '.join(item['content']),
                                score=item['score'])
        elif 'job_type' in item.keys():  # pyjob data
            record = PyjobData(title=item['title'],
                               descrip=' '.join(item['descrip']),
                               loc=item['loc'],
                               job_type=item['job_type'],
                               url=item['url'])
        elif 'articleContent' in item.keys():  # security news data
            record = SecurityNewsData(title=item['title'],
                                      articleContent=item['articleContent'],
                                      date=item['date'],
                                      url=item['url'])
        elif 'votes' in item.keys():  # tech republic data
            record = TechRepublicData(title=item['title'],
                                      content=item['content'],
                                      votes=item['votes'],
                                      from_forum=item['from_forum'])
        if not check_repeat(self.session, record):
            try:
                self.session.add(record)
                self.session.commit()
            except:
                self.session.rollback()
            return item

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            url=os.environ['DATABASE_URL'])

    def open_spider(self, spider):
        self.session = main()

    def close_spider(self, spider):
        self.session.close()

def check_repeat(db, record):
    """Check for repeats by comparing them in the database."""
    models = [TechRepublicData, SecurityNewsData, PyjobData, RedditData]
    temp = db.query(*models)

    for model in models:
        if temp.filter(model.title == record.title).count():
            return True


import logging
from typing import Callable, Union

import numpy as np
import torch
from monai.apps.deepgrow.transforms import AddRandomGuidanced, FindDiscrepancyRegionsd
from monai.handlers import MeanDice, from_engine
from monai.handlers.ignite_metric import IgniteMetric
from monai.inferers import SimpleInferer
from monai.losses import DiceLoss
from monai.metrics import MeanIoU
from monai.transforms import (
    Activationsd,
    AsDiscreted,
    EnsureChannelFirstd,
    EnsureTyped,
    LoadImaged,
    RandRotated,
    RandZoomd,
    Resized,
    ScaleIntensityRangeD,
    SelectItemsd,
    ToNumpyd,
    TorchVisiond,
    ToTensord,
)
from monai.utils import MetricReduction

from monailabel.deepedit.handlers import TensorBoard2DImageHandler
from monailabel.deepedit.interaction import Interaction
from monailabel.deepedit.transforms import AddGuidanceSignald, AddInitialSeedPointd
from monailabel.tasks.train.basic_train import BasicTrainTask, Context
from monailabel.transform.pre import NormalizeLabeld

logger = logging.getLogger(__name__)

class DeepEdit(BasicTrainTask):
    def __init__(
        self,
        model_dir,
        network,
        dimension,
        roi_size,
        max_train_interactions,
        max_val_interactions,
        description="Train DeepEdit Model for Endoscopy",
        **kwargs,
    ):
        self._network = network
        self.dimension = dimension
        self.roi_size = roi_size
        self.max_train_interactions = max_train_interactions
        self.max_val_interactions = max_val_interactions

        super().__init__(model_dir, description, **kwargs)

    def network(self, context: Context):
        return self._network

    def optimizer(self, context: Context):
        return torch.optim.Adam(context.network.parameters(), lr=0.0001)

    def loss_function(self, context: Context):
        return DiceLoss(sigmoid=True, squared_pred=True)

    def get_click_transforms(self, context: Context):
        return [
            Activationsd(keys="pred", sigmoid=True),
            ToNumpyd(keys=("image", "label", "pred")),
            FindDiscrepancyRegionsd(label="label", pred="pred", discrepancy="discrepancy"),
            AddRandomGuidanced(guidance="guidance", discrepancy="discrepancy", probability="probability"),
            AddGuidanceSignald(keys="image", guidance="guidance"),
            ToTensord(keys=("image", "label")),
        ]

    def train_pre_transforms(self, context: Context):
        return [
            LoadImaged(keys=("image", "label"), dtype=np.uint8, image_only=False),
            EnsureChannelFirstd(keys="image"),
            EnsureChannelFirstd(keys="label", channel_dim="no_channel"),
            Resized(keys=("image", "label"), spatial_size=self.roi_size, mode=("area", "nearest")),
            ToTensord(keys="image"),
            TorchVisiond(
                keys="image", name="ColorJitter", brightness=64.0 / 255.0, contrast=0.75, saturation=0.25, hue=0.04
            ),
            RandRotated(keys=("image", "label"), range_x=np.pi, prob=0.5, mode=("bilinear", "nearest")),
            RandZoomd(keys=("image", "label"), min_zoom=0.8, max_zoom=1.2, prob=0.5, mode=("bilinear", "nearest")),
            ScaleIntensityRangeD(keys="image", a_min=0.0, a_max=255.0, b_min=-1.0, b_max=1.0),
            NormalizeLabeld(keys="label", value=1),
            AddInitialSeedPointd(keys="guidance", label="label", connected_regions=5),
            AddGuidanceSignald(keys="image", guidance="guidance"),
            SelectItemsd(keys=("image", "label", "guidance")),
            EnsureTyped(keys=("image", "label")),
        ]

    def train_post_transforms(self, context: Context):
        return [
            Activationsd(keys="pred", sigmoid=True),
            AsDiscreted(keys="pred", threshold=0.5),
        ]

    def val_inferer(self, context: Context):
        return SimpleInferer()

    def val_key_metric(self, context):
        return {
            "val_mean_iou": MeanIoUMetric(output_transform=from_engine(["pred", "label"])),
            self.VAL_METRIC_MEAN_DICE: MeanDice(output_transform=from_engine(["pred", "label"])),
        }

    def train_handlers(self, context: Context):
        handlers = super().train_handlers(context)
        if context.local_rank == 0:
            handlers.append(TensorBoard2DImageHandler(log_dir=context.events_dir, batch_limit=0))
        return handlers

    def val_handlers(self, context: Context):
        handlers = super().val_handlers(context)
        if context.local_rank == 0 and handlers:
            handlers.append(TensorBoard2DImageHandler(log_dir=context.events_dir, batch_limit=0, tag_prefix="val-"))
        return handlers

    def train_iteration_update(self, context: Context):
        return Interaction(
            deepgrow_probability=0.5,
            transforms=self.get_click_transforms(context),
            max_interactions=self.max_train_interactions,
            train=True,
        )

    def val_iteration_update(self, context: Context):
        return Interaction(
            deepgrow_probability=0.5,
            transforms=self.get_click_transforms(context),
            max_interactions=self.max_val_interactions,
            train=False,
        )

class MeanIoUMetric(IgniteMetric):
    def __init__(
        self,
        include_background: bool = True,
        reduction: Union[MetricReduction, str] = MetricReduction.MEAN,
        output_transform: Callable = lambda x: x,
        save_details: bool = True,
    ) -> None:
        metric_fn = MeanIoU(include_background=include_background, reduction=reduction)
        super().__init__(metric_fn=metric_fn, output_transform=output_transform, save_details=save_details)


import pandas as pd
import numpy as np

import ajf_plts
import code

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

from BeamModel import Beam
from Simulation import perform_static_sim

from scipy.stats import wasserstein_distance

from numba import njit
from numba import objmode

# Fixed temperature T = 25 degrees C
# Fixed velocity, v = 15 m/s

SPACING_LABELS = ["S0", "S1", "S2", "S3", "S4"]
WEIGHT_LABELS = ["W1", "W2", "W3", "W4", "W5"]

wim_df = pd.read_feather("./wim_data.feather")

# Filter to leave only 5 axle vehicles
wim_df = wim_df.loc[wim_df.Axles.isin([5])]

# Round to 1 dp
wim_df = wim_df.round(1)

# Filter to leave only the most common axle plan
ax_plan = wim_df.groupby(SPACING_LABELS).agg("count").W1.idxmax()
wim_df = wim_df.loc[(wim_df[SPACING_LABELS] == ax_plan).all(axis=1)]

WEIGHTS = wim_df[WEIGHT_LABELS].values
SPACINGS = wim_df[SPACING_LABELS].values

N_WIM = WEIGHTS.shape[0]

N_VEHICLES = 1000
DELTA = 0.1

ITERATIONS = 100

# delta1_vals = [0.0, 0.0, 0.0, 0.0, 0.0, 0.1]
# xd1_vals = [0.0, 0.0, 0.0, 0.0, 0.0, 11]
# delta2_vals = [0.0, 0.1, 0.2, 0.1, 0.2, 0.2]
# xd2_vals = [0.0, 17, 17, 11, 11, 11]
delta1_vals = [0.1]
xd1_vals = [17]
delta2_vals = [0.2]
xd2_vals = [17]

@njit(cache=True, parallel=False, fastmath=True)
def get_wim_sample(n):
    all_idxs = np.arange(N_WIM)

    idx = np.random.choice(all_idxs, size=n, replace=True)

    w = WEIGHTS[idx, :]
    s = SPACINGS[idx, :]
    return w, s

@njit(cache=True, parallel=False, fastmath=True)
def process_one_beam(Kg, n, WEIGHTS, SPACINGS):
    all_idxs = np.arange(N_WIM)

    idx = np.random.choice(all_idxs, size=n, replace=True)

    weights_arr = WEIGHTS[idx, :]
    spacings_arr = SPACINGS[idx, :]

    results_L = np.zeros(len(weights_arr))
    results_R = np.zeros(len(weights_arr))
    for row in range(len(weights_arr)):
        steps, disp = perform_static_sim(Kg, weights_arr[row, :], spacings_arr[row, :])
        results_L[row] = np.max(np.abs(disp[1]))
        results_R[row] = np.max(np.abs(disp[-1]))
    return results_L, results_R

@njit(cache=True, parallel=False, fastmath=True)
def process_one_iter(Kg1, Kg2, n, WEIGHTS, SPACINGS):
    L1, R1 = process_one_beam(Kg1, n, WEIGHTS, SPACINGS)
    L2, R2 = process_one_beam(Kg2, n, WEIGHTS, SPACINGS)

    with objmode(emd_l="float64", emd_r="float64"):
        emd_l = wasserstein_distance(L1, L2)
        emd_r = wasserstein_distance(R1, R2)

    return emd_l, emd_r

@njit(cache=True, parallel=False, fastmath=True)
def process_all_iters(n_iters, Kg1, Kg2, n_vehicles, WEIGHTS, SPACINGS):
    emd_l = np.zeros(n_iters)
    emd_r = np.zeros(n_iters)

    for i in range(n_iters):
        emd_l[i], emd_r[i] = process_one_iter(Kg1, Kg2, n_vehicles, WEIGHTS, SPACINGS)

    return emd_l, emd_r

# Run these as a static simulation for healthy and damaged cases
beam_1 = Beam()
beam_2 = Beam()

emd_L = np.zeros((len(delta1_vals), ITERATIONS))
emd_R = np.zeros((len(delta1_vals), ITERATIONS))

for i, (d1, xd1, d2, xd2) in enumerate(
    zip(delta1_vals, xd1_vals, delta2_vals, xd2_vals)
):
    print("i=", i)

    beam_1.reset_damage()
    beam_1.inflict_damage_at_x(xd1, d1)
    print("updated beam 1")

    beam_2.reset_damage()
    beam_2.inflict_damage_at_x(xd2, d2)
    print("updated beam 2")

    emd_L[i, :], emd_R[i, :] = process_all_iters(
        ITERATIONS, beam_1.Kg, beam_2.Kg, N_VEHICLES, WEIGHTS, SPACINGS
    )

print(emd_L.mean(axis=1))
print(emd_L.std(axis=1))

print(emd_R.mean(axis=1))
print(emd_R.std(axis=1))


from scoringengine.scoringengine import ScoringEngine, ServiceReport
import requests
import requests.exceptions
import os

SERVICE_NAME = 'http'

ScoringEngine.register_service(SERVICE_NAME)
with open(os.path.join(os.path.dirname(__file__), ('http.sample'))) as f:
    sample_response = f.read()

@ScoringEngine.scheduler.interval_schedule(seconds=10)
def http_all():
    ScoringEngine.logger.info('Scoring http')
    for team in ScoringEngine.teams:
        http(team)

def http(team):
    teamName = team['name']
    host = team['services'][SERVICE_NAME]['host']

    try:
        response = requests.get('http://' + host)
        # Verify that the http response matches the sample
        if response.text == sample_response:
            report(teamName, True)
        else:
            report(teamName, False, 'invalid response')
    except requests.exceptions.RequestException:
        report(teamName, False, 'HTTP error')
    except Exception:
        report(teamName, False, 'error')

def report(team, up, status=''):
    ScoringEngine.report(ServiceReport(team=team, service=SERVICE_NAME, up=up, status=status))


from polygon import arc
import turtle

bob = turtle.Turtle()
turtle.speed(speed=100)
turtle.delay(0)

petals = 16
angle = 30
radius = 10000/ angle

def draw_petal(t, radius, angle):
    for i in range(2):
        arc(t, radius, angle)
        t.lt(180-angle)

for i in range(petals):
    draw_petal(bob, radius, angle)
    bob.lt(360 / petals)

turtle.mainloop()


from tornado.web import RequestHandler
from tornado.escape import json_decode
import json

class BaseHandler(RequestHandler):
    def prepare(self):
        if self.request.body:
            try:
                self.data = json_decode(self.request.body)
            except TypeError or json.JSONDecodeError as e:
                self.write_error(400, error_msg=e)

    def write_error(self, status_code, **kwargs):
        """
        Override RequestHandler.write_error to produce a custom error response.

        For more information, refers to
        https://www.tornadoweb.org/en/stable/guide/structure.html?highlight=write_error
        """
        self.write({"error_code": status_code, "error_msg": kwargs.get("error_msg", "")})
        self.finish()


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

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('booking', '0001_initial'),
    ]

    operations = [
        migrations.AlterField(
            model_name='meetuprequest',
            name='start_time',
            field=models.TimeField(null=True),
        ),
    ]


#!/usr/bin/env python3
import argparse
import collections
import pdb

def dump_map(map, field):
    print(f"(field: {field})")
    for row in map:
        print(row)
    print("\n%%%%%%\n")

def count_lit(map):
    c = collections.Counter()
    for row in map:
        c += collections.Counter(row)
    return c["#"]

def translate(alg, s):
    s = s.replace(".", "0").replace("#", "1")
    return alg[int(s, base=2)]

def map_get(map, x, y, field="."):
    m, n = len(map), len(map[0])
    if x < 0 or x >= m or y < 0 or y >= n:
        return field
    return map[y][x]

def enhance(alg, map, field):
    if field == "." and alg[0] == "#":
        new_field = "#"
    elif field == "#" and alg[511] == ".":
        new_field = "."
    else:
        new_field = field
    new_map = []
    n, m = len(map), len(map[0])
    for y in range(-1, n + 1, 1):
        new_row = ""
        for x in range(-1, m + 1, 1):
            s = ""
            for y_offset in [-1, 0, 1]:
                for x_offset in [-1, 0, 1]:
                    s += map_get(map, x + x_offset, y + y_offset, field=field)
            new_row += translate(alg, s)
        new_map.append(new_row)

    return new_map, new_field

def part1(alg, map, steps=2):
    field = "."
    for _ in range(steps):
        map, field = enhance(alg, map, field)
    dump_map(map, field)

    return count_lit(map)

def part2(alg, map):
    return part1(alg, map, steps=50)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("part", type=int, help="Which part to run.")
    parser.add_argument("input_file", type=str)
    args = parser.parse_args()

    alg = None
    map = []
    with open(args.input_file) as fh:
        for line in fh.readlines():
            line = line.strip()
            if alg is None:
                alg = line
            elif len(line) != 0:
                map.append(line)
    if args.part == 1:
        print(part1(alg, map))
    elif args.part == 2:
        print(part2(alg, map))
    elif args.part == 3:
        pdb.set_trace()
    else:
        print("illegal part")


import requests
import json
import datetime

def format_date(date_str):
    # 将日期字符串解析为datetime对象
    date = datetime.datetime.fromisoformat(date_str)

    # 将datetime对象转换为年月日格式字符串
    return date.strftime("%Y.%m.%d")

devices = {
    "device1": "iPhone",
    "device2": "iPad",
    "device3": "Mac"
}

for device_key, device_name in devices.items():
    device_url = f"https://betahub.cn/api/apple/devices/{device_name}"
    response = requests.get(device_url)
    devices_data = response.json()

    all_data = {}

    for device in devices_data:
        identifier = device.get("identifier")

        url1 = f"https://betahub.cn/api/apple/firmwares/{identifier}?type=1"
        url2 = f"https://betahub.cn/api/apple/firmwares/{identifier}?type=2"

        response1 = requests.get(url1)
        data1 = response1.json()

        filtered_data1 = {
            "id": data1.get("id"),
            "name": data1.get("name"),
            "identifier": data1.get("identifier"),
            "release_date": data1.get("release_date"),
            "firmwares": []
        }

        for firmware1 in data1.get("firmwares", []):
            filtered_firmware1 = {
                "id": firmware1.get("id"),
                "version": "iOS " + firmware1.get("version") if device_name == "iPhone" else
                "iPadOS " + firmware1.get("version") if device_name == "iPad" else
                "MacOS " + firmware1.get("version") if device_name == "Mac" else firmware1.get("version"),
                "build_id": firmware1.get("build_id"),
                "size": f"{round(firmware1.get('size') / 1073741824, 2):.2f}GB",
                "url": firmware1.get("url"),
                "created_at": firmware1.get("created_at"),
                "type": firmware1.get("type"),
                "signing": firmware1.get("signing")
            }
            filtered_data1["firmwares"].append(filtered_firmware1)

        if url2:
            response2 = requests.get(url2)
            data2 = response2.json()

            filtered_data2 = {
                "id": data2.get("id"),
                "name": data2.get("name"),
                "identifier": data2.get("identifier"),
                "release_date": data2.get("release_date"),
                "firmwares": []
            }

            for firmware2 in data2.get("firmwares", []):
                filtered_firmware2 = {
                    "id": firmware2.get("id"),
                    "version": firmware2.get("version"),
                    "build_id": firmware2.get("build_id"),
                    "size": f"{round(firmware2.get('size') / 1073741824, 2):.2f}GB",
                    "url": firmware2.get("url"),
                    "created_at": firmware2.get("created_at"),
                    "type": firmware2.get("type"),
                    "signing": firmware2.get("signing")
                }
                filtered_data2["firmwares"].append(filtered_firmware2)

            # 合并firmwares
            filtered_data1["firmwares"].extend(filtered_data2["firmwares"])

            # 保存到JSON文件
            with open(f"{identifier}.json", "w", encoding="utf-8") as json_file:
                json.dump(filtered_data1, json_file, ensure_ascii=False, indent=4)


import random

def getHex():
    alph = "0123456789ABCDEF"
    ans = random.choice(alph)
    ans += random.choice(alph)
    return ans

def bubbleSort(nums):
    for i in range(len(nums) - 1):
        for j in range(len(nums) - i - 1):
            if int(nums[j], 16) > int(nums[j + 1], 16):
                nums[j], nums[j + 1] = nums[j + 1], nums[j]
    return nums

board = [[], [], [], []]
newBoard = [[], [], [], []]
temp = [[], [], [], []]
foo = input()

if foo == "r":
    for i in range(4):
        for _ in range(4):
            board[i].append(getHex())
else:
    for i in range(4):
        for _ in range(4):
            board[i].append(input())

for s in board:
    print(s)
print(' ')

for smt in range(4):
    for sm in range(4):
        temp[smt].append(board[sm][smt])

for j in range(4):
    for _ in range(4):
        newBoard[j] = bubbleSort(temp[j])
        if j % 2 == 0:
            newBoard[j].reverse()

rez = [[newBoard[j][i] for j in range(len(newBoard))] for i in range(len(newBoard[0]))]
for row in rez:
    print(row)


from packets.Messages import Message
from utils.reader import Reader
from utils.writer import Writer
import json

class LeaderboardMessage(Message):
	def __init__(self, dataPlayers):
		super().__init__()
		self.id = 24403
		self.dataPlayers = dataPlayers

	def decode(self, buffer):
		Reader.__init__(self, buffer)

	def encode(self):
		self.writeVint(0)
		self.writeScID(0,0)
		self.writeString()

		self.writeVint(0)
		#for x in self.dataPlayers:
		#	d = json.loads(x[1])

		self.writeVint(-64)
		self.writeVint(-64)

		self.writeVint(1)
		self.writeVint(0)
		self.writeString("RU") # country


#!/usr/bin/env python3
"""
Launches a registered algorithm on the given set of media
"""

import argparse
import logging
import time

import tator

logging.basicConfig(
    filename='launch_algorithm.log',
    filemode='w',
    format='%(asctime)s %(levelname)s:%(message)s',
    datefmt='%m/%d/%Y %I:%M:%S %p',
    level=logging.INFO)
logger = logging.getLogger(__name__)

def parse_args() -> argparse.Namespace:
    """ Parse the provided script arguments

    Returns:
        Parsed arguments in a namespace object
    """

    parser = argparse.ArgumentParser(
        description="Launches the registered algorithm workflow (via name) on the given set of media")
    parser = tator.get_parser(parser=parser)
    parser.add_argument(
        '--project', type=int, required=True, help='Unique project id')
    parser.add_argument(
        '--algorithm', type=str, required=True, help='Name of registered algorithm to launch')
    parser.add_argument(
        '--media', type=int, required=True, nargs='+', help='Media IDs to process')

    args = parser.parse_args()
    logger.info(args)

    return args

def launch_algorithm(
        host: str,
        token: str,
        project: int,
        algorithm_name: str,
        media_ids: list) -> None:
    """ Launches the registered algorithm on the given set of media

    Args:
        host (str): Tator server url
        token (str): User access token to tator server
        project_id (int): Unique identifier of project that contains the algorithm/media
        algorithm_name (str): Name of algorithm to launch
        media_ids (list of ints): List of media IDs for the algorithm to process

    Postconditions:
        Algorithm launched. UID and GID are printed.
    """

    # Get the interface to tator
    tator_api = tator.get_api(host=host, token=token)

    # Launch the algorithm
    spec = tator.models.AlgorithmLaunchSpec(
        algorithm_name=algorithm_name,
        media_ids=media_ids)

    logger.info("Algorithm Spec")
    logger.info(f"{spec}")

    response = tator_api.algorithm_launch(
        project=project,
        algorithm_launch_spec=spec)

    print('Algorithm launch response logged.')

    logger.info('Algorithm launch response')
    logger.info(response)

    # Monitor progress, wait until complete.
    while True:
        jobs = tator_api.get_job_list(project, gid=response.gid)
        all_done = True
        for job in jobs:
            if job.status != 'Succeeded':
                all_done = False
            if job.status == 'Failed':
                raise ValueError("Algorithm job failed!")
        time.sleep(10)

def main() -> None:
    """ Main routine of this script
    """

    args = parse_args()

    launch_algorithm(
        host=args.host,
        token=args.token,
        project=args.project,
        algorithm_name=args.algorithm,
        media_ids=args.media)

    print('[FINISHED] launch_algorithm.py')

if __name__ == "__main__":
    main()


from rest_framework import serializers
from rest_framework.reverse import reverse

from api.serializers import UserPublicSerializer
from .models import Product
from .validators import validate_title

class ProductInlineSerializer(serializers.Serializer):
    url = serializers.HyperlinkedIdentityField(
    view_name="product-detail",
    lookup_field="pk",
    read_only=True
    )
    title = serializers.CharField(read_only=True)

class ProductSerializer(serializers.ModelSerializer):
    owner = UserPublicSerializer(source="user", read_only=True)
#    my_user_data = serializers.SerializerMethodField(read_only=True)
#    my_discount = serializers.SerializerMethodField(read_only=True)
    edit_url = serializers.SerializerMethodField(read_only=True)
    # ne fonctionne que sur ModelSerializer :
    url = serializers.HyperlinkedIdentityField(
        view_name="product-detail", lookup_field="pk"
    )
    title = serializers.CharField(validators=[validate_title])

    class Meta:
        model = Product
        fields = [
            "owner",  # user_id, a commenter en prod;)
            "url",
            "edit_url",
            "pk",
            "title",
            "content",
            "price",
            "sale_price",
          #  "my_discount",
          #  "my_user_data",
        ]

    def get_my_user_data(self, obj):
        return {"username": obj.user.username}

    def get_edit_url(self, obj):
        # return f"/api/v2/products/{obj.pk}/"
        request = self.context.get("request")
        if request is None:
            return None
        return reverse("product-edit", kwargs={"pk": obj.pk}, request=request)

    # Si create product, les url seront automatiquement générées


__author__ = 'eric'
import cherrypy
import threading
import re
import os
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import *

cherrypy.config.update({'log.screen': False})
cherrypy.config.update({'server.socket_host': '0.0.0.0'})

class CommandWebSocket(WebSocket):

    def received_message(self, message):
        response = self.main.run_server_command(message.data)
        response = re.sub("\n", "<br />", response)
        response = re.sub("\t", " ", response)
        self.send(response, message.is_binary)

class WSServer:

    def __init__(self, main, port):

        self.main = main
        self.port = port

        self.CommandWebSocket = CommandWebSocket
        self.CommandWebSocket.main = self.main

        thread = threading.Thread(target=self.run, args=())
        thread.daemon = True                            # Daemonize thread
        thread.start()

    def run(self):
        cherrypy.config.update({'server.socket_port': self.port})
        WebSocketPlugin(cherrypy.engine).subscribe()
        cherrypy.tools.websocket = WebSocketTool()

        class Root(object):
            @cherrypy.expose
            def index(self):
                script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in
                rel_path = "../web/command.html"
                abs_file_path = os.path.join(script_dir, rel_path)
                commandMarkup = open(abs_file_path).read()
                return commandMarkup

            @cherrypy.expose
            def ws(self):
                # you can access the class instance through
                handler = cherrypy.request.ws_handler

        cherrypy.quickstart(Root(), '/', config={'/ws':
                                                     {
                                                         'tools.websocket.on': True,
                                                         'tools.websocket.handler_cls': self.CommandWebSocket
                                                     },
                                                 'global': {
                                                   'log.screen': False,
                                                   'log.error_file': '',
                                                   'log.access_file': ''
                                                }})


# -*- coding: utf-8 -*-
'''
    :codeauthor: :email:`Nicole Thomas <nicole@saltstack.com>`
'''

# Import Python Libs
import os
import random
import string

# Import Salt Testing Libs
from salttesting import skipIf
from salttesting.helpers import ensure_in_syspath, expensiveTest

ensure_in_syspath('../../../')

# Import Salt Libs
import integration
from salt.config import cloud_providers_config

# Import Third-Party Libs
try:
    import libcloud  # pylint: disable=W0611
    HAS_LIBCLOUD = True
except ImportError:
    HAS_LIBCLOUD = False

def __random_name(size=6):
    '''
    Generates a random cloud instance name
    '''
    return 'CLOUD-TEST-' + ''.join(
        random.choice(string.ascii_uppercase + string.digits)
        for x in range(size)
    )

# Create the cloud instance name to be used throughout the tests
INSTANCE_NAME = __random_name()

@skipIf(HAS_LIBCLOUD is False, 'salt-cloud requires >= libcloud 0.13.2')
class RackspaceTest(integration.ShellCase):
    '''
    Integration tests for the Rackspace cloud provider using the Openstack driver
    '''

    @expensiveTest
    def setUp(self):
        '''
        Sets up the test requirements
        '''
        super(RackspaceTest, self).setUp()

        # check if appropriate cloud provider and profile files are present
        profile_str = 'rackspace-config:'
        provider = 'rackspace'
        providers = self.run_cloud('--list-providers')
        if profile_str not in providers:
            self.skipTest(
                'Configuration file for {0} was not found. Check {0}.conf files '
                'in tests/integration/files/conf/cloud.*.d/ to run these tests.'
                .format(provider)
            )

        # check if api key, user, and tenant are present
        path = os.path.join(integration.FILES,
                            'conf',
                            'cloud.providers.d',
                            provider + '.conf')
        config = cloud_providers_config(path)
        user = config['rackspace-config']['openstack']['user']
        tenant = config['rackspace-config']['openstack']['tenant']
        api = config['rackspace-config']['openstack']['apikey']
        if api == '' or tenant == '' or user == '':
            self.skipTest(
                'A user, tenant, and an api key must be provided to run these '
                'tests. Check tests/integration/files/conf/cloud.providers.d/{0}.conf'
                .format(provider)
            )

    def test_instance(self):
        '''
        Test creating an instance on rackspace with the openstack driver
        '''

        # create the instance
        instance = self.run_cloud('-p rackspace-test {0}'.format(INSTANCE_NAME))
        ret = '        {0}'.format(INSTANCE_NAME)

        # check if instance with salt installed returned successfully
        try:
            self.assertIn(ret, instance)
        except AssertionError:
            self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME))
            raise

        # delete the instance
        delete = self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME))
        ret = '            True'
        try:
            self.assertIn(ret, delete)
        except AssertionError:
            raise

    def tearDown(self):
        '''
        Clean up after tests
        '''
        query = self.run_cloud('--query')
        ret = '        {0}:'.format(INSTANCE_NAME)

        # if test instance is still present, delete it
        if ret in query:
            self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME))

if __name__ == '__main__':
    from integration import run_tests
    run_tests(RackspaceTest)


# -*- coding: utf-8 -*-
"""
Created on Thu Apr 19 14:50:06 2018

@author: jieyang
"""
import os
import time
import re
num_string = {}
f = open(r'./tr.txt',"r")
line = f.readline()
dictionary = ''
normal_dic = ' "!#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`abcdefghijklmnopqrstuvwxyz~'
i = 0
while line:
    i = i + 1
    contant_line = str(line)
    string_line = contant_line.split(',')[1]
    if string_line[0] == '|':
        string_line = contant_line.split('|')[1]
    if contant_line.split(',')[0] == "1177212":
        print("I am sentance:",string_line)
    for em in string_line:
        if em not in normal_dic:
            if i == 1:
                normal_dic = normal_dic + em
        if em in dictionary:
            continue
        else:
       	    dictionary = dictionary + em
    line = f.readline()
f.close()
dictionary = "".join((lambda x:(x.sort(),x)[1])(list(dictionary)))
print(dictionary)


import pygame
import random

pasta = "..\\assets\\"

class parede():
    distancia = 200
    speed =4
    canos = [pygame.sprite.Sprite(),pygame.sprite.Sprite()]
    points = 0
    reinitX = 3000
    def __init__(self):

        self.canos[1-1].image = pygame.image.load(pasta+"canos_a.png")
        self.canos[1-1].rect = self.canos[0].image.get_rect()
        self.canos[2-1].image = pygame.image.load(pasta+"canos_b.png")
        self.canos[2-1].rect = self.canos[1].image.get_rect()
        self.canos[0].rect.top = random.randint(-350,-200)
        self.reinitX = pygame.display.get_window_size()[0]
        self.original()

    def atualize(self):
        self.canos[1].rect.centerx = self.canos[0].rect.centerx
        self.canos[1].rect.top = (self.canos[0].rect.bottom + 200)

    def walk(self):
        self.canos[0].rect.right -= self.speed
        if self.canos[0].rect.right < 0:
            self.canos[0].rect.top = random.randint(-314,-100)
            self.original()
        if round(self.canos[0].rect.right) < round(pygame.display.get_window_size()[0]/2):
            self.points+=1
        self.atualize()
    def original(self):
        self.canos[0].rect.left = self.reinitX
        self.atualize()

class player(pygame.sprite.Sprite):
    jumpForce = 0.0
    momentum = 0.0
    gravidade = 0.0
    fps = 1
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(pasta+"ave.png")  # qual imagem
        self.rect = self.image.get_rect()
    def jump(self):
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN :
                if event.key == pygame.K_SPACE or event.key == pygame.K_k:
                    self.momentum = -self.jumpForce/self.fps
            if event.type == pygame.MOUSEBUTTONDOWN:
                self.momentum = -self.jumpForce/self.fps

        self.momentum += self.gravidade/self.fps
        self.rect.y += self.momentum

class button(pygame.sprite.Sprite):

    def __init__(self, a: str):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(pasta+a)
        self.rect = self.image.get_rect()


import pygame
from decoration import Sky

class GameOver:
    def __init__(self, surface, coin_data, reset_overworld):
        self.display_surface = surface
        self.coin_data = coin_data
        self.reset_overworld = reset_overworld

        self.sky = Sky(8, 'overworld')

        self.font = pygame.font.Font('graphics/ui/ARCADEPI.TTF', 25)
        self.font_game_over = pygame.font.Font('graphics/ui/ARCADEPI.TTF', 50)

    def input(self):
        keys = pygame.key.get_pressed()

        if keys[pygame.K_SPACE]:
            self.reset_overworld()

    def display_game_over(self):
        game_over_text = self.font_game_over.render('GAME OVER', False, '#33323d')
        game_over_rect = game_over_text.get_rect(center = (600, 400))
        self.display_surface.blit(game_over_text, game_over_rect)

        coins_text = self.font.render('Coins: {}'.format(self.coin_data), False, '#33323d')
        coins_rect = coins_text.get_rect(center = (600, 450))
        self.display_surface.blit(coins_text, coins_rect)

    def run(self):
        self.sky.draw(self.display_surface)
        self.display_game_over()
        self.input()