<commit_before>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package filters

import (
	"fmt"

	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
	"sigs.k8s.io/kustomize/kyaml/yaml"
	"sigs.k8s.io/kustomize/kyaml/yaml/merge3"
)

const (
	mergeSourceAnnotation = "config.kubernetes.io/merge-source"
	mergeSourceOriginal   = "original"
	mergeSourceUpdated    = "updated"
	mergeSourceDest       = "dest"
)

// ResourceMatcher interface is used to match two resources based on IsSameResource implementation
// This is the way to group same logical resources in upstream, local and origin for merge
// The default way to group them is using GVKNN similar to how kubernetes server identifies resources
// Users of this library might have their own interpretation of grouping similar resources
// for e.g. if consumer adds a name-prefix to local resource, it should not be treated as new resource
// for updates etc.
// Hence, the callers of this library may pass different implementation for IsSameResource
type ResourceMatcher interface {
	IsSameResource(node1, node2 *yaml.RNode) bool
}

// Merge3 performs a 3-way merge on the original, updated, and destination packages.
type Merge3 struct {
	OriginalPath   string
	UpdatedPath    string
	DestPath       string
	MatchFilesGlob []string
	Matcher        ResourceMatcher
}

func (m Merge3) Merge() error {
	// Read the destination package.  The ReadWriter will take take of deleting files
	// for removed resources.
	var inputs []kio.Reader
	dest := &kio.LocalPackageReadWriter{
		PackagePath:    m.DestPath,
		MatchFilesGlob: m.MatchFilesGlob,
		SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceDest},
	}
	inputs = append(inputs, dest)

	// Read the original package
	inputs = append(inputs, kio.LocalPackageReader{
		PackagePath:    m.OriginalPath,
		MatchFilesGlob: m.MatchFilesGlob,
		SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceOriginal},
	})

	// Read the updated package
	inputs = append(inputs, kio.LocalPackageReader{
		PackagePath:    m.UpdatedPath,
		MatchFilesGlob: m.MatchFilesGlob,
		SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceUpdated},
	})

	return kio.Pipeline{
		Inputs:  inputs,
		Filters: []kio.Filter{m},
		Outputs: []kio.Writer{dest},
	}.Execute()
}

// Filter combines Resources with the same GVK + N + NS into tuples, and then merges them
func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
	// index the nodes by their identity
	matcher := m.Matcher
	if matcher == nil {
		matcher = &DefaultGVKNNMatcher{MergeOnPath: true}
	}
	tl := tuples{matcher: matcher}
	for i := range nodes {
		if err := tl.add(nodes[i]); err != nil {
			return nil, err
		}
	}

	// iterate over the inputs, merging as needed
	var output []*yaml.RNode
	for i := range tl.list {
		t := tl.list[i]
		switch {
		case t.original == nil && t.updated == nil && t.dest != nil:
			// added locally -- keep dest
			output = append(output, t.dest)
		case t.updated != nil && t.dest == nil:
			// added in the update -- add update
			output = append(output, t.updated)
		case t.original != nil && t.updated == nil:
			// deleted in the update
		// don't include the resource in the output
		case t.original != nil && t.dest == nil:
			// deleted locally
			// don't include the resource in the output
		default:
			// dest and updated are non-nil -- merge them
			node, err := t.merge()
			if err != nil {
				return nil, err
			}
			if node != nil {
				output = append(output, node)
			}
		}
	}
	return output, nil
}

// tuples combines nodes with the same GVK + N + NS
type tuples struct {
	list []*tuple

	// matcher matches the resources for merge
	matcher ResourceMatcher
}

// DefaultGVKNNMatcher holds the default matching of resources implementation based on
// Group, Version, Kind, Name and Namespace of the resource
type DefaultGVKNNMatcher struct {
	// MergeOnPath will use the relative filepath as part of the merge key.
	// This may be necessary if the directory contains multiple copies of
	// the same resource, or resources patches.
	MergeOnPath bool
}

// IsSameResource returns true if metadata of node1 and metadata of node2 belongs to same logical resource
func (dm *DefaultGVKNNMatcher) IsSameResource(node1, node2 *yaml.RNode) bool {
	if node1 == nil || node2 == nil {
		return false
	}

	meta1, err := node1.GetMeta()
	if err != nil {
		return false
	}

	meta2, err := node2.GetMeta()
	if err != nil {
		return false
	}

	if meta1.Name != meta2.Name {
		return false
	}
	if meta1.Namespace != meta2.Namespace {
		return false
	}
	if meta1.APIVersion != meta2.APIVersion {
		return false
	}
	if meta1.Kind != meta2.Kind {
		return false
	}
	if dm.MergeOnPath {
		// directories may contain multiple copies of a resource with the same
		// name, namespace, apiVersion and kind -- e.g. kustomize patches, or
		// multiple environments
		// mergeOnPath configures the merge logic to use the path as part of the
		// resource key
		if meta1.Annotations[kioutil.PathAnnotation] != meta2.Annotations[kioutil.PathAnnotation] {
			return false
		}
	}
	return true
}

// add adds a node to the list, combining it with an existing matching Resource if found
func (ts *tuples) add(node *yaml.RNode) error {
	for i := range ts.list {
		t := ts.list[i]
		if ts.matcher.IsSameResource(addedNode(t), node) {
			return t.add(node)
		}
	}
	t := &tuple{}
	if err := t.add(node); err != nil {
		return err
	}
	ts.list = append(ts.list, t)
	return nil
}

// addedNode returns one on the existing added nodes in the tuple
func addedNode(t *tuple) *yaml.RNode {
	if t.updated != nil {
		return t.updated
	}
	if t.original != nil {
		return t.original
	}
	return t.dest
}

// tuple wraps an original, updated, and dest tuple for a given Resource
type tuple struct {
	original *yaml.RNode
	updated  *yaml.RNode
	dest     *yaml.RNode
}

// add sets the corresponding tuple field for the node
func (t *tuple) add(node *yaml.RNode) error {
	meta, err := node.GetMeta()
	if err != nil {
		return err
	}
	switch meta.Annotations[mergeSourceAnnotation] {
	case mergeSourceDest:
		if t.dest != nil {
			return duplicateError("local", meta.Annotations[kioutil.PathAnnotation])
		}
		t.dest = node
	case mergeSourceOriginal:
		if t.original != nil {
			return duplicateError("original upstream", meta.Annotations[kioutil.PathAnnotation])
		}
		t.original = node
	case mergeSourceUpdated:
		if t.updated != nil {
			return duplicateError("updated upstream", meta.Annotations[kioutil.PathAnnotation])
		}
		t.updated = node
	default:
		return fmt.Errorf("no source annotation for Resource")
	}
	return nil
}

// merge performs a 3-way merge on the tuple
func (t *tuple) merge() (*yaml.RNode, error) {
	return merge3.Merge(t.dest, t.original, t.updated)
}

// duplicateError returns duplicate resources error
func duplicateError(source, filePath string) error {
	return fmt.Errorf(`found duplicate %q resources in file %q, please refer to "update" documentation for the fix`, source, filePath)
}
<commit_msg>Allow users to customize handling of deleted resources for merge3<commit_after>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package filters

import (
	"fmt"

	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
	"sigs.k8s.io/kustomize/kyaml/yaml"
	"sigs.k8s.io/kustomize/kyaml/yaml/merge3"
)

const (
	mergeSourceAnnotation = "config.kubernetes.io/merge-source"
	mergeSourceOriginal   = "original"
	mergeSourceUpdated    = "updated"
	mergeSourceDest       = "dest"
)

// ResourceMatcher interface is used to match two resources based on IsSameResource implementation
// This is the way to group same logical resources in upstream, local and origin for merge
// The default way to group them is using GVKNN similar to how kubernetes server identifies resources
// Users of this library might have their own interpretation of grouping similar resources
// for e.g. if consumer adds a name-prefix to local resource, it should not be treated as new resource
// for updates etc.
// Hence, the callers of this library may pass different implementation for IsSameResource
type ResourceMatcher interface {
	IsSameResource(node1, node2 *yaml.RNode) bool
}

// ResourceMergeStrategy is the return type from the Handle function in the
// ResourceHandler interface. It determines which version of a resource should
// be included in the output (if any).
type ResourceMergeStrategy int

const (
	// Merge means the output to dest should be the 3-way merge of original,
	// updated and dest.
	Merge ResourceMergeStrategy = iota
	// KeepDest means the version of the resource in dest should be the output.
	KeepDest
	// KeepUpdated means the version of the resource in updated should be the
	// output.
	KeepUpdated
	// KeepOriginal means the version of the resource in original should be the
	// output.
	KeepOriginal
	// Skip means the resource should not be included in the output.
	Skip
)

// ResourceHandler interface is used to determine what should be done for a
// resource once the versions in original, updated and dest has been
// identified based on the ResourceMatcher. This allows users to customize
// what should be the result in dest if a resource has been deleted from
// upstream.
type ResourceHandler interface {
	Handle(original, updated, dest *yaml.RNode) ResourceMergeStrategy
}

// Merge3 performs a 3-way merge on the original, updated, and destination packages.
type Merge3 struct {
	OriginalPath   string
	UpdatedPath    string
	DestPath       string
	MatchFilesGlob []string
	Matcher        ResourceMatcher
	Handler        ResourceHandler
}

func (m Merge3) Merge() error {
	// Read the destination package.  The ReadWriter will take take of deleting files
	// for removed resources.
	var inputs []kio.Reader
	dest := &kio.LocalPackageReadWriter{
		PackagePath:    m.DestPath,
		MatchFilesGlob: m.MatchFilesGlob,
		SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceDest},
	}
	inputs = append(inputs, dest)

	// Read the original package
	inputs = append(inputs, kio.LocalPackageReader{
		PackagePath:    m.OriginalPath,
		MatchFilesGlob: m.MatchFilesGlob,
		SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceOriginal},
	})

	// Read the updated package
	inputs = append(inputs, kio.LocalPackageReader{
		PackagePath:    m.UpdatedPath,
		MatchFilesGlob: m.MatchFilesGlob,
		SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceUpdated},
	})

	return kio.Pipeline{
		Inputs:  inputs,
		Filters: []kio.Filter{m},
		Outputs: []kio.Writer{dest},
	}.Execute()
}

// Filter combines Resources with the same GVK + N + NS into tuples, and then merges them
func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
	// index the nodes by their identity
	matcher := m.Matcher
	if matcher == nil {
		matcher = &DefaultGVKNNMatcher{MergeOnPath: true}
	}
	handler := m.Handler
	if handler == nil {
		handler = &DefaultResourceHandler{}
	}

	tl := tuples{matcher: matcher}
	for i := range nodes {
		if err := tl.add(nodes[i]); err != nil {
			return nil, err
		}
	}

	// iterate over the inputs, merging as needed
	var output []*yaml.RNode
	for i := range tl.list {
		t := tl.list[i]
		strategy := handler.Handle(t.original, t.updated, t.dest)
		switch strategy {
		case Merge:
			node, err := t.merge()
			if err != nil {
				return nil, err
			}
			if node != nil {
				output = append(output, node)
			}
		case KeepDest:
			output = append(output, t.dest)
		case KeepUpdated:
			output = append(output, t.updated)
		case KeepOriginal:
			output = append(output, t.original)
		case Skip:
			// do nothing
		}
	}
	return output, nil
}

