"""Outpost models"""
from dataclasses import asdict, dataclass, field
from datetime import datetime
from typing import Any, Iterable, Optional
from uuid import uuid4

from dacite.core import from_dict
from django.contrib.auth.models import Permission
from django.core.cache import cache
from django.db import IntegrityError, models, transaction
from django.db.models.base import Model
from django.utils.translation import gettext_lazy as _
from guardian.models import UserObjectPermission
from guardian.shortcuts import assign_perm
from model_utils.managers import InheritanceManager
from packaging.version import Version, parse
from rest_framework.serializers import Serializer
from structlog.stdlib import get_logger

from authentik import __version__, get_build_hash
from authentik.blueprints.models import ManagedModel
from authentik.core.models import (
    USER_PATH_SYSTEM_PREFIX,
    Provider,
    Token,
    TokenIntents,
    User,
    UserTypes,
)
from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction
from authentik.lib.config import CONFIG
from authentik.lib.models import InheritanceForeignKey, SerializerModel
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.errors import exception_to_string
from authentik.outposts.controllers.k8s.utils import get_namespace
from authentik.tenants.models import Tenant

OUR_VERSION = parse(__version__)
OUTPOST_HELLO_INTERVAL = 10
LOGGER = get_logger()

USER_PATH_OUTPOSTS = USER_PATH_SYSTEM_PREFIX + "/outposts"

class ServiceConnectionInvalid(SentryIgnoredException):
    """Exception raised when a Service Connection has invalid parameters"""

@dataclass
# pylint: disable=too-many-instance-attributes
class OutpostConfig:
    """Configuration an outpost uses to configure it self"""

    # update website/docs/outposts/_config.md

    authentik_host: str = ""
    authentik_host_insecure: bool = False
    authentik_host_browser: str = ""

    log_level: str = CONFIG.get("log_level")
    object_naming_template: str = field(default="ak-outpost-%(name)s")

    container_image: Optional[str] = field(default=None)

    docker_network: Optional[str] = field(default=None)
    docker_map_ports: bool = field(default=True)
    docker_labels: Optional[dict[str, str]] = field(default=None)

    kubernetes_replicas: int = field(default=1)
    kubernetes_namespace: str = field(default_factory=get_namespace)
    kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict)
    kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls")
    kubernetes_ingress_class_name: Optional[str] = field(default=None)
    kubernetes_service_type: str = field(default="ClusterIP")
    kubernetes_disabled_components: list[str] = field(default_factory=list)
    kubernetes_image_pull_secrets: list[str] = field(default_factory=list)
    kubernetes_json_patches: Optional[dict[str, list[dict[str, Any]]]] = field(default=None)

class OutpostModel(Model):
    """Base model for providers that need more objects than just themselves"""

    def get_required_objects(self) -> Iterable[models.Model | str]:
        """Return a list of all required objects"""
        return [self]

    class Meta:
        abstract = True

class OutpostType(models.TextChoices):
    """Outpost types, currently only the reverse proxy is available"""

    PROXY = "proxy"
    LDAP = "ldap"
    RADIUS = "radius"

def default_outpost_config(host: Optional[str] = None):
    """Get default outpost config"""
    return asdict(OutpostConfig(authentik_host=host or ""))

@dataclass
class OutpostServiceConnectionState:
    """State of an Outpost Service Connection"""

    version: str
    healthy: bool

class OutpostServiceConnection(models.Model):
    """Connection details for an Outpost Controller, like Docker or Kubernetes"""

    uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
    name = models.TextField(unique=True)

    local = models.BooleanField(
        default=False,
        help_text=_(
            "If enabled, use the local connection. Required Docker socket/Kubernetes Integration"
        ),
    )

    objects = InheritanceManager()

    @property
    def state_key(self) -> str:
        """Key used to save connection state in cache"""
        return f"goauthentik.io/outposts/service_connection_state/{self.pk.hex}"

    @property
    def state(self) -> OutpostServiceConnectionState:
        """Get state of service connection"""
        from authentik.outposts.tasks import outpost_service_connection_state

        state = cache.get(self.state_key, None)
        if not state:
            outpost_service_connection_state.delay(self.pk)
            return OutpostServiceConnectionState("", False)
        return state

    @property
    def component(self) -> str:
        """Return component used to edit this object"""
        # This is called when creating an outpost with a service connection
        # since the response doesn't use the correct inheritance
        return ""

    class Meta:
        verbose_name = _("Outpost Service-Connection")
        verbose_name_plural = _("Outpost Service-Connections")

class DockerServiceConnection(SerializerModel, OutpostServiceConnection):
    """Service Connection to a Docker endpoint"""

    url = models.TextField(
        help_text=_(
            "Can be in the format of 'unix://<path>' when connecting to a local docker daemon, "
            "or 'https://<hostname>:2376' when connecting to a remote system."
        )
    )
    tls_verification = models.ForeignKey(
        CertificateKeyPair,
        null=True,
        blank=True,
        default=None,
        related_name="+",
        on_delete=models.SET_DEFAULT,
        help_text=_(
            "CA which the endpoint's Certificate is verified against. "
            "Can be left empty for no validation."
        ),
    )
    tls_authentication = models.ForeignKey(
        CertificateKeyPair,
        null=True,
        blank=True,
        default=None,
        related_name="+",
        on_delete=models.SET_DEFAULT,
        help_text=_(
            "Certificate/Key used for authentication. Can be left empty for no authentication."
        ),
    )

    @property
    def serializer(self) -> Serializer:
        from authentik.outposts.api.service_connections import DockerServiceConnectionSerializer

        return DockerServiceConnectionSerializer

    @property
    def component(self) -> str:
        return "ak-service-connection-docker-form"

    def __str__(self) -> str:
        return f"Docker Service-Connection {self.name}"

    class Meta:
        verbose_name = _("Docker Service-Connection")
        verbose_name_plural = _("Docker Service-Connections")

class KubernetesServiceConnection(SerializerModel, OutpostServiceConnection):
    """Service Connection to a Kubernetes cluster"""

    kubeconfig = models.JSONField(
        help_text=_(
            "Paste your kubeconfig here. authentik will automatically use "
            "the currently selected context."
        ),
        blank=True,
    )
    verify_ssl = models.BooleanField(
        default=True, help_text=_("Verify SSL Certificates of the Kubernetes API endpoint")
    )

    @property
    def serializer(self) -> Serializer:
        from authentik.outposts.api.service_connections import KubernetesServiceConnectionSerializer

        return KubernetesServiceConnectionSerializer

    @property
    def component(self) -> str:
        return "ak-service-connection-kubernetes-form"

    def __str__(self) -> str:
        return f"Kubernetes Service-Connection {self.name}"

    class Meta:
        verbose_name = _("Kubernetes Service-Connection")
        verbose_name_plural = _("Kubernetes Service-Connections")

class Outpost(SerializerModel, ManagedModel):
    """Outpost instance which manages a service user and token"""

    uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
    name = models.TextField(unique=True)

    type = models.TextField(choices=OutpostType.choices, default=OutpostType.PROXY)
    service_connection = InheritanceForeignKey(
        OutpostServiceConnection,
        default=None,
        null=True,
        blank=True,
        help_text=_(
            "Select Service-Connection authentik should use to manage this outpost. "
            "Leave empty if authentik should not handle the deployment."
        ),
        on_delete=models.SET_DEFAULT,
    )

    _config = models.JSONField(default=default_outpost_config)

    providers = models.ManyToManyField(Provider)

    @property
    def serializer(self) -> Serializer:
        from authentik.outposts.api.outposts import OutpostSerializer

        return OutpostSerializer

    @property
    def config(self) -> OutpostConfig:
        """Load config as OutpostConfig object"""
        return from_dict(OutpostConfig, self._config)

    @config.setter
    def config(self, value):
        """Dump config into json"""
        self._config = asdict(value)

    @property
    def state_cache_prefix(self) -> str:
        """Key by which the outposts status is saved"""
        return f"goauthentik.io/outposts/state/{self.uuid.hex}"

    @property
    def state(self) -> list["OutpostState"]:
        """Get outpost's health status"""
        return OutpostState.for_outpost(self)

    @property
    def user_identifier(self):
        """Username for service user"""
        return f"ak-outpost-{self.uuid.hex}"

    def build_user_permissions(self, user: User):
        """Create per-object and global permissions for outpost service-account"""
        # To ensure the user only has the correct permissions, we delete all of them and re-add
        # the ones the user needs
        with transaction.atomic():
            UserObjectPermission.objects.filter(user=user).delete()
            user.user_permissions.clear()
            for model_or_perm in self.get_required_objects():
                if isinstance(model_or_perm, models.Model):
                    model_or_perm: models.Model
                    code_name = (
                        f"{model_or_perm._meta.app_label}.view_{model_or_perm._meta.model_name}"
                    )
                    try:
                        assign_perm(code_name, user, model_or_perm)
                    except (Permission.DoesNotExist, AttributeError) as exc:
                        LOGGER.warning(
                            "permission doesn't exist",
                            code_name=code_name,
                            user=user,
                            model=model_or_perm,
                        )
                        Event.new(
                            action=EventAction.SYSTEM_EXCEPTION,
                            message=(
                                "While setting the permissions for the service-account, a "
                                "permission was not found: Check "
                                "https://goauthentik.io/docs/troubleshooting/missing_permission"
                            )
                            + exception_to_string(exc),
                        ).set_user(user).save()
                else:
                    app_label, perm = model_or_perm.split(".")
                    permission = Permission.objects.filter(
                        codename=perm,
                        content_type__app_label=app_label,
                    )
                    if not permission.exists():
                        LOGGER.warning("permission doesn't exist", perm=model_or_perm)
                        continue
                    user.user_permissions.add(permission.first())
        LOGGER.debug(
            "Updated service account's permissions",
            obj_perms=UserObjectPermission.objects.filter(user=user),
            perms=user.user_permissions.all(),
        )

    @property
    def user(self) -> User:
        """Get/create user with access to all required objects"""
        user = User.objects.filter(username=self.user_identifier).first()
        user_created = False
        if not user:
            user: User = User.objects.create(username=self.user_identifier)
            user.set_unusable_password()
            user_created = True
        user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT
        user.name = f"Outpost {self.name} Service-Account"
        user.path = USER_PATH_OUTPOSTS
        user.save()
        if user_created:
            self.build_user_permissions(user)
        return user

    @property
    def token_identifier(self) -> str:
        """Get Token identifier"""
        return f"ak-outpost-{self.pk}-api"

    @property
    def token(self) -> Token:
        """Get/create token for auto-generated user"""
        managed = f"goauthentik.io/outpost/{self.token_identifier}"
        tokens = Token.filter_not_expired(
            identifier=self.token_identifier,
            intent=TokenIntents.INTENT_API,
            managed=managed,
        )
        if tokens.exists():
            return tokens.first()
        try:
            return Token.objects.create(
                user=self.user,
                identifier=self.token_identifier,
                intent=TokenIntents.INTENT_API,
                description=f"Autogenerated by authentik for Outpost {self.name}",
                expiring=False,
                managed=managed,
            )
        except IntegrityError:
            # Integrity error happens mostly when managed is reused
            Token.objects.filter(managed=managed).delete()
            Token.objects.filter(identifier=self.token_identifier).delete()
            return self.token

    def get_required_objects(self) -> Iterable[models.Model | str]:
        """Get an iterator of all objects the user needs read access to"""
        objects: list[models.Model | str] = [
            self,
            "authentik_events.add_event",
        ]
        for provider in Provider.objects.filter(outpost=self).select_related().select_subclasses():
            if isinstance(provider, OutpostModel):
                objects.extend(provider.get_required_objects())
            else:
                objects.append(provider)
        if self.managed:
            for tenant in Tenant.objects.filter(web_certificate__isnull=False):
                objects.append(tenant)
                objects.append(tenant.web_certificate)
        return objects

    def __str__(self) -> str:
        return f"Outpost {self.name}"

    class Meta:
        verbose_name = _("Outpost")
        verbose_name_plural = _("Outposts")

