<commit_before>package appcast

// Outputer is the interface that wraps the Output methods.
//
// This interface should be embedded by more use-case specific Outputer
// interfaces.
type Outputer interface {
	Save() error
	GenerateChecksum(algorithm ChecksumAlgorithm)
	Content() []byte
	SetContent(content []byte)
	Checksum() *Checksum
	Provider() Provider
	SetProvider(provider Provider)
	Appcast() Appcaster
	SetAppcast(appcast Appcaster)
}

// Output represents an appcast output data.
//
// This struct should be embedded by more use-case specific Output structs.
type Output struct {
	// content specifies an appcast data which will be outputted.
	content []byte

	// checksum specifies the Checksum pointer that hold a checksum data about
	// the Output.content.
	//
	// This value is set by calling Output.GenerateChecksum.
	checksum *Checksum

	// provider specifies the one of the supported appcast providers.
	provider Provider

	// appcast specifies the provider-specific appcast guessed for the current
	// Output.
	appcast Appcaster
}

// Save should implement a way of saving an appcast content from the
// Output.content depending on the chosen Outputer.
func (o *Output) Save() error {
	panic("implement me")
}

// GenerateChecksum creates a new Checksum instance based on the provided
// algorithm.
func (o *Output) GenerateChecksum(algorithm ChecksumAlgorithm) {
	o.checksum = NewChecksum(algorithm, o.content)
}

// Content is an Output.content getter.
func (o *Output) Content() []byte {
	return o.content
}

// SetContent is an Output.content setter.
func (o *Output) SetContent(content []byte) {
	o.content = content
}

// Checksum is an Output.checksum getter.
func (o *Output) Checksum() *Checksum {
	return o.checksum
}

// Provider is an Output.provider getter.
func (o *Output) Provider() Provider {
	return o.provider
}

// SetProvider is an Output.provider setter.
func (o *Output) SetProvider(provider Provider) {
	o.provider = provider
}

// Appcast is a Output.appcast getter.
func (o *Output) Appcast() Appcaster {
	return o.appcast
}

// SetAppcast is a Output.appcast setter.
func (o *Output) SetAppcast(appcast Appcaster) {
	o.appcast = appcast
}
<commit_msg>Update Output.GenerateChecksum to return the Checksum pointer<commit_after>package appcast

// Outputer is the interface that wraps the Output methods.
//
// This interface should be embedded by more use-case specific Outputer
// interfaces.
type Outputer interface {
	Save() error
	GenerateChecksum(algorithm ChecksumAlgorithm) *Checksum
	Content() []byte
	SetContent(content []byte)
	Checksum() *Checksum
	Provider() Provider
	SetProvider(provider Provider)
	Appcast() Appcaster
	SetAppcast(appcast Appcaster)
}

// Output represents an appcast output data.
//
// This struct should be embedded by more use-case specific Output structs.
type Output struct {
	// content specifies an appcast data which will be outputted.
	content []byte

	// checksum specifies the Checksum pointer that hold a checksum data about
	// the Output.content.
	//
	// This value is set by calling Output.GenerateChecksum.
	checksum *Checksum

	// provider specifies the one of the supported appcast providers.
	provider Provider

	// appcast specifies the provider-specific appcast guessed for the current
	// Output.
	appcast Appcaster
}

// Save should implement a way of saving an appcast content from the
// Output.content depending on the chosen Outputer.
func (o *Output) Save() error {
	panic("implement me")
}

// GenerateChecksum creates a new Checksum instance pointer based on the
// provided algorithm and sets it as an Output.checksum.
func (o *Output) GenerateChecksum(algorithm ChecksumAlgorithm) *Checksum {
	c := NewChecksum(algorithm, o.content)
	o.checksum = c
	return c
}

// Content is an Output.content getter.
func (o *Output) Content() []byte {
	return o.content
}

// SetContent is an Output.content setter.
func (o *Output) SetContent(content []byte) {
	o.content = content
}

// Checksum is an Output.checksum getter.
func (o *Output) Checksum() *Checksum {
	return o.checksum
}

// Provider is an Output.provider getter.
func (o *Output) Provider() Provider {
	return o.provider
}

// SetProvider is an Output.provider setter.
func (o *Output) SetProvider(provider Provider) {
	o.provider = provider
}

// Appcast is a Output.appcast getter.
func (o *Output) Appcast() Appcaster {
	return o.appcast
}

// SetAppcast is a Output.appcast setter.
func (o *Output) SetAppcast(appcast Appcaster) {
	o.appcast = appcast
}
<|endoftext|>


<commit_before>// -*- tab-width: 4; -*-

package main

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/goware/urlx"
)

func underline(s string) string {
	return fmt.Sprintf("\033[4m%s\033[0m", s)
}
func bold(s string) string {
	return fmt.Sprintf("\033[1m%s\033[0m", s)
}
func red(s string) string {
	return fmt.Sprintf("\033[31m%s\033[0m", s)
}
func green(s string) string {
	return fmt.Sprintf("\033[32m%s\033[0m", s)
}
func boldgreen(s string) string {
	return fmt.Sprintf("\033[32;1m%s\033[0m", s)
}
func blue(s string) string {
	return fmt.Sprintf("\033[34m%s\033[0m", s)
}

func PrintTweet(tweet Tweet, now time.Time) {
	text := ShortenMentions(tweet.Text)

	nick := green(tweet.Tweeter.Nick)
	if NormalizeURL(tweet.Tweeter.URL) == NormalizeURL(conf.Twturl) {
		nick = boldgreen(tweet.Tweeter.Nick)
	}
	fmt.Printf("> %s (%s)\n%s\n",
		nick,
		PrettyDuration(now.Sub(tweet.Created)),
		text)
}

func PrintTweetRaw(tweet Tweet) {
	fmt.Printf("%s\t%s\t%s",
		tweet.Tweeter.URL,
		tweet.Created.Format(time.RFC3339),
		tweet.Text)
}

// Turns "@<nick URL>" into "@nick" if we're following URL (or it's us!). If
// we're following as another nick then "@nick(followednick)".
func ShortenMentions(text string) string {
	re := regexp.MustCompile(`@<([^ ]+) *([^>]+)>`)
	return re.ReplaceAllStringFunc(text, func(match string) string {
		parts := re.FindStringSubmatch(match)
		nick, url := parts[1], parts[2]
		if fnick := conf.urlToNick(url); fnick != "" {
			return FormatMention(nick, url, fnick)
		}
		// Not shortening if we're not following
		return match
	})
}

func NormalizeURL(url string) string {
	if url == "" {
		return ""
	}
	u, err := urlx.Parse(url)
	if err != nil {
		return ""
	}
	if u.Scheme == "https" {
		u.Scheme = "http"
		u.Host = strings.TrimSuffix(u.Host, ":443")
	}
	u.User = nil
	u.Path = strings.TrimSuffix(u.Path, "/")
	norm, err := urlx.Normalize(u)
	if err != nil {
		return ""
	}
	return norm
}

// Takes followednick to be able to indicated when somebody (URL) was mentioned
// using a nick other than the one we follow the person as.
func FormatMention(nick, url, followednick string) string {
	str := "@" + nick
	if followednick != nick {
		str += fmt.Sprintf("(%s)", followednick)
	}
	if NormalizeURL(url) == NormalizeURL(conf.Twturl) {
		return red(str)
	}
	return blue(str)
}

func PrettyDuration(duration time.Duration) string {
	s := int(duration.Seconds())
	d := s / 86400
	s %= 86400
	if d >= 365 {
		return fmt.Sprintf("%dy %dw ago", d/365, d%365/7)
	}
	if d >= 14 {
		return fmt.Sprintf("%dw ago", d/7)
	}
	h := s / 3600
	s %= 3600
	if d > 0 {
		str := fmt.Sprintf("%dd", d)
		if h > 0 && d <= 6 {
			str += fmt.Sprintf(" %dh", h)
		}
		return str + " ago"
	}
	m := s / 60
	s %= 60
	if h > 0 || m > 0 {
		str := ""
		hh := ""
		if h > 0 {
			str += fmt.Sprintf("%dh", h)
			hh = " "
		}
		if m > 0 {
			str += fmt.Sprintf("%s%dm", hh, m)
		}
		return str + " ago"
	}
	return fmt.Sprintf("%ds ago", s)
}
<commit_msg>Purge unused funcs<commit_after>// -*- tab-width: 4; -*-

package main

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/goware/urlx"
)

func red(s string) string {
	return fmt.Sprintf("\033[31m%s\033[0m", s)
}
func green(s string) string {
	return fmt.Sprintf("\033[32m%s\033[0m", s)
}
func boldgreen(s string) string {
	return fmt.Sprintf("\033[32;1m%s\033[0m", s)
}
func blue(s string) string {
	return fmt.Sprintf("\033[34m%s\033[0m", s)
}

func PrintTweet(tweet Tweet, now time.Time) {
	text := ShortenMentions(tweet.Text)

	nick := green(tweet.Tweeter.Nick)
	if NormalizeURL(tweet.Tweeter.URL) == NormalizeURL(conf.Twturl) {
		nick = boldgreen(tweet.Tweeter.Nick)
	}
	fmt.Printf("> %s (%s)\n%s\n",
		nick,
		PrettyDuration(now.Sub(tweet.Created)),
		text)
}

func PrintTweetRaw(tweet Tweet) {
	fmt.Printf("%s\t%s\t%s",
		tweet.Tweeter.URL,
		tweet.Created.Format(time.RFC3339),
		tweet.Text)
}

// Turns "@<nick URL>" into "@nick" if we're following URL (or it's us!). If
// we're following as another nick then "@nick(followednick)".
func ShortenMentions(text string) string {
	re := regexp.MustCompile(`@<([^ ]+) *([^>]+)>`)
	return re.ReplaceAllStringFunc(text, func(match string) string {
		parts := re.FindStringSubmatch(match)
		nick, url := parts[1], parts[2]
		if fnick := conf.urlToNick(url); fnick != "" {
			return FormatMention(nick, url, fnick)
		}
		// Not shortening if we're not following
		return match
	})
}

func NormalizeURL(url string) string {
	if url == "" {
		return ""
	}
	u, err := urlx.Parse(url)
	if err != nil {
		return ""
	}
	if u.Scheme == "https" {
		u.Scheme = "http"
		u.Host = strings.TrimSuffix(u.Host, ":443")
	}
	u.User = nil
	u.Path = strings.TrimSuffix(u.Path, "/")
	norm, err := urlx.Normalize(u)
	if err != nil {
		return ""
	}
	return norm
}

// Takes followednick to be able to indicated when somebody (URL) was mentioned
// using a nick other than the one we follow the person as.
func FormatMention(nick, url, followednick string) string {
	str := "@" + nick
	if followednick != nick {
		str += fmt.Sprintf("(%s)", followednick)
	}
	if NormalizeURL(url) == NormalizeURL(conf.Twturl) {
		return red(str)
	}
	return blue(str)
}

