<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cache

import (
	"fmt"
	"sync"

	"k8s.io/apimachinery/pkg/util/sets"
)

// ThreadSafeStore is an interface that allows concurrent indexed
// access to a storage backend.  It is like Indexer but does not
// (necessarily) know how to extract the Store key from a given
// object.
//
// TL;DR caveats: you must not modify anything returned by Get or List as it will break
// the indexing feature in addition to not being thread safe.
//
// The guarantees of thread safety provided by List/Get are only valid if the caller
// treats returned items as read-only. For example, a pointer inserted in the store
// through `Add` will be returned as is by `Get`. Multiple clients might invoke `Get`
// on the same key and modify the pointer in a non-thread-safe way. Also note that
// modifying objects stored by the indexers (if any) will *not* automatically lead
// to a re-index. So it's not a good idea to directly modify the objects returned by
// Get/List, in general.
type ThreadSafeStore interface {
	Add(key string, obj interface{})
	Update(key string, obj interface{})
	Delete(key string)
	Get(key string) (item interface{}, exists bool)
	List() []interface{}
	ListKeys() []string
	Replace(map[string]interface{}, string)
	Index(indexName string, obj interface{}) ([]interface{}, error)
	IndexKeys(indexName, indexedValue string) ([]string, error)
	ListIndexFuncValues(name string) []string
	ByIndex(indexName, indexedValue string) ([]interface{}, error)
	GetIndexers() Indexers

	// AddIndexers adds more indexers to this store.  If you call this after you already have data
	// in the store, the results are undefined.
	AddIndexers(newIndexers Indexers) error
	// Resync is a no-op and is deprecated
	Resync() error
}

// storeIndex implements the indexing functionality for Store interface
type storeIndex struct {
	// indexers maps a name to an IndexFunc
	indexers Indexers
	// indices maps a name to an Index
	indices Indices
}

func (i *storeIndex) reset() {
	i.indices = Indices{}
}

func (i *storeIndex) getKeysFromIndex(indexName string, obj interface{}) (sets.String, error) {
	indexFunc := i.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	indexedValues, err := indexFunc(obj)
	if err != nil {
		return nil, err
	}
	index := i.indices[indexName]

	var storeKeySet sets.String
	if len(indexedValues) == 1 {
		// In majority of cases, there is exactly one value matching.
		// Optimize the most common path - deduping is not needed here.
		storeKeySet = index[indexedValues[0]]
	} else {
		// Need to de-dupe the return list.
		// Since multiple keys are allowed, this can happen.
		storeKeySet = sets.String{}
		for _, indexedValue := range indexedValues {
			for key := range index[indexedValue] {
				storeKeySet.Insert(key)
			}
		}
	}

	return storeKeySet, nil
}

func (i *storeIndex) getKeysByIndex(indexName, indexedValue string) (sets.String, error) {
	indexFunc := i.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	index := i.indices[indexName]
	return index[indexedValue], nil
}

func (i *storeIndex) getIndexValues(indexName string) []string {
	index := i.indices[indexName]
	names := make([]string, 0, len(index))
	for key := range index {
		names = append(names, key)
	}
	return names
}

func (i *storeIndex) addIndexers(newIndexers Indexers) error {
	oldKeys := sets.StringKeySet(i.indexers)
	newKeys := sets.StringKeySet(newIndexers)

	if oldKeys.HasAny(newKeys.List()...) {
		return fmt.Errorf("indexer conflict: %v", oldKeys.Intersection(newKeys))
	}

	for k, v := range newIndexers {
		i.indexers[k] = v
	}
	return nil
}

// threadSafeMap implements ThreadSafeStore
type threadSafeMap struct {
	lock  sync.RWMutex
	items map[string]interface{}

	// index implements the indexing functionality
	index *storeIndex
}

func (c *threadSafeMap) Add(key string, obj interface{}) {
	c.Update(key, obj)
}

func (c *threadSafeMap) Update(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.index.updateIndices(oldObject, obj, key)
}

func (c *threadSafeMap) Delete(key string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if obj, exists := c.items[key]; exists {
		c.index.updateIndices(obj, nil, key)
		delete(c.items, key)
	}
}

func (c *threadSafeMap) Get(key string) (item interface{}, exists bool) {
	c.lock.RLock()
	defer c.lock.RUnlock()
	item, exists = c.items[key]
	return item, exists
}

func (c *threadSafeMap) List() []interface{} {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]interface{}, 0, len(c.items))
	for _, item := range c.items {
		list = append(list, item)
	}
	return list
}

// ListKeys returns a list of all the keys of the objects currently
// in the threadSafeMap.
func (c *threadSafeMap) ListKeys() []string {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]string, 0, len(c.items))
	for key := range c.items {
		list = append(list, key)
	}
	return list
}

func (c *threadSafeMap) Replace(items map[string]interface{}, resourceVersion string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.items = items

	// rebuild any index
	c.index.reset()
	for key, item := range c.items {
		c.index.updateIndices(nil, item, key)
	}
}

// Index returns a list of items that match the given object on the index function.
// Index is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) Index(indexName string, obj interface{}) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	storeKeySet, err := c.index.getKeysFromIndex(indexName, obj)
	if err != nil {
		return nil, err
	}

	list := make([]interface{}, 0, storeKeySet.Len())
	for storeKey := range storeKeySet {
		list = append(list, c.items[storeKey])
	}
	return list, nil
}

// ByIndex returns a list of the items whose indexed values in the given index include the given indexed value
func (c *threadSafeMap) ByIndex(indexName, indexedValue string) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	set, err := c.index.getKeysByIndex(indexName, indexedValue)
	if err != nil {
		return nil, err
	}
	list := make([]interface{}, 0, set.Len())
	for key := range set {
		list = append(list, c.items[key])
	}

	return list, nil
}

// IndexKeys returns a list of the Store keys of the objects whose indexed values in the given index include the given indexed value.
// IndexKeys is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) IndexKeys(indexName, indexedValue string) ([]string, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	set, err := c.index.getKeysByIndex(indexName, indexedValue)
	if err != nil {
		return nil, err
	}
	return set.List(), nil
}

func (c *threadSafeMap) ListIndexFuncValues(indexName string) []string {
	c.lock.RLock()
	defer c.lock.RUnlock()

	return c.index.getIndexValues(indexName)
}

func (c *threadSafeMap) GetIndexers() Indexers {
	return c.index.indexers
}

func (c *threadSafeMap) AddIndexers(newIndexers Indexers) error {
	c.lock.Lock()
	defer c.lock.Unlock()

	if len(c.items) > 0 {
		return fmt.Errorf("cannot add indexers to running index")
	}

	return c.index.addIndexers(newIndexers)
}

// updateIndices modifies the objects location in the managed indexes:
// - for create you must provide only the newObj
// - for update you must provide both the oldObj and the newObj
// - for delete you must provide only the oldObj
// updateIndices must be called from a function that already has a lock on the cache
func (i *storeIndex) updateIndices(oldObj interface{}, newObj interface{}, key string) {
	var oldIndexValues, indexValues []string
	var err error
	for name, indexFunc := range i.indexers {
		if oldObj != nil {
			oldIndexValues, err = indexFunc(oldObj)
		} else {
			oldIndexValues = oldIndexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		if newObj != nil {
			indexValues, err = indexFunc(newObj)
		} else {
			indexValues = indexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		index := i.indices[name]
		if index == nil {
			index = Index{}
			i.indices[name] = index
		}

		if len(indexValues) == 1 && len(oldIndexValues) == 1 && indexValues[0] == oldIndexValues[0] {
			// We optimize for the most common case where indexFunc returns a single value which has not been changed
			continue
		}

		for _, value := range oldIndexValues {
			i.deleteKeyFromIndex(key, value, index)
		}
		for _, value := range indexValues {
			i.addKeyToIndex(key, value, index)
		}
	}
}

func (i *storeIndex) addKeyToIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		set = sets.String{}
		index[indexValue] = set
	}
	set.Insert(key)
}

func (i *storeIndex) deleteKeyFromIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		return
	}
	set.Delete(key)
	// If we don't delete the set when zero, indices with high cardinality
	// short lived resources can cause memory to increase over time from
	// unused empty sets. See `kubernetes/kubernetes/issues/84959`.
	if len(set) == 0 {
		delete(index, indexValue)
	}
}

func (c *threadSafeMap) Resync() error {
	// Nothing to do
	return nil
}

// NewThreadSafeStore creates a new instance of ThreadSafeStore.
func NewThreadSafeStore(indexers Indexers, indices Indices) ThreadSafeStore {
	return &threadSafeMap{
		items: map[string]interface{}{},
		index: &storeIndex{
			indexers: indexers,
			indices:  indices,
		},
	}
}
<commit_msg>Minor cleanup of thread safe store<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cache

import (
	"fmt"
	"sync"

	"k8s.io/apimachinery/pkg/util/sets"
)

// ThreadSafeStore is an interface that allows concurrent indexed
// access to a storage backend.  It is like Indexer but does not
// (necessarily) know how to extract the Store key from a given
// object.
//
// TL;DR caveats: you must not modify anything returned by Get or List as it will break
// the indexing feature in addition to not being thread safe.
//
// The guarantees of thread safety provided by List/Get are only valid if the caller
// treats returned items as read-only. For example, a pointer inserted in the store
// through `Add` will be returned as is by `Get`. Multiple clients might invoke `Get`
// on the same key and modify the pointer in a non-thread-safe way. Also note that
// modifying objects stored by the indexers (if any) will *not* automatically lead
// to a re-index. So it's not a good idea to directly modify the objects returned by
// Get/List, in general.
type ThreadSafeStore interface {
	Add(key string, obj interface{})
	Update(key string, obj interface{})
	Delete(key string)
	Get(key string) (item interface{}, exists bool)
	List() []interface{}
	ListKeys() []string
	Replace(map[string]interface{}, string)
	Index(indexName string, obj interface{}) ([]interface{}, error)
	IndexKeys(indexName, indexedValue string) ([]string, error)
	ListIndexFuncValues(name string) []string
	ByIndex(indexName, indexedValue string) ([]interface{}, error)
	GetIndexers() Indexers

	// AddIndexers adds more indexers to this store.  If you call this after you already have data
	// in the store, the results are undefined.
	AddIndexers(newIndexers Indexers) error
	// Resync is a no-op and is deprecated
	Resync() error
}

// storeIndex implements the indexing functionality for Store interface
type storeIndex struct {
	// indexers maps a name to an IndexFunc
	indexers Indexers
	// indices maps a name to an Index
	indices Indices
}

func (i *storeIndex) reset() {
	i.indices = Indices{}
}