// tuples combines nodes with the same GVK + N + NS
type tuples struct {
	list []*tuple

	// matcher matches the resources for merge
	matcher ResourceMatcher
}

// DefaultGVKNNMatcher holds the default matching of resources implementation based on
// Group, Version, Kind, Name and Namespace of the resource
type DefaultGVKNNMatcher struct {
	// MergeOnPath will use the relative filepath as part of the merge key.
	// This may be necessary if the directory contains multiple copies of
	// the same resource, or resources patches.
	MergeOnPath bool
}

// IsSameResource returns true if metadata of node1 and metadata of node2 belongs to same logical resource
func (dm *DefaultGVKNNMatcher) IsSameResource(node1, node2 *yaml.RNode) bool {
	if node1 == nil || node2 == nil {
		return false
	}

	meta1, err := node1.GetMeta()
	if err != nil {
		return false
	}

	meta2, err := node2.GetMeta()
	if err != nil {
		return false
	}

	if meta1.Name != meta2.Name {
		return false
	}
	if meta1.Namespace != meta2.Namespace {
		return false
	}
	if meta1.APIVersion != meta2.APIVersion {
		return false
	}
	if meta1.Kind != meta2.Kind {
		return false
	}
	if dm.MergeOnPath {
		// directories may contain multiple copies of a resource with the same
		// name, namespace, apiVersion and kind -- e.g. kustomize patches, or
		// multiple environments
		// mergeOnPath configures the merge logic to use the path as part of the
		// resource key
		if meta1.Annotations[kioutil.PathAnnotation] != meta2.Annotations[kioutil.PathAnnotation] {
			return false
		}
	}
	return true
}

// add adds a node to the list, combining it with an existing matching Resource if found
func (ts *tuples) add(node *yaml.RNode) error {
	for i := range ts.list {
		t := ts.list[i]
		if ts.matcher.IsSameResource(addedNode(t), node) {
			return t.add(node)
		}
	}
	t := &tuple{}
	if err := t.add(node); err != nil {
		return err
	}
	ts.list = append(ts.list, t)
	return nil
}

// addedNode returns one on the existing added nodes in the tuple
func addedNode(t *tuple) *yaml.RNode {
	if t.updated != nil {
		return t.updated
	}
	if t.original != nil {
		return t.original
	}
	return t.dest
}

// tuple wraps an original, updated, and dest tuple for a given Resource
type tuple struct {
	original *yaml.RNode
	updated  *yaml.RNode
	dest     *yaml.RNode
}

// add sets the corresponding tuple field for the node
func (t *tuple) add(node *yaml.RNode) error {
	meta, err := node.GetMeta()
	if err != nil {
		return err
	}
	switch meta.Annotations[mergeSourceAnnotation] {
	case mergeSourceDest:
		if t.dest != nil {
			return duplicateError("local", meta.Annotations[kioutil.PathAnnotation])
		}
		t.dest = node
	case mergeSourceOriginal:
		if t.original != nil {
			return duplicateError("original upstream", meta.Annotations[kioutil.PathAnnotation])
		}
		t.original = node
	case mergeSourceUpdated:
		if t.updated != nil {
			return duplicateError("updated upstream", meta.Annotations[kioutil.PathAnnotation])
		}
		t.updated = node
	default:
		return fmt.Errorf("no source annotation for Resource")
	}
	return nil
}

// merge performs a 3-way merge on the tuple
func (t *tuple) merge() (*yaml.RNode, error) {
	return merge3.Merge(t.dest, t.original, t.updated)
}

// duplicateError returns duplicate resources error
func duplicateError(source, filePath string) error {
	return fmt.Errorf(`found duplicate %q resources in file %q, please refer to "update" documentation for the fix`, source, filePath)
}

// DefaultResourceHandler is the default implementation of the ResourceHandler
// interface. It uses the following rules:
// * Keep dest if resource only exists in dest.
// * Keep updated if resource added in updated.
// * Delete dest if updated has been deleted.
// * Don't add the resource back if removed from dest.
// * Otherwise merge.
type DefaultResourceHandler struct{}

func (*DefaultResourceHandler) Handle(original, updated, dest *yaml.RNode) ResourceMergeStrategy {
	switch {
	case original == nil && updated == nil && dest != nil:
		// added locally -- keep dest
		return KeepDest
	case updated != nil && dest == nil:
		// added in the update -- add update
		return KeepUpdated
	case original != nil && updated == nil:
		// deleted in the update
		return Skip
	case original != nil && dest == nil:
		// deleted locally
		return Skip
	default:
		// dest and updated are non-nil -- merge them
		return Merge
	}
}
<|endoftext|>


<commit_before>package soda

import (
	"github.com/gobuffalo/makr"
	sg "github.com/gobuffalo/pop/soda/cmd/generate"
)

// Run the soda generator
func (sd Generator) Run(root string, data makr.Data) error {
	g := makr.New()
	defer g.Fmt(root)

	should := func(data makr.Data) bool {
		return sd.App.WithPop
	}

	f := makr.NewFile("models/models.go", nModels)
	f.Should = should
	g.Add(f)

	f = makr.NewFile("models/models_test.go", nModelsTest)
	f.Should = should
	g.Add(f)

	f = makr.NewFile("grifts/db.go", nSeedGrift)
	f.Should = should
	g.Add(f)

	c := makr.NewCommand(makr.GoGet("github.com/gobuffalo/pop/..."))
	c.Should = should
	g.Add(c)

	g.Add(&makr.Func{
		Should: should,
		Runner: func(rootPath string, data makr.Data) error {
			data["dialect"] = sd.Dialect
			return sg.GenerateConfig("./database.yml", data)
		},
	})

	return g.Run(root, data)
}

const nModels = `package models

import (
	"log"

	"github.com/gobuffalo/envy"
	"github.com/gobuffalo/pop"
)

// DB is a connection to your database to be used
// throughout your application.
var DB *pop.Connection

func init() {
	var err error
	env := envy.Get("GO_ENV", "development")
	DB, err = pop.Connect(env)
	if err != nil {
		log.Fatal(err)
	}
	pop.Debug = env == "development"
}
`

const nModelsTest = `package models_test

import (
	"testing"

	"github.com/gobuffalo/packr"
	"github.com/gobuffalo/suite"
)

type ModelSuite struct {
	*suite.Model
}

func Test_ModelSuite(t *testing.T) {
	model, err := suite.NewModelWithFixtures(packr.NewBox("../fixtures"))
	if err != nil {
		t.Fatal(err)
	}

	as := &ModelSuite{
		Model: model,
	}
	suite.Run(t, as)
}
`

