<commit_before>package main

import (
	"log"
	"net/http"
	"os"

	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-flynn/cluster"
	"github.com/flynn/go-flynn/postgres"
	"github.com/flynn/go-flynn/resource"
	"github.com/flynn/go-sql"
	"github.com/flynn/rpcplus"
	strowgerc "github.com/flynn/strowger/client"
	"github.com/flynn/strowger/types"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
)

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	addr := ":" + port

	db, err := postgres.Open("", "")
	if err != nil {
		log.Fatal(err)
	}

	cc, err := cluster.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	sc, err := strowgerc.New()
	if err != nil {
		log.Fatal(err)
	}

	if err := discoverd.Register("flynn-controller", addr); err != nil {
		log.Fatal(err)
	}

	handler, _ := appHandler(db.DB, cc, sc)
	log.Fatal(http.ListenAndServe(addr, handler))
}

func appHandler(db *sql.DB, cc clusterClient, sc strowgerc.Client) (http.Handler, *martini.Martini) {
	r := martini.NewRouter()
	m := martini.New()
	m.Use(martini.Logger())
	m.Use(martini.Recovery())
	m.Use(render.Renderer())
	m.Action(r.Handle)

	d := NewDB(db)

	providerRepo := NewProviderRepo(d)
	keyRepo := NewKeyRepo(d)
	resourceRepo := NewResourceRepo(d)
	appRepo := NewAppRepo(d)
	artifactRepo := NewArtifactRepo(d)
	releaseRepo := NewReleaseRepo(d)
	formationRepo := NewFormationRepo(d, appRepo, releaseRepo, artifactRepo)
	m.Map(resourceRepo)
	m.Map(appRepo)
	m.Map(artifactRepo)
	m.Map(releaseRepo)
	m.Map(formationRepo)
	m.MapTo(cc, (*clusterClient)(nil))
	m.MapTo(sc, (*strowgerc.Client)(nil))

	getAppMiddleware := crud("apps", ct.App{}, appRepo, r)
	getReleaseMiddleware := crud("releases", ct.Release{}, releaseRepo, r)
	getProviderMiddleware := crud("providers", ct.Provider{}, providerRepo, r)
	crud("artifacts", ct.Artifact{}, artifactRepo, r)
	crud("keys", ct.Key{}, keyRepo, r)

	r.Put("/apps/:apps_id/formations/:releases_id", getAppMiddleware, getReleaseMiddleware, binding.Bind(ct.Formation{}), putFormation)
	r.Get("/apps/:apps_id/formations/:releases_id", getAppMiddleware, getFormationMiddleware, getFormation)
	r.Delete("/apps/:apps_id/formations/:releases_id", getAppMiddleware, getFormationMiddleware, deleteFormation)
	r.Get("/apps/:apps_id/formations", getAppMiddleware, listFormations)

	r.Post("/apps/:apps_id/jobs", getAppMiddleware, binding.Bind(ct.NewJob{}), runJob)
	r.Get("/apps/:apps_id/jobs", getAppMiddleware, jobList)
	r.Delete("/apps/:apps_id/jobs/:jobs_id", getAppMiddleware, connectHostMiddleware, killJob)
	r.Get("/apps/:apps_id/jobs/:jobs_id/log", getAppMiddleware, connectHostMiddleware, jobLog)

	r.Put("/apps/:apps_id/release", getAppMiddleware, binding.Bind(releaseID{}), setAppRelease)
	r.Get("/apps/:apps_id/release", getAppMiddleware, getAppRelease)

	r.Post("/providers/:providers_id/resources", getProviderMiddleware, binding.Bind(ct.ResourceReq{}), resourceServerMiddleware, provisionResource)
	r.Get("/providers/:providers_id/resources", getProviderMiddleware, getProviderResources)
	r.Get("/providers/:providers_id/resources/:resources_id", getProviderMiddleware, getResourceMiddleware, getResource)
	r.Put("/providers/:providers_id/resources/:resources_id", getProviderMiddleware, binding.Bind(ct.Resource{}), putResource)
	r.Get("/apps/:apps_id/resources", getAppMiddleware, getAppResources)

	r.Post("/apps/:apps_id/routes", getAppMiddleware, binding.Bind(strowger.Route{}), createRoute)
	r.Get("/apps/:apps_id/routes", getAppMiddleware, getRouteList)
	r.Get("/apps/:apps_id/routes/:routes_type/:routes_id", getAppMiddleware, getRouteMiddleware, getRoute)
	r.Delete("/apps/:apps_id/routes/:routes_type/:routes_id", getAppMiddleware, getRouteMiddleware, deleteRoute)

	return rpcMuxHandler(m, rpcHandler(formationRepo)), m
}

func rpcMuxHandler(main http.Handler, rpch http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == rpcplus.DefaultRPCPath {
			rpch.ServeHTTP(w, r)
		} else {
			main.ServeHTTP(w, r)
		}
	})
}

func putFormation(formation ct.Formation, app *ct.App, release *ct.Release, repo *FormationRepo, r render.Render) {
	formation.AppID = app.ID
	formation.ReleaseID = release.ID
	err := repo.Add(&formation)
	if app.Protected {
		for typ := range release.Processes {
			if formation.Processes[typ] == 0 {
				r.JSON(400, struct{}{})
				return
			}
		}
	}
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, &formation)
}

func getFormationMiddleware(c martini.Context, app *ct.App, params martini.Params, repo *FormationRepo, w http.ResponseWriter) {
	formation, err := repo.Get(app.ID, params["releases_id"])
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(404)
			return
		}
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	c.Map(formation)
}

func getFormation(formation *ct.Formation, r render.Render) {
	r.JSON(200, formation)
}

func deleteFormation(formation *ct.Formation, repo *FormationRepo, w http.ResponseWriter) {
	err := repo.Remove(formation.AppID, formation.ReleaseID)
	if err != nil {
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	w.WriteHeader(200)
}

func listFormations(app *ct.App, repo *FormationRepo, r render.Render) {
	list, err := repo.List(app.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, list)
}

type releaseID struct {
	ID string `json:"id"`
}

func setAppRelease(app *ct.App, rid releaseID, apps *AppRepo, releases *ReleaseRepo, formations *FormationRepo, r render.Render) {
	rel, err := releases.Get(rid.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	release := rel.(*ct.Release)
	apps.SetRelease(app.ID, release.ID)

	// TODO: use transaction/lock
	fs, err := formations.List(app.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	if len(fs) == 1 && fs[0].ReleaseID != release.ID {
		if err := formations.Add(&ct.Formation{
			AppID:     app.ID,
			ReleaseID: release.ID,
			Processes: fs[0].Processes,
		}); err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
		if err := formations.Remove(app.ID, fs[0].ReleaseID); err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
	}

	r.JSON(200, release)
}

func getAppRelease(app *ct.App, apps *AppRepo, r render.Render, w http.ResponseWriter) {
	release, err := apps.GetRelease(app.ID)
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(404)
			return
		}
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	r.JSON(200, release)
}

func resourceServerMiddleware(c martini.Context, p *ct.Provider, dc resource.DiscoverdClient, w http.ResponseWriter) {
	server, err := resource.NewServerWithDiscoverd(p.URL, dc)
	if err != nil {
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	c.Map(server)
	c.Next()
	server.Close()
}

func putResource(p *ct.Provider, params martini.Params, resource ct.Resource, repo *ResourceRepo, r render.Render) {
	resource.ID = params["resources_id"]
	resource.ProviderID = p.ID
	if err := repo.Add(&resource); err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, &resource)
}

func provisionResource(rs *resource.Server, p *ct.Provider, req ct.ResourceReq, repo *ResourceRepo, r render.Render) {
	var config []byte
	if req.Config != nil {
		config = *req.Config
	} else {
		config = []byte(`{}`)
	}
	data, err := rs.Provision(config)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}

	res := &ct.Resource{
		ProviderID: p.ID,
		ExternalID: data.ID,
		Env:        data.Env,
		Apps:       req.Apps,
	}
	if err := repo.Add(res); err != nil {
		// TODO: attempt to "rollback" provisioning
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, res)
}

func getResourceMiddleware(c martini.Context, params martini.Params, repo *ResourceRepo, w http.ResponseWriter) {
	resource, err := repo.Get(params["resources_id"])
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(404)
			return
		}
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	c.Map(resource)
}

func getResource(resource *ct.Resource, r render.Render) {
	r.JSON(200, resource)
}

func getProviderResources(p *ct.Provider, repo *ResourceRepo, r render.Render) {
	res, err := repo.ProviderList(p.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, res)
}

func getAppResources(app *ct.App, repo *ResourceRepo, r render.Render) {
	res, err := repo.AppList(app.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, res)
}
<commit_msg>controller: Run db migrations on boot<commit_after>package main

import (
	"log"
	"net/http"
	"os"

	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-flynn/cluster"
	"github.com/flynn/go-flynn/postgres"
	"github.com/flynn/go-flynn/resource"
	"github.com/flynn/go-sql"
	"github.com/flynn/rpcplus"
	strowgerc "github.com/flynn/strowger/client"
	"github.com/flynn/strowger/types"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
)

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	addr := ":" + port

	db, err := postgres.Open("", "")
	if err != nil {
		log.Fatal(err)
	}

	if err := migrateDB(db.DB); err != nil {
		log.Fatal(err)
	}

	cc, err := cluster.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	sc, err := strowgerc.New()
	if err != nil {
		log.Fatal(err)
	}

	if err := discoverd.Register("flynn-controller", addr); err != nil {
		log.Fatal(err)
	}

	handler, _ := appHandler(db.DB, cc, sc)
	log.Fatal(http.ListenAndServe(addr, handler))
}

func appHandler(db *sql.DB, cc clusterClient, sc strowgerc.Client) (http.Handler, *martini.Martini) {
	r := martini.NewRouter()
	m := martini.New()
	m.Use(martini.Logger())
	m.Use(martini.Recovery())
	m.Use(render.Renderer())
	m.Action(r.Handle)

	d := NewDB(db)

	providerRepo := NewProviderRepo(d)
	keyRepo := NewKeyRepo(d)
	resourceRepo := NewResourceRepo(d)
	appRepo := NewAppRepo(d)
	artifactRepo := NewArtifactRepo(d)
	releaseRepo := NewReleaseRepo(d)
	formationRepo := NewFormationRepo(d, appRepo, releaseRepo, artifactRepo)
	m.Map(resourceRepo)
	m.Map(appRepo)
	m.Map(artifactRepo)
	m.Map(releaseRepo)
	m.Map(formationRepo)
	m.MapTo(cc, (*clusterClient)(nil))
	m.MapTo(sc, (*strowgerc.Client)(nil))

	getAppMiddleware := crud("apps", ct.App{}, appRepo, r)
	getReleaseMiddleware := crud("releases", ct.Release{}, releaseRepo, r)
	getProviderMiddleware := crud("providers", ct.Provider{}, providerRepo, r)
	crud("artifacts", ct.Artifact{}, artifactRepo, r)
	crud("keys", ct.Key{}, keyRepo, r)

	r.Put("/apps/:apps_id/formations/:releases_id", getAppMiddleware, getReleaseMiddleware, binding.Bind(ct.Formation{}), putFormation)
	r.Get("/apps/:apps_id/formations/:releases_id", getAppMiddleware, getFormationMiddleware, getFormation)
	r.Delete("/apps/:apps_id/formations/:releases_id", getAppMiddleware, getFormationMiddleware, deleteFormation)
	r.Get("/apps/:apps_id/formations", getAppMiddleware, listFormations)

	r.Post("/apps/:apps_id/jobs", getAppMiddleware, binding.Bind(ct.NewJob{}), runJob)
	r.Get("/apps/:apps_id/jobs", getAppMiddleware, jobList)
	r.Delete("/apps/:apps_id/jobs/:jobs_id", getAppMiddleware, connectHostMiddleware, killJob)
	r.Get("/apps/:apps_id/jobs/:jobs_id/log", getAppMiddleware, connectHostMiddleware, jobLog)

	r.Put("/apps/:apps_id/release", getAppMiddleware, binding.Bind(releaseID{}), setAppRelease)
	r.Get("/apps/:apps_id/release", getAppMiddleware, getAppRelease)

	r.Post("/providers/:providers_id/resources", getProviderMiddleware, binding.Bind(ct.ResourceReq{}), resourceServerMiddleware, provisionResource)
	r.Get("/providers/:providers_id/resources", getProviderMiddleware, getProviderResources)
	r.Get("/providers/:providers_id/resources/:resources_id", getProviderMiddleware, getResourceMiddleware, getResource)
	r.Put("/providers/:providers_id/resources/:resources_id", getProviderMiddleware, binding.Bind(ct.Resource{}), putResource)
	r.Get("/apps/:apps_id/resources", getAppMiddleware, getAppResources)

	r.Post("/apps/:apps_id/routes", getAppMiddleware, binding.Bind(strowger.Route{}), createRoute)
	r.Get("/apps/:apps_id/routes", getAppMiddleware, getRouteList)
	r.Get("/apps/:apps_id/routes/:routes_type/:routes_id", getAppMiddleware, getRouteMiddleware, getRoute)
	r.Delete("/apps/:apps_id/routes/:routes_type/:routes_id", getAppMiddleware, getRouteMiddleware, deleteRoute)

	return rpcMuxHandler(m, rpcHandler(formationRepo)), m
}

