<commit_before>package metadata

import "fmt"

func NewCollection(name string) *Collection {
	return &Collection{
		Name:    name,
		Indexes: make(map[string]*CollectionIndex),
	}
}

type Collection struct {
	ID   int64  `json:"_id,omitempty"`
	Name string `json:"name"`

	// NOTE: we reserve the "_" namespace for fields for our own data (created, etc.)
	// All the columns in this table
	Fields map[string]*Field `json:"fields"`

	// map of name -> index
	Indexes map[string]*CollectionIndex `json:"indexes,omitempty"`

	ProvisionState ProvisionState `json:"provision_state"`
}

func (c *Collection) Equal(o *Collection) bool {
	if c.Name != o.Name {
		return false
	}

	return true
}

// TODO: elsewhere?
// We need to ensure that collections have all of the internal fields that we define
// TODO: error here if one that isn't compatible is defined
func (c *Collection) EnsureInternalFields() error {
	for name, internalField := range InternalFields {
		if field, ok := c.Fields[name]; !ok {
			// TODO: make a copy?
			c.Fields[name] = internalField
		} else {
			// If it exists, it must match -- if not error
			if !internalField.Equal(field) {
				return fmt.Errorf("The `%s` namespace for collection fields is reserved: %v", InternalFieldPrefix, field)
			}
		}
	}

	return nil
}

func (c *Collection) ListIndexes() []string {
	indexes := make([]string, 0, len(c.Indexes))
	for name, _ := range c.Indexes {
		indexes = append(indexes, name)
	}
	return indexes
}

// TODO: underlying datasources should know how to do this-- us doing it shouldn't
// be necessary
func (c *Collection) ValidateRecord(record map[string]interface{}) error {
	// TODO: We need to check that we where given no more than the Fields we know about
	for fieldName, field := range c.Fields {
		if v, ok := record[fieldName]; ok {
			if err := field.Validate(v); err != nil {
				return err
			}
		} else {
			if field.NotNull {
				return fmt.Errorf("Missing required field %s", fieldName)
			}
		}
	}
	return nil
}

type CollectionIndex struct {
	ID   int64  `json:"_id,omitempty"`
	Name string `json:"name"`
	// TODO: use CollectionIndexItem
	Fields []string `json:"fields"`
	Unique bool     `json:"unique,omitempty"`

	ProvisionState ProvisionState `json:"provision_state"`
}

func (c *CollectionIndex) Equal(o *CollectionIndex) bool {
	if c.Name != o.Name {
		return false
	}

	if len(c.Fields) != len(o.Fields) {
		return false
	}
	for i, k := range c.Fields {
		if o.Fields[i] != k {
			return false
		}
	}

	if c.Unique != o.Unique {
		return false
	}

	return true
}

type CollectionIndexItem struct {
	ID                int64 `json:"_id,omitempty"`
	CollectionIndexID int64 `json:"collection_index_id"`
	CollectionFieldID int64 `json:"collection_field_id"`

	Field *Field `json:"-"`

	ProvisionState ProvisionState `json:"provision_state"`
}
<commit_msg>Don't enforce internal fields to be set-- they are internal<commit_after>package metadata

import "fmt"

func NewCollection(name string) *Collection {
	return &Collection{
		Name:    name,
		Indexes: make(map[string]*CollectionIndex),
	}
}

type Collection struct {
	ID   int64  `json:"_id,omitempty"`
	Name string `json:"name"`

	// NOTE: we reserve the "_" namespace for fields for our own data (created, etc.)
	// All the columns in this table
	Fields map[string]*Field `json:"fields"`

	// map of name -> index
	Indexes map[string]*CollectionIndex `json:"indexes,omitempty"`

	ProvisionState ProvisionState `json:"provision_state"`
}

func (c *Collection) Equal(o *Collection) bool {
	if c.Name != o.Name {
		return false
	}

	return true
}

// TODO: elsewhere?
// We need to ensure that collections have all of the internal fields that we define
// TODO: error here if one that isn't compatible is defined
func (c *Collection) EnsureInternalFields() error {
	for name, internalField := range InternalFields {
		if field, ok := c.Fields[name]; !ok {
			// TODO: make a copy?
			c.Fields[name] = internalField
		} else {
			// If it exists, it must match -- if not error
			if !internalField.Equal(field) {
				return fmt.Errorf("The `%s` namespace for collection fields is reserved: %v", InternalFieldPrefix, field)
			}
		}
	}

	return nil
}

func (c *Collection) ListIndexes() []string {
	indexes := make([]string, 0, len(c.Indexes))
	for name, _ := range c.Indexes {
		indexes = append(indexes, name)
	}
	return indexes
}

// TODO: underlying datasources should know how to do this-- us doing it shouldn't
// be necessary
func (c *Collection) ValidateRecord(record map[string]interface{}) error {
	// TODO: We need to check that we where given no more than the Fields we know about
	for fieldName, field := range c.Fields {
		// TODO: some flag on the field on whether it is internal or not would be good!!!
		if _, ok := InternalFields[fieldName]; !ok {
			// We don't want to enforce internal fields
			if v, ok := record[fieldName]; ok {
				if err := field.Validate(v); err != nil {
					return err
				}
			} else {
				if field.NotNull {
					return fmt.Errorf("Missing required field %s", fieldName)
				}
			}
		}
	}
	return nil
}

type CollectionIndex struct {
	ID   int64  `json:"_id,omitempty"`
	Name string `json:"name"`
	// TODO: use CollectionIndexItem
	Fields []string `json:"fields"`
	Unique bool     `json:"unique,omitempty"`

	ProvisionState ProvisionState `json:"provision_state"`
}

func (c *CollectionIndex) Equal(o *CollectionIndex) bool {
	if c.Name != o.Name {
		return false
	}

	if len(c.Fields) != len(o.Fields) {
		return false
	}
	for i, k := range c.Fields {
		if o.Fields[i] != k {
			return false
		}
	}

	if c.Unique != o.Unique {
		return false
	}

	return true
}

type CollectionIndexItem struct {
	ID                int64 `json:"_id,omitempty"`
	CollectionIndexID int64 `json:"collection_index_id"`
	CollectionFieldID int64 `json:"collection_field_id"`

	Field *Field `json:"-"`

	ProvisionState ProvisionState `json:"provision_state"`
}
<|endoftext|>


<commit_before>// +build !windows

package daemon // import "github.com/docker/docker/daemon"

import (
	"context"
	"fmt"
	"os/exec"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/sysinfo"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// fillPlatformInfo fills the platform related info.
func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
	v.MemoryLimit = sysInfo.MemoryLimit
	v.SwapLimit = sysInfo.SwapLimit
	v.KernelMemory = sysInfo.KernelMemory
	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
	v.OomKillDisable = sysInfo.OomKillDisable
	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
	v.CPUCfsQuota = sysInfo.CPUCfsQuota
	v.CPUShares = sysInfo.CPUShares
	v.CPUSet = sysInfo.Cpuset
	v.Runtimes = daemon.configStore.GetAllRuntimes()
	v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName()
	v.InitBinary = daemon.configStore.GetInitPath()

	defaultRuntimeBinary := daemon.configStore.GetRuntime(v.DefaultRuntime).Path
	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
		parts := strings.Split(strings.TrimSpace(string(rv)), "\n")
		if len(parts) == 3 {
			parts = strings.Split(parts[1], ": ")
			if len(parts) == 2 {
				v.RuncCommit.ID = strings.TrimSpace(parts[1])
			}
		}

		if v.RuncCommit.ID == "" {
			logrus.Warnf("failed to retrieve %s version: unknown output format: %s", defaultRuntimeBinary, string(rv))
			v.RuncCommit.ID = "N/A"
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
		v.RuncCommit.ID = "N/A"
	}

	// runc is now shipped as a separate package. Set "expected" to same value
	// as "ID" to prevent clients from reporting a version-mismatch
	v.RuncCommit.Expected = v.RuncCommit.ID

	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
		v.ContainerdCommit.ID = rv.Revision
	} else {
		logrus.Warnf("failed to retrieve containerd version: %v", err)
		v.ContainerdCommit.ID = "N/A"
	}

	// containerd is now shipped as a separate package. Set "expected" to same
	// value as "ID" to prevent clients from reporting a version-mismatch
	v.ContainerdCommit.Expected = v.ContainerdCommit.ID

	defaultInitBinary := daemon.configStore.GetInitPath()
	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
		ver, err := parseInitVersion(string(rv))

		if err != nil {
			logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
		}
		v.InitCommit = ver
	} else {
		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
		v.InitCommit.ID = "N/A"
	}

	if !v.MemoryLimit {
		v.Warnings = append(v.Warnings, "WARNING: No memory limit support")
	}
	if !v.SwapLimit {
		v.Warnings = append(v.Warnings, "WARNING: No swap limit support")
	}
	if !v.KernelMemory {
		v.Warnings = append(v.Warnings, "WARNING: No kernel memory limit support")
	}
	if !v.OomKillDisable {
		v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support")
	}
	if !v.CPUCfsQuota {
		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support")
	}
	if !v.CPUCfsPeriod {
		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support")
	}
	if !v.CPUShares {
		v.Warnings = append(v.Warnings, "WARNING: No cpu shares support")
	}
	if !v.CPUSet {
		v.Warnings = append(v.Warnings, "WARNING: No cpuset support")
	}
	if !v.IPv4Forwarding {
		v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
	}
	if !v.BridgeNfIptables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled")
	}
	if !v.BridgeNfIP6tables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
	}
}

func fillDriverWarnings(v *types.Info) {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Data loop file" {
			msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+
				"strongly discouraged for production use.\n         "+
				"Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver)

			v.Warnings = append(v.Warnings, msg)
			continue
		}
		if pair[0] == "Supports d_type" && pair[1] == "false" {
			backingFs := getBackingFs(v)

			msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs)
			if backingFs == "xfs" {
				msg += "         Reformat the filesystem with ftype=1 to enable d_type support.\n"
			}
			msg += "         Running without d_type support will not be supported in future releases."

			v.Warnings = append(v.Warnings, msg)
			continue
		}
	}
}

func getBackingFs(v *types.Info) string {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Backing Filesystem" {
			return pair[1]
		}
	}
	return ""
}

// parseInitVersion parses a Tini version string, and extracts the version.
func parseInitVersion(v string) (types.Commit, error) {
	version := types.Commit{ID: "", Expected: dockerversion.InitCommitID}
	parts := strings.Split(strings.TrimSpace(v), " - ")

	if len(parts) >= 2 {
		gitParts := strings.Split(parts[1], ".")
		if len(gitParts) == 2 && gitParts[0] == "git" {
			version.ID = gitParts[1]
			version.Expected = dockerversion.InitCommitID[0:len(version.ID)]
		}
	}
	if version.ID == "" && strings.HasPrefix(parts[0], "tini version ") {
		version.ID = "v" + strings.TrimPrefix(parts[0], "tini version ")
	}
	if version.ID == "" {
		version.ID = "N/A"
		return version, errors.Errorf("unknown output format: %s", v)
	}
	return version, nil
}
<commit_msg>Add warning to /info if KernelMemoryTCP is not supported<commit_after>// +build !windows

package daemon // import "github.com/docker/docker/daemon"

