func AutoTLS(
	addr string,
	domain string, email string,
	hostConfigs ...host.Configurator) Runner {
	return func(app *Application) error {
		return app.NewHost(&http.Server{Addr: addr}).
			Configure(hostConfigs...).
			ListenAndServeAutoTLS(domain, email, "letscache")
	}
}
AutoTLS can be used as an argument for the `Run` method.
It will start the Application's secure server using
certifications created on the fly by the "autocert" golang/x package,
so localhost may not be working, use it at "production" machine.

Addr should have the form of [host]:port, i.e mydomain.com:443.

The whitelisted domains are separated by whitespace in "domain" argument,
i.e "iris-go.com", can be different than "addr".
If empty, all hosts are currently allowed. This is not recommended,
as it opens a potential attack where clients connect to a server
by IP address and pretend to be asking for an incorrect host name.
Manager will attempt to obtain a certificate for that host, incorrectly,
eventually reaching the CA's rate limit for certificate requests
and making it impossible to obtain actual certificates.

For an "e-mail" use a non-public one, letsencrypt needs that for your own security.

Note: `AutoTLS` will start a new server for you
which will redirect all http versions to their https, including subdomains as well.

Last argument is optional, it accepts one or more
`func(*host.Configurator)` that are being executed
on that specific host that this function will create to start the server.
Via host configurators you can configure the back-end host supervisor,
i.e to add events for shutdown, serve or error.
An example of this use case can be found at:
https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
Look at the `ConfigureHost` too.

Usage:
app.Run(iris.AutoTLS("iris-go.com:443", "iris-go.com www.iris-go.com", "mail@example.com"))

