func (i *InteractiveSession) AskYesNo(prompt string, defaultChoice string) string {
	switch def := strings.ToLower(defaultChoice); def {
	case "y", "yes":
		i.Default = "Y/n"
	default:
		i.Default = "y/N"
	}
	return i.ask(prompt, i.Default, "", ValidateYesNo())
}
AskYesNo asks the user a yes or no question with a default value.  Defaults of `y` or `yes` will
set the default to yes.  Anything else will default to no.  You can use IsYes or IsNo to act on the response
without worrying about what version of y, Y, YES, yes, etc. that the user entered.
package clt
import (
	"bufio"
	"fmt"
	"io"
	"sort"
	"os"
	"strings"
	"golang.org/x/crypto/ssh/terminal"
)
type getOpt int
const (
	noColon getOpt = iota
)
type InteractiveSession struct {
	Prompt  string
	Default string
	ValHint string
	response string
	input    *bufio.Reader
	output   io.Writer
}
func NewInteractiveSession(opts ...SessionOption) *InteractiveSession {
	i := &InteractiveSession{
		input:  bufio.NewReader(os.Stdin),
		output: os.Stdout,
	}
	for _, opt := range opts {
		opt(i)
	}
	return i
}
type SessionOption func(i *InteractiveSession)
func WithInput(r io.Reader) SessionOption {
	return func(i *InteractiveSession) {
		i.input = bufio.NewReader(r)
	}
}
func WithOutput(w io.Writer) SessionOption {
	return func(i *InteractiveSession) {
		i.output = w
	}
}
func (i *InteractiveSession) Reset() {
	i.Prompt = ""
	i.Default = ""
	i.ValHint = ""
	i.response = ""
}
func (i *InteractiveSession) Say(format string, args ...interface{}) *InteractiveSession {
	fmt.Fprintf(i.output, fmt.Sprintf("\n%s\n", format), args...)
	return i
}
func (i *InteractiveSession) Pause() {
	i.Prompt = "\nPress [Enter] to continue."
	i.get(noColon)
}
func (i *InteractiveSession) PauseWithPrompt(format string, args ...interface{}) {
	i.Prompt = fmt.Sprintf(format, args...)
	i.get(noColon)
}
func (i *InteractiveSession) get(opts ...getOpt) (err error) {
	contains := func(wanted getOpt) bool {
		for _, opt := range opts {
			if opt == wanted {
				return true
			}
		}
		return false
	}
	if i.output == nil {
		i.output = bufio.NewWriter(os.Stdout)
	}
	if i.input == nil {
		i.input = bufio.NewReader(os.Stdin)
	}
	switch {
	case len(i.Default) > 0:
		fmt.Fprintf(i.output, "%s  [%s]: ", i.Prompt, i.Default)
	case len(i.ValHint) > 0:
		fmt.Fprintf(i.output, "%s (%s): ", i.Prompt, i.ValHint)
	case contains(noColon):
		fmt.Fprintf(i.output, "%s", i.Prompt)
	case len(i.Prompt) > 0:
		fmt.Fprintf(i.output, "%s: ", i.Prompt)
	default:
	}
	i.response, err = i.input.ReadString('\n')
	if err != nil {
		return err
	}
	i.response = strings.TrimRight(i.response, " \n\r")
	if len(i.Default) > 0 && len(i.response) == 0 {
		switch i.Default {
		case "y/N":
			i.response = "n"
		case "Y/n":
			i.response = "y"
		default:
			i.response = i.Default
		}
	}
	return nil
}
func (i *InteractiveSession) Warn(format string, args ...interface{}) *InteractiveSession {
	fmt.Fprintf(i.output, "\n%s: %s\n", Styled(Yellow).ApplyTo("Warning"), fmt.Sprintf(format, args...))
	return i
}
func (i *InteractiveSession) Error(format string, args ...interface{}) {
	fmt.Fprintf(i.output, "\n\n%s: %s\n", Styled(Red).ApplyTo("Error:"), fmt.Sprintf(format, args...))
	os.Exit(1)
}
func (i *InteractiveSession) Ask(prompt string, validators ...ValidationFunc) string {
	return i.ask(prompt, "", "", validators...)
}
func (i *InteractiveSession) AskWithDefault(prompt string, defaultChoice string, validators ...ValidationFunc) string {
	return i.ask(prompt, defaultChoice, "", validators...)
}
func (i *InteractiveSession) AskWithHint(prompt string, hint string, validators ...ValidationFunc) string {
	return i.ask(prompt, "", hint, validators...)
}
func (i *InteractiveSession) ask(prompt string, def string, hint string, validators ...ValidationFunc) string {
	i.Prompt = prompt
	i.Default = def
	i.ValHint = hint
	i.get()
	for _, validator := range validators {
		if ok, err := validator(i.response); !ok {
			i.Say("\nError: %s\n\n", err)
			i.ask(prompt, def, hint, validators...)
		}
	}
	return i.response
}
func (i *InteractiveSession) AskPassword(validators ...ValidationFunc) string {
	return askPassword(i, "Password: ", validators...)
}
func (i *InteractiveSession) AskPasswordPrompt(prompt string, validators ...ValidationFunc) string {
	return askPassword(i, prompt, validators...)
}
func askPassword(i *InteractiveSession, prompt string, validators ...ValidationFunc) string {
	fmt.Fprintf(i.output, "Password: ")
	pw, err := terminal.ReadPassword(0)
	if err != nil {
		i.Error("\n%s\n", err)
	}
	pwS := strings.TrimSpace(string(pw))
	for _, validator := range validators {
		if ok, err := validator(pwS); !ok {
			i.Say("\nError: %s\n\n", err)
			i.AskPassword(validators...)
		}
	}
	return pwS
}