func (i *storeIndex) getKeysFromIndex(indexName string, obj interface{}) (sets.String, error) {
	indexFunc := i.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	indexedValues, err := indexFunc(obj)
	if err != nil {
		return nil, err
	}
	index := i.indices[indexName]

	var storeKeySet sets.String
	if len(indexedValues) == 1 {
		// In majority of cases, there is exactly one value matching.
		// Optimize the most common path - deduping is not needed here.
		storeKeySet = index[indexedValues[0]]
	} else {
		// Need to de-dupe the return list.
		// Since multiple keys are allowed, this can happen.
		storeKeySet = sets.String{}
		for _, indexedValue := range indexedValues {
			for key := range index[indexedValue] {
				storeKeySet.Insert(key)
			}
		}
	}

	return storeKeySet, nil
}

func (i *storeIndex) getKeysByIndex(indexName, indexedValue string) (sets.String, error) {
	indexFunc := i.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	index := i.indices[indexName]
	return index[indexedValue], nil
}

func (i *storeIndex) getIndexValues(indexName string) []string {
	index := i.indices[indexName]
	names := make([]string, 0, len(index))
	for key := range index {
		names = append(names, key)
	}
	return names
}

func (i *storeIndex) addIndexers(newIndexers Indexers) error {
	oldKeys := sets.StringKeySet(i.indexers)
	newKeys := sets.StringKeySet(newIndexers)

	if oldKeys.HasAny(newKeys.List()...) {
		return fmt.Errorf("indexer conflict: %v", oldKeys.Intersection(newKeys))
	}

	for k, v := range newIndexers {
		i.indexers[k] = v
	}
	return nil
}

// updateIndices modifies the objects location in the managed indexes:
// - for create you must provide only the newObj
// - for update you must provide both the oldObj and the newObj
// - for delete you must provide only the oldObj
// updateIndices must be called from a function that already has a lock on the cache
func (i *storeIndex) updateIndices(oldObj interface{}, newObj interface{}, key string) {
	var oldIndexValues, indexValues []string
	var err error
	for name, indexFunc := range i.indexers {
		if oldObj != nil {
			oldIndexValues, err = indexFunc(oldObj)
		} else {
			oldIndexValues = oldIndexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		if newObj != nil {
			indexValues, err = indexFunc(newObj)
		} else {
			indexValues = indexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		index := i.indices[name]
		if index == nil {
			index = Index{}
			i.indices[name] = index
		}

		if len(indexValues) == 1 && len(oldIndexValues) == 1 && indexValues[0] == oldIndexValues[0] {
			// We optimize for the most common case where indexFunc returns a single value which has not been changed
			continue
		}

		for _, value := range oldIndexValues {
			i.deleteKeyFromIndex(key, value, index)
		}
		for _, value := range indexValues {
			i.addKeyToIndex(key, value, index)
		}
	}
}

func (i *storeIndex) addKeyToIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		set = sets.String{}
		index[indexValue] = set
	}
	set.Insert(key)
}

func (i *storeIndex) deleteKeyFromIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		return
	}
	set.Delete(key)
	// If we don't delete the set when zero, indices with high cardinality
	// short lived resources can cause memory to increase over time from
	// unused empty sets. See `kubernetes/kubernetes/issues/84959`.
	if len(set) == 0 {
		delete(index, indexValue)
	}
}

// threadSafeMap implements ThreadSafeStore
type threadSafeMap struct {
	lock  sync.RWMutex
	items map[string]interface{}

	// index implements the indexing functionality
	index *storeIndex
}

func (c *threadSafeMap) Add(key string, obj interface{}) {
	c.Update(key, obj)
}

func (c *threadSafeMap) Update(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.index.updateIndices(oldObject, obj, key)
}

func (c *threadSafeMap) Delete(key string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if obj, exists := c.items[key]; exists {
		c.index.updateIndices(obj, nil, key)
		delete(c.items, key)
	}
}

func (c *threadSafeMap) Get(key string) (item interface{}, exists bool) {
	c.lock.RLock()
	defer c.lock.RUnlock()
	item, exists = c.items[key]
	return item, exists
}

func (c *threadSafeMap) List() []interface{} {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]interface{}, 0, len(c.items))
	for _, item := range c.items {
		list = append(list, item)
	}
	return list
}

// ListKeys returns a list of all the keys of the objects currently
// in the threadSafeMap.
func (c *threadSafeMap) ListKeys() []string {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]string, 0, len(c.items))
	for key := range c.items {
		list = append(list, key)
	}
	return list
}

func (c *threadSafeMap) Replace(items map[string]interface{}, resourceVersion string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.items = items

	// rebuild any index
	c.index.reset()
	for key, item := range c.items {
		c.index.updateIndices(nil, item, key)
	}
}

// Index returns a list of items that match the given object on the index function.
// Index is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) Index(indexName string, obj interface{}) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	storeKeySet, err := c.index.getKeysFromIndex(indexName, obj)
	if err != nil {
		return nil, err
	}

	list := make([]interface{}, 0, storeKeySet.Len())
	for storeKey := range storeKeySet {
		list = append(list, c.items[storeKey])
	}
	return list, nil
}

// ByIndex returns a list of the items whose indexed values in the given index include the given indexed value
func (c *threadSafeMap) ByIndex(indexName, indexedValue string) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	set, err := c.index.getKeysByIndex(indexName, indexedValue)
	if err != nil {
		return nil, err
	}
	list := make([]interface{}, 0, set.Len())
	for key := range set {
		list = append(list, c.items[key])
	}

	return list, nil
}

// IndexKeys returns a list of the Store keys of the objects whose indexed values in the given index include the given indexed value.
// IndexKeys is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) IndexKeys(indexName, indexedValue string) ([]string, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	set, err := c.index.getKeysByIndex(indexName, indexedValue)
	if err != nil {
		return nil, err
	}
	return set.List(), nil
}

func (c *threadSafeMap) ListIndexFuncValues(indexName string) []string {
	c.lock.RLock()
	defer c.lock.RUnlock()

	return c.index.getIndexValues(indexName)
}

func (c *threadSafeMap) GetIndexers() Indexers {
	return c.index.indexers
}

func (c *threadSafeMap) AddIndexers(newIndexers Indexers) error {
	c.lock.Lock()
	defer c.lock.Unlock()

	if len(c.items) > 0 {
		return fmt.Errorf("cannot add indexers to running index")
	}

	return c.index.addIndexers(newIndexers)
}

func (c *threadSafeMap) Resync() error {
	// Nothing to do
	return nil
}

// NewThreadSafeStore creates a new instance of ThreadSafeStore.
func NewThreadSafeStore(indexers Indexers, indices Indices) ThreadSafeStore {
	return &threadSafeMap{
		items: map[string]interface{}{},
		index: &storeIndex{
			indexers: indexers,
			indices:  indices,
		},
	}
}
<|endoftext|>


<commit_before>package middlewares

import (
	"fmt"
	"runtime"

	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

type (
	// RecoverConfig defines the config for Recover middleware.
	RecoverConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper middleware.Skipper

		// Size of the stack to be printed.
		// Optional. Default value 4KB.
		StackSize int `json:"stack_size"`
	}
)

var (
	// DefaultRecoverConfig is the default Recover middleware config.
	DefaultRecoverConfig = RecoverConfig{
		Skipper:   middleware.DefaultSkipper,
		StackSize: 4 << 10, // 4 KB
	}
)

// Recover returns a middleware which recovers from panics anywhere in the chain
// and handles the control to the centralized HTTPErrorHandler.
func Recover() echo.MiddlewareFunc {
	return RecoverWithConfig(DefaultRecoverConfig)
}

// RecoverWithConfig returns a Recover middleware with config.
// See: `Recover()`.
func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
	// Defaults
	if config.Skipper == nil {
		config.Skipper = DefaultRecoverConfig.Skipper
	}
	if config.StackSize == 0 {
		config.StackSize = DefaultRecoverConfig.StackSize
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			defer func() {
				if r := recover(); r != nil {
					var err error
					switch r := r.(type) {
					case error:
						err = r
					default:
						err = fmt.Errorf("%v", r)
					}
					stack := make([]byte, config.StackSize)
					length := runtime.Stack(stack, false)
					log := logger.WithDomain(c.Request().Host).WithField("panic", true)
					log.Errorf("PANIC RECOVER %s: %s", err.Error(), stack[:length])
					c.Error(err)
				}
			}()
			return next(c)
		}
	}
}
<commit_msg>Simplify defaults<commit_after>package middlewares

import (
	"fmt"
	"runtime"

	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

type (
	// RecoverConfig defines the config for Recover middleware.
	RecoverConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper middleware.Skipper

		// Size of the stack to be printed.
		// Optional. Default value 4KB.
		StackSize int `json:"stack_size"`
	}
)

// RecoverWithConfig returns a Recover middleware with config.
// See: `Recover()`.
func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
	// Defaults
	if config.Skipper == nil {
		config.Skipper = middleware.DefaultSkipper
	}
	if config.StackSize == 0 {
		config.StackSize = 4 << 10 // 4 KB
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			defer func() {
				if r := recover(); r != nil {
					var err error
					switch r := r.(type) {
					case error:
						err = r
					default:
						err = fmt.Errorf("%v", r)
					}
					stack := make([]byte, config.StackSize)
					length := runtime.Stack(stack, false)
					log := logger.WithDomain(c.Request().Host).WithField("panic", true)
					log.Errorf("PANIC RECOVER %s: %s", err.Error(), stack[:length])
					c.Error(err)
				}
			}()
			return next(c)
		}
	}
}
<|endoftext|>


<commit_before>package version

import (
	"math"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
)

func New(c *gin.Context) (string, error) {
	header := c.Request.Header["Accept"][0]
	header = strings.Join(strings.Fields(header), "")
	var ver string

	// header version
	if strings.Contains(header, "version=") {
		ver = strings.Split(strings.SplitAfter(header, "version=")[1], ";")[0]
	}

	// query v
	v := c.Query("v")
	if v != "" {
		ver = v
	}

	if ver == "" {
		return "-1", nil
	}

	_, err := strconv.Atoi(strings.Join(strings.Split(ver, "."), ""))
	if err != nil {
		return "", err
	}
	return ver, nil
}

func Range(left string, op string, right string) bool {
	switch op {
	case "<":
		return (compare(left, right) == -1)
	case "<=":
		return (compare(left, right) <= 0)
	case ">":
		return (compare(left, right) == 1)
	case ">=":
		return (compare(left, right) >= 0)
	case "==":
		return (compare(left, right) == 0)
	}
	return false
}

func compare(left string, right string) int {
	// l > r : 1
	// l == r : 0
	// l < r : -1
	if left == "-1" {
		return 1
	} else if right == "-1" {
		return -1
	}

	lArr := strings.Split(left, ".")
	rArr := strings.Split(right, ".")
	lItems := len(lArr)
	rItems := len(rArr)
	min := int(math.Min(float64(lItems), float64(rItems)))
	for i := 0; i < min; i++ {
		l, _ := strconv.Atoi(lArr[i])
		r, _ := strconv.Atoi(rArr[i])
		if l != r {
			if l > r {
				return 1
			}
			return -1
		}
	}
	if lItems == rItems {
		return 0
	}
	if lItems < rItems {
		return 1
	}

	return -1
}
<commit_msg>Remove unnecessary comments in version.go<commit_after>package version

