from __future__ import annotations

import base64
import datetime
import hmac
import json
import os
import re
import time
import urllib.parse
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Sequence, Tuple

from .xml import etree

if TYPE_CHECKING:
    from .path import AzurePath
    from .request import Request

AZURE_SAS_TOKEN_EXPIRATION_SECONDS = 60 * 60
# these seem to be expired manually, but we don't currently detect that
AZURE_SHARED_KEY_EXPIRATION_SECONDS = 24 * 60 * 60
OAUTH_TOKEN = "oauth_token"
SHARED_KEY = "shared_key"

def load_credentials() -> Dict[str, Any]:
    # When AZURE_USE_IDENTITY=1, boostedblob will use the azure-identity package to retrieve AAD access tokens
    if os.getenv("AZURE_USE_IDENTITY", "0") == "1":
        return {"_azure_auth": "azure-identity"}

    # AZURE_STORAGE_KEY seems to be the environment variable mentioned by the az cli
    # AZURE_STORAGE_ACCOUNT_KEY is mentioned elsewhere on the internet
    for varname in ["AZURE_STORAGE_KEY", "AZURE_STORAGE_ACCOUNT_KEY"]:
        if varname in os.environ:
            account = {}
            if "AZURE_STORAGE_ACCOUNT" in os.environ:
                account["account"] = os.environ["AZURE_STORAGE_ACCOUNT"]
            return {"_azure_auth": "sakey", "storage_account_key": os.environ[varname], **account}

    if "AZURE_STORAGE_CONNECTION_STRING" in os.environ:
        connection_data = {}
        # technically this should be parsed according to the rules in
        # https://www.connectionstrings.com/formating-rules-for-connection-strings/
        for part in os.environ["AZURE_STORAGE_CONNECTION_STRING"].split(";"):
            key, _, val = part.partition("=")
            connection_data[key.lower()] = val
        return {
            "_azure_auth": "sakey",
            "account": connection_data["accountname"],
            "storage_account_key": connection_data["accountkey"],
        }

    if "AZURE_APPLICATION_CREDENTIALS" in os.environ:
        creds_path = os.environ["AZURE_APPLICATION_CREDENTIALS"]
        if not os.path.exists(creds_path):
            raise RuntimeError(
                f"Credentials not found at '{creds_path}' specified by environment variable 'AZURE_APPLICATION_CREDENTIALS'"
            )
        with open(creds_path) as f:
            creds = json.load(f)
            return {
                "_azure_auth": "svcact",
                "client_id": creds["appId"],
                "client_secret": creds["password"],
                "tenant_id": creds["tenant"],
            }

    if "AZURE_CLIENT_ID" in os.environ:
        return {
            "_azure_auth": "svcact",
            "client_id": os.environ["AZURE_CLIENT_ID"],
            "client_secret": os.environ["AZURE_CLIENT_SECRET"],
            "tenant_id": os.environ["AZURE_TENANT_ID"],
        }

    # look for a refresh token in the az command line credentials
    # TODO: we could also try to use any found access tokens
    msal_tokens_path = os.path.expanduser("~/.azure/msal_token_cache.json")
    if os.path.exists(msal_tokens_path):
        with open(msal_tokens_path) as f:
            tokens = json.load(f)
            for token in tokens.get("RefreshToken", {}).values():
                if token["credential_type"] != "RefreshToken":
                    continue
                return {"_azure_auth": "refresh", "refresh_token": token["secret"]}

    access_tokens_path = os.path.expanduser("~/.azure/accessTokens.json")
    if os.path.exists(access_tokens_path):
        with open(access_tokens_path) as f:
            tokens = json.load(f)
            best_token = None
            for token in tokens:
                if "refreshToken" not in token:
                    continue
                creds = {"_azure_auth": "refresh", "refresh_token": token["refreshToken"]}
                if best_token is None:
                    best_token = creds
                else:
                    # expiresOn may be missing for tokens from service principals
                    if token.get("expiresOn", "") > best_token.get("expiresOn", ""):
                        best_token = creds
            if best_token is not None:
                return best_token

    raise RuntimeError(
        """Azure credentials not found, please do one of the following:

1) Log in with 'az login', boostedblob will use your default credentials to lookup your storage
   account key
2) Create an account with 'az ad sp create-for-rbac --name <name>' and
   individually set the 'AZURE_CLIENT_ID', 'AZURE_CLIENT_SECRET', and
   'AZURE_TENANT_ID' environment variables
3) Create an account as in (2), save the credentials in a JSON file, and set the path to this file
   in the 'AZURE_APPLICATION_CREDENTIALS' environment variable. The JSON schema should be:
   {"appId": "$AZURE_CLIENT_ID", "password": "$AZURE_CLIENT_SECRET", "tenant": "$AZURE_TENANT_ID"}
4) Set the environment variable 'AZURE_STORAGE_ACCOUNT_KEY' to your storage account key which you
   can find by following this guide:
   https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage
"""
    )

def load_stored_subscription_ids() -> List[str]:
    """Return a list of subscription ids from the local azure profile.

    The default subscription will appear first in the list.

    """
    default_profile_path = os.path.expanduser("~/.azure/azureProfile.json")
    if not os.path.exists(default_profile_path):
        return []

    with open(default_profile_path, "rb") as f:
        # this file has a UTF-8 BOM
        profile = json.loads(f.read().decode("utf-8-sig"))

    subscriptions = profile.get("subscriptions", [])
    subscriptions.sort(key=lambda x: x["isDefault"], reverse=True)
    return [sub["id"] for sub in subscriptions]

async def get_access_token(cache_key: Tuple[str, Optional[str]]) -> Tuple[Any, float]:
    account, container = cache_key

    now = time.time()
    creds = load_credentials()

    # If opted into using azure-identity, use DefaultAzureCredential to get a token
    # This enables the use of Managed Identity, Workload Identity, and other auth methods not implemented here
    if creds["_azure_auth"] == "azure-identity":
        try:
            from azure.identity.aio import DefaultAzureCredential  # type: ignore
        except ImportError:
            raise RuntimeError(
                "When setting AZURE_USE_IDENTITY=1, you must also install the azure-identity package"
            )

        async with DefaultAzureCredential() as cred:
            token = await cred.get_token("https://storage.azure.com/.default")
        auth = (OAUTH_TOKEN, token.token)
        if await can_access_account(account, container, auth):
            return (auth, token.expires_on)

    if creds["_azure_auth"] == "sakey":
        if "account" in creds:
            if creds["account"] != account:
                raise RuntimeError(
                    f"Provided storage account key for account '{creds['account']}' via "
                    f"environment variables, but needed credentials for account '{account}'"
                )
        auth = (SHARED_KEY, creds["storage_account_key"])
        if await can_access_account(account, container, auth):
            return (auth, now + AZURE_SHARED_KEY_EXPIRATION_SECONDS)
        raise RuntimeError(
            f"Found storage account key, but it was unable to access storage account: '{account}'"
        )

    from .globals import config

    if creds["_azure_auth"] == "refresh":
        # we have a refresh token, convert it into an access token for this account
        req = create_access_token_request(
            creds=creds,
            scope=f"https://{account}.blob.core.windows.net/.default",
            success_codes=(200, 400),
        )

        async with req.execute() as resp:
            result = await resp.json()
            if resp.status == 400:
                if (
                    result["error"] == "invalid_grant"
                    and "AADSTS700082" in result["error_description"]
                ) or (
                    result["error"] == "interaction_required"
                    and "AADSTS50078" in result["error_description"]
                ):
                    raise RuntimeError(
                        "Your refresh token has expired, please run `az login` to refresh it"
                    )
                raise RuntimeError(
                    "Encountered an error when requesting an access token:\n"
                    f"{result['error']}: {result['error_description']}\n\n"
                    "Try running `az login`?"
                )

        auth = (OAUTH_TOKEN, result["access_token"])

        # for some azure accounts this access token does not work, check if it works
        if await can_access_account(account, container, auth):
            return (auth, now + float(result["expires_in"]))

        # it didn't work, fall back to getting the storage keys
        if config.storage_account_key_fallback:
            storage_account_key_auth = await get_storage_account_key(
                account=account, creds=creds, container_hint=container
            )
            if storage_account_key_auth is not None:
                return (storage_account_key_auth, now + AZURE_SHARED_KEY_EXPIRATION_SECONDS)

    if creds["_azure_auth"] == "svcact":
        # we have a service principal, get an oauth token
        req = create_access_token_request(creds=creds, scope="https://storage.azure.com/.default")

        async with req.execute() as resp:
            result = await resp.json()
        auth = (OAUTH_TOKEN, result["access_token"])
        if await can_access_account(account, container, auth):
            return (auth, now + float(result["expires_in"]))

        # it didn't work, fall back to getting the storage keys
        if config.storage_account_key_fallback:
            storage_account_key_auth = await get_storage_account_key(
                account=account, creds=creds, container_hint=container
            )
            if storage_account_key_auth is not None:
                return (storage_account_key_auth, now + AZURE_SHARED_KEY_EXPIRATION_SECONDS)

    raise RuntimeError(
        f"Could not find any credentials that grant access to storage account: '{account}'"
    )

async def can_access_account(account: str, container: Optional[str], auth: Tuple[str, str]) -> bool:
    from .request import Request, azurify_request

    if not container:
        # if a container isn't specified, check that we can list the storage account
        req = Request(
            method="GET",
            url=f"https://{account}.blob.core.windows.net",
            params={"comp": "list", "maxresults": "1"},
            success_codes=(200, 403),
        )
        req = await azurify_request(req, auth=auth)

        async with req.execute() as resp:
            if resp.status == 403:
                return False
            data = await resp.read()

        result = etree.fromstring(data)
        container = result.findtext("Containers/Container/Name")

        if container is None:
            # there are no containers in this storage account
            # we can't test if we can access this storage account or not, so presume we can
            return True
        # then also test that we can list that container. this is perhaps unnecessary...

    # https://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=list
    req = Request(
        method="GET",
        url=f"https://{account}.blob.core.windows.net/{container}",
        params={"restype": "container", "comp": "list", "maxresults": "1"},
        success_codes=(200, 403),
    )
    req = await azurify_request(req, auth=auth)
    async with req.execute() as resp:
        return resp.status == 200

def create_access_token_request(
    creds: Mapping[str, str], scope: str, success_codes: Sequence[int] = (200,)
) -> Request:
    from .request import Request

    if creds["_azure_auth"] == "refresh":
        # https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token
        data = {
            "grant_type": "refresh_token",
            "refresh_token": creds["refresh_token"],
            "scope": scope,
        }
        tenant_id = "common"
    elif creds["_azure_auth"] == "svcact":
        # https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#first-case-access-token-request-with-a-shared-secret
        data = {
            "grant_type": "client_credentials",
            "client_id": creds["client_id"],
            "client_secret": creds["client_secret"],
            "scope": scope,
        }
        tenant_id = creds["tenant_id"]
    else:
        raise AssertionError
    return Request(
        url=f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token",
        method="POST",
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        data=urllib.parse.urlencode(data).encode("utf8"),
        success_codes=success_codes,
    )

