<commit_before>/*
Copyright 2018 The Skaffold 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 cmd

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"

	cmdutil "github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/cmd/util"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/update"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/version"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var (
	opts      = &config.SkaffoldOptions{}
	v         string
	overwrite bool

	updateMsg = make(chan string)
)

var rootCmd = &cobra.Command{
	Use:   "skaffold",
	Short: "A tool that facilitates continuous development for Kubernetes applications.",
}

func NewSkaffoldCommand(out, err io.Writer) *cobra.Command {
	rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
		if err := SetUpLogs(err, v); err != nil {
			return err
		}
		rootCmd.SilenceUsage = true
		logrus.Infof("Skaffold %+v", version.Get())
		go func() {
			if err := updateCheck(updateMsg); err != nil {
				logrus.Infof("update check failed: %s", err)
			}
		}()
		return nil
	}

	rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) {
		select {
		case msg := <-updateMsg:
			fmt.Fprintf(out, "%s\n", msg)
		default:
		}
	}

	rootCmd.SilenceErrors = true
	rootCmd.AddCommand(NewCmdCompletion(out))
	rootCmd.AddCommand(NewCmdVersion(out))
	rootCmd.AddCommand(NewCmdRun(out))
	rootCmd.AddCommand(NewCmdDev(out))
	rootCmd.AddCommand(NewCmdBuild(out))
	rootCmd.AddCommand(NewCmdDeploy(out))
	rootCmd.AddCommand(NewCmdDelete(out))
	rootCmd.AddCommand(NewCmdFix(out))
	rootCmd.AddCommand(NewCmdConfig(out))

	rootCmd.PersistentFlags().StringVarP(&v, "verbosity", "v", constants.DefaultLogLevel.String(), "Log level (debug, info, warn, error, fatal, panic")

	setFlagsFromEnvVariables(rootCmd.Commands())

	return rootCmd
}

func updateCheck(ch chan string) error {
	if !update.IsUpdateCheckEnabled() {
		logrus.Debugf("Update check not enabled, skipping.")
		return nil
	}
	current, err := version.ParseVersion(version.Get().Version)
	if err != nil {
		return errors.Wrap(err, "parsing current semver, skipping update check")
	}
	latest, err := update.GetLatestVersion(context.Background())
	if err != nil {
		return errors.Wrap(err, "getting latest version")
	}
	if latest.GT(current) {
		ch <- fmt.Sprintf("There is a new version (%s) of skaffold available. Download it at %s\n", latest, constants.LatestDownloadURL)
	}
	return nil
}

// Each flag can also be set with an env variable whose name starts with `SKAFFOLD_`.
func setFlagsFromEnvVariables(commands []*cobra.Command) {
	for _, cmd := range commands {
		cmd.Flags().VisitAll(func(f *pflag.Flag) {
			// special case for backward compatibility.
			if f.Name == "namespace" {
				if val, present := os.LookupEnv("SKAFFOLD_DEPLOY_NAMESPACE"); present {
					logrus.Warnln("Using SKAFFOLD_DEPLOY_NAMESPACE env variable is deprecated. Please use SKAFFOLD_NAMESPACE instead.")
					cmd.Flags().Set(f.Name, val)
				}
			}

			envVar := fmt.Sprintf("SKAFFOLD_%s", strings.Replace(strings.ToUpper(f.Name), "-", "_", -1))
			if val, present := os.LookupEnv(envVar); present {
				cmd.Flags().Set(f.Name, val)
			}
		})
	}
}

func AddDevFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Cleanup, "cleanup", true, "Delete deployments after dev mode is interrupted")
	cmd.Flags().StringArrayVarP(&opts.Watch, "watch-image", "w", nil, "Choose which artifacts to watch. Artifacts with image names that contain the expression will be watched only. Default is to watch sources for all artifacts.")
}

func AddRunDeployFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Tail, "tail", false, "Stream logs from deployed objects")
}

func AddRunDevFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&opts.Notification, "toot", false, "Emit a terminal beep after the deploy is complete")
	cmd.Flags().StringArrayVarP(&opts.Profiles, "profile", "p", nil, "Activate profiles by name")
	cmd.Flags().StringVarP(&opts.Namespace, "namespace", "n", "", "Run Helm deployments in the specified namespace")
}

func AddFixFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&overwrite, "overwrite", false, "Overwrite original config with fixed config")
}

func SetUpLogs(out io.Writer, level string) error {
	logrus.SetOutput(out)
	lvl, err := logrus.ParseLevel(v)
	if err != nil {
		return errors.Wrap(err, "parsing log level")
	}
	logrus.SetLevel(lvl)
	return nil
}

func readConfiguration(opts *config.SkaffoldOptions) (*config.SkaffoldConfig, error) {
	config, err := cmdutil.ParseConfig(opts.ConfigurationFile)
	if err != nil {
		return nil, errors.Wrap(err, "parsing skaffold config")
	}
	err = config.ApplyProfiles(opts.Profiles)
	if err != nil {
		return nil, errors.Wrap(err, "applying profiles")
	}
	return config, nil
}
<commit_msg>update check respected quiet flag<commit_after>/*
Copyright 2018 The Skaffold 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 cmd

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"

	cmdutil "github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/cmd/util"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/update"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/version"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var (
	opts      = &config.SkaffoldOptions{}
	v         string
	overwrite bool

	updateMsg = make(chan string)
)

var rootCmd = &cobra.Command{
	Use:   "skaffold",
	Short: "A tool that facilitates continuous development for Kubernetes applications.",
}

func NewSkaffoldCommand(out, err io.Writer) *cobra.Command {
	rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
		if err := SetUpLogs(err, v); err != nil {
			return err
		}
		rootCmd.SilenceUsage = true
		logrus.Infof("Skaffold %+v", version.Get())
		go func() {
			if err := updateCheck(updateMsg); err != nil {
				logrus.Infof("update check failed: %s", err)
			}
		}()
		return nil
	}

	rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) {
		select {
		case msg := <-updateMsg:
			fmt.Fprintf(out, "%s\n", msg)
		default:
		}
	}

	rootCmd.SilenceErrors = true
	rootCmd.AddCommand(NewCmdCompletion(out))
	rootCmd.AddCommand(NewCmdVersion(out))
	rootCmd.AddCommand(NewCmdRun(out))
	rootCmd.AddCommand(NewCmdDev(out))
	rootCmd.AddCommand(NewCmdBuild(out))
	rootCmd.AddCommand(NewCmdDeploy(out))
	rootCmd.AddCommand(NewCmdDelete(out))
	rootCmd.AddCommand(NewCmdFix(out))
	rootCmd.AddCommand(NewCmdConfig(out))

	rootCmd.PersistentFlags().StringVarP(&v, "verbosity", "v", constants.DefaultLogLevel.String(), "Log level (debug, info, warn, error, fatal, panic")

	setFlagsFromEnvVariables(rootCmd.Commands())

	return rootCmd
}

func updateCheck(ch chan string) error {
	if quietFlag {
		logrus.Debugf("Update check is disabled because of quiet mode")
		return nil
	}
	if !update.IsUpdateCheckEnabled() {
		logrus.Debugf("Update check not enabled, skipping.")
		return nil
	}
	current, err := version.ParseVersion(version.Get().Version)
	if err != nil {
		return errors.Wrap(err, "parsing current semver, skipping update check")
	}
	latest, err := update.GetLatestVersion(context.Background())
	if err != nil {
		return errors.Wrap(err, "getting latest version")
	}
	if latest.GT(current) {
		ch <- fmt.Sprintf("There is a new version (%s) of skaffold available. Download it at %s\n", latest, constants.LatestDownloadURL)
	}
	return nil
}

// Each flag can also be set with an env variable whose name starts with `SKAFFOLD_`.
func setFlagsFromEnvVariables(commands []*cobra.Command) {
	for _, cmd := range commands {
		cmd.Flags().VisitAll(func(f *pflag.Flag) {
			// special case for backward compatibility.
			if f.Name == "namespace" {
				if val, present := os.LookupEnv("SKAFFOLD_DEPLOY_NAMESPACE"); present {
					logrus.Warnln("Using SKAFFOLD_DEPLOY_NAMESPACE env variable is deprecated. Please use SKAFFOLD_NAMESPACE instead.")
					cmd.Flags().Set(f.Name, val)
				}
			}

			envVar := fmt.Sprintf("SKAFFOLD_%s", strings.Replace(strings.ToUpper(f.Name), "-", "_", -1))
			if val, present := os.LookupEnv(envVar); present {
				cmd.Flags().Set(f.Name, val)
			}
		})
	}
}

func AddDevFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Cleanup, "cleanup", true, "Delete deployments after dev mode is interrupted")
	cmd.Flags().StringArrayVarP(&opts.Watch, "watch-image", "w", nil, "Choose which artifacts to watch. Artifacts with image names that contain the expression will be watched only. Default is to watch sources for all artifacts.")
}

func AddRunDeployFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Tail, "tail", false, "Stream logs from deployed objects")
}

func AddRunDevFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&opts.Notification, "toot", false, "Emit a terminal beep after the deploy is complete")
	cmd.Flags().StringArrayVarP(&opts.Profiles, "profile", "p", nil, "Activate profiles by name")
	cmd.Flags().StringVarP(&opts.Namespace, "namespace", "n", "", "Run Helm deployments in the specified namespace")
}

func AddFixFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&overwrite, "overwrite", false, "Overwrite original config with fixed config")
}

func SetUpLogs(out io.Writer, level string) error {
	logrus.SetOutput(out)
	lvl, err := logrus.ParseLevel(v)
	if err != nil {
		return errors.Wrap(err, "parsing log level")
	}
	logrus.SetLevel(lvl)
	return nil
}

func readConfiguration(opts *config.SkaffoldOptions) (*config.SkaffoldConfig, error) {
	config, err := cmdutil.ParseConfig(opts.ConfigurationFile)
	if err != nil {
		return nil, errors.Wrap(err, "parsing skaffold config")
	}
	err = config.ApplyProfiles(opts.Profiles)
	if err != nil {
		return nil, errors.Wrap(err, "applying profiles")
	}
	return config, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/containers/buildah/pkg/unshare"
	"github.com/containers/image/storage"
	"github.com/containers/image/transports/alltransports"
	"github.com/pkg/errors"
	"github.com/syndtr/gocapability/capability"
)

var neededCapabilities = []capability.Cap{
	capability.CAP_CHOWN,
	capability.CAP_DAC_OVERRIDE,
	capability.CAP_FOWNER,
	capability.CAP_FSETID,
	capability.CAP_MKNOD,
	capability.CAP_SETFCAP,
}

func maybeReexec() error {
	// With Skopeo we need only the subset of the root capabilities necessary
	// for pulling an image to the storage.  Do not attempt to create a namespace
	// if we already have the capabilities we need.
	capabilities, err := capability.NewPid(0)
	if err != nil {
		return errors.Wrapf(err, "error reading the current capabilities sets")
	}
	for _, cap := range neededCapabilities {
		if !capabilities.Get(capability.EFFECTIVE, cap) {
			// We miss a capability we need, create a user namespaces
			unshare.MaybeReexecUsingUserNamespace(true)
			return nil
		}
	}
	return nil
}

func reexecIfNecessaryForImages(imageNames ...string) error {
	// Check if container-storage are used before doing unshare
	for _, imageName := range imageNames {
		if alltransports.TransportFromImageName(imageName).Name() == storage.Transport.Name() {
			return maybeReexec()
		}
	}
	return nil
}
<commit_msg>Skopeo crashes on any invalid transport<commit_after>package main

import (
	"github.com/containers/buildah/pkg/unshare"
	"github.com/containers/image/storage"
	"github.com/containers/image/transports/alltransports"
	"github.com/pkg/errors"
	"github.com/syndtr/gocapability/capability"
)

var neededCapabilities = []capability.Cap{
	capability.CAP_CHOWN,
	capability.CAP_DAC_OVERRIDE,
	capability.CAP_FOWNER,
	capability.CAP_FSETID,
	capability.CAP_MKNOD,
	capability.CAP_SETFCAP,
}

func maybeReexec() error {
	// With Skopeo we need only the subset of the root capabilities necessary
	// for pulling an image to the storage.  Do not attempt to create a namespace
	// if we already have the capabilities we need.
	capabilities, err := capability.NewPid(0)
	if err != nil {
		return errors.Wrapf(err, "error reading the current capabilities sets")
	}
	for _, cap := range neededCapabilities {
		if !capabilities.Get(capability.EFFECTIVE, cap) {
			// We miss a capability we need, create a user namespaces
			unshare.MaybeReexecUsingUserNamespace(true)
			return nil
		}
	}
	return nil
}

func reexecIfNecessaryForImages(imageNames ...string) error {
	// Check if container-storage are used before doing unshare
	for _, imageName := range imageNames {
		transport := alltransports.TransportFromImageName(imageName)
		if transport != nil && transport.Name() == storage.Transport.Name() {
			return maybeReexec()
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Supports Windows, Linux, Mac, and Raspberry Pi

package main

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"net/http"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/arduino/arduino-create-agent/utilities"
	"github.com/gin-gonic/gin"
	"github.com/googollee/go-socket.io"
)

type connection struct {
	// The websocket connection.
	ws socketio.Socket

	// Buffered channel of outbound messages.
	send     chan []byte
	incoming chan []byte
}

func (c *connection) writer() {
	for message := range c.send {
		err := c.ws.Emit("message", string(message))
		if err != nil {
			break
		}
	}
}

// WsServer overrides socket.io server to set the CORS
type WsServer struct {
	Server *socketio.Server
}

func (s *WsServer) ServeHTTP(c *gin.Context) {
	s.Server.ServeHTTP(c.Writer, c.Request)
}

type AdditionalFile struct {
	Hex      []byte `json:"hex"`
	Filename string `json:"filename"`
}

// Upload contains the data to upload a sketch onto a board
type Upload struct {
	Port        string           `json:"port"`
	Board       string           `json:"board"`
	Rewrite     string           `json:"rewrite"`
	Commandline string           `json:"commandline"`
	Signature   string           `json:"signature"`
	Extra       boardExtraInfo   `json:"extra"`
	Hex         []byte           `json:"hex"`
	Filename    string           `json:"filename"`
	ExtraFiles  []AdditionalFile `json:"extrafiles"`
}

func uploadHandler(c *gin.Context) {
	data := new(Upload)
	c.BindJSON(data)

	log.Printf("%+v", data)

	if data.Port == "" {
		c.String(http.StatusBadRequest, "port is required")
		return
	}

	if data.Board == "" {
		c.String(http.StatusBadRequest, "board is required")
		log.Error("board is required")
		return
	}

	if data.Extra.Network == false {
		if data.Signature == "" {
			c.String(http.StatusBadRequest, "signature is required")
			return
		}

		if data.Commandline == "" {
			c.String(http.StatusBadRequest, "commandline is required for local board")
			return
		}

		err := verifyCommandLine(data.Commandline, data.Signature)

		if err != nil {
			c.String(http.StatusBadRequest, "signature is invalid")
			return
		}
	}

	buffer := bytes.NewBuffer(data.Hex)

	filePath, err := utilities.SaveFileonTempDir(data.Filename, buffer)
	if err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}

	for _, extraFile := range data.ExtraFiles {
		ioutil.WriteFile(filepath.Join(filepath.Dir(filePath), extraFile.Filename), extraFile.Hex, 0644)
	}

	if data.Rewrite != "" {
		data.Board = data.Rewrite
	}

	go spProgramRW(data.Port, data.Board, filePath, data.Commandline, data.Extra)

	c.String(http.StatusAccepted, "")
}

func verifyCommandLine(input string, signature string) error {
	sign, _ := hex.DecodeString(signature)
	block, _ := pem.Decode([]byte(*signatureKey))
	if block == nil {
		return errors.New("invalid key")
	}
	key, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return err
	}
	rsaKey := key.(*rsa.PublicKey)
	h := sha256.New()
	h.Write([]byte(input))
	d := h.Sum(nil)
	return rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, d, sign)
}

func wsHandler() *WsServer {
	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	server.On("connection", func(so socketio.Socket) {
		c := &connection{send: make(chan []byte, 256*10), ws: so}
		h.register <- c
		so.On("command", func(message string) {
			h.broadcast <- []byte(message)
		})

		so.On("disconnection", func() {
			h.unregister <- c
		})
		go c.writer()
	})
	server.On("error", func(so socketio.Socket, err error) {
		log.Println("error:", err)
	})

	wrapper := WsServer{
		Server: server,
	}

	return &wrapper
}
<commit_msg>Add debug messages to understand what's going wrong with the zero upload<commit_after>// Supports Windows, Linux, Mac, and Raspberry Pi

package main

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"net/http"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/arduino/arduino-create-agent/utilities"
	"github.com/gin-gonic/gin"
	"github.com/googollee/go-socket.io"
)

type connection struct {
	// The websocket connection.
	ws socketio.Socket

	// Buffered channel of outbound messages.
	send     chan []byte
	incoming chan []byte
}

func (c *connection) writer() {
	for message := range c.send {
		err := c.ws.Emit("message", string(message))
		if err != nil {
			break
		}
	}
}

// WsServer overrides socket.io server to set the CORS
type WsServer struct {
	Server *socketio.Server
}

func (s *WsServer) ServeHTTP(c *gin.Context) {
	s.Server.ServeHTTP(c.Writer, c.Request)
}

type AdditionalFile struct {
	Hex      []byte `json:"hex"`
	Filename string `json:"filename"`
}

// Upload contains the data to upload a sketch onto a board
type Upload struct {
	Port        string           `json:"port"`
	Board       string           `json:"board"`
	Rewrite     string           `json:"rewrite"`
	Commandline string           `json:"commandline"`
	Signature   string           `json:"signature"`
	Extra       boardExtraInfo   `json:"extra"`
	Hex         []byte           `json:"hex"`
	Filename    string           `json:"filename"`
	ExtraFiles  []AdditionalFile `json:"extrafiles"`
}

func uploadHandler(c *gin.Context) {
	data := new(Upload)
	c.BindJSON(data)

	log.Printf("%+v", data)

	if data.Port == "" {
		c.String(http.StatusBadRequest, "port is required")
		return
	}

	if data.Board == "" {
		c.String(http.StatusBadRequest, "board is required")
		log.Error("board is required")
		return
	}

	if data.Extra.Network == false {
		if data.Signature == "" {
			c.String(http.StatusBadRequest, "signature is required")
			return
		}

		if data.Commandline == "" {
			c.String(http.StatusBadRequest, "commandline is required for local board")
			return
		}

		err := verifyCommandLine(data.Commandline, data.Signature)

		if err != nil {
			c.String(http.StatusBadRequest, "signature is invalid")
			return
		}
	}

	buffer := bytes.NewBuffer(data.Hex)

	filePath, err := utilities.SaveFileonTempDir(data.Filename, buffer)
	if err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}

	for _, extraFile := range data.ExtraFiles {
		path := filepath.Join(filepath.Dir(filePath), extraFile.Filename)
		log.Printf("Saving %s on %s", extraFile.Filename, path)
		err := ioutil.WriteFile(path, extraFile.Hex, 0644)
		if err != nil {
			log.Printf(err.Error())
		}
	}

	if data.Rewrite != "" {
		data.Board = data.Rewrite
	}

	go spProgramRW(data.Port, data.Board, filePath, data.Commandline, data.Extra)

	c.String(http.StatusAccepted, "")
}

func verifyCommandLine(input string, signature string) error {
	sign, _ := hex.DecodeString(signature)
	block, _ := pem.Decode([]byte(*signatureKey))
	if block == nil {
		return errors.New("invalid key")
	}
	key, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return err
	}
	rsaKey := key.(*rsa.PublicKey)
	h := sha256.New()
	h.Write([]byte(input))
	d := h.Sum(nil)
	return rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, d, sign)
}

func wsHandler() *WsServer {
	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	server.On("connection", func(so socketio.Socket) {
		c := &connection{send: make(chan []byte, 256*10), ws: so}
		h.register <- c
		so.On("command", func(message string) {
			h.broadcast <- []byte(message)
		})

		so.On("disconnection", func() {
			h.unregister <- c
		})
		go c.writer()
	})
	server.On("error", func(so socketio.Socket, err error) {
		log.Println("error:", err)
	})

	wrapper := WsServer{
		Server: server,
	}

	return &wrapper
}
<|endoftext|>


<commit_before>package fwk

import (
	"fmt"
	"reflect"
)

type statuscode int

func (sc statuscode) Error() string {
	return fmt.Sprintf("fwk: error code [%d]", int(sc))
}

type Context interface {
	Id() int64      // id of this context (e.g. entry number or some kind of event number)
	Slot() int      // slot number in the pool of event sequences
	Store() Store   // data store corresponding to the id+slot
	Msg() MsgStream // messaging for this context (id+slot)
}

type Component interface {
	Type() string // Type of the component (ex: "github.com/go-hep/fads.MomentumSmearing")
	Name() string // Name of the component (ex: "MyPropagator")
}

type ComponentMgr interface {
	Component(n string) Component
	HasComponent(n string) bool
	Components() []Component
	New(t, n string) (Component, error)
}

type Task interface {
	Component

	StartTask(ctx Context) error
	Process(ctx Context) error
	StopTask(ctx Context) error
}

type TaskMgr interface {
	AddTask(tsk Task) error
	DelTask(tsk Task) error
	HasTask(n string) bool
	GetTask(n string) Task
	Tasks() []Task
}

type Configurer interface {
	Component
	Configure(ctx Context) error
}

type Svc interface {
	Component

	StartSvc(ctx Context) error
	StopSvc(ctx Context) error
}

type SvcMgr interface {
	AddSvc(svc Svc) error
	DelSvc(svc Svc) error
	HasSvc(n string) bool
	GetSvc(n string) Svc
	Svcs() []Svc
}

type App interface {
	Component
	ComponentMgr
	SvcMgr
	TaskMgr
	PropMgr
	PortMgr

	Run() error

	Msg() MsgStream
}

type PropMgr interface {
	DeclProp(c Component, name string, ptr interface{}) error
	SetProp(c Component, name string, value interface{}) error
	GetProp(c Component, name string) (interface{}, error)
	HasProp(c Component, name string) bool
}

type Property interface {
	DeclProp(name string, ptr interface{}) error
	SetProp(name string, value interface{}) error
	GetProp(name string) (interface{}, error)
}

type Store interface {
	Get(key string) (interface{}, error)
	Put(key string, value interface{}) error
	Has(key string) bool
}

// Port holds the name and type of a data item in a store
type Port struct {
	Name string
	Type reflect.Type
}

// DeclPorter is the interface to declare input/output ports for the data flow.
type DeclPorter interface {
	DeclInPort(name string, t reflect.Type) error
	DeclOutPort(name string, t reflect.Type) error
}

// PortMgr is the interface to manage input/output ports for the data flow
type PortMgr interface {
	DeclInPort(c Component, name string, t reflect.Type) error
	DeclOutPort(c Component, name string, t reflect.Type) error
}

type Level int

const (
	//LvlVerbose Level = -20
	LvlDebug   Level = -10
	LvlInfo    Level = 0
	LvlWarning Level = 10
	LvlError   Level = 20
)

func (lvl Level) msgstring() string {
	switch lvl {
	case LvlDebug:
		return "DBG "
	case LvlInfo:
		return "INFO"
	case LvlWarning:
		return "WARN"
	case LvlError:
		return "ERR "
	}
	panic(Errorf("fwk.Level: invalid fwk.Level value [%d]", int(lvl)))
}

func (lvl Level) String() string {
	switch lvl {
	case LvlDebug:
		return "DEBUG"
	case LvlInfo:
		return "INFO"
	case LvlWarning:
		return "WARN"
	case LvlError:
		return "ERROR"
	}
	panic(Errorf("fwk.Level: invalid fwk.Level value [%d]", int(lvl)))
}

type MsgStream interface {
	Debugf(format string, a ...interface{}) (int, error)
	Infof(format string, a ...interface{}) (int, error)
	Warnf(format string, a ...interface{}) (int, error)
	Errorf(format string, a ...interface{}) (int, error)

	Msg(lvl Level, format string, a ...interface{}) (int, error)
}

// Deleter prepares values to be GC-reclaimed
type Deleter interface {
	Delete() error
}

// EOF
<commit_msg>core: doc for Component<commit_after>package fwk

import (
	"fmt"
	"reflect"
)

type statuscode int

func (sc statuscode) Error() string {
	return fmt.Sprintf("fwk: error code [%d]", int(sc))
}

type Context interface {
	Id() int64      // id of this context (e.g. entry number or some kind of event number)
	Slot() int      // slot number in the pool of event sequences
	Store() Store   // data store corresponding to the id+slot
	Msg() MsgStream // messaging for this context (id+slot)
}

// Component is the interface satisfied by all values in fwk.
//
// A component can be asked for:
// its Type() (ex: "github.com/go-hep/fads.MomentumSmearing")
// its Name() (ex: "MyPropagator")
type Component interface {
	Type() string // Type of the component (ex: "github.com/go-hep/fads.MomentumSmearing")
	Name() string // Name of the component (ex: "MyPropagator")
}

type ComponentMgr interface {
	Component(n string) Component
	HasComponent(n string) bool
	Components() []Component
	New(t, n string) (Component, error)
}

type Task interface {
	Component

	StartTask(ctx Context) error
	Process(ctx Context) error
	StopTask(ctx Context) error
}

type TaskMgr interface {
	AddTask(tsk Task) error
	DelTask(tsk Task) error
	HasTask(n string) bool
	GetTask(n string) Task
	Tasks() []Task
}

type Configurer interface {
	Component
	Configure(ctx Context) error
}

type Svc interface {
	Component

	StartSvc(ctx Context) error
	StopSvc(ctx Context) error
}

type SvcMgr interface {
	AddSvc(svc Svc) error
	DelSvc(svc Svc) error
	HasSvc(n string) bool
	GetSvc(n string) Svc
	Svcs() []Svc
}

type App interface {
	Component
	ComponentMgr
	SvcMgr
	TaskMgr
	PropMgr
	PortMgr

	Run() error

	Msg() MsgStream
}

type PropMgr interface {
	DeclProp(c Component, name string, ptr interface{}) error
	SetProp(c Component, name string, value interface{}) error
	GetProp(c Component, name string) (interface{}, error)
	HasProp(c Component, name string) bool
}

type Property interface {
	DeclProp(name string, ptr interface{}) error
	SetProp(name string, value interface{}) error
	GetProp(name string) (interface{}, error)
}

type Store interface {
	Get(key string) (interface{}, error)
	Put(key string, value interface{}) error
	Has(key string) bool
}

// Port holds the name and type of a data item in a store
type Port struct {
	Name string
	Type reflect.Type
}

// DeclPorter is the interface to declare input/output ports for the data flow.
type DeclPorter interface {
	DeclInPort(name string, t reflect.Type) error
	DeclOutPort(name string, t reflect.Type) error
}

// PortMgr is the interface to manage input/output ports for the data flow
type PortMgr interface {
	DeclInPort(c Component, name string, t reflect.Type) error
	DeclOutPort(c Component, name string, t reflect.Type) error
}

type Level int

const (
	//LvlVerbose Level = -20
	LvlDebug   Level = -10
	LvlInfo    Level = 0
	LvlWarning Level = 10
	LvlError   Level = 20
)

func (lvl Level) msgstring() string {
	switch lvl {
	case LvlDebug:
		return "DBG "
	case LvlInfo:
		return "INFO"
	case LvlWarning:
		return "WARN"
	case LvlError:
		return "ERR "
	}
	panic(Errorf("fwk.Level: invalid fwk.Level value [%d]", int(lvl)))
}

func (lvl Level) String() string {
	switch lvl {
	case LvlDebug:
		return "DEBUG"
	case LvlInfo:
		return "INFO"
	case LvlWarning:
		return "WARN"
	case LvlError:
		return "ERROR"
	}
	panic(Errorf("fwk.Level: invalid fwk.Level value [%d]", int(lvl)))
}

type MsgStream interface {
	Debugf(format string, a ...interface{}) (int, error)
	Infof(format string, a ...interface{}) (int, error)
	Warnf(format string, a ...interface{}) (int, error)
	Errorf(format string, a ...interface{}) (int, error)

	Msg(lvl Level, format string, a ...interface{}) (int, error)
}

// Deleter prepares values to be GC-reclaimed
type Deleter interface {
	Delete() error
}

// EOF
<|endoftext|>


<commit_before>package godatai18n

import (
	"database/sql/driver"
	"encoding/json"
	"golang.org/x/net/context"
	"golang.org/x/text/language"
	"reflect"
)

// Use struct field with this type to store translations
// e.g. Translations{"en": map[string]string{"name": "John"}}
type Translations map[string]map[string]string

func (m *Translations) Scan(value interface{}) error {
	return json.Unmarshal(value.([]byte), m)
}

func (m Translations) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}
	return string(b), nil
}

func translateField(field reflect.Value, name string, translations Translations, targetLanguages []language.Tag) {
	langs := []language.Tag{}
	enFound := false
	for lang, tr := range translations {
		_, ok := tr[name]
		if ok {
			// First language in langs will be fallback option for matcher
			// but map order is not stable,
			// so we need to move en to front, if it's available
			if lang == "en" {
				enFound = true
			} else {
				langs = append(langs, language.Make(lang))
			}
		}
	}
	if enFound {
		langs = append([]language.Tag{language.Make("en")}, langs...)
	}

	effectiveLang, _, _ := language.NewMatcher(langs).Match(targetLanguages...)
	field.SetString(translations[effectiveLang.String()][name])
}

func TranslateOne(ctx context.Context, target interface{}) {
	meta := metas.getStructMeta(target)
	if len(meta.fields) == 0 {
		return
	}

	structValue := reflect.ValueOf(target)
	if structValue.Kind() == reflect.Ptr {
		structValue = structValue.Elem()
	}

	translations, ok := structValue.FieldByName("Translations").Interface().(Translations)
	if !ok || len(translations) == 0 {
		return
	}

	targetLanguages, ok := FromContext(ctx)
	if !ok || len(targetLanguages) == 0 {
		targetLanguages = []language.Tag{language.English}
	}

	for _, trF := range meta.fields {
		f := structValue.FieldByName(trF.name)
		if f.IsValid() && f.CanSet() && f.Kind() == reflect.String {
			translateField(f, trF.key, translations, targetLanguages)
		}
	}
}

func TranslateMany(ctx context.Context, targets interface{}) {
	v := reflect.ValueOf(targets)

	for i := 0; i < v.Len(); i++ {
		TranslateOne(ctx, v.Index(i).Interface())
	}
}
<commit_msg>Speedup by caching matchers (-95% time)<commit_after>package godatai18n

import (
	"database/sql/driver"
	"encoding/json"
	"golang.org/x/net/context"
	"golang.org/x/text/language"
	"reflect"
	"sync"
)

// Use struct field with this type to store translations
// e.g. Translations{"en": map[string]string{"name": "John"}}
type Translations map[string]map[string]string

func (m *Translations) Scan(value interface{}) error {
	return json.Unmarshal(value.([]byte), m)
}

func (m Translations) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}
	return string(b), nil
}

var matchers = map[string]language.Matcher{}
var matchersMutex sync.RWMutex

func getMatcher(fieldName string, translations Translations) language.Matcher {
	langs := []language.Tag{}
	enFound := false
	for lang, tr := range translations {
		_, ok := tr[fieldName]
		if ok {
			// First language in langs will be fallback option for matcher
			// but map order is not stable,
			// so we need to move en to front, if it's available
			if lang == "en" {
				enFound = true
			} else {
				langs = append(langs, language.Make(lang))
			}
		}
	}
	if enFound {
		langs = append([]language.Tag{language.Make("en")}, langs...)
	}

	langsKey := ""
	for _, lang := range langs {
		langsKey += lang.String()
	}

	matchersMutex.RLock()
	matcher, ok := matchers[langsKey]
	matchersMutex.RUnlock()

	if ok {
		return matcher
	}

	matcher = language.NewMatcher(langs)

	matchersMutex.Lock()
	matchers[langsKey] = matcher
	matchersMutex.Unlock()

	return matcher
}

func translateField(field reflect.Value, fieldName string, translations Translations, targetLanguages []language.Tag) {
	matcher := getMatcher(fieldName, translations)
	effectiveLang, _, _ := matcher.Match(targetLanguages...)
	field.SetString(translations[effectiveLang.String()][fieldName])
}

func TranslateOne(ctx context.Context, target interface{}) {
	meta := metas.getStructMeta(target)
	if len(meta.fields) == 0 {
		return
	}

	structValue := reflect.ValueOf(target)
	if structValue.Kind() == reflect.Ptr {
		structValue = structValue.Elem()
	}

	translations, ok := structValue.FieldByName("Translations").Interface().(Translations)
	if !ok || len(translations) == 0 {
		return
	}

	targetLanguages, ok := FromContext(ctx)
	if !ok || len(targetLanguages) == 0 {
		targetLanguages = []language.Tag{language.English}
	}

	for _, trF := range meta.fields {
		f := structValue.FieldByName(trF.name)
		if f.IsValid() && f.CanSet() && f.Kind() == reflect.String {
			translateField(f, trF.key, translations, targetLanguages)
		}
	}
}

func TranslateMany(ctx context.Context, targets interface{}) {
	v := reflect.ValueOf(targets)

	for i := 0; i < v.Len(); i++ {
		TranslateOne(ctx, v.Index(i).Interface())
	}
}
<|endoftext|>


<commit_before>package kraken

import (
	"errors"
	"io"

	"code.google.com/p/go.crypto/ssh"
)

var ErrNoMoreCommands = errors.New("No More Commands")

type jobStatus int

const (
	JOB_NO_MORE_COMMANDS jobStatus = iota
	JOB_REMOTE_CONNECTION_CLOSED
)

// Commander will receive terminal output and be asked what to do next
// by calling NextCommand until ErrNoMoreCommands is returned.
type Commander interface {
	NextCommand() ([]byte, error)
	io.Writer
}

type Job struct {
	sshclient  sshClient
	commander  Commander
	statusChan chan jobStatus
}

func NewJob(addr string, conf *ssh.ClientConfig, c Commander) *Job {
	job := Job{}
	job.sshclient = sshClient{address: addr, config: conf}
	job.commander = c
	return &job
}

// Start connects using the provided SSH details and reads/writes
// data over the connection. It also returns a channel to read
// job status messages from.
func (job *Job) Start() (<-chan jobStatus, error) {
	if err := job.sshclient.Connect(); err != nil {
		return nil, err
	}
	if err := job.startCommandLoop(); err != nil {
		return nil, err
	}
	job.statusChan = make(chan jobStatus)
	return job.statusChan, nil
}

func (job *Job) startCommandLoop() error {
	go func() {
		buffer := make([]byte, 100)
		for n, err := job.sshclient.Read(buffer); err == nil || n > 0; n, err = job.sshclient.Read(buffer) {
			_, cerr := job.commander.Write(buffer[:n])
			if cerr != nil {
				print(cerr)
			}
		}
		job.statusChan <- JOB_REMOTE_CONNECTION_CLOSED
	}()
	go func() {
		for command, err := job.commander.NextCommand(); err != ErrNoMoreCommands; command, err = job.commander.NextCommand() {
			job.sshclient.Write(command)
		}
		job.statusChan <- JOB_NO_MORE_COMMANDS
	}()
	return nil
}

// Complete is used to tell the job that it can perform cleanup
// like closing the shh connection.
func (job *Job) Complete() error {
	return job.sshclient.Close()
}
<commit_msg>Temporary solution<commit_after>package kraken

import (
	"errors"
	"io"

	"code.google.com/p/go.crypto/ssh"
)

var ErrNoMoreCommands = errors.New("No More Commands")

type jobStatus int

const (
	JOB_NO_MORE_COMMANDS jobStatus = iota
	JOB_REMOTE_CONNECTION_CLOSED
)

// Commander will receive terminal output and be asked what to do next
// by calling NextCommand until ErrNoMoreCommands is returned.
type Commander interface {
	NextCommand() ([]byte, error)
	io.Writer
}

type Job struct {
	sshclient  sshClient
	commander  Commander
	statusChan chan jobStatus
}

func NewJob(addr string, conf *ssh.ClientConfig, c Commander) *Job {
	job := Job{}
	job.sshclient = sshClient{address: addr, config: conf}
	job.commander = c
	return &job
}

// Start connects using the provided SSH details and reads/writes
// data over the connection. It also returns a channel to read
// job status messages from.
func (job *Job) Start() (<-chan jobStatus, error) {
	if err := job.sshclient.Connect(); err != nil {
		return nil, err
	}
	if err := job.startCommandLoop(); err != nil {
		return nil, err
	}
	job.statusChan = make(chan jobStatus)
	return job.statusChan, nil
}

func (job *Job) startCommandLoop() error {
	go func() {
		buffer := make([]byte, 100)
		for n, err := job.sshclient.Read(buffer); err == nil || n > 0; n, err = job.sshclient.Read(buffer) {
			_, cerr := job.commander.Write(buffer[:n])
			if cerr != nil {
				print(cerr)
			}
		}
		job.statusChan <- JOB_REMOTE_CONNECTION_CLOSED
	}()
	go func() {
		for command, err := job.commander.NextCommand(); err != ErrNoMoreCommands; command, err = job.commander.NextCommand() {
			job.sshclient.Write(command)
		}
		job.statusChan <- JOB_NO_MORE_COMMANDS
	}()
	return nil
}

// Complete is used to tell the job that it can perform cleanup
// like closing the shh connection.
func (job *Job) Complete() error {
	defer close(job.statusChan)
	return job.sshclient.Close()
}
<|endoftext|>


<commit_before>package schema

import (
	"math"
	"testing"

	"github.com/matryer/is"
)

const notBareNumber = false

func TestCastNumber(t *testing.T) {
	t.Run("Success", func(t *testing.T) {
		data := []struct {
			desc   string
			number string
			want   float64
			dc     string
			gc     string
			bn     bool
		}{
			{"Positive_WithSignal", "+10.10", 10.10, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"Positive_WithoutSignal", "10.10", 10.10, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"Negative", "-10.10", -10.10, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"BareNumber", "€95", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtBeginning", "€95", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtBeginningSpace", "EUR 95", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtEnd", "95%", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtEndSpace", "95 %", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"GroupChar", "100,000", 100000, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"DecimalChar", "95;10", 95.10, ";", defaultGroupChar, defaultBareNumber},
			{"Mix", "EUR 95;10", 95.10, ";", ";", notBareNumber},
		}
		for _, d := range data {
			t.Run(d.desc, func(t *testing.T) {
				is := is.New(t)
				got, err := castNumber(d.dc, d.gc, d.bn, d.number, Constraints{})
				is.NoErr(err)
				is.Equal(d.want, got)
			})
		}
	})
	t.Run("NaN", func(t *testing.T) {
		is := is.New(t)
		got, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "NaN", Constraints{})
		is.NoErr(err)
		is.True(math.IsNaN(got))
	})
	t.Run("INF", func(t *testing.T) {
		is := is.New(t)
		got, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "INF", Constraints{})
		is.NoErr(err)
		is.True(math.IsInf(got, 1))
	})
	t.Run("NegativeINF", func(t *testing.T) {
		is := is.New(t)
		got, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "-INF", Constraints{})
		is.NoErr(err)
		is.True(math.IsInf(got, -1))
	})
	t.Run("ValidMaximum", func(t *testing.T) {
		is := is.New(t)
		_, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "2", Constraints{Maximum: "2"})
		is.NoErr(err)
	})
	t.Run("ValidMinimum", func(t *testing.T) {
		is := is.New(t)
		_, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "2", Constraints{Minimum: "2"})
		is.NoErr(err)
	})
	t.Run("Error", func(t *testing.T) {
		data := []struct {
			desc        string
			number      string
			dc          string
			gc          string
			bn          bool
			constraints Constraints
		}{
			{"InvalidNumberToStrip_TooManyNumbers", "+10.10++10", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{}},
			{"NumBiggerThanMaximum", "3", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Maximum: "2"}},
			{"InvalidMaximum", "1", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Maximum: "boo"}},
			{"NumSmallerThanMinimum", "1", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Minimum: "2"}},
			{"InvalidMinimum", "1", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Minimum: "boo"}},
		}
		for _, d := range data {
			t.Run(d.desc, func(t *testing.T) {
				is := is.New(t)
				_, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, d.number, d.constraints)
				is.True(err != nil)
			})
		}
	})
}
<commit_msg>Add default decimal test cases.<commit_after>package schema

import (
	"math"
	"testing"

	"github.com/matryer/is"
)

const notBareNumber = false

func TestCastNumber(t *testing.T) {
	t.Run("Success", func(t *testing.T) {
		data := []struct {
			desc   string
			number string
			want   float64
			dc     string
			gc     string
			bn     bool
		}{
			{"Positive_WithSignal", "+10.10", 10.10, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"Positive_WithoutSignal", "10.10", 10.10, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"Negative", "-10.10", -10.10, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"BareNumber", "€95", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtBeginning", "€95", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtBeginningSpace", "EUR 95", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtEnd", "95%", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"BareNumber_TrailingAtEndSpace", "95 %", 95, defaultDecimalChar, defaultGroupChar, notBareNumber},
			{"GroupChar", "100,000", 100000, defaultDecimalChar, defaultGroupChar, defaultBareNumber},
			{"DecimalChar", "95;10", 95.10, ";", defaultGroupChar, defaultBareNumber},
			{"DecimalCharDefault", "95.10", 95.10, "", defaultGroupChar, defaultBareNumber},
			{"Mix", "EUR 95;10", 95.10, ";", ";", notBareNumber},
		}
		for _, d := range data {
			t.Run(d.desc, func(t *testing.T) {
				is := is.New(t)
				got, err := castNumber(d.dc, d.gc, d.bn, d.number, Constraints{})
				is.NoErr(err)
				is.Equal(d.want, got)
			})
		}
	})
	t.Run("NaN", func(t *testing.T) {
		is := is.New(t)
		got, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "NaN", Constraints{})
		is.NoErr(err)
		is.True(math.IsNaN(got))
	})
	t.Run("INF", func(t *testing.T) {
		is := is.New(t)
		got, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "INF", Constraints{})
		is.NoErr(err)
		is.True(math.IsInf(got, 1))
	})
	t.Run("NegativeINF", func(t *testing.T) {
		is := is.New(t)
		got, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "-INF", Constraints{})
		is.NoErr(err)
		is.True(math.IsInf(got, -1))
	})
	t.Run("ValidMaximum", func(t *testing.T) {
		is := is.New(t)
		_, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "2", Constraints{Maximum: "2"})
		is.NoErr(err)
	})
	t.Run("ValidMinimum", func(t *testing.T) {
		is := is.New(t)
		_, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, "2", Constraints{Minimum: "2"})
		is.NoErr(err)
	})
	t.Run("Error", func(t *testing.T) {
		data := []struct {
			desc        string
			number      string
			dc          string
			gc          string
			bn          bool
			constraints Constraints
		}{
			{"InvalidNumberToStrip_TooManyNumbers", "+10.10++10", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{}},
			{"NumBiggerThanMaximum", "3", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Maximum: "2"}},
			{"InvalidMaximum", "1", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Maximum: "boo"}},
			{"NumSmallerThanMinimum", "1", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Minimum: "2"}},
			{"InvalidMinimum", "1", defaultDecimalChar, defaultGroupChar, notBareNumber, Constraints{Minimum: "boo"}},
			{"DecimalCharDefault", "95;10", "", defaultGroupChar, defaultBareNumber, Constraints{}},
		}
		for _, d := range data {
			t.Run(d.desc, func(t *testing.T) {
				is := is.New(t)
				_, err := castNumber(defaultDecimalChar, defaultGroupChar, defaultBareNumber, d.number, d.constraints)
				is.True(err != nil)
			})
		}
	})
}
<|endoftext|>


<commit_before>package schema

import "testing"

// To be in par with the python library.
func TestDecodeString_URIMustRequireScheme(t *testing.T) {
	if _, err := decodeString(stringURI, "google.com", Constraints{}); err == nil {
		t.Errorf("want:err got:nil")
	}
}

func TestDecodeString_InvalidUUIDVersion(t *testing.T) {
	// This is a uuid3: namespace DNS and python.org.
	if _, err := decodeString(stringUUID, "6fa459ea-ee8a-3ca4-894e-db77e160355e", Constraints{}); err == nil {
		t.Errorf("want:err got:nil")
	}
}

func TestDecodeString_ErrorCheckingConstraints(t *testing.T) {
	data := []struct {
		desc        string
		value       string
		format      string
		constraints Constraints
	}{
		{"InvalidMinLength_UUID", "6fa459ea-ee8a-3ca4-894e-db77e160355e", stringUUID, Constraints{MinLength: 100}},
		{"InvalidMinLength_Email", "foo@bar.com", stringEmail, Constraints{MinLength: 100}},
		{"InvalidMinLength_URI", "http://google.com", stringURI, Constraints{MinLength: 100}},
		{"InvalidMaxLength_UUID", "6fa459ea-ee8a-3ca4-894e-db77e160355e", stringUUID, Constraints{MaxLength: 1}},
		{"InvalidMaxLength_Email", "foo@bar.com", stringEmail, Constraints{MaxLength: 1}},
		{"InvalidMaxLength_URI", "http://google.com", stringURI, Constraints{MaxLength: 1}},
		{"InvalidPattern_UUID", "6fa459ea-ee8a-3ca4-894e-db77e160355e", stringUUID, Constraints{Pattern: "^[0-9a-f]{1}-.*"}},
		{"InvalidPattern_Email", "foo@bar.com", stringEmail, Constraints{Pattern: "[0-9].*"}},
		{"InvalidPattern_URI", "http://google.com", stringURI, Constraints{Pattern: "^//.*"}},
	}
	for _, d := range data {
		t.Run(d.desc, func(t *testing.T) {
			if _, err := decodeString(d.format, d.value, d.constraints); err == nil {
				t.Fatalf("err want:err got:nil")
			}
		})
	}
}

func TestDecodeString_Success(t *testing.T) {
	var data = []struct {
		desc        string
		value       string
		format      string
		constraints Constraints
	}{
		{"URI", "http://google.com", stringURI, Constraints{MinLength: 1, Pattern: "^http://.*"}},
		{"Email", "foo@bar.com", stringEmail, Constraints{MinLength: 1, Pattern: ".*@.*"}},
		{"UUID", "C56A4180-65AA-42EC-A945-5FD21DEC0538", stringUUID, Constraints{MinLength: 36, MaxLength: 36, Pattern: "[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{8}"}},
	}
	for _, d := range data {
		t.Run(d.desc, func(t *testing.T) {
			v, err := decodeString(d.format, d.value, d.constraints)
			if err != nil {
				t.Errorf("want:nil got:%q", err)
			}
			if v != d.value {
				t.Errorf("want:%s got:%s", d.value, v)
			}
		})
	}
}
<commit_msg>add testing for invalid pattern of regexp<commit_after>package schema

import "testing"

// To be in par with the python library.
func TestDecodeString_URIMustRequireScheme(t *testing.T) {
	if _, err := decodeString(stringURI, "google.com", Constraints{}); err == nil {
		t.Errorf("want:err got:nil")
	}
}

func TestDecodeString_InvalidUUIDVersion(t *testing.T) {
	// This is a uuid3: namespace DNS and python.org.
	if _, err := decodeString(stringUUID, "6fa459ea-ee8a-3ca4-894e-db77e160355e", Constraints{}); err == nil {
		t.Errorf("want:err got:nil")
	}
}

func TestDecodeString_ErrorCheckingConstraints(t *testing.T) {
	data := []struct {
		desc        string
		value       string
		format      string
		constraints Constraints
	}{
		{"InvalidMinLength_UUID", "6fa459ea-ee8a-3ca4-894e-db77e160355e", stringUUID, Constraints{MinLength: 100}},
		{"InvalidMinLength_Email", "foo@bar.com", stringEmail, Constraints{MinLength: 100}},
		{"InvalidMinLength_URI", "http://google.com", stringURI, Constraints{MinLength: 100}},
		{"InvalidMaxLength_UUID", "6fa459ea-ee8a-3ca4-894e-db77e160355e", stringUUID, Constraints{MaxLength: 1}},
		{"InvalidMaxLength_Email", "foo@bar.com", stringEmail, Constraints{MaxLength: 1}},
		{"InvalidMaxLength_URI", "http://google.com", stringURI, Constraints{MaxLength: 1}},
		{"InvalidPattern_UUID", "6fa459ea-ee8a-3ca4-894e-db77e160355e", stringUUID, Constraints{Pattern: "^[0-9a-f]{1}-.*"}},
		{"InvalidPattern_Email", "foo@bar.com", stringEmail, Constraints{Pattern: "[0-9].*"}},
		{"InvalidPattern_URI", "http://google.com", stringURI, Constraints{Pattern: "^//.*"}},
		{"InvalidPattern", "http://google.com", stringURI, Constraints{Pattern: "\\"}},
	}
	for _, d := range data {
		t.Run(d.desc, func(t *testing.T) {
			if _, err := decodeString(d.format, d.value, d.constraints); err == nil {
				t.Fatalf("err want:err got:nil")
			}
		})
	}
}

func TestDecodeString_Success(t *testing.T) {
	var data = []struct {
		desc        string
		value       string
		format      string
		constraints Constraints
	}{
		{"URI", "http://google.com", stringURI, Constraints{MinLength: 1, Pattern: "^http://.*"}},
		{"Email", "foo@bar.com", stringEmail, Constraints{MinLength: 1, Pattern: ".*@.*"}},
		{"UUID", "C56A4180-65AA-42EC-A945-5FD21DEC0538", stringUUID, Constraints{MinLength: 36, MaxLength: 36, Pattern: "[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{8}"}},
	}
	for _, d := range data {
		t.Run(d.desc, func(t *testing.T) {
			v, err := decodeString(d.format, d.value, d.constraints)
			if err != nil {
				t.Errorf("want:nil got:%q", err)
			}
			if v != d.value {
				t.Errorf("want:%s got:%s", d.value, v)
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net/rpc"
	"net/rpc/jsonrpc"

	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket"
)

var jrpc *rpc.Client

func rpcInit() error {
	conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/rpc")
	if err != nil {
		return err
	}
	closeOnExit(conn)
	jrpc = jsonrpc.NewClient(conn)
	return nil
}

func ServerName() (string, error) {
	var name string
	err := jrpc.Call("Server.Name", nil, &name)
	return name, err
}

type Server struct {
	Name string
}

func ServerList() ([]Server, error) {
	var list []Server
	err := jrpc.Call("Server.List", nil, &list)
	return list, err
}
<commit_msg>Added MapList<commit_after>package main

import (
	"net/rpc"
	"net/rpc/jsonrpc"

	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket"
)

var jrpc *rpc.Client

func rpcInit() error {
	conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/rpc")
	if err != nil {
		return err
	}
	closeOnExit(conn)
	jrpc = jsonrpc.NewClient(conn)
	return nil
}

func ServerName() (string, error) {
	var name string
	err := jrpc.Call("Server.Name", nil, &name)
	return name, err
}

type Server struct {
	Name string
}

func ServerList() ([]Server, error) {
	var list []Server
	err := jrpc.Call("Server.List", nil, &list)
	return list, err
}

type Map struct {
	Name string
}

func MapList() ([]Map, error) {
	var list []Server
	err := jrpc.Call("Server.Maps", nil, &list)
	return list, err
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd 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 command

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"time"

	"github.com/coreos/etcd/client"
	etcdErr "github.com/coreos/etcd/error"
	"github.com/coreos/etcd/etcdserver"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/mvcc"
	"github.com/coreos/etcd/mvcc/backend"
	"github.com/coreos/etcd/mvcc/mvccpb"
	"github.com/coreos/etcd/pkg/pbutil"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/snap"
	"github.com/coreos/etcd/store"
	"github.com/coreos/etcd/wal"
	"github.com/coreos/etcd/wal/walpb"
	"github.com/gogo/protobuf/proto"
	"github.com/spf13/cobra"
)

var (
	migrateDatadir     string
	migrateWALdir      string
	migrateTransformer string
)

// NewMigrateCommand returns the cobra command for "migrate".
func NewMigrateCommand() *cobra.Command {
	mc := &cobra.Command{
		Use:   "migrate",
		Short: "Migrates keys in a v2 store to a mvcc store",
		Run:   migrateCommandFunc,
	}

	mc.Flags().StringVar(&migrateDatadir, "data-dir", "", "Path to the data directory")
	mc.Flags().StringVar(&migrateWALdir, "wal-dir", "", "Path to the WAL directory")
	mc.Flags().StringVar(&migrateTransformer, "transformer", "", "Path to the user-provided transformer program")
	return mc
}

func migrateCommandFunc(cmd *cobra.Command, args []string) {
	var (
		writer io.WriteCloser
		reader io.ReadCloser
		errc   chan error
	)
	if migrateTransformer != "" {
		writer, reader, errc = startTransformer()
	} else {
		fmt.Println("using default transformer")
		writer, reader, errc = defaultTransformer()
	}

	st := rebuildStoreV2()
	be := prepareBackend()
	defer be.Close()

	maxIndexc := make(chan uint64, 1)
	go func() {
		maxIndexc <- writeStore(writer, st)
		writer.Close()
	}()

	readKeys(reader, be)
	mvcc.UpdateConsistentIndex(be, <-maxIndexc)
	err := <-errc
	if err != nil {
		fmt.Println("failed to transform keys")
		ExitWithError(ExitError, err)
	}

	fmt.Println("finished transforming keys")
}

func prepareBackend() backend.Backend {
	dbpath := path.Join(migrateDatadir, "member", "snap", "db")
	be := backend.New(dbpath, time.Second, 10000)
	tx := be.BatchTx()
	tx.Lock()
	tx.UnsafeCreateBucket([]byte("key"))
	tx.UnsafeCreateBucket([]byte("meta"))
	tx.Unlock()
	return be
}

func rebuildStoreV2() store.Store {
	waldir := migrateWALdir
	if len(waldir) == 0 {
		waldir = path.Join(migrateDatadir, "member", "wal")
	}
	snapdir := path.Join(migrateDatadir, "member", "snap")

	ss := snap.New(snapdir)
	snapshot, err := ss.Load()
	if err != nil && err != snap.ErrNoSnapshot {
		ExitWithError(ExitError, err)
	}

	var walsnap walpb.Snapshot
	if snapshot != nil {
		walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term
	}

	w, err := wal.OpenForRead(waldir, walsnap)
	if err != nil {
		ExitWithError(ExitError, err)
	}
	defer w.Close()

	_, _, ents, err := w.ReadAll()
	if err != nil {
		ExitWithError(ExitError, err)
	}

	st := store.New()
	if snapshot != nil {
		err := st.Recovery(snapshot.Data)
		if err != nil {
			ExitWithError(ExitError, err)
		}
	}

	applier := etcdserver.NewApplierV2(st, nil)
	for _, ent := range ents {
		if ent.Type != raftpb.EntryNormal {
			continue
		}

		var raftReq pb.InternalRaftRequest
		if !pbutil.MaybeUnmarshal(&raftReq, ent.Data) { // backward compatible
			var r pb.Request
			pbutil.MustUnmarshal(&r, ent.Data)
			applyRequest(&r, applier)
		} else {
			if raftReq.V2 != nil {
				req := raftReq.V2
				applyRequest(req, applier)
			}
		}
	}

	return st
}

func applyRequest(r *pb.Request, applyV2 etcdserver.ApplierV2) {
	toTTLOptions(r)
	switch r.Method {
	case "POST":
		applyV2.Post(r)
	case "PUT":
		applyV2.Put(r)
	case "DELETE":
		applyV2.Delete(r)
	case "QGET":
		applyV2.QGet(r)
	case "SYNC":
		applyV2.Sync(r)
	default:
		panic("unknown command")
	}
}

func toTTLOptions(r *pb.Request) store.TTLOptionSet {
	refresh, _ := pbutil.GetBool(r.Refresh)
	ttlOptions := store.TTLOptionSet{Refresh: refresh}
	if r.Expiration != 0 {
		ttlOptions.ExpireTime = time.Unix(0, r.Expiration)
	}
	return ttlOptions
}

func writeStore(w io.Writer, st store.Store) uint64 {
	all, err := st.Get("/1", true, true)
	if err != nil {
		if eerr, ok := err.(*etcdErr.Error); ok && eerr.ErrorCode == etcdErr.EcodeKeyNotFound {
			fmt.Println("no v2 keys to migrate")
			os.Exit(0)
		}
		ExitWithError(ExitError, err)
	}
	return writeKeys(w, all.Node)
}

func writeKeys(w io.Writer, n *store.NodeExtern) uint64 {
	maxIndex := n.ModifiedIndex

	nodes := n.Nodes
	// remove store v2 bucket prefix
	n.Key = n.Key[2:]
	if n.Key == "" {
		n.Key = "/"
	}
	if n.Dir {
		n.Nodes = nil
	}
	b, err := json.Marshal(n)
	if err != nil {
		ExitWithError(ExitError, err)
	}
	fmt.Fprintf(w, string(b))
	for _, nn := range nodes {
		max := writeKeys(w, nn)
		if max > maxIndex {
			maxIndex = max
		}
	}
	return maxIndex
}

func readKeys(r io.Reader, be backend.Backend) error {
	for {
		length64, err := readInt64(r)
		if err != nil {
			if err == io.EOF {
				return nil
			}
			return err
		}

		buf := make([]byte, int(length64))
		if _, err = io.ReadFull(r, buf); err != nil {
			return err
		}

		var kv mvccpb.KeyValue
		err = proto.Unmarshal(buf, &kv)
		if err != nil {
			return err
		}

		mvcc.WriteKV(be, kv)
	}
}

func readInt64(r io.Reader) (int64, error) {
	var n int64
	err := binary.Read(r, binary.LittleEndian, &n)
	return n, err
}

func startTransformer() (io.WriteCloser, io.ReadCloser, chan error) {
	cmd := exec.Command(migrateTransformer)
	cmd.Stderr = os.Stderr

	writer, err := cmd.StdinPipe()
	if err != nil {
		ExitWithError(ExitError, err)
	}

	reader, rerr := cmd.StdoutPipe()
	if rerr != nil {
		ExitWithError(ExitError, rerr)
	}

	if err := cmd.Start(); err != nil {
		ExitWithError(ExitError, err)
	}

	errc := make(chan error, 1)

	go func() {
		errc <- cmd.Wait()
	}()

	return writer, reader, errc
}

func defaultTransformer() (io.WriteCloser, io.ReadCloser, chan error) {
	// transformer decodes v2 keys from sr
	sr, sw := io.Pipe()
	// transformer encodes v3 keys into dw
	dr, dw := io.Pipe()

	decoder := json.NewDecoder(sr)

	errc := make(chan error, 1)

	go func() {
		defer func() {
			sr.Close()
			dw.Close()
		}()

		for decoder.More() {
			node := &client.Node{}
			if err := decoder.Decode(node); err != nil {
				errc <- err
				return
			}

			kv := transform(node)
			if kv == nil {
				continue
			}

			data, err := proto.Marshal(kv)
			if err != nil {
				errc <- err
				return
			}
			buf := make([]byte, 8)
			binary.LittleEndian.PutUint64(buf, uint64(len(data)))
			if _, err := dw.Write(buf); err != nil {
				errc <- err
				return
			}
			if _, err := dw.Write(data); err != nil {
				errc <- err
				return
			}
		}

		errc <- nil
	}()

	return sw, dr, errc
}

func transform(n *client.Node) *mvccpb.KeyValue {
	const unKnownVersion = 1
	if n.Dir {
		return nil
	}
	kv := &mvccpb.KeyValue{
		Key:            []byte(n.Key),
		Value:          []byte(n.Value),
		CreateRevision: int64(n.CreatedIndex),
		ModRevision:    int64(n.ModifiedIndex),
		Version:        unKnownVersion,
	}
	return kv
}
<commit_msg>etcdctl: fix migrate in outputing client.Node to json<commit_after>// Copyright 2016 The etcd 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 command

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"time"

	"github.com/coreos/etcd/client"
	etcdErr "github.com/coreos/etcd/error"
	"github.com/coreos/etcd/etcdserver"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/mvcc"
	"github.com/coreos/etcd/mvcc/backend"
	"github.com/coreos/etcd/mvcc/mvccpb"
	"github.com/coreos/etcd/pkg/pbutil"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/snap"
	"github.com/coreos/etcd/store"
	"github.com/coreos/etcd/wal"
	"github.com/coreos/etcd/wal/walpb"
	"github.com/gogo/protobuf/proto"
	"github.com/spf13/cobra"
)

var (
	migrateDatadir     string
	migrateWALdir      string
	migrateTransformer string
)

// NewMigrateCommand returns the cobra command for "migrate".
func NewMigrateCommand() *cobra.Command {
	mc := &cobra.Command{
		Use:   "migrate",
		Short: "Migrates keys in a v2 store to a mvcc store",
		Run:   migrateCommandFunc,
	}

	mc.Flags().StringVar(&migrateDatadir, "data-dir", "", "Path to the data directory")
	mc.Flags().StringVar(&migrateWALdir, "wal-dir", "", "Path to the WAL directory")
	mc.Flags().StringVar(&migrateTransformer, "transformer", "", "Path to the user-provided transformer program")
	return mc
}

func migrateCommandFunc(cmd *cobra.Command, args []string) {
	var (
		writer io.WriteCloser
		reader io.ReadCloser
		errc   chan error
	)
	if migrateTransformer != "" {
		writer, reader, errc = startTransformer()
	} else {
		fmt.Println("using default transformer")
		writer, reader, errc = defaultTransformer()
	}

	st := rebuildStoreV2()
	be := prepareBackend()
	defer be.Close()

	maxIndexc := make(chan uint64, 1)
	go func() {
		maxIndexc <- writeStore(writer, st)
		writer.Close()
	}()

	readKeys(reader, be)
	mvcc.UpdateConsistentIndex(be, <-maxIndexc)
	err := <-errc
	if err != nil {
		fmt.Println("failed to transform keys")
		ExitWithError(ExitError, err)
	}

	fmt.Println("finished transforming keys")
}

func prepareBackend() backend.Backend {
	dbpath := path.Join(migrateDatadir, "member", "snap", "db")
	be := backend.New(dbpath, time.Second, 10000)
	tx := be.BatchTx()
	tx.Lock()
	tx.UnsafeCreateBucket([]byte("key"))
	tx.UnsafeCreateBucket([]byte("meta"))
	tx.Unlock()
	return be
}

func rebuildStoreV2() store.Store {
	waldir := migrateWALdir
	if len(waldir) == 0 {
		waldir = path.Join(migrateDatadir, "member", "wal")
	}
	snapdir := path.Join(migrateDatadir, "member", "snap")

	ss := snap.New(snapdir)
	snapshot, err := ss.Load()
	if err != nil && err != snap.ErrNoSnapshot {
		ExitWithError(ExitError, err)
	}

	var walsnap walpb.Snapshot
	if snapshot != nil {
		walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term
	}

	w, err := wal.OpenForRead(waldir, walsnap)
	if err != nil {
		ExitWithError(ExitError, err)
	}
	defer w.Close()

	_, _, ents, err := w.ReadAll()
	if err != nil {
		ExitWithError(ExitError, err)
	}

	st := store.New()
	if snapshot != nil {
		err := st.Recovery(snapshot.Data)
		if err != nil {
			ExitWithError(ExitError, err)
		}
	}

	applier := etcdserver.NewApplierV2(st, nil)
	for _, ent := range ents {
		if ent.Type != raftpb.EntryNormal {
			continue
		}

		var raftReq pb.InternalRaftRequest
		if !pbutil.MaybeUnmarshal(&raftReq, ent.Data) { // backward compatible
			var r pb.Request
			pbutil.MustUnmarshal(&r, ent.Data)
			applyRequest(&r, applier)
		} else {
			if raftReq.V2 != nil {
				req := raftReq.V2
				applyRequest(req, applier)
			}
		}
	}

	return st
}

func applyRequest(r *pb.Request, applyV2 etcdserver.ApplierV2) {
	toTTLOptions(r)
	switch r.Method {
	case "POST":
		applyV2.Post(r)
	case "PUT":
		applyV2.Put(r)
	case "DELETE":
		applyV2.Delete(r)
	case "QGET":
		applyV2.QGet(r)
	case "SYNC":
		applyV2.Sync(r)
	default:
		panic("unknown command")
	}
}

func toTTLOptions(r *pb.Request) store.TTLOptionSet {
	refresh, _ := pbutil.GetBool(r.Refresh)
	ttlOptions := store.TTLOptionSet{Refresh: refresh}
	if r.Expiration != 0 {
		ttlOptions.ExpireTime = time.Unix(0, r.Expiration)
	}
	return ttlOptions
}

func writeStore(w io.Writer, st store.Store) uint64 {
	all, err := st.Get("/1", true, true)
	if err != nil {
		if eerr, ok := err.(*etcdErr.Error); ok && eerr.ErrorCode == etcdErr.EcodeKeyNotFound {
			fmt.Println("no v2 keys to migrate")
			os.Exit(0)
		}
		ExitWithError(ExitError, err)
	}
	return writeKeys(w, all.Node)
}

func writeKeys(w io.Writer, n *store.NodeExtern) uint64 {
	maxIndex := n.ModifiedIndex

	nodes := n.Nodes
	// remove store v2 bucket prefix
	n.Key = n.Key[2:]
	if n.Key == "" {
		n.Key = "/"
	}
	if n.Dir {
		n.Nodes = nil
	}
	b, err := json.Marshal(n)
	if err != nil {
		ExitWithError(ExitError, err)
	}
	fmt.Fprint(w, string(b))
	for _, nn := range nodes {
		max := writeKeys(w, nn)
		if max > maxIndex {
			maxIndex = max
		}
	}
	return maxIndex
}

func readKeys(r io.Reader, be backend.Backend) error {
	for {
		length64, err := readInt64(r)
		if err != nil {
			if err == io.EOF {
				return nil
			}
			return err
		}

		buf := make([]byte, int(length64))
		if _, err = io.ReadFull(r, buf); err != nil {
			return err
		}

		var kv mvccpb.KeyValue
		err = proto.Unmarshal(buf, &kv)
		if err != nil {
			return err
		}

		mvcc.WriteKV(be, kv)
	}
}

func readInt64(r io.Reader) (int64, error) {
	var n int64
	err := binary.Read(r, binary.LittleEndian, &n)
	return n, err
}

func startTransformer() (io.WriteCloser, io.ReadCloser, chan error) {
	cmd := exec.Command(migrateTransformer)
	cmd.Stderr = os.Stderr

	writer, err := cmd.StdinPipe()
	if err != nil {
		ExitWithError(ExitError, err)
	}

	reader, rerr := cmd.StdoutPipe()
	if rerr != nil {
		ExitWithError(ExitError, rerr)
	}

	if err := cmd.Start(); err != nil {
		ExitWithError(ExitError, err)
	}

	errc := make(chan error, 1)

	go func() {
		errc <- cmd.Wait()
	}()

	return writer, reader, errc
}

func defaultTransformer() (io.WriteCloser, io.ReadCloser, chan error) {
	// transformer decodes v2 keys from sr
	sr, sw := io.Pipe()
	// transformer encodes v3 keys into dw
	dr, dw := io.Pipe()

	decoder := json.NewDecoder(sr)

	errc := make(chan error, 1)

	go func() {
		defer func() {
			sr.Close()
			dw.Close()
		}()

		for decoder.More() {
			node := &client.Node{}
			if err := decoder.Decode(node); err != nil {
				errc <- err
				return
			}

			kv := transform(node)
			if kv == nil {
				continue
			}

			data, err := proto.Marshal(kv)
			if err != nil {
				errc <- err
				return
			}
			buf := make([]byte, 8)
			binary.LittleEndian.PutUint64(buf, uint64(len(data)))
			if _, err := dw.Write(buf); err != nil {
				errc <- err
				return
			}
			if _, err := dw.Write(data); err != nil {
				errc <- err
				return
			}
		}

		errc <- nil
	}()

	return sw, dr, errc
}

func transform(n *client.Node) *mvccpb.KeyValue {
	const unKnownVersion = 1
	if n.Dir {
		return nil
	}
	kv := &mvccpb.KeyValue{
		Key:            []byte(n.Key),
		Value:          []byte(n.Value),
		CreateRevision: int64(n.CreatedIndex),
		ModRevision:    int64(n.ModifiedIndex),
		Version:        unKnownVersion,
	}
	return kv
}
<|endoftext|>


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

package themefiles

const ScreenCss = `
html {
    font-size: 100%;
    overflow-y: scroll;
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
}

body {
    color: #444;
    font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', "Hiragino Sans GB", "STXihei", "微软雅黑", serif;
    font-size: 12px;
    line-height: 1.5em;
    background: #fefefe;
    width: 75%;
    margin: 10px auto;
    padding: 1em;
    outline: 1300px solid #FAFAFA;
}

body>nav {
    font-size: 0.8em;
}

body>nav>ul.breadcrumb {
    list-style: none;
    margin: 0;
    padding: 0;
}

body>nav>ul.breadcrumb>li {
    display: inline;
}

body>nav>ul.breadcrumb>li:after {
    content: ">";
}

body>nav>ul.breadcrumb>li:last-child:after {
    content: "";
}

a {
    color: #0645ad;
    text-decoration: none;
}

a:visited {
    color: #0b0080;
}

a:hover {
    color: #06e;
}

a:active {
    color: #faa700;
}

a:focus {
    outline: thin dotted;
}

a:hover, a:active {
    outline: 0;
}

span.backtick {
    border: 1px solid #EAEAEA;
    border-radius: 3px;
    background: #F8F8F8;
    padding: 0 3px 0 3px;
}

::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

::selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

a::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

a::selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

p {
    margin: 1em 0;
}

img {
    max-width: 100%;
}

h1,h2,h3,h4,h5,h6 {
    font-weight: normal;
    color: #111;
    line-height: 1em;
}

h4,h5,h6 {
    font-weight: bold;
}

h1 {
    font-size: 2.5em;
    margin: 0 0 15px 0;
}

h2 {
    font-size: 2em;
    border-bottom: 1px solid silver;
    padding-bottom: 5px;
}

h3 {
    font-size: 1.5em;
}

h4 {
    font-size: 1.2em;
}

h5 {
    font-size: 1em;
}

h6 {
    font-size: 0.9em;
}

blockquote {
    color: #666666;
    margin: 0;
    padding-left: 3em;
    border-left: 0.5em #EEE solid;
}

hr {
    display: block;
    height: 2px;
    border: 0;
    border-top: 1px solid #aaa;
    border-bottom: 1px solid #eee;
    margin: 1em 0;
    padding: 0;
}

pre , code, kbd, samp {
    color: #000;
    font-family: monospace;
    font-size: 0.88em;
    border-radius: 3px;
    background-color: #F8F8F8;
    border: 1px solid #CCC;
}

pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
    padding: 5px 12px;
}

pre code {
    border: 0px !important;
    padding: 0;
}

code {
    padding: 0 3px 0 3px;
}

b, strong {
    font-weight: bold;
}

dfn {
    font-style: italic;
}

ins {
    background: #ff9;
    color: #000;
    text-decoration: none;
}

mark {
    background: #ff0;
    color: #000;
    font-style: italic;
    font-weight: bold;
}

sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

ul, ol {
    margin: 1em 0;
    padding: 0 0 0 2em;
}

li p:last-child {
    margin: 0;
}

dd {
    margin: 0 0 0 2em;
}

img {
    border: 0;
    -ms-interpolation-mode: bicubic;
    vertical-align: middle;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

td {
    vertical-align: top;
}

article>.description {
    font-size: 1.2em;
}

.subentries {
    list-style: none;
    padding: 5px 0 5px 0;
    margin: 0 0 0 15px;
}

.subentries>.subentry {
    margin: 0 0 15px 0;
}

.subentries>.subentry:nth-child(odd) {
    background-color:#eee;
}

.subentries>.subentry:nth-child(even) {
    background-color:transparent;
}

.imagegallery>h1 {
    font-size: 1.2em;
}

.imagegallery ol {
    list-style: none;
    margin-left: 0;
}

.filelinks>h1 {
    font-size: 1.2em;
}

.filelinks ol {
    margin-left: 0;
}

.collection>h1 {
    font-size: 1.2em;
}

.csv {
    margin: 20px 0 0 20px;
    overflow: auto;
}

.csv>h1 {
    font-size: 1.2em;
}

.csv>table
{
    font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
    font-size: 1.0em;
    margin: 10px 45px 10px 45px;
    text-align: left;
    border-collapse: collapse;
    border: 1px solid #69c;
}

.csv>table thead
{
    padding: 12px 17px 12px 17px;
    font-weight: normal;
    font-size: 1.2em;
    color: #039;
    border-bottom: 1px dashed #69c;
}

.csv>table td
{
    padding: 7px 17px 7px 17px;
    color: #669;
}

.csv>table tbody tr:hover td
{
    color: #339;
    background: #d0dafd;
}

.pdf {
    width: 80%;
    max-height: 80%;
}

.pdf>h1 {
    font-size: 1.2em;
}

.pdf .metadata {
    float: left;
    font-size: 1.0em;
    margin: 0 15px 0 0;
}

.pdf .metadata .entry {
    margin: 0 0 10px 0;
}

.pdf .previewarea {
    display: block;
    overflow: auto;
    box-shadow: 0 0 10px #000000;
}

.pdf .previewarea canvas {
    float: none;
}

.video>h1 {
    font-size: 1.2em;
}

.audio>h1 {
    font-size: 1.2em;
}

.presentation nav {
    float: left;
    margin: 25px 0 15px 0;
    width: 100%;
    text-align: center;
}

.presentation nav .controls {
    float: left;
}

.presentation nav .pager {
    display: inline;
    cursor: default;
}

.presentation nav .jumper {
    float: right;
}

.presentation .content {
    clear: left;
}

.presentation .slide {
    float: none;
    box-shadow: 0 0 10px #000000;
    padding: 10px;
}

@media only screen and (max-width: 480px) {
    body {
        font-size: 12px;
        width: 95%;
    }

    .presentation nav {
        margin: 25px 0 15px 0;
        width: 100%;
    }

    .presentation nav .pager {
        float: right;
    }

    .presentation nav .jumper {
        display: none;
    }
}

@media only screen and (min-width: 480px) {
    body {
        font-size: 14px;
        width: 95%;
    }
}

@media only screen and (min-width: 768px) {
    body {
        font-size: 16px;
        width: 95%;
    }
}

@media only screen and (min-width: 1024px) {
    body {
        font-size: 16px;
        width: 75%;
    }
}`
<commit_msg> Updated the screen.css of the default theme to increase the min height for presentation slides<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package themefiles

const ScreenCss = `
html {
    height: 100%;
    font-size: 100%;
    overflow-y: scroll;
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
}

body {
    color: #444;
    font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', "Hiragino Sans GB", "STXihei", "微软雅黑", serif;
    font-size: 12px;
    line-height: 1.5em;
    background: #fefefe;
    width: 75%;
    height: 100%;
    margin: 10px auto;
    padding: 1em;
    outline: 1300px solid #FAFAFA;
}

body>nav {
    font-size: 0.8em;
}

body>nav>ul.breadcrumb {
    list-style: none;
    margin: 0;
    padding: 0;
}

body>nav>ul.breadcrumb>li {
    display: inline;
}

body>nav>ul.breadcrumb>li:after {
    content: ">";
}

body>nav>ul.breadcrumb>li:last-child:after {
    content: "";
}

a {
    color: #0645ad;
    text-decoration: none;
}

a:visited {
    color: #0b0080;
}

a:hover {
    color: #06e;
}

a:active {
    color: #faa700;
}

a:focus {
    outline: thin dotted;
}

a:hover, a:active {
    outline: 0;
}

span.backtick {
    border: 1px solid #EAEAEA;
    border-radius: 3px;
    background: #F8F8F8;
    padding: 0 3px 0 3px;
}

::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

::selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

a::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

a::selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

p {
    margin: 1em 0;
}

img {
    max-width: 100%;
}

h1,h2,h3,h4,h5,h6 {
    font-weight: normal;
    color: #111;
    line-height: 1em;
}

h4,h5,h6 {
    font-weight: bold;
}

h1 {
    font-size: 2.5em;
    margin: 0 0 15px 0;
}

h2 {
    font-size: 2em;
    border-bottom: 1px solid silver;
    padding-bottom: 5px;
}

h3 {
    font-size: 1.5em;
}

h4 {
    font-size: 1.2em;
}

h5 {
    font-size: 1em;
}

h6 {
    font-size: 0.9em;
}

blockquote {
    color: #666666;
    margin: 0;
    padding-left: 3em;
    border-left: 0.5em #EEE solid;
}

hr {
    display: block;
    height: 2px;
    border: 0;
    border-top: 1px solid #aaa;
    border-bottom: 1px solid #eee;
    margin: 1em 0;
    padding: 0;
}

pre , code, kbd, samp {
    color: #000;
    font-family: monospace;
    font-size: 0.88em;
    border-radius: 3px;
    background-color: #F8F8F8;
    border: 1px solid #CCC;
}

pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
    padding: 5px 12px;
}

pre code {
    border: 0px !important;
    padding: 0;
}

code {
    padding: 0 3px 0 3px;
}

b, strong {
    font-weight: bold;
}

dfn {
    font-style: italic;
}

ins {
    background: #ff9;
    color: #000;
    text-decoration: none;
}

mark {
    background: #ff0;
    color: #000;
    font-style: italic;
    font-weight: bold;
}

sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

ul, ol {
    margin: 1em 0;
    padding: 0 0 0 2em;
}

li p:last-child {
    margin: 0;
}

dd {
    margin: 0 0 0 2em;
}

img {
    border: 0;
    -ms-interpolation-mode: bicubic;
    vertical-align: middle;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

td {
    vertical-align: top;
}

article>.description {
    font-size: 1.2em;
}

.subentries {
    list-style: none;
    padding: 5px 0 5px 0;
    margin: 0 0 0 15px;
}

.subentries>.subentry {
    margin: 0 0 15px 0;
}

.subentries>.subentry:nth-child(odd) {
    background-color:#eee;
}

.subentries>.subentry:nth-child(even) {
    background-color:transparent;
}

.imagegallery>h1 {
    font-size: 1.2em;
}

.imagegallery ol {
    list-style: none;
    margin-left: 0;
}

.filelinks>h1 {
    font-size: 1.2em;
}

.filelinks ol {
    margin-left: 0;
}

.collection>h1 {
    font-size: 1.2em;
}

.csv {
    margin: 20px 0 0 20px;
    overflow: auto;
}

.csv>h1 {
    font-size: 1.2em;
}

.csv>table
{
    font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
    font-size: 1.0em;
    margin: 10px 45px 10px 45px;
    text-align: left;
    border-collapse: collapse;
    border: 1px solid #69c;
}

.csv>table thead
{
    padding: 12px 17px 12px 17px;
    font-weight: normal;
    font-size: 1.2em;
    color: #039;
    border-bottom: 1px dashed #69c;
}

.csv>table td
{
    padding: 7px 17px 7px 17px;
    color: #669;
}

.csv>table tbody tr:hover td
{
    color: #339;
    background: #d0dafd;
}

.pdf {
    width: 80%;
    max-height: 80%;
}

.pdf>h1 {
    font-size: 1.2em;
}

.pdf .metadata {
    float: left;
    font-size: 1.0em;
    margin: 0 15px 0 0;
}

.pdf .metadata .entry {
    margin: 0 0 10px 0;
}

.pdf .previewarea {
    display: block;
    overflow: auto;
    box-shadow: 0 0 10px #000000;
}

.pdf .previewarea canvas {
    float: none;
}

.video>h1 {
    font-size: 1.2em;
}

.audio>h1 {
    font-size: 1.2em;
}

.presentation nav {
    float: left;
    margin: 25px 0 15px 0;
    width: 100%;
    text-align: center;
}

.presentation nav .controls {
    float: left;
}

.presentation nav .pager {
    display: inline;
    cursor: default;
}

.presentation nav .jumper {
    float: right;
}

.presentation .content {
    clear: left;
}

.presentation .slide {
    float: none;
    box-shadow: 0 0 10px #000000;
    padding: 10px;
}

@media only screen and (max-height: 500px) {
    .presentation .slide {
        min-height: 220px;
    }
}

@media only screen and (min-height: 500px) {
    .presentation .slide {
        min-height: 320px;
    }
}

@media only screen and (min-height: 600px) {
    .presentation .slide {
        min-height: 420px;
    }
}

@media only screen and (min-height: 768px) {
    .presentation .slide {
        min-height: 520px;
    }
}

@media only screen and (max-width: 480px) {
    body {
        font-size: 12px;
        width: 95%;
    }

    .presentation nav {
        margin: 25px 0 15px 0;
        width: 100%;
    }

    .presentation nav .pager {
        float: right;
    }

    .presentation nav .jumper {
        display: none;
    }
}

@media only screen and (min-width: 480px) {
    body {
        font-size: 14px;
        width: 95%;
    }
}

@media only screen and (min-width: 768px) {
    body {
        font-size: 16px;
        width: 95%;
    }
}

@media only screen and (min-width: 1024px) {
    body {
        font-size: 16px;
        width: 75%;
    }
}`
<|endoftext|>


<commit_before>package editor

import (
	"fmt"
	"strings"

	"github.com/elpinal/coco3/screen"
)

type search struct {
	streamSet
	*editor

	basic *basic
}

func newSearch(s streamSet, e *editor) *search {
	return &search{
		streamSet: s,
		editor:    e,
		basic:     &basic{},
	}
}

func (se *search) Mode() mode {
	return modeSearch
}

func (se *search) Position() int {
	return se.basic.pos + 1
}

func (se *search) Runes() []rune {
	return se.buf
}

func (se *search) Message() []rune {
	return append([]rune{'/'}, se.basic.buf...)
}

func (se *search) Highlight() *screen.Hi {
	return nil
}

func (se *search) Run() (end continuity, next mode, err error) {
	next = modeSearch
	r, _, err := se.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	switch r {
	case CharCtrlM, CharCtrlJ:
	case CharEscape, CharCtrlC:
		return end, modeNormal, err
	case CharBackspace, CharCtrlH:
		if len(se.basic.buf) == 0 {
			next = modeNormal
			return
		}
		se.basic.delete(se.basic.pos-1, se.basic.pos)
	case CharCtrlB:
		se.basic.move(0)
	case CharCtrlE:
		se.basic.move(len(se.basic.buf))
	case CharCtrlU:
		se.basic.delete(0, se.basic.pos)
	case CharCtrlW:
		// FIXME: It's redundant.
		ed := newEditor()
		ed.pos = se.basic.pos
		ed.buf = se.basic.buf
		pos := ed.pos
		ed.wordBackward()
		se.basic.delete(pos, ed.pos)
		return
	default:
		se.basic.insert([]rune{r}, se.basic.pos)
	}
	if r != CharCtrlM && r != CharCtrlJ {
		return
	}
	next = modeNormal
	s := string(se.basic.buf)
	if s == "" {
		return
	}
	i, err := se.search(s)
	if err != nil {
		return end, next, err
	}
	se.move(i)
	return
}

func (se *search) search(s string) (int, error) {
	i := strings.Index(string(se.buf[se.pos:]), s)
	if i < 0 {
		return 0, fmt.Errorf("pattern not found: %q", s)
	}
	return i+se.pos, nil
}
<commit_msg>Search first text after cursor<commit_after>package editor

import (
	"fmt"
	"strings"

	"github.com/elpinal/coco3/screen"
)

type search struct {
	streamSet
	*editor

	basic *basic
}

func newSearch(s streamSet, e *editor) *search {
	return &search{
		streamSet: s,
		editor:    e,
		basic:     &basic{},
	}
}

func (se *search) Mode() mode {
	return modeSearch
}

func (se *search) Position() int {
	return se.basic.pos + 1
}

func (se *search) Runes() []rune {
	return se.buf
}

func (se *search) Message() []rune {
	return append([]rune{'/'}, se.basic.buf...)
}

func (se *search) Highlight() *screen.Hi {
	return nil
}

func (se *search) Run() (end continuity, next mode, err error) {
	next = modeSearch
	r, _, err := se.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	switch r {
	case CharCtrlM, CharCtrlJ:
	case CharEscape, CharCtrlC:
		return end, modeNormal, err
	case CharBackspace, CharCtrlH:
		if len(se.basic.buf) == 0 {
			next = modeNormal
			return
		}
		se.basic.delete(se.basic.pos-1, se.basic.pos)
	case CharCtrlB:
		se.basic.move(0)
	case CharCtrlE:
		se.basic.move(len(se.basic.buf))
	case CharCtrlU:
		se.basic.delete(0, se.basic.pos)
	case CharCtrlW:
		// FIXME: It's redundant.
		ed := newEditor()
		ed.pos = se.basic.pos
		ed.buf = se.basic.buf
		pos := ed.pos
		ed.wordBackward()
		se.basic.delete(pos, ed.pos)
		return
	default:
		se.basic.insert([]rune{r}, se.basic.pos)
	}
	if r != CharCtrlM && r != CharCtrlJ {
		return
	}
	next = modeNormal
	s := string(se.basic.buf)
	if s == "" {
		return
	}
	i, err := se.search(s)
	if err != nil {
		return end, next, err
	}
	se.move(i)
	return
}

func (se *search) search(s string) (int, error) {
	i := strings.Index(string(se.slice(se.pos+1, len(se.buf))), s)
	if i < 0 {
		return 0, fmt.Errorf("pattern not found: %q", s)
	}
	return i + se.pos + 1, nil
}
<|endoftext|>


<commit_before>// +build windows
package main

import (
	"bytes"
	"context"
	"encoding/binary"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/go-ole/go-ole"
	"github.com/moutend/go-wca"
)

var version = "latest"
var revision = "latest"

type WAVEFormat struct {
	FormatTag      uint16
	Channels       uint16
	SamplesPerSec  uint32
	AvgBytesPerSec uint32
	BlockAlign     uint16
	BitsPerSample  uint16
	DataSize       uint32
	RawData        []byte
}

func (v *WAVEFormat) Bytes() (output []byte) {
	buf := new(bytes.Buffer)

	binary.Write(buf, binary.BigEndian, []byte("RIFF"))
	binary.Write(buf, binary.LittleEndian, uint32(v.DataSize+36)) // Header size is 44 byte, so 44 - 8 = 36
	binary.Write(buf, binary.BigEndian, []byte("WAVEfmt "))
	binary.Write(buf, binary.LittleEndian, uint32(16)) // 16 (0x10000000) for PCM
	binary.Write(buf, binary.LittleEndian, uint16(1))  // 1 (0x0001) for PCM
	binary.Write(buf, binary.LittleEndian, v.Channels)
	binary.Write(buf, binary.LittleEndian, v.SamplesPerSec)
	binary.Write(buf, binary.LittleEndian, v.AvgBytesPerSec)
	binary.Write(buf, binary.LittleEndian, v.BlockAlign)
	binary.Write(buf, binary.LittleEndian, v.BitsPerSample)
	binary.Write(buf, binary.BigEndian, []byte("data"))
	binary.Write(buf, binary.LittleEndian, v.DataSize)
	binary.Write(buf, binary.LittleEndian, v.RawData)

	return buf.Bytes()
}

type DurationFlag struct {
	Value time.Duration
}

func (f *DurationFlag) Set(value string) (err error) {
	var sec float64

	if sec, err = strconv.ParseFloat(value, 64); err != nil {
		return
	}
	f.Value = time.Duration(sec * float64(time.Second))
	return
}

func (f *DurationFlag) String() string {
	return f.Value.String()
}

type FilenameFlag struct {
	Value string
}

func (f *FilenameFlag) Set(value string) (err error) {
	if !strings.HasSuffix(value, ".wav") {
		err = fmt.Errorf("specify WAVE audio file (*.wav)")
		return
	}
	f.Value = value
	return
}

func (f *FilenameFlag) String() string {
	return f.Value
}

func main() {
	var err error
	if err = run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) (err error) {
	var durationFlag DurationFlag
	var filenameFlag FilenameFlag
	var versionFlag bool
	var audio *WAVEFormat

	f := flag.NewFlagSet(args[0], flag.ExitOnError)
	f.Var(&durationFlag, "duration", "Specify recording duration in second")
	f.Var(&durationFlag, "d", "Alias of --duration")
	f.Var(&filenameFlag, "output", "file name")
	f.Var(&filenameFlag, "o", "Alias of --output")
	f.BoolVar(&versionFlag, "version", false, "Show version")
	f.Parse(args[1:])

	if versionFlag {
		fmt.Printf("%s-%s\n", version, revision)
		return
	}
	if filenameFlag.Value == "" {
		return
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		select {
		case <-signalChan:
			fmt.Println("Interrupted by SIGINT")
			cancel()
		}
		return
	}()

	if audio, err = captureSharedTimerDriven(ctx, durationFlag.Value); err != nil {
		return
	}
	if err = ioutil.WriteFile(filenameFlag.Value, audio.Bytes(), 0644); err != nil {
		return
	}
	fmt.Println("Successfully done")
	return
}

func captureSharedTimerDriven(ctx context.Context, duration time.Duration) (audio *WAVEFormat, err error) {
	if err = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED); err != nil {
		return
	}
	defer ole.CoUninitialize()

	var mmde *wca.IMMDeviceEnumerator
	if err = wca.CoCreateInstance(wca.CLSID_MMDeviceEnumerator, 0, wca.CLSCTX_ALL, wca.IID_IMMDeviceEnumerator, &mmde); err != nil {
		return
	}
	defer mmde.Release()

	var mmd *wca.IMMDevice
	if err = mmde.GetDefaultAudioEndpoint(wca.ECapture, wca.EConsole, &mmd); err != nil {
		return
	}
	defer mmd.Release()

	var ps *wca.IPropertyStore
	if err = mmd.OpenPropertyStore(wca.STGM_READ, &ps); err != nil {
		return
	}
	defer ps.Release()

	var pv wca.PROPVARIANT
	if err = ps.GetValue(&wca.PKEY_Device_FriendlyName, &pv); err != nil {
		return
	}
	fmt.Printf("Capturing audio from: %s\n", pv.String())

	var ac *wca.IAudioClient
	if err = mmd.Activate(wca.IID_IAudioClient, wca.CLSCTX_ALL, nil, &ac); err != nil {
		return
	}
	defer ac.Release()

	var wfx *wca.WAVEFORMATEX
	if err = ac.GetMixFormat(&wfx); err != nil {
		return
	}
	defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(wfx)))

	wfx.WFormatTag = 1
	wfx.WBitsPerSample = 16
	wfx.NSamplesPerSec = 44100
	wfx.NBlockAlign = (wfx.WBitsPerSample / 8) * wfx.NChannels
	wfx.NAvgBytesPerSec = wfx.NSamplesPerSec * uint32(wfx.NBlockAlign)
	wfx.CbSize = 0

	audio = &WAVEFormat{}
	audio.Channels = wfx.NChannels
	audio.SamplesPerSec = wfx.NSamplesPerSec
	audio.AvgBytesPerSec = wfx.NAvgBytesPerSec
	audio.BlockAlign = wfx.NBlockAlign
	audio.BitsPerSample = wfx.WBitsPerSample

	fmt.Println("--------")
	fmt.Printf("Format: PCM %d bit signed integer\n", wfx.WBitsPerSample)
	fmt.Printf("Rate: %d Hz\n", wfx.NSamplesPerSec)
	fmt.Printf("Channels: %d\n", wfx.NChannels)
	fmt.Println("--------")

	var defaultPeriod wca.REFERENCE_TIME
	var minimumPeriod wca.REFERENCE_TIME
	var capturingPeriod time.Duration
	if err = ac.GetDevicePeriod(&defaultPeriod, &minimumPeriod); err != nil {
		return
	}
	capturingPeriod = time.Duration(int(defaultPeriod) * 100)
	fmt.Printf("Default capturing period: %d ms\n", capturingPeriod/time.Millisecond)

	if err = ac.Initialize(wca.AUDCLNT_SHAREMODE_SHARED, 0, wca.REFERENCE_TIME(200*10000), 0, wfx, nil); err != nil {
		return
	}

	var bufferFrameSize uint32
	if err = ac.GetBufferSize(&bufferFrameSize); err != nil {
		return
	}
	fmt.Printf("Allocated buffer size: %d\n", bufferFrameSize)

	var acc *wca.IAudioCaptureClient
	if err = ac.GetService(wca.IID_IAudioCaptureClient, &acc); err != nil {
		return
	}
	defer acc.Release()

	if err = ac.Start(); err != nil {
		return
	}
	fmt.Println("Start capturing audio with shared-timer-driven mode")
	if duration <= 0 {
		fmt.Println("Press Ctrl-C to stop capturing")
	}
	time.Sleep(capturingPeriod)

	var isCapturing bool = true
	var currentDuration time.Duration
	var b *byte
	var data *byte
	var availableFrameSize uint32
	var flags uint32
	var devicePosition uint64
	var qcpPosition uint64
	var padding uint32

	for {
		if !isCapturing {
			break
		}
		select {
		case <-ctx.Done():
			isCapturing = false
			break
		default:
			currentDuration = time.Duration(float64(audio.DataSize) / float64(audio.BitsPerSample/8) / float64(audio.Channels) / float64(audio.SamplesPerSec) * float64(time.Second))
			if duration != 0 && currentDuration > duration {
				isCapturing = false
				break
			}
			if err = acc.GetBuffer(&data, &availableFrameSize, &flags, &devicePosition, &qcpPosition); err != nil {
				return
			}
			if availableFrameSize == 0 {
				continue
			}

			start := unsafe.Pointer(data)
			lim := int(availableFrameSize) * int(wfx.NBlockAlign)

			for n := 0; n < lim; n++ {
				b = (*byte)(unsafe.Pointer(uintptr(start) + uintptr(n)))
				audio.RawData = append(audio.RawData, *b)
			}
			audio.DataSize += uint32(lim)
			if err = ac.GetCurrentPadding(&padding); err != nil {
				return
			}
			time.Sleep(capturingPeriod)
			if err = acc.ReleaseBuffer(availableFrameSize); err != nil {
				return
			}
		}
	}

	fmt.Println("Stop capturing")
	if err = ac.Stop(); err != nil {
		return
	}
	return
}
<commit_msg>Refactor<commit_after>// +build windows

package main

import (
	"bytes"
	"context"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/go-ole/go-ole"
	"github.com/moutend/go-wav"
	"github.com/moutend/go-wca"
)

var version = "latest"
var revision = "latest"

type DurationFlag struct {
	Value time.Duration
}

func (f *DurationFlag) Set(value string) (err error) {
	var sec float64

	if sec, err = strconv.ParseFloat(value, 64); err != nil {
		return
	}
	f.Value = time.Duration(sec * float64(time.Second))
	return
}

func (f *DurationFlag) String() string {
	return f.Value.String()
}

type FilenameFlag struct {
	Value string
}

func (f *FilenameFlag) Set(value string) (err error) {
	if !strings.HasSuffix(value, ".wav") {
		err = fmt.Errorf("specify WAVE audio file (*.wav)")
		return
	}
	f.Value = value
	return
}

func (f *FilenameFlag) String() string {
	return f.Value
}

func main() {
	var err error
	if err = run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) (err error) {
	var durationFlag DurationFlag
	var file []byte
	var filenameFlag FilenameFlag
	var versionFlag bool
	var audio *wav.File

	f := flag.NewFlagSet(args[0], flag.ExitOnError)
	f.Var(&durationFlag, "duration", "Specify recording duration in second")
	f.Var(&durationFlag, "d", "Alias of --duration")
	f.Var(&filenameFlag, "output", "file name")
	f.Var(&filenameFlag, "o", "Alias of --output")
	f.BoolVar(&versionFlag, "version", false, "Show version")
	f.Parse(args[1:])

	if versionFlag {
		fmt.Printf("%s-%s\n", version, revision)
		return
	}
	if filenameFlag.Value == "" {
		return
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		select {
		case <-signalChan:
			fmt.Println("Interrupted by SIGINT")
			cancel()
		}
		return
	}()

	if audio, err = captureSharedTimerDriven(ctx, durationFlag.Value); err != nil {
		return
	}
	if file, err = wav.Marshal(audio); err != nil {
		return
	}
	if err = ioutil.WriteFile(filenameFlag.Value, file, 0644); err != nil {
		return
	}
	fmt.Println("Successfully done")
	return
}

func captureSharedTimerDriven(ctx context.Context, duration time.Duration) (audio *wav.File, err error) {
	if err = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED); err != nil {
		return
	}
	defer ole.CoUninitialize()

	var mmde *wca.IMMDeviceEnumerator
	if err = wca.CoCreateInstance(wca.CLSID_MMDeviceEnumerator, 0, wca.CLSCTX_ALL, wca.IID_IMMDeviceEnumerator, &mmde); err != nil {
		return
	}
	defer mmde.Release()

	var mmd *wca.IMMDevice
	if err = mmde.GetDefaultAudioEndpoint(wca.ECapture, wca.EConsole, &mmd); err != nil {
		return
	}
	defer mmd.Release()

	var ps *wca.IPropertyStore
	if err = mmd.OpenPropertyStore(wca.STGM_READ, &ps); err != nil {
		return
	}
	defer ps.Release()

	var pv wca.PROPVARIANT
	if err = ps.GetValue(&wca.PKEY_Device_FriendlyName, &pv); err != nil {
		return
	}
	fmt.Printf("Capturing audio from: %s\n", pv.String())

	var ac *wca.IAudioClient
	if err = mmd.Activate(wca.IID_IAudioClient, wca.CLSCTX_ALL, nil, &ac); err != nil {
		return
	}
	defer ac.Release()

	var wfx *wca.WAVEFORMATEX
	if err = ac.GetMixFormat(&wfx); err != nil {
		return
	}
	defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(wfx)))

	wfx.WFormatTag = 1
	wfx.NBlockAlign = (wfx.WBitsPerSample / 8) * wfx.NChannels
	wfx.NAvgBytesPerSec = wfx.NSamplesPerSec * uint32(wfx.NBlockAlign)
	wfx.CbSize = 0

	if audio, err = wav.New(int(wfx.NSamplesPerSec), int(wfx.WBitsPerSample), int(wfx.NChannels)); err != nil {
		return
	}

	fmt.Println("--------")
	fmt.Printf("Format: PCM %d bit signed integer\n", int(wfx.WBitsPerSample))
	fmt.Printf("Rate: %d Hz\n", wfx.NSamplesPerSec)
	fmt.Printf("Channels: %d\n", wfx.NChannels)
	fmt.Println("--------")

	var defaultPeriod wca.REFERENCE_TIME
	var minimumPeriod wca.REFERENCE_TIME
	var latency time.Duration
	if err = ac.GetDevicePeriod(&defaultPeriod, &minimumPeriod); err != nil {
		return
	}
	latency = time.Duration(int(defaultPeriod) * 100)

	fmt.Println("Default period: ", defaultPeriod)
	fmt.Println("Minimum period: ", minimumPeriod)
	fmt.Println("Latency: ", latency)

	if err = ac.Initialize(wca.AUDCLNT_SHAREMODE_SHARED, 0, defaultPeriod, 0, wfx, nil); err != nil {
		return
	}

	var bufferFrameSize uint32
	if err = ac.GetBufferSize(&bufferFrameSize); err != nil {
		return
	}
	fmt.Printf("Allocated buffer size: %d\n", bufferFrameSize)

	var acc *wca.IAudioCaptureClient
	if err = ac.GetService(wca.IID_IAudioCaptureClient, &acc); err != nil {
		return
	}
	defer acc.Release()

	if err = ac.Start(); err != nil {
		return
	}
	fmt.Println("Start capturing with shared timer driven mode")
	if duration <= 0 {
		fmt.Println("Press Ctrl-C to stop capturing")
	}

	var output = []byte{}
	var offset int
	var isCapturing bool = true
	var currentDuration time.Duration
	var b *byte
	var data *byte
	var availableFrameSize uint32
	var flags uint32
	var devicePosition uint64
	var qcpPosition uint64

	time.Sleep(latency)

	for {
		if !isCapturing {
			break
		}
		select {
		case <-ctx.Done():
			isCapturing = false
			break
		default:
			// Wait for buffering.
			time.Sleep(latency / 2)

			currentDuration = time.Duration(float64(offset) / float64(wfx.WBitsPerSample/8) / float64(wfx.NChannels) / float64(wfx.NSamplesPerSec) * float64(time.Second))
			if duration != 0 && currentDuration > duration {
				isCapturing = false
				break
			}
			if err = acc.GetBuffer(&data, &availableFrameSize, &flags, &devicePosition, &qcpPosition); err != nil {
				continue
			}
			if availableFrameSize == 0 {
				continue
			}

			start := unsafe.Pointer(data)
			lim := int(availableFrameSize) * int(wfx.NBlockAlign)
			buf := make([]byte, lim)

			for n := 0; n < lim; n++ {
				b = (*byte)(unsafe.Pointer(uintptr(start) + uintptr(n)))
				buf[n] = *b
			}
			offset += lim
			output = append(output, buf...)

			if err = acc.ReleaseBuffer(availableFrameSize); err != nil {
				return
			}
		}
	}

	io.Copy(audio, bytes.NewBuffer(output))

	fmt.Println("Stop capturing")
	if err = ac.Stop(); err != nil {
		return
	}
	return
}
<|endoftext|>