import (
	"math"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
)

func New(c *gin.Context) (string, error) {
	header := c.Request.Header["Accept"][0]
	header = strings.Join(strings.Fields(header), "")
	var ver string

	if strings.Contains(header, "version=") {
		ver = strings.Split(strings.SplitAfter(header, "version=")[1], ";")[0]
	}

	v := c.Query("v")
	if v != "" {
		ver = v
	}

	if ver == "" {
		return "-1", nil
	}

	_, err := strconv.Atoi(strings.Join(strings.Split(ver, "."), ""))
	if err != nil {
		return "", err
	}
	return ver, nil
}

func Range(left string, op string, right string) bool {
	switch op {
	case "<":
		return (compare(left, right) == -1)
	case "<=":
		return (compare(left, right) <= 0)
	case ">":
		return (compare(left, right) == 1)
	case ">=":
		return (compare(left, right) >= 0)
	case "==":
		return (compare(left, right) == 0)
	}
	return false
}

func compare(left string, right string) int {
	// l > r : 1
	// l == r : 0
	// l < r : -1
	if left == "-1" {
		return 1
	} else if right == "-1" {
		return -1
	}

	lArr := strings.Split(left, ".")
	rArr := strings.Split(right, ".")
	lItems := len(lArr)
	rItems := len(rArr)
	min := int(math.Min(float64(lItems), float64(rItems)))
	for i := 0; i < min; i++ {
		l, _ := strconv.Atoi(lArr[i])
		r, _ := strconv.Atoi(rArr[i])
		if l != r {
			if l > r {
				return 1
			}
			return -1
		}
	}
	if lItems == rItems {
		return 0
	}
	if lItems < rItems {
		return 1
	}

	return -1
}
<|endoftext|>


<commit_before><commit_msg>code tidy<commit_after><|endoftext|>


<commit_before>package toml

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"strings"
	"time"
)

var e = fmt.Errorf

// Primitive is a TOML value that hasn't been decoded into a Go value.
// When using the various `Decode*` functions, the type `Primitive` may
// be given to any value, and its decoding will be delayed.
//
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
//
// The underlying representation of a `Primitive` value is subject to change.
// Do not rely on it.
//
// N.B. Primitive values are still parsed, so using them will only avoid
// the overhead of reflection. They can be useful when you don't know the
// exact type of TOML data until run time.
type Primitive interface{}

// PrimitiveDecode is just like the other `Decode*` functions, except it
// decodes a TOML value that has already been parsed. Valid primitive values
// can *only* be obtained from values filled by the decoder functions,
// including `PrimitiveDecode`. (i.e., `v` may contain more `Primitive`
// values.)
//
// Meta data for primitive values is included in the meta data returned by
// the `Decode*` functions.
func PrimitiveDecode(primValue Primitive, v interface{}) error {
	return unify(primValue, rvalue(v))
}

// Decode will decode the contents of `data` in TOML format into a pointer
// `v`.
//
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
// used interchangeably.)
//
// TOML datetimes correspond to Go `time.Time` values.
//
// All other TOML types (float, string, int, bool and array) correspond
// to the obvious Go types.
//
// TOML keys can map to either keys in a Go map or field names in a Go
// struct. The special `toml` struct tag may be used to map TOML keys to
// struct fields that don't match the key name exactly. (See the example.)
// A case insensitive match to struct names will be tried if an exact match
// can't be found.
//
// The mapping between TOML values and Go values is loose. That is, there
// may exist TOML values that cannot be placed into your representation, and
// there may be parts of your representation that do not correspond to
// TOML values.
//
// This decoder will not handle cyclic types. If a cyclic type is passed,
// `Decode` will not terminate.
func Decode(data string, v interface{}) (MetaData, error) {
	p, err := parse(data)
	if err != nil {
		return MetaData{}, err
	}
	return MetaData{p.mapping, p.types, p.ordered}, unify(p.mapping, rvalue(v))
}

// DecodeFile is just like Decode, except it will automatically read the
// contents of the file at `fpath` and decode it for you.
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadFile(fpath)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// DecodeReader is just like Decode, except it will consume all bytes
// from the reader and decode it for you.
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadAll(r)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// unify performs a sort of type unification based on the structure of `rv`,
// which is the client representation.
//
// Any type mismatch produces an error. Finding a type that we don't know
// how to handle produces an unsupported type error.
func unify(data interface{}, rv reflect.Value) error {
	// Special case. Look for a `Primitive` value.
	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
		return unifyAnything(data, rv)
	}

	// Special case. Go's `time.Time` is a struct, which we don't want
	// to confuse with a user struct.
	if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
		return unifyDatetime(data, rv)
	}

	k := rv.Kind()

	// laziness
	if k >= reflect.Int && k <= reflect.Uint64 {
		return unifyInt(data, rv)
	}
	switch k {
	case reflect.Struct:
		return unifyStruct(data, rv)
	case reflect.Map:
		return unifyMap(data, rv)
	case reflect.Slice:
		return unifySlice(data, rv)
	case reflect.String:
		return unifyString(data, rv)
	case reflect.Bool:
		return unifyBool(data, rv)
	case reflect.Interface:
		// we only support empty interfaces.
		if rv.NumMethod() > 0 {
			e("Unsupported type '%s'.", rv.Kind())
		}
		return unifyAnything(data, rv)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		return unifyFloat64(data, rv)
	}
	return e("Unsupported type '%s'.", rv.Kind())
}

func unifyStruct(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return mismatch(rv, "map", mapping)
	}

	rt := rv.Type()
	for i := 0; i < rt.NumField(); i++ {
		// A little tricky. We want to use the special `toml` name in the
		// struct tag if it exists. In particular, we need to make sure that
		// this struct field is in the current map before trying to unify it.
		sft := rt.Field(i)
		kname := sft.Tag.Get("toml")
		if len(kname) == 0 {
			kname = sft.Name
		}
		if datum, ok := insensitiveGet(tmap, kname); ok {
			sf := indirect(rv.Field(i))

			// Don't try to mess with unexported types and other such things.
			if sf.CanSet() {
				if err := unify(datum, sf); err != nil {
					return e("Type mismatch for '%s.%s': %s",
						rt.String(), sft.Name, err)
				}
			} else if len(sft.Tag.Get("toml")) > 0 {
				// Bad user! No soup for you!
				return e("Field '%s.%s' is unexported, and therefore cannot "+
					"be loaded with reflection.", rt.String(), sft.Name)
			}
		}
	}
	return nil
}

func unifyMap(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return badtype("map", mapping)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeMap(rv.Type()))
	}
	for k, v := range tmap {
		rvkey := indirect(reflect.New(rv.Type().Key()))
		rvval := indirect(reflect.New(rv.Type().Elem()))
		if err := unify(v, rvval); err != nil {
			return err
		}

		rvkey.SetString(k)
		rv.SetMapIndex(rvkey, rvval)
	}
	return nil
}

func unifySlice(data interface{}, rv reflect.Value) error {
	slice, ok := data.([]interface{})
	if !ok {
		return badtype("slice", data)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeSlice(rv.Type(), len(slice), len(slice)))
	}
	for i, v := range slice {
		sliceval := indirect(rv.Index(i))
		if err := unify(v, sliceval); err != nil {
			return err
		}
	}
	return nil
}

func unifyDatetime(data interface{}, rv reflect.Value) error {
	if _, ok := data.(time.Time); ok {
		rv.Set(reflect.ValueOf(data))
		return nil
	}
	return badtype("time.Time", data)
}

func unifyString(data interface{}, rv reflect.Value) error {
	if s, ok := data.(string); ok {
		rv.SetString(s)
		return nil
	}
	return badtype("string", data)
}

