func Domain(name string) (string, error) {
	return DomainFromListWithOptions(DefaultList, name, DefaultFindOptions)
}
Domain extract and return the domain name from the input
using the default (Public Suffix) List.

Examples:

publicsuffix.Domain("example.com")
// example.com
publicsuffix.Domain("www.example.com")
// example.com
publicsuffix.Domain("www.example.co.uk")
// example.co.uk
package publicsuffix
import (
	"bufio"
	"fmt"
	"io"
	"net/http/cookiejar"
	"os"
	"strings"
	"golang.org/x/net/idna"
)
const (
	Version = "0.15.0"
	NormalType = 1
	WildcardType = 2
	ExceptionType = 3
	listTokenPrivateDomains = "===BEGIN PRIVATE DOMAINS==="
	listTokenComment        = "//"
)
var DefaultList = NewList()
var DefaultRule = MustNewRule("*")
var DefaultParserOptions = &ParserOption{PrivateDomains: true, ASCIIEncoded: false}
var DefaultFindOptions = &FindOptions{IgnorePrivate: false, DefaultRule: DefaultRule}
type Rule struct {
	Type    int
	Value   string
	Length  int
	Private bool
}
type ParserOption struct {
	PrivateDomains bool
	ASCIIEncoded bool
}
type FindOptions struct {
	IgnorePrivate bool
	DefaultRule *Rule
}
type List struct {
	rules map[string]*Rule
}
func NewList() *List {
	return &List{
		rules: map[string]*Rule{},
	}
}
func NewListFromString(src string, options *ParserOption) (*List, error) {
	l := NewList()
	_, err := l.LoadString(src, options)
	return l, err
}
func NewListFromFile(path string, options *ParserOption) (*List, error) {
	l := NewList()
	_, err := l.LoadFile(path, options)
	return l, err
}
func (l *List) Load(r io.Reader, options *ParserOption) ([]Rule, error) {
	return l.parse(r, options)
}
func (l *List) LoadString(src string, options *ParserOption) ([]Rule, error) {
	r := strings.NewReader(src)
	return l.parse(r, options)
}
func (l *List) LoadFile(path string, options *ParserOption) ([]Rule, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return l.parse(f, options)
}
func (l *List) AddRule(r *Rule) error {
	l.rules[r.Value] = r
	return nil
}
func (l *List) Size() int {
	return len(l.rules)
}
func (l *List) parse(r io.Reader, options *ParserOption) ([]Rule, error) {
	if options == nil {
		options = DefaultParserOptions
	}
	var rules []Rule
	scanner := bufio.NewScanner(r)
	var section int  
Scanning:
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		switch {
		case line == "":
			break
		case strings.Contains(line, listTokenPrivateDomains):
			if !options.PrivateDomains {
				break Scanning
			}
			section = 2
		case strings.HasPrefix(line, listTokenComment):
			break
		default:
			var rule *Rule
			var err error
			if options.ASCIIEncoded {
				rule, err = NewRule(line)
			} else {
				rule, err = NewRuleUnicode(line)
			}
			if err != nil {
				return []Rule{}, err
			}
			rule.Private = (section == 2)
			l.AddRule(rule)
			rules = append(rules, *rule)
		}
	}
	return rules, scanner.Err()
}
func (l *List) Find(name string, options *FindOptions) *Rule {
	if options == nil {
		options = DefaultFindOptions
	}
	part := name
	for {
		rule, ok := l.rules[part]
		if ok && rule.Match(name) && !(options.IgnorePrivate && rule.Private) {
			return rule
		}
		i := strings.IndexRune(part, '.')
		if i < 0 {
			return options.DefaultRule
		}
		part = part[i+1:]
	}
}
func NewRule(content string) (*Rule, error) {
	var rule *Rule
	var value string
	switch content[0] {
	case '*':  
		if content == "*" {
			value = ""
		} else {
			value = content[2:]
		}
		rule = &Rule{Type: WildcardType, Value: value, Length: len(Labels(value)) + 1}
	case '!':  
		value = content[1:]
		rule = &Rule{Type: ExceptionType, Value: value, Length: len(Labels(value))}
	default:  
		value = content
		rule = &Rule{Type: NormalType, Value: value, Length: len(Labels(value))}
	}
	return rule, nil
}
func NewRuleUnicode(content string) (*Rule, error) {
	var err error
	content, err = ToASCII(content)
	if err != nil {
		return nil, err
	}
	return NewRule(content)
}
func MustNewRule(content string) *Rule {
	rule, err := NewRule(content)
	if err != nil {
		panic(err)
	}
	return rule
}
func (r *Rule) Match(name string) bool {
	left := strings.TrimSuffix(name, r.Value)
	if left == "" {
		return r.Type != WildcardType
	}
	return left[len(left)-1:] == "."
}
func (r *Rule) Decompose(name string) (result [2]string) {
	if r == DefaultRule {
		i := strings.LastIndexByte(name, '.')
		if i < 0 {
			return
		}
		result[0], result[1] = name[:i], name[i+1:]
		return
	}
	switch r.Type {
	case NormalType:
		name = strings.TrimSuffix(name, r.Value)
		if len(name) == 0 {
			return
		}
		result[0], result[1] = name[:len(name)-1], r.Value
	case WildcardType:
		name := strings.TrimSuffix(name, r.Value)
		if len(name) == 0 {
			return
		}
		name = name[:len(name)-1]
		i := strings.LastIndexByte(name, '.')
		if i < 0 {
			return
		}
		result[0], result[1] = name[:i], name[i+1:]+"."+r.Value
	case ExceptionType:
		i := strings.IndexRune(r.Value, '.')
		if i < 0 {
			return
		}
		suffix := r.Value[i+1:]
		name = strings.TrimSuffix(name, suffix)
		if len(name) == 0 {
			return
		}
		result[0], result[1] = name[:len(name)-1], suffix
	}
	return
}
func Labels(name string) []string {
	return strings.Split(name, ".")
}
type DomainName struct {
	TLD  string
	SLD  string
	TRD  string
	Rule *Rule
}
func (d *DomainName) String() string {
	switch {
	case d.TLD == "":
		return ""
	case d.SLD == "":
		return d.TLD
	case d.TRD == "":
		return d.SLD + "." + d.TLD
	default:
		return d.TRD + "." + d.SLD + "." + d.TLD
	}
}