import (
	"context"
	"fmt"
	"os/exec"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/sysinfo"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// fillPlatformInfo fills the platform related info.
func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
	v.MemoryLimit = sysInfo.MemoryLimit
	v.SwapLimit = sysInfo.SwapLimit
	v.KernelMemory = sysInfo.KernelMemory
	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
	v.OomKillDisable = sysInfo.OomKillDisable
	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
	v.CPUCfsQuota = sysInfo.CPUCfsQuota
	v.CPUShares = sysInfo.CPUShares
	v.CPUSet = sysInfo.Cpuset
	v.Runtimes = daemon.configStore.GetAllRuntimes()
	v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName()
	v.InitBinary = daemon.configStore.GetInitPath()

	defaultRuntimeBinary := daemon.configStore.GetRuntime(v.DefaultRuntime).Path
	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
		parts := strings.Split(strings.TrimSpace(string(rv)), "\n")
		if len(parts) == 3 {
			parts = strings.Split(parts[1], ": ")
			if len(parts) == 2 {
				v.RuncCommit.ID = strings.TrimSpace(parts[1])
			}
		}

		if v.RuncCommit.ID == "" {
			logrus.Warnf("failed to retrieve %s version: unknown output format: %s", defaultRuntimeBinary, string(rv))
			v.RuncCommit.ID = "N/A"
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
		v.RuncCommit.ID = "N/A"
	}

	// runc is now shipped as a separate package. Set "expected" to same value
	// as "ID" to prevent clients from reporting a version-mismatch
	v.RuncCommit.Expected = v.RuncCommit.ID

	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
		v.ContainerdCommit.ID = rv.Revision
	} else {
		logrus.Warnf("failed to retrieve containerd version: %v", err)
		v.ContainerdCommit.ID = "N/A"
	}

	// containerd is now shipped as a separate package. Set "expected" to same
	// value as "ID" to prevent clients from reporting a version-mismatch
	v.ContainerdCommit.Expected = v.ContainerdCommit.ID

	defaultInitBinary := daemon.configStore.GetInitPath()
	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
		ver, err := parseInitVersion(string(rv))

		if err != nil {
			logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
		}
		v.InitCommit = ver
	} else {
		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
		v.InitCommit.ID = "N/A"
	}

	if !v.MemoryLimit {
		v.Warnings = append(v.Warnings, "WARNING: No memory limit support")
	}
	if !v.SwapLimit {
		v.Warnings = append(v.Warnings, "WARNING: No swap limit support")
	}
	if !v.KernelMemory {
		v.Warnings = append(v.Warnings, "WARNING: No kernel memory limit support")
	}
	if !v.KernelMemoryTCP {
		v.Warnings = append(v.Warnings, "WARNING: No kernel memory TCP limit support")
	}
	if !v.OomKillDisable {
		v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support")
	}
	if !v.CPUCfsQuota {
		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support")
	}
	if !v.CPUCfsPeriod {
		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support")
	}
	if !v.CPUShares {
		v.Warnings = append(v.Warnings, "WARNING: No cpu shares support")
	}
	if !v.CPUSet {
		v.Warnings = append(v.Warnings, "WARNING: No cpuset support")
	}
	if !v.IPv4Forwarding {
		v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
	}
	if !v.BridgeNfIptables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled")
	}
	if !v.BridgeNfIP6tables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
	}
}

func fillDriverWarnings(v *types.Info) {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Data loop file" {
			msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+
				"strongly discouraged for production use.\n         "+
				"Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver)

			v.Warnings = append(v.Warnings, msg)
			continue
		}
		if pair[0] == "Supports d_type" && pair[1] == "false" {
			backingFs := getBackingFs(v)

			msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs)
			if backingFs == "xfs" {
				msg += "         Reformat the filesystem with ftype=1 to enable d_type support.\n"
			}
			msg += "         Running without d_type support will not be supported in future releases."

			v.Warnings = append(v.Warnings, msg)
			continue
		}
	}
}

func getBackingFs(v *types.Info) string {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Backing Filesystem" {
			return pair[1]
		}
	}
	return ""
}

// parseInitVersion parses a Tini version string, and extracts the version.
func parseInitVersion(v string) (types.Commit, error) {
	version := types.Commit{ID: "", Expected: dockerversion.InitCommitID}
	parts := strings.Split(strings.TrimSpace(v), " - ")

	if len(parts) >= 2 {
		gitParts := strings.Split(parts[1], ".")
		if len(gitParts) == 2 && gitParts[0] == "git" {
			version.ID = gitParts[1]
			version.Expected = dockerversion.InitCommitID[0:len(version.ID)]
		}
	}
	if version.ID == "" && strings.HasPrefix(parts[0], "tini version ") {
		version.ID = "v" + strings.TrimPrefix(parts[0], "tini version ")
	}
	if version.ID == "" {
		version.ID = "N/A"
		return version, errors.Errorf("unknown output format: %s", v)
	}
	return version, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"
	"sync"

	"github.com/github/git-lfs/commands"
	"github.com/github/git-lfs/lfs"
)

func main() {
	c := make(chan os.Signal)
	signal.Notify(c)

	var once sync.Once

	go func() {
		for {
			sig := <-c
			once.Do(lfs.ClearTempObjects)
			switch sig {
			case os.Interrupt, os.Kill:
				fmt.Fprintf(os.Stderr, "\nExiting because of %q signal.\n", sig)
				if commands.Erroring {
					os.Exit(1)
				}
				os.Exit(0)
			}
		}
	}()

	commands.Run()
	lfs.LogHttpStats()
	once.Do(lfs.ClearTempObjects)
}
<commit_msg>ンンー ンンンン ンーンン<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"
	"sync"

	"github.com/github/git-lfs/commands"
	"github.com/github/git-lfs/lfs"
)

func main() {
	c := make(chan os.Signal)
	signal.Notify(c)

	var once sync.Once

	go func() {
		for {
			sig := <-c
			once.Do(lfs.ClearTempObjects)
			switch sig {
			case os.Interrupt, os.Kill:
				fmt.Fprintf(os.Stderr, "\nExiting because of %q signal.\n", sig)
				if commands.Erroring {
					os.Exit(2)
				}
				os.Exit(0)
			}
		}
	}()

	commands.Run()
	lfs.LogHttpStats()
	once.Do(lfs.ClearTempObjects)
}
<|endoftext|>


<commit_before>package test

import (
	"testing"
)

// helper to close both conns
func closeBridge(br *Bridge) error {
	if err := br.conn0.Close(); err != nil {
		return err

	}

	return br.conn1.Close()
}

type AsyncResult struct {
	n   int
	err error
}

func TestBridge(t *testing.T) {
	buf := make([]byte, 256)

	t.Run("normal", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg := "ABC"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn0.Write([]byte(msg))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn1.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 1st packet from conn0", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn0.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn0.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn1.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(0, 0, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg2) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 2nd packet from conn0", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn0.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn0.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn1.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(0, 1, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg1) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 1st packet from conn1", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn1.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn1.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn0.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(1, 0, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg2) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 2nd packet from conn1", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn1.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn1.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn0.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(1, 1, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg1) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("reorder packets from conn0", func(t *testing.T) {
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn0.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn0.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		done := make(chan bool)

		go func() {
			nInner, errInner := conn1.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg2) {
				t.Error("unexpected length")
			}
			nInner, errInner = conn1.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg1) {
				t.Error("unexpected length")
			}
			done <- true
		}()

		err = br.Reorder(0)
		if err != nil {
			t.Error(err.Error())
		}
		br.Process()
		<-done
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("reorder packets from conn1", func(t *testing.T) {
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn1.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn1.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		done := make(chan bool)

		go func() {
			nInner, errInner := conn0.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg2) {
				t.Error("unexpected length")
			}
			nInner, errInner = conn0.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg1) {
				t.Error("unexpected length")
			}
			done <- true
		}()

		err = br.Reorder(1)
		if err != nil {
			t.Error(err.Error())
		}
		br.Process()
		<-done
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("inverse error", func(t *testing.T) {
		q := [][]byte{}
		q = append(q, []byte("ABC"))
		if err := inverse(q); err == nil {
			t.Error("inverse should fail if less than 2 pkts")
		}
	})

	t.Run("read closed conn", func(t *testing.T) {
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		if err := conn0.Close(); err != nil {
			t.Error(err)
		}
		if err := conn1.Close(); err != nil {
			t.Error(err)
		}

		_, err := conn0.Read(buf)
		if err == nil {
			t.Error("read should fail as conn is closed")
		}
	})
}
<commit_msg>Added test for bridge.DropNextNWrites<commit_after>package test

import (
	"fmt"
	"net"
	"testing"
)

// helper to close both conns
func closeBridge(br *Bridge) error {
	if err := br.conn0.Close(); err != nil {
		return err

	}

	return br.conn1.Close()
}

type AsyncResult struct {
	n   int
	err error
	msg string
}

func TestBridge(t *testing.T) {
	buf := make([]byte, 256)

	t.Run("normal", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg := "ABC"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		if conn0.LocalAddr().String() != "a0" {
			t.Error("conn0 local addr name should be a0")
		}

		if conn1.LocalAddr().String() != "a1" {
			t.Error("conn0 local addr name should be a1")
		}

		if conn0.LocalAddr().Network() != "udp" {
			t.Error("conn0 local addr name should be a0")
		}

		if conn1.LocalAddr().Network() != "udp" {
			t.Error("conn0 local addr name should be a1")
		}

		n, err := conn0.Write([]byte(msg))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn1.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 1st packet from conn0", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn0.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn0.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn1.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(0, 0, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg2) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 2nd packet from conn0", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn0.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn0.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn1.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(0, 1, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg1) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 1st packet from conn1", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn1.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn1.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn0.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(1, 0, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg2) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("drop 2nd packet from conn1", func(t *testing.T) {
		readRes := make(chan AsyncResult)
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn1.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn1.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		go func() {
			nInner, errInner := conn0.Read(buf)
			readRes <- AsyncResult{n: nInner, err: errInner}
		}()

		br.Drop(1, 1, 1)
		br.Process()

		ar := <-readRes
		if ar.err != nil {
			t.Error(err.Error())
		}
		if ar.n != len(msg1) {
			t.Error("unexpected length")
		}
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("reorder packets from conn0", func(t *testing.T) {
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn0.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn0.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		done := make(chan bool)

		go func() {
			nInner, errInner := conn1.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg2) {
				t.Error("unexpected length")
			}
			nInner, errInner = conn1.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg1) {
				t.Error("unexpected length")
			}
			done <- true
		}()

		err = br.Reorder(0)
		if err != nil {
			t.Error(err.Error())
		}
		br.Process()
		<-done
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("reorder packets from conn1", func(t *testing.T) {
		msg1 := "ABC"
		msg2 := "DEFG"
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		n, err := conn1.Write([]byte(msg1))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg1) {
			t.Error("unexpected length")
		}
		n, err = conn1.Write([]byte(msg2))
		if err != nil {
			t.Error(err.Error())
		}
		if n != len(msg2) {
			t.Error("unexpected length")
		}

		done := make(chan bool)

		go func() {
			nInner, errInner := conn0.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg2) {
				t.Error("unexpected length")
			}
			nInner, errInner = conn0.Read(buf)
			if errInner != nil {
				t.Error(errInner.Error())
			}
			if nInner != len(msg1) {
				t.Error("unexpected length")
			}
			done <- true
		}()

		err = br.Reorder(1)
		if err != nil {
			t.Error(err.Error())
		}
		br.Process()
		<-done
		if err = closeBridge(br); err != nil {
			t.Error(err)
		}
	})

	t.Run("inverse error", func(t *testing.T) {
		q := [][]byte{}
		q = append(q, []byte("ABC"))
		if err := inverse(q); err == nil {
			t.Error("inverse should fail if less than 2 pkts")
		}
	})

	t.Run("read closed conn", func(t *testing.T) {
		br := NewBridge()
		conn0 := br.GetConn0()
		conn1 := br.GetConn1()

		if err := conn0.Close(); err != nil {
			t.Error(err)
		}
		if err := conn1.Close(); err != nil {
			t.Error(err)
		}

		_, err := conn0.Read(buf)
		if err == nil {
			t.Error("read should fail as conn is closed")
		}
	})

	t.Run("drop next N packets", func(t *testing.T) {
		testFrom := func(t *testing.T, fromID int) {
			readRes := make(chan AsyncResult, 5)
			br := NewBridge()
			conn0 := br.GetConn0()
			conn1 := br.GetConn1()
			var srcConn, dstConn net.Conn

			if fromID == 0 {
				br.DropNextNWrites(0, 3)
				srcConn = conn0
				dstConn = conn1
			} else {
				br.DropNextNWrites(1, 3)
				srcConn = conn1
				dstConn = conn0
			}

			go func() {
				for {
					nInner, errInner := dstConn.Read(buf)
					if errInner != nil {
						break
					}
					readRes <- AsyncResult{
						n:   nInner,
						err: nil,
						msg: string(buf)}
				}
			}()
			msgs := make([]string, 0)

			for i := 0; i < 5; i++ {
				msg := fmt.Sprintf("msg%d", i)
				msgs = append(msgs, msg)
				n, err := srcConn.Write([]byte(msg))
				if err != nil {
					t.Errorf("[%d] %s", fromID, err.Error())
				}
				if n != len(msg) {
					t.Errorf("[%d] unexpected length", fromID)
				}

				br.Process()
			}

			nResults := len(readRes)
			if nResults != 2 {
				t.Errorf("[%d] unexpected number of packets", fromID)
			}

			for i := 0; i < 2; i++ {
				ar := <-readRes
				if ar.err != nil {
					t.Errorf("[%d] %s", fromID, ar.err.Error())
				}
				if ar.n != len(msgs[i+3]) {
					t.Errorf("[%d] unexpected length", fromID)
				}
			}

			if err := closeBridge(br); err != nil {
				t.Errorf("[%d] %s", fromID, err.Error())
			}
		}

		testFrom(t, 0)
		testFrom(t, 1)
	})
}
<|endoftext|>


