from __future__ import annotations
from typing import Any, List, Literal, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Callable, Union, Dict, overload
from contextvars import ContextVar
import inspect
import os

from .item import Item, ItemCallbackType
from ..enums import ChannelType, ComponentType
from ..partial_emoji import PartialEmoji
from ..emoji import Emoji
from ..utils import MISSING
from ..components import (
    SelectOption,
    SelectMenu,
)
from ..app_commands.namespace import Namespace

__all__ = (
    'Select',
    'UserSelect',
    'RoleSelect',
    'MentionableSelect',
    'ChannelSelect',
    'select',
)

if TYPE_CHECKING:
    from typing_extensions import TypeAlias, Self

    from .view import View
    from ..types.components import SelectMenu as SelectMenuPayload
    from ..types.interactions import SelectMessageComponentInteractionData
    from ..app_commands import AppCommandChannel, AppCommandThread
    from ..member import Member
    from ..role import Role
    from ..user import User
    from ..interactions import Interaction

    ValidSelectType: TypeAlias = Literal[
        ComponentType.string_select,
        ComponentType.user_select,
        ComponentType.role_select,
        ComponentType.channel_select,
        ComponentType.mentionable_select,
    ]
    PossibleValue: TypeAlias = Union[
        str, User, Member, Role, AppCommandChannel, AppCommandThread, Union[Role, Member], Union[Role, User]
    ]

V = TypeVar('V', bound='View', covariant=True)
BaseSelectT = TypeVar('BaseSelectT', bound='BaseSelect[Any]')
SelectT = TypeVar('SelectT', bound='Select[Any]')
UserSelectT = TypeVar('UserSelectT', bound='UserSelect[Any]')
RoleSelectT = TypeVar('RoleSelectT', bound='RoleSelect[Any]')
ChannelSelectT = TypeVar('ChannelSelectT', bound='ChannelSelect[Any]')
MentionableSelectT = TypeVar('MentionableSelectT', bound='MentionableSelect[Any]')
SelectCallbackDecorator: TypeAlias = Callable[[ItemCallbackType[V, BaseSelectT]], BaseSelectT]

selected_values: ContextVar[Dict[str, List[PossibleValue]]] = ContextVar('selected_values')

class BaseSelect(Item[V]):
    """The base Select model that all other Select models inherit from.

    This class inherits from :class:`Item` and implements the common attributes.

    The following implement this class:

    - :class:`~discord.ui.Select`
    - :class:`~discord.ui.ChannelSelect`
    - :class:`~discord.ui.RoleSelect`
    - :class:`~discord.ui.MentionableSelect`
    - :class:`~discord.ui.UserSelect`

    .. versionadded:: 2.1

    Attributes
    ------------
    row: Optional[:class:`int`]
        The relative row this select menu belongs to. A Discord component can only have 5
        rows. By default, items are arranged automatically into those 5 rows. If you'd
        like to control the relative positioning of the row then passing an index is advised.
        For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
        ordering. The row number must be between 0 and 4 (i.e. zero indexed).
    """

    __slots__ = ('_provided_custom_id', '_underlying', 'row', '_values')

    __item_repr_attributes__: Tuple[str, ...] = (
        'placeholder',
        'min_values',
        'max_values',
        'disabled',
    )

    def __init__(
        self,
        type: ValidSelectType,
        *,
        custom_id: str = MISSING,
        row: Optional[int] = None,
        placeholder: Optional[str] = None,
        min_values: Optional[int] = None,
        max_values: Optional[int] = None,
        disabled: bool = False,
        options: List[SelectOption] = MISSING,
        channel_types: List[ChannelType] = MISSING,
    ) -> None:
        super().__init__()
        self._provided_custom_id = custom_id is not MISSING
        custom_id = os.urandom(16).hex() if custom_id is MISSING else custom_id
        if not isinstance(custom_id, str):
            raise TypeError(f'expected custom_id to be str not {custom_id.__class__.__name__}')

        self._underlying = SelectMenu._raw_construct(
            type=type,
            custom_id=custom_id,
            placeholder=placeholder,
            min_values=min_values,
            max_values=max_values,
            disabled=disabled,
            channel_types=[] if channel_types is MISSING else channel_types,
            options=[] if options is MISSING else options,
        )

        self.row = row
        self._values: List[PossibleValue] = []

    @property
    def values(self) -> List[PossibleValue]:
        values = selected_values.get({})
        return values.get(self.custom_id, self._values)

    @property
    def custom_id(self) -> str:
        """:class:`str`: The ID of the select menu that gets received during an interaction."""
        return self._underlying.custom_id

    @custom_id.setter
    def custom_id(self, value: str) -> None:
        if not isinstance(value, str):
            raise TypeError('custom_id must be a str')

        self._underlying.custom_id = value
        self._provided_custom_id = True

    @property
    def placeholder(self) -> Optional[str]:
        """Optional[:class:`str`]: The placeholder text that is shown if nothing is selected, if any."""
        return self._underlying.placeholder

    @placeholder.setter
    def placeholder(self, value: Optional[str]) -> None:
        if value is not None and not isinstance(value, str):
            raise TypeError('placeholder must be None or str')

        self._underlying.placeholder = value

    @property
    def min_values(self) -> int:
        """:class:`int`: The minimum number of items that must be chosen for this select menu."""
        return self._underlying.min_values

    @min_values.setter
    def min_values(self, value: int) -> None:
        self._underlying.min_values = int(value)

    @property
    def max_values(self) -> int:
        """:class:`int`: The maximum number of items that can be chosen for this select menu."""
        return self._underlying.max_values

    @max_values.setter
    def max_values(self, value: int) -> None:
        self._underlying.max_values = int(value)

    @property
    def disabled(self) -> bool:
        """:class:`bool`: Whether the select is disabled or not."""
        return self._underlying.disabled

    @disabled.setter
    def disabled(self, value: bool) -> None:
        self._underlying.disabled = bool(value)

    @property
    def width(self) -> int:
        return 5

    def to_component_dict(self) -> SelectMenuPayload:
        return self._underlying.to_dict()

    def _refresh_component(self, component: SelectMenu) -> None:
        self._underlying = component

    def _refresh_state(self, interaction: Interaction, data: SelectMessageComponentInteractionData) -> None:
        values = selected_values.get({})
        payload: List[PossibleValue]
        try:
            resolved = Namespace._get_resolved_items(interaction, data['resolved'])
            payload = list(resolved.values())
        except KeyError:
            payload = data.get("values", [])  # type: ignore

        self._values = values[self.custom_id] = payload
        selected_values.set(values)

    def is_dispatchable(self) -> bool:
        return True

    @classmethod
    def from_component(cls, component: SelectMenu) -> Self:
        return cls(
            **{k: getattr(component, k) for k in cls.__item_repr_attributes__},
            row=None,
        )

class Select(BaseSelect[V]):
    """Represents a UI select menu with a list of custom options. This is represented
    to the user as a dropdown menu.

    .. versionadded:: 2.0

    Parameters
    ------------
    custom_id: :class:`str`
        The ID of the select menu that gets received during an interaction.
        If not given then one is generated for you.
    placeholder: Optional[:class:`str`]
        The placeholder text that is shown if nothing is selected, if any.
    min_values: :class:`int`
        The minimum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 0 and 25.
    max_values: :class:`int`
        The maximum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 1 and 25.
    options: List[:class:`discord.SelectOption`]
        A list of options that can be selected in this menu.
    disabled: :class:`bool`
        Whether the select is disabled or not.
    row: Optional[:class:`int`]
        The relative row this select menu belongs to. A Discord component can only have 5
        rows. By default, items are arranged automatically into those 5 rows. If you'd
        like to control the relative positioning of the row then passing an index is advised.
        For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
        ordering. The row number must be between 0 and 4 (i.e. zero indexed).
    """

    __item_repr_attributes__ = BaseSelect.__item_repr_attributes__ + ('options',)

    def __init__(
        self,
        *,
        custom_id: str = MISSING,
        placeholder: Optional[str] = None,
        min_values: int = 1,
        max_values: int = 1,
        options: List[SelectOption] = MISSING,
        disabled: bool = False,
        row: Optional[int] = None,
    ) -> None:
        super().__init__(
            self.type,
            custom_id=custom_id,
            placeholder=placeholder,
            min_values=min_values,
            max_values=max_values,
            disabled=disabled,
            options=options,
            row=row,
        )

    @property
    def values(self) -> List[str]:
        """List[:class:`str`]: A list of values that have been selected by the user."""
        return super().values  # type: ignore

    @property
    def type(self) -> Literal[ComponentType.string_select]:
        """:class:`.ComponentType`: The type of this component."""
        return ComponentType.string_select

    @property
    def options(self) -> List[SelectOption]:
        """List[:class:`discord.SelectOption`]: A list of options that can be selected in this menu."""
        return self._underlying.options

    @options.setter
    def options(self, value: List[SelectOption]) -> None:
        if not isinstance(value, list):
            raise TypeError('options must be a list of SelectOption')
        if not all(isinstance(obj, SelectOption) for obj in value):
            raise TypeError('all list items must subclass SelectOption')

        self._underlying.options = value

    def add_option(
        self,
        *,
        label: str,
        value: str = MISSING,
        description: Optional[str] = None,
        emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
        default: bool = False,
    ) -> None:
        """Adds an option to the select menu.

        To append a pre-existing :class:`discord.SelectOption` use the
        :meth:`append_option` method instead.

        Parameters
        -----------
        label: :class:`str`
            The label of the option. This is displayed to users.
            Can only be up to 100 characters.
        value: :class:`str`
            The value of the option. This is not displayed to users.
            If not given, defaults to the label. Can only be up to 100 characters.
        description: Optional[:class:`str`]
            An additional description of the option, if any.
            Can only be up to 100 characters.
        emoji: Optional[Union[:class:`str`, :class:`.Emoji`, :class:`.PartialEmoji`]]
            The emoji of the option, if available. This can either be a string representing
            the custom or unicode emoji or an instance of :class:`.PartialEmoji` or :class:`.Emoji`.
        default: :class:`bool`
            Whether this option is selected by default.

        Raises
        -------
        ValueError
            The number of options exceeds 25.
        """

        option = SelectOption(
            label=label,
            value=value,
            description=description,
            emoji=emoji,
            default=default,
        )

        self.append_option(option)

    def append_option(self, option: SelectOption) -> None:
        """Appends an option to the select menu.

        Parameters
        -----------
        option: :class:`discord.SelectOption`
            The option to append to the select menu.

        Raises
        -------
        ValueError
            The number of options exceeds 25.
        """

        if len(self._underlying.options) > 25:
            raise ValueError('maximum number of options already provided')

        self._underlying.options.append(option)

class UserSelect(BaseSelect[V]):
    """Represents a UI select menu with a list of predefined options with the current members of the guild.

    If this is sent a private message, it will only allow the user to select the client
    or themselves. Every selected option in a private message will resolve to
    a :class:`discord.User`.

    .. versionadded:: 2.1

    Parameters
    ------------
    custom_id: :class:`str`
        The ID of the select menu that gets received during an interaction.
        If not given then one is generated for you.
    placeholder: Optional[:class:`str`]
        The placeholder text that is shown if nothing is selected, if any.
    min_values: :class:`int`
        The minimum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 0 and 25.
    max_values: :class:`int`
        The maximum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 1 and 25.
    disabled: :class:`bool`
        Whether the select is disabled or not.
    row: Optional[:class:`int`]
        The relative row this select menu belongs to. A Discord component can only have 5
        rows. By default, items are arranged automatically into those 5 rows. If you'd
        like to control the relative positioning of the row then passing an index is advised.
        For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
        ordering. The row number must be between 0 and 4 (i.e. zero indexed).
    """

    def __init__(
        self,
        *,
        custom_id: str = MISSING,
        placeholder: Optional[str] = None,
        min_values: int = 1,
        max_values: int = 1,
        disabled: bool = False,
        row: Optional[int] = None,
    ) -> None:
        super().__init__(
            self.type,
            custom_id=custom_id,
            placeholder=placeholder,
            min_values=min_values,
            max_values=max_values,
            disabled=disabled,
            row=row,
        )

    @property
    def type(self) -> Literal[ComponentType.user_select]:
        """:class:`.ComponentType`: The type of this component."""
        return ComponentType.user_select

    @property
    def values(self) -> List[Union[Member, User]]:
        """List[Union[:class:`discord.Member`, :class:`discord.User`]]: A list of members
        and users that have been selected by the user.

        If this is sent a private message, it will only allow
        the user to select the client or themselves. Every selected option in a private
        message will resolve to a :class:`discord.User`.

        If invoked in a guild, the values will always resolve to :class:`discord.Member`.
        """
        return super().values  # type: ignore