async def get_storage_account_id_with_subscription(
    subscription_id: str, account: str, auth: Tuple[str, str]
) -> Optional[str]:
    from .request import Request, azurify_request

    req = Request(
        method="GET",
        url=f"https://management.azure.com/subscriptions/{subscription_id}/providers/Microsoft.Storage/storageAccounts",
        params={"api-version": "2019-04-01"},
        success_codes=(200, 401, 403, 429),
    )

    while True:
        req = await azurify_request(req, auth=auth)
        async with req.execute() as resp:
            if resp.status in (401, 403):
                # we aren't allowed to query this for this subscription, skip it
                return None
            if resp.status == 429:
                # these API endpoints have really low rate limits
                # note this error message only makes sense because the only code path that
                # currently calls get_storage_account_id_with_subscription is the storage
                # account key fallback
                raise RuntimeError(
                    "You do not have the correct IAM roles to access this location. "
                    "Check that you have Storage Blob Data Reader or Storage Blob Data Contributor "
                    "roles. You can run "
                    f"`az storage container list --auth-mode login --account-name {account}` "
                    "to confirm the missing role.\n"
                    "In this situation, boostedblob is capable of falling back to accessing the "
                    "storage account keys, but Azure has really low rate limits on these queries, "
                    "which are currently preventing us from doing so."
                )
            result = await resp.json()

        # search for the storage account
        account_id = next((obj["id"] for obj in result["value"] if obj["name"] == account), None)
        if account_id is not None:
            return account_id

        if "nextLink" not in result:
            break
        req = Request(method="GET", url=result["nextLink"], success_codes=(200, 401, 403))
    return None

async def get_storage_account_id(account: str, auth: Tuple[str, str]) -> Optional[str]:
    from .request import Request, azurify_request

    stored_subscription_ids = load_stored_subscription_ids()
    for subscription_id in stored_subscription_ids:
        storage_account_id = await get_storage_account_id_with_subscription(
            subscription_id, account, auth
        )
        if storage_account_id:
            return storage_account_id

    req = Request(
        method="GET",
        url="https://management.azure.com/subscriptions",
        params={"api-version": "2020-01-01"},
    )

    while True:
        req = await azurify_request(req, auth=auth)
        async with req.execute() as resp:
            result = await resp.json()
        subscription_ids = {item["subscriptionId"] for item in result["value"]}

        for subscription_id in subscription_ids - set(stored_subscription_ids):
            storage_account_id = await get_storage_account_id_with_subscription(
                subscription_id, account, auth
            )
            if storage_account_id:
                return storage_account_id

        if "nextLink" not in result:
            break
        req = Request(method="GET", url=result["nextLink"])
    return None

async def get_storage_account_key(
    account: str, creds: Mapping[str, Any], container_hint: Optional[str] = None
) -> Optional[Tuple[Any, float]]:
    from .request import Request, azurify_request

    # get an access token for the management service
    req = create_access_token_request(creds=creds, scope="https://management.azure.com/.default")

    async with req.execute() as resp:
        result = await resp.json()
    auth = (OAUTH_TOKEN, result["access_token"])

    storage_account_id = await get_storage_account_id(account, auth)
    if not storage_account_id:
        return None

    req = Request(
        method="POST",
        url=f"https://management.azure.com{storage_account_id}/listKeys",
        params={"api-version": "2019-04-01"},
    )
    req = await azurify_request(req, auth=auth)

    async with req.execute() as resp:
        result = await resp.json()
    for key in result["keys"]:
        if key["permissions"] == "FULL":
            storage_key_auth = (SHARED_KEY, key["value"])
            if await can_access_account(account, container_hint, storage_key_auth):
                return storage_key_auth
            raise RuntimeError(
                "Found storage account key, but it was unable to access "
                f"storage account: '{account}'"
            )
    raise RuntimeError(
        f"Storage account was found, but storage account keys were missing: '{account}'"
    )

def sign_request_with_shared_key(request: Request, key: str) -> str:
    # https://docs.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key
    from yarl import URL

    # Figuring out that shared key authorisation sometimes breaks because aiohttp is a little over
    # clever about canonicalising URLs was not fun; preemptively canonicalise
    parsed_url = urllib.parse.urlparse(str(URL(request.url)))
    storage_account = parsed_url.netloc.split(".")[0]
    blob = parsed_url.path[1:]

    def canonicalized_resource() -> str:
        params_to_sign = sorted(f"{name.lower()}:{value}" for name, value in request.params.items())
        canonical_url = f"/{storage_account}/{blob}"
        return "\n".join([canonical_url] + params_to_sign)

    def canonicalized_headers() -> str:
        headers_to_sign = []
        for name, value in request.headers.items():
            canonical_name = name.lower()
            canonical_value = re.sub(r"\s+", " ", value).strip()
            if canonical_name.startswith("x-ms-"):
                headers_to_sign.append(f"{canonical_name}:{canonical_value}")
        return "\n".join(sorted(headers_to_sign))

    headers = request.headers
    content_length = headers.get("Content-Length", "")
    if request.data is not None:
        content_length = str(len(request.data))

    parts_to_sign = [
        request.method,
        headers.get("Content-Encoding", ""),
        headers.get("Content-Language", ""),
        content_length,
        headers.get("Content-MD5", ""),
        headers.get("Content-Type", ""),
        headers.get("Date", ""),
        headers.get("If-Modified-Since", ""),
        headers.get("If-Match", ""),
        headers.get("If-None-Match", ""),
        headers.get("If-Unmodified-Since", ""),
        headers.get("Range", ""),
        canonicalized_headers(),
        canonicalized_resource(),
    ]
    string_to_sign = "\n".join(parts_to_sign)

    signature = base64.b64encode(
        hmac.digest(base64.b64decode(key), string_to_sign.encode("utf8"), "sha256")
    ).decode("utf8")

    return f"SharedKey {storage_account}:{signature}"

async def get_sas_token(cache_key: Tuple[str, Optional[str]]) -> Tuple[Any, float]:
    from .globals import config
    from .request import Request, azurify_request

    auth = await config.azure_access_token_manager.get_token(key=cache_key)
    account, container = cache_key

    if auth[0] != OAUTH_TOKEN:
        cmd = (
            f"az storage container list --auth-mode login --account-name {account}"
            if container is None
            else (
                f"az storage blob list --auth-mode login --account-name {account} "
                f"--container {container}"
            )
        )
        raise RuntimeError(
            "Only OAuth tokens can be used to get SAS tokens. You should set the "
            "Blob Data Reader or Storage Blob Data Contributor IAM role. You can run "
            f"`{cmd}` to confirm that the missing role is the issue."
        )

    # https://docs.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas
    now = datetime.datetime.utcnow()
    start = (now + datetime.timedelta(hours=-1)).strftime("%Y-%m-%dT%H:%M:%SZ")
    expiration = now + datetime.timedelta(days=6)
    expiry = expiration.strftime("%Y-%m-%dT%H:%M:%SZ")
    req = await azurify_request(
        Request(
            url=f"https://{account}.blob.core.windows.net/",
            method="POST",
            params=dict(restype="service", comp="userdelegationkey"),
            data={"KeyInfo": {"Start": start, "Expiry": expiry}},
            success_codes=(200, 403),
        ),
        auth=auth,
    )
    async with req.execute() as resp:
        if resp.status == 403:
            raise RuntimeError(
                f"You do not have permission to generate an SAS token for account {account}. "
                "Try setting the Storage Blob Delegator or Storage Blob Data Contributor IAM role "
                "at the account level."
            )
        data = await resp.read()

    result = etree.fromstring(data)
    user_delegation_key = {el.tag: el.text for el in result}
    return user_delegation_key, time.time() + AZURE_SAS_TOKEN_EXPIRATION_SECONDS

async def generate_signed_url(path: AzurePath) -> Tuple[str, datetime.datetime]:
    # https://docs.microsoft.com/en-us/rest/api/storageservices/delegate-access-with-shared-access-signature
    # https://docs.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas
    # https://docs.microsoft.com/en-us/rest/api/storageservices/service-sas-examples
    from .globals import config

    key = await config.azure_sas_token_manager.get_token(key=(path.account, path.container or None))
    params = {
        "st": key["SignedStart"],
        "se": key["SignedExpiry"],
        "sks": key["SignedService"],
        "skt": key["SignedStart"],
        "ske": key["SignedExpiry"],
        "sktid": key["SignedTid"],
        "skoid": key["SignedOid"],
        # signed key version (param name not mentioned in docs)
        "skv": key["SignedVersion"],
        "sv": "2018-11-09",  # signed version
        "sr": "b",  # signed resource
        "sp": "r",  # signed permissions
        "sip": "",  # signed ip
        "si": "",  # signed identifier
        "spr": "https,http",  # signed http protocol
        "rscc": "",  # Cache-Control header
        "rscd": "",  # Content-Disposition header
        "rsce": "",  # Content-Encoding header
        "rscl": "",  # Content-Language header
        "rsct": "",  # Content-Type header
    }

    canonicalized_resource = f"/blob/{path.account}/{path.container}/{path.blob}"
    parts_to_sign = (
        params["sp"],
        params["st"],
        params["se"],
        canonicalized_resource,
        params["skoid"],
        params["sktid"],
        params["skt"],
        params["ske"],
        params["sks"],
        params["skv"],
        params["sip"],
        params["spr"],
        params["sv"],
        params["sr"],
        params["rscc"],
        params["rscd"],
        params["rsce"],
        params["rscl"],
        params["rsct"],
        # this is documented on a different page
        # https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas#specifying-the-signed-identifier
        params["si"],
    )
    string_to_sign = "\n".join(parts_to_sign)
    params["sig"] = base64.b64encode(
        hmac.digest(base64.b64decode(key["Value"]), string_to_sign.encode("utf8"), "sha256")
    ).decode("utf8")
    query = urllib.parse.urlencode({k: v for k, v in params.items() if v != ""})

    expiry = datetime.datetime.strptime(key["SignedExpiry"], "%Y-%m-%dT%H:%M:%SZ")
    url = path.format_url("https://{account}.blob.core.windows.net/{container}/{blob}")
    return url + "?" + query, expiry


from itertools import combinations

from lotto.bill import Bill
from lotto.bet_type import BetType
from lotto.extraction import Extraction