func unifyFloat64(data interface{}, rv reflect.Value) error {
	if num, ok := data.(float64); ok {
		switch rv.Kind() {
		case reflect.Float32:
			fallthrough
		case reflect.Float64:
			rv.SetFloat(num)
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("float", data)
}

func unifyInt(data interface{}, rv reflect.Value) error {
	if num, ok := data.(int64); ok {
		switch rv.Kind() {
		case reflect.Int:
			fallthrough
		case reflect.Int8:
			fallthrough
		case reflect.Int16:
			fallthrough
		case reflect.Int32:
			fallthrough
		case reflect.Int64:
			rv.SetInt(int64(num))
		case reflect.Uint:
			fallthrough
		case reflect.Uint8:
			fallthrough
		case reflect.Uint16:
			fallthrough
		case reflect.Uint32:
			fallthrough
		case reflect.Uint64:
			rv.SetUint(uint64(num))
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("integer", data)
}

func unifyBool(data interface{}, rv reflect.Value) error {
	if b, ok := data.(bool); ok {
		rv.SetBool(b)
		return nil
	}
	return badtype("integer", data)
}

func unifyAnything(data interface{}, rv reflect.Value) error {
	// too awesome to fail
	rv.Set(reflect.ValueOf(data))
	return nil
}

// rvalue returns a reflect.Value of `v`. All pointers are resolved.
func rvalue(v interface{}) reflect.Value {
	return indirect(reflect.ValueOf(v))
}

// indirect returns the value pointed to by a pointer.
// Pointers are followed until the value is not a pointer.
// New values are allocated for each nil pointer.
func indirect(v reflect.Value) reflect.Value {
	if v.Kind() != reflect.Ptr {
		return v
	}
	if v.IsNil() {
		v.Set(reflect.New(v.Type().Elem()))
	}
	return indirect(reflect.Indirect(v))
}

func tstring(rv reflect.Value) string {
	return rv.Type().String()
}

func badtype(expected string, data interface{}) error {
	return e("Expected %s but found '%T'.", expected, data)
}

func mismatch(user reflect.Value, expected string, data interface{}) error {
	return e("Type mismatch for %s. Expected %s but found '%T'.",
		tstring(user), expected, data)
}

func insensitiveGet(
	tmap map[string]interface{}, kname string) (interface{}, bool) {

	if datum, ok := tmap[kname]; ok {
		return datum, true
	}
	for k, v := range tmap {
		if strings.EqualFold(kname, k) {
			return v, true
		}
	}
	return nil, false
}

// MetaData allows access to meta information about TOML data that may not
// be inferrable via reflection. In particular, whether a key has been defined
// and the TOML type of a key.
//
// (XXX: If TOML gets NULL values, that information will be added here too.)
type MetaData struct {
	mapping map[string]interface{}
	types   map[string]tomlType
	keys    []Key
}

// IsDefined returns true if the key given exists in the TOML data. The key
// should be specified hierarchially. e.g.,
//
//	// access the TOML key 'a.b.c'
//	IsDefined("a", "b", "c")
//
// IsDefined will return false if an empty key given. Keys are case sensitive.
func (md MetaData) IsDefined(key ...string) bool {
	var hashOrVal interface{}
	var hash map[string]interface{}
	var ok bool

	if len(key) == 0 {
		return false
	}

	hashOrVal = md.mapping
	for _, k := range key {
		if hash, ok = hashOrVal.(map[string]interface{}); !ok {
			return false
		}
		if hashOrVal, ok = hash[k]; !ok {
			return false
		}
	}
	return true
}

// Type returns a string representation of the type of the key specified.
//
// Type will return the empty string if given an empty key or a key that
// does not exist. Keys are case sensitive.
func (md MetaData) Type(key ...string) string {
	fullkey := strings.Join(key, ".")
	if typ, ok := md.types[fullkey]; ok {
		return typ.typeString()
	}
	return ""
}

// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
// to get values of this type.
type Key []string

func (k Key) String() string {
	return strings.Join(k, ".")
}

func (k Key) add(piece string) Key {
	newKey := make(Key, len(k))
	copy(newKey, k)
	return append(newKey, piece)
}

// Keys returns a slice of every key in the TOML data, including key groups.
// Each key is itself a slice, where the first element is the top of the
// hierarchy and the last is the most specific.
//
// The list will have the same order as the keys appeared in the TOML data.
//
// All keys returned are non-empty.
func (md MetaData) Keys() []Key {
	return md.keys
}

func allKeys(m map[string]interface{}, context Key) []Key {
	keys := make([]Key, 0, len(m))
	for k, v := range m {
		keys = append(keys, context.add(k))
		if t, ok := v.(map[string]interface{}); ok {
			keys = append(keys, allKeys(t, context.add(k))...)
		}
	}
	return keys
}
<commit_msg>Close issue #6.<commit_after>package toml

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"strings"
	"time"
)

var e = fmt.Errorf

// Primitive is a TOML value that hasn't been decoded into a Go value.
// When using the various `Decode*` functions, the type `Primitive` may
// be given to any value, and its decoding will be delayed.
//
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
//
// The underlying representation of a `Primitive` value is subject to change.
// Do not rely on it.
//
// N.B. Primitive values are still parsed, so using them will only avoid
// the overhead of reflection. They can be useful when you don't know the
// exact type of TOML data until run time.
type Primitive interface{}

// PrimitiveDecode is just like the other `Decode*` functions, except it
// decodes a TOML value that has already been parsed. Valid primitive values
// can *only* be obtained from values filled by the decoder functions,
// including `PrimitiveDecode`. (i.e., `v` may contain more `Primitive`
// values.)
//
// Meta data for primitive values is included in the meta data returned by
// the `Decode*` functions.
func PrimitiveDecode(primValue Primitive, v interface{}) error {
	return unify(primValue, rvalue(v))
}

// Decode will decode the contents of `data` in TOML format into a pointer
// `v`.
//
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
// used interchangeably.)
//
// TOML datetimes correspond to Go `time.Time` values.
//
// All other TOML types (float, string, int, bool and array) correspond
// to the obvious Go types.
//
// TOML keys can map to either keys in a Go map or field names in a Go
// struct. The special `toml` struct tag may be used to map TOML keys to
// struct fields that don't match the key name exactly. (See the example.)
// A case insensitive match to struct names will be tried if an exact match
// can't be found.
//
// The mapping between TOML values and Go values is loose. That is, there
// may exist TOML values that cannot be placed into your representation, and
// there may be parts of your representation that do not correspond to
// TOML values.
//
// This decoder will not handle cyclic types. If a cyclic type is passed,
// `Decode` will not terminate.
func Decode(data string, v interface{}) (MetaData, error) {
	p, err := parse(data)
	if err != nil {
		return MetaData{}, err
	}
	return MetaData{p.mapping, p.types, p.ordered}, unify(p.mapping, rvalue(v))
}

// DecodeFile is just like Decode, except it will automatically read the
// contents of the file at `fpath` and decode it for you.
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadFile(fpath)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// DecodeReader is just like Decode, except it will consume all bytes
// from the reader and decode it for you.
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadAll(r)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// unify performs a sort of type unification based on the structure of `rv`,
// which is the client representation.
//
// Any type mismatch produces an error. Finding a type that we don't know
// how to handle produces an unsupported type error.
func unify(data interface{}, rv reflect.Value) error {
	// Special case. Look for a `Primitive` value.
	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
		return unifyAnything(data, rv)
	}

	// Special case. Go's `time.Time` is a struct, which we don't want
	// to confuse with a user struct.
	if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
		return unifyDatetime(data, rv)
	}

	k := rv.Kind()

	// laziness
	if k >= reflect.Int && k <= reflect.Uint64 {
		return unifyInt(data, rv)
	}
	switch k {
	case reflect.Struct:
		return unifyStruct(data, rv)
	case reflect.Map:
		return unifyMap(data, rv)
	case reflect.Slice:
		return unifySlice(data, rv)
	case reflect.String:
		return unifyString(data, rv)
	case reflect.Bool:
		return unifyBool(data, rv)
	case reflect.Interface:
		// we only support empty interfaces.
		if rv.NumMethod() > 0 {
			return e("Unsupported type '%s'.", rv.Kind())
		}
		return unifyAnything(data, rv)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		return unifyFloat64(data, rv)
	}
	return e("Unsupported type '%s'.", rv.Kind())
}

func unifyStruct(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return mismatch(rv, "map", mapping)
	}

	rt := rv.Type()
	for i := 0; i < rt.NumField(); i++ {
		// A little tricky. We want to use the special `toml` name in the
		// struct tag if it exists. In particular, we need to make sure that
		// this struct field is in the current map before trying to unify it.
		sft := rt.Field(i)
		kname := sft.Tag.Get("toml")
		if len(kname) == 0 {
			kname = sft.Name
		}
		if datum, ok := insensitiveGet(tmap, kname); ok {
			sf := indirect(rv.Field(i))

			// Don't try to mess with unexported types and other such things.
			if sf.CanSet() {
				if err := unify(datum, sf); err != nil {
					return e("Type mismatch for '%s.%s': %s",
						rt.String(), sft.Name, err)
				}
			} else if len(sft.Tag.Get("toml")) > 0 {
				// Bad user! No soup for you!
				return e("Field '%s.%s' is unexported, and therefore cannot "+
					"be loaded with reflection.", rt.String(), sft.Name)
			}
		}
	}
	return nil
}

func unifyMap(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return badtype("map", mapping)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeMap(rv.Type()))
	}
	for k, v := range tmap {
		rvkey := indirect(reflect.New(rv.Type().Key()))
		rvval := indirect(reflect.New(rv.Type().Elem()))
		if err := unify(v, rvval); err != nil {
			return err
		}

		rvkey.SetString(k)
		rv.SetMapIndex(rvkey, rvval)
	}
	return nil
}

func unifySlice(data interface{}, rv reflect.Value) error {
	slice, ok := data.([]interface{})
	if !ok {
		return badtype("slice", data)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeSlice(rv.Type(), len(slice), len(slice)))
	}
	for i, v := range slice {
		sliceval := indirect(rv.Index(i))
		if err := unify(v, sliceval); err != nil {
			return err
		}
	}
	return nil
}

func unifyDatetime(data interface{}, rv reflect.Value) error {
	if _, ok := data.(time.Time); ok {
		rv.Set(reflect.ValueOf(data))
		return nil
	}
	return badtype("time.Time", data)
}

func unifyString(data interface{}, rv reflect.Value) error {
	if s, ok := data.(string); ok {
		rv.SetString(s)
		return nil
	}
	return badtype("string", data)
}

