<commit_before>package operator

import (
	"fmt"
	"sync"

	"github.com/giantswarm/azuretpr"
	"github.com/giantswarm/microerror"
	"github.com/giantswarm/micrologger"
	"github.com/giantswarm/operatorkit/tpr"
	"github.com/spf13/viper"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	"github.com/giantswarm/azure-operator/flag"
)

const (
	TPRVersion     = "v1"
	TPRDescription = "Managed Kubernetes clusters in Giantnetes running on Azure"
)

// Config represents the configuration used to create an Operator service.
type Config struct {
	// Dependencies.
	Logger    micrologger.Logger
	K8sClient kubernetes.Interface

	// Settings.
	Flag  *flag.Flag
	Viper *viper.Viper
}

// DefaultConfig provides a default configuration to create a new operator
// service by best effort.
func DefaultConfig() Config {
	return Config{
		// Dependencies.
		K8sClient: nil,
		Logger:    nil,

		// Settings.
		Flag:  nil,
		Viper: nil,
	}
}

// Service implements the Operator service interface.
type Service struct {
	Config

	// Internals.
	bootOnce sync.Once
	tpr      *tpr.TPR
}

// New creates a new configured Operator service.
func New(config Config) (*Service, error) {
	// Dependencies.
	if config.K8sClient == nil {
		return nil, microerror.Maskf(invalidConfigError, "kubernetes client must not be empty")
	}
	if config.Logger == nil {
		return nil, microerror.Maskf(invalidConfigError, "logger must not be empty")
	}

	// Settings.
	if config.Flag == nil {
		return nil, microerror.Maskf(invalidConfigError, "flag must not be empty")
	}
	if config.Viper == nil {
		return nil, microerror.Maskf(invalidConfigError, "viper must not be empty")
	}

	tprConfig := tpr.Config{
		K8sClient:   config.K8sClient,
		Logger:      config.Logger,
		Name:        azuretpr.Name,
		Version:     TPRVersion,
		Description: TPRDescription,
	}
	tpr, err := tpr.New(tprConfig)
	if err != nil {
		return nil, microerror.Maskf(err, "creating TPR for %#v", tprConfig)
	}

	newService := &Service{
		Config: config,

		// Internals
		bootOnce: sync.Once{},
		tpr:      tpr,
	}

	return newService, nil
}

// Boot starts the service and implements the watch for azuretpr.
func (s *Service) Boot() {
	s.bootOnce.Do(func() {
		err := s.tpr.CreateAndWait()
		if tpr.IsAlreadyExists(err) {
			s.Logger.Log("debug", "third party resource already exists")
		} else if err != nil {
			s.Logger.Log("error", fmt.Sprintf("%#v", err))
			return
		}

		s.Logger.Log("debug", "starting list/watch")

		newResourceEventHandler := &cache.ResourceEventHandlerFuncs{
			AddFunc:    s.addFunc,
			DeleteFunc: s.deleteFunc,
		}
		newZeroObjectFactory := &tpr.ZeroObjectFactoryFuncs{
			NewObjectFunc:     func() runtime.Object { return &azuretpr.CustomObject{} },
			NewObjectListFunc: func() runtime.Object { return &azuretpr.List{} },
		}

		s.tpr.NewInformer(newResourceEventHandler, newZeroObjectFactory).Run(nil)
	})
}

func (s *Service) addFunc(obj interface{}) {
	customObject := *obj.(*azuretpr.CustomObject)
	s.Config.Logger.Log("debug", fmt.Sprintf("creating cluster '%s'", customObject.Spec.Cluster.Cluster.ID))

	// TODO Add stub code for creating an Azure Resource Group.
}

// deleteFunc TODO
func (s *Service) deleteFunc(obj interface{}) {
	customObject := *obj.(*azuretpr.CustomObject)
	s.Config.Logger.Log("debug", fmt.Sprintf("deleting cluster '%s'", customObject.Spec.Cluster.Cluster.ID))

	// TODO Add stub code for deleting the Azure Resource Group.
}
<commit_msg>Get version and description from azuretpr<commit_after>package operator

import (
	"fmt"
	"sync"

	"github.com/giantswarm/azuretpr"
	"github.com/giantswarm/microerror"
	"github.com/giantswarm/micrologger"
	"github.com/giantswarm/operatorkit/tpr"
	"github.com/spf13/viper"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	"github.com/giantswarm/azure-operator/flag"
)

// Config represents the configuration used to create an Operator service.
type Config struct {
	// Dependencies.
	Logger    micrologger.Logger
	K8sClient kubernetes.Interface

	// Settings.
	Flag  *flag.Flag
	Viper *viper.Viper
}

// DefaultConfig provides a default configuration to create a new operator
// service by best effort.
func DefaultConfig() Config {
	return Config{
		// Dependencies.
		K8sClient: nil,
		Logger:    nil,

		// Settings.
		Flag:  nil,
		Viper: nil,
	}
}

// Service implements the Operator service interface.
type Service struct {
	Config

	// Internals.
	bootOnce sync.Once
	tpr      *tpr.TPR
}

// New creates a new configured Operator service.
func New(config Config) (*Service, error) {
	// Dependencies.
	if config.K8sClient == nil {
		return nil, microerror.Maskf(invalidConfigError, "kubernetes client must not be empty")
	}
	if config.Logger == nil {
		return nil, microerror.Maskf(invalidConfigError, "logger must not be empty")
	}

	// Settings.
	if config.Flag == nil {
		return nil, microerror.Maskf(invalidConfigError, "flag must not be empty")
	}
	if config.Viper == nil {
		return nil, microerror.Maskf(invalidConfigError, "viper must not be empty")
	}

	tprConfig := tpr.Config{
		K8sClient:   config.K8sClient,
		Logger:      config.Logger,
		Name:        azuretpr.Name,
		Version:     azuretpr.VersionV1,
		Description: azuretpr.Description,
	}
	tpr, err := tpr.New(tprConfig)
	if err != nil {
		return nil, microerror.Maskf(err, "creating TPR for %#v", tprConfig)
	}

	newService := &Service{
		Config: config,

		// Internals
		bootOnce: sync.Once{},
		tpr:      tpr,
	}

	return newService, nil
}

// Boot starts the service and implements the watch for azuretpr.
func (s *Service) Boot() {
	s.bootOnce.Do(func() {
		err := s.tpr.CreateAndWait()
		if tpr.IsAlreadyExists(err) {
			s.Logger.Log("debug", "third party resource already exists")
		} else if err != nil {
			s.Logger.Log("error", fmt.Sprintf("%#v", err))
			return
		}

		s.Logger.Log("debug", "starting list/watch")

		newResourceEventHandler := &cache.ResourceEventHandlerFuncs{
			AddFunc:    s.addFunc,
			DeleteFunc: s.deleteFunc,
		}
		newZeroObjectFactory := &tpr.ZeroObjectFactoryFuncs{
			NewObjectFunc:     func() runtime.Object { return &azuretpr.CustomObject{} },
			NewObjectListFunc: func() runtime.Object { return &azuretpr.List{} },
		}

		s.tpr.NewInformer(newResourceEventHandler, newZeroObjectFactory).Run(nil)
	})
}

func (s *Service) addFunc(obj interface{}) {
	customObject := *obj.(*azuretpr.CustomObject)
	s.Config.Logger.Log("debug", fmt.Sprintf("creating cluster '%s'", customObject.Spec.Cluster.Cluster.ID))

	// TODO Add stub code for creating an Azure Resource Group.
}

// deleteFunc TODO
func (s *Service) deleteFunc(obj interface{}) {
	customObject := *obj.(*azuretpr.CustomObject)
	s.Config.Logger.Log("debug", fmt.Sprintf("deleting cluster '%s'", customObject.Spec.Cluster.Cluster.ID))

	// TODO Add stub code for deleting the Azure Resource Group.
}
<|endoftext|>


<commit_before>package workspace

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const solutionFilename = "solution.json"
const legacySolutionFilename = ".solution.json"
const ignoreSubdir = ".exercism"

var metadataFilepath = filepath.Join(ignoreSubdir, solutionFilename)

// Solution contains metadata about a user's solution.
type Solution struct {
	Track       string     `json:"track"`
	Exercise    string     `json:"exercise"`
	ID          string     `json:"id"`
	Team        string     `json:"team,omitempty"`
	URL         string     `json:"url"`
	Handle      string     `json:"handle"`
	IsRequester bool       `json:"is_requester"`
	SubmittedAt *time.Time `json:"submitted_at,omitempty"`
	Dir         string     `json:"-"`
	AutoApprove bool       `json:"auto_approve"`
}

// NewSolution reads solution metadata from a file in the given directory.
func NewSolution(dir string) (*Solution, error) {
	path := filepath.Join(dir, metadataFilepath)
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return &Solution{}, err
	}
	var s Solution
	if err := json.Unmarshal(b, &s); err != nil {
		return &Solution{}, err
	}
	s.Dir = dir
	return &s, nil
}

// Suffix is the serial numeric value appended to an exercise directory.
// This is appended to avoid name conflicts, and does not indicate a particular
// iteration.
func (s *Solution) Suffix() string {
	return strings.Trim(strings.Replace(filepath.Base(s.Dir), s.Exercise, "", 1), "-.")
}

func (s *Solution) String() string {
	str := fmt.Sprintf("%s/%s", s.Track, s.Exercise)
	if s.Suffix() != "" {
		str = fmt.Sprintf("%s (%s)", str, s.Suffix())
	}
	if !s.IsRequester && s.Handle != "" {
		str = fmt.Sprintf("%s by @%s", str, s.Handle)
	}
	return str
}

// Write stores solution metadata to a file.
func (s *Solution) Write(dir string) error {
	b, err := json.Marshal(s)
	if err != nil {
		return err
	}
	metadataAbsoluteFilepath := NewExerciseFromDir(dir).MetadataFilepath()
	if err = os.MkdirAll(filepath.Dir(metadataAbsoluteFilepath), os.FileMode(0755)); err != nil {
		return err
	}
	if err = ioutil.WriteFile(metadataAbsoluteFilepath, b, os.FileMode(0600)); err != nil {
		return err
	}
	s.Dir = dir
	return nil
}

// PathToParent is the relative path from the workspace to the parent dir.
func (s *Solution) PathToParent() string {
	var dir string
	if !s.IsRequester {
		dir = filepath.Join("users")
	}
	return filepath.Join(dir, s.Track)
}
<commit_msg>Refactor inline temp<commit_after>package workspace

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const solutionFilename = "solution.json"
const legacySolutionFilename = ".solution.json"
const ignoreSubdir = ".exercism"

var metadataFilepath = filepath.Join(ignoreSubdir, solutionFilename)

// Solution contains metadata about a user's solution.
type Solution struct {
	Track       string     `json:"track"`
	Exercise    string     `json:"exercise"`
	ID          string     `json:"id"`
	Team        string     `json:"team,omitempty"`
	URL         string     `json:"url"`
	Handle      string     `json:"handle"`
	IsRequester bool       `json:"is_requester"`
	SubmittedAt *time.Time `json:"submitted_at,omitempty"`
	Dir         string     `json:"-"`
	AutoApprove bool       `json:"auto_approve"`
}

// NewSolution reads solution metadata from a file in the given directory.
func NewSolution(dir string) (*Solution, error) {
	b, err := ioutil.ReadFile(filepath.Join(dir, metadataFilepath))
	if err != nil {
		return &Solution{}, err
	}
	var s Solution
	if err := json.Unmarshal(b, &s); err != nil {
		return &Solution{}, err
	}
	s.Dir = dir
	return &s, nil
}

// Suffix is the serial numeric value appended to an exercise directory.
// This is appended to avoid name conflicts, and does not indicate a particular
// iteration.
func (s *Solution) Suffix() string {
	return strings.Trim(strings.Replace(filepath.Base(s.Dir), s.Exercise, "", 1), "-.")
}

func (s *Solution) String() string {
	str := fmt.Sprintf("%s/%s", s.Track, s.Exercise)
	if s.Suffix() != "" {
		str = fmt.Sprintf("%s (%s)", str, s.Suffix())
	}
	if !s.IsRequester && s.Handle != "" {
		str = fmt.Sprintf("%s by @%s", str, s.Handle)
	}
	return str
}

// Write stores solution metadata to a file.
func (s *Solution) Write(dir string) error {
	b, err := json.Marshal(s)
	if err != nil {
		return err
	}
	metadataAbsoluteFilepath := NewExerciseFromDir(dir).MetadataFilepath()
	if err = os.MkdirAll(filepath.Dir(metadataAbsoluteFilepath), os.FileMode(0755)); err != nil {
		return err
	}
	if err = ioutil.WriteFile(metadataAbsoluteFilepath, b, os.FileMode(0600)); err != nil {
		return err
	}
	s.Dir = dir
	return nil
}

// PathToParent is the relative path from the workspace to the parent dir.
func (s *Solution) PathToParent() string {
	var dir string
	if !s.IsRequester {
		dir = filepath.Join("users")
	}
	return filepath.Join(dir, s.Track)
}
<|endoftext|>


<commit_before>package lwcache

