<commit_before>// Copyright 2017 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package helpers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/cilium/cilium/test/config"

	"github.com/onsi/gomega"
	"github.com/onsi/gomega/types"
	"k8s.io/client-go/util/jsonpath"
)

// CmdRes contains a variety of data which results from running a command.
type CmdRes struct {
	cmd      string        // Command to run
	params   []string      // Parameters to provide to command
	stdout   *bytes.Buffer // Stdout from running cmd
	stderr   *bytes.Buffer // Stderr from running cmd
	success  bool          // Whether command successfully executed
	exitcode int           // The exit code of cmd
}

// GetCmd returns res's cmd.
func (res *CmdRes) GetCmd() string {
	return res.cmd
}

// GetExitCode returns res's exitcode.
func (res *CmdRes) GetExitCode() int {
	return res.exitcode
}

// GetStdOut returns the contents of the stdout buffer of res as a string.
func (res *CmdRes) GetStdOut() string {
	return res.stdout.String()
}

// GetStdErr returns the contents of the stderr buffer of res as a string.
func (res *CmdRes) GetStdErr() string {
	return res.stderr.String()
}

// SendToLog writes to `TestLogWriter` the debug message for the running command
func (res *CmdRes) SendToLog() {
	fmt.Fprintf(&config.TestLogWriter, "cmd: %q exitCode: %d \n %s\n",
		res.cmd,
		res.GetExitCode(),
		res.CombineOutput())
}

// WasSuccessful returns true if cmd completed successfully.
func (res *CmdRes) WasSuccessful() bool {
	return res.success
}

// ExpectFail asserts whether res failed to execute. It accepts an optional
// parameter that can be used to annotate failure messages.
func (res *CmdRes) ExpectFail(optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res).ShouldNot(
		CMDSuccess(), optionalDescription...)
}

// ExpectSuccess asserts whether res executed successfully. It accepts an optional
// parameter that can be used to annotate failure messages.
func (res *CmdRes) ExpectSuccess(optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res).Should(
		CMDSuccess(), optionalDescription...)
}

// ExpectContains asserts a string into the stdout of the response of executed
// command. It accepts an optional parameter that can be used to annotate
// failure messages.
func (res *CmdRes) ExpectContains(data string, optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res.Output().String()).To(
		gomega.ContainSubstring(data), optionalDescription...)
}

// CountLines return the number of lines in the stdout of res.
func (res *CmdRes) CountLines() int {
	return strings.Count(res.stdout.String(), "\n")
}

// CombineOutput returns the combined output of stdout and stderr for res.
func (res *CmdRes) CombineOutput() *bytes.Buffer {
	result := new(bytes.Buffer)
	result.WriteString(res.stdout.String())
	result.WriteString(res.stderr.String())
	return result
}

// IntOutput returns the stdout of res as an integer
func (res *CmdRes) IntOutput() (int, error) {
	return strconv.Atoi(strings.Trim(res.stdout.String(), "\n"))
}

// FindResults filters res's stdout using the provided JSONPath filter. It
// returns an array of the values that match the filter, and an error if
// the unmarshalling of the stdout of res fails.
// TODO - what exactly is the need for this vs. Filter function below?
func (res *CmdRes) FindResults(filter string) ([]reflect.Value, error) {

	var data interface{}
	var result []reflect.Value

	err := json.Unmarshal(res.stdout.Bytes(), &data)
	if err != nil {
		return nil, err
	}
	parser := jsonpath.New("").AllowMissingKeys(true)
	parser.Parse(filter)
	fullResults, _ := parser.FindResults(data)
	for _, res := range fullResults {
		for _, val := range res {
			result = append(result, val)
		}
	}
	return result, nil
}

// Filter returns the contents of res's stdout filtered using the provided
// JSONPath filter in a buffer. Returns an error if the unmarshalling of the
// contents of res's stdout fails.
func (res *CmdRes) Filter(filter string) (*bytes.Buffer, error) {
	var data interface{}
	result := new(bytes.Buffer)

	err := json.Unmarshal(res.stdout.Bytes(), &data)
	if err != nil {
		return nil, fmt.Errorf("could not parse JSON from command %q",
			res.cmd)
	}
	parser := jsonpath.New("").AllowMissingKeys(true)
	parser.Parse(filter)
	err = parser.Execute(result, data)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// ByLines returns res's stdout split by the newline character .
func (res *CmdRes) ByLines() []string {
	return strings.Split(res.stdout.String(), "\n")
}

// KVOutput returns a map of the stdout of res split based on
// the separator '='.
// For example, the following strings would be split as follows:
// 		a=1
// 		b=2
// 		c=3
func (res *CmdRes) KVOutput() map[string]string {
	result := make(map[string]string)
	for _, line := range res.ByLines() {
		vals := strings.Split(line, "=")
		if len(vals) == 2 {
			result[vals[0]] = vals[1]
		}
	}
	return result
}

// Output returns res's stdout.
func (res *CmdRes) Output() *bytes.Buffer {
	return res.stdout
}

// OutputPrettyPrint returns a string with the ExitCode, stdout and stderr in a
// pretty format.
func (res *CmdRes) OutputPrettyPrint() string {
	format := func(message string) string {
		result := []string{}
		for _, line := range strings.Split(message, "\n") {
			result = append(result, fmt.Sprintf("\t %s", line))
		}
		return strings.Join(result, "\n")

	}
	return fmt.Sprintf(
		"Exitcode: %d \nStdout:\n %s\nStderr:\n %s\n",
		res.GetExitCode(),
		format(res.GetStdOut()),
		format(res.GetStdErr()))
}

// ExpectEqual asserts whether cmdRes.Output().String() and expected are equal.
// It accepts an optional parameter that can be used to annotate failure
// messages.
func (res *CmdRes) ExpectEqual(expected string, optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res.Output().String()).Should(
		gomega.Equal(expected), optionalDescription...)
}

// Reset resets res's stdout buffer to be empty.
func (res *CmdRes) Reset() {
	res.stdout.Reset()
	return
}

// SingleOut returns res's stdout as a string without any newline characters
func (res *CmdRes) SingleOut() string {
	return strings.Replace(res.stdout.String(), "\n", "", -1)
}

// Unmarshal unmarshalls res's stdout into data. It assumes that the stdout of
// res is in JSON format. Returns an error if the unmarshalling fails.
func (res *CmdRes) Unmarshal(data interface{}) error {
	err := json.Unmarshal(res.stdout.Bytes(), &data)
	return err
}

// GetDebugMessage returns executed command and its output
func (res *CmdRes) GetDebugMessage() string {
	return fmt.Sprintf("cmd: %s\noutput: %s", res.GetCmd(), res.CombineOutput())
}

// WaitUntilMatch waits until the given substring is present in the `CmdRes.stdout`
// If the timeout is reached it will return an error.
func (res *CmdRes) WaitUntilMatch(substr string) error {
	body := func() bool {
		return strings.Contains(res.Output().String(), substr)
	}

	return WithTimeout(
		body,
		fmt.Sprintf("%s is not in the output after timeout", substr),
		&TimeoutConfig{Timeout: HelperTimeout})
}

// BeSuccesfulMatcher a new Ginkgo matcher for CmdRes struct
type BeSuccesfulMatcher struct{}

// Match validates that the given interface will be a `*CmdRes` struct and it
// was successful. In case of not a valid CmdRes will return an error. If the
// command was not successful it returns false.
func (matcher *BeSuccesfulMatcher) Match(actual interface{}) (success bool, err error) {
	res, ok := actual.(*CmdRes)
	if !ok {
		return false, fmt.Errorf("%q is not a valid *CmdRes type", actual)
	}
	return res.WasSuccessful(), nil
}

// FailureMessage it returns a pretty printed error message in the case of the
// command was not successful.
func (matcher *BeSuccesfulMatcher) FailureMessage(actual interface{}) (message string) {
	res, _ := actual.(*CmdRes)
	return fmt.Sprintf("Expected command: %s \nTo succeed, but it fails:\n%s",
		res.GetCmd(), res.OutputPrettyPrint())
}

// NegatedFailureMessage returns a pretty printed error message in case of the
// command is tested with a negative
func (matcher *BeSuccesfulMatcher) NegatedFailureMessage(actual interface{}) (message string) {
	res, _ := actual.(*CmdRes)
	return fmt.Sprintf("Expected command: %s\nTo fails, but it was successful:\n%s",
		res.GetCmd(), res.OutputPrettyPrint())
}

// CMDSuccess return a new Matcher that expects a CmdRes is a successful run command.
func CMDSuccess() types.GomegaMatcher {
	return &BeSuccesfulMatcher{}
}
<commit_msg>Test: CMDSuccess fix typos<commit_after>// Copyright 2017 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package helpers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/cilium/cilium/test/config"

	"github.com/onsi/gomega"
	"github.com/onsi/gomega/types"
	"k8s.io/client-go/util/jsonpath"
)

// CmdRes contains a variety of data which results from running a command.
type CmdRes struct {
	cmd      string        // Command to run
	params   []string      // Parameters to provide to command
	stdout   *bytes.Buffer // Stdout from running cmd
	stderr   *bytes.Buffer // Stderr from running cmd
	success  bool          // Whether command successfully executed
	exitcode int           // The exit code of cmd
}

// GetCmd returns res's cmd.
func (res *CmdRes) GetCmd() string {
	return res.cmd
}

// GetExitCode returns res's exitcode.
func (res *CmdRes) GetExitCode() int {
	return res.exitcode
}

// GetStdOut returns the contents of the stdout buffer of res as a string.
func (res *CmdRes) GetStdOut() string {
	return res.stdout.String()
}

// GetStdErr returns the contents of the stderr buffer of res as a string.
func (res *CmdRes) GetStdErr() string {
	return res.stderr.String()
}

// SendToLog writes to `TestLogWriter` the debug message for the running command
func (res *CmdRes) SendToLog() {
	fmt.Fprintf(&config.TestLogWriter, "cmd: %q exitCode: %d \n %s\n",
		res.cmd,
		res.GetExitCode(),
		res.CombineOutput())
}

// WasSuccessful returns true if cmd completed successfully.
func (res *CmdRes) WasSuccessful() bool {
	return res.success
}

// ExpectFail asserts whether res failed to execute. It accepts an optional
// parameter that can be used to annotate failure messages.
func (res *CmdRes) ExpectFail(optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res).ShouldNot(
		CMDSuccess(), optionalDescription...)
}

// ExpectSuccess asserts whether res executed successfully. It accepts an optional
// parameter that can be used to annotate failure messages.
func (res *CmdRes) ExpectSuccess(optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res).Should(
		CMDSuccess(), optionalDescription...)
}

// ExpectContains asserts a string into the stdout of the response of executed
// command. It accepts an optional parameter that can be used to annotate
// failure messages.
func (res *CmdRes) ExpectContains(data string, optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res.Output().String()).To(
		gomega.ContainSubstring(data), optionalDescription...)
}