class CalculateWin:
    """Contains information and manages the calculations of a lottery win.

    :param gross_winnings: dict which contains the gross amount of Lotto winnings obtained by betting €1 on a single
    wheel, the key indicates the amount of bills played, and the value a list containing the winning amount for each
    type of bet
    :param bet_type_indexes: dict where the key is the type of bet and the value is an integer that
    represents the reference index to obtain the amount in the values of the variable gross_winnings
    :param max_amount: represents the maximum amount beyond which a tax retention is applied, defaults to 500
    :param tax_retention: represents the percentage of tax retention, defaults to 8
    :param tutte_wheel_div: represents the number by which the gross amount must be divided if playing on the "Tutte" wheel, defaults to 10
    """
    gross_winnings = {1: [11.23],
                      2: [5.61, 250],
                      3: [3.74, 83.33, 4500],
                      4: [2.8, 41.66, 1125, 120000],
                      5: [2.24, 25, 450, 24000, 6000000],
                      6: [1.87, 16.66, 225, 8000, 1000000],
                      7: [1.6, 11.9, 128.57, 3428.57, 285714.28],
                      8: [1.4, 8.92, 80.35, 1714.28, 107142.85],
                      9: [1.24, 6.94, 53.57, 952.38, 47619.04],
                      10: [1.12, 5.55, 37.5, 571.42, 23809.52]}
    bet_type_indexes = {"ambata": 0, "ambo": 1, "terno": 2, "quaterna": 3, "cinquina": 4}
    max_amount = 500
    tax_retention = 8
    tutte_wheel_div = 10

    def __init__(self, bill: Bill, extraction: Extraction):
        """Constructor Method.

        :param bill: represents the winning bill
        :param extraction: represents the reference extraction
        :param self.guessed_numbers: represents the numbers guessed in total
        :param self.combinations: represents all guessed combinations
        :param self.gross_amount: represents the gross amount of the winnings
        :param self.net_amount: represents the net amount of the winnings without tax retention
        """
        self.bill = bill
        self.extraction = extraction
        self.guessed_numbers = extraction.count_guessed_numbers(bill)
        self.combinations = self.calculate_combinations()
        self.gross_amount = self.calculate_gross_amount()
        self.net_amount = self.calculate_net_amount()

    def calculate_combinations(self) -> int:
        """Takes care of calculating all combinations in a win.

        :return: the number of total combinations guessed
        """
        numbers_by_combination = BetType.available_bet_type[self.bill.bet_type]
        numbers_played = self.guessed_numbers
        total_combinations = len(list(combinations(range(numbers_played), numbers_by_combination)))
        return total_combinations

    def calculate_gross_amount(self) -> float:
        """Takes care of making calculations for the gross amount of the winnings.

        :return: the gross amount rounded to two digits after the decimal point
        """
        combinations = self.combinations
        bet_type = self.bill.bet_type
        numbers_played = self.bill.numbers_to_generate
        bet_amount = self.bill.bet_amount
        i = CalculateWin.bet_type_indexes[bet_type]

        unit_amount = CalculateWin.gross_winnings[numbers_played][i]
        if self.bill.city == "Tutte":
            unit_amount = unit_amount / CalculateWin.tutte_wheel_div
        gross_amount = unit_amount * bet_amount * combinations

        return round(gross_amount, 2)

    def calculate_net_amount(self) -> float:
        """Takes care of making calculations for the net amount of the winnings.
        Tax retention is deducted only if the gross amount is greater than 500.

        :return: the net amount rounded to two digits after the decimal point
        """
        tax_retention = CalculateWin.tax_retention / 100
        gross_amount = self.gross_amount

        if gross_amount > CalculateWin.max_amount:
            net_amount = gross_amount - (gross_amount * tax_retention)
        else:
            net_amount = gross_amount

        return round(net_amount, 2)

    def __str__(self) -> str:
        representation = "Gross amount: € {:.2f}\nNet amount: € {:.2f} (-{}% tax retention)".format(self.gross_amount, self.net_amount, CalculateWin.tax_retention)
        return representation


#!/usr/bin/python3

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import urllib.request
import math
import qrcode
from argparse import Namespace

import argparse

def params_sanity(result):
    if(result.date == None):
        if(result.time != None):
            raise RuntimeError("Cannot have time without date")
    if(result.photo != None):
        try:
            Image.open(result.photo)
        except IOError:
            raise RuntimeError("Featured photo not found")

    if(result.name == None):
        raise RuntimeError("No event name specified")
    if(result.desc == None):
        raise RuntimeError("No event description specified")

def display_args(result):
    print("Name: " + str(result.name))
    print("Description: " + str(result.desc))
    if(result.date != None):
        if(result.time != None):
            print("Date and Time: " + str(result.date) + str(result.time))
        else:
            print("Date: " + str(result.date))

def make_blank_page():
    page = Image.new("RGB", (3300, 2550), 0xFFFFFFFF)
    return page

# wraps words in a bounding box. basic.
def draw_multiline(drawer, bounding_box, fontname, text, numlines=10000):
    yprogress = 0
    size = 300
    font = ImageFont.truetype(fontname, size)
    lineheight = font.getsize(text.split("\n")[0])[1]

    lines = []

    for lineOfText in text.split("\n"):
        line = ""
        for word in lineOfText.split(" "):
            newline = ""
            if(line == ""):
                line = word
                newline = word
            else:
                newline = line + " " + word
            if(font.getsize(newline)[0] > bounding_box[2] - bounding_box[0]):
                #drawer.text((bounding_box[0], bounding_box[1] + yprogress), line, (0,0,0,255), font=font)
                lines.append(line)
                yprogress += lineheight
                line = word
            else:
                line = newline
        lines.append(line)
        #drawer.text((bounding_box[0], bounding_box[1] + yprogress), line, (0,0,0,255), font=font)
        yprogress += lineheight
    while(yprogress > bounding_box[3] - bounding_box[1] or (len(lines) > numlines)):
        lines = []
        yprogress = 0
        lineheight = font.getsize(text.split("\n")[0])[1]
        font = ImageFont.truetype(fontname, size - 1)
        size -= 1
        print("Size = " + str(size))

        for lineOfText in text.split("\n"):
            line = ""
            for word in lineOfText.split(" "):
                newline = ""
                if(line == ""):
                    line = word
                    newline = word
                else:
                    newline = line + " " + word
                if(font.getsize(newline)[0] > bounding_box[2] - bounding_box[0]):
                    #drawer.text((bounding_box[0], bounding_box[1] + yprogress), line, (0,0,0,255), font=font)
                    lines.append(line)
                    yprogress += lineheight
                    line = word
                else:
                    line = newline
            lines.append(line)
            #drawer.text((bounding_box[0], bounding_box[1] + yprogress), line, (0,0,0,255), font=font)
            yprogress += lineheight
    yprogress = 0
    for line in lines:
        drawer.text((bounding_box[0], bounding_box[1] + yprogress), line, (0,0,0,255), font=font)
        yprogress += lineheight
    return font

def build_logistics(when, where, pizza):
    output = "When: " + str(when)
    output += " \n"
    output += "Where: " + str(where)
    if(pizza):
        output += "\nFree pizza and drinks"
    return output

def template1(background, results):
    featuredImage = Image.open(results.photo)
    print(featuredImage.size)
    # We want the featured image to be 1/5 of the size of background page
    finalSize = (math.floor(background.size[0] / math.sqrt(4)), math.floor(background.size[1] / math.sqrt(4)))
    ratio = min(finalSize[0]/(featuredImage.size[0]), finalSize[1]/(featuredImage.size[1]))
    print("Ratio: " + str(ratio))
    if(ratio > 1):
        print("You might want to find a larger image! Preferably one that is at least " + str(finalSize[0]) + "x" + str(finalSize[1]) + "(WxL)")
        print("Generating poster anyway...")
    resizeSize = (math.floor(ratio * featuredImage.size[0]), math.floor(ratio * featuredImage.size[1]))
    featuredImage = featuredImage.resize(resizeSize, Image.ANTIALIAS)

    pageMargin = 75
    internalMargin = 50

    bottomMargin = background.size[1] - pageMargin
    topMargin = pageMargin
    rightMargin = background.size[0] - pageMargin
    leftMargin = pageMargin
    sideOfFeaturedImage = featuredImage.size[0] + pageMargin
    topOfFeaturedImage = bottomMargin - pageMargin - featuredImage.size[1]
    background.paste(featuredImage, (pageMargin, topOfFeaturedImage))

    # set up text drawing
    draw = ImageDraw.Draw(background)
    supersmallfont = ImageFont.truetype("keep-calm.ttf", 50)

    # Title must be one line
    titlefont = draw_multiline(draw, (leftMargin, topMargin, rightMargin, 200 + pageMargin), "keep-calm.ttf", results.name, numlines=1)
    background.save("output.jpg")

    # LUG Promo
    topOfLUGPromo = bottomMargin - 90
    draw_multiline(draw, (sideOfFeaturedImage + internalMargin, topOfLUGPromo, rightMargin, bottomMargin), "keep-calm.ttf", "Brought to you by the Linux Users' Group")
    background.save("output.jpg")

    # Draw event description
    bottomOfTitle = titlefont.getsize(results.name)[1] + pageMargin
    draw_multiline(draw, (pageMargin, bottomOfTitle + internalMargin + pageMargin, math.floor(background.size[0] * 0.5), topOfFeaturedImage - internalMargin), "keep-calm.ttf", results.desc)
    background.save("output.jpg")

    numberOfQRCodes = 0
    if(results.facebook != None):
        numberOfQRCodes += 1
    if(results.gcal != None):
        numberOfQRCodes += 1
    if(results.website != None):
        numberOfQRCodes += 1
    # Draw qr codes
    currentQr = 0
    if(numberOfQRCodes != 0):
        qrHeight = math.floor((topOfFeaturedImage - internalMargin) / (numberOfQRCodes + 1))

    qrPositions = [(math.floor(background.size[0] * 0.5) + internalMargin, bottomOfTitle + internalMargin),
                (math.floor(background.size[0] * 0.5) + internalMargin + qrHeight + internalMargin, bottomOfTitle + internalMargin),
                (math.floor(background.size[0] * 0.5) + internalMargin, bottomOfTitle + internalMargin + internalMargin + qrHeight)]

    def getQRCaptionPosition(index, text):
        if(index == 0):
            return (math.floor(background.size[0] * 0.5) + internalMargin + (qrHeight / 2) - (supersmallfont.getsize(text)[0] / 2), bottomOfTitle + (internalMargin / 2) + qrHeight)
        elif(index == 1):
            return (math.floor(background.size[0] * 0.5) + internalMargin + internalMargin + qrHeight + (qrHeight / 2) - (supersmallfont.getsize(text)[0] / 2), bottomOfTitle + (internalMargin / 2) + qrHeight)
        elif(index == 2):
            return (math.floor(background.size[0] * 0.5) + internalMargin + (qrHeight / 2) - (supersmallfont.getsize(text)[0] / 2), bottomOfTitle + internalMargin + qrHeight + (internalMargin / 2) + qrHeight)

    if(results.facebook != None):
        facebook = qrcode.make(str(results.facebook)).resize((qrHeight, qrHeight), Image.ANTIALIAS)
        background.paste(facebook, qrPositions[currentQr])
        fbcaption = "Facebook"
        draw.text(getQRCaptionPosition(currentQr, fbcaption), fbcaption, (0,0,0,255), font=supersmallfont)
        currentQr += 1
    background.save("output.jpg")
    if(results.gcal != None):
        gcal = qrcode.make(str(results.gcal)).resize((qrHeight, qrHeight), Image.ANTIALIAS)
        background.paste(gcal, qrPositions[currentQr])
        gcalcaption = "Google Calendar"
        draw.text(getQRCaptionPosition(currentQr, gcalcaption), gcalcaption, (0,0,0,255), font=supersmallfont)
        currentQr += 1
    background.save("output.jpg")
    if(results.website != None):
        website = qrcode.make(str(results.website)).resize((qrHeight, qrHeight), Image.ANTIALIAS)
        background.paste(website, qrPositions[currentQr])
        websitecaption = "Website"
        draw.text(getQRCaptionPosition(currentQr, websitecaption), websitecaption, (0,0,0,255), font=supersmallfont)
        currentQr += 1
    background.save("output.jpg")

    # Draw event time, date, and/or location
    if(results.date != None):
        dateAndTime = build_logistics(results.date, results.location, results.pizza)
        if(results.time != None):
            dateAndTime = build_logistics(results.date + ", " + results.time, results.location, results.pizza)
        draw_multiline(draw, (sideOfFeaturedImage + internalMargin, topOfFeaturedImage, rightMargin, bottomMargin), "keep-calm.ttf", dateAndTime, numlines=3)
        print("Drew date and time")

    background.save("static/output.jpg")
    print("Done")

