<commit_before>package kuberos

import (
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path/filepath"

	"github.com/negz/kuberos/extractor"

	oidc "github.com/coreos/go-oidc"
	"github.com/gorilla/schema"
	"github.com/pkg/errors"
	"github.com/spf13/afero"
	"go.uber.org/zap"
	"golang.org/x/oauth2"
	"k8s.io/api/core/v1"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/tools/clientcmd/api"
)

const (
	// DefaultKubeCfgEndpoint is the default endpoint to which clients should
	// be redirected after authentication.
	DefaultKubeCfgEndpoint = "ui"

	// DefaultAPITokenMountPath is the default mount path for API tokens
	DefaultAPITokenMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"

	schemeHTTP  = "http"
	schemeHTTPS = "https"

	headerForwardedProto  = "X-Forwarded-Proto"
	headerForwardedFor    = "X-Forwarded-For"
	headerForwardedPrefix = "X-Forwarded-Prefix"

	urlParamState            = "state"
	urlParamCode             = "code"
	urlParamError            = "error"
	urlParamErrorDescription = "error_description"
	urlParamErrorURI         = "error_uri"

	templateAuthProvider     = "oidc"
	templateOIDCClientID     = "client-id"
	templateOIDCClientSecret = "client-secret"
	templateOIDCIDToken      = "id-token"
	templateOIDCIssuer       = "idp-issuer-url"
	templateOIDCRefreshToken = "refresh-token"

	templateFormParseMemory = 32 << 20 // 32MB
)

var (
	// DefaultScopes are the minimum required oauth2 scopes for every
	// authentication request.
	DefaultScopes = []string{oidc.ScopeOpenID}

	// ErrInvalidKubeCfgEndpoint indicates an unparseable redirect endpoint.
	ErrInvalidKubeCfgEndpoint = errors.New("invalid redirect endpoint")

	// ErrInvalidState indicates the provided state param was not as expected.
	ErrInvalidState = errors.New("invalid state parameter: user agent or IP address changed between requests")

	// ErrMissingCode indicates a response without an OAuth 2.0 authorization
	// code
	ErrMissingCode = errors.New("response missing authorization code")

	// ErrNoYAMLSerializer indicates we're unable to serialize Kubernetes
	// objects as YAML.
	ErrNoYAMLSerializer = errors.New("no YAML serializer registered")

	decoder = schema.NewDecoder()

	appFs = afero.NewOsFs()

	approvalConsent = oauth2.SetAuthURLParam("prompt", "consent")
)

// A StateFn should take an HTTP request and return a difficult to predict yet
// deterministic state string.
type StateFn func(*http.Request) string

func defaultStateFn(secret []byte) StateFn {
	// Writing to a hash never returns an error.
	// nolint: errcheck, gas
	return func(r *http.Request) string {
		remote := r.RemoteAddr
		// Use the forwarded for header instead of the remote address if it is
		// supplied.
		for h, v := range r.Header {
			if h == headerForwardedFor {
				for _, host := range v {
					remote = host
				}
			}
		}

		h := sha256.New()
		h.Write(secret)
		h.Write([]byte(r.Host))
		h.Write([]byte(remote))
		h.Write([]byte(r.UserAgent()))
		return fmt.Sprintf("%x", h.Sum(nil))
	}
}

// OfflineAsScope determines whether an offline refresh token is requested via
// a scope per the spec or via Google's custom access_type=offline method.
//
// See http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess and
// https://developers.google.com/identity/protocols/OAuth2WebServer#offline
func OfflineAsScope(p *oidc.Provider) bool {
	var s struct {
		Scopes []string `json:"scopes_supported"`
	}
	if err := p.Claims(&s); err != nil {
		return true
	}
	if len(s.Scopes) == 0 {
		return true
	}
	for _, scope := range s.Scopes {
		if scope == oidc.ScopeOfflineAccess {
			return true
		}
	}
	return false
}

// ScopeRequests configures the oauth2 scopes to request during authentication.
type ScopeRequests struct {
	OfflineAsScope bool
	Scopes         []string
}

// Get the scopes to request during authentication.
func (r *ScopeRequests) Get() []string {
	scopes := DefaultScopes
	if r.OfflineAsScope {
		scopes = append(scopes, oidc.ScopeOfflineAccess)
	}
	return append(scopes, r.Scopes...)
}

// Handlers provides HTTP handlers for the Kubernary service.
type Handlers struct {
	log        *zap.Logger
	cfg        *oauth2.Config
	e          extractor.OIDC
	oo         []oauth2.AuthCodeOption
	state      StateFn
	httpClient *http.Client
	endpoint   *url.URL
}

// An Option represents a Handlers option.
type Option func(*Handlers) error

// StateFunction allows the use of a bespoke state generator function.
func StateFunction(fn StateFn) Option {
	return func(h *Handlers) error {
		h.state = fn
		return nil
	}
}

// HTTPClient allows the use of a bespoke HTTP client for OIDC requests.
func HTTPClient(c *http.Client) Option {
	return func(h *Handlers) error {
		h.httpClient = c
		return nil
	}
}

// AuthCodeOptions allows the use of bespoke OAuth2 options.
func AuthCodeOptions(oo []oauth2.AuthCodeOption) Option {
	return func(h *Handlers) error {
		h.oo = oo
		return nil
	}
}

// Logger allows the use of a bespoke Zap logger.
func Logger(l *zap.Logger) Option {
	return func(h *Handlers) error {
		h.log = l
		return nil
	}
}

// NewHandlers returns a new set of Kuberos HTTP handlers.
func NewHandlers(c *oauth2.Config, e extractor.OIDC, ho ...Option) (*Handlers, error) {
	l, err := zap.NewProduction()
	if err != nil {
		return nil, errors.Wrap(err, "cannot create default logger")
	}

	h := &Handlers{
		log:        l,
		cfg:        c,
		e:          e,
		oo:         []oauth2.AuthCodeOption{oauth2.AccessTypeOffline, approvalConsent},
		state:      defaultStateFn([]byte(c.ClientSecret)),
		httpClient: http.DefaultClient,
		endpoint:   &url.URL{Path: DefaultKubeCfgEndpoint},
	}

	// Assume we're using a Googley request for offline access.
	for _, s := range c.Scopes {
		// ...Unless we find an offline scope
		if s == oidc.ScopeOfflineAccess {
			h.oo = []oauth2.AuthCodeOption{approvalConsent}
		}
	}

	for _, o := range ho {
		if err := o(h); err != nil {
			return nil, errors.Wrap(err, "cannot apply handlers option")
		}
	}
	return h, nil
}

// Login redirects to an OIDC provider per the supplied oauth2 config.
func (h *Handlers) Login(w http.ResponseWriter, r *http.Request) {
	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	u := c.AuthCodeURL(h.state(r), h.oo...)
	h.log.Debug("redirect", zap.String("url", u))
	http.Redirect(w, r, u, http.StatusSeeOther)
}

// KubeCfg returns a handler that forms helpers for kubecfg authentication.
func (h *Handlers) KubeCfg(w http.ResponseWriter, r *http.Request) {
	if r.FormValue(urlParamState) != h.state(r) {
		http.Error(w, ErrInvalidState.Error(), http.StatusForbidden)
		return
	}

	if e := r.FormValue(urlParamError); e != "" {
		msg := e
		if desc := r.FormValue(urlParamErrorDescription); desc != "" {
			msg = fmt.Sprintf("%s: %s", msg, desc)
		}
		if uri := r.FormValue(urlParamErrorURI); uri != "" {
			msg = fmt.Sprintf("%s (see %s)", msg, uri)
		}
		http.Error(w, msg, http.StatusForbidden)
		return
	}

	code := r.FormValue(urlParamCode)
	if code == "" {
		http.Error(w, ErrMissingCode.Error(), http.StatusBadRequest)
		return
	}

	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	rsp, err := h.e.Process(r.Context(), c, code)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot process OAuth2 code").Error(), http.StatusForbidden)
		return
	}

	j, err := json.Marshal(rsp)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot marshal JSON").Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	if _, err := w.Write(j); err != nil {
		http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
	}
}

func redirectURL(r *http.Request, endpoint *url.URL) string {
	if r.URL.IsAbs() {
		return fmt.Sprint(r.URL.ResolveReference(endpoint))
	}
	u := &url.URL{}
	u.Scheme = schemeHTTP
	if r.TLS != nil {
		u.Scheme = schemeHTTPS
	}

	for h, v := range r.Header {
		switch h {
		case headerForwardedProto:
			// Redirect to HTTPS if we're listening on HTTP behind an HTTPS ELB.
			for _, proto := range v {
				if proto == schemeHTTPS {
					u.Scheme = schemeHTTPS
				}
			}
		case headerForwardedPrefix:
			// Redirect includes X-Forwarded-Prefix if exists
			for _, prefix := range v {
				u.Path = prefix
			}
		}
	}
	// TODO(negz): Set port if X-Forwarded-Port exists?
	u.Host = r.Host
	return fmt.Sprint(u.ResolveReference(endpoint))
}

// Template returns an HTTP handler that returns a new kubecfg by taking a
// template with existing clusters and adding a user and context for each based
// on the URL parameters passed to it.
func Template(cfg *api.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		r.ParseMultipartForm(templateFormParseMemory) //nolint:errcheck
		p := &extractor.OIDCAuthenticationParams{}

		// TODO(negz): Return an error if any required parameter is absent.
		if err := decoder.Decode(p, r.Form); err != nil {
			http.Error(w, errors.Wrap(err, "cannot parse URL parameter").Error(), http.StatusBadRequest)
			return
		}

		y, err := clientcmd.Write(populateUser(cfg, p))
		if err != nil {
			http.Error(w, errors.Wrap(err, "cannot marshal template to YAML").Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "text/x-yaml; charset=utf-8")
		w.Header().Set("Content-Disposition", "attachment")
		if _, err := w.Write(y); err != nil {
			http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
		}
	}
}

func populateUser(cfg *api.Config, p *extractor.OIDCAuthenticationParams) api.Config {
	c := api.Config{}
	c.AuthInfos = make(map[string]*api.AuthInfo)
	c.Clusters = make(map[string]*api.Cluster)
	c.Contexts = make(map[string]*api.Context)
	c.CurrentContext = cfg.CurrentContext
	c.AuthInfos[p.Username] = &api.AuthInfo{
		AuthProvider: &api.AuthProviderConfig{
			Name: templateAuthProvider,
			Config: map[string]string{
				templateOIDCClientID:     p.ClientID,
				templateOIDCClientSecret: p.ClientSecret,
				templateOIDCIDToken:      p.IDToken,
				templateOIDCRefreshToken: p.RefreshToken,
				templateOIDCIssuer:       p.IssuerURL,
			},
		},
	}

	for name, cluster := range cfg.Clusters {
		// If the cluster definition does not come with certificate-authority-data nor
		// certificate-authority, then check if kuberos has access to the cluster's CA
		// certificate and include it when possible. Assume all errors are non-fatal.
		if len(cluster.CertificateAuthorityData) == 0 && cluster.CertificateAuthority == "" {
			caPath := filepath.Join(DefaultAPITokenMountPath, v1.ServiceAccountRootCAKey)
			if caFile, err := appFs.Open(caPath); err == nil {
				if caCert, err := ioutil.ReadAll(caFile); err == nil {
					cluster.CertificateAuthorityData = caCert
				}
			} else {
				fmt.Printf("Error: %+v\n", err)
			}
		}
		c.Clusters[name] = cluster
		c.Contexts[name] = &api.Context{
			Cluster:  name,
			AuthInfo: p.Username,
		}
	}
	return c
}
<commit_msg>Remove remote IP in state to allow for loadbalancing<commit_after>package kuberos

import (
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path/filepath"

	"github.com/negz/kuberos/extractor"

	oidc "github.com/coreos/go-oidc"
	"github.com/gorilla/schema"
	"github.com/pkg/errors"
	"github.com/spf13/afero"
	"go.uber.org/zap"
	"golang.org/x/oauth2"
	"k8s.io/api/core/v1"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/tools/clientcmd/api"
)

const (
	// DefaultKubeCfgEndpoint is the default endpoint to which clients should
	// be redirected after authentication.
	DefaultKubeCfgEndpoint = "ui"

	// DefaultAPITokenMountPath is the default mount path for API tokens
	DefaultAPITokenMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"

	schemeHTTP  = "http"
	schemeHTTPS = "https"

	headerForwardedProto  = "X-Forwarded-Proto"
	headerForwardedFor    = "X-Forwarded-For"
	headerForwardedPrefix = "X-Forwarded-Prefix"

	urlParamState            = "state"
	urlParamCode             = "code"
	urlParamError            = "error"
	urlParamErrorDescription = "error_description"
	urlParamErrorURI         = "error_uri"

	templateAuthProvider     = "oidc"
	templateOIDCClientID     = "client-id"
	templateOIDCClientSecret = "client-secret"
	templateOIDCIDToken      = "id-token"
	templateOIDCIssuer       = "idp-issuer-url"
	templateOIDCRefreshToken = "refresh-token"

	templateFormParseMemory = 32 << 20 // 32MB
)