// CountLines return the number of lines in the stdout of res.
func (res *CmdRes) CountLines() int {
	return strings.Count(res.stdout.String(), "\n")
}

// CombineOutput returns the combined output of stdout and stderr for res.
func (res *CmdRes) CombineOutput() *bytes.Buffer {
	result := new(bytes.Buffer)
	result.WriteString(res.stdout.String())
	result.WriteString(res.stderr.String())
	return result
}

// IntOutput returns the stdout of res as an integer
func (res *CmdRes) IntOutput() (int, error) {
	return strconv.Atoi(strings.Trim(res.stdout.String(), "\n"))
}

// FindResults filters res's stdout using the provided JSONPath filter. It
// returns an array of the values that match the filter, and an error if
// the unmarshalling of the stdout of res fails.
// TODO - what exactly is the need for this vs. Filter function below?
func (res *CmdRes) FindResults(filter string) ([]reflect.Value, error) {

	var data interface{}
	var result []reflect.Value

	err := json.Unmarshal(res.stdout.Bytes(), &data)
	if err != nil {
		return nil, err
	}
	parser := jsonpath.New("").AllowMissingKeys(true)
	parser.Parse(filter)
	fullResults, _ := parser.FindResults(data)
	for _, res := range fullResults {
		for _, val := range res {
			result = append(result, val)
		}
	}
	return result, nil
}

