<commit_before>package mithril

var (
	// SelfClosingTagToken is a list of self closing elements tag
	SelfClosingTagToken = []string{"area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr", "!doctype"}
)

// VirtualElement is an object which can convert to real DOM element
type VirtualElement struct {
	Tag      string
	Attrs    []Attribute
	Children interface{}
}

// Attr returns or sets the attribute
func (el *VirtualElement) Attr(key string, val ...string) string {
	for _, attr := range el.Attrs {
		if attr.Key() == key {
			if len(val) > 0 {
				attr.Val(val[0])
			}
			return attr.Val()
		}
	}
	if len(val) > 0 {
		el.Attrs = append(el.Attrs, NewStringAttr(key, val[0]))
		return val[0]
	}
	return ""
}

// HasAttr returns true if VirtualElement has this attribute in attributes array
func (el *VirtualElement) HasAttr(key string) bool {
	for _, attr := range el.Attrs {
		if attr.Key() == key {
			return true
		}
	}
	return false
}

// String returns the html string of the element
func (el *VirtualElement) String() string {
	return ""
}
<commit_msg>VirtualElement to html string<commit_after>package mithril

import "fmt"

var (
	// SelfClosingTagToken is a list of self closing elements tag
	SelfClosingTagToken = []string{"area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr", "!doctype"}
)

// VirtualElement is an object which can convert to real DOM element
type VirtualElement struct {
	Tag      string
	Attrs    []Attribute
	Children interface{}
}

// Attr returns or sets the attribute
func (el *VirtualElement) Attr(key string, val ...string) string {
	for _, attr := range el.Attrs {
		if attr.Key() == key {
			if len(val) > 0 {
				attr.Val(val[0])
			}
			return attr.Val()
		}
	}
	if len(val) > 0 {
		el.Attrs = append(el.Attrs, NewStringAttr(key, val[0]))
		return val[0]
	}
	return ""
}

// HasAttr returns true if VirtualElement has this attribute in attributes array
func (el *VirtualElement) HasAttr(key string) bool {
	for _, attr := range el.Attrs {
		if attr.Key() == key {
			return true
		}
	}
	return false
}

// IsSelfClosingTag returns true if Tag is a self closing tag element
func (el *VirtualElement) IsSelfClosingTag() bool {
	for _, val := range SelfClosingTagToken {
		if val == el.Tag {
			return true
		}
	}
	return false
}

// String returns the html string of the element
func (el *VirtualElement) String() string {
	res := make(chan string)
	go func() {
		html := "<"
		if el.Tag != "" {
			html += el.Tag
		} else {
			html += "div"
		}
		for _, attr := range el.Attrs {
			html += (" " + attr.Key())
			if len(attr.Val()) > 0 {
				html += ("=\"" + attr.Val() + "\"")
			}
		}
		if el.IsSelfClosingTag() {
			html += " />"
		} else {
			html += ">"
			switch obj := el.Children.(type) {
			case *VirtualElement:
				html += obj.String()
			case string:
				html += obj
			case int, int32, int64:
				html += fmt.Sprintf("%d", obj)
			case float32, float64:
				html += fmt.Sprintf("%f", obj)
			}
			html += "</"
			if el.Tag != "" {
				html += el.Tag
			} else {
				html += "div"
			}
			html += ">"
		}
		res <- html
	}()
	return <-res
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nsf/termbox-go"
	"github.com/simulatedsimian/emu6502/core6502"
)

func main() {
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	termbox.HideCursor()

	var ctx core6502.BasicCPUContext
	core6502.HardResetCPU(&ctx, 0x400)
	var addr uint16

	//	termx, termy := termbox.Size()

	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				return
			case termbox.KeyPgdn:
				addr += 32
			case termbox.KeyPgup:
				addr -= 32
			}

			printRegisters(1, 1, &ctx)
			printMemory(25, 1, addr, &ctx)

			termbox.Flush()

		case termbox.EventResize:
			//			termx, termy = ev.Width, ev.Height
			termbox.Flush()
		}
	}

}
<commit_msg>adding monitor display<commit_after>package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"github.com/simulatedsimian/emu6502/core6502"
)

type TextInputField struct {
	x, y      int
	inp       []rune
	cursorLoc int
}

func (t *TextInputField) HandleInput(k termbox.Key, r rune) {
	if r >= ' ' {
		t.inp = append(t.inp, r)
	}

	if len(t.inp) > 0 && (k == termbox.KeyBackspace || k == termbox.KeyBackspace2) {
		t.inp = t.inp[:len(t.inp)-1]
	}

	printAtDef(t.x, t.y+1, fmt.Sprintf("%v, %v               ", k, r))

}

func (t *TextInputField) Draw() {
	printAtDef(t.x, t.y, string(t.inp)+" ")
}

func main() {
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	termbox.HideCursor()

	var ctx core6502.BasicCPUContext
	core6502.HardResetCPU(&ctx, 0x400)
	var addr uint16

	textInput := TextInputField{0, 10, nil, 0}

	//	termx, termy := termbox.Size()

	for {
		switch ev := termbox.PollEvent(); ev.Type {

		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				return
			case termbox.KeyPgdn:
				addr += 32
			case termbox.KeyPgup:
				addr -= 32
			}

			printRegisters(1, 1, &ctx)
			printMemory(25, 1, addr, &ctx)
			textInput.HandleInput(ev.Key, ev.Ch)
			textInput.Draw()

			termbox.Flush()

		case termbox.EventResize:
			//			termx, termy = ev.Width, ev.Height
			termbox.Flush()
		}
	}
}
<|endoftext|>


<commit_before>// Copyright ©2015 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 distmv

import (
	"math"
	"math/rand"

	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/mat"
	"gonum.org/v1/gonum/stat"
	"gonum.org/v1/gonum/stat/distuv"
)

var (
	badInputLength = "distmv: input slice length mismatch"
)

// Normal is a multivariate normal distribution (also known as the multivariate
// Gaussian distribution). Its pdf in k dimensions is given by
//  (2 π)^(-k/2) |Σ|^(-1/2) exp(-1/2 (x-μ)'Σ^-1(x-μ))
// where μ is the mean vector and Σ the covariance matrix. Σ must be symmetric
// and positive definite. Use NewNormal to construct.
type Normal struct {
	mu []float64

	sigma mat.SymDense

	chol       mat.Cholesky
	lower      mat.TriDense
	logSqrtDet float64
	dim        int

	src *rand.Rand
}

// NewNormal creates a new Normal with the given mean and covariance matrix.
// NewNormal panics if len(mu) == 0, or if len(mu) != sigma.N. If the covariance
// matrix is not positive-definite, the returned boolean is false.
func NewNormal(mu []float64, sigma mat.Symmetric, src *rand.Rand) (*Normal, bool) {
	if len(mu) == 0 {
		panic(badZeroDimension)
	}
	dim := sigma.Symmetric()
	if dim != len(mu) {
		panic(badSizeMismatch)
	}
	n := &Normal{
		src: src,
		dim: dim,
		mu:  make([]float64, dim),
	}
	copy(n.mu, mu)
	ok := n.chol.Factorize(sigma)
	if !ok {
		return nil, false
	}
	n.sigma = *mat.NewSymDense(dim, nil)
	n.sigma.CopySym(sigma)
	n.chol.LTo(&n.lower)
	n.logSqrtDet = 0.5 * n.chol.LogDet()
	return n, true
}

// NewNormalChol creates a new Normal distribution with the given mean and
// covariance matrix represented by its Cholesky decomposition. NewNormalChol
// panics if len(mu) is not equal to chol.Size().
func NewNormalChol(mu []float64, chol *mat.Cholesky, src *rand.Rand) *Normal {
	dim := len(mu)
	if dim != chol.Size() {
		panic(badSizeMismatch)
	}
	n := &Normal{
		src: src,
		dim: dim,
		mu:  make([]float64, dim),
	}
	n.chol.Clone(chol)
	copy(n.mu, mu)
	chol.LTo(&n.lower)
	n.logSqrtDet = 0.5 * n.chol.LogDet()
	return n
}

// NewNormalPrecision creates a new Normal distribution with the given mean and
// precision matrix (inverse of the covariance matrix). NewNormalPrecision
// panics if len(mu) is not equal to prec.Symmetric(). If the precision matrix
// is not positive-definite, NewNormalPrecision returns nil for norm and false
// for ok.
func NewNormalPrecision(mu []float64, prec *mat.SymDense, src *rand.Rand) (norm *Normal, ok bool) {
	if len(mu) == 0 {
		panic(badZeroDimension)
	}
	dim := prec.Symmetric()
	if dim != len(mu) {
		panic(badSizeMismatch)
	}
	// TODO(btracey): Computing a matrix inverse is generally numerically instable.
	// This only has to compute the inverse of a positive definite matrix, which
	// is much better, but this still loses precision. It is worth considering if
	// instead the precision matrix should be stored explicitly and used instead
	// of the Cholesky decomposition of the covariance matrix where appropriate.
	var chol mat.Cholesky
	ok = chol.Factorize(prec)
	if !ok {
		return nil, false
	}
	var sigma mat.SymDense
	chol.InverseTo(&sigma)
	return NewNormal(mu, &sigma, src)
}

// ConditionNormal returns the Normal distribution that is the receiver conditioned
// on the input evidence. The returned multivariate normal has dimension
// n - len(observed), where n is the dimension of the original receiver. The updated
// mean and covariance are
//  mu = mu_un + sigma_{ob,un}^T * sigma_{ob,ob}^-1 (v - mu_ob)
//  sigma = sigma_{un,un} - sigma_{ob,un}^T * sigma_{ob,ob}^-1 * sigma_{ob,un}
// where mu_un and mu_ob are the original means of the unobserved and observed
// variables respectively, sigma_{un,un} is the unobserved subset of the covariance
// matrix, sigma_{ob,ob} is the observed subset of the covariance matrix, and
// sigma_{un,ob} are the cross terms. The elements of x_2 have been observed with
// values v. The dimension order is preserved during conditioning, so if the value
// of dimension 1 is observed, the returned normal represents dimensions {0, 2, ...}
// of the original Normal distribution.
//
// ConditionNormal returns {nil, false} if there is a failure during the update.
// Mathematically this is impossible, but can occur with finite precision arithmetic.
func (n *Normal) ConditionNormal(observed []int, values []float64, src *rand.Rand) (*Normal, bool) {
	if len(observed) == 0 {
		panic("normal: no observed value")
	}
	if len(observed) != len(values) {
		panic(badInputLength)
	}
	for _, v := range observed {
		if v < 0 || v >= n.Dim() {
			panic("normal: observed value out of bounds")
		}
	}

	_, mu1, sigma11 := studentsTConditional(observed, values, math.Inf(1), n.mu, &n.sigma)
	if mu1 == nil {
		return nil, false
	}
	return NewNormal(mu1, sigma11, src)
}

// CovarianceMatrix returns the covariance matrix of the distribution. Upon
// return, the value at element {i, j} of the covariance matrix is equal to
// the covariance of the i^th and j^th variables.
//  covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
// If the input matrix is nil a new matrix is allocated, otherwise the result
// is stored in-place into the input.
func (n *Normal) CovarianceMatrix(s *mat.SymDense) *mat.SymDense {
	if s == nil {
		s = mat.NewSymDense(n.Dim(), nil)
	}
	sn := s.Symmetric()
	if sn != n.Dim() {
		panic("normal: input matrix size mismatch")
	}
	s.CopySym(&n.sigma)
	return s
}

// Dim returns the dimension of the distribution.
func (n *Normal) Dim() int {
	return n.dim
}

// Entropy returns the differential entropy of the distribution.
func (n *Normal) Entropy() float64 {
	return float64(n.dim)/2*(1+logTwoPi) + n.logSqrtDet
}