var (
	// DefaultScopes are the minimum required oauth2 scopes for every
	// authentication request.
	DefaultScopes = []string{oidc.ScopeOpenID}

	// ErrInvalidKubeCfgEndpoint indicates an unparseable redirect endpoint.
	ErrInvalidKubeCfgEndpoint = errors.New("invalid redirect endpoint")

	// ErrInvalidState indicates the provided state param was not as expected.
	ErrInvalidState = errors.New("invalid state parameter: user agent or IP address changed between requests")

	// ErrMissingCode indicates a response without an OAuth 2.0 authorization
	// code
	ErrMissingCode = errors.New("response missing authorization code")

	// ErrNoYAMLSerializer indicates we're unable to serialize Kubernetes
	// objects as YAML.
	ErrNoYAMLSerializer = errors.New("no YAML serializer registered")

	decoder = schema.NewDecoder()

	appFs = afero.NewOsFs()

	approvalConsent = oauth2.SetAuthURLParam("prompt", "consent")
)

// A StateFn should take an HTTP request and return a difficult to predict yet
// deterministic state string.
type StateFn func(*http.Request) string

func defaultStateFn(secret []byte) StateFn {
	// Writing to a hash never returns an error.
	// nolint: errcheck, gas
	return func(r *http.Request) string {
		h := sha256.New()
		h.Write(secret)
		h.Write([]byte(r.Host))
		h.Write([]byte(r.UserAgent()))
		return fmt.Sprintf("%x", h.Sum(nil))
	}
}

// OfflineAsScope determines whether an offline refresh token is requested via
// a scope per the spec or via Google's custom access_type=offline method.
//
// See http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess and
// https://developers.google.com/identity/protocols/OAuth2WebServer#offline
func OfflineAsScope(p *oidc.Provider) bool {
	var s struct {
		Scopes []string `json:"scopes_supported"`
	}
	if err := p.Claims(&s); err != nil {
		return true
	}
	if len(s.Scopes) == 0 {
		return true
	}
	for _, scope := range s.Scopes {
		if scope == oidc.ScopeOfflineAccess {
			return true
		}
	}
	return false
}

// ScopeRequests configures the oauth2 scopes to request during authentication.
type ScopeRequests struct {
	OfflineAsScope bool
	Scopes         []string
}

// Get the scopes to request during authentication.
func (r *ScopeRequests) Get() []string {
	scopes := DefaultScopes
	if r.OfflineAsScope {
		scopes = append(scopes, oidc.ScopeOfflineAccess)
	}
	return append(scopes, r.Scopes...)
}

// Handlers provides HTTP handlers for the Kubernary service.
type Handlers struct {
	log        *zap.Logger
	cfg        *oauth2.Config
	e          extractor.OIDC
	oo         []oauth2.AuthCodeOption
	state      StateFn
	httpClient *http.Client
	endpoint   *url.URL
}

// An Option represents a Handlers option.
type Option func(*Handlers) error

// StateFunction allows the use of a bespoke state generator function.
func StateFunction(fn StateFn) Option {
	return func(h *Handlers) error {
		h.state = fn
		return nil
	}
}

// HTTPClient allows the use of a bespoke HTTP client for OIDC requests.
func HTTPClient(c *http.Client) Option {
	return func(h *Handlers) error {
		h.httpClient = c
		return nil
	}
}

// AuthCodeOptions allows the use of bespoke OAuth2 options.
func AuthCodeOptions(oo []oauth2.AuthCodeOption) Option {
	return func(h *Handlers) error {
		h.oo = oo
		return nil
	}
}

// Logger allows the use of a bespoke Zap logger.
func Logger(l *zap.Logger) Option {
	return func(h *Handlers) error {
		h.log = l
		return nil
	}
}

// NewHandlers returns a new set of Kuberos HTTP handlers.
func NewHandlers(c *oauth2.Config, e extractor.OIDC, ho ...Option) (*Handlers, error) {
	l, err := zap.NewProduction()
	if err != nil {
		return nil, errors.Wrap(err, "cannot create default logger")
	}

	h := &Handlers{
		log:        l,
		cfg:        c,
		e:          e,
		oo:         []oauth2.AuthCodeOption{oauth2.AccessTypeOffline, approvalConsent},
		state:      defaultStateFn([]byte(c.ClientSecret)),
		httpClient: http.DefaultClient,
		endpoint:   &url.URL{Path: DefaultKubeCfgEndpoint},
	}

	// Assume we're using a Googley request for offline access.
	for _, s := range c.Scopes {
		// ...Unless we find an offline scope
		if s == oidc.ScopeOfflineAccess {
			h.oo = []oauth2.AuthCodeOption{approvalConsent}
		}
	}

	for _, o := range ho {
		if err := o(h); err != nil {
			return nil, errors.Wrap(err, "cannot apply handlers option")
		}
	}
	return h, nil
}

// Login redirects to an OIDC provider per the supplied oauth2 config.
func (h *Handlers) Login(w http.ResponseWriter, r *http.Request) {
	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	u := c.AuthCodeURL(h.state(r), h.oo...)
	h.log.Debug("redirect", zap.String("url", u))
	http.Redirect(w, r, u, http.StatusSeeOther)
}

// KubeCfg returns a handler that forms helpers for kubecfg authentication.
func (h *Handlers) KubeCfg(w http.ResponseWriter, r *http.Request) {
	if r.FormValue(urlParamState) != h.state(r) {
		http.Error(w, ErrInvalidState.Error(), http.StatusForbidden)
		return
	}

	if e := r.FormValue(urlParamError); e != "" {
		msg := e
		if desc := r.FormValue(urlParamErrorDescription); desc != "" {
			msg = fmt.Sprintf("%s: %s", msg, desc)
		}
		if uri := r.FormValue(urlParamErrorURI); uri != "" {
			msg = fmt.Sprintf("%s (see %s)", msg, uri)
		}
		http.Error(w, msg, http.StatusForbidden)
		return
	}

	code := r.FormValue(urlParamCode)
	if code == "" {
		http.Error(w, ErrMissingCode.Error(), http.StatusBadRequest)
		return
	}

	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	rsp, err := h.e.Process(r.Context(), c, code)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot process OAuth2 code").Error(), http.StatusForbidden)
		return
	}

	j, err := json.Marshal(rsp)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot marshal JSON").Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	if _, err := w.Write(j); err != nil {
		http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
	}
}

func redirectURL(r *http.Request, endpoint *url.URL) string {
	if r.URL.IsAbs() {
		return fmt.Sprint(r.URL.ResolveReference(endpoint))
	}
	u := &url.URL{}
	u.Scheme = schemeHTTP
	if r.TLS != nil {
		u.Scheme = schemeHTTPS
	}

	for h, v := range r.Header {
		switch h {
		case headerForwardedProto:
			// Redirect to HTTPS if we're listening on HTTP behind an HTTPS ELB.
			for _, proto := range v {
				if proto == schemeHTTPS {
					u.Scheme = schemeHTTPS
				}
			}
		case headerForwardedPrefix:
			// Redirect includes X-Forwarded-Prefix if exists
			for _, prefix := range v {
				u.Path = prefix
			}
		}
	}
	// TODO(negz): Set port if X-Forwarded-Port exists?
	u.Host = r.Host
	return fmt.Sprint(u.ResolveReference(endpoint))
}

// Template returns an HTTP handler that returns a new kubecfg by taking a
// template with existing clusters and adding a user and context for each based
// on the URL parameters passed to it.
func Template(cfg *api.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		r.ParseMultipartForm(templateFormParseMemory) //nolint:errcheck
		p := &extractor.OIDCAuthenticationParams{}

		// TODO(negz): Return an error if any required parameter is absent.
		if err := decoder.Decode(p, r.Form); err != nil {
			http.Error(w, errors.Wrap(err, "cannot parse URL parameter").Error(), http.StatusBadRequest)
			return
		}

		y, err := clientcmd.Write(populateUser(cfg, p))
		if err != nil {
			http.Error(w, errors.Wrap(err, "cannot marshal template to YAML").Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "text/x-yaml; charset=utf-8")
		w.Header().Set("Content-Disposition", "attachment")
		if _, err := w.Write(y); err != nil {
			http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
		}
	}
}

func populateUser(cfg *api.Config, p *extractor.OIDCAuthenticationParams) api.Config {
	c := api.Config{}
	c.AuthInfos = make(map[string]*api.AuthInfo)
	c.Clusters = make(map[string]*api.Cluster)
	c.Contexts = make(map[string]*api.Context)
	c.CurrentContext = cfg.CurrentContext
	c.AuthInfos[p.Username] = &api.AuthInfo{
		AuthProvider: &api.AuthProviderConfig{
			Name: templateAuthProvider,
			Config: map[string]string{
				templateOIDCClientID:     p.ClientID,
				templateOIDCClientSecret: p.ClientSecret,
				templateOIDCIDToken:      p.IDToken,
				templateOIDCRefreshToken: p.RefreshToken,
				templateOIDCIssuer:       p.IssuerURL,
			},
		},
	}

	for name, cluster := range cfg.Clusters {
		// If the cluster definition does not come with certificate-authority-data nor
		// certificate-authority, then check if kuberos has access to the cluster's CA
		// certificate and include it when possible. Assume all errors are non-fatal.
		if len(cluster.CertificateAuthorityData) == 0 && cluster.CertificateAuthority == "" {
			caPath := filepath.Join(DefaultAPITokenMountPath, v1.ServiceAccountRootCAKey)
			if caFile, err := appFs.Open(caPath); err == nil {
				if caCert, err := ioutil.ReadAll(caFile); err == nil {
					cluster.CertificateAuthorityData = caCert
				}
			} else {
				fmt.Printf("Error: %+v\n", err)
			}
		}
		c.Clusters[name] = cluster
		c.Contexts[name] = &api.Context{
			Cluster:  name,
			AuthInfo: p.Username,
		}
	}
	return c
}
<|endoftext|>


<commit_before>package calc

// KurtPop returns the population kurtosis.
func KurtPop(vals []float64) float64 {
	mean := Mean(vals)
	stdDev := StdDevPop(vals)
	sum := 0.0
	for _, val := range vals {
		dev := (val - mean) / stdDev
		dev *= dev
		sum += dev * dev
	}
	n := len(vals)

	// Calculate left factor from its numerator and denominator.
	leftFactorNum := n * (n + 1)
	leftFactorDen := (n - 1) * (n - 2) * (n - 3)
	lf := float64(leftFactorNum) / float64(leftFactorDen)

	// Calculate right addend from its numerator and denominator.
	rightAddendNum := 3 * (n - 1) * (n - 1)
	rightAddendDen := (n - 2) * (n - 3)
	rightAddend := float64(rightAddendNum) / float64(rightAddendDen)

	// Return formula.
	return lf*sum - rightAddend
}
<commit_msg>Removing kurtpop<commit_after><|endoftext|>


<commit_before>// +build gofuzz

// Copyright 2021 Google LLC
//
// 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 transform

import (
	"github.com/gohugoio/hugo/common/loggers"
	"github.com/gohugoio/hugo/config"
	"github.com/gohugoio/hugo/deps"
	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/hugofs"
	"github.com/gohugoio/hugo/langs"
	"github.com/spf13/afero"
	"github.com/spf13/viper"
)

func newFuzzDeps(cfg config.Provider) *deps.Deps {
	cfg.Set("contentDir", "content")
	cfg.Set("i18nDir", "i18n")

	l := langs.NewLanguage("en", cfg)

	cs, _ := helpers.NewContentSpec(l, loggers.NewErrorLogger(), afero.NewMemMapFs())

	return &deps.Deps{
		Cfg:         cfg,
		Fs:          hugofs.NewMem(l),
		ContentSpec: cs,
	}
}