// Filter returns the contents of res's stdout filtered using the provided
// JSONPath filter in a buffer. Returns an error if the unmarshalling of the
// contents of res's stdout fails.
func (res *CmdRes) Filter(filter string) (*bytes.Buffer, error) {
	var data interface{}
	result := new(bytes.Buffer)

	err := json.Unmarshal(res.stdout.Bytes(), &data)
	if err != nil {
		return nil, fmt.Errorf("could not parse JSON from command %q",
			res.cmd)
	}
	parser := jsonpath.New("").AllowMissingKeys(true)
	parser.Parse(filter)
	err = parser.Execute(result, data)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// ByLines returns res's stdout split by the newline character .
func (res *CmdRes) ByLines() []string {
	return strings.Split(res.stdout.String(), "\n")
}

// KVOutput returns a map of the stdout of res split based on
// the separator '='.
// For example, the following strings would be split as follows:
// 		a=1
// 		b=2
// 		c=3
func (res *CmdRes) KVOutput() map[string]string {
	result := make(map[string]string)
	for _, line := range res.ByLines() {
		vals := strings.Split(line, "=")
		if len(vals) == 2 {
			result[vals[0]] = vals[1]
		}
	}
	return result
}

// Output returns res's stdout.
func (res *CmdRes) Output() *bytes.Buffer {
	return res.stdout
}

// OutputPrettyPrint returns a string with the ExitCode, stdout and stderr in a
// pretty format.
func (res *CmdRes) OutputPrettyPrint() string {
	format := func(message string) string {
		result := []string{}
		for _, line := range strings.Split(message, "\n") {
			result = append(result, fmt.Sprintf("\t %s", line))
		}
		return strings.Join(result, "\n")

	}
	return fmt.Sprintf(
		"Exitcode: %d \nStdout:\n %s\nStderr:\n %s\n",
		res.GetExitCode(),
		format(res.GetStdOut()),
		format(res.GetStdErr()))
}

// ExpectEqual asserts whether cmdRes.Output().String() and expected are equal.
// It accepts an optional parameter that can be used to annotate failure
// messages.
func (res *CmdRes) ExpectEqual(expected string, optionalDescription ...interface{}) bool {
	return gomega.ExpectWithOffset(1, res.Output().String()).Should(
		gomega.Equal(expected), optionalDescription...)
}

// Reset resets res's stdout buffer to be empty.
func (res *CmdRes) Reset() {
	res.stdout.Reset()
	return
}

// SingleOut returns res's stdout as a string without any newline characters
func (res *CmdRes) SingleOut() string {
	return strings.Replace(res.stdout.String(), "\n", "", -1)
}

// Unmarshal unmarshalls res's stdout into data. It assumes that the stdout of
// res is in JSON format. Returns an error if the unmarshalling fails.
func (res *CmdRes) Unmarshal(data interface{}) error {
	err := json.Unmarshal(res.stdout.Bytes(), &data)
	return err
}

// GetDebugMessage returns executed command and its output
func (res *CmdRes) GetDebugMessage() string {
	return fmt.Sprintf("cmd: %s\noutput: %s", res.GetCmd(), res.CombineOutput())
}

// WaitUntilMatch waits until the given substring is present in the `CmdRes.stdout`
// If the timeout is reached it will return an error.
func (res *CmdRes) WaitUntilMatch(substr string) error {
	body := func() bool {
		return strings.Contains(res.Output().String(), substr)
	}

	return WithTimeout(
		body,
		fmt.Sprintf("%s is not in the output after timeout", substr),
		&TimeoutConfig{Timeout: HelperTimeout})
}

// BeSuccesfulMatcher a new Ginkgo matcher for CmdRes struct
type BeSuccesfulMatcher struct{}

// Match validates that the given interface will be a `*CmdRes` struct and it
// was successful. In case of not a valid CmdRes will return an error. If the
// command was not successful it returns false.
func (matcher *BeSuccesfulMatcher) Match(actual interface{}) (success bool, err error) {
	res, ok := actual.(*CmdRes)
	if !ok {
		return false, fmt.Errorf("%q is not a valid *CmdRes type", actual)
	}
	return res.WasSuccessful(), nil
}

// FailureMessage it returns a pretty printed error message in the case of the
// command was not successful.
func (matcher *BeSuccesfulMatcher) FailureMessage(actual interface{}) (message string) {
	res, _ := actual.(*CmdRes)
	return fmt.Sprintf("Expected command: %s \nTo succeed, but it failed:\n%s",
		res.GetCmd(), res.OutputPrettyPrint())
}

// NegatedFailureMessage returns a pretty printed error message in case of the
// command is tested with a negative
func (matcher *BeSuccesfulMatcher) NegatedFailureMessage(actual interface{}) (message string) {
	res, _ := actual.(*CmdRes)
	return fmt.Sprintf("Expected command: %s\nTo have failed, but it was successful:\n%s",
		res.GetCmd(), res.OutputPrettyPrint())
}

// CMDSuccess return a new Matcher that expects a CmdRes is a successful run command.
func CMDSuccess() types.GomegaMatcher {
	return &BeSuccesfulMatcher{}
}
<|endoftext|>


<commit_before>package config

import (
	"os"
	"path/filepath"

	"github.com/admpub/godotenv"
	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/common"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
)

func findEnvFile() []string {
	var envFiles []string
	envFile := filepath.Join(echo.Wd(), `.env`)
	if fi, err := os.Stat(envFile); err == nil && !fi.IsDir() {
		envFiles = append(envFiles, envFile)
	}
	return envFiles
}

func (c *CLIConfig) InitEnviron(needFindEnvFile ...bool) (err error) {
	if len(needFindEnvFile) > 0 && needFindEnvFile[0] {
		c.envFiles = findEnvFile()
	}
	var newEnvVars map[string]string
	if len(c.envFiles) > 0 {
		log.Infof(`Loading env file: %#v`, c.envFiles)
		newEnvVars, err = godotenv.Read(c.envFiles...)
		if err != nil {
			return
		}
	}
	if c.envVars != nil {
		for k := range c.envVars {
			os.Unsetenv(k)
		}
	}
	c.envVars = newEnvVars
	if c.envVars != nil {
		for k, v := range c.envVars {
			log.Infof(`Set env var: %s`, k)
			os.Setenv(k, v)
		}
	}
	return
}

func (c *CLIConfig) WatchEnvConfig() {
	if c.envMonitor != nil {
		c.envMonitor.Close()
		c.envMonitor = nil
	}
	if len(c.envFiles) == 0 {
		return
	}
	c.envMonitor = &com.MonitorEvent{
		Modify: func(file string) {
			log.Info(`Start reloading env file: ` + file)
			err := c.InitEnviron()
			if err == nil {
				log.Info(`Succcessfully reload the env file: ` + file)
				return
			}
			if err == common.ErrIgnoreConfigChange {
				log.Info(`No need to reload the env file: ` + file)
				return
			}
			log.Error(err)
		},
	}
	for _, envFile := range c.envFiles {
		err := c.envMonitor.AddFile(envFile)
		if err != nil {
			log.Error(err)
		}
	}
	c.envMonitor.Watch()
}
<commit_msg>improved<commit_after>package config

import (
	"os"
	"path/filepath"

	"github.com/admpub/godotenv"
	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/common"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
)

func findEnvFile() []string {
	var envFiles []string
	envFile := filepath.Join(echo.Wd(), `.env`)
	if fi, err := os.Stat(envFile); err == nil && !fi.IsDir() {
		envFiles = append(envFiles, envFile)
	}
	return envFiles
}

func (c *CLIConfig) InitEnviron(needFindEnvFile ...bool) (err error) {
	if len(needFindEnvFile) > 0 && needFindEnvFile[0] {
		c.envFiles = findEnvFile()
	}
	var newEnvVars map[string]string
	if len(c.envFiles) > 0 {
		log.Infof(`Loading env file: %#v`, c.envFiles)
		newEnvVars, err = godotenv.Read(c.envFiles...)
		if err != nil {
			return
		}
	}
	if newEnvVars != nil {
		if c.envVars != nil {
			for k, v := range c.envVars {
				newV, ok := newEnvVars[k]
				if !ok {
					log.Infof(`Unset env var: %s`, k)
					os.Unsetenv(k)
					delete(c.envVars, k)
					continue
				}
				if v != newV {
					log.Infof(`Set env var: %s`, k)
					os.Setenv(k, v)
					c.envVars[k] = newV
				}
				delete(newEnvVars, k)
			}
		} else {
			c.envVars = map[string]string{}
		}
		for k, v := range newEnvVars {
			log.Infof(`Set env var: %s`, k)
			os.Setenv(k, v)
			c.envVars[k] = v
		}
	} else {
		if c.envVars != nil {
			for k := range c.envVars {
				log.Infof(`Unset env var: %s`, k)
				os.Unsetenv(k)
			}
		}
		c.envVars = nil
	}
	return
}

func (c *CLIConfig) WatchEnvConfig() {
	if c.envMonitor != nil {
		c.envMonitor.Close()
		c.envMonitor = nil
	}
	if len(c.envFiles) == 0 {
		return
	}
	c.envMonitor = &com.MonitorEvent{
		Modify: func(file string) {
			log.Info(`Start reloading env file: ` + file)
			err := c.InitEnviron()
			if err == nil {
				log.Info(`Succcessfully reload the env file: ` + file)
				return
			}
			if err == common.ErrIgnoreConfigChange {
				log.Info(`No need to reload the env file: ` + file)
				return
			}
			log.Error(err)
		},
	}
	for _, envFile := range c.envFiles {
		err := c.envMonitor.AddFile(envFile)
		if err != nil {
			log.Error(err)
		}
	}
	c.envMonitor.Watch()
}
<|endoftext|>


<commit_before>/*

The analysis package defines the interface between a modular static
analysis and an analysis driver program.

Background

A static analysis is a function that inspects a package of Go code and
reports a set of diagnostics (typically mistakes in the code), and
perhaps produces other results as well, such as suggested refactorings
or other facts. An analysis that reports mistakes is informally called a
"checker". For example, the printf checker reports mistakes in
fmt.Printf format strings.

A "modular" analysis is one that inspects one package at a time but can
save information from a lower-level package and use it when inspecting a
higher-level package, analogous to separate compilation in a toolchain.
The printf checker is modular: when it discovers that a function such as
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
calls to that function too, including calls made from another package.

By implementing a common interface, checkers from a variety of sources
can be easily selected, incorporated, and reused in a wide range of
driver programs including command-line tools (such as vet), text editors and
IDEs, build and test systems (such as go build, Bazel, or Buck), test
frameworks, code review tools, code-base indexers (such as SourceGraph),
documentation viewers (such as godoc), batch pipelines for large code
bases, and so on.

Analyzer

The primary type in the API is Analyzer. An Analyzer statically
describes an analysis function: its name, documentation, flags,
relationship to other analyzers, and of course, its logic.

To define an analysis, a user declares a (logically constant) variable
of type Analyzer. Here is a typical example from one of the analyzers in
the go/analysis/passes/ subdirectory:

	package unusedresult

	var Analyzer = &analysis.Analyzer{
		Name:	"unusedresult",
		Doc:	"check for unused results of calls to some functions",
		Run:    run,
		...
	}

	func run(pass *analysis.Pass) (interface{}, error) {
		...
	}

An analysis driver is a program such as vet that runs a set of
analyses and prints the diagnostics that they report.
The driver program must import the list of Analyzers it needs.
Typically each Analyzer resides in a separate package.
To add a new Analyzer to an existing driver, add another item to the list:

	import ( "unusedresult"; "nilness"; "printf" )

	var analyses = []*analysis.Analyzer{
		unusedresult.Analyzer,
		nilness.Analyzer,
		printf.Analyzer,
	}

A driver may use the name, flags, and documentation to provide on-line
help that describes the analyses its performs.
The doc comment contains a brief one-line summary,
optionally followed by paragraphs of explanation.
The vet command, shown below, is an example of a driver that runs
multiple analyzers. It is based on the multichecker package
(see the "Standalone commands" section for details).

	$ go build golang.org/x/tools/go/analysis/cmd/vet
	$ ./vet help
	vet is a tool for static analysis of Go programs.

	Usage: vet [-flag] [package]

	Registered analyzers:

	    asmdecl      report mismatches between assembly files and Go declarations
	    assign       check for useless assignments
	    atomic       check for common mistakes using the sync/atomic package
	    ...
	    unusedresult check for unused results of calls to some functions

	$ ./vet help unusedresult
	unusedresult: check for unused results of calls to some functions

	Analyzer flags:

	  -unusedresult.funcs value
	        comma-separated list of functions whose results must be used (default Error,String)
	  -unusedresult.stringmethods value
	        comma-separated list of names of methods of type func() string whose results must be used

	Some functions like fmt.Errorf return a result and have no side effects,
	so it is always a mistake to discard the result. This analyzer reports
	calls to certain functions in which the result of the call is ignored.

	The set of functions may be controlled using flags.

The Analyzer type has more fields besides those shown above:

	type Analyzer struct {
		Name			string
		Doc			string
		Flags			flag.FlagSet
		Run			func(*Pass) (interface{}, error)
		RunDespiteErrors	bool
		ResultType		reflect.Type
		Requires		[]*Analyzer
		FactTypes		[]Fact
	}

The Flags field declares a set of named (global) flag variables that
control analysis behavior. Unlike vet, analysis flags are not declared
directly in the command line FlagSet; it is up to the driver to set the
flag variables. A driver for a single analysis, a, might expose its flag
f directly on the command line as -f, whereas a driver for multiple
analyses might prefix the flag name by the analysis name (-a.f) to avoid
ambiguity. An IDE might expose the flags through a graphical interface,
and a batch pipeline might configure them from a config file.
See the "findcall" analyzer for an example of flags in action.

The RunDespiteErrors flag indicates whether the analysis is equipped to
handle ill-typed code. If not, the driver will skip the analysis if
there were parse or type errors.
The optional ResultType field specifies the type of the result value
computed by this analysis and made available to other analyses.
The Requires field specifies a list of analyses upon which
this one depends and whose results it may access, and it constrains the
order in which a driver may run analyses.
The FactTypes field is discussed in the section on Modularity.
The analysis package provides a Validate function to perform basic
sanity checks on an Analyzer, such as that its Requires graph is
acyclic, its fact and result types are unique, and so on.

Finally, the Run field contains a function to be called by the driver to
execute the analysis on a single package. The driver passes it an
instance of the Pass type.

Pass

A Pass describes a single unit of work: the application of a particular
Analyzer to a particular package of Go code.
The Pass provides information to the Analyzer's Run function about the
package being analyzed, and provides operations to the Run function for
reporting diagnostics and other information back to the driver.

	type Pass struct {
		Fset   		*token.FileSet
		Files		[]*ast.File
		OtherFiles	[]string
		Pkg		*types.Package
		TypesInfo	*types.Info
		ResultOf	map[*Analyzer]interface{}
		Report		func(Diagnostic)
		...
	}

The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
type information, and source positions for a single package of Go code.

The OtherFiles field provides the names, but not the contents, of non-Go
files such as assembly that are part of this package. See the "asmdecl"
or "buildtags" analyzers for examples of loading non-Go files and report
diagnostics against them.

The ResultOf field provides the results computed by the analyzers
required by this one, as expressed in its Analyzer.Requires field. The
driver runs the required analyzers first and makes their results
available in this map. Each Analyzer must return a value of the type
described in its Analyzer.ResultType field.
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
provides a control-flow graph for each function in the package (see
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
enables other Analyzers to traverse the syntax trees of the package more
efficiently; and the "buildssa" analyzer constructs an SSA-form
intermediate representation.
Each of these Analyzers extends the capabilities of later Analyzers
without adding a dependency to the core API, so an analysis tool pays
only for the extensions it needs.

The Report function emits a diagnostic, a message associated with a
source position. For most analyses, diagnostics are their primary
result.
For convenience, Pass provides a helper method, Reportf, to report a new
diagnostic by formatting a string.
Diagnostic is defined as:

	type Diagnostic struct {
		Pos      token.Pos
		Category string // optional
		Message  string
	}

The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.

Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
raw text file, use the following sequence:

	content, err := ioutil.ReadFile(filename)
	if err != nil { ... }
	tf := fset.AddFile(filename, -1, len(content))
	tf.SetLinesForContent(content)
	...
	pass.Reportf(tf.LineStart(line), "oops")

Modular analysis with Facts

To improve efficiency and scalability, large programs are routinely
built using separate compilation: units of the program are compiled
separately, and recompiled only when one of their dependencies changes;
independent modules may be compiled in parallel. The same technique may
be applied to static analyses, for the same benefits. Such analyses are
described as "modular".

A compiler’s type checker is an example of a modular static analysis.
Many other checkers we would like to apply to Go programs can be
understood as alternative or non-standard type systems. For example,
vet's printf checker infers whether a function has the "printf wrapper"
type, and it applies stricter checks to calls of such functions. In
addition, it records which functions are printf wrappers for use by
later analysis units to identify other printf wrappers by induction.
A result such as “f is a printf wrapper” that is not interesting by
itself but serves as a stepping stone to an interesting result (such as
a diagnostic) is called a "fact".

The analysis API allows an analysis to define new types of facts, to
associate facts of these types with objects (named entities) declared
within the current package, or with the package as a whole, and to query
for an existing fact of a given type associated with an object or
package.

An Analyzer that uses facts must declare their types:

	var Analyzer = &analysis.Analyzer{
		Name:       "printf",
		FactTypes: []analysis.Fact{new(isWrapper)},
		...
	}

	type isWrapper struct{} // => *types.Func f “is a printf wrapper”

A driver program ensures that facts for a pass’s dependencies are
generated before analyzing the pass and are responsible for propagating
facts between from one pass to another, possibly across address spaces.
Consequently, Facts must be serializable. The API requires that drivers
use the gob encoding, an efficient, robust, self-describing binary
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
if the default encoding is unsuitable. Facts should be stateless.

The Pass type has functions to import and export facts,
associated either with an object or with a package:

	type Pass struct {
		...
		ExportObjectFact func(types.Object, Fact)
		ImportObjectFact func(types.Object, Fact) bool

		ExportPackageFact func(fact Fact)
		ImportPackageFact func(*types.Package, Fact) bool
	}

An Analyzer may only export facts associated with the current package or
its objects, though it may import facts from any package or object that
is an import dependency of the current package.

Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
retrieves the entry from this map and copies its value into the variable
pointed to by fact. This scheme assumes that the concrete type of fact
is a pointer; this assumption is checked by the Validate function.
See the "printf" analyzer for an example of object facts in action.

Some driver implementations (such as those based on Bazel and Blaze) do
not currently apply analyzers to packages of the standard library.
Therefore, for best results, analyzer authors should not rely on
analysis facts being available for standard packages.
For example, although the printf checker is capable of deducing during
analysis of the log package that log.Printf is a printf-wrapper,
this fact is built in to the analyzer so that it correctly checks
calls to log.Printf even when run in a driver that does not apply
it to standard packages. We plan to remove this limitation in future.

Testing an Analyzer

The analysistest subpackage provides utilities for testing an Analyzer.
In a few lines of code, it is possible to run an analyzer on a package
of testdata files and check that it reported all the expected
diagnostics and facts (and no more). Expectations are expressed using
"// want ..." comments in the input code.

Standalone commands

Analyzers are provided in the form of packages that a driver program is
expected to import. The vet command imports a set of several analyzers,
but users may wish to define their own analysis commands that perform
additional checks. To simplify the task of creating an analysis command,
either for a single analyzer or for a whole suite, we provide the
singlechecker and multichecker subpackages.

The singlechecker package provides the main function for a command that
runs one analyzer. By convention, each analyzer such as
go/passes/findcall should be accompanied by a singlechecker-based
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
entirety as:

	package main

	import (
		"golang.org/x/tools/go/analysis/passes/findcall"
		"golang.org/x/tools/go/analysis/singlechecker"
	)

	func main() { singlechecker.Main(findcall.Analyzer) }

A tool that provides multiple analyzers can use multichecker in a
similar way, giving it the list of Analyzers.

*/
package analysis
<commit_msg>go/analysis: copyedit doc.go<commit_after>/*

The analysis package defines the interface between a modular static
analysis and an analysis driver program.

Background

A static analysis is a function that inspects a package of Go code and
reports a set of diagnostics (typically mistakes in the code), and
perhaps produces other results as well, such as suggested refactorings
or other facts. An analysis that reports mistakes is informally called a
"checker". For example, the printf checker reports mistakes in
fmt.Printf format strings.

A "modular" analysis is one that inspects one package at a time but can
save information from a lower-level package and use it when inspecting a
higher-level package, analogous to separate compilation in a toolchain.
The printf checker is modular: when it discovers that a function such as
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
calls to that function too, including calls made from another package.

By implementing a common interface, checkers from a variety of sources
can be easily selected, incorporated, and reused in a wide range of
driver programs including command-line tools (such as vet), text editors and
IDEs, build and test systems (such as go build, Bazel, or Buck), test
frameworks, code review tools, code-base indexers (such as SourceGraph),
documentation viewers (such as godoc), batch pipelines for large code
bases, and so on.

Analyzer

The primary type in the API is Analyzer. An Analyzer statically
describes an analysis function: its name, documentation, flags,
relationship to other analyzers, and of course, its logic.

To define an analysis, a user declares a (logically constant) variable
of type Analyzer. Here is a typical example from one of the analyzers in
the go/analysis/passes/ subdirectory:

	package unusedresult

	var Analyzer = &analysis.Analyzer{
		Name:	"unusedresult",
		Doc:	"check for unused results of calls to some functions",
		Run:    run,
		...
	}

	func run(pass *analysis.Pass) (interface{}, error) {
		...
	}

An analysis driver is a program such as vet that runs a set of
analyses and prints the diagnostics that they report.
The driver program must import the list of Analyzers it needs.
Typically each Analyzer resides in a separate package.
To add a new Analyzer to an existing driver, add another item to the list:

	import ( "unusedresult"; "nilness"; "printf" )

	var analyses = []*analysis.Analyzer{
		unusedresult.Analyzer,
		nilness.Analyzer,
		printf.Analyzer,
	}

A driver may use the name, flags, and documentation to provide on-line
help that describes the analyses it performs.
The doc comment contains a brief one-line summary,
optionally followed by paragraphs of explanation.
The vet command, shown below, is an example of a driver that runs
multiple analyzers. It is based on the multichecker package
(see the "Standalone commands" section for details).

	$ go build golang.org/x/tools/go/analysis/cmd/vet
	$ ./vet help
	vet is a tool for static analysis of Go programs.

	Usage: vet [-flag] [package]

	Registered analyzers:

	    asmdecl      report mismatches between assembly files and Go declarations
	    assign       check for useless assignments
	    atomic       check for common mistakes using the sync/atomic package
	    ...
	    unusedresult check for unused results of calls to some functions

	$ ./vet help unusedresult
	unusedresult: check for unused results of calls to some functions

	Analyzer flags:

	  -unusedresult.funcs value
	        comma-separated list of functions whose results must be used (default Error,String)
	  -unusedresult.stringmethods value
	        comma-separated list of names of methods of type func() string whose results must be used

	Some functions like fmt.Errorf return a result and have no side effects,
	so it is always a mistake to discard the result. This analyzer reports
	calls to certain functions in which the result of the call is ignored.

	The set of functions may be controlled using flags.

The Analyzer type has more fields besides those shown above:

	type Analyzer struct {
		Name			string
		Doc			string
		Flags			flag.FlagSet
		Run			func(*Pass) (interface{}, error)
		RunDespiteErrors	bool
		ResultType		reflect.Type
		Requires		[]*Analyzer
		FactTypes		[]Fact
	}

The Flags field declares a set of named (global) flag variables that
control analysis behavior. Unlike vet, analysis flags are not declared
directly in the command line FlagSet; it is up to the driver to set the
flag variables. A driver for a single analysis, a, might expose its flag
f directly on the command line as -f, whereas a driver for multiple
analyses might prefix the flag name by the analysis name (-a.f) to avoid
ambiguity. An IDE might expose the flags through a graphical interface,
and a batch pipeline might configure them from a config file.
See the "findcall" analyzer for an example of flags in action.

The RunDespiteErrors flag indicates whether the analysis is equipped to
handle ill-typed code. If not, the driver will skip the analysis if
there were parse or type errors.
The optional ResultType field specifies the type of the result value
computed by this analysis and made available to other analyses.
The Requires field specifies a list of analyses upon which
this one depends and whose results it may access, and it constrains the
order in which a driver may run analyses.
The FactTypes field is discussed in the section on Modularity.
The analysis package provides a Validate function to perform basic
sanity checks on an Analyzer, such as that its Requires graph is
acyclic, its fact and result types are unique, and so on.

Finally, the Run field contains a function to be called by the driver to
execute the analysis on a single package. The driver passes it an
instance of the Pass type.

Pass

A Pass describes a single unit of work: the application of a particular
Analyzer to a particular package of Go code.
The Pass provides information to the Analyzer's Run function about the
package being analyzed, and provides operations to the Run function for
reporting diagnostics and other information back to the driver.

	type Pass struct {
		Fset   		*token.FileSet
		Files		[]*ast.File
		OtherFiles	[]string
		Pkg		*types.Package
		TypesInfo	*types.Info
		ResultOf	map[*Analyzer]interface{}
		Report		func(Diagnostic)
		...
	}

The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
type information, and source positions for a single package of Go code.

The OtherFiles field provides the names, but not the contents, of non-Go
files such as assembly that are part of this package. See the "asmdecl"
or "buildtags" analyzers for examples of loading non-Go files and reporting
diagnostics against them.

The ResultOf field provides the results computed by the analyzers
required by this one, as expressed in its Analyzer.Requires field. The
driver runs the required analyzers first and makes their results
available in this map. Each Analyzer must return a value of the type
described in its Analyzer.ResultType field.
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
provides a control-flow graph for each function in the package (see
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
enables other Analyzers to traverse the syntax trees of the package more
efficiently; and the "buildssa" analyzer constructs an SSA-form
intermediate representation.
Each of these Analyzers extends the capabilities of later Analyzers
without adding a dependency to the core API, so an analysis tool pays
only for the extensions it needs.

The Report function emits a diagnostic, a message associated with a
source position. For most analyses, diagnostics are their primary
result.
For convenience, Pass provides a helper method, Reportf, to report a new
diagnostic by formatting a string.
Diagnostic is defined as:

	type Diagnostic struct {
		Pos      token.Pos
		Category string // optional
		Message  string
	}

The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.

Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
raw text file, use the following sequence:

	content, err := ioutil.ReadFile(filename)
	if err != nil { ... }
	tf := fset.AddFile(filename, -1, len(content))
	tf.SetLinesForContent(content)
	...
	pass.Reportf(tf.LineStart(line), "oops")

Modular analysis with Facts

To improve efficiency and scalability, large programs are routinely
built using separate compilation: units of the program are compiled
separately, and recompiled only when one of their dependencies changes;
independent modules may be compiled in parallel. The same technique may
be applied to static analyses, for the same benefits. Such analyses are
described as "modular".

A compiler’s type checker is an example of a modular static analysis.
Many other checkers we would like to apply to Go programs can be
understood as alternative or non-standard type systems. For example,
vet's printf checker infers whether a function has the "printf wrapper"
type, and it applies stricter checks to calls of such functions. In
addition, it records which functions are printf wrappers for use by
later analysis passes to identify other printf wrappers by induction.
A result such as “f is a printf wrapper” that is not interesting by
itself but serves as a stepping stone to an interesting result (such as
a diagnostic) is called a "fact".

The analysis API allows an analysis to define new types of facts, to
associate facts of these types with objects (named entities) declared
within the current package, or with the package as a whole, and to query
for an existing fact of a given type associated with an object or
package.

An Analyzer that uses facts must declare their types:

	var Analyzer = &analysis.Analyzer{
		Name:       "printf",
		FactTypes: []analysis.Fact{new(isWrapper)},
		...
	}

	type isWrapper struct{} // => *types.Func f “is a printf wrapper”

The driver program ensures that facts for a pass’s dependencies are
generated before analyzing the package and is responsible for propagating
facts from one package to another, possibly across address spaces.
Consequently, Facts must be serializable. The API requires that drivers
use the gob encoding, an efficient, robust, self-describing binary
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
if the default encoding is unsuitable. Facts should be stateless.

The Pass type has functions to import and export facts,
associated either with an object or with a package:

	type Pass struct {
		...
		ExportObjectFact func(types.Object, Fact)
		ImportObjectFact func(types.Object, Fact) bool

		ExportPackageFact func(fact Fact)
		ImportPackageFact func(*types.Package, Fact) bool
	}

An Analyzer may only export facts associated with the current package or
its objects, though it may import facts from any package or object that
is an import dependency of the current package.

Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
retrieves the entry from this map and copies its value into the variable
pointed to by fact. This scheme assumes that the concrete type of fact
is a pointer; this assumption is checked by the Validate function.
See the "printf" analyzer for an example of object facts in action.

Some driver implementations (such as those based on Bazel and Blaze) do
not currently apply analyzers to packages of the standard library.
Therefore, for best results, analyzer authors should not rely on
analysis facts being available for standard packages.
For example, although the printf checker is capable of deducing during
analysis of the log package that log.Printf is a printf wrapper,
this fact is built in to the analyzer so that it correctly checks
calls to log.Printf even when run in a driver that does not apply
it to standard packages. We would like to remove this limitation in future.

Testing an Analyzer

The analysistest subpackage provides utilities for testing an Analyzer.
In a few lines of code, it is possible to run an analyzer on a package
of testdata files and check that it reported all the expected
diagnostics and facts (and no more). Expectations are expressed using
"// want ..." comments in the input code.

Standalone commands

Analyzers are provided in the form of packages that a driver program is
expected to import. The vet command imports a set of several analyzers,
but users may wish to define their own analysis commands that perform
additional checks. To simplify the task of creating an analysis command,
either for a single analyzer or for a whole suite, we provide the
singlechecker and multichecker subpackages.

The singlechecker package provides the main function for a command that
runs one analyzer. By convention, each analyzer such as
go/passes/findcall should be accompanied by a singlechecker-based
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
entirety as:

	package main

	import (
		"golang.org/x/tools/go/analysis/passes/findcall"
		"golang.org/x/tools/go/analysis/singlechecker"
	)

	func main() { singlechecker.Main(findcall.Analyzer) }

A tool that provides multiple analyzers can use multichecker in a
similar way, giving it the list of Analyzers.

*/
package analysis
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-telegram-bot-api/telegram-bot-api"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

var store = make(map[string]map[string]float64)

func InitBot(token string) (*tgbotapi.BotAPI, error) {
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		return nil, err
	}

	//bot.Debug = true
	log.Println("Account: ", bot.Self.UserName)

	return bot, nil
}

