func (p *pathBuilder) options(opts Options, jskeys []string) (string, error) {
	p.checkNotInQuery()
	p.inQuery = true
	var keys = make([]string, len(opts))
	var i int
	for k := range opts {
		keys[i] = k
		i++
	}
	sort.Strings(keys)
	p.buf.WriteByte('?')
	amp := false
	for _, k := range keys {
		if amp {
			p.buf.WriteByte('&')
		}
		p.buf.WriteString(url.QueryEscape(k))
		p.buf.WriteByte('=')
		isjson := false
		for _, jskey := range jskeys {
			if k == jskey {
				isjson = true
				break
			}
		}
		if isjson {
			jsonv, err := json.Marshal(opts[k])
			if err != nil {
				return "", fmt.Errorf("invalid option %q: %v", k, err)
			}
			p.buf.WriteString(url.QueryEscape(string(jsonv)))
		} else {
			if err := encval(&p.buf, k, opts[k]); err != nil {
				return "", fmt.Errorf("invalid option %q: %v", k, err)
			}
		}
		amp = true
	}
	return p.path(), nil
}
options encodes the given options to the query.
package couchdb
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"sync"
)
type Options map[string]interface{}
func (opts Options) clone() (result Options) {
	result = make(Options)
	for k, v := range opts {
		result[k] = v
	}
	return
}
type transport struct {
	prefix string  
	http   *http.Client
	mu     sync.RWMutex
	auth   Auth
}
func newTransport(prefix string, rt http.RoundTripper, auth Auth) *transport {
	return &transport{
		prefix: strings.TrimRight(prefix, "/"),
		http:   &http.Client{Transport: rt},
		auth:   auth,
	}
}
func (t *transport) setAuth(a Auth) {
	t.mu.Lock()
	t.auth = a
	t.mu.Unlock()
}
func (t *transport) newRequest(method, path string, body io.Reader) (*http.Request, error) {
	req, err := http.NewRequest(method, t.prefix+path, body)
	if err != nil {
		return nil, err
	}
	t.mu.RLock()
	defer t.mu.RUnlock()
	if t.auth != nil {
		t.auth.AddAuth(req)
	}
	return req, nil
}
func (t *transport) request(method, path string, body io.Reader) (*http.Response, error) {
	req, err := t.newRequest(method, path, body)
	if err != nil {
		return nil, err
	}
	if body != nil {
		req.Header.Set("content-type", "application/json")
	}
	resp, err := t.http.Do(req)
	if err != nil {
		return nil, err
	} else if resp.StatusCode >= 400 {
		return nil, parseError(req, resp)  
	} else {
		return resp, nil
	}
}
func (t *transport) closedRequest(method, path string, body io.Reader) (*http.Response, error) {
	resp, err := t.request(method, path, body)
	if err == nil {
		resp.Body.Close()
	}
	return resp, err
}
type pathBuilder struct {
	buf     bytes.Buffer
	inQuery bool
}
func dbpath(name string) string {
	return "/" + url.QueryEscape(name)
}
func (p *pathBuilder) path() string {
	return p.buf.String()
}
func (p *pathBuilder) checkNotInQuery() {
	if p.inQuery {
		panic("can't add path elements after query string")
	}
}
func (p *pathBuilder) docID(id string) *pathBuilder {
	p.checkNotInQuery()
	if len(id) > 0 && id[0] != '_' {
		p.add(id)
		return p
	}
	slash := strings.IndexByte(id, '/')
	if slash == -1 {
		p.add(id)
		return p
	}
	p.addRaw(id[:slash])
	p.add(id[slash+1:])
	return p
}
func (p *pathBuilder) add(segment string) *pathBuilder {
	p.checkNotInQuery()
	p.buf.WriteByte('/')
	p.buf.WriteString(url.QueryEscape(segment))
	return p
}
func (p *pathBuilder) addRaw(path string) *pathBuilder {
	p.checkNotInQuery()
	p.buf.WriteByte('/')
	p.buf.WriteString(path)
	return p
}
func (p *pathBuilder) rev(rev string) string {
	p.checkNotInQuery()
	p.inQuery = true
	if rev != "" {
		p.buf.WriteString("?rev=")
		p.buf.WriteString(url.QueryEscape(rev))
	}
	return p.path()
}