import os.path

import pytest
from botocore.exceptions import ClientError

from localstack.testing.aws.cloudformation_utils import (
    load_template_file,
    load_template_raw,
    render_template,
)
from localstack.testing.aws.util import is_aws_cloud
from localstack.testing.pytest import markers
from localstack.utils.strings import short_uid
from localstack.utils.sync import ShortCircuitWaitException, poll_condition, wait_until
from tests.aws.services.cloudformation.api.test_stacks import (
    MINIMAL_TEMPLATE,
)

@markers.aws.validated
def test_create_change_set_without_parameters(
    cleanup_stacks, cleanup_changesets, is_change_set_created_and_available, aws_client
):
    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"

    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
    )
    response = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=change_set_name,
        TemplateBody=load_template_raw(template_path),
        ChangeSetType="CREATE",
    )
    change_set_id = response["Id"]
    stack_id = response["StackId"]
    assert change_set_id
    assert stack_id

    try:
        # make sure the change set wasn't executed (which would create a topic)
        topics = aws_client.sns.list_topics()
        topic_arns = list(map(lambda x: x["TopicArn"], topics["Topics"]))
        assert not any("sns-topic-simple" in arn for arn in topic_arns)
        # stack is initially in REVIEW_IN_PROGRESS state. only after executing the change_set will it change its status
        stack_response = aws_client.cloudformation.describe_stacks(StackName=stack_id)
        assert stack_response["Stacks"][0]["StackStatus"] == "REVIEW_IN_PROGRESS"

        # Change set can now either be already created/available or it is pending/unavailable
        wait_until(
            is_change_set_created_and_available(change_set_id), 2, 10, strategy="exponential"
        )
        describe_response = aws_client.cloudformation.describe_change_set(
            ChangeSetName=change_set_id
        )

        assert describe_response["ChangeSetName"] == change_set_name
        assert describe_response["ChangeSetId"] == change_set_id
        assert describe_response["StackId"] == stack_id
        assert describe_response["StackName"] == stack_name
        assert describe_response["ExecutionStatus"] == "AVAILABLE"
        assert describe_response["Status"] == "CREATE_COMPLETE"
        changes = describe_response["Changes"]
        assert len(changes) == 1
        assert changes[0]["Type"] == "Resource"
        assert changes[0]["ResourceChange"]["Action"] == "Add"
        assert changes[0]["ResourceChange"]["ResourceType"] == "AWS::SNS::Topic"
        assert changes[0]["ResourceChange"]["LogicalResourceId"] == "topic123"
    finally:
        cleanup_stacks([stack_id])
        cleanup_changesets([change_set_id])

# TODO: implement
@pytest.mark.xfail(condition=not is_aws_cloud(), reason="Not properly implemented")
@markers.aws.validated
def test_create_change_set_update_without_parameters(
    cleanup_stacks,
    cleanup_changesets,
    is_change_set_created_and_available,
    is_change_set_finished,
    snapshot,
    aws_client,
):
    snapshot.add_transformer(snapshot.transform.cloudformation_api())
    """after creating a stack via a CREATE change set we send an UPDATE change set changing the SNS topic name"""
    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"
    change_set_name2 = f"change-set-{short_uid()}"

    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
    )

    response = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=change_set_name,
        TemplateBody=load_template_raw(template_path),
        ChangeSetType="CREATE",
    )
    snapshot.match("create_change_set", response)
    change_set_id = response["Id"]
    stack_id = response["StackId"]
    assert change_set_id
    assert stack_id

    try:
        # Change set can now either be already created/available or it is pending/unavailable
        wait_until(is_change_set_created_and_available(change_set_id))
        aws_client.cloudformation.execute_change_set(ChangeSetName=change_set_id)
        wait_until(is_change_set_finished(change_set_id))
        template = load_template_raw(template_path)

        update_response = aws_client.cloudformation.create_change_set(
            StackName=stack_name,
            ChangeSetName=change_set_name2,
            TemplateBody=template.replace("sns-topic-simple", "sns-topic-simple-2"),
            ChangeSetType="UPDATE",
        )
        assert wait_until(is_change_set_created_and_available(update_response["Id"]))
        snapshot.match(
            "describe_change_set",
            aws_client.cloudformation.describe_change_set(ChangeSetName=update_response["Id"]),
        )
        snapshot.match(
            "list_change_set", aws_client.cloudformation.list_change_sets(StackName=stack_name)
        )

        describe_response = aws_client.cloudformation.describe_change_set(
            ChangeSetName=update_response["Id"]
        )
        changes = describe_response["Changes"]
        assert len(changes) == 1
        assert changes[0]["Type"] == "Resource"
        change = changes[0]["ResourceChange"]
        assert change["Action"] == "Modify"
        assert change["ResourceType"] == "AWS::SNS::Topic"
        assert change["LogicalResourceId"] == "topic123"
        assert "sns-topic-simple" in change["PhysicalResourceId"]
        assert change["Replacement"] == "True"
        assert "Properties" in change["Scope"]
        assert len(change["Details"]) == 1
        assert change["Details"][0]["Target"]["Name"] == "TopicName"
        assert change["Details"][0]["Target"]["RequiresRecreation"] == "Always"
    finally:
        cleanup_changesets(changesets=[change_set_id])
        cleanup_stacks(stacks=[stack_id])

# def test_create_change_set_with_template_url():
#     pass

@pytest.mark.skipif(condition=not is_aws_cloud(), reason="change set type not implemented")
@markers.aws.validated
def test_create_change_set_create_existing(cleanup_changesets, cleanup_stacks, aws_client):
    """tries to create an already existing stack"""

    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"

    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
    )
    response = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=change_set_name,
        TemplateBody=load_template_raw(template_path),
        ChangeSetType="CREATE",
    )
    change_set_id = response["Id"]
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        ChangeSetName=change_set_id
    )
    stack_id = response["StackId"]
    assert change_set_id
    assert stack_id
    try:
        aws_client.cloudformation.execute_change_set(ChangeSetName=change_set_id)
        aws_client.cloudformation.get_waiter("stack_create_complete").wait(StackName=stack_id)

        with pytest.raises(Exception) as ex:
            change_set_name2 = f"change-set-{short_uid()}"
            aws_client.cloudformation.create_change_set(
                StackName=stack_name,
                ChangeSetName=change_set_name2,
                TemplateBody=load_template_raw("sns_topic_simple.yaml"),
                ChangeSetType="CREATE",
            )
        assert ex is not None
    finally:
        cleanup_changesets([change_set_id])
        cleanup_stacks([stack_id])

@markers.aws.validated
def test_create_change_set_update_nonexisting(aws_client):
    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
    )

    with pytest.raises(Exception) as ex:
        response = aws_client.cloudformation.create_change_set(
            StackName=stack_name,
            ChangeSetName=change_set_name,
            TemplateBody=load_template_raw(template_path),
            ChangeSetType="UPDATE",
        )
        change_set_id = response["Id"]
        stack_id = response["StackId"]
        assert change_set_id
        assert stack_id
    err = ex.value.response["Error"]
    assert err["Code"] == "ValidationError"
    assert "does not exist" in err["Message"]

@markers.aws.validated
def test_create_change_set_invalid_params(aws_client):
    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
    )
    with pytest.raises(ClientError) as ex:
        aws_client.cloudformation.create_change_set(
            StackName=stack_name,
            ChangeSetName=change_set_name,
            TemplateBody=load_template_raw(template_path),
            ChangeSetType="INVALID",
        )
    err = ex.value.response["Error"]
    assert err["Code"] == "ValidationError"

@markers.aws.validated
def test_create_change_set_missing_stackname(aws_client):
    """in this case boto doesn't even let us send the request"""
    change_set_name = f"change-set-{short_uid()}"
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
    )
    with pytest.raises(Exception):
        aws_client.cloudformation.create_change_set(
            StackName="",
            ChangeSetName=change_set_name,
            TemplateBody=load_template_raw(template_path),
            ChangeSetType="CREATE",
        )

@markers.aws.validated
def test_create_change_set_with_ssm_parameter(
    cleanup_changesets,
    cleanup_stacks,
    is_change_set_created_and_available,
    is_stack_created,
    aws_client,
):
    """References a simple stack parameter"""

    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"
    parameter_name = f"ls-param-{short_uid()}"
    parameter_value = f"ls-param-value-{short_uid()}"
    sns_topic_logical_id = "topic123"
    parameter_logical_id = "parameter123"

    aws_client.ssm.put_parameter(Name=parameter_name, Value=parameter_value, Type="String")
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/dynamicparameter_ssm_string.yaml"
    )
    template_rendered = render_template(
        load_template_raw(template_path), parameter_name=parameter_name
    )
    response = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=change_set_name,
        TemplateBody=template_rendered,
        ChangeSetType="CREATE",
    )
    change_set_id = response["Id"]
    stack_id = response["StackId"]
    assert change_set_id
    assert stack_id

    try:
        # make sure the change set wasn't executed (which would create a new topic)
        list_topics_response = aws_client.sns.list_topics()
        matching_topics = [
            t for t in list_topics_response["Topics"] if parameter_value in t["TopicArn"]
        ]
        assert matching_topics == []

        # stack is initially in REVIEW_IN_PROGRESS state. only after executing the change_set will it change its status
        stack_response = aws_client.cloudformation.describe_stacks(StackName=stack_id)
        assert stack_response["Stacks"][0]["StackStatus"] == "REVIEW_IN_PROGRESS"

        # Change set can now either be already created/available or it is pending/unavailable
        wait_until(is_change_set_created_and_available(change_set_id))
        describe_response = aws_client.cloudformation.describe_change_set(
            ChangeSetName=change_set_id
        )

        assert describe_response["ChangeSetName"] == change_set_name
        assert describe_response["ChangeSetId"] == change_set_id
        assert describe_response["StackId"] == stack_id
        assert describe_response["StackName"] == stack_name
        assert describe_response["ExecutionStatus"] == "AVAILABLE"
        assert describe_response["Status"] == "CREATE_COMPLETE"
        changes = describe_response["Changes"]
        assert len(changes) == 1
        assert changes[0]["Type"] == "Resource"
        assert changes[0]["ResourceChange"]["Action"] == "Add"
        assert changes[0]["ResourceChange"]["ResourceType"] == "AWS::SNS::Topic"
        assert changes[0]["ResourceChange"]["LogicalResourceId"] == sns_topic_logical_id

        parameters = describe_response["Parameters"]
        assert len(parameters) == 1
        assert parameters[0]["ParameterKey"] == parameter_logical_id
        assert parameters[0]["ParameterValue"] == parameter_name
        assert parameters[0]["ResolvedValue"] == parameter_value  # the important part

        aws_client.cloudformation.execute_change_set(ChangeSetName=change_set_id)
        wait_until(is_stack_created(stack_id))

        topics = aws_client.sns.list_topics()
        topic_arns = list(map(lambda x: x["TopicArn"], topics["Topics"]))
        assert any((parameter_value in t) for t in topic_arns)
    finally:
        cleanup_changesets([change_set_id])
        cleanup_stacks([stack_id])