<commit_before>package apid

const (
	SystemEventsSelector EventSelector = "system event"
)

var (
	APIDInitializedEvent        = systemEvent{"apid initialized"}
	PluginsInitializedEvent     = systemEvent{"plugins initialized"}
	PostPluginsInitializedEvent = systemEvent{"post plugins initialized"}
	APIListeningEvent           = systemEvent{"api listening"}

	pluginInitFuncs     []PluginInitFunc
	postpluginInitFuncs []PostPluginInitFunc
	services            Services
)

type Services interface {
	API() APIService
	Config() ConfigService
	Data() DataService
	Events() EventsService
	Log() LogService
}

type PluginInitFunc func(Services) error
type PostPluginInitFunc func(Services) error

// passed Services can be a factory - makes copies and maintains returned references
// eg. apid.Initialize(factory.DefaultServicesFactory())

func Initialize(s Services) {
	ss := &servicesSet{}
	services = ss
	// order is important
	ss.config = s.Config()
	ss.log = s.Log()
	ss.events = s.Events()
	ss.api = s.API()
	ss.data = s.Data()

	ss.events.Emit(SystemEventsSelector, APIDInitializedEvent)
}

func RegisterPlugin(plugin PluginInitFunc) {
	pluginInitFuncs = append(pluginInitFuncs, plugin)
}

func RegisterPostPlugin(plugin PostPluginInitFunc) {
	postpluginInitFuncs = append(postpluginInitFuncs, plugin)
}

func InitializePlugins() {
	log := Log()
	log.Debugf("Initializing plugins...")
	for _, p := range pluginInitFuncs {
		err := p(services)
		if err != nil {
			log.Panicf("Error initializing plugin: %s", err)
		}
	}
	Events().Emit(SystemEventsSelector, PluginsInitializedEvent)
	log.Debugf("done initializing plugins")
}

func PostInitializePlugins() {

	log := Log()
	log.Debugf("Post Initializing plugins...")
	for _, p := range postpluginInitFuncs {
		err := p(services)
		if err != nil {
			log.Panicf("Error initializing plugin: %s", err)
		}
	}
	Events().Emit(SystemEventsSelector, PostPluginsInitializedEvent)
	log.Debugf("Done Post initializing plugins")
}

func AllServices() Services {
	return services
}

func Log() LogService {
	return services.Log()
}

func API() APIService {
	return services.API()
}

func Config() ConfigService {
	return services.Config()
}

func Data() DataService {
	return services.Data()
}

func Events() EventsService {
	return services.Events()
}

type servicesSet struct {
	config ConfigService
	log    LogService
	api    APIService
	data   DataService
	events EventsService
}

func (s *servicesSet) API() APIService {
	return s.api
}

func (s *servicesSet) Config() ConfigService {
	return s.config
}

func (s *servicesSet) Data() DataService {
	return s.data
}

func (s *servicesSet) Events() EventsService {
	return s.events
}

func (s *servicesSet) Log() LogService {
	return s.log
}

type systemEvent struct {
	description string
}
<commit_msg>remove post init plugin<commit_after>package apid

const (
	SystemEventsSelector EventSelector = "system event"
)

var (
	APIDInitializedEvent    = systemEvent{"apid initialized"}
	PluginsInitializedEvent = systemEvent{"plugins initialized"}
	APIListeningEvent       = systemEvent{"api listening"}

	pluginInitFuncs []PluginInitFunc
	services        Services
)

type Services interface {
	API() APIService
	Config() ConfigService
	Data() DataService
	Events() EventsService
	Log() LogService
}

type PluginInitFunc func(Services) error

// passed Services can be a factory - makes copies and maintains returned references
// eg. apid.Initialize(factory.DefaultServicesFactory())

func Initialize(s Services) {
	ss := &servicesSet{}
	services = ss
	// order is important
	ss.config = s.Config()
	ss.log = s.Log()
	ss.events = s.Events()
	ss.api = s.API()
	ss.data = s.Data()

	ss.events.Emit(SystemEventsSelector, APIDInitializedEvent)
}

func RegisterPlugin(plugin PluginInitFunc) {
	pluginInitFuncs = append(pluginInitFuncs, plugin)
}

func InitializePlugins() {
	log := Log()
	log.Debugf("Initializing plugins...")
	for _, p := range pluginInitFuncs {
		err := p(services)
		if err != nil {
			log.Panicf("Error initializing plugin: %s", err)
		}
	}
	Events().Emit(SystemEventsSelector, PluginsInitializedEvent)
	log.Debugf("done initializing plugins")
}

func AllServices() Services {
	return services
}

func Log() LogService {
	return services.Log()
}

func API() APIService {
	return services.API()
}

func Config() ConfigService {
	return services.Config()
}

func Data() DataService {
	return services.Data()
}

func Events() EventsService {
	return services.Events()
}

type servicesSet struct {
	config ConfigService
	log    LogService
	api    APIService
	data   DataService
	events EventsService
}

func (s *servicesSet) API() APIService {
	return s.api
}

func (s *servicesSet) Config() ConfigService {
	return s.config
}

func (s *servicesSet) Data() DataService {
	return s.data
}

func (s *servicesSet) Events() EventsService {
	return s.events
}

func (s *servicesSet) Log() LogService {
	return s.log
}

type systemEvent struct {
	description string
}
<|endoftext|>


<commit_before>package gtsdk

import (
	"fmt"
	"net/http"
	"time"
	"crypto/md5"
	"math/rand"
	"strconv"
	"encoding/json"
	"strings"
	"net/url"
	"math"
	"log"
	"io/ioutil"
)

const (
	FN_CHALLENGE = "geetest_challenge"
	FN_VALIDATE = "geetest_validate"
	FN_SECCODE = "geetest_seccode"

	GT_STATUS_SESSION_KEY = "gt_server_status"

	API_URL = "http://api.geetest.com"
	REGISTER_HANDLER = "/register.php"
	VALIDATE_HANDLER = "/validate.php"

	VERSION = "3.2.0"
)

type Geetest struct {
	privateKey  string
	captchaID   string
	sdkVersion  string
	responseStr string
}

//CreateGeeTest 创建GeetestLib实例
func GeetestLib(privateKey, captchaID string) *Geetest {
	return &Geetest{
		privateKey:privateKey,
		captchaID:captchaID,
		sdkVersion:VERSION,
		responseStr:"",
	}
}

//PreProcess 验证初始化预处理.
func (gt *Geetest)PreProcess(userID string) int {
	status, challenge := gt.register(userID)
	gt.responseStr = gt.makeResponseFormat(status, challenge)
	return status
}

func (gt *Geetest)register(userID string) (int, string) {
	challenge := gt.registerChallenge(userID)
	if len(challenge) != 32 {
		return 0, gt.makeFailChallenge()
	}
	return 2, gt.md5Encode(append(challenge, []byte(gt.privateKey)...))
}

func (gt *Geetest)GetResponseStr() string {
	return gt.responseStr
}

func (gt *Geetest)makeFailChallenge() string {
	rand.Seed(time.Now().Unix())
	rnd1 := rand.Intn(100)
	rnd2 := rand.Intn(100)
	md5_str1 := gt.md5Encode([]byte(strconv.Itoa(rnd1)))
	md5_str2 := gt.md5Encode([]byte(strconv.Itoa(rnd2)))
	challenge := md5_str1 + md5_str2[0:2]
	return challenge
}

func (gt *Geetest)makeResponseFormat(status int, challenge string) string {
	jsonmap := make(map[string]interface{})
	jsonmap["success"] = status
	jsonmap["gt"] = gt.captchaID
	jsonmap["challenge"] = challenge
	jsonbyte, _ := json.Marshal(jsonmap)
	return string(jsonbyte)
}

//registerChallenge
func (gt *Geetest)registerChallenge(userID string) (respbytes []byte) {
	var registerURL string
	if userID != "" {
		registerURL = fmt.Sprintf("%s%s?gt=%s&user_id=%s", API_URL, REGISTER_HANDLER, gt.captchaID, userID)
	} else {
		registerURL = fmt.Sprintf("%s%s?gt=%s", API_URL, REGISTER_HANDLER, gt.captchaID)
	}
	client := http.Client{Timeout: 15 * time.Second }
	resp, err := client.Get(registerURL)
	log.Println("err:",registerURL,err)
	if err != nil {
		log.Println(err.Error())
		return
	}
	defer resp.Body.Close()
	log.Println("resp.StatusCode",resp.StatusCode)
	respbytes ,err = ioutil.ReadAll(resp.Body)
	log.Println(respbytes,err)
	if err != nil {
		log.Println(err.Error())
		return
	}
	log.Println(string(respbytes))
	return
}

//SuccessValidate 正常模式的二次验证方式.向geetest server 请求验证结果.
func (gt *Geetest)SuccessValidate(challenge, validate, seccode, userID string) bool {
	if !gt.checkParam(challenge, validate, seccode) || !gt.checkResult(challenge, validate) {
		return false
	}
	validateURL := fmt.Sprintf("%s%s", API_URL, VALIDATE_HANDLER)
	log.Println(validateURL)
	postdata := url.Values{}
	postdata.Add("seccode", seccode)
	postdata.Add("sdk", "python_" + VERSION)
	if userID != "" {
		postdata.Add("user_id", userID)
	}
	backinfo := gt.postValues(validateURL, postdata)
	return backinfo == gt.md5Encode([]byte(seccode))
}

