func (p *Profile) process(s string, toASCII bool) (string, error) {
	var err error
	var isBidi bool
	if p.mapping != nil {
		s, isBidi, err = p.mapping(p, s)
	}
	if p.removeLeadingDots {
		for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
		}
	}
	if err == nil && p.verifyDNSLength && s == "" {
		err = &labelError{s, "A4"}
	}
	labels := labelIter{orig: s}
	for ; !labels.done(); labels.next() {
		label := labels.label()
		if label == "" {
			if err == nil && p.verifyDNSLength {
				err = &labelError{s, "A4"}
			}
			continue
		}
		if strings.HasPrefix(label, acePrefix) {
			u, err2 := decode(label[len(acePrefix):])
			if err2 != nil {
				if err == nil {
					err = err2
				}
				continue
			}
			isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight
			labels.set(u)
			if err == nil && p.validateLabels {
				err = p.fromPuny(p, u)
			}
			if err == nil {
				err = p.validateLabel(u)
			}
		} else if err == nil {
			err = p.validateLabel(label)
		}
	}
	if isBidi && p.bidirule != nil && err == nil {
		for labels.reset(); !labels.done(); labels.next() {
			if !p.bidirule(labels.label()) {
				err = &labelError{s, "B"}
				break
			}
		}
	}
	if toASCII {
		for labels.reset(); !labels.done(); labels.next() {
			label := labels.label()
			if !ascii(label) {
				a, err2 := encode(acePrefix, label)
				if err == nil {
					err = err2
				}
				label = a
				labels.set(a)
			}
			n := len(label)
			if p.verifyDNSLength && err == nil && (n == 0 || n > 63) {
				err = &labelError{label, "A4"}
			}
		}
	}
	s = labels.result()
	if toASCII && p.verifyDNSLength && err == nil {
		n := len(s)
		if n > 0 && s[n-1] == '.' {
			n--
		}
		if len(s) < 1 || n > 253 {
			err = &labelError{s, "A4"}
		}
	}
	return s, err
}
process implements the algorithm described in section 4 of UTS #46,
see https://www.unicode.org/reports/tr46.
package idna  
import (
	"fmt"
	"strings"
	"unicode/utf8"
	"golang.org/x/text/secure/bidirule"
	"golang.org/x/text/unicode/bidi"
	"golang.org/x/text/unicode/norm"
)
func ToASCII(s string) (string, error) {
	return Punycode.process(s, true)
}
func ToUnicode(s string) (string, error) {
	return Punycode.process(s, false)
}
type Option func(*options)
func Transitional(transitional bool) Option {
	return func(o *options) { o.transitional = true }
}
func VerifyDNSLength(verify bool) Option {
	return func(o *options) { o.verifyDNSLength = verify }
}
func RemoveLeadingDots(remove bool) Option {
	return func(o *options) { o.removeLeadingDots = remove }
}
func ValidateLabels(enable bool) Option {
	return func(o *options) {
		if o.mapping == nil && enable {
			o.mapping = normalize
		}
		o.trie = trie
		o.validateLabels = enable
		o.fromPuny = validateFromPunycode
	}
}
func StrictDomainName(use bool) Option {
	return func(o *options) {
		o.trie = trie
		o.useSTD3Rules = use
		o.fromPuny = validateFromPunycode
	}
}
func BidiRule() Option {
	return func(o *options) { o.bidirule = bidirule.ValidString }
}
func ValidateForRegistration() Option {
	return func(o *options) {
		o.mapping = validateRegistration
		StrictDomainName(true)(o)
		ValidateLabels(true)(o)
		VerifyDNSLength(true)(o)
		BidiRule()(o)
	}
}
func MapForLookup() Option {
	return func(o *options) {
		o.mapping = validateAndMap
		StrictDomainName(true)(o)
		ValidateLabels(true)(o)
	}
}
type options struct {
	transitional      bool
	useSTD3Rules      bool
	validateLabels    bool
	verifyDNSLength   bool
	removeLeadingDots bool
	trie *idnaTrie
	fromPuny func(p *Profile, s string) error
	mapping func(p *Profile, s string) (mapped string, isBidi bool, err error)
	bidirule func(s string) bool
}
type Profile struct {
	options
}
func apply(o *options, opts []Option) {
	for _, f := range opts {
		f(o)
	}
}
func New(o ...Option) *Profile {
	p := &Profile{}
	apply(&p.options, o)
	return p
}
func (p *Profile) ToASCII(s string) (string, error) {
	return p.process(s, true)
}
func (p *Profile) ToUnicode(s string) (string, error) {
	pp := *p
	pp.transitional = false
	return pp.process(s, false)
}
func (p *Profile) String() string {
	s := ""
	if p.transitional {
		s = "Transitional"
	} else {
		s = "NonTransitional"
	}
	if p.useSTD3Rules {
		s += ":UseSTD3Rules"
	}
	if p.validateLabels {
		s += ":ValidateLabels"
	}
	if p.verifyDNSLength {
		s += ":VerifyDNSLength"
	}
	return s
}
var (
	Punycode *Profile = punycode
	Lookup *Profile = lookup
	Display *Profile = display
	Registration *Profile = registration
	punycode = &Profile{}
	lookup   = &Profile{options{
		transitional:   true,
		useSTD3Rules:   true,
		validateLabels: true,
		trie:           trie,
		fromPuny:       validateFromPunycode,
		mapping:        validateAndMap,
		bidirule:       bidirule.ValidString,
	}}
	display = &Profile{options{
		useSTD3Rules:   true,
		validateLabels: true,
		trie:           trie,
		fromPuny:       validateFromPunycode,
		mapping:        validateAndMap,
		bidirule:       bidirule.ValidString,
	}}
	registration = &Profile{options{
		useSTD3Rules:    true,
		validateLabels:  true,
		verifyDNSLength: true,
		trie:            trie,
		fromPuny:        validateFromPunycode,
		mapping:         validateRegistration,
		bidirule:        bidirule.ValidString,
	}}
)
type labelError struct{ label, code_ string }
func (e labelError) code() string { return e.code_ }
func (e labelError) Error() string {
	return fmt.Sprintf("idna: invalid label %q", e.label)
}
type runeError rune
func (e runeError) code() string { return "P1" }
func (e runeError) Error() string {
	return fmt.Sprintf("idna: disallowed rune %U", e)
}