func FuzzMarkdownify(data []byte) int {
	v := viper.New()
	v.Set("contentDir", "content")
	ns := New(newFuzzDeps(v))

	for _, test := range []struct {
		s interface{}
	}{
		{string(data)},
	} {
		_, err := ns.Markdownify(test.s)
		if err != nil {
			return 0
		}
	}
	return 1
}
<commit_msg>[hugo] Fix build (#5946)<commit_after>// +build gofuzz

// Copyright 2021 Google LLC
//
// 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 transform

import (
	"github.com/gohugoio/hugo/common/loggers"
	"github.com/gohugoio/hugo/config"
	"github.com/gohugoio/hugo/deps"
	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/hugofs"
	"github.com/gohugoio/hugo/langs"
	"github.com/spf13/afero"
)

func newFuzzDeps(cfg config.Provider) *deps.Deps {
	cfg.Set("contentDir", "content")
	cfg.Set("i18nDir", "i18n")

	l := langs.NewLanguage("en", cfg)

	cs, _ := helpers.NewContentSpec(l, loggers.NewErrorLogger(), afero.NewMemMapFs())

	return &deps.Deps{
		Cfg:         cfg,
		Fs:          hugofs.NewMem(l),
		ContentSpec: cs,
	}
}

func FuzzMarkdownify(data []byte) int {
	v := config.New()
	v.Set("contentDir", "content")
	ns := New(newFuzzDeps(v))

	for _, test := range []struct {
		s interface{}
	}{
		{string(data)},
	} {
		_, err := ns.Markdownify(test.s)
		if err != nil {
			return 0
		}
	}
	return 1
}
<|endoftext|>


<commit_before>package locking

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/git-lfs/git-lfs/lfsapi"
)

type lockClient struct {
	*lfsapi.Client
}

// LockRequest encapsulates the payload sent across the API when a client would
// like to obtain a lock against a particular path on a given remote.
type lockRequest struct {
	// Path is the path that the client would like to obtain a lock against.
	Path string `json:"path"`
	// LatestRemoteCommit is the SHA of the last known commit from the
	// remote that we are trying to create the lock against, as found in
	// `.git/refs/origin/<name>`.
	LatestRemoteCommit string `json:"latest_remote_commit"`
	// Committer is the individual that wishes to obtain the lock.
	Committer *Committer `json:"committer"`
}

// LockResponse encapsulates the information sent over the API in response to
// a `LockRequest`.
type lockResponse struct {
	// Lock is the Lock that was optionally created in response to the
	// payload that was sent (see above). If the lock already exists, then
	// the existing lock is sent in this field instead, and the author of
	// that lock remains the same, meaning that the client failed to obtain
	// that lock. An HTTP status of "409 - Conflict" is used here.
	//
	// If the lock was unable to be created, this field will hold the
	// zero-value of Lock and the Err field will provide a more detailed set
	// of information.
	//
	// If an error was experienced in creating this lock, then the
	// zero-value of Lock should be sent here instead.
	Lock *Lock `json:"lock"`
	// CommitNeeded holds the minimum commit SHA that client must have to
	// obtain the lock.
	CommitNeeded string `json:"commit_needed,omitempty"`
	// Err is the optional error that was encountered while trying to create
	// the above lock.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) Lock(remote string, lockReq *lockRequest) (*lockResponse, *http.Response, error) {
	e := c.Endpoints.Endpoint("upload", remote)
	req, err := c.NewRequest("POST", e, "locks", lockReq)
	if err != nil {
		return nil, nil, err
	}

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	lockRes := &lockResponse{}
	return lockRes, res, lfsapi.DecodeJSON(res, lockRes)
}

// UnlockRequest encapsulates the data sent in an API request to remove a lock.
type unlockRequest struct {
	// Id is the Id of the lock that the user wishes to unlock.
	Id string `json:"id"`

	// Force determines whether or not the lock should be "forcibly"
	// unlocked; that is to say whether or not a given individual should be
	// able to break a different individual's lock.
	Force bool `json:"force"`
}

// UnlockResponse is the result sent back from the API when asked to remove a
// lock.
type unlockResponse struct {
	// Lock is the lock corresponding to the asked-about lock in the
	// `UnlockPayload` (see above). If no matching lock was found, this
	// field will take the zero-value of Lock, and Err will be non-nil.
	Lock *Lock `json:"lock"`
	// Err is an optional field which holds any error that was experienced
	// while removing the lock.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) Unlock(remote, id string, force bool) (*unlockResponse, *http.Response, error) {
	e := c.Endpoints.Endpoint("upload", remote)
	suffix := fmt.Sprintf("locks/%s/unlock", id)
	req, err := c.NewRequest("POST", e, suffix, &unlockRequest{Id: id, Force: force})
	if err != nil {
		return nil, nil, err
	}

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	unlockRes := &unlockResponse{}
	err = lfsapi.DecodeJSON(res, unlockRes)
	return unlockRes, res, err
}

// Filter represents a single qualifier to apply against a set of locks.
type lockFilter struct {
	// Property is the property to search against.
	// Value is the value that the property must take.
	Property, Value string
}

// LockSearchRequest encapsulates the request sent to the server when the client
// would like a list of locks that match the given criteria.
type lockSearchRequest struct {
	// Filters is the set of filters to query against. If the client wishes
	// to obtain a list of all locks, an empty array should be passed here.
	Filters []lockFilter
	// Cursor is an optional field used to tell the server which lock was
	// seen last, if scanning through multiple pages of results.
	//
	// Servers must return a list of locks sorted in reverse chronological
	// order, so the Cursor provides a consistent method of viewing all
	// locks, even if more were created between two requests.
	Cursor string
	// Limit is the maximum number of locks to return in a single page.
	Limit int
}

func (r *lockSearchRequest) QueryValues() map[string]string {
	q := make(map[string]string)
	for _, filter := range r.Filters {
		q[filter.Property] = filter.Value
	}

	if len(r.Cursor) > 0 {
		q["cursor"] = r.Cursor
	}

	if r.Limit > 0 {
		q["limit"] = strconv.Itoa(r.Limit)
	}

	return q
}

// LockList encapsulates a set of Locks.
type lockList struct {
	// Locks is the set of locks returned back, typically matching the query
	// parameters sent in the LockListRequest call. If no locks were matched
	// from a given query, then `Locks` will be represented as an empty
	// array.
	Locks []Lock `json:"locks"`
	// NextCursor returns the Id of the Lock the client should update its
	// cursor to, if there are multiple pages of results for a particular
	// `LockListRequest`.
	NextCursor string `json:"next_cursor,omitempty"`
	// Err populates any error that was encountered during the search. If no
	// error was encountered and the operation was succesful, then a value
	// of nil will be passed here.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) Search(remote string, searchReq *lockSearchRequest) (*lockList, *http.Response, error) {
	e := c.Endpoints.Endpoint("upload", remote)
	req, err := c.NewRequest("GET", e, "locks", nil)
	if err != nil {
		return nil, nil, err
	}

	q := req.URL.Query()
	for key, value := range searchReq.QueryValues() {
		q.Add(key, value)
	}
	req.URL.RawQuery = q.Encode()

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	locks := &lockList{}
	if res.StatusCode == http.StatusOK {
		err = lfsapi.DecodeJSON(res, locks)
	}

	return locks, res, err
}

// lockVerifiableRequest encapsulates the request sent to the server when the
// client would like a list of locks to verify a Git push.
type lockVerifiableRequest struct {
	// Cursor is an optional field used to tell the server which lock was
	// seen last, if scanning through multiple pages of results.
	//
	// Servers must return a list of locks sorted in reverse chronological
	// order, so the Cursor provides a consistent method of viewing all
	// locks, even if more were created between two requests.
	Cursor string `json:"cursor,omitempty"`
	// Limit is the maximum number of locks to return in a single page.
	Limit int `json:"limit,omitempty"`
}

// lockVerifiableList encapsulates a set of Locks to verify a Git push.
type lockVerifiableList struct {
	// Ours is the set of locks returned back matching filenames that the user
	// is allowed to edit.
	Ours []Lock `json:"ours"`

	// Their is the set of locks returned back matching filenames that the user
	// is NOT allowed to edit. Any edits matching these files should reject
	// the Git push.
	Theirs []Lock `json:"theirs"`

	// NextCursor returns the Id of the Lock the client should update its
	// cursor to, if there are multiple pages of results for a particular
	// `LockListRequest`.
	NextCursor string `json:"next_cursor,omitempty"`
	// Err populates any error that was encountered during the search. If no
	// error was encountered and the operation was succesful, then a value
	// of nil will be passed here.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) SearchVerifiable(remote string, vreq *lockVerifiableRequest) (*lockVerifiableList, *http.Response, error) {
	e := c.Endpoints.Endpoint("download", remote)
	req, err := c.NewRequest("POST", e, "locks/verify", vreq)
	if err != nil {
		return nil, nil, err
	}

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	locks := &lockVerifiableList{}
	if res.StatusCode == http.StatusOK {
		err = lfsapi.DecodeJSON(res, locks)
	}

	return locks, res, err
}

// Committer represents a "First Last <email@domain.com>" pair.
type Committer struct {
	// Name is the name of the individual who would like to obtain the
	// lock, for instance: "Rick Olson".
	Name string `json:"name"`
	// Email is the email assopsicated with the individual who would
	// like to obtain the lock, for instance: "rick@github.com".
	Email string `json:"email"`
}

func NewCommitter(name, email string) *Committer {
	return &Committer{Name: name, Email: email}
}

// String implements the fmt.Stringer interface by returning a string
// representation of the Committer in the format "First Last <email>".
func (c *Committer) String() string {
	return fmt.Sprintf("%s <%s>", c.Name, c.Email)
}
<commit_msg>locking: ensure verifiable locks call is made with the correct operation<commit_after>package locking

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/git-lfs/git-lfs/lfsapi"
)

type lockClient struct {
	*lfsapi.Client
}

// LockRequest encapsulates the payload sent across the API when a client would
// like to obtain a lock against a particular path on a given remote.
type lockRequest struct {
	// Path is the path that the client would like to obtain a lock against.
	Path string `json:"path"`
	// LatestRemoteCommit is the SHA of the last known commit from the
	// remote that we are trying to create the lock against, as found in
	// `.git/refs/origin/<name>`.
	LatestRemoteCommit string `json:"latest_remote_commit"`
	// Committer is the individual that wishes to obtain the lock.
	Committer *Committer `json:"committer"`
}

// LockResponse encapsulates the information sent over the API in response to
// a `LockRequest`.
type lockResponse struct {
	// Lock is the Lock that was optionally created in response to the
	// payload that was sent (see above). If the lock already exists, then
	// the existing lock is sent in this field instead, and the author of
	// that lock remains the same, meaning that the client failed to obtain
	// that lock. An HTTP status of "409 - Conflict" is used here.
	//
	// If the lock was unable to be created, this field will hold the
	// zero-value of Lock and the Err field will provide a more detailed set
	// of information.
	//
	// If an error was experienced in creating this lock, then the
	// zero-value of Lock should be sent here instead.
	Lock *Lock `json:"lock"`
	// CommitNeeded holds the minimum commit SHA that client must have to
	// obtain the lock.
	CommitNeeded string `json:"commit_needed,omitempty"`
	// Err is the optional error that was encountered while trying to create
	// the above lock.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) Lock(remote string, lockReq *lockRequest) (*lockResponse, *http.Response, error) {
	e := c.Endpoints.Endpoint("upload", remote)
	req, err := c.NewRequest("POST", e, "locks", lockReq)
	if err != nil {
		return nil, nil, err
	}

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	lockRes := &lockResponse{}
	return lockRes, res, lfsapi.DecodeJSON(res, lockRes)
}

// UnlockRequest encapsulates the data sent in an API request to remove a lock.
type unlockRequest struct {
	// Id is the Id of the lock that the user wishes to unlock.
	Id string `json:"id"`

	// Force determines whether or not the lock should be "forcibly"
	// unlocked; that is to say whether or not a given individual should be
	// able to break a different individual's lock.
	Force bool `json:"force"`
}

// UnlockResponse is the result sent back from the API when asked to remove a
// lock.
type unlockResponse struct {
	// Lock is the lock corresponding to the asked-about lock in the
	// `UnlockPayload` (see above). If no matching lock was found, this
	// field will take the zero-value of Lock, and Err will be non-nil.
	Lock *Lock `json:"lock"`
	// Err is an optional field which holds any error that was experienced
	// while removing the lock.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) Unlock(remote, id string, force bool) (*unlockResponse, *http.Response, error) {
	e := c.Endpoints.Endpoint("upload", remote)
	suffix := fmt.Sprintf("locks/%s/unlock", id)
	req, err := c.NewRequest("POST", e, suffix, &unlockRequest{Id: id, Force: force})
	if err != nil {
		return nil, nil, err
	}

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	unlockRes := &unlockResponse{}
	err = lfsapi.DecodeJSON(res, unlockRes)
	return unlockRes, res, err
}