func rpcMuxHandler(main http.Handler, rpch http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == rpcplus.DefaultRPCPath {
			rpch.ServeHTTP(w, r)
		} else {
			main.ServeHTTP(w, r)
		}
	})
}

func putFormation(formation ct.Formation, app *ct.App, release *ct.Release, repo *FormationRepo, r render.Render) {
	formation.AppID = app.ID
	formation.ReleaseID = release.ID
	err := repo.Add(&formation)
	if app.Protected {
		for typ := range release.Processes {
			if formation.Processes[typ] == 0 {
				r.JSON(400, struct{}{})
				return
			}
		}
	}
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, &formation)
}

func getFormationMiddleware(c martini.Context, app *ct.App, params martini.Params, repo *FormationRepo, w http.ResponseWriter) {
	formation, err := repo.Get(app.ID, params["releases_id"])
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(404)
			return
		}
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	c.Map(formation)
}

func getFormation(formation *ct.Formation, r render.Render) {
	r.JSON(200, formation)
}

func deleteFormation(formation *ct.Formation, repo *FormationRepo, w http.ResponseWriter) {
	err := repo.Remove(formation.AppID, formation.ReleaseID)
	if err != nil {
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	w.WriteHeader(200)
}

func listFormations(app *ct.App, repo *FormationRepo, r render.Render) {
	list, err := repo.List(app.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, list)
}

type releaseID struct {
	ID string `json:"id"`
}

func setAppRelease(app *ct.App, rid releaseID, apps *AppRepo, releases *ReleaseRepo, formations *FormationRepo, r render.Render) {
	rel, err := releases.Get(rid.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	release := rel.(*ct.Release)
	apps.SetRelease(app.ID, release.ID)

	// TODO: use transaction/lock
	fs, err := formations.List(app.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	if len(fs) == 1 && fs[0].ReleaseID != release.ID {
		if err := formations.Add(&ct.Formation{
			AppID:     app.ID,
			ReleaseID: release.ID,
			Processes: fs[0].Processes,
		}); err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
		if err := formations.Remove(app.ID, fs[0].ReleaseID); err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
	}

	r.JSON(200, release)
}

func getAppRelease(app *ct.App, apps *AppRepo, r render.Render, w http.ResponseWriter) {
	release, err := apps.GetRelease(app.ID)
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(404)
			return
		}
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	r.JSON(200, release)
}

func resourceServerMiddleware(c martini.Context, p *ct.Provider, dc resource.DiscoverdClient, w http.ResponseWriter) {
	server, err := resource.NewServerWithDiscoverd(p.URL, dc)
	if err != nil {
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	c.Map(server)
	c.Next()
	server.Close()
}

func putResource(p *ct.Provider, params martini.Params, resource ct.Resource, repo *ResourceRepo, r render.Render) {
	resource.ID = params["resources_id"]
	resource.ProviderID = p.ID
	if err := repo.Add(&resource); err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, &resource)
}

func provisionResource(rs *resource.Server, p *ct.Provider, req ct.ResourceReq, repo *ResourceRepo, r render.Render) {
	var config []byte
	if req.Config != nil {
		config = *req.Config
	} else {
		config = []byte(`{}`)
	}
	data, err := rs.Provision(config)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}

	res := &ct.Resource{
		ProviderID: p.ID,
		ExternalID: data.ID,
		Env:        data.Env,
		Apps:       req.Apps,
	}
	if err := repo.Add(res); err != nil {
		// TODO: attempt to "rollback" provisioning
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, res)
}

func getResourceMiddleware(c martini.Context, params martini.Params, repo *ResourceRepo, w http.ResponseWriter) {
	resource, err := repo.Get(params["resources_id"])
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(404)
			return
		}
		log.Println(err)
		w.WriteHeader(500)
		return
	}
	c.Map(resource)
}

func getResource(resource *ct.Resource, r render.Render) {
	r.JSON(200, resource)
}

func getProviderResources(p *ct.Provider, repo *ResourceRepo, r render.Render) {
	res, err := repo.ProviderList(p.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, res)
}

func getAppResources(app *ct.App, repo *ResourceRepo, r render.Render) {
	res, err := repo.AppList(app.ID)
	if err != nil {
		log.Println(err)
		r.JSON(500, struct{}{})
		return
	}
	r.JSON(200, res)
}
<|endoftext|>


<commit_before>package Hashing

// Implementaiton of Graphite's consistent hashing algorithm.
//
// Should behave as https://github.com/graphite-project/carbon/blob/master/lib/carbon/hashing.py

import (
	"crypto/md5"
	"fmt"
	"sort"
)

type ringEntry struct {
	hash uint16
	key  string
}

type ringEntries []*ringEntry

func (s ringEntries) Len() int           { return len(s) }
func (s ringEntries) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s ringEntries) Less(i, j int) bool { return s[i].hash < s[j].hash }

type ConsistentHashRing struct {
	ring         ringEntries
	nodes        []string
	replicaCount int
}

func NewConsistentHashRing(nodes []string, replicaCount int) *ConsistentHashRing {
	s := &ConsistentHashRing{}
	s.ring = ringEntries{}
	s.nodes = make([]string, 0)
	s.replicaCount = replicaCount

	// Add the given nodes
	for _, n := range nodes {
		s.AddNode(n)
	}

	return s
}

// Compute md5(key) and return the first two bytes as an uint16
func computeRingPosition(key string) uint16 {
	h := md5.New()
	h.Write([]byte(key))
	sum := h.Sum(nil)
	i := uint16(sum[0])<<8 | uint16(sum[1])
	return i
}

// Add a node to the ring
func (s *ConsistentHashRing) AddNode(node string) {
	s.nodes = append(s.nodes, node)

	// Insert node into ring
	for i := 0; i < s.replicaCount; i += 1 {
		key := fmt.Sprintf("%s:%d", node, i)
		position := computeRingPosition(key)
		s.ring = append(s.ring, &ringEntry{position, node})
	}
	sort.Sort(s.ring)
}

func (s *ConsistentHashRing) RemoveNode(node string) {
	// Copy current ring-list and empty other state
	newNodes := make([]string, 0)
	s.nodes = make([]string, 0)
	s.ring = ringEntries{}

	// Copy over nodes we want to keep
	for _, nnode := range newNodes {
		if node != nnode {
			s.AddNode(node)
		}
	}
}

func (s *ConsistentHashRing) getFirstMatchingIndex(key string) int {
	keyHash := computeRingPosition(key)

	// If the hash is greater than the last element, it means we should wrp
	// to the first element.
	if keyHash > s.ring[len(s.ring)-1].hash {
		return 0
	}

	// Do a binary search for the appropriate element
	return sort.Search(
		len(s.ring),
		func(i int) bool { return s.ring[i].hash >= keyHash },
	)
}

// Return first node hit in the ring for the given key.
func (s *ConsistentHashRing) GetNode(key string) string {
	return s.ring[s.getFirstMatchingIndex(key)].key
}

// Return all relevant nodes to send the given key to.
//
// Trivial implementation that makes no attempts at being fast...
func (s *ConsistentHashRing) GetNodes(key string) []string {
	// Array of keys to fill out
	out := make([]int, 1)

	// Get the first element
	out[0] = s.getFirstMatchingIndex(key)

	// Search forward in the hash until we have seen each server once
	for i := (out[0] + 1) % len(s.ring); i != out[0]; i = (i + 1) % len(s.ring) {
		// Check if we already have seen this node
		seen := false
		for _, o := range out {
			if s.ring[i].key == s.ring[o].key {
				seen = true
			}
		}

		if !seen {
			out = append(out, i)
		}
	}

	// Convert output to something sensible
	outStrings := make([]string, len(out))
	for i, o := range out {
		outStrings[i] = s.ring[o].key
	}

	// Can return nodes in any order
	return outStrings
}
<commit_msg>Hashing: Removed allocations when computing hash ring positions. 33% speedup.<commit_after>package Hashing

// Implementaiton of Graphite's consistent hashing algorithm.
//
// Should behave as https://github.com/graphite-project/carbon/blob/master/lib/carbon/hashing.py

import (
	"crypto/md5"
	"fmt"
	"sort"
)

type ringEntry struct {
	hash uint16
	key  string
}

type ringEntries []*ringEntry

func (s ringEntries) Len() int           { return len(s) }
func (s ringEntries) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s ringEntries) Less(i, j int) bool { return s[i].hash < s[j].hash }

type ConsistentHashRing struct {
	ring         ringEntries
	nodes        []string
	replicaCount int
}

func NewConsistentHashRing(nodes []string, replicaCount int) *ConsistentHashRing {
	s := &ConsistentHashRing{}
	s.ring = ringEntries{}
	s.nodes = make([]string, 0)
	s.replicaCount = replicaCount

	// Add the given nodes
	for _, n := range nodes {
		s.AddNode(n)
	}

	return s
}

// Compute md5(key) and return the first two bytes as an uint16
func computeRingPosition(key string) uint16 {
	sum := md5.Sum([]byte(key))
	i := uint16(sum[0])<<8 | uint16(sum[1])
	return i
}

// Add a node to the ring
func (s *ConsistentHashRing) AddNode(node string) {
	s.nodes = append(s.nodes, node)

	// Insert node into ring
	for i := 0; i < s.replicaCount; i += 1 {
		key := fmt.Sprintf("%s:%d", node, i)
		position := computeRingPosition(key)
		s.ring = append(s.ring, &ringEntry{position, node})
	}
	sort.Sort(s.ring)
}

func (s *ConsistentHashRing) RemoveNode(node string) {
	// Copy current ring-list and empty other state
	newNodes := make([]string, 0)
	s.nodes = make([]string, 0)
	s.ring = ringEntries{}

	// Copy over nodes we want to keep
	for _, nnode := range newNodes {
		if node != nnode {
			s.AddNode(node)
		}
	}
}

func (s *ConsistentHashRing) getFirstMatchingIndex(key string) int {
	keyHash := computeRingPosition(key)

	// If the hash is greater than the last element, it means we should wrp
	// to the first element.
	if keyHash > s.ring[len(s.ring)-1].hash {
		return 0
	}

	// Do a binary search for the appropriate element
	return sort.Search(
		len(s.ring),
		func(i int) bool { return s.ring[i].hash >= keyHash },
	)
}

// Return first node hit in the ring for the given key.
func (s *ConsistentHashRing) GetNode(key string) string {
	return s.ring[s.getFirstMatchingIndex(key)].key
}

// Return all relevant nodes to send the given key to.
//
// Trivial implementation that makes no attempts at being fast...
func (s *ConsistentHashRing) GetNodes(key string) []string {
	// Array of keys to fill out
	out := make([]int, 1)

	// Get the first element
	out[0] = s.getFirstMatchingIndex(key)

	// Search forward in the hash until we have seen each server once
	for i := (out[0] + 1) % len(s.ring); i != out[0]; i = (i + 1) % len(s.ring) {
		// Check if we already have seen this node
		seen := false
		for _, o := range out {
			if s.ring[i].key == s.ring[o].key {
				seen = true
			}
		}

		if !seen {
			out = append(out, i)
		}
	}

	// Convert output to something sensible
	outStrings := make([]string, len(out))
	for i, o := range out {
		outStrings[i] = s.ring[o].key
	}

	// Can return nodes in any order
	return outStrings
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"io/ioutil"

	"encoding/json"

	"github.com/romana/core/common"
	"github.com/romana/core/common/api"
	"github.com/romana/core/common/log/trace"
	log "github.com/romana/rlog"
)

const (
	DefaultEtcdPrefix    = "/romana"
	DefaultEtcdEndpoints = "localhost:2379"

	ipamKey        = "/ipam"
	ipamDataKey    = ipamKey + "/data"
	PoliciesPrefix = "/policies"
)

type Client struct {
	config     *common.Config
	Store      *Store
	ipamLocker Locker
	IPAM       *IPAM
}

// NewClient creates a new Client object based on provided config
func NewClient(config *common.Config) (*Client, error) {
	if config.EtcdPrefix == "" {
		config.EtcdPrefix = DefaultEtcdPrefix
	}
	store, err := NewStore(config.EtcdEndpoints, config.EtcdPrefix)
	if err != nil {
		return nil, err
	}

	c := &Client{
		config: config,
		Store:  store,
	}

	err = c.initIPAM(config.InitialTopologyFile)
	if err != nil {
		return nil, err
	}
	err = c.watchIPAM()
	if err != nil {
		return nil, err
	}
	return c, nil
}