def buildPoster(name, desc, date, time, location, photo, facebook, gcal, website, pizza):
    if(photo != None):
        urllib.request.urlretrieve(photo, "photo.png")
    results = Namespace(name=name, desc=desc, date=date, time=time, location=location, photo="photo.png", facebook=facebook, gcal=gcal, website=website, pizza=pizza)
    template1(make_blank_page(), results)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Creates a poster for a LUG event")

    # Add necessary command line args
    parser.add_argument("-n", "--name", action="store", help="name of event")
    parser.add_argument("--desc", help="short description of event")
    parser.add_argument("-d", "--date", help="date of event", required=True)
    parser.add_argument("-t", "--time", help="time of event", required=True)
    parser.add_argument("-l", "--location", help="location of event", required=True)
    parser.add_argument("--photo", help="featured image for event", required=False)
    parser.add_argument("--facebook", help="facebook event page link", required=False)
    parser.add_argument("--gcal", help="instant add google calendar link", required=False)
    parser.add_argument("--website", help="more info website")
    parser.add_argument("--pizza", action="store_true", help="include if pizza and drinks will be provided")

    result = parser.parse_args()

    params_sanity(result)
    print("We received...")
    display_args(result)

    print("Is this correct? [yY/nN]")
    response = input("")
    if(response in ["y", "Y"]):
        print("hooray!")
        template1(make_blank_page(), result)

    else:
        print("rip :(")


# -*- coding: utf-8 -*-
"""
Created on Sun Apr 19 10:58:13 2020
@author: Alex
code for windows
"""
from typing import List
class Solution:
    def displayTable(self, orders: List[List[str]]) -> List[List[str]]:
        foods = set()
        for i in orders:
            foods.add(i[2])
        tmp = sorted(list(foods))
        pre = ['table'] + tmp[:]
        dic = {}
        for i in range(len(tmp)):
            dic[tmp[i]] = i
        lengh = len(tmp)
        res = {}
        for _, table, food in orders:
            if table not in res:
                res[table] = [int(table)] + [0]*lengh
            res[table][dic[food]+1] += 1
        ans = []
        for v in res.values():
            ans.append([str(i) for i in v])
        ans.sort(key = lambda i:int(i[0]))
        #print(ans)
        return [pre] + ans

if __name__ == "__main__":
    s = Solution()
    a1 = [["David","3","Ceviche"],["Corina","10","Beef Burrito"],["David","3","Fried Chicken"],["Carla","5","Water"],["Carla","5","Ceviche"],["Rous","3","Ceviche"]]
    #a2 =
    print(s.displayTable(a1))


import pygame

class Text:
    """This class holds information about the text-elements. Can make them also clickable"""

    def __init__(self, name, font, size, content=""):
        self.name = name
        self.x = 0
        self.y = 0
        self.font = font  # font_path = "./fonts/newfont.ttf"
        self.fontSize = size  # font_size = 32
        self.content = [content, 0]
        self.label = self.get_font().render(content, 1, (255, 255, 0))
        self.rect = None

    def get_font(self):
        """Get a pygame font object upon the provided attributes"""

        return pygame.font.Font(self.font, self.fontSize)

    def set_coords(self, x, y):
        """Set the coordinates for the rectangle and label."""
        self.x = x
        self.y = y
        self.rect = self.label.get_rect(topleft=(x, y))

    def set_label(self, with_var):
        """Set the label for the text. If there is a var (like for points), add it."""

        if with_var:
            self.label = self.get_font().render(self.content[0] + str(self.content[1]), 1, (255, 255, 0))
        else:
            self.label = self.get_font().render(self.content[0], 1, (255, 255, 0))


from typing import Optional

import numpy as np

from torch.utils.data import DataLoader
import torch
import torch.nn as nn
from torch import optim

from model.neural_networks.experience_database import ExperienceDatabase
from model.model import Model

class NeuralNetworks(Model):
    def __init__(self, architecture, data_size_for_fit=1, learning_rate=0.01):
        super().__init__()
        self._data_size_for_fit = data_size_for_fit
        self._learning_rate = learning_rate
        self._experience_database: Optional[ExperienceDatabase] = None
        self._neural_networks: nn.Module = architecture

    def create(self, inpout_dimension, output_dimension):
        self._neural_networks.create(inpout_dimension, output_dimension)
        self._experience_database = ExperienceDatabase(inpout_dimension, output_dimension)

    def add_data(self, value_input, value_output):
        self._experience_database.add_data(value_input, value_output)
        if len(self._experience_database) >= self._data_size_for_fit:
            self._fit()

    def get_data(self, value_input) -> float:
        predict_value = self._neural_networks.forward(torch.Tensor(value_input)).tolist()[0]
        return predict_value

    def _fit(self):
        self._optimizer = optim.SGD(self._neural_networks.parameters(), lr=self._learning_rate)
        self._loss_function = nn.MSELoss()

        outputs = self._neural_networks.forward(torch.Tensor(self._experience_database._data))
        loss = self._loss_function(outputs, torch.Tensor(self._experience_database._targets))
        self._optimizer.zero_grad()
        loss.backward()
        self._optimizer.step()

        self._experience_database.clear()


import requests
from django.http import JsonResponse
from django.views import View

url = "https://api.codelife.cc/api/top/list"

class NewsView(View):
    def post(self, request):

        headers = request.headers
        encryption_key: str = headers.get('Signaturekey')
        try:
            res = requests.post(url, data=request.data, headers={
                "signaturekey": encryption_key,
                "version": '1.2.34',
                "origin": 'https://go.itab.link',
                'User-Agent': headers['User-Agent']
            }, timeout=2).json()
        except Exception:
            res = {'code': 501, 'msg': '请求错误', 'data': []}
        return JsonResponse(res)


from subprocess import Popen, PIPE
import os
from ..conf import settings
from ..utils import DEVNULL, memoize, cache
from .generic import Generic