func PrettyDuration(duration time.Duration) string {
	s := int(duration.Seconds())
	d := s / 86400
	s %= 86400
	if d >= 365 {
		return fmt.Sprintf("%dy %dw ago", d/365, d%365/7)
	}
	if d >= 14 {
		return fmt.Sprintf("%dw ago", d/7)
	}
	h := s / 3600
	s %= 3600
	if d > 0 {
		str := fmt.Sprintf("%dd", d)
		if h > 0 && d <= 6 {
			str += fmt.Sprintf(" %dh", h)
		}
		return str + " ago"
	}
	m := s / 60
	s %= 60
	if h > 0 || m > 0 {
		str := ""
		hh := ""
		if h > 0 {
			str += fmt.Sprintf("%dh", h)
			hh = " "
		}
		if m > 0 {
			str += fmt.Sprintf("%s%dm", hh, m)
		}
		return str + " ago"
	}
	return fmt.Sprintf("%ds ago", s)
}
<|endoftext|>


<commit_before>package sorter

import "testing"

// TestIsSorted tests the arrays if its sorted or not
func TestIsSorted(t *testing.T) {
	tests := []struct {
		arr      []int
		isSorted bool
	}{
		{[]int{0}, true},
		{[]int{0, 0}, true},
		{[]int{1, 2, 3}, true},
		{[]int{1, 2, 3, 4}, true},
		{[]int{0, 1, 2, 3, 4}, true},
		{[]int{0, 1, 1}, true},
		{[]int{0, 1, 2, 1}, false},
		{[]int{0, -1}, false},
		{[]int{0, 1, 2, 3, 4, 3}, false},
	}
	for _, test := range tests {
		// never ignore err
		// here we only check isSorted value
		test := test // capture range variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			isSorted, _ := IsSorted(test.arr)
			if isSorted != test.isSorted {
				t.Fatalf("result of isSorted %v should be %v\n", test.arr, test.isSorted)
			}
		})
	}
}
<commit_msg>tests: add explanation about capturing variable while running parallel tests<commit_after>package sorter

import "testing"

// TestIsSorted tests the arrays if its sorted or not
func TestIsSorted(t *testing.T) {
	tests := []struct {
		arr      []int
		isSorted bool
	}{
		{[]int{0}, true},
		{[]int{0, 0}, true},
		{[]int{1, 2, 3}, true},
		{[]int{1, 2, 3, 4}, true},
		{[]int{0, 1, 2, 3, 4}, true},
		{[]int{0, 1, 1}, true},
		{[]int{0, 1, 2, 1}, false},
		{[]int{0, -1}, false},
		{[]int{0, 1, 2, 3, 4, 3}, false},
	}
	for _, test := range tests {
		// if we dont capture variable here, then its not guaranteed all the array
		// values will be tested
		test := test // capture range variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			// never ignore err
			// here we only check isSorted value
			isSorted, _ := IsSorted(test.arr)
			if isSorted != test.isSorted {
				t.Fatalf("result of isSorted %v should be %v\n", test.arr, test.isSorted)
			}
		})
	}
}
<|endoftext|>


<commit_before>package hll

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"

	"code.google.com/p/snappy-go/snappy"
)

type sparse struct {
	buf                  []byte
	lastVal, numElements uint64
}

func newSparse(estimatedCap uint64) *sparse {
	return &sparse{
		buf:         make([]byte, 0, estimatedCap),
		lastVal:     0,
		numElements: 0,
	}
}

func (s *sparse) Add(x uint64) {
	delta := x - s.lastVal

	// This slice is not strictly necessary, but it saves a lot of complexity. For now, simplicity
	// trumps performance in this case.
	deltaBuf := make([]byte, binary.MaxVarintLen64)

	n := binary.PutUvarint(deltaBuf, delta)
	s.buf = append(s.buf, deltaBuf[0:n]...)
	s.lastVal = x
	s.numElements++
}

func (s *sparse) SizeInBits() uint64 {
	return uint64(len(s.buf) * 8)
}

func (s *sparse) SizeInBytes() uint64 {
	return uint64(len(s.buf))
}

// Returns a function that can be called repeatedly to yield values from the list.
func (s *sparse) GetIterator() u64It {
	// idx := 0
	rdr := bytes.NewBuffer(s.buf)
	var lastDecoded uint64 = 0
	return func() (uint64, bool) {
		delta, err := binary.ReadUvarint(rdr)
		if err != nil {
			return 0, false
		}
		returnVal := lastDecoded + delta
		lastDecoded = returnVal
		return returnVal, true
	}
}

func (s *sparse) GetNumElements() uint64 {
	return s.numElements
}

type jsonableSparse struct {
	B    []byte
	L, N uint64
}

func (s *sparse) MarshalJSON() ([]byte, error) {
	compressed, err := snappyB64(s.buf)
	if err != nil {
		return nil, err
	}
	j := &jsonableSparse{compressed, s.lastVal, s.numElements}
	return json.Marshal(j)
}

func (s *sparse) UnmarshalJSON(buf []byte) error {
	j := jsonableSparse{}
	if err := json.Unmarshal(buf, &j); err != nil {
		return err
	}

	uncompressed, err := unsnappyB64(j.B)
	if err != nil {
		return err
	}

	s.buf, s.lastVal, s.numElements = uncompressed, j.L, j.N
	return nil
}

// Compress the input using snapp and encode the result using URL-safe base64.
func snappyB64(in []byte) ([]byte, error) {
	compressed, err := snappy.Encode(nil, in)
	if err != nil {
		return nil, err
	}

	// Go requires annoying contortions to handle base64'ing buffers whose length is not a multiple
	// of 4.
	s := make([]byte, 0, base64.URLEncoding.EncodedLen(len(compressed))+2)
	base64Buf := bytes.NewBuffer(s)
	b64Enc := base64.NewEncoder(base64.URLEncoding, base64Buf)
	_, err = b64Enc.Write(compressed)
	if err != nil {
		return nil, err
	}
	if err := b64Enc.Close(); err != nil {
		return nil, err
	}
	return base64Buf.Bytes(), nil
}

// The inverse of snappyB64.
func unsnappyB64(in []byte) ([]byte, error) {
	unBase64edBufLen := base64.URLEncoding.DecodedLen(len(in))
	unBase64ed := make([]byte, unBase64edBufLen)
	n, err := base64.URLEncoding.Decode(unBase64ed, in)
	if err != nil {
		return nil, err
	}

	uncompressed, err := snappy.Decode(nil, unBase64ed[:n])
	if err != nil {
		return nil, err
	}

	// The snappy library returns nil when the output length is zero. Fix it.
	if uncompressed == nil {
		uncompressed = []byte{}
	}
	return uncompressed, nil
}
<commit_msg>More concise base64ing, per schmichael's PR feedback<commit_after>package hll

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"

	"code.google.com/p/snappy-go/snappy"
)

type sparse struct {
	buf                  []byte
	lastVal, numElements uint64
}

func newSparse(estimatedCap uint64) *sparse {
	return &sparse{
		buf:         make([]byte, 0, estimatedCap),
		lastVal:     0,
		numElements: 0,
	}
}

func (s *sparse) Add(x uint64) {
	delta := x - s.lastVal

	// This slice is not strictly necessary, but it saves a lot of complexity. For now, simplicity
	// trumps performance in this case.
	deltaBuf := make([]byte, binary.MaxVarintLen64)

	n := binary.PutUvarint(deltaBuf, delta)
	s.buf = append(s.buf, deltaBuf[0:n]...)
	s.lastVal = x
	s.numElements++
}

func (s *sparse) SizeInBits() uint64 {
	return uint64(len(s.buf) * 8)
}

func (s *sparse) SizeInBytes() uint64 {
	return uint64(len(s.buf))
}

// Returns a function that can be called repeatedly to yield values from the list.
func (s *sparse) GetIterator() u64It {
	// idx := 0
	rdr := bytes.NewBuffer(s.buf)
	var lastDecoded uint64 = 0
	return func() (uint64, bool) {
		delta, err := binary.ReadUvarint(rdr)
		if err != nil {
			return 0, false
		}
		returnVal := lastDecoded + delta
		lastDecoded = returnVal
		return returnVal, true
	}
}

func (s *sparse) GetNumElements() uint64 {
	return s.numElements
}

type jsonableSparse struct {
	B    []byte
	L, N uint64
}

func (s *sparse) MarshalJSON() ([]byte, error) {
	compressed, err := snappyB64(s.buf)
	if err != nil {
		return nil, err
	}
	j := &jsonableSparse{compressed, s.lastVal, s.numElements}
	return json.Marshal(j)
}

func (s *sparse) UnmarshalJSON(buf []byte) error {
	j := jsonableSparse{}
	if err := json.Unmarshal(buf, &j); err != nil {
		return err
	}

	uncompressed, err := unsnappyB64(j.B)
	if err != nil {
		return err
	}

	s.buf, s.lastVal, s.numElements = uncompressed, j.L, j.N
	return nil
}

// Compress the input using snapp and encode the result using URL-safe base64.
func snappyB64(in []byte) ([]byte, error) {
	compressed, err := snappy.Encode(nil, in)
	if err != nil {
		return nil, err
	}

	outBuf := make([]byte, base64.URLEncoding.EncodedLen(len(compressed)))
	base64.URLEncoding.Encode(outBuf, compressed)
	return outBuf, nil
}

// The inverse of snappyB64.
func unsnappyB64(in []byte) ([]byte, error) {
	unBase64ed := make([]byte, base64.URLEncoding.DecodedLen(len(in)))
	n, err := base64.URLEncoding.Decode(unBase64ed, in)
	if err != nil {
		return nil, err
	}

	uncompressed, err := snappy.Decode(nil, unBase64ed[:n])
	if err != nil {
		return nil, err
	}

	// The snappy library returns nil when the output length is zero. Fix it now.
	// I filed this bug upstream: https://code.google.com/p/snappy-go/issues/detail?id=6
	if uncompressed == nil {
		uncompressed = []byte{}
	}
	return uncompressed, nil
}
<|endoftext|>


<commit_before>package hello

import (
	"fmt"
	"net/http"

	"code.google.com/p/gorilla/appengine/sessions"
	"code.google.com/p/gorilla/mux"
)

var router = new(mux.Router)
var dStore = sessions.NewDatastoreStore("", []byte("my-secret-key"))
	//[]byte("1234567890123456"))
var mStore = sessions.NewMemcacheStore("", []byte("my-secret-key"))
	//[]byte("1234567890123456"))

func init() {
	// Register a couple of routes.
	router.HandleFunc("/", homeHandler).Name("home")
	router.HandleFunc("/{salutation}/{name}", helloHandler).Name("hello")
	router.HandleFunc("/memcache-session", memcacheSessionHandler).Name("memcache-session")
	router.HandleFunc("/datastore-session", datastoreSessionHandler).Name("datastore-session")
	// Send all incoming requests to router.
	http.Handle("/", router)
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Type", "text/html")
	url1, _ := router.GetRoute("hello").URL("salutation", "hello", "name", "world")
	url2, _ := router.GetRoute("datastore-session").URL()
	url3, _ := router.GetRoute("memcache-session").URL()
	fmt.Fprintf(w, "Try a hello. Or a datastore or memcache session.", url1, url2, url3)
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Type", "text/html")
	vars := mux.Vars(r)
	fmt.Fprintf(w, "%s, %s!", vars["salutation"], vars["name"])
}

func datastoreSessionHandler(w http.ResponseWriter, r *http.Request) {
	// Get a session. We're ignoring the error resulted from decoding an
	// existing session: Get() always returns a session, even if empty.
	session, _ := dStore.Get(r, "session-name")
	if value, ok := session.Values["foo"]; ok {
		// Show a previously saved value.
		fmt.Fprintf(w, `Value for datastore session["foo"] is "%s".`, value)
	} else {
		// Set a value.
		session.Values["foo"] = "bar"
		// Save it.
		err := session.Save(r, w)
		fmt.Fprintf(w, `No value found for datastore session["foo"]. Saved a new one (errors: %v).`, err)
	}
}