// LogProb computes the log of the pdf of the point x.
func (n *Normal) LogProb(x []float64) float64 {
	dim := n.dim
	if len(x) != dim {
		panic(badSizeMismatch)
	}
	c := -0.5*float64(dim)*logTwoPi - n.logSqrtDet
	dst := stat.Mahalanobis(mat.NewVecDense(dim, x), mat.NewVecDense(dim, n.mu), &n.chol)
	return c - 0.5*dst*dst
}

// MarginalNormal returns the marginal distribution of the given input variables.
// That is, MarginalNormal returns
//  p(x_i) = \int_{x_o} p(x_i | x_o) p(x_o) dx_o
// where x_i are the dimensions in the input, and x_o are the remaining dimensions.
// See https://en.wikipedia.org/wiki/Marginal_distribution for more information.
//
// The input src is passed to the call to NewNormal.
func (n *Normal) MarginalNormal(vars []int, src *rand.Rand) (*Normal, bool) {
	newMean := make([]float64, len(vars))
	for i, v := range vars {
		newMean[i] = n.mu[v]
	}
	var s mat.SymDense
	s.SubsetSym(&n.sigma, vars)
	return NewNormal(newMean, &s, src)
}

// MarginalNormalSingle returns the marginal of the given input variable.
// That is, MarginalNormal returns
//  p(x_i) = \int_{x_¬i} p(x_i | x_¬i) p(x_¬i) dx_¬i
// where i is the input index.
// See https://en.wikipedia.org/wiki/Marginal_distribution for more information.
//
// The input src is passed to the constructed distuv.Normal.
func (n *Normal) MarginalNormalSingle(i int, src *rand.Rand) distuv.Normal {
	return distuv.Normal{
		Mu:     n.mu[i],
		Sigma:  math.Sqrt(n.sigma.At(i, i)),
		Source: src,
	}
}

// Mean returns the mean of the probability distribution at x. If the
// input argument is nil, a new slice will be allocated, otherwise the result
// will be put in-place into the receiver.
func (n *Normal) Mean(x []float64) []float64 {
	x = reuseAs(x, n.dim)
	copy(x, n.mu)
	return x
}

// Prob computes the value of the probability density function at x.
func (n *Normal) Prob(x []float64) float64 {
	return math.Exp(n.LogProb(x))
}

// Quantile returns the multi-dimensional inverse cumulative distribution function.
// If x is nil, a new slice will be allocated and returned. If x is non-nil,
// len(x) must equal len(p) and the quantile will be stored in-place into x.
// All of the values of p must be between 0 and 1, inclusive, or Quantile will panic.
func (n *Normal) Quantile(x, p []float64) []float64 {
	dim := n.Dim()
	if len(p) != dim {
		panic(badInputLength)
	}
	if x == nil {
		x = make([]float64, dim)
	}
	if len(x) != len(p) {
		panic(badInputLength)
	}

	// Transform to a standard normal and then transform to a multivariate Gaussian.
	tmp := make([]float64, len(x))
	for i, v := range p {
		tmp[i] = distuv.UnitNormal.Quantile(v)
	}
	n.TransformNormal(x, tmp)
	return x
}

// Rand generates a random number according to the distributon.
// If the input slice is nil, new memory is allocated, otherwise the result is stored
// in place.
func (n *Normal) Rand(x []float64) []float64 {
	x = reuseAs(x, n.dim)
	tmp := make([]float64, n.dim)
	if n.src == nil {
		for i := range x {
			tmp[i] = rand.NormFloat64()
		}
	} else {
		for i := range x {
			tmp[i] = n.src.NormFloat64()
		}
	}
	n.transformNormal(x, tmp)
	return x
}

// ScoreInput returns the gradient of the log-probability with respect to the
// input x. That is, ScoreInput computes
//  ∇_x log(p(x))
// If score is nil, a new slice will be allocated and returned. If score is of
// length the dimension of Normal, then the result will be put in-place into score.
// If neither of these is true, ScoreInput will panic.
func (n *Normal) ScoreInput(score, x []float64) []float64 {
	// Normal log probability is
	//  c - 0.5*(x-μ)' Σ^-1 (x-μ).
	// So the derivative is just
	//  -Σ^-1 (x-μ).
	if len(x) != n.Dim() {
		panic(badInputLength)
	}
	if score == nil {
		score = make([]float64, len(x))
	}
	if len(score) != len(x) {
		panic(badSizeMismatch)
	}
	tmp := make([]float64, len(x))
	copy(tmp, x)
	floats.Sub(tmp, n.mu)

	n.chol.SolveVec(mat.NewVecDense(len(score), score), mat.NewVecDense(len(tmp), tmp))
	floats.Scale(-1, score)
	return score
}

// SetMean changes the mean of the normal distribution. SetMean panics if len(mu)
// does not equal the dimension of the normal distribution.
func (n *Normal) SetMean(mu []float64) {
	if len(mu) != n.Dim() {
		panic(badSizeMismatch)
	}
	copy(n.mu, mu)
}

// TransformNormal transforms the vector, normal, generated from a standard
// multidimensional normal into a vector that has been generated under the
// distribution of the receiver.
//
// If dst is non-nil, the result will be stored into dst, otherwise a new slice
// will be allocated. TransformNormal will panic if the length of normal is not
// the dimension of the receiver, or if dst is non-nil and len(dist) != len(normal).
func (n *Normal) TransformNormal(dst, normal []float64) []float64 {
	if len(normal) != n.dim {
		panic(badInputLength)
	}
	dst = reuseAs(dst, n.dim)
	if len(dst) != len(normal) {
		panic(badInputLength)
	}
	n.transformNormal(dst, normal)
	return dst
}