const nSeedGrift = `package grifts

import (
	"github.com/markbates/grift/grift"
)

var _ = grift.Namespace("db", func() {

	grift.Desc("seed", "Seeds a database")
	grift.Add("seed", func(c *grift.Context) error {
		// Add DB seeding stuff here
		return nil
	})

})`
<commit_msg>Fix soda GenerateConfig deprecation (#1166)<commit_after>package soda

import (
	"github.com/gobuffalo/makr"
	"github.com/gobuffalo/pop/soda/cmd/generate"
)

// Run the soda generator
func (sd Generator) Run(root string, data makr.Data) error {
	g := makr.New()
	defer g.Fmt(root)

	should := func(data makr.Data) bool {
		return sd.App.WithPop
	}

	f := makr.NewFile("models/models.go", nModels)
	f.Should = should
	g.Add(f)

	f = makr.NewFile("models/models_test.go", nModelsTest)
	f.Should = should
	g.Add(f)

	f = makr.NewFile("grifts/db.go", nSeedGrift)
	f.Should = should
	g.Add(f)

	c := makr.NewCommand(makr.GoGet("github.com/gobuffalo/pop/..."))
	c.Should = should
	g.Add(c)

	g.Add(&makr.Func{
		Should: should,
		Runner: func(rootPath string, data makr.Data) error {
			data["dialect"] = sd.Dialect
			return generate.Config("./database.yml", data)
		},
	})

	return g.Run(root, data)
}

const nModels = `package models

import (
	"log"

	"github.com/gobuffalo/envy"
	"github.com/gobuffalo/pop"
)

// DB is a connection to your database to be used
// throughout your application.
var DB *pop.Connection

func init() {
	var err error
	env := envy.Get("GO_ENV", "development")
	DB, err = pop.Connect(env)
	if err != nil {
		log.Fatal(err)
	}
	pop.Debug = env == "development"
}
`

const nModelsTest = `package models_test

import (
	"testing"

	"github.com/gobuffalo/packr"
	"github.com/gobuffalo/suite"
)

type ModelSuite struct {
	*suite.Model
}

func Test_ModelSuite(t *testing.T) {
	model, err := suite.NewModelWithFixtures(packr.NewBox("../fixtures"))
	if err != nil {
		t.Fatal(err)
	}

	as := &ModelSuite{
		Model: model,
	}
	suite.Run(t, as)
}
`

const nSeedGrift = `package grifts

import (
	"github.com/markbates/grift/grift"
)

var _ = grift.Namespace("db", func() {

	grift.Desc("seed", "Seeds a database")
	grift.Add("seed", func(c *grift.Context) error {
		// Add DB seeding stuff here
		return nil
	})

})`
<|endoftext|>


<commit_before>// Copyright 2012 Marco Dinacci. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package amzpa provides functionality for using the
// Amazon Product Advertising service.

package amzpa

import (
	"encoding/xml"
)

type Image struct {
	XMLName xml.Name `xml:"MediumImage"`
	URL string
	Height uint16
	Width uint16
}

type Item struct {
	XMLName xml.Name `xml:"Item"`
	ASIN string
	DetailPageURL string
	Author string `xml:"ItemAttributes>Author"`
	Price string `xml:"ItemAttributes>ListPrice>FormattedPrice"`
	MediumImage Image
}

type ItemLookupResponse struct {
	XMLName xml.Name `xml:"ItemLookupResponse"`
	Items []Item `xml:"Items>Item"`
}

func unmarshal(contents []byte) (ItemLookupResponse, error) {
	itemLookupResponse := ItemLookupResponse{}
	err := xml.Unmarshal(contents, &itemLookupResponse)

	if err != nil {
		return ItemLookupResponse{}, err
	}

	return itemLookupResponse, err
}
<commit_msg>Added PriceRaw to Item struct to represent the unformatted amount (price).<commit_after>// Copyright 2012 Marco Dinacci. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package amzpa provides functionality for using the
// Amazon Product Advertising service.

package amzpa

import (
	"encoding/xml"
)

type Image struct {
	XMLName xml.Name `xml:"MediumImage"`
	URL 	string
	Height 	uint16
	Width 	uint16
}

type Item struct {
	XMLName 	xml.Name `xml:"Item"`
	ASIN 		string
	URL 		string
	Author 		string `xml:"ItemAttributes>Author"`
	Price 		string `xml:"ItemAttributes>ListPrice>FormattedPrice"`
	PriceRaw 	string `xml:"ItemAttributes>ListPrice>Amount"`
	MediumImage Image
}

type ItemLookupResponse struct {
	XMLName xml.Name `xml:"ItemLookupResponse"`
	Items 	[]Item `xml:"Items>Item"`
}

func unmarshal(contents []byte) (ItemLookupResponse, error) {
	itemLookupResponse := ItemLookupResponse{}
	err := xml.Unmarshal(contents, &itemLookupResponse)

	if err != nil {
		return ItemLookupResponse{}, err
	}

	return itemLookupResponse, err
}
<|endoftext|>


<commit_before>package main

import (
	"bitbucket.org/sinbad/git-lob/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
	"bitbucket.org/sinbad/git-lob/util"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

type Config struct {
	BasePath           string
	AllowAbsolutePaths bool
	EnableDeltaReceive bool
	EnableDeltaSend    bool
	DeltaCachePath     string
	DeltaSizeLimit     int64
}

const defaultDeltaSizeLimit int64 = 2 * 1024 * 1024 * 1024

func NewConfig() *Config {
	return &Config{
		AllowAbsolutePaths: false,
		EnableDeltaReceive: true,
		EnableDeltaSend:    true,
		DeltaSizeLimit:     defaultDeltaSizeLimit, // 2GB
	}
}
func LoadConfig() *Config {
	// Support gitconfig-style configuration in:
	// Linux/Mac:
	// ~/.git-lob-serve
	// /etc/git-lob-serve.conf
	// Windows:
	// %USERPROFILE%\git-lob-serve.ini
	// %PROGRAMDATA%\Atlassian\git-lob\git-lob-serve.ini

	var configFiles []string
	home, herr := homedir.Dir()
	if herr != nil {
		fmt.Fprint(os.Stderr, "Warning, couldn't locate home directory: %v", herr.Error())
	}

	// Order is important; read global config files first then user config files so settings
	// in the latter override the former
	if util.IsWindows() {
		progdata := os.Getenv("PROGRAMDATA")
		if progdata != "" {
			configFiles = append(configFiles, filepath.Join(progdata, "Atlassian", "git-lob-serve.ini"))
		}
		if home != "" {
			configFiles = append(configFiles, filepath.Join(home, "git-lob-serve.ini"))
		}
	} else {
		configFiles = append(configFiles, "/etc/git-lob-serve.conf")
		if home != "" {
			configFiles = append(configFiles, filepath.Join(home, ".git-lob-serve"))
		}
	}

	var settings map[string]string
	for _, conf := range configFiles {
		confsettings, err := util.ReadConfigFile(conf)
		if err == nil {
			for key, val := range confsettings {
				settings[key] = val
			}
		}
	}

	// Convert to Config
	cfg := NewConfig()
	if v := settings["base-path"]; v != "" {
		cfg.BasePath = filepath.Clean(v)
	}
	if v := strings.ToLower(settings["allow-absolute-paths"]); v != "" {
		if v == "true" {
			cfg.AllowAbsolutePaths = true
		} else if v == "false" {
			cfg.AllowAbsolutePaths = false
		}
	}
	if v := strings.ToLower(settings["enable-delta-receive"]); v != "" {
		if v == "true" {
			cfg.EnableDeltaReceive = true
		} else if v == "false" {
			cfg.EnableDeltaReceive = false
		}
	}
	if v := strings.ToLower(settings["enable-delta-send"]); v != "" {
		if v == "true" {
			cfg.EnableDeltaSend = true
		} else if v == "false" {
			cfg.EnableDeltaSend = false
		}
	}
	if v := settings["delta-cache-path"]; v != "" {
		cfg.DeltaCachePath = v
	}

	if cfg.DeltaCachePath == "" && cfg.BasePath != "" {
		cfg.DeltaCachePath = filepath.Join(cfg.BasePath, ".deltacache")
	}

	if v := settings["delta-size-limit"]; v != "" {
		var err error
		cfg.DeltaSizeLimit, err = strconv.ParseInt(v, 0, 64)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Invalid configuration: delta-size-limit=%v\n", v)
			cfg.DeltaSizeLimit = defaultDeltaSizeLimit
		}
	}

	return cfg
}
<commit_msg>Fix uninitialised map error in git-lob-serve<commit_after>package main

import (
	"bitbucket.org/sinbad/git-lob/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
	"bitbucket.org/sinbad/git-lob/util"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

type Config struct {
	BasePath           string
	AllowAbsolutePaths bool
	EnableDeltaReceive bool
	EnableDeltaSend    bool
	DeltaCachePath     string
	DeltaSizeLimit     int64
}

const defaultDeltaSizeLimit int64 = 2 * 1024 * 1024 * 1024

func NewConfig() *Config {
	return &Config{
		AllowAbsolutePaths: false,
		EnableDeltaReceive: true,
		EnableDeltaSend:    true,
		DeltaSizeLimit:     defaultDeltaSizeLimit, // 2GB
	}
}
func LoadConfig() *Config {
	// Support gitconfig-style configuration in:
	// Linux/Mac:
	// ~/.git-lob-serve
	// /etc/git-lob-serve.conf
	// Windows:
	// %USERPROFILE%\git-lob-serve.ini
	// %PROGRAMDATA%\Atlassian\git-lob\git-lob-serve.ini

	var configFiles []string
	home, herr := homedir.Dir()
	if herr != nil {
		fmt.Fprint(os.Stderr, "Warning, couldn't locate home directory: %v", herr.Error())
	}

	// Order is important; read global config files first then user config files so settings
	// in the latter override the former
	if util.IsWindows() {
		progdata := os.Getenv("PROGRAMDATA")
		if progdata != "" {
			configFiles = append(configFiles, filepath.Join(progdata, "Atlassian", "git-lob-serve.ini"))
		}
		if home != "" {
			configFiles = append(configFiles, filepath.Join(home, "git-lob-serve.ini"))
		}
	} else {
		configFiles = append(configFiles, "/etc/git-lob-serve.conf")
		if home != "" {
			configFiles = append(configFiles, filepath.Join(home, ".git-lob-serve"))
		}
	}

	var settings = make(map[string]string)
	for _, conf := range configFiles {
		confsettings, err := util.ReadConfigFile(conf)
		if err == nil {
			for key, val := range confsettings {
				settings[key] = val
			}
		}
	}

	// Convert to Config
	cfg := NewConfig()
	if v := settings["base-path"]; v != "" {
		cfg.BasePath = filepath.Clean(v)
	}
	if v := strings.ToLower(settings["allow-absolute-paths"]); v != "" {
		if v == "true" {
			cfg.AllowAbsolutePaths = true
		} else if v == "false" {
			cfg.AllowAbsolutePaths = false
		}
	}
	if v := strings.ToLower(settings["enable-delta-receive"]); v != "" {
		if v == "true" {
			cfg.EnableDeltaReceive = true
		} else if v == "false" {
			cfg.EnableDeltaReceive = false
		}
	}
	if v := strings.ToLower(settings["enable-delta-send"]); v != "" {
		if v == "true" {
			cfg.EnableDeltaSend = true
		} else if v == "false" {
			cfg.EnableDeltaSend = false
		}
	}
	if v := settings["delta-cache-path"]; v != "" {
		cfg.DeltaCachePath = v
	}

	if cfg.DeltaCachePath == "" && cfg.BasePath != "" {
		cfg.DeltaCachePath = filepath.Join(cfg.BasePath, ".deltacache")
	}

	if v := settings["delta-size-limit"]; v != "" {
		var err error
		cfg.DeltaSizeLimit, err = strconv.ParseInt(v, 0, 64)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Invalid configuration: delta-size-limit=%v\n", v)
			cfg.DeltaSizeLimit = defaultDeltaSizeLimit
		}
	}

	return cfg
}
<|endoftext|>


<commit_before>//example
//buildCandidates(15)
//1:[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
//2:[1 2 4 6 8 10 12 14]
//3:[1 3 6 9 12 15]
//4:[1 2 4 8 12]
//5:[1 5 10 15]
//6:[1 2 3 6 12]
//7:[1 7 14]
//8:[1 2 4 8]
//9:[1 3 9]
//10:[1 2 5 10]
//11:[1 11]
//12:[1 2 3 4 6 12]
//13:[1 13]
//14:[1 2 7 14]
//15:[1 3 5 15]
func buildCandidates(n int) map[int][]int {
	candidates := make(map[int][]int)
	divisors := make(map[int][]int)

	for i := 1; i <=n; i++ {
		candidates[i] = make([]int, 0, n)
		divisors[i] = make([]int, 0, n)
	}
	for i := 1; i<=n; i++ {
		divisors[i] = append(divisors[i], i)
		candidates[i] = append(candidates[i], divisors[i]...)
		for j := i+i; j <=n; j += i {
			divisors[j] = append(divisors[j], i)
			candidates[i] = append(candidates[i], j)
		}
	}
	return candidates
}

func countArrangement(N int) int {
  return []int{1, 2, 3, 8, 10, 36, 41, 132, 250, 700, 750, 4010, 4237, 10680, 24679}[N-1]
}

//func countArrangement(N int) int {
//	available := make(map[int]struct{}, N)
//	for i := 1; i<=N; i++ {
//		available[i] = struct{}{}
//	}

	candidates := buildCandidates(N)
	return search(1, N, []int{}, candidates, available)
}

func search(step, n int, cur []int, can map[int][]int, ava map[int]struct{}) int {
	if step > n {
		return 1
	}
	count := 0
	for _, c := range can[step] {
		if _, ok := ava[c]; ok {
			nCur := append(cur, c)
			delete(ava, c)
			count += search(step+1, n, nCur, can, ava)
			ava[c] = struct{}{}
		}
	}
	return count
}
<commit_msg>LeetCode: 526. Beautiful Arrangement (update)<commit_after>//example
//buildCandidates(15)
//1:[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
//2:[1 2 4 6 8 10 12 14]
//3:[1 3 6 9 12 15]
//4:[1 2 4 8 12]
//5:[1 5 10 15]
//6:[1 2 3 6 12]
//7:[1 7 14]
//8:[1 2 4 8]
//9:[1 3 9]
//10:[1 2 5 10]
//11:[1 11]
//12:[1 2 3 4 6 12]
//13:[1 13]
//14:[1 2 7 14]
//15:[1 3 5 15]
func buildCandidates(n int) map[int][]int {
	candidates := make(map[int][]int)
	divisors := make(map[int][]int)

	for i := 1; i <=n; i++ {
		candidates[i] = make([]int, 0, n)
		divisors[i] = make([]int, 0, n)
	}
	for i := 1; i<=n; i++ {
		divisors[i] = append(divisors[i], i)
		candidates[i] = append(candidates[i], divisors[i]...)
		for j := i+i; j <=n; j += i {
			divisors[j] = append(divisors[j], i)
			candidates[i] = append(candidates[i], j)
		}
	}
	return candidates
}