func memcacheSessionHandler(w http.ResponseWriter, r *http.Request) {
	// Get a session. We're ignoring the error resulted from decoding an
	// existing session: Get() always returns a session, even if empty.
	session, _ := mStore.Get(r, "session-name")
	if value, ok := session.Values["foo"]; ok {
		// Show a previously saved value.
		fmt.Fprintf(w, `Value for memcache session["foo"] is "%s".`, value)
	} else {
		// Set a value.
		session.Values["foo"] = "bar"
		// Save it.
		err := session.Save(r, w)
		fmt.Fprintf(w, `No value found for memcache session["foo"]. Saved a new one (errors: %v).`, err)
	}
}
<commit_msg>dev/examples/appengine: session value is now a counter. added cookie example.<commit_after>package hello

import (
	"fmt"
	"net/http"

	"code.google.com/p/gorilla/mux"
	"code.google.com/p/gorilla/sessions"

	gaeSessions "code.google.com/p/gorilla/appengine/sessions"
)

var router = new(mux.Router)
var store = sessions.NewCookieStore([]byte("my-secret-key"),
	[]byte("1234567890123456"))
var dStore = gaeSessions.NewDatastoreStore("", []byte("my-secret-key"),
	[]byte("1234567890123456"))
var mStore = gaeSessions.NewMemcacheStore("", []byte("my-secret-key"),
	[]byte("1234567890123456"))

func init() {
	// Register a couple of routes.
	router.HandleFunc("/", homeHandler).Name("home")
	router.HandleFunc("/{salutation}/{name}", helloHandler).Name("hello")
	router.HandleFunc("/datastore-session", datastoreSessionHandler).Name("datastore-session")
	router.HandleFunc("/cookie-session", cookieSessionHandler).Name("cookie-session")
	router.HandleFunc("/memcache-session", memcacheSessionHandler).Name("memcache-session")
	// Send all incoming requests to router.
	http.Handle("/", router)
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Type", "text/html")
	url1, _ := router.GetRoute("hello").URL("salutation", "hello", "name", "world")
	url2, _ := router.GetRoute("cookie-session").URL()
	url3, _ := router.GetRoute("datastore-session").URL()
	url4, _ := router.GetRoute("memcache-session").URL()
	fmt.Fprintf(w, "Try a hello. Or a cookie, datastore or memcache session.", url1, url2, url3, url4)
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Type", "text/html")
	vars := mux.Vars(r)
	fmt.Fprintf(w, "%s, %s!", vars["salutation"], vars["name"])
}

func cookieSessionHandler(w http.ResponseWriter, r *http.Request) {
	// Get a session. We're ignoring the error resulted from decoding an
	// existing session: Get() always returns a session, even if empty.
	session, _ := store.Get(r, "cookie-session")
	var msg string
	if value, ok := session.Values["counter"]; ok {
		// Increment value.
		session.Values["counter"] = value.(int) + 1
		msg = fmt.Sprintf(`Value for cookie session "counter" is "%v".`, value)
	} else {
		// Set a value.
		session.Values["counter"] = 1
		msg = fmt.Sprintf(`No value found for cookie session "counter".`)
	}
	// Save it.
	err := session.Save(r, w)
	fmt.Fprintf(w, `%s -- Errors: %v`, msg, err)
}

func datastoreSessionHandler(w http.ResponseWriter, r *http.Request) {
	// Get a session. We're ignoring the error resulted from decoding an
	// existing session: Get() always returns a session, even if empty.
	session, _ := dStore.Get(r, "datastore-session")
	var msg string
	if value, ok := session.Values["counter"]; ok {
		// Increment value.
		session.Values["counter"] = value.(int) + 1
		msg = fmt.Sprintf(`Value for datastore session "counter" is "%v".`, value)
	} else {
		// Set a value.
		session.Values["counter"] = 1
		msg = fmt.Sprintf(`No value found for datastore session "counter".`)
	}
	// Save it.
	err := session.Save(r, w)
	fmt.Fprintf(w, `%s -- Errors: %v`, msg, err)
}

func memcacheSessionHandler(w http.ResponseWriter, r *http.Request) {
	// Get a session. We're ignoring the error resulted from decoding an
	// existing session: Get() always returns a session, even if empty.
	session, _ := mStore.Get(r, "memcache-session")
	var msg string
	if value, ok := session.Values["counter"]; ok {
		// Increment value.
		session.Values["counter"] = value.(int) + 1
		msg = fmt.Sprintf(`Value for memcache session "counter" is "%v".`, value)
	} else {
		// Set a value.
		session.Values["counter"] = 1
		msg = fmt.Sprintf(`No value found for memcache session "counter".`)
	}
	// Save it.
	err := session.Save(r, w)
	fmt.Fprintf(w, `%s -- Errors: %v`, msg, err)
}
<|endoftext|>


<commit_before>package storebench

import (
	"io/ioutil"
	"log"
	"strconv"
	"testing"

	"github.com/skyec/astore"
	blobs "github.com/skyec/astore/testing"
)

var benchStore astore.WriteableStore
var benchDir string

func init() {
}
func BenchmarkDefaultWrite(b *testing.B) {
	benchDir, err := ioutil.TempDir("", "astore-benchmarking-")
	if err != nil {
		log.Fatal(err)
	}

	benchStore, err := astore.NewReadWriteableStore(benchDir)
	if err != nil {
		log.Fatal(err)

	}

	err = benchStore.Initialize()
	if err != nil {
		log.Fatal("Failed to initialze the store:", err)
	}

	log.Print("############\nBe sure to 'rm -rf %s'", benchDir)
	blobs := blobs.GenerateBlobs(b.N)
	b.ResetTimer()
	for i := 0; i < len(blobs); i++ {
		err := benchStore.WriteToKey(strconv.Itoa(i%10), blobs[i])
		if err != nil {
			b.Fatal("Failed to write to store:", err)
		}
	}
}
<commit_msg>Automatically clean up after the benchmark tests<commit_after>package storebench

import (
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"testing"

	"github.com/skyec/astore"
	blobs "github.com/skyec/astore/testing"
)

var benchStore astore.WriteableStore
var benchDir string

func init() {
}
func BenchmarkDefaultWrite(b *testing.B) {
	benchDir, err := ioutil.TempDir("", "astore-benchmarking-")
	if err != nil {
		log.Fatal(err)
	}

	benchStore, err := astore.NewReadWriteableStore(benchDir)
	if err != nil {
		log.Fatal(err)

	}

	err = benchStore.Initialize()
	if err != nil {
		log.Fatal("Failed to initialze the store:", err)
	}

	blobs := blobs.GenerateBlobs(b.N)
	b.ResetTimer()
	for i := 0; i < len(blobs); i++ {
		err := benchStore.WriteToKey(strconv.Itoa(i%10), blobs[i])
		if err != nil {
			b.Fatal("Failed to write to store:", err)
		}
	}
	b.StopTimer()
	os.RemoveAll(benchDir)

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
)

// type Document struct is defined in document.go

type DocumentParams struct {
	DocID        bson.ObjectId
	AnnotationID bson.ObjectId
	// CommentID bson.ObjectId
}