func (c *Client) ListHosts() api.HostList {
	return c.IPAM.ListHosts()
}

type HostListCallback func(api.HostList)

func (c *Client) WatchHostsWithCallback(cb HostListCallback) error {
	// TODO this needs a way to remove the callback function
	// (to stop listening)
	log.Tracef(trace.Public, "Entering WatchHostsWithCallback.")
	stopCh := make(chan struct{})
	ch, err := c.WatchHosts(stopCh)
	if err != nil {
		return err
	}
	go func() {
		for {
			select {
			case result := <-ch:
				cb(result)
			}
		}
	}()
	return nil
}

type BlocksCallback func(api.IPAMBlocksResponse)

func (c *Client) WatchBlocksWithCallback(cb BlocksCallback) error {
	// TODO this needs a way to remove the callback function
	// (to stop listening)
	log.Tracef(trace.Public, "Entering WatchBlocksWithCallback.")
	stopCh := make(chan struct{})
	ch, err := c.WatchBlocks(stopCh)
	if err != nil {
		return err
	}
	go func() {
		for {
			select {
			case result := <-ch:
				cb(result)
			}
		}
	}()
	return nil
}

// WatchBlocks is similar to Watch of libkv store, but specific
// to watching for blocks.
func (c *Client) WatchBlocks(stopCh <-chan struct{}) (<-chan api.IPAMBlocksResponse, error) {
	log.Tracef(trace.Public, "Entering WatchBlocks.")
	ch, err := c.Store.ReconnectingWatch(ipamDataKey, stopCh)
	if err != nil {
		return nil, err
	}
	outCh := make(chan api.IPAMBlocksResponse)
	// Since for now everything is stored in a single blob, we are going to get
	// notification on all changes. We can filter them out by checking for
	// the revision in the block list.
	lastBlockListRevision := -1

	go func() {
		log.Tracef(trace.Inside, "WatchBlocks: Entering WatchBlocks goroutine.")
		for {
			select {
			case <-stopCh:
				log.Tracef(trace.Inside, "WatchBlocks: Stop message received")
				return
			case kv := <-ch:
				ipamJson := string(kv.Value)
				log.Tracef(trace.Inside, "WatchBlocks: got JSON [%s]", ipamJson)

				ipam, err := parseIPAM(ipamJson)
				if err != nil {
					if ipamJson == "" {
						log.Warnf("WatchBlocks: Received empty IPAM JSON from KV store")
					} else {
						log.Errorf("WatchBlocks: Error parsing IPAM JSON ```%s ```: %s", ipamJson, err)
					}
					break
				}
				blocks := ipam.ListAllBlocks()
				if blocks.Revision <= lastBlockListRevision {
					log.Debugf("WatchBlocks: Received revision %d smaller than last reported %d, ignoring.", blocks.Revision, lastBlockListRevision)
				} else {
					lastBlockListRevision = blocks.Revision
					log.Tracef(trace.Inside, "WatchBlocks: sending block list revision %d to out channel", blocks.Revision)
					outCh <- *blocks
				}
			}
		}
	}()
	return outCh, nil
}

// WatchHosts is similar to Watch of libkv store, but specific
// to watching for host list.
func (c *Client) WatchHosts(stopCh <-chan struct{}) (<-chan api.HostList, error) {
	log.Tracef(trace.Public, "Entering WatchHosts.")
	ch, err := c.Store.ReconnectingWatch(ipamDataKey, stopCh)
	if err != nil {
		return nil, err
	}
	outCh := make(chan api.HostList)
	// Since for now everything is stored in a single blob, we are going to get
	// notification on all changes. We can filter them out by checking for
	// IPAM's TopologyRevision.
	lastHostListRevision := -1

	go func() {
		log.Tracef(trace.Inside, "WatchHosts: Entering WatchHosts goroutine.")
		for {
			select {
			case <-stopCh:
				log.Tracef(trace.Inside, "WatchHosts: Stop message received")
				return
			case kv := <-ch:
				ipamJson := string(kv.Value)
				ipam, err := parseIPAM(ipamJson)
				log.Tracef(trace.Inside, "WatchHosts: got %s", ipamJson)
				if err != nil {
					log.Errorf("WatchHosts: Error parsing IPAM: %s", err)
					continue
				}
				hostList := ipam.ListHosts()
				if hostList.Revision <= lastHostListRevision {
					log.Debugf("WatchHosts: Received revision %d smaller than last reported %d, ignoring.", hostList.Revision, lastHostListRevision)
				} else {
					lastHostListRevision = hostList.Revision
					log.Tracef(trace.Inside, "WatchHosts: sending host list revision %d to out channel", hostList.Revision)
					outCh <- hostList
				}
			}
		}
	}()
	return outCh, nil
}

func (c *Client) ListPolicies() ([]api.Policy, error) {
	kvps, err := c.Store.ListObjects(PoliciesPrefix)
	if err != nil {
		return nil, err
	}
	policies := make([]api.Policy, 0, len(kvps))
	errors := []error{}
	for i, v := range kvps {
		p := api.Policy{}
		err := json.Unmarshal(v.Value, &p)
		if err != nil {
			errors = append(errors, fmt.Errorf("error decoding policy %d: %v: %v", i+1, v.Value, err))
			continue
		}
		policies = append(policies, p)
	}
	if len(errors) > 0 {
		return policies, fmt.Errorf("%d decoding errors. %v", len(errors), errors)
	}
	return policies, nil
}

// ListTenants is a temporary method to satisfy current agent cache.
func (c *Client) ListTenants() []api.Tenant {
	t := make(map[string]api.Tenant)
	blocks := c.IPAM.ListAllBlocks()
	for _, block := range blocks.Blocks {
		if tenant, ok := t[block.Tenant]; ok {
			segmentFound := false
			for _, segment := range tenant.Segments {
				if segment.ID == block.Segment {
					segmentFound = true
					segment.Blocks = append(segment.Blocks, api.IPNet{IPNet: block.CIDR.IPNet})
					break
				}
			}
			if !segmentFound {
				segmentBlock := api.IPNet{IPNet: block.CIDR.IPNet}
				segmentBlocks := []api.IPNet{segmentBlock}
				segment := api.Segment{
					ID:     block.Segment,
					Blocks: segmentBlocks,
				}
				tenant.Segments = append(tenant.Segments, segment)
			}
		} else {
			// We don't know about this tenant yet...
			segmentBlock := api.IPNet{IPNet: block.CIDR.IPNet}
			segmentBlocks := []api.IPNet{segmentBlock}
			segment := api.Segment{
				ID:     block.Segment,
				Blocks: segmentBlocks,
			}
			t[block.Tenant] = api.Tenant{
				ID:       block.Tenant,
				Segments: []api.Segment{segment},
			}

		}
	}
	tenants := make([]api.Tenant, len(t))
	i := 0
	for _, tenant := range t {
		tenants[i] = tenant
		i++
	}
	return tenants
}

// AddPolicy adds a policy (or modifies it if policy with such ID already
// exists)
func (c *Client) AddPolicy(policy api.Policy) error {
	b, err := json.Marshal(policy)
	if err != nil {
		return err
	}
	return c.Store.PutObject(PoliciesPrefix+"/"+policy.ID, b)
}

// DeletePolicy attempts to delete policy. If the policy does
// not exist, false is returned, instead of an error.
func (c *Client) DeletePolicy(id string) (bool, error) {
	return c.Store.Delete(PoliciesPrefix + "/" + id)
}

// GetPolicy attempts to retrieve a policy.
func (c *Client) GetPolicy(id string) (api.Policy, error) {
	p := api.Policy{}
	v, err := c.Store.GetObject(id)
	if err != nil {
		return p, err
	}
	err = json.Unmarshal(v.Value, &p)
	return p, err
}

func (c *Client) initIPAM(initialTopologyFile *string) error {
	var err error
	c.ipamLocker, err = c.Store.NewLocker(ipamKey)
	if err != nil {
		return err
	}
	log.Tracef(trace.Inside, "initIPAM(): Created locker %v", c.ipamLocker)
	c.ipamLocker.Lock()
	ch, err := c.IPAM.locker.Lock()
	if err != nil {
		return err
	}
	defer c.IPAM.locker.Unlock()

	// Check if IPAM info exists in the store
	var ipamExists bool
	ipamExists, err = c.Store.Exists(ipamDataKey)
	if err != nil {
		return err
	}
	if ipamExists {
		if initialTopologyFile != nil && *initialTopologyFile != "" {
			log.Infof("Ignoring initial topology file %s as IPAM already exists", *initialTopologyFile)
		}
		// Load if exists
		log.Infof("Loading IPAM data from %s", c.Store.getKey(ipamDataKey))
		kv, err := c.Store.Get(ipamDataKey)
		if err != nil {
			return err
		}
		c.IPAM, err = parseIPAM(string(kv.Value))
		if err != nil {
			return err
		}
		c.IPAM.save = c.save
		c.IPAM.locker = c.ipamLocker
		c.IPAM.SetPrevKVPair(kv)
	} else {
		// If does not exist -- initialize with initial topology.

		log.Infof("No IPAM data found at %s, initializing", c.Store.getKey(ipamDataKey))
		c.IPAM, err = NewIPAM(c.save, c.ipamLocker)
		if err != nil {
			return err
		}
		if initialTopologyFile != nil && *initialTopologyFile != "" {
			topoData, err := ioutil.ReadFile(*initialTopologyFile)
			if err != nil {
				return err
			}
			topoReq := &api.TopologyUpdateRequest{}
			err = json.Unmarshal(topoData, topoReq)
			if err != nil {
				return fmt.Errorf("error processing %s: %s", *initialTopologyFile, err)
			}
			c.IPAM, err = NewIPAM(c.save, c.ipamLocker)
			if err != nil {
				return err
			}
			err = c.IPAM.UpdateTopology(*topoReq)
			if err != nil {
				return err
			}
		} else {
			c.IPAM, err = NewIPAM(c.save, c.ipamLocker)
			if err != nil {
				return err
			}
		}
		err = c.save(c.IPAM, ch)
		if err != nil {
			return err
		}
	}
	return nil
}

// save implements the Saver interface of IPAM.
func (c *Client) save(ipam *IPAM, ch <-chan struct{}) error {
	select {
	case <-ch:
		// Probably no need to reload the state at this point,
		// as it would be detected by the watch.
		return common.NewError("Lost lock while saving.")
	default:
		err := c.Store.AtomicPut(ipamDataKey, c.IPAM)
		if err != nil {
			return err
		}
		return nil
	}
}

// watchIPAM watches the backing store, and if a new IPAM is detected, it will
// reinitialize itself with the new value.
func (c *Client) watchIPAM() error {
	log.Tracef(trace.Public, "Entering watchIPAM.")
	stopCh := make(<-chan struct{})
	ch, err := c.Store.ReconnectingWatch(ipamDataKey, stopCh)
	if err != nil {
		return err
	}

	go func() {
		log.Tracef(trace.Inside, "watchIPAM: Entering watchIPAM goroutine.")
		for {
			select {
			case kv := <-ch:
				prevKV := c.IPAM.GetPrevKVPair()
				if prevKV == nil || kv.LastIndex > prevKV.LastIndex {
					log.Infof("Received IPAM with revision %d", kv.LastIndex)
					_, err := c.IPAM.locker.Lock()
					if err != nil {
						log.Error(err)
						// Nothing to do here, but since there is a new version,
						// IPAM will continue failing on save until we get another one and
						// try again
						c.IPAM.locker.Unlock()
						continue
					}
					c.IPAM, err = parseIPAM(string(kv.Value))
					if err != nil {
						log.Error(err)
						c.IPAM.locker.Unlock()
						continue
					}
					c.IPAM.save = c.save
					c.IPAM.locker = c.ipamLocker
					c.IPAM.SetPrevKVPair(kv)
					c.IPAM.locker.Unlock()
					log.Infof("Loaded IPAM with revision %d", kv.LastIndex)
				}
			}
		}
	}()
	return nil
}
<commit_msg>initialization fix<commit_after>package client

import (
	"fmt"
	"io/ioutil"

	"encoding/json"

	"github.com/romana/core/common"
	"github.com/romana/core/common/api"
	"github.com/romana/core/common/log/trace"
	log "github.com/romana/rlog"
)

const (
	DefaultEtcdPrefix    = "/romana"
	DefaultEtcdEndpoints = "localhost:2379"

	ipamKey        = "/ipam"
	ipamDataKey    = ipamKey + "/data"
	PoliciesPrefix = "/policies"
)

