func (r *ResponseMatcher) Handler(h Handler) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.h = h
	if !r.mux.res[r] {
		r.mux.res[r] = true
	}
	return r
}
Handler sets the Handler to be called when this Response Handler is the match for
a given response. It registers the Response Handler in its parent Mux.
package fetchbot
import (
	"net/http"
	"strings"
	"sync"
)
type Context struct {
	Cmd Command
	Q   *Queue
}
type Handler interface {
	Handle(*Context, *http.Response, error)
}
type HandlerFunc func(*Context, *http.Response, error)
func (h HandlerFunc) Handle(ctx *Context, res *http.Response, err error) {
	h(ctx, res, err)
}
type Mux struct {
	DefaultHandler Handler
	mu   sync.RWMutex
	errm map[error]Handler
	res  map[*ResponseMatcher]bool  
}
func NewMux() *Mux {
	return &Mux{
		DefaultHandler: HandlerFunc(func(ctx *Context, res *http.Response, err error) {}),
		errm:           make(map[error]Handler),
		res:            make(map[*ResponseMatcher]bool),
	}
}
func (mux *Mux) Handle(ctx *Context, res *http.Response, err error) {
	mux.mu.RLock()
	defer mux.mu.RUnlock()
	if err != nil {
		if h, ok := mux.errm[err]; ok {
			h.Handle(ctx, res, err)
			return
		}
		if h, ok := mux.errm[nil]; ok {
			h.Handle(ctx, res, err)
			return
		}
	} else {
		var h Handler
		var n = -1
		for r := range mux.res {
			if ok, cnt := r.match(res); ok {
				if cnt > n {
					h, n = r.h, cnt
				}
			}
		}
		if h != nil {
			h.Handle(ctx, res, err)
			return
		}
	}
	mux.DefaultHandler.Handle(ctx, res, err)
}
func (mux *Mux) HandleError(err error, h Handler) {
	mux.mu.Lock()
	defer mux.mu.Unlock()
	mux.errm[err] = h
}
func (mux *Mux) HandleErrors(h Handler) {
	mux.HandleError(nil, h)
}
func (mux *Mux) Response() *ResponseMatcher {
	return &ResponseMatcher{mux: mux}
}
type ResponseMatcher struct {
	method      string
	contentType string
	minStatus   int
	maxStatus   int
	scheme      string
	host        string
	path        string
	predicate   func(*http.Response) bool
	h           Handler
	mux         *Mux
}
func (r *ResponseMatcher) match(res *http.Response) (bool, int) {
	if r.method != "" {
		if r.method != res.Request.Method {
			return false, 0
		}
	}
	if r.contentType != "" {
		if r.contentType != getContentType(res.Header.Get("Content-Type")) {
			return false, 0
		}
	}
	if r.minStatus != 0 || r.maxStatus != 0 {
		if res.StatusCode < r.minStatus || res.StatusCode > r.maxStatus {
			return false, 0
		}
	}
	if r.scheme != "" {
		if res.Request.URL.Scheme != r.scheme {
			return false, 0
		}
	}
	if r.host != "" {
		if res.Request.URL.Host != r.host {
			return false, 0
		}
	}
	if r.predicate != nil {
		if !r.predicate(res) {
			return false, 0
		}
	}
	if r.path != "" {
		if strings.HasPrefix(res.Request.URL.Path, r.path) {
			return true, len(r.path)
		}
		return false, 0
	}
	return true, 0
}
func getContentType(val string) string {
	args := strings.SplitN(val, ";", 2)
	if len(args) > 0 {
		return strings.TrimSpace(args[0])
	}
	return val
}
func (r *ResponseMatcher) Method(m string) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.method = m
	return r
}
func (r *ResponseMatcher) ContentType(ct string) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.contentType = ct
	return r
}
func (r *ResponseMatcher) Status(code int) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.minStatus = code
	r.maxStatus = code
	return r
}
func (r *ResponseMatcher) StatusRange(min, max int) *ResponseMatcher {
	if min > max {
		min, max = max, min
	}
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.minStatus = min
	r.maxStatus = max
	return r
}
func (r *ResponseMatcher) Scheme(scheme string) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.scheme = scheme
	return r
}
func (r *ResponseMatcher) Host(host string) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.host = host
	return r
}
func (r *ResponseMatcher) Path(p string) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.path = p
	return r
}
func (r *ResponseMatcher) Custom(predicate func(*http.Response) bool) *ResponseMatcher {
	r.mux.mu.Lock()
	defer r.mux.mu.Unlock()
	r.predicate = predicate
	return r
}