text: """
  The MIT License (MIT)
  
  Copyright (c) 2015-present Rapptz
  
  Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the "Software"),
  to deal in the Software without restriction, including without limitation
  the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  DEALINGS IN THE SOFTWARE.
  """
  
  from __future__ import annotations
  
  from .errors import (
      BadFlagArgument,
      CommandError,
      MissingFlagArgument,
      TooManyFlags,
      MissingRequiredFlag,
  )
  
  from discord.utils import resolve_annotation
  from .view import StringView
  from .converter import run_converters
  
  from discord.utils import maybe_coroutine, MISSING
  from dataclasses import dataclass, field
  from typing import (
      Dict,
      Iterator,
      Literal,
      Optional,
      Pattern,
      Set,
      TYPE_CHECKING,
      Tuple,
      List,
      Any,
      Type,
      TypeVar,
      Union,
  )
  
  import inspect
  import sys
  import re
  
  __all__ = (
      "Flag",
      "flag",
      "FlagConverter",
  )
  
  
  if TYPE_CHECKING:
      from .context import Context
  
  
  @dataclass
  class Flag:
      """Represents a flag parameter for :class:`FlagConverter`.
  
      The :func:`~discord.ext.commands.flag` function helps
      create these flag objects, but it is not necessary to
      do so. These cannot be constructed manually.
  
      Attributes
      ------------
      name: :class:`str`
          The name of the flag.
      aliases: List[:class:`str`]
          The aliases of the flag name.
      attribute: :class:`str`
          The attribute in the class that corresponds to this flag.
      default: Any
          The default value of the flag, if available.
      annotation: Any
          The underlying evaluated annotation of the flag.
      max_args: :class:`int`
          The maximum number of arguments the flag can accept.
          A negative value indicates an unlimited amount of arguments.
      override: :class:`bool`
          Whether multiple given values overrides the previous value.
      """
  
      name: str = MISSING
      aliases: List[str] = field(default_factory=list)
      attribute: str = MISSING
      annotation: Any = MISSING
      default: Any = MISSING
      max_args: int = MISSING
      override: bool = MISSING
      cast_to_dict: bool = False
      noneable: bool = False
      type: str = MISSING
  
      @property
      def required(self) -> bool:
          """:class:`bool`: Whether the flag is required.
  
          A required flag has no default value.
          """
          return self.default is MISSING
  
  
  def flag(
      *,
      name: str = MISSING,
      aliases: List[str] = MISSING,
      default: Any = MISSING,
      max_args: int = MISSING,
      override: bool = MISSING,
      noneable: bool = MISSING,
      type: str = MISSING
  ) -> Any:
      """Override default functionality and parameters of the underlying :class:`FlagConverter`
      class attributes.
  
      Parameters
      ------------
      name: :class:`str`
          The flag name. If not given, defaults to the attribute name.
      aliases: List[:class:`str`]
          Aliases to the flag name. If not given no aliases are set.
      default: Any
          The default parameter. This could be either a value or a callable that takes
          :class:`Context` as its sole parameter. If not given then it defaults to
          the default value given to the attribute.
      max_args: :class:`int`
          The maximum number of arguments the flag can accept.
          A negative value indicates an unlimited amount of arguments.
          The default value depends on the annotation given.
      override: :class:`bool`
          Whether multiple given values overrides the previous value. The default
          value depends on the annotation given.
      """
      return Flag(
          name=name,
          aliases=aliases,
          default=default,
          max_args=max_args,
          override=override,
          noneable=noneable,
          type=type
      )
  
  def resolve_signature_string(annotation: Any, origin: Any) -> Optional[str]:
      _type = ""
      if not origin:
          _type = annotation.__name__
      elif origin is Literal:
          _type = "|".join(
              f'"{v}"' if isinstance(v, str) else str(v)
              for v in annotation.__args__
          )
      elif origin is list or origin is tuple:
          v = annotation.__args__[0]
          _type = resolve_signature_string(v, getattr(v, "__origin__", None))
      elif origin is Union:
          _type = "|".join(
              resolve_signature_string(v, getattr(v, "__origin__", None))
              for v in annotation.__args__
              if v is not type(None)
          )
      return _type
  
  
  def validate_flag_name(name: str, forbidden: Set[str]):
      if not name:
          raise ValueError("flag names should not be empty")
  
      for ch in name:
          if ch.isspace():
              raise ValueError(f"flag name {name!r} cannot have spaces")
          if ch == "\\":
              raise ValueError(f"flag name {name!r} cannot have backslashes")
          if ch in forbidden:
              raise ValueError(
                  f"flag name {name!r} cannot have any of {forbidden!r} within them"
              )
  
  
  def get_flags(
      namespace: Dict[str, Any], globals: Dict[str, Any], locals: Dict[str, Any]
  ) -> Dict[str, Flag]:
      annotations = namespace.get("__annotations__", {})
      case_insensitive = namespace["__commands_flag_case_insensitive__"]
      flags: Dict[str, Flag] = {}
      cache: Dict[str, Any] = {}
      names: Set[str] = set()
      for name, annotation in annotations.items():
          flag = namespace.pop(name, MISSING)
          if isinstance(flag, Flag):
              flag.annotation = annotation
          else:
              flag = Flag(name=name, annotation=annotation, default=flag)
  
          flag.attribute = name
          if flag.name is MISSING:
              flag.name = name
  
          annotation = flag.annotation = resolve_annotation(
              flag.annotation, globals, locals, cache
          )
  
          if (
              flag.default is MISSING
              and hasattr(annotation, "__commands_is_flag__")
              and annotation._can_be_constructible()
          ):
              flag.default = annotation._construct_default
  
          if flag.aliases is MISSING:
              flag.aliases = []
  
          # Add sensible defaults based off of the type annotation
          # <type> -> (max_args=1)
          # List[str] -> (max_args=-1)
          # Tuple[int, ...] -> (max_args=1)
          # Dict[K, V] -> (max_args=-1, override=True)
          # Union[str, int] -> (max_args=1)
          # Optional[str] -> (default=None, max_args=1)
  
          try:
              origin = annotation.__origin__
          except AttributeError:
              # A regular type hint
              if flag.max_args is MISSING:
                  flag.max_args = 1
          else:
              if origin is Union:
                  # typing.Union
                  if flag.max_args is MISSING:
                      flag.max_args = 1
                  if annotation.__args__[-1] is type(None) and flag.default is MISSING:
                      # typing.Optional
                      flag.default = None
              elif origin is tuple:
                  # typing.Tuple
                  # tuple parsing is e.g. `flag: peter 20`
                  # for Tuple[str, int] would give you flag: ('peter', 20)
                  if flag.max_args is MISSING:
                      flag.max_args = 1
              elif origin is list:
                  # typing.List
                  if flag.max_args is MISSING:
                      flag.max_args = -1
              elif origin is dict:
                  # typing.Dict[K, V]
                  # Equivalent to:
                  # typing.List[typing.Tuple[K, V]]
                  flag.cast_to_dict = True
                  if flag.max_args is MISSING:
                      flag.max_args = -1
                  if flag.override is MISSING:
                      flag.override = True
              elif origin is Literal:
                  if flag.max_args is MISSING:
                      flag.max_args = 1
              else:
                  raise TypeError(
                      f"Unsupported typing annotation {annotation!r} for {flag.name!r} flag"
                  )
  
          if flag.override is MISSING:
              flag.override = False
  
          # Validate flag names are unique
          name = flag.name.casefold() if case_insensitive else flag.name
          if name in names:
              raise TypeError(
                  f"{flag.name!r} flag conflicts with previous flag or alias."
              )
          else:
              names.add(name)
  
          for alias in flag.aliases:
              # Validate alias is unique
              alias = alias.casefold() if case_insensitive else alias
              if alias in names:
                  raise TypeError(
                      f"{flag.name!r} flag alias {alias!r} conflicts with previous flag or alias."
                  )
              else:
                  names.add(alias)
  
          flags[flag.name] = flag
  
      return flags
  
  
  class FlagsMeta(type):
      if TYPE_CHECKING:
          __commands_is_flag__: bool
          __commands_flags__: Dict[str, Flag]
          __commands_flag_aliases__: Dict[str, str]
          __commands_flag_regex__: Pattern[str]
          __commands_flag_case_insensitive__: bool
          __commands_flag_delimiter__: str
          __commands_flag_prefix__: str
  
      def __new__(
          cls: Type[type],
          name: str,
          bases: Tuple[type, ...],
          attrs: Dict[str, Any],
          *,
          case_insensitive: bool = MISSING,
          delimiter: str = MISSING,
          prefix: str = MISSING,
      ):
          attrs["__commands_is_flag__"] = True
  
          try:
              global_ns = sys.modules[attrs["__module__"]].__dict__
          except KeyError:
              global_ns = {}
  
          frame = inspect.currentframe()
          try:
              if frame is None:
                  local_ns = {}
              else:
                  if frame.f_back is None:
                      local_ns = frame.f_locals
                  else:
                      local_ns = frame.f_back.f_locals
          finally:
              del frame
  
          flags: Dict[str, Flag] = {}
          aliases: Dict[str, str] = {}
          for base in reversed(bases):
              if base.__dict__.get("__commands_is_flag__", False):
                  flags.update(base.__dict__["__commands_flags__"])
                  aliases.update(base.__dict__["__commands_flag_aliases__"])
                  if case_insensitive is MISSING:
                      attrs["__commands_flag_case_insensitive__"] = base.__dict__[
                          "__commands_flag_case_insensitive__"
                      ]
                  if delimiter is MISSING:
                      attrs["__commands_flag_delimiter__"] = base.__dict__[
                          "__commands_flag_delimiter__"
                      ]
                  if prefix is MISSING:
                      attrs["__commands_flag_prefix__"] = base.__dict__[
                          "__commands_flag_prefix__"
                      ]
  
          if case_insensitive is not MISSING:
              attrs["__commands_flag_case_insensitive__"] = case_insensitive
          if delimiter is not MISSING:
              attrs["__commands_flag_delimiter__"] = delimiter
          if prefix is not MISSING:
              attrs["__commands_flag_prefix__"] = prefix
  
          case_insensitive = attrs.setdefault("__commands_flag_case_insensitive__", False)
          delimiter = attrs.setdefault("__commands_flag_delimiter__", ":")
          prefix = attrs.setdefault("__commands_flag_prefix__", "")
  
          for flag_name, flag in get_flags(attrs, global_ns, local_ns).items():
              flags[flag_name] = flag
              aliases.update({alias_name: flag_name for alias_name in flag.aliases})
  
          forbidden = set(delimiter).union(prefix)
          for flag_name in flags:
              validate_flag_name(flag_name, forbidden)
          for alias_name in aliases:
              validate_flag_name(alias_name, forbidden)
  
          regex_flags = 0
          if case_insensitive:
              flags = {key.casefold(): value for key, value in flags.items()}
              aliases = {
                  key.casefold(): value.casefold() for key, value in aliases.items()
              }
              regex_flags = re.IGNORECASE
  
          keys = list(re.escape(k) for k in flags)
          keys.extend(re.escape(a) for a in aliases)
          keys = sorted(keys, key=lambda t: len(t), reverse=True)
  
          joined = "|".join(keys)
          pattern = re.compile(
              f"(({re.escape(prefix)})(?P<flag>{joined}){re.escape(delimiter)})",
              regex_flags,
          )
          attrs["__commands_flag_regex__"] = pattern
          attrs["__commands_flags__"] = flags
          attrs["__commands_flag_aliases__"] = aliases
  
          return type.__new__(cls, name, bases, attrs)
  
  
  async def tuple_convert_all(
      ctx: Context, argument: str, flag: Flag, converter: Any
  ) -> Tuple[Any, ...]:
      view = StringView(argument)
      results = []
      param: inspect.Parameter = ctx.current_parameter  # type: ignore
      while not view.eof:
          view.skip_ws()
          if view.eof:
              break
  
          word = view.get_quoted_word()
          if word is None:
              break
  
          try:
              converted = await run_converters(ctx, converter, word, param)
          except CommandError:
              raise
          except Exception as e:
              raise BadFlagArgument(flag) from e
          else:
              results.append(converted)
  
      return tuple(results)
  
  
  async def tuple_convert_flag(
      ctx: Context, argument: str, flag: Flag, converters: Any
  ) -> Tuple[Any, ...]:
      view = StringView(argument)
      results = []
      param: inspect.Parameter = ctx.current_parameter  # type: ignore
      for converter in converters:
          view.skip_ws()
          if view.eof:
              break
  
          word = view.get_quoted_word()
          if word is None:
              break
  
          try:
              converted = await run_converters(ctx, converter, word, param)
          except CommandError:
              raise
          except Exception as e:
              raise BadFlagArgument(flag) from e
          else:
              results.append(converted)
  
      if len(results) != len(converters):
          raise BadFlagArgument(flag)
  
      return tuple(results)
  
  
  async def convert_flag(ctx, argument: str, flag: Flag, annotation: Any = None) -> Any:
      param: inspect.Parameter = ctx.current_parameter  # type: ignore
      annotation = annotation or flag.annotation
      try:
          origin = annotation.__origin__
      except AttributeError:
          pass
      else:
          if origin is tuple:
              if annotation.__args__[-1] is Ellipsis:
                  return await tuple_convert_all(
                      ctx, argument, flag, annotation.__args__[0]
                  )
              else:
                  return await tuple_convert_flag(
                      ctx, argument, flag, annotation.__args__
                  )
          elif origin is list:
              # typing.List[x]
              annotation = annotation.__args__[0]
              return await convert_flag(ctx, argument, flag, annotation)
          elif origin is Union and annotation.__args__[-1] is type(None):
              # typing.Optional[x]
              annotation = Union[annotation.__args__[:-1]]
              return await run_converters(ctx, annotation, argument, param)
          elif origin is dict:
              # typing.Dict[K, V] -> typing.Tuple[K, V]
              return await tuple_convert_flag(ctx, argument, flag, annotation.__args__)
  
      try:
          return await run_converters(ctx, annotation, argument, param)
      except CommandError:
          raise
      except Exception as e:
          raise BadFlagArgument(flag) from e
  
  
  F = TypeVar("F", bound="FlagConverter")
  
  
  class FlagConverter(metaclass=FlagsMeta):
      """A converter that allows for a user-friendly flag syntax.
  
      The flags are defined using :pep:`526` type annotations similar
      to the :mod:`dataclasses` Python module. For more information on
      how this converter works, check the appropriate
      :ref:`documentation <ext_commands_flag_converter>`.
  
      .. container:: operations
  
          .. describe:: iter(x)
  
              Returns an iterator of ``(flag_name, flag_value)`` pairs. This allows it
              to be, for example, constructed as a dict or a list of pairs.
              Note that aliases are not shown.
  
      .. versionadded:: 2.0
  
      Parameters
      -----------
      case_insensitive: :class:`bool`
          A class parameter to toggle case insensitivity of the flag parsing.
          If ``True`` then flags are parsed in a case insensitive manner.
          Defaults to ``False``.
      prefix: :class:`str`
          The prefix that all flags must be prefixed with. By default
          there is no prefix.
      delimiter: :class:`str`
          The delimiter that separates a flag's argument from the flag's name.
          By default this is ``:``.
      """
  
      @classmethod
      def get_flags(cls) -> Dict[str, Flag]:
          """Dict[:class:`str`, :class:`Flag`]: A mapping of flag name to flag object this converter has."""
          return cls.__commands_flags__.copy()
  
      @classmethod
      def _can_be_constructible(cls) -> bool:
          return all(not flag.required for flag in cls.__commands_flags__.values())
  
      def __iter__(self) -> Iterator[Tuple[str, Any]]:
          for flag in self.__class__.__commands_flags__.values():
              yield (flag.name, getattr(self, flag.attribute))
  
      @classmethod
      async def _construct_default(cls: Type[F], ctx: Context) -> F:
          self: F = cls.__new__(cls)
          flags = cls.__commands_flags__
          for flag in flags.values():
              if callable(flag.default):
                  default = await maybe_coroutine(flag.default, ctx)
                  setattr(self, flag.attribute, default)
              else:
                  setattr(self, flag.attribute, flag.default)
          return self
  
      def __repr__(self) -> str:
          pairs = " ".join(
              [
                  f"{flag.attribute}={getattr(self, flag.attribute)!r}"
                  for flag in self.get_flags().values()
              ]
          )
          return f"<{self.__class__.__name__} {pairs}>"
  
      @classmethod
      def parse_flags(cls, argument: str) -> Dict[str, List[str]]:
          result: Dict[str, List[str]] = {}
          flags = cls.__commands_flags__
          aliases = cls.__commands_flag_aliases__
          last_position = 0
          last_flag: Optional[Flag] = None
  
          case_insensitive = cls.__commands_flag_case_insensitive__
          for match in cls.__commands_flag_regex__.finditer(argument):
              begin, end = match.span(0)
              key = match.group("flag")
              if case_insensitive:
                  key = key.casefold()
  
              if key in aliases:
                  key = aliases[key]
  
              flag = flags.get(key)
              if last_position and last_flag is not None:
                  value = argument[last_position : begin - 1].lstrip()
                  if not value:
                      raise MissingFlagArgument(last_flag)
  
                  try:
                      values = result[last_flag.name]
                  except KeyError:
                      result[last_flag.name] = [value]
                  else:
                      values.append(value)
  
              last_position = end
              last_flag = flag
  
          # Add the remaining string to the last available flag
          if last_position and last_flag is not None:
              value = argument[last_position:].strip()
              if not value:
                  raise MissingFlagArgument(last_flag)
  
              try:
                  values = result[last_flag.name]
              except KeyError:
                  result[last_flag.name] = [value]
              else:
                  values.append(value)
  
          # Verification of values will come at a later stage
          return result
  
      @classmethod
      def get_flag_signature(cls):
          # Format: <flagName: value>  [anotherFlag: values*] [yetanotherFlag: value]*
          flags = cls.__commands_flags__
          result = []
          for name, flag in flags.items():
  
              annotation = flag.annotation
              origin = getattr(annotation, "__origin__", None)
  
              _type = flag.type or resolve_signature_string(annotation, origin)
              if flag.noneable:
                  _type = f'{_type}|"None"'
  
              optional = flag.default is not None or (type(None) in annotation.__args__ if hasattr(annotation, "__args__") else False) 
  
              if optional:
                  if origin is tuple:
                      result.append(f"[{name}: {_type}*]")
                  elif origin is list:
                      result.append(f"[{name}: {_type}]*")
                  else:
                      result.append(f"[{name}: {_type}]")
              else:
                  if origin is tuple:
                      result.append(f"<{name}: {_type}*>")
                  elif origin is list:
                      result.append(f"<{name}: {_type}>*")
                  else:
                      result.append(f"<{name}: {_type}>")
  
          return " ".join(result)
  
      @classmethod
      async def convert(cls: Type[F], ctx: Context, argument: str) -> F:
          """|coro|
  
          The method that actually converters an argument to the flag mapping.
  
          Parameters
          ----------
          cls: Type[:class:`FlagConverter`]
              The flag converter class.
          ctx: :class:`Context`
              The invocation context.
          argument: :class:`str`
              The argument to convert from.
  
          Raises
          --------
          FlagError
              A flag related parsing error.
          CommandError
              A command related error.
  
          Returns
          --------
          :class:`FlagConverter`
              The flag converter instance with all flags parsed.
          """
          arguments = cls.parse_flags(argument)
          flags = cls.__commands_flags__
  
          self: F = cls.__new__(cls)
          for name, flag in flags.items():
              try:
                  values = arguments[name]
              except KeyError:
                  if flag.required:
                      raise MissingRequiredFlag(flag)
                  else:
                      if callable(flag.default):
                          default = await maybe_coroutine(flag.default, ctx)
                          setattr(self, flag.attribute, default)
                      else:
                          setattr(self, flag.attribute, flag.default)
                      continue
  
              if flag.max_args > 0 and len(values) > flag.max_args:
                  if flag.override:
                      values = values[-flag.max_args :]
                  else:
                      raise TooManyFlags(flag, values)
  
              # Special case:
              if flag.max_args == 1:
                  value = await convert_flag(ctx, values[0], flag)
                  setattr(self, flag.attribute, value)
                  continue
  
              # Another special case, tuple parsing.
              # Tuple parsing is basically converting arguments within the flag
              # So, given flag: hello 20 as the input and Tuple[str, int] as the type hint
              # We would receive ('hello', 20) as the resulting value
              # This uses the same whitespace and quoting rules as regular parameters.
              values = [await convert_flag(ctx, value, flag) for value in values]
  
              if flag.cast_to_dict:
                  values = dict(values)  # type: ignore
  
              if flag.noneable and any([value.lower() == "none" for value in values]):
                  values = None
  
              setattr(self, flag.attribute, values)
  
          return self
  