type Client struct {
	config     *common.Config
	Store      *Store
	ipamLocker Locker
	IPAM       *IPAM
}

// NewClient creates a new Client object based on provided config
func NewClient(config *common.Config) (*Client, error) {
	if config.EtcdPrefix == "" {
		config.EtcdPrefix = DefaultEtcdPrefix
	}
	store, err := NewStore(config.EtcdEndpoints, config.EtcdPrefix)
	if err != nil {
		return nil, err
	}

	c := &Client{
		config: config,
		Store:  store,
	}

	err = c.initIPAM(config.InitialTopologyFile)
	if err != nil {
		return nil, err
	}
	err = c.watchIPAM()
	if err != nil {
		return nil, err
	}
	return c, nil
}

func (c *Client) ListHosts() api.HostList {
	return c.IPAM.ListHosts()
}

type HostListCallback func(api.HostList)

func (c *Client) WatchHostsWithCallback(cb HostListCallback) error {
	// TODO this needs a way to remove the callback function
	// (to stop listening)
	log.Tracef(trace.Public, "Entering WatchHostsWithCallback.")
	stopCh := make(chan struct{})
	ch, err := c.WatchHosts(stopCh)
	if err != nil {
		return err
	}
	go func() {
		for {
			select {
			case result := <-ch:
				cb(result)
			}
		}
	}()
	return nil
}

type BlocksCallback func(api.IPAMBlocksResponse)

func (c *Client) WatchBlocksWithCallback(cb BlocksCallback) error {
	// TODO this needs a way to remove the callback function
	// (to stop listening)
	log.Tracef(trace.Public, "Entering WatchBlocksWithCallback.")
	stopCh := make(chan struct{})
	ch, err := c.WatchBlocks(stopCh)
	if err != nil {
		return err
	}
	go func() {
		for {
			select {
			case result := <-ch:
				cb(result)
			}
		}
	}()
	return nil
}

// WatchBlocks is similar to Watch of libkv store, but specific
// to watching for blocks.
func (c *Client) WatchBlocks(stopCh <-chan struct{}) (<-chan api.IPAMBlocksResponse, error) {
	log.Tracef(trace.Public, "Entering WatchBlocks.")
	ch, err := c.Store.ReconnectingWatch(ipamDataKey, stopCh)
	if err != nil {
		return nil, err
	}
	outCh := make(chan api.IPAMBlocksResponse)
	// Since for now everything is stored in a single blob, we are going to get
	// notification on all changes. We can filter them out by checking for
	// the revision in the block list.
	lastBlockListRevision := -1

	go func() {
		log.Tracef(trace.Inside, "WatchBlocks: Entering WatchBlocks goroutine.")
		for {
			select {
			case <-stopCh:
				log.Tracef(trace.Inside, "WatchBlocks: Stop message received")
				return
			case kv := <-ch:
				ipamJson := string(kv.Value)
				log.Tracef(trace.Inside, "WatchBlocks: got JSON [%s]", ipamJson)

				ipam, err := parseIPAM(ipamJson)
				if err != nil {
					if ipamJson == "" {
						log.Warnf("WatchBlocks: Received empty IPAM JSON from KV store")
					} else {
						log.Errorf("WatchBlocks: Error parsing IPAM JSON ```%s ```: %s", ipamJson, err)
					}
					break
				}
				blocks := ipam.ListAllBlocks()
				if blocks.Revision <= lastBlockListRevision {
					log.Debugf("WatchBlocks: Received revision %d smaller than last reported %d, ignoring.", blocks.Revision, lastBlockListRevision)
				} else {
					lastBlockListRevision = blocks.Revision
					log.Tracef(trace.Inside, "WatchBlocks: sending block list revision %d to out channel", blocks.Revision)
					outCh <- *blocks
				}
			}
		}
	}()
	return outCh, nil
}

// WatchHosts is similar to Watch of libkv store, but specific
// to watching for host list.
func (c *Client) WatchHosts(stopCh <-chan struct{}) (<-chan api.HostList, error) {
	log.Tracef(trace.Public, "Entering WatchHosts.")
	ch, err := c.Store.ReconnectingWatch(ipamDataKey, stopCh)
	if err != nil {
		return nil, err
	}
	outCh := make(chan api.HostList)
	// Since for now everything is stored in a single blob, we are going to get
	// notification on all changes. We can filter them out by checking for
	// IPAM's TopologyRevision.
	lastHostListRevision := -1

	go func() {
		log.Tracef(trace.Inside, "WatchHosts: Entering WatchHosts goroutine.")
		for {
			select {
			case <-stopCh:
				log.Tracef(trace.Inside, "WatchHosts: Stop message received")
				return
			case kv := <-ch:
				ipamJson := string(kv.Value)
				ipam, err := parseIPAM(ipamJson)
				log.Tracef(trace.Inside, "WatchHosts: got %s", ipamJson)
				if err != nil {
					log.Errorf("WatchHosts: Error parsing IPAM: %s", err)
					continue
				}
				hostList := ipam.ListHosts()
				if hostList.Revision <= lastHostListRevision {
					log.Debugf("WatchHosts: Received revision %d smaller than last reported %d, ignoring.", hostList.Revision, lastHostListRevision)
				} else {
					lastHostListRevision = hostList.Revision
					log.Tracef(trace.Inside, "WatchHosts: sending host list revision %d to out channel", hostList.Revision)
					outCh <- hostList
				}
			}
		}
	}()
	return outCh, nil
}

func (c *Client) ListPolicies() ([]api.Policy, error) {
	kvps, err := c.Store.ListObjects(PoliciesPrefix)
	if err != nil {
		return nil, err
	}
	policies := make([]api.Policy, 0, len(kvps))
	errors := []error{}
	for i, v := range kvps {
		p := api.Policy{}
		err := json.Unmarshal(v.Value, &p)
		if err != nil {
			errors = append(errors, fmt.Errorf("error decoding policy %d: %v: %v", i+1, v.Value, err))
			continue
		}
		policies = append(policies, p)
	}
	if len(errors) > 0 {
		return policies, fmt.Errorf("%d decoding errors. %v", len(errors), errors)
	}
	return policies, nil
}

// ListTenants is a temporary method to satisfy current agent cache.
func (c *Client) ListTenants() []api.Tenant {
	t := make(map[string]api.Tenant)
	blocks := c.IPAM.ListAllBlocks()
	for _, block := range blocks.Blocks {
		if tenant, ok := t[block.Tenant]; ok {
			segmentFound := false
			for _, segment := range tenant.Segments {
				if segment.ID == block.Segment {
					segmentFound = true
					segment.Blocks = append(segment.Blocks, api.IPNet{IPNet: block.CIDR.IPNet})
					break
				}
			}
			if !segmentFound {
				segmentBlock := api.IPNet{IPNet: block.CIDR.IPNet}
				segmentBlocks := []api.IPNet{segmentBlock}
				segment := api.Segment{
					ID:     block.Segment,
					Blocks: segmentBlocks,
				}
				tenant.Segments = append(tenant.Segments, segment)
			}
		} else {
			// We don't know about this tenant yet...
			segmentBlock := api.IPNet{IPNet: block.CIDR.IPNet}
			segmentBlocks := []api.IPNet{segmentBlock}
			segment := api.Segment{
				ID:     block.Segment,
				Blocks: segmentBlocks,
			}
			t[block.Tenant] = api.Tenant{
				ID:       block.Tenant,
				Segments: []api.Segment{segment},
			}

		}
	}
	tenants := make([]api.Tenant, len(t))
	i := 0
	for _, tenant := range t {
		tenants[i] = tenant
		i++
	}
	return tenants
}

// AddPolicy adds a policy (or modifies it if policy with such ID already
// exists)
func (c *Client) AddPolicy(policy api.Policy) error {
	b, err := json.Marshal(policy)
	if err != nil {
		return err
	}
	return c.Store.PutObject(PoliciesPrefix+"/"+policy.ID, b)
}

// DeletePolicy attempts to delete policy. If the policy does
// not exist, false is returned, instead of an error.
func (c *Client) DeletePolicy(id string) (bool, error) {
	return c.Store.Delete(PoliciesPrefix + "/" + id)
}

// GetPolicy attempts to retrieve a policy.
func (c *Client) GetPolicy(id string) (api.Policy, error) {
	p := api.Policy{}
	v, err := c.Store.GetObject(id)
	if err != nil {
		return p, err
	}
	err = json.Unmarshal(v.Value, &p)
	return p, err
}

func (c *Client) initIPAM(initialTopologyFile *string) error {
	var err error
	c.ipamLocker, err = c.Store.NewLocker(ipamKey)
	if err != nil {
		return err
	}
	log.Tracef(trace.Inside, "initIPAM(): Created locker %v", c.ipamLocker)

	ch, err := c.ipamLocker.Lock()

	if err != nil {
		return err
	}
	defer c.ipamLocker.Unlock()

	// Check if IPAM info exists in the store
	var ipamExists bool
	ipamExists, err = c.Store.Exists(ipamDataKey)
	if err != nil {
		return err
	}
	if ipamExists {
		if initialTopologyFile != nil && *initialTopologyFile != "" {
			log.Infof("Ignoring initial topology file %s as IPAM already exists", *initialTopologyFile)
		}
		// Load if exists
		log.Infof("Loading IPAM data from %s", c.Store.getKey(ipamDataKey))
		kv, err := c.Store.Get(ipamDataKey)
		if err != nil {
			return err
		}
		c.IPAM, err = parseIPAM(string(kv.Value))
		if err != nil {
			return err
		}
		c.IPAM.save = c.save
		c.IPAM.locker = c.ipamLocker
		c.IPAM.SetPrevKVPair(kv)
	} else {
		// If does not exist -- initialize with initial topology.

		log.Infof("No IPAM data found at %s, initializing", c.Store.getKey(ipamDataKey))
		c.IPAM, err = NewIPAM(c.save, c.ipamLocker)
		if err != nil {
			return err
		}
		if initialTopologyFile != nil && *initialTopologyFile != "" {
			topoData, err := ioutil.ReadFile(*initialTopologyFile)
			if err != nil {
				return err
			}
			topoReq := &api.TopologyUpdateRequest{}
			err = json.Unmarshal(topoData, topoReq)
			if err != nil {
				return fmt.Errorf("error processing %s: %s", *initialTopologyFile, err)
			}
			c.IPAM, err = NewIPAM(c.save, c.ipamLocker)
			if err != nil {
				return err
			}
			err = c.IPAM.UpdateTopology(*topoReq)
			if err != nil {
				return err
			}
		} else {
			c.IPAM, err = NewIPAM(c.save, c.ipamLocker)
			if err != nil {
				return err
			}
		}
		err = c.save(c.IPAM, ch)
		if err != nil {
			return err
		}
	}
	return nil
}

// save implements the Saver interface of IPAM.
func (c *Client) save(ipam *IPAM, ch <-chan struct{}) error {
	select {
	case <-ch:
		// Probably no need to reload the state at this point,
		// as it would be detected by the watch.
		return common.NewError("Lost lock while saving.")
	default:
		err := c.Store.AtomicPut(ipamDataKey, c.IPAM)
		if err != nil {
			return err
		}
		return nil
	}
}