import (
	"sync"
	"time"
)

const (
	NoExpire = time.Duration(0)
)

const (
	refresherOn  = true
	refresherOff = false
)

type Getter interface {
	Get(key interface{}) (value interface{}, ok bool)
}

type refreshNotifier struct {
	c   *cache
	key interface{}
}

type Cache interface {
	Getter
	Set(key interface{}, item interface{}, expire time.Duration)
	SetExpire(key interface{}, expire time.Duration)
	SetRefresher(fn func(c Cache, key interface{}, currentValue interface{}) (newValue interface{}, err error))
	StartRefresher(key interface{}, refreshInterval time.Duration)
	StopRefresher(key interface{})
}

type cache struct {
	namespace string
	items     map[interface{}]cacheItem
	mutex     sync.RWMutex
	refresher func(c Cache, key interface{}, currentValue interface{}) (newValue interface{}, err error)
	// for refresher
	refresherStatus map[interface{}]bool
	refresherMutex  sync.RWMutex
}

var _ Cache = (*cache)(nil)

type cacheItem struct {
	expiration time.Time
	value      interface{}
	deleter    *time.Timer
}

func New(name string) Cache {
	c := &cache{
		namespace:       name,
		items:           make(map[interface{}]cacheItem),
		mutex:           sync.RWMutex{},
		refresherStatus: make(map[interface{}]bool),
		refresherMutex:  sync.RWMutex{},
	}
	return c
}

// TODO: implement MSet (multi set) for performance
func (c *cache) Set(key, value interface{}, expire time.Duration) {
	expiration := time.Time{}
	if expire != NoExpire {
		expiration = time.Now().Add(expire)
	}
	item := cacheItem{
		value:      value,
		expiration: expiration,
		deleter: time.AfterFunc(expire, func() {
			c.mutexDelete(key)
		}),
	}

	c.mutexSet(key, item)
}

func (c *cache) SetExpire(key interface{}, expire time.Duration) {
	if item, ok := c.mutexGet(key); ok {
		item.expiration = time.Now().Add(expire)
		if item.deleter != nil {
			item.deleter.Reset(expire)
		} else {
			item.deleter = time.AfterFunc(expire, func() {
				c.mutexDelete(key)
			})
		}
		c.mutexSet(key, item)
	}
}

func (c *cache) SetRefresher(fn func(c Cache, key interface{}, currentValue interface{}) (newValue interface{}, err error)) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.refresher = fn
}

func (c *cache) StartRefresher(key interface{}, refreshInterval time.Duration) {
	c.refresherMutex.RLock()
	running := c.refresherStatus[key]
	c.refresherMutex.RUnlock()
	if !running {
		c.refresherMutex.Lock()
		c.refresherStatus[key] = refresherOn
		c.refresherMutex.Unlock()
		time.AfterFunc(refreshInterval, c.startBackGroundRefresh(key, refreshInterval))
	}
}

func (c *cache) StopRefresher(key interface{}) {
	c.refresherMutex.Lock()
	c.refresherStatus[key] = false
	c.refresherMutex.Unlock()
}

func (c *cache) startBackGroundRefresh(key interface{}, interval time.Duration) func() {
	return func() {
		c.refresherMutex.RLock()
		running := c.refresherStatus[key]
		c.refresherMutex.RUnlock()
		if !running {
			return
		}
		c.refresh(key)
		time.AfterFunc(interval, c.startBackGroundRefresh(key, interval))
	}
}

/*
func (c *cache) OnExpire(key string, fn func(item interface{}) error) error {
	return fn(c.item)
}

func (c *cache) OnRefresh(key string, fn func(item interface{}) error) error {
	return fn(c.item)
}
*/

// TODO: implement MGet (multi get) for performance
func (c *cache) Get(key interface{}) (interface{}, bool) {
	now := time.Now()
	item, ok := c.mutexGet(key)

	// no expire on expiration is zero value
	if ok && !item.expiration.IsZero() && now.After(item.expiration) {
		c.mutexDelete(key)
		return nil, false
	}

	return item.value, ok
}

func (c *cache) mutexGet(key interface{}) (cacheItem, bool) {
	c.mutex.RLock()
	item, ok := c.items[key]
	c.mutex.RUnlock()

	return item, ok
}

func (c *cache) mutexDelete(key interface{}) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// for avoid goroutine leak
	if c.items[key].deleter != nil {
		c.items[key].deleter.Stop()
	}

	delete(c.items, key)
}

func (c *cache) mutexSet(key interface{}, item cacheItem) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.items[key] = item
}

func (c *cache) mutexSetValue(key, value interface{}) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	item := c.items[key]
	item.value = value
	c.items[key] = item

}

func (c *cache) refresh(key interface{}) {
	// avoid panic
	// see: https://github.com/azihsoyn/lwcache/issues/5
	if c.refresher == nil {
		return
	}

	item, ok := c.mutexGet(key)
	if !ok {
		// item deleted. not refresh
		return
	}
	val, err := c.refresher(c, key, item.value)
	if err != nil {
		// TODO?: notifyError
		return
	}
	c.mutexSetValue(key, val)
}
<commit_msg>fix set expire<commit_after>package lwcache

import (
	"sync"
	"time"
)

const (
	NoExpire = time.Duration(0)
)

const (
	refresherOn  = true
	refresherOff = false
)

type refreshNotifier struct {
	c   *cache
	key interface{}
}

type Cache interface {
	Get(key interface{}) (value interface{}, ok bool)
	Set(key interface{}, item interface{}, expire time.Duration)
	SetExpire(key interface{}, expire time.Duration)
	SetRefresher(fn func(c Cache, key interface{}, currentValue interface{}) (newValue interface{}, err error))
	StartRefresher(key interface{}, refreshInterval time.Duration)
	StopRefresher(key interface{})
}

type cache struct {
	namespace string
	items     map[interface{}]cacheItem
	mutex     sync.RWMutex
	refresher func(c Cache, key interface{}, currentValue interface{}) (newValue interface{}, err error)
	// for refresher
	refresherStatus map[interface{}]bool
	refresherMutex  sync.RWMutex
}

var _ Cache = (*cache)(nil)

type cacheItem struct {
	expiration time.Time
	value      interface{}
	deleter    *time.Timer
}

func New(name string) Cache {
	c := &cache{
		namespace:       name,
		items:           make(map[interface{}]cacheItem),
		mutex:           sync.RWMutex{},
		refresherStatus: make(map[interface{}]bool),
		refresherMutex:  sync.RWMutex{},
	}
	return c
}

// TODO: implement MSet (multi set) for performance
func (c *cache) Set(key, value interface{}, expire time.Duration) {
	expiration := time.Time{}
	if expire != NoExpire {
		expiration = time.Now().Add(expire)
	}
	item := cacheItem{
		value:      value,
		expiration: expiration,
		deleter: time.AfterFunc(expire, func() {
			c.mutexDelete(key)
		}),
	}

	c.mutexSet(key, item)
}

func (c *cache) SetExpire(key interface{}, expire time.Duration) {
	if item, ok := c.mutexGet(key); ok {
		if expire == NoExpire {
			item.expiration = time.Time{}
			if item.deleter != nil {
				item.deleter.Stop()
				item.deleter = nil
			}
		} else {
			item.expiration = time.Now().Add(expire)
			if item.deleter != nil {
				item.deleter.Reset(expire)
			} else {
				item.deleter = time.AfterFunc(expire, func() {
					c.mutexDelete(key)
				})
			}
		}
		c.mutexSet(key, item)
	}
}

func (c *cache) SetRefresher(fn func(c Cache, key interface{}, currentValue interface{}) (newValue interface{}, err error)) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.refresher = fn
}

func (c *cache) StartRefresher(key interface{}, refreshInterval time.Duration) {
	c.refresherMutex.RLock()
	running := c.refresherStatus[key]
	c.refresherMutex.RUnlock()
	if !running {
		c.refresherMutex.Lock()
		c.refresherStatus[key] = refresherOn
		c.refresherMutex.Unlock()
		time.AfterFunc(refreshInterval, c.startBackGroundRefresh(key, refreshInterval))
	}
}

func (c *cache) StopRefresher(key interface{}) {
	c.refresherMutex.Lock()
	c.refresherStatus[key] = false
	c.refresherMutex.Unlock()
}

func (c *cache) startBackGroundRefresh(key interface{}, interval time.Duration) func() {
	return func() {
		c.refresherMutex.RLock()
		running := c.refresherStatus[key]
		c.refresherMutex.RUnlock()
		if !running {
			return
		}
		c.refresh(key)
		time.AfterFunc(interval, c.startBackGroundRefresh(key, interval))
	}
}

/*
func (c *cache) OnExpire(key string, fn func(item interface{}) error) error {
	return fn(c.item)
}

func (c *cache) OnRefresh(key string, fn func(item interface{}) error) error {
	return fn(c.item)
}
*/

// TODO: implement MGet (multi get) for performance
func (c *cache) Get(key interface{}) (interface{}, bool) {
	now := time.Now()
	item, ok := c.mutexGet(key)

	// no expire on expiration is zero value
	if ok && !item.expiration.IsZero() && now.After(item.expiration) {
		c.mutexDelete(key)
		return nil, false
	}

	return item.value, ok
}

func (c *cache) mutexGet(key interface{}) (cacheItem, bool) {
	c.mutex.RLock()
	item, ok := c.items[key]
	c.mutex.RUnlock()

	return item, ok
}

func (c *cache) mutexDelete(key interface{}) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// for avoid goroutine leak
	if c.items[key].deleter != nil {
		c.items[key].deleter.Stop()
	}

	delete(c.items, key)
}

func (c *cache) mutexSet(key interface{}, item cacheItem) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.items[key] = item
}

func (c *cache) mutexSetValue(key, value interface{}) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	item := c.items[key]
	item.value = value
	c.items[key] = item

}

func (c *cache) refresh(key interface{}) {
	// avoid panic
	// see: https://github.com/azihsoyn/lwcache/issues/5
	if c.refresher == nil {
		return
	}

	item, ok := c.mutexGet(key)
	if !ok {
		// item deleted. not refresh
		return
	}
	val, err := c.refresher(c, key, item.value)
	if err != nil {
		// TODO?: notifyError
		return
	}
	c.mutexSetValue(key, val)
}
<|endoftext|>


<commit_before>package registry

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
)

var errInvalidValue = errors.New("Invalid value")

var (
	tags            = []string{"default", "env", "flag", "registry"}
	typeStringSlice = reflect.TypeOf([]string{})
)

type config struct {
	mutex sync.Locker
	ident string
	items []item
}

func (r *registry) Bind(i sync.Locker) error {
	items, err := bind(i)
	if err != nil {
		return err
	}
	r.configs = append(r.configs, config{
		mutex: i,
		ident: fmt.Sprintf("%s.%d", reflect.TypeOf(i).Elem().Name(), len(r.configs)+1),
		items: items,
	})
	if r.refreshInterval != -1 {
		r.bindChan <- struct{}{}
	}
	return nil
}

type item struct {
	key       string
	reference reflect.Value
}

func (i *item) set(rawValue string) error {
	if len(rawValue) == 0 {
		return nil
	}

	var (
		err          error
		defaultValue interface{}
	)

	switch i.reference.Type().Kind() {
	case reflect.String:
		defaultValue = rawValue
	case reflect.Int:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 0); err == nil {
			defaultValue = int(defaultValue.(int64))
		}
	case reflect.Int8:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 8); err == nil {
			defaultValue = int8(defaultValue.(int64))
		}
	case reflect.Int16:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 16); err == nil {
			defaultValue = int16(defaultValue.(int64))
		}
	case reflect.Int32:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 32); err == nil {
			defaultValue = int32(defaultValue.(int64))
		}
	case reflect.Int64:
		defaultValue, err = strconv.ParseInt(rawValue, 10, 64)
	case reflect.Uint:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 0); err == nil {
			defaultValue = uint(defaultValue.(uint64))
		}
	case reflect.Uint8:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 8); err == nil {
			defaultValue = uint8(defaultValue.(uint64))
		}
	case reflect.Uint16:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 16); err == nil {
			defaultValue = uint16(defaultValue.(uint64))
		}
	case reflect.Uint32:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 32); err == nil {
			defaultValue = uint32(defaultValue.(uint64))
		}
	case reflect.Uint64:
		defaultValue, err = strconv.ParseUint(rawValue, 10, 64)
	case reflect.Float32:
		if defaultValue, err = strconv.ParseFloat(rawValue, 10); err == nil {
			defaultValue = float32(defaultValue.(float64))
		}
	case reflect.Float64:
		defaultValue, err = strconv.ParseFloat(rawValue, 10)
	case reflect.Bool:
		defaultValue, err = strconv.ParseBool(rawValue)
	case reflect.Slice:
		switch i.reference.Type() {
		case typeStringSlice:
			defaultValue = strings.Split(rawValue, ",")
		}
	}

	if err != nil {
		return err
	}

	if i.reference.CanSet() && defaultValue != nil {
		i.reference.Set(reflect.ValueOf(defaultValue))
	}
	return nil
}