func (gt *Geetest)postValues(url string, data url.Values) string {
	var respbyte []byte
	resp, err := http.PostForm(url, data)
	if err != nil {
		return ""
	}
	defer resp.Body.Close()
	respbyte, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err.Error())
	}
	return string(respbyte)
}

func (gt *Geetest)checkResult(origin, validate string) bool {
	encodeStr := gt.md5Encode([]byte(gt.privateKey + "geetest" + origin))
	return encodeStr == validate
}

//FailbackValidate failback模式的二次验证方式.在本地对轨迹进行简单的判断返回验证结果.
func (gt *Geetest)FailbackValidate(challenge, validate, seccode string) bool {
	if !gt.checkParam(challenge, validate, seccode) {
		return false
	}
	validate_str := strings.Split(validate, "_")
	if len(validate_str) < 3 {
		return false
	}
	encodeAns := validate_str[0]
	encodeFbii := validate_str[1]
	encodeIgi := validate_str[2]
	decodeAns := gt.decodeResponse(challenge, encodeAns)
	decodeFbii := gt.decodeResponse(challenge, encodeFbii)
	decodeIgi := gt.decodeResponse(challenge, encodeIgi)
	validateResult := gt.validateFailImage(decodeAns, decodeFbii, decodeIgi)
	return validateResult
}

func (gt *Geetest)checkParam(params ...string) bool {
	for _, param := range params {
		if strings.TrimSpace(param) == "" {
			return false
		}
	}
	return true
}

func (gt *Geetest)validateFailImage(ans, fullBgIndex, imgGrpIndex int) bool{
	var thread float64 = 3
	fullBgIndexStr := gt.md5Encode([]byte(strconv.Itoa(fullBgIndex)))[0:10]
	imgGrpIndexStr := gt.md5Encode([]byte(strconv.Itoa(imgGrpIndex)))[0:10]
	var answerDecode []byte
	for i := 0; i < 10; i++ {
		if i % 2 == 0 {
			answerDecode = append(answerDecode, fullBgIndexStr[i])
		} else if i % 2 == 1 {
			answerDecode = append(answerDecode, imgGrpIndexStr[i])
		}
	}
	xDecode := answerDecode[4:]
	xInt64,err := strconv.ParseInt(string(xDecode), 16, 32)
	if err != nil{
		log.Println(err.Error())
	}
	xInt := int(xInt64)
	result := xInt % 200
	if result < 40 {
		result = 40
	}
	return math.Abs(float64(ans - result)) < thread
}

func (gt *Geetest)md5Encode(values []byte) string {
	return fmt.Sprintf("%x", md5.Sum(values))
}

func (gt *Geetest)decodeRandBase(challenge string) int {
	baseStr := challenge[32:]
	var tempList []int
	for _, char := range baseStr {
		tempChar := int(char)
		result := tempChar - 48
		if (tempChar > 57) {
			result = tempChar - 87
		}
		tempList = append(tempList, result)
	}
	return tempList[0] * 36 + tempList[1]
}

func (gt *Geetest)decodeResponse(challenge, userresponse string) (res int) {
	if len(userresponse) > 100 {
		return
	}
	digits := []int{1, 2, 5, 10, 50}
	key := make(map[rune]int)
	for _, i := range challenge {
		if _,exist := key[i]; exist {
			continue
		}
		value := digits[len(key) % 5]
		key[i] = value
	}
	for _, i := range userresponse {
		res += key[i]
	}
	res -= gt.decodeRandBase(challenge)
	return
}

<commit_msg>update: 清理日志代码<commit_after>package gtsdk

import (
	"fmt"
	"net/http"
	"time"
	"crypto/md5"
	"math/rand"
	"strconv"
	"encoding/json"
	"strings"
	"net/url"
	"math"
	"log"
	"io/ioutil"
)

const (
	FN_CHALLENGE = "geetest_challenge"
	FN_VALIDATE = "geetest_validate"
	FN_SECCODE = "geetest_seccode"

	GT_STATUS_SESSION_KEY = "gt_server_status"

	API_URL = "http://api.geetest.com"
	REGISTER_HANDLER = "/register.php"
	VALIDATE_HANDLER = "/validate.php"

	VERSION = "3.2.0"
)

type Geetest struct {
	privateKey  string
	captchaID   string
	sdkVersion  string
	responseStr string
}

//CreateGeeTest 创建GeetestLib实例
func GeetestLib(privateKey, captchaID string) *Geetest {
	return &Geetest{
		privateKey:privateKey,
		captchaID:captchaID,
		sdkVersion:VERSION,
		responseStr:"",
	}
}

//PreProcess 验证初始化预处理.
func (gt *Geetest)PreProcess(userID string) int {
	status, challenge := gt.register(userID)
	gt.responseStr = gt.makeResponseFormat(status, challenge)
	return status
}

func (gt *Geetest)register(userID string) (int, string) {
	challenge := gt.registerChallenge(userID)
	if len(challenge) != 32 {
		return 0, gt.makeFailChallenge()
	}
	return 2, gt.md5Encode(append(challenge, []byte(gt.privateKey)...))
}

func (gt *Geetest)GetResponseStr() string {
	return gt.responseStr
}

func (gt *Geetest)makeFailChallenge() string {
	rand.Seed(time.Now().Unix())
	rnd1 := rand.Intn(100)
	rnd2 := rand.Intn(100)
	md5_str1 := gt.md5Encode([]byte(strconv.Itoa(rnd1)))
	md5_str2 := gt.md5Encode([]byte(strconv.Itoa(rnd2)))
	challenge := md5_str1 + md5_str2[0:2]
	return challenge
}

func (gt *Geetest)makeResponseFormat(status int, challenge string) string {
	jsonmap := make(map[string]interface{})
	jsonmap["success"] = status
	jsonmap["gt"] = gt.captchaID
	jsonmap["challenge"] = challenge
	jsonbyte, _ := json.Marshal(jsonmap)
	return string(jsonbyte)
}

//registerChallenge
func (gt *Geetest)registerChallenge(userID string) (respbytes []byte) {
	var registerURL string
	if userID != "" {
		registerURL = fmt.Sprintf("%s%s?gt=%s&user_id=%s", API_URL, REGISTER_HANDLER, gt.captchaID, userID)
	} else {
		registerURL = fmt.Sprintf("%s%s?gt=%s", API_URL, REGISTER_HANDLER, gt.captchaID)
	}
	client := http.Client{Timeout: 15 * time.Second }
	resp, err := client.Get(registerURL)
	if err != nil {
		log.Println(err.Error())
		return
	}
	defer resp.Body.Close()
	respbytes ,err = ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err.Error())
		return
	}
	return
}

//SuccessValidate 正常模式的二次验证方式.向geetest server 请求验证结果.
func (gt *Geetest)SuccessValidate(challenge, validate, seccode, userID string) bool {
	if !gt.checkParam(challenge, validate, seccode) || !gt.checkResult(challenge, validate) {
		return false
	}
	validateURL := fmt.Sprintf("%s%s", API_URL, VALIDATE_HANDLER)
	postdata := url.Values{}
	postdata.Add("seccode", seccode)
	postdata.Add("sdk", "python_" + VERSION)
	if userID != "" {
		postdata.Add("user_id", userID)
	}
	backinfo := gt.postValues(validateURL, postdata)
	return backinfo == gt.md5Encode([]byte(seccode))
}

func (gt *Geetest)postValues(url string, data url.Values) string {
	var respbyte []byte
	resp, err := http.PostForm(url, data)
	if err != nil {
		return ""
	}
	defer resp.Body.Close()
	respbyte, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err.Error())
	}
	return string(respbyte)
}

func (gt *Geetest)checkResult(origin, validate string) bool {
	encodeStr := gt.md5Encode([]byte(gt.privateKey + "geetest" + origin))
	return encodeStr == validate
}

//FailbackValidate failback模式的二次验证方式.在本地对轨迹进行简单的判断返回验证结果.
func (gt *Geetest)FailbackValidate(challenge, validate, seccode string) bool {
	if !gt.checkParam(challenge, validate, seccode) {
		return false
	}
	validate_str := strings.Split(validate, "_")
	if len(validate_str) < 3 {
		return false
	}
	encodeAns := validate_str[0]
	encodeFbii := validate_str[1]
	encodeIgi := validate_str[2]
	decodeAns := gt.decodeResponse(challenge, encodeAns)
	decodeFbii := gt.decodeResponse(challenge, encodeFbii)
	decodeIgi := gt.decodeResponse(challenge, encodeIgi)
	validateResult := gt.validateFailImage(decodeAns, decodeFbii, decodeIgi)
	return validateResult
}

func (gt *Geetest)checkParam(params ...string) bool {
	for _, param := range params {
		if strings.TrimSpace(param) == "" {
			return false
		}
	}
	return true
}

func (gt *Geetest)validateFailImage(ans, fullBgIndex, imgGrpIndex int) bool{
	var thread float64 = 3
	fullBgIndexStr := gt.md5Encode([]byte(strconv.Itoa(fullBgIndex)))[0:10]
	imgGrpIndexStr := gt.md5Encode([]byte(strconv.Itoa(imgGrpIndex)))[0:10]
	var answerDecode []byte
	for i := 0; i < 10; i++ {
		if i % 2 == 0 {
			answerDecode = append(answerDecode, fullBgIndexStr[i])
		} else if i % 2 == 1 {
			answerDecode = append(answerDecode, imgGrpIndexStr[i])
		}
	}
	xDecode := answerDecode[4:]
	xInt64,err := strconv.ParseInt(string(xDecode), 16, 32)
	if err != nil{
		log.Println(err.Error())
	}
	xInt := int(xInt64)
	result := xInt % 200
	if result < 40 {
		result = 40
	}
	return math.Abs(float64(ans - result)) < thread
}

func (gt *Geetest)md5Encode(values []byte) string {
	return fmt.Sprintf("%x", md5.Sum(values))
}

func (gt *Geetest)decodeRandBase(challenge string) int {
	baseStr := challenge[32:]
	var tempList []int
	for _, char := range baseStr {
		tempChar := int(char)
		result := tempChar - 48
		if (tempChar > 57) {
			result = tempChar - 87
		}
		tempList = append(tempList, result)
	}
	return tempList[0] * 36 + tempList[1]
}

func (gt *Geetest)decodeResponse(challenge, userresponse string) (res int) {
	if len(userresponse) > 100 {
		return
	}
	digits := []int{1, 2, 5, 10, 50}
	key := make(map[rune]int)
	for _, i := range challenge {
		if _,exist := key[i]; exist {
			continue
		}
		value := digits[len(key) % 5]
		key[i] = value
	}
	for _, i := range userresponse {
		res += key[i]
	}
	res -= gt.decodeRandBase(challenge)
	return
}

<|endoftext|>


<commit_before>package packer

import "log"

// A Build represents a single job within Packer that is responsible for
// building some machine image artifact. Builds are meant to be parallelized.
type Build interface {
	Name() string
	Prepare() error
	Run(Ui, Cache) (Artifact, error)
	Cancel()
}

// A build struct represents a single build job, the result of which should
// be a single machine image artifact. This artifact may be comprised of
// multiple files, of course, but it should be for only a single provider
// (such as VirtualBox, EC2, etc.).
type coreBuild struct {
	name          string
	builder       Builder
	builderConfig interface{}
	hooks         map[string][]Hook
	provisioners  []coreBuildProvisioner

	prepareCalled bool
}