// watchIPAM watches the backing store, and if a new IPAM is detected, it will
// reinitialize itself with the new value.
func (c *Client) watchIPAM() error {
	log.Tracef(trace.Public, "Entering watchIPAM.")
	stopCh := make(<-chan struct{})
	ch, err := c.Store.ReconnectingWatch(ipamDataKey, stopCh)
	if err != nil {
		return err
	}

	go func() {
		log.Tracef(trace.Inside, "watchIPAM: Entering watchIPAM goroutine.")
		for {
			select {
			case kv := <-ch:
				prevKV := c.IPAM.GetPrevKVPair()
				if prevKV == nil || kv.LastIndex > prevKV.LastIndex {
					log.Infof("Received IPAM with revision %d", kv.LastIndex)
					_, err := c.IPAM.locker.Lock()
					if err != nil {
						log.Error(err)
						// Nothing to do here, but since there is a new version,
						// IPAM will continue failing on save until we get another one and
						// try again
						c.IPAM.locker.Unlock()
						continue
					}
					c.IPAM, err = parseIPAM(string(kv.Value))
					if err != nil {
						log.Error(err)
						c.IPAM.locker.Unlock()
						continue
					}
					c.IPAM.save = c.save
					c.IPAM.locker = c.ipamLocker
					c.IPAM.SetPrevKVPair(kv)
					c.IPAM.locker.Unlock()
					log.Infof("Loaded IPAM with revision %d", kv.LastIndex)
				}
			}
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>package service

import (
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"golang.org/x/net/html"

	"github.com/kataras/iris"

	"github.com/VirrageS/cache"
	"github.com/VirrageS/scrape"
)

const (
	productHuntUrl = "https://www.producthunt.com/"
)

type ProductHuntAPI struct {
	*iris.Context
}

func (p ProductHuntAPI) Get() {
	c := p.Context.Get("cache").(*cache.Cache)
	cached_items, ok := c.Get("producthunt")
	if ok {
		p.JSON(iris.StatusOK, cached_items)
		return
	}

	response, err := http.Get(productHuntUrl)

	if err != nil {
		p.JSON(iris.StatusInternalServerError, iris.Map{
			"Error": "Could not make response",
		})
		return
	}

	root, err := html.Parse(response.Body)
	if err != nil {
		p.JSON(iris.StatusInternalServerError, iris.Map{
			"Error": "Could not parse body",
		})
		return
	}

	headline := make([]HeadlineItem, 0)
	products := scrape.Find(scrape.Find(root, "ul")[0], "li")

	limit := len(products)
	if limit > maxItemsLimit {
		limit = maxItemsLimit
	}

	for _, product := range products[:limit] {
		// get url
		link := scrape.Find(product, "div a")[0]
		url := "https://producthunt.com" + scrape.Attr(link, "href")

		// get name
		info := scrape.Find(link, "div span")
		name := scrape.Text(info[0])

		// get description
		description := scrape.Text(info[1])

		// get stars
		meta := scrape.Find(product, "button div")[0]

		re := regexp.MustCompile("[0-9,]+")
		number := re.FindAllString(scrape.Text(meta), -1)[0]
		points, _ := strconv.Atoi(strings.Replace(number, ",", "", -1))

		headline = append(headline, HeadlineItem{Title: name, Description: description, Url: url, Points: points})
	}

	sort.Sort(ByPoints(headline))
	if len(headline) > 0 {
		c.Set("producthunt", &headline)
	}
	p.JSON(iris.StatusOK, &headline)
}
<commit_msg>Add product skipping when name is empty (ProductHuntAPI) Now product is skipped when it's name is empty. Due to that also changed product limit counting.<commit_after>package service

import (
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"golang.org/x/net/html"

	"github.com/kataras/iris"

	"github.com/VirrageS/cache"
	"github.com/VirrageS/scrape"
)

const (
	productHuntUrl = "https://www.producthunt.com/"
)

type ProductHuntAPI struct {
	*iris.Context
}

func (p ProductHuntAPI) Get() {
	c := p.Context.Get("cache").(*cache.Cache)
	cached_items, ok := c.Get("producthunt")
	if ok {
		p.JSON(iris.StatusOK, cached_items)
		return
	}

	response, err := http.Get(productHuntUrl)

	if err != nil {
		p.JSON(iris.StatusInternalServerError, iris.Map{
			"Error": "Could not make response",
		})
		return
	}

	root, err := html.Parse(response.Body)
	if err != nil {
		p.JSON(iris.StatusInternalServerError, iris.Map{
			"Error": "Could not parse body",
		})
		return
	}

	headline := make([]HeadlineItem, 0)
	products := scrape.Find(scrape.Find(root, "ul")[0], "li")

	for _, product := range products {
		// get url
		link := scrape.Find(product, "div a")[0]
		url := "https://producthunt.com" + scrape.Attr(link, "href")

		// get name
		info := scrape.Find(link, "div span")
		name := scrape.Text(info[0])

		// skip products with empty name
		if name == "" {
			continue
		}

		// get description
		description := scrape.Text(info[1])

		// get stars
		meta := scrape.Find(product, "button div")[0]

		re := regexp.MustCompile("[0-9,]+")
		number := re.FindAllString(scrape.Text(meta), -1)[0]
		points, _ := strconv.Atoi(strings.Replace(number, ",", "", -1))

		headline = append(headline, HeadlineItem{Title: name, Description: description, Url: url, Points: points})

		if len(headline) >= maxItemsLimit {
			break
		}
	}

	sort.Sort(ByPoints(headline))
	if len(headline) > 0 {
		c.Set("producthunt", &headline)
	}
	p.JSON(iris.StatusOK, &headline)
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Original source: github.com/micro/go-micro/v3/store/store.go

// Package store is an interface for distributed data storage.
// The design document is located at https://github.com/micro/development/blob/master/design/framework/store.md
package store

import (
	"encoding/json"
	"errors"
	"time"
)

var (
	// DefaultStore implementation
	DefaultStore Store
	// DefaultBlobStore implementation
	DefaultBlobStore BlobStore
	// ErrNotFound is returned when a key doesn't exist
	ErrNotFound = errors.New("not found")
)

// Store is a data storage interface
type Store interface {
	// Init initialises the store. It must perform any required setup on the backing storage implementation and check that it is ready for use, returning any errors.
	Init(...Option) error
	// Options allows you to view the current options.
	Options() Options
	// Read takes a single key name and optional ReadOptions. It returns matching []*Record or an error.
	Read(key string, opts ...ReadOption) ([]*Record, error)
	// Write() writes a record to the store, and returns an error if the record was not written.
	Write(r *Record, opts ...WriteOption) error
	// Delete removes the record with the corresponding key from the store.
	Delete(key string, opts ...DeleteOption) error
	// List returns any keys that match, or an empty list with no error if none matched.
	List(opts ...ListOption) ([]string, error)
	// Close the store
	Close() error
	// String returns the name of the implementation.
	String() string
}

// Record is an item stored or retrieved from a Store
type Record struct {
	// The key to store the record
	Key string `json:"key"`
	// The value within the record
	Value []byte `json:"value"`
	// Any associated metadata for indexing
	Metadata map[string]interface{} `json:"metadata"`
	// Time to expire a record: TODO: change to timestamp
	Expiry time.Duration `json:"expiry,omitempty"`
}

// NewRecord returns a record from key, val
func NewRecord(key string, val interface{}) *Record {
	b, _ := json.Marshal(val)
	return &Record{
		Key:   key,
		Value: b,
	}
}

// Encode will marshal any type into the byte Value field
func (r *Record) Encode(v interface{}) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}
	r.Value = b
	return nil
}

// Scan is a convenience helper for decoding records
func (r *Record) Scan(v interface{}) error {
	return json.Unmarshal(r.Value, v)
}

// Read records
func Read(key string, opts ...ReadOption) ([]*Record, error) {
	// execute the query
	return DefaultStore.Read(key, opts...)
}

// Write a record to the store
func Write(r *Record) error {
	return DefaultStore.Write(r)
}

// Delete removes the record with the corresponding key from the store.
func Delete(key string) error {
	return DefaultStore.Delete(key)
}

// List returns any keys that match, or an empty list with no error if none matched.
func List(opts ...ListOption) ([]string, error) {
	return DefaultStore.List(opts...)
}
<commit_msg>add helper methods to store<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Original source: github.com/micro/go-micro/v3/store/store.go

// Package store is an interface for distributed data storage.
// The design document is located at https://github.com/micro/development/blob/master/design/framework/store.md
package store

import (
	"encoding/json"
	"errors"
	"time"
)

var (
	// DefaultStore implementation
	DefaultStore Store
	// DefaultBlobStore implementation
	DefaultBlobStore BlobStore
	// ErrNotFound is returned when a key doesn't exist
	ErrNotFound = errors.New("not found")
)

// Store is a data storage interface
type Store interface {
	// Init initialises the store. It must perform any required setup on the backing storage implementation and check that it is ready for use, returning any errors.
	Init(...Option) error
	// Options allows you to view the current options.
	Options() Options
	// Read takes a single key name and optional ReadOptions. It returns matching []*Record or an error.
	Read(key string, opts ...ReadOption) ([]*Record, error)
	// Write() writes a record to the store, and returns an error if the record was not written.
	Write(r *Record, opts ...WriteOption) error
	// Delete removes the record with the corresponding key from the store.
	Delete(key string, opts ...DeleteOption) error
	// List returns any keys that match, or an empty list with no error if none matched.
	List(opts ...ListOption) ([]string, error)
	// Close the store
	Close() error
	// String returns the name of the implementation.
	String() string
}

// Record is an item stored or retrieved from a Store
type Record struct {
	// The key to store the record
	Key string `json:"key"`
	// The value within the record
	Value []byte `json:"value"`
	// Any associated metadata for indexing
	Metadata map[string]interface{} `json:"metadata"`
	// Time to expire a record: TODO: change to timestamp
	Expiry time.Duration `json:"expiry,omitempty"`
}

// NewRecord returns a record from key, val
func NewRecord(key string, val interface{}) *Record {
	b, _ := json.Marshal(val)
	return &Record{
		Key:   key,
		Value: b,
	}
}

// Encode will marshal any type into the byte Value field
func (r *Record) Encode(v interface{}) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}
	r.Value = b
	return nil
}

// Decode is a convenience helper for decoding records
func (r *Record) Decode(v interface{}) error {
	return json.Unmarshal(r.Value, v)
}

// Read records
func Read(key string, opts ...ReadOption) ([]*Record, error) {
	// execute the query
	return DefaultStore.Read(key, opts...)
}

// Write a record to the store
func Write(r *Record) error {
	return DefaultStore.Write(r)
}

// Delete removes the record with the corresponding key from the store.
func Delete(key string) error {
	return DefaultStore.Delete(key)
}

// List returns any keys that match, or an empty list with no error if none matched.
func List(opts ...ListOption) ([]string, error) {
	return DefaultStore.List(opts...)
}
<|endoftext|>


<commit_before>// Copyright ©2021 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package r3

import (
	"gonum.org/v1/gonum/mat"
	"gonum.org/v1/gonum/num/quat"
)

// Mat represents a 3×3 matrix. Useful for rotation matrices and such.
// The zero value is usable as the 3×3 zero matrix.
type Mat struct {
	data *array
}

var _ mat.Matrix = (*Mat)(nil)

// NewMat returns a new 3×3 matrix Mat type and populates its elements
// with values passed as argument in row-major form. If val argument
// is nil then NewMat returns a matrix filled with zeros.
func NewMat(val []float64) *Mat {
	if len(val) == 9 {
		return &Mat{arrayFrom(val)}
	}
	if val == nil {
		return &Mat{new(array)}
	}
	panic(mat.ErrShape)
}

// Dims returns the number of rows and columns of this matrix.
// This method will always return 3×3 for a Mat.
func (m *Mat) Dims() (r, c int) { return 3, 3 }

// T returns the transpose of Mat. Changes in the receiver will be reflected in the returned matrix.
func (m *Mat) T() mat.Matrix { return mat.Transpose{Matrix: m} }

// Scale multiplies the elements of a by f, placing the result in the receiver.
//
// See the mat.Scaler interface for more information.
func (m *Mat) Scale(f float64, a mat.Matrix) {
	r, c := a.Dims()
	if r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			m.Set(i, j, f*a.At(i, j))
		}
	}
}

// Performs matrix multiplication on v:
//  result = M * v
func (m *Mat) MulVec(v Vec) Vec {
	if m.data == nil {
		return Vec{}
	}
	return Vec{
		X: v.X*m.At(0, 0) + v.Y*m.At(0, 1) + v.Z*m.At(0, 2),
		Y: v.X*m.At(1, 0) + v.Y*m.At(1, 1) + v.Z*m.At(1, 2),
		Z: v.X*m.At(2, 0) + v.Y*m.At(2, 1) + v.Z*m.At(2, 2),
	}
}

// Performs transposed matrix multiplication on v:
//  result = Mᵀ * v
func (m *Mat) MulVecTrans(v Vec) Vec {
	if m.data == nil {
		return Vec{}
	}
	return Vec{
		X: v.X*m.At(0, 0) + v.Y*m.At(1, 0) + v.Z*m.At(2, 0),
		Y: v.X*m.At(0, 1) + v.Y*m.At(1, 1) + v.Z*m.At(2, 1),
		Z: v.X*m.At(0, 2) + v.Y*m.At(1, 2) + v.Z*m.At(2, 2),
	}
}

// CloneFrom makes a copy of a into the receiver m.
// Mat expects a 3×3 input matrix.
func (m *Mat) CloneFrom(a mat.Matrix) {
	r, c := a.Dims()
	if r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			m.Set(i, j, a.At(i, j))
		}
	}
}

// Sub subtracts the matrix b from a, placing the result in the receiver.
// Sub will panic if the two matrices do not have the same shape.
func (m *Mat) Sub(a, b mat.Matrix) {
	if r, c := a.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if r, c := b.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}

	m.Set(0, 0, a.At(0, 0)-b.At(0, 0))
	m.Set(0, 1, a.At(0, 1)-b.At(0, 1))
	m.Set(0, 2, a.At(0, 2)-b.At(0, 2))
	m.Set(1, 0, a.At(1, 0)-b.At(1, 0))
	m.Set(1, 1, a.At(1, 1)-b.At(1, 1))
	m.Set(1, 2, a.At(1, 2)-b.At(1, 2))
	m.Set(2, 0, a.At(2, 0)-b.At(2, 0))
	m.Set(2, 1, a.At(2, 1)-b.At(2, 1))
	m.Set(2, 2, a.At(2, 2)-b.At(2, 2))
}