@dataclass
class OutpostState:
    """Outpost instance state, last_seen and version"""

    uid: str
    last_seen: Optional[datetime] = field(default=None)
    version: Optional[str] = field(default=None)
    version_should: Version = field(default=OUR_VERSION)
    build_hash: str = field(default="")
    hostname: str = field(default="")
    args: dict = field(default_factory=dict)

    _outpost: Optional[Outpost] = field(default=None)

    @property
    def version_outdated(self) -> bool:
        """Check if outpost version matches our version"""
        if not self.version:
            return False
        if self.build_hash != get_build_hash():
            return False
        return parse(self.version) < OUR_VERSION

    @staticmethod
    def for_outpost(outpost: Outpost) -> list["OutpostState"]:
        """Get all states for an outpost"""
        keys = cache.keys(f"{outpost.state_cache_prefix}/*")
        if not keys:
            return []
        states = []
        for key in keys:
            instance_uid = key.replace(f"{outpost.state_cache_prefix}/", "")
            states.append(OutpostState.for_instance_uid(outpost, instance_uid))
        return states

    @staticmethod
    def for_instance_uid(outpost: Outpost, uid: str) -> "OutpostState":
        """Get state for a single instance"""
        key = f"{outpost.state_cache_prefix}/{uid}"
        default_data = {"uid": uid, "channel_ids": []}
        data = cache.get(key, default_data)
        if isinstance(data, str):
            cache.delete(key)
            data = default_data
        state = from_dict(OutpostState, data)
        # pylint: disable=protected-access
        state._outpost = outpost
        return state

    def save(self, timeout=OUTPOST_HELLO_INTERVAL):
        """Save current state to cache"""
        full_key = f"{self._outpost.state_cache_prefix}/{self.uid}"
        return cache.set(full_key, asdict(self), timeout=timeout)

    def delete(self):
        """Manually delete from cache, used on channel disconnect"""
        full_key = f"{self._outpost.state_cache_prefix}/{self.uid}"
        cache.delete(full_key)


import copy
import functools
import inspect
from collections.abc import Callable, Iterator
from typing import Any, NamedTuple, TypeVar

__all__ = ['latebinding']

_R = TypeVar('_R')
_T = TypeVar('_T')
_V = TypeVar('_V')

class _LateBound(NamedTuple):
    actual: Any

def late(o: _T | Iterator[_V] | Callable[[], _R]) -> _T | _V | _R:
    if isinstance(o, int | float | bool | str | bytes):
        return o  # type: ignore

    return _LateBound(actual=o)  # type: ignore

__ = late
包 = late

def _resolve_value(value):
    if isinstance(value, _LateBound):
        value = value.actual
    if isinstance(value, int | float | bool | str | bytes):
        return value
    if isinstance(value, Iterator):
        return next(value)
    if inspect.isfunction(value):
        return value()
    return copy.deepcopy(value)

def _lateargs(func: Callable, **kwargs) -> dict[str, Any]:

    lateargs = {
        name: _resolve_value(param.default)
        for name, param in inspect.signature(func).parameters.items()
        if name not in kwargs and param.default != inspect._empty
    }
    return {**kwargs, **lateargs}

def latebinding(target: Callable | type) -> Callable | type:
    if type(target) is type:
        return _latebindclass(target)

    @functools.wraps(target)
    def wrapper(*args, **kwargs):
        kwargs = _lateargs(target, **kwargs)
        return target(*args, **kwargs)

    return wrapper

def _latebindclass(cls: type) -> type:
    old_init = cls.__init__  # type: ignore[misc]

    @functools.wraps(old_init)
    def new_init(self, *args, **kwargs):
        kwargs = _lateargs(old_init, **kwargs)
        old_init(self, *args, **kwargs)

    cls.__init__ = new_init  # type: ignore[misc]
    return cls


"""empty message

Revision ID: 24d3490f4c0a
Revises: ed55e1da3fbc
Create Date: 2022-11-07 23:33:06.377935

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '24d3490f4c0a'
down_revision = 'ed55e1da3fbc'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('desparasitacion', sa.Column('cliente_id', sa.Integer(), nullable=True))
    op.create_foreign_key(None, 'desparasitacion', 'cliente', ['cliente_id'], ['id'])
    op.add_column('ficha__medica', sa.Column('cliente_id', sa.Integer(), nullable=True))
    op.create_foreign_key(None, 'ficha__medica', 'cliente', ['cliente_id'], ['id'])
    op.add_column('vacuna', sa.Column('cliente_id', sa.Integer(), nullable=True))
    op.create_foreign_key(None, 'vacuna', 'cliente', ['cliente_id'], ['id'])
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint(None, 'vacuna', type_='foreignkey')
    op.drop_column('vacuna', 'cliente_id')
    op.drop_constraint(None, 'ficha__medica', type_='foreignkey')
    op.drop_column('ficha__medica', 'cliente_id')
    op.drop_constraint(None, 'desparasitacion', type_='foreignkey')
    op.drop_column('desparasitacion', 'cliente_id')
    # ### end Alembic commands ###


'''2019年8月份之后裁判文书网改版，其反爬非常强，所以模拟键盘鼠标操作后等待很久也等不到刷新，
所以这里主要给大家练习下如何通过selenium库模拟键盘鼠标操作。'''

from selenium.webdriver.common.by import By
from selenium.webdriver import Chrome
import time
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
Chrome = Chrome(options=chrome_options)    #前三行，启动chromedriver,无界面浏览
#Chrome = Chrome()       #有界面浏览
Chrome.get('http://wenshu.court.gov.cn/')
Chrome.maximize_window()
Chrome.find_element(By.XPATH, '//*[@id="_view_1540966814000"]/div/div[1]/div[2]/input').clear()  # 清空原搜索框
Chrome.find_element(By.XPATH, '//*[@id="_view_1540966814000"]/div/div[1]/div[2]/input').send_keys('房地产')  # 在搜索框内模拟输入'房地产'三个字
Chrome.find_element(By.XPATH, '//*[@id="_view_1540966814000"]/div/div[1]/div[3]').click()  # 点击搜索按钮
time.sleep(20)  # 现在裁判文书网反爬非常厉害，所以可能等待也等不到刷新，所以这里主要给大家练习下模拟键盘鼠标操作
data = Chrome.page_source
Chrome.quit()
print(data)

金融数据挖掘案例实战2/裁判文书网数据挖掘.py

裁判文书网数据挖掘.py


"""
Request Argument Standardization
"""

import logging
import re
from collections import UserDict, abc, defaultdict
from datetime import datetime as dt
from pprint import pformat
from types import MappingProxyType

import jmespath
import orjson

try:
    from re import Pattern  # py>=3.7
except ImportError:
    from typing import Pattern

try:
    from functools import singledispatchmethod  # py>=3.7
except ImportError:
    from singledispatchmethod import singledispatchmethod

from biothings.utils.common import dotdict, split_ids

class OptionError(ValueError):
    def __init__(self, reason=None, **kwargs):
        super().__init__()
        self.info = {"reason": reason}
        self.info.update(kwargs)

    def simplify(self):
        self.info = {k: v for k, v in self.info.items() if v}

    def __str__(self):
        return f"OptionError({pformat(self.info)})"

class Converter:
    """
    A generic HTTP request argument processing unit.
    Only perform one level of validation at this moment.
    The strict switch controls the type conversion rules.
    """

    def __init__(self, **kwargs):
        self.keyword = kwargs.get("keyword")
        self.type_ = kwargs.get("type", str)
        self.strict = kwargs.get("strict", True)
        translations = kwargs.get("translations", ())

        # Opinion on what value self.type_ can take
        # ---------------------------------------------
        # Although it may sound attractive to use non-native
        # "type" here to simplify certain object constuction
        # through the converstion process, and indeed it is
        # supported through self.to_type, this could lead to
        # difficulties in OptionSet serialization and other
        # problems in integration with this module.

        self.translations = []

        if isinstance(translations, dict):
            translations = translations.items()

        for pattern, repl in translations:
            if isinstance(pattern, Pattern):
                self.translations.append((pattern, repl))
            elif isinstance(pattern, tuple):
                self.translations.append((re.compile(*pattern), repl))
            elif isinstance(pattern, str):
                self.translations.append((re.compile(pattern), repl))
            else:  # https://docs.python.org/3/library/re.html#re.compile
                raise TypeError("Invalid Regex Pattern.")

    def __call__(self, value, to_type):
        return self.convert_to(value, to_type)

    @classmethod
    def subclasses(cls, kwargs):
        for kls in cls.__subclasses__():
            name = kls.__name__[: -len("ArgCvter")]
            yield name.lower(), kls(**kwargs)

    def convert(self, value):
        return self.convert_to(value, self.type_)

    def convert_to(self, value, to_type):
        # default implementation
        # only works for strings
        assert isinstance(value, str)

        if to_type is None:
            to_type = self.type_

        if to_type is str:
            return value  # pass through

        if to_type is bool:
            return self.str_to_bool(value)

        if to_type is int:
            return self.str_to_int(value)

        if to_type in (list, tuple, set):
            lst = self.str_to_list(value)
            return self.to_type(lst, to_type)

        return self.to_type(value, to_type)

    def translate(self, value):
        if isinstance(value, (tuple, list, set)):
            return (type(value))(self.translate(item) for item in value)

        if not isinstance(value, str):
            return value  # can only perform translations to strings

        # https://docs.python.org/3/library/re.html#re.sub
        for pattern, repl in self.translations:
            value = re.sub(pattern, repl, value)

        if self.keyword == "jmespath" and value:
            # processing jmespath parameter to be a tuple of (target_field_path, jmes_query)
            try:
                target_field_path, jmes_query = value.split("|", maxsplit=1)
                jmes_query = jmespath.compile(jmes_query)
            except ValueError as err:  # JMES exeptions are subclasses of ValueError
                raise OptionError(keyword=self.keyword, reason="Invalid value for jmespath parameter", details=str(err))
            value = target_field_path, jmes_query

        return value

    @staticmethod
    def str_to_bool(val):
        """Interpret string representation of bool values."""
        assert isinstance(val, str)
        try:  # if it is a number
            return float(val) > 0
        except ValueError:
            pass  # process as keywords
        return val.lower() in ("1", "true", "yes", "y", "t")

    # Opinion on str -> list
    #
    # It appears to have become more problematic recently, as the variety
    # of data increase in biothings applications, causing the identifiers
    # and field values hard to escape properly when used in queries.
    #
    # Consider implementing a very safe splitting algorithm that only works
    # for basic cases like a,b,c and use other methods like JSON input to
    # pass in complex queries.
    #
    # For example, for field reagent.GNF_mm+hs-MGC in Mygene:
    # the current algorithm will split it into ['reagent.GNF_mm', 'hs-MGC'

    @staticmethod
    def str_to_list(val):
        """Cast Biothings-style str to list."""
        try:  # core splitting algorithm
            lst = split_ids(str(val))
        except ValueError as err:
            raise OptionError(str(err))
        return lst

    def str_to_int(self, val):
        """Convert a numerical string to an integer."""
        assert isinstance(val, str)
        if not self.strict:
            val = self.to_type(val, float)
        return self.to_type(val, int)

    @staticmethod
    def to_type(val, type_):
        """
        Native type casting in Python.
        Fallback approach for type casting.
        """
        try:
            result = (type_)(val)
        except (ValueError, TypeError):
            raise OptionError(f"Expect type {type_.__name__}.")
        return result

class PathArgCvter(Converter):
    """
    Dedicated argument converter for path arguments.
    Correspond to arguments received in tornado for
        RequestHandler.path_args
        RequestHandler.path_kwargs
    See https://www.tornadoweb.org/en/stable/web.html
    """

class QueryArgCvter(Converter):
    """
    Dedicated argument converter for url query arguments.
    Correspond to arguments received in tornado from
        RequestHandler.get_query_argument
    See https://www.tornadoweb.org/en/stable/web.html
    """

    @classmethod
    def str_to_bool(cls, val):
        """Biothings-style str to bool interpretation"""
        # empty string indicates the presence of its key
        # we consider this to be a positive boolean value
        # this is especially useful in url when the user
        # may specify endpoint?op1&op2&op3 in which case
        # it makes sense to consider their keys true.
        return super().str_to_bool(val) or val.lower() == ""

class FormArgCvter(Converter):
    """
    Dedicated argument converter for HTTP body arguments.
    Additionally support JSON seriealization format as values.
    Correspond to arguments received in tornado from
        RequestHandler.get_body_argument
    See https://www.tornadoweb.org/en/stable/web.html
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # If jsoninput evaluates to true,
        # try to load the str as a json dump
        jsoninput = kwargs.get("jsoninput", False)
        if isinstance(jsoninput, bool):
            self.jsoninput = jsoninput
        else:  # it itself can be in argument format
            self.jsoninput = self.convert_to(jsoninput, bool)

    # Opinion on JsonInput
    #
    # The aforementioned feature was partly for convenience and partly
    # for backward compatibility with the original published design.
    #
    # It might be more beneficial to use standard data serialization
    # format like JSON to indicate data type unequivocally.

    def convert_to(self, value, to_type):
        if self.jsoninput:
            try:  # attempt to load as json first
                _value = orjson.loads(value)
            except orjson.JSONDecodeError as exc:
                logging.debug(repr(exc))
            else:  # no more conversions
                if isinstance(_value, to_type):
                    return _value
        if isinstance(value, to_type):
            return value
        if isinstance(value, str):
            return super().convert_to(value, to_type)
        return self.to_type(value, to_type)