// Keeps track of the provisioner and the configuration of the provisioner
// within the build.
type coreBuildProvisioner struct {
	provisioner Provisioner
	config      []interface{}
}

// Returns the name of the build.
func (b *coreBuild) Name() string {
	return b.name
}

// Prepare prepares the build by doing some initialization for the builder
// and any hooks. This _must_ be called prior to Run.
func (b *coreBuild) Prepare() (err error) {
	// TODO: lock
	b.prepareCalled = true

	// Prepare the builder
	err = b.builder.Prepare(b.builderConfig)
	if err != nil {
		log.Printf("Build '%s' prepare failure: %s\n", b.name, err)
		return
	}

	// Prepare the provisioners
	for _, coreProv := range b.provisioners {
		if err = coreProv.provisioner.Prepare(coreProv.config...); err != nil {
			return
		}
	}

	return
}

// Runs the actual build. Prepare must be called prior to running this.
func (b *coreBuild) Run(ui Ui, cache Cache) (Artifact, error) {
	if !b.prepareCalled {
		panic("Prepare must be called first")
	}

	// Copy the hooks
	hooks := make(map[string][]Hook)
	for hookName, hookList := range b.hooks {
		hooks[hookName] = make([]Hook, len(hookList))
		copy(hooks[hookName], hookList)
	}

	// Add a hook for the provisioners if we have provisioners
	if len(b.provisioners) > 0 {
		provisioners := make([]Provisioner, len(b.provisioners))
		for i, p := range b.provisioners {
			provisioners[i] = p.provisioner
		}

		if _, ok := hooks[HookProvision]; !ok {
			hooks[HookProvision] = make([]Hook, 0, 1)
		}

		hooks[HookProvision] = append(hooks[HookProvision], &ProvisionHook{provisioners})
	}

	hook := &DispatchHook{hooks}
	return b.builder.Run(ui, hook, cache)
}

// Cancels the build if it is running.
func (b *coreBuild) Cancel() {
	b.builder.Cancel()
}
<commit_msg>packer: Comments on Build interface<commit_after>package packer

import "log"

// A Build represents a single job within Packer that is responsible for
// building some machine image artifact. Builds are meant to be parallelized.
type Build interface {
	// Name is the name of the build. This is unique across a single template,
	// but not absolutely unique. This is meant more to describe to the user
	// what is being built rather than being a unique identifier.
	Name() string

	// Prepare configures the various components of this build and reports
	// any errors in doing so (such as syntax errors, validation errors, etc.)
	Prepare() error

	// Run runs the actual builder, returning an artifact implementation
	// of what is built. If anything goes wrong, an error is returned.
	Run(Ui, Cache) (Artifact, error)

	// Cancel will cancel a running build. This will block until the build
	// is actually completely cancelled.
	Cancel()
}

// A build struct represents a single build job, the result of which should
// be a single machine image artifact. This artifact may be comprised of
// multiple files, of course, but it should be for only a single provider
// (such as VirtualBox, EC2, etc.).
type coreBuild struct {
	name          string
	builder       Builder
	builderConfig interface{}
	hooks         map[string][]Hook
	provisioners  []coreBuildProvisioner

	prepareCalled bool
}

// Keeps track of the provisioner and the configuration of the provisioner
// within the build.
type coreBuildProvisioner struct {
	provisioner Provisioner
	config      []interface{}
}

// Returns the name of the build.
func (b *coreBuild) Name() string {
	return b.name
}

// Prepare prepares the build by doing some initialization for the builder
// and any hooks. This _must_ be called prior to Run.
func (b *coreBuild) Prepare() (err error) {
	// TODO: lock
	b.prepareCalled = true

	// Prepare the builder
	err = b.builder.Prepare(b.builderConfig)
	if err != nil {
		log.Printf("Build '%s' prepare failure: %s\n", b.name, err)
		return
	}

	// Prepare the provisioners
	for _, coreProv := range b.provisioners {
		if err = coreProv.provisioner.Prepare(coreProv.config...); err != nil {
			return
		}
	}

	return
}

// Runs the actual build. Prepare must be called prior to running this.
func (b *coreBuild) Run(ui Ui, cache Cache) (Artifact, error) {
	if !b.prepareCalled {
		panic("Prepare must be called first")
	}

	// Copy the hooks
	hooks := make(map[string][]Hook)
	for hookName, hookList := range b.hooks {
		hooks[hookName] = make([]Hook, len(hookList))
		copy(hooks[hookName], hookList)
	}

	// Add a hook for the provisioners if we have provisioners
	if len(b.provisioners) > 0 {
		provisioners := make([]Provisioner, len(b.provisioners))
		for i, p := range b.provisioners {
			provisioners[i] = p.provisioner
		}

		if _, ok := hooks[HookProvision]; !ok {
			hooks[HookProvision] = make([]Hook, 0, 1)
		}

		hooks[HookProvision] = append(hooks[HookProvision], &ProvisionHook{provisioners})
	}

	hook := &DispatchHook{hooks}
	return b.builder.Run(ui, hook, cache)
}

// Cancels the build if it is running.
func (b *coreBuild) Cancel() {
	b.builder.Cancel()
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All rights reserved.

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 e2e

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	. "github.com/onsi/ginkgo"
)

const (
	nautilusImage       = "kubernetes/update-demo:nautilus"
	kittenImage         = "kubernetes/update-demo:kitten"
	updateDemoSelector  = "name=update-demo"
	updateDemoContainer = "update-demo"
	validateTimeout     = 10 * time.Minute // TODO: Make this 30 seconds once #4566 is resolved.
	kubectlProxyPort    = 8011
)

var _ = Describe("kubectl", func() {

	// Constants.
	var (
		updateDemoRoot = filepath.Join(testContext.repoRoot, "examples/update-demo")
		nautilusPath   = filepath.Join(updateDemoRoot, "nautilus-rc.yaml")
		kittenPath     = filepath.Join(updateDemoRoot, "kitten-rc.yaml")
	)

	var cmd *exec.Cmd

	BeforeEach(func() {
		cmd = kubectlCmd("proxy", fmt.Sprintf("--port=%d", kubectlProxyPort))
		if err := cmd.Start(); err != nil {
			Failf("Unable to start kubectl proxy: %v", err)
		}
	})

	AfterEach(func() {
		if cmd.Process == nil {
			Logf("No process associated with the kubectl proxy")
			return
		}
		// Kill the proxy
		errChan := make(chan error, 1)
		go func() {
			if err := cmd.Process.Signal(os.Interrupt); err != nil {
				errChan <- err
			}
			_, err := cmd.Process.Wait()
			errChan <- err
		}()
		select {
		case <-time.After(10 * time.Second):
			Fail("Timed out waiting for kubectl proxy process to exit")
		case err := <-errChan:
			if err != nil {
				Failf("Unable to kill kubectl proxy: %v", err)
			}
		}
	})

	It("should create and stop a replication controller", func() {
		defer cleanup(nautilusPath)

		By("creating a replication controller")
		runKubectl("create", "-f", nautilusPath)
		validateController(nautilusImage, 2)
	})

	It("should scale a replication controller", func() {
		defer cleanup(nautilusPath)

		By("creating a replication controller")
		runKubectl("create", "-f", nautilusPath)
		validateController(nautilusImage, 2)
		By("scaling down the replication controller")
		runKubectl("resize", "rc", "update-demo-nautilus", "--replicas=1")
		validateController(nautilusImage, 1)
		By("scaling up the replication controller")
		runKubectl("resize", "rc", "update-demo-nautilus", "--replicas=2")
		validateController(nautilusImage, 2)
	})

	It("should do a rolling update of a replication controller", func() {
		// Cleanup all resources in case we fail somewhere in the middle
		defer cleanup(updateDemoRoot)

		By("creating the initial replication controller")
		runKubectl("create", "-f", nautilusPath)
		validateController(nautilusImage, 2)
		By("rollingupdate to new replication controller")
		runKubectl("rollingupdate", "update-demo-nautilus", "--update-period=1s", "-f", kittenPath)
		validateController(kittenImage, 2)
	})

})

func cleanup(filePath string) {
	By("using stop to clean up resources")
	runKubectl("stop", "-f", filePath)

	resources := runKubectl("get", "pods,rc", "-l", updateDemoSelector, "--no-headers")
	if resources != "" {
		Failf("Resources left running after stop:\n%s", resources)
	}
}

func validateController(image string, replicas int) {

	getPodsTemplate := "--template={{range.items}}{{.id}} {{end}}"

	// NB: kubectl adds the "exists" function to the standard template functions.
	// This lets us check to see if the "running" entry exists for each of the containers
	// we care about. Exists will never return an error and it's safe to check a chain of
	// things, any one of which may not exist. In the below template, all of info,
	// containername, and running might be nil, so the normal index function isn't very
	// helpful.
	// This template is unit-tested in kubectl, so if you change it, update the unit test.
	//
	// You can read about the syntax here: http://golang.org/pkg/text/template/
	getContainerStateTemplate := fmt.Sprintf(`--template={{and (exists . "currentState" "info" "%s" "state" "running")}}`, updateDemoContainer)

	getImageTemplate := fmt.Sprintf(`--template={{(index .currentState.info "%s").image}}`, updateDemoContainer)

	By(fmt.Sprintf("waiting for all containers in %s pods to come up.", updateDemoSelector))
	for start := time.Now(); time.Since(start) < validateTimeout; time.Sleep(5 * time.Second) {
		getPodsOutput := runKubectl("get", "pods", "-o", "template", getPodsTemplate, "-l", updateDemoSelector)
		pods := strings.Fields(getPodsOutput)
		if numPods := len(pods); numPods != replicas {
			By(fmt.Sprintf("Replicas for %s: expected=%d actual=%d", updateDemoSelector, replicas, numPods))
			continue
		}
		var runningPods []string
		for _, podID := range pods {
			running := runKubectl("get", "pods", podID, "-o", "template", getContainerStateTemplate)
			if running == "false" {
				Logf("%s is created but not running", podID)
				continue
			}

			currentImage := runKubectl("get", "pods", podID, "-o", "template", getImageTemplate)
			if currentImage != image {
				Logf("%s is created but running wrong image; expected: %s, actual: %s", podID, image, currentImage)
				continue
			}

			data, err := getData(podID)
			if err != nil {
				Logf("%s is running right image but fetching data failed: %v", podID, err)
				continue
			}
			if strings.Contains(data.image, image) {
				Logf("%s is running right image but fetched data has the wrong info: %s", podID, data)
				continue
			}

			Logf("%s is verified up and running", podID)
			runningPods = append(runningPods, podID)
		}
		if len(runningPods) == replicas {
			return
		}
	}
	Failf("Timed out waiting for %s pods to reach valid state", updateDemoSelector)
}

type updateDemoData struct {
	image string `json:"image"`
}

func getData(podID string) (*updateDemoData, error) {
	resp, err := http.Get(fmt.Sprintf("http://localhost:%d/api/v1beta1/proxy/pods/%s/data.json", kubectlProxyPort, podID))
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("received non-200 status code from master: %d", resp.StatusCode)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	Logf("got data: %s", body)
	var data updateDemoData
	err = json.Unmarshal(body, &data)
	return &data, err
}