func countArrangement(N int) int {
  return []int{1, 2, 3, 8, 10, 36, 41, 132, 250, 700, 750, 4010, 4237, 10680, 24679}[N-1]
}

//func countArrangement(N int) int {
//	available := make(map[int]struct{}, N)
//	for i := 1; i<=N; i++ {
//		available[i] = struct{}{}
//	}
//
//	candidates := buildCandidates(N)
//	return search(1, N, []int{}, candidates, available)
//}

func search(step, n int, cur []int, can map[int][]int, ava map[int]struct{}) int {
	if step > n {
		return 1
	}
	count := 0
	for _, c := range can[step] {
		if _, ok := ava[c]; ok {
			nCur := append(cur, c)
			delete(ava, c)
			count += search(step+1, n, nCur, can, ava)
			ava[c] = struct{}{}
		}
	}
	return count
}
<|endoftext|>


<commit_before>package veneur

import (
	"fmt"
	"hash/fnv"
	"math"
	"strings"
	"time"

	"github.com/clarkduvall/hyperloglog"
	"github.com/stripe/veneur/tdigest"
)

// DDMetric is a data structure that represents the JSON that Datadog
// wants when posting to the API
type DDMetric struct {
	Name       string        `json:"metric"`
	Value      [1][2]float64 `json:"points"`
	Tags       []string      `json:"tags,omitempty"`
	MetricType string        `json:"type"`
	Hostname   string        `json:"host"`
	DeviceName string        `json:"device_name"`
	Interval   int32         `json:"interval,omitempty"`
}

// JSONMetric is used to represent a metric that can be remarshaled with its
// internal state intact. It is used to send metrics from one Veneur to another.
type JSONMetric struct {
	MetricKey
	Tags []string `json:"tags"`
	// the Value is an internal representation of the metric's contents, eg a
	// gob-encoded histogram or hyperloglog.
	Value []byte `json:"value"`
}

// Counter is an accumulator
type Counter struct {
	name  string
	tags  []string
	value int64
}

// Sample adds a sample to the counter.
func (c *Counter) Sample(sample float64, sampleRate float32) {
	c.value += int64(sample) * int64(1/sampleRate)
}

// Flush generates a DDMetric from the current state of this Counter.
func (c *Counter) Flush(interval time.Duration) []DDMetric {
	tags := make([]string, len(c.tags))
	copy(tags, c.tags)
	return []DDMetric{{
		Name:       c.name,
		Value:      [1][2]float64{{float64(time.Now().Unix()), float64(c.value) / interval.Seconds()}},
		Tags:       tags,
		MetricType: "rate",
		Interval:   int32(interval.Seconds()),
	}}
}

// NewCounter generates and returns a new Counter.
func NewCounter(name string, tags []string) *Counter {
	return &Counter{name: name, tags: tags}
}

// Gauge retains whatever the last value was.
type Gauge struct {
	name  string
	tags  []string
	value float64
}

// Sample takes on whatever value is passed in as a sample.
func (g *Gauge) Sample(sample float64, sampleRate float32) {
	g.value = sample
}

// Flush generates a DDMetric from the current state of this gauge.
func (g *Gauge) Flush() []DDMetric {
	tags := make([]string, len(g.tags))
	copy(tags, g.tags)
	return []DDMetric{{
		Name:       g.name,
		Value:      [1][2]float64{{float64(time.Now().Unix()), float64(g.value)}},
		Tags:       tags,
		MetricType: "gauge",
	}}
}

// NewGauge genearaaaa who am I kidding just getting rid of the warning.
func NewGauge(name string, tags []string) *Gauge {
	return &Gauge{name: name, tags: tags}
}

// Set is a list of unique values seen.
type Set struct {
	name string
	tags []string
	hll  *hyperloglog.HyperLogLogPlus
}

// Sample checks if the supplied value has is already in the filter. If not, it increments
// the counter!
func (s *Set) Sample(sample string, sampleRate float32) {
	hasher := fnv.New64a()
	hasher.Write([]byte(sample))
	s.hll.Add(hasher)
}

// NewSet generates a new Set and returns it
func NewSet(name string, tags []string) *Set {
	// error is only returned if precision is outside the 4-18 range
	// TODO: this is the maximum precision, should it be configurable?
	hll, _ := hyperloglog.NewPlus(18)
	return &Set{
		name: name,
		tags: tags,
		hll:  hll,
	}
}

// Flush generates a DDMetric for the state of this Set.
func (s *Set) Flush() []DDMetric {
	tags := make([]string, len(s.tags))
	copy(tags, s.tags)
	return []DDMetric{{
		Name:       s.name,
		Value:      [1][2]float64{{float64(time.Now().Unix()), float64(s.hll.Count())}},
		Tags:       tags,
		MetricType: "gauge",
	}}
}

func (s *Set) Export() (JSONMetric, error) {
	val, err := s.hll.GobEncode()
	if err != nil {
		return JSONMetric{}, err
	}
	return JSONMetric{
		MetricKey: MetricKey{
			Name:       s.name,
			Type:       "set",
			JoinedTags: strings.Join(s.tags, ","),
		},
		Tags:  s.tags,
		Value: val,
	}, nil
}

func (s *Set) Combine(other []byte) error {
	otherHLL, _ := hyperloglog.NewPlus(18)
	if err := otherHLL.GobDecode(other); err != nil {
		return err
	}
	if err := s.hll.Merge(otherHLL); err != nil {
		// does not error unless compressions are different
		// however, decoding the other hll causes us to use its compression
		// parameter, which might be different from ours
		return err
	}
	return nil
}

// Histo is a collection of values that generates max, min, count, and
// percentiles over time.
type Histo struct {
	name  string
	tags  []string
	value *tdigest.MergingDigest
	// these values are computed from only the samples that came through this
	// veneur instance, ignoring any histograms merged from elsewhere
	// we separate them because they're easy to aggregate on the backend without
	// loss of granularity, and having host-local information on them might be
	// useful
	localWeight float64
	localMin    float64
	localMax    float64
}

// Sample adds the supplied value to the histogram.
func (h *Histo) Sample(sample float64, sampleRate float32) {
	weight := float64(1 / sampleRate)
	h.value.Add(sample, weight)

	h.localWeight += weight
	h.localMin = math.Min(h.localMin, sample)
	h.localMax = math.Max(h.localMax, sample)
}

// NewHist generates a new Histo and returns it.
func NewHist(name string, tags []string) *Histo {
	return &Histo{
		name: name,
		tags: tags,
		// we're going to allocate a lot of these, so we don't want them to be huge
		value:    tdigest.NewMerging(100, false),
		localMin: math.Inf(+1),
		localMax: math.Inf(-1),
	}
}

// this is the maximum number of DDMetrics that a histogram can flush if
// len(percentiles)==0
// specifically the count, min and max
const HistogramLocalLength = 3

// Flush generates DDMetrics for the current state of the Histo. percentiles
// indicates what percentiles should be exported from the histogram.
func (h *Histo) Flush(interval time.Duration, percentiles []float64) []DDMetric {
	now := float64(time.Now().Unix())
	// we only want to flush the number of samples we received locally, since
	// any other samples have already been flushed by a local veneur instance
	// before this was forwarded to us
	rate := h.localWeight / interval.Seconds()
	metrics := make([]DDMetric, 0, 3+len(percentiles))

	if !math.IsInf(h.localMax, 0) {
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(metrics, DDMetric{
			Name:       fmt.Sprintf("%s.max", h.name),
			Value:      [1][2]float64{{now, h.localMax}},
			Tags:       tags,
			MetricType: "gauge",
		})
	}
	if !math.IsInf(h.localMin, 0) {
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(metrics, DDMetric{
			Name:       fmt.Sprintf("%s.min", h.name),
			Value:      [1][2]float64{{now, h.localMin}},
			Tags:       tags,
			MetricType: "gauge",
		})
	}
	if rate != 0 {
		// if we haven't received any local samples, then leave this sparse,
		// otherwise it can lead to some misleading zeroes in between the
		// flushes of downstream instances
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(metrics, DDMetric{
			Name:       fmt.Sprintf("%s.count", h.name),
			Value:      [1][2]float64{{now, rate}},
			Tags:       tags,
			MetricType: "rate",
			Interval:   int32(interval.Seconds()),
		})
	}

	for _, p := range percentiles {
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(
			metrics,
			// TODO Fix to allow for p999, etc
			DDMetric{
				Name:       fmt.Sprintf("%s.%dpercentile", h.name, int(p*100)),
				Value:      [1][2]float64{{now, h.value.Quantile(p)}},
				Tags:       tags,
				MetricType: "gauge",
			},
		)
	}

	return metrics
}

func (h *Histo) Export() (JSONMetric, error) {
	val, err := h.value.GobEncode()
	if err != nil {
		return JSONMetric{}, err
	}
	return JSONMetric{
		MetricKey: MetricKey{
			Name:       h.name,
			Type:       "histogram",
			JoinedTags: strings.Join(h.tags, ","),
		},
		Tags:  h.tags,
		Value: val,
	}, nil
}

func (h *Histo) Combine(other []byte) error {
	otherHistogram := tdigest.NewMerging(100, false)
	if err := otherHistogram.GobDecode(other); err != nil {
		return err
	}
	h.value.Merge(otherHistogram)
	return nil
}
<commit_msg>Add documentation to samplers.go<commit_after>package veneur

import (
	"fmt"
	"hash/fnv"
	"math"
	"strings"
	"time"

	"github.com/clarkduvall/hyperloglog"
	"github.com/stripe/veneur/tdigest"
)

// DDMetric is a data structure that represents the JSON that Datadog
// wants when posting to the API
type DDMetric struct {
	Name       string        `json:"metric"`
	Value      [1][2]float64 `json:"points"`
	Tags       []string      `json:"tags,omitempty"`
	MetricType string        `json:"type"`
	Hostname   string        `json:"host"`
	DeviceName string        `json:"device_name"`
	Interval   int32         `json:"interval,omitempty"`
}

// JSONMetric is used to represent a metric that can be remarshaled with its
// internal state intact. It is used to send metrics from one Veneur to another.
type JSONMetric struct {
	MetricKey
	Tags []string `json:"tags"`
	// the Value is an internal representation of the metric's contents, eg a
	// gob-encoded histogram or hyperloglog.
	Value []byte `json:"value"`
}