class JsonArgCvter(Converter):
    """
    Dedicated argument converter for JSON HTTP bodys.
    Here it is used for dict JSON objects, with their
    first level keys considered as parameters and
    their values considered as arguments to process.

    May correspond to this tornado implementation:
    https://www.tornadoweb.org/en/stable/web.html#input
    """

    def convert_to(self, value, to_type):
        if isinstance(value, to_type):
            return value  # type matches

        if self.strict:
            # since JSON support value types
            # strict mode enforces it and essentially
            # makes this step a validation step.
            raise OptionError(f"Expect type {to_type.__name__}.")

        # mostly for biothings client 0.2.3 compatibility
        if isinstance(value, str) and to_type is list:
            return self.str_to_list(value)

        return self.to_type(value, to_type)

    def to_type(self, val, type_):
        if issubclass(type_, (list, tuple, set)) and not self.strict:
            val = (val,)  # "abc" -> ["abc"] instead of ["a", "b", "c"]

        return super().to_type(val, type_)

class ReqResult(dotdict):
    # besides multi-level attribute(dot)
    # read and write access, this class
    # also returns None value for missing
    # keys instead of raising an error

    def __str__(self):
        return f"ReqResult({pformat(self)})"

class ReqArgs:
    class Path:
        def __init__(self, args=None, kwargs=None):
            if args is None:
                args = ()
            if kwargs is None:
                kwargs = {}
            assert isinstance(args, (tuple, list))
            assert isinstance(kwargs, dict)
            self.args = args
            self.kwargs = kwargs

        def __getitem__(self, key):
            try:
                if isinstance(key, int):
                    return self.args[key]
                if isinstance(key, str):
                    return self.kwargs[key]
            except (KeyError, IndexError):
                return None

        def __bool__(self):
            return bool(self.args) or bool(self.kwargs)

        def __str__(self):
            lines = []
            for src in ("args", "kwargs"):
                if getattr(self, src):
                    lines.append("{}={}".format(src, str(getattr(self, src))))
            return "Path(" + ", ".join(lines) + (")")

    def __init__(self, path=None, query=None, form=None, json_=None):
        assert isinstance(query, (dict, type(None)))
        assert isinstance(form, (dict, type(None)))

        if not isinstance(path, (self.Path, type(None))):
            path = self.Path(*path)

        self.path = path  # positional and named capture group in a routing pattern
        self.query = query  # key value pairs after a question mark at the end of an url
        self.form = form  # type multipart/form-data and application/x-www-form-urlencoded
        self.json = json_ if isinstance(json_, dict) else {}  # type application/json

    def lookup(self, locator, order=None, src=False):
        if isinstance(locator, str):
            locator = Locator(dict(keyword=locator))
        elif isinstance(locator, dict):
            locator = Locator(locator)
        elif not isinstance(locator, Locator):
            raise TypeError("Unknown Locator.")

        if order is None:
            order = ("path", "query", "form", "json")
        elif isinstance(order, str):
            order = (order,)
        elif not isinstance(order, abc.Iterable):
            raise TypeError("Unknown Order.")

        for loc in order:
            try:
                args = getattr(self, loc)
                val = locator.lookin(args)
            except AttributeError:
                _ = "No such location: %s."
                logging.warning(_, loc)
            else:
                if val is not None:
                    return (val, loc) if src else val

        return (None, None) if src else None

    def __str__(self):
        lines = []
        for src in ("path", "query", "form", "json"):
            if getattr(self, src):
                lines.append("{}={}".format(src, str(getattr(self, src))))
        return "ReqArgs(" + ",\n".join(lines) + (")")

class Locator:
    """
    Describes the location of an argument in ReqArgs.
    {
        "keyword": <str>,
        "path": <int or str>,
        "alias": <str or [<str>, ...]>
    }
    """

    def __init__(self, defdict):
        self.keyword = defdict.get("keyword")
        self.path = defdict.get("path")
        aliases = defdict.get("alias", [])

        assert isinstance(self.path, (str, int, type(None)))
        assert isinstance(self.keyword, (str, type(None)))

        if isinstance(aliases, (list, tuple)):
            self.aliases = aliases
        elif isinstance(aliases, str):
            self.aliases = [aliases]
        else:  # validation failed
            raise ValueError("Unknown Alias.")

    @singledispatchmethod
    def lookin(self, location):
        """
        Find an argument in the specified location.
        Use directions indicated in this locator.
        """

    @lookin.register(ReqArgs.Path)
    def _(self, path):
        if self.path is not None:
            return path[self.path]
        return None

    @lookin.register(dict)  # all others
    def _(self, dic):
        if self.keyword in dic:
            return dic[self.keyword]
        for alias in self.aliases:
            if alias in dic:
                return dic[alias]
        return None

class Existentialist:
    """
    Describes the requirement of
    the existance of an argument.
    {
        "default": <object>,
        "required": <bool>,
    }
    """

    def __init__(self, defdict):
        self._defdict = MappingProxyType(defdict)
        self.keyword = defdict.get("keyword")
        self.required = bool(defdict.get("required"))
        self.default = defdict.get("default")

        if self.default and self.required:
            logging.warning(
                (
                    "A default value is set for parameter '%s' "
                    "while 'required' is set to True, making it"
                    "ineffective."
                ),
                self.keyword,
            )

    def inquire(self, obj):
        if obj is None:
            if self.required:
                raise OptionError(
                    missing=self.keyword,
                    keyword=None,  # empty this field
                    alias=self._defdict.get("alias"),
                )

            obj = self.default

        return obj

class Validator:
    """
    Describes the requirement of
    the existance of an argument.
    {
        "enum": <container>,
        "max": <int>,
        "min": <int>,
        "date_format": <str>,
    }
    """

    def __init__(self, defdict):
        self._defdict = MappingProxyType(defdict)
        self.keyword = defdict.get("keyword")
        self.strict = defdict.get("strict", True)
        self.enum = defdict.get("enum", ())
        self.max = defdict.get("max")
        self.min = defdict.get("min")
        self.date_format = defdict.get("date_format")

        assert isinstance(self.enum, abc.Container)
        assert isinstance(self.max, (int, type(None)))
        assert isinstance(self.min, (int, type(None)))
        assert isinstance(self.date_format, (str, type(None)))

    def validate(self, obj):
        if self.enum and not self._in_enum(obj):
            raise OptionError(
                keyword=self.keyword,
                allowed=self.enum,
                alias=self._defdict.get("alias"),
            )

        if self.max:
            if isinstance(obj, (list, tuple, set)):
                self._check_list_max(obj)
            elif isinstance(obj, (int, float, complex)):
                self._check_num_max(obj)

        if self.min:
            if isinstance(obj, (list, tuple, set)):
                self._check_list_min(obj)
            elif isinstance(obj, (int, float, complex)):
                self._check_num_min(obj)

        if self.date_format and isinstance(obj, str):
            self._check_date_format(obj)
        return obj

    def _in_enum(self, value):
        if isinstance(value, (list, tuple, set)):
            for val in value:
                if not self._in_enum(val):
                    return False
            return True

        return value in self.enum

    def _check_list_max(self, container):
        if len(container) > self.max:
            raise OptionError(keyword=self.keyword, max=self.max, size=len(container))

    def _check_num_max(self, num):
        if isinstance(num, bool):
            return

        if num > self.max:
            raise OptionError(keyword=self.keyword, max=self.max, num=num)

    def _check_list_min(self, container):
        if len(container) > self.min:
            raise OptionError(keyword=self.keyword, min=self.min, size=len(container))

    def _check_num_min(self, num):
        if isinstance(num, bool):
            return

        if num < self.min:
            raise OptionError(keyword=self.keyword, min=self.min, num=num)

    def _check_date_format(self, value):
        try:
            dt.strptime(value, self.date_format)
        except Exception:
            raise OptionError(keyword=self.keyword, date_format=self.date_format, num=value)