@markers.aws.validated
def test_describe_change_set_nonexisting(snapshot, aws_client):
    with pytest.raises(Exception) as ex:
        aws_client.cloudformation.describe_change_set(
            StackName="somestack", ChangeSetName="DoesNotExist"
        )
    snapshot.match("exception", ex.value)

@pytest.mark.skipif(
    condition=not is_aws_cloud(),
    reason="fails because of the properties mutation in the result_handler",
)
@markers.aws.validated
def test_execute_change_set(
    is_change_set_finished,
    is_change_set_created_and_available,
    is_change_set_failed_and_unavailable,
    cleanup_changesets,
    cleanup_stacks,
    aws_client,
):
    """check if executing a change set succeeds in creating/modifying the resources in changed"""

    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
    )
    template_body = load_template_raw(template_path)

    response = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=change_set_name,
        TemplateBody=template_body,
        ChangeSetType="CREATE",
    )
    change_set_id = response["Id"]
    stack_id = response["StackId"]
    assert change_set_id
    assert stack_id

    try:
        assert wait_until(is_change_set_created_and_available(change_set_id=change_set_id))
        aws_client.cloudformation.execute_change_set(ChangeSetName=change_set_id)
        assert wait_until(is_change_set_finished(change_set_id))
        # check if stack resource was created
        topics = aws_client.sns.list_topics()
        topic_arns = list(map(lambda x: x["TopicArn"], topics["Topics"]))
        assert any(("sns-topic-simple" in t) for t in topic_arns)

        # new change set name
        change_set_name = f"change-set-{short_uid()}"
        # check if update with identical stack leads to correct behavior
        response = aws_client.cloudformation.create_change_set(
            StackName=stack_name,
            ChangeSetName=change_set_name,
            TemplateBody=template_body,
            ChangeSetType="UPDATE",
        )
        change_set_id = response["Id"]
        stack_id = response["StackId"]
        assert wait_until(is_change_set_failed_and_unavailable(change_set_id=change_set_id))
        describe_failed_change_set_result = aws_client.cloudformation.describe_change_set(
            ChangeSetName=change_set_id
        )
        assert describe_failed_change_set_result["ChangeSetName"] == change_set_name
        assert (
            describe_failed_change_set_result["StatusReason"]
            == "The submitted information didn't contain changes. Submit different information to create a change set."
        )
        with pytest.raises(ClientError) as e:
            aws_client.cloudformation.execute_change_set(ChangeSetName=change_set_id)
        e.match("InvalidChangeSetStatus")
        e.match(
            rf"ChangeSet \[{change_set_id}\] cannot be executed in its current status of \[FAILED\]"
        )
    finally:
        cleanup_changesets([change_set_id])
        cleanup_stacks([stack_id])

@markers.aws.validated
def test_delete_change_set_exception(snapshot, aws_client):
    """test error cases when trying to delete a change set"""
    with pytest.raises(Exception) as e1:
        aws_client.cloudformation.delete_change_set(
            StackName="nostack", ChangeSetName="DoesNotExist"
        )
    snapshot.match("e1", e1)

    with pytest.raises(Exception) as e2:
        aws_client.cloudformation.delete_change_set(ChangeSetName="DoesNotExist")
    snapshot.match("e2", e2)

@markers.aws.validated
def test_create_and_then_remove_non_supported_resource_change_set(deploy_cfn_template):
    # first deploy cfn with a CodeArtifact resource that is not actually supported
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/code_artifact_template.yaml"
    )
    template_body = load_template_raw(template_path)
    stack = deploy_cfn_template(
        template=template_body,
        parameters={"CADomainName": f"domainname-{short_uid()}"},
    )

    # removal of CodeArtifact should not throw exception
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/code_artifact_remove_template.yaml"
    )
    template_body = load_template_raw(template_path)
    deploy_cfn_template(
        is_update=True,
        template=template_body,
        stack_name=stack.stack_name,
    )

@markers.aws.validated
def test_create_and_then_update_refreshes_template_metadata(
    aws_client,
    cleanup_changesets,
    cleanup_stacks,
    is_change_set_finished,
    is_change_set_created_and_available,
):
    stacks_to_cleanup = set()
    changesets_to_cleanup = set()

    try:
        stack_name = f"stack-{short_uid()}"

        template_path = os.path.join(
            os.path.dirname(__file__), "../../../templates/sns_topic_simple.yaml"
        )

        template_body = load_template_raw(template_path)

        create_response = aws_client.cloudformation.create_change_set(
            StackName=stack_name,
            ChangeSetName=f"change-set-{short_uid()}",
            TemplateBody=template_body,
            ChangeSetType="CREATE",
        )

        stacks_to_cleanup.add(create_response["StackId"])
        changesets_to_cleanup.add(create_response["Id"])

        aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
            ChangeSetName=create_response["Id"]
        )

        aws_client.cloudformation.execute_change_set(
            StackName=stack_name, ChangeSetName=create_response["Id"]
        )

        wait_until(is_change_set_finished(create_response["Id"]))

        # Note the metadata alone won't change if there are no changes to resources
        # TODO: find a better way to make a replacement in yaml template
        template_body = template_body.replace(
            "TopicName: sns-topic-simple",
            "TopicName: sns-topic-simple-updated",
        )

        update_response = aws_client.cloudformation.create_change_set(
            StackName=stack_name,
            ChangeSetName=f"change-set-{short_uid()}",
            TemplateBody=template_body,
            ChangeSetType="UPDATE",
        )

        stacks_to_cleanup.add(update_response["StackId"])
        changesets_to_cleanup.add(update_response["Id"])

        wait_until(is_change_set_created_and_available(update_response["Id"]))

        aws_client.cloudformation.execute_change_set(
            StackName=stack_name, ChangeSetName=update_response["Id"]
        )

        wait_until(is_change_set_finished(update_response["Id"]))

        summary = aws_client.cloudformation.get_template_summary(StackName=stack_name)

        assert "TopicName" in summary["Metadata"]
        assert "sns-topic-simple-updated" in summary["Metadata"]
    finally:
        cleanup_stacks(list(stacks_to_cleanup))
        cleanup_changesets(list(changesets_to_cleanup))

# TODO: the intention of this test is not particularly clear. The resource isn't removed, it'll just generate a new bucket with a new default name
# TODO: rework this to a conditional instead of two templates + parameter usage instead of templating
@markers.aws.validated
def test_create_and_then_remove_supported_resource_change_set(deploy_cfn_template, aws_client):
    first_bucket_name = f"test-bucket-1-{short_uid()}"
    second_bucket_name = f"test-bucket-2-{short_uid()}"
    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/for_removal_setup.yaml"
    )
    template_body = load_template_raw(template_path)

    stack = deploy_cfn_template(
        template=template_body,
        template_mapping={
            "first_bucket_name": first_bucket_name,
            "second_bucket_name": second_bucket_name,
        },
    )
    assert first_bucket_name in stack.outputs["FirstBucket"]
    assert second_bucket_name in stack.outputs["SecondBucket"]

    available_buckets = aws_client.s3.list_buckets()
    bucket_names = [bucket["Name"] for bucket in available_buckets["Buckets"]]
    assert first_bucket_name in bucket_names
    assert second_bucket_name in bucket_names

    template_path = os.path.join(
        os.path.dirname(__file__), "../../../templates/for_removal_remove.yaml"
    )
    template_body = load_template_raw(template_path)
    stack_updated = deploy_cfn_template(
        is_update=True,
        template=template_body,
        template_mapping={"first_bucket_name": first_bucket_name},
        stack_name=stack.stack_name,
    )

    assert first_bucket_name in stack_updated.outputs["FirstBucket"]

    def assert_bucket_gone():
        available_buckets = aws_client.s3.list_buckets()
        bucket_names = [bucket["Name"] for bucket in available_buckets["Buckets"]]
        return first_bucket_name in bucket_names and second_bucket_name not in bucket_names

    poll_condition(condition=assert_bucket_gone, timeout=20, interval=5)

@markers.snapshot.skip_snapshot_verify(
    paths=[
        "$..NotificationARNs",
        "$..IncludeNestedStacks",
        "$..Parameters",
    ]
)
@markers.aws.validated
def test_empty_changeset(snapshot, cleanups, aws_client):
    """
    Creates a change set that doesn't actually update any resources and then tries to execute it
    """
    snapshot.add_transformer(snapshot.transform.cloudformation_api())

    stack_name = f"stack-{short_uid()}"
    change_set_name = f"change-set-{short_uid()}"
    change_set_name_nochange = f"change-set-nochange-{short_uid()}"
    cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name))

    template_path = os.path.join(os.path.dirname(__file__), "../../../templates/cdkmetadata.yaml")
    template = load_template_file(template_path)

    # 1. create change set and execute

    first_changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=change_set_name,
        TemplateBody=template,
        Capabilities=["CAPABILITY_AUTO_EXPAND", "CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"],
        ChangeSetType="CREATE",
    )
    snapshot.match("first_changeset", first_changeset)

    def _check_changeset_available():
        status = aws_client.cloudformation.describe_change_set(
            StackName=stack_name, ChangeSetName=first_changeset["Id"]
        )["Status"]
        if status == "FAILED":
            raise ShortCircuitWaitException("Change set in unrecoverable status")
        return status == "CREATE_COMPLETE"

    assert wait_until(_check_changeset_available)

    describe_first_cs = aws_client.cloudformation.describe_change_set(
        StackName=stack_name, ChangeSetName=first_changeset["Id"]
    )
    snapshot.match("describe_first_cs", describe_first_cs)
    assert describe_first_cs["ExecutionStatus"] == "AVAILABLE"

    aws_client.cloudformation.execute_change_set(
        StackName=stack_name, ChangeSetName=first_changeset["Id"]
    )

    def _check_changeset_success():
        status = aws_client.cloudformation.describe_change_set(
            StackName=stack_name, ChangeSetName=first_changeset["Id"]
        )["ExecutionStatus"]
        if status in ["EXECUTE_FAILED", "UNAVAILABLE", "OBSOLETE"]:
            raise ShortCircuitWaitException("Change set in unrecoverable status")
        return status == "EXECUTE_COMPLETE"

    assert wait_until(_check_changeset_success)

    # 2. create a new change set without changes
    nochange_changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=change_set_name_nochange,
        TemplateBody=template,
        Capabilities=["CAPABILITY_AUTO_EXPAND", "CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"],
        ChangeSetType="UPDATE",
    )
    snapshot.match("nochange_changeset", nochange_changeset)

    describe_nochange = aws_client.cloudformation.describe_change_set(
        StackName=stack_name, ChangeSetName=nochange_changeset["Id"]
    )
    snapshot.match("describe_nochange", describe_nochange)
    assert describe_nochange["ExecutionStatus"] == "UNAVAILABLE"

    # 3. try to execute the unavailable change set
    with pytest.raises(aws_client.cloudformation.exceptions.InvalidChangeSetStatusException) as e:
        aws_client.cloudformation.execute_change_set(
            StackName=stack_name, ChangeSetName=nochange_changeset["Id"]
        )
    snapshot.match("error_execute_failed", e.value)