class RoleSelect(BaseSelect[V]):
    """Represents a UI select menu with a list of predefined options with the current roles of the guild.

    Please note that if you use this in a private message with a user, no roles will be displayed to the user.

    .. versionadded:: 2.1

    Parameters
    ------------
    custom_id: :class:`str`
        The ID of the select menu that gets received during an interaction.
        If not given then one is generated for you.
    placeholder: Optional[:class:`str`]
        The placeholder text that is shown if nothing is selected, if any.
    min_values: :class:`int`
        The minimum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 0 and 25.
    max_values: :class:`int`
        The maximum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 1 and 25.
    disabled: :class:`bool`
        Whether the select is disabled or not.
    row: Optional[:class:`int`]
        The relative row this select menu belongs to. A Discord component can only have 5
        rows. By default, items are arranged automatically into those 5 rows. If you'd
        like to control the relative positioning of the row then passing an index is advised.
        For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
        ordering. The row number must be between 0 and 4 (i.e. zero indexed).
    """

    def __init__(
        self,
        *,
        custom_id: str = MISSING,
        placeholder: Optional[str] = None,
        min_values: int = 1,
        max_values: int = 1,
        disabled: bool = False,
        row: Optional[int] = None,
    ) -> None:
        super().__init__(
            self.type,
            custom_id=custom_id,
            placeholder=placeholder,
            min_values=min_values,
            max_values=max_values,
            disabled=disabled,
            row=row,
        )

    @property
    def type(self) -> Literal[ComponentType.role_select]:
        """:class:`.ComponentType`: The type of this component."""
        return ComponentType.role_select

    @property
    def values(self) -> List[Role]:
        """List[:class:`discord.Role`]: A list of roles that have been selected by the user."""
        return super().values  # type: ignore

class MentionableSelect(BaseSelect[V]):
    """Represents a UI select menu with a list of predefined options with the current members and roles in the guild.

    If this is sent in a private message, it will only allow the user to select
    the client or themselves. Every selected option in a private message
    will resolve to a :class:`discord.User`. It will not give the user any roles
    to select.

    .. versionadded:: 2.1

    Parameters
    ------------
    custom_id: :class:`str`
        The ID of the select menu that gets received during an interaction.
        If not given then one is generated for you.
    placeholder: Optional[:class:`str`]
        The placeholder text that is shown if nothing is selected, if any.
    min_values: :class:`int`
        The minimum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 0 and 25.
    max_values: :class:`int`
        The maximum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 1 and 25.
    disabled: :class:`bool`
        Whether the select is disabled or not.
    row: Optional[:class:`int`]
        The relative row this select menu belongs to. A Discord component can only have 5
        rows. By default, items are arranged automatically into those 5 rows. If you'd
        like to control the relative positioning of the row then passing an index is advised.
        For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
        ordering. The row number must be between 0 and 4 (i.e. zero indexed).
    """

    def __init__(
        self,
        *,
        custom_id: str = MISSING,
        placeholder: Optional[str] = None,
        min_values: int = 1,
        max_values: int = 1,
        disabled: bool = False,
        row: Optional[int] = None,
    ) -> None:
        super().__init__(
            self.type,
            custom_id=custom_id,
            placeholder=placeholder,
            min_values=min_values,
            max_values=max_values,
            disabled=disabled,
            row=row,
        )

    @property
    def type(self) -> Literal[ComponentType.mentionable_select]:
        """:class:`.ComponentType`: The type of this component."""
        return ComponentType.mentionable_select

    @property
    def values(self) -> List[Union[Member, User, Role]]:
        """List[Union[:class:`discord.Role`, :class:`discord.Member`, :class:`discord.User`]]: A list of roles, members,
        and users that have been selected by the user.

        If this is sent a private message, it will only allow
        the user to select the client or themselves. Every selected option in a private
        message will resolve to a :class:`discord.User`.

        If invoked in a guild, the values will always resolve to :class:`discord.Member`.
        """
        return super().values  # type: ignore

class ChannelSelect(BaseSelect[V]):
    """Represents a UI select menu with a list of predefined options with the current channels in the guild.

    Please note that if you use this in a private message with a user, no channels will be displayed to the user.

    .. versionadded:: 2.1

    Parameters
    ------------
    custom_id: :class:`str`
        The ID of the select menu that gets received during an interaction.
        If not given then one is generated for you.
    channel_types: List[:class:`~discord.ChannelType`]
        The types of channels to show in the select menu. Defaults to all channels.
    placeholder: Optional[:class:`str`]
        The placeholder text that is shown if nothing is selected, if any.
    min_values: :class:`int`
        The minimum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 0 and 25.
    max_values: :class:`int`
        The maximum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 1 and 25.
    disabled: :class:`bool`
        Whether the select is disabled or not.
    row: Optional[:class:`int`]
        The relative row this select menu belongs to. A Discord component can only have 5
        rows. By default, items are arranged automatically into those 5 rows. If you'd
        like to control the relative positioning of the row then passing an index is advised.
        For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
        ordering. The row number must be between 0 and 4 (i.e. zero indexed).
    """

    __item_repr_attributes__ = BaseSelect.__item_repr_attributes__ + ('channel_types',)

    def __init__(
        self,
        *,
        custom_id: str = MISSING,
        channel_types: List[ChannelType] = MISSING,
        placeholder: Optional[str] = None,
        min_values: int = 1,
        max_values: int = 1,
        disabled: bool = False,
        row: Optional[int] = None,
    ) -> None:
        super().__init__(
            self.type,
            custom_id=custom_id,
            placeholder=placeholder,
            min_values=min_values,
            max_values=max_values,
            disabled=disabled,
            row=row,
            channel_types=channel_types,
        )

    @property
    def type(self) -> Literal[ComponentType.channel_select]:
        """:class:`.ComponentType`: The type of this component."""
        return ComponentType.channel_select

    @property
    def channel_types(self) -> List[ChannelType]:
        """List[:class:`~discord.ChannelType`]: A list of channel types that can be selected."""
        return self._underlying.channel_types

    @channel_types.setter
    def channel_types(self, value: List[ChannelType]) -> None:
        if not isinstance(value, list):
            raise TypeError('channel_types must be a list of ChannelType')
        if not all(isinstance(obj, ChannelType) for obj in value):
            raise TypeError('all list items must be a ChannelType')

        self._underlying.channel_types = value

    @property
    def values(self) -> List[Union[AppCommandChannel, AppCommandThread]]:
        """List[Union[:class:`~discord.app_commands.AppCommandChannel`, :class:`~discord.app_commands.AppCommandThread`]]: A list of channels selected by the user."""
        return super().values  # type: ignore

@overload
def select(
    *,
    cls: Type[SelectT] = Select[V],
    options: List[SelectOption] = MISSING,
    channel_types: List[ChannelType] = ...,
    placeholder: Optional[str] = ...,
    custom_id: str = ...,
    min_values: int = ...,
    max_values: int = ...,
    disabled: bool = ...,
    row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, SelectT]:
    ...

@overload
def select(
    *,
    cls: Type[UserSelectT] = UserSelect[V],
    options: List[SelectOption] = MISSING,
    channel_types: List[ChannelType] = ...,
    placeholder: Optional[str] = ...,
    custom_id: str = ...,
    min_values: int = ...,
    max_values: int = ...,
    disabled: bool = ...,
    row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, UserSelectT]:
    ...

@overload
def select(
    *,
    cls: Type[RoleSelectT] = RoleSelect[V],
    options: List[SelectOption] = MISSING,
    channel_types: List[ChannelType] = ...,
    placeholder: Optional[str] = ...,
    custom_id: str = ...,
    min_values: int = ...,
    max_values: int = ...,
    disabled: bool = ...,
    row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, RoleSelectT]:
    ...

@overload
def select(
    *,
    cls: Type[ChannelSelectT] = ChannelSelect[V],
    options: List[SelectOption] = MISSING,
    channel_types: List[ChannelType] = ...,
    placeholder: Optional[str] = ...,
    custom_id: str = ...,
    min_values: int = ...,
    max_values: int = ...,
    disabled: bool = ...,
    row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, ChannelSelectT]:
    ...

@overload
def select(
    *,
    cls: Type[MentionableSelectT] = MentionableSelect[V],
    options: List[SelectOption] = MISSING,
    channel_types: List[ChannelType] = MISSING,
    placeholder: Optional[str] = ...,
    custom_id: str = ...,
    min_values: int = ...,
    max_values: int = ...,
    disabled: bool = ...,
    row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, MentionableSelectT]:
    ...