See `Run` and `core/host/Supervisor#ListenAndServeAutoTLS` for more.
package iris
import (
	stdContext "context"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
	"time"
	"github.com/kataras/golog"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/errors"
	"github.com/kataras/iris/core/host"
	"github.com/kataras/iris/core/maintenance"
	"github.com/kataras/iris/core/netutil"
	"github.com/kataras/iris/core/router"
	"github.com/kataras/iris/core/handlerconv"
	"github.com/kataras/iris/cache"
	"github.com/kataras/iris/view"
	requestLogger "github.com/kataras/iris/middleware/logger"
	"github.com/kataras/iris/middleware/recover"
)
var (
	Version = maintenance.Version
)
const (
	StatusContinue           = 100  
	StatusSwitchingProtocols = 101  
	StatusProcessing         = 102  
	StatusOK                   = 200  
	StatusCreated              = 201  
	StatusAccepted             = 202  
	StatusNonAuthoritativeInfo = 203  
	StatusNoContent            = 204  
	StatusResetContent         = 205  
	StatusPartialContent       = 206  
	StatusMultiStatus          = 207  
	StatusAlreadyReported      = 208  
	StatusIMUsed               = 226  
	StatusMultipleChoices   = 300  
	StatusMovedPermanently  = 301  
	StatusFound             = 302  
	StatusSeeOther          = 303  
	StatusNotModified       = 304  
	StatusUseProxy          = 305  
	_                       = 306  
	StatusTemporaryRedirect = 307  
	StatusPermanentRedirect = 308  
	StatusBadRequest                   = 400  
	StatusUnauthorized                 = 401  
	StatusPaymentRequired              = 402  
	StatusForbidden                    = 403  
	StatusNotFound                     = 404  
	StatusMethodNotAllowed             = 405  
	StatusNotAcceptable                = 406  
	StatusProxyAuthRequired            = 407  
	StatusRequestTimeout               = 408  
	StatusConflict                     = 409  
	StatusGone                         = 410  
	StatusLengthRequired               = 411  
	StatusPreconditionFailed           = 412  
	StatusRequestEntityTooLarge        = 413  
	StatusRequestURITooLong            = 414  
	StatusUnsupportedMediaType         = 415  
	StatusRequestedRangeNotSatisfiable = 416  
	StatusExpectationFailed            = 417  
	StatusTeapot                       = 418  
	StatusUnprocessableEntity          = 422  
	StatusLocked                       = 423  
	StatusFailedDependency             = 424  
	StatusUpgradeRequired              = 426  
	StatusPreconditionRequired         = 428  
	StatusTooManyRequests              = 429  
	StatusRequestHeaderFieldsTooLarge  = 431  
	StatusUnavailableForLegalReasons   = 451  
	StatusInternalServerError           = 500  
	StatusNotImplemented                = 501  
	StatusBadGateway                    = 502  
	StatusServiceUnavailable            = 503  
	StatusGatewayTimeout                = 504  
	StatusHTTPVersionNotSupported       = 505  
	StatusVariantAlsoNegotiates         = 506  
	StatusInsufficientStorage           = 507  
	StatusLoopDetected                  = 508  
	StatusNotExtended                   = 510  
	StatusNetworkAuthenticationRequired = 511  
)
const (
	MethodGet     = "GET"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodDelete  = "DELETE"
	MethodConnect = "CONNECT"
	MethodHead    = "HEAD"
	MethodPatch   = "PATCH"
	MethodOptions = "OPTIONS"
	MethodTrace   = "TRACE"
)
const MethodNone = "NONE"
type Application struct {
	*router.APIBuilder
	*router.Router
	ContextPool *context.Pool
	config *Configuration
	logger *golog.Logger
	view view.View
	once sync.Once
	mu sync.Mutex
	Hosts             []*host.Supervisor
	hostConfigurators []host.Configurator
}
func New() *Application {
	config := DefaultConfiguration()
	app := &Application{
		config:     &config,
		logger:     golog.Default,
		APIBuilder: router.NewAPIBuilder(),
		Router:     router.NewRouter(),
	}
	app.ContextPool = context.New(func() context.Context {
		return context.NewContext(app)
	})
	return app
}
func Default() *Application {
	app := New()
	app.Use(recover.New())
	app.Use(requestLogger.New())
	return app
}
func (app *Application) WWW() router.Party {
	return app.SubdomainRedirect(app, app.Subdomain("www"))
}
func (app *Application) SubdomainRedirect(from, to router.Party) router.Party {
	sd := router.NewSubdomainRedirectWrapper(app.ConfigurationReadOnly().GetVHost, from.GetRelPath(), to.GetRelPath())
	app.WrapRouter(sd)
	return to
}
func (app *Application) Configure(configurators ...Configurator) *Application {
	for _, cfg := range configurators {
		cfg(app)
	}
	return app
}
func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
	return app.config
}
func (app *Application) Logger() *golog.Logger {
	return app.logger
}
var (
	HTML = view.HTML
	Django = view.Django
	Handlebars = view.Handlebars
	Pug = view.Pug
	Amber = view.Amber
)
const NoLayout = view.NoLayout
func (app *Application) RegisterView(viewEngine view.Engine) {
	app.view.Register(viewEngine)
}
func (app *Application) View(writer io.Writer, filename string, layout string, bindingData interface{}) error {
	if app.view.Len() == 0 {
		err := errors.New("view engine is missing, use `RegisterView`")
		app.Logger().Error(err)
		return err
	}
	err := app.view.ExecuteWriter(writer, filename, layout, bindingData)
	if err != nil {
		app.Logger().Error(err)
	}
	return err
}
var (
	LimitRequestBodySize = context.LimitRequestBodySize
	StaticEmbeddedHandler = router.StaticEmbeddedHandler
	StripPrefix = router.StripPrefix
	Gzip = context.Gzip
	FromStd = handlerconv.FromStd
	Cache = cache.Handler
	NoCache = cache.NoCache
	StaticCache = cache.StaticCache
	Cache304 = cache.Cache304
)
func (app *Application) SPA(assetHandler context.Handler) *router.SPABuilder {
	s := router.NewSPABuilder(assetHandler)
	app.APIBuilder.HandleMany("GET HEAD", "/{f:path}", s.Handler)
	return s
}
func (app *Application) ConfigureHost(configurators ...host.Configurator) *Application {
	app.mu.Lock()
	app.hostConfigurators = append(app.hostConfigurators, configurators...)
	app.mu.Unlock()
	return app
}
func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
	app.mu.Lock()
	defer app.mu.Unlock()
	if srv.Handler == nil {
		srv.Handler = app.Router
	}
	if srv.ErrorLog == nil {
		srv.ErrorLog = log.New(app.logger.Printer.Output, "[HTTP Server] ", 0)
	}
	if srv.Addr == "" {
		srv.Addr = ":8080"
	}
	app.logger.Debugf("Host: addr is %s", srv.Addr)
	su := host.New(srv)
	if app.config.vhost == "" {  
		app.config.vhost = netutil.ResolveVHost(srv.Addr)
	}
	app.logger.Debugf("Host: virtual host is %s", app.config.vhost)
	if !app.config.DisableStartupLog {
		su.RegisterOnServe(host.WriteStartupLogOnServe(app.logger.Printer.Output))  
		app.logger.Debugf("Host: register startup notifier")
	}
	if !app.config.DisableInterruptHandler {
		shutdownTimeout := 5 * time.Second
		host.RegisterOnInterrupt(host.ShutdownOnInterrupt(su, shutdownTimeout))
		app.logger.Debugf("Host: register server shutdown on interrupt(CTRL+C/CMD+C)")
	}
	su.IgnoredErrors = append(su.IgnoredErrors, app.config.IgnoreServerErrors...)
	if len(su.IgnoredErrors) > 0 {
		app.logger.Debugf("Host: server will ignore the following errors: %s", su.IgnoredErrors)
	}
	su.Configure(app.hostConfigurators...)
	app.Hosts = append(app.Hosts, su)
	return su
}
var RegisterOnInterrupt = host.RegisterOnInterrupt
func (app *Application) Shutdown(ctx stdContext.Context) error {
	for i, su := range app.Hosts {
		app.logger.Debugf("Host[%d]: Shutdown now", i)
		if err := su.Shutdown(ctx); err != nil {
			app.logger.Debugf("Host[%d]: Error while trying to shutdown", i)
			return err
		}
	}
	return nil
}
type Runner func(*Application) error
func Listener(l net.Listener, hostConfigs ...host.Configurator) Runner {
	return func(app *Application) error {
		app.config.vhost = netutil.ResolveVHost(l.Addr().String())
		return app.NewHost(&http.Server{Addr: l.Addr().String()}).
			Configure(hostConfigs...).
			Serve(l)
	}
}
func Server(srv *http.Server, hostConfigs ...host.Configurator) Runner {
	return func(app *Application) error {
		return app.NewHost(srv).
			Configure(hostConfigs...).
			ListenAndServe()
	}
}
func Addr(addr string, hostConfigs ...host.Configurator) Runner {
	return func(app *Application) error {
		return app.NewHost(&http.Server{Addr: addr}).
			Configure(hostConfigs...).
			ListenAndServe()
	}
}
func TLS(addr string, certFile, keyFile string, hostConfigs ...host.Configurator) Runner {
	return func(app *Application) error {
		return app.NewHost(&http.Server{Addr: addr}).
			Configure(hostConfigs...).
			ListenAndServeTLS(certFile, keyFile)
	}
}