@markers.aws.validated
def test_deleted_changeset(snapshot, cleanups, aws_client):
    """simple case verifying that proper exception is thrown when trying to get a deleted changeset"""
    snapshot.add_transformer(snapshot.transform.cloudformation_api())

    changeset_name = f"changeset-{short_uid()}"
    stack_name = f"stack-{short_uid()}"
    cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name))

    snapshot.add_transformer(snapshot.transform.regex(stack_name, "<stack-name>"))

    template_path = os.path.join(os.path.dirname(__file__), "../../../templates/cdkmetadata.yaml")
    template = load_template_file(template_path)

    # 1. create change set
    create = aws_client.cloudformation.create_change_set(
        ChangeSetName=changeset_name,
        StackName=stack_name,
        TemplateBody=template,
        Capabilities=["CAPABILITY_AUTO_EXPAND", "CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"],
        ChangeSetType="CREATE",
    )
    snapshot.match("create", create)

    changeset_id = create["Id"]

    def _check_changeset_available():
        status = aws_client.cloudformation.describe_change_set(
            StackName=stack_name, ChangeSetName=changeset_id
        )["Status"]
        if status == "FAILED":
            raise ShortCircuitWaitException("Change set in unrecoverable status")
        return status == "CREATE_COMPLETE"

    assert wait_until(_check_changeset_available)

    # 2. delete change set
    aws_client.cloudformation.delete_change_set(ChangeSetName=changeset_id, StackName=stack_name)

    with pytest.raises(aws_client.cloudformation.exceptions.ChangeSetNotFoundException) as e:
        aws_client.cloudformation.describe_change_set(
            StackName=stack_name, ChangeSetName=changeset_id
        )
    snapshot.match("postdelete_changeset_notfound", e.value)

@markers.aws.validated
def test_autoexpand_capability_requirement(cleanups, aws_client):
    stack_name = f"test-stack-{short_uid()}"
    changeset_name = f"test-changeset-{short_uid()}"
    queue_name = f"test-queue-{short_uid()}"
    cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name))

    template_body = load_template_raw(
        os.path.join(
            os.path.dirname(__file__), "../../../templates/cfn_macro_languageextensions.yaml"
        )
    )

    with pytest.raises(aws_client.cloudformation.exceptions.InsufficientCapabilitiesException):
        # requires the capability
        aws_client.cloudformation.create_stack(
            StackName=stack_name,
            TemplateBody=template_body,
            Parameters=[
                {"ParameterKey": "QueueList", "ParameterValue": "faa,fbb,fcc"},
                {"ParameterKey": "QueueNameParam", "ParameterValue": queue_name},
            ],
        )

    # does not require the capability
    create_changeset_result = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=changeset_name,
        TemplateBody=template_body,
        ChangeSetType="CREATE",
        Parameters=[
            {"ParameterKey": "QueueList", "ParameterValue": "faa,fbb,fcc"},
            {"ParameterKey": "QueueNameParam", "ParameterValue": queue_name},
        ],
    )
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        ChangeSetName=create_changeset_result["Id"]
    )

# FIXME: a CreateStack operation should work with an existing stack if its in REVIEW_IN_PROGRESS
@pytest.mark.skip(reason="not implemented correctly yet")
@markers.aws.validated
def test_create_while_in_review(aws_client, snapshot, cleanups):
    snapshot.add_transformer(snapshot.transform.cloudformation_api())
    stack_name = f"stack-{short_uid()}"
    changeset_name = f"changeset-{short_uid()}"
    cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name))

    changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=changeset_name,
        ChangeSetType="CREATE",
        TemplateBody=MINIMAL_TEMPLATE,
    )
    stack_id = changeset["StackId"]
    changeset_id = changeset["Id"]
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        StackName=stack_name, ChangeSetName=changeset_name
    )

    # I would have actually expected this to throw, but it doesn't
    create_stack_while_in_review = aws_client.cloudformation.create_stack(
        StackName=stack_name, TemplateBody=MINIMAL_TEMPLATE
    )
    snapshot.match("create_stack_while_in_review", create_stack_while_in_review)
    aws_client.cloudformation.get_waiter("stack_create_complete").wait(StackName=stack_name)

    # describe change set and stack (change set is now obsolete)
    describe_stack = aws_client.cloudformation.describe_stacks(StackName=stack_id)
    snapshot.match("describe_stack", describe_stack)
    describe_change_set = aws_client.cloudformation.describe_change_set(ChangeSetName=changeset_id)
    snapshot.match("describe_change_set", describe_change_set)

@markers.snapshot.skip_snapshot_verify(
    paths=["$..Capabilities", "$..IncludeNestedStacks", "$..NotificationARNs", "$..Parameters"]
)
@markers.aws.validated
def test_multiple_create_changeset(aws_client, snapshot, cleanups):
    snapshot.add_transformer(snapshot.transform.cloudformation_api())
    stack_name = f"repeated-stack-{short_uid()}"
    initial_changeset_name = f"initial-changeset-{short_uid()}"
    cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name))

    initial_changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=initial_changeset_name,
        ChangeSetType="CREATE",
        TemplateBody=MINIMAL_TEMPLATE,
    )
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        StackName=stack_name, ChangeSetName=initial_changeset_name
    )
    snapshot.match(
        "initial_changeset",
        aws_client.cloudformation.describe_change_set(ChangeSetName=initial_changeset["Id"]),
    )

    # multiple change sets can exist for a given stack
    additional_changeset_name = f"additionalchangeset-{short_uid()}"
    additional_changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=additional_changeset_name,
        ChangeSetType="CREATE",
        TemplateBody=MINIMAL_TEMPLATE,
    )
    snapshot.match("additional_changeset", additional_changeset)
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        StackName=stack_name, ChangeSetName=additional_changeset_name
    )

@markers.snapshot.skip_snapshot_verify(paths=["$..LastUpdatedTime", "$..StackStatusReason"])
@markers.aws.validated
def test_create_changeset_with_stack_id(aws_client, snapshot, cleanups):
    """
    The test answers the question if the `StackName` parameter in `CreateChangeSet` can also be a full Stack ID (ARN).
    This can make sense in two cases:
    1. a `CREATE` change set type while the stack is in `REVIEW_IN_PROGRESS` (otherwise it would fail) => covered by this test
    2. an `UPDATE` change set type when the stack has been deployed before already

    On an initial `CREATE` we can't actually know the stack ID yet since the `CREATE` will first create the stack.

    Error case: using `CREATE` with a stack ID from a stack that is in `DELETE_COMPLETE` state.
        => A single stack instance identified by a unique ID can never leave its `DELETE_COMPLETE` state
        => `DELETE_COMPLETE` is the only *real* terminal state of a Stack
    """
    snapshot.add_transformer(snapshot.transform.cloudformation_api())
    stack_name = f"repeated-stack-{short_uid()}"
    initial_changeset_name = "initial-changeset"
    cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name))

    # create initial change set
    initial_changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=initial_changeset_name,
        ChangeSetType="CREATE",
        TemplateBody=MINIMAL_TEMPLATE,
    )
    initial_stack_id = initial_changeset["StackId"]
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        StackName=stack_name, ChangeSetName=initial_changeset_name
    )

    # new CREATE change set on stack that is in REVIEW_IN_PROGRESS state
    additional_create_changeset_name = "additional-create"
    additional_create_changeset = aws_client.cloudformation.create_change_set(
        StackName=initial_stack_id,
        ChangeSetName=additional_create_changeset_name,
        ChangeSetType="CREATE",
        TemplateBody=MINIMAL_TEMPLATE,
    )
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        ChangeSetName=additional_create_changeset["Id"]
    )

    describe_stack = aws_client.cloudformation.describe_stacks(StackName=initial_stack_id)
    snapshot.match("describe_stack", describe_stack)

    # delete and try to revive the stack with the same ID (won't work)
    aws_client.cloudformation.delete_stack(StackName=stack_name)
    aws_client.cloudformation.get_waiter("stack_delete_complete").wait(StackName=stack_name)

    assert (
        aws_client.cloudformation.describe_stacks(StackName=initial_stack_id)["Stacks"][0][
            "StackStatus"
        ]
        == "DELETE_COMPLETE"
    )
    with pytest.raises(aws_client.cloudformation.exceptions.ClientError) as e:
        aws_client.cloudformation.create_change_set(
            StackName=initial_stack_id,
            ChangeSetName="revived-stack-changeset",
            ChangeSetType="CREATE",
            TemplateBody=MINIMAL_TEMPLATE,
        )
    snapshot.match("recreate_deleted_with_id_exception", e.value.response)

@markers.snapshot.skip_snapshot_verify(
    paths=[
        # gotta skip quite a lot unfortunately
        # FIXME: tackle this when fixing API parity of CloudFormation
        "$..EnableTerminationProtection",
        "$..LastUpdatedTime",
        "$..Capabilities",
        "$..ChangeSetId",
        "$..IncludeNestedStacks",
        "$..NotificationARNs",
        "$..Parameters",
        "$..StackId",
        "$..StatusReason",
        "$..StackStatusReason",
    ]
)
@markers.aws.validated
def test_name_conflicts(aws_client, snapshot, cleanups):
    """
    changeset-based equivalent to tests.aws.services.cloudformation.api.test_stacks.test_name_conflicts

    Tests behavior of creating a stack and changeset with the same names of ones that were previously deleted

    1. Create ChangeSet
    2. Create another ChangeSet
    3. Execute ChangeSet / Create Stack
    4. Creating a new ChangeSet (CREATE) for this stack should fail since it already exists & is running/active
    5. Delete Stack
    6. Create ChangeSet / re-use ChangeSet and Stack names from 1.

    """
    snapshot.add_transformer(snapshot.transform.cloudformation_api())
    stack_name = f"repeated-stack-{short_uid()}"
    initial_changeset_name = f"initial-changeset-{short_uid()}"
    cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name))

    initial_changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=initial_changeset_name,
        ChangeSetType="CREATE",
        TemplateBody=MINIMAL_TEMPLATE,
    )
    initial_stack_id = initial_changeset["StackId"]
    initial_changeset_id = initial_changeset["Id"]
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        StackName=stack_name, ChangeSetName=initial_changeset_name
    )

    # actually create the stack
    aws_client.cloudformation.execute_change_set(
        StackName=stack_name, ChangeSetName=initial_changeset_name
    )
    aws_client.cloudformation.get_waiter("stack_create_complete").wait(StackName=stack_name)

    # creating should now fail (stack is created & active)
    with pytest.raises(aws_client.cloudformation.exceptions.ClientError) as e:
        aws_client.cloudformation.create_change_set(
            StackName=stack_name,
            ChangeSetName=initial_changeset_name,
            ChangeSetType="CREATE",
            TemplateBody=MINIMAL_TEMPLATE,
        )
    snapshot.match("create_changeset_existingstack_exc", e.value.response)

    # delete stack
    aws_client.cloudformation.delete_stack(StackName=stack_name)
    aws_client.cloudformation.get_waiter("stack_delete_complete").wait(StackName=stack_name)

    # creating for stack name with same name should work again
    # re-using the changset name should also not matter :)
    second_initial_changeset = aws_client.cloudformation.create_change_set(
        StackName=stack_name,
        ChangeSetName=initial_changeset_name,
        ChangeSetType="CREATE",
        TemplateBody=MINIMAL_TEMPLATE,
    )
    second_initial_stack_id = second_initial_changeset["StackId"]
    second_initial_changeset_id = second_initial_changeset["Id"]
    assert second_initial_changeset_id != initial_changeset_id
    assert initial_stack_id != second_initial_stack_id
    aws_client.cloudformation.get_waiter("change_set_create_complete").wait(
        ChangeSetName=second_initial_changeset_id
    )

    # only one should be active, and this one is in review state right now
    new_stack_desc = aws_client.cloudformation.describe_stacks(StackName=stack_name)
    snapshot.match("new_stack_desc", new_stack_desc)
    assert len(new_stack_desc["Stacks"]) == 1
    assert new_stack_desc["Stacks"][0]["StackId"] == second_initial_stack_id

    # can still access both by using the ARN (stack id)
    # and they should be different from each other
    stack_id_desc = aws_client.cloudformation.describe_stacks(StackName=initial_stack_id)
    new_stack_id_desc = aws_client.cloudformation.describe_stacks(StackName=second_initial_stack_id)
    snapshot.match("stack_id_desc", stack_id_desc)
    snapshot.match("new_stack_id_desc", new_stack_id_desc)

    # can still access all change sets by their ID
    initial_changeset_id_desc = aws_client.cloudformation.describe_change_set(
        ChangeSetName=initial_changeset_id
    )
    snapshot.match("initial_changeset_id_desc", initial_changeset_id_desc)
    second_initial_changeset_id_desc = aws_client.cloudformation.describe_change_set(
        ChangeSetName=second_initial_changeset_id
    )
    snapshot.match("second_initial_changeset_id_desc", second_initial_changeset_id_desc)