// Add adds a and b element-wise, placing the result in the receiver. Add will panic if the two matrices do not have the same shape.
func (m *Mat) Add(a, b mat.Matrix) {
	if r, c := a.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if r, c := b.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}

	m.Set(0, 0, a.At(0, 0)+b.At(0, 0))
	m.Set(0, 1, a.At(0, 1)+b.At(0, 1))
	m.Set(0, 2, a.At(0, 2)+b.At(0, 2))
	m.Set(1, 0, a.At(1, 0)+b.At(1, 0))
	m.Set(1, 1, a.At(1, 1)+b.At(1, 1))
	m.Set(1, 2, a.At(1, 2)+b.At(1, 2))
	m.Set(2, 0, a.At(2, 0)+b.At(2, 0))
	m.Set(2, 1, a.At(2, 1)+b.At(2, 1))
	m.Set(2, 2, a.At(2, 2)+b.At(2, 2))
}

// VecRow returns the elements in the ith row of the receiver.
func (m *Mat) VecRow(i int) Vec {
	if i > 2 {
		panic(mat.ErrRowAccess)
	}
	if m.data == nil {
		return Vec{}
	}
	return Vec{X: m.At(i, 0), Y: m.At(i, 1), Z: m.At(i, 2)}
}

// VecCol returns the elements in the jth column of the receiver.
func (m *Mat) VecCol(j int) Vec {
	if j > 2 {
		panic(mat.ErrColAccess)
	}
	if m.data == nil {
		return Vec{}
	}
	return Vec{X: m.At(0, j), Y: m.At(1, j), Z: m.At(2, j)}
}

// Outer calculates the outer product of the vectors x and y,
// where x and y are treated as column vectors, and stores the result in the receiver.
//  m = alpha * x * yᵀ
func (m *Mat) Outer(alpha float64, x, y Vec) {
	ax := alpha * x.X
	ay := alpha * x.Y
	az := alpha * x.Z
	m.Set(0, 0, ax*y.X)
	m.Set(0, 1, ax*y.Y)
	m.Set(0, 2, ax*y.Z)

	m.Set(1, 0, ay*y.X)
	m.Set(1, 1, ay*y.Y)
	m.Set(1, 2, ay*y.Z)

	m.Set(2, 0, az*y.X)
	m.Set(2, 1, az*y.Y)
	m.Set(2, 2, az*y.Z)
}

// Sets the rotation component of this matrix to the rotation specified by q,
// as outlined at https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion.
//
// RotationFromQuat requires a normalized quaternion q to perform a non-scaling rotation.
// Example:
//  q = quat.Scale(1/quat.Abs(q), q)
func (m *Mat) RotationFromQuat(q quat.Number) {
	w, x, y, z := q.Real, q.Imag, q.Jmag, q.Kmag
	x2, y2, z2 := x*x, y*y, z*z
	xw, xy, xz := x*w, x*y, x*z
	yw, zw, yz := y*w, z*w, y*z
	m.Set(0, 0, 1-2*y2-2*z2)
	m.Set(0, 1, 2*xy-2*zw)
	m.Set(0, 2, 2*xz+2*yw)
	m.Set(1, 0, 2*xy+2*zw)
	m.Set(1, 1, 1-2*x2-2*z2)
	m.Set(1, 2, 2*yz-2*xw)
	m.Set(2, 0, 2*xz-2*yw)
	m.Set(2, 1, 2*yz+2*xw)
	m.Set(2, 2, 1-2*x2-2*y2)
}

// Det calculates the determinant of the receiver using the following formula
//      ⎡a b c⎤
//  m = ⎢d e f⎥
//      ⎣g h i⎦
//  det(m) = a(ei − fh) − b(di − fg) + c(dh − eg)
func (m *Mat) Det() float64 {
	a := m.At(0, 0)
	b := m.At(0, 1)
	c := m.At(0, 2)

	deta := m.At(1, 1)*m.At(2, 2) - m.At(1, 2)*m.At(2, 1)
	detb := m.At(1, 0)*m.At(2, 2) - m.At(1, 2)*m.At(2, 0)
	detc := m.At(1, 0)*m.At(2, 1) - m.At(1, 1)*m.At(2, 0)
	return a*deta - b*detb + c*detc
}
<commit_msg>spatial/r3: fix doc comments to start with function name<commit_after>// Copyright ©2021 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package r3

import (
	"gonum.org/v1/gonum/mat"
	"gonum.org/v1/gonum/num/quat"
)

// Mat represents a 3×3 matrix. Useful for rotation matrices and such.
// The zero value is usable as the 3×3 zero matrix.
type Mat struct {
	data *array
}

var _ mat.Matrix = (*Mat)(nil)

// NewMat returns a new 3×3 matrix Mat type and populates its elements
// with values passed as argument in row-major form. If val argument
// is nil then NewMat returns a matrix filled with zeros.
func NewMat(val []float64) *Mat {
	if len(val) == 9 {
		return &Mat{arrayFrom(val)}
	}
	if val == nil {
		return &Mat{new(array)}
	}
	panic(mat.ErrShape)
}

// Dims returns the number of rows and columns of this matrix.
// This method will always return 3×3 for a Mat.
func (m *Mat) Dims() (r, c int) { return 3, 3 }

// T returns the transpose of Mat. Changes in the receiver will be reflected in the returned matrix.
func (m *Mat) T() mat.Matrix { return mat.Transpose{Matrix: m} }

// Scale multiplies the elements of a by f, placing the result in the receiver.
//
// See the mat.Scaler interface for more information.
func (m *Mat) Scale(f float64, a mat.Matrix) {
	r, c := a.Dims()
	if r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			m.Set(i, j, f*a.At(i, j))
		}
	}
}

// MulVec returns the matrix-vector product M⋅v.
func (m *Mat) MulVec(v Vec) Vec {
	if m.data == nil {
		return Vec{}
	}
	return Vec{
		X: v.X*m.At(0, 0) + v.Y*m.At(0, 1) + v.Z*m.At(0, 2),
		Y: v.X*m.At(1, 0) + v.Y*m.At(1, 1) + v.Z*m.At(1, 2),
		Z: v.X*m.At(2, 0) + v.Y*m.At(2, 1) + v.Z*m.At(2, 2),
	}
}

// MulVecTrans returns the matrix-vector product Mᵀ⋅v.
func (m *Mat) MulVecTrans(v Vec) Vec {
	if m.data == nil {
		return Vec{}
	}
	return Vec{
		X: v.X*m.At(0, 0) + v.Y*m.At(1, 0) + v.Z*m.At(2, 0),
		Y: v.X*m.At(0, 1) + v.Y*m.At(1, 1) + v.Z*m.At(2, 1),
		Z: v.X*m.At(0, 2) + v.Y*m.At(1, 2) + v.Z*m.At(2, 2),
	}
}

// CloneFrom makes a copy of a into the receiver m.
// Mat expects a 3×3 input matrix.
func (m *Mat) CloneFrom(a mat.Matrix) {
	r, c := a.Dims()
	if r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			m.Set(i, j, a.At(i, j))
		}
	}
}

// Sub subtracts the matrix b from a, placing the result in the receiver.
// Sub will panic if the two matrices do not have the same shape.
func (m *Mat) Sub(a, b mat.Matrix) {
	if r, c := a.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if r, c := b.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}

	m.Set(0, 0, a.At(0, 0)-b.At(0, 0))
	m.Set(0, 1, a.At(0, 1)-b.At(0, 1))
	m.Set(0, 2, a.At(0, 2)-b.At(0, 2))
	m.Set(1, 0, a.At(1, 0)-b.At(1, 0))
	m.Set(1, 1, a.At(1, 1)-b.At(1, 1))
	m.Set(1, 2, a.At(1, 2)-b.At(1, 2))
	m.Set(2, 0, a.At(2, 0)-b.At(2, 0))
	m.Set(2, 1, a.At(2, 1)-b.At(2, 1))
	m.Set(2, 2, a.At(2, 2)-b.At(2, 2))
}

// Add adds a and b element-wise, placing the result in the receiver. Add will panic if the two matrices do not have the same shape.
func (m *Mat) Add(a, b mat.Matrix) {
	if r, c := a.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if r, c := b.Dims(); r != 3 || c != 3 {
		panic(mat.ErrShape)
	}
	if m.data == nil {
		m.data = new(array)
	}

	m.Set(0, 0, a.At(0, 0)+b.At(0, 0))
	m.Set(0, 1, a.At(0, 1)+b.At(0, 1))
	m.Set(0, 2, a.At(0, 2)+b.At(0, 2))
	m.Set(1, 0, a.At(1, 0)+b.At(1, 0))
	m.Set(1, 1, a.At(1, 1)+b.At(1, 1))
	m.Set(1, 2, a.At(1, 2)+b.At(1, 2))
	m.Set(2, 0, a.At(2, 0)+b.At(2, 0))
	m.Set(2, 1, a.At(2, 1)+b.At(2, 1))
	m.Set(2, 2, a.At(2, 2)+b.At(2, 2))
}

// VecRow returns the elements in the ith row of the receiver.
func (m *Mat) VecRow(i int) Vec {
	if i > 2 {
		panic(mat.ErrRowAccess)
	}
	if m.data == nil {
		return Vec{}
	}
	return Vec{X: m.At(i, 0), Y: m.At(i, 1), Z: m.At(i, 2)}
}

// VecCol returns the elements in the jth column of the receiver.
func (m *Mat) VecCol(j int) Vec {
	if j > 2 {
		panic(mat.ErrColAccess)
	}
	if m.data == nil {
		return Vec{}
	}
	return Vec{X: m.At(0, j), Y: m.At(1, j), Z: m.At(2, j)}
}

// Outer calculates the outer product of the vectors x and y,
// where x and y are treated as column vectors, and stores the result in the receiver.
//  m = alpha * x * yᵀ
func (m *Mat) Outer(alpha float64, x, y Vec) {
	ax := alpha * x.X
	ay := alpha * x.Y
	az := alpha * x.Z
	m.Set(0, 0, ax*y.X)
	m.Set(0, 1, ax*y.Y)
	m.Set(0, 2, ax*y.Z)

	m.Set(1, 0, ay*y.X)
	m.Set(1, 1, ay*y.Y)
	m.Set(1, 2, ay*y.Z)

	m.Set(2, 0, az*y.X)
	m.Set(2, 1, az*y.Y)
	m.Set(2, 2, az*y.Z)
}

// RotationFromQuat converts the quaternion q to the corresponding orthogonal
// matrix and stores the result in the receiver. q should be normalized but this
// assumption is not checked.
//
// See https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion for more
// details.
func (m *Mat) RotationFromQuat(q quat.Number) {
	w, x, y, z := q.Real, q.Imag, q.Jmag, q.Kmag
	x2, y2, z2 := x*x, y*y, z*z
	xw, xy, xz := x*w, x*y, x*z
	yw, zw, yz := y*w, z*w, y*z
	m.Set(0, 0, 1-2*y2-2*z2)
	m.Set(0, 1, 2*xy-2*zw)
	m.Set(0, 2, 2*xz+2*yw)
	m.Set(1, 0, 2*xy+2*zw)
	m.Set(1, 1, 1-2*x2-2*z2)
	m.Set(1, 2, 2*yz-2*xw)
	m.Set(2, 0, 2*xz-2*yw)
	m.Set(2, 1, 2*yz+2*xw)
	m.Set(2, 2, 1-2*x2-2*y2)
}

// Det calculates the determinant of the receiver using the following formula
//      ⎡a b c⎤
//  m = ⎢d e f⎥
//      ⎣g h i⎦
//  det(m) = a(ei − fh) − b(di − fg) + c(dh − eg)
func (m *Mat) Det() float64 {
	a := m.At(0, 0)
	b := m.At(0, 1)
	c := m.At(0, 2)

	deta := m.At(1, 1)*m.At(2, 2) - m.At(1, 2)*m.At(2, 1)
	detb := m.At(1, 0)*m.At(2, 2) - m.At(1, 2)*m.At(2, 0)
	detc := m.At(1, 0)*m.At(2, 1) - m.At(1, 1)*m.At(2, 0)
	return a*deta - b*detb + c*detc
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"
	"time"
)

type Logfile struct {
	baseDir string
	file *os.File
	name string
	nlines int
	maxlines int
}

func NewLogfile(baseDir string, maxlines int) (*Logfile) {
	return &Logfile{baseDir, nil, "", 0, maxlines}
}