func unifyFloat64(data interface{}, rv reflect.Value) error {
	if num, ok := data.(float64); ok {
		switch rv.Kind() {
		case reflect.Float32:
			fallthrough
		case reflect.Float64:
			rv.SetFloat(num)
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("float", data)
}

func unifyInt(data interface{}, rv reflect.Value) error {
	if num, ok := data.(int64); ok {
		switch rv.Kind() {
		case reflect.Int:
			fallthrough
		case reflect.Int8:
			fallthrough
		case reflect.Int16:
			fallthrough
		case reflect.Int32:
			fallthrough
		case reflect.Int64:
			rv.SetInt(int64(num))
		case reflect.Uint:
			fallthrough
		case reflect.Uint8:
			fallthrough
		case reflect.Uint16:
			fallthrough
		case reflect.Uint32:
			fallthrough
		case reflect.Uint64:
			rv.SetUint(uint64(num))
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("integer", data)
}

func unifyBool(data interface{}, rv reflect.Value) error {
	if b, ok := data.(bool); ok {
		rv.SetBool(b)
		return nil
	}
	return badtype("integer", data)
}

func unifyAnything(data interface{}, rv reflect.Value) error {
	// too awesome to fail
	rv.Set(reflect.ValueOf(data))
	return nil
}

// rvalue returns a reflect.Value of `v`. All pointers are resolved.
func rvalue(v interface{}) reflect.Value {
	return indirect(reflect.ValueOf(v))
}

// indirect returns the value pointed to by a pointer.
// Pointers are followed until the value is not a pointer.
// New values are allocated for each nil pointer.
func indirect(v reflect.Value) reflect.Value {
	if v.Kind() != reflect.Ptr {
		return v
	}
	if v.IsNil() {
		v.Set(reflect.New(v.Type().Elem()))
	}
	return indirect(reflect.Indirect(v))
}

func tstring(rv reflect.Value) string {
	return rv.Type().String()
}

func badtype(expected string, data interface{}) error {
	return e("Expected %s but found '%T'.", expected, data)
}

func mismatch(user reflect.Value, expected string, data interface{}) error {
	return e("Type mismatch for %s. Expected %s but found '%T'.",
		tstring(user), expected, data)
}

func insensitiveGet(
	tmap map[string]interface{}, kname string) (interface{}, bool) {

	if datum, ok := tmap[kname]; ok {
		return datum, true
	}
	for k, v := range tmap {
		if strings.EqualFold(kname, k) {
			return v, true
		}
	}
	return nil, false
}

// MetaData allows access to meta information about TOML data that may not
// be inferrable via reflection. In particular, whether a key has been defined
// and the TOML type of a key.
//
// (XXX: If TOML gets NULL values, that information will be added here too.)
type MetaData struct {
	mapping map[string]interface{}
	types   map[string]tomlType
	keys    []Key
}

// IsDefined returns true if the key given exists in the TOML data. The key
// should be specified hierarchially. e.g.,
//
//	// access the TOML key 'a.b.c'
//	IsDefined("a", "b", "c")
//
// IsDefined will return false if an empty key given. Keys are case sensitive.
func (md MetaData) IsDefined(key ...string) bool {
	var hashOrVal interface{}
	var hash map[string]interface{}
	var ok bool

	if len(key) == 0 {
		return false
	}

	hashOrVal = md.mapping
	for _, k := range key {
		if hash, ok = hashOrVal.(map[string]interface{}); !ok {
			return false
		}
		if hashOrVal, ok = hash[k]; !ok {
			return false
		}
	}
	return true
}

// Type returns a string representation of the type of the key specified.
//
// Type will return the empty string if given an empty key or a key that
// does not exist. Keys are case sensitive.
func (md MetaData) Type(key ...string) string {
	fullkey := strings.Join(key, ".")
	if typ, ok := md.types[fullkey]; ok {
		return typ.typeString()
	}
	return ""
}

// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
// to get values of this type.
type Key []string

func (k Key) String() string {
	return strings.Join(k, ".")
}

func (k Key) add(piece string) Key {
	newKey := make(Key, len(k))
	copy(newKey, k)
	return append(newKey, piece)
}

// Keys returns a slice of every key in the TOML data, including key groups.
// Each key is itself a slice, where the first element is the top of the
// hierarchy and the last is the most specific.
//
// The list will have the same order as the keys appeared in the TOML data.
//
// All keys returned are non-empty.
func (md MetaData) Keys() []Key {
	return md.keys
}

func allKeys(m map[string]interface{}, context Key) []Key {
	keys := make([]Key, 0, len(m))
	for k, v := range m {
		keys = append(keys, context.add(k))
		if t, ok := v.(map[string]interface{}); ok {
			keys = append(keys, allKeys(t, context.add(k))...)
		}
	}
	return keys
}
<|endoftext|>


<commit_before>// package Commands defines and implements command-line commands and flags
// used by devopsdays-cli. Commands and flags are implemented using Cobra.
package commands

import (
	"bytes"
	"fmt"
	"os"

	"github.com/devopsdays/devopsdays-cli/helpers/paths"
	"github.com/dimiro1/banner"
	"github.com/mattn/go-colorable"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var myBanner = `

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|d|e|v|o|p|s|d|a|y|s|-|c|l|i|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

`

// webdir is the path to the source files for the Hugo website
var webdir = paths.GetWebdir()

// const webdir = "/Users/mattstratton/src/devopsdays-web"

var cfgFile string

// Debug means should we run in debug mode. Duh.
var Debug bool

// City is the city we will be using - obtained via local flag
var City string

// Year is the year we will be using - obtained via local flag
var Year string

// All is used by a flag on Show commands to represent showing all of a thing
var All bool

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "devopsdays-cli",
	Short: "Run maintenance tasks for the devopsdays.org website",
	Long: `
Command-line utilities for the devopsdays.org website
built with love by mattstratton in Go.

Complete documentation is available at https://github.com/devopsdays/devopsdays-cli`,
	Run: func(cmd *cobra.Command, args []string) {
		mainPrompt()
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	isEnabled := true
	isColorEnabled := true
	banner.Init(colorable.NewColorableStdout(), isEnabled, isColorEnabled, bytes.NewBufferString(myBanner))

	RootCmd.PersistentFlags().BoolVarP(&Debug, "debug", "d", false, "enable debug mode")

}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".devopsdays-cli") // name of config file (without extension)
	viper.AddConfigPath("$HOME")           // adding home directory as first search path
	viper.AutomaticEnv()                   // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<commit_msg>Fix godoc for commands package<commit_after>// package commands defines and implements command-line commands and flags
// used by devopsdays-cli. Commands and flags are implemented using Cobra.
package commands

import (
	"bytes"
	"fmt"
	"os"

	"github.com/devopsdays/devopsdays-cli/helpers/paths"
	"github.com/dimiro1/banner"
	"github.com/mattn/go-colorable"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var myBanner = `

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|d|e|v|o|p|s|d|a|y|s|-|c|l|i|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

`

// webdir is the path to the source files for the Hugo website
var webdir = paths.GetWebdir()

// const webdir = "/Users/mattstratton/src/devopsdays-web"

var cfgFile string

// Debug means should we run in debug mode. Duh.
var Debug bool

// City is the city we will be using - obtained via local flag
var City string

// Year is the year we will be using - obtained via local flag
var Year string

// All is used by a flag on Show commands to represent showing all of a thing
var All bool

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "devopsdays-cli",
	Short: "Run maintenance tasks for the devopsdays.org website",
	Long: `
Command-line utilities for the devopsdays.org website
built with love by mattstratton in Go.

Complete documentation is available at https://github.com/devopsdays/devopsdays-cli`,
	Run: func(cmd *cobra.Command, args []string) {
		mainPrompt()
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	isEnabled := true
	isColorEnabled := true
	banner.Init(colorable.NewColorableStdout(), isEnabled, isColorEnabled, bytes.NewBufferString(myBanner))

	RootCmd.PersistentFlags().BoolVarP(&Debug, "debug", "d", false, "enable debug mode")

}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".devopsdays-cli") // name of config file (without extension)
	viper.AddConfigPath("$HOME")           // adding home directory as first search path
	viper.AutomaticEnv()                   // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"
	"container/list"
	js "encoding/json"

	"github.com/kurrik/oauth1a"
	"github.com/codingneo/twittergo"
	"github.com/kurrik/json"
	"github.com/robfig/cron"
	//"github.com/PuerkitoBio/goquery"
	"github.com/advancedlogic/GoOse"
	"github.com/codingneo/tweetsbot/ranking"
)

func LoadCredentials() (client *twittergo.Client, err error) {
	credentials, err := ioutil.ReadFile("CREDENTIALS")
	if err != nil {
		return
	}
	lines := strings.Split(string(credentials), "\n")
	config := &oauth1a.ClientConfig{
		ConsumerKey:    lines[0],
		ConsumerSecret: lines[1],
	}
	user := oauth1a.NewAuthorizedConfig(lines[2], lines[3])
	client = twittergo.NewClient(config, user, "stream.twitter.com")
	return
}

type Args struct {
	Track string
	Lang string
}

func parseArgs() *Args {
	a := &Args{}
	flag.StringVar(&a.Track, "track", "Data Science,Big Data", "Keyword to look up")
	flag.StringVar(&a.Lang, "lang", "en", "Language to look up")
	flag.Parse()
	return a
}

type streamConn struct {
	client   *http.Client
	resp     *http.Response
	url      *url.URL
	stale    bool
	closed   bool
	mu       sync.Mutex
	// wait time before trying to reconnect, this will be
	// exponentially moved up until reaching maxWait, when
	// it will exit
	wait    int
	maxWait int
	connect func() (*http.Response, error)
}

func NewStreamConn(max int) streamConn {
	return streamConn{wait: 1, maxWait: max}
}

func (conn *streamConn) Close() {
	// Just mark the connection as stale, and let the connect() handler close after a read
	conn.mu.Lock()
	defer conn.mu.Unlock()
	conn.stale = true
	conn.closed = true
	if conn.resp != nil {
		conn.resp.Body.Close()
	}
}

func (conn *streamConn) isStale() bool {
	conn.mu.Lock()
	r := conn.stale
	conn.mu.Unlock()
	return r
}

func readStream(client *twittergo.Client, sc streamConn, path string, query url.Values,
				resp *twittergo.APIResponse, handler func([]byte), done chan bool) {

	var reader *bufio.Reader
	reader = bufio.NewReader(resp.Body)

	for {
		//we've been closed
		if sc.isStale() {
			sc.Close()
			fmt.Println("Connection closed, shutting down ")
			break
		}

		line, err := reader.ReadBytes('\n')

		if err != nil {
			if sc.isStale() {
				fmt.Println("conn stale, continue")
				continue
			}

			time.Sleep(time.Second * time.Duration(sc.wait))
			//try reconnecting, but exponentially back off until MaxWait is reached then exit?
			resp, err := Connect(client, path, query)
			if err != nil || resp == nil {
				fmt.Println(" Could not reconnect to source? sleeping and will retry ")
				if sc.wait < sc.maxWait {
					sc.wait = sc.wait * 2
				} else {
					fmt.Println("exiting, max wait reached")
					done <- true
					return
				}
				continue
			}
			if resp.StatusCode != 200 {
				fmt.Printf("resp.StatusCode = %d", resp.StatusCode)
				if sc.wait < sc.maxWait {
					sc.wait = sc.wait * 2
				}
				continue
			}

			reader = bufio.NewReader(resp.Body)
			continue
		} else if sc.wait != 1 {
			sc.wait = 1
		}
		line = bytes.TrimSpace(line)
		fmt.Println("Received a line ")

		if len(line) == 0 {
			continue
		}
		handler(line)
	}
}

func Connect(client *twittergo.Client, path string, query url.Values) (resp *twittergo.APIResponse, err error) {
	var (
		req 	*http.Request
	)

	url := fmt.Sprintf("%v?%v", path, query.Encode())
	req, err = http.NewRequest("GET", url, nil)
	if err != nil {
		err = fmt.Errorf("Could not parse request: %v\n", err)
		return
	}
	resp, err = client.SendRequest(req)
	if err != nil {
		err = fmt.Errorf("Could not send request: %v\n", err)
		return
	}

	fmt.Printf("resp.StatusCode=%d\n", resp.StatusCode)
	return
}

func filterStream(client *twittergo.Client, path string, query url.Values) (err error) {
	var (
		resp    *twittergo.APIResponse
	)

	sc := NewStreamConn(300)

	resp, err = Connect(client, path, query)

	done := make(chan bool)
	stream := make(chan []byte, 1000)
	go func() {
		topList := list.New()

		//Cron job to store toplist per hour
		c := cron.New()
		c.AddFunc("0 * * * * *",
			func() {
				fmt.Println("cron cron cron cron ............................")
				filename := "./data/toplist-" +
										time.Now().Local().Format("2006-01-02") +
										".json"

				output := make(map[string]interface{})
				output["articles"] = make([]ranking.Item, 0)

				f, err := os.OpenFile(filename, os.O_RDWR, 0666)
				if (err != nil) {
					fmt.Println("[Cron] File not exist")
					f, err = os.Create(filename)
					if (err != nil) {
						fmt.Println("[Cron] File creation error")
					}
				}

				tlist := make([]ranking.Item, 0)
				for e := topList.Front(); e != nil; e = e.Next() {
					fmt.Println("[Cron] Write url into file")
					//f.WriteString(e.Value.(ranking.Item).Url)
					//f.WriteString("\n")
					tlist = append(tlist, e.Value.(ranking.Item))
				}
				output["articles"] = tlist

				jsonstr, _ := js.Marshal(output)
				f.WriteString(string(jsonstr))
				f.Sync()
				f.Close()
			})
		c.Start()
		fmt.Println("cron job start")

		g := goose.New()
		for data := range stream {
			fmt.Println(string(data))
			tweet := &twittergo.Tweet{}
			err := json.Unmarshal(data, tweet)
			if (err == nil) {
				fmt.Printf("ID:                   %v\n", tweet.Id())
				fmt.Printf("User:                 %v\n", tweet.User().ScreenName())
				fmt.Printf("Tweet:                %v\n", tweet.Text())

				rs := tweet.RetweetStatus()
				vote := 0
				if (rs != nil) {
					fmt.Printf("retweet_count:        %d\n", rs.RetweetCount())
					fmt.Printf("favorite_count:        %d\n", rs.FavoriteCount())
					vote += int(rs.RetweetCount()+rs.FavoriteCount())
				}

				e := tweet.Entities()
				if (e != nil) {
					fmt.Printf("url:        %v\n", e.FirstUrl().ExpandedUrl())

					// Form top item
					if (e.FirstUrl().ExpandedUrl()!="") {
						item := ranking.Item{}
						item.Vote = vote
						item.Url = e.FirstUrl().ExpandedUrl()

						// article extraction
						//doc, err := goquery.NewDocument(item.Url)
						article := g.ExtractFromUrl(item.Url)

						fmt.Println("title", article.Title)
    				fmt.Println("description", article.MetaDescription)
    				fmt.Println("top image", article.TopImage)

    				if (article.Title != "") &&
    					 (article.MetaDescription != "")) {
							item.Title = article.Title
    					item.Description = article.MetaDescription
    					item.Image = article.TopImage

    					ranking.Insert(topList, item)
    				}

						//if err == nil {
						//	item.Title = doc.Find("title").Text()
						//	fmt.Printf("title:        %v\n", item.Title)
						//	ranking.Insert(topList, item)
						//}

						fmt.Println("**********************************")
						for e := topList.Front(); e != nil; e = e.Next() {
							fmt.Printf("%d: %v\n",e.Value.(ranking.Item).Vote, e.Value.(ranking.Item).Url)
						}
					}
				}
			}
		}
	}()

	readStream(client, sc, path, query, resp, func(line []byte) {
		stream <- line}, done)

	return
}

func main() {
	var (
		err    error
		args   *Args
		client *twittergo.Client
	)

	args = parseArgs()
	if client, err = LoadCredentials(); err != nil {
		fmt.Printf("Could not parse CREDENTIALS file: %v\n", err)
		os.Exit(1)
	}
	fmt.Println(args.Track)
	query := url.Values{}
	query.Set("track", args.Track)
	query.Set("lang", args.Lang)

	fmt.Println("Printing everything about data science:")
	fmt.Printf("=========================================================\n")
	if err = filterStream(client, "/1.1/statuses/filter.json", query); err != nil {
		fmt.Println("Error: %v\n", err)
	}
	fmt.Printf("\n\n")

}
<commit_msg>Bug fix<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"
	"container/list"
	js "encoding/json"

	"github.com/kurrik/oauth1a"
	"github.com/codingneo/twittergo"
	"github.com/kurrik/json"
	"github.com/robfig/cron"
	//"github.com/PuerkitoBio/goquery"
	"github.com/advancedlogic/GoOse"
	"github.com/codingneo/tweetsbot/ranking"
)

func LoadCredentials() (client *twittergo.Client, err error) {
	credentials, err := ioutil.ReadFile("CREDENTIALS")
	if err != nil {
		return
	}
	lines := strings.Split(string(credentials), "\n")
	config := &oauth1a.ClientConfig{
		ConsumerKey:    lines[0],
		ConsumerSecret: lines[1],
	}
	user := oauth1a.NewAuthorizedConfig(lines[2], lines[3])
	client = twittergo.NewClient(config, user, "stream.twitter.com")
	return
}

type Args struct {
	Track string
	Lang string
}

func parseArgs() *Args {
	a := &Args{}
	flag.StringVar(&a.Track, "track", "Data Science,Big Data", "Keyword to look up")
	flag.StringVar(&a.Lang, "lang", "en", "Language to look up")
	flag.Parse()
	return a
}

type streamConn struct {
	client   *http.Client
	resp     *http.Response
	url      *url.URL
	stale    bool
	closed   bool
	mu       sync.Mutex
	// wait time before trying to reconnect, this will be
	// exponentially moved up until reaching maxWait, when
	// it will exit
	wait    int
	maxWait int
	connect func() (*http.Response, error)
}

func NewStreamConn(max int) streamConn {
	return streamConn{wait: 1, maxWait: max}
}

func (conn *streamConn) Close() {
	// Just mark the connection as stale, and let the connect() handler close after a read
	conn.mu.Lock()
	defer conn.mu.Unlock()
	conn.stale = true
	conn.closed = true
	if conn.resp != nil {
		conn.resp.Body.Close()
	}
}

func (conn *streamConn) isStale() bool {
	conn.mu.Lock()
	r := conn.stale
	conn.mu.Unlock()
	return r
}

func readStream(client *twittergo.Client, sc streamConn, path string, query url.Values,
				resp *twittergo.APIResponse, handler func([]byte), done chan bool) {

	var reader *bufio.Reader
	reader = bufio.NewReader(resp.Body)

	for {
		//we've been closed
		if sc.isStale() {
			sc.Close()
			fmt.Println("Connection closed, shutting down ")
			break
		}

		line, err := reader.ReadBytes('\n')

		if err != nil {
			if sc.isStale() {
				fmt.Println("conn stale, continue")
				continue
			}

			time.Sleep(time.Second * time.Duration(sc.wait))
			//try reconnecting, but exponentially back off until MaxWait is reached then exit?
			resp, err := Connect(client, path, query)
			if err != nil || resp == nil {
				fmt.Println(" Could not reconnect to source? sleeping and will retry ")
				if sc.wait < sc.maxWait {
					sc.wait = sc.wait * 2
				} else {
					fmt.Println("exiting, max wait reached")
					done <- true
					return
				}
				continue
			}
			if resp.StatusCode != 200 {
				fmt.Printf("resp.StatusCode = %d", resp.StatusCode)
				if sc.wait < sc.maxWait {
					sc.wait = sc.wait * 2
				}
				continue
			}

			reader = bufio.NewReader(resp.Body)
			continue
		} else if sc.wait != 1 {
			sc.wait = 1
		}
		line = bytes.TrimSpace(line)
		fmt.Println("Received a line ")

		if len(line) == 0 {
			continue
		}
		handler(line)
	}
}

func Connect(client *twittergo.Client, path string, query url.Values) (resp *twittergo.APIResponse, err error) {
	var (
		req 	*http.Request
	)

	url := fmt.Sprintf("%v?%v", path, query.Encode())
	req, err = http.NewRequest("GET", url, nil)
	if err != nil {
		err = fmt.Errorf("Could not parse request: %v\n", err)
		return
	}
	resp, err = client.SendRequest(req)
	if err != nil {
		err = fmt.Errorf("Could not send request: %v\n", err)
		return
	}

	fmt.Printf("resp.StatusCode=%d\n", resp.StatusCode)
	return
}

func filterStream(client *twittergo.Client, path string, query url.Values) (err error) {
	var (
		resp    *twittergo.APIResponse
	)

	sc := NewStreamConn(300)

	resp, err = Connect(client, path, query)

	done := make(chan bool)
	stream := make(chan []byte, 1000)
	go func() {
		topList := list.New()

		//Cron job to store toplist per hour
		c := cron.New()
		c.AddFunc("0 * * * * *",
			func() {
				fmt.Println("cron cron cron cron ............................")
				filename := "./data/toplist-" +
										time.Now().Local().Format("2006-01-02") +
										".json"

				output := make(map[string]interface{})
				output["articles"] = make([]ranking.Item, 0)

				f, err := os.OpenFile(filename, os.O_RDWR, 0666)
				if (err != nil) {
					fmt.Println("[Cron] File not exist")
					f, err = os.Create(filename)
					if (err != nil) {
						fmt.Println("[Cron] File creation error")
					}
				}

				tlist := make([]ranking.Item, 0)
				for e := topList.Front(); e != nil; e = e.Next() {
					fmt.Println("[Cron] Write url into file")
					//f.WriteString(e.Value.(ranking.Item).Url)
					//f.WriteString("\n")
					tlist = append(tlist, e.Value.(ranking.Item))
				}
				output["articles"] = tlist

				jsonstr, _ := js.Marshal(output)
				f.WriteString(string(jsonstr))
				f.Sync()
				f.Close()
			})
		c.Start()
		fmt.Println("cron job start")

		g := goose.New()
		for data := range stream {
			fmt.Println(string(data))
			tweet := &twittergo.Tweet{}
			err := json.Unmarshal(data, tweet)
			if (err == nil) {
				fmt.Printf("ID:                   %v\n", tweet.Id())
				fmt.Printf("User:                 %v\n", tweet.User().ScreenName())
				fmt.Printf("Tweet:                %v\n", tweet.Text())

				rs := tweet.RetweetStatus()
				vote := 0
				if (rs != nil) {
					fmt.Printf("retweet_count:        %d\n", rs.RetweetCount())
					fmt.Printf("favorite_count:        %d\n", rs.FavoriteCount())
					vote += int(rs.RetweetCount()+rs.FavoriteCount())
				}

				e := tweet.Entities()
				if (e != nil) {
					fmt.Printf("url:        %v\n", e.FirstUrl().ExpandedUrl())

					// Form top item
					if (e.FirstUrl().ExpandedUrl()!="") {
						item := ranking.Item{}
						item.Vote = vote
						item.Url = e.FirstUrl().ExpandedUrl()

						// article extraction
						//doc, err := goquery.NewDocument(item.Url)
						article := g.ExtractFromUrl(item.Url)

						fmt.Println("title", article.Title)
    				fmt.Println("description", article.MetaDescription)
    				fmt.Println("top image", article.TopImage)

    				if (article.Title != "") &&
    					 (article.MetaDescription != "") {
							item.Title = article.Title
    					item.Description = article.MetaDescription
    					item.Image = article.TopImage

    					ranking.Insert(topList, item)
    				}

						//if err == nil {
						//	item.Title = doc.Find("title").Text()
						//	fmt.Printf("title:        %v\n", item.Title)
						//	ranking.Insert(topList, item)
						//}

						fmt.Println("**********************************")
						for e := topList.Front(); e != nil; e = e.Next() {
							fmt.Printf("%d: %v\n",e.Value.(ranking.Item).Vote, e.Value.(ranking.Item).Url)
						}
					}
				}
			}
		}
	}()

	readStream(client, sc, path, query, resp, func(line []byte) {
		stream <- line}, done)

	return
}

func main() {
	var (
		err    error
		args   *Args
		client *twittergo.Client
	)

	args = parseArgs()
	if client, err = LoadCredentials(); err != nil {
		fmt.Printf("Could not parse CREDENTIALS file: %v\n", err)
		os.Exit(1)
	}
	fmt.Println(args.Track)
	query := url.Values{}
	query.Set("track", args.Track)
	query.Set("lang", args.Lang)

	fmt.Println("Printing everything about data science:")
	fmt.Printf("=========================================================\n")
	if err = filterStream(client, "/1.1/statuses/filter.json", query); err != nil {
		fmt.Println("Error: %v\n", err)
	}
	fmt.Printf("\n\n")

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"

	"image"
	"image/draw"
	"image/png"
)

type Size struct {
	x, y int
}

type sprite struct {
	name string
	img  image.Image
	rect image.Rectangle
	area int
	size Size
}

type ByArea []sprite

func (a ByArea) Len() int           { return len(a) }
func (a ByArea) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByArea) Less(i, j int) bool { return a[i].area < a[j].area }