// transformNormal performs the same operation as TransformNormal except no
// safety checks are performed and both input slices must be non-nil.
func (n *Normal) transformNormal(dst, normal []float64) []float64 {
	srcVec := mat.NewVecDense(n.dim, normal)
	dstVec := mat.NewVecDense(n.dim, dst)
	dstVec.MulVec(&n.lower, srcVec)
	floats.Add(dst, n.mu)
	return dst
}
<commit_msg>stat/distmv: remove use of lower and add method for directly generati… (#274)<commit_after>// Copyright ©2015 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 distmv

import (
	"math"
	"math/rand"

	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/mat"
	"gonum.org/v1/gonum/stat"
	"gonum.org/v1/gonum/stat/distuv"
)

var (
	badInputLength = "distmv: input slice length mismatch"
)

// Normal is a multivariate normal distribution (also known as the multivariate
// Gaussian distribution). Its pdf in k dimensions is given by
//  (2 π)^(-k/2) |Σ|^(-1/2) exp(-1/2 (x-μ)'Σ^-1(x-μ))
// where μ is the mean vector and Σ the covariance matrix. Σ must be symmetric
// and positive definite. Use NewNormal to construct.
type Normal struct {
	mu []float64

	sigma mat.SymDense

	chol       mat.Cholesky
	logSqrtDet float64
	dim        int

	src *rand.Rand
}

// NewNormal creates a new Normal with the given mean and covariance matrix.
// NewNormal panics if len(mu) == 0, or if len(mu) != sigma.N. If the covariance
// matrix is not positive-definite, the returned boolean is false.
func NewNormal(mu []float64, sigma mat.Symmetric, src *rand.Rand) (*Normal, bool) {
	if len(mu) == 0 {
		panic(badZeroDimension)
	}
	dim := sigma.Symmetric()
	if dim != len(mu) {
		panic(badSizeMismatch)
	}
	n := &Normal{
		src: src,
		dim: dim,
		mu:  make([]float64, dim),
	}
	copy(n.mu, mu)
	ok := n.chol.Factorize(sigma)
	if !ok {
		return nil, false
	}
	n.sigma = *mat.NewSymDense(dim, nil)
	n.sigma.CopySym(sigma)
	n.logSqrtDet = 0.5 * n.chol.LogDet()
	return n, true
}

// NewNormalChol creates a new Normal distribution with the given mean and
// covariance matrix represented by its Cholesky decomposition. NewNormalChol
// panics if len(mu) is not equal to chol.Size().
func NewNormalChol(mu []float64, chol *mat.Cholesky, src *rand.Rand) *Normal {
	dim := len(mu)
	if dim != chol.Size() {
		panic(badSizeMismatch)
	}
	n := &Normal{
		src: src,
		dim: dim,
		mu:  make([]float64, dim),
	}
	n.chol.Clone(chol)
	copy(n.mu, mu)
	n.logSqrtDet = 0.5 * n.chol.LogDet()
	return n
}

// NewNormalPrecision creates a new Normal distribution with the given mean and
// precision matrix (inverse of the covariance matrix). NewNormalPrecision
// panics if len(mu) is not equal to prec.Symmetric(). If the precision matrix
// is not positive-definite, NewNormalPrecision returns nil for norm and false
// for ok.
func NewNormalPrecision(mu []float64, prec *mat.SymDense, src *rand.Rand) (norm *Normal, ok bool) {
	if len(mu) == 0 {
		panic(badZeroDimension)
	}
	dim := prec.Symmetric()
	if dim != len(mu) {
		panic(badSizeMismatch)
	}
	// TODO(btracey): Computing a matrix inverse is generally numerically instable.
	// This only has to compute the inverse of a positive definite matrix, which
	// is much better, but this still loses precision. It is worth considering if
	// instead the precision matrix should be stored explicitly and used instead
	// of the Cholesky decomposition of the covariance matrix where appropriate.
	var chol mat.Cholesky
	ok = chol.Factorize(prec)
	if !ok {
		return nil, false
	}
	var sigma mat.SymDense
	chol.InverseTo(&sigma)
	return NewNormal(mu, &sigma, src)
}

// ConditionNormal returns the Normal distribution that is the receiver conditioned
// on the input evidence. The returned multivariate normal has dimension
// n - len(observed), where n is the dimension of the original receiver. The updated
// mean and covariance are
//  mu = mu_un + sigma_{ob,un}^T * sigma_{ob,ob}^-1 (v - mu_ob)
//  sigma = sigma_{un,un} - sigma_{ob,un}^T * sigma_{ob,ob}^-1 * sigma_{ob,un}
// where mu_un and mu_ob are the original means of the unobserved and observed
// variables respectively, sigma_{un,un} is the unobserved subset of the covariance
// matrix, sigma_{ob,ob} is the observed subset of the covariance matrix, and
// sigma_{un,ob} are the cross terms. The elements of x_2 have been observed with
// values v. The dimension order is preserved during conditioning, so if the value
// of dimension 1 is observed, the returned normal represents dimensions {0, 2, ...}
// of the original Normal distribution.
//
// ConditionNormal returns {nil, false} if there is a failure during the update.
// Mathematically this is impossible, but can occur with finite precision arithmetic.
func (n *Normal) ConditionNormal(observed []int, values []float64, src *rand.Rand) (*Normal, bool) {
	if len(observed) == 0 {
		panic("normal: no observed value")
	}
	if len(observed) != len(values) {
		panic(badInputLength)
	}
	for _, v := range observed {
		if v < 0 || v >= n.Dim() {
			panic("normal: observed value out of bounds")
		}
	}

	_, mu1, sigma11 := studentsTConditional(observed, values, math.Inf(1), n.mu, &n.sigma)
	if mu1 == nil {
		return nil, false
	}
	return NewNormal(mu1, sigma11, src)
}

// CovarianceMatrix returns the covariance matrix of the distribution. Upon
// return, the value at element {i, j} of the covariance matrix is equal to
// the covariance of the i^th and j^th variables.
//  covariance(i, j) = E[(x_i - E[x_i])(x_j - E[x_j])]
// If the input matrix is nil a new matrix is allocated, otherwise the result
// is stored in-place into the input.
func (n *Normal) CovarianceMatrix(s *mat.SymDense) *mat.SymDense {
	if s == nil {
		s = mat.NewSymDense(n.Dim(), nil)
	}
	sn := s.Symmetric()
	if sn != n.Dim() {
		panic("normal: input matrix size mismatch")
	}
	s.CopySym(&n.sigma)
	return s
}

// Dim returns the dimension of the distribution.
func (n *Normal) Dim() int {
	return n.dim
}

// Entropy returns the differential entropy of the distribution.
func (n *Normal) Entropy() float64 {
	return float64(n.dim)/2*(1+logTwoPi) + n.logSqrtDet
}

// LogProb computes the log of the pdf of the point x.
func (n *Normal) LogProb(x []float64) float64 {
	dim := n.dim
	if len(x) != dim {
		panic(badSizeMismatch)
	}
	c := -0.5*float64(dim)*logTwoPi - n.logSqrtDet
	dst := stat.Mahalanobis(mat.NewVecDense(dim, x), mat.NewVecDense(dim, n.mu), &n.chol)
	return c - 0.5*dst*dst
}

// MarginalNormal returns the marginal distribution of the given input variables.
// That is, MarginalNormal returns
//  p(x_i) = \int_{x_o} p(x_i | x_o) p(x_o) dx_o
// where x_i are the dimensions in the input, and x_o are the remaining dimensions.
// See https://en.wikipedia.org/wiki/Marginal_distribution for more information.
//
// The input src is passed to the call to NewNormal.
func (n *Normal) MarginalNormal(vars []int, src *rand.Rand) (*Normal, bool) {
	newMean := make([]float64, len(vars))
	for i, v := range vars {
		newMean[i] = n.mu[v]
	}
	var s mat.SymDense
	s.SubsetSym(&n.sigma, vars)
	return NewNormal(newMean, &s, src)
}

// MarginalNormalSingle returns the marginal of the given input variable.
// That is, MarginalNormal returns
//  p(x_i) = \int_{x_¬i} p(x_i | x_¬i) p(x_¬i) dx_¬i
// where i is the input index.
// See https://en.wikipedia.org/wiki/Marginal_distribution for more information.
//
// The input src is passed to the constructed distuv.Normal.
func (n *Normal) MarginalNormalSingle(i int, src *rand.Rand) distuv.Normal {
	return distuv.Normal{
		Mu:     n.mu[i],
		Sigma:  math.Sqrt(n.sigma.At(i, i)),
		Source: src,
	}
}

// Mean returns the mean of the probability distribution at x. If the
// input argument is nil, a new slice will be allocated, otherwise the result
// will be put in-place into the receiver.
func (n *Normal) Mean(x []float64) []float64 {
	x = reuseAs(x, n.dim)
	copy(x, n.mu)
	return x
}

// Prob computes the value of the probability density function at x.
func (n *Normal) Prob(x []float64) float64 {
	return math.Exp(n.LogProb(x))
}

// Quantile returns the multi-dimensional inverse cumulative distribution function.
// If x is nil, a new slice will be allocated and returned. If x is non-nil,
// len(x) must equal len(p) and the quantile will be stored in-place into x.
// All of the values of p must be between 0 and 1, inclusive, or Quantile will panic.
func (n *Normal) Quantile(x, p []float64) []float64 {
	dim := n.Dim()
	if len(p) != dim {
		panic(badInputLength)
	}
	if x == nil {
		x = make([]float64, dim)
	}
	if len(x) != len(p) {
		panic(badInputLength)
	}

	// Transform to a standard normal and then transform to a multivariate Gaussian.
	tmp := make([]float64, len(x))
	for i, v := range p {
		tmp[i] = distuv.UnitNormal.Quantile(v)
	}
	n.TransformNormal(x, tmp)
	return x
}

// Rand generates a random number according to the distributon.
// If the input slice is nil, new memory is allocated, otherwise the result is stored
// in place.
func (n *Normal) Rand(x []float64) []float64 {
	return NormalRand(x, n.mu, &n.chol, n.src)
}

// NormalRand generates a random number with the given mean and Cholesky
// decomposition of the covariance matrix.
// If x is nil, new memory is allocated and returned, otherwise the result is stored
// in place into x. NormalRand panics if x is non-nil and not equal to len(mu),
// or if len(mu) != chol.Size().
//
// This function saves time and memory if the Cholesky decomposition is already
// available. Otherwise, the NewNormal function should be used.
func NormalRand(x, mean []float64, chol *mat.Cholesky, src *rand.Rand) []float64 {
	x = reuseAs(x, len(mean))
	if len(mean) != chol.Size() {
		panic(badInputLength)
	}
	if src == nil {
		for i := range x {
			x[i] = rand.NormFloat64()
		}
	} else {
		for i := range x {
			x[i] = src.NormFloat64()
		}
	}
	transformNormal(x, x, mean, chol)
	return x
}

// ScoreInput returns the gradient of the log-probability with respect to the
// input x. That is, ScoreInput computes
//  ∇_x log(p(x))
// If score is nil, a new slice will be allocated and returned. If score is of
// length the dimension of Normal, then the result will be put in-place into score.
// If neither of these is true, ScoreInput will panic.
func (n *Normal) ScoreInput(score, x []float64) []float64 {
	// Normal log probability is
	//  c - 0.5*(x-μ)' Σ^-1 (x-μ).
	// So the derivative is just
	//  -Σ^-1 (x-μ).
	if len(x) != n.Dim() {
		panic(badInputLength)
	}
	if score == nil {
		score = make([]float64, len(x))
	}
	if len(score) != len(x) {
		panic(badSizeMismatch)
	}
	tmp := make([]float64, len(x))
	copy(tmp, x)
	floats.Sub(tmp, n.mu)

	n.chol.SolveVec(mat.NewVecDense(len(score), score), mat.NewVecDense(len(tmp), tmp))
	floats.Scale(-1, score)
	return score
}

// SetMean changes the mean of the normal distribution. SetMean panics if len(mu)
// does not equal the dimension of the normal distribution.
func (n *Normal) SetMean(mu []float64) {
	if len(mu) != n.Dim() {
		panic(badSizeMismatch)
	}
	copy(n.mu, mu)
}

// TransformNormal transforms the vector, normal, generated from a standard
// multidimensional normal into a vector that has been generated under the
// distribution of the receiver.
//
// If dst is non-nil, the result will be stored into dst, otherwise a new slice
// will be allocated. TransformNormal will panic if the length of normal is not
// the dimension of the receiver, or if dst is non-nil and len(dist) != len(normal).
func (n *Normal) TransformNormal(dst, normal []float64) []float64 {
	if len(normal) != n.dim {
		panic(badInputLength)
	}
	dst = reuseAs(dst, n.dim)
	if len(dst) != len(normal) {
		panic(badInputLength)
	}
	transformNormal(dst, normal, n.mu, &n.chol)
	return dst
}

// transformNormal performs the same operation as Normal.TransformNormal except
// no safety checks are performed and all memory must be provided.
func transformNormal(dst, normal, mu []float64, chol *mat.Cholesky) []float64 {
	dim := len(mu)
	dstVec := mat.NewVecDense(dim, dst)
	srcVec := mat.NewVecDense(dim, normal)
	// If dst and normal are the same slice, make them the same Vector otherwise
	// mat complains about being tricky.
	if &normal[0] == &dst[0] {
		srcVec = dstVec
	}
	dstVec.MulVec(chol.RawU().T(), srcVec)
	floats.Add(dst, mu)
	return dst
}
<|endoftext|>


<commit_before>package gosnmp

import (
	"bytes"
	"container/list"
	"runtime"
)

type berEncoderFactory struct {
	bufPool *bufferPool
}

func newBerEncoderFactory(logger Logger) *berEncoderFactory {
	factory := new(berEncoderFactory)
	// Encoders are typically used and destroyed in short order, so we should only have a few active at any time. Each encoder may use quite a few small
	// temporary buffers during the encoding process though. Here we're setting things up for NumCpu * 2 encoders to be able to use 200 buffers each.
	factory.bufPool = newBufferPool(runtime.NumCPU()*2*200, 64, logger)
	return factory
}

type berEncoder struct {
	bufChain *list.List
	bufPool  *bufferPool
}

func (factory *berEncoderFactory) newBerEncoder() *berEncoder {
	encoder := new(berEncoder)
	encoder.bufChain = list.New()
	encoder.bufPool = factory.bufPool
	return encoder
}

func (encoder *berEncoder) serialize() []byte {
	totalLen := 0
	for e := encoder.bufChain.Front(); e != nil; e = e.Next() {
		buf := e.Value.(*bytes.Buffer)
		totalLen += buf.Len()
	}
	serializedMsg := bytes.NewBuffer(make([]byte, 0, totalLen))
	for e := encoder.bufChain.Front(); e != nil; e = e.Next() {
		buf := e.Value.(*bytes.Buffer)
		buf.WriteTo(serializedMsg)
	}
	return serializedMsg.Bytes()
}

func (encoder *berEncoder) destroy() {
	for e := encoder.bufChain.Front(); e != nil; e = e.Next() {
		buf := e.Value.(*bytes.Buffer)
		encoder.bufPool.putBuffer(buf)
	}
	encoder.bufChain.Init() // make sure to release references
}

func (e *berEncoder) append() *bytes.Buffer {
	buf := e.bufPool.getBuffer()
	e.bufChain.PushBack(buf)
	return buf
}

type BerHeader struct {
	bytes.Buffer
}

func (encoder *berEncoder) newHeader(blockType snmpBlockType) *BerHeader {
	h := BerHeader{*encoder.append()}
	h.WriteByte(byte(blockType))
	return &h
}

func (h *BerHeader) setContentLength(contentLength int) (headerLength int, blockLength int) {
	if contentLength < 127 {
		h.WriteByte(byte(contentLength))
	} else {
		n := calculateLengthLen(contentLength)
		h.WriteByte(0x80 | n)
		for ; n > 0; n-- {
			h.WriteByte(byte(contentLength >> uint((n-1)*8)))
		}
	}
	headerLength = h.Len()
	blockLength = headerLength + contentLength
	return
}

func calculateLengthLen(l int) byte {
	numBytes := 1
	for ; l > 255; l >>= 8 {
		numBytes++
	}
	return byte(numBytes)
}

func encode2sComplementInt(buf *bytes.Buffer, val int64) {
	numBytesToWrite := calculate2sComplementIntLen(val)
	for i := numBytesToWrite; i > 0; i-- {
		buf.WriteByte(byte(val >> uint((i-1)*8)))
	}
	return
}

func calculate2sComplementIntLen(val int64) int {
	numBytes := 1
	for ; val > 127; val >>= 8 {
		numBytes++
	}
	for ; val < -128; val >>= 8 {
		numBytes++
	}
	return numBytes
}

func encodeBase128Int(buf *bytes.Buffer, val int64) int {
	if val == 0 {
		buf.WriteByte(0)
		return 1
	}
	numBytesToWrite := calculateBase128IntLen(val)
	for i := numBytesToWrite - 1; i >= 0; i-- {
		byteToWrite := byte(val>>uint(i*7)) & 0x7f
		if i != 0 {
			byteToWrite |= 0x80
		}
		buf.WriteByte(byteToWrite)
	}
	return int(numBytesToWrite)
}

func calculateBase128IntLen(val int64) int {
	numBytes := 0
	for i := val; i > 0; i >>= 7 {
		numBytes++
	}
	return numBytes
}
<commit_msg>Fixing berEncoder so that it actually encodes header blocks<commit_after>package gosnmp

import (
	"bytes"
	"container/list"
	"runtime"
)

type berEncoderFactory struct {
	bufPool *bufferPool
	logger  Logger
}

func newBerEncoderFactory(logger Logger) *berEncoderFactory {
	factory := new(berEncoderFactory)
	// Encoders are typically used and destroyed in short order, so we should only have a few active at any time. Each encoder may use quite a few small
	// temporary buffers during the encoding process though. Here we're setting things up for NumCpu * 2 encoders to be able to use 200 buffers each.
	factory.bufPool = newBufferPool(runtime.NumCPU()*2*200, 64, logger)
	factory.logger = logger
	return factory
}

type berEncoder struct {
	bufChain *list.List
	bufPool  *bufferPool
	logger   Logger
}

func (factory *berEncoderFactory) newBerEncoder() *berEncoder {
	encoder := new(berEncoder)
	encoder.bufChain = list.New()
	encoder.bufPool = factory.bufPool
	encoder.logger = factory.logger
	return encoder
}

func (encoder *berEncoder) serialize() []byte {
	totalLen := 0
	for e := encoder.bufChain.Front(); e != nil; e = e.Next() {
		buf := e.Value.(*bytes.Buffer)
		totalLen += buf.Len()
	}
	serializedMsg := bytes.NewBuffer(make([]byte, 0, totalLen))
	for e := encoder.bufChain.Front(); e != nil; e = e.Next() {
		buf := e.Value.(*bytes.Buffer)
		buf.WriteTo(serializedMsg)
	}
	return serializedMsg.Bytes()
}

func (encoder *berEncoder) destroy() {
	for e := encoder.bufChain.Front(); e != nil; e = e.Next() {
		buf := e.Value.(*bytes.Buffer)
		encoder.bufPool.putBuffer(buf)
	}
	encoder.bufChain.Init() // make sure to release references
}

func (e *berEncoder) append() *bytes.Buffer {
	buf := e.bufPool.getBuffer()
	e.bufChain.PushBack(buf)
	return buf
}

type BerHeader struct {
	buf *bytes.Buffer
}

func (encoder *berEncoder) newHeader(blockType snmpBlockType) *BerHeader {
	h := BerHeader{buf: encoder.append()}
	h.buf.WriteByte(byte(blockType))
	return &h
}

func (h *BerHeader) setContentLength(contentLength int) (headerLength int, blockLength int) {
	if contentLength < 127 {
		h.buf.WriteByte(byte(contentLength))
	} else {
		n := calculateLengthLen(contentLength)
		h.buf.WriteByte(0x80 | n)
		for ; n > 0; n-- {
			h.buf.WriteByte(byte(contentLength >> uint((n-1)*8)))
		}
	}
	headerLength = h.buf.Len()
	blockLength = headerLength + contentLength
	return
}

func calculateLengthLen(l int) byte {
	numBytes := 1
	for ; l > 255; l >>= 8 {
		numBytes++
	}
	return byte(numBytes)
}

func encode2sComplementInt(buf *bytes.Buffer, val int64) {
	numBytesToWrite := calculate2sComplementIntLen(val)
	for i := numBytesToWrite; i > 0; i-- {
		buf.WriteByte(byte(val >> uint((i-1)*8)))
	}
	return
}

func calculate2sComplementIntLen(val int64) int {
	numBytes := 1
	for ; val > 127; val >>= 8 {
		numBytes++
	}
	for ; val < -128; val >>= 8 {
		numBytes++
	}
	return numBytes
}

func encodeBase128Int(buf *bytes.Buffer, val int64) int {
	if val == 0 {
		buf.WriteByte(0)
		return 1
	}
	numBytesToWrite := calculateBase128IntLen(val)
	for i := numBytesToWrite - 1; i >= 0; i-- {
		byteToWrite := byte(val>>uint(i*7)) & 0x7f
		if i != 0 {
			byteToWrite |= 0x80
		}
		buf.WriteByte(byteToWrite)
	}
	return int(numBytesToWrite)
}

func calculateBase128IntLen(val int64) int {
	numBytes := 0
	for i := val; i > 0; i >>= 7 {
		numBytes++
	}
	return numBytes
}
<|endoftext|>


<commit_before>// cryptopasta - basic cryptography examples
//
// Written in 2015 by George Tankersley <george.tankersley@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see // <http://creativecommons.org/publicdomain/zero/1.0/>.

// Provides symmetric authenticated encryption using 256-bit AES-GCM with a random nonce.
package cryptopasta

import (
	"crypto/aes"
	"crypto/cipher"
	"math/rand"
)

// NewEncryptionKey generates a random 256-bit key for Encrypt() and
// Decrypt(). It panics if the source of randomness fails.
func NewEncryptionKey() [32]byte {
	key := [32]byte{}
	_, err := rand.Read(key[:])
	if err != nil {
		panic(err)
	}
	return key
}

// Encrypt encrypts data using 256-bit AES-GCM.  This both hides the content of
// the data and provides a check that it hasn't been altered. Output takes the
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Encrypt(plaintext []byte, key [32]byte) (ciphertext []byte, err error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonce := make([]byte, gcm.NonceSize())
	_, err = rand.Read(nonce)
	if err != nil {
		return nil, err
	}

	return gcm.Seal(nonce, nonce, plaintext, nil), nil
}

// Decrypt decrypts data using 256-bit AES-GCM.  This both hides the content of
// the data and provides a check that it hasn't been altered. Expects input
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Decrypt(ciphertext []byte, key [32]byte) (plaintext []byte, err error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	return gcm.Open(nil,
		ciphertext[:gcm.NonceSize()],
		ciphertext[gcm.NonceSize():],
		nil,
	)
}
<commit_msg>Swap math/rand with crypto/rand<commit_after>// cryptopasta - basic cryptography examples
//
// Written in 2015 by George Tankersley <george.tankersley@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see // <http://creativecommons.org/publicdomain/zero/1.0/>.

// Provides symmetric authenticated encryption using 256-bit AES-GCM with a random nonce.
package cryptopasta

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
)

