func QueryEscape(s string) string {
	return EscapeEx(s, EncodeQueryComponent)
}
QueryEscape escapes the string so it can be safely placed
inside a URL query.
package url
import (
	"strconv"
)
type Encoding int
const (
	EncodePath Encoding = 1 + iota
	EncodeUserPassword
	EncodeQueryComponent
	EncodeFragment
)
type EscapeError string
func (e EscapeError) Error() string {
	return "invalid URL escape " + strconv.Quote(string(e))
}
func ishex(c byte) bool {
	switch {
	case '0' <= c && c <= '9':
		return true
	case 'a' <= c && c <= 'f':
		return true
	case 'A' <= c && c <= 'F':
		return true
	}
	return false
}
func unhex(c byte) byte {
	switch {
	case '0' <= c && c <= '9':
		return c - '0'
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10
	}
	return 0
}
func shouldEscape(c byte, mode Encoding) bool {
	if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
		return false
	}
	switch c {
	case '-', '_', '.', '~':  
		return false
	case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@':  
		switch mode {
		case EncodePath:  
			return c == '?'
		case EncodeUserPassword:  
			return c == '@' || c == '/' || c == ':'
		case EncodeQueryComponent:  
			return true
		case EncodeFragment:  
			return false
		}
	}
	return true
}
func QueryUnescape(s string) (string, error) {
	return UnescapeEx(s, EncodeQueryComponent)
}
func Unescape(s string) (string, error) {
	return UnescapeEx(s, EncodePath)
}
func UnescapeEx(s string, mode Encoding) (string, error) {
	n := 0
	hasPlus := false
	for i := 0; i < len(s); {
		switch s[i] {
		case '%':
			n++
			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
				s = s[i:]
				if len(s) > 3 {
					s = s[0:3]
				}
				return "", EscapeError(s)
			}
			i += 3
		case '+':
			hasPlus = mode == EncodeQueryComponent
			i++
		default:
			i++
		}
	}
	if n == 0 && !hasPlus {
		return s, nil
	}
	t := make([]byte, len(s)-2*n)
	j := 0
	for i := 0; i < len(s); {
		switch s[i] {
		case '%':
			t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
			j++
			i += 3
		case '+':
			if mode == EncodeQueryComponent {
				t[j] = ' '
			} else {
				t[j] = '+'
			}
			j++
			i++
		default:
			t[j] = s[i]
			j++
			i++
		}
	}
	return string(t), nil
}