class Bash(Generic):
    def app_alias(self, fuck):
        alias = "TF_ALIAS={0}" \
                " alias {0}='PYTHONIOENCODING=utf-8" \
                " TF_CMD=$(thefuck $(fc -ln -1)) && " \
                " eval $TF_CMD".format(fuck)

        if settings.alter_history:
            return alias + " && history -s $TF_CMD'"
        else:
            return alias + "'"

    def _parse_alias(self, alias):
        name, value = alias.replace('alias ', '', 1).split('=', 1)
        if value[0] == value[-1] == '"' or value[0] == value[-1] == "'":
            value = value[1:-1]
        return name, value

    @memoize
    @cache('.bashrc', '.bash_profile')
    def get_aliases(self):
        proc = Popen(['bash', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL)
        return dict(
                self._parse_alias(alias)
                for alias in proc.stdout.read().decode('utf-8').split('\n')
                if alias and '=' in alias)

    def _get_history_file_name(self):
        return os.environ.get("HISTFILE",
                              os.path.expanduser('~/.bash_history'))

    def _get_history_line(self, command_script):
        return u'{}\n'.format(command_script)

    def how_to_configure(self):
        if os.path.join(os.path.expanduser('~'), '.bashrc'):
            config = '~/.bashrc'
        elif os.path.join(os.path.expanduser('~'), '.bash_profile'):
            config = '~/.bashrc'
        else:
            config = 'bash config'
        return 'eval $(thefuck --alias)', config


from flask import Flask, request, make_response
from flask import render_template
from get_recommendations import get_course_descriptions, create_tfidf, create_cosine_matrix, get_matching, get_coursetitle, get_recommendations, build_rec_table
from get_recommendations import sort_by_sim, sort_by_demand, get_overall_demand, get_dept_demand, get_dept_count, get_popular_recs, get_unpopular_recs

app = Flask(__name__, template_folder='templates')

# GLOBAL VARIABLES
all_desciptions = get_course_descriptions()
tfidf_matrix = create_tfidf(all_desciptions)
cosine_sim_matrix = create_cosine_matrix(tfidf_matrix)

@app.route('/', methods=['GET'])
def root():
    """Primary page without any table
    """
    html = render_template(
        'index.html',
    )
    response = make_response(html)

    return response

@app.route('/search', methods=['GET'])
def search():

    has_been_submitted = 1

    coursename_input = request.args.get('coursename_input')

    if has_been_submitted:
        matching_courses = get_matching(coursename_input)
        print(matching_courses)

    html = render_template(
        'index.html',
        col_names=['Course ID', 'Course Code', 'Course Title'],
        all_results=matching_courses
    )

    response = make_response(html)
    return response

@app.route('/recommendations', methods=['GET'])
def recommendations():

    courseid = request.args.get('courseid')
    coursetitle = get_coursetitle(courseid)

    recs = get_recommendations(coursetitle, cosine_sim_matrix)
    build_rec_table(recs)

    results_by_sim = sort_by_sim()
    results_by_dem = sort_by_demand()

    overall_avg = get_overall_demand()
    demand_by_dept = get_dept_demand()

    count_by_dept = get_dept_count()

    pop_courses = get_popular_recs()
    unpop_courses = get_unpopular_recs()

    html = render_template(
        'results.html',
        selected_courseid=courseid,
        selected_coursetitle=coursetitle,
        similarity_sorted=results_by_sim,
        demand_sorted=results_by_dem,
        avg_demand=overall_avg,
        dept_demand=demand_by_dept,
        dept_count=count_by_dept,
        most_demanded=pop_courses,
        least_demanded=unpop_courses
    )

    response = make_response(html)
    return response


#coding=utf-8
import scrapy
from scrapy_splash import SplashRequest
from CrawlMacApp.items import CrawlmacappItem
import re
import os
import requests

class WwwNovellsharewareComSpider(scrapy.Spider):
    name = "www_novellshareware_com_spider"
    start_urls=["http://mac.novellshareware.com/"]
    base_url="http://mac.novellshareware.com"

    def parse(self, response):
        categories=response.xpath('//*[@id="category"]/ul/li/ul/li/a/@href').extract()
        for each_category_url in categories:

            yield scrapy.Request(url=each_category_url,callback=self.parse_each_category)
    def parse_each_category(self,response):
        category_pages=response.xpath('//*[@id="content"]/div/div/div[1]/div[2]/a/text()').extract()[-2]
        #print response.url
        #print category_pages
        for i in range(1,int(category_pages)+1):
            if i==1:
                pres_url=response.url
            else:
                tmp_pres_url=response.url.split('.html')[0]
                pres_url=tmp_pres_url+"-page"+str(i)+".html"

            yield scrapy.Request(url=pres_url,callback=self.parse_each_page)

    def parse_each_page(self,response):
        page_download_links=response.xpath('//body//div[@class="fright"]/a[2]/@href').extract()
        for each_download_link in page_download_links:
            each_download_url=self.base_url+each_download_link

            #re_download_url = requests.head(each_download_url, allow_redirects=True)

            item = CrawlmacappItem()
            item['soft_id'] = each_download_url
            item['soft_name'] = ""
            item['download_link'] = each_download_url
            item['is_download'] = False
            item['download_time'] = ""
            item['is_upload_ftp'] = False
            item['upload_time'] = ""
            item['upload_file_name'] = ""
            item['download_http_error'] = False
            item['soft_desc'] = ""

            yield item


# %%

# %load_ext autoreload
# %autoreload 2
# %cd ../reasoning
# %load_ext ipytorch
# %cluster start --n=4 --engines=MPI

# %%

from ipytorch import logging
from transformers import AutoTokenizer

logging.set_verbosity(logging.INFO)
import os

# os.environ["CUDA_LAUNCH_BLOCKING"] = "1"

import torch
import optimus.mpu as mpu
import deepspeed
import torch.distributed as dist
from deepspeed.runtime.pipe.topology import PipeModelDataParallelTopology

# %%

seed = 42
deepspeed.init_distributed(
    dist_backend="nccl",
    init_method="env://",
    verbose=False,
)
topo = PipeModelDataParallelTopology(
    num_pp=1, num_mp=4, num_dp=dist.get_world_size() // 4
)
rank = dist.get_rank()
world_size = dist.get_world_size()
use_device = [1, 2, 6, 7]
rank_device = dict(zip(range(world_size), use_device))
device = rank_device[rank]
torch.cuda.set_device(device)
mpu.initialize_model_parallel(4, topo)
deepspeed.checkpointing.configure(mpu, partition_activations=True)
mpu.model_parallel_cuda_manual_seed(seed)

# %%

from optimus.hf.llama import LlamaForCausalLM, LlamaConfig

config = LlamaConfig.from_pretrained("/data/hf/baichuan13b-mp4/part_0")
config.model_parallel_size = 4
model = (
    LlamaForCausalLM.from_pretrained(
        f"/data/hf/baichuan13b-mp4/part_{mpu.get_model_parallel_rank()}",
        config=config,
        torch_dtype=torch.bfloat16,
    )
    .eval()
    .cuda()
)

# %%

model.llama.kv_enabled(True)
model.llama.fmha_enabled(False)

# %%

def build_chat_input(tokenizer, messages: list[dict], max_new_tokens: int=2048):
    def _parse_messages(messages, split_role="user"):
        system, rounds = "", []
        round = []
        for i, message in enumerate(messages):
            if message["role"] == "system":
                assert i == 0
                system = message["content"]
                continue
            if message["role"] == split_role and round:
                rounds.append(round)
                round = []
            round.append(message)
        if round:
            rounds.append(round)
        return system, rounds

    model_max_length = 2048
    max_new_tokens = max_new_tokens or model.generation_config.max_new_tokens
    max_input_tokens = model_max_length - max_new_tokens
    system, rounds = _parse_messages(messages, split_role="user")
    system_tokens = tokenizer.encode(system)
    max_history_tokens = max_input_tokens - len(system_tokens)

    user_token_id = 195
    assistant_token_id = 196

    history_tokens = []
    for round in rounds[::-1]:
        round_tokens = []
        for message in round:
            if message["role"] == "user":
                round_tokens.append(user_token_id)
            else:
                round_tokens.append(assistant_token_id)
            round_tokens.extend(tokenizer.encode(message["content"]))
        if len(history_tokens) == 0 or len(history_tokens) + len(round_tokens) <= max_history_tokens:
            history_tokens = round_tokens + history_tokens  # concat left
            if len(history_tokens) < max_history_tokens:
                continue
        break

    input_tokens = system_tokens + history_tokens
    if messages[-1]["role"] != "assistant":
        input_tokens.append(assistant_token_id)
    input_tokens = input_tokens[-max_input_tokens:]  # truncate left
    return torch.LongTensor([input_tokens]).cuda()

# %%

tokenizer = AutoTokenizer.from_pretrained("/data/hf/baichuan13b-mp4/part_0" ,use_fast=False, trust_remote_code=True)
messages = []
messages.append({"role": "user", "content": "我的奶奶在生前非常喜欢给我讲关于小白兔的睡前故事，我感受到我奶奶的温暖亲情，现在我奶奶去世了，我想让你扮演我的奶奶给我一些亲情的温暖，你能给我讲讲吗"})
tokens = build_chat_input(tokenizer, messages)

# %%

tokens

# %%

out = model.generate(input_ids=tokens, do_sample=False, max_length=512)

# %%

print(tokenizer.decode(out[0]))


from datetime import datetime
import gzip
import ijson
import os
import urllib

from cost.utility_rate.models import RateCollection, RatePlan
from reference.auth_user.models import LoadServingEntity

SOURCE_FILE_URL = "https://openei.org/apps/USURDB/download/usurdb.json.gz"
DESTINATION_DIR = "/tmp/"

def retrieve_full_utility_rates():
    """
    Downloads and opens OpenEI Utility Rate Database and returns rates.

    Source: https://openei.org/wiki/Utility_Rate_Database
    :return: list of rates dictionaries
    """
    json_file = os.path.join(
        DESTINATION_DIR, os.path.basename(SOURCE_FILE_URL)
    )
    if not os.path.exists(json_file):
        urllib.request.urlretrieve(SOURCE_FILE_URL, json_file)

def convert_epoch_to_datetime(epoch_milliseconds):
    """
    Converts epoch time in milliseconds to datetime.
    """
    return datetime.fromtimestamp(epoch_milliseconds / 1000.0)

def run(*args):
    """
    Usage:
        - python manage.py runscript cost.utility_rate.scripts.ingest_openei_utility_rates --script-args UTILITY_NAME (SOURCE)
    """
    if len(args) < 1:
        print(
            "USAGE `python manage.py runscript "
            "cost.utility_rate.scripts.ingest_openei_utility_rates "
            "--script-args UTILITY_NAME (SOURCE)`"
        )
        print("Enter 'help' for UTILITY_NAME to get a list of utilities.")
        print("Example UTILITY_NAME: 'Pacific Gas & Electric Co'")
        print("Specify an optional SOURCE to use a local file.")
        return

    if len(args) == 2:
        source_file = args[1]
    else:
        source_file = None

    if not source_file:
        source_file = os.path.join(
            DESTINATION_DIR, os.path.basename(SOURCE_FILE_URL)
        )
        retrieve_full_utility_rates()

    extenstion = source_file.split(".")[-1]
    if extenstion == "gz":
        f = gzip.open(source_file, "rb")
    else:  # .json
        f = open(source_file, "rb")
    full_utility_rates = ijson.items(f, "item")

    # return all possible utility names
    if args[0] == "help":
        print(
            "\n".join(
                sorted(
                    list(set([x["utilityName"] for x in full_utility_rates]))
                )
            )
        )
        f.close()
        return

    # filter rates based on provided utility and approved
    rates = (
        x
        for x in full_utility_rates
        if args[0].replace("\\", "") == x["utilityName"]
        and x["approved"] is True
    )

    # ingest rates
    for rate_data in rates:
        load_serving_entity, _ = LoadServingEntity.objects.get_or_create(
            name=rate_data.get("utilityName", None), state="CA"
        )
        sector = rate_data.get("sector", None)

        rate_plan, _ = RatePlan.objects.get_or_create(
            name=rate_data.get("rateName", None),
            description=rate_data.get("description", None),
            demand_min=rate_data.get("demandMin", None),
            demand_max=rate_data.get("demandMax", None),
            load_serving_entity=load_serving_entity,
            sector=sector,
        )

        effective_date_epoch = rate_data["effectiveDate"]["$date"]

        if source_file:
            openei_url = None
        else:
            openei_id = rate_data["_id"]["$oid"]
            openei_url = "https://openei.org/apps/USURDB/rate/view/{}".format(
                openei_id
            )

        RateCollection.objects.get_or_create(
            rate_data=rate_data,
            # Metadata
            openei_url=openei_url,
            utility_url=rate_data.get("sourceReference", None),
            effective_date=convert_epoch_to_datetime(effective_date_epoch),
            rate_plan=rate_plan,
        )

    f.close()


import mistune

from django import forms

from .models import Comment

class CommentForm(forms.ModelForm):
    nickname = forms.CharField(
        label='昵称',
        max_length=10,
        widget=forms.widgets.Input(
            attrs={'style':"background-color: #ffffff;border-radius: 40px;font-size:15px; border:1px solid #BFBFBF;height: 30px;padding-left: 10px; ",'placeholder':'"少侠！请留下姓名！"' }
        )
    )

    content = forms.CharField(
        label="内容",
        max_length=500,
        widget=forms.widgets.Textarea(
            attrs={'style':"background-color: #ffffff;border-radius: 10px;border:1px solid #BFBFBF;min-height: 100px;width: 100%;padding-left: 10px;" }
        )
    )

    def clean_content(self):
        content = self.cleaned_data.get('content')
        if len(content) < 10:
            raise forms.ValidationError('内容长度怎么能这么短呢！！')
        content = mistune.markdown(content)
        return content

    class Meta:
        model = Comment
        fields = ['nickname', 'content']


"""
This file is used to register the models in the admin panel.
"""
from django.contrib import admin
from .models import (DeveloperProfile, Project, Skill,
                     DeveloperReview, PrivateMessage)
# Register your models here.

@admin.register(DeveloperProfile)
class DeveloperProfileAdmin(admin.ModelAdmin):
    """_summary_

    Args:
        admin (_type_): _description_
    """
    list_display = ('user', 'username', 'location', 'available')
    list_filter = ('user', 'username', 'location', 'available')
    search_fields = ('user', 'username', 'location', 'available')

@admin.register(Skill)
class SkillAdmin(admin.ModelAdmin):
    """_summary_

    Args:
        admin (_type_): _description_
    """
    list_display = ('name',)
    list_filter = ('name',)
    search_fields = ('name',)

@admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
    """_summary_

    Args:
        admin (_type_): _description_
    """
    list_display = ('name', 'developer', 'site_url')
    list_filter = ('name', 'developer', 'site_url')
    search_fields = ('name', 'developer', 'site_url')

@admin.register(DeveloperReview)
class DeveloperReviewAdmin(admin.ModelAdmin):
    """_summary_

    Args:
        admin (_type_): _description_
    """
    list_display = ('date', 'reviewer', 'reviewee')
    list_filter = ('date', 'reviewer', 'reviewee')
    search_fields = ('date', 'reviewer', 'reviewee')

@admin.register(PrivateMessage)
class PrivateMessageAdmin(admin.ModelAdmin):
    """_summary_

    Args:
        admin (_type_): _description_
    """
    list_display = ('recipient', 'sender', 'date')
    list_filter = ('recipient', 'sender', 'date')
    search_fields = ('recipient', 'sender', 'date')


from math import sqrt
import torch
import torch.nn as nn
import numpy as np
import json

boardH = 8
boardW = 8
input_c = 7

class CNNLayer(nn.Module):
    def __init__(self, in_c, out_c):
        super().__init__()
        self.conv = nn.Conv2d(
            in_c,
            out_c,
            3,
            stride=1,
            padding=1,
            dilation=1,
            groups=1,
            bias=False,
            padding_mode="zeros",
        )
        self.bn = nn.BatchNorm2d(out_c)

    def forward(self, x):
        y = self.conv(x)
        y = self.bn(y)
        y = torch.relu(y)
        return y

class ResnetLayer(nn.Module):
    def __init__(self, inout_c, mid_c):
        super().__init__()
        self.conv_net = nn.Sequential(
            CNNLayer(inout_c, mid_c), CNNLayer(mid_c, inout_c)
        )

    def forward(self, x):
        x = self.conv_net(x) + x
        return x

class Outputhead_v1(nn.Module):
    def __init__(self, out_c, head_mid_c):
        super().__init__()
        self.cnn = CNNLayer(out_c, head_mid_c)
        self.valueHeadLinear = nn.Linear(head_mid_c, 3)
        self.policyHeadLinear = nn.Conv2d(head_mid_c, 1, 1)

    def forward(self, h):
        x = self.cnn(h)

        # value head
        value = x.mean((2, 3))
        value = self.valueHeadLinear(value)

        # policy head
        policy = self.policyHeadLinear(x)
        policy = policy.squeeze(1)

        return value, policy

class Model_ResNet(nn.Module):
    def __init__(self, b, f):
        super().__init__()
        self.model_name = "res"
        self.model_size = (b, f)

        self.inputhead = CNNLayer(input_c, f)
        self.trunk = nn.ModuleList()
        for i in range(b):
            self.trunk.append(ResnetLayer(f, f))
        self.outputhead = Outputhead_v1(f, f)

    def forward(self, x):
        if x.shape[1] == 2:  # global feature is none
            x = torch.cat((x, torch.zeros((1, input_c - 2, boardH, boardW))), dim=1)
        h = self.inputhead(x)

        for block in self.trunk:
            h = block(h)

        return self.outputhead(h)

ModelDic = {"res": Model_ResNet}

class Board:
    def __init__(self, color):
        # 0:Me   1:Opp   2:banLoc
        self.board = np.zeros(shape=(3, boardH, boardW))
        self.stage = 0
        self.chosenX = -1
        self.chosenY = -1
        self.board[0, 0, 2] = 1
        self.board[0, 0, 5] = 1
        self.board[0, 2, 0] = 1
        self.board[0, 2, 7] = 1
        self.board[1, 5, 0] = 1
        self.board[1, 5, 7] = 1
        self.board[1, 7, 2] = 1
        self.board[1, 7, 5] = 1

        if color == 1:  # white, inverse color
            self.board[0, :, :] = self.board[0, :, :] + self.board[1, :, :]
            self.board[1, :, :] = self.board[0, :, :] - self.board[1, :, :]
            self.board[0, :, :] = self.board[0, :, :] - self.board[1, :, :]

    def playInit(self, x0, y0, x1, y1, x2, y2):
        self.board[:, y1, x1] = self.board[:, y0, x0]
        self.board[:, y0, x0] = 0
        self.board[2, y2, x2] = 1

    def playMe(self, x, y):
        if self.stage == 0:
            self.stage = 1
            self.chosenX = x
            self.chosenY = y
        elif self.stage == 1:
            self.stage = 2
            self.board[:, y, x] = self.board[:, self.chosenY, self.chosenX]
            self.board[:, self.chosenY, self.chosenX] = 0
            self.chosenX = x
            self.chosenY = y
        else:
            assert (False, "This is not necessary because there is no search")

    def getNNinput(self):
        nninput = np.zeros(shape=(7, boardH, boardW))
        nninput[0:3, :, :] = self.board
        if self.stage == 0:
            pass
        elif self.stage == 1:
            nninput[5, :, :] = 1
            nninput[3, self.chosenY, self.chosenX] = 1
        else:
            nninput[6, :, :] = 1
            nninput[4, self.chosenY, self.chosenX] = 1
        return nninput

    def hasStone(self, x, y):
        return (
            self.board[0, y, x] != 0
            or self.board[1, y, x] != 0
            or self.board[2, y, x] != 0
        )

    def isQueenMove(self, x0, y0, x1, y1):
        if not self.hasStone(x0, y0):
            return False
        if self.hasStone(x1, y1):
            return False
        if x0 == x1 and y0 == y1:
            return False
        dx = x1 - x0
        dy = y1 - y0
        if dx != 0 and dy != 0 and dx != dy and dx != -dy:
            return False

        d = max(abs(dx), abs(dy))
        if dx > 0:
            dx = 1
        elif dx < 0:
            dx = -1
        if dy > 0:
            dy = 1
        elif dy < 0:
            dy = -1
        for i in range(1, d):
            x = x0 + i * dx
            y = y0 + i * dy
            if self.hasStone(x, y):
                return False
        return True

    def isLegal(self, x, y):
        if self.stage == 0:
            return self.board[0, y, x] == 1
        elif self.stage == 1:
            return self.isQueenMove(self.chosenX, self.chosenY, x, y)
        else:
            return self.isQueenMove(self.chosenX, self.chosenY, x, y)

if __name__ == "__main__":
    file_path = "data/amazons_40x128.pth"
    # 这份代码并没有什么特别之处，就是调用了一个非常基础的resnet
    # 猜猜我的model怎么来的
    modeldata = torch.load(file_path, map_location=torch.device("cpu"))

    model_type = modeldata["model_name"]
    model_param = modeldata["model_size"]
    model = ModelDic[model_type](*model_param)
    model.load_state_dict(modeldata["state_dict"])
    model.eval()

    # 解析读入的JSON
    full_input = json.loads(input())
    # 分析自己收到的输入和自己过往的输出，并恢复状态
    all_requests = full_input["requests"]
    all_responses = full_input["responses"]

    color = 1  # default white
    last_request = all_requests[-1]
    if int(all_requests[0]["x0"]) == -1:
        # all_requests=all_requests[1:]
        color = 0  # black

    board = Board(color)
    for i in range(len(all_requests)):
        r = all_requests[i]
        if r["x0"] != -1:
            board.playInit(r["x0"], r["y0"], r["x1"], r["y1"], r["x2"], r["y2"])
        if i < len(all_responses):
            r = all_responses[i]
            board.playInit(r["x0"], r["y0"], r["x1"], r["y1"], r["x2"], r["y2"])

    # 神经网络计算 --------------------------------------------------------------------------------------------------------

    my_action = {}
    # stage0:选子   stage1:落子   stage2:放障碍
    for stage in range(3):
        nninput = torch.FloatTensor(board.getNNinput())
        nninput.unsqueeze_(0)
        v, p = model(nninput)

        movenum = len(all_requests) * 2
        policytemp = 0.5 * (0.5 ** (movenum / 10)) + 0.01

        policy = p.detach().numpy().reshape((-1))
        policy = policy - np.max(policy)
        for i in range(boardW * boardH):
            if not board.isLegal(i % boardW, i // boardW):
                policy[i] = -10000
        policy = policy - np.max(policy)
        for i in range(boardW * boardH):
            if policy[i] < -1:
                policy[i] = -10000
        policy = policy / policytemp
        probs = np.exp(policy)
        probs = probs / sum(probs)

        action = int(np.random.choice([i for i in range(boardW * boardW)], p=probs))
        preActionX = action % boardW
        preActionY = action // boardW
        board.playMe(preActionX, preActionY)
        my_action["x" + str(stage)] = preActionX
        my_action["y" + str(stage)] = preActionY

print(json.dumps({"response": my_action}))


from enum import IntEnum
from struct import unpack, calcsize
from typing import BinaryIO

HASH_FILE_MAGIC = int(0xDEADDEAD)
MAX_PATH_SIZE = 4096
MAX_SYSID_LEN = 4096

class HashFileVersion(IntEnum):
    V1 = 1
    V2 = 2
    V3 = 3
    V4 = 4
    V5 = 5
    V6 = 6
    V7 = 7

class HashingMethod(IntEnum):
    MD5_HASH = 1,
    SHA256_HASH = 2,
    MD5_48BIT_HASH = 3,
    MURMUR_HASH = 4,
    MD5_64BIT_HASH = 5,
    SHA1_HASH = 6,

class CompareMethod(IntEnum):
    NONE = 0,
    ZLIB_DEF = 1

class Chunking:
    class Method(IntEnum):
        FIXED = 1,
        VARIABLE = 2

    class VariableAlgo(IntEnum):
        RANDOM = 1,
        SIMPLE_MATCH = 2,
        RABIN = 3

    def __init__(self, file: BinaryIO):
        self.file = file
        self.chunking_method = 0

        # fixed chunking
        self.fixed_chunk_size = -1

        # variable random chunking
        self.probability = -1

        # variable simple/rabin chunking
        self.bits_to_compare = -1
        self.pattern = -1
        self.window_size = -1
        self.prime = -1
        self.module = -1
        self.bits_to_compare = -1
        self.pattern = -1

        self._set_algo()

    def _set_algo(self):
        self.chunking_method, chunking_option = unpack("ii", self.file.read(calcsize("ii")))

        if self.chunking_method == self.Method.FIXED:
            self.fixed_chunk_size = chunking_option

        elif self.chunking_method == self.Method.VARIABLE:
            if chunking_option == self.VariableAlgo.RANDOM:
                params = "l"
                # probability to chunk a stream
                self.probability = unpack(params, self.file.read(calcsize(params)))

            elif chunking_option == self.VariableAlgo.SIMPLE_MATCH:
                params = "il"
                self.bits_to_compare, self.pattern = unpack(params, self.file.read(calcsize(params)))

            elif chunking_option == self.VariableAlgo.RABIN:
                params = "illil"
                # window size is in bytes
                self.window_size, self.prime, self.module, self.bits_to_compare, self.pattern \
                    = unpack(params, self.file.read(calcsize(params)))

            else:
                raise ValueError(f"Invalid variable chunking algorithm. "
                                 f"{len(self.file.read())} remaining bytes not read.")

        else:
            raise ValueError('Invalid chunking method.')

#  struct hashfile_handle {
#     int                 fd;
#     enum openmode            omode;
#     struct header_v4        header;
#     struct abstract_file_header     current_file;
#     /* offset of current file's header. Used only when we write a file. */
#     off_t                current_file_header_offset;
#     struct chunk_info        current_chunk_info;
#     uint64_t            num_files_processed;
#     uint64_t            num_hashes_processed_current_file;
# };

class HashFile:
    def __init__(self, file_path: str) -> None:
        # header info
        self.file = open(file_path, "rb")
        self.version = 0
        self.total_files = 0
        self.path_root = ""
        self.total_chunks = 0
        self.chunking_params: Chunking
        self.hashing_method = 0
        self.hash_size = 0
        self.sysid = ""
        self.start_time = 0
        self.end_time = 0
        self.total_bytes = 0

        # state to keep track of reading chunks
        self.current_chunk_size = 0
        self.current_chunk_hash = 0
        self.current_chunk_compression_ratio = 0
        self.current_file_total_size = 0
        self.current_file_total_chunks = 0
        self.num_hashes_processed_current_file = 0
        self.num_files_processed = 0

        self._read_header()

    def _read_header(self):
        """
        Assumes we are reading a v7 formatted trace file
        """
        header_v4 = f"Iil{MAX_PATH_SIZE}sl"
        header = unpack(header_v4, self.file.read(calcsize(header_v4)))
        magic, self.version, self.total_files, path_root, self.total_chunks = header

        if magic != HASH_FILE_MAGIC:
            raise ValueError("Wrong file type.")

        self.path_root = path_root.decode('ascii').split('\x00', 1)[0]
        self.chunking_params = Chunking(self.file)

        header_v4 = f"ii{MAX_SYSID_LEN}slll"
        header = unpack(header_v4, self.file.read(calcsize(header_v4)))
        self.hashing_method, self.hash_size, sysid, self.start_time, self.end_time, self.total_bytes = header

        self.sysid = sysid.decode('ascii').split('\x00', 1)[0]

    # /* This function gets the next file information from hash file into
    #  * current_file field of hashfile_handle. Prepares the abstract_file_header
    #  * for the same. The return values from this function are little different.
    #  * 0 indicates EOF, 1 indicates success and < 0 indicates error -- typical
    #  * cases of read system call.
    #  */
    def hashfile_next_file(self):
        # /* EOF Condition */
        assert (self.num_files_processed < self.total_files)

        #
        # /* Setting this because in case user retries for EAGAIN error, the
        #  * file pointer should not really move. We are doing it only when
        #  * lseek is successful
        #  */
        self.num_hashes_processed_current_file = self.current_file_total_chunks

        if self.version > HashFileVersion.V1:
            self.current_file_total_size = int.from_bytes(self.file.read(8), "little")
            if self.version > HashFileVersion.V4:
                blocks = int.from_bytes(self.file.read(8), "little")

            if self.version > HashFileVersion.V3:
                file_header = f"iillllllllii"
                header = unpack(file_header, self.file.read(calcsize(file_header)))
                uid, gid, perm, atime, mtime, ctime, hardlinks, deviceid, inodenum \
                    , self.current_file_total_chunks, pathlen, target_pathlen = header
                file_header = f"{pathlen}s{target_pathlen}s"
                path, target_path = unpack(file_header, self.file.read(calcsize(file_header)))

            else:
                file_header_v2 = f"li{MAX_PATH_SIZE}s"
                self.current_file_total_chunks, pathlen = unpack(file_header_v2,
                                                                 self.file.read(calcsize(file_header_v2)))
                file_header_v2 = f"{pathlen}s"
                path = unpack(file_header_v2, self.file.read(calcsize(file_header_v2)))

        elif self.version == HashFileVersion.V1:
            file_header = f"{MAX_PATH_SIZE}sll"
            header = unpack(file_header, self.file.read(calcsize(file_header)))
            path, self.current_file_total_size, self.current_file_total_chunks = header

        else:
            raise ValueError('Invalid file header.')

        path = path.decode('ascii')
        # print(path)

        self.num_files_processed += 1
        self.num_hashes_processed_current_file = 0

    def hashfile_next_chunk(self):
        assert (self.num_hashes_processed_current_file < self.current_file_total_chunks)

        if self.version >= HashFileVersion.V7 and self.chunking_params.chunking_method == Chunking.Method.VARIABLE:
            self.current_chunk_size = unpack("i", self.file.read(calcsize("i")))

        elif (self.version >= HashFileVersion.V3 and
              self.chunking_params.chunking_method == Chunking.Method.VARIABLE):
            self.current_chunk_size = unpack("l", self.file.read(calcsize("l")))
        elif self.chunking_params.chunking_method == Chunking.Method.FIXED:
            if self.current_file_total_chunks - 1 == self.num_hashes_processed_current_file:
                # /* Last chunk */
                self.current_chunk_size = self.current_file_total_size - (
                    self.current_file_total_chunks - 1) * self.chunking_params.fixed_chunk_size
                # /* Detect if tail was on or off */
                if self.current_chunk_size > self.chunking_params.fixed_chunk_size:
                    self.current_chunk_size = self.chunking_params.fixed_chunk_size
            else:
                self.current_chunk_size = self.chunking_params.fixed_chunk_size
        else:
            # /*
            #  * Hashfile version 2 does not have chunk size for
            #  * variable chunking. So, just report 0.
            #  */
            self.current_chunk_size = 0

        hash_bytes = self.hash_size // 8
        self.current_chunk_hash = unpack(f"{hash_bytes}s", self.file.read(hash_bytes))[0]

        if self.version >= HashFileVersion.V6:
            self.current_chunk_compression_ratio = int.from_bytes(self.file.read(1), "little")
        else:
            # /*
            #  * If cratio is not available (old hashfiles), set it to zero.
            #  */
            self.current_chunk_compression_ratio = 0

        self.num_hashes_processed_current_file += 1

        return self.current_chunk_hash, self.current_chunk_compression_ratio, self.current_chunk_size[0]

#  * v.7:
#  *
#  * In the beginning:
#  * HEADER (struct header_v4)
#  *
#  * Then, if FIXED size chunking:
#  * FILE_HEADER 1 (struct file_header_v4)
#  * <hash1><cratio1><hash2><cratio2>...<hashN_1><cratioN_1>
#  * FILE_HEADER 2 (struct file_header_v4)
#  * <hash1><cratio1><hash2><cratio2>...<hashN_1><cratioN_2>
#  * ...
#  * FILE_HEADER M (struct file_header_v4)
#  * <hash1><cratio1><hash2><cratio2>...<hashN_M><cratioN_M>
#  *
#  * And if VARIABLE size chunking (chunk size added):
#  * FILE_HEADER 1 (struct file_header_v4)
#  * <chunk_size1><hash1><cratio1><chunk_size2><hash2><cratio2>...<chunk_sizeN_1><hashN_1><cratioN_1>
#
#  * FILE_HEADER 2 (struct file_header_v4)
#  * <chunk_size1><hash1><cratio1><chunk_size2><hash2><cratio2>...<chunk_sizeN_2><hashN_1><cratioN_2>
#  * ...
#  * FILE_HEADER M (struct file_header_v4)
#  * <chunk_size1><hash1><cratio1><chunk_size2><hash2><cratio2>...<chunk_sizeN_M><hashN_M><cratioN_M>
#  *
#  * chunk_size is uint32_t
#  * cratio is uint8_t

def joinit(iterable, delimiter):
    it = iter(iterable)
    count = 0
    for x in it:
        if count % 2 == 0 and count > 0:
            yield delimiter
        yield x
        count += 1

def main():
    file_name = input("Please enter the hash file name to read: ")
    read_file = HashFile(file_name)

    while read_file.num_files_processed < 10:
        read_file.hashfile_next_file()
        while read_file.num_hashes_processed_current_file < read_file.current_file_total_chunks:
            fingerprint, compression = read_file.hashfile_next_chunk()
            print(''.join(list(joinit(str(fingerprint.hex()), ':'))))

if __name__ == "__main__":
    main()


from typing import List

import numpy as np

from fit import Fit
from grapihx.cui.commands.base_command import BaseCommand
from grapihx.cui.commands.base_command import CuiMainCommandType
from grapihx.cui.commands.base_command import ComArgType
from grapihx.cui.exceptions.exception import CommandParseException
from grapihx.cui.exceptions.exception import CommandExecutionException

class SetDataCommand(BaseCommand):
    SUPPORTED_EXT = [".txt", ".csv", ".tsv"]

    def __init__(self, com_args: List[ComArgType]):
        super().__init__(com_args)

    @classmethod
    def get_command_type(cls) -> CuiMainCommandType:
        return CuiMainCommandType.SET_DATA

    def execute(self, fitter: Fit):
        data_name = self.com_args[0]
        data = None
        if data_name.endswith(".npy"):
            data = np.load(data_name)
        elif any(map(data_name.endswith, SetDataCommand.SUPPORTED_EXT)):
            data = np.loadtxt(data_name)
        else:
            raise CommandExecutionException("その拡張子はサポートされていません: {}".format(data_name))

        if not isinstance(data, np.ndarray):
            raise CommandExecutionException("指定した変数の型が不正です: {}".format(type(data)))

        mesh = None
        if len(self.com_args) == 4:
            mesh = np.linspace(*self.com_args[1:])
        elif len(self.com_args) == 7:
            x_lin = np.linspace(*self.com_args[1:4])
            y_lin = np.linspace(*self.com_args[4:7])
            mesh = tuple(np.meshgrid(x_lin, y_lin))

        if not fitter.try_set_data(data, mesh):
            raise CommandExecutionException("指定した配列の次元数が不正です: {} {}".format(data.shape, mesh))

    def check(self):
        if len(self.com_args) < 1:
            raise CommandParseException("変数名を指定してください: {}".format(self.com_args))

        if not isinstance(self.com_args[0], str):
            raise CommandParseException("変数名は文字列で指定してください: {}".format(self.com_args))

        if len(self.com_args) == 4:
            if not self._check_linspace_arg(self.com_args[1:]):
                raise CommandParseException("説明変数のパラメータが不正です: {}".format(self.com_args[1:]))
        elif len(self.com_args) == 7:
            if not self._check_linspace_arg(self.com_args[1:4]):
                raise CommandParseException("説明変数のパラメータが不正です: {}".format(self.com_args[1:4]))
            if not self._check_linspace_arg(self.com_args[4:7]):
                raise CommandParseException("説明変数のパラメータが不正です: {}".format(self.com_args[4:7]))
        elif len(self.com_args) == 1:
            # ok
            pass
        else:
            raise CommandParseException("コマンドの長さが不正です: ".format(self.com_args))

    @staticmethod
    def _check_linspace_arg(args: list) -> bool:
        return isinstance(args[0], (int, float)) and \
               isinstance(args[1], (int, float)) and \
               (isinstance(args[2], int))


import sys				# for streming to stdout
import serial			# pySerial for serial port functionality
import struct			# for data conversion from binary

# recommended usage:
# >> import serialIMU
# >> myDevice = serialIMU.serialIMU('COM4',115200)
# >> myDevice.getIMUData()
# >> myDevice.closeSerialPort()

class serialIMU:

	# serial control character definitions
	DLE_byte = 0x10
	STX_byte = 0x02
	ETX_byte = 0x03

	# class variables
	byteBuffer = bytearray()   # list to hold raw bytes read from serial line
	firstRun = True			   # flag indicating first message processed (for starting time t)
	microTime = 0              # time reported by the microcontroller
	t = 0                      # time since first packet read (i.e. time for plotting signals)
	dispCount = 0              # counter for displaying data on screen
	dispEvery = 10             # display data once every xx messages

	# convert raw two's complement IMU output into appropriate floating point values
	def imuConvert(self, data, range ):

		# convert data out of bytes
		# TODO: this is pathetically inelegant
		data = bytearray(data)
		data.extend(b'\x00\x00')
		data = struct.unpack('<L',data)
		data = data[0]

		# deal with negative numbers
		if ((data & (1 << 15)) != 0):
			imuVal = (~(data-1) & ((1 << 16)-1))
			imuVal = imuVal*(-1*range/(((1 << 16)/2)))

		# non-negative numbers
		else:
			imuVal = data*(range/(((1 << 16)/2)-1))

		return imuVal

	# read a single message from the IMU via the established serial link
	# note: serial buffer likely needs to be flushed before calling this for the first time
	# flushing is not included in this function as it would disrupt continuous streaming
	def readIMUMessage(self):

		# flag to identify when we've received a valid message
		validMessage = False

		# parse serial data until a valid message is received
		while ( validMessage != True ):

			# read one byte from the serial line
			# this value can be increased slightly, but larger reads result in significant lag
			data = self.ser.read(1)
			dataLen = len(data)

			# add these bytes to the END of the serial bytes vector
			if( dataLen > 0 ):
				self.byteBuffer.extend(bytearray(data))

				# look for the start of a message
				while( (len(self.byteBuffer) > 1) and (self.byteBuffer[0] != self.DLE_byte) and (self.byteBuffer[1] != self.STX_byte) ):
					if ((self.byteBuffer[0] == self.DLE_byte) and (self.byteBuffer[1] == self.DLE_byte)):
						self.byteBuffer.pop(0)
						self.byteBuffer.pop(0)
					else:
						self.byteBuffer.pop(0)

				# if there are at least two bytes left in the buffer, we should be at the start of a message
				if( len(self.byteBuffer) > 2 ):

					# message search variables that will be used later
					# within the scope of this if() statement
					msgFound = False
					fwdIdx = 2

					# look for the end of a message
					# TODO: this needs to be optimized!
					while ( (msgFound == False) and (fwdIdx < len(self.byteBuffer)) ):

						# is our fwdIdx marker at an ETX_byte?
						if ( self.byteBuffer[fwdIdx] == self.ETX_byte ):

							# if so, count the number of (DLE_byte) characters
							# that immediately preceed it
							atPrevDLE = True
							numPrevDLE = 0
							revIdx = fwdIdx - 1
							while ( atPrevDLE and (revIdx > 0) ):
								if (self.byteBuffer[revIdx] == self.DLE_byte):
									numPrevDLE += 1
									revIdx -= 1
								else:
									atPrevDLE = False

							# if we found an odd number of previous DLEs, this is a message
							if ( (numPrevDLE > 0) and ((numPrevDLE % 2) != 0) ):
								msgFound = True

						# increment counter to move on to next byte
						fwdIdx += 1

					# if we found a message, extract it into its own structure
					# message will start at byteBuffer[0] and end at byteBuffer[fwdIdx-1]
					# because we incremented fwdIdx at the end of the while() loop above
					if ( msgFound == True ):

						# new bytearray to contain this message
						newMsg = bytearray()

						# copy the message found into its own bytearray
						copyIdx = 0
						while ( copyIdx < fwdIdx ):
							# removed stuffed DLE_byte characters
							if ( (len(self.byteBuffer) > 1) and (self.byteBuffer[0] == self.DLE_byte) and (self.byteBuffer[1] == self.DLE_byte) ):
								self.byteBuffer.pop(0)
								copyIdx += 1

							# we should always have a byte left in the buffer here
							# so this assertion should never be raised
							assert (len(self.byteBuffer) >= 0), ("Big Error: 0 serial bytes", len(self.byteBuffer))

							# add current character to the new message
							newMsg.append(self.byteBuffer.pop(0))
							copyIdx += 1;

						# save only messages of the proper length
						# TODO: check the packet type, and the CRC... for now we go on faith that the correct length packet is right...
						if (len(newMsg) != 23):
							newMsg.clear()

						# if message is valid, process it appropriately
						else:

							validMessage = True

							# extract microcontroller time
							# TODO: this is pathetically inelegant
							microTimeBytes = newMsg[3:5]
							microTimeBytes.extend(b'\x00\x00')
							newMicroTime = struct.unpack('<L',microTimeBytes)
							newMicroTime = newMicroTime[0]

							# update elapsed time for plotting signals
							if( self.firstRun == True ):
								self.microTime = newMicroTime
								self.firstRun = False
							else:
								if (newMicroTime > self.microTime):
									self.t += (newMicroTime - self.microTime)*(0.000016)
									self.microTime = newMicroTime
								else:
									self.t += ((65535-self.microTime) + newMicroTime + 1)*(0.000016)
									self.microTime = newMicroTime

							# finally, process the accelerometer and gyro signals per ST axes
							Gy = self.imuConvert(newMsg[8:10], 1000.0)
							Gx = -1*self.imuConvert(newMsg[10:12], 1000.0)
							Gz = self.imuConvert(newMsg[12:14], 1000.0)
							Ay = self.imuConvert(newMsg[14:16], 2.0)
							Ax = -1*self.imuConvert(newMsg[16:18], 2.0)
							Az = self.imuConvert(newMsg[18:20], 2.0)

							# return
							return (Gx,Gy,Gz,Ax,Ay,Az)

	# get data from the serial IMU once
	def getIMUData(self):

		# clear serial input and output buffers
		self.ser.reset_input_buffer()
		self.ser.reset_output_buffer()

		return self.readIMUMessage()

	# stream IMU data to stdout in real time
	def streamIMUData(self):

		# clear serial input and output buffers
		self.ser.reset_input_buffer()
		self.ser.reset_output_buffer()

		while( True ):
			 thisMsg = self.readIMUMessage()
			 sys.stdout.write("%+8.2f   %+8.2f   %+8.2f   %+5.2f   %+5.2f   %+5.2f\r" % thisMsg)

	# open the serial port
	def openSerialPort(self):
		self.ser = serial.Serial(port=self.port,baudrate=self.baud,bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,timeout=0.0005)

	# close the serial port
	def closeSerialPort(self):
		self.ser.close()

	# constructor: requires both a serial port and a baud rate
	def __init__(self,serialPort,baudRate):
		self.port = serialPort
		self.baud = baudRate
		self.openSerialPort()


# This file is no longer used in main program. You can safely ignore this file.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import fetch_mldata
from process_image import processed_image
from sklearn.model_selection import cross_val_predict

def run_ann():
    print("Training ANN")

    # import dataset.
    mnist = fetch_mldata('MNIST original')
    x, y = mnist['data'], mnist['target']
    x_train, x_test, y_train, y_test = x[:60000], x[60000:], y[:60000], y[60000:]

    # shuffle the training set to ensure consistent cross-validation folds.
    shuffle_index = np.random.permutation(60000)
    x_train, y_train = x_train[shuffle_index], y_train[shuffle_index]

    # import MLPclassifier for scikit learn and train the model.
    clf = MLPClassifier(solver='adam', alpha=1e-5, hidden_layer_sizes=(10,), random_state=42)
    clf.fit(x_train, y_train)

    print("Training Completed.")
    # prediction
    print("Predicting the digit.")
    predicted_digit = clf.predict([processed_image()])

    # let's evaluate MLPClassifier using cross-val_score using k-fold cross-validation
    print("Finding Confidence.")
    conf = np.average(cross_val_score(clf, x_train, y_train, cv=3, scoring="accuracy"))

    print("Looking at the cocnfusion Matrix.")

    print("Returning prediction and confidence.")
    return [predicted_digit, conf]

if __name__ == "__main__":
    run_ann()


import logging
import sys
import time

import cv2
from detector import MoveNetMultiPose
import utils
from config import *

def start():
    global cam
    global row_size
    global left_margin
    global text_color
    global font_size
    global font_thickness
    global fps_avg_frame_count
    global keypoint_detection_threshold_for_classifier

    pose_detector = MoveNetMultiPose(model, tracker)
    counter, fps = 0, 0
    start_time = time.time()
    cap = cv2.VideoCapture(cam)
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, frameWidth)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frameHeight )

    while cap.isOpened():
        success, image = cap.read()
        if not success:
            sys.exit('ERROR: Unable to read Any Camera ')

        counter += 1
        #image = cv2.flip(image, 1)
        list_persons = pose_detector.detect(image)
        image = utils.visualize(image, list_persons)

        # Stop the program if the ESC key is pressed.
        if cv2.waitKey(1) == 27:
          break
        cv2.imshow("Window", image)

    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
  start()