func main() {
	flag.Parse()

	args := flag.Args()

	inputDir := args[0]

	files, _ := ioutil.ReadDir(inputDir)
	sprites := make([]sprite, len(files))

	totalX := 0
	totalY := 0

	for i := range sprites {
		s := readSprite(inputDir, files[i].Name())
		sprites[i] = s
		totalX += s.size.x
		totalY += s.size.y
	}

	// we want to place the largest sprite first
	sort.Sort(sort.Reverse(ByArea(sprites)))

	// the final image
	dst := image.NewRGBA(image.Rect(0, 0, 1024, 1024))

	for i := range sprites {
		s := &sprites[i]
		draw.Draw(dst, s.rect, s.img, image.ZP, draw.Src)
	}

	writer, err := os.Create("test.png")
	err = png.Encode(writer, dst)
	if err != nil {
		log.Fatal(err)
	}
}

func readSprite(dir, name string) (s sprite) {
	path := path.Join(dir, name)
	reader, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()

	img, err := png.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	s.name = name
	s.img = img
	s.rect = img.Bounds()
	s.size = Size{s.rect.Dx(), s.rect.Dy()}
	s.area = s.size.x * s.size.y
	return
}
<commit_msg>Broken packer tree<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"

	"image"
	"image/draw"
	"image/png"
)