def select(
    *,
    cls: Type[BaseSelectT] = Select[V],
    options: List[SelectOption] = MISSING,
    channel_types: List[ChannelType] = MISSING,
    placeholder: Optional[str] = None,
    custom_id: str = MISSING,
    min_values: int = 1,
    max_values: int = 1,
    disabled: bool = False,
    row: Optional[int] = None,
) -> SelectCallbackDecorator[V, BaseSelectT]:
    """A decorator that attaches a select menu to a component.

    The function being decorated should have three parameters, ``self`` representing
    the :class:`discord.ui.View`, the :class:`discord.Interaction` you receive and
    the chosen select class.

    To obtain the selected values inside the callback, you can use the ``values`` attribute of the chosen class in the callback. The list of values
    will depend on the type of select menu used. View the table below for more information.

    +----------------------------------------+-----------------------------------------------------------------------------------------------------------------+
    | Select Type                            | Resolved Values                                                                                |
    +========================================+=================================================================================================================+
    | :class:`discord.ui.Select`             | List[:class:`str`]                                                                                |
    +----------------------------------------+-----------------------------------------------------------------------------------------------------------------+
    | :class:`discord.ui.UserSelect`         | List[Union[:class:`discord.Member`, :class:`discord.User`]]                                                     |
    +----------------------------------------+-----------------------------------------------------------------------------------------------------------------+
    | :class:`discord.ui.RoleSelect`         | List[:class:`discord.Role`]                                                                                |
    +----------------------------------------+-----------------------------------------------------------------------------------------------------------------+
    | :class:`discord.ui.MentionableSelect`  | List[Union[:class:`discord.Role`, :class:`discord.Member`, :class:`discord.User`]]                              |
    +----------------------------------------+-----------------------------------------------------------------------------------------------------------------+
    | :class:`discord.ui.ChannelSelect`      | List[Union[:class:`~discord.app_commands.AppCommandChannel`, :class:`~discord.app_commands.AppCommandThread`]]  |
    +----------------------------------------+-----------------------------------------------------------------------------------------------------------------+

    .. versionchanged:: 2.1
        Added the following keyword-arguments: ``cls``, ``channel_types``

    Example
    ---------
    .. code-block:: python3

        class View(discord.ui.View):

            @discord.ui.select(cls=ChannelSelect, channel_types=[discord.ChannelType.text])
            async def select_channels(self, interaction: discord.Interaction, select: ChannelSelect):
                return await interaction.response.send_message(f'You selected {select.values[0].mention}')

    Parameters
    ------------
    cls: Union[Type[:class:`discord.ui.Select`], Type[:class:`discord.ui.UserSelect`], Type[:class:`discord.ui.RoleSelect`], \
        Type[:class:`discord.ui.MentionableSelect`], Type[:class:`discord.ui.ChannelSelect`]]
        The class to use for the select menu. Defaults to :class:`discord.ui.Select`. You can use other
        select types to display different select menus to the user. See the table above for the different
        values you can get from each select type. Subclasses work as well, however the callback in the subclass will
        get overridden.
    placeholder: Optional[:class:`str`]
        The placeholder text that is shown if nothing is selected, if any.
    custom_id: :class:`str`
        The ID of the select menu that gets received during an interaction.
        It is recommended not to set this parameter to prevent conflicts.
    row: Optional[:class:`int`]
        The relative row this select menu belongs to. A Discord component can only have 5
        rows. By default, items are arranged automatically into those 5 rows. If you'd
        like to control the relative positioning of the row then passing an index is advised.
        For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
        ordering. The row number must be between 0 and 4 (i.e. zero indexed).
    min_values: :class:`int`
        The minimum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 0 and 25.
    max_values: :class:`int`
        The maximum number of items that must be chosen for this select menu.
        Defaults to 1 and must be between 1 and 25.
    options: List[:class:`discord.SelectOption`]
        A list of options that can be selected in this menu. This can only be used with
        :class:`Select` instances.
    channel_types: List[:class:`~discord.ChannelType`]
        The types of channels to show in the select menu. Defaults to all channels. This can only be used
        with :class:`ChannelSelect` instances.
    disabled: :class:`bool`
        Whether the select is disabled or not. Defaults to ``False``.
    """

    def decorator(func: ItemCallbackType[V, BaseSelectT]) -> ItemCallbackType[V, BaseSelectT]:
        if not inspect.iscoroutinefunction(func):
            raise TypeError('select function must be a coroutine function')
        callback_cls = getattr(cls, '__origin__', cls)
        if not issubclass(callback_cls, BaseSelect):
            supported_classes = ", ".join(["ChannelSelect", "MentionableSelect", "RoleSelect", "Select", "UserSelect"])
            raise TypeError(f'cls must be one of {supported_classes} or a subclass of one of them, not {cls!r}.')

        func.__discord_ui_model_type__ = callback_cls
        func.__discord_ui_model_kwargs__ = {
            'placeholder': placeholder,
            'custom_id': custom_id,
            'row': row,
            'min_values': min_values,
            'max_values': max_values,
            'disabled': disabled,
        }
        if issubclass(callback_cls, Select):
            func.__discord_ui_model_kwargs__['options'] = options
        if issubclass(callback_cls, ChannelSelect):
            func.__discord_ui_model_kwargs__['channel_types'] = channel_types

        return func

    return decorator  # type: ignore


#!/usr/bin/env python2.7
import numpy as np
import cv2
import glob
import json
from copy import copy
import os

class Configure():
    def __init__(self):
        self.objpoints = []
        self.imgpoints = []
        self.height = 480
        self.width = 640

    def getCalibrationParameters(self):
        dim = (8,5)
        objp = np.zeros((dim[0]*dim[1], 3), np.float32)
        objp[:,:2] = np.mgrid[0:dim[0], 0:dim[1]].T.reshape(-1,2)
        images = glob.glob('../samples/pitch1/*.png')

        for fname in images:
            img = cv2.imread(fname)
            gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

            # Find the chess board corners
            ret, corners = cv2.findChessboardCorners(gray, dim, None)

            # If found, add object points, image points (after refining them)
            if ret == True:
                self.objpoints.append(objp)
                corners2 = copy(corners)
                criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
                _ = cv2.cornerSubPix(gray,corners2,(11,11),(-1,-1),criteria)
                self.imgpoints.append(corners2)

                # Draw and display the corners
                # Comment this out to skip showing sample images!
                _ = cv2.drawChessboardCorners(img, dim, corners2, ret)
                cv2.imshow('img',img)
            cv2.waitKey(1000)

        ret, camera_matrix, dist, _, _ = cv2.calibrateCamera(self.objpoints, self.imgpoints, gray.shape[::-1],None,None)
        new_camera_matrix, roi=cv2.getOptimalNewCameraMatrix(camera_matrix, dist,(self.width,self.height),0,(self.width,self.height))

        pitch1 = {'new_camera_matrix' : new_camera_matrix.tolist(),
            'camera_matrix' : camera_matrix.tolist(),
            'dist' : dist.tolist()}

        pitch0 = {'new_camera_matrix' : new_camera_matrix.tolist(),
            'camera_matrix' : camera_matrix.tolist(),
            'dist' : dist.tolist()}

        data = {0 : pitch0, 1: pitch1}

        return data

if __name__ == "__main__":
    path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../config/", "undistort_pitch1.json")
    C = Configure()
    data = C.getCalibrationParameters()
    with open(path, 'w') as f:
        f.write(json.dumps(data))


from pytube import YouTube
def checkVideoResolution(tmp):
    videoResolution = ["2160p","1440p","1080p","720p","480p","360p","240p", "144p"]
    array = []
    url = YouTube(tmp)
    for i in range(len(videoResolution)):
        if(len(url.streams.filter(adaptive=True, file_extension='mp4', res=videoResolution[i]))>0):
            array.append(videoResolution[i])
    return array

def checkAudioResolution(tmp):
    audioResolution = ["128kbps","48kbps"]
    array = []
    url = YouTube(tmp)
    for i in range(len(audioResolution)):
        if(len(url.streams.filter(file_extension='mp4',type="audio", abr=audioResolution[i]))>0):
            array.append(audioResolution[i])
    return array


import datetime
import json

import requests

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