func bind(i interface{}) ([]item, error) {
	var (
		rt = reflect.TypeOf(i)
		rv = reflect.ValueOf(i)
	)

	if rt.Kind() == reflect.Ptr {
		rt = rt.Elem()
		rv = rv.Elem()
	}

	var items []item

	for i := 0; i < rt.NumField(); i++ {
		var (
			field = rt.Field(i)
			value = rv.FieldByName(field.Name)
		)
		if len(field.PkgPath) != 0 { // enexported
			continue
		}
		switch field.Type.Kind() {
		case reflect.Struct:
			i, err := bind(value.Addr().Interface())
			if err != nil {
				return nil, fmt.Errorf("'%s': %v", field.Name, err)
			}
			items = append(items, i...)
		default:
			item, err := makeItem(field, value)
			if err != nil {
				return nil, fmt.Errorf("'%s': %v", field.Name, err)
			}
			if len(item.key) != 0 {
				items = append(items, item)
			}
		}
	}
	return items, nil
}

func makeItem(field reflect.StructField, value reflect.Value) (item, error) {
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}

	if !value.IsValid() {
		return item{}, errInvalidValue
	}

	var (
		tagValue    string
		rawValue    string
		registryKey string
	)

	for _, key := range tags {
		tagValue = field.Tag.Get(key)
		switch key {
		case "registry":
			registryKey = tagValue
		case "default":
			rawValue = tagValue
		case "env":
			if value := os.Getenv(tagValue); len(value) != 0 {
				rawValue = value
			}
		case "flag":
			if len(tagValue) != 0 {
				if value := flag(tagValue); len(value) != 0 {
					rawValue = value
				}
			}
		}
	}

	new := item{key: registryKey, reference: value}

	if err := new.set(rawValue); err != nil {
		return item{}, err
	}

	return new, nil
}

func flag(name string) string {
	prefix := "--"
	if len(name) == 1 {
		prefix = "-"
	}
	name = prefix + name
	for i, arg := range args {
		if strings.Contains(arg, "=") && strings.HasPrefix(arg, name) {
			if parts := strings.Split(arg, "="); len(parts) == 2 {
				return parts[1]
			}
		}
		if arg == name {
			if len(args) >= i {
				return args[i+1]
			}
		}
	}
	return ""
}
<commit_msg>Add support int slice param type<commit_after>package registry

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
)

var errInvalidValue = errors.New("Invalid value")

var (
	tags            = []string{"default", "env", "flag", "registry"}
	typeStringSlice = reflect.TypeOf([]string{})
	typeIntSlice    = reflect.TypeOf([]int{})
)

type config struct {
	mutex sync.Locker
	ident string
	items []item
}

func (r *registry) Bind(i sync.Locker) error {
	items, err := bind(i)
	if err != nil {
		return err
	}
	r.configs = append(r.configs, config{
		mutex: i,
		ident: fmt.Sprintf("%s.%d", reflect.TypeOf(i).Elem().Name(), len(r.configs)+1),
		items: items,
	})
	if r.refreshInterval != -1 {
		r.bindChan <- struct{}{}
	}
	return nil
}

type item struct {
	key       string
	reference reflect.Value
}

func (i *item) set(rawValue string) error {
	if len(rawValue) == 0 {
		return nil
	}

	var (
		err          error
		defaultValue interface{}
	)

	switch i.reference.Type().Kind() {
	case reflect.String:
		defaultValue = rawValue
	case reflect.Int:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 0); err == nil {
			defaultValue = int(defaultValue.(int64))
		}
	case reflect.Int8:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 8); err == nil {
			defaultValue = int8(defaultValue.(int64))
		}
	case reflect.Int16:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 16); err == nil {
			defaultValue = int16(defaultValue.(int64))
		}
	case reflect.Int32:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 32); err == nil {
			defaultValue = int32(defaultValue.(int64))
		}
	case reflect.Int64:
		defaultValue, err = strconv.ParseInt(rawValue, 10, 64)
	case reflect.Uint:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 0); err == nil {
			defaultValue = uint(defaultValue.(uint64))
		}
	case reflect.Uint8:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 8); err == nil {
			defaultValue = uint8(defaultValue.(uint64))
		}
	case reflect.Uint16:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 16); err == nil {
			defaultValue = uint16(defaultValue.(uint64))
		}
	case reflect.Uint32:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 32); err == nil {
			defaultValue = uint32(defaultValue.(uint64))
		}
	case reflect.Uint64:
		defaultValue, err = strconv.ParseUint(rawValue, 10, 64)
	case reflect.Float32:
		if defaultValue, err = strconv.ParseFloat(rawValue, 10); err == nil {
			defaultValue = float32(defaultValue.(float64))
		}
	case reflect.Float64:
		defaultValue, err = strconv.ParseFloat(rawValue, 10)
	case reflect.Bool:
		defaultValue, err = strconv.ParseBool(rawValue)
	case reflect.Slice:
		switch i.reference.Type() {
		case typeStringSlice:
			defaultValue = strings.Split(rawValue, ",")
		case typeIntSlice:
			var (
				arr    []int
				arrVal int64
			)
			for _, v := range strings.Split(rawValue, ",") {
				if arrVal, err = strconv.ParseInt(v, 10, 64); err != nil {
					break
				}
				arr = append(arr, int(arrVal))
			}
			defaultValue = arr
		}
	}

	if err != nil {
		return err
	}

	if i.reference.CanSet() && defaultValue != nil {
		i.reference.Set(reflect.ValueOf(defaultValue))
	}
	return nil
}

func bind(i interface{}) ([]item, error) {
	var (
		rt = reflect.TypeOf(i)
		rv = reflect.ValueOf(i)
	)

	if rt.Kind() == reflect.Ptr {
		rt = rt.Elem()
		rv = rv.Elem()
	}

	var items []item

	for i := 0; i < rt.NumField(); i++ {
		var (
			field = rt.Field(i)
			value = rv.FieldByName(field.Name)
		)
		if len(field.PkgPath) != 0 { // enexported
			continue
		}
		switch field.Type.Kind() {
		case reflect.Struct:
			i, err := bind(value.Addr().Interface())
			if err != nil {
				return nil, fmt.Errorf("'%s': %v", field.Name, err)
			}
			items = append(items, i...)
		default:
			item, err := makeItem(field, value)
			if err != nil {
				return nil, fmt.Errorf("'%s': %v", field.Name, err)
			}
			if len(item.key) != 0 {
				items = append(items, item)
			}
		}
	}
	return items, nil
}

func makeItem(field reflect.StructField, value reflect.Value) (item, error) {
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}

	if !value.IsValid() {
		return item{}, errInvalidValue
	}

	var (
		tagValue    string
		rawValue    string
		registryKey string
	)

	for _, key := range tags {
		tagValue = field.Tag.Get(key)
		switch key {
		case "registry":
			registryKey = tagValue
		case "default":
			rawValue = tagValue
		case "env":
			if value := os.Getenv(tagValue); len(value) != 0 {
				rawValue = value
			}
		case "flag":
			if len(tagValue) != 0 {
				if value := flag(tagValue); len(value) != 0 {
					rawValue = value
				}
			}
		}
	}

	new := item{key: registryKey, reference: value}

	if err := new.set(rawValue); err != nil {
		return item{}, err
	}

	return new, nil
}