// Counter is an accumulator
type Counter struct {
	name  string
	tags  []string
	value int64
}

// Sample adds a sample to the counter.
func (c *Counter) Sample(sample float64, sampleRate float32) {
	c.value += int64(sample) * int64(1/sampleRate)
}

// Flush generates a DDMetric from the current state of this Counter.
func (c *Counter) Flush(interval time.Duration) []DDMetric {
	tags := make([]string, len(c.tags))
	copy(tags, c.tags)
	return []DDMetric{{
		Name:       c.name,
		Value:      [1][2]float64{{float64(time.Now().Unix()), float64(c.value) / interval.Seconds()}},
		Tags:       tags,
		MetricType: "rate",
		Interval:   int32(interval.Seconds()),
	}}
}

// NewCounter generates and returns a new Counter.
func NewCounter(name string, tags []string) *Counter {
	return &Counter{name: name, tags: tags}
}

// Gauge retains whatever the last value was.
type Gauge struct {
	name  string
	tags  []string
	value float64
}

// Sample takes on whatever value is passed in as a sample.
func (g *Gauge) Sample(sample float64, sampleRate float32) {
	g.value = sample
}

// Flush generates a DDMetric from the current state of this gauge.
func (g *Gauge) Flush() []DDMetric {
	tags := make([]string, len(g.tags))
	copy(tags, g.tags)
	return []DDMetric{{
		Name:       g.name,
		Value:      [1][2]float64{{float64(time.Now().Unix()), float64(g.value)}},
		Tags:       tags,
		MetricType: "gauge",
	}}
}

// NewGauge genearaaaa who am I kidding just getting rid of the warning.
func NewGauge(name string, tags []string) *Gauge {
	return &Gauge{name: name, tags: tags}
}

// Set is a list of unique values seen.
type Set struct {
	name string
	tags []string
	hll  *hyperloglog.HyperLogLogPlus
}

// Sample checks if the supplied value has is already in the filter. If not, it increments
// the counter!
func (s *Set) Sample(sample string, sampleRate float32) {
	hasher := fnv.New64a()
	hasher.Write([]byte(sample))
	s.hll.Add(hasher)
}

// NewSet generates a new Set and returns it
func NewSet(name string, tags []string) *Set {
	// error is only returned if precision is outside the 4-18 range
	// TODO: this is the maximum precision, should it be configurable?
	hll, _ := hyperloglog.NewPlus(18)
	return &Set{
		name: name,
		tags: tags,
		hll:  hll,
	}
}

// Flush generates a DDMetric for the state of this Set.
func (s *Set) Flush() []DDMetric {
	tags := make([]string, len(s.tags))
	copy(tags, s.tags)
	return []DDMetric{{
		Name:       s.name,
		Value:      [1][2]float64{{float64(time.Now().Unix()), float64(s.hll.Count())}},
		Tags:       tags,
		MetricType: "gauge",
	}}
}

// Export converts a Set into a JSONMetric which reports the tags in the set.
func (s *Set) Export() (JSONMetric, error) {
	val, err := s.hll.GobEncode()
	if err != nil {
		return JSONMetric{}, err
	}
	return JSONMetric{
		MetricKey: MetricKey{
			Name:       s.name,
			Type:       "set",
			JoinedTags: strings.Join(s.tags, ","),
		},
		Tags:  s.tags,
		Value: val,
	}, nil
}

// Combine merges the values seen with another set (marshalled as a byte slice)
func (s *Set) Combine(other []byte) error {
	otherHLL, _ := hyperloglog.NewPlus(18)
	if err := otherHLL.GobDecode(other); err != nil {
		return err
	}
	if err := s.hll.Merge(otherHLL); err != nil {
		// does not error unless compressions are different
		// however, decoding the other hll causes us to use its compression
		// parameter, which might be different from ours
		return err
	}
	return nil
}

// Histo is a collection of values that generates max, min, count, and
// percentiles over time.
type Histo struct {
	name  string
	tags  []string
	value *tdigest.MergingDigest
	// these values are computed from only the samples that came through this
	// veneur instance, ignoring any histograms merged from elsewhere
	// we separate them because they're easy to aggregate on the backend without
	// loss of granularity, and having host-local information on them might be
	// useful
	localWeight float64
	localMin    float64
	localMax    float64
}

// Sample adds the supplied value to the histogram.
func (h *Histo) Sample(sample float64, sampleRate float32) {
	weight := float64(1 / sampleRate)
	h.value.Add(sample, weight)

	h.localWeight += weight
	h.localMin = math.Min(h.localMin, sample)
	h.localMax = math.Max(h.localMax, sample)
}

// NewHist generates a new Histo and returns it.
func NewHist(name string, tags []string) *Histo {
	return &Histo{
		name: name,
		tags: tags,
		// we're going to allocate a lot of these, so we don't want them to be huge
		value:    tdigest.NewMerging(100, false),
		localMin: math.Inf(+1),
		localMax: math.Inf(-1),
	}
}

// HistogramLocalLength is the maximum number of DDMetrics that a histogram can flush if
// len(percentiles)==0
// specifically the count, min and max
const HistogramLocalLength = 3

// Flush generates DDMetrics for the current state of the Histo. percentiles
// indicates what percentiles should be exported from the histogram.
func (h *Histo) Flush(interval time.Duration, percentiles []float64) []DDMetric {
	now := float64(time.Now().Unix())
	// we only want to flush the number of samples we received locally, since
	// any other samples have already been flushed by a local veneur instance
	// before this was forwarded to us
	rate := h.localWeight / interval.Seconds()
	metrics := make([]DDMetric, 0, 3+len(percentiles))

	if !math.IsInf(h.localMax, 0) {
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(metrics, DDMetric{
			Name:       fmt.Sprintf("%s.max", h.name),
			Value:      [1][2]float64{{now, h.localMax}},
			Tags:       tags,
			MetricType: "gauge",
		})
	}
	if !math.IsInf(h.localMin, 0) {
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(metrics, DDMetric{
			Name:       fmt.Sprintf("%s.min", h.name),
			Value:      [1][2]float64{{now, h.localMin}},
			Tags:       tags,
			MetricType: "gauge",
		})
	}
	if rate != 0 {
		// if we haven't received any local samples, then leave this sparse,
		// otherwise it can lead to some misleading zeroes in between the
		// flushes of downstream instances
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(metrics, DDMetric{
			Name:       fmt.Sprintf("%s.count", h.name),
			Value:      [1][2]float64{{now, rate}},
			Tags:       tags,
			MetricType: "rate",
			Interval:   int32(interval.Seconds()),
		})
	}

	for _, p := range percentiles {
		tags := make([]string, len(h.tags))
		copy(tags, h.tags)
		metrics = append(
			metrics,
			// TODO Fix to allow for p999, etc
			DDMetric{
				Name:       fmt.Sprintf("%s.%dpercentile", h.name, int(p*100)),
				Value:      [1][2]float64{{now, h.value.Quantile(p)}},
				Tags:       tags,
				MetricType: "gauge",
			},
		)
	}

	return metrics
}

// Export converts a Histogram into a JSONMetric
func (h *Histo) Export() (JSONMetric, error) {
	val, err := h.value.GobEncode()
	if err != nil {
		return JSONMetric{}, err
	}
	return JSONMetric{
		MetricKey: MetricKey{
			Name:       h.name,
			Type:       "histogram",
			JoinedTags: strings.Join(h.tags, ","),
		},
		Tags:  h.tags,
		Value: val,
	}, nil
}

// Combine merges the values of a histogram with another histogram
// (marshalled as a byte slice)
func (h *Histo) Combine(other []byte) error {
	otherHistogram := tdigest.NewMerging(100, false)
	if err := otherHistogram.GobDecode(other); err != nil {
		return err
	}
	h.value.Merge(otherHistogram)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"
)

// Should serve a known static error page if all backend servers are down
// and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServersDown(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve a known static error page if all backend servers return a
// 5xx response and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServers5xx(t *testing.T) {
	t.Error("Not implemented")
}

// Should back off requests against origin for a very short period of time
// if origin returns a 5xx response so as not to overwhelm it.
func TestFailoverOrigin5xxBackOff(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	const expectedResponseStale = "going off like stilton"
	const expectedResponseFresh = "as fresh as daisies"

	const respTTL = time.Duration(2 * time.Second)
	const respTTLWithBuffer = 5 * respTTL
	// Allow varnish's beresp.saintmode to expire.
	const waitSaintMode = time.Duration(5 * time.Second)
	headerValue := fmt.Sprintf("max-age=%.0f", respTTL.Seconds())

	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)

	var expectedBody string
	for requestCount := 1; requestCount < 6; requestCount++ {
		switch requestCount {
		case 1:
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Cache-Control", headerValue)
				w.Write([]byte(expectedBody))
			})
		case 2:
			time.Sleep(respTTLWithBuffer)
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusServiceUnavailable)
				w.Write([]byte(originServer.Name))
			})
		case 5:
			time.Sleep(waitSaintMode)
			expectedBody = expectedResponseFresh

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Write([]byte(expectedBody))
			})
		}

		resp, err := client.RoundTrip(req)
		if err != nil {
			t.Fatal(err)
		}

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}
		if bodyStr := string(body); bodyStr != expectedBody {
			t.Errorf(
				"Request %d received incorrect response body. Expected %q, got %q",
				requestCount,
				expectedBody,
				bodyStr,
			)
		}
	}
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received a request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}
<commit_msg>Comment request flow for 5xxServeStale<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"
)

// Should serve a known static error page if all backend servers are down
// and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServersDown(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve a known static error page if all backend servers return a
// 5xx response and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServers5xx(t *testing.T) {
	t.Error("Not implemented")
}

// Should back off requests against origin for a very short period of time
// if origin returns a 5xx response so as not to overwhelm it.
func TestFailoverOrigin5xxBackOff(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	const expectedResponseStale = "going off like stilton"
	const expectedResponseFresh = "as fresh as daisies"

	const respTTL = time.Duration(2 * time.Second)
	const respTTLWithBuffer = 5 * respTTL
	// Allow varnish's beresp.saintmode to expire.
	const waitSaintMode = time.Duration(5 * time.Second)
	headerValue := fmt.Sprintf("max-age=%.0f", respTTL.Seconds())

	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)

	var expectedBody string
	for requestCount := 1; requestCount < 6; requestCount++ {
		switch requestCount {
		case 1: // Request 1 populates cache.
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Cache-Control", headerValue)
				w.Write([]byte(expectedBody))
			})
		case 2: // Requests 2,3,4 come from stale.
			time.Sleep(respTTLWithBuffer)
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusServiceUnavailable)
				w.Write([]byte(originServer.Name))
			})
		case 5: // Last request comes directly from origin again.
			time.Sleep(waitSaintMode)
			expectedBody = expectedResponseFresh

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Write([]byte(expectedBody))
			})
		}

		resp, err := client.RoundTrip(req)
		if err != nil {
			t.Fatal(err)
		}

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}
		if bodyStr := string(body); bodyStr != expectedBody {
			t.Errorf(
				"Request %d received incorrect response body. Expected %q, got %q",
				requestCount,
				expectedBody,
				bodyStr,
			)
		}
	}
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received a request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}
<|endoftext|>