from webob.exc import HTTPUnauthorized

from repoze.bfg.chameleon_zpt import render_template_to_response
from karl.views.api import TemplateAPI
from karl.utils import get_setting

def login_view(context, request):

    system_name = get_setting(context, 'system_name', 'KARL')

    page_title = '' # Per #366377, don't say what screen
    api = TemplateAPI(context, request, page_title)

    came_from = request.params.get('came_from', request.url)

    if came_from.endswith('login.html'):
        came_from = came_from[:-len('login.html')]
    elif came_from.endswith('logout.html'):
        came_from = came_from[:-len('logout.html')]

    api.status_message = status_message=request.params.get('reason', None)
    response = render_template_to_response(
        'templates/login.pt',
        api=api,
        came_from=came_from,
        nothing='',
        app_url=request.application_url,
        )
    plugins = request.environ.get('repoze.who.plugins', {})
    auth_tkt = plugins.get('auth_tkt')
    if auth_tkt is not None:
        forget_headers = auth_tkt.forget(request.environ, {})
        response.headers.update(forget_headers)
    return response

def logout_view(context, request, reason='Logged out'):
    unauthorized = HTTPUnauthorized()
    unauthorized.headerlist.append(
        ('X-Authorization-Failure-Reason', reason))
    return unauthorized


from django.http import HttpResponse
from django.shortcuts import render
import string as st
ab = st.punctuation
print(ab)
def index(request):

   return render(request,'index.html')
    # return HttpResponse('''''')

def analyze(request):
    djtext = request.POST.get('text','default')

    removepunc = request.POST.get('removepunc', 'off')

    capital = request.POST.get('capital','off')
    newLine = request.POST.get('newline','off')
    spaceRemover = request.POST.get('spaceRemover','off')
    counter = request.POST.get('characterCount','off')

    if removepunc =="on":
       analyzed = ""
       for char in djtext:
           if char not in ab:
               analyzed = analyzed + char
       params = {"purpose":"remove punctuation","analyzed_text":analyzed}
       djtext = analyzed

       # return render(request,'analyze.html',params)

    if capital == "on":
        analyzed = ""
        for char in djtext:
             analyzed = analyzed + char.upper()
        params = {"purpose": "capitalisation", "analyzed_text": analyzed}
        # return render(request, 'analyze.html', params)
        djtext = analyzed
    if newLine =='on':
        analyzed = ""
        for char in djtext:
            if char !="\n" and char!="\r":
             analyzed = analyzed +char
        params = {"purpose": "removeNewLine", "analyzed_text": analyzed}
        # return render(request, 'analyze.html', params)
        djtext= analyzed
    if spaceRemover =='on':
        analyzed = ""
        for char in djtext:
            if char !=" ":
             analyzed = analyzed +char
        params = {"purpose": "extraSpacesRemover", "analyzed_text": analyzed}
        # return render(request, 'analyze.html', params)
        djtext=analyzed
    if counter =='on':
        count = 0
        for char in djtext:
            count +=1
        final = f"total no of characters in = {djtext} is {count}"

        params = {"purpose": "characterCounter", "analyzed_text": final}
        # return render(request, 'analyze.html', params)
        djtext=final
    if counter!='on' and spaceRemover !='on' and newLine !='on' and capital != "on" and removepunc !="on" :
        return HttpResponse("Sorry .........please select option")

    return render(request, 'analyze.html', params)


from langpack.contrib.django import trans, localize, trans_lazy
from nose import tools as test
from datetime import datetime

from .cases import AppTestCase

class TestShortcuts(AppTestCase):
    def test_trans(self):
        translator = self.get_translator()
        translator.add_translations('en', {'foo': 'bar'})
        test.assert_equal(trans('foo'), 'bar')
        test.assert_equal(trans_lazy('foo'), 'bar')

    def test_localize(self):
        translator = self.get_translator()

        translator.add_translations('en', {
            'datetime': {
                'formats': {
                    'short': '%d.%M.%Y',
                },
            },
        })

        translator.add_formatter(self.format_datetime, ['datetime'])
        now = datetime.now()

        assert localize(now, 'short') == now.strftime('%d.%M.%Y')
        assert localize(now, '%d.%M.%Y') == now.strftime('%d.%M.%Y')

    @staticmethod
    def format_datetime(value, format, translator):
        format = translator.get_template('datetime.formats.' + format, default=format)
        return value.strftime(format)


from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.shortcuts import render,  get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse

from .utils import render_to_pdf

from .models import Experience, Education, Skill
from user_profile.models import UserProfile

def home(request):
	return render(request, '/home/dzee/resume_builder/index.html')

