func lockFileName(path string) string {
	return path + ".lock"
}
lockFileName returns the name of the lock file associated with
the given path.
package cookiejar
import (
	"encoding/json"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"time"
	"gopkg.in/retry.v1"
	filelock "github.com/juju/go4/lock"
	"gopkg.in/errgo.v1"
)
func (j *Jar) Save() error {
	if j.filename == "" {
		return nil
	}
	return j.save(time.Now())
}
func (j *Jar) MarshalJSON() ([]byte, error) {
	j.mu.Lock()
	defer j.mu.Unlock()
	data, _ := json.Marshal(j.allPersistentEntries())
	return data, nil
}
func (j *Jar) save(now time.Time) error {
	locked, err := lockFile(lockFileName(j.filename))
	if err != nil {
		return errgo.Mask(err)
	}
	defer locked.Close()
	f, err := os.OpenFile(j.filename, os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		return errgo.Mask(err)
	}
	defer f.Close()
	j.mu.Lock()
	defer j.mu.Unlock()
	if err := j.mergeFrom(f); err != nil {
		log.Printf("cannot read cookie file to merge it; ignoring it: %v", err)
	}
	j.deleteExpired(now)
	if err := f.Truncate(0); err != nil {
		return errgo.Notef(err, "cannot truncate file")
	}
	if _, err := f.Seek(0, 0); err != nil {
		return errgo.Mask(err)
	}
	return j.writeTo(f)
}
func (j *Jar) load() error {
	if _, err := os.Stat(filepath.Dir(j.filename)); os.IsNotExist(err) {
		return nil
	}
	locked, err := lockFile(lockFileName(j.filename))
	if err != nil {
		return errgo.Mask(err)
	}
	defer locked.Close()
	f, err := os.Open(j.filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	defer f.Close()
	if err := j.mergeFrom(f); err != nil {
		return errgo.Mask(err)
	}
	return nil
}
func (j *Jar) mergeFrom(r io.Reader) error {
	decoder := json.NewDecoder(r)
	var data json.RawMessage
	if err := decoder.Decode(&data); err != nil {
		if err == io.EOF {
			return nil
		}
		return err
	}
	var entries []entry
	if err := json.Unmarshal(data, &entries); err != nil {
		log.Printf("warning: discarding cookies in invalid format (error: %v)", err)
		return nil
	}
	j.merge(entries)
	return nil
}
func (j *Jar) writeTo(w io.Writer) error {
	encoder := json.NewEncoder(w)
	entries := j.allPersistentEntries()
	if err := encoder.Encode(entries); err != nil {
		return err
	}
	return nil
}
func (j *Jar) allPersistentEntries() []entry {
	var entries []entry
	for _, submap := range j.entries {
		for _, e := range submap {
			if e.Persistent {
				entries = append(entries, e)
			}
		}
	}
	sort.Sort(byCanonicalHost{entries})
	return entries
}