<commit_before>package fire

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/ory-am/fosite"
	"github.com/ory-am/fosite/handler/core"
	"github.com/ory-am/fosite/handler/core/client"
	"github.com/ory-am/fosite/handler/core/implicit"
	"github.com/ory-am/fosite/handler/core/owner"
	"github.com/ory-am/fosite/handler/core/strategy"
	"github.com/ory-am/fosite/token/hmac"
	"gopkg.in/mgo.v2"
)

// AccessToken is the internal model used to stored access tokens. The model
// can be mounted as a fire Resource to become manageable via the API.
type AccessToken struct {
	Base          `bson:",inline" fire:"access-token:access-tokens:access_tokens"`
	Signature     string    `json:"-" valid:"required"`
	RequestedAt   time.Time `json:"requested-at" valid:"required" bson:"requested_at"`
	GrantedScopes []string  `json:"granted-scopes" valid:"required" bson:"granted_scopes"`
}

var accessTokenModel *AccessToken

func init() {
	accessTokenModel = &AccessToken{}
	Init(accessTokenModel)
}

// A Authenticator provides OAuth2 based authentication. The implementation
// currently supports the Resource Owner Credentials, Client Credentials and
// Implicit Grant flows. The flows can be enabled using their respective methods.
type Authenticator struct {
	storage *authenticatorStorage

	strategy     *strategy.HMACSHAStrategy
	handleHelper *core.HandleHelper
	fosite       *fosite.Fosite
}

// NetAuthenticator creates and returns a new Authenticator.
func NewAuthenticator(db *mgo.Database, ownerModel, clientModel Model, secret string) *Authenticator {
	// initialize models
	Init(ownerModel)
	Init(clientModel)

	// extract attributes from owner
	ownerIdentifiable := ownerModel.getBase().attributesByTag("identifiable")
	if len(ownerIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	ownerVerifiable := ownerModel.getBase().attributesByTag("verifiable")
	if len(ownerVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}

	// extract attributes from client
	clientIdentifiable := clientModel.getBase().attributesByTag("identifiable")
	if len(clientIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	clientVerifiable := clientModel.getBase().attributesByTag("verifiable")
	if len(clientVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}
	clientCallable := clientModel.getBase().attributesByTag("callable")
	if len(clientCallable) != 1 {
		panic("expected to find exactly one 'callable' tag on model")
	}

	// create storage
	s := &authenticatorStorage{
		db:                 db,
		ownerModel:         ownerModel,
		ownerIDAttr:        ownerIdentifiable[0],
		ownerSecretAttr:    ownerVerifiable[0],
		clientModel:        clientModel,
		clientIDAttr:       clientIdentifiable[0],
		clientSecretAttr:   clientVerifiable[0],
		clientCallableAttr: clientCallable[0],
	}

	// set the default token lifespan to one hour
	tokenLifespan := time.Hour

	// create a new token generation strategy
	strategy := &strategy.HMACSHAStrategy{
		Enigma: &hmac.HMACStrategy{
			GlobalSecret: []byte(secret),
		},
		AccessTokenLifespan:   tokenLifespan,
		AuthorizeCodeLifespan: tokenLifespan,
	}

	// instantiate a new fosite instance
	f := fosite.NewFosite(s)

	// set mandatory scope
	f.MandatoryScope = "fire"

	// this little helper is used by some of the handlers later
	handleHelper := &core.HandleHelper{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
		AccessTokenLifespan: tokenLifespan,
	}

	// add a request validator for access tokens to fosite
	f.AuthorizedRequestValidators.Append(&core.CoreValidator{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
	})

	return &Authenticator{
		storage:      s,
		fosite:       f,
		handleHelper: handleHelper,
		strategy:     strategy,
	}
}

// EnablePasswordGrant enables the usage of the OAuth 2.0 Resource Owner Password
// Credentials Grant.
//
// Note: This method should only be called once.
func (a *Authenticator) EnablePasswordGrant() {
	// create handler
	passwordHandler := &owner.ResourceOwnerPasswordCredentialsGrantHandler{
		HandleHelper:                                 a.handleHelper,
		ResourceOwnerPasswordCredentialsGrantStorage: a.storage,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(passwordHandler)
}

// EnableCredentialsGrant enables the usage of the OAuth 2.0 Client Credentials Grant.
//
// Note: This method should only be called once.
func (a *Authenticator) EnableCredentialsGrant() {
	// create handler
	credentialsHandler := &client.ClientCredentialsGrantHandler{
		HandleHelper: a.handleHelper,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(credentialsHandler)
}

// EnableImplicitGrant enables the usage of the OAuth 2.0 Implicit Grant.
//
// Note: This method should only be called once.
func (a *Authenticator) EnableImplicitGrant() {
	// create handler
	implicitHandler := &implicit.AuthorizeImplicitGrantTypeHandler{
		AccessTokenStrategy: a.handleHelper.AccessTokenStrategy,
		AccessTokenStorage:  a.handleHelper.AccessTokenStorage,
		AccessTokenLifespan: a.handleHelper.AccessTokenLifespan,
	}

	// add handler to fosite
	a.fosite.AuthorizeEndpointHandlers.Append(implicitHandler)
}

// HashPassword returns an Authenticator compatible hash of the password.
func (a *Authenticator) HashPassword(password string) ([]byte, error) {
	return a.fosite.Hasher.Hash([]byte(password))
}

// MustHashPassword is the same as HashPassword except that it raises and error
// when the hashing failed.
func (a *Authenticator) MustHashPassword(password string) []byte {
	bytes, err := a.HashPassword(password)
	if err != nil {
		panic(err)
	}

	return bytes
}

// Register will create all necessary routes on the passed router. If want to
// prefix the auth endpoint (e.g. /auth/) you need to pass it to Register.
//
// Note: This functions should only be called once after enabling all flows.
func (a *Authenticator) Register(prefix string, router gin.IRouter) {
	router.POST(prefix+"/token", a.tokenEndpoint)
	router.POST(prefix+"/authorize", a.authorizeEndpoint)

	// TODO: Redirect to auxiliary Login form.
}

// Authorizer returns a callback that can be used to protect resources by requiring
// an access tokens with the provides scopes to be granted.
func (a *Authenticator) Authorizer() Callback {
	// TODO: Add scopes.

	return func(ctx *Context) (error, error) {
		// prepare fosite
		f := fosite.NewContext()
		session := &strategy.HMACSession{}

		// validate request
		_, err := a.fosite.ValidateRequestAuthorization(f, ctx.GinContext.Request, session, "fire")
		if err != nil {
			return err, nil
		}

		return nil, nil
	}
}

func (a *Authenticator) tokenEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// create new session
	s := &strategy.HMACSession{}

	// obtain access request
	req, err := a.fosite.NewAccessRequest(f, ctx.Request, s)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// grant the mandatory scope
	if req.GetScopes().Has("fire") {
		req.GrantScope("fire")
	}

	// obtain access response
	res, err := a.fosite.NewAccessResponse(f, ctx.Request, req)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAccessResponse(ctx.Writer, req, res)
}

func (a *Authenticator) authorizeEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// obtain authorize request
	req, err := a.fosite.NewAuthorizeRequest(f, ctx.Request)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}

	// get credentials
	username := ctx.Request.Form.Get("username")
	password := ctx.Request.Form.Get("password")

	// authenticate user
	err = a.storage.Authenticate(f, username, password)
	if err != nil {
		uri := ctx.Request.Referer() + "&error=invalid_credentials"
		ctx.Redirect(http.StatusTemporaryRedirect, uri)
		return
	}

	// create new session
	s := &strategy.HMACSession{}

	// obtain authorize response
	res, err := a.fosite.NewAuthorizeResponse(ctx, ctx.Request, req, s)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAuthorizeResponse(ctx.Writer, req, res)
}
<commit_msg>properly redirect with error<commit_after>package fire

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/ory-am/fosite"
	"github.com/ory-am/fosite/handler/core"
	"github.com/ory-am/fosite/handler/core/client"
	"github.com/ory-am/fosite/handler/core/implicit"
	"github.com/ory-am/fosite/handler/core/owner"
	"github.com/ory-am/fosite/handler/core/strategy"
	"github.com/ory-am/fosite/token/hmac"
	"gopkg.in/mgo.v2"
)

// AccessToken is the internal model used to stored access tokens. The model
// can be mounted as a fire Resource to become manageable via the API.
type AccessToken struct {
	Base          `bson:",inline" fire:"access-token:access-tokens:access_tokens"`
	Signature     string    `json:"-" valid:"required"`
	RequestedAt   time.Time `json:"requested-at" valid:"required" bson:"requested_at"`
	GrantedScopes []string  `json:"granted-scopes" valid:"required" bson:"granted_scopes"`
}

var accessTokenModel *AccessToken

func init() {
	accessTokenModel = &AccessToken{}
	Init(accessTokenModel)
}

// A Authenticator provides OAuth2 based authentication. The implementation
// currently supports the Resource Owner Credentials, Client Credentials and
// Implicit Grant flows. The flows can be enabled using their respective methods.
type Authenticator struct {
	storage *authenticatorStorage

	strategy     *strategy.HMACSHAStrategy
	handleHelper *core.HandleHelper
	fosite       *fosite.Fosite
}