func InitWebHook(bot *tgbotapi.BotAPI, config Config) (tgbotapi.UpdatesChannel, error) {
	URL, err := url.Parse(config.Url)
	if err != nil {
		return nil, err
	}

	bot.SetWebhook(tgbotapi.WebhookConfig{URL: URL})

	updates := bot.ListenForWebhook(URL.Path)

	go http.ListenAndServe("localhost:"+config.Port, nil)
	if err != nil {
		return nil, err
	}

	return updates, nil
}

func ProcessUpdates(updates tgbotapi.UpdatesChannel, bot *tgbotapi.BotAPI) {

	for update := range updates {
		if update.Message == nil {
			continue
		}

		text := update.Message.Text
		parsedText := strings.Fields(text)
		var response string
		var money float64
		var err error
		var category string

		account := strconv.FormatInt(int64(update.Message.From.ID), 10)
		if len(parsedText) > 3 {
			money, err = strconv.ParseFloat(parsedText[1], 64)
			if err != nil {
				log.Println("[ERROR]: ", err)
			}

			category = parsedText[2]
		} else {
			money = 0
			category = "default"
		}

		switch true {
		case strings.Contains(text, "/start"):
			response = startMessage()
		case strings.HasPrefix(text, "+"):
			response = addMoney(money, account, category)
		case strings.HasPrefix(text, "-"):
			response = "removing money"
		case strings.Contains(text, "/status"):
			response = "getting status"
		default:
			response = "i don't get what you want from me."
		}
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, response)
		msg.ReplyToMessageID = update.Message.MessageID

		bot.Send(msg)
	}
}