class Bill(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    comment = models.CharField(max_length=45, default='')
    amount = models.FloatField(default=1.00)
    status = models.CharField(max_length=15, null=True, blank=True)
    site = models.CharField(max_length=45)

    def get_url(self):
        try:
            headers = {
                'Authorization': f'Bearer {settings.QIWI_SECRET_KEY}',
                'Content-Type': 'application/json',
                'Accept': 'application/json',
            }

            expirationDateTime = self.created_at + datetime.timedelta(days=2)
            expirationDateTime = expirationDateTime.strftime('%Y-%m-%dT%H:%M:%S+03:00')

            request_data = {
                'amount': {
                    'currency': 'RUB',
                    'value': str(round(self.amount, 2))
                },
                'comment': str(self.comment),
                'expirationDateTime': str(expirationDateTime),
            }
            request_data = json.dumps(request_data)
            response = requests.put(f'https://api.qiwi.com/partner/bill/v1/bills/{settings.QIWI_DB_VERSION}_{self.id}/', headers=headers, data=request_data)
            data = response.json()

            self.status = data['status']['value']
            return data['payUrl']
        except:
            return None

    def reject(self):
        try:
            headers = {
                'Authorization': f'Bearer {settings.QIWI_SECRET_KEY}',
                'Content-Type': 'application/json',
                'Accept': 'application/json',
            }
            response = requests.post(f'https://api.qiwi.com/partner/bill/v1/bills/{settings.QIWI_DB_VERSION}_{self.id}/reject/', headers=headers)
            data = response.json()

            self.status = data['status']['value']
        except:
            return

    def success(self):
        import hmac
        import hashlib

        try:
            secret_key = bytes(settings.OPLATA_KEY)
            message = bytes(f'{self.id}|{self.status}|RUB|{self.amount}')
            signature = hmac.new(secret_key, message, hashlib.sha256).hexdigest()

            headers = {
                'Content-Type': 'application/json',
                'X-Api-Signature-SHA256': signature,
            }

            request_data = {
                'id': self.id,
                'status': self.status,
                'amount': {
                    'currency': 'RUB',
                    'value': str(self.amount)
                },
                'comment': self.comment,
            }

            request_data = json.dumps(request_data)

            response = requests.post(self.site, data=request_data, headers=headers)
            return response
        except:
            return None


from sqlalchemy import and_
from sqlalchemy import delete
from sqlalchemy import desc
from sqlalchemy import select
from sqlalchemy.orm import Session

from danswer.db.models import ConnectorCredentialPair
from danswer.db.models import DeletionAttempt
from danswer.db.models import DeletionStatus
from danswer.db.models import IndexingStatus

def check_deletion_attempt_is_allowed(
    connector_credential_pair: ConnectorCredentialPair,
) -> bool:
    """
    To be deletable:
        (1) connector should be disabled
        (2) there should be no in-progress/planned index attempts
    """
    return bool(
        connector_credential_pair.connector.disabled
        and (
            connector_credential_pair.last_attempt_status != IndexingStatus.IN_PROGRESS
            and connector_credential_pair.last_attempt_status
            != IndexingStatus.NOT_STARTED
        )
    )

def create_deletion_attempt(
    connector_id: int,
    credential_id: int,
    db_session: Session,
) -> int:
    new_attempt = DeletionAttempt(
        connector_id=connector_id,
        credential_id=credential_id,
        status=DeletionStatus.NOT_STARTED,
    )
    db_session.add(new_attempt)
    db_session.commit()

    return new_attempt.id

def get_not_started_index_attempts(db_session: Session) -> list[DeletionAttempt]:
    stmt = select(DeletionAttempt).where(
        DeletionAttempt.status == DeletionStatus.NOT_STARTED
    )
    not_started_deletion_attempts = db_session.scalars(stmt)
    return list(not_started_deletion_attempts.all())

def get_deletion_attempts(
    db_session: Session,
    connector_ids: list[int] | None = None,
    statuses: list[DeletionStatus] | None = None,
    ordered_by_time_updated: bool = False,
    limit: int | None = None,
) -> list[DeletionAttempt]:
    stmt = select(DeletionAttempt)
    if connector_ids:
        stmt = stmt.where(DeletionAttempt.connector_id.in_(connector_ids))
    if statuses:
        stmt = stmt.where(DeletionAttempt.status.in_(statuses))
    if ordered_by_time_updated:
        stmt = stmt.order_by(desc(DeletionAttempt.time_updated))
    if limit:
        stmt = stmt.limit(limit)

    deletion_attempts = db_session.scalars(stmt)
    return list(deletion_attempts.all())

def delete_deletion_attempts(
    db_session: Session, connector_id: int, credential_id: int
) -> None:
    stmt = delete(DeletionAttempt).where(
        and_(
            DeletionAttempt.connector_id == connector_id,
            DeletionAttempt.credential_id == credential_id,
        )
    )
    db_session.execute(stmt)


import json

from flask import Flask, render_template, jsonify, request, make_response, current_app
from random import *
from flask_cors import CORS
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
import logging
from logging.handlers import RotatingFileHandler
from flask_httpauth import HTTPTokenAuth
from app.license_util import license_generate, license_verify

# -----------------------------------setting begin--------------------------------------------
logging.basicConfig(level=logging.DEBUG)
file_log_handler = RotatingFileHandler('logs', maxBytes=1024 * 1024, backupCount=10)
formatter = logging.Formatter('%(levelname)s %(filename)s %(lineno)d %(message)s')
file_log_handler.setFormatter(formatter)
# 为全局的日志工具对象添加日志记录器
logging.getLogger().addHandler(file_log_handler)

app = Flask(__name__,
            static_folder="../dist/static",  # 设置静态文件夹目录
            template_folder="../dist")  # 设置vue编译输出目录dist文件夹，为Flask模板文件目录
app.config.from_object('config')
CORS(app, supports_credentials=True)

# 跨域配置
@app.after_request
def after_request(resp):
    resp = make_response(resp)
    resp.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:5000'
    resp.headers['Access-Control-Allow-Methods'] = 'GET,POST'
    resp.headers['Access-Control-Allow-Headers'] = 'content-type,Authorization'
    return resp

# -----------------------------------setting end--------------------------------------------

# -----------------------------------auth begin--------------------------------------------
auth = HTTPTokenAuth(scheme='Bearer')

@auth.verify_token
def verify_token(token):
    return TokenTool.verify_auth_token(token)

# -----------------------------------auth end--------------------------------------------

# -----------------------------------routes begin--------------------------------------------
# 登录态检查
@app.route('/api/authCheck')
@auth.login_required
def authCheck():
    return jsonify({'msg': 'ok'})

# license验证登录
@app.route('/api/login', methods=['POST'])
def login():
    try:
        user = license_verify.license_verify()
    except Exception as ex:
        return forbidden('Invalid license. ' + str(ex))
    token = TokenTool.generate_auth_token(600, user)
    response = {
        'token': token,
    }
    return response

# license生成
@app.route('/api/generate', methods=['POST'])
def generate():
    data = request.get_data()
    data = json.loads(data)['data']
    username = data['username']
    valid_seconds = data['valid_seconds']
    modules = data['modules']
    try:
        license_generate.license_generate(username, valid_seconds, modules)
    except Exception as ex:
        return unauthorized('Generate license failed. ' + str(ex))
    return jsonify({'msg': 'ok'})

# 前端获取license信息
@app.route('/api/licenseMassage', methods=['GET'])
@auth.login_required
def get_license_massage():
    token = request.headers.get('Authorization')[7:]
    try:
        user = TokenTool.get_token_message(token)
    except Exception:
        return unauthorized('token is needed')
    response = {
        'modules': user['modules'],
        'valid_date': user['valid_date']
    }
    return response

# 模块鉴权
@app.route('/api/moduleAccess', methods=['POST'])
@auth.login_required
def module_access_check():
    token = request.headers.get('Authorization')[7:]
    try:
        user = TokenTool.get_token_message(token)
    except Exception:
        return unauthorized('token is needed')
    modules = user['modules']
    data = request.get_data()
    moduleName = json.loads(data)['data']['moduleName']
    if moduleName in modules:
        return {'access': True}
    return {'access': False}

# 能力测试接口——生成随机数
@app.route('/api/random')
@auth.login_required
def random_number():
    response = {
        'randomNumber': randint(1, 100)
    }
    return jsonify(response)

# url redirect 所有的url将被重定向至index.html，由前端vue-router进行分发
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
# @auth_login
def catch_all(path):
    # 使用模板插件，引入index.html。此处会自动Flask模板文件目录寻找index.html文件。
    return render_template("index.html", name="index")
# -----------------------------------routes  end--------------------------------------------

# -----------------------------------error begin--------------------------------------------
def forbidden(message):
    response = jsonify({'error': 'forbidden', 'message': message})
    response.status_code = 403
    return response

def unauthorized(message):
    response = jsonify({'error': 'unauthorized', 'message': message})
    response.status_code = 401
    return response
# -----------------------------------error  end  --------------------------------------------

# -----------------------------------Data Base begin--------------------------------------------
# token生成验证工具 后续应存储于数据库
class TokenTool:
    @staticmethod
    def generate_auth_token(expiration=1800, user=None):
        if user is None:
            user = {}
        serializer = Serializer(app.config['SECRET_KEY'], expires_in=expiration)
        token = serializer.dumps(user).decode('utf-8')
        return token

    @staticmethod
    def verify_auth_token(token):
        serializer = Serializer(current_app.config['SECRET_KEY'])
        try:
            serializer.loads(token)
        except Exception:
            return False
        return True

    @staticmethod
    def get_token_message(token):
        serializer = Serializer(current_app.config['SECRET_KEY'])
        try:
            user = serializer.loads(token)
        except Exception as ex:
            raise ex
        return user

# -----------------------------------end----------------------------------------------------

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


from XssMapObject import XssMapObject

class RequestVariableProbe(object):
    """
    Isolates parameters from HTTP requests that can be probed with reflection checking
    or XSS scanning.
    """

    @staticmethod
    def __has_URL_params(url):
        """
        (Private) Checks if provided URL has parameters in it.

        Args:
            url (str)

        Returns:
            (bool)
        """

        if '?' not in url:
            return False

        return True

    @staticmethod
    def __process_URL_params(url):
        """
        (Private) Processes a URL, returning a list of param objects based on its content.

        Args:
            url (str)

        Returns:
            (list)
        """

        output_list = []
        params_dump = url.split('?', 1)[1]

        # split on the '&' chars
        originals = params_dump.split('&')

        for orig in originals:

            this_param = {}

            this_param['delivery'] = 'url'

            # for each, split again on '='
            this_param['name'] = orig.split('=', 1)[0]
            this_param['value'] = orig.split('=', 1)[1]

            output_list.append(this_param)

        return output_list

    @staticmethod
    def __process_body_params(body):
        """
        (Private) Processes a request body (URL form-encoded), returning a list of param objects
        based on its content.

        Args:
            body (str)
        """

        output_list = []

        # Note: making a big assumption that this request body is already URL form-encoded and
        # therefore can split on the ampersands

        originals = body.split('&')

        for orig in originals:

            this_param = {}

            this_param['delivery'] = 'body'

            # for each, split again on '='
            this_param['name'] = orig.split('=', 1)[0]
            this_param['value'] = orig.split('=', 1)[1]

            output_list.append(this_param)

        return output_list

    @staticmethod
    def probe_POST_request(original_POST_url, original_POST_body):
        """
        Probe POST request for parameters.

        Args:
            original_POST_url (str)
            original_POST_body (str)

        Returns:
            (XssMapObject)
        """

        output = XssMapObject()
        output.request_url_root = original_POST_url.split('?', 1)[0]
        output.request_type = 'POST'
        output.params_other = []

        # Though it's a POST, maybe there are params in the URL to identify
        if RequestVariableProbe.__has_URL_params(original_POST_url):
            output.params_other = RequestVariableProbe.__process_URL_params(original_POST_url)

        body_params = RequestVariableProbe.__process_body_params(original_POST_body)
        for param in body_params:
            output.params_other.append(param)

        return output

    @staticmethod
    def probe_GET_request(original_GET_url):
        """
        Probe GET request for parameters.

        Args:
            original_GET_request (str)

        Returns:
            (XssMapObject)
        """

        output = XssMapObject()
        output.request_url_root = original_GET_url.split('?', 1)[0]
        output.request_type = 'GET'
        output.params_other = []

        if RequestVariableProbe.__has_URL_params(original_GET_url):
            output.params_other = RequestVariableProbe.__process_URL_params(original_GET_url)

        return output


'''
Created on 29/11/2009
@author: Nahuel
'''
import unittest
from opsys.process.ProcessStore import ProcessStore
from opsys.process.Process import Process

class TestProcessStore(unittest.TestCase):

    def setUp(self):
        self.store = ProcessStore()
        self.testPCB = Process(547, 'x', 10, [], 1, 1).get_pcb()

    def test_emptyWorkQueue(self):
        self.assertTrue(self.store.work_queue_is_empty())
        self.store.put_in_work_queue(self.testPCB)
        self.assertFalse(self.store.work_queue_is_empty())

    def test_emptyReadyQueue(self):
        self.assertTrue(self.store.ready_queue_is_empty())
        self.store.put_in_ready_queue(self.testPCB)
        self.assertFalse(self.store.ready_queue_is_empty())

    def test_work2ReadyQueue(self):
        self.store.put_in_work_queue(self.testPCB)
        self.assertFalse(self.store.work_queue_is_empty())
        self.assertTrue(self.store.ready_queue_is_empty())
        self.store.work_to_ready_queue(self.testPCB)
        self.assertTrue(self.store.work_queue_is_empty())
        self.assertFalse(self.store.ready_queue_is_empty())


rows, cols = [int(x) for x in input().split()]
matrix = []
for i in range(rows):
    list = []
    for j in range(cols):
        first_last = 97 + i
        middle = 97 + i + j
        list.append(f'{chr(first_last)}{chr(middle)}{chr(first_last)}')
    matrix.append(list)
for row in range(len(matrix)):
    print(' '.join(x for x in matrix[row]))

Multidimensional Lists - Exercise 1/05. Matrix of Palindromes.py


#!/usr/bin/env python

import visvis as vv
app = vv.use()

f = vv.clf()
a = vv.cla()

vv.plot([12,34,21,38], lc='b', ls=':',mc='b', mw=7, lw=2, ms='s', mec='r')
vv.plot([1,3,4],[33,47,12], lc='r', mc='r', ms='.')
vv.plot([20,24,45,21], lc='g', ls='--', mc='g', mw=12, lw=3, ms='')
vv.plot([35,14,40,31], lc='k', ls='-.', mc='g', mw=12, lw=3, ms='*')
# If the star is not visible, your OpenGl system does not support point sprites

a = vv.gca()
a.legend = 'line 1', 'line 2', 'line 3'
a.axis.showGrid = 1

a.axis.xlabel = 'measurement number'
a.axis.ylabel = 'some quantity [unit]'
vv.title('An example of \b{plotting}')

app.Run()


import os
import sys
import logging
from song import Song
import numpy as np

# Dataset: Loads and passes test data to the model
class Dataset:
    def __init__(self, logger, config):
        self.logger=logger
        self.config=config
        # Raw data
        self.mixtures = []
        self.vocals = []
        # Outputs for CNN
        self.mixture_windows = []
        self.labels = []

    # Load mixture and vocals and generates STFT for them
    def load(self, folder):
        if os.path.isdir(folder):
            for root, dirs, files in os.walk(folder):
                for file in filter(lambda f: f.endswith(".wav"), files):
                    self.logger.info("Loading song %s and computing stft for it.", os.path.join(root, file))
                    song_type = os.path.splitext(file)[0].lower()
                    if song_type == "mixture" or song_type == "vocals":
                        song = Song(self.logger, os.path.basename(root), self.config)
                        song.load_file(os.path.join(root,file))
                        song.compute_stft()
                        if(song_type == "mixture"):
                            self.mixtures.append(song)
                        elif(song_type == "vocals"):
                            self.vocals.append(song)
                        self.logger.debug("%s loaded successfully.", song_type)
                    else:
                        self.logger.debug("File %s is not named correctly. Ignoring...", song_type)
        else:
            self.logger.critical("Folder %s does not exist!", folder)
            sys.exit(8)
        if (len(self.mixtures) != len(self.vocals)):
            self.logger.critical("There doesn't appear to be a vocal track for each mixture (or the other way around).")
            sys.exit(15)

    def get_data_for_cnn(self):
        length = self.config.getint("song", "sample_length")
        self.logger.info("Preparing data of type 'mixture' for the CNN...")
        if len(self.mixtures) == 0:
            self.logger.critical("No mixtures for training found. Did you name them wrong?")
            sys.exit(9)
        self.logger.debug("Preparing %i songs...", len(self.mixtures))
        amplitudes = None
        for num in range(0, len(self.mixtures)):
            if amplitudes is None:
                amplitudes = self.mixtures[0].split_spectrogram(length)
            else:
                amplitudes = np.vstack((amplitudes, self.mixtures[0].split_spectrogram(length)))
            del self.mixtures[0]
        self.logger.debug("Got %i slices. Each slice has %i frequency bins, and each frequency bin has %i time slices.", len(amplitudes), len(amplitudes[0]), len(amplitudes[0][0]))
        self.logger.debug("Adding a 4th dimension to placate the CNN model...")
        # Add a dimension to make the CNN accept the data. Signifies that we have a greyscale "picture"
        amplitudes = np.array(amplitudes).reshape(len(amplitudes), len(amplitudes[0]), len(amplitudes[0][0]), 1)
        self.mixture_windows = amplitudes

    def get_labels_for_cnn(self):
        length = self.config.getint("song", "sample_length")
        self.logger.info("Preparing data of type 'vocals' for the CNN...")
        if len(self.vocals) == 0:
            self.logger.critical("No original vocals for training found. Did you name them wrong?")
            sys.exit(10)
        self.logger.debug("Preparing %i songs...", len(self.vocals))
        labels = []
        for num in range(0, len(self.vocals)):
            labels.extend(self.vocals[0].get_labels(length))
            del self.vocals[0]
        self.logger.debug("Got %i slices.", len(labels))
        self.labels = np.array(labels)


import os.path
import subprocess

def compressData(files, output, name, finalDirName):
    print("Compressing data")
    shellScriptCall = ["./dataCompressor.sh"]
    shellScriptCall.append(output)
    shellScriptCall.append(str(len(files)))
    shellScriptCall.extend(files)
    shellScriptCall.append(name)
    shellScriptCall.append(finalDirName)
    subprocess.call(shellScriptCall)

def parseStats(files, stats, configs, resultsCsv):
    print("Parsing stats and turning into csv")
    shellScriptCall = ["./dataParser.sh"]
    shellScriptCall.append(resultsCsv)
    shellScriptCall.append(files)
    shellScriptCall.append(str(len(stats)))
    shellScriptCall.extend(stats)
    shellScriptCall.append(str(len(configs)))
    shellScriptCall.extend(configs)
    subprocess.call(shellScriptCall)

# Main function that must be called from stats_analyzer.py
def runParse(config, csvPath):
    outDir = config["outputPath"]
    statsFiles = config["filesPaths"]
    statsToParse = config["statsAnalyzed"]
    configsToAnalyze = config["configs"]
    compressedFile = os.path.join(outDir, "stats.tar")
    finalDirName = os.path.join(outDir, "stats")
    compressData(statsFiles, compressedFile, "*stats.txt", finalDirName)
    parseStats(finalDirName, statsToParse, configsToAnalyze, csvPath)


from collections import namedtuple

import dgl
from dgl.data.tree import SSTDataset

SSTBatch = namedtuple('SSTBatch', ['graph', 'mask', 'wordid', 'label'])

trainset = SSTDataset(mode='tiny')
tiny_sst = trainset.trees
num_vocabs = trainset.num_vocabs
num_classes = trainset.num_classes

vocab = trainset.vocab # vocabulary dict: key -> id
inv_vocab = {v: k for k, v in vocab.items()} # inverted vocabulary dict: id -> word

a_tree = tiny_sst[0]
for token in a_tree.ndata['x'].tolist():
    if token != trainset.PAD_WORD:
        print(inv_vocab[token], end=" ")

##############################################################################
# Step 1: Batching
# ----------------
#
# Add all the trees to one graph, using
# the :func:`~dgl.batched_graph.batch` API.
#
import networkx as nx
import matplotlib.pyplot as plt

graph = dgl.batch(tiny_sst)
def plot_tree(g):
    # this plot requires pygraphviz package
    pos = nx.nx_agraph.graphviz_layout(g, prog='dot')
    nx.draw(g, pos, with_labels=False, node_size=10,
            node_color=[[.5, .5, .5]], arrowsize=4)
    # plt.show()
# plot_tree(graph.to_networkx())

# Step 2: Tree-LSTM cell with message-passing APIs
# ------------------------------------------------
#
# Researchers have proposed two types of Tree-LSTMs: Child-Sum
# Tree-LSTMs, and :math:`N`-ary Tree-LSTMs. In this tutorial you focus
# on applying *Binary* Tree-LSTM to binarized constituency trees. This
# application is also known as *Constituency Tree-LSTM*. Use PyTorch
# as a backend framework to set up the network.
#
# In `N`-ary Tree-LSTM, each unit at node :math:`j` maintains a hidden
# representation :math:`h_j` and a memory cell :math:`c_j`. The unit
# :math:`j` takes the input vector :math:`x_j` and the hidden
# representations of the child units: :math:`h_{jl}, 1\leq l\leq N` as
# input, then update its new hidden representation :math:`h_j` and memory
# cell :math:`c_j` by:
#
# .. math::
#
#    i_j & = & \sigma\left(W^{(i)}x_j + \sum_{l=1}^{N}U^{(i)}_l h_{jl} + b^{(i)}\right),  & (1)\\
#    f_{jk} & = & \sigma\left(W^{(f)}x_j + \sum_{l=1}^{N}U_{kl}^{(f)} h_{jl} + b^{(f)} \right), &  (2)\\
#    o_j & = & \sigma\left(W^{(o)}x_j + \sum_{l=1}^{N}U_{l}^{(o)} h_{jl} + b^{(o)} \right), & (3)  \\
#    u_j & = & \textrm{tanh}\left(W^{(u)}x_j + \sum_{l=1}^{N} U_l^{(u)}h_{jl} + b^{(u)} \right), & (4)\\
#    c_j & = & i_j \odot u_j + \sum_{l=1}^{N} f_{jl} \odot c_{jl}, &(5) \\
#    h_j & = & o_j \cdot \textrm{tanh}(c_j), &(6)  \\
#
# It can be decomposed into three phases: ``message_func``,
# ``reduce_func`` and ``apply_node_func``.
#
# .. note::
#    ``apply_node_func`` is a new node UDF that has not been introduced before. In
#    ``apply_node_func``, a user specifies what to do with node features,
#    without considering edge features and messages. In a Tree-LSTM case,
#    ``apply_node_func`` is a must, since there exists (leaf) nodes with
#    :math:`0` incoming edges, which would not be updated with
#    ``reduce_func``.
#
import torch as th
import torch.nn as nn
class TreeLSTMCell(nn.Module):
    def __init__(self, x_size, h_size):
        super(TreeLSTMCell, self).__init__()
        self.W_iou = nn.Linear(x_size, 3 * h_size, bias=False)
        self.U_iou = nn.Linear(2 * h_size, 3 * h_size, bias=False)
        self.b_iou = nn.Parameter(th.zeros(1, 3 * h_size))
        self.U_f = nn.Linear(2 * h_size, 2 * h_size)

    def message_func(self, edges):
        return {'h': edges.src['h'], 'c': edges.src['c']}

    def reduce_func(self, nodes):
        # concatenate h_j1 for equation (1), (2), (3), (4)
        h_cat = nodes.mailbox['h'].view(nodes.mailbox['h'].size(0), -1)
        # equation (2)
        f = th.sigmoid(self.U_f(h_cat)).view(*nodes.mailbox['h'].size())
        # second term of equation (5)
        c = th.sum(f * nodes.mailbox['c'], 1)
        return {'iou': self.U_iou(h_cat), 'c': c}

    def apply_node_func(self, nodes):
        # equation (1), (3), (4)
        iou = nodes.data['iou'] + self.b_iou
        i, o, u = th.chunk(iou, 3, 1)
        i, o, u = th.sigmoid(i) ,th.sigmoid(o), th.tanh(u)

        # equation (5)
        c = i * u + nodes.data['c']
        # equation (6)
        h = o * th.tanh(c)
        return {'h': h, 'c': c}

##############################################################################
# Step 3: Define traversal
# ------------------------
#
# After you define the message-passing functions, induce the
# right order to trigger them. This is a significant departure from models
# such as GCN, where all nodes are pulling messages from upstream ones
# *simultaneously*.
#
# In the case of Tree-LSTM, messages start from leaves of the tree, and
# propagate/processed upwards until they reach the roots. A visualization
# is as follows:
#
# .. figure:: https://i.loli.net/2018/11/09/5be4b5d2df54d.gif
#    :alt:
#
# DGL defines a generator to perform the topological sort, each item is a
# tensor recording the nodes from bottom level to the roots. One can
# appreciate the degree of parallelism by inspecting the difference of the
# followings:
#
# to heterogenous graph
trv_a_tree = dgl.graph(a_tree.edges())
print('Traversing one tree:')
print(dgl.topological_nodes_generator(trv_a_tree))

# to heterogenous graph
trv_graph = dgl.graph(graph.edges())
print('Traversing many trees at the same time:')
print(dgl.topological_nodes_generator(trv_graph))

##############################################################################
# Call :meth:`~dgl.DGLGraph.prop_nodes` to trigger the message passing:

import dgl.function as fn
import torch as th

trv_graph.ndata['a'] = th.ones(graph.number_of_nodes(), 1)
traversal_order = dgl.topological_nodes_generator(trv_graph)
trv_graph.prop_nodes(traversal_order,
                     message_func=fn.copy_src('a', 'a'),
                     reduce_func=fn.sum('a', 'a'))

class TreeLSTM(nn.Module):
    def __init__(self,
                 num_vocabs,
                 x_size,
                 h_size,
                 num_classes,
                 dropout,
                 pretrained_emb=None):
        super(TreeLSTM, self).__init__()
        self.x_size = x_size
        self.embedding = nn.Embedding(num_vocabs, x_size)
        if pretrained_emb is not None:
            print('Using glove')
            self.embedding.weight.data.copy_(pretrained_emb)
            self.embedding.weight.requires_grad = True
        self.dropout = nn.Dropout(dropout)
        self.linear = nn.Linear(h_size, num_classes)
        self.cell = TreeLSTMCell(x_size, h_size)

    def forward(self, batch, h, c):
        '''
        Compute tree-lstm prediction given a batch.
        :param batch: dgl.data.SSTBatch
        :param h: Tensor initial hidden state
        :param c: Tensor initial cell state
        :return: logits : Tensor
            The prediction of each node.
        '''
        g = batch.graph
        # to heterogenous graph
        g = dgl.graph(g.edges())
        # feed embedding
        embeds = self.embedding(batch.wordid * batch.mask)
        g.ndata['iou'] = self.cell.W_iou(self.dropout(embeds)) * batch.mask.float().unsqueeze(-1)
        g.ndata['h'] = h
        g.ndata['c'] = c
        # propagate
        dgl.prop_nodes_topo(g,
                            message_func=self.cell.message_func,
                            reduce_func=self.cell.reduce_func,
                            apply_node_func=self.cell.apply_node_func)
        # compute logits
        h = self.dropout(g.ndata.pop('h'))
        logits = self.linear(h)
        return logits

##############################################################################
# Main Loop
# ---------
#
# Finally, you could write a training paradigm in PyTorch.
#

from torch.utils.data import DataLoader
import torch.nn.functional as F

device = th.device('cpu')

# hyper parameters
x_size = 256
h_size = 256
dropout = 0.5
lr = 0.05
weight_decay = 1e-4
epochs = 10

# create the model
model = TreeLSTM(trainset.num_vocabs,
                 x_size,
                 h_size,
                 trainset.num_classes,
                 dropout)

print(model)

# create the optimizer
optimizer = th.optim.Adagrad(model.parameters(),
                             lr=lr,
                             weight_decay=weight_decay)

def batcher(dev):
    def batcher_dev(batch):
        batch_trees = dgl.batch(batch)
        return  SSTBatch(graph=batch_trees,
                         mask=batch_trees.ndata['mask'].to(device),
                         wordid=batch_trees.ndata['x'].to(device),
                         label=batch_trees.ndata['y'].to(device))

    return batcher_dev

train_loader = DataLoader(dataset=tiny_sst,
                          batch_size=5,
                          collate_fn=batcher(device),
                          shuffle=False,
                          num_workers=0)

# training loop
for epoch in range(epochs):
    for step, batch in enumerate(train_loader):
        g = batch.graph
        n = g.number_of_nodes()
        h = th.zeros((n, h_size))
        c = th.zeros((n, h_size))
        logits = model(batch, h, c)
        logp =F.log_softmax(logits, 1)
        loss = F.nll_loss(logp, batch.label, reduction='sum')
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        pred = th.argmax(logits, 1)
        acc = float(th.sum(th.eq(batch.label, pred))) / len(batch.label)
        print("Epoch {:05d} | Step {:05d} | Loss {:.4f} | Acc {:.4f} |".format(
            epoch, step, loss.item(), acc))


# editor: Wang Zhixiong
from typing import TypeVar, Generic, List, Iterator
from typing import Any
from typing import Union
from typing import Generator
from typing import Callable
from typing import Optional

K = Union[str, int, float]
D = Union[None, str, int, float]

class TreeNode:
    def __init__(self, k: K, v: D,
                 left: object = None,
                 right: object = None) -> None:
        self.key = k  # key
        self.val = v  # value
        self.leftChild = left  # left pointer
        self.rightChild = right  # right pointer

    def __iter__(self) -> Iterator[Any]:
        return iter(tolist(self))

def size(b: Union[TreeNode, None]) -> int:
    if b is None:
        return 0
    else:
        return 1 + size(b.leftChild) +\
               size(b.rightChild)  # type: ignore

def insert(bst: Union[TreeNode, None], key: K,
           val: D) -> Optional[TreeNode]:
    if bst is None:
        bst = TreeNode(key, val)
    elif key is None or val is None:
        if bst.leftChild is None:
            bst.leftChild = TreeNode(key, val)
        else:
            if bst.rightChild is None:
                bst.rightChild = TreeNode(key, val)
        # raise AttributeError("The element is wrong.")
    elif bst.key is None:
        if bst.leftChild is None:
            bst.leftChild = TreeNode(key, val)
        else:
            if bst.rightChild is None:
                bst.rightChild = TreeNode(key, val)
    else:
        if isinstance(key, str):
            key_num = 0
            for i in range(len(key)):
                key_num = key_num + ord(key[i])
        else:
            key_num = key  # type: ignore
        if isinstance(bst.key, str):
            bstkey_num = 0
            for i in range(len(bst.key)):
                bstkey_num = bstkey_num + ord(bst.key[i])
        else:
            bstkey_num = bst.key  # type: ignore
        if key_num <= bstkey_num:
            if bst.leftChild is None:
                bst.leftChild = TreeNode(key, val)
            else:
                insert(bst.leftChild, key, val)
        else:
            if bst.rightChild is None:
                bst.rightChild = TreeNode(key, val)  # type: ignore
            else:
                insert(bst.rightChild, key, val)
    return bst

def get(bst: Union[TreeNode, None], key: K) -> Union[TreeNode, None]:
    if bst is None:
        return None
    if type(bst.key) != key:
        if get(bst.leftChild, key) is not None:
            return get(bst.leftChild, key)
        if get(bst.rightChild, key) is not None:
            return get(bst.rightChild, key)
    if key == bst.key:
        return bst

def find(bst: Union[TreeNode, None],
         key: K) -> Union[D, bool]:
    if get(bst, key) is None:
        return False
    else:
        return get(bst, key).val  # type: ignore

def parent(bst: Union[TreeNode, None],
           key: K) -> Union[TreeNode, None]:
    if bst is None or bst.key == key:
        return None
    elif key == bst.leftChild.key or key == bst.rightChild.key:
        return bst
    elif key < bst.key:
        return parent(bst.leftChild, key)
    else:
        return parent(bst.rightChild, key)

def is_member(bst: Union[TreeNode, None],
              k: K, v: D) -> bool:
    if find(bst, k) == v:
        return True
    else:
        return False

def delete(bst: Union[TreeNode, None],
           key: K) -> None:
    res = tolist(bst)
    res1 = res[0::2]
    index = None
    for i in range(0, len(res1)):
        if key == res1[i]:
            index = i
    res2 = res[1::2]
    if index is None:
        raise AttributeError("The element does not exist.")
    del res[index * 2 + 1]
    del res[index * 2]
    return fromlist(res)

def tolist(bst: Union[TreeNode, None]) -> List:
    res = []  # type: ignore

    def tolist_loop(bst, ans):
        if bst is not None:
            ans.append(bst.key)
            ans.append(bst.val)
            ans = tolist_loop(bst.leftChild, ans)
            ans = tolist_loop(bst.rightChild, ans)
        return ans

    return tolist_loop(bst, res)

def fromlist(lst: List) -> Union[TreeNode, None, bool]:
    bst = None
    if len(lst) == 0:
        return None
    elif len(lst) % 2 == 1:
        return False
    for i in range(0, len(lst)):
        for j in range(0, len(lst)):
            if lst[i] == lst[j] and i % 2 == 0 and j % 2 == 0:
                lst[i + 1] = lst[j + 1]
    else:
        for i in range(0, len(lst), 2):
            bst = insert(bst, lst[i], lst[i + 1])
        return bst

def map(bst: Union[TreeNode, None],
        f: Callable[[float], float]) -> TreeNode:
    if bst is not None and bst.key is not None:
        bst.val = f(bst.val)
        map(bst.leftChild, f)
        map(bst.rightChild, f)
    return bst

def func(bst: Union[TreeNode, None],
         f: Callable[[float], float]) -> int:
    ans = [0]

    def func_loop(bst, f, ans):
        if bst is not None:
            ans[0] = f(ans[0], bst.val)
            func_loop(bst.leftChild, f, ans)
            func_loop(bst.rightChild, f, ans)
        return ans

    return func_loop(bst, f, ans)[0]

def filter(tree: Union[TreeNode, None],
           rule: Generator[str, int, float]) -> Union[TreeNode, None]:
    bst = None

    def filter_loop(bst, current, rule):
        if current is not None:
            if rule(current.key) is False:
                bst = insert(bst, current.key, current.val)
            bst = filter_loop(bst, current.leftChild, rule)
            bst = filter_loop(bst, current.rightChild, rule)
        return bst

    return filter_loop(bst, tree, rule)

def mconcat(bst1: Union[TreeNode, None],
            bst2: Union[TreeNode, None]) -> Union[TreeNode, None, bool]:
    lst1 = tolist(bst1)
    lst2 = tolist(bst2)
    lst = lst1 + lst2
    return fromlist(lst)

def mempty() -> None:
    return None

def iterator(bst: Union[TreeNode, None]) -> List:
    return [tolist(bst), 0]

def next_item(it_lst: List) -> Callable[[], Any]:
    lst = it_lst[0]
    cur = it_lst[1]

    def foo():
        nonlocal cur
        if cur >= len(lst) or lst == []:
            raise StopIteration
        tmp = lst[cur]
        cur = cur + 1
        it_lst[1] = it_lst[1] + 1
        return tmp

    return foo

def display(bst: Union[TreeNode, None]) -> dict:
    if bst is None:
        return {}
    else:
        a = tolist(bst)
        b = dict(zip(a[0::2], a[1::2]))
        return b


import requests
import sys

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

MAX_RETRY_NUM = 5
BACKOFF_FACTOR = 1
STATUS_FORCELIST = [502, 503, 504]

def get_request(url):
    """
    Attempts to get the HTML content with the given URL by making an HTTP GET request. It is set up to
    retry the request for a maximum number of retries.
    :param url:
    :return:
    """
    try:
        session = requests.Session()
        retries = Retry(total=MAX_RETRY_NUM, backoff_factor=BACKOFF_FACTOR, status_forcelist=STATUS_FORCELIST)
        session.mount('http://', HTTPAdapter(max_retries=retries))
        request_page = session.get(url)
        return request_page
    except requests.exceptions.ConnectionError as errc:
        # ConnectionError occurs in the event of a network problem (DNS failure, refused connection)
        print(f"Connection error: {errc}")
    except requests.exceptions.HTTPError as errh:
        # HTTPError occurs in the event of a rare invalid HTTP response
        print(f"HTTP error: {errh}")
    except requests.exceptions.Timeout as errt:
        # Timeout exception occurs whenever a request times out
        print(f"Request timeout error: {errt}")
    except requests.exceptions.TooManyRedirects as errm:
        # TooManyRedirects exception occurs if a request exceeds the configured number of maximum redirections
        print(f"URL was bad: {errm}")
    except requests.exceptions.RequestException as err:
        # RequestException occurs for any kind of exceptions that are raised
        print(f"Error during requests to {url}: {err}")
        sys.exit(1)


from PIL import Image
import colorsys
import numpy as np
nx, ny = 128, 128

def createHSVimage(hue, sat, val, alpha):
    rgba = []
    # convert hsv -> rgb
    for h, s, v, a in zip(hue.tolist(), sat.tolist(), val.tolist(), alpha.tolist()):
        r, g, b = colorsys.hsv_to_rgb(h, s, v)
        rgba.append( (int(255*r), int(255*g), int(255*b), int(255*a)) )
    # new image for color composite
    imrgb = Image.new('RGBA', (nx, ny))
    imrgb.putdata(rgba)
    imrgb = imrgb.transpose(Image.FLIP_TOP_BOTTOM)
    return imrgb

x = np.linspace(-1.2, 1.2, nx)[np.newaxis,:]
y = np.linspace(-1.2, 1.2, ny)[:,np.newaxis]

rr = np.sqrt(x**2 + y**2)
th = np.arctan2(y, x)

phase = 0.0
boost = 2.0			# exaggerate the field angle
phi = np.remainder(phase + boost*np.arctan2(x, y),
                  2.0*np.pi)/(2.0*np.pi) # should be in range [0, 1]
# dip = np.where(rr <= 1.0, 1.0 - np.sqrt(1.0 - rr**2), 1.0)
dip = np.where(rr <= 1.0, rr**2, 1.0)
hue = phi

bgamma = 2.0
# hue is in-plane angle
hue = phi.flatten()
# saturation is out-of-plane angle
sat = dip.flatten()

# alpha channel to smoothly cut out the circle
sharpness = 20.0
alpha = 1.0/(1.0 + np.exp(sharpness*(rr-1.05))).flatten()

for field_strength in [0.5, 1.0]:
    # value is field strength
    val = np.array([field_strength]*nx*ny)
    imrgb = createHSVimage(hue, sat, val, alpha)
    imrgb.save("mhdcuts-Bkey-%2.2i.png" % (int(10*field_strength)))

# and another one, with saturation going down in the middle but value too
val = np.where(rr <= 1.0, 0.8 + 0.2*rr**2, 1.0).flatten()
imrgb = createHSVimage(hue, sat, val, alpha)
imrgb.save("mhdcuts-Bkey-sat.png")

# now do another one, with full saturation but value proportional to radius
sat = np.ones(nx*ny, np.float)
val = np.where(rr <= 1.0, rr, 1.0).flatten()
imrgb = createHSVimage(hue, sat, val, alpha)
imrgb.save("mhdcuts-Bkey-val.png")

# and finally one that combines everything....
peak = 0.7                              # fully saturated, value=1 appears here
val = np.where(rr >= peak,  (peak/rr)**2 , 1.0).flatten()
sat = np.where(rr <= peak, (rr/peak)**3, 1.0).flatten()
imrgb = createHSVimage(hue, sat, val, alpha)
imrgb.save("mhdcuts-Bkey-both.png")


# Напишите программу, удаляющую из текста все слова, содержащие ""абв"".
# Добавлено сохранение пунктуации

import string
string.punctuation

def main():
    text = 'вапроеалдад абв роло АБВ, абвапро апргшл'

    for i in string.punctuation:
        if i in text:
            text = text.replace(i, f' {i}')
    text = list(filter(lambda el: 'абв' not in el.lower(), text.split()))
    text = ' '.join(text)

    for i in string.punctuation:
        if i in text:
            text = text.replace(f' {i}', i)
    print(text)

if __name__ == "__main__":
    main()


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

import math
import numpy as np

################################################################################
# ANGLE MATH
################################################################################

def quaternionToRotationMatrix( q ):

  # algorithm expects q = [ qw, qx, qy, qz ] and we use
  # q = [ qw, qx, qy, qz ], so we have to set it differently.
  q = np.array([ q[3], q[0], q[1], q[2] ])

  n = np.dot(q, q)

  if n < np.finfo(np.float64).eps:
      return np.identity(3)

  q *= math.sqrt(2.0 / n)
  q = np.outer(q, q)
  return np.array([
    [1.0-q[2, 2]-q[3, 3],     q[1, 2]-q[3, 0],     q[1, 3]+q[2, 0]],
    [    q[1, 2]+q[3, 0], 1.0-q[1, 1]-q[3, 3],     q[2, 3]-q[1, 0]],
    [    q[1, 3]-q[2, 0],     q[2, 3]+q[1, 0], 1.0-q[1, 1]-q[2, 2]]
  ])

def eulerAnglesfromRotationMatrix( R ):

  r00 = R[0][0]
  r10 = R[1][0]
  r20 = R[2][0]
  r21 = R[2][1]
  r22 = R[2][2]

  theta_x = math.atan2(r21, r22)
  theta_y = math.atan2(-r20, math.sqrt( r21 * r21 + r22 * r22 ))
  theta_z = math.atan2(r10, r00)

  # convert to degrees
  theta_x = math.degrees( theta_x )
  theta_y = math.degrees( theta_y )
  theta_z = math.degrees( theta_z )

  angles = [theta_x, theta_y , theta_z]

  return angles

def R_axis_angle(angle, axis):
    """Generate the rotation matrix from the axis-angle notation.

    Conversion equations
    ====================

    From Wikipedia (http://en.wikipedia.org/wiki/Rotation_matrix), the conversion is given by::

        c = cos(angle); s = sin(angle); C = 1-c
        xs = x*s;   ys = y*s;   zs = z*s
        xC = x*C;   yC = y*C;   zC = z*C
        xyC = x*yC; yzC = y*zC; zxC = z*xC
        [ x*xC+c   xyC-zs   zxC+ys ]
        [ xyC+zs   y*yC+c   yzC-xs ]
        [ zxC-ys   yzC+xs   z*zC+c ]

    @param axis:    The 3D rotation axis.
    @type axis:     numpy array, len 3
    @param angle:   The rotation angle.
    @type angle:    float
    """

    # Trig factors.
    ca = math.cos(angle)
    sa = math.sin(angle)
    C = 1 - ca

    # Depack the axis.
    x, y, z = axis

    # Multiplications (to remove duplicate calculations).
    xs = x*sa
    ys = y*sa
    zs = z*sa
    xC = x*C
    yC = y*C
    zC = z*C
    xyC = x*yC
    yzC = y*zC
    zxC = z*xC

    # Create the rotation matrix.

    matrix = np.zeros((3,3))

    matrix[0, 0] = x*xC + ca
    matrix[0, 1] = xyC - zs
    matrix[0, 2] = zxC + ys
    matrix[1, 0] = xyC + zs
    matrix[1, 1] = y*yC + ca
    matrix[1, 2] = yzC - xs
    matrix[2, 0] = zxC - ys
    matrix[2, 1] = yzC + xs
    matrix[2, 2] = z*zC + ca

    return matrix

################################################################################
# TRANSFORMATION MATH
################################################################################

def to44( T ):
  """
  @brief compute a transformation in 4x4 matrix form.
  @param T 3x4 or 4x4 transformation matrix.
  @return 4x4 transformation matrix.
  """
  T44 = np.eye(4, 4)
  T44[:3,:4] = T[:3,:4]
  return T44

def eyeFromShape( T ):
  """
  @brief create an identity matrix that mimics the shape of another 2D matrix.
  @param T 2D matrix whose shape will be used.
  @return identity matrix with the same shape as T.
  """
  return np.eye( T.shape[0], T.shape[1] )

def composeTransformation( R, t, T ):
  """
  @brief create a transfomation matrix from a rotation matrix and translation vector.
  @param R rotation matrix.
  @param t translation vector.
  @param T matrix on which the transformation will be written. Probably np.eye(3,4) or np.eye(4,4).
  @return the composed transformation.
  """

  T[0:3, 0:3] = R
  T[0:3, 3] = t

  return T

def composeTransformations( Rs, ts ):

  assert( len(Rs) == len(ts) )

  transformations = []

  for R, t in zip(Rs, ts):

    T = np.eye(4, 4)
    T = composeTransformation(R, t, T)

    transformations.append( T )

  return transformations

def decomposeTransformation( T ):
  """
  @brief decompose a 3x4 or 4x4 transformation matrix into R and t matrices.
  @param T 3x4 or 4x4 transformation matrix.
  @return rotation matrix R, translation vector t.
  """

  return T[0:3, 0:3], T[0:3, 3]

def decomposeTransformations( transformations ):
  """
  @brief decompose array of transformations into R and t arrays.
  @param transformations array of 3x4 or 4x4 matrices.
  @return array of 3x3 rotation matrices, array of 3D translation vectors
  """

  Rs = []
  ts = []

  for transform in transformations:

    R, t = decomposeTransformation( transform )

    Rs.append( R )
    ts.append( t )

  return np.array( Rs ), np.array( ts )

def transformationInverse( T ):
  """
  @brief compute the inverse of a transformation matrix.
  @param T 3x4 or 4x4 transformation matrix.
  @return the matrix inverse of T.
  """

  R, t = decomposeTransformation( T )

  Ri = R.transpose()
  ti = -Ri.dot( t )

  Ti = eyeFromShape( T )
  return composeTransformation(Ri, ti, Ti)

def getPositionsFromTransformations( Rs, ts ):

  ps = []

  for R, t in zip(Rs, ts):

    pos = -(R.transpose()).dot( t )

    ps.append( pos )

  return ps

def preMultiplyPoses(poses, T):
  """
  @brief pre-multiply an array of poses by a transformation matrix T (T*P),
    independently of the transformation represantation. Both poses and 'T'
    are allowed to be 3x4 or 4x4 matrices.
  """

  T44 = to44( T )

  new_poses = []
  for pose in poses:
    new_pose = T44.dot( to44( pose ) )
    new_poses.append( new_pose[:pose.shape[0],:pose.shape[1]] )

  return np.array( new_poses )

def postMultiplyPoses(poses, T):
  """
  @brief post-multiply an array of poses by a transformation matrix T (P*T),
    independently of the transformation represantation. Both poses and 'T'
    are allowed to be 3x4 or 4x4 matrices.
  """

  T44 = to44( T )

  new_poses = []
  for pose in poses:
    new_pose = to44( pose ).dot( T44 )
    new_poses.append( new_pose[:pose.shape[0],:pose.shape[1]] )

  return np.array( new_poses )

def alignToInitialPose( poses, initial_pose ):
  """
  @brief Align a path to some intial pose (given in the same reference frame W).
  @param poses array of 3x4 or 4x4 matrices.
  @param initial_pose 3x4 or 4x4 matrix.
  @return array of transformed poses with the same shape as the input poses.
  """

  path_to_world = to44( poses[0] )
  target_to_world = to44( initial_pose )

  # compute the desired transformation
  T = target_to_world.dot( transformationInverse( path_to_world ) )

  return preMultiplyPoses(poses, T)

def alignToInitialPose2( positions, orientations, pos_ini, ori_ini ):
  """
  @brief Align a path to some intial pose (given in the same reference frame W).
  @param positions array of 3D vectors.
  @param orientations array of 3x3 matrices.
  @param pos_ini 3D vector.
  @param ori_ini 3x3 matrix.
  @return array of transformed positions, array of transformed orientations.
  """

  positions_new = []
  for pos in positions:
    pos_new = ori_ini.dot( pos ) + pos_ini
    positions_new.append( pos_new )

  orientations_new = []
  for ori in orientations:
    ori_new = ori_ini.dot( ori )
    orientations_new.append( ori_new )

  return positions_new, orientations_new


from signal import signal
import Finder.CandleStick as candle
import Enum.CommonEnum as enum

def isPiercingCloudCoverPattern(prev_openPrice, prev_closePrice, openPrice, closePrice):
    #closePrice < prev_openPrice and closePrice > prev_closePrice and openPrice < prev_closePrice and \ will move seperate method later
    return candle.getCandleColor(openPrice, closePrice) == enum.Candle.GREEN and candle.getCandleColor(prev_openPrice, prev_closePrice) == enum.Candle.RED and \
       closePrice < prev_openPrice and closePrice > prev_closePrice and openPrice < prev_closePrice and \
       candle.getTrend(prev_openPrice, prev_closePrice, closePrice) == enum.Trend.UP

def isDarkCloudCoverPattern(prev_openPrice, prev_closePrice, openPrice, closePrice):
    #closePrice > prev_openPrice and closePrice < prev_closePrice and openPrice > prev_closePrice and \ will move seperate method later
    return candle.getCandleColor(openPrice, closePrice) == enum.Candle.RED and candle.getCandleColor(prev_openPrice, prev_closePrice) == enum.Candle.GREEN and \
       closePrice > prev_openPrice and closePrice < prev_closePrice and openPrice > prev_closePrice and \
       candle.getTrend(prev_openPrice, prev_closePrice, closePrice) == enum.Trend.DOWN

def find_ThreeWhiteKnights(highPrice, prev1_highPrice, prev2_highPrice, prev3_highPrice):
    # Three White Soldiers
    return highPrice > prev1_highPrice and \
        prev1_highPrice > prev2_highPrice and \
        prev2_highPrice > prev3_highPrice

def find_ThreeBlackCrows(highPrice, prev1_highPrice, prev2_highPrice, prev3_highPrice):
    # Three Black Crows
    return highPrice < prev1_highPrice and \
        prev1_highPrice < prev2_highPrice and \
        prev2_highPrice < prev3_highPrice

def find_Harami_Pattern(openPrice, highPrice, lowPrice, closePrice, prev_openPrice, prev_closePrice):
    result = enum.HaramiCandleSys.NONE
    if candle.candle.isRed(prev_openPrice, prev_closePrice) and \
        candle.candle.isGreen(openPrice, closePrice) and \
        prev_closePrice < lowPrice and \
        prev_openPrice > highPrice:
        result = enum.HaramiCandleSys.BULL
    elif candle.candle.isGreen(prev_openPrice, prev_closePrice) and \
        candle.candle.isRed(openPrice, closePrice) and \
        prev_closePrice > highPrice and \
        prev_openPrice < lowPrice:
        result = enum.HaramiCandleSys.BEAR
    return result

#where a candle is followed by three candles of the other color which are in turn followed by a candle of the same color as the first one.
# The three candles in the middle should be contained within the ranges of the other two.
def find_ThreeSystem_Method(openPrice, closePrice, prev1_closePrice, prev1_openPrice, prev2_openPrice, prev2_closePrice, prev3_openPrice, prev3_closePrice, prev4_openPrice, prev4_closePrice):
    result = enum.ThreeSystem_Method.NONE
    # Bullish Strike Method
    if candle.isGreen(openPrice, closePrice):
        if candle.isRed(prev1_openPrice, prev1_closePrice) and candle.isRed(prev2_openPrice, prev2_closePrice) and \
        candle.isRed(prev3_openPrice, prev3_closePrice) and candle.isGreen(prev4_openPrice, prev4_closePrice) and closePrice > prev3_openPrice and \
        prev4_openPrice < prev1_closePrice and prev1_closePrice < prev2_closePrice and prev2_closePrice < prev3_closePrice:
            result = enum.ThreeSystem_Method.BULL
    # Bearish Strike Method
    elif candle.isRed(openPrice, closePrice):
        if candle.isGreen(prev1_openPrice, prev1_closePrice) and candle.isGreen(prev2_openPrice, prev2_closePrice) and \
        candle.isGreen(prev3_openPrice, prev3_closePrice) and candle.isRed(prev4_openPrice, prev4_closePrice) and closePrice < prev3_openPrice and \
        prev4_openPrice > prev1_closePrice and prev1_closePrice > prev2_closePrice and prev2_closePrice > prev3_closePrice:
            result = enum.ThreeSystem_Method.BEAR
    return result


"""
This code is for a Monte Carlo sensitivity analysis
of the ABM of environmental migration

@author: kelseabest
"""

#import packages
from matplotlib.colors import LinearSegmentedColormap
import random
import math
import numpy as np
import matplotlib.pyplot as plt

#define vars
N = 100 #number of individual agents
N_hh = 10 #number of households
run_time = 100 #steps to run
decision = "utility"

#current values
mig_threshold = 1000 #migration threshold
mig_util = 400 #utility to migrate
wealth_factor = 3000
ag_factor = 100

#these are for monte carlo
size_mc = 1000 #number of MC draws

mig_threshold_sd = 500 #standard deviation
mig_threshold_mc = np.random.normal(mig_threshold, mig_threshold_sd, size_mc)

mig_util_sd = 200 #standard deviation
mig_util_mc = np.random.normal(mig_util, mig_util_sd, size_mc)

wealth_sd = 1000 #standard deviation
wealth_factor_mc = np.random.normal(wealth_factor, wealth_sd, size_mc)

ag_sd = 20 #standard deviation
ag_factor_mc = np.random.normal(ag_factor, ag_sd, size_mc)

#here I can do a for loop to loop through MC
# initialize model

mig_mc = pd.DataFrame()

for i in mig_threshold_mc:
    model = ABM_Model(run_time, N_hh, N, decision, mig_util, i, wealth_factor, ag_factor)

    #run model for ticks
    while (model.tick < model.ticks):
        model.model_step()
        model.data_collect()
        model.tick_up()
    data = model.data_set  #data should be stored here
    migs = model.migrations

    final_migs = migs.iloc[-1, 1]
    row = pd.DataFrame({'mig_threshold': [i], 'migrations': [final_migs]})
    mig_mc = pd.concat([mig_mc, row])


import cv2
import numpy as np
import os

# from .myEdgeDetector import myCanny
from myHoughLines import Handwrite_HoughLines
from myHoughTransform import Handwrite_HoughTransform

# parameters
sigma     = 2
threshold = 0.03
rhostep    = 2
thetastep  = np.pi / 90
num_lines    = 15
# end of parameters

img0 = cv2.imread('img02.jpg')

if (img0.ndim == 3):
    img = cv2.cvtColor(img0,cv2.COLOR_BGR2GRAY)
else:
    img = img0

img_edge = cv2.Canny(img, 50, 150, apertureSize = 3)
img_edge = np.float32(img_edge) / 255
img_threshold = np.float32(img_edge > threshold)

[img_houghtrans, rhoList, thetaList] = Handwrite_HoughTransform(img_threshold, rhostep, thetastep)

cv2.imwrite('edge02.png', 255 * np.sqrt(img_edge / img_edge.max()))
cv2.imwrite('thres02.png', 255 * img_threshold)
cv2.imwrite('hough02.png', 255 * img_houghtrans / img_houghtrans.max())

[rhos, thetas] = Handwrite_HoughLines(img_houghtrans, num_lines)

# display your line segment results in red
for k in np.arange(num_lines):
    a = np.cos(thetaList[thetas[k]])
    b = np.sin(thetaList[thetas[k]])

    x0 = a*rhoList[rhos[k]]
    y0 = b*rhoList[rhos[k]]

    x1 = int(x0 + 1000*(-b))
    y1 = int(y0 + 1000*(a))

    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a))

    cv2.line(img0,(x1,y1),(x2,y2),(0,0,255),1)