type Size struct {
	x, y int
}

func (a Size) Equal(b Size) bool {
	return a.x == b.x && a.y == b.y
}

func (a Size) Larger(b Size) bool {
	return b.x < a.x && b.y < a.y
}

func (a Size) Smaller(b Size) bool {
	return !a.Larger(b)
}

type sprite struct {
	name string
	img  image.Image
	rect image.Rectangle
	area int
	size Size
}

type ByArea []sprite

func (a ByArea) Len() int           { return len(a) }
func (a ByArea) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByArea) Less(i, j int) bool { return a[i].area < a[j].area }

type Node struct {
	child [2]*Node
	rect  image.Rectangle
	img   *sprite
}

func (n *Node) size() Size {
	return Size{n.rect.Dx(), n.rect.Dy()}
}

func (n *Node) print() {
	fmt.Println(n)
	if n.child[0] != nil {
		n.child[0].print()
	}
	if n.child[1] != nil {
		n.child[1].print()
	}
}

func (n *Node) insert(img *sprite) bool {
	// there is already an image in this node
	if n.img != nil {
		fmt.Println("already contains an image")
		return false
	}

	// try to insert into either of the nodes children
	if n.child[0] != nil {
		fmt.Println("has a 0 child")
		in := n.child[0].insert(img)

		if in {
			return true
		} else {
			fmt.Println("has a 1 child")
			return n.child[1].insert(img)
		}
	}

	if n.rect.Dx() < img.size.x || n.rect.Dy() < img.size.y {
		fmt.Println("space too small")
		return false
	}

	if n.rect.Dx() == img.size.x && n.rect.Dy() == img.size.y {
		fmt.Println("prefect fit")
		n.img = img
		return true
	}

	if n.rect.Dx() >= img.size.x && n.rect.Dy() >= img.size.y {
		fmt.Println("Split")
		n.split(img)
	}

	return n.insert(img)

}

func (n *Node) split(img *sprite) {
	var tl0 image.Point
	var br0 image.Point

	var tl1 image.Point
	var br1 image.Point

	dx := n.size().x - img.size.x
	dy := n.size().y - img.size.y

	rc := n.rect

	tl0 = rc.Min
	br1 = rc.Max

	if dx > dy {
		fmt.Println("split on x")
		br0 = image.Point{rc.Min.X + img.size.x, rc.Dy()}
		tl1 = image.Point{rc.Min.X + img.size.x - 1, rc.Min.Y}
	} else {
		fmt.Println("split on y")
		br0 = image.Point{rc.Dx(), rc.Min.Y + img.size.y}
		tl1 = image.Point{rc.Min.X, rc.Min.Y + img.size.y - 1}
	}

	rect0 := image.Rectangle{tl0, br0}
	n.child[0] = &Node{rect: rect0}

	rect1 := image.Rectangle{tl1, br1}
	n.child[1] = &Node{rect: rect1}
}

func main() {
	flag.Parse()

	args := flag.Args()

	inputDir := args[0]

	files, _ := ioutil.ReadDir(inputDir)
	sprites := make([]sprite, len(files))

	totalX := 0
	totalY := 0

	for i := range sprites {
		s := readSprite(inputDir, files[i].Name())
		sprites[i] = s
		totalX += s.size.x
		totalY += s.size.y
	}

	// we want to place the largest sprite first
	sort.Sort(sort.Reverse(ByArea(sprites)))

	// the final image
	dst := image.NewRGBA(image.Rect(0, 0, 2048, 2048))

	n := Node{rect: image.Rect(0, 0, 1024, 1024)}

	for i := range sprites {
		s := &sprites[i]
		fmt.Printf("inserting %s\n", s.name)
		n.insert(s)
		draw.Draw(dst, s.rect, s.img, image.ZP, draw.Src)
	}

	n.print()

	writer, err := os.Create("test.png")
	err = png.Encode(writer, dst)
	if err != nil {
		log.Fatal(err)
	}
}

func readSprite(dir, name string) (s sprite) {
	path := path.Join(dir, name)
	reader, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()

	img, err := png.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	s.name = name
	s.img = img
	s.rect = img.Bounds()
	s.size = Size{s.rect.Dx(), s.rect.Dy()}
	s.area = s.size.x * s.size.y
	return
}
<|endoftext|>


<commit_before>package heartbeater

import (
	"errors"
	"math"
	"os"
	"time"

	"github.com/cloudfoundry/storeadapter"
	"github.com/pivotal-golang/clock"
	"github.com/pivotal-golang/lager"
)

var (
	ErrLockFailed       = errors.New("failed to compare and swap")
	ErrStoreUnavailable = errors.New("failed to connect to etcd")
)

type Heartbeater struct {
	client   storeadapter.StoreAdapter
	key      string
	value    string
	interval time.Duration
	logger   lager.Logger

	clock clock.Clock
}

func New(
	etcdClient storeadapter.StoreAdapter,
	clock clock.Clock,
	heartbeatKey string,
	heartbeatValue string,
	heartbeatInterval time.Duration,
	logger lager.Logger,
) Heartbeater {
	return Heartbeater{
		client:   etcdClient,
		clock:    clock,
		key:      heartbeatKey,
		value:    heartbeatValue,
		interval: heartbeatInterval,
		logger:   logger,
	}
}

func (h Heartbeater) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := h.logger.Session("heartbeat", lager.Data{"key": h.key, "value": h.value})

	ttl := uint64(math.Ceil((h.interval * 2).Seconds()))

	node := storeadapter.StoreNode{
		Key:   h.key,
		Value: []byte(h.value),
		TTL:   ttl,
	}

	if h.acquireHeartbeat(logger, node, ttl, signals) {
		close(ready)

		return h.maintainHeartbeat(logger, node, ttl, signals)
	}

	return nil
}

func (h Heartbeater) acquireHeartbeat(logger lager.Logger, node storeadapter.StoreNode, ttl uint64, signals <-chan os.Signal) bool {
	logger.Info("starting")

	err := h.client.CompareAndSwap(node, node)
	if err != nil {
		var stopWatch chan<- bool
		var watchEvents <-chan storeadapter.WatchEvent
		var watchErrors <-chan error

		watchEvents, stopWatch, watchErrors = h.client.Watch(h.key)
		defer close(stopWatch)

		intervalTimer := h.clock.NewTimer(0)
		defer intervalTimer.Stop()

	WATCH:
		for {
			select {
			case event := <-watchEvents:
				if !(event.Type == storeadapter.DeleteEvent || event.Type == storeadapter.ExpireEvent) {
					continue WATCH
				}
			case <-intervalTimer.C():
			case <-watchErrors:
				watchEvents, stopWatch, watchErrors = h.client.Watch(h.key)
				continue WATCH
			case <-signals:
				return false
			}

			err := h.client.Create(node)
			if err == nil {
				logger.Info("created-node")
				break
			}

			intervalTimer.Reset(h.interval)
		}
	}

	logger.Info("started")
	return true
}

func (h Heartbeater) maintainHeartbeat(logger lager.Logger, node storeadapter.StoreNode, ttl uint64, signals <-chan os.Signal) error {
	var connectionTimer clock.Timer
	var connectionTimeout <-chan time.Time

	intervalTimer := h.clock.NewTimer(h.interval)
	defer intervalTimer.Stop()

	for {
		select {
		case sig := <-signals:
			logger.Info("received-shutdown-signal")
			switch sig {
			case os.Kill:
				return nil
			default:
				h.client.CompareAndDelete(node)
				return nil
			}

		case <-connectionTimeout:
			logger.Info("connection-timed-out")
			return ErrStoreUnavailable

		case <-intervalTimer.C():
			err := h.client.CompareAndSwap(node, node)
			switch err {
			case storeadapter.ErrorTimeout:
				logger.Error("store-timeout", err)
				if connectionTimeout == nil {
					connectionTimer = h.clock.NewTimer(time.Duration(ttl) * time.Second)
					connectionTimeout = connectionTimer.C()
				}
			case storeadapter.ErrorKeyNotFound:
				err = h.client.Create(node)
				if err != nil && connectionTimeout == nil {
					connectionTimer = h.clock.NewTimer(time.Duration(ttl) * time.Second)
					connectionTimeout = connectionTimer.C()
				}
			case nil:
				if connectionTimeout != nil {
					connectionTimer.Stop()
					connectionTimeout = nil
				}
			default:
				logger.Error("compare-and-swap-failed", err)
				return ErrLockFailed
			}
			intervalTimer.Reset(h.interval)
		}
	}
}
<commit_msg>Add debug logging to heartbeater [#89826352]<commit_after>package heartbeater

import (
	"errors"
	"math"
	"os"
	"time"

	"github.com/cloudfoundry/storeadapter"
	"github.com/pivotal-golang/clock"
	"github.com/pivotal-golang/lager"
)

var (
	ErrLockFailed       = errors.New("failed to compare and swap")
	ErrStoreUnavailable = errors.New("failed to connect to etcd")
)

type Heartbeater struct {
	client storeadapter.StoreAdapter
	key    string
	value  string

	keyCreateRetryInterval time.Duration
	keyHeartbeatInterval   time.Duration
	keyTTL                 uint64
	clock                  clock.Clock

	logger lager.Logger
}

func New(
	etcdClient storeadapter.StoreAdapter,
	clock clock.Clock,
	heartbeatKey string,
	heartbeatValue string,
	heartbeatInterval time.Duration,
	logger lager.Logger,
) Heartbeater {
	return Heartbeater{
		client: etcdClient,
		key:    heartbeatKey,
		value:  heartbeatValue,

		keyCreateRetryInterval: heartbeatInterval,
		keyHeartbeatInterval:   heartbeatInterval,
		keyTTL:                 uint64(math.Ceil((heartbeatInterval * 2).Seconds())),
		clock:                  clock,

		logger: logger,
	}
}

func (h Heartbeater) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := h.logger.Session("heartbeat", lager.Data{"key": h.key, "value": h.value})

	node := storeadapter.StoreNode{
		Key:   h.key,
		Value: []byte(h.value),
		TTL:   h.keyTTL,
	}

	if h.acquireHeartbeat(logger, node, signals) {
		close(ready)

		return h.maintainHeartbeat(logger, node, signals)
	}

	return nil
}