func flag(name string) string {
	prefix := "--"
	if len(name) == 1 {
		prefix = "-"
	}
	name = prefix + name
	for i, arg := range args {
		if strings.Contains(arg, "=") && strings.HasPrefix(arg, name) {
			if parts := strings.Split(arg, "="); len(parts) == 2 {
				return parts[1]
			}
		}
		if arg == name {
			if len(args) >= i {
				return args[i+1]
			}
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package wikifier

type tocBlock struct {
	secCount int
	*parserBlock
}

func newTocBlock(name string, b *parserBlock) block {
	return &tocBlock{0, b}
}

func (toc *tocBlock) html(page *Page, el element) {
	el.setTag("ul")
	el.addHTML(HTML("
Contents
"))

	// add each top-level section
	for _, child := range page.main.blockContent() {
		if sec, ok := child.(*secBlock); ok {
			toc.tocAdd(sec, el, page)
		}
	}

	// don't show the toc if there are <2 on the page
	if toc.secCount < 2 {
		el.hide()
	}
}

func (toc *tocBlock) tocAdd(sec *secBlock, addTo element, page *Page) {
	toc.secCount++

	// create an item for this section
	var subList element
	if !sec.isIntro {
		li := addTo.createChild("li", "")
		a := li.createChild("a", "link-internal")
		a.setAttr("href", "#"+sec.headingID)
		a.addHTML(page.formatTextOpts(sec.title, fmtOpt{pos: sec.openPos}))
		addTo = li
	} else {
		subList = addTo
	}

	// create a sub-list for each section underneath
	for _, child := range sec.blockContent() {
		if secChild, ok := child.(*secBlock); ok {
			if subList == nil {
				subList = addTo.createChild("ul", "")
			}
			toc.tocAdd(secChild, subList, page)
		}
	}
}
<commit_msg>in toc{}, if there's no title, skip the level increase #41<commit_after>package wikifier

type tocBlock struct {
	secCount int
	*parserBlock
}

func newTocBlock(name string, b *parserBlock) block {
	return &tocBlock{0, b}
}

func (toc *tocBlock) html(page *Page, el element) {
	el.setTag("ul")
	el.addHTML(HTML("
Contents
"))

	// add each top-level section
	for _, child := range page.main.blockContent() {
		if sec, ok := child.(*secBlock); ok {
			toc.tocAdd(sec, el, page)
		}
	}

	// don't show the toc if there are <2 on the page
	if toc.secCount < 2 {
		el.hide()
	}
}

func (toc *tocBlock) tocAdd(sec *secBlock, addTo element, page *Page) {
	toc.secCount++

	// create an item for this section if it has a title and isn't intro
	var subList element
	if !sec.isIntro || sec.title == "" {
		li := addTo.createChild("li", "")
		a := li.createChild("a", "link-internal")
		a.setAttr("href", "#"+sec.headingID)
		a.addHTML(page.formatTextOpts(sec.title, fmtOpt{pos: sec.openPos}))
		addTo = li
	} else {
		subList = addTo
	}

	// create a sub-list for each section underneath
	for _, child := range sec.blockContent() {
		if secChild, ok := child.(*secBlock); ok {
			if subList == nil {
				subList = addTo.createChild("ul", "")
			}
			toc.tocAdd(secChild, subList, page)
		}
	}
}
<|endoftext|>


<commit_before>package fs

import (
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"sync"
)

type EntryKind uint8

const (
	DirEntry  EntryKind = 1
	FileEntry EntryKind = 2
)

type Entry struct {
	Kind EntryKind
}

type FS interface {
	// The returned map is immutable and is cached across invocations. Do not
	// mutate it.
	ReadDirectory(path string) map[string]Entry
	ReadFile(path string) (string, bool)

	// This is part of the interface because the mock interface used for tests
	// should not depend on file system behavior (i.e. different slashes for
	// Windows) while the real interface should.
	Dir(path string) string
	Base(path string) string
	Join(parts ...string) string
	RelativeToCwd(path string) (string, bool)
}

////////////////////////////////////////////////////////////////////////////////

type mockFS struct {
	dirs  map[string]map[string]Entry
	files map[string]string
}

func MockFS(input map[string]string) FS {
	dirs := make(map[string]map[string]Entry)
	files := make(map[string]string)

	for k, v := range input {
		files[k] = v
		original := k

		// Build the directory map
		for {
			kDir := path.Dir(k)
			dir, ok := dirs[kDir]
			if !ok {
				dir = make(map[string]Entry)
				dirs[kDir] = dir
			}
			if kDir == k {
				break
			}
			if k == original {
				dir[path.Base(k)] = Entry{Kind: FileEntry}
			} else {
				dir[path.Base(k)] = Entry{Kind: DirEntry}
			}
			k = kDir
		}
	}

	return &mockFS{dirs, files}
}

func (fs *mockFS) ReadDirectory(path string) map[string]Entry {
	return fs.dirs[path]
}

func (fs *mockFS) ReadFile(path string) (string, bool) {
	contents, ok := fs.files[path]
	return contents, ok
}

func (*mockFS) Dir(p string) string {
	return path.Dir(p)
}

func (*mockFS) Base(p string) string {
	return path.Base(p)
}

func (*mockFS) Join(parts ...string) string {
	return path.Clean(path.Join(parts...))
}

func (*mockFS) RelativeToCwd(path string) (string, bool) {
	return "", false
}

////////////////////////////////////////////////////////////////////////////////

type realFS struct {
	// Stores the file entries for directories we've listed before
	entriesMutex sync.RWMutex
	entries      map[string]map[string]Entry

	// For the current working directory
	cwd   string
	cwdOk bool
}

func RealFS() FS {
	cwd, cwdErr := os.Getwd()
	return &realFS{
		entries: make(map[string]map[string]Entry),
		cwd:     cwd,
		cwdOk:   cwdErr == nil,
	}
}

func (fs *realFS) ReadDirectory(dir string) map[string]Entry {
	// First, check the cache
	cached, ok := func() (map[string]Entry, bool) {
		fs.entriesMutex.RLock()
		defer fs.entriesMutex.RUnlock()
		cached, ok := fs.entries[dir]
		return cached, ok
	}()

	// Cache hit: stop now
	if ok {
		return cached
	}

	// Cache miss: read the directory entries
	names, err := readdir(dir)
	entries := make(map[string]Entry)
	if err == nil {
		for _, name := range names {
			// Use "stat", not "lstat", because we want to follow symbolic links
			if stat, err := os.Stat(filepath.Join(dir, name)); err == nil {
				if stat.IsDir() {
					entries[name] = Entry{Kind: DirEntry}
				} else {
					entries[name] = Entry{Kind: FileEntry}
				}
			}
		}
	}

	// Update the cache unconditionally. Even if the read failed, we don't want to
	// retry again later. The directory is inaccessible so trying again is wasted.
	fs.entriesMutex.Lock()
	defer fs.entriesMutex.Unlock()
	if err != nil {
		fs.entries[dir] = nil
		return nil
	}
	fs.entries[dir] = entries
	return entries
}

func (fs *realFS) ReadFile(path string) (string, bool) {
	buffer, err := ioutil.ReadFile(path)
	return string(buffer), err == nil
}

func (*realFS) Dir(p string) string {
	return filepath.Dir(p)
}

func (*realFS) Base(p string) string {
	return filepath.Base(p)
}

func (*realFS) Join(parts ...string) string {
	return filepath.Clean(filepath.Join(parts...))
}

func (fs *realFS) RelativeToCwd(path string) (string, bool) {
	if fs.cwdOk {
		if rel, err := filepath.Rel(fs.cwd, path); err == nil {
			return rel, true
		}
	}
	return "", false
}

func readdir(dirname string) ([]string, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return f.Readdirnames(-1)
}
<commit_msg>add symlink info to ReadDirectory<commit_after>package fs

import (
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"sync"
)

type EntryKind uint8

const (
	DirEntry  EntryKind = 1
	FileEntry EntryKind = 2
)

type Entry struct {
	Kind    EntryKind
	Symlink string
}

type FS interface {
	// The returned map is immutable and is cached across invocations. Do not
	// mutate it.
	ReadDirectory(path string) map[string]Entry
	ReadFile(path string) (string, bool)

	// This is part of the interface because the mock interface used for tests
	// should not depend on file system behavior (i.e. different slashes for
	// Windows) while the real interface should.
	Dir(path string) string
	Base(path string) string
	Join(parts ...string) string
	RelativeToCwd(path string) (string, bool)
}

////////////////////////////////////////////////////////////////////////////////

type mockFS struct {
	dirs  map[string]map[string]Entry
	files map[string]string
}

func MockFS(input map[string]string) FS {
	dirs := make(map[string]map[string]Entry)
	files := make(map[string]string)

	for k, v := range input {
		files[k] = v
		original := k

		// Build the directory map
		for {
			kDir := path.Dir(k)
			dir, ok := dirs[kDir]
			if !ok {
				dir = make(map[string]Entry)
				dirs[kDir] = dir
			}
			if kDir == k {
				break
			}
			if k == original {
				dir[path.Base(k)] = Entry{Kind: FileEntry}
			} else {
				dir[path.Base(k)] = Entry{Kind: DirEntry}
			}
			k = kDir
		}
	}

	return &mockFS{dirs, files}
}

func (fs *mockFS) ReadDirectory(path string) map[string]Entry {
	return fs.dirs[path]
}

func (fs *mockFS) ReadFile(path string) (string, bool) {
	contents, ok := fs.files[path]
	return contents, ok
}

func (*mockFS) Dir(p string) string {
	return path.Dir(p)
}

func (*mockFS) Base(p string) string {
	return path.Base(p)
}

func (*mockFS) Join(parts ...string) string {
	return path.Clean(path.Join(parts...))
}

func (*mockFS) RelativeToCwd(path string) (string, bool) {
	return "", false
}

////////////////////////////////////////////////////////////////////////////////

type realFS struct {
	// Stores the file entries for directories we've listed before
	entriesMutex sync.RWMutex
	entries      map[string]map[string]Entry

	// For the current working directory
	cwd   string
	cwdOk bool
}

func RealFS() FS {
	cwd, cwdErr := os.Getwd()
	return &realFS{
		entries: make(map[string]map[string]Entry),
		cwd:     cwd,
		cwdOk:   cwdErr == nil,
	}
}

func (fs *realFS) ReadDirectory(dir string) map[string]Entry {
	// First, check the cache
	cached, ok := func() (map[string]Entry, bool) {
		fs.entriesMutex.RLock()
		defer fs.entriesMutex.RUnlock()
		cached, ok := fs.entries[dir]
		return cached, ok
	}()

	// Cache hit: stop now
	if ok {
		return cached
	}

	// Cache miss: read the directory entries
	names, err := readdir(dir)
	entries := make(map[string]Entry)
	if err == nil {
		for _, name := range names {
			entryPath := filepath.Join(dir, name)

			// Use "lstat" since we want information about symbolic links
			if stat, err := os.Lstat(entryPath); err == nil {
				mode := stat.Mode()
				symlink := ""

				// Follow symlinks now so the cache contains the translation
				if (mode & os.ModeSymlink) != 0 {
					link, err := os.Readlink(entryPath)
					if err != nil {
						continue // Skip over this entry
					}
					symlink = filepath.Clean(filepath.Join(dir, link))

					// Re-run "lstat" on the symlink target
					stat2, err2 := os.Lstat(symlink)
					if err2 != nil {
						continue // Skip over this entry
					}
					mode = stat2.Mode()
					if (mode & os.ModeSymlink) != 0 {
						continue // Symlink chains are not supported
					}
				}

				// We consider the entry either a directory or a file
				if (mode & os.ModeDir) != 0 {
					entries[name] = Entry{Kind: DirEntry, Symlink: symlink}
				} else {
					entries[name] = Entry{Kind: FileEntry, Symlink: symlink}
				}
			}
		}
	}

	// Update the cache unconditionally. Even if the read failed, we don't want to
	// retry again later. The directory is inaccessible so trying again is wasted.
	fs.entriesMutex.Lock()
	defer fs.entriesMutex.Unlock()
	if err != nil {
		fs.entries[dir] = nil
		return nil
	}
	fs.entries[dir] = entries
	return entries
}

func (fs *realFS) ReadFile(path string) (string, bool) {
	buffer, err := ioutil.ReadFile(path)
	return string(buffer), err == nil
}

func (*realFS) Dir(p string) string {
	return filepath.Dir(p)
}

func (*realFS) Base(p string) string {
	return filepath.Base(p)
}

func (*realFS) Join(parts ...string) string {
	return filepath.Clean(filepath.Join(parts...))
}

func (fs *realFS) RelativeToCwd(path string) (string, bool) {
	if fs.cwdOk {
		if rel, err := filepath.Rel(fs.cwd, path); err == nil {
			return rel, true
		}
	}
	return "", false
}

func readdir(dirname string) ([]string, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return f.Readdirnames(-1)
}
<|endoftext|>


<commit_before>// This is a wrapper around make that runs the given target conditionally, i.e. only when considered necessary.
//
// For example, the Homebrew target only bumps the formula for vespa-cli if no pull request has previously been made
// for the latest release.
//
// This source file is not part of the standard Vespa CLI build and is only used from the Makefile in this directory.

//go:build ignore

package main

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

func init() {
	log.SetPrefix("cond-make: ")
	log.SetFlags(0) // No timestamps
}

func requireEnv(variable string) (string, error) {
	value := os.Getenv(variable)
	if value == "" {
		return "", fmt.Errorf("environment variable %s is not set", variable)
	}
	return value, nil
}

func quote(args []string) string {
	var sb strings.Builder
	for i, arg := range args {
		if strings.Contains(arg, " ") {
			sb.WriteString(fmt.Sprintf("%q", arg))
		} else {
			sb.WriteString(arg)
		}
		if i < len(args)-1 {
			sb.WriteString(" ")
		}
	}
	return sb.String()
}

func newCmd(name string, arg ...string) (*exec.Cmd, *bytes.Buffer, *bytes.Buffer) {
	cmd := exec.Command(name, arg...)
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = io.MultiWriter(os.Stdout, &stdout)
	cmd.Stderr = io.MultiWriter(os.Stderr, &stderr)
	log.Printf("$ %s", quote(cmd.Args))
	return cmd, &stdout, &stderr
}

func runCmd(name string, arg ...string) (string, string, error) {
	cmd, stdout, stderr := newCmd(name, arg...)
	err := cmd.Run()
	return stdout.String(), stderr.String(), err
}

// latestTag returns the most recent tag as determined by sorting local git tags as version numbers.
func latestTag() (string, error) {
	stdout, _, err := runCmd("sh", "-c", "git tag -l 'v[0-9]*' | sort -V | tail -1")
	if err != nil {
		return "", err
	}
	version := strings.TrimSpace(stdout)
	if version == "" {
		return "", fmt.Errorf("no tag found")
	}
	return version, nil
}

// latestReleasedTag returns the tag of the most recent release available on given mirror.
func latestReleasedTag(mirror string) (string, error) {
	switch mirror {
	case "github":
		resp, err := http.Get("https://api.github.com/repos/vespa-engine/vespa/releases/latest")
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()
		var release gitHubRelease
		dec := json.NewDecoder(resp.Body)
		if err := dec.Decode(&release); err != nil {
			return "", err
		}
		return release.TagName, nil
	case "homebrew":
		cmd, stdout, _ := newCmd("brew", "info", "--json", "--formula", "vespa-cli")
		cmd.Stdout = stdout // skip printing output to os.Stdout
		if err := cmd.Run(); err != nil {
			return "", err
		}
		var brewInfo []brewFormula
		if err := json.Unmarshal(stdout.Bytes(), &brewInfo); err != nil {
			return "", err
		}
		if len(brewInfo) == 0 {
			return "", fmt.Errorf("vespa-cli formula not found")
		}
		return "v" + brewInfo[0].Versions.Stable, nil
	}
	return "", fmt.Errorf("invalid mirror: %q", mirror)
}

// hasChanges returns true if there are changes to Vespa CLI code between tag1 and tag2.
func hasChanges(tag1, tag2 string) (bool, error) {
	_, _, err := runCmd("git", "diff", "--quiet", tag1, tag2, ".")
	if err != nil {
		var exitErr *exec.ExitError
		if errors.As(err, &exitErr) {
			switch exitErr.ExitCode() {
			case 0:
				return false, nil
			case 1:
				return true, nil
			}
		}
	}
	return false, err
}

// candidateTag returns the latest tag that should be released to mirror. If there is nothing to release, the returned
// tag is empty.
func candidateTag(mirror string) (string, error) {
	latestTag, err := latestTag()
	if err != nil {
		return "", err
	}
	releasedTag, err := latestReleasedTag(mirror)
	if err != nil {
		return "", err
	}
	changes, err := hasChanges(releasedTag, latestTag)
	if err != nil {
		return "", err
	}
	if !changes {
		log.Printf("no changes found between %s and %s: skipping release", releasedTag, latestTag)
		return "", nil
	}
	log.Printf("found changes between %s and %s: creating release", releasedTag, latestTag)
	return latestTag, nil
}

// switchToTag checks out the given tag in git and returns the current branch name. The Makefile and this file always
// preserved from current branch after checking out tag.
func switchToTag(tag string) (string, error) {
	stdout, _, err := runCmd("git", "rev-parse", "--abbrev-ref", "HEAD")
	if err != nil {
		return "", err
	}
	prevBranch := strings.TrimSpace(stdout)
	if err := checkoutRef(tag); err != nil {
		return "", err
	}
	_, _, err = runCmd("git", "checkout", prevBranch, "Makefile", "cond_make.go")
	if err != nil {
		return "", err
	}
	return prevBranch, err
}

func checkoutRef(ref string) error {
	_, _, err := runCmd("git", "checkout", ref)
	return err
}

// releaseToHomebrew releases Vespa CLI to GitHub by calling the given make target, if necessary.
func releaseToHomebrew(target string) error {
	if _, err := requireEnv("HOMEBREW_GITHUB_API_TOKEN"); err != nil {
		return err
	}
	tag, err := candidateTag("homebrew")
	if tag == "" || err != nil {
		return err
	}
	prevBranch, err := switchToTag(tag)
	if err != nil {
		return err
	}
	defer checkoutRef(prevBranch)
	_, stderr, err := runCmd("make", "--", target)
	if err != nil {
		if strings.Contains(stderr, "Error: These pull requests may be duplicates:") {
			return nil // fine, pull request already created
		}
	}
	return err
}

// releaseToGitHub releases Vespa CLI to GitHub by calling the given make target, if necessary.
func releaseToGitHub(target string) error {
	if _, err := requireEnv("GH_TOKEN"); err != nil {
		return err
	}
	tag, err := candidateTag("github")
	if tag == "" || err != nil {
		return err
	}
	prevBranch, err := switchToTag(tag)
	if err != nil {
		return err
	}
	defer checkoutRef(prevBranch)
	_, _, err = runCmd("make", "--", target)
	return err
}

func main() {
	if len(os.Args) != 2 {
		log.Fatalf("usage: %s TARGET", os.Args[0])
	}
	target := os.Args[1]
	switch target {
	case "--dist-homebrew":
		if err := releaseToHomebrew(target); err != nil {
			log.Fatal(err)
		}
	case "--dist-github":
		if err := releaseToGitHub(target); err != nil {
			log.Fatal(err)
		}
	default:
		log.Fatalf("unsupported target: %s", target)
	}
}

type gitHubRelease struct {
	TagName string `json:"tag_name"`
}

type brewFormula struct {
	Versions brewVersions `json:"versions"`
}

type brewVersions struct {
	Stable string `json:"stable"`
}
<commit_msg>Make build compatible with Go 1.16<commit_after>// This is a wrapper around make that runs the given target conditionally, i.e. only when considered necessary.
//
// For example, the Homebrew target only bumps the formula for vespa-cli if no pull request has previously been made
// for the latest release.
//
// This source file is not part of the standard Vespa CLI build and is only used from the Makefile in this directory.

//go:build ignore
// +build ignore

package main

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

func init() {
	log.SetPrefix("cond-make: ")
	log.SetFlags(0) // No timestamps
}

func requireEnv(variable string) (string, error) {
	value := os.Getenv(variable)
	if value == "" {
		return "", fmt.Errorf("environment variable %s is not set", variable)
	}
	return value, nil
}

func quote(args []string) string {
	var sb strings.Builder
	for i, arg := range args {
		if strings.Contains(arg, " ") {
			sb.WriteString(fmt.Sprintf("%q", arg))
		} else {
			sb.WriteString(arg)
		}
		if i < len(args)-1 {
			sb.WriteString(" ")
		}
	}
	return sb.String()
}

func newCmd(name string, arg ...string) (*exec.Cmd, *bytes.Buffer, *bytes.Buffer) {
	cmd := exec.Command(name, arg...)
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = io.MultiWriter(os.Stdout, &stdout)
	cmd.Stderr = io.MultiWriter(os.Stderr, &stderr)
	log.Printf("$ %s", quote(cmd.Args))
	return cmd, &stdout, &stderr
}

func runCmd(name string, arg ...string) (string, string, error) {
	cmd, stdout, stderr := newCmd(name, arg...)
	err := cmd.Run()
	return stdout.String(), stderr.String(), err
}

// latestTag returns the most recent tag as determined by sorting local git tags as version numbers.
func latestTag() (string, error) {
	stdout, _, err := runCmd("sh", "-c", "git tag -l 'v[0-9]*' | sort -V | tail -1")
	if err != nil {
		return "", err
	}
	version := strings.TrimSpace(stdout)
	if version == "" {
		return "", fmt.Errorf("no tag found")
	}
	return version, nil
}

// latestReleasedTag returns the tag of the most recent release available on given mirror.
func latestReleasedTag(mirror string) (string, error) {
	switch mirror {
	case "github":
		resp, err := http.Get("https://api.github.com/repos/vespa-engine/vespa/releases/latest")
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()
		var release gitHubRelease
		dec := json.NewDecoder(resp.Body)
		if err := dec.Decode(&release); err != nil {
			return "", err
		}
		return release.TagName, nil
	case "homebrew":
		cmd, stdout, _ := newCmd("brew", "info", "--json", "--formula", "vespa-cli")
		cmd.Stdout = stdout // skip printing output to os.Stdout
		if err := cmd.Run(); err != nil {
			return "", err
		}
		var brewInfo []brewFormula
		if err := json.Unmarshal(stdout.Bytes(), &brewInfo); err != nil {
			return "", err
		}
		if len(brewInfo) == 0 {
			return "", fmt.Errorf("vespa-cli formula not found")
		}
		return "v" + brewInfo[0].Versions.Stable, nil
	}
	return "", fmt.Errorf("invalid mirror: %q", mirror)
}

// hasChanges returns true if there are changes to Vespa CLI code between tag1 and tag2.
func hasChanges(tag1, tag2 string) (bool, error) {
	_, _, err := runCmd("git", "diff", "--quiet", tag1, tag2, ".")
	if err != nil {
		var exitErr *exec.ExitError
		if errors.As(err, &exitErr) {
			switch exitErr.ExitCode() {
			case 0:
				return false, nil
			case 1:
				return true, nil
			}
		}
	}
	return false, err
}

// candidateTag returns the latest tag that should be released to mirror. If there is nothing to release, the returned
// tag is empty.
func candidateTag(mirror string) (string, error) {
	latestTag, err := latestTag()
	if err != nil {
		return "", err
	}
	releasedTag, err := latestReleasedTag(mirror)
	if err != nil {
		return "", err
	}
	changes, err := hasChanges(releasedTag, latestTag)
	if err != nil {
		return "", err
	}
	if !changes {
		log.Printf("no changes found between %s and %s: skipping release", releasedTag, latestTag)
		return "", nil
	}
	log.Printf("found changes between %s and %s: creating release", releasedTag, latestTag)
	return latestTag, nil
}

// switchToTag checks out the given tag in git and returns the current branch name. The Makefile and this file always
// preserved from current branch after checking out tag.
func switchToTag(tag string) (string, error) {
	stdout, _, err := runCmd("git", "rev-parse", "--abbrev-ref", "HEAD")
	if err != nil {
		return "", err
	}
	prevBranch := strings.TrimSpace(stdout)
	if err := checkoutRef(tag); err != nil {
		return "", err
	}
	_, _, err = runCmd("git", "checkout", prevBranch, "Makefile", "cond_make.go")
	if err != nil {
		return "", err
	}
	return prevBranch, err
}

func checkoutRef(ref string) error {
	_, _, err := runCmd("git", "checkout", ref)
	return err
}

// releaseToHomebrew releases Vespa CLI to GitHub by calling the given make target, if necessary.
func releaseToHomebrew(target string) error {
	if _, err := requireEnv("HOMEBREW_GITHUB_API_TOKEN"); err != nil {
		return err
	}
	tag, err := candidateTag("homebrew")
	if tag == "" || err != nil {
		return err
	}
	prevBranch, err := switchToTag(tag)
	if err != nil {
		return err
	}
	defer checkoutRef(prevBranch)
	_, stderr, err := runCmd("make", "--", target)
	if err != nil {
		if strings.Contains(stderr, "Error: These pull requests may be duplicates:") {
			return nil // fine, pull request already created
		}
	}
	return err
}

// releaseToGitHub releases Vespa CLI to GitHub by calling the given make target, if necessary.
func releaseToGitHub(target string) error {
	if _, err := requireEnv("GH_TOKEN"); err != nil {
		return err
	}
	tag, err := candidateTag("github")
	if tag == "" || err != nil {
		return err
	}
	prevBranch, err := switchToTag(tag)
	if err != nil {
		return err
	}
	defer checkoutRef(prevBranch)
	_, _, err = runCmd("make", "--", target)
	return err
}

func main() {
	if len(os.Args) != 2 {
		log.Fatalf("usage: %s TARGET", os.Args[0])
	}
	target := os.Args[1]
	switch target {
	case "--dist-homebrew":
		if err := releaseToHomebrew(target); err != nil {
			log.Fatal(err)
		}
	case "--dist-github":
		if err := releaseToGitHub(target); err != nil {
			log.Fatal(err)
		}
	default:
		log.Fatalf("unsupported target: %s", target)
	}
}

type gitHubRelease struct {
	TagName string `json:"tag_name"`
}

type brewFormula struct {
	Versions brewVersions `json:"versions"`
}

type brewVersions struct {
	Stable string `json:"stable"`
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/mail"
	"os"
	"os/signal"
	"time"
)

const (
	tasklist_template = "ui_template.html"
)

type Task struct {
	Description string
	Frequency   time.Duration
	Users       []User // already a list (future feature)
}
type User mail.Address
type TaskList map[string]Task

func main() {

	file := "tasks.json"
	tasks := loadFromJson(file)
	defer saveToJson(file, tasks)

	go uiServer(8080, tasks)
	// go handleGlobalContext(&ctx)

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	select {
	case <-sig:
		fmt.Println("\nExiting …")
	}
}

func uiServer(port int, tasks TaskList) {
	http.Handle("/", tasks)
	http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, r.URL.Path[1:])
	})
	http.ListenAndServe(fmt.Sprintf(":%d", port), nil)

}

func (tasks TaskList) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case "GET":
		if req.URL.Path == "/" {
			w.Header()["Content-Type"] = []string{"text/html"}
			ts, err := ioutil.ReadFile(tasklist_template)
			logFatal(err)
			t := template.Must(template.New("tasklist").Parse(string(ts)))

			t.Execute(w, tasks)
		}

	case "POST":
		err := req.ParseForm()
		if err == nil {
			if req.URL.Path == "/commit" {
				/* What we get via POST:
				E-Mail: email
				Name: name
				each checked task is transmitted as one key
				(see for-loop below)
				req.Form looks like this:
				map[name:[sternenseemann] Foobar:[do] submit:[Commit] email:[foo@foo.de]]
				*/
				for taskname, _ := range tasks {
					if req.Form[taskname] != nil {
						fmt.Println("The User", req.Form["name"][0], "with email", req.Form["email"][0],
							"commited theirselves the task", taskname)
						fmt.Println(tasks[taskname])
					}
				}
				http.Redirect(w, req, "/", http.StatusFound)
			}
		} else {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	}

}

func loadFromJson(file string) TaskList {
	b, err := ioutil.ReadFile(file)
	if err != nil {
		l := make(TaskList)
		return l
	}
	var tasks TaskList
	err = json.Unmarshal(b, &tasks)
	logFatal(err)
	return tasks
}

func saveToJson(file string, tasks TaskList) {
	b, err := json.Marshal(tasks)

	logFatal(err)
	err = ioutil.WriteFile(file, b, 0644)
	logFatal(err)
}

func logFatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>save before exiting<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/mail"
	"os"
	"os/signal"
	"time"
)

const (
	tasklist_template = "ui_template.html"
)

type Task struct {
	Description string
	Frequency   time.Duration
	Users       []User // already a list (future feature)
}
type User mail.Address
type TaskList map[string]Task

func main() {

	file := "tasks.json"
	tasks := loadFromJson(file)
	defer saveToJson(file, tasks)

	go uiServer(8080, tasks)
	// go handleGlobalContext(&ctx)

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	select {
	case <-sig:
		saveToJson(file, tasks)
		fmt.Println("\nExiting …")
	}
}

func uiServer(port int, tasks TaskList) {
	http.Handle("/", tasks)
	http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, r.URL.Path[1:])
	})
	http.ListenAndServe(fmt.Sprintf(":%d", port), nil)

}