// NewEncryptionKey generates a random 256-bit key for Encrypt() and
// Decrypt(). It panics if the source of randomness fails.
func NewEncryptionKey() [32]byte {
	key := [32]byte{}
	_, err := rand.Read(key[:])
	if err != nil {
		panic(err)
	}
	return key
}

// Encrypt encrypts data using 256-bit AES-GCM.  This both hides the content of
// the data and provides a check that it hasn't been altered. Output takes the
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Encrypt(plaintext []byte, key [32]byte) (ciphertext []byte, err error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonce := make([]byte, gcm.NonceSize())
	_, err = rand.Read(nonce)
	if err != nil {
		return nil, err
	}

	return gcm.Seal(nonce, nonce, plaintext, nil), nil
}

// Decrypt decrypts data using 256-bit AES-GCM.  This both hides the content of
// the data and provides a check that it hasn't been altered. Expects input
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Decrypt(ciphertext []byte, key [32]byte) (plaintext []byte, err error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	return gcm.Open(nil,
		ciphertext[:gcm.NonceSize()],
		ciphertext[gcm.NonceSize():],
		nil,
	)
}
<|endoftext|>


<commit_before>package tasks

import (
	"math/rand"
	"sync"
	"time"
)

// Status is the status of the task.
type Status int

// TaskExecuter executes a series of task functions.
type TaskExecuter interface {
	QueueTask(task func() error) string
	GetTaskStatus(id string) Status
	completeTask(id string, task func() error)
}

type defaultExecuter struct {
	sync.RWMutex
	m map[string]Status
}

// These are some enumerated Status constants.
// INPROGRESS: Task is still in progress.
// SUCCESS: Task finished successfully.
// FAILURE: Task finished unsuccessfully.
// NOTFOUND: Task could not be found.
const (
	INPROGRESS Status = iota
	SUCCESS
	FAILURE
	NOTFOUND
)

// DefaultTaskExecuter is an instance of a NewTaskExecuter.
var DefaultTaskExecuter = NewTaskExecuter()

func (s Status) String() string {
	var str string

	switch s {
	case INPROGRESS:
		str = "The task is in progress."
	case SUCCESS:
		str = "The task was successfully completed."
	case FAILURE:
		str = "The task failed."
	case NOTFOUND:
		str = "Error: task not found."
	}
	return str
}

// NewTaskExecuter returns a TaskExecuter ready to execute.
func NewTaskExecuter() TaskExecuter {
	return &defaultExecuter{m: make(map[string]Status)}
}

// QueueTask initializes a new task, taking a generic task function. If the
// task panics, the panic will be caught. However, if the task launches another
// goroutine which panics, the panic cannot be caught.
func (ex *defaultExecuter) QueueTask(task func() error) string {
	id := generateID(20)
	ex.Lock()
	ex.m[id] = INPROGRESS
	ex.Unlock()
	go ex.completeTask(id, task)
	return id
}

// GetTaskStatus gets the current status of a task.
func (ex *defaultExecuter) GetTaskStatus(id string) Status {
	ex.RLock()
	defer ex.RUnlock()

	if status, ok := ex.m[id]; ok {
		return status
	}
	return NOTFOUND
}

func (ex *defaultExecuter) completeTask(id string, task func() error) {
	defer func() {
		if r := recover(); r != nil {
			ex.Lock()
			ex.m[id] = FAILURE
			ex.Unlock()
		}
	}()

	// Run the task.
	if err := task(); err != nil {
		ex.Lock()
		ex.m[id] = FAILURE
		ex.Unlock()
		return
	}

	ex.Lock()
	ex.m[id] = SUCCESS
	ex.Unlock()
}

// Borrowed from https://siongui.github.io/2015/04/13/go-generate-random-string/
func generateID(strlen int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	result := make([]byte, strlen)
	for i := 0; i < strlen; i++ {
		result[i] = chars[rand.Intn(len(chars))]
	}
	return string(result)
}
<commit_msg>Refactored tasks package to use a concurrent map struct<commit_after>package tasks

import (
	"math/rand"
	"sync"
	"time"
)

// Status is the status of the task.
type Status int

// TaskExecuter executes a series of task functions.
type TaskExecuter interface {
	QueueTask(task func() error) string
	GetTaskStatus(id string) Status
	completeTask(id string, task func() error)
}

type concurrentStatusMap struct {
	sync.RWMutex
	m map[string]Status
}

type defaultExecuter struct {
	cMap concurrentStatusMap
}

// These are some enumerated Status constants.
// INPROGRESS: Task is still in progress.
// SUCCESS: Task finished successfully.
// FAILURE: Task finished unsuccessfully.
// NOTFOUND: Task could not be found.
const (
	INPROGRESS Status = iota
	SUCCESS
	FAILURE
	NOTFOUND
)

// DefaultTaskExecuter is an instance of a NewTaskExecuter.
var DefaultTaskExecuter = NewTaskExecuter()

// Map k to v in the map
func (c *concurrentStatusMap) put(k string, v Status) {
	c.Lock()
	c.m[k] = v
	c.Unlock()
}

// Get the value of k in the map
func (c *concurrentStatusMap) get(k string) (Status, bool) {
	c.RLock()
	v, ok := c.m[k]
	c.RUnlock()
	return v, ok
}

func (s Status) String() string {
	var str string

	switch s {
	case INPROGRESS:
		str = "The task is in progress."
	case SUCCESS:
		str = "The task was successfully completed."
	case FAILURE:
		str = "The task failed."
	case NOTFOUND:
		str = "Error: task not found."
	}
	return str
}

// NewTaskExecuter returns a TaskExecuter ready to execute.
func NewTaskExecuter() TaskExecuter {
	return &defaultExecuter{
		cMap: concurrentStatusMap{m: make(map[string]Status)},
	}
}

// QueueTask initializes a new task, taking a generic task function. If the
// task panics, the panic will be caught. However, if the task launches another
// goroutine which panics, the panic cannot be caught.
func (ex *defaultExecuter) QueueTask(task func() error) string {
	id := generateID(20)
	ex.cMap.put(id, INPROGRESS)
	go ex.completeTask(id, task)
	return id
}

// GetTaskStatus gets the current status of a task.
func (ex *defaultExecuter) GetTaskStatus(id string) Status {
	if status, ok := ex.cMap.get(id); ok {
		return status
	}
	return NOTFOUND
}

func (ex *defaultExecuter) completeTask(id string, task func() error) {
	defer func() {
		if r := recover(); r != nil {
			ex.cMap.put(id, FAILURE)
		}
	}()

	// Run the task.
	if err := task(); err != nil {
		ex.cMap.put(id, FAILURE)
		return
	}

	ex.cMap.put(id, SUCCESS)
}