lines = cv2.HoughLinesP(np.uint8(255 * img_threshold), rhostep, thetastep, \
                        50, minLineLength = 20, maxLineGap = 5)
# display line segment results from cv2.HoughLinesP in green
for line in lines:
    coords = line[0]
    cv2.line(img0, (coords[0], coords[1]), (coords[2], coords[3]), (0, 255, 0), 1)

cv2.imwrite('line02.png', img0)


import tensorflow as tf
from tensorflow.python.ops.losses.losses_impl import Reduction

def one_step_td_loss(reward_t_1, gamma, q_t, q_t_1, action_t, done, double_q=False, q_t_1_d=None):
    with tf.name_scope('one_step_td_loss'):
        with tf.name_scope('Q_Estimate'):
            # Get shape of action vector (required for indexing in next step)
            action_shape = tf.shape(action_t)

            # Get action index array to be used to index q_t array to get action value of that experience
            action_t_index = tf.transpose(tf.stack([tf.range(action_shape[0]), action_t]))
            q_estimate = tf.gather_nd(q_t, action_t_index)

        # Define target value, using stop_gradient as this should not contribute to the gradient update and
        # dealing with the fact that the value after the terminal state should be 0 by multiplying with (1 - done)
        # where done is an indicator representing whether the current state is terminal, stored as 1 for terminal, 0 not
        with tf.name_scope('Target'):
            if double_q and (q_t_1_d is not None):
                q_t_1_d_shape = tf.shape(q_t_1_d)
                q_t_1_index = tf.transpose(tf.stack([tf.range(q_t_1_d_shape[0]), tf.argmax(q_t_1_d, axis=1,
                                                                                output_type=tf.int32)]))
                max_q = tf.gather_nd(q_t_1, q_t_1_index)
            else:
                max_q = tf.reduce_max(q_t_1, axis=1)
            next_q = tf.multiply((1.0 - done), max_q)
            q_target = tf.stop_gradient(reward_t_1 + gamma*next_q)

            tf.summary.histogram('next_q', next_q)

        # Compute mean Huber loss for batch
        loss = tf.losses.huber_loss(q_target, q_estimate, reduction=Reduction.MEAN)

        # Compute TD error for prioritised replay
        td_error = tf.abs(q_target - q_estimate)
    return loss, td_error


