text: # -*- coding: utf-8 -*-
  
  """
  The MIT License (MIT)
  
  Copyright (c) 2015-2020 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.
  """
  
  import copy
  from collections import namedtuple, defaultdict
  
  from . import utils
  from .role import Role
  from .member import Member, VoiceState
  from .activity import create_activity
  from .emoji import Emoji
  from .errors import InvalidData
  from .permissions import PermissionOverwrite
  from .colour import Colour
  from .errors import InvalidArgument, ClientException
  from .channel import *
  from .enums import VoiceRegion, Status, ChannelType, try_enum, VerificationLevel, ContentFilter, NotificationLevel
  from .mixins import Hashable
  from .user import User
  from .invite import Invite
  from .iterators import AuditLogIterator, MemberIterator
  from .webhook import Webhook
  from .widget import Widget
  from .asset import Asset
  from .flags import SystemChannelFlags
  
  BanEntry = namedtuple('BanEntry', 'reason user')
  _GuildLimit = namedtuple('_GuildLimit', 'emoji bitrate filesize')
  
  
  class Guild(Hashable):
      """Represents a Discord guild.
  
      This is referred to as a "server" in the official Discord UI.
  
      .. container:: operations
  
          .. describe:: x == y
  
              Checks if two guilds are equal.
  
          .. describe:: x != y
  
              Checks if two guilds are not equal.
  
          .. describe:: hash(x)
  
              Returns the guild's hash.
  
          .. describe:: str(x)
  
              Returns the guild's name.
  
      Attributes
      ----------
      name: :class:`str`
          The guild name.
      emojis: Tuple[:class:`Emoji`, ...]
          All emojis that the guild owns.
      region: :class:`VoiceRegion`
          The region the guild belongs on. There is a chance that the region
          will be a :class:`str` if the value is not recognised by the enumerator.
      afk_timeout: :class:`int`
          The timeout to get sent to the AFK channel.
      afk_channel: Optional[:class:`VoiceChannel`]
          The channel that denotes the AFK channel. None if it doesn't exist.
      icon: Optional[:class:`str`]
          The guild's icon.
      id: :class:`int`
          The guild's ID.
      owner_id: :class:`int`
          The guild owner's ID. Use :attr:`Guild.owner` instead.
      unavailable: :class:`bool`
          Indicates if the guild is unavailable. If this is ``True`` then the
          reliability of other attributes outside of :meth:`Guild.id` is slim and they might
          all be None. It is best to not do anything with the guild if it is unavailable.
  
          Check the :func:`on_guild_unavailable` and :func:`on_guild_available` events.
      max_presences: Optional[:class:`int`]
          The maximum amount of presences for the guild.
      max_members: Optional[:class:`int`]
          The maximum amount of members for the guild.
      banner: Optional[:class:`str`]
          The guild's banner.
      description: Optional[:class:`str`]
          The guild's description.
      mfa_level: :class:`int`
          Indicates the guild's two factor authorisation level. If this value is 0 then
          the guild does not require 2FA for their administrative members. If the value is
          1 then they do.
      verification_level: :class:`VerificationLevel`
          The guild's verification level.
      explicit_content_filter: :class:`ContentFilter`
          The guild's explicit content filter.
      default_notifications: :class:`NotificationLevel`
          The guild's notification settings.
      features: List[:class:`str`]
          A list of features that the guild has. They are currently as follows:
  
          - ``VIP_REGIONS``: Guild has VIP voice regions
          - ``VANITY_URL``: Guild can have a vanity invite URL (e.g. discord.gg/discord-api)
          - ``INVITE_SPLASH``: Guild's invite page can have a special splash.
          - ``VERIFIED``: Guild is a verified server.
          - ``PARTNERED``: Guild is a partnered server.
          - ``MORE_EMOJI``: Guild is allowed to have more than 50 custom emoji.
          - ``DISCOVERABLE``: Guild shows up in Server Discovery.
          - ``COMMERCE``: Guild can sell things using store channels.
          - ``PUBLIC``: Users can lurk in this guild via Server Discovery.
          - ``NEWS``: Guild can create news channels.
          - ``BANNER``: Guild can upload and use a banner (i.e. :meth:`banner_url`).
          - ``ANIMATED_ICON``: Guild can upload an animated icon.
          - ``PUBLIC_DISABLED``: Guild cannot be public.
  
      splash: Optional[:class:`str`]
          The guild's invite splash.
      premium_tier: :class:`int`
          The premium tier for this guild. Corresponds to "Nitro Server" in the official UI.
          The number goes from 0 to 3 inclusive.
      premium_subscription_count: :class:`int`
          How many users have currently "boosted" this guild.
      preferred_locale: Optional[:class:`str`]
          The preferred locale for the guild. Used when filtering Server Discovery
          results to a specific language.
      discovery_splash: :class:`str`
          The guild's discovery splash.
  
          .. versionadded:: 1.3
      """
  
      __slots__ = ('afk_timeout', 'afk_channel', '_members', '_channels', 'icon',
                   'name', 'id', 'unavailable', 'banner', 'region', '_state',
                   '_roles', '_member_count', '_large',
                   'owner_id', 'mfa_level', 'emojis', 'features',
                   'verification_level', 'explicit_content_filter', 'splash',
                   '_voice_states', '_system_channel_id', 'default_notifications',
                   'description', 'max_presences', 'max_members', 'premium_tier',
                   'premium_subscription_count', '_system_channel_flags',
                   'preferred_locale', 'discovery_splash', '_rules_channel_id')
  
      _PREMIUM_GUILD_LIMITS = {
          None: _GuildLimit(emoji=50, bitrate=96e3, filesize=8388608),
          0: _GuildLimit(emoji=50, bitrate=96e3, filesize=8388608),
          1: _GuildLimit(emoji=100, bitrate=128e3, filesize=8388608),
          2: _GuildLimit(emoji=150, bitrate=256e3, filesize=52428800),
          3: _GuildLimit(emoji=250, bitrate=384e3, filesize=104857600),
      }
  
      def __init__(self, *, data, state):
          self._channels = {}
          self._members = {}
          self._voice_states = {}
          self._state = state
          self._from_data(data)
  
      def _add_channel(self, channel):
          self._channels[channel.id] = channel
  
      def _remove_channel(self, channel):
          self._channels.pop(channel.id, None)
  
      def _voice_state_for(self, user_id):
          return self._voice_states.get(user_id)
  
      def _add_member(self, member):
          self._members[member.id] = member
  
      def _remove_member(self, member):
          self._members.pop(member.id, None)
  
      def __str__(self):
          return self.name
  
      def __repr__(self):
          attrs = (
              'id', 'name', 'shard_id', 'chunked'
          )
          resolved = ['%s=%r' % (attr, getattr(self, attr)) for attr in attrs]
          resolved.append('member_count=%r' % getattr(self, '_member_count', None))
          return '<Guild %s>' % ' '.join(resolved)
  
      def _update_voice_state(self, data, channel_id):
          user_id = int(data['user_id'])
          channel = self.get_channel(channel_id)
          try:
              # check if we should remove the voice state from cache
              if channel is None:
                  after = self._voice_states.pop(user_id)
              else:
                  after = self._voice_states[user_id]
  
              before = copy.copy(after)
              after._update(data, channel)
          except KeyError:
              # if we're here then we're getting added into the cache
              after = VoiceState(data=data, channel=channel)
              before = VoiceState(data=data, channel=None)
              self._voice_states[user_id] = after
  
          member = self.get_member(user_id)
          if member is None:
              try:
                  member = Member(data=data['member'], state=self._state, guild=self)
              except KeyError:
                  member = None
  
          return member, before, after
  
      def _add_role(self, role):
          # roles get added to the bottom (position 1, pos 0 is @everyone)
          # so since self.roles has the @everyone role, we can't increment
          # its position because it's stuck at position 0. Luckily x += False
          # is equivalent to adding 0. So we cast the position to a bool and
          # increment it.
          for r in self._roles.values():
              r.position += (not r.is_default())
  
          self._roles[role.id] = role
  
      def _remove_role(self, role_id):
          # this raises KeyError if it fails..
          role = self._roles.pop(role_id)
  
          # since it didn't, we can change the positions now
          # basically the same as above except we only decrement
          # the position if we're above the role we deleted.
          for r in self._roles.values():
              r.position -= r.position > role.position
  
          return role
  
      def _from_data(self, guild):
          # according to Stan, this is always available even if the guild is unavailable
          # I don't have this guarantee when someone updates the guild.
          member_count = guild.get('member_count', None)
          if member_count:
              self._member_count = member_count
  
          self.name = guild.get('name')
          self.region = try_enum(VoiceRegion, guild.get('region'))
          self.verification_level = try_enum(VerificationLevel, guild.get('verification_level'))
          self.default_notifications = try_enum(NotificationLevel, guild.get('default_message_notifications'))
          self.explicit_content_filter = try_enum(ContentFilter, guild.get('explicit_content_filter', 0))
          self.afk_timeout = guild.get('afk_timeout')
          self.icon = guild.get('icon')
          self.banner = guild.get('banner')
          self.unavailable = guild.get('unavailable', False)
          self.id = int(guild['id'])
          self._roles = {}
          state = self._state # speed up attribute access
          for r in guild.get('roles', []):
              role = Role(guild=self, data=r, state=state)
              self._roles[role.id] = role
  
          self.mfa_level = guild.get('mfa_level')
          self.emojis = tuple(map(lambda d: state.store_emoji(self, d), guild.get('emojis', [])))
          self.features = guild.get('features', [])
          self.splash = guild.get('splash')
          self._system_channel_id = utils._get_as_snowflake(guild, 'system_channel_id')
          self.description = guild.get('description')
          self.max_presences = guild.get('max_presences')
          self.max_members = guild.get('max_members')
          self.premium_tier = guild.get('premium_tier', 0)
          self.premium_subscription_count = guild.get('premium_subscription_count') or 0
          self._system_channel_flags = guild.get('system_channel_flags', 0)
          self.preferred_locale = guild.get('preferred_locale')
          self.discovery_splash = guild.get('discovery_splash')
          self._rules_channel_id = utils._get_as_snowflake(guild, 'rules_channel_id')
  
          for mdata in guild.get('members', []):
              member = Member(data=mdata, guild=self, state=state)
              self._add_member(member)
  
          self._sync(guild)
          self._large = None if member_count is None else self._member_count >= 250
  
          self.owner_id = utils._get_as_snowflake(guild, 'owner_id')
          self.afk_channel = self.get_channel(utils._get_as_snowflake(guild, 'afk_channel_id'))
  
          for obj in guild.get('voice_states', []):
              self._update_voice_state(obj, int(obj['channel_id']))
  
      def _sync(self, data):
          try:
              self._large = data['large']
          except KeyError:
              pass
  
          empty_tuple = tuple()
          for presence in data.get('presences', []):
              user_id = int(presence['user']['id'])
              member = self.get_member(user_id)
              if member is not None:
                  member._presence_update(presence, empty_tuple)
  
          if 'channels' in data:
              channels = data['channels']
              for c in channels:
                  c_type = c['type']
                  if c_type in (ChannelType.text.value, ChannelType.news.value):
                      self._add_channel(TextChannel(guild=self, data=c, state=self._state))
                  elif c_type == ChannelType.voice.value:
                      self._add_channel(VoiceChannel(guild=self, data=c, state=self._state))
                  elif c_type == ChannelType.category.value:
                      self._add_channel(CategoryChannel(guild=self, data=c, state=self._state))
                  elif c_type == ChannelType.store.value:
                      self._add_channel(StoreChannel(guild=self, data=c, state=self._state))
  
      @property
      def channels(self):
          """List[:class:`abc.GuildChannel`]: A list of channels that belongs to this guild."""
          return list(self._channels.values())
  
      @property
      def large(self):
          """:class:`bool`: Indicates if the guild is a 'large' guild.
  
          A large guild is defined as having more than ``large_threshold`` count
          members, which for this library is set to the maximum of 250.
          """
          if self._large is None:
              try:
                  return self._member_count >= 250
              except AttributeError:
                  return len(self._members) >= 250
          return self._large
  
      @property
      def voice_channels(self):
          """List[:class:`VoiceChannel`]: A list of voice channels that belongs to this guild.
  
          This is sorted by the position and are in UI order from top to bottom.
          """
          r = [ch for ch in self._channels.values() if isinstance(ch, VoiceChannel)]
          r.sort(key=lambda c: (c.position, c.id))
          return r
  
      @property
      def me(self):
          """Similar to :attr:`Client.user` except an instance of :class:`Member`.
          This is essentially used to get the member version of yourself.
          """
          self_id = self._state.user.id
          return self.get_member(self_id)
  
      @property
      def voice_client(self):
          """Returns the :class:`VoiceClient` associated with this guild, if any."""
          return self._state._get_voice_client(self.id)
  
      @property
      def text_channels(self):
          """List[:class:`TextChannel`]: A list of text channels that belongs to this guild.
  
          This is sorted by the position and are in UI order from top to bottom.
          """
          r = [ch for ch in self._channels.values() if isinstance(ch, TextChannel)]
          r.sort(key=lambda c: (c.position, c.id))
          return r
  
      @property
      def categories(self):
          """List[:class:`CategoryChannel`]: A list of categories that belongs to this guild.
  
          This is sorted by the position and are in UI order from top to bottom.
          """
          r = [ch for ch in self._channels.values() if isinstance(ch, CategoryChannel)]
          r.sort(key=lambda c: (c.position, c.id))
          return r
  
      def by_category(self):
          """Returns every :class:`CategoryChannel` and their associated channels.
  
          These channels and categories are sorted in the official Discord UI order.
  
          If the channels do not have a category, then the first element of the tuple is
          ``None``.
  
          Returns
          --------
          List[Tuple[Optional[:class:`CategoryChannel`], List[:class:`abc.GuildChannel`]]]:
              The categories and their associated channels.
          """
          grouped = defaultdict(list)
          for channel in self._channels.values():
              if isinstance(channel, CategoryChannel):
                  continue
  
              grouped[channel.category_id].append(channel)
  
          def key(t):
              k, v = t
              return ((k.position, k.id) if k else (-1, -1), v)
  
          _get = self._channels.get
          as_list = [(_get(k), v) for k, v in grouped.items()]
          as_list.sort(key=key)
          for _, channels in as_list:
              channels.sort(key=lambda c: (c._sorting_bucket, c.position, c.id))
          return as_list
  
      def get_channel(self, channel_id):
          """Returns a channel with the given ID.
  
          Parameters
          -----------
          channel_id: :class:`int`
              The ID to search for.
  
          Returns
          --------
          Optional[:class:`.abc.GuildChannel`]
              The returned channel or ``None`` if not found.
          """
          return self._channels.get(channel_id)
  
      @property
      def system_channel(self):
          """Optional[:class:`TextChannel`]: Returns the guild's channel used for system messages.
  
          If no channel is set, then this returns ``None``.
          """
          channel_id = self._system_channel_id
          return channel_id and self._channels.get(channel_id)
  
      @property
      def system_channel_flags(self):
          """:class:`SystemChannelFlags`: Returns the guild's system channel settings."""
          return SystemChannelFlags._from_value(self._system_channel_flags)
  
      @property
      def rules_channel(self):
          """Optional[:class:`TextChannel`]: Return's the guild's channel used for the rules.
          Must be a discoverable guild.
  
          If no channel is set, then this returns ``None``.
  
          .. versionadded:: 1.3
          """
          channel_id = self._rules_channel_id
          return channel_id and self._channels.get(channel_id)
  
      @property
      def emoji_limit(self):
          """:class:`int`: The maximum number of emoji slots this guild has."""
          more_emoji = 200 if 'MORE_EMOJI' in self.features else 50
          return max(more_emoji, self._PREMIUM_GUILD_LIMITS[self.premium_tier].emoji)
  
      @property
      def bitrate_limit(self):
          """:class:`float`: The maximum bitrate for voice channels this guild can have."""
          vip_guild = self._PREMIUM_GUILD_LIMITS[1].bitrate if 'VIP_REGIONS' in self.features else 96e3
          return max(vip_guild, self._PREMIUM_GUILD_LIMITS[self.premium_tier].bitrate)
  
      @property
      def filesize_limit(self):
          """:class:`int`: The maximum number of bytes files can have when uploaded to this guild."""
          return self._PREMIUM_GUILD_LIMITS[self.premium_tier].filesize
  
      @property
      def members(self):
          """List[:class:`Member`]: A list of members that belong to this guild."""
          return list(self._members.values())
  
      def get_member(self, user_id):
          """Returns a member with the given ID.
  
          Parameters
          -----------
          user_id: :class:`int`
              The ID to search for.
  
          Returns
          --------
          Optional[:class:`Member`]
              The member or ``None`` if not found.
          """
          return self._members.get(user_id)
  
      @property
      def premium_subscribers(self):
          """List[:class:`Member`]: A list of members who have "boosted" this guild."""
          return [member for member in self.members if member.premium_since is not None]
  
      @property
      def roles(self):
          """Returns a :class:`list` of the guild's roles in hierarchy order.
  
          The first element of this list will be the lowest role in the
          hierarchy.
          """
          return sorted(self._roles.values())
  
      def get_role(self, role_id):
          """Returns a role with the given ID.
  
          Parameters
          -----------
          role_id: :class:`int`
              The ID to search for.
  
          Returns
          --------
          Optional[:class:`Role`]
              The role or ``None`` if not found.
          """
          return self._roles.get(role_id)
  
      @property
      def default_role(self):
          """Gets the @everyone role that all members have by default."""
          return self.get_role(self.id)
  
      @property
      def owner(self):
          """:class:`Member`: The member that owns the guild."""
          return self.get_member(self.owner_id)
  
      @property
      def icon_url(self):
          """:class:`Asset`: Returns the guild's icon asset."""
          return self.icon_url_as()
  
      def is_icon_animated(self):
          """:class:`bool`: Returns True if the guild has an animated icon."""
          return bool(self.icon and self.icon.startswith('a_'))
  
      def icon_url_as(self, *, format=None, static_format='webp', size=1024):
          """Returns an :class:`Asset` for the guild's icon.
  
          The format must be one of 'webp', 'jpeg', 'jpg', 'png' or 'gif', and
          'gif' is only valid for animated avatars. The size must be a power of 2
          between 16 and 4096.
  
          Parameters
          -----------
          format: Optional[:class:`str`]
              The format to attempt to convert the icon to.
              If the format is ``None``, then it is automatically
              detected into either 'gif' or static_format depending on the
              icon being animated or not.
          static_format: Optional[:class:`str`]
              Format to attempt to convert only non-animated icons to.
          size: :class:`int`
              The size of the image to display.
  
          Raises
          ------
          InvalidArgument
              Bad image format passed to ``format`` or invalid ``size``.
  
          Returns
          --------
          :class:`Asset`
              The resulting CDN asset.
          """
          return Asset._from_guild_icon(self._state, self, format=format, static_format=static_format, size=size)
  
      @property
      def banner_url(self):
          """:class:`Asset`: Returns the guild's banner asset."""
          return self.banner_url_as()
  
      def banner_url_as(self, *, format='webp', size=2048):
          """Returns an :class:`Asset` for the guild's banner.
  
          The format must be one of 'webp', 'jpeg', or 'png'. The
          size must be a power of 2 between 16 and 4096.
  
          Parameters
          -----------
          format: :class:`str`
              The format to attempt to convert the banner to.
          size: :class:`int`
              The size of the image to display.
  
          Raises
          ------
          InvalidArgument
              Bad image format passed to ``format`` or invalid ``size``.
  
          Returns
          --------
          :class:`Asset`
              The resulting CDN asset.
          """
          return Asset._from_guild_image(self._state, self.id, self.banner, 'banners', format=format, size=size)
  
      @property
      def splash_url(self):
          """:class:`Asset`: Returns the guild's invite splash asset."""
          return self.splash_url_as()
  
      def splash_url_as(self, *, format='webp', size=2048):
          """Returns an :class:`Asset` for the guild's invite splash.
  
          The format must be one of 'webp', 'jpeg', 'jpg', or 'png'. The
          size must be a power of 2 between 16 and 4096.
  
          Parameters
          -----------
          format: :class:`str`
              The format to attempt to convert the splash to.
          size: :class:`int`
              The size of the image to display.
  
          Raises
          ------
          InvalidArgument
              Bad image format passed to ``format`` or invalid ``size``.
  
          Returns
          --------
          :class:`Asset`
              The resulting CDN asset.
          """
          return Asset._from_guild_image(self._state, self.id, self.splash, 'splashes', format=format, size=size)
  
      @property
      def discovery_splash_url(self):
          """:class:`Asset`: Returns the guild's discovery splash asset.
  
          .. versionadded:: 1.3
          """
          return self.discovery_splash_url_as()
  
      def discovery_splash_url_as(self, *, format='webp', size=2048):
          """Returns an :class:`Asset` for the guild's discovery splash.
  
          The format must be one of 'webp', 'jpeg', 'jpg', or 'png'. The
          size must be a power of 2 between 16 and 4096.
  
          .. versionadded:: 1.3
  
          Parameters
          -----------
          format: :class:`str`
              The format to attempt to convert the splash to.
          size: :class:`int`
              The size of the image to display.
  
          Raises
          ------
          InvalidArgument
              Bad image format passed to ``format`` or invalid ``size``.
  
          Returns
          --------
          :class:`Asset`
              The resulting CDN asset.
          """
          return Asset._from_guild_image(self._state, self.id, self.discovery_splash, 'discovery-splashes', format=format, size=size)
  
      @property
      def member_count(self):
          """Returns the true member count regardless of it being loaded fully or not."""
          return self._member_count
  
      @property
      def chunked(self):
          """Returns a boolean indicating if the guild is "chunked".
  
          A chunked guild means that :attr:`member_count` is equal to the
          number of members stored in the internal :attr:`members` cache.
  
          If this value returns ``False``, then you should request for
          offline members.
          """
          count = getattr(self, '_member_count', None)
          if count is None:
              return False
          return count == len(self._members)
  
      @property
      def shard_id(self):
          """:class:`int`: Returns the shard ID for this guild if applicable."""
          count = self._state.shard_count
          if count is None:
              return None
          return (self.id >> 22) % count
  
      @property
      def created_at(self):
          """:class:`datetime.datetime`: Returns the guild's creation time in UTC."""
          return utils.snowflake_time(self.id)
  
      def get_member_named(self, name):
          """Returns the first member found that matches the name provided.
  
          The name can have an optional discriminator argument, e.g. "Jake#0001"
          or "Jake" will both do the lookup. However the former will give a more
          precise result. Note that the discriminator must have all 4 digits
          for this to work.
  
          If a nickname is passed, then it is looked up via the nickname. Note
          however, that a nickname + discriminator combo will not lookup the nickname
          but rather the username + discriminator combo due to nickname + discriminator
          not being unique.
  
          If no member is found, ``None`` is returned.
  
          Parameters
          -----------
          name: :class:`str`
              The name of the member to lookup with an optional discriminator.
  
          Returns
          --------
          :class:`Member`
              The member in this guild with the associated name. If not found
              then ``None`` is returned.
          """
  
          result = None
          members = self.members
          if len(name) > 5 and name[-5] == '#':
              # The 5 length is checking to see if #0000 is in the string,
              # as a#0000 has a length of 6, the minimum for a potential
              # discriminator lookup.
              potential_discriminator = name[-4:]
  
              # do the actual lookup and return if found
              # if it isn't found then we'll do a full name lookup below.
              result = utils.get(members, name=name[:-5], discriminator=potential_discriminator)
              if result is not None:
                  return result
  
          def pred(m):
              return m.nick == name or m.name == name
  
          return utils.find(pred, members)
  
      def _create_channel(self, name, overwrites, channel_type, category=None, **options):
          if overwrites is None:
              overwrites = {}
          elif not isinstance(overwrites, dict):
              raise InvalidArgument('overwrites parameter expects a dict.')
  
          perms = []
          for target, perm in overwrites.items():
              if not isinstance(perm, PermissionOverwrite):
                  raise InvalidArgument('Expected PermissionOverwrite received {0.__name__}'.format(type(perm)))
  
              allow, deny = perm.pair()
              payload = {
                  'allow': allow.value,
                  'deny': deny.value,
                  'id': target.id
              }
  
              if isinstance(target, Role):
                  payload['type'] = 'role'
              else:
                  payload['type'] = 'member'
  
              perms.append(payload)
  
          try:
              options['rate_limit_per_user'] = options.pop('slowmode_delay')
          except KeyError:
              pass
  
          parent_id = category.id if category else None
          return self._state.http.create_channel(self.id, channel_type.value, name=name, parent_id=parent_id,
                                                 permission_overwrites=perms, **options)
  
      async def create_text_channel(self, name, *, overwrites=None, category=None, reason=None, **options):
          """|coro|
  
          Creates a :class:`TextChannel` for the guild.
  
          Note that you need the :attr:`~Permissions.manage_channels` permission
          to create the channel.
  
          The ``overwrites`` parameter can be used to create a 'secret'
          channel upon creation. This parameter expects a :class:`dict` of
          overwrites with the target (either a :class:`Member` or a :class:`Role`)
          as the key and a :class:`PermissionOverwrite` as the value.
  
          .. note::
  
              Creating a channel of a specified position will not update the position of
              other channels to follow suit. A follow-up call to :meth:`~TextChannel.edit`
              will be required to update the position of the channel in the channel list.
  
          Examples
          ----------
  
          Creating a basic channel:
  
          .. code-block:: python3
  
              channel = await guild.create_text_channel('cool-channel')
  
          Creating a "secret" channel:
  
          .. code-block:: python3
  
              overwrites = {
                  guild.default_role: discord.PermissionOverwrite(read_messages=False),
                  guild.me: discord.PermissionOverwrite(read_messages=True)
              }
  
              channel = await guild.create_text_channel('secret', overwrites=overwrites)
  
          Parameters
          -----------
          name: :class:`str`
              The channel's name.
          overwrites
              A :class:`dict` of target (either a role or a member) to
              :class:`PermissionOverwrite` to apply upon creation of a channel.
              Useful for creating secret channels.
          category: Optional[:class:`CategoryChannel`]
              The category to place the newly created channel under.
              The permissions will be automatically synced to category if no
              overwrites are provided.
          position: :class:`int`
              The position in the channel list. This is a number that starts
              at 0. e.g. the top channel is position 0.
          topic: Optional[:class:`str`]
              The new channel's topic.
          slowmode_delay: :class:`int`
              Specifies the slowmode rate limit for user in this channel, in seconds.
              The maximum value possible is `21600`.
          nsfw: :class:`bool`
              To mark the channel as NSFW or not.
          reason: Optional[:class:`str`]
              The reason for creating this channel. Shows up on the audit log.
  
          Raises
          -------
          Forbidden
              You do not have the proper permissions to create this channel.
          HTTPException
              Creating the channel failed.
          InvalidArgument
              The permission overwrite information is not in proper form.
  
          Returns
          -------
          :class:`TextChannel`
              The channel that was just created.
          """
          data = await self._create_channel(name, overwrites, ChannelType.text, category, reason=reason, **options)
          channel = TextChannel(state=self._state, guild=self, data=data)
  
          # temporarily add to the cache
          self._channels[channel.id] = channel
          return channel
  
      async def create_voice_channel(self, name, *, overwrites=None, category=None, reason=None, **options):
          """|coro|
  
          This is similar to :meth:`create_text_channel` except makes a :class:`VoiceChannel` instead, in addition
          to having the following new parameters.
  
          Parameters
          -----------
          bitrate: :class:`int`
              The channel's preferred audio bitrate in bits per second.
          user_limit: :class:`int`
              The channel's limit for number of members that can be in a voice channel.
          """
          data = await self._create_channel(name, overwrites, ChannelType.voice, category, reason=reason, **options)
          channel = VoiceChannel(state=self._state, guild=self, data=data)
  
          # temporarily add to the cache
          self._channels[channel.id] = channel
          return channel
  
      async def create_category(self, name, *, overwrites=None, reason=None, position=None):
          """|coro|
  
          Same as :meth:`create_text_channel` except makes a :class:`CategoryChannel` instead.
  
          .. note::
  
              The ``category`` parameter is not supported in this function since categories
              cannot have categories.
          """
          data = await self._create_channel(name, overwrites, ChannelType.category, reason=reason, position=position)
          channel = CategoryChannel(state=self._state, guild=self, data=data)
  
          # temporarily add to the cache
          self._channels[channel.id] = channel
          return channel
  
      create_category_channel = create_category
  
      async def leave(self):
          """|coro|
  
          Leaves the guild.
  
          .. note::
  
              You cannot leave the guild that you own, you must delete it instead
              via :meth:`delete`.
  
          Raises
          --------
          HTTPException
              Leaving the guild failed.
          """
          await self._state.http.leave_guild(self.id)
  
      async def delete(self):
          """|coro|
  
          Deletes the guild. You must be the guild owner to delete the
          guild.
  
          Raises
          --------
          HTTPException
              Deleting the guild failed.
          Forbidden
              You do not have permissions to delete the guild.
          """
  
          await self._state.http.delete_guild(self.id)
  
      async def edit(self, *, reason=None, **fields):
          """|coro|
  
          Edits the guild.
  
          You must have the :attr:`~Permissions.manage_guild` permission
          to edit the guild.
  
          Parameters
          ----------
          name: :class:`str`
              The new name of the guild.
          description: :class:`str`
              The new description of the guild. This is only available to guilds that
              contain `VERIFIED` in :attr:`Guild.features`.
          icon: :class:`bytes`
              A :term:`py:bytes-like object` representing the icon. Only PNG/JPEG supported
              and GIF for guilds with ``ANIMATED_ICON`` feature.
              Could be ``None`` to denote removal of the icon.
          banner: :class:`bytes`
              A :term:`py:bytes-like object` representing the banner.
              Could be ``None`` to denote removal of the banner.
          splash: :class:`bytes`
              A :term:`py:bytes-like object` representing the invite splash.
              Only PNG/JPEG supported. Could be ``None`` to denote removing the
              splash. Only available for partnered guilds with ``INVITE_SPLASH``
              feature.
          region: :class:`VoiceRegion`
              The new region for the guild's voice communication.
          afk_channel: Optional[:class:`VoiceChannel`]
              The new channel that is the AFK channel. Could be ``None`` for no AFK channel.
          afk_timeout: :class:`int`
              The number of seconds until someone is moved to the AFK channel.
          owner: :class:`Member`
              The new owner of the guild to transfer ownership to. Note that you must
              be owner of the guild to do this.
          verification_level: :class:`VerificationLevel`
              The new verification level for the guild.
          default_notifications: :class:`NotificationLevel`
              The new default notification level for the guild.
          explicit_content_filter: :class:`ContentFilter`
              The new explicit content filter for the guild.
          vanity_code: :class:`str`
              The new vanity code for the guild.
          system_channel: Optional[:class:`TextChannel`]
              The new channel that is used for the system channel. Could be ``None`` for no system channel.
          system_channel_flags: :class:`SystemChannelFlags`
              The new system channel settings to use with the new system channel.
          reason: Optional[:class:`str`]
              The reason for editing this guild. Shows up on the audit log.
  
          Raises
          -------
          Forbidden
              You do not have permissions to edit the guild.
          HTTPException
              Editing the guild failed.
          InvalidArgument
              The image format passed in to ``icon`` is invalid. It must be
              PNG or JPG. This is also raised if you are not the owner of the
              guild and request an ownership transfer.
          """
  
          http = self._state.http
          try:
              icon_bytes = fields['icon']
          except KeyError:
              icon = self.icon
          else:
              if icon_bytes is not None:
                  icon = utils._bytes_to_base64_data(icon_bytes)
              else:
                  icon = None
  
          try:
              banner_bytes = fields['banner']
          except KeyError:
              banner = self.banner
          else:
              if banner_bytes is not None:
                  banner = utils._bytes_to_base64_data(banner_bytes)
              else:
                  banner = None
  
          try:
              vanity_code = fields['vanity_code']
          except KeyError:
              pass
          else:
              await http.change_vanity_code(self.id, vanity_code, reason=reason)
  
          try:
              splash_bytes = fields['splash']
          except KeyError:
              splash = self.splash
          else:
              if splash_bytes is not None:
                  splash = utils._bytes_to_base64_data(splash_bytes)
              else:
                  splash = None
  
          fields['icon'] = icon
          fields['banner'] = banner
          fields['splash'] = splash
  
          try:
              default_message_notifications = int(fields.pop('default_notifications'))
          except (TypeError, KeyError):
              pass
          else:
              fields['default_message_notifications'] = default_message_notifications
  
          try:
              afk_channel = fields.pop('afk_channel')
          except KeyError:
              pass
          else:
              if afk_channel is None:
                  fields['afk_channel_id'] = afk_channel
              else:
                  fields['afk_channel_id'] = afk_channel.id
  
          try:
              system_channel = fields.pop('system_channel')
          except KeyError:
              pass
          else:
              if system_channel is None:
                  fields['system_channel_id'] = system_channel
              else:
                  fields['system_channel_id'] = system_channel.id
  
          if 'owner' in fields:
              if self.owner_id != self._state.self_id:
                  raise InvalidArgument('To transfer ownership you must be the owner of the guild.')
  
              fields['owner_id'] = fields['owner'].id
  
          if 'region' in fields:
              fields['region'] = str(fields['region'])
  
          level = fields.get('verification_level', self.verification_level)
          if not isinstance(level, VerificationLevel):
              raise InvalidArgument('verification_level field must be of type VerificationLevel')
  
          fields['verification_level'] = level.value
  
          explicit_content_filter = fields.get('explicit_content_filter', self.explicit_content_filter)
          if not isinstance(explicit_content_filter, ContentFilter):
              raise InvalidArgument('explicit_content_filter field must be of type ContentFilter')
  
          fields['explicit_content_filter'] = explicit_content_filter.value
  
          system_channel_flags = fields.get('system_channel_flags', self.system_channel_flags)
          if not isinstance(system_channel_flags, SystemChannelFlags):
              raise InvalidArgument('system_channel_flags field must be of type SystemChannelFlags')
  
          fields['system_channel_flags'] = system_channel_flags.value
          await http.edit_guild(self.id, reason=reason, **fields)
  
      async def fetch_channels(self):
          """|coro|
  
          Retrieves all :class:`abc.GuildChannel` that the guild has.
  
          .. note::
  
              This method is an API call. For general usage, consider :attr:`channels` instead.
  
          .. versionadded:: 1.2
  
          Raises
          -------
          InvalidData
              An unknown channel type was received from Discord.
          HTTPException
              Retrieving the channels failed.
  
          Returns
          -------
          List[:class:`abc.GuildChannel`]
              All channels in the guild.
          """
          data = await self._state.http.get_all_guild_channels(self.id)
  
          def convert(d):
              factory, ch_type = _channel_factory(d['type'])
              if factory is None:
                  raise InvalidData('Unknown channel type {type} for channel ID {id}.'.format_map(data))
  
              channel = factory(guild=self, state=self._state, data=d)
              return channel
  
          return [convert(d) for d in data]
  
      def fetch_members(self, *, limit=1000, after=None):
          """|coro|
  
          Retrieves an :class:`.AsyncIterator` that enables receiving the guild's members.
  
          .. note::
  
              This method is an API call. For general usage, consider :attr:`members` instead.
  
          .. versionadded:: 1.3
  
          All parameters are optional.
  
          Parameters
          ----------
          limit: Optional[:class:`int`]
              The number of members to retrieve. Defaults to 1000.
              Pass ``None`` to fetch all members. Note that this is potentially slow.
          after: Optional[Union[:class:`.abc.Snowflake`, :class:`datetime.datetime`]]
              Retrieve members after this date or object.
              If a date is provided it must be a timezone-naive datetime representing UTC time.
  
          Raises
          ------
          HTTPException
              Getting the members failed.
  
          Yields
          ------
          :class:`.Member`
              The member with the member data parsed.
  
          Examples
          --------
  
          Usage ::
  
              async for member in guild.fetch_members(limit=150):
                  print(member.name)
  
          Flattening into a list ::
  
              members = await guild.fetch_members(limit=150).flatten()
              # members is now a list of Member...
          """
          return MemberIterator(self, limit=limit, after=after)
  
      async def fetch_member(self, member_id):
          """|coro|
  
          Retreives a :class:`Member` from a guild ID, and a member ID.
  
          .. note::
  
              This method is an API call. For general usage, consider :meth:`get_member` instead.
  
          Parameters
          -----------
          member_id: :class:`int`
              The member's ID to fetch from.
  
          Raises
          -------
          Forbidden
              You do not have access to the guild.
          HTTPException
              Getting the guild failed.
  
          Returns
          --------
          :class:`Member`
              The member from the member ID.
          """
          data = await self._state.http.get_member(self.id, member_id)
          return Member(data=data, state=self._state, guild=self)
  
      async def fetch_ban(self, user):
          """|coro|
  
          Retrieves the :class:`BanEntry` for a user, which is a namedtuple
          with a ``user`` and ``reason`` field. See :meth:`bans` for more
          information.
  
          You must have the :attr:`~Permissions.ban_members` permission
          to get this information.
  
          Parameters
          -----------
          user: :class:`abc.Snowflake`
              The user to get ban information from.
  
          Raises
          ------
          Forbidden
              You do not have proper permissions to get the information.
          NotFound
              This user is not banned.
          HTTPException
              An error occurred while fetching the information.
  
          Returns
          -------
          BanEntry
              The BanEntry object for the specified user.
          """
          data = await self._state.http.get_ban(user.id, self.id)
          return BanEntry(
              user=User(state=self._state, data=data['user']),
              reason=data['reason']
          )
  
      async def bans(self):
          """|coro|
  
          Retrieves all the users that are banned from the guild.
  
          This coroutine returns a :class:`list` of BanEntry objects, which is a
          namedtuple with a ``user`` field to denote the :class:`User`
          that got banned along with a ``reason`` field specifying
          why the user was banned that could be set to ``None``.
  
          You must have the :attr:`~Permissions.ban_members` permission
          to get this information.
  
          Raises
          -------
          Forbidden
              You do not have proper permissions to get the information.
          HTTPException
              An error occurred while fetching the information.
  
          Returns
          --------
          List[BanEntry]
              A list of BanEntry objects.
          """
  
          data = await self._state.http.get_bans(self.id)
          return [BanEntry(user=User(state=self._state, data=e['user']),
                           reason=e['reason'])
                  for e in data]
  
      async def prune_members(self, *, days, compute_prune_count=True, reason=None):
          r"""|coro|
  
          Prunes the guild from its inactive members.
  
          The inactive members are denoted if they have not logged on in
          ``days`` number of days and they have no roles.
  
          You must have the :attr:`~Permissions.kick_members` permission
          to use this.
  
          To check how many members you would prune without actually pruning,
          see the :meth:`estimate_pruned_members` function.
  
          Parameters
          -----------
          days: :class:`int`
              The number of days before counting as inactive.
          reason: Optional[:class:`str`]
              The reason for doing this action. Shows up on the audit log.
          compute_prune_count: :class:`bool`
              Whether to compute the prune count. This defaults to ``True``
              which makes it prone to timeouts in very large guilds. In order
              to prevent timeouts, you must set this to ``False``. If this is
              set to ``False``\, then this function will always return ``None``.
  
          Raises
          -------
          Forbidden
              You do not have permissions to prune members.
          HTTPException
              An error occurred while pruning members.
          InvalidArgument
              An integer was not passed for ``days``.
  
          Returns
          ---------
          Optional[:class:`int`]
              The number of members pruned. If ``compute_prune_count`` is ``False``
              then this returns ``None``.
          """
  
          if not isinstance(days, int):
              raise InvalidArgument('Expected int for ``days``, received {0.__class__.__name__} instead.'.format(days))
  
          data = await self._state.http.prune_members(self.id, days, compute_prune_count=compute_prune_count, reason=reason)
          return data['pruned']
  
      async def webhooks(self):
          """|coro|
  
          Gets the list of webhooks from this guild.
  
          Requires :attr:`~.Permissions.manage_webhooks` permissions.
  
          Raises
          -------
          Forbidden
              You don't have permissions to get the webhooks.
  
          Returns
          --------
          List[:class:`Webhook`]
              The webhooks for this guild.
          """
  
          data = await self._state.http.guild_webhooks(self.id)
          return [Webhook.from_state(d, state=self._state) for d in data]
  
      async def estimate_pruned_members(self, *, days):
          """|coro|
  
          Similar to :meth:`prune_members` except instead of actually
          pruning members, it returns how many members it would prune
          from the guild had it been called.
  
          Parameters
          -----------
          days: :class:`int`
              The number of days before counting as inactive.
  
          Raises
          -------
          Forbidden
              You do not have permissions to prune members.
          HTTPException
              An error occurred while fetching the prune members estimate.
          InvalidArgument
              An integer was not passed for ``days``.
  
          Returns
          ---------
          :class:`int`
              The number of members estimated to be pruned.
          """
  
          if not isinstance(days, int):
              raise InvalidArgument('Expected int for ``days``, received {0.__class__.__name__} instead.'.format(days))
  
          data = await self._state.http.estimate_pruned_members(self.id, days)
          return data['pruned']
  
      async def invites(self):
          """|coro|
  
          Returns a list of all active instant invites from the guild.
  
          You must have the :attr:`~Permissions.manage_guild` permission to get
          this information.
  
          Raises
          -------
          Forbidden
              You do not have proper permissions to get the information.
          HTTPException
              An error occurred while fetching the information.
  
          Returns
          -------
          List[:class:`Invite`]
              The list of invites that are currently active.
          """
  
          data = await self._state.http.invites_from(self.id)
          result = []
          for invite in data:
              channel = self.get_channel(int(invite['channel']['id']))
              invite['channel'] = channel
              invite['guild'] = self
              result.append(Invite(state=self._state, data=invite))
  
          return result
  
      async def fetch_emojis(self):
          r"""|coro|
  
          Retrieves all custom :class:`Emoji`\s from the guild.
  
          .. note::
  
              This method is an API call. For general usage, consider :attr:`emojis` instead.
  
          Raises
          ---------
          HTTPException
              An error occurred fetching the emojis.
  
          Returns
          --------
          List[:class:`Emoji`]
              The retrieved emojis.
          """
          data = await self._state.http.get_all_custom_emojis(self.id)
          return [Emoji(guild=self, state=self._state, data=d) for d in data]
  
      async def fetch_emoji(self, emoji_id):
          """|coro|
  
          Retrieves a custom :class:`Emoji` from the guild.
  
          .. note::
  
              This method is an API call.
              For general usage, consider iterating over :attr:`emojis` instead.
  
          Parameters
          -------------
          emoji_id: :class:`int`
              The emoji's ID.
  
          Raises
          ---------
          NotFound
              The emoji requested could not be found.
          HTTPException
              An error occurred fetching the emoji.
  
          Returns
          --------
          :class:`Emoji`
              The retrieved emoji.
          """
          data = await self._state.http.get_custom_emoji(self.id, emoji_id)
          return Emoji(guild=self, state=self._state, data=data)
  
      async def create_custom_emoji(self, *, name, image, roles=None, reason=None):
          r"""|coro|
  
          Creates a custom :class:`Emoji` for the guild.
  
          There is currently a limit of 50 static and animated emojis respectively per guild,
          unless the guild has the ``MORE_EMOJI`` feature which extends the limit to 200.
  
          You must have the :attr:`~Permissions.manage_emojis` permission to
          do this.
  
          Parameters
          -----------
          name: :class:`str`
              The emoji name. Must be at least 2 characters.
          image: :class:`bytes`
              The :term:`py:bytes-like object` representing the image data to use.
              Only JPG, PNG and GIF images are supported.
          roles: Optional[List[:class:`Role`]]
              A :class:`list` of :class:`Role`\s that can use this emoji. Leave empty to make it available to everyone.
          reason: Optional[:class:`str`]
              The reason for creating this emoji. Shows up on the audit log.
  
          Raises
          -------
          Forbidden
              You are not allowed to create emojis.
          HTTPException
              An error occurred creating an emoji.
  
          Returns
          --------
          :class:`Emoji`
              The created emoji.
          """
  
          img = utils._bytes_to_base64_data(image)
          if roles:
              roles = [role.id for role in roles]
          data = await self._state.http.create_custom_emoji(self.id, name, img, roles=roles, reason=reason)
          return self._state.store_emoji(self, data)
  
      async def fetch_roles(self):
          """|coro|
  
          Retrieves all :class:`Role` that the guild has.
  
          .. note::
  
              This method is an API call. For general usage, consider :attr:`roles` instead.
  
          .. versionadded:: 1.3
  
          Raises
          -------
          HTTPException
              Retrieving the roles failed.
  
          Returns
          -------
          List[:class:`Role`]
              All roles in the guild.
          """
          data = await self._state.http.get_roles(self.id)
          return [Role(guild=self, state=self._state, data=d) for d in data]
  
      async def create_role(self, *, reason=None, **fields):
          """|coro|
  
          Creates a :class:`Role` for the guild.
  
          All fields are optional.
  
          You must have the :attr:`~Permissions.manage_roles` permission to
          do this.
  
          Parameters
          -----------
          name: :class:`str`
              The role name. Defaults to 'new role'.
          permissions: :class:`Permissions`
              The permissions to have. Defaults to no permissions.
          colour: :class:`Colour`
              The colour for the role. Defaults to :meth:`Colour.default`.
              This is aliased to ``color`` as well.
          hoist: :class:`bool`
              Indicates if the role should be shown separately in the member list.
              Defaults to ``False``.
          mentionable: :class:`bool`
              Indicates if the role should be mentionable by others.
              Defaults to ``False``.
          reason: Optional[:class:`str`]
              The reason for creating this role. Shows up on the audit log.
  
          Raises
          -------
          Forbidden
              You do not have permissions to create the role.
          HTTPException
              Creating the role failed.
          InvalidArgument
              An invalid keyword argument was given.
  
          Returns
          --------
          :class:`Role`
              The newly created role.
          """
  
          try:
              perms = fields.pop('permissions')
          except KeyError:
              fields['permissions'] = 0
          else:
              fields['permissions'] = perms.value
  
          try:
              colour = fields.pop('colour')
          except KeyError:
              colour = fields.get('color', Colour.default())
          finally:
              fields['color'] = colour.value
  
          valid_keys = ('name', 'permissions', 'color', 'hoist', 'mentionable')
          for key in fields:
              if key not in valid_keys:
                  raise InvalidArgument('%r is not a valid field.' % key)
  
          data = await self._state.http.create_role(self.id, reason=reason, **fields)
          role = Role(guild=self, data=data, state=self._state)
  
          # TODO: add to cache
          return role
  
      async def kick(self, user, *, reason=None):
          """|coro|
  
          Kicks a user from the guild.
  
          The user must meet the :class:`abc.Snowflake` abc.
  
          You must have the :attr:`~Permissions.kick_members` permission to
          do this.
  
          Parameters
          -----------
          user: :class:`abc.Snowflake`
              The user to kick from their guild.
          reason: Optional[:class:`str`]
              The reason the user got kicked.
  
          Raises
          -------
          Forbidden
              You do not have the proper permissions to kick.
          HTTPException
              Kicking failed.
          """
          await self._state.http.kick(user.id, self.id, reason=reason)
  
      async def ban(self, user, *, reason=None, delete_message_days=1):
          """|coro|
  
          Bans a user from the guild.
  
          The user must meet the :class:`abc.Snowflake` abc.
  
          You must have the :attr:`~Permissions.ban_members` permission to
          do this.
  
          Parameters
          -----------
          user: :class:`abc.Snowflake`
              The user to ban from their guild.
          delete_message_days: :class:`int`
              The number of days worth of messages to delete from the user
              in the guild. The minimum is 0 and the maximum is 7.
          reason: Optional[:class:`str`]
              The reason the user got banned.
  
          Raises
          -------
          Forbidden
              You do not have the proper permissions to ban.
          HTTPException
              Banning failed.
          """
          await self._state.http.ban(user.id, self.id, delete_message_days, reason=reason)
  
      async def unban(self, user, *, reason=None):
          """|coro|
  
          Unbans a user from the guild.
  
          The user must meet the :class:`abc.Snowflake` abc.
  
          You must have the :attr:`~Permissions.ban_members` permission to
          do this.
  
          Parameters
          -----------
          user: :class:`abc.Snowflake`
              The user to unban.
          reason: Optional[:class:`str`]
              The reason for doing this action. Shows up on the audit log.
  
          Raises
          -------
          Forbidden
              You do not have the proper permissions to unban.
          HTTPException
              Unbanning failed.
          """
          await self._state.http.unban(user.id, self.id, reason=reason)
  
      async def vanity_invite(self):
          """|coro|
  
          Returns the guild's special vanity invite.
  
          The guild must have 'VANITY_URL' in :attr:`~Guild.features`.
  
          You must have the :attr:`~Permissions.manage_guild` permission to use
          this as well.
  
          Raises
          -------
          Forbidden
              You do not have the proper permissions to get this.
          HTTPException
              Retrieving the vanity invite failed.
  
          Returns
          --------
          :class:`Invite`
              The special vanity invite.
          """
  
          # we start with { code: abc }
          payload = await self._state.http.get_vanity_code(self.id)
  
          # get the vanity URL channel since default channels aren't
          # reliable or a thing anymore
          data = await self._state.http.get_invite(payload['code'])
  
          payload['guild'] = self
          payload['channel'] = self.get_channel(int(data['channel']['id']))
          payload['revoked'] = False
          payload['temporary'] = False
          payload['max_uses'] = 0
          payload['max_age'] = 0
          return Invite(state=self._state, data=payload)
  
      def ack(self):
          """|coro|
  
          Marks every message in this guild as read.
  
          The user must not be a bot user.
  
          Raises
          -------
          HTTPException
              Acking failed.
          ClientException
              You must not be a bot user.
          """
  
          state = self._state
          if state.is_bot:
              raise ClientException('Must not be a bot account to ack messages.')
          return state.http.ack_guild(self.id)
  
      def audit_logs(self, *, limit=100, before=None, after=None, oldest_first=None, user=None, action=None):
          """Returns an :class:`AsyncIterator` that enables receiving the guild's audit logs.
  
          You must have the :attr:`~Permissions.view_audit_log` permission to use this.
  
          Examples
          ----------
  
          Getting the first 100 entries: ::
  
              async for entry in guild.audit_logs(limit=100):
                  print('{0.user} did {0.action} to {0.target}'.format(entry))
  
          Getting entries for a specific action: ::
  
              async for entry in guild.audit_logs(action=discord.AuditLogAction.ban):
                  print('{0.user} banned {0.target}'.format(entry))
  
          Getting entries made by a specific user: ::
  
              entries = await guild.audit_logs(limit=None, user=guild.me).flatten()
              await channel.send('I made {} moderation actions.'.format(len(entries)))
  
          Parameters
          -----------
          limit: Optional[:class:`int`]
              The number of entries to retrieve. If ``None`` retrieve all entries.
          before: Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]
              Retrieve entries before this date or entry.
              If a date is provided it must be a timezone-naive datetime representing UTC time.
          after: Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]
              Retrieve entries after this date or entry.
              If a date is provided it must be a timezone-naive datetime representing UTC time.
          oldest_first: :class:`bool`
              If set to ``True``, return entries in oldest->newest order. Defaults to True if
              ``after`` is specified, otherwise ``False``.
          user: :class:`abc.Snowflake`
              The moderator to filter entries from.
          action: :class:`AuditLogAction`
              The action to filter with.
  
          Raises
          -------
          Forbidden
              You are not allowed to fetch audit logs
          HTTPException
              An error occurred while fetching the audit logs.
  
          Yields
          --------
          :class:`AuditLogEntry`
              The audit log entry.
          """
          if user:
              user = user.id
  
          if action:
              action = action.value
  
          return AuditLogIterator(self, before=before, after=after, limit=limit,
                                  oldest_first=oldest_first, user_id=user, action_type=action)
  
      async def widget(self):
          """|coro|
  
          Returns the widget of the guild.
  
          .. note::
  
              The guild must have the widget enabled to get this information.
  
          Raises
          -------
          Forbidden
              The widget for this guild is disabled.
          HTTPException
              Retrieving the widget failed.
  
          Returns
          --------
          :class:`Widget`
              The guild's widget.
          """
          data = await self._state.http.get_widget(self.id)
  
          return Widget(state=self._state, data=data)
  
      async def query_members(self, query, *, limit=5, cache=True):
          """|coro|
  
          Request members that belong to this guild whose username starts with
          the query given.
  
          This is a websocket operation and can be slow.
  
          .. warning::
  
              Most bots do not need to use this. It's mainly a helper
              for bots who have disabled ``guild_subscriptions``.
  
          .. versionadded:: 1.3
  
          Parameters
          -----------
          query: :class:`str`
              The string that the username's start with. An empty string
              requests all members.
          limit: :class:`int`
              The maximum number of members to send back. This must be
              a number between 1 and 1000.
          cache: :class:`bool`
              Whether to cache the members internally. This makes operations
              such as :meth:`get_member` work for those that matched.
  
          Raises
          -------
          asyncio.TimeoutError
              The query timed out waiting for the members.
  
          Returns
          --------
          List[:class:`Member`]
              The list of members that have matched the query.
          """
          limit = limit or 5
          return await self._state.query_members(self, query=query, limit=limit, cache=cache)
  