// Borrowed from https://siongui.github.io/2015/04/13/go-generate-random-string/
func generateID(strlen int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	result := make([]byte, strlen)
	for i := 0; i < strlen; i++ {
		result[i] = chars[rand.Intn(len(chars))]
	}
	return string(result)
}
<|endoftext|>


<commit_before>package eval

import (
	"fmt"
	"os"

	"github.com/xiaq/elvish/parse"
)

// Definition of Op and friends and combinators.

// Op operates on an Evaluator.
type Op func(*Evaluator)

// typeStar is either a single Type or a Kleene star of a Type.
type typeStar struct {
	t    Type
	star bool
}

// typeRun is a run of typeStar's.
type typeRun []typeStar

// count returns the least number of Type's in a typeRun, and whether the
// actual number could be larger.
func (tr typeRun) count() (ntypes int, more bool) {
	for _, ts := range tr {
		if ts.star {
			more = true
		} else {
			ntypes++
		}
	}
	return
}

// mayCountTo returns whether a run of n Type's may match the typeRun.
func (tr typeRun) mayCountTo(n int) bool {
	ntypes, more := tr.count()
	if more {
		return n >= ntypes
	} else {
		return n == ntypes
	}
}

// newFixedTypeRun returns a typeRun where all typeStar's are simple
// non-starred types.
func newFixedTypeRun(ts ...Type) typeRun {
	tr := make([]typeStar, len(ts))
	for i, t := range ts {
		tr[i].t = t
	}
	return tr
}

// newFixedTypeRun returns a typeRun representing n types of t, and followed by
// a star of t if v is true.
func newHomoTypeRun(t Type, n int, v bool) typeRun {
	tr := make([]typeStar, n)
	for i := 0; i < n; i++ {
		tr[i].t = t
	}
	if v {
		tr = append(tr, typeStar{t, true})
	}
	return tr
}

// valuesOp operates on an Evaluator and results in some values.
type valuesOp struct {
	tr typeRun
	f  func(*Evaluator) []Value
}

// portOp operates on an Evaluator and results in a port.
type portOp func(*Evaluator) *port

// stateUpdatesOp operates on an Evaluator and results in a receiving channel
// of StateUpdate's.
type stateUpdatesOp func(*Evaluator) <-chan *StateUpdate

func combineChunk(ops []valuesOp) Op {
	return func(ev *Evaluator) {
		for _, op := range ops {
			s := op.f(ev)
			if ev.statusCb != nil {
				ev.statusCb(s)
			}
		}
	}
}

func combineClosure(ops []valuesOp, enclosed map[string]Type, bounds [2]StreamType) valuesOp {
	op := combineChunk(ops)
	// BUG(xiaq): Closure arguments is (again) not supported
	f := func(ev *Evaluator) []Value {
		enclosed := make(map[string]*Value, len(enclosed))
		for name := range enclosed {
			enclosed[name] = ev.scope[name]
		}
		return []Value{NewClosure(nil, op, enclosed, bounds)}
	}
	return valuesOp{newFixedTypeRun(&ClosureType{bounds}), f}
}

func combinePipeline(ops []stateUpdatesOp, bounds [2]StreamType, internals []StreamType, p parse.Pos) valuesOp {
	f := func(ev *Evaluator) []Value {
		// TODO(xiaq): Should catch when compiling
		if !ev.ports[0].compatible(bounds[0]) {
			ev.errorf(p, "pipeline input not satisfiable")
		}
		if !ev.ports[1].compatible(bounds[1]) {
			ev.errorf(p, "pipeline output not satisfiable")
		}
		var nextIn *port
		updates := make([]<-chan *StateUpdate, len(ops))
		// For each form, create a dedicated Evaluator and run
		for i, op := range ops {
			newEv := ev.copy(fmt.Sprintf("<form op %v>", op), false)
			if i > 0 {
				newEv.ports[0] = nextIn
			}
			if i < len(ops)-1 {
				switch internals[i] {
				case unusedStream:
					newEv.ports[1] = nil
					nextIn = nil
				case fdStream:
					// os.Pipe sets O_CLOEXEC, which is what we want.
					reader, writer, e := os.Pipe()
					if e != nil {
						ev.errorf(p, "failed to create pipe: %s", e)
					}
					newEv.ports[1] = &port{f: writer, shouldClose: true}
					nextIn = &port{f: reader, shouldClose: true}
				case chanStream:
					// TODO Buffered channel?
					ch := make(chan Value)
					// Only the writer closes the channel port
					newEv.ports[1] = &port{ch: ch, shouldClose: true}
					nextIn = &port{ch: ch}
				default:
					panic("bad StreamType value")
				}
			}
			updates[i] = op(newEv)
		}
		// Collect exit values
		exits := make([]Value, len(ops))
		for i, update := range updates {
			for up := range update {
				exits[i] = NewString(up.Msg)
			}
		}
		return exits
	}
	return valuesOp{newHomoTypeRun(&StringType{}, len(ops), false), f}
}

func combineForm(cmd valuesOp, tlist valuesOp, ports []portOp, a *formAnnotation, p parse.Pos) stateUpdatesOp {
	return func(ev *Evaluator) <-chan *StateUpdate {
		// XXX Currently it's guaranteed that cmd evaluates into a single
		// Value.
		cmd := cmd.f(ev)[0]
		cmdStr := cmd.String()
		fm := &form{
			name: cmdStr,
		}
		if tlist.f != nil {
			fm.args = tlist.f(ev)
		}

		switch a.commandType {
		case commandBuiltinFunction:
			fm.Command.Func = a.builtinFunc.fn
		case commandBuiltinSpecial:
			fm.Command.Special = a.specialOp
		case commandDefinedFunction:
			v, ok1 := ev.scope["fn-"+cmdStr]
			fn, ok2 := (*v).(*Closure)
			if !(ok1 && ok2) {
				panic("Compiler bug")
			}
			fm.Command.Closure = fn
		case commandClosure:
			fm.Command.Closure = cmd.(*Closure)
		case commandExternal:
			path, e := ev.search(cmdStr)
			if e != nil {
				ev.errorf(p, "%s", e)
			}
			fm.Command.Path = path
		default:
			panic("bad commandType value")
		}

		newEv := ev.copy(fmt.Sprintf("<form redir %v>", fm), true)
		newEv.growPorts(len(ports))

		for i, op := range ports {
			if op != nil {
				newEv.ports[i] = op(ev)
			}
		}

		return newEv.execForm(fm)
	}
}

func combineSpaced(ops []valuesOp) valuesOp {
	tr := make(typeRun, 0, len(ops))
	for _, op := range ops {
		tr = append(tr, op.tr...)
	}

	f := func(ev *Evaluator) []Value {
		// Use number of compound expressions as an estimation of the number
		// of values
		vs := make([]Value, 0, len(ops))
		for _, op := range ops {
			us := op.f(ev)
			vs = append(vs, us...)
		}
		return vs
	}
	return valuesOp{tr, f}
}

func caret(ev *Evaluator, lhs, rhs Value) Value {
	return NewString(lhs.String() + rhs.String())
}

func combineCompound(ops []valuesOp) valuesOp {
	n := 1
	more := false
	for _, op := range ops {
		m, b := op.tr.count()
		n *= m
		more = more || b
	}

	f := func(ev *Evaluator) []Value {
		vs := ops[0].f(ev)
		for _, op := range ops[1:] {
			us := op.f(ev)
			if len(us) == 1 {
				u := us[0]
				for i := range vs {
					vs[i] = caret(ev, vs[i], u)
				}
			} else {
				// Do a cartesian product
				newvs := make([]Value, len(vs)*len(us))
				for i, v := range vs {
					for j, u := range us {
						newvs[i*len(us)+j] = caret(ev, v, u)
					}
				}
				vs = newvs
			}
		}
		return vs
	}
	return valuesOp{newHomoTypeRun(StringType{}, n, more), f}
}

func literalValue(v ...Value) valuesOp {
	tr := make(typeRun, len(v))
	for i := range tr {
		tr[i].t = v[i].Type()
	}
	f := func(e *Evaluator) []Value {
		return v
	}
	return valuesOp{tr, f}
}

func makeString(text string) valuesOp {
	return literalValue(NewString(text))
}

func makeVar(cp *Compiler, name string, p parse.Pos) valuesOp {
	tr := newFixedTypeRun(cp.resolveVar(name, p))
	f := func(ev *Evaluator) []Value {
		val, ok := ev.scope[name]
		if !ok {
			panic("Compiler bug")
		}
		return []Value{*val}
	}
	return valuesOp{tr, f}
}

func combineSubscript(cp *Compiler, left, right valuesOp, lp, rp parse.Pos) valuesOp {
	if !left.tr.mayCountTo(1) {
		// TODO Also check at runtime
		cp.errorf(lp, "left operand of subscript must be a single value")
	}
	var t Type
	switch left.tr[0].t.(type) {
	case EnvType:
		t = StringType{}
	case TableType, AnyType:
		t = AnyType{}
	default:
		cp.errorf(lp, "left operand of subscript must be of type string, env, table or any")
	}

	if !right.tr.mayCountTo(1) {
		// TODO Also check at runtime
		cp.errorf(rp, "right operand of subscript must be a single value")
	}
	if _, ok := right.tr[0].t.(StringType); !ok {
		cp.errorf(rp, "right operand of subscript must be of type string")
	}

	f := func(ev *Evaluator) []Value {
		l := left.f(ev)
		r := right.f(ev)
		return []Value{evalSubscript(ev, l[0], r[0], lp, rp)}
	}
	return valuesOp{newFixedTypeRun(t), f}
}

func combineTable(list valuesOp, keys []valuesOp, values []valuesOp, p parse.Pos) valuesOp {
	f := func(ev *Evaluator) []Value {
		t := NewTable()
		t.append(list.f(ev)...)
		for i, kop := range keys {
			vop := values[i]
			ks := kop.f(ev)
			vs := vop.f(ev)
			if len(ks) != len(vs) {
				ev.errorf(p, "Number of keys doesn't match number of values: %d vs. %d", len(ks), len(vs))
			}
			for j, k := range ks {
				t.Dict[k] = vs[j]
			}
		}
		return []Value{t}
	}
	return valuesOp{newFixedTypeRun(TableType{}), f}
}

func combineOutputCapture(op valuesOp, bounds [2]StreamType) valuesOp {
	// XXX Wrong type; tr should be variadic
	tr := newFixedTypeRun()
	f := func(ev *Evaluator) []Value {
		vs := []Value{}
		newEv := ev.copy(fmt.Sprintf("<output capture %v>", op), true)
		newEv.ports = make([]*port, len(ev.ports))
		copy(newEv.ports, ev.ports)
		ch := make(chan Value)
		newEv.ports[1] = &port{ch: ch}
		go func() {
			for v := range ch {
				vs = append(vs, v)
			}
		}()
		op.f(newEv)
		return vs
	}
	return valuesOp{tr, f}
}
<commit_msg>Fix Evaluator created for output capture.<commit_after>package eval

import (
	"fmt"
	"os"

	"github.com/xiaq/elvish/parse"
)

// Definition of Op and friends and combinators.

// Op operates on an Evaluator.
type Op func(*Evaluator)

// typeStar is either a single Type or a Kleene star of a Type.
type typeStar struct {
	t    Type
	star bool
}

// typeRun is a run of typeStar's.
type typeRun []typeStar

// count returns the least number of Type's in a typeRun, and whether the
// actual number could be larger.
func (tr typeRun) count() (ntypes int, more bool) {
	for _, ts := range tr {
		if ts.star {
			more = true
		} else {
			ntypes++
		}
	}
	return
}