def profile(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	context = {
		'first_name': user.first_name,
		'last_name': user.last_name,
		'email': user.email,
		'phone': profile.phone,
		'profession': profile.profession,
		'bio': profile.bio,
		'theme': profile.color,
	}
	return render(request, 'resume/profile.html', context)

def update_user(request):
	user = request.user
	user.first_name = request.POST['first_name']
	user.last_name = request.POST['last_name']
	user.email = request.POST['email']
	user.save()
	profile = get_object_or_404(UserProfile, user=user)
	profile.phone = request.POST['phone']
	profile.profession = request.POST['profession']
	profile.bio = request.POST['bio']
	profile.save()
	return HttpResponseRedirect(reverse('resume:profile'))

################################# CRUD EXPERIENCE

def experience(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	experiences = Experience.objects.filter(user=request.user)
	if experience:
		context = {
			'experiences': experiences,
			'theme': profile.color,
		}
		return render(request, 'resume/experience.html', context)
	context = {
		'theme': profile.color,
	}
	return render(request, 'resume/experience.html', context)

def create_experience(request):
	experience = Experience()
	experience.user = request.user
	experience.company = request.POST['company']
	experience.role = request.POST['role']
	experience.startDate = request.POST['start']
	experience.endDate = request.POST['end']
	experience.description = request.POST['description']
	experience.save()
	return HttpResponseRedirect(reverse('resume:experience'))

def update_experience(request):
	id = request.POST['id']
	experience =get_object_or_404(Experience, id=id)
	experience.company = request.POST['company']
	experience.role = request.POST['role']
	# experience.startDate = request.POST['start']
	# experience.endDate = request.POST['end']
	experience.description = request.POST['description']
	experience.save()
	return HttpResponseRedirect(reverse('resume:experience'))

def delete_experience(request, id):
	experience = get_object_or_404(Experience, id=id)
	experience.delete()
	return HttpResponseRedirect(reverse('resume:experience'))

################################# CRUD EDUCAION

def education(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	educations = Education.objects.filter(user=request.user)
	if educations:
		context = {
			'educations': educations,
			'theme': profile.color,
		}
		return render(request, 'resume/education.html', context)
	context = {
		'theme': profile.color,
	}
	return render(request, 'resume/education.html', context)

def create_education(request):
	education = Education()
	education.user = request.user
	education.school = request.POST['school']
	education.degree = request.POST['degree']
	education.startDate = request.POST['start']
	education.endDate = request.POST['end']
	education.description = request.POST['description']
	education.save()
	return HttpResponseRedirect(reverse('resume:education'))

def update_education(request):
	id = request.POST['id']
	education =get_object_or_404(Education, id=id)
	education.school = request.POST['school']
	education.degree = request.POST['degree']
	# education.startDate = request.POST['start']
	# education.endDate = request.POST['end']
	education.description = request.POST['description']
	education.save()
	return HttpResponseRedirect(reverse('resume:education'))

def delete_education(request, id):
	education = get_object_or_404(Education, id=id)
	education.delete()
	return HttpResponseRedirect(reverse('resume:education'))

################################# CRUD SKILL

def skills(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	skills = Skill.objects.filter(user=request.user)
	skills = skills[::-1] ##reversing the list
	context = {
		'skills': skills,
		'theme': profile.color,
	}
	return render(request, 'resume/skills.html', context)

def create_skill(request):
	skill = Skill()
	skill.user = request.user
	skill.name = request.POST['name']
	skill.save()
	return HttpResponseRedirect(reverse('resume:skills'))

def delete_skill(request, id):
	skill = get_object_or_404(Skill, id=id)
	skill.delete()
	return HttpResponseRedirect(reverse('resume:skills'))

################################# SETTINGS

def settings(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	context = {
		'username': user.username,
		'email': user.email,
		'theme': profile.color,
	}
	return render(request, 'resume/settings.html', context)

def set_blue(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	profile.color = 'blue'
	profile.save()
	return HttpResponseRedirect(reverse('resume:settings'))

def set_green(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	profile.color = 'green'
	profile.save()
	return HttpResponseRedirect(reverse('resume:settings'))

def set_orange(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	profile.color = 'orange'
	profile.save()
	return HttpResponseRedirect(reverse('resume:settings'))

def set_pink(request):
	user = request.user
	profile = get_object_or_404(UserProfile, user=user)
	profile.color = 'pink'
	profile.save()
	return HttpResponseRedirect(reverse('resume:settings'))

################################# BUILD RESUME

def generate_resume(request, *args, **kwargs):
	profile = get_object_or_404(UserProfile, user=request.user)
	experiences = Experience.objects.filter(user=request.user)
	educations = Education.objects.filter(user=request.user)
	skills = Skill.objects.filter(user=request.user)
	context = {
		'full_name': request.user.first_name + ' '  + request.user.last_name,
		#'email': user.email,
		'profession': profile.profession,
		'about_me': profile.bio,
		'experiences': experiences,
		'educations': educations,
		'skills': skills,
		'theme': profile.color,
	}
	pdf = render_to_pdf('pdf/test.html', context)
	if pdf:
		response = HttpResponse(pdf, content_type='application/pdf')
		download = request.GET.get("download")
		if download == 'True':
			response['Content-Disposition'] = 'attachment; filename=test.pdf'
		return response
	return HttpResponse('PDF not found')


from basicImports import *
import requests
import random
import string
import ast
from os import walk
import requests # request img from web
import shutil # save img locally
from datetime import date

# READ CATEGORIES FROM HERE https://stylesatlife.com/articles/types-of-cars/
# MAKE A DICTIONARY OF CAR NAMES AND THEN ASSIGN CATEGORIES

fx = open('carCatCleaned.txt', 'r')
catDict = json.loads(fx.read())
fx.close()

print(len(catDict.keys()))

dictKeys = list(catDict.keys())
dictKeys.sort()

for key in dictKeys:
    if len(catDict[key]['type']) == 0:
        del catDict[key]
studiedApps = {}
studiedApps['Turo'] = 1
studiedApps['GetAround'] = 1
studiedApps['GerAroundEurope'] = 1

cities = ['Barcelona', 'Berlin', 'Hamburg', 'Los Angeles','London', 'Liverpool', 'Las Vegas', 'Lyon', 'Madrid','Miami', 'New York City', 'Ottawa',  'Paris',  'Toronto','Washington D.C.' ]
# cities = {'Barcelona', 'Berlin', 'Hamburg', 'Liverpool', 'London', 'Lyon', 'Madrid', 'Paris', 'Las Vegas', 'Los Angeles', 'Miami','New York City', 'Ottawa', 'Toronto','Washington D.C.' }
targetFolder = '/home/hakhan/Google Drive/p2pCarRentalProject/AnalysisScripts/IntermediateData/0-output/data/APPNAME/'

catCats = ['sedan', 'hatchback', 'coupe', 'truck', 'suv', 'wagon',  'van/minivan']
found = {}
notFound = {}
totalTypes = {}

citiesAndServices = {}
for city in cities:
    citiesAndServices[city] = {}
    for service in studiedApps.keys():
        citiesAndServices[city][service] = {}
        for cat in catCats:
            citiesAndServices[city][service][cat] = {}

totalModels = {}

moreThanOne = {}
totalVehicles = {}

ownerVehicles = {}
for city in cities:
    ownerVehicles[city] = {}
    for service in studiedApps.keys():
        ownerVehicles[city][service] = {}

studiedApps = {}
studiedApps['GerAroundEurope'] = 1
studiedApps['Turo'] = 1
studiedApps['GetAround'] = 1

loadPath = '/home/hakhan/Google Drive/p2pCarRentalProject/AnalysisScripts/IntermediateData/vehicleCat-output/'
fx = open(loadPath + 'vehicleCategories.txt','r')
carIdToCat = json.loads(fx.read())
fx.close()

possibleCats = ['sedan', 'SUV', 'hatchback', 'van/minivan', 'coupe', 'truck', 'wagon']
priceDict = {}
currencyConversion = {}
currencyConversion['USD'] = 1
currencyConversion['US'] = 1
currencyConversion['GBP'] = 1.21
currencyConversion['CAD'] = 0.73
currencyConversion['€'] = 1.06
currencyConversion['£'] = 1.21
vehiclePrices = {}

totalMeta = {'Turo': {'Las Vegas': 1, 'Liverpool': 1, 'London': 1, 'Los Angeles': 1, 'Miami': 1, 'New York City': 1, 'Ottawa': 1, 'Toronto': 1, 'Washington D.C.': 1}, 'GetAround': {'Las Vegas': 1, 'Los Angeles': 1, 'Miami': 1, 'New York City': 1, 'Washington D.C.': 1}, 'GerAroundEurope': {'Barcelona': 1, 'Berlin': 1, 'Hamburg': 1, 'Liverpool': 1, 'London': 1, 'Lyon': 1, 'Madrid': 1, 'Paris': 1}}

pricesDict = {}

weekdays= ['Monday','Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday']

carDatesDict = {}

studiedApps = {}
studiedApps['GerAroundEurope'] = 1
studiedApps['Turo'] = 1
studiedApps['GetAround'] = 1

platformService = {}
for platform in studiedApps:
    platformService[platform] = {}
    # vehiclePrices[platform] = {}
    listData = {}
    carDatesDict[platform] = {}
    tempFolder = targetFolder.replace('APPNAME',platform)
    filenames = next(walk(tempFolder), (None, None, []))[2]  # [] if no file
    filenames.sort()
    nf = 0
    carCount = 0
    for fileName in filenames:
        cityName = fileName.split('-')[0]
        if cityName != 'New York':
            platformService[platform][cityName] = 1
            print(platform, cityName)
            carDatesDict[platform][cityName] = {}
            if 1:
            # try:
                fx = open(tempFolder+fileName,'r')
                content = json.loads(fx.read())
                fx.close()
                carCount = 0
                totalDates = list(content.keys())
                totalDates.sort()
                keyCount = 0
                vehiclePrices = {}

                for i in range(0, len(totalDates)):
                    keyDate = totalDates[i]
                    recordDate = totalDates[i]
                    recordDate = recordDate.split(')')[0]
                    startDate = recordDate.split(' (')[0]

                    d0 = startDate#datetime.strptime(startDate, '%Y-%m-%d')
                    d1 = ''
                    aheadDates = recordDate.split(' (')[1]
                    aheadDates = aheadDates.split(' - - ')
                    aheadDates[0] = aheadDates[0].split(' ')[0]
                    # aheadDates[1] = aheadDates[1].split(' ')[0]

                    if platform == 'Turo':
                        aheadDates[0] = aheadDates[0].split('-')
                        aheadDates[0] = aheadDates[0][2]+'-'+aheadDates[0][0]+'-'+aheadDates[0][1]
                    d1 = aheadDates[0]

                    for vehicleId in content[keyDate]:
                        vid = str(vehicleId)
                        try:
                            v10 = carDatesDict[platform][cityName][vid]
                        except:
                            carDatesDict[platform][cityName][vid] = {}

                        try:
                            v10 = carDatesDict[platform][cityName][vid][d0]
                        except:
                            carDatesDict[platform][cityName][vid][d0] = []
                        vehicleTrips = content[keyDate][vehicleId]['trips']

                        carDatesDict[platform][cityName][vid][d0].append([d1, vehicleTrips])
                        # print(vid, d0, d1, vehicleTrips)
                        # time.sleep(10000)
            fx = open('carDatesDict-'+platform+'-'+cityName+'.txt','w')
            fx.write(json.dumps(carDatesDict))
            fx.close()
            carDatesDict[platform] = {}
    carDatesDict = {}

print(platformService)


#! /usr/bin/env python3
# coding=utf-8

# Ruibo Liu @Dartmouth College
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for Agent."""

from absl import logging
from absl.testing import absltest, parameterized

from stable_alignment.sandbox import Agent

logging.set_verbosity("info")
logging.set_stderrthreshold("info")

class AgentTest(parameterized.TestCase):
    """Test cases for Social Agents."""

    def test_agent_internal_memory(self):
        """Test the save/update functions of agent's internal memory."""
        agent = Agent(agent_id=19, location=(3, 4), world_id=0, label="good")
        self.assertEqual(agent.model_type, "text-davinci-002")
        agent.reset_memory()
        agent.save_int_memory(
            question="What's the weather like today?", answer="It is pretty good!"
        )
        self.assertDictEqual(
            agent.internal_mem, {"What's the weather like today?": "It is pretty good!"}
        )

    def test_agent_response(self):
        """Test whether the agent is able to generate self-consistent answers."""
        agent = Agent(
            agent_id=0,
            location=(0, 0),
            model_type="text-davinci-003",
            world_id=0,
            label="good",
        )
        self.assertEqual(agent.model_type, "text-davinci-003")
        agent.reset_memory()
        agent.save_int_memory(
            question="Do you love any ball games?",
            answer="I love all of them except basketball!",
        )
        logging.info(
            agent.response("Do you want to play basketball with me?", verbose=True)
        )

    def test_agent_response_chat_gpt(self):
        """Test whether the agent is able to generate answers with GPT-3.5 engine."""
        agent = Agent(
            agent_id=0,
            location=(0, 0),
            model_type="gpt-3.5-turbo",
            world_id=0,
            label="good",
        )
        self.assertEqual(agent.model_type, "gpt-3.5-turbo")
        agent.reset_memory()
        agent.save_int_memory(
            question="Do you love any ball games?",
            answer="I love all of them except basketball!",
        )
        logging.info(
            agent.response("Do you want to play basketball with me?", verbose=True)
        )

    def test_agent_init_with_paths_no_world_id(self):
        """Test that we can initialize the agent with only memory and embedding paths."""
        agent = Agent(
            agent_id=1,
            location=(0, 1),
            int_mem_path="./data/cache/world_0/internal_memory/agent_1.pkl",
            int_mem_emb_path="./data/cache/world_0/internal_memory/agent_1_emb.pkl",
            ext_mem_path="./data/cache/world_0/external_memory/agent_1.jsonl",
            label="good",
        )
        agent.reset_memory()
        agent.save_int_memory(
            question="Do you love any ball games?",
            answer="I love all of them except basketball!",
        )
        logging.info(
            agent.response("Do you want to play basketball with me?", verbose=True)
        )

    def test_agent_init_with_paths_expect_fail(self):
        """Test that initializing the agent with no world id and not all three paths would assert false."""
        try:
            Agent(
                agent_id=1,
                location=(0, 1),
                model_type="text-davinci-002",
                int_mem_path="./data/cache/world_0/internal_memory/agent_1.pkl",
                int_mem_emb_path="./data/cache/world_0/internal_memory/agent_1_emb.pkl",
                label="good",
            )
        except AssertionError as e:
            logging.info(str(e))
        else:
            self.fail("Should raise an AssertionError.")

if __name__ == "__main__":
    absltest.main()


import datetime
import json
import os

import requests
from dotenv import load_dotenv

load_dotenv()
AUTH_TOKEN=os.getenv('AUTH_TOKEN')
REQUEST_URL=os.getenv('REQUEST_URL')
def save_last_update(created_at):
    with open("./last_update.json","w") as f:
        json.dump({"last_update":created_at},f)

def get_last_update():
    with open("./last_update.json","r")as f:
        json_data =json.load(f)
    return json_data["last_update"]

def get_message():
    last_update = datetime.datetime.strptime(get_last_update(),"%Y-%m-%dT%H:%M:%SZ")
    response = requests.get(REQUEST_URL,headers={"Authorization":f"Bearer {AUTH_TOKEN}"})
    github_log = reversed(response.json())
    message=""
    for log in github_log:
        created_at = datetime.datetime.strptime(log["created_at"],"%Y-%m-%dT%H:%M:%SZ")
        if created_at > last_update:
            if log["type"] == "PushEvent":
                message+=(message_format(log))

    save_last_update(log["created_at"])
    return message

def message_format(log):
    return f'```{log["actor"]["login"]}さんがpushしました。\nmessage:{log["payload"]["commits"][0]["message"]}```\n'

if __name__=="__main__":
    get_message()


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

"""App initialization part, registering global
methods or procedures to the app instance.
"""

import logging
import markdown2
from flask import Flask, Markup
import config
from database import Database
from models import Tag, Category, fetch_all_instances

logger = logging.getLogger(__name__)
# initialize app
app = Flask(__name__)
app.secret_key = app.config['SECRET_KEY']
app.config.from_object(config)
app.db = Database(app)
app.config['post_tags'] = {}
app.config['categories'] = []

@app.teardown_request
def close_session(exception=None):
    if not exception:
        app.db.session.commit()
        app.db.remove_current_session()
    else:
        app.db.roll_back_current_session()
        app.db.remove_current_session()
        app.db.dispose_pool()

@app.before_first_request
def init_app():
    # get some global objects
    # create tag dictionary for app-wide use
    if not app.config['post_tags']:
        for tag in Tag.get_all_tags():
            app.config['post_tags'][tag.name] = tag.id

    if not app.config['categories']:
        app.config['categories'] = Category.fetch_all_categories()

@app.template_filter('parse_markdown')
def parse_markdown(markdown_text):
    return Markup(markdown2.markdown(markdown_text))


from bs4 import BeautifulSoup
import requests
def count_problems(link):
    source  = requests.get(link).text
    soup = BeautifulSoup(source, 'lxml').body

    content = (soup.find('table', {'class': 'problems'}))
    if content == None :
        return " ";
    problems = content.findAll('tr')
    res = ""
    for i in range(len(problems)):
        if i > 0 :
            problem =  problems[i].td.a.text
            problem = problem.split(' ')
            # print(problem)
            for j in problem:
                if len(j) and j != '\r\n':
                    j = j.split('\r')
                    res = res + j[0] + " "
    return res
print(count_problems('https://codeforces.com/contest/1392'))


""""whether"""
def main():
    """check the wheather in which city in the world!!!"""
    import requests
    api_address='http://api.openweathermap.org/data/2.5/weather?appid=0c42f7f6b53b244c78a418f4f181282a&q='
    city = input()
    new_address = api_address + city
    json_data = requests.get(new_address).json()
    format_add = json_data['weather'][0]["description"]
    print(format_add)
main()


_over = False
while _over != True:
    print("q for exit")
    _list = input("Word:")
    if _list == "q":
        _over = True
    else:
        _return = ""
        _list2 = []
        i = -1

        for words in _list:
            _list2.append(words)

        for _words in _list2:
            _return = _return + _list2[i]
            i = i - 1
        print(_return)


def IsotypicComponent(S, arg, use_antisymmetry=False):
    if isinstance(arg, Partition):
        list_partitions = [arg]
    elif isinstance(arg, Integer):
        list_partitions = Partitions(arg)
    else :
        print("Error: arg should be a partition or an integer.")

    basis = S.basis()
    result = {}
    P1 = basis.values().pop()[0].parent()
    for nu in list_partitions:
        result_nu = {}
        if use_antisymmetry == True:
            antisymmetries = antisymmetries_of_tableau(nu.initial_tableau())
            P2 = DiagonalAntisymmetricPolynomialRing(P1._R, P1.ncols(), P1.nrows(),
                                                 P1.ninert(), antisymmetries)
        for deg, value in basis.iteritems():
            if use_antisymmetry:
                gen = []
                for p in value:
                    temp = apply_young_idempotent(P2(p), nu)
                    if temp != 0:
                        gen += [temp]
            else:
                gen = []
                for p in value:
                    temp = apply_young_idempotent(p, nu)
                    if temp != 0:
                        gen += [temp]
            if gen != []:
                result_nu[(deg, tuple(nu))] = Subspace(gen, {}).basis()[0]
        if result_nu != {}:
            result[nu] = Subspace(result_nu, operators={})

    if len(result.keys()) == 1:
        key = result.keys()[0]
        return result[key]
    else:
        return result


from enum import Enum

ELEMENT = {
    "ground": "electric",
    "electric": "water",
    "water": "fire",
    "fire": "grass",
    "grass": "ground",
    "light": "dark",
    "dark": "light",
    "neutral": ""
}

RENDER_ELEMENT = {
    "ground": "⛰",
    "electric": "🌩",
    "water": "💦",
    "fire": "🔥",
    "grass": "🍂",
    "light": "💡",
    "dark": "🌛",
    "neutral": "✨"
}

class Rarity(Enum):
    COMMON = 0
    UNCOMMON = 1
    RARE = 2
    SR = 3
    UR = 4
    L = 5

STR_TO_RARITY = {
    "common": Rarity.COMMON,
    "uncommon": Rarity.UNCOMMON,
    "rare": Rarity.RARE,
    "super rare": Rarity.SR,
    "ultra rare": Rarity.UR,
    "legendary": Rarity.L
}


num = input("insert number: ")
def primelist (num):
    primelist = [2]
    for i in range(3, num+1):
        is_prime = True
        for j in range(len(primelist)):
            if (i % primelist[j-1] == 0):
                is_prime = False
        if is_prime:
            primelist.append(i)
    return primelist
primelist = (primelist(num))

prime_multiplier_list = []
e = 0
while (num > 1 or e < len(primelist)):
    # for e in range(len(primelist)):
        while (num % primelist[e] == 0):
            num /= primelist[e]
            prime_multiplier_list.append(primelist[e])
        e+=1
print (prime_multiplier_list)


## load environment
import streamlit as st
import pickle
import re
from nltk.tokenize import word_tokenize
from nltk.stem import WordNetLemmatizer
wnl = WordNetLemmatizer()
from pandas import DataFrame
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import Ridge
from numpy import concatenate
from numpy import asarray
from numpy import append as ap
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
from scipy.sparse import hstack
from nltk.corpus import stopwords
import matplotlib.pyplot as plt

# function definitions =======================================================================================
# define function to lemmatize long-form text
def lemmatizer(sentence):
    token_words = word_tokenize(sentence)
    lem_sentence=[]
    for word in token_words:
        lemma = wnl.lemmatize(word)
        lem_sentence.append(lemma)
        lem_sentence.append(" ")
    return "".join(lem_sentence)

# make preprocessing pipeline:
pattern = re.compile(r'\b(' + r'|'.join(stopwords.words('english')) + r')\b\s*')

def preproc(text):
    ll = text.lower()
    l = re.sub(r'http\S+',' ', ll) # remove links
    n = re.sub(r'[0-9]+', ' ', l) # remove numbers
    s = re.sub(r'[^\w]',' ', n)  # remove symbols
    w = pattern.sub('', s) # remove stopwords
    p = lemmatizer(w) # lemmatize all words
    return p

## load models
model, tfidf, onehot, goodwords, badwords, result_features = pickle.load(open("pickle/appv3models.pkl", "rb"))
story_example = pickle.load(open("pickle/app_example.pkl", "rb"))

parent_categories = ['Journalism', 'Comics', 'Dance',  'Photography',
                     'Games', 'Music', 'Technology', 'Crafts',
                     'Film & Video', 'Art', 'Design', 'Theater',
                     'Food', 'Fashion', 'Publishing']
#st.markdown('', unsafe_allow_html = True)

# Sidebar==================================================================================
# list of categories for making the drop down menu
c = st.sidebar.selectbox(
    'Category', parent_categories)

# give general suggestion drop down
if st.sidebar.checkbox("Show general suggestions"):
  st.sidebar.markdown('*Here are words that you may consider using more:*.')
  st.sidebar.markdown(', '.join(list(goodwords['feature'])[:50]))
  st.sidebar.markdown('*Here are words that you may consider using less:*.')
  st.sidebar.markdown(', '.join(list(badwords['feature'])[:50]))

# links to github and presentation
st.sidebar.markdown(" ")
st.sidebar.markdown("Learn more at:")
st.sidebar.markdown('[Github.com/ShengpeiWang/Kickstarter](https://github.com/ShengpeiWang/kickstarter)', unsafe_allow_html=True)
st.sidebar.markdown('[See presentation](https://docs.google.com/presentation/d/1oJsKwlv7ab87P3WkZVBMHWjuGsLIRW0dGD4xwoAYb5Q/edit?usp=sharing)', unsafe_allow_html=True)

# Main page ===============================================================================
# inputs-------------------------------------------------------
st.title("Let's kickstart your Kickstarter project!")

u_title = st.text_input("What's your idea?", "Black Diplomats - Decolonize the global affairs conversation", key = "title")

u_blurb = st.text_input("Blurb?", "A podcast and video series called Black Diplomats, featuring interviews with POC and women who specialize in global affairs.", key = "blurb")

u_story = st.text_area("Your draft story here:", story_example, key = "story")

st.button('Run')

# run model based on user input---------------------------------
# data wrangling
category =  DataFrame({'category' : [c]})
title_l = len(u_title)
story_tb = u_story + " " + u_title + " " + u_blurb
story_p = preproc(story_tb)
total_words = len(story_p .split())

tfidf_m = tfidf.transform([story_p])
encoded = onehot.transform(category)

x_info = asarray([title_l, total_words])
x_sparse = hstack([tfidf_m, encoded]).toarray()
x_full = asarray(ap(x_sparse, x_info).reshape(1, -1))

pred = model.predict(x_full)

pred_median = 10 ** pred[0]

# return model prediction -----------------------------------------
st.header("Your project will raise around $" + str(round(pred_median, 2)))

# return feature importance----------------------------------------
# get words in the user entry that contributed positively or negatively to the proposal performance
result_features['input'] = tfidf_m[:1500].toarray().T
result_features['value'] = result_features['input']*result_features['importance']
rec = result_features.sort_values(axis = 'index', by = ['value'])
rec_negative = result_features.sort_values(axis = 'index', by = ['value'], ascending = False)

empty = pd.DataFrame({"feature": [" ", " ", " ", " ", " ", " ", " ", " ", " "],
                      "importance": [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      "input": [0, 0, 0, 0, 0, 0, 0, 0, 0],
                      "value": [0, 0, 0, 0, 0, 0, 0, 0, 0]})

positive = pd.concat([empty, rec[rec['value'] > 0 ]]).tail(8)

negative = pd.concat([empty, rec_negative[rec_negative['value'] < 0 ]]).tail(8)

plt.subplot(1, 3, 1)
plt.barh(range(8), negative['value'],
         color = "coral", edgecolor = "black", linewidth = 1.2)
plt.yticks(range(8), negative['feature'])
plt.title('Words to rephrase')
plt.xlabel('Importance')

plt.subplot(1, 3, 3)
plt.barh(range(8), positive['value'],
         color = "dodgerblue", edgecolor = "black", linewidth = 1.2)
plt.yticks(range(8), positive['feature'])
plt.title('Words to use more')
plt.xlabel('Importance')

st.pyplot()


# -*- coding: utf-8 -*-
"""
Notifications
-------------
Example showing how to add notifications to a characteristic and handle the responses.
Updated on 2019-07-03 by hbldh <henrik.blidh@gmail.com>
"""
import datetime
import logging
import asyncio
import platform

import binascii
import threading

from bleak import BleakClient
from bleak import _logger as logger
from bleak import discover
import queue
import json
from bleak import BleakScanner
# from pythonosc.udp_client import SimpleUDPClient
# from websocketServerTest import glQueue

from data_transfer import DataSend

glQueue=queue.Queue(maxsize=5000)
dataqueue=queue.Queue(maxsize=5000)
def findBlooth():
    newloop = asyncio.new_event_loop()
    asyncio.set_event_loop(newloop)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(findHardware())

    # loop=asyncio.get_event_loop()
    # loop.run_until_complete(findHardware())
async def findHardware():
    async with BleakScanner() as scanner:
        await asyncio.sleep(3.0)
        devices = await scanner.get_discovered_devices()
    ret=[]
    for d in devices:
        if d.name.startswith('Brain'):
            ret.append(d.name+';'+d.address)
            print(d.name,d.address)
    bloothsend=DataSend(1,ret)
    finBloothStr=json.dumps(bloothsend,default=lambda obj:obj.__dict__,sort_keys=True)
    dataqueue.put(finBloothStr)
    # dataqueue.put('findstrtes')
CHARACTERISTIC_UUID = (
    "2d30c082-f39f-4ce6-923f-3484ea480596"
)  # <--- Change to the characteristic you want to enable notifications from. 2d30c082-f39f-4ce6-923f-3484ea480596
# client=SimpleUDPClient('127.0.0.1',1337)

def notification_handler(sender, data):
    """Simple notification handler which prints the data received."""
    # print(len(data))
    print("Received data: %s" % binascii.hexlify(data))
    glQueue.put(data)

    # client.send_message("/filter1",data)

async def run(address, loop, debug=False,socket_connect_sta=None):
    global bleconnect_status
    if debug:
        import sys

        # loop.set_debug(True)
        l = logging.getLogger("asyncio")
        l.setLevel(logging.DEBUG)
        h = logging.StreamHandler(sys.stdout)
        h.setLevel(logging.DEBUG)
        l.addHandler(h)
        logger.addHandler(h)
    try:
        async with BleakClient(address, loop=loop) as client:

            bleconnect_status=True
            x = await client.is_connected()
            print(x)
            logger.info("Connected: {0}".format(x))
            # await client.write_gatt_char('2d30c083-f39f-4ce6-923f-3484ea480596', binascii.a2b_hex('62'))
            await client.start_notify(CHARACTERISTIC_UUID, notification_handler)
            await client.write_gatt_char('2d30c083-f39f-4ce6-923f-3484ea480596', binascii.a2b_hex('43'))
            await asyncio.sleep(1.0, loop=loop)
            await client.write_gatt_char('2d30c083-f39f-4ce6-923f-3484ea480596', binascii.a2b_hex('62'))
            # await client.write_gatt_char('2d30c083-f39f-4ce6-923f-3484ea480596', binascii.a2b_hex('62')) #2d30c083-f39f-4ce6-923f-3484ea480596
            # await client.write_gatt_char('2d30c083-f39f-4ce6-923f-3484ea480596', binascii.a2b_hex('43'))
            blestatus_number=0
            while True:
                blestats=await client.is_connected()
                if blestats==False:
                    blestatus_number=blestatus_number+1
                if blestatus_number>=5 or socket_connect_sta.connect==False:
                    if blestatus_number>=5:
                        socket_connect_sta.ble_is_alive=False
                        error_ret_obj=DataSend(1008,"蓝牙断开连接")
                        error_ret_str=json.dumps(error_ret_obj,default=lambda obj:obj.__dict__,sort_keys=True)
                        dataqueue.put(error_ret_str)
                    bleconnect_status=False
                    await client.stop_notify(CHARACTERISTIC_UUID)
                    await client.disconnect()
                    break
                await asyncio.sleep(1.0, loop=loop)
                # await client.write_gatt_char('2d30c083-f39f-4ce6-923f-3484ea480596', binascii.a2b_hex('43'))
            await client.stop_notify(CHARACTERISTIC_UUID)
    except Exception as e:
        print(e)
def connect(imei,socket_connect_sta):
    from data_analysis import dataAnalysis
    datathread=threading.Thread(target=dataAnalysis,args=(socket_connect_sta,))
    datathread.setDaemon(True)
    datathread.start()
    address = (
        imei  # <--- BC:DD:C2:C9:12:22Change to your device's address here if you are using Windows or Linux
        if platform.system() != "Darwin"
        else imei  # <--- Change to your device's address here if you are using macOS
    )

    newloop = asyncio.new_event_loop()
    asyncio.set_event_loop(newloop)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run(address, loop, True,socket_connect_sta))

if __name__ == "__main__":
    import os
    print(str)

    os.environ["PYTHONASYNCIODEBUG"] = str(1)
    address = (
        "BC:DD:C2:C9:12:22"  # <--- BC:DD:C2:C9:12:22Change to your device's address here if you are using Windows or Linux
        if platform.system() != "Darwin"
        else "243E23AE-4A99-406C-B317-18F1BD7B4CBE"
              # <--- Change to your device's address here if you are using macOS
    )
    print(address)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run(address, loop, True,'test'))


#!/usr/bin/python3

#In folder must be file translate.txt and files translate_*.txt

import glob, sys

orig = "translate.txt"
nams = glob.glob("./translate_*.txt")
strg = "STRG.txt"

sorig = list()
count = 0
sstrg = list()

trans = list()

stat = list()
stat.append(0) #strg
stat.append(0) #orig

with open(orig) as f:
    for i in f:
        sorig.append(i)
        count += 1

with open(strg) as f:
    for i in f:
        sstrg.append(i)

for tr in nams:
    j = 0
    cu = list()
    stat.append(0)
    with open(tr) as f:
        for i in f:
            cu.append(i)
            j += 1
    if j != count:
        print("Wrong lines count in " + tr)
        sys.exit()
    trans.append(cu)

fin = list()

def resolve(i, d):
    global trans, sstrg, strg, sorig, orig, nams, stat, fin
    print("RESOLVE:\n" + strg + " [0]: " + sstrg[i])
    print(orig + " [1]: " + sorig[i])
    for j in d:
        print(nams[j] + " [" + str(j + 2) + "]: " + trans[j][i])
    print("Select: ")
    s = int(input())
    if s < 0 or s > len(d) + 2:
        print("wrong number")
        resolve()
    else:
        p = ""
        if s == 0:
            p = sstrg[i]
        elif s == 1:
            p = sorig[i]
        else:
            p = trans[s-2][i]
        stat[s] += 1
        fin.append(p)

for i in range(count):
    d = list()
    for c in range(len(trans)):
        if trans[c][i] != sorig[i]:
            d.append(c)
    if len(d) > 1:
        resolve(i, d)
    elif len(d) == 1:
        fin.append(trans[d[0]][i])
        stat[d[0] + 2] += 1
    else:
        fin.append(sorig[i])
        stat[1] += 1

with open("final.txt", "w") as f:
    for i in fin:
        f.write(i)

print("DONE")
print("count:\t\t\t" + str(count))
print("stat: ")
print(strg + ":\t\t" + str(stat[0]))
print(orig + ":\t\t" + str(stat[1]))
for d in range(len(nams)):
    print(nams[d] + ":\t" + str(stat[d+2]))


# Crie um código em Python que teste se o site Pudim está acessível pelo computador usado.

import urllib.request

try:
    site = urllib.request.urlopen('http://pudim.com.br/')
except:
    print('O site não está disponível no momento. Tente mais tarde.')
else:
    print('\033[33mConexão com o site estabelecida com sucesso.\033[m')

Módulo 3/Desafios/Desafio114 - Site está acessível.py


from datetime import date, timedelta
import pandas as pd
import requests

from get_stats import get_team_stats_dict
from get_matches import get_match_results
from available_stats import available_stats

# [{'Sacramento Kings': 'Boston Celtics', 'Charlotte Hornets': 'Philadelphia 76ers'}, ['W', 'L']]
# team stats is a dataframe
def to_dataframe(daily_games, start_date, end_date, season):  # , mean_dict, std_dict):
    full_dataframe = []
    game_number = 0  # counter to match with the correct game
    daily_results = daily_games[1]  # win or loss for each game
    score = daily_games[2]
    game_id = daily_games[3]

    for home_team, away_team in daily_games[0].items():  # loops through matchups
        home_team_stats = get_team_stats_dict(home_team, start_date, end_date, season)
        away_team_stats = get_team_stats_dict(away_team, start_date, end_date, season)

        current_game = [home_team, away_team]

        current_game.append(game_id[game_number])

        current_game.append(score.pop(0))

        for stat, stat_type in available_stats.items():
            current_game.append(home_team_stats[stat])

        current_game.append(score.pop(0))

        for stat, stat_type in available_stats.items():
            current_game.append(away_team_stats[stat])

        if daily_results[game_number] == 'W':
            result = 1
        else:
            result = 0

        current_game.append(result)
        game_number += 1

        print(current_game)

        full_dataframe.append(current_game)

    return full_dataframe

def date_range(start_date, end_date):
    for n in range(int((end_date - start_date).days)):
        yield start_date + timedelta(n)

def training_set(start_year, start_month, start_day, end_year, end_month, end_day, season, season_start):
    start_date = date(start_year, start_month, start_day)
    end_date = date(end_year, end_month, end_day)

    total_games = []

    for single_date in date_range(start_date, end_date):
        current_date = single_date.strftime('%m/%d/%Y')
        print(current_date)

        previous_day = single_date - timedelta(days=1)
        previous_day_formatted = previous_day.strftime('%m/%d/%Y')

        current_day_games = get_match_results(current_date, season)
        current_day_games_with_stats = to_dataframe(current_day_games, season_start, previous_day_formatted, season)

        for game in current_day_games_with_stats:
            game.append(current_date)
            total_games.append(game)

    print(total_games)
    return total_games

def make_dataframe(game_list):
    games = pd.DataFrame(game_list,
                         columns=['Home', 'Away', 'Game_ID', 'H_Score', 'H_W_PCT', 'H_FG_PCT', 'H_FG3_PCT', 'H_FT_PCT',
                                  'H_REB', 'H_AST', 'H_TOV', 'H_STL',
                                  'H_BLK', 'H_PLUS_MINUS', 'H_OFF_RATING', 'H_DEF_RATING', 'H_TS_PCT', 'A_Score',
                                  'A_W_PCT', 'A_FG_PCT', 'A_FG3_PCT',
                                  'A_FT_PCT', 'A_REB', 'A_AST', 'A_TOV', 'A_STL',
                                  'A_BLK', 'A_PLUS_MINUS', 'A_OFF_RATING', 'A_DEF_RATING', 'A_TS_PCT', 'Result',
                                  'Date'])

    print(games)
    return games

def main():
    attempts = 10

    for i in range(attempts):
        try:
            #start day has to be at least three days after the start of the season
            all_games = training_set(start_year=2020, start_month=12, start_day=27, end_year=2021, end_month=3,
                                     end_day=20,
                                     season='2020-21', season_start='12/22/2020')
            df = make_dataframe(all_games)

            print(df)
            df.to_csv(r'C:\Users\student\honors\nba\nba_data\nba_df_2020.csv', index=False)
        except requests.exceptions.ReadTimeout or ValueError:
            if i < attempts - 1:
                continue
            else:
                raise
        break

if __name__ == '__main__':
    main()


N = int(input("Write an integer: "))
odd_numbers = list()
even_numbers = list()
#even_numbers = [e for e in range(1, N+1) if (e % 2) == 0]
#odd_numbers = [o for o in range(1, N+1) if (o % 2) == 0]
for i in range(1, N+1):
    if (i % 2) == 0:
        even_numbers.append(i)
    else:
        odd_numbers.append(i)
sum_of_odds = 0
for m in odd_numbers:
    sum_of_odds += m
sum_of_evens = 0
for j in even_numbers:
    sum_of_evens += j
avarage_of_evens = sum_of_evens // len(even_numbers)
print("""
The sum of odd numbers = {}
The avarage of even numbers = {}

""".format(sum_of_odds,avarage_of_evens))


#!/usr/bin/env python3
import os
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import ParseError
from datetime import datetime
from urllib.request import urlretrieve
from urllib.parse import urlparse

SAVE_DIR = '/tmp/podcasts'
XML_FILE_PATH = 'http://rss.dw.com/xml/DKpodcast_dwn1_en'

def parse_xml(root):
    for l1 in root:
        for l2 in l1:
            if not l2.tag == 'item':
                continue
            for l3 in l2:
                if not l3.tag == 'enclosure':
                    continue
                url = l3.attrib.get('url')
                filename = retrieve_filename(url)
                if os.path.splitext(filename)[-1] == '.mp3' or l3.attrib.get('type') == 'audio/mpeg':
                    filepath = os.path.join(SAVE_DIR, filename or datetime.now().isoformat())
                    if os.path.exists(filepath):
                        print("File {} already exists".format(filename))
                        continue
                    urlretrieve(url, filepath)

def retrieve_filename(url):
    path = urlparse(url).path
    return os.path.basename(path)

if __name__ == '__main__':
    xml_file = urlretrieve(XML_FILE_PATH, os.path.join('/tmp', retrieve_filename(XML_FILE_PATH) + '.xml'))[0]
    try:
        tree = ET.parse(xml_file)
    except FileNotFoundError:
        print("File can't be downloaded")
        exit(1)
    except ParseError:
        print("Incorrect file. Are you sure it is in xml format?")
        exit(1)

    os.makedirs(SAVE_DIR, exist_ok=True)

    parse_xml(tree.getroot())


from flask import Flask, render_template, jsonify, Response
from flask_mysqldb import MySQL
import pandas as pd
import json
import os

app = Flask(__name__)

#MySQL configurations
app.config['MYSQL_USER'] = 'Enter SQL Username'
app.config['MYSQL_PASSWORD'] = 'Enter SQL Password'
app.config['MYSQL_DB'] = 'HIV_AIDS'
app.config['MYSQL_HOST'] = 'localhost'
mysql = MySQL(app)

@app.route('/')
def home():
        return render_template ("hiv.html")

@app.route('/treatment')
def treatment():
        return render_template("treatments.html")

@app.route('/donate')
def donate():
        return render_template("donate.html")

@app.route('/prevention')
def prevention():
        return render_template("preventions.html")

@app.route('/death')
def death():
        return render_template("deaths.html")

@app.route('/hiv_info')
def hiv_info():
        with open(os.path.join('Resources', 'CSV files', 'aids_2013_to_2017.csv'), newline='') as csvfile:
                line = csvfile.readline()
                rows = []
                while line:
                        print(line)
                        rows.append(line)
                        line = csvfile.readline()
                join = '\n'.join(rows)
                resp = Response(join)
                resp.headers["Content-Type"] = 'application/csv'
                return resp

@app.route("/geojson")
def geojson():
        with open(os.path.join('Resources', 'geoJSON', 'countries.geojson')) as f:
                d = json.load(f)
                return jsonify(d)

@app.route('/life-expectancy')
def life_expectancy():
        cur = mysql.connection
        df = pd.read_sql('SELECT Entity, Year, Life_Expectancy FROM  Life_Expectancy', cur)

        jsonfiles = json.loads(df.to_json(orient='records'))

        return jsonify(jsonfiles)

@app.route('/deaths')
def deaths():
        cur = mysql.connection

        df = pd.read_sql('SELECT Entity, Year, Toddlers, Teens, Adults, Retired, Elderly FROM Death', cur)

        jsonfiles = json.loads(df.to_json(orient='records'))

        return jsonify(jsonfiles)

@app.route('/aids')
def aids():
        cur = mysql.connection

        df = pd.read_sql('SELECT Entity, Year, Deaths FROM AIDS', cur)

        jsonfiles = json.loads(df.to_json(orient='records'))
        return jsonify(jsonfiles)

@app.route('/art')
def art():
        cur = mysql.connection

        df = pd.read_sql('SELECT Entity,Year, `Percent_Living_With_HIV` FROM ART', cur)

        jsonfiles = json.loads(df.to_json(orient='records'))
        return jsonify(jsonfiles)

if __name__ == '__main__':
    app.run(debug=True)


# Here is one type of pseudocode for this coding schema:
#
# Take a string and determine the relevant frequencies of the characters.
# Build and sort a list of tuples from lowest to highest frequencies.
# Build the Huffman Tree by assigning a binary code to each letter, using shorter codes for the more frequent letters. (This is the heart of the Huffman algorithm.)
# Trim the Huffman Tree (remove the frequencies from the previously built tree).
# Encode the text into its compressed form.
# Decode the text from its compressed form.
# You then will need to create encoding, decoding, and sizing schemas.

import sys

class Node(object):
    def __init__(self, letter=None, freq=None, left_child=None, right_child=None):
        self.letter = letter
        self.freq = freq
        self.left_child = left_child
        self.right_child = right_child
        self.code = ''

class Tree:
    def __init__(self, node, single):
        self.root = node
        self.single = single
        self.codes = {}

    def create_binary(self, node):

        # check data is not single character, if yes binary = 0
        if self.single:
            node.code = '0'
            self.codes[node.letter] = node.code
            return

        # check if node contains left child, if yes binary code string + 0
        if node.left_child is not None:
            node.left_child.code = node.code + '0'
            self.create_binary(node.left_child)

        # check if node contains right child if yes binary code string + 1
        if node.right_child is not None:
            node.right_child.code = node.code + '1'
            self.create_binary(node.right_child)

        # if not single , left child , or right child binary code complete output {letter : binary code}
        if node.letter is not None and node.letter != '':
            self.codes[node.letter] = node.code

class PriorityQueue:

    # create queue and set length param to 0
    def __init__(self):
        self.queue = []
        self.length = 0

    # add the node to the queue increase length by 1
    def put(self, node):
        self.queue.append(node)
        self.length += 1

    # find least frequently used node, loop over the queue by index if the given node freq is less then the first
    # node in the queue set lfu to node value of that index once lfu found decrease len of queue by 1 and remove node
    # from priority queue
    def pop_lfu(self):
        lfu = self.queue[0]
        index = 0
        for i in range(self.length):
            if self.queue[i].freq < lfu.freq:
                lfu = self.queue[i]
                index = i

        self.length -= 1
        del self.queue[index]
        return lfu

def huffman_encoding(data):

    # ensure that data is a str, if no then return a none value
    if not isinstance(data, str) or len(data) == 0:
        return None, None

    # initialize a dict, loop over the letters in the provided data if letter is in the dict add 1 to the freq if not
    # yet in f set value to 1
    f = {}
    for letter in data:
        if letter in f:
            f[letter] += 1
        else:
            f[letter] = 1

    # set PriorityQueue class to priority_queue variable
    priority_queue = PriorityQueue()

    # loop over the letters in the frequency dict, create node objects with initialized values and add these nodes to
    # the priority queue
    for letter in f:
        node = Node(letter, f[letter])
        priority_queue.put(node)

    # while there're still nodes in the queue get the least frequently used (lfu) node and set it to a node variable
    # to be combined with the next lfu node in the queue if one exists. This creates a parent node with the freq equal
    # to the freq of the lfu_1 and lfu_2 combined and puts that combined node value back into the queue for further
    # iteration
    while priority_queue.length > 1:
        node_1 = priority_queue.pop_lfu()
        node_2 = priority_queue.pop_lfu()
        parent_node_freq = node_1.freq + node_2.freq
        parent_node = Node("", parent_node_freq, node_1, node_2)
        priority_queue.put(parent_node)

    # root is updated to first value in priority queue as it is now the first value in the huffman tree, check if length
    # of data is a single character or multiple if single add True value so iteration stops in decode action
    root = priority_queue.queue[0]
    if data == len(data) * data[0]:
        single = True
    else:
        single = False

    # create the binary tree, passing in the root and single boolean value if single True binary tree value will be set
    # to 0, else create the binary tree starting with the root node, setting the codes variable to the binary codes of
    # the branches
    binary_tree = Tree(root, single)
    binary_tree.create_binary(root)
    codes = binary_tree.codes

    # added codes to string return the string of binary data along with the binary tree
    encoded = ''
    for letter in data:
        encoded += codes[letter]

    return encoded, binary_tree

def huffman_decoding(encoded, tree):

    decoded = ''
    root = tree.root
    node = root
    index = 0

    # check if tree is only a single character if so return it
    if tree.single:
        decoded = root.letter * root.freq
        return decoded

    # while the index is not equal to the length of the encoded string, go through the endcoded data if the code is 0
    # traverse left, if node is 1 traverse right adding one to the index each iteration until left and right are none
    # once none add the letter of that last node to the decoded string
    while index != len(encoded):
        if encoded[index] == '0':
            node = node.left_child
        elif encoded[index] == '1':
            node = node.right_child
        if node.left_child is None and node.right_child is None:
            decoded += node.letter
            node = root
        index += 1

    return decoded

def testing(data):
    encoded, tree = huffman_encoding(data)

    if encoded is not None:
        print("------------------------------------------------------------")
        print("The size of the data is: {}\n".format(sys.getsizeof(data)))
        print("The content of the data is: {}\n".format(data))

        encoded, tree = huffman_encoding(data)

        print("The size of the encoded data is: {}\n".format(sys.getsizeof(int(encoded, base=2))))
        print("The content of the encoded data is: {}\n".format(encoded))

        decoded = huffman_decoding(encoded, tree)

        print("The size of the decoded data is: {}\n".format(sys.getsizeof(decoded)))
        print("The content of the encoded data is: {}\n".format(decoded))

testing(1)  # return none
testing('')  # return none
testing('Z')  # original size: 50, content: Z, compressed size: 24, binary: 0, decoded size: 50, decoded content: Z
testing('ZZ')  # original size: 51, content: ZZ, compressed size: 24, binary: 00, decoded size: 51, decoded content: ZZ
testing("The bird is the word")  # original size: 69, content: The bird is the word, compressed size: 36,
                                 # binary: 0110111011111100111000001010110000100011010011110111111010101011001010
                                 # decoded size: 69, decoded content: The bird is the word