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
}
WithZone returns an IP that's the same as ip but with the provided
zone. If zone is empty, the zone is removed. If ip is an IPv4
address it's returned unchanged.
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
}