func kubectlCmd(args ...string) *exec.Cmd {
	defaultArgs := []string{"--auth-path=" + testContext.authConfig}
	if testContext.certDir != "" {
		defaultArgs = append(defaultArgs,
			fmt.Sprintf("--certificate-authority=%s", filepath.Join(testContext.certDir, "ca.crt")),
			fmt.Sprintf("--client-certificate=%s", filepath.Join(testContext.certDir, "kubecfg.crt")),
			fmt.Sprintf("--client-key=%s", filepath.Join(testContext.certDir, "kubecfg.key")))
	}
	kubectlArgs := append(defaultArgs, args...)
	// TODO: Remove this once gcloud writes a proper entry in the kubeconfig file.
	if testContext.provider == "gke" {
		kubectlArgs = append(kubectlArgs, "--server="+testContext.host)
	}
	cmd := exec.Command("kubectl", kubectlArgs...)
	Logf("Running '%s %s'", cmd.Path, strings.Join(cmd.Args, " "))
	return cmd
}

func runKubectl(args ...string) string {
	var stdout, stderr bytes.Buffer
	cmd := kubectlCmd(args...)
	cmd.Stdout, cmd.Stderr = &stdout, &stderr

	if err := cmd.Run(); err != nil {
		Failf("Error running %v:\nCommand stdout:\n%v\nstderr:\n%v\n", cmd, cmd.Stdout, cmd.Stderr)
		return ""
	}
	Logf(stdout.String())
	// TODO: trimspace should be unnecessary after switching to use kubectl binary directly
	return strings.TrimSpace(stdout.String())
}
<commit_msg>Replace the use of kubectl proxy with a standard api client.<commit_after>/*
Copyright 2015 Google Inc. All rights reserved.

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 e2e

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"

	. "github.com/onsi/ginkgo"
)

const (
	nautilusImage       = "kubernetes/update-demo:nautilus"
	kittenImage         = "kubernetes/update-demo:kitten"
	updateDemoSelector  = "name=update-demo"
	updateDemoContainer = "update-demo"
	validateTimeout     = 10 * time.Minute // TODO: Make this 30 seconds once #4566 is resolved.
	kubectlProxyPort    = 8011
)

var _ = Describe("kubectl", func() {

	// Constants.
	var (
		updateDemoRoot = filepath.Join(testContext.repoRoot, "examples/update-demo")
		nautilusPath   = filepath.Join(updateDemoRoot, "nautilus-rc.yaml")
		kittenPath     = filepath.Join(updateDemoRoot, "kitten-rc.yaml")
	)

	var c *client.Client

	BeforeEach(func() {
		var err error
		c, err = loadClient()
		expectNoError(err)
	})

	It("should create and stop a replication controller", func() {
		defer cleanup(nautilusPath)

		By("creating a replication controller")
		runKubectl("create", "-f", nautilusPath)
		validateController(c, nautilusImage, 2)
	})

	It("should scale a replication controller", func() {
		defer cleanup(nautilusPath)

		By("creating a replication controller")
		runKubectl("create", "-f", nautilusPath)
		validateController(c, nautilusImage, 2)
		By("scaling down the replication controller")
		runKubectl("resize", "rc", "update-demo-nautilus", "--replicas=1")
		validateController(c, nautilusImage, 1)
		By("scaling up the replication controller")
		runKubectl("resize", "rc", "update-demo-nautilus", "--replicas=2")
		validateController(c, nautilusImage, 2)
	})

	It("should do a rolling update of a replication controller", func() {
		// Cleanup all resources in case we fail somewhere in the middle
		defer cleanup(updateDemoRoot)

		By("creating the initial replication controller")
		runKubectl("create", "-f", nautilusPath)
		validateController(c, nautilusImage, 2)
		By("rollingupdate to new replication controller")
		runKubectl("rollingupdate", "update-demo-nautilus", "--update-period=1s", "-f", kittenPath)
		validateController(c, kittenImage, 2)
	})

})

func cleanup(filePath string) {
	By("using stop to clean up resources")
	runKubectl("stop", "-f", filePath)

	resources := runKubectl("get", "pods,rc", "-l", updateDemoSelector, "--no-headers")
	if resources != "" {
		Failf("Resources left running after stop:\n%s", resources)
	}
}

func validateController(c *client.Client, image string, replicas int) {

	getPodsTemplate := "--template={{range.items}}{{.id}} {{end}}"

	// NB: kubectl adds the "exists" function to the standard template functions.
	// This lets us check to see if the "running" entry exists for each of the containers
	// we care about. Exists will never return an error and it's safe to check a chain of
	// things, any one of which may not exist. In the below template, all of info,
	// containername, and running might be nil, so the normal index function isn't very
	// helpful.
	// This template is unit-tested in kubectl, so if you change it, update the unit test.
	//
	// You can read about the syntax here: http://golang.org/pkg/text/template/
	getContainerStateTemplate := fmt.Sprintf(`--template={{and (exists . "currentState" "info" "%s" "state" "running")}}`, updateDemoContainer)

	getImageTemplate := fmt.Sprintf(`--template={{(index .currentState.info "%s").image}}`, updateDemoContainer)

	By(fmt.Sprintf("waiting for all containers in %s pods to come up.", updateDemoSelector))
	for start := time.Now(); time.Since(start) < validateTimeout; time.Sleep(5 * time.Second) {
		getPodsOutput := runKubectl("get", "pods", "-o", "template", getPodsTemplate, "-l", updateDemoSelector)
		pods := strings.Fields(getPodsOutput)
		if numPods := len(pods); numPods != replicas {
			By(fmt.Sprintf("Replicas for %s: expected=%d actual=%d", updateDemoSelector, replicas, numPods))
			continue
		}
		var runningPods []string
		for _, podID := range pods {
			running := runKubectl("get", "pods", podID, "-o", "template", getContainerStateTemplate)
			if running == "false" {
				Logf("%s is created but not running", podID)
				continue
			}

			currentImage := runKubectl("get", "pods", podID, "-o", "template", getImageTemplate)
			if currentImage != image {
				Logf("%s is created but running wrong image; expected: %s, actual: %s", podID, image, currentImage)
				continue
			}

			data, err := getData(c, podID)
			if err != nil {
				Logf("%s is running right image but fetching data failed: %v", podID, err)
				continue
			}
			if strings.Contains(data.image, image) {
				Logf("%s is running right image but fetched data has the wrong info: %s", podID, data)
				continue
			}

			Logf("%s is verified up and running", podID)
			runningPods = append(runningPods, podID)
		}
		if len(runningPods) == replicas {
			return
		}
	}
	Failf("Timed out waiting for %s pods to reach valid state", updateDemoSelector)
}

type updateDemoData struct {
	image string `json:"image"`
}

func getData(c *client.Client, podID string) (*updateDemoData, error) {
	body, err := c.Get().
		Prefix("proxy").
		Resource("pods").
		Name(podID).
		Suffix("data.json").
		Do().
		Raw()
	if err != nil {
		return nil, err
	}
	Logf("got data: %s", body)
	var data updateDemoData
	err = json.Unmarshal(body, &data)
	return &data, err
}

func kubectlCmd(args ...string) *exec.Cmd {
	defaultArgs := []string{"--auth-path=" + testContext.authConfig}
	if testContext.certDir != "" {
		defaultArgs = append(defaultArgs,
			fmt.Sprintf("--certificate-authority=%s", filepath.Join(testContext.certDir, "ca.crt")),
			fmt.Sprintf("--client-certificate=%s", filepath.Join(testContext.certDir, "kubecfg.crt")),
			fmt.Sprintf("--client-key=%s", filepath.Join(testContext.certDir, "kubecfg.key")))
	}
	kubectlArgs := append(defaultArgs, args...)
	// TODO: Remove this once gcloud writes a proper entry in the kubeconfig file.
	if testContext.provider == "gke" {
		kubectlArgs = append(kubectlArgs, "--server="+testContext.host)
	}
	cmd := exec.Command("kubectl", kubectlArgs...)
	Logf("Running '%s %s'", cmd.Path, strings.Join(cmd.Args, " "))
	return cmd
}

func runKubectl(args ...string) string {
	var stdout, stderr bytes.Buffer
	cmd := kubectlCmd(args...)
	cmd.Stdout, cmd.Stderr = &stdout, &stderr

	if err := cmd.Run(); err != nil {
		Failf("Error running %v:\nCommand stdout:\n%v\nstderr:\n%v\n", cmd, cmd.Stdout, cmd.Stderr)
		return ""
	}
	Logf(stdout.String())
	// TODO: trimspace should be unnecessary after switching to use kubectl binary directly
	return strings.TrimSpace(stdout.String())
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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 metar provides weather using the METAR API from
the NOAA Aviation Digital Data Service,
available at https://www.aviationweather.gov/.
*/
package metar

import (
	"encoding/xml"
	"fmt"
	"math"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/soumya92/barista/modules/weather"
)

// Config represents NOAA ADDS configuration
// from which a weather.Provider can be built.
type Config struct {
	station          string
	stripRemarks     bool
	includeFlightCat bool
}

// Station creates a configuration for the given airport code (e.g. KSEA).
func Station(station string) *Config {
	return &Config{station: station}
}

// StripRemarks strips remarks from the description.
func (c *Config) StripRemarks() *Config {
	c.stripRemarks = true
	return c
}

// IncludeFlightCat adds flight category to the description.
func (c *Config) IncludeFlightCat() *Config {
	c.includeFlightCat = true
	return c
}

// Provider wraps an ADDS XML url and configuration
// so that it can be used as a weather.Provider.
type Provider struct {
	url              string
	stripRemarks     bool
	includeFlightCat bool
}

// Build builds a weather provider from the configuration.
func (c *Config) Build() weather.Provider {
	u := url.URL{
		Scheme: "https",
		Host:   "aviationweather.gov",
		Path:   "/adds/dataserver_current/httpparam",
	}
	q := u.Query()
	q.Set("dataSource", "metars")
	q.Set("requestType", "retrieve")
	q.Set("format", "xml")
	q.Set("stationString", c.station)
	q.Set("hoursBeforeNow", "3")
	q.Set("mostRecent", "true")
	u.RawQuery = q.Encode()

	return Provider{
		url:              u.String(),
		stripRemarks:     c.stripRemarks,
		includeFlightCat: c.includeFlightCat,
	}
}

type skyCondition struct {
	SkyCover  string `xml:"sky_cover,attr"`
	CloudBase int    `xml:"cloud_base_ft_agl,attr"`
}

type metar struct {
	RawText            string         `xml:"raw_text"`
	StationID          string         `xml:"station_id"`
	ObservationTime    string         `xml:"observation_time"`
	Latitude           float64        `xml:"latitude"`
	Longitude          float64        `xml:"longitude"`
	Temperature        float64        `xml:"temp_c"`
	Dewpoint           float64        `xml:"dewpoint_c"`
	WindDirection      int            `xml:"wind_dir_degrees"`
	WindSpeed          int            `xml:"wind_speed_kt"`
	WindGust           int            `xml:"wind_gust_kt"`
	Visibility         float64        `xml:"visibility_statute_mi"`
	Altimeter          float64        `xml:"altim_in_hg"`
	SeaLevelPressure   float64        `xml:"sea_level_pressure_mb"`
	WxString           string         `xml:"wx_string"`
	SkyConditions      []skyCondition `xml:"sky_condition"`
	FlightCategory     string         `xml:"flight_category"`
	VerticalVisibility int            `xml:"vert_vis_ft"`
	StationElevation   float64        `xml:"elevation_m"`
}

func (m metar) getBarometricPressure() weather.Pressure {
	if m.SeaLevelPressure == 0.0 {
		return weather.PressureFromInHg(m.Altimeter)
	}
	return weather.PressureFromMillibar(m.SeaLevelPressure)
}

type addsResponse struct {
	Metars []metar `xml:"data>METAR"`
}