import json
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
from drawing import draw_pitch

def import_xtvalues():
    with open('input_data/open_xt_12x8_v1.json', 'r') as f:
     xTvalues = np.array(json.load(f))
    return xTvalues

def offset_df(df, dx, dy):
    df = df.copy()
    df.x = df.x+dx
    df.y = df.y+dy
    return df

def create_multipoints(df):
  dfxT = df.from_records(import_xtvalues()).unstack().reset_index()
  dfxT.columns = ['x', 'y', 'xT']

  dfxT2= df.from_records(import_xtvalues()).unstack().reset_index()
  dfxT2.columns = ['x', 'y', 'xT']

  dfxT = pd.concat([offset_df(dfxT, dx, dy)
                    for dx, dy
                    in [(0.25, 0.25), (0.25, 0.75), (0.75, 0.25), (0.75, 0.75)]
                  ])
  dfxT2= pd.concat([offset_df(dfxT2, dx, dy)
                    for dx, dy
                    in [(0.25, 0.25), (0.25, 0.75), (0.75, 0.25), (0.75, 0.75)]
                  ])

  ny, nx = import_xtvalues().shape

  dfxT.x = dfxT.x*100/nx
  dfxT.y = dfxT.y*100/ny

  #only consider locations with better than median threat (i.e. ignore defensive positions)
  dfxT.xT = np.clip(dfxT.xT-dfxT.xT.median(), 0, 1)

  #flip axis if necessary (to align with attacking team)
  dfxT2.x = 100-dfxT.x
  dfxT2.y = 100-dfxT.y

  fig, ax = draw_pitch()

  #plotting pitch with probability
  rgba_colors = np.zeros((dfxT.shape[0],4))
  rgba_colors = np.zeros((dfxT2.shape[0],4))
  rgba_colors[:,0] = 1.0
  rgba_colors[:,3] = dfxT.xT.values/dfxT.xT.max()
  rgba_colors[:,3] = dfxT2.xT.values/dfxT2.xT.max()
  plt.scatter(dfxT['x'], dfxT['y'], c=rgba_colors)
  plt.scatter(dfxT2['x'], dfxT2['y'], c=rgba_colors)

  return fig,dfxT,rgba_colors