func (lf *Logfile) Close() {
	if lf.file != nil {
		lf.writeln("EXIT")
		lf.file.Close()
	}
}

func (lf *Logfile) writeln(s string) error {
	_, err := fmt.Fprintf(lf.file, "%d %s\n", time.Now().Unix(), s)
	if err == nil {
		lf.nlines += 1
	}
	return err
}

func (lf *Logfile) rotate() error {
	fn := fmt.Sprintf("%s.log", time.Now().UTC().Format(time.RFC3339))
	pathn := path.Join(lf.baseDir, "log", fn)
	newf, err := os.OpenFile(pathn, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		return err
	}

	currentPath = path.Join(lf.baseDir, "log", "current")

	if lf.file == nil {
		// Set lf.file just so we can write out NEXTLOG.
		// If this fails, that's okay
		lf.file, _ = os.OpenFile(currentPath, os.O_WRONLY|os.O_APPEND, 0666)
	}

	if lf.file != nil {
		// Note location of new log
		logmsg := fmt.Sprintf(". NEXTLOG %s", fn)
		lf.writeln(logmsg)

		// All done with the current log
		lf.file.Close()
	}

	// Point to new log file
	lf.file = newf

	// Record symlink to new log
	os.Remove(currentPath)
	os.Symlink(fn, currentPath)

	logmsg := fmt.Sprintf(". PREVLOG %s", lf.name)
	lf.writeln(logmsg)

	lf.name = fn

	return nil
}

func (lf *Logfile) Log(s string) error {
	if lf.file == nil {
		lf.rotate()
	}

	err := lf.writeln(s)
	if err == nil {
		return err
	}

	if lf.nlines >= lf.maxlines {
		return lf.rotate()
	}

	return nil
}
<commit_msg>Oops, variable assignment<commit_after>package main

import (
	"fmt"
	"os"
	"path"
	"time"
)

type Logfile struct {
	baseDir string
	file *os.File
	name string
	nlines int
	maxlines int
}

func NewLogfile(baseDir string, maxlines int) (*Logfile) {
	return &Logfile{baseDir, nil, "", 0, maxlines}
}

func (lf *Logfile) Close() {
	if lf.file != nil {
		lf.writeln("EXIT")
		lf.file.Close()
	}
}

func (lf *Logfile) writeln(s string) error {
	_, err := fmt.Fprintf(lf.file, "%d %s\n", time.Now().Unix(), s)
	if err == nil {
		lf.nlines += 1
	}
	return err
}

func (lf *Logfile) rotate() error {
	fn := fmt.Sprintf("%s.log", time.Now().UTC().Format(time.RFC3339))
	pathn := path.Join(lf.baseDir, "log", fn)
	newf, err := os.OpenFile(pathn, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		return err
	}

	currentPath := path.Join(lf.baseDir, "log", "current")

	if lf.file == nil {
		// Set lf.file just so we can write out NEXTLOG.
		// If this fails, that's okay
		lf.file, _ = os.OpenFile(currentPath, os.O_WRONLY|os.O_APPEND, 0666)
	}

	if lf.file != nil {
		// Note location of new log
		logmsg := fmt.Sprintf(". NEXTLOG %s", fn)
		lf.writeln(logmsg)

		// All done with the current log
		lf.file.Close()
	}

	// Point to new log file
	lf.file = newf

	// Record symlink to new log
	os.Remove(currentPath)
	os.Symlink(fn, currentPath)

	logmsg := fmt.Sprintf(". PREVLOG %s", lf.name)
	lf.writeln(logmsg)

	lf.name = fn

	return nil
}

func (lf *Logfile) Log(s string) error {
	if lf.file == nil {
		lf.rotate()
	}

	err := lf.writeln(s)
	if err == nil {
		return err
	}

	if lf.nlines >= lf.maxlines {
		return lf.rotate()
	}

	return nil
}
<|endoftext|>


<commit_before>package templates

var LoggedInHome = `
<!doctype html>
  <html lang="en">
  <head>
    <title>Koding | A New Way For Developers To Work</title>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-title" content="Koding" />
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1" />
    <link rel="shortcut icon" href="/a/images/favicon.ico" />
    <link rel="fluid-icon" href="/a/images/logos/fluid512.png" title="Koding" />

    <link rel="stylesheet" href="/a/css/kd.css?%s" />
    <link rel="stylesheet" href="/a/css/koding.css?%s" />
  </head>

  <body class='logged-in'>
  <!--[if IE]><script>(function(){window.location.href='/unsupported.html'})();</script><![endif]-->

  <script>var KD={}</script>
  <script>var KD={"config":%s}</script>

  <script>KD.isLoggedInOnLoad=true;</script>

  <script>KD.userAccount=%s;</script>
  <script>KD.userMachines=%s;</script>
  <script>KD.userWorkspaces=%s;</script>
  <script>KD.currentGroup=%s;</script>

  <script src='/a/js/kd.libs.js?%s'></script>
  <script src='/a/js/kd.js?%s'></script>
  <script src='/a/js/koding.js?%s'></script>

  <script>
    KD.utils.defer(function () {
      KD.currentGroup = KD.remote.revive(KD.currentGroup);
      KD.userAccount = KD.remote.revive(KD.userAccount);
    });
  </script>

  <script type="text/javascript">
    window.analytics||(window.analytics=[]),window.analytics.methods=["identify","track","trackLink","trackForm","trackClick","trackSubmit","page","pageview","ab","alias","ready","group","on","once","off"],window.analytics.factory=function(t){return function(){var a=Array.prototype.slice.call(arguments);return a.unshift(t),window.analytics.push(a),window.analytics}};for(var i=0;window.analytics.methods.length>i;i++){var method=window.analytics.methods[i];window.analytics[method]=window.analytics.factory(method)}window.analytics.load=function(t){var a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src=("https:"===document.location.protocol?"https://":"http://")+"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(a,n)},window.analytics.SNIPPET_VERSION="2.0.8",
    window.analytics.load("4c570qjqo0");
    window.analytics.page();
  </script>

  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-6520910-8', 'auto');
  </script>

  <script type="text/javascript">
    var _user_id = '%s'; var _session_id = '%s'; var _sift = _sift || []; _sift.push(['_setAccount', 'f270274999']); _sift.push(['_setUserId', _user_id]); _sift.push(['_setSessionId', _session_id]); _sift.push(['_trackPageview']); (function() { function ls() { var e = document.createElement('script'); e.type = 'text/javascript'; e.async = true; e.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'cdn.siftscience.com/s.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e, s); } if (window.attachEvent) { window.attachEvent('onload', ls); } else { window.addEventListener('load', ls, false); } })();
	</script>
</body>
</html>
`
<commit_msg>payment: fix formatting<commit_after>package templates

var LoggedInHome = `
<!doctype html>
  <html lang="en">
  <head>
    <title>Koding | A New Way For Developers To Work</title>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-title" content="Koding" />
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1" />
    <link rel="shortcut icon" href="/a/images/favicon.ico" />
    <link rel="fluid-icon" href="/a/images/logos/fluid512.png" title="Koding" />

    <link rel="stylesheet" href="/a/css/kd.css?%s" />
    <link rel="stylesheet" href="/a/css/koding.css?%s" />
  </head>

  <body class='logged-in'>
  <!--[if IE]><script>(function(){window.location.href='/unsupported.html'})();</script><![endif]-->

  <script>var KD={}</script>
  <script>var KD={"config":%s}</script>

  <script>KD.isLoggedInOnLoad=true;</script>

  <script>KD.userAccount=%s;</script>
  <script>KD.userMachines=%s;</script>
  <script>KD.userWorkspaces=%s;</script>
  <script>KD.currentGroup=%s;</script>

  <script src='/a/js/kd.libs.js?%s'></script>
  <script src='/a/js/kd.js?%s'></script>
  <script src='/a/js/koding.js?%s'></script>

  <script>
    KD.utils.defer(function () {
      KD.currentGroup = KD.remote.revive(KD.currentGroup);
      KD.userAccount = KD.remote.revive(KD.userAccount);
    });
  </script>

  <script type="text/javascript">
    window.analytics||(window.analytics=[]),window.analytics.methods=["identify","track","trackLink","trackForm","trackClick","trackSubmit","page","pageview","ab","alias","ready","group","on","once","off"],window.analytics.factory=function(t){return function(){var a=Array.prototype.slice.call(arguments);return a.unshift(t),window.analytics.push(a),window.analytics}};for(var i=0;window.analytics.methods.length>i;i++){var method=window.analytics.methods[i];window.analytics[method]=window.analytics.factory(method)}window.analytics.load=function(t){var a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src=("https:"===document.location.protocol?"https://":"http://")+"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(a,n)},window.analytics.SNIPPET_VERSION="2.0.8",
    window.analytics.load("4c570qjqo0");
    window.analytics.page();
  </script>

  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-6520910-8', 'auto');
  </script>

  <script type="text/javascript">
    var _user_id = '%s'; var _session_id = '%s'; var _sift = _sift || []; _sift.push(['_setAccount', 'f270274999']); _sift.push(['_setUserId', _user_id]); _sift.push(['_setSessionId', _session_id]); _sift.push(['_trackPageview']); (function() { function ls() { var e = document.createElement('script'); e.type = 'text/javascript'; e.async = true; e.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'cdn.siftscience.com/s.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e, s); } if (window.attachEvent) { window.attachEvent('onload', ls); } else { window.addEventListener('load', ls, false); } })();
  </script>
</body>
</html>
`
<|endoftext|>


<commit_before>package api

import (
	"koding/db/mongodb/modelhelper"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/common/response"
	"socialapi/workers/payment"

	stripe "github.com/stripe/stripe-go"
)

// DeleteCustomer deletes customer for a group
func DeleteCustomer(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	if err := payment.DeleteCustomerForGroup(context.GroupName); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewDeleted()
}

// UpdateCustomer updates customer of a group
func UpdateCustomer(u *url.URL, h http.Header, params *stripe.CustomerParams, context *models.Context) (int, http.Header, interface{}, error) {
	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		payment.UpdateCustomerForGroup(
			context.Client.Account.Nick,
			context.GroupName,
			params,
		),
	)
}

// GetCustomer returns the customer info of a group
func GetCustomer(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		payment.GetCustomerForGroup(context.GroupName),
	)
}

// CreateCustomer creates the customer for a group
func CreateCustomer(u *url.URL, h http.Header, req *stripe.CustomerParams, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	return response.HandleResultAndError(
		payment.EnsureCustomerForGroup(
			context.Client.Account.Nick,
			context.GroupName,
			req,
		),
	)
}

// Info return usage info for a group
func Info(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	group, err := modelhelper.GetGroup(context.GroupName)
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		payment.EnsureInfoForGroup(group, context.Client.Account.Nick),
	)
}
<commit_msg>socialapi/payment: do not allow customer deletion via API<commit_after>package api

import (
	"koding/db/mongodb/modelhelper"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/common/response"
	"socialapi/workers/payment"

	stripe "github.com/stripe/stripe-go"
)

// DeleteCustomer deletes customer for a group. Here for symmetry.
func DeleteCustomer(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	// do not allow customer deletion, causes losing track of transactions.
	return http.StatusForbidden, nil, nil, nil

	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	if err := payment.DeleteCustomerForGroup(context.GroupName); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewDeleted()
}

// UpdateCustomer updates customer of a group
func UpdateCustomer(u *url.URL, h http.Header, params *stripe.CustomerParams, context *models.Context) (int, http.Header, interface{}, error) {
	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		payment.UpdateCustomerForGroup(
			context.Client.Account.Nick,
			context.GroupName,
			params,
		),
	)
}

// GetCustomer returns the customer info of a group
func GetCustomer(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		payment.GetCustomerForGroup(context.GroupName),
	)
}

// CreateCustomer creates the customer for a group
func CreateCustomer(u *url.URL, h http.Header, req *stripe.CustomerParams, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	return response.HandleResultAndError(
		payment.EnsureCustomerForGroup(
			context.Client.Account.Nick,
			context.GroupName,
			req,
		),
	)
}

// Info return usage info for a group
func Info(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if err := checkContext(context); err != nil {
		return response.NewBadRequest(err)
	}

	group, err := modelhelper.GetGroup(context.GroupName)
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		payment.EnsureInfoForGroup(group, context.Client.Account.Nick),
	)
}
<|endoftext|>


<commit_before>// Package stateful defines a nested stateful lexer.
//
// This lexer is based heavily on the approach used by Chroma (and Pygments).
//
// The lexer is a state machine defined by a map of rules keyed by state. Each rule
// is a named regex and optional operation to apply when the rule matches.
//
// Lexing starts in the "Root" group. Each rule is matched in order, with the first
// successful match producing a lexeme. If the matching rule has an associated Mutator
// it will be executed. The name of each rule is prefixed with the name of its group
// to yield the token identifier used during matching.
//
// A state change can be introduced with the Mutator `Push(state)`. `Pop()` will
// return to the previous state.
//
// To reuse rules from another state, use `Include(state)`.
//
// See the example and tests in this package for details.
package stateful

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"regexp"
	"sort"
	"unicode/utf8"

	"github.com/alecthomas/participle"
	"github.com/alecthomas/participle/lexer"
)