func (tasks TaskList) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case "GET":
		if req.URL.Path == "/" {
			w.Header()["Content-Type"] = []string{"text/html"}
			ts, err := ioutil.ReadFile(tasklist_template)
			logFatal(err)
			t := template.Must(template.New("tasklist").Parse(string(ts)))

			t.Execute(w, tasks)
		}

	case "POST":
		err := req.ParseForm()
		if err == nil {
			if req.URL.Path == "/commit" {
				/* What we get via POST:
				E-Mail: email
				Name: name
				each checked task is transmitted as one key
				(see for-loop below)
				req.Form looks like this:
				map[name:[sternenseemann] Foobar:[do] submit:[Commit] email:[foo@foo.de]]
				*/
				for taskname, _ := range tasks {
					if req.Form[taskname] != nil {
						fmt.Println("The User", req.Form["name"][0], "with email", req.Form["email"][0],
							"commited theirselves the task", taskname)
						fmt.Println(tasks[taskname])
					}
				}
				http.Redirect(w, req, "/", http.StatusFound)
			}
		} else {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	}

}

func loadFromJson(file string) TaskList {
	b, err := ioutil.ReadFile(file)
	if err != nil {
		l := make(TaskList)
		return l
	}
	var tasks TaskList
	err = json.Unmarshal(b, &tasks)
	logFatal(err)
	return tasks
}

func saveToJson(file string, tasks TaskList) {
	b, err := json.Marshal(tasks)

	logFatal(err)
	err = ioutil.WriteFile(file, b, 0644)
	logFatal(err)
}

func logFatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"golang.org/x/oauth2"
	"gopkg.in/authboss.v0"
	_ "gopkg.in/authboss.v0/auth"
	_ "gopkg.in/authboss.v0/confirm"
	_ "gopkg.in/authboss.v0/lock"
	aboauth "gopkg.in/authboss.v0/oauth2"
	_ "gopkg.in/authboss.v0/recover"
	_ "gopkg.in/authboss.v0/register"
	_ "gopkg.in/authboss.v0/remember"

	"github.com/aarondl/tpl"
	"github.com/gorilla/mux"
	"github.com/gorilla/schema"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"github.com/justinas/alice"
	"github.com/justinas/nosurf"
)

var funcs = template.FuncMap{
	"formatDate": func(date time.Time) string {
		return date.Format("2006/01/02 03:04pm")
	},
	"yield": func() string { return "" },
}