// Filter represents a single qualifier to apply against a set of locks.
type lockFilter struct {
	// Property is the property to search against.
	// Value is the value that the property must take.
	Property, Value string
}

// LockSearchRequest encapsulates the request sent to the server when the client
// would like a list of locks that match the given criteria.
type lockSearchRequest struct {
	// Filters is the set of filters to query against. If the client wishes
	// to obtain a list of all locks, an empty array should be passed here.
	Filters []lockFilter
	// Cursor is an optional field used to tell the server which lock was
	// seen last, if scanning through multiple pages of results.
	//
	// Servers must return a list of locks sorted in reverse chronological
	// order, so the Cursor provides a consistent method of viewing all
	// locks, even if more were created between two requests.
	Cursor string
	// Limit is the maximum number of locks to return in a single page.
	Limit int
}

func (r *lockSearchRequest) QueryValues() map[string]string {
	q := make(map[string]string)
	for _, filter := range r.Filters {
		q[filter.Property] = filter.Value
	}

	if len(r.Cursor) > 0 {
		q["cursor"] = r.Cursor
	}

	if r.Limit > 0 {
		q["limit"] = strconv.Itoa(r.Limit)
	}

	return q
}

// LockList encapsulates a set of Locks.
type lockList struct {
	// Locks is the set of locks returned back, typically matching the query
	// parameters sent in the LockListRequest call. If no locks were matched
	// from a given query, then `Locks` will be represented as an empty
	// array.
	Locks []Lock `json:"locks"`
	// NextCursor returns the Id of the Lock the client should update its
	// cursor to, if there are multiple pages of results for a particular
	// `LockListRequest`.
	NextCursor string `json:"next_cursor,omitempty"`
	// Err populates any error that was encountered during the search. If no
	// error was encountered and the operation was succesful, then a value
	// of nil will be passed here.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) Search(remote string, searchReq *lockSearchRequest) (*lockList, *http.Response, error) {
	e := c.Endpoints.Endpoint("upload", remote)
	req, err := c.NewRequest("GET", e, "locks", nil)
	if err != nil {
		return nil, nil, err
	}

	q := req.URL.Query()
	for key, value := range searchReq.QueryValues() {
		q.Add(key, value)
	}
	req.URL.RawQuery = q.Encode()

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	locks := &lockList{}
	if res.StatusCode == http.StatusOK {
		err = lfsapi.DecodeJSON(res, locks)
	}

	return locks, res, err
}

// lockVerifiableRequest encapsulates the request sent to the server when the
// client would like a list of locks to verify a Git push.
type lockVerifiableRequest struct {
	// Cursor is an optional field used to tell the server which lock was
	// seen last, if scanning through multiple pages of results.
	//
	// Servers must return a list of locks sorted in reverse chronological
	// order, so the Cursor provides a consistent method of viewing all
	// locks, even if more were created between two requests.
	Cursor string `json:"cursor,omitempty"`
	// Limit is the maximum number of locks to return in a single page.
	Limit int `json:"limit,omitempty"`
}

// lockVerifiableList encapsulates a set of Locks to verify a Git push.
type lockVerifiableList struct {
	// Ours is the set of locks returned back matching filenames that the user
	// is allowed to edit.
	Ours []Lock `json:"ours"`

	// Their is the set of locks returned back matching filenames that the user
	// is NOT allowed to edit. Any edits matching these files should reject
	// the Git push.
	Theirs []Lock `json:"theirs"`

	// NextCursor returns the Id of the Lock the client should update its
	// cursor to, if there are multiple pages of results for a particular
	// `LockListRequest`.
	NextCursor string `json:"next_cursor,omitempty"`
	// Err populates any error that was encountered during the search. If no
	// error was encountered and the operation was succesful, then a value
	// of nil will be passed here.
	Err string `json:"error,omitempty"`
}

func (c *lockClient) SearchVerifiable(remote string, vreq *lockVerifiableRequest) (*lockVerifiableList, *http.Response, error) {
	e := c.Endpoints.Endpoint("upload", remote)
	req, err := c.NewRequest("POST", e, "locks/verify", vreq)
	if err != nil {
		return nil, nil, err
	}

	res, err := c.DoWithAuth(remote, req)
	if err != nil {
		return nil, res, err
	}

	locks := &lockVerifiableList{}
	if res.StatusCode == http.StatusOK {
		err = lfsapi.DecodeJSON(res, locks)
	}

	return locks, res, err
}

// Committer represents a "First Last <email@domain.com>" pair.
type Committer struct {
	// Name is the name of the individual who would like to obtain the
	// lock, for instance: "Rick Olson".
	Name string `json:"name"`
	// Email is the email assopsicated with the individual who would
	// like to obtain the lock, for instance: "rick@github.com".
	Email string `json:"email"`
}

func NewCommitter(name, email string) *Committer {
	return &Committer{Name: name, Email: email}
}

// String implements the fmt.Stringer interface by returning a string
// representation of the Committer in the format "First Last <email>".
func (c *Committer) String() string {
	return fmt.Sprintf("%s <%s>", c.Name, c.Email)
}
<|endoftext|>


<commit_before>package golog

import (
	"bytes"
	"fmt"
	"path"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type LogMessage struct {
	Level       int
	Nanoseconds int64
	Message     string
	// A map from the type of metadata to the metadata, if present.
	// By convention, fields in this map will be entirely lowercase and
	// single word.
	Metadata map[string]string
}

// TODO(awreece) comment this
// Skip 0 refers to the function calling getLocation.
type MakeMetadataFunc func(skip int) map[string]string

// Return a nil LogLocation.
func NoLocation(skip int) map[string]string { return make(map[string]string) }

// Walks up the stack skip frames and returns the LogLocation for that frame.
// TODO(awreece) Provide a arg to select which fields to produce?
func FullLocation(skip int) map[string]string {
	pc, file, line, ok := runtime.Caller(skip + 1)
	if !ok {
		// TODO add timestamp.
		return make(map[string]string)
	} else {
		// TODO(awreece) Make sure this is compiler agnostic.
		funcParts := strings.SplitN(runtime.FuncForPC(pc).Name(), ".", 2)
		// TODO add timestamp.
		return map[string]string{
			"package":  funcParts[0],
			"file": path.Base(file),
			"function": funcParts[1],
			"line": strconv.Itoa(line),
		}
	}

	panic("Flow never reaches here, this mollifies the compiler")
}

// Render the formatted metadata to the buffer. If all present, format is
// "{time} {pack}.{func}/{file}:{line}". If some fields omitted, intelligently
// delimits the remaining fields.
func renderMetadata(buf *bytes.Buffer, m *LogMessage) {
	if m == nil {
		// TODO Panic here?
		return
	}

	t := time.NanosecondsToLocalTime(m.Nanoseconds)
	buf.WriteString(t.Format(" 15:04:05.000000"))

	packName, packPresent := m.Metadata["package"]
	file, filePresent := m.Metadata["file"]
	funcName, funcPresent := m.Metadata["function"]
	line, linePresent := m.Metadata["line"]

	if packPresent || filePresent || funcPresent || linePresent {
		buf.WriteString(" ")
	}

	// TODO(awreece) This logic is terrifying.
	if packPresent {
		buf.WriteString(packName)
	}
	if funcPresent {
		if packPresent {
			buf.WriteString(".")
		}
		buf.WriteString(funcName)
	}
	if (packPresent || funcPresent) && (filePresent || linePresent) {
		buf.WriteString("/")
	}
	if filePresent {
		buf.WriteString(file)
	}
	if linePresent {
		if filePresent {
			buf.WriteString(":")
		}
		buf.WriteString(line)
	}
}

// Format the message as a string, optionally inserting a newline.
// Format is: "L{level} {time} {pack}.{func}/{file}:{line}] {message}"
func formatLogMessage(m *LogMessage, insertNewline bool) string {
	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("L%d", m.Level))
	renderMetadata(&buf, m)
	buf.WriteString("] ")
	buf.WriteString(m.Message)
	if insertNewline {
		buf.WriteString("\n")
	}
	return buf.String()
}
<commit_msg>More coherent comments<commit_after>package golog