// The August-Roche-Magnus approximation to the saturation vapor pressure.
// https://en.wikipedia.org/wiki/Clausius–Clapeyron_relation
func satVaporPressure(temp float64) float64 {
	return 6.1094 * math.Exp((17.625*temp)/(temp+243.04))
}

// See also: http://andrew.rsmas.miami.edu/bmcnoldy/Humidity.html
func relativeHumidity(temp float64, dewpoint float64) float64 {
	return 100 * (satVaporPressure(dewpoint) / satVaporPressure(temp))
}

var remarksPattern = regexp.MustCompile(` RMK (.*)$`)
var tempPattern = regexp.MustCompile(`\b(\d+)/(\d+)\b`)
var preciseTempPattern = regexp.MustCompile(`\bT\d{8}\b`) // T01320072

func encodeMetarTemp(temp float64) string {
	minus := ""
	if temp < 0 {
		minus = "M"
		temp = -temp
	}

	return fmt.Sprintf("%s%04.1f", minus, temp)
}

func (m metar) encodeMetar(stripRemarks bool, includeFlightCat bool) string {
	mt := strings.TrimSpace(m.RawText)
	if stripRemarks {
		mt = remarksPattern.ReplaceAllString(mt, "")

		// Include the temperature to 0.1C, if it's included in the
		// base METAR. If it is, the METAR will have a T block, and the
		// value will already be parsed in the Temperature and Dewpoint
		// fields of the XML response.
		if preciseTempPattern.MatchString(m.RawText) {
			preciseTemp := fmt.Sprintf(
				"%s/%s",
				encodeMetarTemp(m.Temperature),
				encodeMetarTemp(m.Dewpoint))
			mt = tempPattern.ReplaceAllString(mt, preciseTemp)
		}
	}

	if includeFlightCat {
		mt = fmt.Sprintf("[%s] %s", m.FlightCategory, mt)
	}

	return mt
}

// Cloudiness, in oktas (eighths of the sky covered)
type cloudiness int

const (
	cloudsNone      cloudiness = 0
	cloudsFew                  = 2
	cloudsScattered            = 4
	cloudsBroken               = 7
	cloudsOvercast             = 8
)

var cloudinessMap = map[string]cloudiness{
	"CLR":   cloudsNone,
	"SKC":   cloudsNone,
	"CAVOK": cloudsNone,
	"FEW":   cloudsFew,
	"SCT":   cloudsScattered,
	"BKN":   cloudsBroken,
	"OVC":   cloudsOvercast,
	"OVX":   cloudsOvercast,
}

func (m metar) getCloudiness() cloudiness {
	c := cloudsNone
	for _, skyCond := range m.SkyConditions {
		coverage := cloudinessMap[skyCond.SkyCover]
		if coverage > c {
			c = coverage
		}
	}
	return c
}

func (m metar) getCloudCover() float64 {
	return float64(m.getCloudiness()) / 8.0
}

var thunderstormPattern = regexp.MustCompile(`\b[+-]?TS(..)\b`) // +TSRA, -TSSN
var precipPattern = regexp.MustCompile(`\b([+-]?)(..)?(..)\b`)

// see http://weather.cod.edu/notes/metar.html
var precipMapping = map[string]weather.Condition{
	"DZ": weather.Drizzle,
	"RA": weather.Rain,
	"SN": weather.Snow,
	"SG": weather.Snow,
	"IC": weather.Sleet,
	"PL": weather.Sleet,
	"GR": weather.Hail,
	"GS": weather.Hail,
	"UP": weather.ConditionUnknown,
	"BR": weather.Mist,
	"FG": weather.Fog,
	"FU": weather.Smoke,
	"VA": weather.Smoke,
	"DU": weather.Whirls,
	"SA": weather.Whirls,
	"HZ": weather.Haze,
	"PY": weather.Haze,
	"FC": weather.Tornado,
	"PO": weather.Whirls,
	"SQ": weather.Windy,
	"SS": weather.Whirls,
}

var precipOrder = []weather.Condition{
	weather.Tornado,
	weather.Hail,
	weather.Whirls,
	weather.Windy,
	weather.Smoke,
	weather.Sleet,
	weather.Snow,
	weather.Fog,
	weather.Haze,
	weather.Rain,
	weather.Drizzle,
	weather.ConditionUnknown,
}

func (m metar) getCondition() weather.Condition {
	// Check for thunderstorms first, since that's considered a modifier,
	// rather than a weather condition in and of itself.
	if thunderstormPattern.MatchString(m.WxString) {
		return weather.Thunderstorm
	}

	// Find all of the weather conditions present in the METAR.
	hasCondition := map[weather.Condition]bool{}
	for _, wx := range precipPattern.FindAllStringSubmatch(m.WxString, 0) {
		precip := wx[3]
		hasCondition[precipMapping[precip]] = true
	}

	for _, condition := range precipOrder {
		if hasCondition[condition] {
			return condition
		}
	}

	// No precipitation, look at clouds.
	switch m.getCloudiness() {
	case cloudsOvercast:
		return weather.Overcast
	case cloudsBroken:
		return weather.Cloudy
	case cloudsScattered:
	case cloudsFew:
		return weather.PartlyCloudy
	case cloudsNone:
		return weather.Clear
	}

	return weather.Clear
}

// GetWeather gets weather information from NOAA ADDS.
func (p Provider) GetWeather() (*weather.Weather, error) {
	response, err := http.Get(p.url)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	var resp addsResponse
	err = xml.NewDecoder(response.Body).Decode(&resp)
	if err != nil {
		return nil, err
	}

	if len(resp.Metars) != 1 {
		err = fmt.Errorf("Expected one METAR in response body, got %d", len(resp.Metars))
		return nil, err
	}

	m := resp.Metars[0]

	updated, err := time.Parse(time.RFC3339, m.ObservationTime)
	if err != nil {
		return nil, err
	}

	return &weather.Weather{
		Location:    m.StationID,
		Condition:   m.getCondition(),
		Description: m.encodeMetar(p.stripRemarks, p.includeFlightCat),
		Temperature: weather.TemperatureFromC(m.Temperature),
		Humidity:    relativeHumidity(m.Temperature, m.Dewpoint),
		Pressure:    m.getBarometricPressure(),
		Wind: weather.Wind{
			weather.SpeedFromKnots(float64(m.WindSpeed)),
			weather.Direction(m.WindDirection),
		},
		CloudCover:  m.getCloudCover(),
		Updated:     updated,
		Attribution: "NWS",
	}, nil
}
<commit_msg>metar: Handle bare [+-]TS precipitation stanzas.<commit_after>// Copyright 2017 Google Inc.
//
// 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 metar provides weather using the METAR API from
the NOAA Aviation Digital Data Service,
available at https://www.aviationweather.gov/.
*/
package metar

import (
	"encoding/xml"
	"fmt"
	"math"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/soumya92/barista/modules/weather"
)

// Config represents NOAA ADDS configuration
// from which a weather.Provider can be built.
type Config struct {
	station          string
	stripRemarks     bool
	includeFlightCat bool
}

// Station creates a configuration for the given airport code (e.g. KSEA).
func Station(station string) *Config {
	return &Config{station: station}
}

// StripRemarks strips remarks from the description.
func (c *Config) StripRemarks() *Config {
	c.stripRemarks = true
	return c
}

// IncludeFlightCat adds flight category to the description.
func (c *Config) IncludeFlightCat() *Config {
	c.includeFlightCat = true
	return c
}

// Provider wraps an ADDS XML url and configuration
// so that it can be used as a weather.Provider.
type Provider struct {
	url              string
	stripRemarks     bool
	includeFlightCat bool
}

// Build builds a weather provider from the configuration.
func (c *Config) Build() weather.Provider {
	u := url.URL{
		Scheme: "https",
		Host:   "aviationweather.gov",
		Path:   "/adds/dataserver_current/httpparam",
	}
	q := u.Query()
	q.Set("dataSource", "metars")
	q.Set("requestType", "retrieve")
	q.Set("format", "xml")
	q.Set("stationString", c.station)
	q.Set("hoursBeforeNow", "3")
	q.Set("mostRecent", "true")
	u.RawQuery = q.Encode()

	return Provider{
		url:              u.String(),
		stripRemarks:     c.stripRemarks,
		includeFlightCat: c.includeFlightCat,
	}
}

type skyCondition struct {
	SkyCover  string `xml:"sky_cover,attr"`
	CloudBase int    `xml:"cloud_base_ft_agl,attr"`
}

type metar struct {
	RawText            string         `xml:"raw_text"`
	StationID          string         `xml:"station_id"`
	ObservationTime    string         `xml:"observation_time"`
	Latitude           float64        `xml:"latitude"`
	Longitude          float64        `xml:"longitude"`
	Temperature        float64        `xml:"temp_c"`
	Dewpoint           float64        `xml:"dewpoint_c"`
	WindDirection      int            `xml:"wind_dir_degrees"`
	WindSpeed          int            `xml:"wind_speed_kt"`
	WindGust           int            `xml:"wind_gust_kt"`
	Visibility         float64        `xml:"visibility_statute_mi"`
	Altimeter          float64        `xml:"altim_in_hg"`
	SeaLevelPressure   float64        `xml:"sea_level_pressure_mb"`
	WxString           string         `xml:"wx_string"`
	SkyConditions      []skyCondition `xml:"sky_condition"`
	FlightCategory     string         `xml:"flight_category"`
	VerticalVisibility int            `xml:"vert_vis_ft"`
	StationElevation   float64        `xml:"elevation_m"`
}

func (m metar) getBarometricPressure() weather.Pressure {
	if m.SeaLevelPressure == 0.0 {
		return weather.PressureFromInHg(m.Altimeter)
	}
	return weather.PressureFromMillibar(m.SeaLevelPressure)
}

type addsResponse struct {
	Metars []metar `xml:"data>METAR"`
}

// The August-Roche-Magnus approximation to the saturation vapor pressure.
// https://en.wikipedia.org/wiki/Clausius–Clapeyron_relation
func satVaporPressure(temp float64) float64 {
	return 6.1094 * math.Exp((17.625*temp)/(temp+243.04))
}

// See also: http://andrew.rsmas.miami.edu/bmcnoldy/Humidity.html
func relativeHumidity(temp float64, dewpoint float64) float64 {
	return 100 * (satVaporPressure(dewpoint) / satVaporPressure(temp))
}

var remarksPattern = regexp.MustCompile(` RMK (.*)$`)
var tempPattern = regexp.MustCompile(`\b(\d+)/(\d+)\b`)
var preciseTempPattern = regexp.MustCompile(`\bT\d{8}\b`) // T01320072

func encodeMetarTemp(temp float64) string {
	minus := ""
	if temp < 0 {
		minus = "M"
		temp = -temp
	}

	return fmt.Sprintf("%s%04.1f", minus, temp)
}

func (m metar) encodeMetar(stripRemarks bool, includeFlightCat bool) string {
	mt := strings.TrimSpace(m.RawText)
	if stripRemarks {
		mt = remarksPattern.ReplaceAllString(mt, "")

		// Include the temperature to 0.1C, if it's included in the
		// base METAR. If it is, the METAR will have a T block, and the
		// value will already be parsed in the Temperature and Dewpoint
		// fields of the XML response.
		if preciseTempPattern.MatchString(m.RawText) {
			preciseTemp := fmt.Sprintf(
				"%s/%s",
				encodeMetarTemp(m.Temperature),
				encodeMetarTemp(m.Dewpoint))
			mt = tempPattern.ReplaceAllString(mt, preciseTemp)
		}
	}

	if includeFlightCat {
		mt = fmt.Sprintf("[%s] %s", m.FlightCategory, mt)
	}

	return mt
}