var (
	ab        = authboss.New()
	database  = NewMemStorer()
	templates = tpl.Must(tpl.Load("views", "views/partials", "layout.html.tpl", funcs))
	schemaDec = schema.NewDecoder()
)

func setupAuthboss() {
	ab.Storer = database
	ab.OAuth2Storer = database
	ab.MountPath = "/auth"
	ab.ViewsPath = "ab_views"
	ab.RootURL = `http://localhost:3000`

	ab.LayoutDataMaker = layoutData

	ab.OAuth2Providers = map[string]authboss.OAuth2Provider{
		"google": authboss.OAuth2Provider{
			OAuth2Config: &oauth2.Config{
				ClientID:     ``,
				ClientSecret: ``,
				Scopes:       []string{`profile`, `email`},
				Endpoint:     aboauth.GoogleEndpoint,
			},
			Callback: aboauth.Google,
		},
	}

	b, err := ioutil.ReadFile(filepath.Join("views", "layout.html.tpl"))
	if err != nil {
		panic(err)
	}
	ab.Layout = template.Must(template.New("layout").Funcs(funcs).Parse(string(b)))

	ab.XSRFName = "csrf_token"
	ab.XSRFMaker = func(_ http.ResponseWriter, r *http.Request) string {
		return nosurf.Token(r)
	}

	ab.CookieStoreMaker = NewCookieStorer
	ab.SessionStoreMaker = NewSessionStorer

	ab.Mailer = authboss.LogMailer(os.Stdout)

	ab.Policies = []authboss.Validator{
		authboss.Rules{
			FieldName:       "email",
			Required:        true,
			AllowWhitespace: false,
		},
		authboss.Rules{
			FieldName:       "password",
			Required:        true,
			MinLength:       4,
			MaxLength:       8,
			AllowWhitespace: false,
		},
	}

	if err := ab.Init(); err != nil {
		log.Fatal(err)
	}
}

func main() {
	// Initialize Sessions and Cookies
	// Typically gorilla securecookie and sessions packages require
	// highly random secret keys that are not divulged to the public.
	//
	// In this example we use keys generated one time (if these keys ever become
	// compromised the gorilla libraries allow for key rotation, see gorilla docs)
	// The keys are 64-bytes as recommended for HMAC keys as per the gorilla docs.
	//
	// These values MUST be changed for any new project as these keys are already "compromised"
	// as they're in the public domain, if you do not change these your application will have a fairly
	// wide-opened security hole. You can generate your own with the code below, or using whatever method
	// you prefer:
	//
	//    func main() {
	//        fmt.Println(base64.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(64)))
	//    }
	//
	// We store them in base64 in the example to make it easy if we wanted to move them later to
	// a configuration environment var or file.
	cookieStoreKey, _ := base64.StdEncoding.DecodeString(`NpEPi8pEjKVjLGJ6kYCS+VTCzi6BUuDzU0wrwXyf5uDPArtlofn2AG6aTMiPmN3C909rsEWMNqJqhIVPGP3Exg==`)
	sessionStoreKey, _ := base64.StdEncoding.DecodeString(`AbfYwmmt8UCwUuhd9qvfNA9UCuN1cVcKJN1ofbiky6xCyyBj20whe40rJa3Su0WOWLWcPpO1taqJdsEI/65+JA==`)
	cookieStore = securecookie.New(cookieStoreKey, nil)
	sessionStore = sessions.NewCookieStore(sessionStoreKey)

	// Initialize ab.
	setupAuthboss()

	// Set up our router
	schemaDec.IgnoreUnknownKeys(true)
	mux := mux.NewRouter()

	// Routes
	gets := mux.Methods("GET").Subrouter()
	posts := mux.Methods("POST").Subrouter()

	mux.PathPrefix("/auth").Handler(ab.NewRouter())

	gets.Handle("/blogs/new", authProtect(newblog))
	gets.Handle("/blogs/{id}/edit", authProtect(edit))
	gets.HandleFunc("/blogs", index)
	gets.HandleFunc("/", index)

	posts.Handle("/blogs/{id}/edit", authProtect(update))
	posts.Handle("/blogs/new", authProtect(create))

	// This should actually be a DELETE but I can't be bothered to make a proper
	// destroy link using javascript atm.
	gets.HandleFunc("/blogs/{id}/destroy", destroy)

	mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, "Not found")
	})

	// Set up our middleware chain
	stack := alice.New(logger /*nosurfing,*/, ab.ExpireMiddleware).Then(mux)

	// Start the server
	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "8080"
	}
	log.Println(http.ListenAndServe("localhost:"+port, stack))
}

func layoutData(w http.ResponseWriter, r *http.Request) authboss.HTMLData {
	currentUserName := ""
	userInter, err := ab.CurrentUser(w, r)
	if userInter != nil && err == nil {
		currentUserName = userInter.(*User).Name
	}

	return authboss.HTMLData{
		"loggedin":               userInter != nil,
		"username":               "",
		authboss.FlashSuccessKey: ab.FlashSuccess(w, r),
		authboss.FlashErrorKey:   ab.FlashError(w, r),
		"current_user_name":      currentUserName,
	}
}

func index(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("posts", blogs)
	mustRender(w, r, "index", data)
}

func newblog(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("post", Blog{})
	mustRender(w, r, "new", data)
}

var nextID = len(blogs) + 1

func create(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	// TODO: Validation

	var b Blog
	if badRequest(w, schemaDec.Decode(&b, r.PostForm)) {
		return
	}

	b.ID = nextID
	nextID++
	b.Date = time.Now()
	b.AuthorID = "Zeratul"

	blogs = append(blogs, b)

	http.Redirect(w, r, "/", http.StatusFound)
}

func edit(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	data := layoutData(w, r).MergeKV("post", blogs.Get(id))
	mustRender(w, r, "edit", data)
}

func update(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	id, ok := blogID(w, r)
	if !ok {
		return
	}

	// TODO: Validation

	var b = blogs.Get(id)
	if badRequest(w, schemaDec.Decode(b, r.PostForm)) {
		return
	}

	b.Date = time.Now()

	http.Redirect(w, r, "/", http.StatusFound)
}

func destroy(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	blogs.Delete(id)

	http.Redirect(w, r, "/", http.StatusFound)
}

func blogID(w http.ResponseWriter, r *http.Request) (int, bool) {
	vars := mux.Vars(r)
	str := vars["id"]

	id, err := strconv.Atoi(str)
	if err != nil {
		log.Println("Error parsing blog id:", err)
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	if id <= 0 {
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	return id, true
}

func mustRender(w http.ResponseWriter, r *http.Request, name string, data authboss.HTMLData) {
	data.MergeKV("csrf_token", nosurf.Token(r))
	err := templates.Render(w, name, data)
	if err == nil {
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintln(w, "Error occurred rendering template:", err)
}

func badRequest(w http.ResponseWriter, err error) bool {
	if err == nil {
		return false
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, "Bad request:", err)

	return true
}
<commit_msg>Fix default port to be 3000 like the rooturl says.<commit_after>package main

import (
	"encoding/base64"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"golang.org/x/oauth2"
	"gopkg.in/authboss.v0"
	_ "gopkg.in/authboss.v0/auth"
	_ "gopkg.in/authboss.v0/confirm"
	_ "gopkg.in/authboss.v0/lock"
	aboauth "gopkg.in/authboss.v0/oauth2"
	_ "gopkg.in/authboss.v0/recover"
	_ "gopkg.in/authboss.v0/register"
	_ "gopkg.in/authboss.v0/remember"

	"github.com/aarondl/tpl"
	"github.com/gorilla/mux"
	"github.com/gorilla/schema"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"github.com/justinas/alice"
	"github.com/justinas/nosurf"
)

var funcs = template.FuncMap{
	"formatDate": func(date time.Time) string {
		return date.Format("2006/01/02 03:04pm")
	},
	"yield": func() string { return "" },
}

var (
	ab        = authboss.New()
	database  = NewMemStorer()
	templates = tpl.Must(tpl.Load("views", "views/partials", "layout.html.tpl", funcs))
	schemaDec = schema.NewDecoder()
)

func setupAuthboss() {
	ab.Storer = database
	ab.OAuth2Storer = database
	ab.MountPath = "/auth"
	ab.ViewsPath = "ab_views"
	ab.RootURL = `http://localhost:3000`

	ab.LayoutDataMaker = layoutData

	ab.OAuth2Providers = map[string]authboss.OAuth2Provider{
		"google": authboss.OAuth2Provider{
			OAuth2Config: &oauth2.Config{
				ClientID:     ``,
				ClientSecret: ``,
				Scopes:       []string{`profile`, `email`},
				Endpoint:     aboauth.GoogleEndpoint,
			},
			Callback: aboauth.Google,
		},
	}

	b, err := ioutil.ReadFile(filepath.Join("views", "layout.html.tpl"))
	if err != nil {
		panic(err)
	}
	ab.Layout = template.Must(template.New("layout").Funcs(funcs).Parse(string(b)))

	ab.XSRFName = "csrf_token"
	ab.XSRFMaker = func(_ http.ResponseWriter, r *http.Request) string {
		return nosurf.Token(r)
	}

	ab.CookieStoreMaker = NewCookieStorer
	ab.SessionStoreMaker = NewSessionStorer

	ab.Mailer = authboss.LogMailer(os.Stdout)

	ab.Policies = []authboss.Validator{
		authboss.Rules{
			FieldName:       "email",
			Required:        true,
			AllowWhitespace: false,
		},
		authboss.Rules{
			FieldName:       "password",
			Required:        true,
			MinLength:       4,
			MaxLength:       8,
			AllowWhitespace: false,
		},
	}

	if err := ab.Init(); err != nil {
		log.Fatal(err)
	}
}

func main() {
	// Initialize Sessions and Cookies
	// Typically gorilla securecookie and sessions packages require
	// highly random secret keys that are not divulged to the public.
	//
	// In this example we use keys generated one time (if these keys ever become
	// compromised the gorilla libraries allow for key rotation, see gorilla docs)
	// The keys are 64-bytes as recommended for HMAC keys as per the gorilla docs.
	//
	// These values MUST be changed for any new project as these keys are already "compromised"
	// as they're in the public domain, if you do not change these your application will have a fairly
	// wide-opened security hole. You can generate your own with the code below, or using whatever method
	// you prefer:
	//
	//    func main() {
	//        fmt.Println(base64.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(64)))
	//    }
	//
	// We store them in base64 in the example to make it easy if we wanted to move them later to
	// a configuration environment var or file.
	cookieStoreKey, _ := base64.StdEncoding.DecodeString(`NpEPi8pEjKVjLGJ6kYCS+VTCzi6BUuDzU0wrwXyf5uDPArtlofn2AG6aTMiPmN3C909rsEWMNqJqhIVPGP3Exg==`)
	sessionStoreKey, _ := base64.StdEncoding.DecodeString(`AbfYwmmt8UCwUuhd9qvfNA9UCuN1cVcKJN1ofbiky6xCyyBj20whe40rJa3Su0WOWLWcPpO1taqJdsEI/65+JA==`)
	cookieStore = securecookie.New(cookieStoreKey, nil)
	sessionStore = sessions.NewCookieStore(sessionStoreKey)

	// Initialize ab.
	setupAuthboss()

	// Set up our router
	schemaDec.IgnoreUnknownKeys(true)
	mux := mux.NewRouter()

	// Routes
	gets := mux.Methods("GET").Subrouter()
	posts := mux.Methods("POST").Subrouter()

	mux.PathPrefix("/auth").Handler(ab.NewRouter())

	gets.Handle("/blogs/new", authProtect(newblog))
	gets.Handle("/blogs/{id}/edit", authProtect(edit))
	gets.HandleFunc("/blogs", index)
	gets.HandleFunc("/", index)

	posts.Handle("/blogs/{id}/edit", authProtect(update))
	posts.Handle("/blogs/new", authProtect(create))

	// This should actually be a DELETE but I can't be bothered to make a proper
	// destroy link using javascript atm.
	gets.HandleFunc("/blogs/{id}/destroy", destroy)

	mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, "Not found")
	})

	// Set up our middleware chain
	stack := alice.New(logger /*nosurfing,*/, ab.ExpireMiddleware).Then(mux)

	// Start the server
	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "3000"
	}
	log.Println(http.ListenAndServe("localhost:"+port, stack))
}

func layoutData(w http.ResponseWriter, r *http.Request) authboss.HTMLData {
	currentUserName := ""
	userInter, err := ab.CurrentUser(w, r)
	if userInter != nil && err == nil {
		currentUserName = userInter.(*User).Name
	}

	return authboss.HTMLData{
		"loggedin":               userInter != nil,
		"username":               "",
		authboss.FlashSuccessKey: ab.FlashSuccess(w, r),
		authboss.FlashErrorKey:   ab.FlashError(w, r),
		"current_user_name":      currentUserName,
	}
}

func index(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("posts", blogs)
	mustRender(w, r, "index", data)
}

func newblog(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("post", Blog{})
	mustRender(w, r, "new", data)
}

var nextID = len(blogs) + 1

