func getScheme(url string) (scheme, path string) {
	for i, c := range []byte(url) {
		switch {
		case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
		case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
			if i == 0 {
				return "", url
			}
		case c == ':':
			return url[:i], url[i+1:]
		default:
			return "", url
		}
	}
	return "", url
}
getScheme splits the url into (scheme, path) where scheme is the protocol.
If the scheme cannot be determined ("", url) is returned.
package safebrowsing
import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"strings"
	"golang.org/x/net/idna"
)
var (
	dotsRegexp          = regexp.MustCompile("[.]+")
	portRegexp          = regexp.MustCompile(`:\d+$`)
	possibleIPRegexp    = regexp.MustCompile(`^(?i)((?:0x[0-9a-f]+|[0-9\.])+)$`)
	trailingSpaceRegexp = regexp.MustCompile(`^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) `)
)
func ValidURL(url string) bool {
	parsed, err := parseURL(url)
	return parsed != nil && err == nil
}
func generateHashes(url string) (map[hashPrefix]string, error) {
	patterns, err := generatePatterns(url)
	if err != nil {
		return nil, err
	}
	hashes := make(map[hashPrefix]string)
	for _, p := range patterns {
		hashes[hashFromPattern(p)] = p
	}
	return hashes, nil
}
func generatePatterns(url string) ([]string, error) {
	hosts, err := generateLookupHosts(url)
	if err != nil {
		return nil, err
	}
	paths, err := generateLookupPaths(url)
	if err != nil {
		return nil, err
	}
	var patterns []string
	for _, h := range hosts {
		for _, p := range paths {
			patterns = append(patterns, h+p)
		}
	}
	return patterns, nil
}
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 isUnicode(s string) bool {
	for _, c := range []byte(s) {
		if c > 0x80 {
			return true
		}
	}
	return false
}
func split(s string, c string, cutc bool) (string, string) {
	i := strings.Index(s, c)
	if i < 0 {
		return s, ""
	}
	if cutc {
		return s[:i], s[i+len(c):]
	}
	return s[:i], s[i:]
}
func escape(s string) string {
	var b bytes.Buffer
	for _, c := range []byte(s) {
		if c < 0x20 || c >= 0x7f || c == ' ' || c == '#' || c == '%' {
			b.WriteString(fmt.Sprintf("%%%02x", c))
		} else {
			b.WriteByte(c)
		}
	}
	return b.String()
}
func unescape(s string) string {
	var b bytes.Buffer
	for len(s) > 0 {
		if len(s) >= 3 && s[0] == '%' && isHex(s[1]) && isHex(s[2]) {
			b.WriteByte(unhex(s[1])<<4 | unhex(s[2]))
			s = s[3:]
		} else {
			b.WriteByte(s[0])
			s = s[1:]
		}
	}
	return b.String()
}
func recursiveUnescape(s string) (string, error) {
	const maxDepth = 1024
	for i := 0; i < maxDepth; i++ {
		t := unescape(s)
		if t == s {
			return s, nil
		}
		s = t
	}
	return "", errors.New("safebrowsing: unescaping is too recursive")
}
func normalizeEscape(s string) (string, error) {
	u, err := recursiveUnescape(s)
	if err != nil {
		return "", err
	}
	return escape(u), nil
}