// Cloudiness, in oktas (eighths of the sky covered)
type cloudiness int

const (
	cloudsNone      cloudiness = 0
	cloudsFew                  = 2
	cloudsScattered            = 4
	cloudsBroken               = 7
	cloudsOvercast             = 8
)

var cloudinessMap = map[string]cloudiness{
	"CLR":   cloudsNone,
	"SKC":   cloudsNone,
	"CAVOK": cloudsNone,
	"FEW":   cloudsFew,
	"SCT":   cloudsScattered,
	"BKN":   cloudsBroken,
	"OVC":   cloudsOvercast,
	"OVX":   cloudsOvercast,
}

func (m metar) getCloudiness() cloudiness {
	c := cloudsNone
	for _, skyCond := range m.SkyConditions {
		coverage := cloudinessMap[skyCond.SkyCover]
		if coverage > c {
			c = coverage
		}
	}
	return c
}

func (m metar) getCloudCover() float64 {
	return float64(m.getCloudiness()) / 8.0
}

var thunderstormPattern = regexp.MustCompile(`\b[+-]?TS(..)?\b`) // +TSRA, -TSSN, TS
var precipPattern = regexp.MustCompile(`\b([+-]?)(..)?(..)\b`)

// see http://weather.cod.edu/notes/metar.html
var precipMapping = map[string]weather.Condition{
	"DZ": weather.Drizzle,
	"RA": weather.Rain,
	"SN": weather.Snow,
	"SG": weather.Snow,
	"IC": weather.Sleet,
	"PL": weather.Sleet,
	"GR": weather.Hail,
	"GS": weather.Hail,
	"UP": weather.ConditionUnknown,
	"BR": weather.Mist,
	"FG": weather.Fog,
	"FU": weather.Smoke,
	"VA": weather.Smoke,
	"DU": weather.Whirls,
	"SA": weather.Whirls,
	"HZ": weather.Haze,
	"PY": weather.Haze,
	"FC": weather.Tornado,
	"PO": weather.Whirls,
	"SQ": weather.Windy,
	"SS": weather.Whirls,
}

var precipOrder = []weather.Condition{
	weather.Tornado,
	weather.Hail,
	weather.Whirls,
	weather.Windy,
	weather.Smoke,
	weather.Sleet,
	weather.Snow,
	weather.Fog,
	weather.Haze,
	weather.Rain,
	weather.Drizzle,
	weather.ConditionUnknown,
}

func (m metar) getCondition() weather.Condition {
	// Check for thunderstorms first, since that's considered a modifier,
	// rather than a weather condition in and of itself.
	if thunderstormPattern.MatchString(m.WxString) {
		return weather.Thunderstorm
	}

	// Find all of the weather conditions present in the METAR.
	hasCondition := map[weather.Condition]bool{}
	for _, wx := range precipPattern.FindAllStringSubmatch(m.WxString, 0) {
		precip := wx[3]
		hasCondition[precipMapping[precip]] = true
	}

	for _, condition := range precipOrder {
		if hasCondition[condition] {
			return condition
		}
	}

	// No precipitation, look at clouds.
	switch m.getCloudiness() {
	case cloudsOvercast:
		return weather.Overcast
	case cloudsBroken:
		return weather.Cloudy
	case cloudsScattered:
	case cloudsFew:
		return weather.PartlyCloudy
	case cloudsNone:
		return weather.Clear
	}

	return weather.Clear
}

// GetWeather gets weather information from NOAA ADDS.
func (p Provider) GetWeather() (*weather.Weather, error) {
	response, err := http.Get(p.url)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	var resp addsResponse
	err = xml.NewDecoder(response.Body).Decode(&resp)
	if err != nil {
		return nil, err
	}

	if len(resp.Metars) != 1 {
		err = fmt.Errorf("Expected one METAR in response body, got %d", len(resp.Metars))
		return nil, err
	}

	m := resp.Metars[0]

	updated, err := time.Parse(time.RFC3339, m.ObservationTime)
	if err != nil {
		return nil, err
	}

	return &weather.Weather{
		Location:    m.StationID,
		Condition:   m.getCondition(),
		Description: m.encodeMetar(p.stripRemarks, p.includeFlightCat),
		Temperature: weather.TemperatureFromC(m.Temperature),
		Humidity:    relativeHumidity(m.Temperature, m.Dewpoint),
		Pressure:    m.getBarometricPressure(),
		Wind: weather.Wind{
			weather.SpeedFromKnots(float64(m.WindSpeed)),
			weather.Direction(m.WindDirection),
		},
		CloudCover:  m.getCloudCover(),
		Updated:     updated,
		Attribution: "NWS",
	}, nil
}
<|endoftext|>


<commit_before>package rtp

import (
	"math/rand"
	"time"
)

// Payloader payloads a byte array for use as rtp.Packet payloads
type Payloader interface {
	Payload(mtu int, payload []byte) [][]byte
}

// Packetizer packetizes a payload
type Packetizer interface {
	Packetize(payload []byte, samples uint32) []*Packet
	EnableAbsSendTime(value int)
}

type packetizer struct {
	MTU         int
	PayloadType uint8
	SSRC        uint32
	Payloader   Payloader
	Sequencer   Sequencer
	Timestamp   uint32
	ClockRate   uint32
	AbsSendTime int //if this is nonzero, then it's the extension number that's applied to http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
}

// NewPacketizer returns a new instance of a Packetizer for a specific payloader
func NewPacketizer(mtu int, pt uint8, ssrc uint32, payloader Payloader, sequencer Sequencer, clockRate uint32) Packetizer {
	rs := rand.NewSource(time.Now().UnixNano())
	r := rand.New(rs)

	return &packetizer{
		MTU:         mtu,
		PayloadType: pt,
		SSRC:        ssrc,
		Payloader:   payloader,
		Sequencer:   sequencer,
		Timestamp:   r.Uint32(),
		ClockRate:   clockRate,
	}
}

func (p *packetizer) EnableAbsSendTime(value int) {
	p.AbsSendTime = value
}

func toNtpTime(t time.Time) uint64 {
	var s uint64
	var f uint64
	u := uint64(t.UnixNano())
	s = u / 1e9
	s += 0x83AA7E80 //offset in seconds between unix epoch and ntp epoch
	f = u % 1e9
	f <<= 32
	f /= 1e9
	s <<= 32

	return s | f
}

// Packetize packetizes the payload of an RTP packet and returns one or more RTP packets
func (p *packetizer) Packetize(payload []byte, samples uint32) []*Packet {
	// Guard against an empty payload
	if len(payload) == 0 {
		return nil
	}

	payloads := p.Payloader.Payload(p.MTU-12, payload)
	packets := make([]*Packet, len(payloads))

	for i, pp := range payloads {
		packets[i] = &Packet{
			Header: Header{
				Version:        2,
				Padding:        false,
				Extension:      false,
				Marker:         i == len(payloads)-1,
				PayloadType:    p.PayloadType,
				SequenceNumber: p.Sequencer.NextSequenceNumber(),
				Timestamp:      p.Timestamp, // Figure out how to do timestamps
				SSRC:           p.SSRC,
			},
			Payload: pp,
		}
	}
	p.Timestamp += samples

	if p.AbsSendTime != 0 {
		t := toNtpTime(time.Now()) >> 14
		//apply http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
		packets[len(payloads)-1].Header.Extension = true
		packets[len(payloads)-1].ExtensionProfile = 0xBEDE
		packets[len(payloads)-1].ExtensionPayload = []byte{
			//the first byte is
			// 0 1 2 3 4 5 6 7
			//+-+-+-+-+-+-+-+-+
			//|  ID   |  len  |
			//+-+-+-+-+-+-+-+-+
			//per RFC65285
			//Len is the number of bytes in the extension - 1

			byte((p.AbsSendTime << 4) | 2),
			byte(t & 0xFF0000 >> 16),
			byte(t & 0xFF00 >> 8),
			byte(t & 0xFF),
		}

	}

	return packets
}
<commit_msg>Some improvements from @maxhawkins review<commit_after>package rtp

import (
	"math/rand"
	"time"
)

// Payloader payloads a byte array for use as rtp.Packet payloads
type Payloader interface {
	Payload(mtu int, payload []byte) [][]byte
}

// Packetizer packetizes a payload
type Packetizer interface {
	Packetize(payload []byte, samples uint32) []*Packet
	EnableAbsSendTime(value int)
}

type packetizer struct {
	MTU              int
	PayloadType      uint8
	SSRC             uint32
	Payloader        Payloader
	Sequencer        Sequencer
	Timestamp        uint32
	ClockRate        uint32
	extensionNumbers struct { //put extension numbers in here. If they're 0, the extension is disabled (0 is not a legal extension number)
		AbsSendTime int //http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
	}
	timegen func() time.Time
}

// NewPacketizer returns a new instance of a Packetizer for a specific payloader
func NewPacketizer(mtu int, pt uint8, ssrc uint32, payloader Payloader, sequencer Sequencer, clockRate uint32) Packetizer {
	rs := rand.NewSource(time.Now().UnixNano())
	r := rand.New(rs)

	return &packetizer{
		MTU:         mtu,
		PayloadType: pt,
		SSRC:        ssrc,
		Payloader:   payloader,
		Sequencer:   sequencer,
		Timestamp:   r.Uint32(),
		ClockRate:   clockRate,
		timegen:     time.Now,
	}
}

func (p *packetizer) EnableAbsSendTime(value int) {
	p.extensionNumbers.AbsSendTime = value
}

func toNtpTime(t time.Time) uint64 {
	var s uint64
	var f uint64
	u := uint64(t.UnixNano())
	s = u / 1e9
	s += 0x83AA7E80 //offset in seconds between unix epoch and ntp epoch
	f = u % 1e9
	f <<= 32
	f /= 1e9
	s <<= 32

	return s | f
}

// Packetize packetizes the payload of an RTP packet and returns one or more RTP packets
func (p *packetizer) Packetize(payload []byte, samples uint32) []*Packet {
	// Guard against an empty payload
	if len(payload) == 0 {
		return nil
	}

	payloads := p.Payloader.Payload(p.MTU-12, payload)
	packets := make([]*Packet, len(payloads))

	for i, pp := range payloads {
		packets[i] = &Packet{
			Header: Header{
				Version:        2,
				Padding:        false,
				Extension:      false,
				Marker:         i == len(payloads)-1,
				PayloadType:    p.PayloadType,
				SequenceNumber: p.Sequencer.NextSequenceNumber(),
				Timestamp:      p.Timestamp, // Figure out how to do timestamps
				SSRC:           p.SSRC,
			},
			Payload: pp,
		}
	}
	p.Timestamp += samples

	if len(packets) != 0 && p.extensionNumbers.AbsSendTime != 0 {
		t := toNtpTime(p.timegen()) >> 14
		//apply http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
		packets[len(packets)-1].Header.Extension = true
		packets[len(packets)-1].ExtensionProfile = 0xBEDE
		packets[len(packets)-1].ExtensionPayload = []byte{
			//the first byte is
			// 0 1 2 3 4 5 6 7
			//+-+-+-+-+-+-+-+-+
			//|  ID   |  len  |
			//+-+-+-+-+-+-+-+-+
			//per RFC 5285
			//Len is the number of bytes in the extension - 1

			byte((p.extensionNumbers.AbsSendTime << 4) | 2),
			byte(t & 0xFF0000 >> 16),
			byte(t & 0xFF00 >> 8),
			byte(t & 0xFF),
		}

	}

	return packets
}
<|endoftext|>