// mayCountTo returns whether a run of n Type's may match the typeRun.
func (tr typeRun) mayCountTo(n int) bool {
	ntypes, more := tr.count()
	if more {
		return n >= ntypes
	} else {
		return n == ntypes
	}
}

// newFixedTypeRun returns a typeRun where all typeStar's are simple
// non-starred types.
func newFixedTypeRun(ts ...Type) typeRun {
	tr := make([]typeStar, len(ts))
	for i, t := range ts {
		tr[i].t = t
	}
	return tr
}

// newFixedTypeRun returns a typeRun representing n types of t, and followed by
// a star of t if v is true.
func newHomoTypeRun(t Type, n int, v bool) typeRun {
	tr := make([]typeStar, n)
	for i := 0; i < n; i++ {
		tr[i].t = t
	}
	if v {
		tr = append(tr, typeStar{t, true})
	}
	return tr
}

// valuesOp operates on an Evaluator and results in some values.
type valuesOp struct {
	tr typeRun
	f  func(*Evaluator) []Value
}

// portOp operates on an Evaluator and results in a port.
type portOp func(*Evaluator) *port

// stateUpdatesOp operates on an Evaluator and results in a receiving channel
// of StateUpdate's.
type stateUpdatesOp func(*Evaluator) <-chan *StateUpdate

func combineChunk(ops []valuesOp) Op {
	return func(ev *Evaluator) {
		for _, op := range ops {
			s := op.f(ev)
			if ev.statusCb != nil {
				ev.statusCb(s)
			}
		}
	}
}

func combineClosure(ops []valuesOp, enclosed map[string]Type, bounds [2]StreamType) valuesOp {
	op := combineChunk(ops)
	// BUG(xiaq): Closure arguments is (again) not supported
	f := func(ev *Evaluator) []Value {
		enclosed := make(map[string]*Value, len(enclosed))
		for name := range enclosed {
			enclosed[name] = ev.scope[name]
		}
		return []Value{NewClosure(nil, op, enclosed, bounds)}
	}
	return valuesOp{newFixedTypeRun(&ClosureType{bounds}), f}
}

func combinePipeline(ops []stateUpdatesOp, bounds [2]StreamType, internals []StreamType, p parse.Pos) valuesOp {
	f := func(ev *Evaluator) []Value {
		// TODO(xiaq): Should catch when compiling
		if !ev.ports[0].compatible(bounds[0]) {
			ev.errorf(p, "pipeline input not satisfiable")
		}
		if !ev.ports[1].compatible(bounds[1]) {
			ev.errorf(p, "pipeline output not satisfiable")
		}
		var nextIn *port
		updates := make([]<-chan *StateUpdate, len(ops))
		// For each form, create a dedicated Evaluator and run
		for i, op := range ops {
			newEv := ev.copy(fmt.Sprintf("<form op %v>", op), false)
			if i > 0 {
				newEv.ports[0] = nextIn
			}
			if i < len(ops)-1 {
				switch internals[i] {
				case unusedStream:
					newEv.ports[1] = nil
					nextIn = nil
				case fdStream:
					// os.Pipe sets O_CLOEXEC, which is what we want.
					reader, writer, e := os.Pipe()
					if e != nil {
						ev.errorf(p, "failed to create pipe: %s", e)
					}
					newEv.ports[1] = &port{f: writer, shouldClose: true}
					nextIn = &port{f: reader, shouldClose: true}
				case chanStream:
					// TODO Buffered channel?
					ch := make(chan Value)
					// Only the writer closes the channel port
					newEv.ports[1] = &port{ch: ch, shouldClose: true}
					nextIn = &port{ch: ch}
				default:
					panic("bad StreamType value")
				}
			}
			updates[i] = op(newEv)
		}
		// Collect exit values
		exits := make([]Value, len(ops))
		for i, update := range updates {
			for up := range update {
				exits[i] = NewString(up.Msg)
			}
		}
		return exits
	}
	return valuesOp{newHomoTypeRun(&StringType{}, len(ops), false), f}
}

func combineForm(cmd valuesOp, tlist valuesOp, ports []portOp, a *formAnnotation, p parse.Pos) stateUpdatesOp {
	return func(ev *Evaluator) <-chan *StateUpdate {
		// XXX Currently it's guaranteed that cmd evaluates into a single
		// Value.
		cmd := cmd.f(ev)[0]
		cmdStr := cmd.String()
		fm := &form{
			name: cmdStr,
		}
		if tlist.f != nil {
			fm.args = tlist.f(ev)
		}

		switch a.commandType {
		case commandBuiltinFunction:
			fm.Command.Func = a.builtinFunc.fn
		case commandBuiltinSpecial:
			fm.Command.Special = a.specialOp
		case commandDefinedFunction:
			v, ok1 := ev.scope["fn-"+cmdStr]
			fn, ok2 := (*v).(*Closure)
			if !(ok1 && ok2) {
				panic("Compiler bug")
			}
			fm.Command.Closure = fn
		case commandClosure:
			fm.Command.Closure = cmd.(*Closure)
		case commandExternal:
			path, e := ev.search(cmdStr)
			if e != nil {
				ev.errorf(p, "%s", e)
			}
			fm.Command.Path = path
		default:
			panic("bad commandType value")
		}

		newEv := ev.copy(fmt.Sprintf("<form redir %v>", fm), true)
		newEv.growPorts(len(ports))

		for i, op := range ports {
			if op != nil {
				newEv.ports[i] = op(ev)
			}
		}

		return newEv.execForm(fm)
	}
}

func combineSpaced(ops []valuesOp) valuesOp {
	tr := make(typeRun, 0, len(ops))
	for _, op := range ops {
		tr = append(tr, op.tr...)
	}

	f := func(ev *Evaluator) []Value {
		// Use number of compound expressions as an estimation of the number
		// of values
		vs := make([]Value, 0, len(ops))
		for _, op := range ops {
			us := op.f(ev)
			vs = append(vs, us...)
		}
		return vs
	}
	return valuesOp{tr, f}
}

func caret(ev *Evaluator, lhs, rhs Value) Value {
	return NewString(lhs.String() + rhs.String())
}

func combineCompound(ops []valuesOp) valuesOp {
	n := 1
	more := false
	for _, op := range ops {
		m, b := op.tr.count()
		n *= m
		more = more || b
	}

	f := func(ev *Evaluator) []Value {
		vs := ops[0].f(ev)
		for _, op := range ops[1:] {
			us := op.f(ev)
			if len(us) == 1 {
				u := us[0]
				for i := range vs {
					vs[i] = caret(ev, vs[i], u)
				}
			} else {
				// Do a cartesian product
				newvs := make([]Value, len(vs)*len(us))
				for i, v := range vs {
					for j, u := range us {
						newvs[i*len(us)+j] = caret(ev, v, u)
					}
				}
				vs = newvs
			}
		}
		return vs
	}
	return valuesOp{newHomoTypeRun(StringType{}, n, more), f}
}

func literalValue(v ...Value) valuesOp {
	tr := make(typeRun, len(v))
	for i := range tr {
		tr[i].t = v[i].Type()
	}
	f := func(e *Evaluator) []Value {
		return v
	}
	return valuesOp{tr, f}
}

func makeString(text string) valuesOp {
	return literalValue(NewString(text))
}

func makeVar(cp *Compiler, name string, p parse.Pos) valuesOp {
	tr := newFixedTypeRun(cp.resolveVar(name, p))
	f := func(ev *Evaluator) []Value {
		val, ok := ev.scope[name]
		if !ok {
			panic("Compiler bug")
		}
		return []Value{*val}
	}
	return valuesOp{tr, f}
}

func combineSubscript(cp *Compiler, left, right valuesOp, lp, rp parse.Pos) valuesOp {
	if !left.tr.mayCountTo(1) {
		// TODO Also check at runtime
		cp.errorf(lp, "left operand of subscript must be a single value")
	}
	var t Type
	switch left.tr[0].t.(type) {
	case EnvType:
		t = StringType{}
	case TableType, AnyType:
		t = AnyType{}
	default:
		cp.errorf(lp, "left operand of subscript must be of type string, env, table or any")
	}

	if !right.tr.mayCountTo(1) {
		// TODO Also check at runtime
		cp.errorf(rp, "right operand of subscript must be a single value")
	}
	if _, ok := right.tr[0].t.(StringType); !ok {
		cp.errorf(rp, "right operand of subscript must be of type string")
	}

	f := func(ev *Evaluator) []Value {
		l := left.f(ev)
		r := right.f(ev)
		return []Value{evalSubscript(ev, l[0], r[0], lp, rp)}
	}
	return valuesOp{newFixedTypeRun(t), f}
}

func combineTable(list valuesOp, keys []valuesOp, values []valuesOp, p parse.Pos) valuesOp {
	f := func(ev *Evaluator) []Value {
		t := NewTable()
		t.append(list.f(ev)...)
		for i, kop := range keys {
			vop := values[i]
			ks := kop.f(ev)
			vs := vop.f(ev)
			if len(ks) != len(vs) {
				ev.errorf(p, "Number of keys doesn't match number of values: %d vs. %d", len(ks), len(vs))
			}
			for j, k := range ks {
				t.Dict[k] = vs[j]
			}
		}
		return []Value{t}
	}
	return valuesOp{newFixedTypeRun(TableType{}), f}
}