func startMessage() string {
	return `This is check wallet bot, usage:
		   + <money> <category(optional)> - add money to wallet
		   - <money> <category(optional)> - remove money from wallet`
}

func addMoney(money float64, account, category string) string {
	val, ok := store[account]
	if !ok {
		log.Println("store value: ", val)
		store[account] = make(map[string]float64)
		log.Println("store value: ", val)
	}
	log.Println("category", category)
	return "add: " + strconv.FormatFloat(money, 'f', -1, 64)
}
<commit_msg>add remove operation and status<commit_after>package main

import (
	"github.com/go-telegram-bot-api/telegram-bot-api"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

var store = make(map[string]map[string]float64)

func InitBot(token string) (*tgbotapi.BotAPI, error) {
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		return nil, err
	}

	log.Println("Account: ", bot.Self.UserName)

	return bot, nil
}

func InitWebHook(bot *tgbotapi.BotAPI, config Config) (tgbotapi.UpdatesChannel, error) {
	URL, err := url.Parse(config.Url)
	if err != nil {
		return nil, err
	}

	bot.SetWebhook(tgbotapi.WebhookConfig{URL: URL})

	updates := bot.ListenForWebhook(URL.Path)

	go http.ListenAndServe("localhost:"+config.Port, nil)
	if err != nil {
		return nil, err
	}

	return updates, nil
}

func ProcessUpdates(updates tgbotapi.UpdatesChannel, bot *tgbotapi.BotAPI) {

	for update := range updates {
		if update.Message == nil {
			continue
		}

		text := update.Message.Text
		parsedText := strings.Fields(text)
		var response string
		var money float64
		var err error
		var category string

		account := strconv.FormatInt(int64(update.Message.From.ID), 10)
		if len(parsedText) > 3 {
			money, err = strconv.ParseFloat(parsedText[1], 64)
			if err != nil {
				log.Println("[ERROR]: ", err)
			}

			category = parsedText[2]
		} else {
			money = 0
			category = "default"
		}

		switch {
		case strings.Contains(text, "/start"):
			response = startMessage()
		case strings.HasPrefix(text, "+"):
			response = addMoney(money, account, category)
		case strings.HasPrefix(text, "-"):
			response = removeMoney(money, account, category)
		case strings.Contains(text, "/status"):
			response = getStatus(account)
		default:
			response = "i don't get what you want from me."
		}

		msg := tgbotapi.NewMessage(update.Message.Chat.ID, response)
		msg.ReplyToMessageID = update.Message.MessageID

		bot.Send(msg)
	}
}

func startMessage() string {
	return `This is check wallet bot, usage:
		   + <money> <category(optional)> - add money to wallet
		   - <money> <category(optional)> - remove money from wallet`
}

func addMoney(money float64, account, category string) string {
	_, ok := store[account]
	if !ok {
		store[account] = make(map[string]float64)
	}

	store[account][category] += money

	return "add: " + strconv.FormatFloat(money, 'f', -1, 64)
}

func removeMoney(money float64, account, category string) string {
	_, ok := store[account]
	if !ok {
		store[account] = make(map[string]float64)
	}

	store[account][category] -= money

	return "remove: " + strconv.FormatFloat(money, 'f', -1, 64)
}

func getStatus(account string) string {
	_, ok := store[account]
	if !ok {
		store[account] = make(map[string]float64)
	}
	var sum float64
	for _, val := range store[account] {
		sum += val
	}

	return "wallet: " + strconv.FormatFloat(sum, 'f', -1, 64)
}<|endoftext|>


<commit_before>// run

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This used to crash because the scheduler
// tried to kick off a new scheduling thread for f
// when time.Nanoseconds went into the system call.
// It's not okay to schedule new goroutines
// until main has started.

package main

import "time"

func f() {
}

func init() {
	go f()
	time.Now()
}

func main() {
}
<commit_msg>test/initsyscall.go: delete It's testing an old property of the language and is no longer relevant.<commit_after><|endoftext|>


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

// This is the main login engine.

package engine

import (
	"errors"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
)

var errNoConfig = errors.New("No user config available")
var errNoDevice = errors.New("No device provisioned locally for this user")

// Login is an engine.
type Login struct {
	libkb.Contextified
	deviceType string
	username   string
	clientType keybase1.ClientType
}

// NewLogin creates a Login engine.  username is optional.
// deviceType should be libkb.DeviceTypeDesktop or
// libkb.DeviceTypeMobile.
func NewLogin(g *libkb.GlobalContext, deviceType string, username string, ct keybase1.ClientType) *Login {
	return &Login{
		Contextified: libkb.NewContextified(g),
		deviceType:   deviceType,
		username:     username,
		clientType:   ct,
	}
}

// Name is the unique engine name.
func (e *Login) Name() string {
	return "Login"
}

// GetPrereqs returns the engine prereqs.
func (e *Login) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *Login) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *Login) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&LoginCurrentDevice{},
		&LoginProvision{},
	}
}

// Run starts the engine.
func (e *Login) Run(ctx *Context) error {

	sendNotification := func() {
		e.G().NotifyRouter.HandleLogin(string(e.G().Env.GetUsername()))
	}

	// First see if this device is already provisioned and it is possible to log in.
	// Note that if e.username is an email address, this will always fail, which it
	// should.
	eng := NewLoginCurrentDevice(e.G(), e.username)
	err := RunEngine(eng, ctx)
	if err == nil {
		// login successful
		e.G().Log.Debug("LoginCurrentDevice.Run() was successful")
		sendNotification()
		return nil
	}

	// if this device has been provisioned already and there was an error, then
	// return that error.  Otherwise, ignore it and keep going.
	if !e.notProvisionedErr(err) {
		return err
	}

	e.G().Log.Debug("LoginCurrentDevice error: %s (continuing with device provisioning...)", err)

	// this device needs to be provisioned

	// clear out any existing session:
	e.G().Logout()

	// transaction around config file
	tx, err := e.G().Env.GetConfigWriter().BeginTransaction()
	if err != nil {
		return err
	}

	// From this point on, if there's an error, we abort the
	// transaction.
	defer func() {
		if tx != nil {
			tx.Abort()
		}
	}()

	// run the username engine to load a user
	ueng := NewLoginUsername(e.G(), e.username)
	if err = RunEngine(ueng, ctx); err != nil {
		return err
	}

	darg := &LoginProvisionArg{
		DeviceType: e.deviceType,
		ClientType: e.clientType,
		User:       ueng.User(),
	}
	deng := NewLoginProvision(e.G(), darg)
	if err = RunEngine(deng, ctx); err != nil {
		return err
	}

	// commit the config changes
	if err := tx.Commit(); err != nil {
		return err
	}

	// Zero out the TX so that we don't abort it in the defer()
	// exit.
	tx = nil

	sendNotification()
	return nil
}

// notProvisionedErr will return true if err signifies that login
// failed because this device has not yet been provisioned.
func (e *Login) notProvisionedErr(err error) bool {
	if err == errNoDevice {
		return true
	}
	if err == errNoConfig {
		return true
	}

	e.G().Log.Debug("notProvisioned, not handling error %s (err type: %T)", err, err)

	return false
}
<commit_msg>Bypass LoginCurrentDevice if usernameOrEmail is email<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// This is the main login engine.

package engine

import (
	"errors"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
)

var errNoConfig = errors.New("No user config available")
var errNoDevice = errors.New("No device provisioned locally for this user")

// Login is an engine.
type Login struct {
	libkb.Contextified
	deviceType      string
	usernameOrEmail string
	clientType      keybase1.ClientType
}

// NewLogin creates a Login engine.  username is optional.
// deviceType should be libkb.DeviceTypeDesktop or
// libkb.DeviceTypeMobile.
func NewLogin(g *libkb.GlobalContext, deviceType string, usernameOrEmail string, ct keybase1.ClientType) *Login {
	return &Login{
		Contextified:    libkb.NewContextified(g),
		deviceType:      deviceType,
		usernameOrEmail: usernameOrEmail,
		clientType:      ct,
	}
}

// Name is the unique engine name.
func (e *Login) Name() string {
	return "Login"
}

// GetPrereqs returns the engine prereqs.
func (e *Login) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *Login) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *Login) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&LoginCurrentDevice{},
		&LoginProvision{},
	}
}

// Run starts the engine.
func (e *Login) Run(ctx *Context) error {
	if len(e.usernameOrEmail) > 0 && libkb.CheckEmail.F(e.usernameOrEmail) {
		// If e.usernameOrEmail is provided and it is an email address, then
		// LoginCurrentDevice is pointless.  It would return an error,
		// but might as well not even use it.
		e.G().Log.Debug("skipping LoginCurrentDevice since %q provided to Login, which looks like an email address.", e.usernameOrEmail)
	} else {
		// First see if this device is already provisioned and it is possible to log in.
		eng := NewLoginCurrentDevice(e.G(), e.usernameOrEmail)
		err := RunEngine(eng, ctx)
		if err == nil {
			// login successful
			e.G().Log.Debug("LoginCurrentDevice.Run() was successful")
			e.sendNotification()
			return nil
		}

		// if this device has been provisioned already and there was an error, then
		// return that error.  Otherwise, ignore it and keep going.
		if !e.notProvisionedErr(err) {
			return err
		}

		e.G().Log.Debug("LoginCurrentDevice error: %s (continuing with device provisioning...)", err)
	}

	e.G().Log.Debug("attempting device provisioning")

	// clear out any existing session:
	e.G().Logout()

	// transaction around config file
	tx, err := e.G().Env.GetConfigWriter().BeginTransaction()
	if err != nil {
		return err
	}

	// From this point on, if there's an error, we abort the
	// transaction.
	defer func() {
		if tx != nil {
			tx.Abort()
		}
	}()

	// run the username engine to load a user
	ueng := NewLoginUsername(e.G(), e.usernameOrEmail)
	if err = RunEngine(ueng, ctx); err != nil {
		return err
	}

	darg := &LoginProvisionArg{
		DeviceType: e.deviceType,
		ClientType: e.clientType,
		User:       ueng.User(),
	}
	deng := NewLoginProvision(e.G(), darg)
	if err = RunEngine(deng, ctx); err != nil {
		return err
	}

	// commit the config changes
	if err := tx.Commit(); err != nil {
		return err
	}

	// Zero out the TX so that we don't abort it in the defer()
	// exit.
	tx = nil

	e.sendNotification()
	return nil
}

