import random
from collections import defaultdict
from copy import deepcopy
from typing import Any, Dict, List, Union

import boto3
from botocore.exceptions import ClientError
from chaoslib.exceptions import ActivityFailed, FailedActivity
from chaoslib.types import Configuration, Secrets
from logzero import logger

from chaosaws import aws_client
from chaosaws.types import AWSResponse

__all__ = [
    "stop_instance",
    "stop_instances",
    "terminate_instances",
    "terminate_instance",
    "start_instances",
    "restart_instances",
    "detach_random_volume",
    "attach_volume",
]

def stop_instance(
    instance_id: str = None,
    az: str = None,
    force: bool = False,
    filters: List[Dict[str, Any]] = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Stop a single EC2 instance.

    You may provide an instance id explicitly or, if you only specify the AZ,
    a random instance will be selected. If you need more control, you can
    also provide a list of filters following the documentation
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances
    """

    if not az and not instance_id and not filters:
        raise FailedActivity(
            "To stop an EC2 instance, you must specify either the instance id,"
            " an AZ to pick a random instance from, or a set of filters."
        )

    if az and not instance_id and not filters:
        logger.warning(
            "Based on configuration provided I am going to "
            "stop a random instance in AZ %s!" % az
        )

    client = aws_client("ec2", configuration, secrets)

    if not instance_id:
        filters = deepcopy(filters) if filters else []

        if az:
            filters.append({"Name": "availability-zone", "Values": [az]})
        instance_types = pick_random_instance(filters, client)

        if not instance_types:
            raise FailedActivity(f"No instances in availability zone: {az}")
    else:
        instance_types = get_instance_type_by_id([instance_id], client)

    logger.debug(f"Picked EC2 instance '{instance_types}' from AZ '{az}' to be stopped")

    return stop_instances_any_type(
        instance_types=instance_types, force=force, client=client
    )

def stop_instances(
    instance_ids: List[str] = None,
    az: str = None,
    filters: List[Dict[str, Any]] = None,
    force: bool = False,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Stop the given EC2 instances or, if none is provided, all instances
    of the given availability zone. If you need more control, you can
    also provide a list of filters following the documentation
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances
    """

    if not az and not instance_ids and not filters:
        raise FailedActivity(
            "To stop EC2 instances, you must specify either the instance ids,"
            " an AZ to pick random instances from, or a set of filters."
        )

    if az and not instance_ids and not filters:
        logger.warning(
            "Based on configuration provided I am going to "
            "stop all instances in AZ %s!" % az
        )

    client = aws_client("ec2", configuration, secrets)

    if not instance_ids:
        filters = deepcopy(filters) if filters else []

        if az:
            filters.append({"Name": "availability-zone", "Values": [az]})
        instance_types = list_instances_by_type(filters, client)

        if not instance_types:
            raise FailedActivity(f"No instances in availability zone: {az}")
    else:
        instance_types = get_instance_type_by_id(instance_ids, client)

    logger.debug(
        "Picked EC2 instances '{}' from AZ '{}' to be stopped".format(
            str(instance_types), az
        )
    )

    return stop_instances_any_type(
        instance_types=instance_types, force=force, client=client
    )

def terminate_instance(
    instance_id: str = None,
    az: str = None,
    filters: List[Dict[str, Any]] = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Terminates a single EC2 instance.

    An instance may be targeted by specifying it by instance-id. If only the
    availability-zone is provided, a random instances in that AZ will be
    selected and terminated. For more control, please reference the available
    filters found:
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances
    """

    if not any([instance_id, az, filters]):
        raise FailedActivity(
            "To terminate an EC2, you must specify the "
            "instance-id, an Availability Zone, or provide a "
            "set of filters"
        )

    if az and not any([instance_id, filters]):
        logger.warning(
            "Based on configuration provided I am going to "
            "terminate a random instance in AZ %s!" % az
        )

    client = aws_client("ec2", configuration, secrets)
    if not instance_id:
        filters = deepcopy(filters) or []

        if az:
            filters.append({"Name": "availability-zone", "Values": [az]})
            logger.debug("Looking for instances in AZ: %s" % az)

        # Randomly select an instance
        instance_types = pick_random_instance(filters, client)

        if not instance_types:
            raise FailedActivity(
                "No instances found matching filters: %s" % str(filters)
            )

        logger.debug("Instance selected: %s" % str(instance_types))
    else:
        instance_types = get_instance_type_by_id([instance_id], client)

    return terminate_instances_any_type(instance_types, client)

def terminate_instances(
    instance_ids: List[str] = None,
    az: str = None,
    filters: List[Dict[str, Any]] = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Terminates multiple EC2 instances

    A set of instances may be targeted by providing them as the instance-ids.

    WARNING: If  only an Availability Zone is specified, all instances in
    that AZ will be terminated.

    Additional filters may be used to narrow the scope:
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances
    """
    if not any([instance_ids, az, filters]):
        raise FailedActivity(
            "To terminate instances, you must specify the "
            "instance-id, an Availability Zone, or provide a "
            "set of filters"
        )

    if az and not any([instance_ids, filters]):
        logger.warning(
            "Based on configuration provided I am going to "
            "terminate all instances in AZ %s!" % az
        )

    client = aws_client("ec2", configuration, secrets)
    if not instance_ids:
        filters = deepcopy(filters) or []

        if az:
            filters.append({"Name": "availability-zone", "Values": [az]})
            logger.debug("Looking for instances in AZ: %s" % az)

        # Select instances based on filters
        instance_types = list_instances_by_type(filters, client)

        if not instance_types:
            raise FailedActivity(
                "No instances found matching filters: %s" % str(filters)
            )

        logger.debug(f"Instances in AZ {az} selected: {str(instance_types)}}}.")
    else:
        instance_types = get_instance_type_by_id(instance_ids, client)

    return terminate_instances_any_type(instance_types, client)

def start_instances(
    instance_ids: List[str] = None,
    az: str = None,
    filters: List[Dict[str, Any]] = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Starts one or more EC2 instances.

    WARNING: If only an Availability Zone is provided, all instances in the
    provided AZ will be started.

    Additional filters may be used to narrow the scope:
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances
    """
    if not any([instance_ids, az, filters]):
        raise FailedActivity(
            "To start instances, you must specify the "
            "instance-id, an Availability Zone, or provide a "
            "set of filters"
        )

    if az and not any([instance_ids, filters]):
        logger.warning(
            "Based on configuration provided I am going to "
            "start all instances in AZ %s!" % az
        )

    client = aws_client("ec2", configuration, secrets)

    if not instance_ids:
        filters = deepcopy(filters) or []

        if az:
            filters.append({"Name": "availability-zone", "Values": [az]})
            logger.debug("Looking for instances in AZ: %s" % az)

        # Select instances based on filters
        instance_types = list_instances_by_type(filters, client)

        if not instance_types:
            raise FailedActivity(
                "No instances found matching filters: %s" % str(filters)
            )

        logger.debug(f"Instances in AZ {az} selected: {str(instance_types)}}}.")
    else:
        instance_types = get_instance_type_by_id(instance_ids, client)
    return start_instances_any_type(instance_types, client)

def restart_instances(
    instance_ids: List[str] = None,
    az: str = None,
    filters: List[Dict[str, Any]] = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Restarts one or more EC2 instances.

    WARNING: If only an Availability Zone is provided, all instances in the
    provided AZ will be restarted.

    Additional filters may be used to narrow the scope:
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances
    """
    if not any([instance_ids, az, filters]):
        raise FailedActivity(
            "To restart instances, you must specify the "
            "instance-id, an Availability Zone, or provide a "
            "set of filters"
        )

    if az and not any([instance_ids, filters]):
        logger.warning(
            "Based on configuration provided I am going to "
            "restart all instances in AZ %s!" % az
        )

    client = aws_client("ec2", configuration, secrets)

    if not instance_ids:
        filters = deepcopy(filters) or []

        if az:
            filters.append({"Name": "availability-zone", "Values": [az]})
            logger.debug("Looking for instances in AZ: %s" % az)

        # Select instances based on filters
        instance_types = list_instances_by_type(filters, client)

        if not instance_types:
            raise FailedActivity(
                "No instances found matching filters: %s" % str(filters)
            )

        logger.debug(f"Instances in AZ {az} selected: {str(instance_types)}}}.")
    else:
        instance_types = get_instance_type_by_id(instance_ids, client)
    return restart_instances_any_type(instance_types, client)

def detach_random_volume(
    instance_ids: List[str] = None,
    filters: List[Dict[str, Any]] = None,
    force: bool = True,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Detaches a random ebs volume (non root) from one or more EC2 instances

    Parameters:
        One of:
            instance_ids: a list of one or more ec2 instance ids
            filters: a list of key/value pairs to pull ec2 instances

        force: force detach volume (default: true)

    Additional filters may be used to narrow the scope:
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances
    """
    if not any([instance_ids, filters]):
        raise FailedActivity(
            "To detach volumes, you must specify the "
            "instance_id or provide a set of filters"
        )

    client = aws_client("ec2", configuration, secrets)

    if not instance_ids:
        filters = deepcopy(filters) or []
        instances = list_instance_volumes(client, filters=filters)
    else:
        instances = list_instance_volumes(client, instance_ids=instance_ids)

    results = []
    for e in instances:
        results.append(detach_instance_volume(client, force, e))
    return results

def attach_volume(
    instance_ids: List[str] = None,
    filters: List[Dict[str, Any]] = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> List[AWSResponse]:
    """
    Attaches a previously detached EBS volume to its associated EC2 instance.

    If neither 'instance_ids' or 'filters' are provided, all detached volumes
    will be reattached to their respective instances

    Parameters:
        One of:
            instance_ids: list: instance ids
            filters: list: key/value pairs to pull ec2 instances
    """
    client = aws_client("ec2", configuration, secrets)

    if not instance_ids and not filters:
        instances = []
    elif not instance_ids and filters:
        filters = deepcopy(filters) or []
        instances = list_instances(client, filters=filters)
    else:
        instances = list_instances(client, instance_ids=instance_ids)

    volumes = get_detached_volumes(client)
    results = []
    for volume in volumes:
        for t in volume["Tags"]:
            if t["Key"] != "ChaosToolkitDetached":
                continue
            attach_data = t["Value"].split(";")
            device_name = attach_data[0].split("=")[-1]
            instance_id = attach_data[1].split("=")[-1]

            if not instances or instance_id in [e["InstanceId"] for e in instances]:
                results.append(
                    attach_instance_volume(
                        client, instance_id, volume["VolumeId"], device_name
                    )
                )
    return results

###############################################################################
# Private functions
###############################################################################
def list_instances_by_type(
    filters: List[Dict[str, Any]], client: boto3.client
) -> Dict[str, Any]:
    """
    Return all instance ids matching the given filters by type
    (InstanceLifecycle) ie spot, on demand, etc.
    """
    logger.debug(f"EC2 instances query: {str(filters)}")
    res = client.describe_instances(Filters=filters)
    logger.debug(f"Instances matching the filter query: {str(res)}")

    return get_instance_type_from_response(res)

def list_instances(
    client: boto3.client,
    filters: List[Dict[str, Any]] = None,
    instance_ids: List[str] = None,
) -> List[Dict[str, Any]]:
    """
    Return all instance ids matching either the filters or provided list of ids

    Does not group instances by type
    """
    if filters:
        params = dict(Filters=filters)
    else:
        params = dict(InstanceIds=instance_ids)

    results = []
    response = client.describe_instances(**params)["Reservations"]
    for r in response:
        for e in r["Instances"]:
            results.append(e)
    return results

def list_instance_volumes(
    client: boto3.client,
    instance_ids: List[str] = None,
    filters: List[Dict[str, Any]] = None,
) -> List[AWSResponse]:
    """
    Return all (non root) instance volumes for instances matching either
    the provided filters or instance ids (do not group by type)
    """
    if filters:
        params = dict(Filters=filters)
    else:
        params = dict(InstanceIds=instance_ids)

    response = client.describe_instances(**params)["Reservations"]

    if not response:
        raise FailedActivity("no instances found matching: %s" % str(params))

    results = {}
    for r in response:
        for e in r["Instances"]:
            instance_id = e["InstanceId"]
            bdm = e.get("BlockDeviceMappings", [])
            for b in bdm:
                if b["DeviceName"] in ("/dev/sda1", "/dev/xvda"):
                    continue
                results.setdefault(instance_id, []).append(
                    {b["DeviceName"]: b["Ebs"]["VolumeId"]}
                )

    volumes = []
    for r in results:
        # select 1 volume at random
        volume = random.sample(results[r], 1)[0]
        for k, v in volume.items():
            volumes.append({"InstanceId": r, "DeviceName": k, "VolumeId": v})
    return volumes

def pick_random_instance(
    filters: List[Dict[str, Any]], client: boto3.client
) -> Union[str, dict, None]:
    """
    Select an instance at random based on the returned list of instances
    matching the given filter.
    """
    instances_type = list_instances_by_type(filters, client)
    if not instances_type:
        return

    random_id = random.choice(
        [item for sublist in instances_type.values() for item in sublist]
    )

    for k, v in instances_type.items():
        if random_id in v:
            return {k: [random_id]}

def get_instance_type_from_response(response: Dict) -> Dict:
    """
    Transform list of instance IDs to a dict with IDs by instance type
    """
    instances_type = defaultdict(List)
    # reservations are instances that were started together

    for reservation in response["Reservations"]:
        for inst in reservation["Instances"]:
            # when this field is missing, we assume "normal"
            # which means On-Demand or Reserved
            # this seems what the last line of the docs imply at
            # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-purchasing-options.html
            lifecycle = inst.get("InstanceLifecycle", "normal")

            if lifecycle not in instances_type.keys():
                # adding empty list (value) for new instance type (key)
                instances_type[lifecycle] = []

            instances_type[lifecycle].append(inst["InstanceId"])

    return instances_type

def get_spot_request_ids_from_response(response: Dict) -> List[str]:
    """
    Return list of all spot request ids from AWS response object
    (DescribeInstances)
    """
    spot_request_ids = []

    for reservation in response["Reservations"]:
        for inst in reservation["Instances"]:
            # when this field is missing, we assume "normal"
            # which means On-Demand or Reserved
            lifecycle = inst.get("InstanceLifecycle", "normal")

            if lifecycle == "spot":
                spot_request_ids.append(inst["SpotInstanceRequestId"])

    return spot_request_ids

def get_instance_type_by_id(instance_ids: List[str], client: boto3.client) -> Dict:
    """
    Return dict object with instance ids grouped by instance types
    """
    res = client.describe_instances(InstanceIds=instance_ids)

    return get_instance_type_from_response(res)

def stop_instances_any_type(
    instance_types: dict = None, force: bool = False, client: boto3.client = None
) -> List[AWSResponse]:
    """
    Stop instances regardless of the instance type (on demand, spot)
    """

    response = []
    if "normal" in instance_types:
        logger.debug("Stopping instances: {}".format(instance_types["normal"]))

        response.append(
            client.stop_instances(InstanceIds=instance_types["normal"], Force=force)
        )

    if "spot" in instance_types:
        # TODO: proper support for spot fleets
        # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-fleet.html

        # To properly stop spot instances have to cancel spot requests first
        spot_request_ids = get_spot_request_ids_from_response(
            client.describe_instances(InstanceIds=instance_types["spot"])
        )

        logger.debug(f"Canceling spot requests: {spot_request_ids}")
        client.cancel_spot_instance_requests(SpotInstanceRequestIds=spot_request_ids)
        logger.debug("Terminating spot instances: {}".format(instance_types["spot"]))

        response.append(client.terminate_instances(InstanceIds=instance_types["spot"]))

    if "scheduled" in instance_types:
        # TODO: add support for scheduled instances
        # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-scheduled-instances.html
        raise FailedActivity("Scheduled instances support is not implemented")
    return response

def terminate_instances_any_type(
    instance_types: dict = None, client: boto3.client = None
) -> List[AWSResponse]:
    """
    Terminates instance(s) regardless of type
    """
    response = []

    for k, v in instance_types.items():
        logger.debug(f"Terminating {k} instance(s): {instance_types[k]}")
        if k == "spot":
            instances = get_spot_request_ids_from_response(
                client.describe_instances(InstanceIds=v)
            )
            # Cancel spot request prior to termination
            client.cancel_spot_instance_requests(SpotInstanceRequestIds=instances)
            response.append(client.terminate_instances(InstanceIds=v))
            continue
        response.append(client.terminate_instances(InstanceIds=v))
    return response

def start_instances_any_type(
    instance_types: dict, client: boto3.client
) -> List[AWSResponse]:
    """
    Starts one or more instances regardless of type
    """
    results = []
    for k, v in instance_types.items():
        logger.debug(f"Starting {k} instance(s): {v}")
        response = client.start_instances(InstanceIds=v)
        results.extend(response.get("StartingInstances", []))
    return results

def restart_instances_any_type(instance_types: dict, client: boto3.client):
    """
    Restarts one or more instances regardless of type
    """
    results = []
    for k, v in instance_types.items():
        logger.debug(f"Restarting {k} instance(s): {v}")
        client.reboot_instances(InstanceIds=v)
    return results

def detach_instance_volume(
    client: boto3.client, force: bool, volume: Dict[str, str]
) -> AWSResponse:
    """
    Detach volume from an instance
    """
    try:
        response = client.detach_volume(
            Device=volume["DeviceName"],
            InstanceId=volume["InstanceId"],
            VolumeId=volume["VolumeId"],
            Force=force,
        )

        # tag volume with instance information (to reattach on rollback)
        client.create_tags(
            Resources=[volume["VolumeId"]],
            Tags=[
                {
                    "Key": "ChaosToolkitDetached",
                    "Value": "DeviceName=%s;InstanceId=%s"
                    % (volume["DeviceName"], volume["InstanceId"]),
                }
            ],
        )
        return response
    except ClientError as e:
        raise FailedActivity(
            "unable to detach volume %s from %s: %s"
            % (volume["VolumeId"], volume["InstanceId"], e.response["Error"]["Message"])
        )

def get_detached_volumes(client: boto3.client):
    results = []
    paginator = client.get_paginator("describe_volumes")
    for p in paginator.paginate(
        Filters=[{"Name": "tag-key", "Values": ["ChaosToolkitDetached"]}]
    ):
        for v in p["Volumes"]:
            results.append(v)
    return results

def attach_instance_volume(
    client: boto3.client, instance_id: str, volume_id: str, mount_point: str
) -> AWSResponse:
    try:
        response = client.attach_volume(
            Device=mount_point, InstanceId=instance_id, VolumeId=volume_id
        )
        logger.debug(f"Attached volume {volume_id} to instance {instance_id}")
    except ClientError as e:
        raise FailedActivity(
            "Unable to attach volume %s to instance %s: %s"
            % (volume_id, instance_id, e.response["Error"]["Message"])
        )
    return response

def authorize_security_group_ingress(
    requested_security_group_id: str,
    ip_protocol: str,
    from_port: int,
    to_port: int,
    ingress_security_group_id: str = None,
    cidr_ip: str = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> AWSResponse:
    """
    Add one ingress rule to a security group
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.authorize_security_group_ingress

    - requested_security_group_id: the id for the security group to update
    - ip_protocol: ip protocol name (tcp, udp, icmp, icmpv6) or -1 to specify all
    - from_port: start of port range
    - to_port: end of port range
    - ingress_security_group_id: id of the securiy group to allow access to. You can either specify this or cidr_ip.
    - cidr_ip: the IPv6 CIDR range.
    You can either specify this or ingress_security_group_id
    """  # noqa: E501
    client = aws_client("ec2", configuration, secrets)
    request_kwargs = create_ingress_kwargs(
        requested_security_group_id,
        ip_protocol,
        from_port,
        to_port,
        ingress_security_group_id,
        cidr_ip,
    )
    try:
        response = client.authorize_security_group_ingress(**request_kwargs)
        return response
    except ClientError as e:
        raise ActivityFailed(
            "Failed to add ingress rule: {}".format(e.response["Error"]["Message"])
        )

def revoke_security_group_ingress(
    requested_security_group_id: str,
    ip_protocol: str,
    from_port: int,
    to_port: int,
    ingress_security_group_id: str = None,
    cidr_ip: str = None,
    configuration: Configuration = None,
    secrets: Secrets = None,
) -> AWSResponse:
    """
    Remove one ingress rule from a security group
    https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.revoke_security_group_ingress

    - requested_security_group_id: the id for the security group to update
    - ip_protocol: ip protocol name (tcp, udp, icmp, icmpv6) or -1 to specify all
    - from_port: start of port range
    - to_port: end of port range
    - ingress_security_group_id: id of the securiy group to allow access to. You can either specify this or cidr_ip.
    - cidr_ip: the IPv6 CIDR range. You can either specify this or ingress_security_group_id
    """  # noqa: E501
    client = aws_client("ec2", configuration, secrets)
    request_kwargs = create_ingress_kwargs(
        requested_security_group_id,
        ip_protocol,
        from_port,
        to_port,
        ingress_security_group_id,
        cidr_ip,
    )
    try:
        response = client.revoke_security_group_ingress(**request_kwargs)
        return response
    except ClientError as e:
        raise ActivityFailed(
            "Failed to remove ingress rule: {}".format(e.response["Error"]["Message"])
        )

def create_ingress_kwargs(
    requested_security_group_id: str,
    ip_protocol: str,
    from_port: int,
    to_port: int,
    ingress_security_group_id: str = None,
    cidr_ip: str = None,
) -> Dict[str, any]:
    request_kwargs = {
        "GroupId": requested_security_group_id,
        "IpPermissions": [
            {
                "IpProtocol": ip_protocol,
                "IpRanges": [
                    {
                        # conditionally assign the following
                        # 'CidrIp': cidr_ip
                    }
                ],
                "FromPort": from_port,
                "ToPort": to_port,
                "UserIdGroupPairs": [
                    {
                        # conditionally assign the following
                        # 'GroupId': ingress_security_group_id
                    }
                ],
            }
        ],
    }
    req = request_kwargs["IpPermissions"][0]
    if cidr_ip is not None:
        req["IpRanges"][0]["CidrIp"] = cidr_ip
    if ingress_security_group_id is not None:
        req["UserIdGroupPairs"][0]["GroupId"] = ingress_security_group_id
    return request_kwargs


class Board:
    def __init__(self):
        self.board = [[0, 0, 0],
                      [0, 0, 0],
                      [0, 0, 0]]

    def check_if_is_player(self, cords):
        if self.board[cords[0]][cords[1]] == "x":
            return True

    def check_if_move_is_possible(self, cords):
        if self.board[cords[0]][cords[1]] == 0 or self.board[cords[0]][cords[1]] == "0":
            return True

    def check_if_last_move_is_possible(self, cords_start, cords_end):
        if (self.board[cords_end[0]][cords_end[1]] == 0 or self.board[cords_end[0]][cords_end[1]] == "0") and \
                (cords_start[0] == cords_end[0] or cords_start[1] == cords_end[1]):
            return True

    def make_move(self, player, cords):
        self.board[cords[0]][cords[1]] = player

    def get_pos(self, cords):
        return self.board[cords[0]][cords[1]]

    def clear(self, cords):
        self.board[cords[0]][cords[1]] = str(0)

    def check_win(self):
        wins = {
            "x": 0,
            "o": 0
        }

        for x in range(3):
            stat = ""
            for y in range(3):
                stat += str(self.board[x][y])
            if stat == "xxx":
                wins["x"] += 1
            elif stat == "ooo":
                wins["o"] += 1

        for x in range(3):
            stat = ""
            for y in range(3):
                stat += str(self.board[y][x])
            if stat == "xxx":
                wins["x"] += 1
            elif stat == "ooo":
                wins["o"] += 1

        stat = ""
        for x in range(3):
            for y in range(3):
                if x == y:
                    stat += str(self.board[y][x])
        if stat == "xxx":
            wins["x"] += 1
        elif stat == "ooo":
            wins["o"] += 1

        stat = ""
        n = 2
        for x in range(3):
            for y in range(3):
                if y == n:
                    stat += str(self.board[y][x])
                    n -= 1
        if stat == "xxx":
            wins["x"] += 1
        elif stat == "ooo":
            wins["o"] += 1

        if wins["x"] == wins["o"] == 1:
            return "rm"
        elif wins["x"] == 1:
            return "x"
        elif wins["o"] == 1:
            return "o"
        else:
            return "rm"


from app.utils.database import connect_mongo, connect_s3
from datetime import datetime

class DB():
  def __init__(self):
    self.db = connect_mongo('flask');
    self.s3_client = connect_s3('s3')

  def add_single_document(self, collection_name, data):
    coll = self.db[collection_name];
    inserted = coll.insert_one(data)
    return inserted.inserted_id

  def add_ip(self, collection_name, ip):
    coll = self.db[collection_name];
    if(coll.count_documents({'ip': ip}, limit = 1) == 0):
      data = {'ip': ip, 'count': 1}
      self.add_single_document('users', data)
    else:
      # coll.find_one({'ip': ip})
      coll.update_one({'ip': ip}, {"$inc": {"count": 1}})

  def upload_file_to_bucket(self, bucket_name, file, file_name):
    # file_id = self.add_single_document('user-images', {'user': file_name})
    file_id = 1231434
    if(self.s3_client.head_bucket(Bucket=bucket_name)['ResponseMetadata']['HTTPStatusCode'] != 200):
      self.s3_client.create_bucket(Bucket=bucket_name)
    self.s3_client.put_object(ACL='public-read', Body=file, Bucket=bucket_name,
                              Key=file_name+'.jpg',
                              Metadata={'_id': str(file_id)},
                              ContentType=file.content_type)

  def get_file_object(self, bucket_name, file_key):
    return self.s3_client.get_object(Bucket=bucket_name, Key=file_key)['Body']


import os
import sys
current_dir = os.path.dirname(os.path.abspath('__file__'))
root_dir = os.path.abspath(os.path.join(current_dir, '../../'))
sys.path.append(root_dir)

from glob2 import glob
import joblib
from scipy.io import wavfile
import torch
import sudo_rm_rf.utils.progress_display as progress_display
from __config__ import *

def parse_info_from_name(preprocessed_dirname):
    """! Given a name of a preprocessed dataset root dirname infer all the
    encoded information
    Args:
        preprocessed_dirname: A dirname as the one follows:
        wsj0_2mix_8k_4s_min_preprocessed or even a dirpath
    Returns:
        min_or_max: String whether the mixtures are aligned with the maximum
        or the minimum number of samples of the constituting sources
        n_speakers: number of speakers in mixtures
        fs: sampling rate in kHz
        wav_timelength: The timelength in seconds of all the mixtures and
                        clean sources
    """
    try:
        dirname = os.path.basename(preprocessed_dirname)
        elements = dirname.split('_')
        min_or_max = elements[-2]
        assert (min_or_max == 'min' or min_or_max == 'max')
        wav_timelength = float(elements[-3][:-1])
        fs = float(elements[-4][:-1]) * 1000
        n_speakers = int(elements[-5].strip("mix"))

        return min_or_max, n_speakers, fs, wav_timelength

    except:
        raise IOError("The structure of the wsj0-mix preprocessed "
                      "dataset name is not in the proper format. A proper "
                      "format would be: "
                      "wsj0_{number of speakers}mix_{fs}k_{timelength}s_{min "
                      "or max}_preprocessed")

def infer_output_name(input_dirpath, wav_timelength):
    """! Infer the name for the output folder as shown in the example: E.g.
    for input_dirpath: wsj0-mix/2speakers/wav8k/min and for 4s timelength it
    would be wsj0_2mix_8k_4s_min_preprocessed
    Args: input_dirpath: The path of a wsj0mix dataset e.g.
                         wsj0-mix/2speakers/wav8k/min (for mixes with minimum
                         length)
          wav_timelength: The timelength in seconds of all the mixtures and
                          clean sources
    Returns: outputname: as specified in string format
             fs: sampling rate in Hz
             n_speakers: number of speakers in mixtures
    """

    try:
        elements = input_dirpath.lower().split('/')
        min_or_max = elements[-1]
        assert (min_or_max == 'min' or min_or_max == 'max')
        fs = int(elements[-2].strip('wav').strip('k')) * 1000
        n_speakers = int(elements[-3].strip("speakers"))
        output_name = "wsj0_{}mix_{}k_{}s_{}_preprocessed".format(
            n_speakers,
            fs / 1000.,
            float(wav_timelength),
            min_or_max)

        # test that the inferred output name is parsable back
        (inf_min_or_max,
         inf_n_speakers,
         inf_fs,
         inf_wav_timelength) = parse_info_from_name(output_name)
        assert(inf_min_or_max == min_or_max and
               inf_n_speakers == n_speakers and
               inf_fs == fs and
               inf_wav_timelength == wav_timelength)

        return output_name, fs, n_speakers, min_or_max

    except:
        raise IOError("The structure of the wsj0-mix is not in the right "
                "format. A proper format would be: "
                "wsj0-mix/{2 or 3}speakers/wav{fs in Hz}k/{min or max}")

def normalize_wav(wav, eps=10e-7, std=None):
    mean = wav.mean()
    if std is None:
        std = wav.std()
    return (wav - mean) / (std + eps)

def normalize_tensor_wav(wav, eps=10e-7, std=None):
    mean = wav.mean(-1, keepdim=True)
    if std is None:
        std = wav.std(-1, keepdim=True)
    return (wav - mean) / (std + eps)

def write_data_wrapper_func(input_dirpath,
                            clean_folders,
                            max_wav_samples,
                            output_dirpath,
                            min_or_max=None):

    def process_uid(uid):
        mix_path = os.path.join(input_dirpath, 'mix', uid)
        mix_wav = wavfile.read(mix_path)[1] / 29491.

        mix_wav = torch.tensor(mix_wav, dtype=torch.float32)

        sources_paths = [os.path.join(input_dirpath, fo, uid)
                         for fo in clean_folders]
        sources_w_list = [wavfile.read(p)[1] / 29491.
                          for p in sources_paths]
        sources_w_list = [torch.tensor(normalize_wav(np_vec),
                                       dtype=torch.float32).unsqueeze(0)
                          for np_vec in sources_w_list]
        sources_wavs = torch.cat(sources_w_list, dim=0)

        min_len = min(mix_wav.shape[-1], sources_wavs.shape[-1])
        if min_len < max_wav_samples:
            padded_mix_wav = torch.zeros(max_wav_samples)
            padded_sources_wavs = torch.zeros(sources_wavs.shape[0],
                                              max_wav_samples)
            padded_mix_wav[:mix_wav.shape[-1]] = mix_wav
            padded_sources_wavs[
                :, :min(max_wav_samples, sources_wavs.shape[-1])] = \
                sources_wavs[:, :min(max_wav_samples, sources_wavs.shape[-1])]
            mix_wav = padded_mix_wav
            sources_wavs = padded_sources_wavs

        mix_wav = mix_wav[:max_wav_samples]
        sources_wavs = sources_wavs[:, :max_wav_samples]
        mix_std = mix_wav.detach().cpu().numpy().std()
        mix_wav_norm = torch.tensor(normalize_wav(mix_wav),
                                    dtype=torch.float32)
        sources_wavs_norm = normalize_tensor_wav(sources_wavs,
                                                 std=mix_std)

        output_uid_folder = os.path.join(output_dirpath, uid)
        data = {
            'mixture_wav': mix_wav,
            'clean_sources_wavs': sources_wavs,
            'mixture_wav_norm': mix_wav_norm,
            'clean_sources_wavs_norm': sources_wavs_norm
        }

        if not os.path.exists(output_uid_folder):
            os.makedirs(output_uid_folder)

        for k, v in data.items():
            file_path = os.path.join(output_uid_folder, k)
            joblib.dump(v, file_path, compress=0)

    return lambda uid: process_uid(uid)

def convert_subset(input_dirpath,
                   output_dirpath,
                   fs,
                   n_speakers,
                   wav_timelength,
                   subset=None,
                   min_or_max=None):
    """! Convert a subset of files in the appropriate format
    Args:
        input_dirpath: The path of a wsj0mix dataset e.g.
                       wsj0-mix/2speakers/wav8k/min (for mixes with
                       minimum length)
        output_dirpath: The path for storing the new dataset
                        (the directories would be created recursively)
        n_speakers: number of speakers in mixtures
        fs: sampling rate in Hz
        wav_timelength: The timelength in seconds of all the mixtures and
                        clean sources
    Generates: The structure in output_dirpath where each unique id would
    have a corresponding folder with all the files in tensors or .txt for
    configs
            e.g. uid: 423a0105_1.2681_446o030n_-1.2681.wav -->
            output_dirpath/423a0105_1.2681_446o030n_-1.2681
                          mixture_wav (tensor)
                          clean_sources_wavs (tensor)
    """
    mixtures_dir = os.path.join(input_dirpath, 'mix')
    files = glob(mixtures_dir + '/*.wav')
    unique_ids = set([os.path.basename(f) for f in files])
    max_wav_samples = int(wav_timelength * fs)

    clean_folders = ['s'+str(n+1) for n in range(n_speakers)]

    write_data_func = write_data_wrapper_func(input_dirpath,
                                              clean_folders,
                                              max_wav_samples,
                                              output_dirpath,
                                              min_or_max=min_or_max)

    progress_display.progress_bar_wrapper(
        write_data_func,
        list(unique_ids),
        message='{}: Processing {} files...'.format(
            subset, len(unique_ids)))

def convert_wsj0mix_to_universal_dataset(input_dirpath,
                                         output_dirpath,
                                         wav_timelength):
    """! This function converts the wsj0mix dataset in a universal
    dataset where each sample has each own folder and all values are
    stored as Tensors for efficiency and in order to be loaded
    irrespective of the structure of the dataset.
    Args:
        input_dirpath: The path of a wsj0mix dataset e.g.
                       wsj0-mix/2speakers/wav8k/min (for mixes with
                       minimum length)
        output_dirpath: The path for storing the new dataset
                        (the directories would be created recursively)
        wav_timelength: The timelength in seconds of all the mixtures
                        and clean sources
    Intermediate:
        output_name: Default name would be infered as follows:
                     E.g. for wsj0-mix/2speakers/wav8k/min and for 4s
                     timelength:
                     it would be wsj0_2mix_8k_4s_min_preprocessed
    """
    output_name, fs, n_speakers, min_or_max = infer_output_name(
        input_dirpath, wav_timelength)

    root_out_dir = os.path.join(output_dirpath, output_name)

    subsets = os.listdir(input_dirpath)
    print("All the subsets are: {}".format(subsets))
    for subset in subsets:
        subset_input_dirpath = os.path.join(input_dirpath, subset)
        subset_output_dirpath = os.path.join(root_out_dir, subset)
        convert_subset(subset_input_dirpath,
                       subset_output_dirpath,
                       fs,
                       n_speakers,
                       wav_timelength,
                       subset=subset,
                       min_or_max=min_or_max)

    print("Dataset ready at: {}".format(root_out_dir))

def run_all():
    input_dirpath = os.path.join(WSJ0_MIX_2_8K_PATH, 'max')
    output_dirpath = WSJ0_MIX_2_8K_PREPROCESSED_BASE_P
    wav_timelength = 4
    convert_wsj0mix_to_universal_dataset(input_dirpath,
                                         output_dirpath,
                                         wav_timelength)

if __name__ == "__main__":
    run_all()


import sys
import argparse
from backend.camera_module_options import get_camera_module_name_options
from run_commands.command_options import get_instance_of_run_config_by_name, get_command_names

def main():
    raw_args = sys.argv
    parsed_args = parse_command_line_args()
    run_config = get_instance_of_run_config_by_name(parsed_args.command, parsed_args, raw_args)
    run_config.run()

def parse_command_line_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("command",
                        help="The name of the command you want to use",
                        choices=get_command_names())
    camera_module_name_options = get_camera_module_name_options()
    parser.add_argument("-c", "--camera_module",
                        help="The name of the camera module to use. Defaults to \"dummy\"",
                        choices=camera_module_name_options,
                        default=camera_module_name_options[0])
    parser.add_argument("-f", "--force_album",
                        help="If this is set, the application is limited to the specified album when running")
    return parser.parse_args()

if __name__ == '__main__':
    main()


import numpy as np
from sklearn.preprocessing import PolynomialFeatures

class LinearRegression:
    def __init__(self, data, labels, poly=1, include_bias=True, regularization=False) -> None:
        self.poly = poly
        self.include_bias = include_bias
        self.regularization = regularization

        # 更新data
        self.data = PolynomialFeatures(degree=self.poly, include_bias=self.include_bias).fit_transform(data)
        self.labels = labels.reshape(-1, 1)

        # 更新theta
        num_features = self.data.shape[1]
        self.theta = np.zeros((num_features, 1))

    def fit(self, lamda=None):
        if self.regularization:
            self.theta = np.linalg.inv(self.data.T.dot(self.data) + lamda * np.eye(self.data.shape[1])).dot(
                self.data.T).dot(self.labels)
        else:
            self.theta = np.linalg.inv(self.data.T.dot(self.data)).dot(self.data.T).dot(self.labels)
        return self.theta

    def train(self, alpha, num_iterations=500, lamda=None):
        cost_history = self.gradient_descent(alpha, num_iterations, lamda)
        return self.theta, cost_history

    def gradient_descent(self, alpha, num_iterations, lamda=None):
        cost_history = []
        for _ in range(num_iterations):
            cost = self.gradient_step(alpha, lamda)
            cost_history.append(cost)
        return cost_history

    def gradient_step(self, alpha, lamda=None):
        num_examples = self.data.shape[0]
        prediction = LinearRegression.hypothesis(self.data, self.theta)
        delta = prediction - self.labels
        theta = self.theta
        if self.regularization:
            theta[1:] = (theta[1:] - alpha * (1 / num_examples) * (np.dot(delta.T, self.data[:, 1:])).T
                         - alpha * lamda * theta[1:])
            theta[0] = theta[0] - alpha * (1 / num_examples) * np.sum(delta)
        else:
            theta = theta - alpha * (1 / num_examples) * (np.dot(delta.T, self.data)).T

        self.theta = theta

        cost = (1 / 2) * np.dot(delta.T, delta)
        return cost[0][0]

    @staticmethod
    def hypothesis(data, theta):
        predictions = np.dot(data, theta)
        return predictions

    def predict(self, data):
        data_processed = PolynomialFeatures(degree=self.poly, include_bias=self.include_bias).fit_transform(data)
        predictions = LinearRegression.hypothesis(data_processed, self.theta)
        return predictions


import asyncio
import time
import random

global_lock = asyncio.Semaphore(1)

async def run_cmd(cmd, timeout=None, task_id=None):
    async with global_lock:
        print(f"{task_id} subprocess start")
        start = time.time()
        proc = await asyncio.create_subprocess_shell("exec "+cmd)
        try:
            if timeout:
                await asyncio.wait_for(proc.wait(), timeout=timeout)
            else:
                await proc.wait()
            print(f'[{cmd!r} exited with {proc.returncode}]')
        except asyncio.TimeoutError as e:
            print(f'[{cmd!r} get timeout error]')
        except Exception as e:
            print(f'[{cmd!r} get uncaught exception {e}]')
        finally:
            if proc.returncode is None:
                print(f"{task_id} kill")
                proc.kill()
            end = time.time()
            print(f"{task_id} subprocess cost {end-start}")
        print(f"{task_id} subprocess end")

def cpu(task_id):
    print(f"{task_id} cpu start")
    for i in range(10000000):
        i = i + 1
    print(f"{task_id} cpu end")

async def io(task_id):
    print(f"{task_id} io start")
    await asyncio.sleep(0.05)
    print(f"{task_id} io end")

async def single_round(cmd, timeout=None, task_id=None):
    await run_cmd(cmd, timeout=timeout, task_id=task_id)
    await io(task_id)
    cpu(task_id)
    await io(task_id)

async def main(timeout):
    tasks = [single_round(f"sleep {random.random()*timeout}", timeout=timeout, task_id=random.randint(0, 1000)) for i in range(5)]
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(8))


p1 = str(input('Digite a frase: ')).strip().upper()
pal1 = p1.split()
jun1 = ''.join(pal1)
inv = jun1[::-1]
'''inv = ''
for letra in range(len(jun1) - 1, -1, -1):
    inv += jun1[letra]'''
print(f'O inverso de {jun1} é {inv}!')
if inv == jun1:
    print('É um palindromo!')
else:
    print('Não é um palindromo!')


# -*- encoding: utf-8 -*-
"""
hio.help.helping module

"""

import types
import functools

def copy_func(f, name=None):
    """
    Copy a function in detail.
    To change name of func provide name parameter

    functools to update_wrapper assigns and updates following attributes
    WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')
    WRAPPER_UPDATES = ('__dict__',)
    Based on
    https://stackoverflow.com/questions/6527633/how-can-i-make-a-deepcopy-of-a-function-in-python
    https://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function
    """
    g = types.FunctionType(f.__code__,
                           f.__globals__,
                           name=f.__name__,
                           argdefs=f.__defaults__,
                           closure=f.__closure__
                          )
    g = functools.update_wrapper(g, f)
    g.__kwdefaults__ = f.__kwdefaults__
    if name:
        g.__name__ = name
    return g


import gzip
import io
from urllib import parse

from env_test_env import *

try:
    import weed
except Exception as e:
    print(f'Could not import weed, err: {e}')
    import traceback

    traceback.print_exc()

# try:
#     import python_weed
# except Exception as e:
#     print(f'Could not import python_weed, err: {e}')
#     import traceback
#     traceback.print_exc()

# import weed
# print(weed)
from weed.conf import *
from weed.util import *
from weed.master import *
from weed.volume import *
from weed.operation import *
from weed.filer import WeedFiler

set_global_logger_level(logging.DEBUG)

WEED_MASTER_IP = 'localhost'
WEED_MASTER_PORT = 9333

# noinspection DuplicatedCode
def test_weed_master():
    master = WeedMaster()
    assert master.__repr__()

    # assign
    assign_key_dict = master.acquire_assign_info()
    assert isinstance(assign_key_dict, dict)
    assert 'fid' in assign_key_dict
    assert int(assign_key_dict['fid'].replace(',', ''), 16) > 0x001
    fid = assign_key_dict['fid']
    volume_id = fid.split(',')[0]
    assert len(volume_id) >= 1

    # lookup
    lookup_dict = master.lookup(fid)
    assert isinstance(lookup_dict, dict)
    assert 'locations' in lookup_dict
    locations_list = lookup_dict['locations']
    assert 'url' in locations_list[0]
    assert 'publicUrl' in locations_list[0]

    # vacuum
    vacuum_dict = master.vacuum()
    assert isinstance(vacuum_dict, dict)
    assert 'Topology' in vacuum_dict

    # status
    status_dict = master.get_status()
    assert isinstance(status_dict, dict)
    assert 'Topology' in status_dict

def test_weed_master_2():
    master = WeedMaster()
    assert master.__repr__()

    # assign
    wak = master.acquire_new_assign_key(10)
    assert isinstance(wak, dict)
    assert 'fid' in wak

    fid = wak['fid']

    fids = [fid] + [fid + '_' + str(i + 1) for i in range(10)]
    locations = []
    for i in fids:
        locations_dict = master.lookup(i)
        assert 'locations' in locations_dict
        locations.append(locations_dict['locations'])

    for i, l in enumerate(locations):
        if i < (len(l) - 1):
            assert l[i] == l[i + 1]

def test_weed_volume():
    volume = WeedVolume()
    assert volume.__repr__()

    # status
    status_dict = volume.get_status()
    assert isinstance(status_dict, dict)
    assert 'Version' in status_dict
    assert 'Volumes' in status_dict

def test_weed_assign_key():
    wak = WeedAssignKey()
    assert wak
    assert wak.__repr__()

def test_weed_assign_key_extended():
    wak = WeedAssignKeyExtended()
    assert wak
    assert wak.__repr__()

def test_weed_operation_response():
    wor = WeedOperationResponse()
    assert wor.status == Status.FAILED  # init is FAILED
    assert wor.__repr__()

# noinspection DuplicatedCode
def test_volume_put_get_delete_file():
    master = WeedMaster()
    assert master.__repr__()

    # assign
    assign_key_dict = master.get_assign_key()
    assert isinstance(assign_key_dict, dict)
    assert 'fid' in assign_key_dict
    assert int(assign_key_dict['fid'].replace(',', ''), 16) > 0x001
    fid = assign_key_dict['fid']
    volume_id = fid.split(',')[0]
    assert len(volume_id) >= 1

    # lookup
    lookup_dict = master.lookup(fid)
    assert isinstance(lookup_dict, dict)
    assert 'locations' in lookup_dict
    locations_list = lookup_dict['locations']
    assert 'url' in locations_list[0]
    assert 'publicUrl' in locations_list[0]

    volume_url = 'http://' + locations_list[0]['publicUrl']
    url = parse.urlparse(volume_url)
    assert url is not None

    # volume = WeedVolume(host=url_base.hostname, port=url_base.port)
    volume = master.get_volume(fid)
    status_dict = volume.get_status()
    assert isinstance(status_dict, dict)
    assert 'Version' in status_dict
    assert 'Volumes' in status_dict
    assert isinstance(status_dict['Volumes'], list)

    # file_to_post = './test_file_to_post_to_weed.xml'
    file_to_update = 'test_file_to_post_to_weed.xml'
    file_to_post = os.path.join(TEST_PATH, file_to_update)

    with open(file_to_post, 'wb') as tmp_file:
        # tmp_file.write(b"nonsense " * 1024 * 256)
        tmp_file.write(b"nonsense " * 8)
    put_result = volume.put_file(os.path.abspath(file_to_post), fid)
    assert 'error' not in put_result
    assert 'size' in put_result

    data = volume.get_file(fid)
    assert data
    # print data
    with open(file_to_post, 'rb') as fd:
        file_data = fd.read()
    assert data == file_data

    delete_result = volume.delete_file(fid)
    assert delete_result
    assert b'error' not in delete_result
    assert b'size' in delete_result

def test_accquire_new_fid():
    op = WeedOperation()
    fids = op.acquire_new_fids()
    assert isinstance(fids, (tuple, list))
    assert ',' in fids[0]
    count = 5
    fids = op.acquire_new_fids(count)
    for i in range(count):
        assert ',' in fids[i]

def test_put_a_file_with_fid():
    op = WeedOperation()
    fid = op.acquire_new_fids()[0]
    file_name = 'test_opensource_logo.jpg'
    fpath = os.path.join(TEST_PATH, file_name)
    assert op.put(open(fpath, 'rb'), fid, file_name)

def test_put_file():
    # test put_file in weed.util
    op = WeedOperation()
    # fid = ''
    file_name = 'test_opensource_logo.jpg'
    fpath = os.path.join(TEST_PATH, file_name)
    master = WeedMaster()
    fid_full_url = master.acquire_new_assign_key()['fid_full_url']
    print(('test_weed.py, fid_full_url: %s, fpath: %s' % (fid_full_url, fpath)))
    with open(fpath, 'rb') as f:
        g_logger.info('fp position: %d' % f.tell())
        g_logger.info('fp info: length: %d' % len(f.read()))
        f.seek(0)

        rsp = put_file(f, fid_full_url, file_name)
        assert rsp.ok()
        assert rsp.storage_size > 0
        fid = os.path.split(fid_full_url)[1]

    # read
    wor = op.crud_read(fid, file_name)
    assert wor
    content = wor.content
    assert len(content) > 3
    with open(fpath, 'rb') as _:
        original_content = _.read()
    assert content == original_content

def test_file_operations():
    op = WeedOperation()
    assert op.__repr__()

    # create
    # fid = ''
    file_name = 'test_opensource_logo.jpg'
    fpath = os.path.join(TEST_PATH, file_name)
    with open(fpath, 'rb') as f:
        rsp = op.crud_create(f, file_name)
        assert rsp.ok()
        assert len(rsp.fid) > 3
        fid = rsp.fid
        print(fid)
        assert len(fid) > 1
        assert os.path.split(op.get_fid_full_url(fid))[1] == fid
        assert rsp.fid.replace(',', '') > '01'
        assert rsp.url
        assert rsp.storage_size > 0

    # test exists
    assert op.exists(fid)
    assert op.exists(fid + 'wrong_fid') is False
    assert op.exists('wrong_fid') is False
    assert op.exists(fid.replace(',', '/')) is False

    # read
    content = op.get(fid, file_name).content
    content2 = op.get_content(fid, file_name)
    assert content == content2
    with open(fpath, 'rb') as f:
        original_content = f.read()
    assert content == original_content

    # update
    file_to_update = 'test_file_to_post_to_weed.xml'
    fpath = os.path.join(TEST_PATH, file_to_update)
    with open(fpath, 'rb+') as tmp_file:
        tmp_file.write(b"testdata " * 1024 * 256)
        tmp_file.seek(0)
        rsp = op.crud_update(tmp_file, fid)
        assert rsp
        fid_2 = rsp.fid
        assert fid_2 == fid
        assert rsp.fid.replace(',', '') > '01'
        assert rsp.url
        assert rsp.storage_size > 0

    # delete
    rsp = op.crud_delete(fid)
    assert rsp.storage_size > 0
    rsp = op.crud_delete('3,20323023')  # delete an unexisted file, should return False
    assert rsp.storage_size == 0

def test_weed_filer():
    wf = WeedFiler()
    assert wf.uri == 'localhost:27100'
    assert wf.url_base == 'http://localhost:27100'

    d = '/test/'
    new_d = '/test/new_dir/'

    # put f1
    f1_content = 'hello, how are you'
    f1 = io.StringIO(f1_content)
    f1_path = d + 'test.txt'
    assert wf.put(f1, f1_path) == f1_path

    # mkdir
    assert wf.mkdir(new_d)

    # put f2
    f2_content = 'hello, how are you?'
    f2 = io.StringIO(f2_content)
    f2_path = new_d + 'hello.txt'
    assert wf.put(f2, f2_path) == f2_path

    # list
    j = wf.list(new_d)
    assert isinstance(j, dict)
    # print(j)

    if 'Directory' in j:
        assert j['Directory'] == '/test/new_dir/'
    if 'Path' in j:
        assert j['Path'] == '/test/new_dir'
    assert j['Entries']
    entries = j['Entries']
    file_names = []
    for f in entries:
        if 'FullPath' in f:
            file_names.append(f['FullPath'].split('/')[-1])

    assert 'hello.txt' in file_names

    # get f1
    wf_get = wf.get(f1_path)
    assert int(wf_get['content_length']) > 0
    if 'gzip' in wf_get['content_type']:
        content_gz = wf_get['content']
        content = gzip.open(io.BytesIO(content_gz)).read()
        assert content == f1_content
    elif 'text' in wf_get['content_type']:
        assert wf_get['content'] == str.encode(f1_content)
    else:
        pass

    # delete f1, f2
    assert wf.delete(f1_path)
    assert wf.delete(f2_path)

if __name__ == '__main__':
    test_weed_master()
    test_weed_volume()
    test_file_operations()
    test_volume_put_get_delete_file()


import pygame
import cv2
import numpy as np

pygame.init()
dis = pygame.display.set_mode((400, 300))
pygame.display.update()
pygame.display.set_caption('Snake game by Suhani and Nidhi')

blue=(0,0,255)
red=(255,0,0)

# Create a VideoCapture object
cap = cv2.VideoCapture(0)  # 0 for the default camera, you can change this number for other cameras

# Check if the camera is opened correctly
if not cap.isOpened():
    print("Error: Could not open camera.")
    exit()

# Loop to continuously capture frames from the camera
while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Check if the frame was successfully captured
    if not ret:
        print("Error: Could not read frame.")
        break

    # Display the frame
    cv2.imshow('Camera Feed', frame)

    # Break the loop on pressing 'q'
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Release the VideoCapture object and close the OpenCV window
cap.release()
cv2.destroyAllWindows()

game_over = False
while not game_over:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game_over = True

    pygame.draw.rect(dis,blue,[200,150,10,10])
    pygame.display.update()

pygame.quit()
quit()


import pickle
import sys

import emcee
import numpy
import pandas as pd
from sklearn.neighbors import KernelDensity
from tqdm import tqdm

from dataloader import *
from linmix import LinMix
from multiprocessing import Pool
from scipy import integrate

np.random.seed(20200918)

def linear_model(x, slope, intercept):
    return slope * x + intercept

def log_lnl_chi2(theta, x, y, yerr):
    intercept, slope, scatter = theta
    ypred = linear_model(x, slope, intercept)
    var = (yerr ** 2) + (scatter ** 2)

    residual = y - ypred

    return -0.5 * np.sum(((residual ** 2) / var) + np.log(2 * np.pi * var))

def log_lnl_with_x_posterior(theta, x, y, yerr, x_kdes):
    """Similar to the chi-2 likelihood but we assume x is a random variable.

    Product of the joint probability of x and y which is an integral where P(y|x') is Gaussian
    with mean at y_hat(x') and variance yerr^2 + scatter^2 and P(x') is the posterior probability of x=x'
    integrated over dx'.
    """
    intercept, slope, scatter = theta

    def y_given_x_pdf(x, y, yerr):
        """Returns a single value, the log probability of y given x"""
        ypred = linear_model(x, slope, intercept)
        var = (yerr ** 2) + (scatter ** 2)
        return stats.norm(loc=ypred, scale=var).pdf(y)

    lnl = 0
    for i in range(x.shape[0]):
        x_pdf = lambda _x: np.exp(x_kdes[i].score(np.array([_x]).reshape(1, -1)))

        integrand = lambda _x: y_given_x_pdf(_x, y[i], yerr[i]) * x_pdf(_x)
        prob, _ = integrate.quad(integrand, 0, 20)
        lnl += np.log(prob)

    return lnl if np.isfinite(lnl) else -np.inf

def log_posterior(theta, x, y, yerr, log_lnl_func=log_lnl_chi2, log_prior_func=None):
    """Return the posterior probability.
    By default uniform prior is assumed on all free parameters
    """
    x_kdes = []
    for i in range(x.shape[0]):
        x_kde = KernelDensity().fit(x[i].reshape(len(x[i]), -1))
        x_kdes.append(x_kde)

    lnl = log_lnl_func(theta, x, y, yerr, x_kdes)
    if log_prior_func is not None:
        raise NotImplementedError

    return lnl

def run_x_posterior_mcmc(x, y, yerr, nwalkers=25, nsteps=5000, sampler_kwargs={}):
    """[summary]

    Args:
        x (array-like; n x m): Sample of the posterior distribution of sample size m
          for each of n rows.
        y (array-like; n x 1): Observed y values of size n.
    """
    if isinstance(x, pd.Series):
        x = x.values
    if isinstance(y, pd.Series):
        y = y.values
    if isinstance(yerr, pd.Series):
        yerr = yerr.values

    # Start with OLS solution as a guess
    xmean = np.mean(x, axis=1)
    slope_guess = stats.pearsonr(xmean, y)[0] * np.std(y) / np.std(xmean)
    intercept_guess = np.mean(y) - (slope_guess * np.mean(xmean))
    guess = np.array([intercept_guess, slope_guess, 1])
    ndim = len(guess)

    # Let the initial point sample from a Gaussian with standard deviation
    # that's 1/2 of the guess value such that about 95% of the initial position
    # starts within the range (-2*guess, 2*guess)
    pos = guess + ((guess / 2) * np.random.randn(nwalkers, ndim))
    sampler = emcee.EnsembleSampler(
        nwalkers,
        ndim,
        log_posterior,
        args=(x, y, yerr),
        kwargs=dict(log_lnl_func=log_lnl_with_x_posterior),
        **sampler_kwargs,
    )
    sampler.run_mcmc(pos, nsteps, progress=VERBOSE)

    theta_estimate = sampler.get_chain().reshape((nsteps * nwalkers, ndim)).mean(axis=0)
    if VERBOSE:
        print(
            f"ESTIMATED PARAMTERS\nSlope: {theta_estimate[1]}\nIntercept: {theta_estimate[0]}\nScatter: {theta_estimate[2]}"
        )
    return sampler

def run_chi2_mcmc(x, y, yerr, nwalkers=25, nsteps=5000, sampler_kwargs={}):
    # Start with OLS solution as a guess
    slope_guess = stats.pearsonr(x, y)[0] * np.std(y) / np.std(x)
    intercept_guess = np.mean(y) - (slope_guess * np.mean(x))
    guess = np.array([intercept_guess, slope_guess, 1])
    ndim = len(guess)

    # Let the initial point sample from a Gaussian with standard deviation
    # that's 1/2 of the guess value such that about 95% of the initial position
    # starts within the range (-2*guess, 2*guess)
    pos = guess + ((guess / 2) * np.random.randn(nwalkers, ndim))
    sampler = emcee.EnsembleSampler(
        nwalkers, ndim, log_posterior, args=(x, y, yerr), **sampler_kwargs
    )
    sampler.run_mcmc(pos, nsteps, progress=VERBOSE)

    theta_estimate = sampler.get_chain().reshape((nsteps * nwalkers, ndim)).mean(axis=0)
    if VERBOSE:
        print(
            f"ESTIMATED PARAMTERS\nSlope: {theta_estimate[1]}\nIntercept: {theta_estimate[0]}\nScatter: {theta_estimate[2]}"
        )
    return sampler

def run_linmix(age, age_err, hr, hr_err, linmix_kwargs={}, run_kwargs={}):
    """Estimated mock of Lee20 result."""

    lm = LinMix(x=age, y=hr, xsig=age_err, ysig=hr_err, **linmix_kwargs)
    lm.run_mcmc(silent=(not VERBOSE), **run_kwargs)

    results = pd.DataFrame({"slope": lm.chain["beta"], "intercept": lm.chain["alpha"]})
    return results

if __name__ == "__main__":
    VERBOSE = "-v" in sys.argv[1:]

    # # With summary statistics
    # data = pd.read_csv("data/HRvsAge_Median+STD+Bounds.csv")
    # age = data["Age_global"]
    # age_err = data["Age_global_err"]
    # hr = data["HR"]
    # hr_err = data["HR_err"]
    # results = run_linmix(age, age_err, hr, hr_err, linmix_kwargs=dict(K=2))
    # results.to_csv("results/linmix_1.csv", index=False)

    # # With real data
    # age_df = load_age_sample_from_mcmc_chains("campbell", mode="read")
    # hr_df = load_hr("campbell")
    # age_df, hr_df = clean_data(age_df, hr_df)

    # age = age_df["age"].groupby("snid").mean()
    # age_err = age_df["age"].groupby("snid").std()
    # hr = hr_df["hr"]
    # hr_err = hr_df["hr_err"]
    # results = run_linmix(age, age_err, hr, hr_err)
    # results.to_csv("results/linmix_2.csv", index=False)

    # # With real data but use the whole Age distribution
    # # Assume each age datapoint is a delta function with zero variance
    # age_df = load_age_sample_from_mcmc_chains("campbell", mode="read")
    # hr_df = load_hr("campbell")
    # age_df, hr_df = clean_data(age_df, hr_df)

    # df = age_df.merge(hr_df, on="snid", how="left")
    # age = df["age"]
    # age_err = np.zeros(len(age))
    # hr = df["hr"]
    # hr_err = df["hr_err"]

    # with Pool() as pool:
    #     sampler = run_chi2_mcmc(
    #         age, hr, hr_err, nsteps=1000, sampler_kwargs=dict(pool=pool)
    #     )
    # with open("results/chi2-mcmc-sampler.pkl", "wb") as f:
    #     pickle.dump(sampler.get_chain(), f)

    # results = run_linmix(age, age_err, hr, hr_err, linmix_kwargs=dict(K=1))
    # results.to_csv("results/linmix_3.csv", index=False)

    # Create all possible slope given each Age from its posterior sample
    # age_df = load_age_sample_from_mcmc_chains("campbell", mode="read")
    # hr_df = load_hr("campbell")
    # age_df, hr_df = clean_data(age_df, hr_df)

    # slopes = []
    # intercepts = []
    # for i in tqdm(range(1000), total=1000):
    #     age = age_df.groupby("snid").sample(1)["age"]
    #     hr = hr_df["hr"]
    #     hr_err = hr_df["hr_err"]

    #     with Pool() as pool:
    #         sampler = run_chi2_mcmc(
    #             age,
    #             hr,
    #             hr_err,
    #             nsteps=3000,
    #             nwalkers=10,
    #             sampler_kwargs=dict(pool=pool),
    #         )

    #     intercept, slope, _ = sampler.get_chain(flat=True, discard=1000).mean(axis=0)
    #     intercepts.append(intercept)
    #     slopes.append(slope)

    # pd.DataFrame({"slope": slopes, "intercept": intercepts}).to_csv(
    #     "results/chi2-mcmc-sampler.csv"
    # )

    # slopes = []
    # intercepts = []
    # for i in tqdm(range(1000)):
    #     age = age_df.groupby("snid").sample(1)["age"]
    #     age_err = np.zeros(len(age))
    #     hr = hr_df["hr"]
    #     hr_err = hr_df["hr_err"]

    #     results = run_linmix(age, age_err, hr, hr_err, linmix_kwargs=dict(K=2))

    #     slopes.append(results["slope"].mean())
    #     intercepts.append(results["intercept"].mean())
    # pd.DataFrame({"slope": slopes, "intercept": intercepts}).to_csv(
    #     "results/linmix-mcmc-sampler.csv"
    # )

    age_df = load_age_sample_from_mcmc_chains("campbell", mode="read")
    hr_df = load_hr("campbell")
    age_df, hr_df = clean_data(age_df, hr_df)

    age_matrix = np.array(list(age_df["age"].groupby("snid").agg(list)))

    with Pool() as pool:
        sampler = run_x_posterior_mcmc(
            age_matrix,
            hr_df["hr"],
            hr_df["hr_err"],
            nsteps=20,
            sampler_kwargs=dict(pool=pool),
        )

    np.savetxt("results/x_posterior_mcmc.csv", sampler.get_chain(flat=True), delimiter=",")


import csv
import io
import os

from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand

from reviews.models import Category, Comment, Genre, Review, Title

User = get_user_model()

DATAFOLDER = os.getcwd() + '//static//data//'

class Command(BaseCommand):
    help = "Импортирует информацию в БД из csv файлов в папке data"

    def handle(self, *args, **options):
        self.import_genres()
        self.import_categories()
        self.import_users()
        self.import_titles()
        self.import_reviews()

    def import_genres(self):
        with io.open(DATAFOLDER + 'genre.csv', encoding='utf-8') as f:
            csv_file = csv.DictReader(f)
            for row in csv_file:
                Genre.objects.get_or_create(name=row['name'], slug=row['slug'])

    def import_categories(self):
        with io.open(DATAFOLDER + 'category.csv', encoding='utf-8') as f:
            csv_file = csv.DictReader(f)
            for row in csv_file:
                Category.objects.get_or_create(name=row['name'],
                                               slug=row['slug'])

    def import_users(self):
        with io.open(DATAFOLDER + 'users.csv', encoding='utf-8') as f:
            csv_file = csv.DictReader(f)
            for row in csv_file:
                User.objects.get_or_create(id=row['id'],
                                           username=row['username'],
                                           email=row['email'],
                                           role=row['role'],
                                           bio=row['bio'],
                                           first_name=row['first_name'],
                                           last_name=row['last_name'])

    def import_titles(self):
        with io.open(DATAFOLDER + 'titles.csv', encoding='utf-8') as f:
            csv_file = csv.DictReader(f)
            for row in csv_file:
                Title.objects.get_or_create(
                    name=row['name'],
                    year=row['year'],
                    category=Category.objects.get(id=row['category']))

        with io.open(DATAFOLDER + 'genre_title.csv', encoding='utf-8') as f:
            csv_file = csv.DictReader(f)
            for row in csv_file:
                genre = Genre.objects.get(id=row['genre_id'])
                Title.objects.get(id=row['title_id']).genre.add(genre)

    def import_reviews(self):
        with io.open(DATAFOLDER + 'review.csv', encoding='utf-8') as f:
            csv_file = csv.DictReader(f)
            for row in csv_file:
                title = Title.objects.get(id=row['title_id'])
                author = User.objects.get(id=row['author'])
                Review.objects.get_or_create(title=title,
                                             text=row['text'],
                                             author=author,
                                             score=row['score'],
                                             pub_date=row['pub_date'])

    def import_comments(self):
        with io.open(DATAFOLDER + 'comments.csv', encoding='utf-8') as f:
            csv_file = csv.DictReader(f)
            for row in csv_file:
                review = Review.objects.get(id=row['review_id'])
                author = User.objects.get(id=row['author'])
                Comment.objects.get_or_create(review=review,
                                              text=row['text'],
                                              author=author,
                                              pub_date=row['pub_date'])


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import _init_paths

import os

import torch
import torch.utils.data
from opts import opts
from models.model import create_model, load_model, save_model
from models.data_parallel import DataParallel
from logger import Logger
from datasets.dataset_factory import get_dataset
from trains.train_factory import train_factory

def main(opt):
  #torch.manual_seed(opt.seed)
  torch.backends.cudnn.benchmark = not opt.not_cuda_benchmark and not opt.test

  if opt.task != 'reweight_paper':
    Dataset = get_dataset(opt.dataset, opt.task)
  else:
    #python main_ep.py reweight_paper --load_model ../models/best_resmeta_50/model_last.pth  --fewshot_data basenovel_fewshot --master_batch_size 1 --batch_size 8 --head_conv 0 --cat_spec_wh --lr 1e-5 --gpus 0,1,2,3,4,5,6,7,8
    Dataset = get_dataset('coco_mixed', 'mixdet')

  opt = opts().update_dataset_info_and_set_heads(opt, Dataset)
  print(opt)

  logger = Logger(opt)

  os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str
  opt.device = torch.device('cuda' if opt.gpus[0] >= 0 else 'cpu')

  print('Creating model...')
  if opt.task != 'reweight_paper':
    model = create_model(opt.arch, opt.heads, opt.head_conv, extras={'learnable': opt.learnable, 'metasize': opt.metasize})
  else:
    print(100*'=')
    print(opt.heads, opt.head_conv)
    print(Dataset.num_classes)
    model = create_model('resmeta_50', opt.heads, opt.head_conv, extras={'learnable': opt.learnable, 'metasize': opt.metasize})

  if opt.task != 'reweight_paper':
    optimizer = torch.optim.Adam(model.meta_params, opt.lr)
  else:
    optimizer = torch.optim.Adam(model.parameters(), opt.lr)

  start_epoch = 0
  if opt.task != 'reweight_paper':
    if opt.load_model != '':
      model, optimizer, start_epoch = load_model(
        model, opt.load_model, optimizer, opt.resume, opt.lr, opt.lr_step)
  else:
    if opt.load_model != '':
      l = torch.load(opt.load_model)['state_dict']
      mk,uk = model.load_state_dict(l, strict=False)
      print('Missing Keys for model:    ',mk)
      print('')
      print('Unknown Keys for model:    ',uk)

  if opt.task != 'reweight_paper' and opt.task != 'ctdet':
    Trainer = train_factory[opt.task]
  else:
    Trainer = train_factory['epdet']

  trainer = Trainer(opt, model, optimizer)
  trainer.set_device(opt.gpus, opt.chunk_sizes, opt.device)

  print('Setting up data...')
  if opt.task != 'reweight_paper' and opt.task != 'ctdet':
    val_loader = torch.utils.data.DataLoader(
        Dataset(opt, 'val', base=True), #the 20 left-out classes are only for testing
        batch_size=1,
        shuffle=False,
        num_workers=1,
        pin_memory=True
    )
    train_loader = torch.utils.data.DataLoader(
        Dataset(opt, 'train', base=True),
        batch_size=opt.batch_size,
        shuffle=True,
        num_workers=opt.num_workers,
        pin_memory=True,
        drop_last=True
    )
  else:
    val_loader = torch.utils.data.DataLoader(
        Dataset(opt, 'val'),
        batch_size=1,
        shuffle=False,
        num_workers=1,
        pin_memory=True
    )

    train_loader = torch.utils.data.DataLoader(
        Dataset(opt, 'train'),
        batch_size=opt.batch_size,
        shuffle=True,
        num_workers=opt.num_workers,
        pin_memory=True,
        drop_last=True
    )

  if opt.task != 'reweight_paper':
    if opt.load_basemodel:
      print('=====> Loading pretrained models')
      l = torch.load(opt.load_basemodel)['state_dict']
      mk,uk = model.load_state_dict(l, strict=False)
      print('Missing Keys for base model:    ',mk)
      print('')
      print('Unknown Keys for base model:    ',uk)

    if opt.load_metamodel:
      print('=====> Loading meta-pretrained models')
      l = torch.load(opt.load_metamodel)['state_dict']
      mk,uk = model.rw.load_state_dict(l, strict=False)
      print('Missing Keys for meta model:    ',mk)
      print('')
      print('Unknown Keys for meta model:    ',uk)

  print('Starting training...')
  best = 1e10
  for epoch in range(start_epoch + 1, opt.num_epochs + 1):

    # hardcoded warmpup
    if opt.task != 'reweight_paper':
      if epoch == 1:
        lr = opt.lr/100
        print('**** Warmup LR to', lr)
        for param_group in optimizer.param_groups:
            param_group['lr'] = lr
      elif epoch == 2:
        lr = opt.lr
        print('**** Warmup finished to', lr)
        for param_group in optimizer.param_groups:
            param_group['lr'] = lr

    mark = epoch if opt.save_all else 'last'
    log_dict_train, _ = trainer.train(epoch, train_loader)
    logger.write('epoch: {} |'.format(epoch))
    for k, v in log_dict_train.items():
      logger.scalar_summary('train_{}'.format(k), v, epoch)
      logger.write('{} {:8f} | '.format(k, v))
    if opt.val_intervals > 0 and epoch % opt.val_intervals == 0:
      save_model(os.path.join(opt.save_dir, 'model_{}.pth'.format(mark)),
                 epoch, model, optimizer)
      with torch.no_grad():
        log_dict_val, preds = trainer.val(epoch, val_loader)
      for k, v in log_dict_val.items():
        logger.scalar_summary('val_{}'.format(k), v, epoch)
        logger.write('{} {:8f} | '.format(k, v))
      if log_dict_val[opt.metric] < best:
        best = log_dict_val[opt.metric]
        save_model(os.path.join(opt.save_dir, 'model_best.pth'),
                   epoch, model)
    else:
      save_model(os.path.join(opt.save_dir, 'model_last.pth'),
                 epoch, model, optimizer)
    logger.write('\n')
    if epoch in opt.lr_step:
      save_model(os.path.join(opt.save_dir, 'model_{}.pth'.format(epoch)),
                 epoch, model, optimizer)
      lr = opt.lr * (0.1 ** (opt.lr_step.index(epoch) + 1))
      print('Drop LR to', lr)
      for param_group in optimizer.param_groups:
          param_group['lr'] = lr
  logger.close()

if __name__ == '__main__':
  opt = opts().parse()
  main(opt)


import argparse
import sys
from pathlib import Path
from typing import Union

from config.settings import get_config

DATA_SRC = 'data_src'
DATA_DST = 'data_dst'

ALIGNED = 'aligned'
ALIGNED_DEBUG = 'aligned_debug'
ALIGNED_CONVERT = 'aligned_convert'
MANUAL_EXTRACT = 'manual_extract'

def get_workspace_structure():
    """Create a workspace directory structure template"""
    return {
        DATA_SRC: [ALIGNED],
        DATA_DST: [ALIGNED_CONVERT, ALIGNED_DEBUG, ALIGNED, MANUAL_EXTRACT]
    }

def get_base_workspaces_path() -> Path:
    config = get_config()
    return config.WORKSPACES_BASE

def clear_directory(target: Path):
    # don't try to delete root!
    assert target != target.parent

    children = list(target.rglob("*"))
    # children

    response = input(
        f"{target} already exists, all {len(children)} files in this directory will be deleted. (Y|N)")
    if response != 'Y':
        print("Quitting")
        sys.exit()

    directories = []
    for child in children:
        if child.is_file():
            child.unlink()
        elif child.is_dir():
            directories.append(child)

    for directory in reversed(directories):
        directory.rmdir()

def create_workspace(workspace_name):
    base = get_base_workspaces_path()

    workspace_name = Path(workspace_name)
    new_workspace = base / workspace_name.name

    # ensure our target is a level below the base directory
    assert len(new_workspace.parts) > len(base.parts)

    if new_workspace.is_dir():
        clear_directory(new_workspace)
    if new_workspace.is_file():
        raise FileExistsError()

    new_workspace.mkdir(exist_ok=True)

    data_src = new_workspace / DATA_SRC
    data_dst = new_workspace / DATA_DST

    data_dst.mkdir()
    data_src.mkdir()

    project_structure = get_workspace_structure()

    for top_level_key in project_structure:
        sub_folders = project_structure[top_level_key]
        for folder in sub_folders:
            (new_workspace / top_level_key / folder).mkdir()

def makedir_iterable_structure(structure: Union[dict, list], current_base):
    """Take an iterable structure and produce directories from it"""
    if structure:
        for top_level_key in structure:
            recur_mkdir(structure, top_level_key, current_base)

def recur_mkdir(structure: Union[dict, list, str], current_entry, current_base: Path):
    """Recursively traverse the template structure and create directories"""

    if current_entry and isinstance(current_entry, str):
        current_base /= current_entry
        current_base.mkdir()
    else:
        return makedir_iterable_structure(current_entry, current_base)

    if isinstance(structure, dict):
        next_structure = structure.get(current_entry)
        if isinstance(next_structure, (list, dict)):
            return makedir_iterable_structure(next_structure, current_base)
        else:
            return recur_mkdir([], next_structure, current_base)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('workspace_name')
    create_workspace(parser.parse_args().workspace_name)


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if root== None:
            return []

        level_list =[]
        curr_level = [root]
        level_list.append([root.val])

        while curr_level:
            next_level=[]
            next_level_vals=[]

            for node in curr_level:
                if node.left!=None:
                    next_level.append(node.left)
                    next_level_vals.append(node.left.val)
                    #print(node.left.val)
                if node.right!=None:
                    next_level.append(node.right)
                    next_level_vals.append(node.right.val)
                    #print(node.right.val)
            if next_level:
                level_list.append(next_level_vals)
            curr_level = next_level

        return level_list

Binary Tree Level Order Traversal/Binary Tree Level Order Traversal.py


"""
    1st: bipartite

    Time    O(RC)
    Space   O(RC)
    2265 ms, faster than 100.00%
"""

class Solution:
    def minimumOperations(self, grid: List[List[int]]) -> int:
        R, C = len(grid), len(grid[0])
        dirs = [(0, -1), (0, 1), (-1, 0), (1, 0)]
        seen = set()

        def dfs(i, j, color):

            blackWhite = [0, 0]
            if i < 0 or i == R or j < 0 or j == C:
                return blackWhite

            if grid[i][j] == 0:
                return blackWhite

            key = (i, j)
            if key in seen:
                return blackWhite
            seen.add(key)

            blackWhite[color] += 1
            for di, dj in dirs:
                _i = i + di
                _j = j + dj
                r = dfs(_i, _j, (color+1) % 2)  # bipartite
                blackWhite[0] += r[0]
                blackWhite[1] += r[1]
            return blackWhite

        res = 0
        for i in range(R):
            for j in range(C):
                if grid[i][j] == 0:
                    continue
                if (i, j) in seen:
                    continue
                res += min(dfs(i, j, 0))
        return res


'''from PIL import Image
img = Image.open('images/letters/set1/blue/75.png', 'r')
img = img.convert("RGBA")
img_w, img_h = img.size
background = Image.open('../test.png', 'r')#Image.new('RGBA', (1440, 900), (255, 255, 225, 225))
bg_w, bg_h = background.size
offset = ((bg_w - img_w) // 2, (bg_h - img_h) // 2)
background.paste(img, offset)
background.save('out3.png')
'''
import textwrap
import os
from PIL import Image

def textlist(text): # converts text into list of strings
	list1 = text.split("<br />")

	textlist = []
	for text in list1:
		textlist= textlist + textwrap.wrap(text,width = 33)
	return(textlist)

scale = 15
xoff = 42
yoff = 40
line_spacing = 23

letter_spacing = 10
max_lines = 18

inputtext = 'test.text'
f = open(inputtext, "r")
text = textlist(f.read())
f.close

letterlist = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.?{}()-_+=*&^%@<>|/'\"\\;:"

#for char in text:
filename = 'images/letters/set1/blue/{}.png'
bg_file = 'images/bg/ruled.jpg'
save_name = 'page{}.png'
bg = Image.open(bg_file, 'r')
bg_w, bg_h = bg.size
text_img = Image.new('RGBA', (bg_w, bg_h), (0, 0, 0, 0))
text_img.paste(bg, (0,0))
image_list = []

i = 0
j = -1
img_num = 0

#str1 = '\n'
#str1 += str1.join(text)
for str1 in text:
	print(str1)
	i = 0
	j +=1
	for letts in str1:
		if(letts in letterlist):
			if i*letter_spacing < bg_w - xoff - 2*scale:
				pass
			else:
				i = 0
				j += 1

			if j > max_lines:
				text_img.save(save_name.format(img_num), format="png")
				text_img = text_img.convert('RGB')#.resize((2480, 3508), Image. ANTIALIAS)
				image_list.append(text_img)
				img_num += 1
				i = 0
				j = 0
				text_img = Image.new('RGBA', (bg_w, bg_h), (0, 0, 0, 0))
				text_img.paste(bg, (0,0))
			if ord(letts) == 32 and i==0:
				pass
			else:
				try:
					ironman = Image.open(filename.format(ord(letts)), 'r').resize((2*scale,3*scale))
				except:
					ironman = Image.open(filename.format(ord(letts)), 'r').resize((2*scale,3*scale))
				text_img.paste(ironman, (i*letter_spacing + xoff,j*line_spacing + yoff), mask=ironman)

			i += 1

text_img.save(save_name.format(img_num), format="png")
text_img = text_img.convert('RGB')#.resize((2480, 3508), Image. ANTIALIAS)
image_list.append(text_img)

image_list[0].save('imagelist.pdf',save_all=True, append_images=image_list[1:])


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

import os, sys
import platform
import fileinput
import shutil

path = os.path.dirname(os.path.abspath(__file__))
pathToTemplate = path+'/../template/'
pathToReducedModel = path+'/../../../morlib/'
sys.path.insert(0,path+'/../../../')

from mor.utility import utility as u

slash = '/'
if "Windows" in platform.platform():
    slash ='\\'

class PackageBuilder():
    """
    **Contain all the parameters & functions related to building the package**
    """
    def __init__(self,outputDir,packageName = None ,addToLib = False):

        self.outputDir = outputDir
        self.meshes = []

        self.addToLibBool = addToLib

        if packageName :
            self.packageName = 'reduced_'+packageName

            if os.path.isdir(pathToReducedModel+self.packageName) and addToLib:
                raise Exception('A Package named %s already exist in the MOR lib !\nPlease choose another name for this new package' % packageName)

        self.dataDir = self.outputDir+slash+'data'+slash
        self.debugDir = self.outputDir+slash+'debug'+slash
        self.meshDir = self.outputDir+slash+'mesh'+slash

    def checkNodeNbr(self,modeFileName):
        '''
        '''

        nbrOfModes = -1
        try:

            with open(self.dataDir+modeFileName, "r") as myFile:
                lineSplit = myFile.readline().strip().split();
                nbrOfModes = lineSplit[1]

        except IOError:
            print("IOError : there is no "+self.dataDir+modeFileName)

        except:
            raise

        return int(nbrOfModes)

    def cleanStateFile(self,periodSaveGIE,stateFileName):
        '''
        '''

        counter = 1
        for line in fileinput.input(self.debugDir+stateFileName, inplace=True):
            if line.find('T=') != -1:
                line = 'T= '+str(periodSaveGIE*counter)+'\n'
                print("%s" % line, end="")
                counter += 1
            else : print(line, end="")

    def copyAndCleanState(self,results,periodSaveGIE,stateFileName,velocityFileName=None,gie=None):
        '''
        '''

        u.checkExistance(self.debugDir)

        if os.path.exists(self.debugDir+stateFileName):
            os.remove(self.debugDir+stateFileName)
        if velocityFileName and os.path.exists(self.debugDir+velocityFileName):
            os.remove(self.debugDir+velocityFileName)
        if gie:
            for fileName in gie :
                if os.path.exists(self.debugDir+fileName):
                    os.remove(self.debugDir+fileName)

        for res in results:
            u.copyFileIntoAnother(res["directory"]+slash+"stateFile.state",self.debugDir+stateFileName)

            if velocityFileName is not None:
                u.copyFileIntoAnother(res["directory"]+"/stateFileVelocity.state",self.debugDir+velocityFileName)
            if gie:
                for fileName in gie :
                    u.copyFileIntoAnother(res["directory"]+slash+fileName,self.debugDir+fileName)

        self.cleanStateFile(periodSaveGIE,stateFileName)

    def finalizePackage(self,result):
        '''
        '''

        shutil.move(result['directory']+slash+self.packageName+'.py', self.outputDir+slash+self.packageName+'.py')

        with open(result['directory']+slash+'meshFiles.txt', "r") as meshFiles:
            self.meshes = meshFiles.read().splitlines()

        u.checkExistance(self.meshDir)

        if self.meshes:
            for mesh in self.meshes:
                u.copy(mesh, self.meshDir)

        if self.addToLibBool :

            self.addToLib()

    def addToLib(self):
        '''
        '''

        u.copy(self.outputDir, pathToReducedModel+self.packageName+slash)

        try:
            with open(pathToTemplate+'myInit.txt', "r") as myfile:
                myInit = myfile.read()

                myInit = myInit.replace('MyReducedModel',self.packageName[0].upper()+self.packageName[1:])
                myInit = myInit.replace('myReducedModel',self.packageName)

                with open(pathToReducedModel+self.packageName+slash+'__init__.py', "a") as logFile:
                    logFile.write(myInit)

                # print(myInit)

            for line in fileinput.input(pathToReducedModel+'__init__.py', inplace=True):
                if line.find('__all__') != -1:
                    if line.find('[]') != -1:
                        line = line[:-2]+"'"+self.packageName+"']"'\n'

                    else:
                        line = line[:-2]+",'"+self.packageName+"']"'\n'
                    print("%s" % line),

                else : print(line),

        except:
            print ("Unexpected error:", sys.exc_info()[0])
            raise


#!/bin/python3

import math
import os
import random
import re
import sys

#
# Complete the 'bomberMan' function below.
#
# The function is expected to return a STRING_ARRAY.
# The function accepts following parameters:
#  1. INTEGER n
#  2. STRING_ARRAY grid
#

def bomberMan(n, grid):
    grid_dict = {(x, y): 3 if elem == 'O' else '.'
                 for y, line in enumerate(grid)
                 for x, elem in enumerate(line)}

    max_x = max(key[0] for key in grid_dict.keys())
    max_y = max(key[1] for key in grid_dict.keys())

    adj_offsets = [(0, 1), (0, -1), (1, 0), (-1, 0)]

    def remove_adj_bombs(grid, pos):
        x, y = pos
        for (dx, dy) in adj_offsets:
            if (x + dx, y + dy) in grid:
                grid[(x + dx, y + dy)] = "."

        return grid

    def grid_to_str(grid):
        grid_str = ""
        for y in range(max_y + 1):
            for x in range(max_x + 1):
                grid_str += grid_dict[(x, y)] if grid_dict[(x, y)] == "." else "O"
            grid_str += "\n"

        return grid_str

    def get_grid_at_step_n(grid, n):
        for step in range(2, n + 1):
            if step % 2 == 0:
                for pos, elem in grid.items():
                    if elem == ".":
                        grid[pos] = step + 3

            if step % 2 == 1:
                new_grid = grid.copy()
                for pos, elem in grid.items():
                    if elem == step:
                        new_grid[pos] = "."
                        new_grid = remove_adj_bombs(new_grid, pos)
                grid = new_grid
        return grid

    if n < 10:
        start_time = 2
    else:
        grid_dict = get_grid_at_step_n(grid_dict, 3)
        num_full_cycles_to_skip = (n - 3) // 4
        start_time = 3 + 4 * num_full_cycles_to_skip + 1  # continue the process from this step

    for step in range(start_time, n + 1):
        if step % 2 == 0:
            for pos, elem in grid_dict.items():
                if elem == ".":
                    grid_dict[pos] = step + 3

        if step % 2 == 1:
            new_grid = grid_dict.copy()
            for pos, elem in grid_dict.items():
                if elem <= step:
                    new_grid[pos] = "."
                    new_grid = remove_adj_bombs(new_grid, pos)

            grid_dict = new_grid

    ret_arr = []
    for y in range(max_y + 1):
        row_str = ""
        for x in range(max_x + 1):
            row_str += grid_dict[(x, y)] if grid_dict[(x, y)] == "." else "O"
        ret_arr.append(row_str)

    return ret_arr

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    first_multiple_input = input().rstrip().split()

    r = int(first_multiple_input[0])

    c = int(first_multiple_input[1])

    n = int(first_multiple_input[2])

    grid = []

    for _ in range(r):
        grid_item = input()
        grid.append(grid_item)

    result = bomberMan(n, grid)

    fptr.write('\n'.join(result))
    fptr.write('\n')

    fptr.close()

Algorithms/02 - Implementation/The Bomberman Game.py


from django.contrib.auth import get_user_model
from django.db import models

User = get_user_model()

class Tag(models.Model):
    name = models.CharField(verbose_name='Имя тэга',
                            max_length=200, unique=True)
    color = models.CharField(verbose_name='Цвет тэга',
                             max_length=7, unique=True)
    slug = models.SlugField(verbose_name='Слаг', max_length=200,
                            unique=True)

    def __str__(self):
        return f'{self.name} цвет {self.color}'

    class Meta:
        verbose_name = 'Тэг'
        verbose_name_plural = 'Тэги'
        ordering = ('name', )

class Ingredient(models.Model):
    name = models.CharField(verbose_name='Имя ингредиента', max_length=150)
    measurement_unit = models.CharField(
        verbose_name='Единицы измерения', max_length=10)

    def __str__(self):
        return f'{self.name} {self.measurement_unit}'

    class Meta:
        verbose_name = 'Ингредиент'
        verbose_name_plural = 'Ингредиенты'

class Recipe(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE,
                               verbose_name='Автор рецепта',
                               related_name='recipes')
    name = models.CharField(max_length=200, verbose_name='Название рецепта')
    text = models.TextField(verbose_name='Текст рецепта')
    cooking_time = models.PositiveSmallIntegerField()
    image = models.ImageField(
        verbose_name='Фото блюда', upload_to='recipe_images/',
        default=None, null=True)
    tags = models.ManyToManyField(
        Tag, through='TagRecipe')
    ingredients = models.ManyToManyField(
        Ingredient, through='IngredientRecipe', through_fields=('recipe',
                                                                'ingredient'))
    pub_date = models.DateTimeField(
        verbose_name='Дата публикации',
        auto_now_add=True,
        editable=False,
    )

    def __str__(self) -> str:
        return f'{self.name}. Автор: {self.author}'

    class Meta:
        verbose_name = 'Рецепт'
        verbose_name_plural = 'Рецепты'
        ordering = ('-pub_date',)

class IngredientRecipe(models.Model):
    ingredient = models.ForeignKey(
        Ingredient, on_delete=models.CASCADE, verbose_name='Ингредиент')
    recipe = models.ForeignKey(
        Recipe, on_delete=models.CASCADE, verbose_name='Рецепт')
    amount = models.PositiveIntegerField(
        verbose_name='Количество ингридиентов')

    def __str__(self):
        return f'{self.ingredient} {self.recipe}'

    class Meta:
        verbose_name = 'Ингредиент рецепта'
        verbose_name_plural = 'Ингредиенты рецепта'

class TagRecipe(models.Model):
    tag = models.ForeignKey(Tag, on_delete=models.CASCADE,
                            verbose_name='Тэги рецепта')
    recipe = models.ForeignKey(
        Recipe, on_delete=models.CASCADE, verbose_name='Рецепт')

    def __str__(self):
        return f'{self.tag} {self.recipe}'

    class Meta:
        verbose_name = 'Ингредиент рецепта'
        verbose_name_plural = 'Ингредиенты рецепта'

class FavoriteRecipe(models.Model):
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='favorite',
        verbose_name='Пользователь'
    )
    favorite_recipe = models.ForeignKey(
        Recipe,
        on_delete=models.CASCADE,
        related_name='favorite_recipe',
        verbose_name='Избранный рецепт'
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=('user', 'favorite_recipe'),
                name='unique favourite')]
        verbose_name = 'Избранное'
        verbose_name_plural = 'Избранные'
        ordering = ('id',)

    def __str__(self):
        return (f'Пользователь: {self.user.username}'
                f'рецепт: {self.favorite_recipe.name}')

class ShoppingCart(models.Model):
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='shopping_cart',
        verbose_name='Пользователь'
    )
    recipe = models.ForeignKey(
        Recipe,
        on_delete=models.CASCADE,
        related_name='recipe_shopping_cart',
        verbose_name='Рецепт'
    )

    class Meta:
        ordering = ('id',)
        constraints = [
            models.UniqueConstraint(
                fields=('user', 'recipe'),
                name='unique recipe in shopping cart')]
        verbose_name = 'Список покупок'
        verbose_name_plural = 'Список покупок'

    def __str__(self):
        return (f'Пользователь: {self.user.username},'
                f'рецепт в списке: {self.recipe.name}')


import re

text = r'(2(3AC)A)'
#text = r'(15a)B'

subgroup_pattern = r"[(]\d+\w+[)]"
text_pattern = r"\D+"
count_pattern = r"\d+"
result = re.finditer(subgroup_pattern, text)
while '(' in text:
  for x in result:
    a, b, subgroup = x.start(), x.end(), x.group()
  subtext = text[a+1:b-1]
  count = int(re.search(count_pattern, subtext).group(0))
  sub_text = re.search(text_pattern, subtext).group(0)
  replace_text = sub_text * count
  text = text.replace(subgroup, replace_text)
  result = re.finditer(subgroup_pattern, text)
print(text)