func combineOutputCapture(op valuesOp, bounds [2]StreamType) valuesOp {
	// XXX Wrong type; tr should be variadic
	tr := newFixedTypeRun()
	f := func(ev *Evaluator) []Value {
		vs := []Value{}
		newEv := ev.copy(fmt.Sprintf("<output capture %v>", op), false)
		newEv.ports = make([]*port, len(ev.ports))
		copy(newEv.ports, ev.ports)
		ch := make(chan Value)
		newEv.ports[1] = &port{ch: ch}
		go func() {
			for v := range ch {
				vs = append(vs, v)
			}
		}()
		op.f(newEv)
		newEv.closePorts()
		return vs
	}
	return valuesOp{tr, f}
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2017 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cloud

import (
	"fmt"
	"net/http"

	"github.com/pkg/errors"
)

// ErrorResponse represents an error cause by talking to the API
type ErrorResponse struct {
	Response *http.Response
	Message  string
	Code     int
}

func (e *ErrorResponse) Error() string {
	return fmt.Sprintf("%d %v", e.Code, e.Message)
}

var (
	ErrNotAuthorized    = errors.New("Not allowed to upload result to Load Impact cloud")
	ErrNotAuthenticated = errors.New("Failed to authenticate with Load Impact cloud")
	ErrNotUnknown       = errors.New("An error occurred talking to Load Impact cloud")
)
<commit_msg>Fix bad error name<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2017 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cloud

import (
	"fmt"
	"net/http"

	"github.com/pkg/errors"
)

// ErrorResponse represents an error cause by talking to the API
type ErrorResponse struct {
	Response *http.Response
	Message  string
	Code     int
}

func (e *ErrorResponse) Error() string {
	return fmt.Sprintf("%d %v", e.Code, e.Message)
}

var (
	ErrNotAuthorized    = errors.New("Not allowed to upload result to Load Impact cloud")
	ErrNotAuthenticated = errors.New("Failed to authenticate with Load Impact cloud")
	ErrUnknown          = errors.New("An error occurred talking to Load Impact cloud")
)
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

    http://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.
*/

package feature

import (
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/spf13/pflag"
)

type Feature string

const (
	flagName = "feature-gates"

	// allAlphaGate is a global toggle for alpha features. Per-feature key
	// values override the default set by allAlphaGate. Examples:
	//   AllAlpha=false,NewFeature=true  will result in newFeature=true
	//   AllAlpha=true,NewFeature=false  will result in newFeature=false
	allAlphaGate Feature = "AllAlpha"
)

var (
	// The generic features.
	defaultFeatures = map[Feature]FeatureSpec{
		allAlphaGate: {Default: false, PreRelease: Alpha},
	}

	// Special handling for a few gates.
	specialFeatures = map[Feature]func(f *featureGate, val bool){
		allAlphaGate: setUnsetAlphaGates,
	}

	// DefaultFeatureGate is a shared global FeatureGate.
	DefaultFeatureGate FeatureGate = NewFeatureGate()
)

type FeatureSpec struct {
	Default    bool
	PreRelease prerelease
}

type prerelease string

const (
	// Values for PreRelease.
	Alpha = prerelease("ALPHA")
	Beta  = prerelease("BETA")
	GA    = prerelease("")
)

// FeatureGate parses and stores flag gates for known features from
// a string like feature1=true,feature2=false,...
type FeatureGate interface {
	// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
	AddFlag(fs *pflag.FlagSet)
	// Set parses and stores flag gates for known features
	// from a string like feature1=true,feature2=false,...
	Set(value string) error
	// Enabled returns true if the key is enabled.
	Enabled(key Feature) bool
	// Add adds features to the featureGate.
	Add(features map[Feature]FeatureSpec) error
	// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
	KnownFeatures() []string
}

// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
type featureGate struct {
	known   map[Feature]FeatureSpec
	special map[Feature]func(*featureGate, bool)
	enabled map[Feature]bool

	// is set to true when AddFlag is called. Note: initialization is not go-routine safe, lookup is
	closed bool
}

func setUnsetAlphaGates(f *featureGate, val bool) {
	for k, v := range f.known {
		if v.PreRelease == Alpha {
			if _, found := f.enabled[k]; !found {
				f.enabled[k] = val
			}
		}
	}
}

// Set, String, and Type implement pflag.Value
var _ pflag.Value = &featureGate{}

func NewFeatureGate() *featureGate {
	f := &featureGate{
		known:   map[Feature]FeatureSpec{},
		special: specialFeatures,
		enabled: map[Feature]bool{},
	}
	for k, v := range defaultFeatures {
		f.known[k] = v
	}
	return f
}

// Set Parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func (f *featureGate) Set(value string) error {
	for _, s := range strings.Split(value, ",") {
		if len(s) == 0 {
			continue
		}
		arr := strings.SplitN(s, "=", 2)
		k := Feature(strings.TrimSpace(arr[0]))
		_, ok := f.known[Feature(k)]
		if !ok {
			return fmt.Errorf("unrecognized key: %s", k)
		}
		if len(arr) != 2 {
			return fmt.Errorf("missing bool value for %s", k)
		}
		v := strings.TrimSpace(arr[1])
		boolValue, err := strconv.ParseBool(v)
		if err != nil {
			return fmt.Errorf("invalid value of %s: %s, err: %v", k, v, err)
		}
		f.enabled[k] = boolValue

		// Handle "special" features like "all alpha gates"
		if fn, found := f.special[k]; found {
			fn(f, boolValue)
		}
	}

	glog.Infof("feature gates: %v", f.enabled)
	return nil
}

// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
func (f *featureGate) String() string {
	pairs := []string{}
	for k, v := range f.enabled {
		pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
	}
	sort.Strings(pairs)
	return strings.Join(pairs, ",")
}

func (f *featureGate) Type() string {
	return "mapStringBool"
}

// Add adds features to the featureGate.
func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
	if f.closed {
		return fmt.Errorf("cannot add a feature gate after adding it to the flag set")
	}

	for name, spec := range features {
		if existingSpec, found := f.known[name]; found {
			if existingSpec == spec {
				continue
			}
			return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
		}

		f.known[name] = spec
	}
	return nil
}

// Enabled returns true if the key is enabled.
func (f *featureGate) Enabled(key Feature) bool {
	defaultValue := f.known[key].Default
	if f.enabled != nil {
		if v, ok := f.enabled[key]; ok {
			return v
		}
	}
	return defaultValue
}

// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
	f.closed = true

	known := f.KnownFeatures()
	fs.Var(f, flagName, ""+
		"A set of key=value pairs that describe feature gates for alpha/experimental features. "+
		"Options are:\n"+strings.Join(known, "\n"))
}

// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
func (f *featureGate) KnownFeatures() []string {
	var known []string
	for k, v := range f.known {
		pre := ""
		if v.PreRelease != GA {
			pre = fmt.Sprintf("%s - ", v.PreRelease)
		}
		known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default))
	}
	sort.Strings(known)
	return known
}
<commit_msg>Make feature gate threadsafe<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

    http://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.
*/

package feature

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
	"sync"

	"github.com/golang/glog"
	"github.com/spf13/pflag"
)

type Feature string

const (
	flagName = "feature-gates"

	// allAlphaGate is a global toggle for alpha features. Per-feature key
	// values override the default set by allAlphaGate. Examples:
	//   AllAlpha=false,NewFeature=true  will result in newFeature=true
	//   AllAlpha=true,NewFeature=false  will result in newFeature=false
	allAlphaGate Feature = "AllAlpha"
)

var (
	// The generic features.
	defaultFeatures = map[Feature]FeatureSpec{
		allAlphaGate: {Default: false, PreRelease: Alpha},
	}

	// Special handling for a few gates.
	specialFeatures = map[Feature]func(f *featureGate, val bool){
		allAlphaGate: setUnsetAlphaGates,
	}

	// DefaultFeatureGate is a shared global FeatureGate.
	DefaultFeatureGate FeatureGate = NewFeatureGate()
)

type FeatureSpec struct {
	Default    bool
	PreRelease prerelease
}

type prerelease string

const (
	// Values for PreRelease.
	Alpha = prerelease("ALPHA")
	Beta  = prerelease("BETA")
	GA    = prerelease("")
)

// FeatureGate parses and stores flag gates for known features from
// a string like feature1=true,feature2=false,...
type FeatureGate interface {
	// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
	AddFlag(fs *pflag.FlagSet)
	// Set parses and stores flag gates for known features
	// from a string like feature1=true,feature2=false,...
	Set(value string) error
	// Enabled returns true if the key is enabled.
	Enabled(key Feature) bool
	// Add adds features to the featureGate.
	Add(features map[Feature]FeatureSpec) error
	// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
	KnownFeatures() []string
}

// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
type featureGate struct {
	lock sync.RWMutex

	known   map[Feature]FeatureSpec
	special map[Feature]func(*featureGate, bool)
	enabled map[Feature]bool

	// is set to true when AddFlag is called. Note: initialization is not go-routine safe, lookup is
	closed bool
}

func setUnsetAlphaGates(f *featureGate, val bool) {
	for k, v := range f.known {
		if v.PreRelease == Alpha {
			if _, found := f.enabled[k]; !found {
				f.enabled[k] = val
			}
		}
	}
}

// Set, String, and Type implement pflag.Value
var _ pflag.Value = &featureGate{}

func NewFeatureGate() *featureGate {
	f := &featureGate{
		known:   map[Feature]FeatureSpec{},
		special: specialFeatures,
		enabled: map[Feature]bool{},
	}
	for k, v := range defaultFeatures {
		f.known[k] = v
	}
	return f
}

// Set Parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func (f *featureGate) Set(value string) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	for _, s := range strings.Split(value, ",") {
		if len(s) == 0 {
			continue
		}
		arr := strings.SplitN(s, "=", 2)
		k := Feature(strings.TrimSpace(arr[0]))
		_, ok := f.known[Feature(k)]
		if !ok {
			return fmt.Errorf("unrecognized key: %s", k)
		}
		if len(arr) != 2 {
			return fmt.Errorf("missing bool value for %s", k)
		}
		v := strings.TrimSpace(arr[1])
		boolValue, err := strconv.ParseBool(v)
		if err != nil {
			return fmt.Errorf("invalid value of %s: %s, err: %v", k, v, err)
		}
		f.enabled[k] = boolValue

		// Handle "special" features like "all alpha gates"
		if fn, found := f.special[k]; found {
			fn(f, boolValue)
		}
	}

	glog.Infof("feature gates: %v", f.enabled)
	return nil
}

// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
func (f *featureGate) String() string {
	f.lock.RLock()
	defer f.lock.RUnlock()

	pairs := []string{}
	for k, v := range f.enabled {
		pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
	}
	sort.Strings(pairs)
	return strings.Join(pairs, ",")
}

func (f *featureGate) Type() string {
	return "mapStringBool"
}

// Add adds features to the featureGate.
func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	if f.closed {
		return fmt.Errorf("cannot add a feature gate after adding it to the flag set")
	}

	for name, spec := range features {
		if existingSpec, found := f.known[name]; found {
			if existingSpec == spec {
				continue
			}
			return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
		}

		f.known[name] = spec
	}
	return nil
}

// Enabled returns true if the key is enabled.
func (f *featureGate) Enabled(key Feature) bool {
	f.lock.RLock()
	defer f.lock.RUnlock()

	defaultValue := f.known[key].Default
	if f.enabled != nil {
		if v, ok := f.enabled[key]; ok {
			return v
		}
	}
	return defaultValue
}

// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
	f.lock.Lock()
	f.closed = true
	f.lock.Unlock()

	known := f.KnownFeatures()
	fs.Var(f, flagName, ""+
		"A set of key=value pairs that describe feature gates for alpha/experimental features. "+
		"Options are:\n"+strings.Join(known, "\n"))
}

// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
func (f *featureGate) KnownFeatures() []string {
	f.lock.RLock()
	defer f.lock.RUnlock()
	var known []string
	for k, v := range f.known {
		pre := ""
		if v.PreRelease != GA {
			pre = fmt.Sprintf("%s - ", v.PreRelease)
		}
		known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default))
	}
	sort.Strings(known)
	return known
}
<|endoftext|>


<commit_before>package etcd

import (
	"time"

	jose "gopkg.in/square/go-jose.v2"

	"github.com/dexidp/dex/storage"
)

// AuthCode is a mirrored struct from storage with JSON struct tags
type AuthCode struct {
	ID          string   `json:"ID"`
	ClientID    string   `json:"clientID"`
	RedirectURI string   `json:"redirectURI"`
	Nonce       string   `json:"nonce,omitempty"`
	Scopes      []string `json:"scopes,omitempty"`

	ConnectorID   string `json:"connectorID,omitempty"`
	ConnectorData []byte `json:"connectorData,omitempty"`
	Claims        Claims `json:"claims,omitempty"`

	Expiry time.Time `json:"expiry"`
}

func fromStorageAuthCode(a storage.AuthCode) AuthCode {
	return AuthCode{
		ID:            a.ID,
		ClientID:      a.ClientID,
		RedirectURI:   a.RedirectURI,
		ConnectorID:   a.ConnectorID,
		ConnectorData: a.ConnectorData,
		Nonce:         a.Nonce,
		Scopes:        a.Scopes,
		Claims:        fromStorageClaims(a.Claims),
		Expiry:        a.Expiry,
	}
}

// AuthRequest is a mirrored struct from storage with JSON struct tags
type AuthRequest struct {
	ID       string `json:"id"`
	ClientID string `json:"client_id"`

	ResponseTypes []string `json:"response_types"`
	Scopes        []string `json:"scopes"`
	RedirectURI   string   `json:"redirect_uri"`
	Nonce         string   `json:"nonce"`
	State         string   `json:"state"`

	ForceApprovalPrompt bool `json:"force_approval_prompt"`

	Expiry time.Time `json:"expiry"`

	LoggedIn bool `json:"logged_in"`

	Claims Claims `json:"claims"`

	ConnectorID   string `json:"connector_id"`
	ConnectorData []byte `json:"connector_data"`
}

func fromStorageAuthRequest(a storage.AuthRequest) AuthRequest {
	return AuthRequest{
		ID:                  a.ID,
		ClientID:            a.ClientID,
		ResponseTypes:       a.ResponseTypes,
		Scopes:              a.Scopes,
		RedirectURI:         a.RedirectURI,
		Nonce:               a.Nonce,
		State:               a.State,
		ForceApprovalPrompt: a.ForceApprovalPrompt,
		Expiry:              a.Expiry,
		LoggedIn:            a.LoggedIn,
		Claims:              fromStorageClaims(a.Claims),
		ConnectorID:         a.ConnectorID,
		ConnectorData:       a.ConnectorData,
	}
}

