func (ip IP) As4() [4]byte {
	if ip.z == z4 || ip.Is4in6() {
		var ret [4]byte
		binary.BigEndian.PutUint32(ret[:], uint32(ip.addr.lo))
		return ret
	}
	if ip.z == z0 {
		panic("As4 called on IP zero value")
	}
	panic("As4 called on IPv6 address")
}
As4 returns an IPv4 or IPv4-in-IPv6 address in its 4 byte representation.
If ip is the IP zero value or an IPv6 address, As4 panics.
Note that 0.0.0.0 is not the zero value.
package netaddr  
import (
	"encoding/binary"
	"errors"
	"fmt"
	"math"
	"net"
	"sort"
	"strconv"
	"strings"
	"go4.org/intern"
)
type IP struct {
	addr uint128
	z *intern.Value
}
var (
	z0    = (*intern.Value)(nil)
	z4    = new(intern.Value)
	z6noz = new(intern.Value)
)
func IPv6LinkLocalAllNodes() IP { return IPv6Raw([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) }
func IPv6Unspecified() IP { return IP{z: z6noz} }
func IPv4(a, b, c, d uint8) IP {
	return IP{
		addr: uint128{0, 0xffff00000000 | uint64(a)<<24 | uint64(b)<<16 | uint64(c)<<8 | uint64(d)},
		z:    z4,
	}
}
func IPv6Raw(addr [16]byte) IP {
	return IP{
		addr: uint128{
			binary.BigEndian.Uint64(addr[:8]),
			binary.BigEndian.Uint64(addr[8:]),
		},
		z: z6noz,
	}
}
func ipv6Slice(addr []byte) IP {
	return IP{
		addr: uint128{
			binary.BigEndian.Uint64(addr[:8]),
			binary.BigEndian.Uint64(addr[8:]),
		},
		z: z6noz,
	}
}
func IPFrom16(addr [16]byte) IP {
	return IPv6Raw(addr).Unmap()
}
func IPFrom4(addr [4]byte) IP {
	return IPv4(addr[0], addr[1], addr[2], addr[3])
}
func ParseIP(s string) (IP, error) {
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '.':
			return parseIPv4(s)
		case ':':
			return parseIPv6(s)
		case '%':
			return IP{}, parseIPError{in: s, msg: "missing IPv6 address"}
		}
	}
	return IP{}, parseIPError{in: s, msg: "unable to parse IP"}
}
func MustParseIP(s string) IP {
	ip, err := ParseIP(s)
	if err != nil {
		panic(err)
	}
	return ip
}
type parseIPError struct {
	in  string  
	msg string  
	at  string  
}
func (err parseIPError) Error() string {
	if err.at != "" {
		return fmt.Sprintf("ParseIP(%q): %s (at %q)", err.in, err.msg, err.at)
	}
	return fmt.Sprintf("ParseIP(%q): %s", err.in, err.msg)
}
func parseIPv4(s string) (ip IP, err error) {
	var fields [3]uint8
	var val, pos int
	for i := 0; i < len(s); i++ {
		if s[i] >= '0' && s[i] <= '9' {
			val = val*10 + int(s[i]) - '0'
			if val > 255 {
				return IP{}, parseIPError{in: s, msg: "IPv4 field has value >255"}
			}
		} else if s[i] == '.' {
			if i == 0 || i == len(s)-1 || s[i-1] == '.' {
				return IP{}, parseIPError{in: s, msg: "IPv4 field must have at least one digit", at: s[i:]}
			}
			if pos == 3 {
				return IP{}, parseIPError{in: s, msg: "IPv4 address too long"}
			}
			fields[pos] = uint8(val)
			pos++
			val = 0
		} else {
			return IP{}, parseIPError{in: s, msg: "unexpected character", at: s[i:]}
		}
	}
	if pos < 3 {
		return IP{}, parseIPError{in: s, msg: "IPv4 address too short"}
	}
	return IPv4(fields[0], fields[1], fields[2], uint8(val)), nil
}
func parseIPv6(in string) (IP, error) {
	s := in
	zone := ""
	i := strings.IndexByte(s, '%')
	if i != -1 {
		s, zone = s[:i], s[i+1:]
		if zone == "" {
			return IP{}, parseIPError{in: in, msg: "zone must be a non-empty string"}
		}
	}
	var ip [16]byte
	ellipsis := -1  
	if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
		ellipsis = 0
		s = s[2:]
		if len(s) == 0 {
			return IPv6Unspecified().WithZone(zone), nil
		}
	}
	i = 0
	for i < 16 {
		off := 0
		acc := uint32(0)
		for ; off < len(s); off++ {
			c := s[off]
			if c >= '0' && c <= '9' {
				acc = (acc << 4) + uint32(c-'0')
			} else if c >= 'a' && c <= 'f' {
				acc = (acc << 4) + uint32(c-'a'+10)
			} else if c >= 'A' && c <= 'F' {
				acc = (acc << 4) + uint32(c-'A'+10)
			} else {
				break
			}
			if acc > math.MaxUint16 {
				return IP{}, parseIPError{in: in, msg: "IPv6 field has value >=2^16", at: s}
			}
		}
		if off == 0 {
			return IP{}, parseIPError{in: in, msg: "each colon-separated field must have at least one digit", at: s}
		}
		if off < len(s) && s[off] == '.' {
			if ellipsis < 0 && i != 12 {
				return IP{}, parseIPError{in: in, msg: "embedded IPv4 address must replace the final 2 fields of the address", at: s}
			}
			if i+4 > 16 {
				return IP{}, parseIPError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s}
			}
			ip4, err := parseIPv4(s)
			if err != nil {
				return IP{}, parseIPError{in: in, msg: err.Error(), at: s}
			}
			ip[i] = ip4.v4(0)
			ip[i+1] = ip4.v4(1)
			ip[i+2] = ip4.v4(2)
			ip[i+3] = ip4.v4(3)
			s = ""
			i += 4
			break
		}
		ip[i] = byte(acc >> 8)
		ip[i+1] = byte(acc)
		i += 2
		s = s[off:]
		if len(s) == 0 {
			break
		}
		if s[0] != ':' {
			return IP{}, parseIPError{in: in, msg: "unexpected character, want colon", at: s}
		} else if len(s) == 1 {
			return IP{}, parseIPError{in: in, msg: "colon must be followed by more characters", at: s}
		}
		s = s[1:]
		if s[0] == ':' {
			if ellipsis >= 0 {  
				return IP{}, parseIPError{in: in, msg: "multiple :: in address", at: s}
			}
			ellipsis = i
			s = s[1:]
			if len(s) == 0 {  
				break
			}
		}
	}
	if len(s) != 0 {
		return IP{}, parseIPError{in: in, msg: "trailing garbage after address", at: s}
	}
	if i < 16 {
		if ellipsis < 0 {
			return IP{}, parseIPError{in: in, msg: "address string too short"}
		}
		n := 16 - i
		for j := i - 1; j >= ellipsis; j-- {
			ip[j+n] = ip[j]
		}
		for j := ellipsis + n - 1; j >= ellipsis; j-- {
			ip[j] = 0
		}
	} else if ellipsis >= 0 {
		return IP{}, parseIPError{in: in, msg: "the :: must expand to at least one field of zeros"}
	}
	return IPv6Raw(ip).WithZone(zone), nil
}
func FromStdIP(std net.IP) (ip IP, ok bool) {
	ret, ok := FromStdIPRaw(std)
	if ret.Is4in6() {
		ret.z = z4
	}
	return ret, ok
}
func FromStdIPRaw(std net.IP) (ip IP, ok bool) {
	switch len(std) {
	case 4:
		return IPv4(std[0], std[1], std[2], std[3]), true
	case 16:
		return ipv6Slice(std), true
	}
	return IP{}, false
}
func (ip IP) v4(i uint8) uint8 {
	return uint8(ip.addr.lo >> ((3 - i) * 8))
}
func (ip IP) v6(i uint8) uint8 {
	return uint8(*(ip.addr.halves()[(i/8)%2]) >> ((7 - i%8) * 8))
}
func (ip IP) v6u16(i uint8) uint16 {
	return uint16(*(ip.addr.halves()[(i/4)%2]) >> ((3 - i%4) * 16))
}
func (ip IP) IsZero() bool {
	return ip.z == z0
}
func (ip IP) IsValid() bool { return ip.z != z0 }
func (ip IP) BitLen() uint8 {
	switch ip.z {
	case z0:
		return 0
	case z4:
		return 32
	}
	return 128
}
func (ip IP) Zone() string {
	if ip.z == nil {
		return ""
	}
	zone, _ := ip.z.Get().(string)
	return zone
}
func (ip IP) Compare(ip2 IP) int {
	f1, f2 := ip.BitLen(), ip2.BitLen()
	if f1 < f2 {
		return -1
	}
	if f1 > f2 {
		return 1
	}
	if hi1, hi2 := ip.addr.hi, ip2.addr.hi; hi1 < hi2 {
		return -1
	} else if hi1 > hi2 {
		return 1
	}
	if lo1, lo2 := ip.addr.lo, ip2.addr.lo; lo1 < lo2 {
		return -1
	} else if lo1 > lo2 {
		return 1
	}
	if ip.Is6() {
		za, zb := ip.Zone(), ip2.Zone()
		if za < zb {
			return -1
		} else if za > zb {
			return 1
		}
	}
	return 0
}
func (ip IP) Less(ip2 IP) bool { return ip.Compare(ip2) == -1 }
func (ip IP) lessOrEq(ip2 IP) bool { return ip.Compare(ip2) <= 0 }
func (ip IP) ipZone(reuse net.IP) (stdIP net.IP, zone string) {
	base := reuse[:0]
	switch {
	case ip.z == z0:
		return nil, ""
	case ip.Is4():
		a4 := ip.As4()
		return append(base, a4[:]...), ""
	default:
		a16 := ip.As16()
		return append(base, a16[:]...), ip.Zone()
	}
}
func (ip IP) IPAddr() *net.IPAddr {
	stdIP, zone := ip.ipZone(nil)
	return &net.IPAddr{IP: stdIP, Zone: zone}
}
func (ip IP) Is4() bool {
	return ip.z == z4
}
func (ip IP) Is4in6() bool {
	return ip.Is6() && ip.addr.hi == 0 && ip.addr.lo>>32 == 0xffff
}
func (ip IP) Is6() bool {
	return ip.z != z0 && ip.z != z4
}
func (ip IP) Unmap() IP {
	if ip.Is4in6() {
		ip.z = z4
	}
	return ip
}
func (ip IP) WithZone(zone string) IP {
	if !ip.Is6() {
		return ip
	}
	if zone == "" {
		ip.z = z6noz
		return ip
	}
	ip.z = intern.GetByString(zone)
	return ip
}
func (ip IP) withoutZone() IP {
	if !ip.Is6() {
		return ip
	}
	ip.z = z6noz
	return ip
}
func (ip IP) hasZone() bool {
	return ip.z != z0 && ip.z != z4 && ip.z != z6noz
}
func (ip IP) IsLinkLocalUnicast() bool {
	if ip.Is4() {
		return ip.v4(0) == 169 && ip.v4(1) == 254
	}
	if ip.Is6() {
		return ip.v6u16(0)&0xffc0 == 0xfe80
	}
	return false  
}
func (ip IP) IsLoopback() bool {
	if ip.Is4() {
		return ip.v4(0) == 127
	}
	if ip.Is6() {
		return ip.addr.hi == 0 && ip.addr.lo == 1
	}
	return false  
}
func (ip IP) IsMulticast() bool {
	if ip.Is4() {
		return ip.v4(0)&0xf0 == 0xe0
	}
	if ip.Is6() {
		return ip.addr.hi>>(64-8) == 0xff  
	}
	return false  
}
func (ip IP) IsInterfaceLocalMulticast() bool {
	if ip.Is6() {
		return ip.v6u16(0)&0xff0f == 0xff01
	}
	return false  
}
func (ip IP) IsLinkLocalMulticast() bool {
	if ip.Is4() {
		return ip.v4(0) == 224 && ip.v4(1) == 0 && ip.v4(2) == 0
	}
	if ip.Is6() {
		return ip.v6u16(0)&0xff0f == 0xff02
	}
	return false  
}
func (ip IP) IsGlobalUnicast() bool {
	if ip.z == z0 {
		return false
	}
	if ip.Is4() && (ip == IPv4(0, 0, 0, 0) || ip == IPv4(255, 255, 255, 255)) {
		return false
	}
	return ip != IPv6Unspecified() &&
		!ip.IsLoopback() &&
		!ip.IsMulticast() &&
		!ip.IsLinkLocalUnicast()
}
func (ip IP) IsPrivate() bool {
	if ip.Is4() {
		return ip.v4(0) == 10 ||
			(ip.v4(0) == 172 && ip.v4(1)&0xf0 == 16) ||
			(ip.v4(0) == 192 && ip.v4(1) == 168)
	}
	if ip.Is6() {
		return ip.v6(0)&0xfe == 0xfc
	}
	return false  
}
func (ip IP) IsUnspecified() bool {
	return ip == IPv4(0, 0, 0, 0) || ip == IPv6Unspecified()
}
func (ip IP) Prefix(bits uint8) (IPPrefix, error) {
	effectiveBits := bits
	switch ip.z {
	case z0:
		return IPPrefix{}, nil
	case z4:
		if bits > 32 {
			return IPPrefix{}, fmt.Errorf("prefix length %d too large for IPv4", bits)
		}
		effectiveBits += 96
	default:
		if bits > 128 {
			return IPPrefix{}, fmt.Errorf("prefix length %d too large for IPv6", bits)
		}
	}
	ip.addr = ip.addr.and(mask6[effectiveBits])
	return IPPrefixFrom(ip, bits), nil
}
func (ip IP) Netmask(mask []byte) (IPPrefix, error) {
	l := len(mask)
	switch ip.z {
	case z0:
		return IPPrefix{}, nil
	case z4:
		if l != net.IPv4len {
			return IPPrefix{}, fmt.Errorf("netmask length %d incorrect for IPv4", l)
		}
	default:
		if l != net.IPv6len {
			return IPPrefix{}, fmt.Errorf("netmask length %d incorrect for IPv6", l)
		}
	}
	ones, bits := net.IPMask(mask).Size()
	if ones == 0 && bits == 0 {
		return IPPrefix{}, errors.New("netmask is non-contiguous")
	}
	return ip.Prefix(uint8(ones))
}
func (ip IP) As16() [16]byte {
	var ret [16]byte
	binary.BigEndian.PutUint64(ret[:8], ip.addr.hi)
	binary.BigEndian.PutUint64(ret[8:], ip.addr.lo)
	return ret
}