# This program is created to test the functionality of the objects, objects can  use the attributes inside the class as well as the methods inside them.

#creating classes
class User:

  #creating objects attributes
  def  __init__(self, userid, username):
    self.id = userid
    self.uID = username
    self.follower = 0
    self.following = 0

  #creating objects methods
  def follow(self, user):
    self.following +=1
    user.follower +=1

#creating objects

user_1 = User("001","aakash")
user_2 = User("002", "Smriti")

#Using objects with attributes
print(user_1.id)

#Using objects with methods

user_1.follow(user_2)
print(f"{user_1.uID} followers are {user_1.fo}")


#VARIABLES
zero  = [1,1,0,1,1,1,1]
one   = [0,0,0,1,0,0,1]
two   = [1,0,1,1,1,1,0]
three = [1,0,1,1,0,1,1]
four  = [0,1,1,1,0,0,1]
five  = [1,1,1,0,0,1,1]
six   = [1,1,1,0,1,1,1]
seven = [1,0,0,1,0,0,1]
eight = [1,1,1,1,1,1,1]
nine  = [1,1,1,1,0,1,1]
error = [1,1,1,0,1,1,0]
list1 = [zero,one,two,three,four,five,six,seven,eight,nine,error]
temp  = [0,0,0,0,0,0,0]