func create(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	// TODO: Validation

	var b Blog
	if badRequest(w, schemaDec.Decode(&b, r.PostForm)) {
		return
	}

	b.ID = nextID
	nextID++
	b.Date = time.Now()
	b.AuthorID = "Zeratul"

	blogs = append(blogs, b)

	http.Redirect(w, r, "/", http.StatusFound)
}

func edit(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	data := layoutData(w, r).MergeKV("post", blogs.Get(id))
	mustRender(w, r, "edit", data)
}

func update(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	id, ok := blogID(w, r)
	if !ok {
		return
	}

	// TODO: Validation

	var b = blogs.Get(id)
	if badRequest(w, schemaDec.Decode(b, r.PostForm)) {
		return
	}

	b.Date = time.Now()

	http.Redirect(w, r, "/", http.StatusFound)
}

func destroy(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	blogs.Delete(id)

	http.Redirect(w, r, "/", http.StatusFound)
}

func blogID(w http.ResponseWriter, r *http.Request) (int, bool) {
	vars := mux.Vars(r)
	str := vars["id"]

	id, err := strconv.Atoi(str)
	if err != nil {
		log.Println("Error parsing blog id:", err)
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	if id <= 0 {
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	return id, true
}

func mustRender(w http.ResponseWriter, r *http.Request, name string, data authboss.HTMLData) {
	data.MergeKV("csrf_token", nosurf.Token(r))
	err := templates.Render(w, name, data)
	if err == nil {
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintln(w, "Error occurred rendering template:", err)
}

func badRequest(w http.ResponseWriter, err error) bool {
	if err == nil {
		return false
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, "Bad request:", err)

	return true
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"go/build"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"golang.org/x/tools/blog"
	"golang.org/x/tools/playground/socket"
)

const (
	packagePath = "github.com/pietv/pietv.pub"
)

var (
	httpFlag   = flag.String("http", "localhost:8080", "HTTP listen address")
	originFlag = flag.String("origin", "", "web socket origin for Go Playground (e.g. localhost)")
	baseFlag   = flag.String("base", "", "base path for articles and resources")
)

func main() {
	flag.Parse()

	if *baseFlag == "" {
		// By default, the base is the blog package location.
		p, err := build.Default.Import(packagePath, "", build.FindOnly)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't find the blog package: %v\n", err)
			os.Exit(1)
		}
		*baseFlag = p.Dir
	}

	ln, err := net.Listen("tcp", *httpFlag)
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()

	host, port, err := net.SplitHostPort(*httpFlag)
	if err != nil {
		log.Fatal(err)
	}

	srv, err := blog.NewServer(blog.Config{
		ContentPath:  filepath.Join(*baseFlag, "articles"),
		TemplatePath: filepath.Join(*baseFlag, "templates"),
		Hostname:     host,
		HomeArticles: 4,
		FeedArticles: 4,
		FeedTitle:    "Pie TV",
		PlayEnabled:  true,
	})
	if err != nil {
		log.Fatalf("%v\n", err)
	}

	origin := &url.URL{Scheme: "http"}
	if *originFlag != "" {
		origin.Host = net.JoinHostPort(*originFlag, port)
	} else {
		origin.Host = *httpFlag
	}

	http.Handle("/resources/", http.FileServer(http.Dir(*baseFlag)))
	http.Handle("/socket", socket.NewHandler(origin))
	http.Handle("/", srv)
	log.Fatal(http.Serve(ln, nil))
}
<commit_msg>default host and port<commit_after>package main

import (
	"flag"
	"fmt"
	"go/build"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"golang.org/x/tools/blog"
	"golang.org/x/tools/playground/socket"
)

const (
	packagePath = "github.com/pietv/pietv.pub"
)

var (
	httpFlag   = flag.String("http", "pietv.pub:80", "HTTP listen address")
	originFlag = flag.String("origin", "pietv.pub", "web socket origin for Go Playground (e.g. localhost)")
	baseFlag   = flag.String("base", "", "base path for articles and resources")
)

func main() {
	flag.Parse()

	if *baseFlag == "" {
		// By default, the base is the blog package location.
		p, err := build.Default.Import(packagePath, "", build.FindOnly)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't find the blog package: %v\n", err)
			os.Exit(1)
		}
		*baseFlag = p.Dir
	}

	ln, err := net.Listen("tcp", *httpFlag)
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()

	host, port, err := net.SplitHostPort(*httpFlag)
	if err != nil {
		log.Fatal(err)
	}

	srv, err := blog.NewServer(blog.Config{
		ContentPath:  filepath.Join(*baseFlag, "articles"),
		TemplatePath: filepath.Join(*baseFlag, "templates"),
		Hostname:     host,
		HomeArticles: 4,
		FeedArticles: 4,
		FeedTitle:    "Pie TV",
		PlayEnabled:  true,
	})
	if err != nil {
		log.Fatalf("%v\n", err)
	}

	origin := &url.URL{Scheme: "http"}
	if *originFlag != "" {
		origin.Host = net.JoinHostPort(*originFlag, port)
	} else {
		origin.Host = *httpFlag
	}

	http.Handle("/resources/", http.FileServer(http.Dir(*baseFlag)))
	http.Handle("/socket", socket.NewHandler(origin))
	http.Handle("/", srv)
	log.Fatal(http.Serve(ln, nil))
}
<|endoftext|>


<commit_before>package stripe

import (
	"net/url"
)

type CardType string

const (
	Unknown    CardType = "Unknown"
	Visa       CardType = "Visa"
	Amex       CardType = "American Express"
	MasterCard CardType = "MasterCard"
	Discover   CardType = "Discover"
	JCB        CardType = "JCB"
	DinersClub CardType = "Diners Club"
)

type CardParams struct {
	Token                                         string
	Customer, Recipient                           string
	Name, Number, Month, Year, CVC                string
	Address1, Address2, City, State, Zip, Country string
}

type Card struct {
	Id          string   `json:"id"`
	Name        string   `json:"name,omitempty"`
	Type        CardType `json:"type"`
	Month       uint8    `json:"exp_month"`
	Year        uint16   `json:"exp_year"`
	Last4       string   `json:"last4"`
	Fingerprint string   `json:"fingerprint"`
	CardCountry string   `json:"country,omitempty"`
	Customer    string   `json:"customer,omitempty"`
	Recipient   string   `json:recipient,omitempty"`
	Address1    string   `json:"address_line1,omitempty"`
	Address2    string   `json:"address_line2,omitempty"`
	Country     string   `json:"address_country,omitempty"`
	State       string   `json:"address_state,omitempty"`
	Zip         string   `json:"address_zip,omitempty"`
	City        string   `json:"address_city"`
	Line1Check  string   `json:"address_line1_check,omitempty"`
	ZipCheck    string   `json:"address_zip_check,omitempty"`
	CVCCheck    string   `json:"cvc_check,omitempty"`
}

func (c *CardParams) appendTo(values *url.Values) {
	values.Add("card[number]", c.Number)
	values.Add("card[exp_month]", c.Month)
	values.Add("card[exp_year]", c.Year)

	if len(c.Name) > 0 {
		values.Add("card[name]", c.Name)
	}

	if len(c.CVC) > 0 {
		values.Add("card[cvc]", c.CVC)
	}

	if len(c.Address1) > 0 {
		values.Add("card[address1]", c.Address1)
	}

	if len(c.Address2) > 0 {
		values.Add("card[address2]", c.Address2)
	}

	if len(c.City) > 0 {
		values.Add("card[address_city]", c.City)
	}

	if len(c.State) > 0 {
		values.Add("card[address_state", c.State)
	}

	if len(c.Zip) > 0 {
		values.Add("card[address_zip]", c.Zip)
	}

	if len(c.Country) > 0 {
		values.Add("card[address_country]", c.Country)
	}
}
<commit_msg>fix minor JSON serialization issue<commit_after>package stripe

import (
	"net/url"
)

type CardType string

const (
	Unknown    CardType = "Unknown"
	Visa       CardType = "Visa"
	Amex       CardType = "American Express"
	MasterCard CardType = "MasterCard"
	Discover   CardType = "Discover"
	JCB        CardType = "JCB"
	DinersClub CardType = "Diners Club"
)

type CardParams struct {
	Token                                         string
	Customer, Recipient                           string
	Name, Number, Month, Year, CVC                string
	Address1, Address2, City, State, Zip, Country string
}

type Card struct {
	Id          string   `json:"id"`
	Name        string   `json:"name,omitempty"`
	Type        CardType `json:"type"`
	Month       uint8    `json:"exp_month"`
	Year        uint16   `json:"exp_year"`
	Last4       string   `json:"last4"`
	Fingerprint string   `json:"fingerprint"`
	CardCountry string   `json:"country,omitempty"`
	Customer    string   `json:"customer,omitempty"`
	Recipient   string   `json:"recipient,omitempty"`
	Address1    string   `json:"address_line1,omitempty"`
	Address2    string   `json:"address_line2,omitempty"`
	Country     string   `json:"address_country,omitempty"`
	State       string   `json:"address_state,omitempty"`
	Zip         string   `json:"address_zip,omitempty"`
	City        string   `json:"address_city"`
	Line1Check  string   `json:"address_line1_check,omitempty"`
	ZipCheck    string   `json:"address_zip_check,omitempty"`
	CVCCheck    string   `json:"cvc_check,omitempty"`
}

func (c *CardParams) appendTo(values *url.Values) {
	values.Add("card[number]", c.Number)
	values.Add("card[exp_month]", c.Month)
	values.Add("card[exp_year]", c.Year)

	if len(c.Name) > 0 {
		values.Add("card[name]", c.Name)
	}

	if len(c.CVC) > 0 {
		values.Add("card[cvc]", c.CVC)
	}

	if len(c.Address1) > 0 {
		values.Add("card[address1]", c.Address1)
	}

	if len(c.Address2) > 0 {
		values.Add("card[address2]", c.Address2)
	}

	if len(c.City) > 0 {
		values.Add("card[address_city]", c.City)
	}

	if len(c.State) > 0 {
		values.Add("card[address_state", c.State)
	}

	if len(c.Zip) > 0 {
		values.Add("card[address_zip]", c.Zip)
	}

	if len(c.Country) > 0 {
		values.Add("card[address_country]", c.Country)
	}
}
<|endoftext|>


<commit_before>package nbt

import (
	"bytes"
	"encoding/base64"
	"testing"
)

func TestSmall(t *testing.T) { //test.nbt
	testNBT(`CgALaGVsbG8gd29ybGQIAARuYW1lAAlCYW5hbnJhbWEA`,
		NewTag("hello world", NewCompound([]Tag{
			NewTag("name", NewString("Bananrama")),
		})), t)
}

func TestLarge(t *testing.T) { //bigtest.nbt
	data := make([]byte, 1000)
	for i := 0; i < 1000; i++ {
		t := (i*i*255+i*7)%100
		data[i] = byte(t)
	}
	testNBT(`CgAFTGV2ZWwEAAhsb25nVGVzdH//////////AgAJc2hvcnRUZXN0f/8IAApzdHJpbmdUZXN0AClI`+
		`RUxMTyBXT1JMRCBUSElTIElTIEEgVEVTVCBTVFJJTkcgw4XDhMOWIQUACWZsb2F0VGVzdD7/GDID`+
		`AAdpbnRUZXN0f////woAFG5lc3RlZCBjb21wb3VuZCB0ZXN0CgADaGFtCAAEbmFtZQAGSGFtcHVz`+
		`BQAFdmFsdWU/QAAAAAoAA2VnZwgABG5hbWUAB0VnZ2JlcnQFAAV2YWx1ZT8AAAAAAAkAD2xpc3RU`+
		`ZXN0IChsb25nKQQAAAAFAAAAAAAAAAsAAAAAAAAADAAAAAAAAAANAAAAAAAAAA4AAAAAAAAADwkA`+
		`E2xpc3RUZXN0IChjb21wb3VuZCkKAAAAAggABG5hbWUAD0NvbXBvdW5kIHRhZyAjMAQACmNyZWF0`+
		`ZWQtb24AAAEmUjfVjQAIAARuYW1lAA9Db21wb3VuZCB0YWcgIzEEAApjcmVhdGVkLW9uAAABJlI3`+
		`1Y0AAQAIYnl0ZVRlc3R/BwBlYnl0ZUFycmF5VGVzdCAodGhlIGZpcnN0IDEwMDAgdmFsdWVzIG9m`+
		`IChuKm4qMjU1K24qNyklMTAwLCBzdGFydGluZyB3aXRoIG49MCAoMCwgNjIsIDM0LCAxNiwgOCwg`+
		`Li4uKSkAAAPoAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIY`+
		`OGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAI`+
		`ChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRS`+
		`NiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4u`+
		`WCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIA`+
		`DCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6Ckgs`+
		`GhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCRO`+
		`HlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoC`+
		`GDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQ`+
		`CAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQU`+
		`UjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwO`+
		`LlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZi`+
		`AAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpI`+
		`LBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQk`+
		`Th5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFha`+
		`Ahg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4i`+
		`EAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpE`+
		`FFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAYACmRvdWJsZVRlc3Q/349r`+
		`u/9qXgA=`,
		NewTag("Level", NewCompound([]Tag {
			NewTag("longTest", NewLong(9223372036854775807)),
			NewTag("shortTest", NewShort(32767)),
			NewTag("stringTest", NewString("HELLO WORLD THIS IS A TEST STRING ÅÄÖ!")),
			NewTag("floatTest", NewFloat(0.49823147)),
			NewTag("intTest", NewInt(2147483647)),
			NewTag("nested compound test", NewCompound([]Tag{
				NewTag("ham", NewCompound([]Tag {
					NewTag("name", NewString("Hampus")),
					NewTag("value", NewFloat(0.75)),
				})),
				NewTag("egg", NewCompound([]Tag {
					NewTag("name", NewString("Eggbert")),
					NewTag("value", NewFloat(0.5)),
				})),
			})),
			NewTag("listTest (long)", NewList([]Data {
				NewLong(11),
				NewLong(12),
				NewLong(13),
				NewLong(14),
				NewLong(15),
			})),
			NewTag("listTest (compound)", NewList([]Data {
				NewCompound([]Tag {
					NewTag("name", NewString("Compound tag #0")),
					NewTag("created-on", NewLong(1264099775885)),
				}),
				NewCompound([]Tag {
					NewTag("name", NewString("Compound tag #1")),
					NewTag("created-on", NewLong(1264099775885)),
				}),
			})),
			NewTag("byteTest", NewByte(127)),
			NewTag("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))", NewByteArray(data)),
			NewTag("doubleTest", NewDouble(0.4931287132182315)),
		})), t)
}

func testNBT(input string, middle Tag, t *testing.T) {
	n, c, err := ReadNBTFrom(base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(input)))
	if err != nil {
		t.Errorf("error encountered while reading nbt data: %q", err)
		return
	}
	if !n.Equal(middle) {
		t.Error("parsed nbt data did not match given nbt structure")
		return
	}
	o := new(bytes.Buffer)
	b := base64.NewEncoder(base64.StdEncoding, o)
	d, err := n.WriteTo(b)
	b.Close()
	if err != nil {
		t.Errorf("error encountered while writing nbt data: %q", err)
		return
	}
	if c != d {
		t.Error("read and write byte counts do not match")
		return
	}
	if o.String() != input {
		t.Error("input and output do not match")
	}
}
<commit_msg>Go fmt<commit_after>package nbt