import (
	"bytes"
	"fmt"
	"path"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type LogMessage struct {
	Level       int
	Nanoseconds int64
	Message     string
	// A map from the type of metadata to the metadata, if present.
	// By convention, fields in this map will be entirely lowercase and
	// single word.
	Metadata map[string]string
}

// TODO(awreece) comment this
// Skip 0 refers to the function calling this function.
type MakeMetadataFunc func(skip int) map[string]string

// Return a nil LogLocation.
func NoLocation(skip int) map[string]string { return make(map[string]string) }

// Walks up the stack skip frames and returns the metatdata for that frame.
// TODO(awreece) Provide a arg to select which fields to produce?
func FullLocation(skip int) map[string]string {
	pc, file, line, ok := runtime.Caller(skip + 1)
	if !ok {
		// TODO add timestamp.
		return make(map[string]string)
	} else {
		// TODO(awreece) Make sure this is compiler agnostic.
		funcParts := strings.SplitN(runtime.FuncForPC(pc).Name(), ".", 2)
		// TODO add timestamp.
		return map[string]string{
			"package":  funcParts[0],
			"file": path.Base(file),
			"function": funcParts[1],
			"line": strconv.Itoa(line),
		}
	}

	panic("Flow never reaches here, this mollifies the compiler")
}

// Render the formatted metadata to the buffer. If all present, format is
// "{time} {pack}.{func}/{file}:{line}". If some fields omitted, intelligently
// delimits the remaining fields.
func renderMetadata(buf *bytes.Buffer, m *LogMessage) {
	if m == nil {
		// TODO Panic here?
		return
	}

	t := time.NanosecondsToLocalTime(m.Nanoseconds)
	buf.WriteString(t.Format(" 15:04:05.000000"))

	packName, packPresent := m.Metadata["package"]
	file, filePresent := m.Metadata["file"]
	funcName, funcPresent := m.Metadata["function"]
	line, linePresent := m.Metadata["line"]

	if packPresent || filePresent || funcPresent || linePresent {
		buf.WriteString(" ")
	}

	// TODO(awreece) This logic is terrifying.
	if packPresent {
		buf.WriteString(packName)
	}
	if funcPresent {
		if packPresent {
			buf.WriteString(".")
		}
		buf.WriteString(funcName)
	}
	if (packPresent || funcPresent) && (filePresent || linePresent) {
		buf.WriteString("/")
	}
	if filePresent {
		buf.WriteString(file)
	}
	if linePresent {
		if filePresent {
			buf.WriteString(":")
		}
		buf.WriteString(line)
	}
}

// Format the message as a string, optionally inserting a newline.
// Format is: "L{level} {time} {pack}.{func}/{file}:{line}] {message}"
func formatLogMessage(m *LogMessage, insertNewline bool) string {
	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("L%d", m.Level))
	renderMetadata(&buf, m)
	buf.WriteString("] ")
	buf.WriteString(m.Message)
	if insertNewline {
		buf.WriteString("\n")
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package fake

import "strings"

// Character generates random character in the given language
func Character() string {
	return lookup(lang, "characters", true)
}

// CharactersN generates n random characters in the given language
func CharactersN(n int) string {
	var chars []string
	for i := 0; i < n; i++ {
		chars = append(chars, Character())
	}
	return strings.Join(chars, "")
}

// Characters generates from 1 to 5 characters in the given language
func Characters() string {
	return CharactersN(r.Intn(5) + 1)
}

// Word generates random word
func Word() string {
	return lookup(lang, "words", true)
}

// WordsN generates n random words
func WordsN(n int) string {
	words := make([]string, n)
	for i := 0; i < n; i++ {
		words[i] = Word()
	}
	return strings.Join(words, " ")
}

func containsWord(words []string, word string) bool {
	for _, w := range words {
		if w == word {
			return true
		}
	}
	return false
}

// WordsNUnique generates n unique random words
func WordsNUnique(n int) []string {
	words := make([]string, n)
	word := Word()
	for i := 0; i < n; {
		if word != "" && !containsWord(words, word) {
			words[i] = word
			i++
			word = ""
		}
		word = word + Word()
	}
	return words
}

// Words generates from 1 to 5 random words
func Words() string {
	return WordsN(r.Intn(5) + 1)
}

// Title generates from 2 to 5 titleized words
func Title() string {
	return strings.ToTitle(WordsN(2 + r.Intn(4)))
}

// Sentence generates random sentence
func Sentence() string {
	var words []string
	for i := 0; i < 3+r.Intn(12); i++ {
		word := Word()
		if r.Intn(5) == 0 {
			word += ","
		}
		words = append(words, Word())
	}

	sentence := strings.Join(words, " ")

	if r.Intn(8) == 0 {
		sentence += "!"
	} else {
		sentence += "."
	}

	return sentence
}

// SentencesN generates n random sentences
func SentencesN(n int) string {
	sentences := make([]string, n)
	for i := 0; i < n; i++ {
		sentences[i] = Sentence()
	}
	return strings.Join(sentences, " ")
}

// Sentences generates from 1 to 5 random sentences
func Sentences() string {
	return SentencesN(r.Intn(5) + 1)
}

// Paragraph generates paragraph
func Paragraph() string {
	return SentencesN(r.Intn(10) + 1)
}

// ParagraphsN generates n paragraphs
func ParagraphsN(n int) string {
	var paragraphs []string
	for i := 0; i < n; i++ {
		paragraphs = append(paragraphs, Paragraph())
	}
	return strings.Join(paragraphs, "\t")
}

// Paragraphs generates from 1 to 5 paragraphs
func Paragraphs() string {
	return ParagraphsN(r.Intn(5) + 1)
}
<commit_msg>Fix random comma insertion in Sentence()<commit_after>package fake

import "strings"

// Character generates random character in the given language
func Character() string {
	return lookup(lang, "characters", true)
}

// CharactersN generates n random characters in the given language
func CharactersN(n int) string {
	var chars []string
	for i := 0; i < n; i++ {
		chars = append(chars, Character())
	}
	return strings.Join(chars, "")
}

// Characters generates from 1 to 5 characters in the given language
func Characters() string {
	return CharactersN(r.Intn(5) + 1)
}

// Word generates random word
func Word() string {
	return lookup(lang, "words", true)
}

// WordsN generates n random words
func WordsN(n int) string {
	words := make([]string, n)
	for i := 0; i < n; i++ {
		words[i] = Word()
	}
	return strings.Join(words, " ")
}

func containsWord(words []string, word string) bool {
	for _, w := range words {
		if w == word {
			return true
		}
	}
	return false
}

// WordsNUnique generates n unique random words
func WordsNUnique(n int) []string {
	words := make([]string, n)
	word := Word()
	for i := 0; i < n; {
		if word != "" && !containsWord(words, word) {
			words[i] = word
			i++
			word = ""
		}
		word = word + Word()
	}
	return words
}

// Words generates from 1 to 5 random words
func Words() string {
	return WordsN(r.Intn(5) + 1)
}

// Title generates from 2 to 5 titleized words
func Title() string {
	return strings.ToTitle(WordsN(2 + r.Intn(4)))
}

// Sentence generates random sentence
func Sentence() string {
	var words []string
	for i := 0; i < 3+r.Intn(12); i++ {
		word := Word()
		if r.Intn(5) == 0 {
			word += ","
		}
		words = append(words, word)
	}

	sentence := strings.Join(words, " ")

	if r.Intn(8) == 0 {
		sentence += "!"
	} else {
		sentence += "."
	}

	return sentence
}

// SentencesN generates n random sentences
func SentencesN(n int) string {
	sentences := make([]string, n)
	for i := 0; i < n; i++ {
		sentences[i] = Sentence()
	}
	return strings.Join(sentences, " ")
}

// Sentences generates from 1 to 5 random sentences
func Sentences() string {
	return SentencesN(r.Intn(5) + 1)
}

// Paragraph generates paragraph
func Paragraph() string {
	return SentencesN(r.Intn(10) + 1)
}

// ParagraphsN generates n paragraphs
func ParagraphsN(n int) string {
	var paragraphs []string
	for i := 0; i < n; i++ {
		paragraphs = append(paragraphs, Paragraph())
	}
	return strings.Join(paragraphs, "\t")
}

// Paragraphs generates from 1 to 5 paragraphs
func Paragraphs() string {
	return ParagraphsN(r.Intn(5) + 1)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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 integration

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"testing"

	"github.com/blang/semver"

	"k8s.io/minikube/pkg/drivers"
)

func TestDriverInstallOrUpdate(t *testing.T) {
	if NoneDriver() {
		t.Skip("Skip none driver.")
	}

	if runtime.GOOS != "linux" {
		t.Skip("Skip if not linux.")
	}
	MaybeParallel(t)

	tests := []struct {
		name string
		path string
	}{
		{name: "driver-without-version-support", path: filepath.Join(*testdataDir, "kvm2-driver-without-version")},
		{name: "driver-with-older-version", path: filepath.Join(*testdataDir, "kvm2-driver-without-version")},
	}

	originalPath := os.Getenv("PATH")
	defer os.Setenv("PATH", originalPath)

	for _, tc := range tests {
		dir, err := ioutil.TempDir("", tc.name)
		if err != nil {
			t.Fatalf("Expected to create tempdir. test: %s, got: %v", tc.name, err)
		}
		defer os.RemoveAll(dir)

		pwd, err := os.Getwd()
		if err != nil {
			t.Fatalf("Error not expected when getting working directory. test: %s, got: %v", tc.name, err)
		}

		path := filepath.Join(pwd, tc.path)

		_, err = os.Stat(filepath.Join(path, "docker-machine-driver-kvm2"))
		if err != nil {
			t.Fatalf("Expected driver to exist. test: %s, got: %v", tc.name, err)
		}

		// change permission to allow driver to be executable
		err = os.Chmod(filepath.Join(path, "docker-machine-driver-kvm2"), 0777)
		if err != nil {
			t.Fatalf("Expected not expected when changing driver permission. test: %s, got: %v", tc.name, err)
		}

		os.Setenv("PATH", fmt.Sprintf("%s:%s", path, originalPath))

		newerVersion, err := semver.Make("1.1.3")
		if err != nil {
			t.Fatalf("Expected new semver. test: %v, got: %v", tc.name, err)
		}

		err = drivers.InstallOrUpdate("docker-machine-driver-kvm2", dir, newerVersion)
		if err != nil {
			t.Fatalf("Expected to update driver. test: %s, got: %v", tc.name, err)
		}

		_, err = os.Stat(filepath.Join(dir, "docker-machine-driver-kvm2"))
		if err != nil {
			t.Fatalf("Expected driver to be download. test: %s, got: %v", tc.name, err)
		}
	}
}
<commit_msg>Stricter permissions<commit_after>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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 integration

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"testing"

	"github.com/blang/semver"

	"k8s.io/minikube/pkg/drivers"
)

func TestDriverInstallOrUpdate(t *testing.T) {
	if NoneDriver() {
		t.Skip("Skip none driver.")
	}

	if runtime.GOOS != "linux" {
		t.Skip("Skip if not linux.")
	}
	MaybeParallel(t)

	tests := []struct {
		name string
		path string
	}{
		{name: "driver-without-version-support", path: filepath.Join(*testdataDir, "kvm2-driver-without-version")},
		{name: "driver-with-older-version", path: filepath.Join(*testdataDir, "kvm2-driver-without-version")},
	}

	originalPath := os.Getenv("PATH")
	defer os.Setenv("PATH", originalPath)

	for _, tc := range tests {
		dir, err := ioutil.TempDir("", tc.name)
		if err != nil {
			t.Fatalf("Expected to create tempdir. test: %s, got: %v", tc.name, err)
		}
		defer os.RemoveAll(dir)

		pwd, err := os.Getwd()
		if err != nil {
			t.Fatalf("Error not expected when getting working directory. test: %s, got: %v", tc.name, err)
		}

		path := filepath.Join(pwd, tc.path)

		_, err = os.Stat(filepath.Join(path, "docker-machine-driver-kvm2"))
		if err != nil {
			t.Fatalf("Expected driver to exist. test: %s, got: %v", tc.name, err)
		}

		// change permission to allow driver to be executable
		err = os.Chmod(filepath.Join(path, "docker-machine-driver-kvm2"), 0700)
		if err != nil {
			t.Fatalf("Expected not expected when changing driver permission. test: %s, got: %v", tc.name, err)
		}

		os.Setenv("PATH", fmt.Sprintf("%s:%s", path, originalPath))

		newerVersion, err := semver.Make("1.1.3")
		if err != nil {
			t.Fatalf("Expected new semver. test: %v, got: %v", tc.name, err)
		}

		err = drivers.InstallOrUpdate("docker-machine-driver-kvm2", dir, newerVersion)
		if err != nil {
			t.Fatalf("Expected to update driver. test: %s, got: %v", tc.name, err)
		}

		_, err = os.Stat(filepath.Join(dir, "docker-machine-driver-kvm2"))
		if err != nil {
			t.Fatalf("Expected driver to be download. test: %s, got: %v", tc.name, err)
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Rename BuildResult to something more fluent<commit_after><|endoftext|>


<commit_before><commit_msg>Baseline blog structure<commit_after><|endoftext|>


<commit_before>package astilectron

import (
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/asticode/go-astilog"
	"github.com/asticode/go-astitools/context"
	"github.com/asticode/go-astitools/exec"
	"github.com/pkg/errors"
)

// Versions
const (
	DefaultAcceptTCPTimeout = 30 * time.Second
	VersionAstilectron      = "0.29.0"
	VersionElectron         = "4.0.1"
)

// Misc vars
var (
	validOSes = map[string]bool{
		"darwin":  true,
		"linux":   true,
		"windows": true,
	}
)

// App event names
const (
	EventNameAppClose         = "app.close"
	EventNameAppCmdQuit       = "app.cmd.quit" // Sends an event to Electron to properly quit the app
	EventNameAppCmdStop       = "app.cmd.stop" // Cancel the context which results in exiting abruptly Electron's app
	EventNameAppCrash         = "app.crash"
	EventNameAppErrorAccept   = "app.error.accept"
	EventNameAppEventReady    = "app.event.ready"
	EventNameAppNoAccept      = "app.no.accept"
	EventNameAppTooManyAccept = "app.too.many.accept"
)

// Astilectron represents an object capable of interacting with Astilectron
type Astilectron struct {
	canceller    *asticontext.Canceller
	channelQuit  chan bool
	closeOnce    sync.Once
	dispatcher   *dispatcher
	displayPool  *displayPool
	dock         *Dock
	executer     Executer
	identifier   *identifier
	listener     net.Listener
	options      Options
	paths        *Paths
	provisioner  Provisioner
	reader       *reader
	stderrWriter *astiexec.StdWriter
	stdoutWriter *astiexec.StdWriter
	supported    *Supported
	writer       *writer
}

// Options represents Astilectron options
type Options struct {
	AcceptTCPTimeout   time.Duration
	AppName            string
	AppIconDarwinPath  string // Darwin systems requires a specific .icns file
	AppIconDefaultPath string
	BaseDirectoryPath  string
	DataDirectoryPath  string
	ElectronSwitches   []string
	SingleInstance     bool
}

// Supported represents Astilectron supported features
type Supported struct {
	Notification *bool `json:"notification"`
}

// New creates a new Astilectron instance
func New(o Options) (a *Astilectron, err error) {
	// Validate the OS
	if !IsValidOS(runtime.GOOS) {
		err = errors.Wrapf(err, "OS %s is invalid", runtime.GOOS)
		return
	}

	// Init
	a = &Astilectron{
		canceller:   asticontext.NewCanceller(),
		channelQuit: make(chan bool),
		dispatcher:  newDispatcher(),
		displayPool: newDisplayPool(),
		executer:    DefaultExecuter,
		identifier:  newIdentifier(),
		options:     o,
		provisioner: DefaultProvisioner,
	}

	// Set paths
	if a.paths, err = newPaths(runtime.GOOS, runtime.GOARCH, o); err != nil {
		err = errors.Wrap(err, "creating new paths failed")
		return
	}

	// Add default listeners
	a.On(EventNameAppCmdStop, func(e Event) (deleteListener bool) {
		a.Stop()
		return
	})
	a.On(EventNameDisplayEventAdded, func(e Event) (deleteListener bool) {
		a.displayPool.update(e.Displays)
		return
	})
	a.On(EventNameDisplayEventMetricsChanged, func(e Event) (deleteListener bool) {
		a.displayPool.update(e.Displays)
		return
	})
	a.On(EventNameDisplayEventRemoved, func(e Event) (deleteListener bool) {
		a.displayPool.update(e.Displays)
		return
	})
	return
}

// IsValidOS validates the OS
func IsValidOS(os string) (ok bool) {
	_, ok = validOSes[os]
	return
}

// SetProvisioner sets the provisioner
func (a *Astilectron) SetProvisioner(p Provisioner) *Astilectron {
	a.provisioner = p
	return a
}

// SetExecuter sets the executer
func (a *Astilectron) SetExecuter(e Executer) *Astilectron {
	a.executer = e
	return a
}

// On implements the Listenable interface
func (a *Astilectron) On(eventName string, l Listener) {
	a.dispatcher.addListener(targetIDApp, eventName, l)
}

// Start starts Astilectron
func (a *Astilectron) Start() (err error) {
	// Log
	astilog.Debug("Starting...")

	// Provision
	if err = a.provision(); err != nil {
		return errors.Wrap(err, "provisioning failed")
	}

	// Unfortunately communicating with Electron through stdin/stdout doesn't work on Windows so all communications
	// will be done through TCP
	if err = a.listenTCP(); err != nil {
		return errors.Wrap(err, "listening failed")
	}

	// Execute
	if err = a.execute(); err != nil {
		err = errors.Wrap(err, "executing failed")
		return
	}
	return
}

// provision provisions Astilectron
func (a *Astilectron) provision() error {
	astilog.Debug("Provisioning...")
	var ctx, _ = a.canceller.NewContext()
	return a.provisioner.Provision(ctx, a.options.AppName, runtime.GOOS, runtime.GOARCH, *a.paths)
}

// listenTCP listens to the first TCP connection coming its way (this should be Astilectron)
func (a *Astilectron) listenTCP() (err error) {
	// Log
	astilog.Debug("Listening...")

	// Listen
	if a.listener, err = net.Listen("tcp", "127.0.0.1:"); err != nil {
		return errors.Wrap(err, "tcp net.Listen failed")
	}

	// Check a connection has been accepted quickly enough
	var chanAccepted = make(chan bool)
	go a.watchNoAccept(a.options.AcceptTCPTimeout, chanAccepted)

	// Accept connections
	go a.acceptTCP(chanAccepted)
	return
}

// watchNoAccept checks whether a TCP connection is accepted quickly enough
func (a *Astilectron) watchNoAccept(timeout time.Duration, chanAccepted chan bool) {
	//check timeout
	if timeout == 0 {
		timeout = DefaultAcceptTCPTimeout
	}
	var t = time.NewTimer(timeout)
	defer t.Stop()
	for {
		select {
		case <-chanAccepted:
			return
		case <-t.C:
			astilog.Errorf("No TCP connection has been accepted in the past %s", timeout)
			a.dispatcher.dispatch(Event{Name: EventNameAppNoAccept, TargetID: targetIDApp})
			a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
			return
		}
	}
}

// watchAcceptTCP accepts TCP connections
func (a *Astilectron) acceptTCP(chanAccepted chan bool) {
	for i := 0; i <= 1; i++ {
		// Accept
		var conn net.Conn
		var err error
		if conn, err = a.listener.Accept(); err != nil {
			astilog.Errorf("%s while TCP accepting", err)
			a.dispatcher.dispatch(Event{Name: EventNameAppErrorAccept, TargetID: targetIDApp})
			a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
			return
		}

		// We only accept the first connection which should be Astilectron, close the next one and stop
		// the app
		if i > 0 {
			astilog.Errorf("Too many TCP connections")
			a.dispatcher.dispatch(Event{Name: EventNameAppTooManyAccept, TargetID: targetIDApp})
			a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
			conn.Close()
			return
		}

		// Let the timer know a connection has been accepted
		chanAccepted <- true

		// Create reader and writer
		a.writer = newWriter(conn)
		ctx, _ := a.canceller.NewContext()
		a.reader = newReader(ctx, a.dispatcher, conn)
		go a.reader.read()
	}
}

// execute executes Astilectron in Electron
func (a *Astilectron) execute() (err error) {
	// Log
	astilog.Debug("Executing...")

	// Create command
	var ctx, _ = a.canceller.NewContext()
	var singleInstance string
	if a.options.SingleInstance == true {
		singleInstance = "true"
	} else {
		singleInstance = "false"
	}
	var cmd = exec.CommandContext(ctx, a.paths.AppExecutable(), append([]string{a.paths.AstilectronApplication(), a.listener.Addr().String(), singleInstance}, a.options.ElectronSwitches...)...)
	a.stderrWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stderr says: %s", i) })
	a.stdoutWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stdout says: %s", i) })
	cmd.Stderr = a.stderrWriter
	cmd.Stdout = a.stdoutWriter

	// Execute command
	if err = a.executeCmd(cmd); err != nil {
		return errors.Wrap(err, "executing cmd failed")
	}
	return
}

// executeCmd executes the command
func (a *Astilectron) executeCmd(cmd *exec.Cmd) (err error) {
	var e = synchronousFunc(a.canceller, a, func() {
		err = a.executer(a, cmd)
	}, EventNameAppEventReady)

	// Update display pool
	if e.Displays != nil {
		a.displayPool.update(e.Displays)
	}

	// Create dock
	a.dock = newDock(a.canceller, a.dispatcher, a.identifier, a.writer)

	// Update supported features
	a.supported = e.Supported
	return
}

// watchCmd watches the cmd execution
func (a *Astilectron) watchCmd(cmd *exec.Cmd) {
	// Wait
	cmd.Wait()

	// Check the canceller to check whether it was a crash
	if !a.canceller.Cancelled() {
		astilog.Debug("App has crashed")
		a.dispatcher.dispatch(Event{Name: EventNameAppCrash, TargetID: targetIDApp})
	} else {
		astilog.Debug("App has closed")
		a.dispatcher.dispatch(Event{Name: EventNameAppClose, TargetID: targetIDApp})
	}
	a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
}

// Close closes Astilectron properly
func (a *Astilectron) Close() {
	astilog.Debug("Closing...")
	a.canceller.Cancel()
	if a.listener != nil {
		a.listener.Close()
	}
	if a.reader != nil {
		a.reader.close()
	}
	if a.stderrWriter != nil {
		a.stderrWriter.Close()
	}
	if a.stdoutWriter != nil {
		a.stdoutWriter.Close()
	}
	if a.writer != nil {
		a.writer.close()
	}
}

// HandleSignals handles signals
func (a *Astilectron) HandleSignals() {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGABRT, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
	go func() {
		for sig := range ch {
			astilog.Debugf("Received signal %s", sig)
			a.Stop()
		}
	}()
}

// Stop orders Astilectron to stop
func (a *Astilectron) Stop() {
	astilog.Debug("Stopping...")
	a.canceller.Cancel()
	a.closeOnce.Do(func() {
		close(a.channelQuit)
	})
}

// Wait is a blocking pattern
func (a *Astilectron) Wait() {
	<-a.channelQuit
}

// Quit quits the app
func (a *Astilectron) Quit() error {
	return a.writer.write(Event{Name: EventNameAppCmdQuit})
}

// Paths returns the paths
func (a *Astilectron) Paths() Paths {
	return *a.paths
}

// Displays returns the displays
func (a *Astilectron) Displays() []*Display {
	return a.displayPool.all()
}

// Dock returns the dock
func (a *Astilectron) Dock() *Dock {
	return a.dock
}

// PrimaryDisplay returns the primary display
func (a *Astilectron) PrimaryDisplay() *Display {
	return a.displayPool.primary()
}

// NewMenu creates a new app menu
func (a *Astilectron) NewMenu(i []*MenuItemOptions) *Menu {
	return newMenu(nil, targetIDApp, i, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewWindow creates a new window
func (a *Astilectron) NewWindow(url string, o *WindowOptions) (*Window, error) {
	return newWindow(a.options, a.Paths(), url, o, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewWindowInDisplay creates a new window in a specific display
// This overrides the center attribute
func (a *Astilectron) NewWindowInDisplay(d *Display, url string, o *WindowOptions) (*Window, error) {
	if o.X != nil {
		*o.X += d.Bounds().X
	} else {
		o.X = PtrInt(d.Bounds().X)
	}
	if o.Y != nil {
		*o.Y += d.Bounds().Y
	} else {
		o.Y = PtrInt(d.Bounds().Y)
	}
	return newWindow(a.options, a.Paths(), url, o, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewTray creates a new tray
func (a *Astilectron) NewTray(o *TrayOptions) *Tray {
	return newTray(o, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewNotification creates a new notification
func (a *Astilectron) NewNotification(o *NotificationOptions) *Notification {
	return newNotification(o, a.supported != nil && a.supported.Notification != nil && *a.supported.Notification, a.canceller, a.dispatcher, a.identifier, a.writer)
}
<commit_msg>Bumped astilectron version<commit_after>package astilectron

import (
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/asticode/go-astilog"
	"github.com/asticode/go-astitools/context"
	"github.com/asticode/go-astitools/exec"
	"github.com/pkg/errors"
)

// Versions
const (
	DefaultAcceptTCPTimeout = 30 * time.Second
	VersionAstilectron      = "0.30.0"
	VersionElectron         = "4.0.1"
)

// Misc vars
var (
	validOSes = map[string]bool{
		"darwin":  true,
		"linux":   true,
		"windows": true,
	}
)

// App event names
const (
	EventNameAppClose         = "app.close"
	EventNameAppCmdQuit       = "app.cmd.quit" // Sends an event to Electron to properly quit the app
	EventNameAppCmdStop       = "app.cmd.stop" // Cancel the context which results in exiting abruptly Electron's app
	EventNameAppCrash         = "app.crash"
	EventNameAppErrorAccept   = "app.error.accept"
	EventNameAppEventReady    = "app.event.ready"
	EventNameAppNoAccept      = "app.no.accept"
	EventNameAppTooManyAccept = "app.too.many.accept"
)

// Astilectron represents an object capable of interacting with Astilectron
type Astilectron struct {
	canceller    *asticontext.Canceller
	channelQuit  chan bool
	closeOnce    sync.Once
	dispatcher   *dispatcher
	displayPool  *displayPool
	dock         *Dock
	executer     Executer
	identifier   *identifier
	listener     net.Listener
	options      Options
	paths        *Paths
	provisioner  Provisioner
	reader       *reader
	stderrWriter *astiexec.StdWriter
	stdoutWriter *astiexec.StdWriter
	supported    *Supported
	writer       *writer
}

// Options represents Astilectron options
type Options struct {
	AcceptTCPTimeout   time.Duration
	AppName            string
	AppIconDarwinPath  string // Darwin systems requires a specific .icns file
	AppIconDefaultPath string
	BaseDirectoryPath  string
	DataDirectoryPath  string
	ElectronSwitches   []string
	SingleInstance     bool
}

// Supported represents Astilectron supported features
type Supported struct {
	Notification *bool `json:"notification"`
}

// New creates a new Astilectron instance
func New(o Options) (a *Astilectron, err error) {
	// Validate the OS
	if !IsValidOS(runtime.GOOS) {
		err = errors.Wrapf(err, "OS %s is invalid", runtime.GOOS)
		return
	}

	// Init
	a = &Astilectron{
		canceller:   asticontext.NewCanceller(),
		channelQuit: make(chan bool),
		dispatcher:  newDispatcher(),
		displayPool: newDisplayPool(),
		executer:    DefaultExecuter,
		identifier:  newIdentifier(),
		options:     o,
		provisioner: DefaultProvisioner,
	}

	// Set paths
	if a.paths, err = newPaths(runtime.GOOS, runtime.GOARCH, o); err != nil {
		err = errors.Wrap(err, "creating new paths failed")
		return
	}

	// Add default listeners
	a.On(EventNameAppCmdStop, func(e Event) (deleteListener bool) {
		a.Stop()
		return
	})
	a.On(EventNameDisplayEventAdded, func(e Event) (deleteListener bool) {
		a.displayPool.update(e.Displays)
		return
	})
	a.On(EventNameDisplayEventMetricsChanged, func(e Event) (deleteListener bool) {
		a.displayPool.update(e.Displays)
		return
	})
	a.On(EventNameDisplayEventRemoved, func(e Event) (deleteListener bool) {
		a.displayPool.update(e.Displays)
		return
	})
	return
}

// IsValidOS validates the OS
func IsValidOS(os string) (ok bool) {
	_, ok = validOSes[os]
	return
}

// SetProvisioner sets the provisioner
func (a *Astilectron) SetProvisioner(p Provisioner) *Astilectron {
	a.provisioner = p
	return a
}

// SetExecuter sets the executer
func (a *Astilectron) SetExecuter(e Executer) *Astilectron {
	a.executer = e
	return a
}

// On implements the Listenable interface
func (a *Astilectron) On(eventName string, l Listener) {
	a.dispatcher.addListener(targetIDApp, eventName, l)
}

// Start starts Astilectron
func (a *Astilectron) Start() (err error) {
	// Log
	astilog.Debug("Starting...")

	// Provision
	if err = a.provision(); err != nil {
		return errors.Wrap(err, "provisioning failed")
	}

	// Unfortunately communicating with Electron through stdin/stdout doesn't work on Windows so all communications
	// will be done through TCP
	if err = a.listenTCP(); err != nil {
		return errors.Wrap(err, "listening failed")
	}

	// Execute
	if err = a.execute(); err != nil {
		err = errors.Wrap(err, "executing failed")
		return
	}
	return
}

// provision provisions Astilectron
func (a *Astilectron) provision() error {
	astilog.Debug("Provisioning...")
	var ctx, _ = a.canceller.NewContext()
	return a.provisioner.Provision(ctx, a.options.AppName, runtime.GOOS, runtime.GOARCH, *a.paths)
}

// listenTCP listens to the first TCP connection coming its way (this should be Astilectron)
func (a *Astilectron) listenTCP() (err error) {
	// Log
	astilog.Debug("Listening...")

	// Listen
	if a.listener, err = net.Listen("tcp", "127.0.0.1:"); err != nil {
		return errors.Wrap(err, "tcp net.Listen failed")
	}

	// Check a connection has been accepted quickly enough
	var chanAccepted = make(chan bool)
	go a.watchNoAccept(a.options.AcceptTCPTimeout, chanAccepted)

	// Accept connections
	go a.acceptTCP(chanAccepted)
	return
}

// watchNoAccept checks whether a TCP connection is accepted quickly enough
func (a *Astilectron) watchNoAccept(timeout time.Duration, chanAccepted chan bool) {
	//check timeout
	if timeout == 0 {
		timeout = DefaultAcceptTCPTimeout
	}
	var t = time.NewTimer(timeout)
	defer t.Stop()
	for {
		select {
		case <-chanAccepted:
			return
		case <-t.C:
			astilog.Errorf("No TCP connection has been accepted in the past %s", timeout)
			a.dispatcher.dispatch(Event{Name: EventNameAppNoAccept, TargetID: targetIDApp})
			a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
			return
		}
	}
}

// watchAcceptTCP accepts TCP connections
func (a *Astilectron) acceptTCP(chanAccepted chan bool) {
	for i := 0; i <= 1; i++ {
		// Accept
		var conn net.Conn
		var err error
		if conn, err = a.listener.Accept(); err != nil {
			astilog.Errorf("%s while TCP accepting", err)
			a.dispatcher.dispatch(Event{Name: EventNameAppErrorAccept, TargetID: targetIDApp})
			a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
			return
		}

		// We only accept the first connection which should be Astilectron, close the next one and stop
		// the app
		if i > 0 {
			astilog.Errorf("Too many TCP connections")
			a.dispatcher.dispatch(Event{Name: EventNameAppTooManyAccept, TargetID: targetIDApp})
			a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
			conn.Close()
			return
		}

		// Let the timer know a connection has been accepted
		chanAccepted <- true

		// Create reader and writer
		a.writer = newWriter(conn)
		ctx, _ := a.canceller.NewContext()
		a.reader = newReader(ctx, a.dispatcher, conn)
		go a.reader.read()
	}
}

// execute executes Astilectron in Electron
func (a *Astilectron) execute() (err error) {
	// Log
	astilog.Debug("Executing...")

	// Create command
	var ctx, _ = a.canceller.NewContext()
	var singleInstance string
	if a.options.SingleInstance == true {
		singleInstance = "true"
	} else {
		singleInstance = "false"
	}
	var cmd = exec.CommandContext(ctx, a.paths.AppExecutable(), append([]string{a.paths.AstilectronApplication(), a.listener.Addr().String(), singleInstance}, a.options.ElectronSwitches...)...)
	a.stderrWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stderr says: %s", i) })
	a.stdoutWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stdout says: %s", i) })
	cmd.Stderr = a.stderrWriter
	cmd.Stdout = a.stdoutWriter

	// Execute command
	if err = a.executeCmd(cmd); err != nil {
		return errors.Wrap(err, "executing cmd failed")
	}
	return
}

// executeCmd executes the command
func (a *Astilectron) executeCmd(cmd *exec.Cmd) (err error) {
	var e = synchronousFunc(a.canceller, a, func() {
		err = a.executer(a, cmd)
	}, EventNameAppEventReady)

	// Update display pool
	if e.Displays != nil {
		a.displayPool.update(e.Displays)
	}

	// Create dock
	a.dock = newDock(a.canceller, a.dispatcher, a.identifier, a.writer)

	// Update supported features
	a.supported = e.Supported
	return
}

// watchCmd watches the cmd execution
func (a *Astilectron) watchCmd(cmd *exec.Cmd) {
	// Wait
	cmd.Wait()

	// Check the canceller to check whether it was a crash
	if !a.canceller.Cancelled() {
		astilog.Debug("App has crashed")
		a.dispatcher.dispatch(Event{Name: EventNameAppCrash, TargetID: targetIDApp})
	} else {
		astilog.Debug("App has closed")
		a.dispatcher.dispatch(Event{Name: EventNameAppClose, TargetID: targetIDApp})
	}
	a.dispatcher.dispatch(Event{Name: EventNameAppCmdStop, TargetID: targetIDApp})
}

// Close closes Astilectron properly
func (a *Astilectron) Close() {
	astilog.Debug("Closing...")
	a.canceller.Cancel()
	if a.listener != nil {
		a.listener.Close()
	}
	if a.reader != nil {
		a.reader.close()
	}
	if a.stderrWriter != nil {
		a.stderrWriter.Close()
	}
	if a.stdoutWriter != nil {
		a.stdoutWriter.Close()
	}
	if a.writer != nil {
		a.writer.close()
	}
}

// HandleSignals handles signals
func (a *Astilectron) HandleSignals() {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGABRT, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
	go func() {
		for sig := range ch {
			astilog.Debugf("Received signal %s", sig)
			a.Stop()
		}
	}()
}

// Stop orders Astilectron to stop
func (a *Astilectron) Stop() {
	astilog.Debug("Stopping...")
	a.canceller.Cancel()
	a.closeOnce.Do(func() {
		close(a.channelQuit)
	})
}

// Wait is a blocking pattern
func (a *Astilectron) Wait() {
	<-a.channelQuit
}

// Quit quits the app
func (a *Astilectron) Quit() error {
	return a.writer.write(Event{Name: EventNameAppCmdQuit})
}

// Paths returns the paths
func (a *Astilectron) Paths() Paths {
	return *a.paths
}

// Displays returns the displays
func (a *Astilectron) Displays() []*Display {
	return a.displayPool.all()
}

// Dock returns the dock
func (a *Astilectron) Dock() *Dock {
	return a.dock
}

// PrimaryDisplay returns the primary display
func (a *Astilectron) PrimaryDisplay() *Display {
	return a.displayPool.primary()
}

// NewMenu creates a new app menu
func (a *Astilectron) NewMenu(i []*MenuItemOptions) *Menu {
	return newMenu(nil, targetIDApp, i, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewWindow creates a new window
func (a *Astilectron) NewWindow(url string, o *WindowOptions) (*Window, error) {
	return newWindow(a.options, a.Paths(), url, o, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewWindowInDisplay creates a new window in a specific display
// This overrides the center attribute
func (a *Astilectron) NewWindowInDisplay(d *Display, url string, o *WindowOptions) (*Window, error) {
	if o.X != nil {
		*o.X += d.Bounds().X
	} else {
		o.X = PtrInt(d.Bounds().X)
	}
	if o.Y != nil {
		*o.Y += d.Bounds().Y
	} else {
		o.Y = PtrInt(d.Bounds().Y)
	}
	return newWindow(a.options, a.Paths(), url, o, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewTray creates a new tray
func (a *Astilectron) NewTray(o *TrayOptions) *Tray {
	return newTray(o, a.canceller, a.dispatcher, a.identifier, a.writer)
}

// NewNotification creates a new notification
func (a *Astilectron) NewNotification(o *NotificationOptions) *Notification {
	return newNotification(o, a.supported != nil && a.supported.Notification != nil && *a.supported.Notification, a.canceller, a.dispatcher, a.identifier, a.writer)
}
<|endoftext|>


<commit_before>package main

import (
	. "fmt"
	"polydawn.net/docket/confl"
	"polydawn.net/docket/dex"
)

type runCmdOpts struct {
	Source      string `short:"s" long:"source" default:"graph" description:"Container source."`
}

const DefaultRunTarget = "default"

//Runs a container
func (opts *runCmdOpts) Execute(args []string) error {
	//Get configuration
	target   := GetTarget(args, DefaultRunTarget)
	settings := confl.NewConfigLoad(".")
	config   := settings.GetConfig(target)
	var sourceGraph *dex.Graph

	//Right now, go-flags' default announation does not appear to work when in a sub-command.
	//	Will investigate and hopefully remove this later.
	if opts.Source == "" {
		opts.Source = "graph"
	}

	//Parse input URI
	sourceScheme, sourcePath := ParseURI(opts.Source)
	_ = sourcePath //remove later

	//Prepare input
	switch sourceScheme {
		case "docker":
			//TODO: check that docker has the image loaded
		case "graph":
			//Look up the graph, and clear any unwanted state
			sourceGraph = dex.NewGraph(settings.Graph)
			sourceGraph.Cleanse()
		case "file":
			//If the user did not specify an image path, set one
			if sourcePath == "" {
				sourcePath = "./image.tar"
			}
		case "index":
			return Errorf("Source " + sourceScheme + " is not supported yet.")
	}

	//Start or connect to a docker daemon
	dock := StartDocker(settings)

	//Prepare cache
	switch sourceScheme {
		case "graph":
			//Import the latest lineage
			dock.Import(sourceGraph.Load(config.Image), config.Image, "latest")
		case "file":
			//Load image from file
			dock.ImportFromFilenameTagstring(sourcePath, config.Image)
	}

	//Run the container and wait for it to finish
	container := Launch(dock, config)
	container.Wait()

	//Remove if desired
	if config.Purge {
		container.Purge()
	}

	//Stop the docker daemon if it's a child process
	dock.Slay()

	return nil
}
<commit_msg>Added index source to the run command.<commit_after>package main

import (
	"polydawn.net/docket/confl"
	"polydawn.net/docket/dex"
)

type runCmdOpts struct {
	Source      string `short:"s" long:"source" default:"graph" description:"Container source."`
}

const DefaultRunTarget = "default"

//Runs a container
func (opts *runCmdOpts) Execute(args []string) error {
	//Get configuration
	target   := GetTarget(args, DefaultRunTarget)
	settings := confl.NewConfigLoad(".")
	config   := settings.GetConfig(target)
	var sourceGraph *dex.Graph

	//Right now, go-flags' default announation does not appear to work when in a sub-command.
	//	Will investigate and hopefully remove this later.
	if opts.Source == "" {
		opts.Source = "graph"
	}

	//Parse input URI
	sourceScheme, sourcePath := ParseURI(opts.Source)
	_ = sourcePath //remove later

	//Prepare input
	switch sourceScheme {
		case "docker":
			//TODO: check that docker has the image loaded
		case "graph":
			//Look up the graph, and clear any unwanted state
			sourceGraph = dex.NewGraph(settings.Graph)
			sourceGraph.Cleanse()
		case "file":
			//If the user did not specify an image path, set one
			if sourcePath == "" {
				sourcePath = "./image.tar"
			}
	}

	//Start or connect to a docker daemon
	dock := StartDocker(settings)

	//Prepare cache
	switch sourceScheme {
		case "graph":
			//Import the latest lineage
			dock.Import(sourceGraph.Load(config.Image), config.Image, "latest")
		case "file":
			//Load image from file
			dock.ImportFromFilenameTagstring(sourcePath, config.Image)
		case "index":
			//TODO: check that docker doesn't already have the image loaded
			dock.Pull(config.Image)
	}

	//Run the container and wait for it to finish
	container := Launch(dock, config)
	container.Wait()

	//Remove if desired
	if config.Purge {
		container.Purge()
	}

	//Stop the docker daemon if it's a child process
	dock.Slay()

	return nil
}
<|endoftext|>


<commit_before>package audio

/*
#ifdef _GOSMF_OSX_
  #include <CoreFoundation/CoreFoundation.h>
#endif

#include <OpenAL/al.h>
#include <OpenAL/alc.h>

ALuint genBuffer() {
  ALuint sound;

  alGenBuffers(1, &sound);
  return sound;
}

*/
import "C"
import "unsafe"

func Init() {
	initDevice()
}

func Cleanup() {
	destroyDevice()
}

type Sound struct {
	channels  uint16
	frequency uint32
	size      uint32
	data      []byte
	buffer    C.ALuint
}

func (w *Sound) attachSoundData() {
	w.buffer = C.genBuffer()
	C.alBufferData(w.buffer, C.AL_FORMAT_STEREO16, unsafe.Pointer(&w.data[0]), C.ALsizei(w.size), C.ALsizei(w.frequency))
}

func (w *Sound) Play() {
	var source C.ALuint
	C.alGenSources(1, &source)

	C.alSourcei(source, C.AL_BUFFER, C.ALint(w.buffer))
	C.alSourcePlay(source)
}
<commit_msg>some more audio cleanup<commit_after>package audio

/*
#ifdef _GOSMF_OSX_
  #include <CoreFoundation/CoreFoundation.h>
#endif

#include <OpenAL/al.h>
#include <OpenAL/alc.h>

*/
import "C"
import "unsafe"

func Init() {
	initDevice()
}

func Cleanup() {
	destroyDevice()
}

type Sound struct {
	channels  uint16
	frequency uint32
	size      uint32
	data      []byte
	buffer    C.ALuint
}

func (s *Sound) attachSoundData() {
	C.alGenBuffers(1, &s.buffer)
	C.alBufferData(s.buffer, C.AL_FORMAT_STEREO16, unsafe.Pointer(&s.data[0]), C.ALsizei(s.size), C.ALsizei(s.frequency))
}

func (s *Sound) Play() {
	var source C.ALuint
	C.alGenSources(1, &source)

	C.alSourcei(source, C.AL_BUFFER, C.ALint(s.buffer))
	C.alSourcePlay(source)
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/json"
	"fmt"
)

type Authority struct {
	AuthorityChainID  string   `json:"identity_chainid"`
	ManagementChainID string   `json:"management_chaind"`
	MatryoshkaHash    string   `json:"matryoshka_hash"`
	SigningKey        string   `json:"signing_key"`
	Status            int      `json:"status"`
	Efficiency        int      `json:"efficiency"`
	CoinbaseAddress   string   `json:"coinbase_address"`
	AnchorKeys        []string `json:"anchor_keys"`
	// KeyHistory []string `json:"-"`
}

func (a *Authority) String() string {
	var s string

	s += fmt.Sprintln("AuthorityChainID:", a.AuthorityChainID)
	s += fmt.Sprintln("ManagementChainID:", a.ManagementChainID)
	s += fmt.Sprintln("MatryoshkaHash:", a.MatryoshkaHash)
	s += fmt.Sprintln("SigningKey:", a.SigningKey)
	s += fmt.Sprintln("Status:", a.Status)
	s += fmt.Sprintln("Efficiency:", a.Efficiency)
	s += fmt.Sprintln("CoinbaseAddress:", a.CoinbaseAddress)

	s += fmt.Sprintln("AnchorKeys {")
	for _, k := range a.AnchorKeys {
		s += fmt.Sprintln(" ", k)
	}
	s += fmt.Sprintln("}")

	// s += fmt.Sprintln("KeyHisory {")
	// for _, k := range a.KeyHistory {
	// 	s += fmt.Sprintln(" ", k)
	// }
	// s += fmt.Sprintln("}")

	return s
}

// GetAuthorites retrieves a list of the known athorities from factomd
func GetAuthorites() ([]*Authority, error) {
	req := NewJSON2Request("authorities", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	// create a temporary type to unmarshal the json object
	a := new(struct {
		Authorities []*Authority `json:"authorities"`
	})

	if err := json.Unmarshal(resp.JSONResult(), a); err != nil {
		return nil, err
	}

	return a.Authorities, nil
}
<commit_msg>added todo question<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/json"
	"fmt"
)

type Authority struct {
	AuthorityChainID  string   `json:"identity_chainid"`
	ManagementChainID string   `json:"management_chaind"`
	MatryoshkaHash    string   `json:"matryoshka_hash"`
	SigningKey        string   `json:"signing_key"`
	Status            int      `json:"status"`
	Efficiency        int      `json:"efficiency"`
	CoinbaseAddress   string   `json:"coinbase_address"`
	AnchorKeys        []string `json:"anchor_keys"`
	// TODO: should keyhistory be part of the api return for an Authority?
	// KeyHistory []string `json:"-"`
}

func (a *Authority) String() string {
	var s string

	s += fmt.Sprintln("AuthorityChainID:", a.AuthorityChainID)
	s += fmt.Sprintln("ManagementChainID:", a.ManagementChainID)
	s += fmt.Sprintln("MatryoshkaHash:", a.MatryoshkaHash)
	s += fmt.Sprintln("SigningKey:", a.SigningKey)
	s += fmt.Sprintln("Status:", a.Status)
	s += fmt.Sprintln("Efficiency:", a.Efficiency)
	s += fmt.Sprintln("CoinbaseAddress:", a.CoinbaseAddress)

	s += fmt.Sprintln("AnchorKeys {")
	for _, k := range a.AnchorKeys {
		s += fmt.Sprintln(" ", k)
	}
	s += fmt.Sprintln("}")

	// s += fmt.Sprintln("KeyHisory {")
	// for _, k := range a.KeyHistory {
	// 	s += fmt.Sprintln(" ", k)
	// }
	// s += fmt.Sprintln("}")

	return s
}

// GetAuthorites retrieves a list of the known athorities from factomd
func GetAuthorites() ([]*Authority, error) {
	req := NewJSON2Request("authorities", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	// create a temporary type to unmarshal the json object
	a := new(struct {
		Authorities []*Authority `json:"authorities"`
	})

	if err := json.Unmarshal(resp.JSONResult(), a); err != nil {
		return nil, err
	}

	return a.Authorities, nil
}
<|endoftext|>


<commit_before>// Package aws provides core functionality for making requests to AWS services.
package aws

// SDKName is the name of this AWS SDK
const SDKName = "aws-sdk-go"

// SDKVersion is the version of this SDK
const SDKVersion = "0.9.13"
<commit_msg>Tag release v0.9.15<commit_after>// Package aws provides core functionality for making requests to AWS services.
package aws

// SDKName is the name of this AWS SDK
const SDKName = "aws-sdk-go"

// SDKVersion is the version of this SDK
const SDKVersion = "0.9.15"
<|endoftext|>


<commit_before>package gosupplychain

import (
	"strings"
)

// LicenseFilePrefix is a list of filename prefixes that indicate it
//  might contain a software license
var LicenseFilePrefix = []string{
	"license",
	"copying",
	"unlicense",
	"copyright",
}

// IsPossibleLicenseFile returns true if the filename might be contain a software license
func IsPossibleLicenseFile(filename string) bool {
	lowerfile := strings.ToLower(filename)
	for _, prefix := range LicenseFilePrefix {
		if strings.HasPrefix(lowerfile, prefix) {
			return true
		}
	}
	return false
}
<commit_msg>Add copyleft<commit_after>package gosupplychain

import (
	"strings"
)

// LicenseFilePrefix is a list of filename prefixes that indicate it
//  might contain a software license
var LicenseFilePrefix = []string{
	"license",
	"copying",
	"unlicense",
	"copyright",
	"copyleft"
}

// IsPossibleLicenseFile returns true if the filename might be contain a software license
func IsPossibleLicenseFile(filename string) bool {
	lowerfile := strings.ToLower(filename)
	for _, prefix := range LicenseFilePrefix {
		if strings.HasPrefix(lowerfile, prefix) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package gosshtool

import (
	"golang.org/x/crypto/ssh"
	"io"
	"log"
	"net"
)

type LocalForwardServer struct {
	LocalBindAddress string
	RemoteAddress    string
	SshServerAddress string
	SshUserName      string
	SshUserPassword  string
	SshPrivateKey    string
	tunnel           *Tunnel
}

//create tunnel
func (this *LocalForwardServer) createTunnel() {
	if this.SshUserPassword == "" && this.SshUserName == "" {
		log.Fatal("No password or private key available")
	}
	if this.SshPrivateKey != "" {
		//todo
	}

	config := &ssh.ClientConfig{
		User: this.SshUserName,
		Auth: []ssh.AuthMethod{
			ssh.Password(this.SshUserPassword),
		},
	}

	client, err := ssh.Dial("tcp", this.SshServerAddress, config)
	if err != nil {
		log.Fatal("Failed to dial: " + err.Error())
	}
	log.Println("create ssh client ok")
	this.tunnel = &Tunnel{client}
}

func (this *LocalForwardServer) handleConnectionAndForward(conn *net.Conn) {
	sshConn, err := this.tunnel.Client.Dial("tcp", this.RemoteAddress)
	if err != nil {
		log.Fatalf("ssh client dial error:%v", err)
	}
	log.Println("create ssh connection ok")
	go localReaderToRemoteWriter(*conn, sshConn)
	go remoteReaderToLoacalWriter(sshConn, *conn)
}

func localReaderToRemoteWriter(localConn net.Conn, sshConn net.Conn) {
	_, err := io.Copy(sshConn, localConn)
	if err != nil {
		log.Fatalf("io copy error:%v", err)
	}
}

func remoteReaderToLoacalWriter(sshConn net.Conn, localConn net.Conn) {
	_, err := io.Copy(localConn, sshConn)
	if err != nil {
		log.Fatalf("io copy error:%v", err)
	}
}

func (this *LocalForwardServer) Init() {
	this.createTunnel()
}

func (this *LocalForwardServer) Start(call func()) {
	ln, err := net.Listen("tcp", this.LocalBindAddress)
	if err != nil {
		log.Fatalf("net listen error :%v", err)
	}
	var called bool
	for {
		if !called {
			go call()
			called = true
		}
		conn, err := ln.Accept()
		if err != nil {
			log.Println(err)
		}
		go this.handleConnectionAndForward(&conn)
		defer conn.Close()
	}
}

func (this *LocalForwardServer) Stop() {
	err := this.tunnel.Client.Close()
	if err != nil {
		log.Fatalf("ssh client stop error:%v", err)
	}
}
<commit_msg>support ssh key auth<commit_after>package gosshtool

import (
	"golang.org/x/crypto/ssh"
	"io"
	"log"
	"net"
)

type LocalForwardServer struct {
	LocalBindAddress string
	RemoteAddress    string
	SshServerAddress string
	SshUserName      string
	SshUserPassword  string
	SshPrivateKey    string
	tunnel           *Tunnel
}

//create tunnel
func (this *LocalForwardServer) createTunnel() {
	if this.SshUserPassword == "" && this.SshUserName == "" {
		log.Fatal("No password or private key available")
	}
	config := &ssh.ClientConfig{
		User: this.SshUserName,
		Auth: []ssh.AuthMethod{
			ssh.Password(this.SshUserPassword),
		},
	}
	if this.SshPrivateKey != "" {
		log.Println(this.SshPrivateKey)
		signer, err := ssh.ParsePrivateKey([]byte(this.SshPrivateKey))
		if err != nil {
			log.Fatalf("ssh.ParsePrivateKey error:%v", err)
		}
		clientkey := ssh.PublicKeys(signer)
		config = &ssh.ClientConfig{
			User: this.SshUserName,
			Auth: []ssh.AuthMethod{
				clientkey,
			},
		}

	}

	client, err := ssh.Dial("tcp", this.SshServerAddress, config)
	if err != nil {
		log.Fatal("Failed to dial: " + err.Error())
	}
	log.Println("create ssh client ok")
	this.tunnel = &Tunnel{client}
}

func (this *LocalForwardServer) handleConnectionAndForward(conn *net.Conn) {
	sshConn, err := this.tunnel.Client.Dial("tcp", this.RemoteAddress)
	if err != nil {
		log.Fatalf("ssh client dial error:%v", err)
	}
	log.Println("create ssh connection ok")
	go localReaderToRemoteWriter(*conn, sshConn)
	go remoteReaderToLoacalWriter(sshConn, *conn)
}

func localReaderToRemoteWriter(localConn net.Conn, sshConn net.Conn) {
	_, err := io.Copy(sshConn, localConn)
	if err != nil {
		log.Fatalf("io copy error:%v", err)
	}
}

func remoteReaderToLoacalWriter(sshConn net.Conn, localConn net.Conn) {
	_, err := io.Copy(localConn, sshConn)
	if err != nil {
		log.Fatalf("io copy error:%v", err)
	}
}

func (this *LocalForwardServer) Init() {
	this.createTunnel()
}

func (this *LocalForwardServer) Start(call func()) {
	ln, err := net.Listen("tcp", this.LocalBindAddress)
	if err != nil {
		log.Fatalf("net listen error :%v", err)
	}
	var called bool
	for {
		if !called {
			go call()
			called = true
		}
		conn, err := ln.Accept()
		if err != nil {
			log.Println(err)
		}
		go this.handleConnectionAndForward(&conn)
		defer conn.Close()
	}
}

func (this *LocalForwardServer) Stop() {
	err := this.tunnel.Client.Close()
	if err != nil {
		log.Fatalf("ssh client stop error:%v", err)
	}
}
<|endoftext|>