// NetAuthenticator creates and returns a new Authenticator.
func NewAuthenticator(db *mgo.Database, ownerModel, clientModel Model, secret string) *Authenticator {
	// initialize models
	Init(ownerModel)
	Init(clientModel)

	// extract attributes from owner
	ownerIdentifiable := ownerModel.getBase().attributesByTag("identifiable")
	if len(ownerIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	ownerVerifiable := ownerModel.getBase().attributesByTag("verifiable")
	if len(ownerVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}

	// extract attributes from client
	clientIdentifiable := clientModel.getBase().attributesByTag("identifiable")
	if len(clientIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	clientVerifiable := clientModel.getBase().attributesByTag("verifiable")
	if len(clientVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}
	clientCallable := clientModel.getBase().attributesByTag("callable")
	if len(clientCallable) != 1 {
		panic("expected to find exactly one 'callable' tag on model")
	}

	// create storage
	s := &authenticatorStorage{
		db:                 db,
		ownerModel:         ownerModel,
		ownerIDAttr:        ownerIdentifiable[0],
		ownerSecretAttr:    ownerVerifiable[0],
		clientModel:        clientModel,
		clientIDAttr:       clientIdentifiable[0],
		clientSecretAttr:   clientVerifiable[0],
		clientCallableAttr: clientCallable[0],
	}

	// set the default token lifespan to one hour
	tokenLifespan := time.Hour

	// create a new token generation strategy
	strategy := &strategy.HMACSHAStrategy{
		Enigma: &hmac.HMACStrategy{
			GlobalSecret: []byte(secret),
		},
		AccessTokenLifespan:   tokenLifespan,
		AuthorizeCodeLifespan: tokenLifespan,
	}

	// instantiate a new fosite instance
	f := fosite.NewFosite(s)

	// set mandatory scope
	f.MandatoryScope = "fire"

	// this little helper is used by some of the handlers later
	handleHelper := &core.HandleHelper{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
		AccessTokenLifespan: tokenLifespan,
	}

	// add a request validator for access tokens to fosite
	f.AuthorizedRequestValidators.Append(&core.CoreValidator{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
	})

	return &Authenticator{
		storage:      s,
		fosite:       f,
		handleHelper: handleHelper,
		strategy:     strategy,
	}
}

// EnablePasswordGrant enables the usage of the OAuth 2.0 Resource Owner Password
// Credentials Grant.
//
// Note: This method should only be called once.
func (a *Authenticator) EnablePasswordGrant() {
	// create handler
	passwordHandler := &owner.ResourceOwnerPasswordCredentialsGrantHandler{
		HandleHelper:                                 a.handleHelper,
		ResourceOwnerPasswordCredentialsGrantStorage: a.storage,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(passwordHandler)
}

// EnableCredentialsGrant enables the usage of the OAuth 2.0 Client Credentials Grant.
//
// Note: This method should only be called once.
func (a *Authenticator) EnableCredentialsGrant() {
	// create handler
	credentialsHandler := &client.ClientCredentialsGrantHandler{
		HandleHelper: a.handleHelper,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(credentialsHandler)
}

// EnableImplicitGrant enables the usage of the OAuth 2.0 Implicit Grant.
//
// Note: This method should only be called once.
func (a *Authenticator) EnableImplicitGrant() {
	// create handler
	implicitHandler := &implicit.AuthorizeImplicitGrantTypeHandler{
		AccessTokenStrategy: a.handleHelper.AccessTokenStrategy,
		AccessTokenStorage:  a.handleHelper.AccessTokenStorage,
		AccessTokenLifespan: a.handleHelper.AccessTokenLifespan,
	}

	// add handler to fosite
	a.fosite.AuthorizeEndpointHandlers.Append(implicitHandler)
}

// HashPassword returns an Authenticator compatible hash of the password.
func (a *Authenticator) HashPassword(password string) ([]byte, error) {
	return a.fosite.Hasher.Hash([]byte(password))
}

// MustHashPassword is the same as HashPassword except that it raises and error
// when the hashing failed.
func (a *Authenticator) MustHashPassword(password string) []byte {
	bytes, err := a.HashPassword(password)
	if err != nil {
		panic(err)
	}

	return bytes
}

// Register will create all necessary routes on the passed router. If want to
// prefix the auth endpoint (e.g. /auth/) you need to pass it to Register.
//
// Note: This functions should only be called once after enabling all flows.
func (a *Authenticator) Register(prefix string, router gin.IRouter) {
	router.POST(prefix+"/token", a.tokenEndpoint)
	router.POST(prefix+"/authorize", a.authorizeEndpoint)

	// TODO: Redirect to auxiliary Login form.
}

// Authorizer returns a callback that can be used to protect resources by requiring
// an access tokens with the provides scopes to be granted.
func (a *Authenticator) Authorizer() Callback {
	// TODO: Add scopes.

	return func(ctx *Context) (error, error) {
		// prepare fosite
		f := fosite.NewContext()
		session := &strategy.HMACSession{}

		// validate request
		_, err := a.fosite.ValidateRequestAuthorization(f, ctx.GinContext.Request, session, "fire")
		if err != nil {
			return err, nil
		}

		return nil, nil
	}
}

func (a *Authenticator) tokenEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// create new session
	s := &strategy.HMACSession{}

	// obtain access request
	req, err := a.fosite.NewAccessRequest(f, ctx.Request, s)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// grant the mandatory scope
	if req.GetScopes().Has("fire") {
		req.GrantScope("fire")
	}

	// obtain access response
	res, err := a.fosite.NewAccessResponse(f, ctx.Request, req)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAccessResponse(ctx.Writer, req, res)
}

func (a *Authenticator) authorizeEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// obtain authorize request
	req, err := a.fosite.NewAuthorizeRequest(f, ctx.Request)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}

	// get credentials
	username := ctx.Request.Form.Get("username")
	password := ctx.Request.Form.Get("password")

	// authenticate user
	err = a.storage.Authenticate(f, username, password)
	if err != nil {
		// TODO: Check for an official invalid credentials error format.
		uri := ctx.Request.Form.Get("redirect_uri")
		uri += "?error=invalid_credentials"
		uri += "&error_description=The+provided+credentials+are+invalid"
		uri += "&state=" + ctx.Request.Form.Get("state")
		ctx.Redirect(http.StatusTemporaryRedirect, uri)
		return
	}

	// create new session
	s := &strategy.HMACSession{}

	// obtain authorize response
	res, err := a.fosite.NewAuthorizeResponse(ctx, ctx.Request, req, s)
	if err != nil {
		ctx.Error(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAuthorizeResponse(ctx.Writer, req, res)
}
<|endoftext|>


<commit_before>package game

func init() {
  registerActionType("multistrike", &ActionMultiStrike{})
}
type ActionMultiStrike struct {
  basicIcon
  Ent     *Entity
  Power   int
  Cost    int
  Range   int
  Melee   int
  Count   int

  targets map[*Entity]bool
  marks   map[*Entity]bool
}

func (a *ActionMultiStrike) Prep() bool {
  if a.Ent.AP < a.Cost {
    return false
  }

  targets := getEntsWithinRange(a.Ent, a.Range, a.Ent.level)
  if len(targets) == 0 {
    return false
  }

  a.targets = make(map[*Entity]bool, len(a.targets))
  a.marks = make(map[*Entity]bool, a.Count)
  for _,target := range targets {
    a.targets[target] = true
    a.Ent.level.GetCellAtPos(target.pos).highlight |= Attackable
  }
  return true
}

func (a *ActionMultiStrike) Cancel() {
  a.marks = nil
  a.targets = nil
  a.Ent.level.clearCache(Attackable | Targeted)
}

func (a *ActionMultiStrike) MouseOver(bx,by float64) {
}

func (a *ActionMultiStrike) MouseClick(bx,by float64) bool {
  bp := MakeBoardPos(int(bx), int(by))
  t := a.Ent.level.GetCellAtPos(bp).ent
  if t == nil { return false }
  if _,ok := a.targets[t]; !ok { return false }
  if _,ok := a.marks[t]; ok {
    return true
  }
  a.marks[t] = true
  a.Ent.level.GetCellAtPos(bp).highlight |= Targeted
  return len(a.marks) == a.Count
}

func (a *ActionMultiStrike) Maintain(dt int64) bool {
  if a.marks == nil || a.Ent.AP < a.Cost {
    a.Cancel()
    return true
  }
  a.Ent.AP -= a.Cost

  if a.Melee != 0 {
    a.Ent.s.Command("melee")
  } else {
    a.Ent.s.Command("ranged")
  }

  attack := a.Power + a.Ent.CurrentAttackMod() + ((Dice("5d5") - 2) / 3)

  for mark,_ := range a.marks {
    defense := mark.CurrentDefenseMod()

    mark.s.Command("defend")
    if attack <= defense {
      mark.s.Command("undamaged")
    } else {
      mark.Health -= attack - defense
      if mark.Health <= 0 {
        mark.s.Command("killed")
      } else {
        mark.s.Command("damaged")
      }
    }

    // TODO: This is kinda dumb, we just change facing a bunch and stay facing
    // at the last target (which is random).  Might want to do something like
    // face the average of all of the targets
    a.Ent.turnToFace(mark.pos)
  }

  a.Cancel()
  return true
}
<commit_msg>Separate rolls for each attack in a multistrike<commit_after>package game

func init() {
  registerActionType("multistrike", &ActionMultiStrike{})
}
type ActionMultiStrike struct {
  basicIcon
  Ent     *Entity
  Power   int
  Cost    int
  Range   int
  Melee   int
  Count   int

  targets map[*Entity]bool
  marks   map[*Entity]bool
}

func (a *ActionMultiStrike) Prep() bool {
  if a.Ent.AP < a.Cost {
    return false
  }

  targets := getEntsWithinRange(a.Ent, a.Range, a.Ent.level)
  if len(targets) == 0 {
    return false
  }

  a.targets = make(map[*Entity]bool, len(a.targets))
  a.marks = make(map[*Entity]bool, a.Count)
  for _,target := range targets {
    a.targets[target] = true
    a.Ent.level.GetCellAtPos(target.pos).highlight |= Attackable
  }
  return true
}

func (a *ActionMultiStrike) Cancel() {
  a.marks = nil
  a.targets = nil
  a.Ent.level.clearCache(Attackable | Targeted)
}

func (a *ActionMultiStrike) MouseOver(bx,by float64) {
}

func (a *ActionMultiStrike) MouseClick(bx,by float64) bool {
  bp := MakeBoardPos(int(bx), int(by))
  t := a.Ent.level.GetCellAtPos(bp).ent
  if t == nil { return false }
  if _,ok := a.targets[t]; !ok { return false }
  if _,ok := a.marks[t]; ok {
    return true
  }
  a.marks[t] = true
  a.Ent.level.GetCellAtPos(bp).highlight |= Targeted
  return len(a.marks) == a.Count
}

func (a *ActionMultiStrike) Maintain(dt int64) bool {
  if a.marks == nil || a.Ent.AP < a.Cost {
    a.Cancel()
    return true
  }
  a.Ent.AP -= a.Cost

  if a.Melee != 0 {
    a.Ent.s.Command("melee")
  } else {
    a.Ent.s.Command("ranged")
  }

  for mark,_ := range a.marks {
    attack := a.Power + a.Ent.CurrentAttackMod() + ((Dice("5d5") - 2) / 3)
    defense := mark.CurrentDefenseMod()

    mark.s.Command("defend")
    if attack <= defense {
      mark.s.Command("undamaged")
    } else {
      mark.Health -= attack - defense
      if mark.Health <= 0 {
        mark.s.Command("killed")
      } else {
        mark.s.Command("damaged")
      }
    }

    // TODO: This is kinda dumb, we just change facing a bunch and stay facing
    // at the last target (which is random).  Might want to do something like
    // face the average of all of the targets
    a.Ent.turnToFace(mark.pos)
  }

  a.Cancel()
  return true
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package badges

import (
	"sync"

	"encoding/json"

	"github.com/keybase/client/go/gregor"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	jsonw "github.com/keybase/go-jsonw"
)

// BadgeState represents the number of badges on the app. It's threadsafe.
// Useable from both the client service and gregor server.
// See service:Badger for the service part that owns this.
type BadgeState struct {
	sync.Mutex

	log   logger.Logger
	state keybase1.BadgeState

	inboxVers chat1.InboxVers
	// Map from ConversationID.String to BadgeConversationInfo.
	chatUnreadMap map[string]keybase1.BadgeConversationInfo
}

// NewBadgeState creates a new empty BadgeState.
func NewBadgeState(log logger.Logger) *BadgeState {
	return &BadgeState{
		log:           log,
		inboxVers:     chat1.InboxVers(0),
		chatUnreadMap: make(map[string]keybase1.BadgeConversationInfo),
	}
}

// Exports the state summary
func (b *BadgeState) Export() (keybase1.BadgeState, error) {
	b.Lock()
	defer b.Unlock()

	b.state.Conversations = []keybase1.BadgeConversationInfo{}
	for _, info := range b.chatUnreadMap {
		b.state.Conversations = append(b.state.Conversations, info)
	}
	b.state.InboxVers = int(b.inboxVers)

	return b.state, nil
}

type problemSetBody struct {
	Count int `json:"count"`
}

// UpdateWithGregor updates the badge state from a gregor state.
func (b *BadgeState) UpdateWithGregor(gstate gregor.State) error {
	b.Lock()
	defer b.Unlock()

	b.state.NewTlfs = 0
	b.state.NewFollowers = 0
	b.state.RekeysNeeded = 0

	items, err := gstate.Items()
	if err != nil {
		return err
	}
	for _, item := range items {
		categoryObj := item.Category()
		if categoryObj == nil {
			continue
		}
		category := categoryObj.String()
		switch category {
		case "tlf":
			jsw, err := jsonw.Unmarshal(item.Body().Bytes())
			if err != nil {
				b.log.Warning("BadgeState encountered non-json 'tlf' item: %v", err)
				continue
			}
			itemType, err := jsw.AtKey("type").GetString()
			if err != nil {
				b.log.Warning("BadgeState encountered gregor 'tlf' item without 'type': %v", err)
				continue
			}
			if itemType != "created" {
				continue
			}
			b.state.NewTlfs++
		case "kbfs_tlf_problem_set_count", "kbfs_tlf_sbs_problem_set_count":
			var body problemSetBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState encountered non-json 'problem set' item: %v", err)
				continue
			}
			b.state.RekeysNeeded += body.Count
		case "follow":
			b.state.NewFollowers++
		}
	}

	return nil
}

func (b *BadgeState) UpdateWithChat(update chat1.UnreadUpdate, inboxVers chat1.InboxVers) {
	b.Lock()
	defer b.Unlock()

	// Skip stale updates
	if inboxVers < b.inboxVers {
		return
	}

	b.updateWithChat(update)
}

func (b *BadgeState) UpdateWithChatFull(update chat1.UnreadUpdateFull) {
	b.Lock()
	defer b.Unlock()

	if update.Ignore {
		return
	}

	// Skip stale updates
	if update.InboxVers < b.inboxVers {
		return
	}

	b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)

	for _, upd := range update.Updates {
		b.updateWithChat(upd)
	}

	b.inboxVers = update.InboxVers
}

func (b *BadgeState) Clear() {
	b.Lock()
	defer b.Unlock()

	b.state = keybase1.BadgeState{}
	b.inboxVers = chat1.InboxVers(0)
	b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)
}

func (b *BadgeState) updateWithChat(update chat1.UnreadUpdate) {
	b.chatUnreadMap[update.ConvID.String()] = keybase1.BadgeConversationInfo{
		ConvID:         keybase1.ChatConversationID(update.ConvID),
		UnreadMessages: update.UnreadMessages,
	}
}
<commit_msg>update inbox version on incremental chat updates<commit_after>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package badges

import (
	"sync"

	"encoding/json"

	"github.com/keybase/client/go/gregor"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	jsonw "github.com/keybase/go-jsonw"
)

// BadgeState represents the number of badges on the app. It's threadsafe.
// Useable from both the client service and gregor server.
// See service:Badger for the service part that owns this.
type BadgeState struct {
	sync.Mutex

	log   logger.Logger
	state keybase1.BadgeState

	inboxVers chat1.InboxVers
	// Map from ConversationID.String to BadgeConversationInfo.
	chatUnreadMap map[string]keybase1.BadgeConversationInfo
}

// NewBadgeState creates a new empty BadgeState.
func NewBadgeState(log logger.Logger) *BadgeState {
	return &BadgeState{
		log:           log,
		inboxVers:     chat1.InboxVers(0),
		chatUnreadMap: make(map[string]keybase1.BadgeConversationInfo),
	}
}

// Exports the state summary
func (b *BadgeState) Export() (keybase1.BadgeState, error) {
	b.Lock()
	defer b.Unlock()

	b.state.Conversations = []keybase1.BadgeConversationInfo{}
	for _, info := range b.chatUnreadMap {
		b.state.Conversations = append(b.state.Conversations, info)
	}
	b.state.InboxVers = int(b.inboxVers)

	return b.state, nil
}

type problemSetBody struct {
	Count int `json:"count"`
}

// UpdateWithGregor updates the badge state from a gregor state.
func (b *BadgeState) UpdateWithGregor(gstate gregor.State) error {
	b.Lock()
	defer b.Unlock()

	b.state.NewTlfs = 0
	b.state.NewFollowers = 0
	b.state.RekeysNeeded = 0

	items, err := gstate.Items()
	if err != nil {
		return err
	}
	for _, item := range items {
		categoryObj := item.Category()
		if categoryObj == nil {
			continue
		}
		category := categoryObj.String()
		switch category {
		case "tlf":
			jsw, err := jsonw.Unmarshal(item.Body().Bytes())
			if err != nil {
				b.log.Warning("BadgeState encountered non-json 'tlf' item: %v", err)
				continue
			}
			itemType, err := jsw.AtKey("type").GetString()
			if err != nil {
				b.log.Warning("BadgeState encountered gregor 'tlf' item without 'type': %v", err)
				continue
			}
			if itemType != "created" {
				continue
			}
			b.state.NewTlfs++
		case "kbfs_tlf_problem_set_count", "kbfs_tlf_sbs_problem_set_count":
			var body problemSetBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState encountered non-json 'problem set' item: %v", err)
				continue
			}
			b.state.RekeysNeeded += body.Count
		case "follow":
			b.state.NewFollowers++
		}
	}

	return nil
}