// Get a single document, specified by DocID,
// Get the Annotation, if specified.
func getDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("getDocument-request: %v\n", req)

	// assemble results into a json-object
	result := make(map[string]interface{})

	switch req.Method {
	case "POST":
		// get document, annotation and comment parameters
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("request body is %s\n", string(body))
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		log.Printf("Params is: %#v\n", params)
		if err != nil {
			log.Printf("JSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		if params.DocID == "" {
			log.Printf("DocID is empty.\n")
			http.Error(rw, "DocID is empty", http.StatusBadRequest) // 400
			return
		}

		// get document
		doc, err := getDocument(bson.M{"_id": params.DocID})
		if err != nil {
			log.Printf("DocID not found: error %#v\n", err)
			http.Error(rw, "DocID not found", http.StatusNotFound) // 404
			return
		}
		result["document"] = doc

		// get Pages, expect at least 1.
		pages, err := getPages(bson.M{"documentid": doc.ID})
		if err != nil {
			log.Printf("Pages with DocID not found: error %#v\n", err)
			http.Error(rw, "DocID not found", http.StatusNotFound) // 404
			return
		}
		result["pages"] = pages

		// Be paranoid and limit annotation to the Document they belong to.
		selector := bson.M{"documentid": params.DocID}
		if params.AnnotationID != "" {
			selector["_id"] = params.AnnotationID
		} // or leave it undefined for all annotations of DocID
		annotations, err := getAnnotations(selector)
		if err != nil {
			log.Printf("AnnotationID not found: error %#v\n", err)
			http.Error(rw, "AnnotationID not found", http.StatusNotFound) // 404
			return
		}
		result["annotations"] = annotations

		// marshal and write out.
		j, err := json.Marshal(result)
		if err != nil {
			log.Printf("Error marshalling results: error %#v\n", err)
			http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
			return
		}
		rw.WriteHeader(200)
		rw.Write(j)
		return

	default: // request.Method
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

// get all documents with certain limits.
// For lazy loading place a start-at at next call
func getDocumentsHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("getDocument-request: %v\n", req)

	// assemble results into a json-object
	result := make(map[string]interface{})

	switch req.Method {
	case "POST":
		// get document, annotation and comment parameters
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("request body is %s\n", string(body))
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		log.Printf("Params is: %#v\n", params)
		if err != nil {
			log.Printf("JSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		// get document
		// UGLY HACK: get them all.
		docs, err := getDocuments(nil)
		if err != nil {
			log.Printf("GetDocuments error %#v\n", err)
			http.Error(rw, "GetDocuments error", http.StatusNotFound) // 404
			return
		}
		result["documents"] = docs

		// get optional annotation, error if it is specified but not there.

		// bs := bson.M{}
		// if params.AnnotationID != "" {
		// 	bs = bson.M{"_id": params.AnnotationID}
		// } else {
		// 	bs = bson.M{"DocID": params.DocID}
		// }
		// annotations, err := getAnnotations(bs)
		// if err != nil {
		// 	log.Printf("AnnotationID not found: error %#v\n", err)
		// 	http.Error(rw, "AnnotationID not found", http.StatusNotFound) // 404
		// 	return
		// }
		// result["annotations"] = annotations

		// marshal and write out.
		j, err := json.Marshal(result)
		if err != nil {
			log.Printf("Error marshalling results: error %#v\n", err)
			http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
			return
		}
		rw.WriteHeader(200)
		rw.Write(j)
		return

	default: // request.Method
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func getDocumentListHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("getDocument-request: %v\n", req)

	switch req.Method {
	case "POST": // Use POST as that's the easiest to encode json parameters
		body, _ := ioutil.ReadAll(req.Body)
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		if err != nil {
			log.Printf("JSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		docs, err := getDocuments(nil)
		if err != nil {
			log.Printf("getDocuments error %#v\n", err)
			http.Error(rw, "getDocuments error", http.StatusInternalServerError) // 400
			return
		}

		j, err := json.Marshal(docs)
		if err != nil {
			log.Printf("Error marshalling results: error %#v\n", err)
			http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
			return
		}
		rw.WriteHeader(200)
		rw.Write(j)
		return

	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func insertDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\ninsertDocument-request: %v\n", req)

	switch req.Method {
	case "POST":
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("\n\nbody is %s\n", string(body))
		doc := &Document{}
		err := json.Unmarshal(body, doc)
		if err != nil {
			log.Printf("\n\nJSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		log.Printf("\n\nDocument to insert is: %#v\n", *doc)

		if doc.ID == "" {
			doc.ID = bson.NewObjectId()
			log.Printf("\n\nCreating new ObjectId: %v\n", doc.ID)
		}
		err = insertDocument(doc)
		if err != nil {
			log.Printf("Error inserting  document: error %#v\n", err)
			http.Error(rw, "error inserting document", http.StatusInternalServerError) // 500
			return
		}

		//This is a HACK
		// Add page-record
		page := newPage()
		page.DocumentID = doc.ID
		page.PageNumber = 1
		page.Text = "Hallo"
		// page.Lines = [][]CharObject{ [ { ...
		err = insertPage(page)
		if err != nil {
			log.Printf("Error inserting page: error %#v\n", err)
			http.Error(rw, "error inserting page", http.StatusInternalServerError) // 500
			return
		}

		rw.WriteHeader(200)
		rw.Write([]byte(`OK, inserted`))
		return
	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func updateDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\nupdateDocument-request: %v\n", req)

	switch req.Method {
	case "POST":
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("\n\nbody is %s\n", string(body))
		doc := &Document{}
		err := json.Unmarshal(body, doc)
		if err != nil {
			log.Printf("\n\nJSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		log.Printf("\n\nDocument to update is: %#v\n", *doc)
		err = upsertDocument(doc)
		if err != nil {
			log.Printf("Error inserting/updating  document: error %#v\n", err)
			http.Error(rw, "error inserting/updating document", http.StatusInternalServerError) // 500
			return
		}

		rw.WriteHeader(200)
		rw.Write([]byte(`OK, updated`))
		return
	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func deleteDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\ndelete-Document-request: %v\n", req)

	// get session
	cs, err := getClientSession(req.Header.Get(headerKeySessionKey))
	if err != nil {
		http.Error(rw, "error", http.StatusInternalServerError)
		return
	}
	defer cs.done()

	// get account
	acc := cs.account
	if acc == nil {
		http.Error(rw, "forbidden", http.StatusForbidden)
		return
	}
	// TODO: test for Admin-user flag.

	switch req.Method {
	case "POST":
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("\n\nbody is %s\n", string(body))
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		if err != nil {
			log.Printf("\n\nJSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		// Delete Annotation-records with DocID
		err = removeAnnotations(bson.M{"documentid": params.DocID})
		if err != nil {
			log.Printf("Error deleting annotation on document: error %#v\n", err)
			http.Error(rw, "error deleting annotation on document", http.StatusInternalServerError) // 500
			return
		}

		// Delete Page-records with DocID
		err = removePages(bson.M{"documentid": params.DocID})
		if err != nil {
			log.Printf("Error deleting pages of document: error %#v\n", err)
			http.Error(rw, "error deleting pages of document", http.StatusInternalServerError) // 500
			return
		}

		// Delete the document record.
		log.Printf("\n\nDocumentID to delete is: %#v\n", params.DocID)
		err = removeDocument(params.DocID)
		if err != nil {
			log.Printf("Error deleting document: error %#v\n", err)
			http.Error(rw, "error deleting document", http.StatusInternalServerError) // 500
			return
		}

		rw.WriteHeader(200)
		rw.Write([]byte(`OK, deleted`))
		return
	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}
<commit_msg>Refactored mongo search queries according to new DB-schema names.<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
)

// type Document struct is defined in document.go

type DocumentParams struct {
	DocID        bson.ObjectId
	AnnotationID bson.ObjectId
	// CommentID bson.ObjectId
}

// Get a single document, specified by DocID,
// Get the Annotation, if specified.
func getDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("getDocument-request: %v\n", req)

	// assemble results into a json-object
	result := make(map[string]interface{})

	switch req.Method {
	case "POST":
		// get document, annotation and comment parameters
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("request body is %s\n", string(body))
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		log.Printf("Params is: %#v\n", params)
		if err != nil {
			log.Printf("JSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		if params.DocID == "" {
			log.Printf("DocID is empty.\n")
			http.Error(rw, "DocID is empty", http.StatusBadRequest) // 400
			return
		}

		// get document
		doc, err := getDocument(bson.M{"_id": params.DocID})
		if err != nil {
			log.Printf("DocID not found: error %#v\n", err)
			http.Error(rw, "DocID not found", http.StatusNotFound) // 404
			return
		}
		result["document"] = doc

		// get Pages, expect at least 1.
		pages, err := getPages(bson.M{"documentId": doc.ID})
		if err != nil {
			log.Printf("Pages with DocID not found: error %#v\n", err)
			http.Error(rw, "DocID not found", http.StatusNotFound) // 404
			return
		}
		result["pages"] = pages

		// Be paranoid and limit annotation to the Document they belong to.
		selector := bson.M{"documentId": params.DocID}
		if params.AnnotationID != "" {
			selector["_id"] = params.AnnotationID
		} // or leave it undefined for all annotations of DocID
		annotations, err := getAnnotations(selector)
		if err != nil {
			log.Printf("AnnotationID not found: error %#v\n", err)
			http.Error(rw, "AnnotationID not found", http.StatusNotFound) // 404
			return
		}
		result["annotations"] = annotations

		// marshal and write out.
		j, err := json.Marshal(result)
		if err != nil {
			log.Printf("Error marshalling results: error %#v\n", err)
			http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
			return
		}
		rw.WriteHeader(200)
		rw.Write(j)
		return

	default: // request.Method
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

// get all documents with certain limits.
// For lazy loading place a start-at at next call
func getDocumentsHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("getDocument-request: %v\n", req)

	// assemble results into a json-object
	result := make(map[string]interface{})

	switch req.Method {
	case "POST":
		// get document, annotation and comment parameters
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("request body is %s\n", string(body))
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		log.Printf("Params is: %#v\n", params)
		if err != nil {
			log.Printf("JSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		// get document
		// UGLY HACK: get them all.
		docs, err := getDocuments(nil)
		if err != nil {
			log.Printf("GetDocuments error %#v\n", err)
			http.Error(rw, "GetDocuments error", http.StatusNotFound) // 404
			return
		}
		result["documents"] = docs

		// get optional annotation, error if it is specified but not there.

		// bs := bson.M{}
		// if params.AnnotationID != "" {
		// 	bs = bson.M{"_id": params.AnnotationID}
		// } else {
		// 	bs = bson.M{"DocID": params.DocID}
		// }
		// annotations, err := getAnnotations(bs)
		// if err != nil {
		// 	log.Printf("AnnotationID not found: error %#v\n", err)
		// 	http.Error(rw, "AnnotationID not found", http.StatusNotFound) // 404
		// 	return
		// }
		// result["annotations"] = annotations

		// marshal and write out.
		j, err := json.Marshal(result)
		if err != nil {
			log.Printf("Error marshalling results: error %#v\n", err)
			http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
			return
		}
		rw.WriteHeader(200)
		rw.Write(j)
		return

	default: // request.Method
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func getDocumentListHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("getDocument-request: %v\n", req)

	switch req.Method {
	case "POST": // Use POST as that's the easiest to encode json parameters
		body, _ := ioutil.ReadAll(req.Body)
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		if err != nil {
			log.Printf("JSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		docs, err := getDocuments(nil)
		if err != nil {
			log.Printf("getDocuments error %#v\n", err)
			http.Error(rw, "getDocuments error", http.StatusInternalServerError) // 400
			return
		}

		j, err := json.Marshal(docs)
		if err != nil {
			log.Printf("Error marshalling results: error %#v\n", err)
			http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
			return
		}
		rw.WriteHeader(200)
		rw.Write(j)
		return

	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func insertDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\ninsertDocument-request: %v\n", req)

	switch req.Method {
	case "POST":
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("\n\nbody is %s\n", string(body))
		doc := &Document{}
		err := json.Unmarshal(body, doc)
		if err != nil {
			log.Printf("\n\nJSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		log.Printf("\n\nDocument to insert is: %#v\n", *doc)

		if doc.ID == "" {
			doc.ID = bson.NewObjectId()
			log.Printf("\n\nCreating new ObjectId: %v\n", doc.ID)
		}
		err = insertDocument(doc)
		if err != nil {
			log.Printf("Error inserting  document: error %#v\n", err)
			http.Error(rw, "error inserting document", http.StatusInternalServerError) // 500
			return
		}

		//This is a HACK
		// Add page-record
		page := newPage()
		page.DocumentID = doc.ID
		page.PageNumber = 1
		page.Text = "Hallo"
		// page.Lines = [][]CharObject{ [ { ...
		err = insertPage(page)
		if err != nil {
			log.Printf("Error inserting page: error %#v\n", err)
			http.Error(rw, "error inserting page", http.StatusInternalServerError) // 500
			return
		}

		rw.WriteHeader(200)
		rw.Write([]byte(`OK, inserted`))
		return
	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func updateDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\nupdateDocument-request: %v\n", req)

	switch req.Method {
	case "POST":
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("\n\nbody is %s\n", string(body))
		doc := &Document{}
		err := json.Unmarshal(body, doc)
		if err != nil {
			log.Printf("\n\nJSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		log.Printf("\n\nDocument to update is: %#v\n", *doc)
		err = upsertDocument(doc)
		if err != nil {
			log.Printf("Error inserting/updating  document: error %#v\n", err)
			http.Error(rw, "error inserting/updating document", http.StatusInternalServerError) // 500
			return
		}

		rw.WriteHeader(200)
		rw.Write([]byte(`OK, updated`))
		return
	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}

func deleteDocumentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\ndelete-Document-request: %v\n", req)

	// get session
	cs, err := getClientSession(req.Header.Get(headerKeySessionKey))
	if err != nil {
		http.Error(rw, "error", http.StatusInternalServerError)
		return
	}
	defer cs.done()

	// get account
	acc := cs.account
	if acc == nil {
		http.Error(rw, "forbidden", http.StatusForbidden)
		return
	}
	// TODO: test for Admin-user flag.

	switch req.Method {
	case "POST":
		body, _ := ioutil.ReadAll(req.Body)
		log.Printf("\n\nbody is %s\n", string(body))
		params := &DocumentParams{}
		err := json.Unmarshal(body, params)
		if err != nil {
			log.Printf("\n\nJSON unmarshal error %#v\n", err)
			http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
			return
		}

		// Delete Annotation-records with DocID
		err = removeAnnotations(bson.M{"documentId": params.DocID})
		if err != nil {
			log.Printf("Error deleting annotation on document: error %#v\n", err)
			http.Error(rw, "error deleting annotation on document", http.StatusInternalServerError) // 500
			return
		}

		// Delete Page-records with DocID
		err = removePages(bson.M{"documentId": params.DocID})
		if err != nil {
			log.Printf("Error deleting pages of document: error %#v\n", err)
			http.Error(rw, "error deleting pages of document", http.StatusInternalServerError) // 500
			return
		}

		// Delete the document record.
		log.Printf("\n\nDocumentID to delete is: %#v\n", params.DocID)
		err = removeDocument(params.DocID)
		if err != nil {
			log.Printf("Error deleting document: error %#v\n", err)
			http.Error(rw, "error deleting document", http.StatusInternalServerError) // 500
			return
		}

		rw.WriteHeader(200)
		rw.Write([]byte(`OK, deleted`))
		return
	default:
		http.Error(rw, "error", http.StatusMethodNotAllowed) // 405
	}
}
<|endoftext|>


<commit_before>// IronWorker (elastic computing) client library
package worker

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"time"

	"github.com/iron-io/iron_go/api"
	"github.com/iron-io/iron_go/config"
)

type Worker struct {
	Settings config.Settings
}

func New() *Worker {
	return &Worker{Settings: config.Config("iron_worker")}
}

func (w *Worker) codes(s ...string) *api.URL     { return api.Action(w.Settings, "codes", s...) }
func (w *Worker) tasks(s ...string) *api.URL     { return api.Action(w.Settings, "tasks", s...) }
func (w *Worker) schedules(s ...string) *api.URL { return api.Action(w.Settings, "schedules", s...) }

// exponential sleep between retries, replace this with your own preferred strategy
func sleepBetweenRetries(previousDuration time.Duration) time.Duration {
	if previousDuration >= 60*time.Second {
		return previousDuration
	}
	return previousDuration * previousDuration
}

var GoCodeRunner = []byte(`#!/bin/sh
root() {
  while [ $# -gt 0 ]; do
    if [ "$1" = "-d" ]; then
      printf "%s\n" "$2"
      break
    fi
  done
}
cd "$(root "$@")"
chmod +x worker
./worker "$@"
`)

// NewGoCodePackage creates an IronWorker code package from a Go package.
// The codeName is the name the code package will have have once it is uploaded.
//
// The packageArgs are equivalent to the args you would give to `go build`.
//
// If the packageArgs are a list of .go files, they will be treated as a list of
// source files specifying a single Go package.
//
// Otherwise it's treated as a Go package name that will be searched in GOPATH,
// and compiled.
//
// Please note that if you don't use `package main` for your Go package, this
// function will not work as expected.
func NewGoCodePackage(codeName string, packageArgs ...string) (code Code, err error) {
	tempDir, err := ioutil.TempDir("", "iron-go-build-"+codeName)
	if err != nil {
		return
	}

	defer os.RemoveAll(tempDir)

	os.Setenv("GOOS", "linux")
	os.Setenv("GOARCH", "amd64")
	args := []string{"build", "-x", "-v", "-o", tempDir + "/worker"}
	cmd := exec.Command("go", append(args, packageArgs...)...)
	output, err := cmd.CombinedOutput()

	if err != nil {
		fmt.Fprintln(os.Stderr, "vvvvvvvvvvvvvvvvvvvv go build output vvvvvvvvvvvvvvvvvvvv")
		fmt.Fprintln(os.Stderr, string(output))
		fmt.Fprintln(os.Stderr, "^^^^^^^^^^^^^^^^^^^^ go build output ^^^^^^^^^^^^^^^^^^^^")
		return
	}

	fd, err := os.Open(tempDir + "/worker")
	if err != nil {
		return
	}
	defer fd.Close()
	workerExe, err := ioutil.ReadAll(fd)
	if err != nil {
		return
	}

	code = Code{
		Name:     codeName,
		Runtime:  "sh",
		FileName: "__runner__.sh",
		Source: CodeSource{
			"worker":        workerExe,
			"__runner__.sh": GoCodeRunner,
		},
	}

	return
}

// WaitForTask returns a channel that will receive the completed task and is closed afterwards.
// If an error occured during the wait, the channel will be closed.
func (w *Worker) WaitForTask(taskId string) chan TaskInfo {
	out := make(chan TaskInfo)
	go func() {
		defer close(out)
		retryDelay := 100 * time.Millisecond

		for {
			info, err := w.TaskInfo(taskId)
			if err != nil {
				return
			}

			if info.Status == "queued" || info.Status == "running" {
				retryDelay = sleepBetweenRetries(retryDelay)
				time.Sleep(retryDelay)
			} else {
				out <- info
				return
			}
		}
	}()

	return out
}

func (w *Worker) WaitForTaskLog(taskId string) chan []byte {
	out := make(chan []byte)

	go func() {
		defer close(out)
		retryDelay := 100 * time.Millisecond

		for {
			log, err := w.TaskLog(taskId)
			if err != nil {
				e, ok := err.(api.HTTPResponseError)
				if ok && e.Response().StatusCode == 404 {
					retryDelay = sleepBetweenRetries(retryDelay)
					time.Sleep(retryDelay)
					continue
				}
				return
			}
			out <- log
			return
		}
	}()
	return out
}

func clamp(value, min, max int) int {
	if value < min {
		return min
	} else if value > max {
		return max
	}
	return value
}
<commit_msg>made default exponential backoff more sane<commit_after>// IronWorker (elastic computing) client library
package worker

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"time"

	"github.com/iron-io/iron_go/api"
	"github.com/iron-io/iron_go/config"
)

type Worker struct {
	Settings config.Settings
}

func New() *Worker {
	return &Worker{Settings: config.Config("iron_worker")}
}

func (w *Worker) codes(s ...string) *api.URL     { return api.Action(w.Settings, "codes", s...) }
func (w *Worker) tasks(s ...string) *api.URL     { return api.Action(w.Settings, "tasks", s...) }
func (w *Worker) schedules(s ...string) *api.URL { return api.Action(w.Settings, "schedules", s...) }

// exponential sleep between retries, replace this with your own preferred strategy
func sleepBetweenRetries(previousDuration time.Duration) time.Duration {
	if previousDuration >= 60*time.Second {
		return previousDuration
	}
	return previousDuration + previousDuration
}

var GoCodeRunner = []byte(`#!/bin/sh
root() {
  while [ $# -gt 0 ]; do
    if [ "$1" = "-d" ]; then
      printf "%s\n" "$2"
      break
    fi
  done
}
cd "$(root "$@")"
chmod +x worker
./worker "$@"
`)

// NewGoCodePackage creates an IronWorker code package from a Go package.
// The codeName is the name the code package will have have once it is uploaded.
//
// The packageArgs are equivalent to the args you would give to `go build`.
//
// If the packageArgs are a list of .go files, they will be treated as a list of
// source files specifying a single Go package.
//
// Otherwise it's treated as a Go package name that will be searched in GOPATH,
// and compiled.
//
// Please note that if you don't use `package main` for your Go package, this
// function will not work as expected.
func NewGoCodePackage(codeName string, packageArgs ...string) (code Code, err error) {
	tempDir, err := ioutil.TempDir("", "iron-go-build-"+codeName)
	if err != nil {
		return
	}

	defer os.RemoveAll(tempDir)

	os.Setenv("GOOS", "linux")
	os.Setenv("GOARCH", "amd64")
	args := []string{"build", "-x", "-v", "-o", tempDir + "/worker"}
	cmd := exec.Command("go", append(args, packageArgs...)...)
	output, err := cmd.CombinedOutput()

	if err != nil {
		fmt.Fprintln(os.Stderr, "vvvvvvvvvvvvvvvvvvvv go build output vvvvvvvvvvvvvvvvvvvv")
		fmt.Fprintln(os.Stderr, string(output))
		fmt.Fprintln(os.Stderr, "^^^^^^^^^^^^^^^^^^^^ go build output ^^^^^^^^^^^^^^^^^^^^")
		return
	}

	fd, err := os.Open(tempDir + "/worker")
	if err != nil {
		return
	}
	defer fd.Close()
	workerExe, err := ioutil.ReadAll(fd)
	if err != nil {
		return
	}

	code = Code{
		Name:     codeName,
		Runtime:  "sh",
		FileName: "__runner__.sh",
		Source: CodeSource{
			"worker":        workerExe,
			"__runner__.sh": GoCodeRunner,
		},
	}

	return
}

// WaitForTask returns a channel that will receive the completed task and is closed afterwards.
// If an error occured during the wait, the channel will be closed.
func (w *Worker) WaitForTask(taskId string) chan TaskInfo {
	out := make(chan TaskInfo)
	go func() {
		defer close(out)
		retryDelay := 100 * time.Millisecond

		for {
			info, err := w.TaskInfo(taskId)
			if err != nil {
				return
			}

			if info.Status == "queued" || info.Status == "running" {
				time.Sleep(retryDelay)
				retryDelay = sleepBetweenRetries(retryDelay)
			} else {
				out <- info
				return
			}
		}
	}()

	return out
}

func (w *Worker) WaitForTaskLog(taskId string) chan []byte {
	out := make(chan []byte)

	go func() {
		defer close(out)
		retryDelay := 100 * time.Millisecond

		for {
			log, err := w.TaskLog(taskId)
			if err != nil {
				e, ok := err.(api.HTTPResponseError)
				if ok && e.Response().StatusCode == 404 {
					time.Sleep(retryDelay)
					retryDelay = sleepBetweenRetries(retryDelay)
					continue
				}
				return
			}
			out <- log
			return
		}
	}()
	return out
}

func clamp(value, min, max int) int {
	if value < min {
		return min
	} else if value > max {
		return max
	}
	return value
}
<|endoftext|>


<commit_before>package dexcom

import (
	"strconv"

	dataTypesActivityPhysical "github.com/tidepool-org/platform/data/types/activity/physical"
	dataTypesFood "github.com/tidepool-org/platform/data/types/food"
	dataTypesInsulin "github.com/tidepool-org/platform/data/types/insulin"
	"github.com/tidepool-org/platform/structure"
	structureValidator "github.com/tidepool-org/platform/structure/validator"
)

const (
	EventTypeCarbs    = "carbs"
	EventTypeExercise = "exercise"
	EventTypeHealth   = "health"
	EventTypeInsulin  = "insulin"

	EventUnitCarbsGrams         = "grams"
	EventValueCarbsGramsMaximum = dataTypesFood.CarbohydrateNetGramsMaximum
	EventValueCarbsGramsMinimum = dataTypesFood.CarbohydrateNetGramsMinimum

	EventSubTypeExerciseLight        = "light"
	EventSubTypeExerciseMedium       = "medium"
	EventSubTypeExerciseHeavy        = "heavy"
	EventUnitExerciseMinutes         = "minutes"
	EventValueExerciseMinutesMaximum = dataTypesActivityPhysical.DurationValueMinutesMaximum
	EventValueExerciseMinutesMinimum = dataTypesActivityPhysical.DurationValueMinutesMinimum

	EventSubTypeHealthAlcohol      = "alcohol"
	EventSubTypeHealthCycle        = "cycle"
	EventSubTypeHealthHighSymptoms = "highSymptoms"
	EventSubTypeHealthIllness      = "illness"
	EventSubTypeHealthLowSymptoms  = "lowSymptoms"
	EventSubTypeHealthStress       = "stress"

	EventSubTypeInsulinFastActing = "fastActing"
	EventSubTypeInsulinLongActing = "longActing"
	EventUnitInsulinUnits         = "units"
	EventValueInsulinUnitsMaximum = dataTypesInsulin.DoseTotalUnitsMaximum
	EventValueInsulinUnitsMinimum = dataTypesInsulin.DoseTotalUnitsMinimum

	EventStatusCreated = "created"
	EventStatusDeleted = "deleted"
)

func EventTypes() []string {
	return []string{
		EventTypeCarbs,
		EventTypeExercise,
		EventTypeHealth,
		EventTypeInsulin,
	}
}

func EventSubTypesExercise() []string {
	return []string{
		EventSubTypeExerciseLight,
		EventSubTypeExerciseMedium,
		EventSubTypeExerciseHeavy,
	}
}

func EventSubTypesHealth() []string {
	return []string{
		EventSubTypeHealthAlcohol,
		EventSubTypeHealthCycle,
		EventSubTypeHealthHighSymptoms,
		EventSubTypeHealthIllness,
		EventSubTypeHealthLowSymptoms,
		EventSubTypeHealthStress,
	}
}

func EventSubTypesInsulin() []string {
	return []string{
		EventSubTypeInsulinFastActing,
		EventSubTypeInsulinLongActing,
	}
}

func EventStatuses() []string {
	return []string{
		EventStatusCreated,
		EventStatusDeleted,
	}
}

type EventsResponse struct {
	Events *Events `json:"events,omitempty"`
}

func ParseEventsResponse(parser structure.ObjectParser) *EventsResponse {
	if !parser.Exists() {
		return nil
	}
	datum := NewEventsResponse()
	parser.Parse(datum)
	return datum
}

func NewEventsResponse() *EventsResponse {
	return &EventsResponse{}
}

func (e *EventsResponse) Parse(parser structure.ObjectParser) {
	e.Events = ParseEvents(parser.WithReferenceArrayParser("events"))
}

func (e *EventsResponse) Validate(validator structure.Validator) {
	if eventsValidator := validator.WithReference("events"); e.Events != nil {
		e.Events.Validate(eventsValidator)
	} else {
		eventsValidator.ReportError(structureValidator.ErrorValueNotExists())
	}
}

type Events []*Event

func ParseEvents(parser structure.ArrayParser) *Events {
	if !parser.Exists() {
		return nil
	}
	datum := NewEvents()
	parser.Parse(datum)
	return datum
}

func NewEvents() *Events {
	return &Events{}
}

func (e *Events) Parse(parser structure.ArrayParser) {
	for _, reference := range parser.References() {
		*e = append(*e, ParseEvent(parser.WithReferenceObjectParser(reference)))
	}
}

func (e *Events) Validate(validator structure.Validator) {
	for index, event := range *e {
		if eventValidator := validator.WithReference(strconv.Itoa(index)); event != nil {
			event.Validate(eventValidator)
		} else {
			eventValidator.ReportError(structureValidator.ErrorValueNotExists())
		}
	}
}

type Event struct {
	SystemTime  *Time    `json:"systemTime,omitempty"`
	DisplayTime *Time    `json:"displayTime,omitempty"`
	Type        *string  `json:"eventType,omitempty"`
	SubType     *string  `json:"eventSubType,omitempty"`
	Unit        *string  `json:"unit,omitempty"`
	Value       *float64 `json:"value,omitempty"`
	ID          *string  `json:"eventId,omitempty"`
	Status      *string  `json:"eventStatus,omitempty"`
}

func ParseEvent(parser structure.ObjectParser) *Event {
	if !parser.Exists() {
		return nil
	}
	datum := NewEvent()
	parser.Parse(datum)
	return datum
}

func NewEvent() *Event {
	return &Event{}
}

func (e *Event) Parse(parser structure.ObjectParser) {
	e.SystemTime = TimeFromRaw(parser.Time("systemTime", TimeFormat))
	e.DisplayTime = TimeFromRaw(parser.Time("displayTime", TimeFormat))
	e.Type = parser.String("eventType")
	e.SubType = parser.String("eventSubType")
	e.Unit = parser.String("unit")
	e.Value = parser.Float64("value")
	e.ID = parser.String("eventId")
	e.Status = parser.String("eventStatus")
}

func (e *Event) Validate(validator structure.Validator) {
	validator = validator.WithMeta(e)
	validator.Time("systemTime", e.SystemTime.Raw()).Exists().NotZero().BeforeNow(SystemTimeNowThreshold)
	validator.Time("displayTime", e.DisplayTime.Raw()).Exists().NotZero()
	validator.String("eventType", e.Type).Exists().OneOf(EventTypes()...)
	if e.Type != nil {
		switch *e.Type {
		case EventTypeCarbs:
			e.validateCarbs(validator)
		case EventTypeExercise:
			e.validateExercise(validator)
		case EventTypeHealth:
			e.validateHealth(validator)
		case EventTypeInsulin:
			e.validateInsulin(validator)
		}
	}
	validator.String("eventId", e.ID).Exists().NotEmpty()
	validator.String("eventStatus", e.Status).Exists().OneOf(EventStatuses()...)
}

func (e *Event) validateCarbs(validator structure.Validator) {
	validator.String("eventSubType", e.SubType).NotExists()
	if e.Unit != nil || e.Value != nil {
		validator.String("unit", e.Unit).Exists().OneOf(EventUnitCarbsGrams)
		validator.Float64("value", e.Value).Exists().InRange(EventValueCarbsGramsMinimum, EventValueCarbsGramsMaximum)
	}
}

func (e *Event) validateExercise(validator structure.Validator) {
	// HACK: Dexcom - value of -1 is invalid; ignore unit and value instead (per Dexcom)
	if e.Value != nil && *e.Value == -1.0 {
		e.Unit = nil
		e.Value = nil
	}

	validator.String("eventSubType", e.SubType).OneOf(EventSubTypesExercise()...)
	if e.Unit != nil || e.Value != nil {
		validator.String("unit", e.Unit).Exists().OneOf(EventUnitExerciseMinutes)
		validator.Float64("value", e.Value).Exists().InRange(EventValueExerciseMinutesMinimum, EventValueExerciseMinutesMaximum)
	}
}

func (e *Event) validateHealth(validator structure.Validator) {
	validator.String("eventSubType", e.SubType).OneOf(EventSubTypesHealth()...)
	validator.String("unit", e.Unit).NotExists()
	if e.Value != nil {
		validator.Float64("value", e.Value).EqualTo(0)
	}
}

func (e *Event) validateInsulin(validator structure.Validator) {
	validator.String("eventSubType", e.SubType).OneOf(EventSubTypesInsulin()...)
	if e.Unit != nil || e.Value != nil {
		validator.String("unit", e.Unit).Exists().OneOf(EventUnitInsulinUnits)
		validator.Float64("value", e.Value).Exists().InRange(EventValueInsulinUnitsMinimum, EventValueInsulinUnitsMaximum)
	}
}
<commit_msg>Remove unnecessary nil equality check<commit_after>package dexcom

import (
	"strconv"

	dataTypesActivityPhysical "github.com/tidepool-org/platform/data/types/activity/physical"
	dataTypesFood "github.com/tidepool-org/platform/data/types/food"
	dataTypesInsulin "github.com/tidepool-org/platform/data/types/insulin"
	"github.com/tidepool-org/platform/structure"
	structureValidator "github.com/tidepool-org/platform/structure/validator"
)

const (
	EventTypeCarbs    = "carbs"
	EventTypeExercise = "exercise"
	EventTypeHealth   = "health"
	EventTypeInsulin  = "insulin"

	EventUnitCarbsGrams         = "grams"
	EventValueCarbsGramsMaximum = dataTypesFood.CarbohydrateNetGramsMaximum
	EventValueCarbsGramsMinimum = dataTypesFood.CarbohydrateNetGramsMinimum

	EventSubTypeExerciseLight        = "light"
	EventSubTypeExerciseMedium       = "medium"
	EventSubTypeExerciseHeavy        = "heavy"
	EventUnitExerciseMinutes         = "minutes"
	EventValueExerciseMinutesMaximum = dataTypesActivityPhysical.DurationValueMinutesMaximum
	EventValueExerciseMinutesMinimum = dataTypesActivityPhysical.DurationValueMinutesMinimum

	EventSubTypeHealthAlcohol      = "alcohol"
	EventSubTypeHealthCycle        = "cycle"
	EventSubTypeHealthHighSymptoms = "highSymptoms"
	EventSubTypeHealthIllness      = "illness"
	EventSubTypeHealthLowSymptoms  = "lowSymptoms"
	EventSubTypeHealthStress       = "stress"

	EventSubTypeInsulinFastActing = "fastActing"
	EventSubTypeInsulinLongActing = "longActing"
	EventUnitInsulinUnits         = "units"
	EventValueInsulinUnitsMaximum = dataTypesInsulin.DoseTotalUnitsMaximum
	EventValueInsulinUnitsMinimum = dataTypesInsulin.DoseTotalUnitsMinimum

	EventStatusCreated = "created"
	EventStatusDeleted = "deleted"
)

func EventTypes() []string {
	return []string{
		EventTypeCarbs,
		EventTypeExercise,
		EventTypeHealth,
		EventTypeInsulin,
	}
}

func EventSubTypesExercise() []string {
	return []string{
		EventSubTypeExerciseLight,
		EventSubTypeExerciseMedium,
		EventSubTypeExerciseHeavy,
	}
}

func EventSubTypesHealth() []string {
	return []string{
		EventSubTypeHealthAlcohol,
		EventSubTypeHealthCycle,
		EventSubTypeHealthHighSymptoms,
		EventSubTypeHealthIllness,
		EventSubTypeHealthLowSymptoms,
		EventSubTypeHealthStress,
	}
}

func EventSubTypesInsulin() []string {
	return []string{
		EventSubTypeInsulinFastActing,
		EventSubTypeInsulinLongActing,
	}
}

func EventStatuses() []string {
	return []string{
		EventStatusCreated,
		EventStatusDeleted,
	}
}

type EventsResponse struct {
	Events *Events `json:"events,omitempty"`
}

func ParseEventsResponse(parser structure.ObjectParser) *EventsResponse {
	if !parser.Exists() {
		return nil
	}
	datum := NewEventsResponse()
	parser.Parse(datum)
	return datum
}

func NewEventsResponse() *EventsResponse {
	return &EventsResponse{}
}

func (e *EventsResponse) Parse(parser structure.ObjectParser) {
	e.Events = ParseEvents(parser.WithReferenceArrayParser("events"))
}

func (e *EventsResponse) Validate(validator structure.Validator) {
	if eventsValidator := validator.WithReference("events"); e.Events != nil {
		e.Events.Validate(eventsValidator)
	} else {
		eventsValidator.ReportError(structureValidator.ErrorValueNotExists())
	}
}

type Events []*Event

func ParseEvents(parser structure.ArrayParser) *Events {
	if !parser.Exists() {
		return nil
	}
	datum := NewEvents()
	parser.Parse(datum)
	return datum
}

func NewEvents() *Events {
	return &Events{}
}

func (e *Events) Parse(parser structure.ArrayParser) {
	for _, reference := range parser.References() {
		*e = append(*e, ParseEvent(parser.WithReferenceObjectParser(reference)))
	}
}

func (e *Events) Validate(validator structure.Validator) {
	for index, event := range *e {
		if eventValidator := validator.WithReference(strconv.Itoa(index)); event != nil {
			event.Validate(eventValidator)
		} else {
			eventValidator.ReportError(structureValidator.ErrorValueNotExists())
		}
	}
}

type Event struct {
	SystemTime  *Time    `json:"systemTime,omitempty"`
	DisplayTime *Time    `json:"displayTime,omitempty"`
	Type        *string  `json:"eventType,omitempty"`
	SubType     *string  `json:"eventSubType,omitempty"`
	Unit        *string  `json:"unit,omitempty"`
	Value       *float64 `json:"value,omitempty"`
	ID          *string  `json:"eventId,omitempty"`
	Status      *string  `json:"eventStatus,omitempty"`
}

func ParseEvent(parser structure.ObjectParser) *Event {
	if !parser.Exists() {
		return nil
	}
	datum := NewEvent()
	parser.Parse(datum)
	return datum
}

func NewEvent() *Event {
	return &Event{}
}

func (e *Event) Parse(parser structure.ObjectParser) {
	e.SystemTime = TimeFromRaw(parser.Time("systemTime", TimeFormat))
	e.DisplayTime = TimeFromRaw(parser.Time("displayTime", TimeFormat))
	e.Type = parser.String("eventType")
	e.SubType = parser.String("eventSubType")
	e.Unit = parser.String("unit")
	e.Value = parser.Float64("value")
	e.ID = parser.String("eventId")
	e.Status = parser.String("eventStatus")
}

func (e *Event) Validate(validator structure.Validator) {
	validator = validator.WithMeta(e)
	validator.Time("systemTime", e.SystemTime.Raw()).Exists().NotZero().BeforeNow(SystemTimeNowThreshold)
	validator.Time("displayTime", e.DisplayTime.Raw()).Exists().NotZero()
	validator.String("eventType", e.Type).Exists().OneOf(EventTypes()...)
	if e.Type != nil {
		switch *e.Type {
		case EventTypeCarbs:
			e.validateCarbs(validator)
		case EventTypeExercise:
			e.validateExercise(validator)
		case EventTypeHealth:
			e.validateHealth(validator)
		case EventTypeInsulin:
			e.validateInsulin(validator)
		}
	}
	validator.String("eventId", e.ID).Exists().NotEmpty()
	validator.String("eventStatus", e.Status).Exists().OneOf(EventStatuses()...)
}

func (e *Event) validateCarbs(validator structure.Validator) {
	validator.String("eventSubType", e.SubType).NotExists()
	if e.Unit != nil || e.Value != nil {
		validator.String("unit", e.Unit).Exists().OneOf(EventUnitCarbsGrams)
		validator.Float64("value", e.Value).Exists().InRange(EventValueCarbsGramsMinimum, EventValueCarbsGramsMaximum)
	}
}

func (e *Event) validateExercise(validator structure.Validator) {
	// HACK: Dexcom - value of -1 is invalid; ignore unit and value instead (per Dexcom)
	if e.Value != nil && *e.Value == -1.0 {
		e.Unit = nil
		e.Value = nil
	}

	validator.String("eventSubType", e.SubType).OneOf(EventSubTypesExercise()...)
	if e.Unit != nil || e.Value != nil {
		validator.String("unit", e.Unit).Exists().OneOf(EventUnitExerciseMinutes)
		validator.Float64("value", e.Value).Exists().InRange(EventValueExerciseMinutesMinimum, EventValueExerciseMinutesMaximum)
	}
}

func (e *Event) validateHealth(validator structure.Validator) {
	validator.String("eventSubType", e.SubType).OneOf(EventSubTypesHealth()...)
	validator.String("unit", e.Unit).NotExists()
	validator.Float64("value", e.Value).EqualTo(0)
}

func (e *Event) validateInsulin(validator structure.Validator) {
	validator.String("eventSubType", e.SubType).OneOf(EventSubTypesInsulin()...)
	if e.Unit != nil || e.Value != nil {
		validator.String("unit", e.Unit).Exists().OneOf(EventUnitInsulinUnits)
		validator.Float64("value", e.Value).Exists().InRange(EventValueInsulinUnitsMinimum, EventValueInsulinUnitsMaximum)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Musicbeat.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package stddata provides a simple mechanism for making
information about "standard" data sets available
for lookups and queries. The standards are:
	Federal Reserve E-Payments Routing Directory
	ISO 639 Language Codes
	ISO 4217 Currency Codes
	ISO 3166-1 Country Codes (Officially Assigned)

Packages

The pieces of stddata's implementation are organized
as follows:
	stddata - interfaces, types, and functions for managing the data providers
	stddata/bank - Federal Reserve E-Payments Routing Directory
		A handy, fixed format text file available at the Fed's website
	stddata/country - ISO 3166-1 Country Codes (Officially Assigned)
		ISO charges for access to this information through their website, but
		Wikipedia has a table of these codes. A data set was extracted from
		Wikipedia's website for use in this package.
	stddata/currency - ISO 4217 Currency Codes
		A handy xml document available from iso.org's website.
	stddata/language - ISO 639 Language Codes
		A handy, pipe-delimited csv file.

*/
package stddata

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
)

// Provider is the interface that wraps all the interfaces
// together. A type that implements Provider's methods
// can be managed as a Standard Data Provider.
type Provider interface {
	// Load loads the data, according to the needs of the particular
	// implementation's standard data set. It returns the number of
	// items it has loaded. If an error occurs, it returns that as well.
	Load() (n int, err error)
	// Search takes the name of the index to be searched, and the value
	// to match in that index. It returns an interface and an error.
	// The value that is returned as v is intended to be marshaled as
	// json -- it is expected to be the collection of entities that
	// match the search.
	Search(index string, q string) (v interface{}, err error)
}

// Service is used to handle http access to the stddata providers' data.
type Service struct {
	Provider   Provider
	Count      int
	EntityName string
}

// LoadProvider is used to prepare the data.
//
// Implementations retrieve their source data, and index it for
// searching.
func (s *Service) LoadProvider(p Provider, e string) (err error) {
	s.Provider = p
	s.EntityName = e
	n, err := s.Provider.Load()
	if err != nil {
		log.Printf("Provider for %s failed to load. %s\n", e, err)
		return errors.New("Searches will get 503 Service Unavailable for this provider")
	}
	s.Count = n
	return nil
}

// ServeHTTP is the Service's implementation for searching.
//
// After some basic validation of the search request, the
// Provider's Search() implementation is called. The response
// from Search() is marshalled into json.
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	// Get the "index=query" parts of the request, for example, "name=Abc".
	// Or for a dump of an index, "name=_dump"
	v := strings.Split(r.URL.RawQuery, "=")
	index := v[0]
	if len(v) < 2 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	if len(index) < 1 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	query := v[1]
	if len(query) < 1 {
		http.Error(w, "Invalid query", http.StatusBadRequest)
		return
	}
	res, err := s.Provider.Search(index, query)
	if err != nil {
		if serr, ok := err.(*ServiceError); ok {
			w.WriteHeader(serr.Code)
			return
		}
		log.Printf("Error %v\n", err)
		return
	}
	// convert result to json
	j, err := json.MarshalIndent(res, "", "  ")
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	io.WriteString(w, fmt.Sprintf("%s\n", j))
}

// ServiceError combines an http status code and an
// application error message.
type ServiceError struct {
	Msg  string // description of error
	Code int    // http status constant
}

// Error implements the built-in error interface on ServiceError.
func (e *ServiceError) Error() string {
	return e.Msg
}
<commit_msg>Comment clarified.<commit_after>// Copyright 2014 Musicbeat.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package stddata provides a simple mechanism for making
information about "standard" data sets available
for lookups and queries. The standards are:
	Federal Reserve E-Payments Routing Directory
	ISO 639 Language Codes
	ISO 4217 Currency Codes
	ISO 3166-1 Country Codes (Officially Assigned)

Packages

The pieces of stddata's implementation are organized
as follows:
	stddata - interfaces, types, and functions for managing the data providers
	stddata/bank - Federal Reserve E-Payments Routing Directory
		A handy, fixed format text file available at the Fed's website
	stddata/country - ISO 3166-1 Country Codes (Officially Assigned)
		ISO charges for access to this information through their website, but
		Wikipedia has a table of these codes. A data set was extracted from
		Wikipedia's website for use in this package.
	stddata/currency - ISO 4217 Currency Codes
		A handy xml document available from iso.org's website.
	stddata/language - ISO 639 Language Codes
		A handy, pipe-delimited csv file.

*/
package stddata

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
)

// Provider is the interface for a Standard Data Provider. A type that
// implements Provider's methods can be managed as a Standard Data Provider.
type Provider interface {
	// Load loads the data, according to the needs of the particular
	// implementation's standard data set. It returns the number of
	// items it has loaded. If an error occurs, it returns that as well.
	Load() (n int, err error)
	// Search takes the name of the index to be searched, and the value
	// to match in that index. It returns an interface and an error.
	// The value that is returned as v is intended to be marshaled as
	// json -- it is expected to be the collection of entities that
	// match the search.
	Search(index string, q string) (v interface{}, err error)
}

// Service is used to handle http access to the stddata providers' data.
type Service struct {
	Provider   Provider
	Count      int
	EntityName string
}

// LoadProvider is used to prepare the data.
//
// Implementations retrieve their source data, and index it for
// searching.
func (s *Service) LoadProvider(p Provider, e string) (err error) {
	s.Provider = p
	s.EntityName = e
	n, err := s.Provider.Load()
	if err != nil {
		log.Printf("Provider for %s failed to load. %s\n", e, err)
		return errors.New("Searches will get 503 Service Unavailable for this provider")
	}
	s.Count = n
	return nil
}

// ServeHTTP is the Service's implementation for searching.
//
// After some basic validation of the search request, the
// Provider's Search() implementation is called. The response
// from Search() is marshalled into json.
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	// Get the "index=query" parts of the request, for example, "name=Abc".
	// Or for a dump of an index, "name=_dump"
	v := strings.Split(r.URL.RawQuery, "=")
	index := v[0]
	if len(v) < 2 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	if len(index) < 1 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	query := v[1]
	if len(query) < 1 {
		http.Error(w, "Invalid query", http.StatusBadRequest)
		return
	}
	res, err := s.Provider.Search(index, query)
	if err != nil {
		if serr, ok := err.(*ServiceError); ok {
			w.WriteHeader(serr.Code)
			return
		}
		log.Printf("Error %v\n", err)
		return
	}
	// convert result to json
	j, err := json.MarshalIndent(res, "", "  ")
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	io.WriteString(w, fmt.Sprintf("%s\n", j))
}

// ServiceError combines an http status code and an
// application error message.
type ServiceError struct {
	Msg  string // description of error
	Code int    // http status constant
}

// Error implements the built-in error interface on ServiceError.
func (e *ServiceError) Error() string {
	return e.Msg
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"testing"
)

func TestFormatYear(t *testing.T) {
	cases := []struct {
		in, want string
	}{
		{"2015", "Thu, 01 Jan 2015 00:00:00 +0000"},
		{"20151102", "Mon, 02 Nov 2015 00:00:00 +0000"},
		{"20152402", "Tue, 24 Feb 2015 00:00:00 +0000"},
		{"", ""},
		{"NOT_A_YEAR", ""},
	}
	for _, c := range cases {
		got := formatYear(c.in)
		if got != c.want {
			t.Errorf("formatYear(%q) == %q, want %q", c.in, got, c.want)
		}
	}
}

func TestFileUrl(t *testing.T) {
	cases := []struct {
		relativePath, baseUrl, want string
	}{
		{"", "", ""},
		{"c/d/e", "a/b/", "a/b/c/d/e"},
		{"c d", "a/b/", "a/b/c%20d"},
	}
	for _, c := range cases {
		got := fileUrl(c.relativePath, c.baseUrl)
		if got != c.want {
			t.Errorf("fileUrl(%q, %q) == %q, want %q", c.relativePath, c.baseUrl, got, c.want)
		}
	}
}
func TestAddMetaPubDate(t *testing.T) {
	pubDate := "Mon, 25 Nov 2013 00:00:00 +0000"
	in := Item{}
	path := "./vendor/src/github.com/mikkyang/id3-go/test.mp3"
	f, _ := os.Stat(path)

	addMeta(path, f, &in)

	if in.PubDate != pubDate {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.PubDate, pubDate)
	}

}
<commit_msg>addMeta: test add Title<commit_after>package main

import (
	"os"
	"testing"
)

func TestFormatYear(t *testing.T) {
	cases := []struct {
		in, want string
	}{
		{"2015", "Thu, 01 Jan 2015 00:00:00 +0000"},
		{"20151102", "Mon, 02 Nov 2015 00:00:00 +0000"},
		{"20152402", "Tue, 24 Feb 2015 00:00:00 +0000"},
		{"", ""},
		{"NOT_A_YEAR", ""},
	}
	for _, c := range cases {
		got := formatYear(c.in)
		if got != c.want {
			t.Errorf("formatYear(%q) == %q, want %q", c.in, got, c.want)
		}
	}
}

func TestFileUrl(t *testing.T) {
	cases := []struct {
		relativePath, baseUrl, want string
	}{
		{"", "", ""},
		{"c/d/e", "a/b/", "a/b/c/d/e"},
		{"c d", "a/b/", "a/b/c%20d"},
	}
	for _, c := range cases {
		got := fileUrl(c.relativePath, c.baseUrl)
		if got != c.want {
			t.Errorf("fileUrl(%q, %q) == %q, want %q", c.relativePath, c.baseUrl, got, c.want)
		}
	}
}

func TestAddMetaTitle(t *testing.T) {
	title := "Nice Life (Feat. Basick)"
	in := Item{}
	path := "./vendor/src/github.com/mikkyang/id3-go/test.mp3"
	f, _ := os.Stat(path)

	addMeta(path, f, &in)

	if in.Title != title {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.Title, title)
	}
}

func TestAddMetaTitleFallbackOnFilieName(t *testing.T) {
	title := "test.mp3"
	in := Item{}
	f, _ := os.Stat("./vendor/src/github.com/mikkyang/id3-go/test.mp3")

	addMeta("NOT_PATH_TO_FILE", f, &in)

	if in.Title != title {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.Title, title)
	}
}

func TestAddMetaPubDate(t *testing.T) {
	pubDate := "Mon, 25 Nov 2013 00:00:00 +0000"
	in := Item{}
	path := "./vendor/src/github.com/mikkyang/id3-go/test.mp3"
	f, _ := os.Stat(path)

	addMeta(path, f, &in)

	if in.PubDate != pubDate {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.PubDate, pubDate)
	}

}
<|endoftext|>


<commit_before>package email

import (
	"code.google.com/p/go-uuid/uuid"

	"bytes"
	"encoding/json"
	"fmt"
	"mime/multipart"
	"net/mail"
	"net/textproto"
	"os"
	"strings"
	"time"
)

// Individual message for sending to a host.
type Email struct {
	Id      string
	Host    string
	From    string
	To      []string
	Message []byte
}

// Add the specified content to a multipart/alternative writer.
func addPart(w *multipart.Writer, contentType string, content []byte) error {
	header := make(textproto.MIMEHeader)
	header.Add("Content-Type", contentType)
	writer, err := w.CreatePart(header)
	if err != nil {
		return err
	}
	_, err = writer.Write(content)
	return err
}

// Create a multipart/alternative body with the specified data. Both the body
// and the separator are returned. Because data is written to a bytes.Buffer,
// it is probably safe to ignore any errors.
func createMultipartBody(text, html string) ([]byte, string) {
	var (
		buff   = &bytes.Buffer{}
		writer = multipart.NewWriter(buff)
	)
	addPart(writer, "text/plain", []byte(text))
	addPart(writer, "text/html", []byte(html))
	writer.Close()
	return buff.Bytes(), writer.Boundary()
}

// Attempt to extract the host from the provided email address.
func hostFromAddress(data string) (string, error) {
	if addr, err := mail.ParseAddress(data); err != nil {
		return "", err
	} else {
		return strings.Split(addr.Address, "@")[1], nil
	}
}

// Group a list of email addresses by their host.
func groupAddressesByHost(addrs []string) (map[string][]string, error) {
	m := make(map[string][]string)
	for _, addr := range addrs {
		if host, err := hostFromAddress(addr); err != nil {
			return nil, err
		} else {
			if m[host] == nil {
				m[host] = make([]string, 0, 1)
			}
			m[host] = append(m[host], addr)
		}
	}
	return m, nil
}

// Create an array of emails from the specified information. An email will be
// generated for each individual host and for each BCC recipient.
func NewEmails(from string, to, cc, bcc []string, subject string, text, html string) ([]*Email, error) {

	// Retrieve the current hostname
	hostname, err := os.Hostname()
	if err != nil {
		return nil, err
	}

	// Create the array of emails that will be returned, the buffer that will
	// be used for generating the message, and each of the individual parts
	// of the message
	var (
		emails         = make([]*Email, 0, 1)
		buff           = &bytes.Buffer{}
		id             = fmt.Sprintf("<%s@%s>", uuid.New(), hostname)
		body, boundary = createMultipartBody(text, html)
		hdrs           = map[string]string{
			"Message-ID":   id,
			"From":         from,
			"To":           strings.Join(to, ","),
			"Subject":      subject,
			"Date":         time.Now().Format(time.RubyDate),
			"MIME-Version": "1.0",
			"Content-Type": fmt.Sprintf("multipart/alternative; boundary=\"%s\"", boundary),
		}
	)

	// If any Cc addresses were provided, add them to the headers
	if len(cc) > 0 {
		hdrs["Cc"] = strings.Join(cc, ",")
	}

	// Write all of the headers followed by the body
	for h := range hdrs {
		buff.Write([]byte(fmt.Sprintf("%s: %s\r\n", h, hdrs[h])))
	}

	// Write the extra CRLF and body
	buff.Write([]byte("\r\n"))
	buff.Write(body)

	// Combine the "To", "Cc", and "Bcc" addresses and group them by hostname
	// in order to make delivery much more efficient
	addrMap, err := groupAddressesByHost(append(append(to, cc...), bcc...))
	for host := range addrMap {
		emails = append(emails, &Email{
			Id:      id,
			Host:    host,
			From:    from,
			To:      addrMap[host],
			Message: buff.Bytes(),
		})
	}

	return emails, nil
}

// Load an email from disk.
func LoadEmail(filename string) (*Email, error) {

	// Attempt to open the file
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	// Attempt to decode the JSON from the file
	var e Email
	if err = json.NewDecoder(f).Decode(&e); err != nil {
		return nil, err
	}

	return &e, nil
}
<commit_msg>Added Save() and Delete() methods to Email type.<commit_after>package email

import (
	"code.google.com/p/go-uuid/uuid"

	"bytes"
	"encoding/json"
	"fmt"
	"mime/multipart"
	"net/mail"
	"net/textproto"
	"os"
	"path"
	"strings"
	"time"
)

// Individual message for sending to a host.
type Email struct {
	Id      string
	Host    string
	From    string
	To      []string
	Message []byte
}

// Add the specified content to a multipart/alternative writer.
func addPart(w *multipart.Writer, contentType string, content []byte) error {
	header := make(textproto.MIMEHeader)
	header.Add("Content-Type", contentType)
	writer, err := w.CreatePart(header)
	if err != nil {
		return err
	}
	_, err = writer.Write(content)
	return err
}

// Create a multipart/alternative body with the specified data. Both the body
// and the separator are returned. Because data is written to a bytes.Buffer,
// it is probably safe to ignore any errors.
func createMultipartBody(text, html string) ([]byte, string) {
	var (
		buff   = &bytes.Buffer{}
		writer = multipart.NewWriter(buff)
	)
	addPart(writer, "text/plain", []byte(text))
	addPart(writer, "text/html", []byte(html))
	writer.Close()
	return buff.Bytes(), writer.Boundary()
}

// Attempt to extract the host from the provided email address.
func hostFromAddress(data string) (string, error) {
	if addr, err := mail.ParseAddress(data); err != nil {
		return "", err
	} else {
		return strings.Split(addr.Address, "@")[1], nil
	}
}

// Group a list of email addresses by their host.
func groupAddressesByHost(addrs []string) (map[string][]string, error) {
	m := make(map[string][]string)
	for _, addr := range addrs {
		if host, err := hostFromAddress(addr); err != nil {
			return nil, err
		} else {
			if m[host] == nil {
				m[host] = make([]string, 0, 1)
			}
			m[host] = append(m[host], addr)
		}
	}
	return m, nil
}

// Create an array of emails from the specified information. An email will be
// generated for each individual host and for each BCC recipient.
func NewEmails(from string, to, cc, bcc []string, subject string, text, html string) ([]*Email, error) {

	// Retrieve the current hostname
	hostname, err := os.Hostname()
	if err != nil {
		return nil, err
	}

	// Create the array of emails that will be returned, the buffer that will
	// be used for generating the message, and each of the individual parts
	// of the message
	var (
		emails         = make([]*Email, 0, 1)
		buff           = &bytes.Buffer{}
		id             = fmt.Sprintf("<%s@%s>", uuid.New(), hostname)
		body, boundary = createMultipartBody(text, html)
		hdrs           = map[string]string{
			"Message-ID":   id,
			"From":         from,
			"To":           strings.Join(to, ","),
			"Subject":      subject,
			"Date":         time.Now().Format(time.RubyDate),
			"MIME-Version": "1.0",
			"Content-Type": fmt.Sprintf("multipart/alternative; boundary=\"%s\"", boundary),
		}
	)

	// If any Cc addresses were provided, add them to the headers
	if len(cc) > 0 {
		hdrs["Cc"] = strings.Join(cc, ",")
	}

	// Write all of the headers followed by the body
	for h := range hdrs {
		buff.Write([]byte(fmt.Sprintf("%s: %s\r\n", h, hdrs[h])))
	}

	// Write the extra CRLF and body
	buff.Write([]byte("\r\n"))
	buff.Write(body)

	// Combine the "To", "Cc", and "Bcc" addresses and group them by hostname
	// in order to make delivery much more efficient
	addrMap, err := groupAddressesByHost(append(append(to, cc...), bcc...))
	for host := range addrMap {
		emails = append(emails, &Email{
			Id:      id,
			Host:    host,
			From:    from,
			To:      addrMap[host],
			Message: buff.Bytes(),
		})
	}

	return emails, nil
}

// Load an email from disk.
func LoadEmail(filename string) (*Email, error) {

	// Attempt to open the file
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	// Decode the JSON from the file
	var e Email
	if err = json.NewDecoder(f).Decode(&e); err != nil {
		return nil, err
	}

	return &e, nil
}

// Save the email to the specified directory.
func (e *Email) Save(directory string) error {

	// Attempt to create the , making sure nobody else can read it
	f, err := os.OpenFile(path.Join(directory, e.Id), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	// Encode the data as JSON
	if err = json.NewEncoder(f).Encode(e); err != nil {
		return err
	}

	return nil
}

// Delete the email from the specified directory.
func (e *Email) Delete(directory string) error {
	return os.Remove(path.Join(directory, e.Id))
}
<|endoftext|>