func XML(indent bool) Option {
	return joinOpts(
		WithMarshaler(&XMLMarshaler{Indent: indent}),
		ContentType(MediaTypeXML),
		Accept(MediaTypeXML),
	)
}
XML sets Requester.Marshaler to the XMLMarshaler.
If the arg is true, the generated XML will be indented.
The XMLMarshaler will set the Content-Type header to
"application/xml" unless explicitly overwritten.
package requester
import (
	"encoding/base64"
	"net/http"
	"net/url"
	"strings"
	"unicode"
	"github.com/ansel1/merry"
	"github.com/gemalto/requester/httpclient"
	goquery "github.com/google/go-querystring/query"
)
const (
	HeaderAccept        = "Accept"
	HeaderContentType   = "Content-Type"
	HeaderAuthorization = "Authorization"
	HeaderRange         = "Range"
	MediaTypeJSON          = "application/json"
	MediaTypeXML           = "application/xml"
	MediaTypeForm          = "application/x-www-form-urlencoded"
	MediaTypeOctetStream   = "application/octet-stream"
	MediaTypeTextPlain     = "text/plain"
	MediaTypeMultipart     = "multipart/mixed"
	MediaTypeMultipartForm = "multipart/form-data"
)
type Option interface {
	Apply(*Requester) error
}
type OptionFunc func(*Requester) error
func (f OptionFunc) Apply(r *Requester) error {
	return f(r)
}
func (r *Requester) With(opts ...Option) (*Requester, error) {
	r2 := r.Clone()
	err := r2.Apply(opts...)
	if err != nil {
		return nil, err
	}
	return r2, nil
}
func (r *Requester) MustWith(opts ...Option) *Requester {
	if r2, err := r.With(opts...); err != nil {
		panic(err)
	} else {
		return r2
	}
}
func (r *Requester) Apply(opts ...Option) error {
	for _, o := range opts {
		err := o.Apply(r)
		if err != nil {
			return merry.Prepend(err, "applying options")
		}
	}
	return nil
}
func (r *Requester) MustApply(opts ...Option) {
	if err := r.Apply(opts...); err != nil {
		panic(err)
	}
}
func Method(m string, paths ...string) Option {
	return OptionFunc(func(r *Requester) error {
		r.Method = m
		if len(paths) > 0 {
			err := RelativeURL(paths...).Apply(r)
			if err != nil {
				return err
			}
		}
		return nil
	})
}
func Head(paths ...string) Option {
	return Method(http.MethodHead, paths...)
}
func Get(paths ...string) Option {
	return Method(http.MethodGet, paths...)
}
func Post(paths ...string) Option {
	return Method(http.MethodPost, paths...)
}
func Put(paths ...string) Option {
	return Method(http.MethodPut, paths...)
}
func Patch(paths ...string) Option {
	return Method(http.MethodPatch, paths...)
}
func Delete(paths ...string) Option {
	return Method(http.MethodDelete, paths...)
}
func AddHeader(key, value string) Option {
	return OptionFunc(func(b *Requester) error {
		if b.Header == nil {
			b.Header = make(http.Header)
		}
		b.Header.Add(key, value)
		return nil
	})
}
func Header(key, value string) Option {
	return OptionFunc(func(b *Requester) error {
		if b.Header == nil {
			b.Header = make(http.Header)
		}
		b.Header.Set(key, value)
		return nil
	})
}
func DeleteHeader(key string) Option {
	return OptionFunc(func(b *Requester) error {
		b.Header.Del(key)
		return nil
	})
}
func BasicAuth(username, password string) Option {
	if username == "" && password == "" {
		return DeleteHeader(HeaderAuthorization)
	}
	return Header(HeaderAuthorization, "Basic "+basicAuth(username, password))
}
func basicAuth(username, password string) string {
	auth := username + ":" + password
	return base64.StdEncoding.EncodeToString([]byte(auth))
}
func BearerAuth(token string) Option {
	if token == "" {
		return DeleteHeader(HeaderAuthorization)
	}
	return Header(HeaderAuthorization, "Bearer "+token)
}
func URL(rawurl string) Option {
	return OptionFunc(func(b *Requester) error {
		u, err := url.Parse(rawurl)
		if err != nil {
			return merry.Prepend(err, "invalid url")
		}
		b.URL = u
		return nil
	})
}
func RelativeURL(paths ...string) Option {
	return OptionFunc(func(r *Requester) error {
		for _, p := range paths {
			u, err := url.Parse(p)
			if err != nil {
				return merry.Prepend(err, "invalid url")
			}
			if r.URL == nil {
				r.URL = u
			} else {
				r.URL = r.URL.ResolveReference(u)
			}
		}
		return nil
	})
}
func AppendPath(elements ...string) Option {
	return OptionFunc(func(r *Requester) error {
		if len(elements) == 0 {
			return nil
		}
		var basePath string
		if r.URL != nil {
			basePath = r.URL.EscapedPath()
		}
		trailingSlash := strings.HasSuffix(basePath, "/")
		els := elements[:0]
		for _, e := range elements {
			trailingSlash = strings.HasSuffix(e, "/")
			e = strings.TrimFunc(e, func(r rune) bool {
				return unicode.IsSpace(r) || r == rune('/')
			})
			if len(e) > 0 {
				els = append(els, e)
			}
		}
		els = append(els, "")
		copy(els[1:], els)
		els[0] = strings.TrimSuffix(basePath, "/")
		newPath := strings.Join(els, "/")
		if trailingSlash {
			newPath += "/"
		}
		return RelativeURL(newPath).Apply(r)
	})
}
func QueryParams(queryStructs ...interface{}) Option {
	return OptionFunc(func(s *Requester) error {
		if s.QueryParams == nil {
			s.QueryParams = url.Values{}
		}
		for _, queryStruct := range queryStructs {
			var values url.Values
			switch t := queryStruct.(type) {
			case nil:
			case map[string]string:
				for key, value := range t {
					s.QueryParams.Add(key, value)
				}
				continue
			case map[string][]string:
				values = url.Values(t)
			case url.Values:
				values = t
			default:
				var err error
				values, err = goquery.Values(queryStruct)
				if err != nil {
					return merry.Prepend(err, "invalid query struct")
				}
			}
			for key, values := range values {
				for _, value := range values {
					s.QueryParams.Add(key, value)
				}
			}
		}
		return nil
	})
}
func QueryParam(k, v string) Option {
	return OptionFunc(func(s *Requester) error {
		if k == "" {
			return nil
		}
		if s.QueryParams == nil {
			s.QueryParams = url.Values{}
		}
		s.QueryParams.Add(k, v)
		return nil
	})
}
func Body(body interface{}) Option {
	return OptionFunc(func(b *Requester) error {
		b.Body = body
		return nil
	})
}
func WithMarshaler(m Marshaler) Option {
	return OptionFunc(func(b *Requester) error {
		b.Marshaler = m
		return nil
	})
}
func WithUnmarshaler(m Unmarshaler) Option {
	return OptionFunc(func(b *Requester) error {
		b.Unmarshaler = m
		return nil
	})
}
func Accept(accept string) Option {
	return Header(HeaderAccept, accept)
}
func ContentType(contentType string) Option {
	return Header(HeaderContentType, contentType)
}
func Range(byteRange string) Option {
	return Header(HeaderRange, byteRange)
}
func Host(host string) Option {
	return OptionFunc(func(b *Requester) error {
		b.Host = host
		return nil
	})
}
func joinOpts(opts ...Option) Option {
	return OptionFunc(func(r *Requester) error {
		for _, opt := range opts {
			err := opt.Apply(r)
			if err != nil {
				return err
			}
		}
		return nil
	})
}
func JSON(indent bool) Option {
	return joinOpts(
		WithMarshaler(&JSONMarshaler{Indent: indent}),
		ContentType(MediaTypeJSON),
		Accept(MediaTypeJSON),
	)
}