func (b *BadgeState) UpdateWithChat(update chat1.UnreadUpdate, inboxVers chat1.InboxVers) {
	b.Lock()
	defer b.Unlock()

	// Skip stale updates
	if inboxVers < b.inboxVers {
		return
	}

	b.inboxVers = inboxVers
	b.updateWithChat(update)
}

func (b *BadgeState) UpdateWithChatFull(update chat1.UnreadUpdateFull) {
	b.Lock()
	defer b.Unlock()

	if update.Ignore {
		return
	}

	// Skip stale updates
	if update.InboxVers < b.inboxVers {
		return
	}

	b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)

	for _, upd := range update.Updates {
		b.updateWithChat(upd)
	}

	b.inboxVers = update.InboxVers
}

func (b *BadgeState) Clear() {
	b.Lock()
	defer b.Unlock()

	b.state = keybase1.BadgeState{}
	b.inboxVers = chat1.InboxVers(0)
	b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)
}

func (b *BadgeState) updateWithChat(update chat1.UnreadUpdate) {
	b.chatUnreadMap[update.ConvID.String()] = keybase1.BadgeConversationInfo{
		ConvID:         keybase1.ChatConversationID(update.ConvID),
		UnreadMessages: update.UnreadMessages,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)
import (
	"runtime/pprof"
	"runtime"
	"flag"
)

func main() {
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	commandtype := flag.String("type", "", "server or client")
	service := flag.String("service", "", "like :8080")
	times := flag.Int("times", 1, "client exec times")
	flag.Parse()
	runtime.SetBlockProfileRate(1)
	log.Println(*cpuprofile)
	if *cpuprofile != "" {
		log.Println("cpuprofiling")
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	if *commandtype == "client" {
		client(*service, *times)
	} else if *commandtype == "server" {
		server(*service, *times)
	} else {
		log.Fatal("not exists type: " + *commandtype)
		log.Fatal(flag.Usage)
	}
}

func dieIfError(err error) {
}

func client(service string, times int) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
	for i := 0; i < times; i++ {
		conn, err := net.DialTCP("tcp", nil, tcpAddr)
		if err != nil {
			log.Fatal("Fatal error: %s", err.Error())
		}
		_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
		if err != nil {
			log.Fatal("Fatal error: %s", err.Error())
		}
		result, err := ioutil.ReadAll(conn)
		if err != nil {
			log.Fatal("Fatal error: %s", err.Error())
		}
		log.Println(string(result))
	}
}

func server(service string, times int) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
	count := 0
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		count += 1
		responce(conn, count)
		if count == times {
			return
		}
	}

}

func responce(conn net.Conn, count int) {
	defer conn.Close()
	now := time.Now().String()
	log.Println(strconv.Itoa(count) + " Access come !")
	conn.Write([]byte(now))
}
<commit_msg>行数など出力<commit_after>package main

import (
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)
import (
	"runtime/pprof"
	"runtime"
	"flag"
)

func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	commandtype := flag.String("type", "", "server or client")
	service := flag.String("service", "", "like :8080")
	times := flag.Int("times", 1, "client exec times")
	flag.Parse()
	runtime.SetBlockProfileRate(1)
	log.Println(*cpuprofile)
	if *cpuprofile != "" {
		log.Println("cpuprofiling")
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	if *commandtype == "client" {
		client(*service, *times)
	} else if *commandtype == "server" {
		server(*service, *times)
	} else {
		log.Fatal("not exists type: " + *commandtype)
		log.Fatal(flag.Usage)
	}
}

func dieIfError(err error) {
}

func client(service string, times int) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
	for i := 0; i < times; i++ {
		conn, err := net.DialTCP("tcp", nil, tcpAddr)
		if err != nil {
			log.Fatal("Fatal error: %s", err.Error())
		}
		_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
		if err != nil {
			log.Fatal("Fatal error: %s", err.Error())
		}
		result, err := ioutil.ReadAll(conn)
		if err != nil {
			log.Fatal("Fatal error: %s", err.Error())
		}
		log.Println(string(result))
	}
}

func server(service string, times int) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
	count := 0
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		count += 1
		responce(conn, count)
		if count == times {
			return
		}
	}

}

func responce(conn net.Conn, count int) {
	defer conn.Close()
	now := time.Now().String()
	log.Println(strconv.Itoa(count) + " Access come !")
	conn.Write([]byte(now))
}
<|endoftext|>