import (
	"bytes"
	"encoding/base64"
	"testing"
)

func TestSmall(t *testing.T) { //test.nbt
	testNBT(`CgALaGVsbG8gd29ybGQIAARuYW1lAAlCYW5hbnJhbWEA`,
		NewTag("hello world", NewCompound([]Tag{
			NewTag("name", NewString("Bananrama")),
		})), t)
}

func TestLarge(t *testing.T) { //bigtest.nbt
	data := make([]byte, 1000)
	for i := 0; i < 1000; i++ {
		t := (i*i*255 + i*7) % 100
		data[i] = byte(t)
	}
	testNBT(`CgAFTGV2ZWwEAAhsb25nVGVzdH//////////AgAJc2hvcnRUZXN0f/8IAApzdHJpbmdUZXN0AClI`+
		`RUxMTyBXT1JMRCBUSElTIElTIEEgVEVTVCBTVFJJTkcgw4XDhMOWIQUACWZsb2F0VGVzdD7/GDID`+
		`AAdpbnRUZXN0f////woAFG5lc3RlZCBjb21wb3VuZCB0ZXN0CgADaGFtCAAEbmFtZQAGSGFtcHVz`+
		`BQAFdmFsdWU/QAAAAAoAA2VnZwgABG5hbWUAB0VnZ2JlcnQFAAV2YWx1ZT8AAAAAAAkAD2xpc3RU`+
		`ZXN0IChsb25nKQQAAAAFAAAAAAAAAAsAAAAAAAAADAAAAAAAAAANAAAAAAAAAA4AAAAAAAAADwkA`+
		`E2xpc3RUZXN0IChjb21wb3VuZCkKAAAAAggABG5hbWUAD0NvbXBvdW5kIHRhZyAjMAQACmNyZWF0`+
		`ZWQtb24AAAEmUjfVjQAIAARuYW1lAA9Db21wb3VuZCB0YWcgIzEEAApjcmVhdGVkLW9uAAABJlI3`+
		`1Y0AAQAIYnl0ZVRlc3R/BwBlYnl0ZUFycmF5VGVzdCAodGhlIGZpcnN0IDEwMDAgdmFsdWVzIG9m`+
		`IChuKm4qMjU1K24qNyklMTAwLCBzdGFydGluZyB3aXRoIG49MCAoMCwgNjIsIDM0LCAxNiwgOCwg`+
		`Li4uKSkAAAPoAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIY`+
		`OGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAI`+
		`ChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRS`+
		`NiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4u`+
		`WCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIA`+
		`DCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6Ckgs`+
		`GhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCRO`+
		`HlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoC`+
		`GDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQ`+
		`CAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQU`+
		`UjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwO`+
		`LlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZi`+
		`AAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpI`+
		`LBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQk`+
		`Th5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFha`+
		`Ahg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4i`+
		`EAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpE`+
		`FFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAYACmRvdWJsZVRlc3Q/349r`+
		`u/9qXgA=`,
		NewTag("Level", NewCompound([]Tag{
			NewTag("longTest", NewLong(9223372036854775807)),
			NewTag("shortTest", NewShort(32767)),
			NewTag("stringTest", NewString("HELLO WORLD THIS IS A TEST STRING ÅÄÖ!")),
			NewTag("floatTest", NewFloat(0.49823147)),
			NewTag("intTest", NewInt(2147483647)),
			NewTag("nested compound test", NewCompound([]Tag{
				NewTag("ham", NewCompound([]Tag{
					NewTag("name", NewString("Hampus")),
					NewTag("value", NewFloat(0.75)),
				})),
				NewTag("egg", NewCompound([]Tag{
					NewTag("name", NewString("Eggbert")),
					NewTag("value", NewFloat(0.5)),
				})),
			})),
			NewTag("listTest (long)", NewList([]Data{
				NewLong(11),
				NewLong(12),
				NewLong(13),
				NewLong(14),
				NewLong(15),
			})),
			NewTag("listTest (compound)", NewList([]Data{
				NewCompound([]Tag{
					NewTag("name", NewString("Compound tag #0")),
					NewTag("created-on", NewLong(1264099775885)),
				}),
				NewCompound([]Tag{
					NewTag("name", NewString("Compound tag #1")),
					NewTag("created-on", NewLong(1264099775885)),
				}),
			})),
			NewTag("byteTest", NewByte(127)),
			NewTag("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))", NewByteArray(data)),
			NewTag("doubleTest", NewDouble(0.4931287132182315)),
		})), t)
}

func testNBT(input string, middle Tag, t *testing.T) {
	n, c, err := ReadNBTFrom(base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(input)))
	if err != nil {
		t.Errorf("error encountered while reading nbt data: %q", err)
		return
	}
	if !n.Equal(middle) {
		t.Error("parsed nbt data did not match given nbt structure")
		return
	}
	o := new(bytes.Buffer)
	b := base64.NewEncoder(base64.StdEncoding, o)
	d, err := n.WriteTo(b)
	b.Close()
	if err != nil {
		t.Errorf("error encountered while writing nbt data: %q", err)
		return
	}
	if c != d {
		t.Error("read and write byte counts do not match")
		return
	}
	if o.String() != input {
		t.Error("input and output do not match")
	}
}
<|endoftext|>


<commit_before>package awsutil

import (
	"errors"
	"strings"

	libjson "github.com/Symantec/Dominator/lib/json"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
)

func (tag Tag) makeFilter() *ec2.Filter {
	if tag.Key == "" {
		return nil
	}
	if tag.Value == "" {
		return &ec2.Filter{
			Name:   aws.String("tag-key"),
			Values: aws.StringSlice([]string{tag.Key}),
		}
	} else {
		return &ec2.Filter{
			Name:   aws.String("tag:" + tag.Key),
			Values: aws.StringSlice([]string{tag.Value}),
		}
	}
}

func (tag *Tag) string() string {
	return tag.Key + ":" + tag.Value
}

func (tag *Tag) set(value string) error {
	splitValue := strings.Split(value, ":")
	if len(splitValue) != 2 {
		return errors.New(`malformed tag: "` + value + `"`)
	}
	*tag = Tag{splitValue[0], splitValue[1]}
	return nil
}

func createTagsFromList(list []*ec2.Tag) Tags {
	tags := make(Tags, len(list))
	for _, tag := range list {
		tags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value)
	}
	return tags
}

func (tags Tags) copy() Tags {
	newTags := make(Tags, len(tags))
	for key, value := range tags {
		newTags[key] = value
	}
	return newTags
}

func (to Tags) merge(from Tags) {
	for key, value := range from {
		to[key] = value
	}
}

func (tags Tags) makeFilters() []*ec2.Filter {
	if len(tags) < 1 {
		return nil
	}
	filters := make([]*ec2.Filter, 0, len(tags))
	for key, value := range tags {
		filters = append(filters, Tag{key, value}.makeFilter())
	}
	return filters
}

func (tags *Tags) string() string {
	pairs := make([]string, 0, len(*tags))
	for key, value := range *tags {
		pairs = append(pairs, key+":"+value)
	}
	return strings.Join(pairs, ",")
}

func (tags *Tags) set(value string) error {
	newTags := make(Tags)
	if value == "" {
		*tags = newTags
		return nil
	}
	for _, tag := range strings.Split(value, ",") {
		if len(tag) < 3 {
			return errors.New(`malformed tag: "` + tag + `"`)
		}
		if tag[0] == '@' {
			var fileTags Tags
			if err := libjson.ReadFromFile(tag[1:], &fileTags); err != nil {
				return errors.New("error loading tags file: " + err.Error())
			}
			newTags.Merge(fileTags)
			continue
		}
		splitTag := strings.Split(tag, ":")
		if len(splitTag) != 2 {
			return errors.New(`malformed tag: "` + tag + `"`)
		}
		if splitTag[0] == "" {
			return errors.New("empty tag key")
		}
		newTags[splitTag[0]] = splitTag[1]
	}
	*tags = newTags
	return nil
}
<commit_msg>Change tag flags separator from ':' to '=' to support common convention.<commit_after>package awsutil

import (
	"errors"
	"strings"

	libjson "github.com/Symantec/Dominator/lib/json"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
)

func (tag Tag) makeFilter() *ec2.Filter {
	if tag.Key == "" {
		return nil
	}
	if tag.Value == "" {
		return &ec2.Filter{
			Name:   aws.String("tag-key"),
			Values: aws.StringSlice([]string{tag.Key}),
		}
	} else {
		return &ec2.Filter{
			Name:   aws.String("tag:" + tag.Key),
			Values: aws.StringSlice([]string{tag.Value}),
		}
	}
}

func (tag *Tag) string() string {
	return tag.Key + "=" + tag.Value
}

func (tag *Tag) set(value string) error {
	splitValue := strings.Split(value, "=")
	if len(splitValue) != 2 {
		return errors.New(`malformed tag: "` + value + `"`)
	}
	*tag = Tag{splitValue[0], splitValue[1]}
	return nil
}

func createTagsFromList(list []*ec2.Tag) Tags {
	tags := make(Tags, len(list))
	for _, tag := range list {
		tags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value)
	}
	return tags
}

func (tags Tags) copy() Tags {
	newTags := make(Tags, len(tags))
	for key, value := range tags {
		newTags[key] = value
	}
	return newTags
}

func (to Tags) merge(from Tags) {
	for key, value := range from {
		to[key] = value
	}
}

func (tags Tags) makeFilters() []*ec2.Filter {
	if len(tags) < 1 {
		return nil
	}
	filters := make([]*ec2.Filter, 0, len(tags))
	for key, value := range tags {
		filters = append(filters, Tag{key, value}.makeFilter())
	}
	return filters
}

func (tags *Tags) string() string {
	pairs := make([]string, 0, len(*tags))
	for key, value := range *tags {
		pairs = append(pairs, key+"="+value)
	}
	return strings.Join(pairs, ",")
}

func (tags *Tags) set(value string) error {
	newTags := make(Tags)
	if value == "" {
		*tags = newTags
		return nil
	}
	for _, tag := range strings.Split(value, ",") {
		if len(tag) < 3 {
			return errors.New(`malformed tag: "` + tag + `"`)
		}
		if tag[0] == '@' {
			var fileTags Tags
			if err := libjson.ReadFromFile(tag[1:], &fileTags); err != nil {
				return errors.New("error loading tags file: " + err.Error())
			}
			newTags.Merge(fileTags)
			continue
		}
		splitTag := strings.Split(tag, "=")
		if len(splitTag) != 2 {
			return errors.New(`malformed tag: "` + tag + `"`)
		}
		if splitTag[0] == "" {
			return errors.New("empty tag key")
		}
		newTags[splitTag[0]] = splitTag[1]
	}
	*tags = newTags
	return nil
}
<|endoftext|>