func toStorageAuthRequest(a AuthRequest) storage.AuthRequest {
	return storage.AuthRequest{
		ID:                  a.ID,
		ClientID:            a.ClientID,
		ResponseTypes:       a.ResponseTypes,
		Scopes:              a.Scopes,
		RedirectURI:         a.RedirectURI,
		Nonce:               a.Nonce,
		State:               a.State,
		ForceApprovalPrompt: a.ForceApprovalPrompt,
		LoggedIn:            a.LoggedIn,
		ConnectorID:         a.ConnectorID,
		ConnectorData:       a.ConnectorData,
		Expiry:              a.Expiry,
		Claims:              toStorageClaims(a.Claims),
	}
}

// RefreshToken is a mirrored struct from storage with JSON struct tags
type RefreshToken struct {
	ID string `json:"id"`

	Token string `json:"token"`

	CreatedAt time.Time `json:"created_at"`
	LastUsed  time.Time `json:"last_used"`

	ClientID string `json:"client_id"`

	ConnectorID   string `json:"connector_id"`
	ConnectorData []byte `json:"connector_data"`
	Claims        Claims `json:"claims"`

	Scopes []string `json:"scopes"`

	Nonce string `json:"nonce"`
}

func toStorageRefreshToken(r RefreshToken) storage.RefreshToken {
	return storage.RefreshToken{
		ID:            r.ID,
		Token:         r.Token,
		CreatedAt:     r.CreatedAt,
		LastUsed:      r.LastUsed,
		ClientID:      r.ClientID,
		ConnectorID:   r.ConnectorID,
		ConnectorData: r.ConnectorData,
		Scopes:        r.Scopes,
		Nonce:         r.Nonce,
		Claims:        toStorageClaims(r.Claims),
	}
}

func fromStorageRefreshToken(r storage.RefreshToken) RefreshToken {
	return RefreshToken{
		ID:            r.ID,
		Token:         r.Token,
		CreatedAt:     r.CreatedAt,
		LastUsed:      r.LastUsed,
		ClientID:      r.ClientID,
		ConnectorID:   r.ConnectorID,
		ConnectorData: r.ConnectorData,
		Scopes:        r.Scopes,
		Nonce:         r.Nonce,
		Claims:        fromStorageClaims(r.Claims),
	}
}

// Claims is a mirrored struct from storage with JSON struct tags.
type Claims struct {
	UserID            string   `json:"userID"`
	Username          string   `json:"username"`
	PreferredUsername string   `json:"preferredUsername"`
	Email             string   `json:"email"`
	EmailVerified     bool     `json:"emailVerified"`
	Groups            []string `json:"groups,omitempty"`
}

func fromStorageClaims(i storage.Claims) Claims {
	return Claims{
		UserID:            i.UserID,
		Username:          i.Username,
		PreferredUsername: i.PreferredUsername,
		Email:             i.Email,
		EmailVerified:     i.EmailVerified,
		Groups:            i.Groups,
	}
}

func toStorageClaims(i Claims) storage.Claims {
	return storage.Claims{
		UserID:            i.UserID,
		Username:          i.Username,
		PreferredUsername: i.PreferredUsername,
		Email:             i.Email,
		EmailVerified:     i.EmailVerified,
		Groups:            i.Groups,
	}
}

// Keys is a mirrored struct from storage with JSON struct tags
type Keys struct {
	SigningKey       *jose.JSONWebKey          `json:"signing_key,omitempty"`
	SigningKeyPub    *jose.JSONWebKey          `json:"signing_key_pub,omitempty"`
	VerificationKeys []storage.VerificationKey `json:"verification_keys"`
	NextRotation     time.Time                 `json:"next_rotation"`
}

// OfflineSessions is a mirrored struct from storage with JSON struct tags
type OfflineSessions struct {
	UserID  string                              `json:"user_id,omitempty"`
	ConnID  string                              `json:"conn_id,omitempty"`
	Refresh map[string]*storage.RefreshTokenRef `json:"refresh,omitempty"`
}

func fromStorageOfflineSessions(o storage.OfflineSessions) OfflineSessions {
	return OfflineSessions{
		UserID:  o.UserID,
		ConnID:  o.ConnID,
		Refresh: o.Refresh,
	}
}

func toStorageOfflineSessions(o OfflineSessions) storage.OfflineSessions {
	s := storage.OfflineSessions{
		UserID:  o.UserID,
		ConnID:  o.ConnID,
		Refresh: o.Refresh,
	}
	if s.Refresh == nil {
		// Server code assumes this will be non-nil.
		s.Refresh = make(map[string]*storage.RefreshTokenRef)
	}
	return s
}
<commit_msg>Fix ETCD storage backend<commit_after>package etcd

import (
	"time"

	jose "gopkg.in/square/go-jose.v2"

	"github.com/dexidp/dex/storage"
)

// AuthCode is a mirrored struct from storage with JSON struct tags
type AuthCode struct {
	ID          string   `json:"ID"`
	ClientID    string   `json:"clientID"`
	RedirectURI string   `json:"redirectURI"`
	Nonce       string   `json:"nonce,omitempty"`
	Scopes      []string `json:"scopes,omitempty"`

	ConnectorID string `json:"connectorID,omitempty"`
	Claims      Claims `json:"claims,omitempty"`

	Expiry time.Time `json:"expiry"`
}

func fromStorageAuthCode(a storage.AuthCode) AuthCode {
	return AuthCode{
		ID:          a.ID,
		ClientID:    a.ClientID,
		RedirectURI: a.RedirectURI,
		ConnectorID: a.ConnectorID,
		Nonce:       a.Nonce,
		Scopes:      a.Scopes,
		Claims:      fromStorageClaims(a.Claims),
		Expiry:      a.Expiry,
	}
}

// AuthRequest is a mirrored struct from storage with JSON struct tags
type AuthRequest struct {
	ID       string `json:"id"`
	ClientID string `json:"client_id"`

	ResponseTypes []string `json:"response_types"`
	Scopes        []string `json:"scopes"`
	RedirectURI   string   `json:"redirect_uri"`
	Nonce         string   `json:"nonce"`
	State         string   `json:"state"`

	ForceApprovalPrompt bool `json:"force_approval_prompt"`

	Expiry time.Time `json:"expiry"`

	LoggedIn bool `json:"logged_in"`

	Claims Claims `json:"claims"`

	ConnectorID   string `json:"connector_id"`
	ConnectorData []byte `json:"connector_data"`
}

func fromStorageAuthRequest(a storage.AuthRequest) AuthRequest {
	return AuthRequest{
		ID:                  a.ID,
		ClientID:            a.ClientID,
		ResponseTypes:       a.ResponseTypes,
		Scopes:              a.Scopes,
		RedirectURI:         a.RedirectURI,
		Nonce:               a.Nonce,
		State:               a.State,
		ForceApprovalPrompt: a.ForceApprovalPrompt,
		Expiry:              a.Expiry,
		LoggedIn:            a.LoggedIn,
		Claims:              fromStorageClaims(a.Claims),
		ConnectorID:         a.ConnectorID,
	}
}

func toStorageAuthRequest(a AuthRequest) storage.AuthRequest {
	return storage.AuthRequest{
		ID:                  a.ID,
		ClientID:            a.ClientID,
		ResponseTypes:       a.ResponseTypes,
		Scopes:              a.Scopes,
		RedirectURI:         a.RedirectURI,
		Nonce:               a.Nonce,
		State:               a.State,
		ForceApprovalPrompt: a.ForceApprovalPrompt,
		LoggedIn:            a.LoggedIn,
		ConnectorID:         a.ConnectorID,
		Expiry:              a.Expiry,
		Claims:              toStorageClaims(a.Claims),
	}
}

// RefreshToken is a mirrored struct from storage with JSON struct tags
type RefreshToken struct {
	ID string `json:"id"`

	Token string `json:"token"`

	CreatedAt time.Time `json:"created_at"`
	LastUsed  time.Time `json:"last_used"`

	ClientID string `json:"client_id"`

	ConnectorID   string `json:"connector_id"`
	ConnectorData []byte `json:"connector_data"`
	Claims        Claims `json:"claims"`

	Scopes []string `json:"scopes"`

	Nonce string `json:"nonce"`
}

func toStorageRefreshToken(r RefreshToken) storage.RefreshToken {
	return storage.RefreshToken{
		ID:          r.ID,
		Token:       r.Token,
		CreatedAt:   r.CreatedAt,
		LastUsed:    r.LastUsed,
		ClientID:    r.ClientID,
		ConnectorID: r.ConnectorID,
		Scopes:      r.Scopes,
		Nonce:       r.Nonce,
		Claims:      toStorageClaims(r.Claims),
	}
}

func fromStorageRefreshToken(r storage.RefreshToken) RefreshToken {
	return RefreshToken{
		ID:          r.ID,
		Token:       r.Token,
		CreatedAt:   r.CreatedAt,
		LastUsed:    r.LastUsed,
		ClientID:    r.ClientID,
		ConnectorID: r.ConnectorID,
		Scopes:      r.Scopes,
		Nonce:       r.Nonce,
		Claims:      fromStorageClaims(r.Claims),
	}
}

// Claims is a mirrored struct from storage with JSON struct tags.
type Claims struct {
	UserID            string   `json:"userID"`
	Username          string   `json:"username"`
	PreferredUsername string   `json:"preferredUsername"`
	Email             string   `json:"email"`
	EmailVerified     bool     `json:"emailVerified"`
	Groups            []string `json:"groups,omitempty"`
}

func fromStorageClaims(i storage.Claims) Claims {
	return Claims{
		UserID:            i.UserID,
		Username:          i.Username,
		PreferredUsername: i.PreferredUsername,
		Email:             i.Email,
		EmailVerified:     i.EmailVerified,
		Groups:            i.Groups,
	}
}

func toStorageClaims(i Claims) storage.Claims {
	return storage.Claims{
		UserID:            i.UserID,
		Username:          i.Username,
		PreferredUsername: i.PreferredUsername,
		Email:             i.Email,
		EmailVerified:     i.EmailVerified,
		Groups:            i.Groups,
	}
}

// Keys is a mirrored struct from storage with JSON struct tags
type Keys struct {
	SigningKey       *jose.JSONWebKey          `json:"signing_key,omitempty"`
	SigningKeyPub    *jose.JSONWebKey          `json:"signing_key_pub,omitempty"`
	VerificationKeys []storage.VerificationKey `json:"verification_keys"`
	NextRotation     time.Time                 `json:"next_rotation"`
}

// OfflineSessions is a mirrored struct from storage with JSON struct tags
type OfflineSessions struct {
	UserID        string                              `json:"user_id,omitempty"`
	ConnID        string                              `json:"conn_id,omitempty"`
	Refresh       map[string]*storage.RefreshTokenRef `json:"refresh,omitempty"`
	ConnectorData []byte                              `json:"connectorData,omitempty"`
}

func fromStorageOfflineSessions(o storage.OfflineSessions) OfflineSessions {
	return OfflineSessions{
		UserID:        o.UserID,
		ConnID:        o.ConnID,
		Refresh:       o.Refresh,
		ConnectorData: o.ConnectorData,
	}
}

func toStorageOfflineSessions(o OfflineSessions) storage.OfflineSessions {
	s := storage.OfflineSessions{
		UserID:        o.UserID,
		ConnID:        o.ConnID,
		Refresh:       o.Refresh,
		ConnectorData: o.ConnectorData,
	}
	if s.Refresh == nil {
		// Server code assumes this will be non-nil.
		s.Refresh = make(map[string]*storage.RefreshTokenRef)
	}
	return s
}
<|endoftext|>