// notProvisionedErr will return true if err signifies that login
// failed because this device has not yet been provisioned.
func (e *Login) notProvisionedErr(err error) bool {
	if err == errNoDevice {
		return true
	}
	if err == errNoConfig {
		return true
	}

	e.G().Log.Debug("notProvisioned, not handling error %s (err type: %T)", err, err)

	return false
}

func (e *Login) sendNotification() {
	e.G().NotifyRouter.HandleLogin(string(e.G().Env.GetUsername()))
}
<|endoftext|>


<commit_before>// Copyright 2013 beego authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

// Package i18n is for app Internationalization and Localization.
package i18n

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/Unknwon/goconfig"
)

var (
	locales = &localeStore{store: make(map[string]*locale)}
)

type locale struct {
	id      int
	lang    string
	message *goconfig.ConfigFile
}

type localeStore struct {
	langs []string
	store map[string]*locale
}

// Get locale from localeStore use specify lang string
func (d *localeStore) getLocale(lang string) (*locale, bool) {
	for _, l := range d.store {
		if l.lang == lang {
			return l, true
		}
	}
	return nil, false
}

// Get target language string
func (d *localeStore) Get(lang, section, format string) (string, bool) {
	if locale, ok := d.getLocale(lang); ok {
		if section == "" {
			section = goconfig.DEFAULT_SECTION
		}
		value, err := locale.message.GetValue(section, format)
		if err == nil {
			return value, true
		}
	}
	return "", false
}

func (d *localeStore) Add(lc *locale) bool {
	if _, ok := d.store[lc.lang]; ok {
		return false
	}
	lc.id = len(d.langs)
	d.langs = append(d.langs, lc.lang)
	d.store[lc.lang] = lc
	return true
}

func (d *localeStore) Reload(langs ...string) error {
	if len(langs) == 0 {
		for _, lc := range d.store {
			err := lc.message.Reload()
			if err != nil {
				return err
			}
		}
	} else {
		for _, lang := range langs {
			if lc, ok := d.getLocale(lang); ok {
				err := lc.message.Reload()
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// Reload locales
func ReloadLangs(langs ...string) error {
	return locales.Reload(langs...)
}

// List all locale languages
func ListLangs() []string {
	langs := make([]string, len(locales.langs))
	copy(langs, locales.langs)
	return langs
}

// Check language name if exist
func IsExist(lang string) bool {
	_, ok := locales.store[lang]
	return ok
}

// Check language name if exist
func IndexLang(lang string) int {
	if lc, ok := locales.store[lang]; ok {
		return lc.id
	}
	return -1
}

// Get language by index id
func GetLangByIndex(index int) string {
	if index < 0 || index >= len(locales.langs) {
		return ""
	}
	return locales.langs[index]
}

// SetMessage sets the message file for localization.
func SetMessage(lang, filePath string) error {
	message, err := goconfig.LoadConfigFile(filePath)
	if err == nil {
		message.BlockMode = false
		lc := new(locale)
		lc.lang = lang
		lc.message = message
		if locales.Add(lc) == false {
			return fmt.Errorf("Lang %s alread exist", lang)
		}
	}
	return err
}

// A Locale describles the information of localization.
type Locale struct {
	Lang string
}

// Tr translate content to target language.
func (l Locale) Tr(format string, args ...interface{}) string {
	return Tr(l.Lang, format, args...)
}

// Index get lang index of LangStore
func (l Locale) Index() int {
	return IndexLang(l.Lang)
}

// Tr translate content to target language.
func Tr(lang, format string, args ...interface{}) string {
	var section string
	parts := strings.SplitN(format, ".", 2)
	if len(parts) == 2 {
		section = parts[0]
		format = parts[1]
	}

	value, ok := locales.Get(lang, section, format)
	if ok {
		format = value
	}

	if len(args) > 0 {
		params := make([]interface{}, 0, len(args))
		for _, arg := range args {
			if arg != nil {
				val := reflect.ValueOf(arg)
				if val.Kind() == reflect.Slice {
					for i := 0; i < val.Len(); i++ {
						params = append(params, val.Index(i).Interface())
					}
				} else {
					params = append(params, arg)
				}
			}
		}
		return fmt.Sprintf(format, params...)
	}
	return fmt.Sprintf(format)
}
<commit_msg>support more locale files in one lang<commit_after>// Copyright 2013 beego authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

// Package i18n is for app Internationalization and Localization.
package i18n

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/Unknwon/goconfig"
)

var (
	locales = &localeStore{store: make(map[string]*locale)}
)

type locale struct {
	id      int
	lang    string
	message *goconfig.ConfigFile
}

type localeStore struct {
	langs []string
	store map[string]*locale
}

// Get locale from localeStore use specify lang string
func (d *localeStore) getLocale(lang string) (*locale, bool) {
	for _, l := range d.store {
		if l.lang == lang {
			return l, true
		}
	}
	return nil, false
}

// Get target language string
func (d *localeStore) Get(lang, section, format string) (string, bool) {
	if locale, ok := d.getLocale(lang); ok {
		if section == "" {
			section = goconfig.DEFAULT_SECTION
		}
		value, err := locale.message.GetValue(section, format)
		if err == nil {
			return value, true
		}
	}
	return "", false
}

func (d *localeStore) Add(lc *locale) bool {
	if _, ok := d.store[lc.lang]; ok {
		return false
	}
	lc.id = len(d.langs)
	d.langs = append(d.langs, lc.lang)
	d.store[lc.lang] = lc
	return true
}

func (d *localeStore) Reload(langs ...string) error {
	if len(langs) == 0 {
		for _, lc := range d.store {
			err := lc.message.Reload()
			if err != nil {
				return err
			}
		}
	} else {
		for _, lang := range langs {
			if lc, ok := d.getLocale(lang); ok {
				err := lc.message.Reload()
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// Reload locales
func ReloadLangs(langs ...string) error {
	return locales.Reload(langs...)
}

// List all locale languages
func ListLangs() []string {
	langs := make([]string, len(locales.langs))
	copy(langs, locales.langs)
	return langs
}

// Check language name if exist
func IsExist(lang string) bool {
	_, ok := locales.store[lang]
	return ok
}

// Check language name if exist
func IndexLang(lang string) int {
	if lc, ok := locales.store[lang]; ok {
		return lc.id
	}
	return -1
}

// Get language by index id
func GetLangByIndex(index int) string {
	if index < 0 || index >= len(locales.langs) {
		return ""
	}
	return locales.langs[index]
}

// SetMessage sets the message file for localization.
func SetMessage(lang, filePath string, appendFiles ...string) error {
	message, err := goconfig.LoadConfigFile(filePath, appendFiles...)
	if err == nil {
		message.BlockMode = false
		lc := new(locale)
		lc.lang = lang
		lc.message = message
		if locales.Add(lc) == false {
			return fmt.Errorf("Lang %s alread exist", lang)
		}
	}
	return err
}

// A Locale describles the information of localization.
type Locale struct {
	Lang string
}

// Tr translate content to target language.
func (l Locale) Tr(format string, args ...interface{}) string {
	return Tr(l.Lang, format, args...)
}

// Index get lang index of LangStore
func (l Locale) Index() int {
	return IndexLang(l.Lang)
}

// Tr translate content to target language.
func Tr(lang, format string, args ...interface{}) string {
	var section string
	parts := strings.SplitN(format, ".", 2)
	if len(parts) == 2 {
		section = parts[0]
		format = parts[1]
	}

	value, ok := locales.Get(lang, section, format)
	if ok {
		format = value
	}

	if len(args) > 0 {
		params := make([]interface{}, 0, len(args))
		for _, arg := range args {
			if arg != nil {
				val := reflect.ValueOf(arg)
				if val.Kind() == reflect.Slice {
					for i := 0; i < val.Len(); i++ {
						params = append(params, val.Index(i).Interface())
					}
				} else {
					params = append(params, arg)
				}
			}
		}
		return fmt.Sprintf(format, params...)
	}
	return fmt.Sprintf(format)
}
<|endoftext|>


<commit_before>package qset

import (
	"errors"
	"strconv"
	"sync"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/kavehmz/crdt"
)

/*QSet is a race free implementation of what LWW can use as udnerlying set.
This implementation uses redis ZSET.
ZSET in redis uses scores to sort the elements. Score is a IEEE 754 floating point number,
that is able to represent precisely integer numbers between -(2^53) and +(2^53) included.
That is between -9007199254740992 and 9007199254740992.
This will limit this sets precision to save element's action timestamp to 1 milli-seconds.
Notice that time.Time precision is 1 nano-seconds by defaults. For this lack of precision all
timestamps are rounded to nearest microsecond.
Using redis can also cause latency cause by network or socket communication.
*/
type QSet struct {
	// Conn is the redis connection to be used.
	Conn redis.Conn
	// AddSet sets which key will be used in redis for the set.
	SetKey string
	// Marshal function needs to convert the lww.Element to string. Redis can only store and retrieve string values.
	Marshal func(lww.Element) string
	// UnMarshal function needs to be able to convert a Marshalled string back to a readable structure for consumer of library.
	UnMarshal func(string) lww.Element
	// LastState is an error type that will return the error state of last executed redis command. Add redis connection are not shareable this can be used after each command to know the last state.
	LastState error

	set lww.Set
	sync.RWMutex
}

type setData struct {
	element lww.Element
	ts      time.Time
}

func roundToMicro(t time.Time) int64 {
	return t.Round(time.Microsecond).UnixNano() / 1000
}

func (s *QSet) checkErr(err error) {
	if err != nil {
		s.LastState = err
		return
	}
	s.LastState = nil
}

//Init will do a one time setup for underlying set. It will be called from WLL.Init
func (s *QSet) Init() {
	if s.Conn == nil {
		s.checkErr(errors.New("Conn must be set"))
		return
	}
	if s.Marshal == nil {
		s.checkErr(errors.New("Marshal must be set"))
		return
	}
	if s.UnMarshal == nil {
		s.checkErr(errors.New("UnMarshal must be set"))
		return
	}
	if s.SetKey == "" {
		s.checkErr(errors.New("SetKey must be set"))
		return
	}
	_, err := s.Conn.Do("DEL", s.SetKey)
	s.checkErr(err)

	s.set.Init()
	s.readMembers()
}

func (s *QSet) readMembers() {
	zs, err := redis.Strings(s.Conn.Do("ZRANGE", s.SetKey, 0, -1, "WITHSCORES"))
	s.checkErr(err)
	for i := 0; i < len(zs); i += 2 {
		n, _ := strconv.Atoi(zs[i+1])
		s.set.Set(zs[i], time.Unix(0, 0).Add(time.Duration(n)*time.Microsecond))
	}
}

//Set adds an element to the set if it does not exists. It it exists Set will update the provided timestamp.
func (s *QSet) Set(e lww.Element, t time.Time) {
	s.set.Set(s.Marshal(e), t.Round(time.Microsecond))

	go func() {
		s.Lock()
		defer s.Unlock()
		_, err := s.Conn.Do("ZADD", s.SetKey, roundToMicro(t), s.Marshal(e))
		s.checkErr(err)
	}()
}

//Len must return the number of members in the set
func (s *QSet) Len() int {
	return s.set.Len()
}

//Get returns timestmap of the element in the set if it exists and true. Otherwise it will return an empty timestamp and false.
func (s *QSet) Get(e lww.Element) (time.Time, bool) {
	return s.set.Get(e)
}

//List returns list of all elements in the set
func (s *QSet) List() []lww.Element {
	var l []lww.Element
	for _, v := range s.set.List() {

		l = append(l, s.UnMarshal(v.(string)))
	}
	return l
}
<commit_msg>Better documentation for the struct<commit_after>package qset

import (
	"errors"
	"strconv"
	"sync"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/kavehmz/crdt"
)

/*QSet a implementation of TimedSet for LWW that used Redis as its persistence later but Maps for operations.
This mix will make it about 100 times faster than original RedisSet.
This implementatin will have more memory foot print handle some operation in a non-blocking way.

Init function will initialize the internal map from redis. Also it will subscribe to a channel with the same name as SetKey to get the new changes and it will apply them to the map.
*/
type QSet struct {
	// Conn is the redis connection to be used.
	Conn redis.Conn
	// SetSet sets which key will be used in redis for the set.
	SetKey string
	// Marshal function needs to convert the lww.Element to string. Redis can only store and retrieve string values.
	Marshal func(lww.Element) string
	// UnMarshal function needs to be able to convert a Marshalled string back to a readable structure for consumer of library.
	UnMarshal func(string) lww.Element
	// LastState is an error type that will return the error state of last executed redis command. Add redis connection are not shareable this can be used after each command to know the last state.
	LastState error

	set lww.Set
	sync.RWMutex
}

type setData struct {
	element lww.Element
	ts      time.Time
}

func roundToMicro(t time.Time) int64 {
	return t.Round(time.Microsecond).UnixNano() / 1000
}

func (s *QSet) checkErr(err error) {
	if err != nil {
		s.LastState = err
		return
	}
	s.LastState = nil
}

//Init will do a one time setup for underlying set. It will be called from WLL.Init
func (s *QSet) Init() {
	if s.Conn == nil {
		s.checkErr(errors.New("Conn must be set"))
		return
	}
	if s.Marshal == nil {
		s.checkErr(errors.New("Marshal must be set"))
		return
	}
	if s.UnMarshal == nil {
		s.checkErr(errors.New("UnMarshal must be set"))
		return
	}
	if s.SetKey == "" {
		s.checkErr(errors.New("SetKey must be set"))
		return
	}
	_, err := s.Conn.Do("DEL", s.SetKey)
	s.checkErr(err)

	s.set.Init()
	s.readMembers()
}

func (s *QSet) readMembers() {
	zs, err := redis.Strings(s.Conn.Do("ZRANGE", s.SetKey, 0, -1, "WITHSCORES"))
	s.checkErr(err)
	for i := 0; i < len(zs); i += 2 {
		n, _ := strconv.Atoi(zs[i+1])
		s.set.Set(zs[i], time.Unix(0, 0).Add(time.Duration(n)*time.Microsecond))
	}
}

//Set adds an element to the set if it does not exists. It it exists Set will update the provided timestamp.
func (s *QSet) Set(e lww.Element, t time.Time) {
	s.set.Set(s.Marshal(e), t.Round(time.Microsecond))

	go func() {
		s.Lock()
		defer s.Unlock()
		_, err := s.Conn.Do("ZADD", s.SetKey, roundToMicro(t), s.Marshal(e))
		s.checkErr(err)
	}()
}

//Len must return the number of members in the set
func (s *QSet) Len() int {
	return s.set.Len()
}

//Get returns timestmap of the element in the set if it exists and true. Otherwise it will return an empty timestamp and false.
func (s *QSet) Get(e lww.Element) (time.Time, bool) {
	return s.set.Get(e)
}

//List returns list of all elements in the set
func (s *QSet) List() []lww.Element {
	var l []lww.Element
	for _, v := range s.set.List() {

		l = append(l, s.UnMarshal(v.(string)))
	}
	return l
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/configservice"
)

func resourceAwsConfigDeliveryChannel() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsConfigDeliveryChannelPut,
		Read:   resourceAwsConfigDeliveryChannelRead,
		Update: resourceAwsConfigDeliveryChannelPut,
		Delete: resourceAwsConfigDeliveryChannelDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:         schema.TypeString,
				Optional:     true,
				ForceNew:     true,
				Default:      "default",
				ValidateFunc: validateMaxLength(256),
			},
			"s3_bucket_name": {
				Type:     schema.TypeString,
				Required: true,
			},
			"s3_key_prefix": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"sns_topic_arn": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validateArn,
			},
			"snapshot_delivery_properties": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"delivery_frequency": {
							Type:         schema.TypeString,
							Optional:     true,
							ValidateFunc: validateConfigExecutionFrequency,
						},
					},
				},
			},
		},
	}
}

