def domain(value,
           allow_empty = False,
           allow_ips = False,
           **kwargs):
    """Validate that ``value`` is a valid domain name.

    .. caution::

      This validator does not verify that ``value`` **exists** as a domain. It
      merely verifies that its contents *might* exist as a domain.

    .. note::

      This validator checks to validate that ``value`` resembles a valid
      domain name. It is - generally - compliant with
      `RFC 1035 <https://tools.ietf.org/html/rfc1035>`_ and
      `RFC 6761 <https://tools.ietf.org/html/rfc6761>`_, however it diverges
      in a number of key ways:

        * Including authentication (e.g. ``username:password@domain.dev``) will
          fail validation.
        * Including a path (e.g. ``domain.dev/path/to/file``) will fail validation.
        * Including a port (e.g. ``domain.dev:8080``) will fail validation.

      If you are hoping to validate a more complete URL, we recommend that you
      see :func:`url <validator_collection.validators.url>`.

    .. hint::

      Leading and trailing whitespace will be automatically stripped.

    :param value: The value to validate.
    :type value: :class:`str <python:str>` / :obj:`None <python:None>`

    :param allow_empty: If ``True``, returns :obj:`None <python:None>` if
      ``value`` is empty. If ``False``, raises a
      :class:`EmptyValueError <validator_collection.errors.EmptyValueError>`
      if ``value`` is empty. Defaults to ``False``.
    :type allow_empty: :class:`bool <python:bool>`

    :param allow_ips: If ``True``, will succeed when validating IP addresses,
      If ``False``, will raise a :class:`InvalidDomainError` if ``value`` is an IP
      address. Defaults to ``False``.
    :type allow_ips: :class:`bool <python:bool>`

    :returns: ``value`` / :obj:`None <python:None>`
    :rtype: :class:`str <python:str>` / :obj:`None <python:None>`

    :raises EmptyValueError: if ``value`` is empty and ``allow_empty`` is ``False``
    :raises CannotCoerceError: if ``value`` is not a :class:`str <python:str>` or
      :obj:`None <python:None>`
    :raises InvalidDomainError: if ``value`` is not a valid domain name or
      empty with ``allow_empty`` set to ``True``
    :raises SlashInDomainError: if ``value`` contains a slash or backslash
    :raises AtInDomainError: if ``value`` contains an ``@`` symbol
    :raises ColonInDomainError: if ``value`` contains a ``:`` symbol
    :raises WhitespaceInDomainError: if ``value`` contains whitespace

    """
    is_recursive = kwargs.pop('is_recursive', False)

    if not value and not allow_empty:
        raise errors.EmptyValueError('value (%s) was empty' % value)
    elif not value:
        return None

    if not isinstance(value, basestring):
        raise errors.CannotCoerceError('value must be a valid string, '
                                       'was %s' % type(value))

    if '/' in value:
        raise errors.SlashInDomainError('valid domain name cannot contain "/"')
    if '\\' in value:
        raise errors.SlashInDomainError('valid domain name cannot contain "\\"')
    if '@' in value:
        raise errors.AtInDomainError('valid domain name cannot contain "@"')
    if ':' in value:
        raise errors.ColonInDomainError('valid domain name cannot contain ":"')

    value = value.strip().lower()

    for item in string_.whitespace:
        if item in value:
            raise errors.WhitespaceInDomainError('valid domain name cannot contain '
                                                 'whitespace')

    if value in SPECIAL_USE_DOMAIN_NAMES:
        return value

    if allow_ips:
        try:
            ip_address(value, allow_empty = allow_empty)
            is_valid = True
        except (ValueError, TypeError, AttributeError):
            is_valid = False

        if is_valid:
            return value

    is_valid = DOMAIN_REGEX.match(value)

    if not is_valid and not is_recursive:
        with_prefix = 'http://' + value
        try:
            url(with_prefix, force_run = True, is_recursive = True)                                  # pylint: disable=E1123
        except ValueError:
            raise errors.InvalidDomainError('value (%s) is not a valid domain' % value)

    return value
Validate that ``value`` is a valid domain name.

    .. caution::

      This validator does not verify that ``value`` **exists** as a domain. It
      merely verifies that its contents *might* exist as a domain.

    .. note::

      This validator checks to validate that ``value`` resembles a valid
      domain name. It is - generally - compliant with
      `RFC 1035 <https://tools.ietf.org/html/rfc1035>`_ and
      `RFC 6761 <https://tools.ietf.org/html/rfc6761>`_, however it diverges
      in a number of key ways:

        * Including authentication (e.g. ``username:password@domain.dev``) will
          fail validation.
        * Including a path (e.g. ``domain.dev/path/to/file``) will fail validation.
        * Including a port (e.g. ``domain.dev:8080``) will fail validation.

      If you are hoping to validate a more complete URL, we recommend that you
      see :func:`url <validator_collection.validators.url>`.

    .. hint::

      Leading and trailing whitespace will be automatically stripped.

    :param value: The value to validate.
    :type value: :class:`str <python:str>` / :obj:`None <python:None>`

    :param allow_empty: If ``True``, returns :obj:`None <python:None>` if
      ``value`` is empty. If ``False``, raises a
      :class:`EmptyValueError <validator_collection.errors.EmptyValueError>`
      if ``value`` is empty. Defaults to ``False``.
    :type allow_empty: :class:`bool <python:bool>`

    :param allow_ips: If ``True``, will succeed when validating IP addresses,
      If ``False``, will raise a :class:`InvalidDomainError` if ``value`` is an IP
      address. Defaults to ``False``.
    :type allow_ips: :class:`bool <python:bool>`

    :returns: ``value`` / :obj:`None <python:None>`
    :rtype: :class:`str <python:str>` / :obj:`None <python:None>`

    :raises EmptyValueError: if ``value`` is empty and ``allow_empty`` is ``False``
    :raises CannotCoerceError: if ``value`` is not a :class:`str <python:str>` or
      :obj:`None <python:None>`
    :raises InvalidDomainError: if ``value`` is not a valid domain name or
      empty with ``allow_empty`` set to ``True``
    :raises SlashInDomainError: if ``value`` contains a slash or backslash
    :raises AtInDomainError: if ``value`` contains an ``@`` symbol
    :raises ColonInDomainError: if ``value`` contains a ``:`` symbol
    :raises WhitespaceInDomainError: if ``value`` contains whitespace