func deinterleave(X uint64) (uint32, uint32) {
	return squash(X), squash(X >> 1)
}
Deinterleave the bits of X into 32-bit words containing the even and odd
bitlevels of X, respectively.
package geohash
import (
	"errors"
	"fmt"
	"math"
)
type Direction int
const (
	North Direction = iota
	NorthEast
	East
	SouthEast
	South
	SouthWest
	West
	NorthWest
)
func Encode(lat, lng float64) string {
	return EncodeWithPrecision(lat, lng, 12)
}
func EncodeWithPrecision(lat, lng float64, chars uint) string {
	bits := 5 * chars
	inthash := EncodeIntWithPrecision(lat, lng, bits)
	enc := base32encoding.Encode(inthash)
	return enc[12-chars:]
}
func EncodeInt(lat, lng float64) uint64
func encodeInt(lat, lng float64) uint64 {
	latInt := encodeRange(lat, 90)
	lngInt := encodeRange(lng, 180)
	return interleave(latInt, lngInt)
}
func EncodeIntWithPrecision(lat, lng float64, bits uint) uint64 {
	hash := EncodeInt(lat, lng)
	return hash >> (64 - bits)
}
type Box struct {
	MinLat float64
	MaxLat float64
	MinLng float64
	MaxLng float64
}
func (b Box) Center() (lat, lng float64) {
	lat = (b.MinLat + b.MaxLat) / 2.0
	lng = (b.MinLng + b.MaxLng) / 2.0
	return
}
func (b Box) Contains(lat, lng float64) bool {
	return (b.MinLat <= lat && lat <= b.MaxLat &&
		b.MinLng <= lng && lng <= b.MaxLng)
}
func maxDecimalPower(r float64) float64 {
	m := int(math.Floor(math.Log10(r)))
	return math.Pow10(m)
}
func (b Box) Round() (lat, lng float64) {
	x := maxDecimalPower(b.MaxLat - b.MinLat)
	lat = math.Ceil(b.MinLat/x) * x
	x = maxDecimalPower(b.MaxLng - b.MinLng)
	lng = math.Ceil(b.MinLng/x) * x
	return
}
func errorWithPrecision(bits uint) (latErr, lngErr float64) {
	b := int(bits)
	latBits := b / 2
	lngBits := b - latBits
	latErr = math.Ldexp(180.0, -latBits)
	lngErr = math.Ldexp(360.0, -lngBits)
	return
}
func BoundingBox(hash string) Box {
	bits := uint(5 * len(hash))
	inthash := base32encoding.Decode(hash)
	return BoundingBoxIntWithPrecision(inthash, bits)
}
func BoundingBoxIntWithPrecision(hash uint64, bits uint) Box {
	fullHash := hash << (64 - bits)
	latInt, lngInt := deinterleave(fullHash)
	lat := decodeRange(latInt, 90)
	lng := decodeRange(lngInt, 180)
	latErr, lngErr := errorWithPrecision(bits)
	return Box{
		MinLat: lat,
		MaxLat: lat + latErr,
		MinLng: lng,
		MaxLng: lng + lngErr,
	}
}
func BoundingBoxInt(hash uint64) Box {
	return BoundingBoxIntWithPrecision(hash, 64)
}
func Validate(hash string) error {
	if 5*len(hash) > 64 {
		return errors.New("too long")
	}
	for i := 0; i < len(hash); i++ {
		if !base32encoding.ValidByte(hash[i]) {
			return fmt.Errorf("invalid character %q", hash[i])
		}
	}
	return nil
}
func Decode(hash string) (lat, lng float64) {
	box := BoundingBox(hash)
	return box.Round()
}
func DecodeCenter(hash string) (lat, lng float64) {
	box := BoundingBox(hash)
	return box.Center()
}
func DecodeIntWithPrecision(hash uint64, bits uint) (lat, lng float64) {
	box := BoundingBoxIntWithPrecision(hash, bits)
	return box.Round()
}
func DecodeInt(hash uint64) (lat, lng float64) {
	return DecodeIntWithPrecision(hash, 64)
}
func ConvertStringToInt(hash string) (uint64, uint) {
	return base32encoding.Decode(hash), uint(5 * len(hash))
}
func ConvertIntToString(hash uint64, chars uint) string {
	enc := base32encoding.Encode(hash)
	return enc[12-chars:]
}
func Neighbors(hash string) []string {
	box := BoundingBox(hash)
	lat, lng := box.Center()
	latDelta := box.MaxLat - box.MinLat
	lngDelta := box.MaxLng - box.MinLng
	precision := uint(len(hash))
	return []string{
		EncodeWithPrecision(lat+latDelta, lng, precision),
		EncodeWithPrecision(lat+latDelta, lng+lngDelta, precision),
		EncodeWithPrecision(lat, lng+lngDelta, precision),
		EncodeWithPrecision(lat-latDelta, lng+lngDelta, precision),
		EncodeWithPrecision(lat-latDelta, lng, precision),
		EncodeWithPrecision(lat-latDelta, lng-lngDelta, precision),
		EncodeWithPrecision(lat, lng-lngDelta, precision),
		EncodeWithPrecision(lat+latDelta, lng-lngDelta, precision),
	}
}
func NeighborsInt(hash uint64) []uint64 {
	return NeighborsIntWithPrecision(hash, 64)
}
func NeighborsIntWithPrecision(hash uint64, bits uint) []uint64 {
	box := BoundingBoxIntWithPrecision(hash, bits)
	lat, lng := box.Center()
	latDelta := box.MaxLat - box.MinLat
	lngDelta := box.MaxLng - box.MinLng
	return []uint64{
		EncodeIntWithPrecision(lat+latDelta, lng, bits),
		EncodeIntWithPrecision(lat+latDelta, lng+lngDelta, bits),
		EncodeIntWithPrecision(lat, lng+lngDelta, bits),
		EncodeIntWithPrecision(lat-latDelta, lng+lngDelta, bits),
		EncodeIntWithPrecision(lat-latDelta, lng, bits),
		EncodeIntWithPrecision(lat-latDelta, lng-lngDelta, bits),
		EncodeIntWithPrecision(lat, lng-lngDelta, bits),
		EncodeIntWithPrecision(lat+latDelta, lng-lngDelta, bits),
	}
}
func Neighbor(hash string, direction Direction) string {
	return Neighbors(hash)[direction]
}
func NeighborInt(hash uint64, direction Direction) uint64 {
	return NeighborsIntWithPrecision(hash, 64)[direction]
}
func NeighborIntWithPrecision(hash uint64, bits uint, direction Direction) uint64 {
	return NeighborsIntWithPrecision(hash, bits)[direction]
}
var exp232 = math.Exp2(32)
func encodeRange(x, r float64) uint32 {
	p := (x + r) / (2 * r)
	return uint32(p * exp232)
}
func decodeRange(X uint32, r float64) float64 {
	p := float64(X) / exp232
	x := 2*r*p - r
	return x
}
func spread(x uint32) uint64 {
	X := uint64(x)
	X = (X | (X << 16)) & 0x0000ffff0000ffff
	X = (X | (X << 8)) & 0x00ff00ff00ff00ff
	X = (X | (X << 4)) & 0x0f0f0f0f0f0f0f0f
	X = (X | (X << 2)) & 0x3333333333333333
	X = (X | (X << 1)) & 0x5555555555555555
	return X
}
func interleave(x, y uint32) uint64 {
	return spread(x) | (spread(y) << 1)
}
func squash(X uint64) uint32 {
	X &= 0x5555555555555555
	X = (X | (X >> 1)) & 0x3333333333333333
	X = (X | (X >> 2)) & 0x0f0f0f0f0f0f0f0f
	X = (X | (X >> 4)) & 0x00ff00ff00ff00ff
	X = (X | (X >> 8)) & 0x0000ffff0000ffff
	X = (X | (X >> 16)) & 0x00000000ffffffff
	return uint32(X)
}