func resourceAwsConfigDeliveryChannelPut(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).configconn

	name := d.Get("name").(string)
	channel := configservice.DeliveryChannel{
		Name:         aws.String(name),
		S3BucketName: aws.String(d.Get("s3_bucket_name").(string)),
	}

	if v, ok := d.GetOk("s3_key_prefix"); ok {
		channel.S3KeyPrefix = aws.String(v.(string))
	}
	if v, ok := d.GetOk("sns_topic_arn"); ok {
		channel.SnsTopicARN = aws.String(v.(string))
	}

	if p, ok := d.GetOk("snapshot_delivery_properties"); ok {
		propertiesBlocks := p.([]interface{})
		block := propertiesBlocks[0].(map[string]interface{})

		if v, ok := block["delivery_frequency"]; ok {
			channel.ConfigSnapshotDeliveryProperties = &configservice.ConfigSnapshotDeliveryProperties{
				DeliveryFrequency: aws.String(v.(string)),
			}
		}
	}

	input := configservice.PutDeliveryChannelInput{DeliveryChannel: &channel}

	err := resource.Retry(2*time.Minute, func() *resource.RetryError {
		_, err := conn.PutDeliveryChannel(&input)
		if err == nil {
			return nil
		}

		awsErr, ok := err.(awserr.Error)
		if ok && awsErr.Code() == "InsufficientDeliveryPolicyException" {
			return resource.RetryableError(err)
		}

		return resource.NonRetryableError(err)
	})
	if err != nil {
		return fmt.Errorf("Creating Delivery Channel failed: %s", err)
	}

	d.SetId(name)

	return resourceAwsConfigDeliveryChannelRead(d, meta)
}

func resourceAwsConfigDeliveryChannelRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).configconn

	input := configservice.DescribeDeliveryChannelsInput{
		DeliveryChannelNames: []*string{aws.String(d.Id())},
	}
	out, err := conn.DescribeDeliveryChannels(&input)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "NoSuchDeliveryChannelException" {
				log.Printf("[WARN] Delivery Channel %q is gone (NoSuchDeliveryChannelException)", d.Id())
				d.SetId("")
				return nil
			}
		}
		return fmt.Errorf("Getting Delivery Channel failed: %s", err)
	}

	if len(out.DeliveryChannels) < 1 {
		log.Printf("[WARN] Delivery Channel %q is gone (no channels found)", d.Id())
		d.SetId("")
		return nil
	}

	if len(out.DeliveryChannels) > 1 {
		return fmt.Errorf("Received %d delivery channels under %s (expected exactly 1): %s",
			len(out.DeliveryChannels), d.Id(), out.DeliveryChannels)
	}

	channel := out.DeliveryChannels[0]

	d.Set("name", channel.Name)
	d.Set("s3_bucket_name", channel.S3BucketName)
	d.Set("s3_key_prefix", channel.S3KeyPrefix)
	d.Set("sns_topic_arn", channel.SnsTopicARN)

	if channel.ConfigSnapshotDeliveryProperties != nil {
		d.Set("snapshot_delivery_properties", flattenConfigSnapshotDeliveryProperties(channel.ConfigSnapshotDeliveryProperties))
	}

	return nil
}

func resourceAwsConfigDeliveryChannelDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).configconn
	input := configservice.DeleteDeliveryChannelInput{
		DeliveryChannelName: aws.String(d.Id()),
	}
	_, err := conn.DeleteDeliveryChannel(&input)
	if err != nil {
		return fmt.Errorf("Unable to delete delivery channel: %s", err)
	}

	d.SetId("")
	return nil
}
<commit_msg>resource/aws_config_delivery_channel: Retry deletion<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/configservice"
)

func resourceAwsConfigDeliveryChannel() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsConfigDeliveryChannelPut,
		Read:   resourceAwsConfigDeliveryChannelRead,
		Update: resourceAwsConfigDeliveryChannelPut,
		Delete: resourceAwsConfigDeliveryChannelDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:         schema.TypeString,
				Optional:     true,
				ForceNew:     true,
				Default:      "default",
				ValidateFunc: validateMaxLength(256),
			},
			"s3_bucket_name": {
				Type:     schema.TypeString,
				Required: true,
			},
			"s3_key_prefix": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"sns_topic_arn": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validateArn,
			},
			"snapshot_delivery_properties": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"delivery_frequency": {
							Type:         schema.TypeString,
							Optional:     true,
							ValidateFunc: validateConfigExecutionFrequency,
						},
					},
				},
			},
		},
	}
}