#FUNCTION FOR DECIMAL INPUT
def decimalinput(num,list1):
   if (num>=0 and num<=9):
      temp=list1[num]
      printing(temp)
   else:
      printing(error)

def bin_dec(binary):
   decimal = 0
   for i in binary:
       if (int(i)==0 or int(i)==1):
           decimal = decimal*2 + int(i)
       else:
           print ("\nWRONG BINARY INPUT")
           printing(error)
           exit (0)
   print ("Decimal value is=",decimal)
   decimalinput(decimal,list1)

#FUNCTION FOR PRINTING THE 7 SEGMENT OUTPUT
def printing (temp):
   b=[]
   for i in range(0,7):
      if (i==0 or i==2 or i==5):
         if(temp[i] ==1):
            b.append("_")
         else:
               b.append(" ")
      else:
         if(temp[i]==1):
            b.append("|")
         else:
            b.append(" ")

#printing(b)
   print("\nLCD output : ")
   print(" ",b[0],sep="")
   print(b[1],b[2],b[3],sep="")
   print(b[4],b[5],b[6],sep="")

#main
print("BCD TO 7 SEGMENGT DISPLAY ")
while(1):
   ch=int(input("\n0.Exit\n1.Decimal input\n2.Binary input\n Enter your choice :"))
   if ch==0:
      print("\n\nEXIT!!!\n\n")
      exit (0)
   elif ch==1:
      dec = int(input("Enter decimal value :"))
      decimalinput(dec,list1)
   elif ch==2:
       bin = input("Enter binary input :")
       bin_dec(bin)
   else:
      print("Wrong input !!!")
      printing(error)


def solution(N):
    maxgap = 0
    # Ignore the '0b' at the beginning.
    inlst = list(bin(N))[2:]
    # Convert to ints.
    inlst = [int(x) for x in inlst]
    if inlst.count(0) == 0:
        # print(n, 0)
        return 0
    gap = 0
    ingap = False
    start = 0
    for i,bitval in enumerate(inlst):
        if bitval == 1:
            if not ingap:
                continue
            ingap = False
            gap = i - start
        else:
            if ingap:
                continue
            ingap = True
            start = i
        maxgap = max(gap, maxgap)
    # print(n, maxgap)
    return maxgap