<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def detect_ip(kind):
 """ Detect IP address. kind can be: IPV4 - returns IPv4 address IPV6_ANY - returns any IPv6 address (no preference) IPV6_PUBLIC - returns public IPv6 address IPV6_TMP - returns temporary IPV6 address (privacy extensions) This function either returns an IP address (str) or raises a GetIpException. """

    if kind not in (IPV4, IPV6_PUBLIC, IPV6_TMP, IPV6_ANY):
        raise ValueError("invalid kind specified")

    # We create an UDP socket and connect it to a public host.
    # We query the OS to know what our address is.
    # No packet will really be sent since we are using UDP.
    af = socket.AF_INET if kind == IPV4 else socket.AF_INET6
    s = socket.socket(af, socket.SOCK_DGRAM)
    try:
        if kind in [IPV6_PUBLIC, IPV6_TMP, ]:
            # caller wants some specific kind of IPv6 address (not IPV6_ANY)
            try:
                if kind == IPV6_PUBLIC:
                    preference = socket.IPV6_PREFER_SRC_PUBLIC
                elif kind == IPV6_TMP:
                    preference = socket.IPV6_PREFER_SRC_TMP
                s.setsockopt(socket.IPPROTO_IPV6,
                             socket.IPV6_ADDR_PREFERENCES, preference)
            except socket.error as e:
                if e.errno == errno.ENOPROTOOPT:
                    raise GetIpException("Kernel doesn't support IPv6 address preference")
                else:
                    raise GetIpException("Unable to set IPv6 address preference: %s" % e)

        try:
            outside_ip = OUTSIDE_IPV4 if kind == IPV4 else OUTSIDE_IPV6
            s.connect((outside_ip, 9))
        except (socket.error, socket.gaierror) as e:
            raise GetIpException(str(e))

        ip = s.getsockname()[0]
    finally:
        s.close()
    return ip