func resourceAwsConfigDeliveryChannelPut(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).configconn

	name := d.Get("name").(string)
	channel := configservice.DeliveryChannel{
		Name:         aws.String(name),
		S3BucketName: aws.String(d.Get("s3_bucket_name").(string)),
	}

	if v, ok := d.GetOk("s3_key_prefix"); ok {
		channel.S3KeyPrefix = aws.String(v.(string))
	}
	if v, ok := d.GetOk("sns_topic_arn"); ok {
		channel.SnsTopicARN = aws.String(v.(string))
	}

	if p, ok := d.GetOk("snapshot_delivery_properties"); ok {
		propertiesBlocks := p.([]interface{})
		block := propertiesBlocks[0].(map[string]interface{})

		if v, ok := block["delivery_frequency"]; ok {
			channel.ConfigSnapshotDeliveryProperties = &configservice.ConfigSnapshotDeliveryProperties{
				DeliveryFrequency: aws.String(v.(string)),
			}
		}
	}

	input := configservice.PutDeliveryChannelInput{DeliveryChannel: &channel}

	err := resource.Retry(2*time.Minute, func() *resource.RetryError {
		_, err := conn.PutDeliveryChannel(&input)
		if err == nil {
			return nil
		}

		awsErr, ok := err.(awserr.Error)
		if ok && awsErr.Code() == "InsufficientDeliveryPolicyException" {
			return resource.RetryableError(err)
		}

		return resource.NonRetryableError(err)
	})
	if err != nil {
		return fmt.Errorf("Creating Delivery Channel failed: %s", err)
	}

	d.SetId(name)

	return resourceAwsConfigDeliveryChannelRead(d, meta)
}

func resourceAwsConfigDeliveryChannelRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).configconn

	input := configservice.DescribeDeliveryChannelsInput{
		DeliveryChannelNames: []*string{aws.String(d.Id())},
	}
	out, err := conn.DescribeDeliveryChannels(&input)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "NoSuchDeliveryChannelException" {
				log.Printf("[WARN] Delivery Channel %q is gone (NoSuchDeliveryChannelException)", d.Id())
				d.SetId("")
				return nil
			}
		}
		return fmt.Errorf("Getting Delivery Channel failed: %s", err)
	}

	if len(out.DeliveryChannels) < 1 {
		log.Printf("[WARN] Delivery Channel %q is gone (no channels found)", d.Id())
		d.SetId("")
		return nil
	}

	if len(out.DeliveryChannels) > 1 {
		return fmt.Errorf("Received %d delivery channels under %s (expected exactly 1): %s",
			len(out.DeliveryChannels), d.Id(), out.DeliveryChannels)
	}

	channel := out.DeliveryChannels[0]

	d.Set("name", channel.Name)
	d.Set("s3_bucket_name", channel.S3BucketName)
	d.Set("s3_key_prefix", channel.S3KeyPrefix)
	d.Set("sns_topic_arn", channel.SnsTopicARN)

	if channel.ConfigSnapshotDeliveryProperties != nil {
		d.Set("snapshot_delivery_properties", flattenConfigSnapshotDeliveryProperties(channel.ConfigSnapshotDeliveryProperties))
	}

	return nil
}

func resourceAwsConfigDeliveryChannelDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).configconn
	input := configservice.DeleteDeliveryChannelInput{
		DeliveryChannelName: aws.String(d.Id()),
	}

	err := resource.Retry(30*time.Second, func() *resource.RetryError {
		_, err := conn.DeleteDeliveryChannel(&input)
		if err != nil {
			if isAWSErr(err, configservice.ErrCodeLastDeliveryChannelDeleteFailedException, "there is a running configuration recorder") {
				return resource.RetryableError(err)
			}

			return resource.NonRetryableError(err)
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Unable to delete delivery channel: %s", err)
	}

	d.SetId("")
	return nil
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package db_test

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

	"github.com/syncthing/syncthing/lib/db"
	"github.com/syncthing/syncthing/lib/fs"
	"github.com/syncthing/syncthing/lib/protocol"
)

var files, oneFile, firstHalf, secondHalf []protocol.FileInfo
var benchS *db.FileSet

func lazyInitBenchFileSet() {
	if benchS != nil {
		return
	}

	for i := 0; i < 1000; i++ {
		files = append(files, protocol.FileInfo{
			Name:    fmt.Sprintf("file%d", i),
			Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}},
			Blocks:  genBlocks(i),
		})
	}

	middle := len(files) / 2
	firstHalf = files[:middle]
	secondHalf = files[middle:]
	oneFile = firstHalf[middle-1 : middle]

	ldb, _ := tempDB()
	benchS = db.NewFileSet("test)", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), ldb)
	replace(benchS, remoteDevice0, files)
	replace(benchS, protocol.LocalDeviceID, firstHalf)
}

func tempDB() (*db.Lowlevel, string) {
	dir, err := ioutil.TempDir("", "syncthing")
	if err != nil {
		panic(err)
	}
	dbi, err := db.Open(filepath.Join(dir, "db"))
	if err != nil {
		panic(err)
	}
	return dbi, dir
}

func BenchmarkReplaceAll(b *testing.B) {
	ldb, dir := tempDB()
	defer func() {
		ldb.Close()
		os.RemoveAll(dir)
	}()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		m := db.NewFileSet("test)", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), ldb)
		replace(m, protocol.LocalDeviceID, files)
	}

	b.ReportAllocs()
}

func BenchmarkUpdateOneChanged(b *testing.B) {
	lazyInitBenchFileSet()

	changed := make([]protocol.FileInfo, 1)
	changed[0] = oneFile[0]
	changed[0].Version = changed[0].Version.Update(myID)
	changed[0].Blocks = genBlocks(len(changed[0].Blocks))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if i%1 == 0 {
			benchS.Update(protocol.LocalDeviceID, changed)
		} else {
			benchS.Update(protocol.LocalDeviceID, oneFile)
		}
	}

	b.ReportAllocs()
}

func BenchmarkUpdateOneUnchanged(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		benchS.Update(protocol.LocalDeviceID, oneFile)
	}

	b.ReportAllocs()
}

func BenchmarkNeedHalf(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithNeed(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(secondHalf) {
			b.Errorf("wrong length %d != %d", count, len(secondHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkHave(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithHave(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(firstHalf) {
			b.Errorf("wrong length %d != %d", count, len(firstHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkGlobal(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithGlobal(func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(files) {
			b.Errorf("wrong length %d != %d", count, len(files))
		}
	}

	b.ReportAllocs()
}

func BenchmarkNeedHalfTruncated(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithNeedTruncated(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(secondHalf) {
			b.Errorf("wrong length %d != %d", count, len(secondHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkHaveTruncated(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithHaveTruncated(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(firstHalf) {
			b.Errorf("wrong length %d != %d", count, len(firstHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkGlobalTruncated(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithGlobalTruncated(func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(files) {
			b.Errorf("wrong length %d != %d", count, len(files))
		}
	}

	b.ReportAllocs()
}
<commit_msg>lib/db: Fix, optimize and extend benchmarks (#5467)<commit_after>// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package db_test

import (
	"fmt"
	"testing"

	"github.com/syncthing/syncthing/lib/db"
	"github.com/syncthing/syncthing/lib/fs"
	"github.com/syncthing/syncthing/lib/protocol"
)

var files, oneFile, firstHalf, secondHalf []protocol.FileInfo
var benchS *db.FileSet

func lazyInitBenchFileSet() {
	if benchS != nil {
		return
	}

	for i := 0; i < 1000; i++ {
		files = append(files, protocol.FileInfo{
			Name:    fmt.Sprintf("file%d", i),
			Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}},
			Blocks:  genBlocks(i),
		})
	}

	middle := len(files) / 2
	firstHalf = files[:middle]
	secondHalf = files[middle:]
	oneFile = firstHalf[middle-1 : middle]

	ldb := db.OpenMemory()
	benchS = db.NewFileSet("test)", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), ldb)
	replace(benchS, remoteDevice0, files)
	replace(benchS, protocol.LocalDeviceID, firstHalf)
}

func BenchmarkReplaceAll(b *testing.B) {
	ldb := db.OpenMemory()
	defer ldb.Close()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		m := db.NewFileSet("test)", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), ldb)
		replace(m, protocol.LocalDeviceID, files)
	}

	b.ReportAllocs()
}

func BenchmarkUpdateOneChanged(b *testing.B) {
	lazyInitBenchFileSet()

	changed := make([]protocol.FileInfo, 1)
	changed[0] = oneFile[0]
	changed[0].Version = changed[0].Version.Copy().Update(myID)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if i%2 == 0 {
			benchS.Update(protocol.LocalDeviceID, changed)
		} else {
			benchS.Update(protocol.LocalDeviceID, oneFile)
		}
	}

	b.ReportAllocs()
}

func BenchmarkUpdate100Changed(b *testing.B) {
	lazyInitBenchFileSet()

	unchanged := files[100:200]
	changed := append([]protocol.FileInfo{}, unchanged...)
	for i := range changed {
		changed[i].Version = changed[i].Version.Copy().Update(myID)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if i%2 == 0 {
			benchS.Update(protocol.LocalDeviceID, changed)
		} else {
			benchS.Update(protocol.LocalDeviceID, unchanged)
		}
	}

	b.ReportAllocs()
}

func BenchmarkUpdate100ChangedRemote(b *testing.B) {
	lazyInitBenchFileSet()

	unchanged := files[100:200]
	changed := append([]protocol.FileInfo{}, unchanged...)
	for i := range changed {
		changed[i].Version = changed[i].Version.Copy().Update(myID)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if i%2 == 0 {
			benchS.Update(remoteDevice0, changed)
		} else {
			benchS.Update(remoteDevice0, unchanged)
		}
	}

	b.ReportAllocs()
}

func BenchmarkUpdateOneUnchanged(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		benchS.Update(protocol.LocalDeviceID, oneFile)
	}

	b.ReportAllocs()
}

func BenchmarkNeedHalf(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithNeed(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(secondHalf) {
			b.Errorf("wrong length %d != %d", count, len(secondHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkNeedHalfRemote(b *testing.B) {
	lazyInitBenchFileSet()

	ldb := db.OpenMemory()
	defer ldb.Close()
	fset := db.NewFileSet("test)", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), ldb)
	replace(fset, remoteDevice0, firstHalf)
	replace(fset, protocol.LocalDeviceID, files)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		fset.WithNeed(remoteDevice0, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(secondHalf) {
			b.Errorf("wrong length %d != %d", count, len(secondHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkHave(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithHave(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(firstHalf) {
			b.Errorf("wrong length %d != %d", count, len(firstHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkGlobal(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithGlobal(func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(files) {
			b.Errorf("wrong length %d != %d", count, len(files))
		}
	}

	b.ReportAllocs()
}

func BenchmarkNeedHalfTruncated(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithNeedTruncated(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(secondHalf) {
			b.Errorf("wrong length %d != %d", count, len(secondHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkHaveTruncated(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithHaveTruncated(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(firstHalf) {
			b.Errorf("wrong length %d != %d", count, len(firstHalf))
		}
	}

	b.ReportAllocs()
}

func BenchmarkGlobalTruncated(b *testing.B) {
	lazyInitBenchFileSet()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		count := 0
		benchS.WithGlobalTruncated(func(fi db.FileIntf) bool {
			count++
			return true
		})
		if count != len(files) {
			b.Errorf("wrong length %d != %d", count, len(files))
		}
	}

	b.ReportAllocs()
}
<|endoftext|>