func (h Heartbeater) acquireHeartbeat(logger lager.Logger, node storeadapter.StoreNode, signals <-chan os.Signal) bool {
	logger.Info("starting")

	err := h.client.CompareAndSwap(node, node)
	if err != nil {
		var stopWatch chan<- bool
		var watchEvents <-chan storeadapter.WatchEvent
		var watchErrors <-chan error

		watchEvents, stopWatch, watchErrors = h.client.Watch(h.key)
		defer close(stopWatch)

		intervalTimer := h.clock.NewTimer(0)
		defer intervalTimer.Stop()

	WATCH:
		for {
			select {
			case event := <-watchEvents:
				if !(event.Type == storeadapter.DeleteEvent || event.Type == storeadapter.ExpireEvent) {
					continue WATCH
				}
			case <-intervalTimer.C():
			case <-watchErrors:
				watchEvents, stopWatch, watchErrors = h.client.Watch(h.key)
				continue WATCH
			case <-signals:
				return false
			}

			err := h.client.Create(node)
			if err == nil {
				logger.Info("created-node")
				break
			}

			intervalTimer.Reset(h.keyCreateRetryInterval)
		}
	}

	logger.Info("started")
	return true
}

func (h Heartbeater) maintainHeartbeat(logger lager.Logger, node storeadapter.StoreNode, signals <-chan os.Signal) error {
	var connectionTimer clock.Timer
	var connectionTimeout <-chan time.Time

	intervalTimer := h.clock.NewTimer(h.keyHeartbeatInterval)
	defer intervalTimer.Stop()

	for {
		select {
		case sig := <-signals:
			logger.Info("received-shutdown-signal")
			switch sig {
			case os.Kill:
				return nil
			default:
				h.client.CompareAndDelete(node)
				return nil
			}

		case <-connectionTimeout:
			logger.Info("connection-timed-out")
			return ErrStoreUnavailable

		case <-intervalTimer.C():
			logger.Debug("compare-and-swapping")
			err := h.client.CompareAndSwap(node, node)
			if err != nil {
				logger.Error("failed-compare-and-swapping", err)
			} else {
				logger.Debug("succeeded-compare-and-swapping")
			}
			switch err {
			case storeadapter.ErrorTimeout:
				if connectionTimeout == nil {
					connectionTimer = h.clock.NewTimer(time.Duration(h.keyTTL) * time.Second)
					connectionTimeout = connectionTimer.C()
				}
			case storeadapter.ErrorKeyNotFound:
				logger.Debug("re-creating-node")
				err = h.client.Create(node)
				if err != nil {
					logger.Error("failed-re-creating-node", err)
				} else {
					logger.Debug("succeeded-re-creating-node")
				}
				if err != nil && connectionTimeout == nil {
					connectionTimer = h.clock.NewTimer(time.Duration(h.keyTTL) * time.Second)
					connectionTimeout = connectionTimer.C()
				}
			case nil:
				if connectionTimeout != nil {
					connectionTimer.Stop()
					connectionTimeout = nil
				}
			default:
				return ErrLockFailed
			}
			intervalTimer.Reset(h.keyHeartbeatInterval)
		}
	}
}
<|endoftext|>


<commit_before>// 7 february 2014
package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

// MessageBox button types.
const (
	_MB_ABORTRETRYIGNORE = 0x00000002
	_MB_CANCELTRYCONTINUE = 0x00000006
	_MB_HELP = 0x00004000
	_MB_OK = 0x00000000
	_MB_OKCANCEL = 0x00000001
	_MB_RETRYCANCEL = 0x00000005
	_MB_YESNO = 0x00000004
	_MB_YESNOCANCEL = 0x00000003
)

// MessageBox icon types.
const (
	_MB_ICONEXCLAMATION = 0x00000030
	_MB_ICONWARNING = 0x00000030
	_MB_ICONINFORMATION = 0x00000040
	_MB_ICONASTERISK = 0x00000040
	_MB_ICONQUESTION = 0x00000020
	_MB_ICONSTOP = 0x00000010
	_MB_ICONERROR = 0x00000010
	_MB_ICONHAND = 0x00000010
)

// MessageBox default button types.
const (
	_MB_DEFBUTTON1 = 0x00000000
	_MB_DEFBUTTON2 = 0x00000100
	_MB_DEFBUTTON3 = 0x00000200
	_MB_DEFBUTTON4 = 0x00000300
)

// MessageBox modality types.
const (
	_MB_APPLMODAL = 0x00000000
	_MB_SYSTEMMODAL = 0x00001000
	_MB_TASKMODAL = 0x00002000
)

// MessageBox miscellaneous types.
const (
	_MB_DEFAULT_DESKTOP_ONLY = 0x00020000
	_MB_RIGHT = 0x00080000
	_MB_RTLREADING = 0x00100000
	_MB_SETFOREGROUND = 0x00010000
	_MB_TOPMOST = 0x00040000
	_MB_SERVICE_NOTIFICATION = 0x00200000
)

// MessageBox return values.
const (
	_IDABORT = 3
	_IDCANCEL = 2
	_IDCONTINUE = 11
	_IDIGNORE = 5
	_IDNO = 7
	_IDOK = 1
	_IDRETRY = 4
	_IDTRYAGAIN = 10
	_IDYES = 6
)

var (
	_messageBox = user32.NewProc("MessageBoxW")
)

func msgBox(lpText string, lpCaption string, uType uint32) (result int) {
	r1, _, err := _messageBox.Call(
		uintptr(_NULL),
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpText))),
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpCaption))),
		uintptr(uType))
	if r1 == 0 {		// failure
		panic(fmt.Sprintf("error displaying message box to user: %v\nstyle: 0x%08X\ntitle: %q\ntext:\n%s", err, uType, lpCaption, lpText))
	}
	return int(r1)
}

// MsgBox displays an informational message box to the user with just an OK button.
func MsgBox(title string, textfmt string, args ...interface{}) {
	// TODO add an icon?
	msgBox(fmt.Sprintf(textfmt, args...), title, _MB_OK)
}

// MsgBoxError displays a message box to the user with just an OK button and an icon indicating an error.
func MsgBoxError(title string, textfmt string, args ...interface{}) {
	// TODO add an icon?
	msgBox(fmt.Sprintf(textfmt, args...), title, _MB_OK | _MB_ERROR)
}
<commit_msg>Fixed a build error in the previous commit.<commit_after>// 7 february 2014
package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

// MessageBox button types.
const (
	_MB_ABORTRETRYIGNORE = 0x00000002
	_MB_CANCELTRYCONTINUE = 0x00000006
	_MB_HELP = 0x00004000
	_MB_OK = 0x00000000
	_MB_OKCANCEL = 0x00000001
	_MB_RETRYCANCEL = 0x00000005
	_MB_YESNO = 0x00000004
	_MB_YESNOCANCEL = 0x00000003
)

// MessageBox icon types.
const (
	_MB_ICONEXCLAMATION = 0x00000030
	_MB_ICONWARNING = 0x00000030
	_MB_ICONINFORMATION = 0x00000040
	_MB_ICONASTERISK = 0x00000040
	_MB_ICONQUESTION = 0x00000020
	_MB_ICONSTOP = 0x00000010
	_MB_ICONERROR = 0x00000010
	_MB_ICONHAND = 0x00000010
)

// MessageBox default button types.
const (
	_MB_DEFBUTTON1 = 0x00000000
	_MB_DEFBUTTON2 = 0x00000100
	_MB_DEFBUTTON3 = 0x00000200
	_MB_DEFBUTTON4 = 0x00000300
)

// MessageBox modality types.
const (
	_MB_APPLMODAL = 0x00000000
	_MB_SYSTEMMODAL = 0x00001000
	_MB_TASKMODAL = 0x00002000
)

// MessageBox miscellaneous types.
const (
	_MB_DEFAULT_DESKTOP_ONLY = 0x00020000
	_MB_RIGHT = 0x00080000
	_MB_RTLREADING = 0x00100000
	_MB_SETFOREGROUND = 0x00010000
	_MB_TOPMOST = 0x00040000
	_MB_SERVICE_NOTIFICATION = 0x00200000
)

// MessageBox return values.
const (
	_IDABORT = 3
	_IDCANCEL = 2
	_IDCONTINUE = 11
	_IDIGNORE = 5
	_IDNO = 7
	_IDOK = 1
	_IDRETRY = 4
	_IDTRYAGAIN = 10
	_IDYES = 6
)

var (
	_messageBox = user32.NewProc("MessageBoxW")
)

func msgBox(lpText string, lpCaption string, uType uint32) (result int) {
	r1, _, err := _messageBox.Call(
		uintptr(_NULL),
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpText))),
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpCaption))),
		uintptr(uType))
	if r1 == 0 {		// failure
		panic(fmt.Sprintf("error displaying message box to user: %v\nstyle: 0x%08X\ntitle: %q\ntext:\n%s", err, uType, lpCaption, lpText))
	}
	return int(r1)
}

// MsgBox displays an informational message box to the user with just an OK button.
func MsgBox(title string, textfmt string, args ...interface{}) {
	// TODO add an icon?
	msgBox(fmt.Sprintf(textfmt, args...), title, _MB_OK)
}

// MsgBoxError displays a message box to the user with just an OK button and an icon indicating an error.
func MsgBoxError(title string, textfmt string, args ...interface{}) {
	// TODO add an icon?
	msgBox(fmt.Sprintf(textfmt, args...), title, _MB_OK | _MB_ICONERROR)
}
<|endoftext|>