var eolBytes = []byte("\n")

// A Rule matching input and possibly changing state.
type Rule struct {
	Name    string
	Pattern string
	Mutator Mutator
}

// Rules grouped by name.
type Rules map[string][]Rule

// CompiledRule is a Rule with its pattern compiled.
type CompiledRule struct {
	Rule
	RE *regexp.Regexp
}

// CompiledRules grouped by name.
type CompiledRules map[string][]CompiledRule

// A Mutator mutates the state of the Lexer
type Mutator interface {
	MutateLexer(lexer *Lexer) error
}

// RulesMutator is an optional interface that Mutators can implement.
//
// It is applied during rule construction to mutate the rule map.
type RulesMutator interface {
	MutateRules(state string, rule int, rules CompiledRules) error
}

// MutatorFunc is a function that is also a Mutator.
type MutatorFunc func(*Lexer) error

func (m MutatorFunc) MutateLexer(lexer *Lexer) error { return m(lexer) } // nolint: golint

// Pop to the previous state.
func Pop() Mutator {
	return MutatorFunc(func(lexer *Lexer) error {
		lexer.stack = lexer.stack[:len(lexer.stack)-1]
		return nil
	})
}

// Push to the given state.
//
// The target state will then be the set of rules used for matching
// until another Push or Pop is encountered.
func Push(state string) Mutator {
	return MutatorFunc(func(lexer *Lexer) error {
		lexer.stack = append(lexer.stack, state)
		return nil
	})
}

type include struct{ state string }

func (i include) MutateLexer(lexer *Lexer) error { panic("should not be called") }

func (i include) MutateRules(state string, rule int, rules CompiledRules) error {
	includedRules, ok := rules[i.state]
	if !ok {
		return fmt.Errorf("invalid include state %q", i.state)
	}
	clone := make([]CompiledRule, len(includedRules))
	copy(clone, includedRules)
	rules[state] = append(rules[state][:rule], append(clone, rules[state][rule+1:]...)...)
	return nil
}

// Include rules from another state in this one.
func Include(state string) Rule {
	return Rule{Mutator: include{state}}
}

// Definition is the lexer.Definition.
type Definition struct {
	rules   CompiledRules
	symbols map[string]rune
}

// New constructs a new stateful lexer from rules.
func New(rules Rules) (*Definition, error) {
	compiled := CompiledRules{}
	for key, set := range rules {
		for i, rule := range set {
			pattern := "^(?:" + rule.Pattern + ")"
			re, err := regexp.Compile(pattern)
			if err != nil {
				return nil, fmt.Errorf("%s.%d: %w", key, i, err)
			}
			compiled[key] = append(compiled[key], CompiledRule{rule, re})
		}
	}
restart:
	for state, rules := range compiled {
		for i, rule := range rules {
			if mutator, ok := rule.Mutator.(RulesMutator); ok {
				if err := mutator.MutateRules(state, i, compiled); err != nil {
					return nil, fmt.Errorf("%s.%d: %w", state, i, err)
				}
				goto restart
			}
		}
	}
	keys := make([]string, 0, len(compiled))
	for key := range compiled {
		keys = append(keys, key)
	}
	symbols := map[string]rune{
		"EOF": lexer.EOF,
	}
	sort.Strings(keys)
	rn := lexer.EOF - 1
	for _, key := range keys {
		for i, rule := range compiled[key] {
			rule.Name = key + rule.Name
			compiled[key][i] = rule
			if _, ok := symbols[rule.Name]; ok {
				panic("duplicate key " + rule.Name)
			}
			symbols[rule.Name] = rn
			rn--
		}
	}
	return &Definition{rules: compiled, symbols: symbols}, nil
}

func (d *Definition) Lex(r io.Reader) (lexer.Lexer, error) { // nolint: golint
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	return &Lexer{
		def:   d,
		data:  data,
		stack: []string{"Root"},
		pos: lexer.Position{
			Filename: lexer.NameOfReader(r),
			Line:     1,
			Column:   1,
		},
	}, nil
}

func (d *Definition) Symbols() map[string]rune { // nolint: golint
	return d.symbols
}

// Lexer implementation.
type Lexer struct {
	stack []string
	def   *Definition
	data  []byte
	pos   lexer.Position
}

func (l *Lexer) Next() (lexer.Token, error) { // nolint: golint
	ruleKey := l.stack[len(l.stack)-1]
	rules := l.def.rules[ruleKey]
	for len(l.data) > 0 {
		var match []int
		var rule *CompiledRule
		for _, re := range rules {
			match = re.RE.FindIndex(l.data)
			if match != nil {
				rule = &re // nolint: scopelint
				if match[0] == 0 && match[1] == 0 {
					return lexer.Token{}, fmt.Errorf("rule %q matched, but did not consume any input", rule.Name)
				}
				break
			}
		}
		if match == nil || rule == nil {
			return lexer.Token{}, participle.Errorf(l.pos, "no match")
		}

		if rule.Mutator != nil {
			if err := rule.Mutator.MutateLexer(l); err != nil {
				return lexer.Token{}, participle.Errorf(l.pos, "rule %q mutator returned an error", rule.Name)
			}
		}

		span := l.data[match[0]:match[1]]
		l.data = l.data[match[1]:]

		// Update position.
		pos := l.pos
		l.pos.Offset += match[1]
		lines := bytes.Count(span, eolBytes)
		l.pos.Line += lines
		// Update column.
		if lines == 0 {
			l.pos.Column += utf8.RuneCount(span)
		} else {
			l.pos.Column = utf8.RuneCount(span[bytes.LastIndex(span, eolBytes):])
		}
		return lexer.Token{
			Type:  l.def.symbols[rule.Name],
			Value: string(span),
			Pos:   pos,
		}, nil
	}
	return lexer.EOFToken(l.pos), nil
}
<commit_msg>Don't use %w yet.<commit_after>// Package stateful defines a nested stateful lexer.
//
// This lexer is based heavily on the approach used by Chroma (and Pygments).
//
// The lexer is a state machine defined by a map of rules keyed by state. Each rule
// is a named regex and optional operation to apply when the rule matches.
//
// Lexing starts in the "Root" group. Each rule is matched in order, with the first
// successful match producing a lexeme. If the matching rule has an associated Mutator
// it will be executed. The name of each rule is prefixed with the name of its group
// to yield the token identifier used during matching.
//
// A state change can be introduced with the Mutator `Push(state)`. `Pop()` will
// return to the previous state.
//
// To reuse rules from another state, use `Include(state)`.
//
// See the example and tests in this package for details.
package stateful

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"regexp"
	"sort"
	"unicode/utf8"

	"github.com/alecthomas/participle"
	"github.com/alecthomas/participle/lexer"
)

var eolBytes = []byte("\n")

// A Rule matching input and possibly changing state.
type Rule struct {
	Name    string
	Pattern string
	Mutator Mutator
}

// Rules grouped by name.
type Rules map[string][]Rule

// CompiledRule is a Rule with its pattern compiled.
type CompiledRule struct {
	Rule
	RE *regexp.Regexp
}

// CompiledRules grouped by name.
type CompiledRules map[string][]CompiledRule

// A Mutator mutates the state of the Lexer
type Mutator interface {
	MutateLexer(lexer *Lexer) error
}

// RulesMutator is an optional interface that Mutators can implement.
//
// It is applied during rule construction to mutate the rule map.
type RulesMutator interface {
	MutateRules(state string, rule int, rules CompiledRules) error
}

// MutatorFunc is a function that is also a Mutator.
type MutatorFunc func(*Lexer) error

func (m MutatorFunc) MutateLexer(lexer *Lexer) error { return m(lexer) } // nolint: golint

// Pop to the previous state.
func Pop() Mutator {
	return MutatorFunc(func(lexer *Lexer) error {
		lexer.stack = lexer.stack[:len(lexer.stack)-1]
		return nil
	})
}

// Push to the given state.
//
// The target state will then be the set of rules used for matching
// until another Push or Pop is encountered.
func Push(state string) Mutator {
	return MutatorFunc(func(lexer *Lexer) error {
		lexer.stack = append(lexer.stack, state)
		return nil
	})
}

type include struct{ state string }

func (i include) MutateLexer(lexer *Lexer) error { panic("should not be called") }

func (i include) MutateRules(state string, rule int, rules CompiledRules) error {
	includedRules, ok := rules[i.state]
	if !ok {
		return fmt.Errorf("invalid include state %q", i.state)
	}
	clone := make([]CompiledRule, len(includedRules))
	copy(clone, includedRules)
	rules[state] = append(rules[state][:rule], append(clone, rules[state][rule+1:]...)...)
	return nil
}

// Include rules from another state in this one.
func Include(state string) Rule {
	return Rule{Mutator: include{state}}
}

// Definition is the lexer.Definition.
type Definition struct {
	rules   CompiledRules
	symbols map[string]rune
}

// New constructs a new stateful lexer from rules.
func New(rules Rules) (*Definition, error) {
	compiled := CompiledRules{}
	for key, set := range rules {
		for i, rule := range set {
			pattern := "^(?:" + rule.Pattern + ")"
			re, err := regexp.Compile(pattern)
			if err != nil {
				return nil, fmt.Errorf("%s.%d: %s", key, i, err)
			}
			compiled[key] = append(compiled[key], CompiledRule{rule, re})
		}
	}
restart:
	for state, rules := range compiled {
		for i, rule := range rules {
			if mutator, ok := rule.Mutator.(RulesMutator); ok {
				if err := mutator.MutateRules(state, i, compiled); err != nil {
					return nil, fmt.Errorf("%s.%d: %s", state, i, err)
				}
				goto restart
			}
		}
	}
	keys := make([]string, 0, len(compiled))
	for key := range compiled {
		keys = append(keys, key)
	}
	symbols := map[string]rune{
		"EOF": lexer.EOF,
	}
	sort.Strings(keys)
	rn := lexer.EOF - 1
	for _, key := range keys {
		for i, rule := range compiled[key] {
			rule.Name = key + rule.Name
			compiled[key][i] = rule
			if _, ok := symbols[rule.Name]; ok {
				panic("duplicate key " + rule.Name)
			}
			symbols[rule.Name] = rn
			rn--
		}
	}
	return &Definition{rules: compiled, symbols: symbols}, nil
}

func (d *Definition) Lex(r io.Reader) (lexer.Lexer, error) { // nolint: golint
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	return &Lexer{
		def:   d,
		data:  data,
		stack: []string{"Root"},
		pos: lexer.Position{
			Filename: lexer.NameOfReader(r),
			Line:     1,
			Column:   1,
		},
	}, nil
}

func (d *Definition) Symbols() map[string]rune { // nolint: golint
	return d.symbols
}

// Lexer implementation.
type Lexer struct {
	stack []string
	def   *Definition
	data  []byte
	pos   lexer.Position
}

func (l *Lexer) Next() (lexer.Token, error) { // nolint: golint
	ruleKey := l.stack[len(l.stack)-1]
	rules := l.def.rules[ruleKey]
	for len(l.data) > 0 {
		var match []int
		var rule *CompiledRule
		for _, re := range rules {
			match = re.RE.FindIndex(l.data)
			if match != nil {
				rule = &re // nolint: scopelint
				if match[0] == 0 && match[1] == 0 {
					return lexer.Token{}, fmt.Errorf("rule %q matched, but did not consume any input", rule.Name)
				}
				break
			}
		}
		if match == nil || rule == nil {
			return lexer.Token{}, participle.Errorf(l.pos, "no match")
		}

		if rule.Mutator != nil {
			if err := rule.Mutator.MutateLexer(l); err != nil {
				return lexer.Token{}, participle.Errorf(l.pos, "rule %q mutator returned an error", rule.Name)
			}
		}

		span := l.data[match[0]:match[1]]
		l.data = l.data[match[1]:]

		// Update position.
		pos := l.pos
		l.pos.Offset += match[1]
		lines := bytes.Count(span, eolBytes)
		l.pos.Line += lines
		// Update column.
		if lines == 0 {
			l.pos.Column += utf8.RuneCount(span)
		} else {
			l.pos.Column = utf8.RuneCount(span[bytes.LastIndex(span, eolBytes):])
		}
		return lexer.Token{
			Type:  l.def.symbols[rule.Name],
			Value: string(span),
			Pos:   pos,
		}, nil
	}
	return lexer.EOFToken(l.pos), nil
}
<|endoftext|>