# For Future Work
# ------------------

# Consider supporting the OpenAPI-compatible JSON Schema
# definitions as a subset of keys to describe the Option.
# By doing this, it is both easier to validate the input
# and to generate an OpenAPI Specification. Validation
# can be performed by existing packages like "jsonschema",
# and components of the OpenAPI Specifications can be
# generated by directly taking the relevant keys from the
# Option definition. However, keep in mind that validation
# and converstion will still not be straightforward when
# dealing with query parameters and form-encoded requests.

# To illustrate the benefit of using a subset of JSON Schema
# as our option validation language, take the example of
# validating complex objects. Currently, nested objects or
# containers are only validated at the top level, with the
# help of JSON schema, we could easily find the syntax needed
# to define the object structure and perform validation.
# Comparing to designing the schema language ourselves,
# and writing validation code for that purpose, using an
# existing framework should save time and improve accuracy,
# not to mention the additional benefit of spec generation.

# For more about OpenAPI-compatible JSON Schema:
# https://swagger.io/specification/#schema-object

class Option(UserDict):
    """
    A parameter for end applications to consume.
    Find the value of it in the desired *location*.

    For example:
    {
        "keyword": "q",
        "location": ("query", "form", "json"),
        "default": "__all__",
        "type": "str"
    }
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._locater = Locator(self)
        self._exists = Existentialist(self)
        self._typify = dict(Converter.subclasses(self))
        self._validator = Validator(self)

        # default argument parsing location order
        self.order = self.get("location", None)
        if self.order == "body":  # shortcut
            self.order = ("form", "json")

    def parse(self, reqargs):
        if not isinstance(reqargs, ReqArgs):
            reqargs = ReqArgs(*reqargs)

        # ------- debug here -------
        # if self.get("keyword") == "q":
        #     print()  # breakpoint
        # ---------------------------

        # find the user input
        val, loc = reqargs.lookup(locator=self._locater, order=self.order, src=True)

        if val is None:
            val = self._exists.inquire(val)
        else:  # type conversion and transform
            val = self._typify[loc].convert(val)
            val = self._typify[loc].translate(val)

        # additional conditions
        val = self._validator.validate(val)

        return val

class OptionSet(UserDict):
    """
    A collection of options that a specific endpoint consumes.
    Divided into *groups* and by the *request methods*.

    For example:
    {
        "*":{"raw":{...},"size":{...},"dotfield":{...}},
        "GET":{"q":{...},"from":{...},"sort":{...}},
        "POST":{"q":{...},"scopes":{...}}
    }
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.groups = set()  # explicit result access groups
        self.setup()  # populate self.optset variable

    def __missing__(self, key):
        self.data[key] = {}
        return self[key]

    def setup(self):
        """
        Apply the wildcard method configurations dict.
        Must call this method after changes to this object.
        """
        # store Option objects used for parse method
        self.optset = defaultdict(dict)

        for method, options in self.data.items():
            for keyword, defdict in options.items():
                option = dict(defdict)
                option["keyword"] = keyword
                self.optset[method][keyword] = Option(option)
                if "group" in option:
                    if isinstance(option["group"], (list, tuple, set)):
                        self.groups.update(option["group"])
                    elif isinstance(option["group"], str):
                        self.groups.add(option["group"])

        wildcards = self.optset.get("*", {})
        for _method, options in self.optset.items():
            for keyword, option in wildcards.items():
                options.setdefault(keyword, option)

    def parse(self, method, reqargs):
        """
        Parse a HTTP request, represented by its method and args,
        with this OptionSet and return an attribute dictionary.
        """

        options = self.optset.get(method, self.optset["*"])
        result = defaultdict(dict)  # to accomodate groups

        for keyword, option in options.items():
            try:
                val = option.parse(reqargs)
            except OptionError as err:
                err.info.setdefault("keyword", keyword)
                err.info["alias"] = option.get("alias")
                err.simplify()  # remove empty fields
                raise err  # with helpful info

            if val is not None:
                if "group" in option:
                    group = option["group"]
                    if isinstance(group, str):
                        result[group][keyword] = val
                    else:  # assume iterable
                        for _group in group:
                            result[_group][keyword] = val
                else:  # top level keywords
                    result[keyword] = val
            elif "default" in option:  # explicit None
                result[keyword] = None

        # make sure all named groups exist
        for group in self.groups:
            if group not in result:
                result[group] = {}

        return ReqResult(result)

class OptionsManager(UserDict):
    """
    A collection of OptionSet(s) that makes up an application.
    Provide an interface to setup and serialize.

    Example:
    {
        "annotation": {"*": {...}, "GET": {...}, "POST": {... }},
        "query": {"*": {...},  "GET": {...}, "POST": {... }},
        "metadata": {"GET": {...}, "POST": {... }}
    }
    """

    def add(self, name, optionset, groups=()):
        if not name:
            logging.warning("Ignore unnamed optionset:\n%s", optionset)
        if name not in self.data:
            self.data[name] = OptionSet(optionset)
            self.data[name].groups.update(groups)
        else:  # update existing optionset
            for method, options in optionset.items():
                # merge second level objects
                self.data[name][method].update(options)
                self.data[name].groups.update(groups)
                self.data[name].setup()  # required

    def log(self):
        # serializable API-ready format
        return self._serialize(self)

    def _serialize(self, obj):
        if isinstance(obj, abc.Mapping):
            _obj = {}
            items = list(obj.items())
            for key, val in sorted(items):
                _obj[key] = self._serialize(val)
            return _obj
        if isinstance(obj, (list, tuple)):
            return [self._serialize(item) for item in obj]
        if isinstance(obj, (str, int)):
            return obj
        if hasattr(obj, "__name__"):
            return obj.__name__
        return str(obj)  # best effort


from typing import List, Dict, Optional

from pydantic import BaseModel, Field

__all__ = ["ProductGetArgs"]

class ProductGetArgs(BaseModel):
    """
    获取一个产品的信息

    doc: https://open.taobao.com/api.htm?docId=4&docType=2
    """

    product_id: Optional[int] = Field(
        None,
        title="Product的id",
        description="""
    两种方式来查看一个产品:
    1.传入product_id来查询
    2.传入cid和props来查询
    """,
    )

    cid: Optional[int] = Field(
        None,
        title="商品类目id",
        description="""

    调用taobao.itemcats.get获取;
    必须是叶子类目id,
    如果没有传product_id,那么cid和props必须要传.
    """,
    )

    #
    props: Optional[int] = Field(
        None,
        title="诺基亚N73这个产品的关键属性列表",
        description="品牌:诺基亚;型号:N73,对应的PV值就是10005:10027;10006:29729.",
    )

    method: str = Field("taobao.product.get", title="固定值")

    # 需要返回的字段列表，可选值为返回示例值中的可以看到的字段
    fields: List[str] = ("name", "binds", "product_id")

    def to_dict(self) -> Dict[str, str]:
        d = self.dict()
        d["fields"] = ",".join(d["fields"])
        return d


from typing import Union

import numpy as np
import scipy
import skimage
from scipy import ndimage

def resize_img3d(img: np.ndarray, target_size: Union[tuple, list, np.array]):
    scale = get_scale(img, target_size)
    resized_img = scipy.ndimage.zoom(img, scale)
    return resized_img

def resize_mask3d(mask, target_size):
    scale = get_scale(mask, target_size)
    ohe_mask = ohe_ndarray(mask)

    # Process each ohe channel individually
    resized = []
    for ch in range(ohe_mask.shape[-1]):
        resized_ch = ndimage.zoom(ohe_mask[:, :, :, ch], scale)
        new_mask = skimage.img_as_bool(resized_ch)
        resized += [new_mask]
    resized = np.stack(resized).astype(np.uint8)

    # From ohe to indices
    resized = np.argmax(resized, axis=0)
    return resized

def get_scale(img, target_shape):
    img_shape = np.array(img.shape)
    target_shape = np.array(target_shape)

    scale = target_shape / img_shape
    return scale

def ohe_ndarray(array):
    shape = array.shape
    values = array.reshape(-1).astype(np.uint8)
    n_values = np.max(values) + 1
    ohe = np.eye(n_values)[values]

    return ohe.reshape(*shape, n_values)

def pad_to_size_3d(img, result_size, value=0):
    new_shape = [s for s in result_size]
    if len(img.shape) == 4:
        new_shape.append(img.shape[3])
    new_img = np.full(new_shape, value, dtype=img.dtype)

    shape_diff = np.array(new_shape) - img.shape
    pad0, pad1, pad2 = shape_diff[0] // 2, shape_diff[1] // 2, shape_diff[2] // 2
    new_img[
        pad0 : pad0 + img.shape[0],
        pad1 : pad1 + img.shape[1],
        pad2 : pad2 + img.shape[2],
    ] = img.copy()

    return new_img


import torch
import torch.nn as nn
from mmcv.cnn import ConvModule
from mmcv.ops import point_sample, rel_roi_point_to_rel_img_point
from mmcv.runner import BaseModule

from mmdet.models.builder import HEADS, build_loss
from mmdet.models.utils import (get_uncertain_point_coords_with_randomness,
                                get_uncertainty)