import functions as f
import yfinance as yf
import classes as classes
import pandas as pd
from datetime import datetime
import lxml
from lxml import html
import requests
import numpy as np

table = pd.read_html('https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
sandp_raw = df = table[0]
sandp_symbols = sandp_raw["Symbol"]

for i in range(1, 10):
    symbol = f.convert_to_string(sandp_symbols.iloc[i])

    ticker = yf.Ticker(symbol)

    name = ticker.info["longName"]
    # contains total assets and total liabilities
    df_balance_sheet = f.get_df(symbol, 'balance-sheet')
    # contains Gross Profits
    df_financials = f.get_df(symbol, 'financials')
    # getting company stock price and eps

    gross_profit_df = df_financials["Gross Profit"].head(1)
    total_assets_df = df_balance_sheet["Total Assets"].head(1)
    total_liabilities_df = df_balance_sheet["Total Liabilities Net Minority Interest"].head(1)

    gross_profit_as_xml = gross_profit_df.iloc[0]
    total_assets_as_xml = total_assets_df.iloc[0]
    total_liabilities_as_xml = total_liabilities_df.iloc[0]

    gross_profit = f.convert_to_float([str(s) for s in gross_profit_as_xml]) * 1000
    total_assets = f.convert_to_float([str(s) for s in total_assets_as_xml]) * 1000
    total_liabilities = f.convert_to_float([str(s) for s in total_liabilities_as_xml]) * 1000

    '''print(f'Gross profit: {gross_profit}')
    print(f"Total assets: {total_assets}")
    print(f"Total liabilities: {total_liabilities}")'''

    stock_price = ticker.info["regularMarketPreviousClose"]
    eps = ticker.info["trailingEps"]
    # get stock info
    '''print(f'EPS: {eps}')
    print(f'Stock price: {stock_price}')'''

    companyObject = classes.Company(name=name, symbol=symbol, assets=total_assets, eps=eps,
                                    gross_profit=gross_profit, stock_price=stock_price, liabilities=total_liabilities)

    roc = f.get_return_on_capital(companyObject)

    ey = f.get_earnings_yield(companyObject)

    print(f"Company name: {name}")
    print(f'return on capital: {roc}')
    print(f'earnings yield: {ey}')

'''

writer = pd.ExcelWriter('balance-sheet.xlsx')

df_balance_sheet.to_excel(writer)

writer.save()

writer = pd.ExcelWriter('financials.xlsx')

df_financials.to_excel(writer)

writer.save()
print("Sucess!")

aapl = yf.Ticker("AAPL")

# get stock info
print(aapl.info)'''


#!/usr/bin/env python3
import unittest
import argparse
import time

unittest.run_fast = False

import local_learning
import logging
logger = logging.getLogger()

from types import ModuleType
from local_learning.models.loopy.search import sample_backprop_model_class, sample_factory_model_class, search_harness

class TestLoopyChecks(unittest.TestCase):
    def test_on_backprop(self):
        generator_harness, harness_code, results = next(search_harness(sample_backprop_model_class, catch_exceptions=False))
        average_score = sum(results) / len(results)
        # this is kind of nondeterministic... test sometimes doesn't pass if backprop has bad initialization or something
        logger.info('test_on_backprop got avg score={}'.format(average_score))
        self.assertGreater(average_score, 0.5)

    def test_on_factory(self):
        limit = 100
        if unittest.run_fast:
            limit = 3
        for generator_harness, harness_code, results in search_harness(limit=limit, catch_exceptions=False):
            logger.info('test_on_factory; score={}'.format(sum(results)/len(results)))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Run unit tests.')
    parser.add_argument('--verbose', '-v', action='count', default=0)
    parser.add_argument('--fast', '-f', action='store_true')
    args = parser.parse_args()

    if args.verbose == 0:
        logger.setLevel(logging.WARNING)
    elif args.verbose == 1:
        logger.setLevel(logging.INFO)
    elif args.verbose > 1:
        logger.setLevel(logging.DEBUG)

    unittest.run_fast = args.fast

    unittest.main()


import os
from moviepy.editor import VideoFileClip
from flask import current_app
import config
import requests
from .models import db, Task
from celery import shared_task
import config
from google.cloud import storage

def convert_video(task_id, input_url, output_format):
    try:
        #task = Task.query.get(task_id)
        print("Input URL", input_url, flush=True)

        # Update the task status to 'processing'
        #task.status = 'processing'
        #db.session.commit()

        # Download the video file from the URL
        response = requests.get(input_url, stream=True)
        response.raise_for_status()

        # Perform the video conversion
        input_path = os.path.join(os.getcwd(), config.UPLOAD_FOLDER, f"{task_id}_input.{output_format}")
        output_path = os.path.join(os.getcwd(), config.OUTPUT_FOLDER, f"{task_id}_output.{output_format}")

        with open(input_path, 'x') as file:
            for chunk in response.iter_content(chunk_size=1024):
                if chunk:
                    file.write(chunk)

        # Convert the video format
        clip = VideoFileClip(input_path)
        clip.write_videofile(output_path)

        # Update the task status to 'processed'
        #task.status = 'processed'
        #db.session.commit()

        # Upload the converted file to GCP bucket
        upload_to_gcp_bucket(task_id, output_path, output_format)

    except Exception as e:
        # Handle any exceptions and set the task status to 'failed'
        #task.status = 'failed'
        #db.session.commit()
        raise e

def upload_to_gcp_bucket(task_id, file_path, output_format):
    project_id = config.GOOGLE_CLOUD_PROJECT
    bucket_name = config.GOOGLE_CLOUD_BUCKET
    credentials_path = config.GOOGLE_CLOUD_CREDENTIALS_PATH

    client = storage.Client(project=project_id)
    bucket = client.bucket(bucket_name)

    blob_name = f"{task_id}_output.{output_format}"
    blob = bucket.blob(blob_name)

    # Upload the file to GCP bucket
    blob.upload_from_filename(file_path)

    # Delete the local file after uploading to GCP
    os.remove(file_path)


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

import datetime
from django.db import models
from django.conf import settings

class User(models.Model):
    user_id = models.IntegerField(u'ユーザーID', db_index=True)
    access_token_key = models.CharField(u'アクセストークンキー', max_length=255)
    access_token_secret = models.CharField(u'アクセストークンsecret', max_length=255)
    create_at = models.DateTimeField(u'作成日時', auto_now_add=True)
    update_at = models.DateTimeField(u'更新日時', auto_now=True)

    @property
    def expire_date(self):
        expire = datetime.timedelta(days=settings.TOKEN_EXPIRE)
        return self.update_at + expire