@HEADS.register_module()
class MaskPointHead(BaseModule):
    """A mask point head use in PointRend.

    ``MaskPointHead`` use shared multi-layer perceptron (equivalent to
    nn.Conv1d) to predict the logit of input points. The fine-grained feature
    and coarse feature will be concatenate together for predication.

    Args:
        num_fcs (int): Number of fc layers in the head. Default: 3.
        in_channels (int): Number of input channels. Default: 256.
        fc_channels (int): Number of fc channels. Default: 256.
        num_classes (int): Number of classes for logits. Default: 80.
        class_agnostic (bool): Whether use class agnostic classification.
            If so, the output channels of logits will be 1. Default: False.
        coarse_pred_each_layer (bool): Whether concatenate coarse feature with
            the output of each fc layer. Default: True.
        conv_cfg (dict | None): Dictionary to construct and config conv layer.
            Default: dict(type='Conv1d'))
        norm_cfg (dict | None): Dictionary to construct and config norm layer.
            Default: None.
        loss_point (dict): Dictionary to construct and config loss layer of
            point head. Default: dict(type='CrossEntropyLoss', use_mask=True,
            loss_weight=1.0).
        init_cfg (dict or list[dict], optional): Initialization config dict.
    """

    def __init__(self,
                 num_classes,
                 num_fcs=3,
                 in_channels=256,
                 fc_channels=256,
                 class_agnostic=False,
                 coarse_pred_each_layer=True,
                 conv_cfg=dict(type='Conv1d'),
                 norm_cfg=None,
                 act_cfg=dict(type='ReLU'),
                 loss_point=dict(
                     type='CrossEntropyLoss', use_mask=True, loss_weight=1.0),
                 init_cfg=dict(
                     type='Normal', std=0.001,
                     override=dict(name='fc_logits'))):
        super().__init__(init_cfg)
        self.num_fcs = num_fcs
        self.in_channels = in_channels
        self.fc_channels = fc_channels
        self.num_classes = num_classes
        self.class_agnostic = class_agnostic
        self.coarse_pred_each_layer = coarse_pred_each_layer
        self.conv_cfg = conv_cfg
        self.norm_cfg = norm_cfg
        self.loss_point = build_loss(loss_point)

        fc_in_channels = in_channels + num_classes
        self.fcs = nn.ModuleList()
        for _ in range(num_fcs):
            fc = ConvModule(
                fc_in_channels,
                fc_channels,
                kernel_size=1,
                stride=1,
                padding=0,
                conv_cfg=conv_cfg,
                norm_cfg=norm_cfg,
                act_cfg=act_cfg)
            self.fcs.append(fc)
            fc_in_channels = fc_channels
            fc_in_channels += num_classes if self.coarse_pred_each_layer else 0

        out_channels = 1 if self.class_agnostic else self.num_classes
        self.fc_logits = nn.Conv1d(
            fc_in_channels, out_channels, kernel_size=1, stride=1, padding=0)

    def forward(self, fine_grained_feats, coarse_feats):
        """Classify each point base on fine grained and coarse feats.

        Args:
            fine_grained_feats (Tensor): Fine grained feature sampled from FPN,
                shape (num_rois, in_channels, num_points).
            coarse_feats (Tensor): Coarse feature sampled from CoarseMaskHead,
                shape (num_rois, num_classes, num_points).

        Returns:
            Tensor: Point classification results,
                shape (num_rois, num_class, num_points).
        """

        x = torch.cat([fine_grained_feats, coarse_feats], dim=1)
        for fc in self.fcs:
            x = fc(x)
            if self.coarse_pred_each_layer:
                x = torch.cat((x, coarse_feats), dim=1)
        return self.fc_logits(x)

    def get_targets(self, rois, rel_roi_points, sampling_results, gt_masks,
                    cfg):
        """Get training targets of MaskPointHead for all images.

        Args:
            rois (Tensor): Region of Interest, shape (num_rois, 5).
            rel_roi_points: Points coordinates relative to RoI, shape
                (num_rois, num_points, 2).
            sampling_results (:obj:`SamplingResult`): Sampling result after
                sampling and assignment.
            gt_masks (Tensor) : Ground truth segmentation masks of
                corresponding boxes, shape (num_rois, height, width).
            cfg (dict): Training cfg.

        Returns:
            Tensor: Point target, shape (num_rois, num_points).
        """

        num_imgs = len(sampling_results)
        rois_list = []
        rel_roi_points_list = []
        for batch_ind in range(num_imgs):
            inds = (rois[:, 0] == batch_ind)
            rois_list.append(rois[inds])
            rel_roi_points_list.append(rel_roi_points[inds])
        pos_assigned_gt_inds_list = [
            res.pos_assigned_gt_inds for res in sampling_results
        ]
        cfg_list = [cfg for _ in range(num_imgs)]

        point_targets = map(self._get_target_single, rois_list,
                            rel_roi_points_list, pos_assigned_gt_inds_list,
                            gt_masks, cfg_list)
        point_targets = list(point_targets)

        if len(point_targets) > 0:
            point_targets = torch.cat(point_targets)

        return point_targets

    def _get_target_single(self, rois, rel_roi_points, pos_assigned_gt_inds,
                           gt_masks, cfg):
        """Get training target of MaskPointHead for each image."""
        num_pos = rois.size(0)
        num_points = cfg.num_points
        if num_pos > 0:
            gt_masks_th = (
                gt_masks.to_tensor(rois.dtype, rois.device).index_select(
                    0, pos_assigned_gt_inds))
            gt_masks_th = gt_masks_th.unsqueeze(1)
            rel_img_points = rel_roi_point_to_rel_img_point(
                rois, rel_roi_points, gt_masks_th)
            point_targets = point_sample(gt_masks_th,
                                         rel_img_points).squeeze(1)
        else:
            point_targets = rois.new_zeros((0, num_points))
        return point_targets

    def loss(self, point_pred, point_targets, labels):
        """Calculate loss for MaskPointHead.

        Args:
            point_pred (Tensor): Point predication result, shape
                (num_rois, num_classes, num_points).
            point_targets (Tensor): Point targets, shape (num_roi, num_points).
            labels (Tensor): Class label of corresponding boxes,
                shape (num_rois, )

        Returns:
            dict[str, Tensor]: a dictionary of point loss components
        """

        loss = dict()
        if self.class_agnostic:
            loss_point = self.loss_point(point_pred, point_targets,
                                         torch.zeros_like(labels))
        else:
            loss_point = self.loss_point(point_pred, point_targets, labels)
        loss['loss_point'] = loss_point
        return loss

    def get_roi_rel_points_train(self, mask_pred, labels, cfg):
        """Get ``num_points`` most uncertain points with random points during
        train.

        Sample points in [0, 1] x [0, 1] coordinate space based on their
        uncertainty. The uncertainties are calculated for each point using
        '_get_uncertainty()' function that takes point's logit prediction as
        input.

        Args:
            mask_pred (Tensor): A tensor of shape (num_rois, num_classes,
                mask_height, mask_width) for class-specific or class-agnostic
                prediction.
            labels (list): The ground truth class for each instance.
            cfg (dict): Training config of point head.

        Returns:
            point_coords (Tensor): A tensor of shape (num_rois, num_points, 2)
                that contains the coordinates sampled points.
        """
        point_coords = get_uncertain_point_coords_with_randomness(
            mask_pred, labels, cfg.num_points, cfg.oversample_ratio,
            cfg.importance_sample_ratio)
        return point_coords

    def get_roi_rel_points_test(self, mask_pred, pred_label, cfg):
        """Get ``num_points`` most uncertain points during test.

        Args:
            mask_pred (Tensor): A tensor of shape (num_rois, num_classes,
                mask_height, mask_width) for class-specific or class-agnostic
                prediction.
            pred_label (list): The predication class for each instance.
            cfg (dict): Testing config of point head.

        Returns:
            point_indices (Tensor): A tensor of shape (num_rois, num_points)
                that contains indices from [0, mask_height x mask_width) of the
                most uncertain points.
            point_coords (Tensor): A tensor of shape (num_rois, num_points, 2)
                that contains [0, 1] x [0, 1] normalized coordinates of the
                most uncertain points from the [mask_height, mask_width] grid .
        """
        num_points = cfg.subdivision_num_points
        uncertainty_map = get_uncertainty(mask_pred, pred_label)
        num_rois, _, mask_height, mask_width = uncertainty_map.shape

        # During ONNX exporting, the type of each elements of 'shape' is
        # `Tensor(float)`, while it is `float` during PyTorch inference.
        if isinstance(mask_height, torch.Tensor):
            h_step = 1.0 / mask_height.float()
            w_step = 1.0 / mask_width.float()
        else:
            h_step = 1.0 / mask_height
            w_step = 1.0 / mask_width
        # cast to int to avoid dynamic K for TopK op in ONNX
        mask_size = int(mask_height * mask_width)
        uncertainty_map = uncertainty_map.view(num_rois, mask_size)
        num_points = min(mask_size, num_points)
        point_indices = uncertainty_map.topk(num_points, dim=1)[1]
        xs = w_step / 2.0 + (point_indices % mask_width).float() * w_step
        ys = h_step / 2.0 + (point_indices // mask_width).float() * h_step
        point_coords = torch.stack([xs, ys], dim=2)
        return point_indices, point_coords


import subprocess
import os
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from pathlib import Path
from tqdm import tqdm
from pprint import pprint

from DataQuality import Evaluator

def get_wav_len(fname):
    result = subprocess.run(
        [
            "ffprobe", "-v", "error", "-show_entries",
            "format=duration", "-of",
            "default=noprint_wrappers=1:nokey=1", fname
        ],
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT
    )
    return float(result.stdout)

def get_dir_total(dir_path):
    dir_path = Path(dir_path)
    files = os.listdir(dir_path)
    total = 0
    for f in tqdm(files):
        total += get_wav_len(dir_path.joinpath(f))
    return total

def get_csv_total_by_lang(csv_path):
    df = pd.read_csv(csv_path)
    langs = df["lang"].unique()
    result = {}
    for l in langs:
        l_df = df[df["lang"] == l]
        total = 0
        for _, row in l_df.iterrows():
            total += row['end'] - row['start']
        result[l] = total
    return result

def get_length_distr(fname):
    df = pd.read_csv(fname)
    df_begin = df["start"].to_list()
    df_end = df["end"].to_list()
    lengths = [ end - beg for beg, end in zip(df_begin, df_end) ]
    plt.hist(lengths)
    plt.ylim((-1, 30000))
    plt.show()

def get_expected_n_variance(csv, col_name, lang_filter=None, lang_col='lang'):
    df = pd.read_csv(csv)
    if lang_filter:
        df = df[df[lang_col] == lang_filter]
    data = df[col_name].to_numpy()

    return data.mean(), data.std(), len(data)

def get_sigma_ratio(csv, col_name, sigma_count = 1):
    avg, sigma, _ = get_expected_n_variance(csv, col_name)
    df = pd.read_csv(csv)
    data = df[col_name].to_numpy()
    left = avg - sigma * sigma_count
    right = avg + sigma * sigma_count
    in_count = sum([ 1 if left < x < right else 0 for x in data])
    return in_count / len(data), (left, right)

def replace_empty(csv, col_name, replacement):
    df = pd.read_csv(csv)
    df.to_csv(csv.replace('.csv', '_old.csv'))
    df[col_name] = df[col_name].replace(np.nan, replacement)
    df.to_csv(csv)

def combined_mos_phoned_scatter(csv_file, lang_col="lang", mos_col="mos_pred", eval_col="phonetic_ev", img_dir="", title=None):
    color_wheel = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']
    data_by_lang = Evaluator.load_by_lang(
        csv_file=csv_file,
        lang_col=lang_col,
        mos_col=mos_col,
        eval_col=eval_col
    )
    del data_by_lang['all_langs']
    stat_by_lang = Evaluator.statistic_by_lang(
        csv_file=csv_file,
        lang_col=lang_col,
        mos_col=mos_col,
        eval_col=eval_col
    )
    fig, axes = plt.subplots(2, 2, dpi=200, figsize=(10, 8))
    axes[0, 0].set_title('total')
    axes[0, 0].set_xlim((0., 1.05))
    axes[0, 0].set_ylim((0., 5.))
    for i, lang in enumerate(data_by_lang.keys()):
        axes[0, 0].scatter(data_by_lang[lang]["eval"], data_by_lang[lang]["mos"], s=1, c=color_wheel[i])
    text = 'n: {}\ncorrelation: {}\np-value: {:e}'.format(
        round(stat_by_lang['all_langs'][2], 3),
        round(stat_by_lang['all_langs'][0], 3),
        stat_by_lang['all_langs'][1]
    )
    axes[0, 0].text(0.05, 0.3, text, bbox={"facecolor":"orange", "alpha":0.2, "pad":5})

    del stat_by_lang['all_langs']

    for i, lang in enumerate(data_by_lang.keys()):
        print(((i + 1) // 2, (i + 1) % 2))
        axes[(i + 1) // 2, (i + 1) % 2].scatter(data_by_lang[lang]["eval"], data_by_lang[lang]["mos"], s=1, c=color_wheel[i])
        axes[(i + 1) // 2, (i + 1) % 2].set_title(lang)
        text = 'n: {}\ncorrelation: {}\np-value: {:e}'.format(
            round(stat_by_lang[lang][2], 3),
            round(stat_by_lang[lang][0], 3),
            stat_by_lang[lang][1]
        )
        axes[(i + 1) // 2, (i + 1) % 2].text(0.05, 0.3, text, bbox={"facecolor":"orange", "alpha":0.2, "pad":5})
        axes[(i + 1) // 2, (i + 1) % 2].set_xlim((0., 1.05))
        axes[(i + 1) // 2, (i + 1) % 2].set_ylim((0., 5.))
    plt.tight_layout()
    fig.suptitle(title, fontweight='bold', fontsize=13)
    fig.supxlabel('Phonetic Edit Distance')
    fig.supylabel('Predicted MOS')
    plt.subplots_adjust(bottom=0.07, top=0.93, left=0.06)
    plt.savefig(f"{img_dir}/combined.png")

dirs = [
    'refs/asr/audio_to_release/ckt',
    'refs/asr/audio_to_release/evn',
    'refs/asr/audio_to_release/mhr',
    'refs/asr/audio_to_release/sah',
    'refs/asr/audio_to_release/yrk'
]

pprint(get_sigma_ratio(
    'models/wav2vec2-base-960h/out.csv',
    'mos_pred',
    sigma_count=2
))

""" pprint(get_expected_n_variance(
    'models/wav2vec2-base-960h/out.csv',
    'mos_pred'
)) """

""" combined_mos_phoned_scatter(
    'models/wav2vec2-base/out.csv',
    img_dir='models/wav2vec2-base/img',
    title='wav2vec2-base'
) """


import requests, json
from termcolor import colored
from unidecode import unidecode

def getHeadlines():
    source="google-news-in"
    newsSource =source
    url = "https://newsapi.org/v2/top-headlines?apiKey=2ff80ad49a294ffc88827b9f0b47cb6c&sources=" + newsSource
    response = requests.get(url)
    data = response.json()
    if data["status"] != "error":
        articles = data["articles"]
        for article in articles:
            #print(colored(unidecode(article["title"]),'green'))
            if article["description"] is not None:
                headline=unidecode(article["description"])
                #print(headline)
                return headline
                #print(colored(article["url"],'yellow'))
                #print(" ")
    else:
        print("No news today")
        return "No news today"

if __name__ == '__main__':
    getHeadlines()


# coding:utf-8
import sys

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout

from qmaterialwidgets import FilledTextEdit, FilledPushButton, TextEdit, setTheme, Theme, palette

class Demo(QWidget):

    def __init__(self):
        super().__init__()
        # setTheme(Theme.DARK)
        self.setStyleSheet('Demo{background:'+palette.surface.name()+'}')

        self.hBoxLayout = QHBoxLayout(self)
        self.filledTextEdit = FilledTextEdit(self)
        self.textEdit = TextEdit(self)

        self.filledTextEdit.setLabel('Label')
        self.textEdit.setLabel('JoJo7')
        self.textEdit.setMarkdown("* Lesson 1: 别对我抱有什么奇怪的期待 \n* Lesson 2: 不要让肌肉察觉 \n* Lesson 3: 相信回旋吧，只管相信就是了！\n* Lesson 4: 表达敬意吧，表达出敬意，然后迈向回旋的另一个全新阶段 \n* Lesson 5: 最短的捷径就是绕原路，绕远路才是我的最短捷径")

        self.hBoxLayout.setContentsMargins(30, 30, 30, 30)
        self.hBoxLayout.setSpacing(50)
        self.hBoxLayout.addWidget(self.filledTextEdit)
        self.hBoxLayout.addWidget(self.textEdit)
        self.resize(800, 400)

if __name__ == '__main__':
    QApplication.setHighDpiScaleFactorRoundingPolicy(
        Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

    app = QApplication(sys.argv)
    w = Demo()
    w.show()
    app.exec()


import os
import multiprocessing
from ctypes import c_int
from parallelize import parallelize, per_item

def test_runs_loop_body_in_process_per_cpu_by_default():
    cpus = multiprocessing.cpu_count()
    pids = multiprocessing.Array(c_int, 100)
    sequence = range(100)

    for i in parallelize(sequence):
        pids[i] = os.getpid()

    assert len(set(pids)) == cpus

def test_can_run_loop_body_in_process_per_item():
    pids = multiprocessing.Array(c_int, 10)
    sequence = range(10)

    for i in parallelize(sequence, fork=per_item):
        pids[i] = os.getpid()

    assert len(set(pids)) == len(sequence)


'Save a subset of lines from an input file; start at offset and count n lines'
'default 100 lines starting from 0'

import sys
import argparse

parser = argparse.ArgumentParser( description = "Save a subset of lines from the input file to the output file" )
parser.add_argument( "input_file", help = "path to input file" )
parser.add_argument( "output_file", help = "path to output file" )
parser.add_argument( "-o", "--offset", help = "line number to start from, default 0", type = int, default = 0 )
parser.add_argument( "-l", "--lines", help = "number of lines to write, default 100", type = int, default = 100 )

args = parser.parse_args()

try:
	lines = int( sys.argv[4] )
except IndexError:
	lines = 100

i = open( args.input_file )
o = open( args.output_file, 'wb' )

offset = args.offset
count = 0

for line in i:

	if offset > 0:
		offset -= 1
		continue

	o.write( line )
	count += 1

	if count >= args.lines:
		break


""" This file is used to setup the logging configuration as a dictionary.
    This dictionary object passed in to the logger utility class to decide the format,
    handlers (console, file, etc.) and log levels.
"""
import time
import logging

class UTCFormatter(logging.Formatter):
    converter = time.gmtime

logging_config = {
    'version': 1,
    'formatters': {
        'utc': {
            '()': UTCFormatter,
            'format': '%(asctime)s %(module)s.%(funcName)s:%(lineno)d [%(levelname)s]- %(message)s'
        }
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'utc',
            'stream': 'ext://sys.stdout'
        }
    },
    'loggers': {
        'basic': {
            'level': 'DEBUG',
            'handlers': ['console']
        }
    },
    'root': {
        'level': 'DEBUG',
        'handlers': ['console']
    }
}


import imageio
import numpy as np
import math
import time
import cv2

def evaluate_model(labpoint,prepoint):
    MinDistance_Shreshold=6
    batch_size=labpoint.shape[0]
    TP = np.zeros([batch_size], np.int32)
    FP = np.zeros([batch_size], np.int32)
    FN = np.zeros([batch_size], np.int32)

    for i in range(batch_size):
        pre_len = len(np.nonzero(prepoint[i, :, 2])[0])
        # pre_len = prepoint.shape[1]
        for j in range(len(labpoint[i])):
            x1=labpoint[i][j][0]
            y1=labpoint[i][j][1]
            min_dist=MinDistance_Shreshold+0.00001
            for j in range(pre_len):
                x2=prepoint[i][j][0]
                y2=prepoint[i][j][1]
                square=(x1-x2)**2+(y1-y2)**2
                distance=math.sqrt(square)
                if distance<min_dist:
                    min_dist=distance
            if min_dist<=MinDistance_Shreshold:
                TP[i]+=1
            else:
                FN[i]+=1
        FP[i]=max(pre_len-TP[i],0)
    return np.sum(TP),np.sum(FP),np.sum(FN)

def get_PR(TP,FP,FN):
    try :
        precious = TP / (TP + FP)
        recall = TP / (TP + FN)
        F1_Measure = 2 * precious * recall / (precious + recall)
    except ZeroDivisionError:
        print("ZeroDivisionError")
        precious, recall, F1_Measure=0,0,0
    return precious,recall,F1_Measure

def validation_model(sess,valid_records,validation_dataset_reader,net_output,output,image,write_path):
    print("validation ..........")
    TP,FP,FN,totle_time= 0, 0 ,0,0
    for itr in range(len(valid_records)):
        valid_images, valid_annotations, valid_points = validation_dataset_reader.next_batch(1)
        time_start = time.time()
        net_output_, output_ = sess.run([net_output, output], feed_dict={image: valid_images})
        time_end = time.time()
        use_time = time_end - time_start
        if itr != 0:
            totle_time += use_time
        TP_, FP_, FN_=evaluate_model(valid_points, output_)
        output_=np.squeeze(output_,0)
        TP+=TP_ ; FP+=FP_ ; FN+=FN_
        print('TP_ %d    FP_ %d  FN_  %d' % (TP_ , FP_, FN_))
        precious, recall, F1_Measure = get_PR(TP, FP, FN)
        print('use time %.4f Precious: %.2f     Recall: %.2f    F1_Measure: %.2f' % (use_time,precious * 100, recall * 100, F1_Measure * 100))

        # """
        # debug
        image_co = valid_images[0].astype(np.uint8)
        for j in range(len(valid_points[0])):
            pointx1 = valid_points[0][j][0]
            pointy1 = valid_points[0][j][1]
            cv2.circle(image_co, (pointx1, pointy1), 5, (255, 0, 0), 2)
        for j in range(output_.shape[0]):
            pointx1 = output_[j][0].astype(np.uint)
            pointy1 = output_[j][1].astype(np.uint)
            cv2.circle(image_co, (pointx1, pointy1), 3, (0, 255, 0), -1)
        imageio.imwrite(write_path + str(itr) + "_co.png", image_co)
        # imageio.imwrite(write_path + str(itr) + '_org' + ".jpg", (valid_images[0]).astype(np.uint8))
        imageio.imwrite(write_path + str(itr) + '_out' + ".png", (255 * net_output_[0]).astype(np.uint8))
        imageio.imwrite(write_path + str(itr) + '_gt'  + ".png",(255 * valid_annotations[0]).astype(np.uint8))
        # """
    avguse_time = totle_time / (len(valid_records))
    precious, recall, F1_Measure = get_PR(TP, FP, FN)
    print('average use time: %.4f Precious: %.2f     Recall: %.2f    F1_Measure: %.2f' % (avguse_time,precious * 100, recall * 100, F1_Measure * 100))
    print("saving model - Step: %d," % (itr))


"""
# 22846 인증된 쉬운 게임    21.12.01 success

둘은 자신의 차례에 모니터에 쓰여있는 수의 약수를 하나 선택해 모니터에 있는 값에 더한다. 이때 제한 K를 초과한 사람이 패배하게 된다.
캐릭터 팀에서 만들어진 캐릭터는 게임을 할 때 최선의 전략으로 플레이를 하게 된다. K가 주어졌을 때 누가 이기게 되는지 구해보자!

# 입력
입력의 첫 줄에 자연수 K가 주어진다.
# 출력
칼리가 이기게 된다면 Kali를 링고가 이기게 된다면 Ringo를 출력한다.

# 예제
|input|output|
|--|--|
|2|Kali|
|3|Ringo|
"""

from typing import List, Any, Dict, Tuple

def get_divigers(target: int, max_num: int) -> List[int]:
    divigers: List[int] = []
    i = 1
    while i <= max_num and i * i <= target:
        if target % i == 0:
            divigers.append(i)
            if (target/i <= max_num) and (not i * i == target):
                divigers.append(int(target/i))
        i = i+1
    divigers.sort()
    divigers.reverse()
    return divigers

class SimpleGame:
    players: List[str] = ["Kali", "Ringo"]

    def __init__(self, num: int):
        self.__target: int = num
        # Dict : {leftValue : useNum}, useNum 0 means NotWinnable
        self.__dp_cache: Dict[int, int] = {}

    def predict_winner(self) -> Any:
        v = self.__predict_dp(1)
        return self.players[v == 0]

    def __predict_dp(self, cur_num) -> int:
        if cur_num in self.__dp_cache:
            return self.__dp_cache[cur_num]

        diff = self.__target - cur_num
        if self.__is_base_condition(diff):
            self.__dp_cache[cur_num] = diff
            return diff

        divigers = get_divigers(cur_num, diff)
        result = self.__is_winnable(cur_num, divigers)
        self.__dp_cache[cur_num] = result
        return result

    def __is_base_condition(self, value):
        return value == 1 or value == 0

    def __is_winnable(self, base_number, divigers: List[int]):
        result = 0
        for diviger in divigers:
            ret = self.__predict_dp(base_number + diviger)
            if ret == 0:
                result = diviger
                break
        return result

def solve():
    game = SimpleGame(int(input()))
    ret = game.predict_winner()
    print(ret)

if __name__ == "__main__":
    solve()


from argparse import ArgumentParser, ArgumentError
from unittest.mock import patch

import pytest

from brain_brew.commands.argument_reader import BBArgumentReader, Commands

@pytest.fixture()
def arg_reader_test1():
    return BBArgumentReader(test_mode=True)

def test_constructor(arg_reader_test1):
    assert isinstance(arg_reader_test1, BBArgumentReader)
    assert isinstance(arg_reader_test1, ArgumentParser)

class TestArguments:
    class CommandRun:
        @pytest.mark.parametrize("arguments", [
            ([Commands.RUN_RECIPE.value]),
            ([Commands.RUN_RECIPE.value, ""]),
        ])
        def test_broken_arguments(self, arg_reader_test1, arguments):
            def raise_exit(message):
                raise SystemExit

            with pytest.raises(SystemExit):
                with patch.object(BBArgumentReader, "error", side_effect=raise_exit):
                    arg_reader_test1.get_parsed(arguments)

        @pytest.mark.parametrize("arguments, recipe, verify_only", [
            ([Commands.RUN_RECIPE.value, "test_recipe.yaml"], "test_recipe.yaml", False),
            ([Commands.RUN_RECIPE.value, "test_recipe.yaml", "--verify"], "test_recipe.yaml", True),
            ([Commands.RUN_RECIPE.value, "test_recipe.yaml", "-v"], "test_recipe.yaml", True),
        ])
        def test_correct_arguments(self, arg_reader_test1, arguments, recipe, verify_only):
            parsed_args = arg_reader_test1.parse_args(arguments)

            assert parsed_args.recipe == recipe
            assert parsed_args.verify_only == verify_only

    class CommandInit:
        @pytest.mark.parametrize("arguments, location", [
            (["init", "crowdankifolder72"], "crowdankifolder72"),
        ])
        def test_correct_arguments(self, arg_reader_test1, arguments, location):
            parsed_args = arg_reader_test1.parse_args(arguments)

            assert parsed_args.crowdanki_folder == location


import numpy as np
import cv2 as cv
import glob
import os
from os.path import join as opj
import argparse
import shutil
import sys

def get_args():
    parser = argparse.ArgumentParser(description='check the properties of stereo video.')
    parser.add_argument('--dir', dest='dir', type=str, required=True)
    parser.add_argument('--save', dest='save', type=str, required=True)
    parser.add_argument('--resize', dest='resize', nargs='+', type=int, help='resize_w resize_h', required=True)
    args = parser.parse_args()
    return args

if __name__ == '__main__':
    args = get_args()
    src_dir = args.dir
    sv_dir = args.save

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

    included_extensions = ['jpg', 'jpeg', 'png']
    file_names = [fn for fn in os.listdir(src_dir)
        if any(fn.endswith(ext) for ext in included_extensions)]
    file_names.sort()

    for fn in file_names:
        source = opj(src_dir, fn)
        target = opj(sv_dir, fn)

        img = cv.imread(source)
        rs_img = cv.resize(img, (args.resize[0], args.resize[1]))
        cv.imwrite(target, rs_img)


from PIL import Image
# function for joining images horizontally
def concat_images_horizontally(image_1,image_2):
    new_im = Image.new("RGB",(image_1.width + image_2.width,max(image_1.height,image_2.height)))
    new_im.paste(image_1,(0,0))
    new_im.paste(image_2,(image_1.width,0))
    return new_im

# function for joining images vertically
def concat_images_vertically(image_1,image_2):
    new_im = Image.new("RGB",(max(image_1.width,image_2.width),image_1.height+image_2.height))
    new_im.paste(image_1,(0,0))
    new_im.paste(image_2,(0,image_1.height))
    return new_im


import json

class phrase_table(object):

    def __init__(self, file="data/alignment_table_all_final.json"):
        with open(file) as infile:
            self.trans_dict = json.load(infile)

    # if there's no alignment of the word -> find out Chinese tokens that appear in the phrase table
    def find_no_align_trans(self, ch_sent, en_word, en_pat_token, verb_index, nlp):
        if en_word not in self.trans_dict:
            return []
        candidates = []
        en_word = nlp(en_word.lower())[0].lemma_ if nlp(en_word.lower())[0].lemma_ != '-PRON-' else en_word.lower()
        for j, w in enumerate(ch_sent.split()):
            if w in self.trans_dict[en_word].keys():
                candidates += [(j, en_pat_token, abs(verb_index-j))]
        candidates = sorted(candidates, key=lambda k: k[2]) # sort by distance between 'V' and the word
    #     print(en_word, [ch_sent.split()[z] for z,x,c in candidates], ch_sent)
        return [ (candidates[0][0], candidates[0][1]) ] if candidates else [] # [(ch_index, en_pat_token)]

    # filter out aligned Chinese token that are not in the phrase table
    def filter_ch_alignment(self, en_word, ch_sent, ch_indices, en_pat_token, verb_index, nlp):
        remain = []
        en_word = nlp(en_word.lower())[0].lemma_ if nlp(en_word.lower())[0].lemma_ != '-PRON-' else en_word.lower()
        for index in ch_indices:
            try:
                ch_word = ch_sent.split()[index]
            except:
                continue
    #             print(ch_sent, index)
            if en_word not in self.trans_dict: # not in phrase table -> assume the alignment is correct
                remain += [(index, en_pat_token)]
            elif ch_word in self.trans_dict[en_word].keys():
                remain += [(index, en_pat_token)]

        # if the en_word has no aligned Chinese tokens
        if not remain:
            return self.find_no_align_trans(ch_sent, en_word, en_pat_token, verb_index, nlp)
        return remain

PHRASE_TABLE = phrase_table()


from flask import Flask, redirect, url_for, render_template, request, jsonify, session, flash
import requests
import string

app = Flask(__name__)
app.debug = True
app.secret_key = "sup"

def search(ig_name):
	url = "https://www.instagram.com/{}/?__a=1".format(ig_name)
	r = requests.get(url)
	stcode = r.status_code
	if stcode == 200:
		res = r.json()
		followers = ("Followers: {}".format(res['graphql']['user']['edge_followed_by']['count']))
		following = ("Following: {}".format(res['graphql']['user']['edge_follow']['count']))
		posts = ("Posts: {}".format(len(res["graphql"]['user']["edge_owner_to_timeline_media"]['edges'])))
		#photos and likes of every photo
		likes = sum([res["graphql"]['user']["edge_owner_to_timeline_media"]['edges'][i]["node"]["edge_liked_by"]['count'] for i in range(len(res["graphql"]['user']["edge_owner_to_timeline_media"]['edges']))])
    	# total_likes = "Total Likes: {}".format(likes)
		return followers, following, posts, likes
	else:
		print("Shit is Broken")

@app.route("/", methods=["POST", "GET"] )
def home():
	if request.method == "POST":
		name = request.form["nm"]
		return redirect(url_for("response", name=name))
	else:
		return render_template("index.html", title="Instgram Analyzer")

@app.route("/response/<name>", methods=["POST", "GET"])
def response(name):
	data = search(name)
	if data[3] == 0:
		flash("Enable to calculate number of likes due to the account being private.")
	return render_template("response.html", title="Response", name=name, posts=data[2], likes=data[3], following=data[1], followers=data[0])

if __name__ == "__main__":
	app.run()


#!/usr/bin/env python3

"""
Parses the output of a Rust `criterion` benchmark run and outputs a TSV with the throughput* values.
Assumes input of the form:
```
Day13_A/input_handling_baseline/right_longer
                        time:   [154.47 ns 154.77 ns 155.09 ns]
                        thrpt:  [2.9544 GiB/s 2.9606 GiB/s 2.9664 GiB/s]
```
which can be achieved by invoking the criterion bench as below:
```
cargo bench --bench day13_impls -- --format terse --quiet > data.txt
```

* The time values can also be output by slightly modifying the script.
"""

from typing import TypeAlias

UnitIndex: TypeAlias = int
Value: TypeAlias = tuple[float, UnitIndex]
Field: TypeAlias = tuple[Value, Value, Value]
TimeField: TypeAlias = Field
ThrptField: TypeAlias = Field

ImplName: TypeAlias = str
InputName: TypeAlias = str

def body(f):
    # an absurdly slow algorithm. But the input is fairly small
    """"""

    time_units = ["ps", "ns", "µs", "ms", "s"]
    thrpt_units = ["B/s", "KiB/s", "MiB/s", "GiB/s", "TiB/s"]

    def do_field(name, input, expected_prefix, unit_list) -> Field:
        prefix, _, val_list = input.partition("[")
        if prefix.strip() != expected_prefix:
            raise ValueError(f"expected prefix '{expected_prefix}', got '{prefix}'")

        if val_list[-1] != "]":
            raise ValueError(f"expected closing bracket at end of {input} for {name}")

        vals = val_list[0:-1].split(" ", maxsplit=6 + 1)
        low = (float(vals[0]), unit_list.index(vals[1]))
        mid = (float(vals[2]), unit_list.index(vals[3]))
        upp = (float(vals[4]), unit_list.index(vals[5]))

        return (low, mid, upp)

    benches: list[tuple[ImplName, InputName, TimeField, ThrptField]] = []

    input_encounter_order: list[InputName] = []
    impl_encounter_order: list[ImplName] = []

    # read all the lines in the input, parse into tuples
    # along the way, record the encounter order
    while True:
        header, time, throughput = (
            f.readline().strip(),
            f.readline().strip(),
            f.readline().strip(),
        )
        if (not header) or (not time) or (not throughput):
            break

        header_chunks: list = header.split("/", maxsplit=3 + 1)
        if len(header_chunks) != 3:
            raise ValueError(
                f"got '{header_chunks}', expected 3 fields separated by '/'"
            )

        benchmark_name, impl_name, input_name = header_chunks
        if impl_name not in impl_encounter_order:
            impl_encounter_order.append(impl_name)
        if input_name not in input_encounter_order:
            input_encounter_order.append(input_name)

        fields = (
            ("time", time, "time:", time_units),
            ("throughput", throughput, "thrpt:", thrpt_units),
        )
        time, throughput = (do_field(*field) for field in fields)
        benches.append((impl_name, input_name, time, throughput))

    scaling_list = [1024**i for i in range(len(time_units))]
    trials: dict[InputName, dict[ImplName, tuple[TimeField, ThrptField]]] = {
        name: {} for name in input_encounter_order
    }
    for impl_name, input_name, time_field, thrpt_field in benches:
        trials[input_name][impl_name] = (time_field, thrpt_field)

    min_time_unit_for_input: dict[InputName, UnitIndex] = {
        input_name: min(p[0][0][1] for p in trials[input_name].values())
        for input_name in trials
    }
    min_thrpt_unit_for_input: dict[InputName, UnitIndex] = {
        input_name: min(p[1][0][1] for p in trials[input_name].values())
        for input_name in trials
    }

    # output data file
    # https://stackoverflow.com/questions/41942693/clustered-bar-plot-in-gnuplot-with-errorbars?noredirect=1&lq=1
    def stringify(field: Field, lowest_unit: UnitIndex) -> str:
        (low, med, hi) = field
        return "\t".join(
            str(f * scaling_list[unit_index - lowest_unit])
            for (f, unit_index) in (low, med, hi)
        )

    print("Title", *(f"low\t{impl}\thigh" for impl in impl_encounter_order), sep="\t")
    for input_name in input_encounter_order:
        a: dict[ImplName, tuple[TimeField, ThrptField]] = trials[input_name]
        unit_for_input = thrpt_units[min_thrpt_unit_for_input[input_name]]
        print(
            f"{input_name} ({unit_for_input})",
            *[
                stringify(a[impl][1], min_thrpt_unit_for_input[input_name])
                for impl in impl_encounter_order
            ],
            sep="\t",
            flush=False,
        )

if __name__ == "__main__":
    import sys

    body(sys.stdin)


from collections import deque

all_materials = [int(n) for n in input().split()]
magic_lv_value = deque([int(n) for n in input().split()])
items = {'Gemstone': 0, 'Porcelain Sculpture': 0, 'Gold': 0, 'Diamond Jewellery': 0}
items_names = ['Gemstone', 'Porcelain Sculpture', 'Gold', 'Diamond Jewellery']
succeeded = False

while all_materials and magic_lv_value:
    material = all_materials.pop()
    value = magic_lv_value.popleft()
    magic = material + value
    if magic < 100:
        if magic % 2 == 0:
            magic = material*2 + value*3
        elif magic % 2 == 1:
            magic *= 2
    elif magic > 499:
        magic /= 2

    if 0 < (magic // 100) < 5:
        items[items_names[int((magic // 100)-1)]] += 1

    if items['Gemstone'] and items['Porcelain Sculpture']:
        succeeded = True
    elif items['Gold'] and items['Diamond Jewellery']:
        succeeded = True
if succeeded:
    print('The wedding presents are made!')
else:
    print("Aladdin does not have enough wedding presents.")
if magic_lv_value:
    print(f"Magic left: {', '.join(list(map(str, magic_lv_value)))}")
else:
    print(f"Materials left: {', '.join(list(map(str, all_materials)))}")
for key, value in sorted(items.items()):
    if value:
        print(f"{key}: {value}")


from data.components.slime import Slime

__author__ = 'marcman'

from data.stage.stage import Stage
import random

class Stage04Slimes(Stage):
    def __init__(self, description):
        Stage.__init__(self, description)
        self.targets = []
        self.targets.append(Slime(random.randint(800, 1500), random.randint(100, 500)) for _ in range(25))

    def get_targets(self):
        return self.targets


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-n','--names', nargs='+', help='<Required> Set names', required=True)
parser.add_argument('-s','--startup')

args = parser.parse_args()

with open('%s' % 'main.c', 'wb') as f:
    f.write(bytes('''// WARNING: Do not change main.c, the file is automatically generated when building
// Generated by main_generato.py

#ifndef APP_LOG
#define APP_LOG NULL
#endif

#ifndef APP_TITLE
#define APP_TITLE "Neon-engine application"
#endif

#include <neon.h>
#include <memtrack.h>
\n\n''', 'utf8'))
    if args.startup:
        f.write(bytes("extern int {0}(int argc, char *argv[]);\n".format(args.startup), 'utf8'))
    for name in args.names:
        f.write(bytes("extern int {0}_on_init(void);\n".format(name), 'utf8'))
        f.write(bytes("extern void {0}_on_update(float);\n".format(name), 'utf8'))
        f.write(bytes("extern void {0}_on_present(int, int, float);\n".format(name), 'utf8'))
        f.write(bytes("extern void {0}_on_event(const SDL_Event *event);\n".format(name), 'utf8'))
        f.write(bytes("extern void {0}_on_cleanup(void);\n\n".format(name), 'utf8'))
    f.write(bytes('APP_STATE states[] = {\n', 'utf8'))
    for name in args.names:
        f.write(bytes("    {{{0}_on_init, {0}_on_update, {0}_on_present, {0}_on_event, {0}_on_cleanup}},\n".format(name), 'utf8'))
    f.write(bytes('};\n', 'utf8'))
    f.write(bytes('''extern int main(int argc, char *argv[]) {\n''', 'utf8'))
    if args.startup:
        f.write(bytes("    {0}(argc, argv);".format(args.startup), 'utf8'))
    f.write(bytes('''    LOG_INIT(APP_LOG);
    MEMTRACK_INIT();
    return application_exec(APP_TITLE, states, countof(states));
}''', 'utf8'))


from django.shortcuts import get_object_or_404, render
from .models import Room, Contacts, Building
from rsv.models import Reservation, Purpose

# Create your views here.

def main(request):
  rooms = []
  rooms.append(get_object_or_404(Room, name="1공학관 304"))
  rooms.append(get_object_or_404(Room, name="4공학관 106"))
  rooms.append(get_object_or_404(Room, name="과학기술관 103"))
  rooms.append(get_object_or_404(Room, name="잔디축구장"))
  rooms.append(get_object_or_404(Room, name="클러스터 506"))
  rooms.append(get_object_or_404(Room, name="Lion's Hall"))

  contents = {'rooms' : rooms}

  return render(request, 'main.html', contents)

def useGuide(request):

  contacts = Contacts.objects.all()
  contents = {}

  for contact in contacts:
    category = contact.category
    if not category in contents:
      contents[category]=[]
    contents[category].append([contact.building_name, contact.phone_number])

  return render(request, 'useGuide.html', {'contents' : contents})

def mainplace(request):
  rooms = []
  rooms.append(get_object_or_404(Room, name="1공학관 304"))
  rooms.append(get_object_or_404(Room, name="4공학관 106"))
  rooms.append(get_object_or_404(Room, name="과학기술관 103"))
  rooms.append(get_object_or_404(Room, name="잔디축구장"))
  rooms.append(get_object_or_404(Room, name="클러스터 506"))
  rooms.append(get_object_or_404(Room, name="Lion's Hall"))

  contents = {'rooms' : rooms}

  return render(request, 'mainplace.html',contents)

def building(request):
  buildings = Building.objects
  return render(request, 'building.html', {'buildings':buildings})

def roomlist(request, building_id):
  roomlist = Room.objects.filter(building = building_id)

  return render(request, 'roomlist.html', {'roomlist' : roomlist})

def headcount(request, count):
  if count == 20:
    rooms = Room.objects.filter(capacity__lt = count)
    headcount = "20명 미만"
  elif count == 51:
    rooms = Room.objects.filter(capacity__gte = count)
    headcount = "50명 이상"
  else:
    rooms = Room.objects.filter(capacity__lt = count , capacity__gte = count-10)
    headcount = str(count-10) + " ~ " + str(count-1)+"명"

  return render(request, 'headcount.html', {'rooms':rooms, 'headcount':headcount})

def recommend(request, purpose_id):
  rsv = Reservation.objects.filter(purpose = purpose_id, admit = 1).values('room_id')

  rooms = {}
  for entry in rsv:
    room_id = entry['room_id']
    if not room_id in rooms:
      room = get_object_or_404(Room, pk = room_id)
      rooms[room_id] = [room,0]
    rooms[room_id][1] += 1

  sorted_rooms = sorted(rooms.items(), reverse=True, key=lambda x: x[1][1])

  purpose = get_object_or_404(Purpose, pk = purpose_id)
  return render(request, 'recommend.html', {"rooms":sorted_rooms, "purpose":purpose})


from __future__ import annotations

from typing import TYPE_CHECKING

from .. import cache, errors

__all__ = ("default_default_ticket_config", "default_current_ticket")

if TYPE_CHECKING:
    from typing import Any

    from .. import models
    from ..commands.common import CommonSlashCommand

def default_default_ticket_config(
    command: CommonSlashCommand[Any],
) -> models.TicketConfig:
    try:
        return next(
            i
            for i in cache.ticket_configs
            if i.guild_id == command.interaction.guild_id and i.default
        )
    except StopIteration as e:
        raise errors.TicketConfigNoDefaultError(command.interaction) from e

def default_current_ticket(
    command: CommonSlashCommand[Any],
) -> models.Ticket:
    try:
        return next(
            i for i in cache.tickets if i.channel_id == command.interaction.channel_id
        )
    except StopIteration as e:
        raise errors.TicketNotFoundError(
            command.interaction, command.interaction.user.id
        ) from e