<commit_before>//
// 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 convert

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/opencontainers/specs"
)

type IsolatorCapSet struct {
	Sets []string `json:"set"`
}

type ResourceMem struct {
	Limit string `json:"limit"`
}

type ResourceCPU struct {
	Limit string `json:"limit"`
}

var manifestName string

func Oci2aciManifest(ociPath string) (string, error) {
	if bValidate := validateOCIProc(ociPath); bValidate != true {
		err := errors.New("Invalid oci bundle.")
		return "", err
	}

	dirWork := createWorkDir()
	// convert layout
	aciManifestPath, err := convertLayout(ociPath, dirWork)
	if err != nil {
		return "", err
	}
	return aciManifestPath, err

}

func Oci2aciImage(ociPath string) (string, error) {
	if bValidate := validateOCIProc(ociPath); bValidate != true {
		err := errors.New("Invalid oci bundle.")
		return "", err
	}

	dirWork := createWorkDir()
	// First, convert layout
	_, err := convertLayout(ociPath, dirWork)
	if err != nil {
		return "", err
	}

	// Second, build image
	aciImgPath, err := buildACI(dirWork)

	return aciImgPath, err

}

// Entry point of oci2aci,
// First convert oci layout to aci layout, then build aci layout to image.
func RunOCI2ACI(args []string, flagDebug bool, flagName string) error {
	var srcPath, dstPath string

	srcPath = args[0]
	if len(args) == 1 {
		dstPath = ""
	} else {
		dstPath = args[1]
		ext := filepath.Ext(dstPath)
		if ext != schema.ACIExtension {
			errStr := fmt.Sprintf("Extension must be %s (given %s)", schema.ACIExtension, ext)
			err := errors.New(errStr)
			return err
		}
	}

	if flagDebug {
		InitDebug()
	}

	manifestName = flagName
	_, err := types.NewACName(manifestName)
	if err != nil {
		return err
	}

	if bValidate := validateOCIProc(srcPath); bValidate != true {
		log.Printf("Conversion stop.")
		return nil
	}

	dirWork := createWorkDir()
	// First, convert layout
	manifestPath, err := convertLayout(srcPath, dirWork)
	if err != nil {
		if debugEnabled {
			log.Printf("Conversion from oci to aci layout failed: %v", err)
		}

	} else {
		if debugEnabled {
			log.Printf("Manifest:%v generated successfully.", manifestPath)
		}
	}
	// Second, build image
	imgPath, err := buildACI(dirWork)
	if err != nil {
		if debugEnabled {
			log.Printf("Generate aci image failed:%v", err)
		}
	} else {
		if debugEnabled {
			log.Printf("Image:%v generated successfully.", imgPath)
		}
	}
	// Save aci image to the path user specified
	if dstPath != "" {
		if err = run(exec.Command("cp", imgPath, dstPath)); err != nil {
			if debugEnabled {
				log.Printf("Store aci image failed:%v", err)
			}
		} else {
			if debugEnabled {
				log.Printf("Image:%v generated successfully", dstPath)
			}

		}

	}

	return nil
}

// Create work directory for the conversion output
func createWorkDir() string {
	idir, err := ioutil.TempDir("", "oci2aci")
	if err != nil {
		return ""
	}
	rootfs := filepath.Join(idir, "rootfs")
	os.MkdirAll(rootfs, 0755)

	data := []byte{}
	if err := ioutil.WriteFile(filepath.Join(idir, "manifest"), data, 0644); err != nil {
		return ""
	}
	return idir
}

// The structure of appc manifest:
// 1.acKind
// 2. acVersion
// 3. name
// 4. labels
//	4.1 version
//	4.2 os
//	4.3 arch
// 5. app
//	5.1 exec
//	5.2 user
//	5.3 group
//	5.4 eventHandlers
//	5.5 workingDirectory
//	5.6 environment
//	5.7 mountPoints
//	5.8 ports
//      5.9 isolators
// 6. annotations
//	6.1 created
//	6.2 authors
//	6.3 homepage
//	6.4 documentation
// 7. dependencies
//	7.1 imageName
//	7.2 imageID
//	7.3 labels
//	7.4 size
// 8. pathWhitelist

func genManifest(path string) *schema.ImageManifest {
	// Get runtime.json and config.json
	runtimePath := path + "/runtime.json"
	configPath := path + "/config.json"

	runtime, err := ioutil.ReadFile(runtimePath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file runtime.json failed: %v", err)
		}
		return nil
	}

	config, err := ioutil.ReadFile(configPath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file config.json failed: %v", err)
		}
		return nil
	}

	var spec specs.LinuxSpec
	err = json.Unmarshal(config, &spec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal config.json failed: %v", err)
		}
		return nil
	}

	var runSpec specs.LinuxRuntimeSpec
	err = json.Unmarshal(runtime, &runSpec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal runtime.json failed: %v", err)
		}
		return nil
	}
	// Begin to convert runtime.json/config.json to manifest
	m := new(schema.ImageManifest)

	// 1. Assemble "acKind" field
	m.ACKind = schema.ImageManifestKind

	// 2. Assemble "acVersion" field
	m.ACVersion = schema.AppContainerVersion

	// 3. Assemble "name" field
	m.Name = types.ACIdentifier(manifestName)

	// 4. Assemble "labels" field
	// 4.1 "version"
	label := new(types.Label)
	label.Name = types.ACIdentifier("version")
	label.Value = spec.Version
	m.Labels = append(m.Labels, *label)
	// 4.2 "os"
	label = new(types.Label)
	label.Name = types.ACIdentifier("os")
	label.Value = spec.Platform.OS
	m.Labels = append(m.Labels, *label)
	// 4.3 "arch"
	label = new(types.Label)
	label.Name = types.ACIdentifier("arch")
	label.Value = spec.Platform.Arch
	m.Labels = append(m.Labels, *label)

	// 5. Assemble "app" field
	app := new(types.App)
	// 5.1 "exec"
	app.Exec = spec.Process.Args
	if len(app.Exec) == 0 {
		app.Exec = append(app.Exec, "/bin/sh")
	}

	if len(app.Exec) > 0 && !filepath.IsAbs(app.Exec[0]) {
		app.Exec[0] = "/bin/" + app.Exec[0]
	}

	// 5.2 "user"
	app.User = fmt.Sprintf("%d", spec.Process.User.UID)
	// 5.3 "group"
	app.Group = fmt.Sprintf("%d", spec.Process.User.GID)
	// 5.4 "eventHandlers"
	event := new(types.EventHandler)
	event.Name = "pre-start"
	for index := range runSpec.Hooks.Prestart {
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/ls")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	event = new(types.EventHandler)
	event.Name = "post-stop"
	for index := range runSpec.Hooks.Poststop {
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/ls")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	// 5.5 "workingDirectory"
	app.WorkingDirectory = spec.Process.Cwd
	// 5.6 "environment"
	env := new(types.EnvironmentVariable)
	for index := range spec.Process.Env {
		s := strings.Split(spec.Process.Env[index], "=")
		env.Name = s[0]
		env.Value = s[1]
		app.Environment = append(app.Environment, *env)
	}

	// 5.7 "mountPoints"
	for index := range spec.Mounts {
		mount := new(types.MountPoint)
		mount.Name = types.ACName(spec.Mounts[index].Name)
		mount.Path = spec.Mounts[index].Path
		mount.ReadOnly = false
		app.MountPoints = append(app.MountPoints, *mount)
	}

	// 5.8 "ports"

	// 5.9 "isolators"
	if runSpec.Linux.Resources != nil {
		if runSpec.Linux.Resources.CPU.Quota != 0 {
			cpuLimt := new(ResourceCPU)
			cpuLimt.Limit = fmt.Sprintf("%dm", runSpec.Linux.Resources.CPU.Quota)
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/cpu")
			bytes, _ := json.Marshal(cpuLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
		if runSpec.Linux.Resources.Memory.Limit != 0 {
			memLimt := new(ResourceMem)
			memLimt.Limit = fmt.Sprintf("%dG", runSpec.Linux.Resources.Memory.Limit/(1024*1024*1024))
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/memory")
			bytes, _ := json.Marshal(memLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
	}

	if len(spec.Linux.Capabilities) != 0 {
		isolatorCapSet := new(IsolatorCapSet)
		isolatorCapSet.Sets = append(isolatorCapSet.Sets, spec.Linux.Capabilities...)

		isolator := new(types.Isolator)
		isolator.Name = types.ACIdentifier(types.LinuxCapabilitiesRetainSetName)
		bytes, _ := json.Marshal(isolatorCapSet)

		valueRaw := json.RawMessage(bytes)
		isolator.ValueRaw = &valueRaw

		app.Isolators = append(app.Isolators, *isolator)
	}

	// 6. "annotations"

	// 7. "dependencies"

	// 8. "pathWhitelist"

	m.App = app

	return m
}

// Convert OCI layout to ACI layout
func convertLayout(srcPath, dstPath string) (string, error) {
	src, _ := filepath.Abs(srcPath)
	src += "/rootfs"
	if err := run(exec.Command("cp", "-rf", src, dstPath)); err != nil {
		return "", err
	}

	m := genManifest(srcPath)

	bytes, err := json.MarshalIndent(m, "", "\t")
	if err != nil {
		return "", err
	}

	manifestPath := dstPath + "/manifest"

	ioutil.WriteFile(manifestPath, bytes, 0644)
	return manifestPath, nil
}
<commit_msg>Update dealt with oci Process.Args, Process.Cwd, prestart and poststone<commit_after>//
// 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 convert

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/opencontainers/specs"
)

type IsolatorCapSet struct {
	Sets []string `json:"set"`
}

type ResourceMem struct {
	Limit string `json:"limit"`
}

type ResourceCPU struct {
	Limit string `json:"limit"`
}

var manifestName string

func Oci2aciManifest(ociPath string) (string, error) {
	if bValidate := validateOCIProc(ociPath); bValidate != true {
		err := errors.New("Invalid oci bundle.")
		return "", err
	}

	dirWork := createWorkDir()
	// convert layout
	aciManifestPath, err := convertLayout(ociPath, dirWork)
	if err != nil {
		return "", err
	}
	return aciManifestPath, err

}

func Oci2aciImage(ociPath string) (string, error) {
	if bValidate := validateOCIProc(ociPath); bValidate != true {
		err := errors.New("Invalid oci bundle.")
		return "", err
	}

	dirWork := createWorkDir()
	// First, convert layout
	_, err := convertLayout(ociPath, dirWork)
	if err != nil {
		return "", err
	}

	// Second, build image
	aciImgPath, err := buildACI(dirWork)

	return aciImgPath, err

}

// Entry point of oci2aci,
// First convert oci layout to aci layout, then build aci layout to image.
func RunOCI2ACI(args []string, flagDebug bool, flagName string) error {
	var srcPath, dstPath string

	srcPath = args[0]
	if len(args) == 1 {
		dstPath = ""
	} else {
		dstPath = args[1]
		ext := filepath.Ext(dstPath)
		if ext != schema.ACIExtension {
			errStr := fmt.Sprintf("Extension must be %s (given %s)", schema.ACIExtension, ext)
			err := errors.New(errStr)
			return err
		}
	}

	if flagDebug {
		InitDebug()
	}

	manifestName = flagName
	_, err := types.NewACName(manifestName)
	if err != nil {
		return err
	}

	if bValidate := validateOCIProc(srcPath); bValidate != true {
		log.Printf("Conversion stop.")
		return nil
	}

	dirWork := createWorkDir()
	// First, convert layout
	manifestPath, err := convertLayout(srcPath, dirWork)
	if err != nil {
		if debugEnabled {
			log.Printf("Conversion from oci to aci layout failed: %v", err)
		}

	} else {
		if debugEnabled {
			log.Printf("Manifest:%v generated successfully.", manifestPath)
		}
	}
	// Second, build image
	imgPath, err := buildACI(dirWork)
	if err != nil {
		if debugEnabled {
			log.Printf("Generate aci image failed:%v", err)
		}
	} else {
		if debugEnabled {
			log.Printf("Image:%v generated successfully.", imgPath)
		}
	}
	// Save aci image to the path user specified
	if dstPath != "" {
		if err = run(exec.Command("cp", imgPath, dstPath)); err != nil {
			if debugEnabled {
				log.Printf("Store aci image failed:%v", err)
			}
		} else {
			if debugEnabled {
				log.Printf("Image:%v generated successfully", dstPath)
			}

		}

	}

	return nil
}

// Create work directory for the conversion output
func createWorkDir() string {
	idir, err := ioutil.TempDir("", "oci2aci")
	if err != nil {
		return ""
	}
	rootfs := filepath.Join(idir, "rootfs")
	os.MkdirAll(rootfs, 0755)

	data := []byte{}
	if err := ioutil.WriteFile(filepath.Join(idir, "manifest"), data, 0644); err != nil {
		return ""
	}
	return idir
}

// The structure of appc manifest:
// 1.acKind
// 2. acVersion
// 3. name
// 4. labels
//	4.1 version
//	4.2 os
//	4.3 arch
// 5. app
//	5.1 exec
//	5.2 user
//	5.3 group
//	5.4 eventHandlers
//	5.5 workingDirectory
//	5.6 environment
//	5.7 mountPoints
//	5.8 ports
//      5.9 isolators
// 6. annotations
//	6.1 created
//	6.2 authors
//	6.3 homepage
//	6.4 documentation
// 7. dependencies
//	7.1 imageName
//	7.2 imageID
//	7.3 labels
//	7.4 size
// 8. pathWhitelist

func genManifest(path string) *schema.ImageManifest {
	// Get runtime.json and config.json
	runtimePath := path + "/runtime.json"
	configPath := path + "/config.json"

	runtime, err := ioutil.ReadFile(runtimePath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file runtime.json failed: %v", err)
		}
		return nil
	}

	config, err := ioutil.ReadFile(configPath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file config.json failed: %v", err)
		}
		return nil
	}

	var spec specs.LinuxSpec
	err = json.Unmarshal(config, &spec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal config.json failed: %v", err)
		}
		return nil
	}

	var runSpec specs.LinuxRuntimeSpec
	err = json.Unmarshal(runtime, &runSpec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal runtime.json failed: %v", err)
		}
		return nil
	}
	// Begin to convert runtime.json/config.json to manifest
	m := new(schema.ImageManifest)

	// 1. Assemble "acKind" field
	m.ACKind = schema.ImageManifestKind

	// 2. Assemble "acVersion" field
	m.ACVersion = schema.AppContainerVersion

	// 3. Assemble "name" field
	m.Name = types.ACIdentifier(manifestName)

	// 4. Assemble "labels" field
	// 4.1 "version"
	label := new(types.Label)
	label.Name = types.ACIdentifier("version")
	label.Value = spec.Version
	m.Labels = append(m.Labels, *label)
	// 4.2 "os"
	label = new(types.Label)
	label.Name = types.ACIdentifier("os")
	label.Value = spec.Platform.OS
	m.Labels = append(m.Labels, *label)
	// 4.3 "arch"
	label = new(types.Label)
	label.Name = types.ACIdentifier("arch")
	label.Value = spec.Platform.Arch
	m.Labels = append(m.Labels, *label)

	// 5. Assemble "app" field
	app := new(types.App)
	// 5.1 "exec"
	app.Exec = spec.Process.Args

	prefixDir := ""
	//var exeStr string
	if app.Exec == nil {
		app.Exec = append(app.Exec, "/bin/sh")
	} else {
		if !filepath.IsAbs(app.Exec[0]) {
			if spec.Process.Cwd == "" {
				prefixDir = "/"
			} else {
				prefixDir = spec.Process.Cwd
			}
		}
		app.Exec[0] = prefixDir + app.Exec[0]
	}

	// 5.2 "user"
	app.User = fmt.Sprintf("%d", spec.Process.User.UID)
	// 5.3 "group"
	app.Group = fmt.Sprintf("%d", spec.Process.User.GID)
	// 5.4 "eventHandlers"
	event := new(types.EventHandler)
	event.Name = "pre-start"
	for index := range runSpec.Hooks.Prestart {
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/echo")
		event.Exec = append(event.Exec, "-n")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	event = new(types.EventHandler)
	event.Name = "post-stop"
	for index := range runSpec.Hooks.Poststop {
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/echo")
		event.Exec = append(event.Exec, "-n")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	// 5.5 "workingDirectory"
	app.WorkingDirectory = spec.Process.Cwd
	// 5.6 "environment"
	env := new(types.EnvironmentVariable)
	for index := range spec.Process.Env {
		s := strings.Split(spec.Process.Env[index], "=")
		env.Name = s[0]
		env.Value = s[1]
		app.Environment = append(app.Environment, *env)
	}

	// 5.7 "mountPoints"
	for index := range spec.Mounts {
		mount := new(types.MountPoint)
		mount.Name = types.ACName(spec.Mounts[index].Name)
		mount.Path = spec.Mounts[index].Path
		mount.ReadOnly = false
		app.MountPoints = append(app.MountPoints, *mount)
	}

	// 5.8 "ports"

	// 5.9 "isolators"
	if runSpec.Linux.Resources != nil {
		if runSpec.Linux.Resources.CPU.Quota != 0 {
			cpuLimt := new(ResourceCPU)
			cpuLimt.Limit = fmt.Sprintf("%dm", runSpec.Linux.Resources.CPU.Quota)
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/cpu")
			bytes, _ := json.Marshal(cpuLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
		if runSpec.Linux.Resources.Memory.Limit != 0 {
			memLimt := new(ResourceMem)
			memLimt.Limit = fmt.Sprintf("%dG", runSpec.Linux.Resources.Memory.Limit/(1024*1024*1024))
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/memory")
			bytes, _ := json.Marshal(memLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
	}

	if len(spec.Linux.Capabilities) != 0 {
		isolatorCapSet := new(IsolatorCapSet)
		isolatorCapSet.Sets = append(isolatorCapSet.Sets, spec.Linux.Capabilities...)

		isolator := new(types.Isolator)
		isolator.Name = types.ACIdentifier(types.LinuxCapabilitiesRetainSetName)
		bytes, _ := json.Marshal(isolatorCapSet)

		valueRaw := json.RawMessage(bytes)
		isolator.ValueRaw = &valueRaw

		app.Isolators = append(app.Isolators, *isolator)
	}

	// 6. "annotations"

	// 7. "dependencies"

	// 8. "pathWhitelist"

	m.App = app

	return m
}

// Convert OCI layout to ACI layout
func convertLayout(srcPath, dstPath string) (string, error) {
	src, _ := filepath.Abs(srcPath)
	src += "/rootfs"
	if err := run(exec.Command("cp", "-rf", src, dstPath)); err != nil {
		return "", err
	}

	m := genManifest(srcPath)

	bytes, err := json.MarshalIndent(m, "", "\t")
	if err != nil {
		return "", err
	}

	manifestPath := dstPath + "/manifest"

	ioutil.WriteFile(manifestPath, bytes, 0644)
	return manifestPath, nil
}
<|endoftext|>


<commit_before>package epochs

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math/big"
	"time"
)

const SecondsPerDay = 24 * 60 * 60

// epoch2time gets a Unix time of the given x after dividing by q and
// adding s.
func epoch2time(x, q, s *big.Int) time.Time {
	z := new(big.Int)
	m := new(big.Int)
	z.DivMod(x, q, m)
	z.Add(z, s)
	r := m.Mul(m, big.NewInt(1e9)).Div(m, q)
	return time.Unix(z.Int64(), r.Int64()).UTC()
}

// time2epoch reverses epoch2time.
func time2epoch(t time.Time, m, s *big.Int) int64 {
	bf := new(big.Float).SetInt(big.NewInt(t.UnixNano()))
	bf.Quo(bf, big.NewFloat(1e9))
	bf.Sub(bf, new(big.Float).SetInt(s))
	bf.Mul(bf, new(big.Float).SetInt(m))

	r, acc := bf.Int64()
	if acc != big.Exact {
		fmt.Println(acc)
	}

	return r
}

// Chrome time is the number of microseconds since 1601-01-01, which
// is 11,644,473,600 seconds before the Unix epoch.
func Chrome(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e6),
		big.NewInt(-11644473600),
	)
}
func ToChrome(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e6),
		big.NewInt(-11644473600),
	)
}

// Cocoa time is the number of seconds since 2001-01-01, which
// is 978,307,200 seconds after the Unix epoch.
func Cocoa(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1),
		big.NewInt(978307200),
	)
}
func ToCocoa(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1),
		big.NewInt(978307200),
	)
}

// GoogleCalendar seems to count 32-day months from the day before the
// Unix epoch. @noppers worked out how to do this.
func GoogleCalendar(num int64) time.Time {

	n := int(num)

	totalDays := n / SecondsPerDay
	seconds := n % SecondsPerDay

	// A "Google month" has 32 days!
	months := totalDays / 32
	days := totalDays % 32

	// The "Google epoch" is apparently off by a day.
	t := time.Unix(-SecondsPerDay, 0).UTC()

	// Add the days first...
	u := t.AddDate(0, 0, days)

	// ...then the months...
	v := u.AddDate(0, months, 0)

	// ...then the seconds.
	w := v.Add(time.Duration(seconds * 1e9))

	return w
}
func ToGoogleCalendar(t time.Time) int64 {
	y := t.Year() - 1970
	m := int(t.Month()) - 1
	r := ((((y*12+m)*32+t.Day())*24+t.Hour())*60+t.Minute())*60 + t.Second()
	return int64(r)
}

// ICQ time is the number of days since 1899-12-30, which is
// 2,209,161,600 seconds before the Unix epoch. Days can have a
// fractional part.
func ICQ(days float64) time.Time {

	t := time.Unix(-2209161600, 0).UTC()

	intdays := int(days)

	// Want the fractional part of the day in nanoseconds.
	fracday := int64((days - float64(intdays)) * SecondsPerDay * 1e9)

	return t.AddDate(0, 0, intdays).Add(time.Duration(fracday))
}

// Java time is the number of milliseconds since the Unix epoch.
func Java(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1000),
		big.NewInt(0),
	)
}
func ToJava(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1000),
		big.NewInt(0),
	)
}

// Mozilla time (e.g., formhistory.sqlite) is the number of
// microseconds since the Unix epoch.
func Mozilla(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e6),
		big.NewInt(0),
	)
}
func ToMozilla(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e6),
		big.NewInt(0),
	)
}

// OLE time is the number of days since 1899-12-30, which is
// 2,209,161,600 seconds before the Unix epoch. Days can have a
// fractional part and is given as a string of hex characters
// representing an IEEE 8-byte floating-point number.
func OLE(days string) time.Time {
	var d [8]byte
	var f float64

	n, err := fmt.Sscanf(
		days,
		"%02x%02x%02x%02x%02x%02x%02x%02x",
		&d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7],
	)
	if err != nil {
		fmt.Println("fmt.Sscanf failed:", err)
	}
	if n != 8 {
		fmt.Println("fmt.Sscanf did not scan 8 items:", n)
	}

	buf := bytes.NewReader(d[:])
	if err := binary.Read(buf, binary.LittleEndian, &f); err != nil {
		fmt.Println("binary.Read failed:", err)
	}

	return ICQ(f)
}

// Symbian time is the number of microseconds since the year 0, which
// is 62,167,219,200 seconds before the Unix epoch.
func Symbian(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e6),
		big.NewInt(-62167219200),
	)
}
func ToSymbian(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e6),
		big.NewInt(-62167219200),
	)
}

// Unix time is the number of seconds since 1970-01-01.
func Unix(num int64) time.Time {
	return time.Unix(num, 0).UTC()
}
func ToUnix(t time.Time) int64 {
	return t.Unix()
}

// UUID version 1 time (RFC 4122) is the number of hectonanoseconds
// (100 ns) since 1582-10-15, which is 12,219,292,800 seconds before
// the Unix epoch.
func UUIDv1(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e7),
		big.NewInt(-12219292800),
	)
}
func ToUUIDv1(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e7),
		big.NewInt(-12219292800),
	)
}

// Windows date time (e.g., .NET) is the number of hectonanoseconds
// (100 ns) since 0001-01-01, which is 62,135,596,800 seconds before
// the Unix epoch.
func WindowsDate(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e7),
		big.NewInt(-62135596800),
	)
}
func ToWindowsDate(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e7),
		big.NewInt(-62135596800),
	)
}

// Windows file time (e.g., NTFS) is the number of hectonanoseconds
// (100 ns) since 1601-01-01, which is 11,644,473,600 seconds before
// the Unix epoch.
func WindowsFile(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e7),
		big.NewInt(-11644473600),
	)
}
func ToWindowsFile(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e7),
		big.NewInt(-11644473600),
	)
}
<commit_msg>implement ToOLE<commit_after>package epochs

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"math/big"
	"time"
)

const SecondsPerDay = 24 * 60 * 60
const NanosecondsPerDay = SecondsPerDay * 1e9

// epoch2time gets a Unix time of the given x after dividing by q and
// adding s.
func epoch2time(x, q, s *big.Int) time.Time {
	z := new(big.Int)
	m := new(big.Int)
	z.DivMod(x, q, m)
	z.Add(z, s)
	r := m.Mul(m, big.NewInt(1e9)).Div(m, q)
	return time.Unix(z.Int64(), r.Int64()).UTC()
}

// time2epoch reverses epoch2time.
func time2epoch(t time.Time, m, s *big.Int) int64 {
	bf := new(big.Float).SetInt(big.NewInt(t.UnixNano()))
	bf.Quo(bf, big.NewFloat(1e9))
	bf.Sub(bf, new(big.Float).SetInt(s))
	bf.Mul(bf, new(big.Float).SetInt(m))

	r, acc := bf.Int64()
	if acc != big.Exact {
		fmt.Println(acc)
	}

	return r
}

// Chrome time is the number of microseconds since 1601-01-01, which
// is 11,644,473,600 seconds before the Unix epoch.
func Chrome(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e6),
		big.NewInt(-11644473600),
	)
}
func ToChrome(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e6),
		big.NewInt(-11644473600),
	)
}

// Cocoa time is the number of seconds since 2001-01-01, which
// is 978,307,200 seconds after the Unix epoch.
func Cocoa(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1),
		big.NewInt(978307200),
	)
}
func ToCocoa(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1),
		big.NewInt(978307200),
	)
}

// GoogleCalendar seems to count 32-day months from the day before the
// Unix epoch. @noppers worked out how to do this.
func GoogleCalendar(num int64) time.Time {

	n := int(num)

	totalDays := n / SecondsPerDay
	seconds := n % SecondsPerDay

	// A "Google month" has 32 days!
	months := totalDays / 32
	days := totalDays % 32

	// The "Google epoch" is apparently off by a day.
	t := time.Unix(-SecondsPerDay, 0).UTC()

	// Add the days first...
	u := t.AddDate(0, 0, days)

	// ...then the months...
	v := u.AddDate(0, months, 0)

	// ...then the seconds.
	w := v.Add(time.Duration(seconds * 1e9))

	return w
}
func ToGoogleCalendar(t time.Time) int64 {
	y := t.Year() - 1970
	m := int(t.Month()) - 1
	r := ((((y*12+m)*32+t.Day())*24+t.Hour())*60+t.Minute())*60 + t.Second()
	return int64(r)
}

// ICQ time is the number of days since 1899-12-30, which is
// 2,209,161,600 seconds before the Unix epoch. Days can have a
// fractional part.
func ICQ(days float64) time.Time {

	t := time.Unix(-2209161600, 0).UTC()

	intdays := int(days)

	// Want the fractional part of the day in nanoseconds.
	fracday := int64((days - float64(intdays)) * NanosecondsPerDay)

	return t.AddDate(0, 0, intdays).Add(time.Duration(fracday))
}
func ToICQ(t time.Time) float64 {
	t2 := time.Unix(-2209161600, 0)
	return float64(t.Sub(t2).Nanoseconds()) / float64(NanosecondsPerDay)
}

// Java time is the number of milliseconds since the Unix epoch.
func Java(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1000),
		big.NewInt(0),
	)
}
func ToJava(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1000),
		big.NewInt(0),
	)
}

// Mozilla time (e.g., formhistory.sqlite) is the number of
// microseconds since the Unix epoch.
func Mozilla(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e6),
		big.NewInt(0),
	)
}
func ToMozilla(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e6),
		big.NewInt(0),
	)
}

// OLE time is the number of days since 1899-12-30, which is
// 2,209,161,600 seconds before the Unix epoch. Days can have a
// fractional part and is given as a string of hex characters
// representing an IEEE 8-byte floating-point number.
func OLE(days string) time.Time {
	var d [8]byte
	var f float64

	n, err := fmt.Sscanf(
		days,
		"%02x%02x%02x%02x%02x%02x%02x%02x",
		&d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7],
	)
	if err != nil {
		fmt.Println("fmt.Sscanf failed:", err)
	}
	if n != 8 {
		fmt.Println("fmt.Sscanf did not scan 8 items:", n)
	}

	buf := bytes.NewReader(d[:])
	if err := binary.Read(buf, binary.LittleEndian, &f); err != nil {
		fmt.Println("binary.Read failed:", err)
	}

	return ICQ(f)
}
func ToOLE(t time.Time) string {
	icq := ToICQ(t)
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.LittleEndian, math.Float64bits(icq))
	if err != nil {
		fmt.Println("binary.Write failed:", err)
	}
	return fmt.Sprintf("%016x", buf.Bytes())
}

// Symbian time is the number of microseconds since the year 0, which
// is 62,167,219,200 seconds before the Unix epoch.
func Symbian(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e6),
		big.NewInt(-62167219200),
	)
}
func ToSymbian(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e6),
		big.NewInt(-62167219200),
	)
}

// Unix time is the number of seconds since 1970-01-01.
func Unix(num int64) time.Time {
	return time.Unix(num, 0).UTC()
}
func ToUnix(t time.Time) int64 {
	return t.Unix()
}

// UUID version 1 time (RFC 4122) is the number of hectonanoseconds
// (100 ns) since 1582-10-15, which is 12,219,292,800 seconds before
// the Unix epoch.
func UUIDv1(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e7),
		big.NewInt(-12219292800),
	)
}
func ToUUIDv1(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e7),
		big.NewInt(-12219292800),
	)
}

// Windows date time (e.g., .NET) is the number of hectonanoseconds
// (100 ns) since 0001-01-01, which is 62,135,596,800 seconds before
// the Unix epoch.
func WindowsDate(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e7),
		big.NewInt(-62135596800),
	)
}
func ToWindowsDate(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e7),
		big.NewInt(-62135596800),
	)
}

// Windows file time (e.g., NTFS) is the number of hectonanoseconds
// (100 ns) since 1601-01-01, which is 11,644,473,600 seconds before
// the Unix epoch.
func WindowsFile(num int64) time.Time {
	return epoch2time(
		big.NewInt(num),
		big.NewInt(1e7),
		big.NewInt(-11644473600),
	)
}
func ToWindowsFile(t time.Time) int64 {
	return time2epoch(
		t,
		big.NewInt(1e7),
		big.NewInt(-11644473600),
	)
}
<|endoftext|>


<commit_before>// Copyright 2013 Alex Browne.  All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

// File errors.go declares all the different errors that might be thrown
// by the package and provides constructors for each one.

package zoom

import (
	"fmt"
	"reflect"
)

// TODO: add more custom error types based on common use cases throughout the package

// NameAlreadyRegisteredError is returned if you try to register a
// name which has already been registered.
type NameAlreadyRegisteredError struct {
	name string
}

func (e *NameAlreadyRegisteredError) Error() string {
	return "zoom: the name '" + e.name + "' has already been registered"
}

func NewNameAlreadyRegisteredError(name string) *NameAlreadyRegisteredError {
	return &NameAlreadyRegisteredError{name}
}

// TypeAlreadyRegisteredError is returned if you try to register a
// type which has already been registered.
type TypeAlreadyRegisteredError struct {
	typ reflect.Type
}

func (e *TypeAlreadyRegisteredError) Error() string {
	return "zoom: the type '" + e.typ.String() + "' has already been registered"
}

func NewTypeAlreadyRegisteredError(typ reflect.Type) *TypeAlreadyRegisteredError {
	return &TypeAlreadyRegisteredError{typ}
}

// ModelTypeNotRegisteredError is returned if you attempt to perform
// certain operations for unregistered types.
type ModelTypeNotRegisteredError struct {
	typ reflect.Type
}

func (e *ModelTypeNotRegisteredError) Error() string {
	return "zoom: the type '" + e.typ.String() + "' has not been registered"
}

func NewModelTypeNotRegisteredError(typ reflect.Type) *ModelTypeNotRegisteredError {
	return &ModelTypeNotRegisteredError{typ}
}

// ModelNameNotRegisteredError is returned if you attempt to perform
// certain operations for unregistered names.
type ModelNameNotRegisteredError struct {
	name string
}

func (e *ModelNameNotRegisteredError) Error() string {
	return "zoom: the model name '" + e.name + "' has not been registered"
}

func NewModelNameNotRegisteredError(name string) *ModelNameNotRegisteredError {
	return &ModelNameNotRegisteredError{name}
}

// KeyNotFoundError is returned from Find, Scan, and Query functions if the
// model you are trying to find does not exist in the database.
type KeyNotFoundError struct {
	key       string
	modelType reflect.Type
}

func (e *KeyNotFoundError) Error() string {
	return fmt.Sprintf("zoom: could not find model of type %s with key %s", e.modelType.String(), e.key)
}

func NewKeyNotFoundError(key string, modelType reflect.Type) *KeyNotFoundError {
	return &KeyNotFoundError{key, modelType}
}
<commit_msg>refactor errors.go to use fmt.Sprintf instead of string concatenation<commit_after>// Copyright 2013 Alex Browne.  All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

// File errors.go declares all the different errors that might be thrown
// by the package and provides constructors for each one.

package zoom

import (
	"fmt"
	"reflect"
)

// TODO: add more custom error types based on common use cases throughout the package

// NameAlreadyRegisteredError is returned if you try to register a
// name which has already been registered.
type NameAlreadyRegisteredError struct {
	name string
}

func (e *NameAlreadyRegisteredError) Error() string {
	return fmt.Sprintf("zoom: the name %s has already been registered", e.name)
}

func NewNameAlreadyRegisteredError(name string) *NameAlreadyRegisteredError {
	return &NameAlreadyRegisteredError{name}
}

// TypeAlreadyRegisteredError is returned if you try to register a
// type which has already been registered.
type TypeAlreadyRegisteredError struct {
	typ reflect.Type
}

func (e *TypeAlreadyRegisteredError) Error() string {
	return fmt.Sprintf("zoom: the type %s has already been registered", e.typ.String())
}

func NewTypeAlreadyRegisteredError(typ reflect.Type) *TypeAlreadyRegisteredError {
	return &TypeAlreadyRegisteredError{typ}
}

// ModelTypeNotRegisteredError is returned if you attempt to perform
// certain operations for unregistered types.
type ModelTypeNotRegisteredError struct {
	typ reflect.Type
}

func (e *ModelTypeNotRegisteredError) Error() string {
	return fmt.Sprintf("zoom: the type %s has not been registered", e.typ.String())
}

func NewModelTypeNotRegisteredError(typ reflect.Type) *ModelTypeNotRegisteredError {
	return &ModelTypeNotRegisteredError{typ}
}

// ModelNameNotRegisteredError is returned if you attempt to perform
// certain operations for unregistered names.
type ModelNameNotRegisteredError struct {
	name string
}

func (e *ModelNameNotRegisteredError) Error() string {
	return fmt.Sprintf("zoom: the model name %s has not been registered", e.name)
}

func NewModelNameNotRegisteredError(name string) *ModelNameNotRegisteredError {
	return &ModelNameNotRegisteredError{name}
}

// KeyNotFoundError is returned from Find, Scan, and Query functions if the
// model you are trying to find does not exist in the database.
type KeyNotFoundError struct {
	key       string
	modelType reflect.Type
}

func (e *KeyNotFoundError) Error() string {
	return fmt.Sprintf("zoom: could not find model of type %s with key %s", e.modelType.String(), e.key)
}

func NewKeyNotFoundError(key string, modelType reflect.Type) *KeyNotFoundError {
	return &KeyNotFoundError{key, modelType}
}
<|endoftext|>


<commit_before>package arangolite

type statusCodedError interface {
	error
	StatusCode() int
}

type statusCodedErrorBehavior struct {
	error
	statusCode int
}

func (e *statusCodedErrorBehavior) StatusCode() int {
	return e.statusCode
}

func withStatusCode(err error, statusCode int) error {
	return statusCodedErrorBehavior{err, statusCode}
}

// HasStatusCode returns true when one of the given error status code matches the one returned by the database.
func HasStatusCode(err error, statusCode ...int) bool {
	e, ok := err.(statusCodedError)
	if !ok {
		return false
	}
	code := e.StatusCode()
	for _, c := range statusCode {
		if code == c {
			return true
		}
	}
	return false
}

// GetStatusCode returns the status code encapsulated in the error.
func GetStatusCode(err error) (code int, ok bool) {
	e, ok := err.(statusCodedError)
	if !ok {
		return 0, false
	}
	return e.StatusCode(), true
}

type numberedError interface {
	error
	ErrorNum() int
}

type numberedErrorBehavior struct {
	error
	errorNum int
}

func (e *numberedErrorBehavior) ErrorNum() int {
	return e.errorNum
}

func withErrorNum(err error, errorNum int) error {
	return numberedErrorBehavior{err, errorNum}
}

// HasErrorNum returns true when one of the given error num matches the one returned by the database.
func HasErrorNum(err error, errorNum ...int) bool {
	e, ok := err.(numberedError)
	if !ok {
		return false
	}
	num := e.ErrorNum()
	for _, n := range errorNum {
		if num == n {
			return true
		}
	}
	return false
}

// GetErrorNum returns the database error num encapsulated in the error.
func GetErrorNum(err error) (errorNum int, ok bool) {
	e, ok := err.(numberedError)
	if !ok {
		return 0, false
	}
	return e.ErrorNum(), true
}

// IsErrInvalidRequest returns true when the database returns a 400.
func IsErrInvalidRequest(err error) bool {
	return HasStatusCode(err, 400)
}

// IsErrUnauthorized returns true when the database returns a 401.
func IsErrUnauthorized(err error) bool {
	return HasStatusCode(err, 401)
}

// IsErrForbidden returns true when the database returns a 403.
func IsErrForbidden(err error) bool {
	return HasStatusCode(err, 403)
}

// IsErrUnique returns true when the error num is a 1210 - ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.
func IsErrUnique(err error) bool {
	return HasErrorNum(err, 1210)
}

// IsErrNotFound returns true when the database returns a 404 or when the error num is:
// 1202 - ERROR_ARANGO_DOCUMENT_NOT_FOUND
// 1203 - ERROR_ARANGO_COLLECTION_NOT_FOUND
func IsErrNotFound(err error) bool {
	return HasStatusCode(err, 404) || HasErrorNum(err, 1202, 1203)
}
<commit_msg>Fixed<commit_after>package arangolite

type statusCodedError interface {
	error
	StatusCode() int
}

type statusCodedErrorBehavior struct {
	error
	statusCode int
}

func (e statusCodedErrorBehavior) StatusCode() int {
	return e.statusCode
}

func withStatusCode(err error, statusCode int) error {
	return struct {
		error
		statusCodedErrorBehavior
	}{
		err,
		statusCodedErrorBehavior{statusCode: statusCode},
	}
}

// HasStatusCode returns true when one of the given error status code matches the one returned by the database.
func HasStatusCode(err error, statusCode ...int) bool {
	e, ok := err.(statusCodedError)
	if !ok {
		return false
	}
	code := e.StatusCode()
	for _, c := range statusCode {
		if code == c {
			return true
		}
	}
	return false
}

// GetStatusCode returns the status code encapsulated in the error.
func GetStatusCode(err error) (code int, ok bool) {
	e, ok := err.(statusCodedError)
	if !ok {
		return 0, false
	}
	return e.StatusCode(), true
}

type numberedError interface {
	error
	ErrorNum() int
}

type numberedErrorBehavior struct {
	error
	errorNum int
}

func (e numberedErrorBehavior) ErrorNum() int {
	return e.errorNum
}

func withErrorNum(err error, errorNum int) error {
	return struct {
		error
		numberedErrorBehavior
	}{
		err,
		numberedErrorBehavior{errorNum: errorNum},
	}
}

// HasErrorNum returns true when one of the given error num matches the one returned by the database.
func HasErrorNum(err error, errorNum ...int) bool {
	e, ok := err.(numberedError)
	if !ok {
		return false
	}
	num := e.ErrorNum()
	for _, n := range errorNum {
		if num == n {
			return true
		}
	}
	return false
}

// GetErrorNum returns the database error num encapsulated in the error.
func GetErrorNum(err error) (errorNum int, ok bool) {
	e, ok := err.(numberedError)
	if !ok {
		return 0, false
	}
	return e.ErrorNum(), true
}

// IsErrInvalidRequest returns true when the database returns a 400.
func IsErrInvalidRequest(err error) bool {
	return HasStatusCode(err, 400)
}

// IsErrUnauthorized returns true when the database returns a 401.
func IsErrUnauthorized(err error) bool {
	return HasStatusCode(err, 401)
}

// IsErrForbidden returns true when the database returns a 403.
func IsErrForbidden(err error) bool {
	return HasStatusCode(err, 403)
}

// IsErrUnique returns true when the error num is a 1210 - ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.
func IsErrUnique(err error) bool {
	return HasErrorNum(err, 1210)
}

// IsErrNotFound returns true when the database returns a 404 or when the error num is:
// 1202 - ERROR_ARANGO_DOCUMENT_NOT_FOUND
// 1203 - ERROR_ARANGO_COLLECTION_NOT_FOUND
func IsErrNotFound(err error) bool {
	return HasStatusCode(err, 404) || HasErrorNum(err, 1202, 1203)
}
<|endoftext|>


<commit_before>package gforms

type Errors map[string]string
<commit_msg>Updated Errors method.<commit_after>package gforms

type Errors map[string]string

func (es Errors) Has(key string) bool {
	_, ok := es[key]
	return ok
}

func (es Errors) Get(key string) string {
	v, _ := es[key]
	return v
}
<|endoftext|>


<commit_before>package errors

import (
	"bytes"
	"errors"
	"fmt"
	"runtime"
	"strconv"
	"strings"
)

var prefix string

type erx struct {
	pc     uintptr
	error  error
	parent *erx
}

// Implementation of the error interface.
func (e erx) Error() string {
	x, flat := &e, make([]*erx, 0, 16)
	for {
		flat = append(flat, x)
		if x.parent == nil {
			break
		}
		x = x.parent
	}
	max := len(flat) - 1

	var buf bytes.Buffer
	for i := 0; i <= max; i++ {
		x = flat[max-i]

		if i == 0 {
			buf.WriteString("E ")
		} else {
			buf.WriteString("\n")
			buf.WriteString(prefix)
			buf.WriteString("+ ")
		}

		fn := runtime.FuncForPC(x.pc)
		if fn == nil {
			buf.WriteString("unknown")
		} else {
			file, line := fn.FileLine(x.pc)
			buf.WriteString(trimSourcePath(fn.Name(), file))
			buf.WriteRune(':')
			buf.WriteString(strconv.Itoa(line))
		}

		if x.error != nil {
			buf.WriteRune(' ')
			buf.WriteString(x.error.Error())
		}
	}

	return buf.String()
}

// New returns a new error with the given printf-formatted error message.
func New(text string, a ...interface{}) error {
	x := &erx{
		pc:    getPC(3),
		error: errors.New(text),
	}
	if len(a) == 0 {
		x.error = errors.New(text)
	} else {
		x.error = fmt.Errorf(text, a)
	}

	return x
}

// Append returns a new error with the parent error
// and given printf-formatted error message.
func Append(parent error, text string, a ...interface{}) error {
	pc := getPC(3)
	p := extend(parent, pc)

	var err error
	if len(a) == 0 {
		err = errors.New(text)
	} else {
		err = fmt.Errorf(text, a)
	}

	if parent == nil {
		p.error = err
		return p
	}

	e := &erx{
		pc:     pc,
		error:  err,
		parent: p,
	}

	return e
}

// Wrap returns wrapped one or more errors.
func Wrap(errs ...error) error {
	if len(errs) == 0 {
		return nil
	}

	pc := getPC(3)

	var x, parent *erx

loop:
	for _, err := range errs {
		if err == nil {
			continue
		}

		parent = x
		x = extend(err, pc)

		if parent == nil {
			continue
		}

		e := x
		for e.parent != nil {
			if e == parent {
				x = parent
				continue loop
			}
			e = e.parent
		}
		e.parent = parent
	}

	if x == nil {
		return nil
	}

	return x
}

// Sets the prefix for child errors.
func SetPrefix(s string) {
	prefix = s
}

func getPC(calldepth int) uintptr {
	var pcs [1]uintptr
	runtime.Callers(calldepth, pcs[:])

	return pcs[0]
}

func extend(err error, pc uintptr) *erx {
	e, ok := err.(*erx)
	if !ok {
		e = &erx{
			pc:    pc,
			error: err,
		}
	}

	return e
}

func trimSourcePath(name, path string) string {
	const sep = '/'

	indexName := strings.LastIndexFunc(name, func(r rune) bool {
		return r == sep
	})

	n := 2
	if indexName == -1 {
		n = 1
	}

	indexPath := strings.LastIndexFunc(path, func(r rune) bool {
		if r == sep {
			n--
		}
		return n == 0
	})

	if indexName == -1 {
		return path[indexPath+1:]
	}

	return name[:indexName] + path[indexPath:]
}
<commit_msg>fixed variadic functions<commit_after>package errors

import (
	"bytes"
	"errors"
	"fmt"
	"runtime"
	"strconv"
	"strings"
)

var prefix string

type erx struct {
	pc     uintptr
	error  error
	parent *erx
}

// Implementation of the error interface.
func (e erx) Error() string {
	x, flat := &e, make([]*erx, 0, 16)
	for {
		flat = append(flat, x)
		if x.parent == nil {
			break
		}
		x = x.parent
	}
	max := len(flat) - 1

	var buf bytes.Buffer
	for i := 0; i <= max; i++ {
		x = flat[max-i]

		if i == 0 {
			buf.WriteString("E ")
		} else {
			buf.WriteString("\n")
			buf.WriteString(prefix)
			buf.WriteString("+ ")
		}

		fn := runtime.FuncForPC(x.pc)
		if fn == nil {
			buf.WriteString("unknown")
		} else {
			file, line := fn.FileLine(x.pc)
			buf.WriteString(trimSourcePath(fn.Name(), file))
			buf.WriteRune(':')
			buf.WriteString(strconv.Itoa(line))
		}

		if x.error != nil {
			buf.WriteRune(' ')
			buf.WriteString(x.error.Error())
		}
	}

	return buf.String()
}

// New returns a new error with the given printf-formatted error message.
func New(text string, a ...interface{}) error {
	x := &erx{
		pc:    getPC(3),
		error: errors.New(text),
	}
	if len(a) == 0 {
		x.error = errors.New(text)
	} else {
		x.error = fmt.Errorf(text, a...)
	}

	return x
}

// Append returns a new error with the parent error
// and given printf-formatted error message.
func Append(parent error, text string, a ...interface{}) error {
	pc := getPC(3)
	p := extend(parent, pc)

	var err error
	if len(a) == 0 {
		err = errors.New(text)
	} else {
		err = fmt.Errorf(text, a...)
	}

	if parent == nil {
		p.error = err
		return p
	}

	e := &erx{
		pc:     pc,
		error:  err,
		parent: p,
	}

	return e
}

// Wrap returns wrapped one or more errors.
func Wrap(errs ...error) error {
	if len(errs) == 0 {
		return nil
	}

	pc := getPC(3)

	var x, parent *erx

loop:
	for _, err := range errs {
		if err == nil {
			continue
		}

		parent = x
		x = extend(err, pc)

		if parent == nil {
			continue
		}

		e := x
		for e.parent != nil {
			if e == parent {
				x = parent
				continue loop
			}
			e = e.parent
		}
		e.parent = parent
	}

	if x == nil {
		return nil
	}

	return x
}

// Sets the prefix for child errors.
func SetPrefix(s string) {
	prefix = s
}

func getPC(calldepth int) uintptr {
	var pcs [1]uintptr
	runtime.Callers(calldepth, pcs[:])

	return pcs[0]
}

func extend(err error, pc uintptr) *erx {
	e, ok := err.(*erx)
	if !ok {
		e = &erx{
			pc:    pc,
			error: err,
		}
	}

	return e
}

func trimSourcePath(name, path string) string {
	const sep = '/'

	indexName := strings.LastIndexFunc(name, func(r rune) bool {
		return r == sep
	})

	n := 2
	if indexName == -1 {
		n = 1
	}

	indexPath := strings.LastIndexFunc(path, func(r rune) bool {
		if r == sep {
			n--
		}
		return n == 0
	})

	if indexName == -1 {
		return path[indexPath+1:]
	}

	return name[:indexName] + path[indexPath:]
}
<|endoftext|>


<commit_before>package executor

import "net/http"

type Error interface {
	error

	Name() string
	HttpCode() int
}

type execError struct {
	name     string
	message  string
	httpCode int
}

func (err execError) Name() string {
	return err.name
}

func (err execError) Error() string {
	return err.message
}

func (err execError) HttpCode() int {
	return err.httpCode
}

var Errors = map[string]Error{}

func registerError(name string, message string, status int) Error {
	err := execError{name, message, status}
	Errors[name] = err
	return err
}

var (
	ErrContainerGuidNotAvailable      = registerError("ContainerGuidNotAvailable", "container guid not available", http.StatusBadRequest)
	ErrContainerNotCompleted          = registerError("ContainerNotCompleted", "container must be stopped before it can be deleted", http.StatusBadRequest)
	ErrInsufficientResourcesAvailable = registerError("InsufficientResourcesAvailable", "insufficient resources available", http.StatusServiceUnavailable)
	ErrContainerNotFound              = registerError("ContainerNotFound", "container not found", http.StatusNotFound)
	ErrStepsInvalid                   = registerError("StepsInvalid", "steps invalid", http.StatusBadRequest)
	ErrLimitsInvalid                  = registerError("LimitsInvalid", "container limits invalid", http.StatusBadRequest)
	ErrGuidNotSpecified               = registerError("GuidNotSpecified", "container guid not specified", http.StatusBadRequest)
	ErrInvalidTransition              = registerError("InvalidStateTransition", "container cannot transition to given state", http.StatusConflict)
	ErrFailureToCheckSpace            = registerError("ErrFailureToCheckSpace", "failed to check available space", http.StatusInternalServerError)
	ErrInvalidSecurityGroup           = registerError("ErrInvalidSecurityGroup", "security group has invalid values", http.StatusBadRequest)
	ErrNoProcessToStop                = registerError("ErrNoProcessToStop", "failed to find a process to stop", http.StatusNotFound)
)
<commit_msg>Remove unused http codes from errors<commit_after>package executor

type Error interface {
	error

	Name() string
}

type execError struct {
	name    string
	message string
}

func (err execError) Name() string {
	return err.name
}

func (err execError) Error() string {
	return err.message
}

var Errors = map[string]Error{}

func registerError(name, message string) Error {
	err := execError{name, message}
	Errors[name] = err
	return err
}

var (
	ErrContainerGuidNotAvailable      = registerError("ContainerGuidNotAvailable", "container guid not available")
	ErrContainerNotCompleted          = registerError("ContainerNotCompleted", "container must be stopped before it can be deleted")
	ErrInsufficientResourcesAvailable = registerError("InsufficientResourcesAvailable", "insufficient resources available")
	ErrContainerNotFound              = registerError("ContainerNotFound", "container not found")
	ErrStepsInvalid                   = registerError("StepsInvalid", "steps invalid")
	ErrLimitsInvalid                  = registerError("LimitsInvalid", "container limits invalid")
	ErrGuidNotSpecified               = registerError("GuidNotSpecified", "container guid not specified")
	ErrInvalidTransition              = registerError("InvalidStateTransition", "container cannot transition to given state")
	ErrFailureToCheckSpace            = registerError("ErrFailureToCheckSpace", "failed to check available space")
	ErrInvalidSecurityGroup           = registerError("ErrInvalidSecurityGroup", "security group has invalid values")
	ErrNoProcessToStop                = registerError("ErrNoProcessToStop", "failed to find a process to stop")
)
<|endoftext|>


<commit_before>package main

import "math"
import "fmt"

func test() {
	fmt.Println("Called test()")

}

func main() {
	fmt.Println(math.Cos(3.4))
	test()

}
<commit_msg>Testing out the base64 module<commit_after>package main

import (
	"math"
	"fmt"
	"encoding/base64"
)

func test() {
	fmt.Println("Called test()")

}

func main() {
	// testing out base64 encoding of URLs
	url := []byte("http://www.golang.com")
	str := base64.StdEncoding.EncodeToString(url)
	fmt.Println(str)

	fmt.Println(math.Cos(3.4))
	test()

}
<|endoftext|>


<commit_before>package gobotslack

import (
	"fmt"
	"github.com/BurntSushi/toml"
	log "github.com/Sirupsen/logrus"
	"github.com/eternnoir/gobot"
	"github.com/eternnoir/gobot/payload"
	"github.com/nlopes/slack"
)

const AdapterName string = "gobotslack"

func init() {
	gobot.RegisterAdapter(AdapterName, &SlackAdapter{})
}

type SlackAdapter struct {
	bot            *gobot.Gobot
	api            *slack.Client
	rtm            *slack.RTM
	token          string
	defaultChannel string
	channelMap     map[string]slack.Channel
	userNameMap    map[string]slack.User
	userIdMap      map[string]slack.User
}

type SlackConfig struct {
	Token   string
	Channel string
}

func (sa *SlackAdapter) Init(bot *gobot.Gobot) error {
	log.Infof("SlackAdapter init.")
	var conf SlackConfig
	if _, err := toml.DecodeFile(bot.ConfigPath+"/slack.toml", &conf); err != nil {
		return err
	}
	log.Infof("SlackAdapter get config %#v", conf)
	sa.token = conf.Token
	sa.bot = bot
	sa.api = slack.New(sa.token)
	dc := "general"
	if conf.Channel != "" {
		dc = conf.Channel
	}
	sa.defaultChannel = dc
	log.Infof("SlackAdapter init done. %#v", sa)
	return nil
}

func (sa *SlackAdapter) Start() {
	log.Info("SlackAdapter start.")
	sa.initChannelMap()
	sa.initUserMap()
	sa.startRTM()
}

func (sa *SlackAdapter) initChannelMap() {
	chs, err := sa.api.GetChannels(false)
	if err != nil {
		log.Error(err)
		panic("SlackConfig load channels fail.")
	}
	sa.channelMap = map[string]slack.Channel{}
	for _, ch := range chs {
		log.Infof("[SlackAdapter] load channel %s Id: %s", ch.Name, ch.ID)
		sa.channelMap[ch.Name] = ch
	}
}

func (sa *SlackAdapter) initUserMap() {
	users, err := sa.api.GetUsers()
	if err != nil {
		log.Error(err)
		panic("SlackConfig load users fail.")
	}
	log.Infof("[SlackAdapter] load users %#v", users)
	sa.userNameMap = map[string]slack.User{}
	sa.userIdMap = map[string]slack.User{}
	for _, user := range users {
		sa.userNameMap[user.Name] = user
		sa.userIdMap[user.ID] = user
	}
}

func (sa *SlackAdapter) Send(text string) error {
	log.Infof("[SlackAdapter] Get new text to send.%s", text, sa.defaultChannel)
	if ch, ok := sa.channelMap[sa.defaultChannel]; ok {
		log.Infof("[SlackAdapter] Send new text %s. To %s", text, ch.Name)
		_, _, err := sa.api.PostMessage("#"+ch.Name, text, slack.PostMessageParameters{AsUser: true})
		if err != nil {
			log.Error(err)
		}
	} else {
		log.Errorf("[SlackAdapter] Channel name %s not found.", sa.defaultChannel)
	}
	return nil
}

func (sa *SlackAdapter) Reply(orimessage *payload.Message, text string) error {
	log.Infof("Get Replay message. Origin message is %s. Text %s", orimessage.Text, text)
	ev := orimessage.Payload.(*slack.MessageEvent)
	resMsg := sa.rtm.NewOutgoingMessage(text, ev.Channel)
	sa.rtm.SendMessage(resMsg)
	return nil
}

func (sa *SlackAdapter) startRTM() {
	rtm := sa.api.NewRTM()
	sa.rtm = rtm
	go rtm.ManageConnection()

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			log.Info("Event Received: ")
			switch ev := msg.Data.(type) {
			case *slack.HelloEvent:
				// Ignore hello

			case *slack.ConnectedEvent:
				fmt.Println("Infos:", ev.Info)
				fmt.Println("Connection counter:", ev.ConnectionCount)
				// Replace #general with your Channel ID
				rtm.SendMessage(rtm.NewOutgoingMessage("Hello world", "#general"))

			case *slack.MessageEvent:
				log.Infof("[SlackAdapter] Get message %#v", ev)
				msg := &payload.Message{}
				msg.SourceAdapter = AdapterName
				msg.Text = ev.Msg.Text
				msg.Payload = ev
				sa.bot.Receive(msg)

			case *slack.PresenceChangeEvent:
				fmt.Printf("Presence Change: %v\n", ev)

			case *slack.LatencyReport:
				fmt.Printf("Current latency: %v\n", ev.Value)

			case *slack.RTMError:
				log.Errorf("[SlackAdapter] Error: %s", ev.Error())

			case *slack.InvalidAuthEvent:
				log.Error("[SlackAdapter] InvalidAuthEvent Error")
				break Loop

			default:

				// Ignore other events..
				// fmt.Printf("Unexpected: %v\n", msg.Data)
			}
		}
	}

}
<commit_msg>add parse support.<commit_after>package gobotslack

import (
	"fmt"
	"github.com/BurntSushi/toml"
	log "github.com/Sirupsen/logrus"
	"github.com/eternnoir/gobot"
	"github.com/eternnoir/gobot/payload"
	"github.com/nlopes/slack"
)

const AdapterName string = "gobotslack"

func init() {
	gobot.RegisterAdapter(AdapterName, &SlackAdapter{})
}

type SlackAdapter struct {
	bot            *gobot.Gobot
	api            *slack.Client
	rtm            *slack.RTM
	token          string
	defaultChannel string
	channelMap     map[string]slack.Channel
	userNameMap    map[string]slack.User
	userIdMap      map[string]slack.User
}

type SlackConfig struct {
	Token   string
	Channel string
}

func (sa *SlackAdapter) Init(bot *gobot.Gobot) error {
	log.Infof("SlackAdapter init.")
	var conf SlackConfig
	if _, err := toml.DecodeFile(bot.ConfigPath+"/slack.toml", &conf); err != nil {
		return err
	}
	log.Infof("SlackAdapter get config %#v", conf)
	sa.token = conf.Token
	sa.bot = bot
	sa.api = slack.New(sa.token)
	dc := "general"
	if conf.Channel != "" {
		dc = conf.Channel
	}
	sa.defaultChannel = dc
	log.Infof("SlackAdapter init done. %#v", sa)
	return nil
}

func (sa *SlackAdapter) Start() {
	log.Info("SlackAdapter start.")
	sa.initChannelMap()
	sa.initUserMap()
	sa.startRTM()
}

func (sa *SlackAdapter) initChannelMap() {
	chs, err := sa.api.GetChannels(false)
	if err != nil {
		log.Error(err)
		panic("SlackConfig load channels fail.")
	}
	sa.channelMap = map[string]slack.Channel{}
	for _, ch := range chs {
		log.Infof("[SlackAdapter] load channel %s Id: %s", ch.Name, ch.ID)
		sa.channelMap[ch.Name] = ch
	}
}

func (sa *SlackAdapter) initUserMap() {
	users, err := sa.api.GetUsers()
	if err != nil {
		log.Error(err)
		panic("SlackConfig load users fail.")
	}
	log.Infof("[SlackAdapter] load users %#v", users)
	sa.userNameMap = map[string]slack.User{}
	sa.userIdMap = map[string]slack.User{}
	for _, user := range users {
		sa.userNameMap[user.Name] = user
		sa.userIdMap[user.ID] = user
	}
}

func (sa *SlackAdapter) Send(text string) error {
	log.Infof("[SlackAdapter] Get new text to send.%s", text, sa.defaultChannel)
	if ch, ok := sa.channelMap[sa.defaultChannel]; ok {
		log.Infof("[SlackAdapter] Send new text %s. To %s", text, ch.Name)
		_, _, err := sa.api.PostMessage("#"+ch.Name, text, slack.PostMessageParameters{AsUser: true, Parse: "full"})
		if err != nil {
			log.Error(err)
		}
	} else {
		log.Errorf("[SlackAdapter] Channel name %s not found.", sa.defaultChannel)
	}
	return nil
}

func (sa *SlackAdapter) Reply(orimessage *payload.Message, text string) error {
	log.Infof("Get Replay message. Origin message is %s. Text %s", orimessage.Text, text)
	ev := orimessage.Payload.(*slack.MessageEvent)
	resMsg := sa.rtm.NewOutgoingMessage(text, ev.Channel)
	sa.rtm.SendMessage(resMsg)
	return nil
}

func (sa *SlackAdapter) startRTM() {
	rtm := sa.api.NewRTM()
	sa.rtm = rtm
	go rtm.ManageConnection()

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			log.Info("Event Received: ")
			switch ev := msg.Data.(type) {
			case *slack.HelloEvent:
				// Ignore hello

			case *slack.ConnectedEvent:
				fmt.Println("Infos:", ev.Info)
				fmt.Println("Connection counter:", ev.ConnectionCount)
				// Replace #general with your Channel ID
				rtm.SendMessage(rtm.NewOutgoingMessage("Hello world", "#general"))

			case *slack.MessageEvent:
				log.Infof("[SlackAdapter] Get message %#v", ev)
				msg := &payload.Message{}
				msg.SourceAdapter = AdapterName
				msg.Text = ev.Msg.Text
				msg.Payload = ev
				sa.bot.Receive(msg)

			case *slack.PresenceChangeEvent:
				fmt.Printf("Presence Change: %v\n", ev)

			case *slack.LatencyReport:
				fmt.Printf("Current latency: %v\n", ev.Value)

			case *slack.RTMError:
				log.Errorf("[SlackAdapter] Error: %s", ev.Error())

			case *slack.InvalidAuthEvent:
				log.Error("[SlackAdapter] InvalidAuthEvent Error")
				break Loop

			default:

				// Ignore other events..
				// fmt.Printf("Unexpected: %v\n", msg.Data)
			}
		}
	}

}
<|endoftext|>


<commit_before>package gopherpods

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/mail"
	"google.golang.org/appengine/urlfetch"

	"golang.org/x/net/context"
)

const (
	yyyymmdd = "2006-01-02"
)

var (
	podcastsTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/podcasts.html",
	))

	submitTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/submit.html",
	))

	thanksTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/thanks.html",
	))

	submissionsTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/submissions.html",
	))

	successTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/success.html",
	))
)

type aehandler struct {
	h      func(ctx context.Context, w http.ResponseWriter, r *http.Request) error
	method string
}

func (a aehandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != a.method {
		http.NotFound(w, r)
		return
	}

	ctx := appengine.NewContext(r)
	if err := a.h(ctx, w, r); err != nil {
		log.Errorf(ctx, "%v", err)
		http.Error(w, "There was an error, sorry", http.StatusInternalServerError)
		return
	}
}

func init() {
	http.Handle("/", aehandler{podcastsHandler, "GET"})
	http.Handle("/submit/", aehandler{submitHandler, "GET"})
	http.Handle("/submit/add", aehandler{submitAddHandler, "POST"})

	http.Handle("/submissions/", aehandler{submissionsHandler, "GET"})
	http.Handle("/submissions/add", aehandler{submissionsAddHandler, "POST"})
	http.Handle("/submissions/del", aehandler{submissionsDelHandler, "POST"})

	http.Handle("/tasks/email", aehandler{emailHandler, "GET"})
}

type Podcast struct {
	ID    int64        `datastore:",noindex"`
	Show  string       `datastore:",noindex"`
	Title string       `datastore:",noindex"`
	Desc  string       `datastore:",noindex"`
	URL   template.URL `datastore:",noindex"`
	Date  time.Time    `datastore:""`
	Added time.Time    `datastore:""`
}

func (p *Podcast) DateFormatted() string {
	return p.Date.Format(yyyymmdd)
}

type Submission struct {
	Show      string       `datastore:",noindex"`
	Title     string       `datastore:",noindex"`
	Desc      string       `datastore:",noindex"`
	URL       template.URL `datastore:",noindex"`
	Date      time.Time    `datastore:",noindex"`
	Submitted time.Time    `datastore:""`
	Key       string       `datastore:"-"`
}

func (s *Submission) DateFormatted() string {
	return s.Date.Format(yyyymmdd)
}

func podcastsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	podcasts := make([]Podcast, 0)
	if _, err := datastore.NewQuery("Podcast").GetAll(ctx, &podcasts); err != nil {
		return err
	}

	var tmplData = struct {
		Podcasts []Podcast
	}{
		podcasts,
	}

	return podcastsTmpl.ExecuteTemplate(w, "base", tmplData)
}

func submitHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	return submitTmpl.ExecuteTemplate(w, "base", nil)
}

func sanitize(xss string) string {
	return template.HTMLEscapeString(template.JSEscapeString(strings.TrimSpace(xss)))
}

type RecaptchaResponse struct {
	Success   bool     `json:"success"`
	ErrorCode []string `json:"error-codes"`
}

func submitAddHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}

	if !appengine.IsDevAppServer() {
		form := url.Values{}
		form.Add("secret", os.Getenv("SECRET"))
		form.Add("response", r.FormValue("g-recaptcha-response"))
		form.Add("remoteip", r.RemoteAddr)
		req, err := http.NewRequest("POST", "https://www.google.com/recaptcha/api/siteverify", strings.NewReader(form.Encode()))
		if err != nil {
			return err
		}
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

		cli := urlfetch.Client(ctx)
		resp, err := cli.Do(req)
		if err != nil {
			return err
		}

		var recaptcha RecaptchaResponse
		if err := json.NewDecoder(resp.Body).Decode(&recaptcha); err != nil {
			return err
		}

		if !recaptcha.Success {
			log.Infof(ctx, "%v", recaptcha)
			return fmt.Errorf("reCAPTCHA check failed")
		}
	}

	date, err := time.Parse(yyyymmdd, sanitize(r.FormValue("date")))
	if err != nil {
		return err
	}

	sub := Submission{
		Show:      sanitize(r.FormValue("show")),
		Title:     sanitize(r.FormValue("title")),
		Desc:      sanitize(r.FormValue("desc")),
		URL:       template.URL(sanitize(r.FormValue("url"))),
		Submitted: time.Now(),
		Date:      date,
	}

	if _, err := datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "Submission", nil), &sub); err != nil {
		return err
	}

	return thanksTmpl.ExecuteTemplate(w, "base", nil)
}

func submissionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	submissions := make([]Submission, 0)
	keys, err := datastore.NewQuery("Submission").Order("Submitted").GetAll(ctx, &submissions)
	if err != nil {
		return err
	}

	for i := range submissions {
		submissions[i].Key = keys[i].Encode()
	}

	var tmplData = struct {
		Submissions []Submission
	}{
		Submissions: submissions,
	}

	return submissionsTmpl.ExecuteTemplate(w, "base", tmplData)
}

func submissionsAddHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}

	ID, _, err := datastore.AllocateIDs(ctx, "Podcast", nil, 100)
	if err != nil {
		return err
	}

	date, err := time.Parse(yyyymmdd, r.FormValue("date"))
	if err != nil {
		return err
	}

	podcast := Podcast{
		ID:    ID,
		Show:  r.FormValue("show"),
		Title: r.FormValue("title"),
		Desc:  r.FormValue("desc"),
		URL:   template.URL(r.FormValue("url")),
		Date:  date,
		Added: time.Now(),
	}

	if _, err := datastore.Put(ctx, datastore.NewKey(ctx, "Podcast", "", ID, nil), &podcast); err != nil {
		return err
	}

	key, err := datastore.DecodeKey(r.FormValue("key"))
	if err != nil {
		return err
	}

	if err := datastore.Delete(ctx, key); err != nil {
		return err
	}

	return successTmpl.ExecuteTemplate(w, "base", nil)
}

func submissionsDelHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}

	key, err := datastore.DecodeKey(r.FormValue("key"))
	if err != nil {
		return err
	}

	if err := datastore.Delete(ctx, key); err != nil {
		return err
	}

	return successTmpl.ExecuteTemplate(w, "base", nil)
}

func emailHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	keys, err := datastore.NewQuery("Submission").KeysOnly().GetAll(ctx, nil)
	if err != nil {
		return err
	}

	if len(keys) == 0 {
		return nil
	}

	msg := mail.Message{
		Subject: "GopherPods",
		Sender:  os.Getenv("EMAIL"),
		Body: fmt.Sprintf("There are %d outstanding submissions.\n\nhttps://gopherpods.appspot.com/submissions/\n\n%v",
			len(keys), time.Now()),
	}

	if err := mail.SendToAdmins(ctx, &msg); err != nil {
		return err
	}

	return nil
}
<commit_msg>Refactor recaptcha check, simplify mail and handlers<commit_after>package gopherpods

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/mail"
	"google.golang.org/appengine/urlfetch"

	"golang.org/x/net/context"
)

const (
	yyyymmdd     = "2006-01-02"
	recaptchaURL = "https://www.google.com/recaptcha/api/siteverify"
)

var (
	podcastsTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/podcasts.html",
	))

	submitTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/submit.html",
	))

	thanksTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/thanks.html",
	))

	submissionsTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/submissions.html",
	))

	successTmpl = template.Must(template.ParseFiles(
		"static/html/base.html",
		"static/html/success.html",
	))
)

type aehandler struct {
	h      func(ctx context.Context, w http.ResponseWriter, r *http.Request) error
	method string
}

func (a aehandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != a.method {
		http.NotFound(w, r)
		return
	}

	ctx := appengine.NewContext(r)
	if err := a.h(ctx, w, r); err != nil {
		log.Errorf(ctx, "%v", err)
		http.Error(w, "There was an error, sorry", http.StatusInternalServerError)
		return
	}
}

func init() {
	http.Handle("/", aehandler{podcastsHandler, "GET"})
	http.Handle("/submit", aehandler{submitHandler, "GET"})
	http.Handle("/submit/add", aehandler{submitAddHandler, "POST"})

	http.Handle("/submissions", aehandler{submissionsHandler, "GET"})
	http.Handle("/submissions/add", aehandler{submissionsAddHandler, "POST"})
	http.Handle("/submissions/del", aehandler{submissionsDelHandler, "POST"})

	http.Handle("/tasks/email", aehandler{emailHandler, "GET"})
}

type Podcast struct {
	ID    int64        `datastore:",noindex"`
	Show  string       `datastore:",noindex"`
	Title string       `datastore:",noindex"`
	Desc  string       `datastore:",noindex"`
	URL   template.URL `datastore:",noindex"`
	Date  time.Time    `datastore:""`
	Added time.Time    `datastore:""`
}

func (p *Podcast) DateFormatted() string {
	return p.Date.Format(yyyymmdd)
}

type Submission struct {
	Show      string       `datastore:",noindex"`
	Title     string       `datastore:",noindex"`
	Desc      string       `datastore:",noindex"`
	URL       template.URL `datastore:",noindex"`
	Date      time.Time    `datastore:",noindex"`
	Submitted time.Time    `datastore:""`
	Key       string       `datastore:"-"`
}

func (s *Submission) DateFormatted() string {
	return s.Date.Format(yyyymmdd)
}

func podcastsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	podcasts := make([]Podcast, 0)
	if _, err := datastore.NewQuery("Podcast").Order("-Date").GetAll(ctx, &podcasts); err != nil {
		return err
	}

	var tmplData = struct {
		Podcasts []Podcast
	}{
		podcasts,
	}

	return podcastsTmpl.ExecuteTemplate(w, "base", tmplData)
}

func submitHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	return submitTmpl.ExecuteTemplate(w, "base", nil)
}

func sanitize(xss string) string {
	return template.HTMLEscapeString(template.JSEscapeString(strings.TrimSpace(xss)))
}

func recaptchaCheck(ctx context.Context, response, ip string) (bool, error) {
	if appengine.IsDevAppServer() {
		return true, nil
	}

	form := url.Values{}
	form.Add("secret", os.Getenv("SECRET"))
	form.Add("response", response)
	form.Add("remoteip", ip)
	req, err := http.NewRequest("POST", recaptchaURL, strings.NewReader(form.Encode()))
	if err != nil {
		return false, err
	}

	cli := urlfetch.Client(ctx)

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	resp, err := cli.Do(req)
	if err != nil {
		return false, err
	}

	var recaptcha RecaptchaResponse
	if err := json.NewDecoder(resp.Body).Decode(&recaptcha); err != nil {
		return false, err
	}

	if !recaptcha.Success {
		log.Warningf(ctx, "%+v", recaptcha)
		return false, nil
	}

	return true, nil
}

type RecaptchaResponse struct {
	Success   bool     `json:"success"`
	ErrorCode []string `json:"error-codes"`
}

func submitAddHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}

	success, err := recaptchaCheck(ctx, r.FormValue("g-recaptcha-response"), r.RemoteAddr)
	if err != nil {
		return err
	}

	if !success {
		http.Error(w, "failed reCAPTCHA check", http.StatusBadRequest)
		return nil
	}

	date, err := time.Parse(yyyymmdd, sanitize(r.FormValue("date")))
	if err != nil {
		return err
	}

	sub := Submission{
		Show:      sanitize(r.FormValue("show")),
		Title:     sanitize(r.FormValue("title")),
		Desc:      sanitize(r.FormValue("desc")),
		URL:       template.URL(sanitize(r.FormValue("url"))),
		Submitted: time.Now(),
		Date:      date,
	}

	if _, err := datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "Submission", nil), &sub); err != nil {
		return err
	}

	return thanksTmpl.ExecuteTemplate(w, "base", nil)
}

func submissionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	submissions := make([]Submission, 0)
	keys, err := datastore.NewQuery("Submission").Order("Submitted").GetAll(ctx, &submissions)
	if err != nil {
		return err
	}

	for i := range submissions {
		submissions[i].Key = keys[i].Encode()
	}

	var tmplData = struct {
		Submissions []Submission
	}{
		Submissions: submissions,
	}

	return submissionsTmpl.ExecuteTemplate(w, "base", tmplData)
}

func submissionsAddHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}

	ID, _, err := datastore.AllocateIDs(ctx, "Podcast", nil, 100)
	if err != nil {
		return err
	}

	date, err := time.Parse(yyyymmdd, r.FormValue("date"))
	if err != nil {
		return err
	}

	podcast := Podcast{
		ID:    ID,
		Show:  r.FormValue("show"),
		Title: r.FormValue("title"),
		Desc:  r.FormValue("desc"),
		URL:   template.URL(r.FormValue("url")),
		Date:  date,
		Added: time.Now(),
	}

	if _, err := datastore.Put(ctx, datastore.NewKey(ctx, "Podcast", "", ID, nil), &podcast); err != nil {
		return err
	}

	key, err := datastore.DecodeKey(r.FormValue("key"))
	if err != nil {
		return err
	}

	if err := datastore.Delete(ctx, key); err != nil {
		return err
	}

	return successTmpl.ExecuteTemplate(w, "base", nil)
}

func submissionsDelHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}

	key, err := datastore.DecodeKey(r.FormValue("key"))
	if err != nil {
		return err
	}

	if err := datastore.Delete(ctx, key); err != nil {
		return err
	}

	return successTmpl.ExecuteTemplate(w, "base", nil)
}

func emailHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	keys, err := datastore.NewQuery("Submission").KeysOnly().GetAll(ctx, nil)
	if err != nil {
		return err
	}

	if len(keys) == 0 {
		return nil
	}

	msg := mail.Message{
		Subject: "GopherPods",
		Sender:  os.Getenv("EMAIL"),
		Body:    fmt.Sprintf("There are %d outstanding submissions", len(keys)),
	}

	if err := mail.SendToAdmins(ctx, &msg); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


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

package kex2

import (
	"crypto/rand"
	"encoding/hex"
	"errors"
	"io"
	"testing"
	"time"

	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	"golang.org/x/net/context"
)

const (
	GoodProvisionee                  = 0
	BadProvisioneeFailHello          = 1 << iota
	BadProvisioneeFailDidCounterSign = 1 << iota
	BadProvisioneeSlowHello          = 1 << iota
	BadProvisioneeSlowDidCounterSign = 1 << iota
	BadProvisioneeCancel             = 1 << iota
)

type mockProvisioner struct {
	uid keybase1.UID
}

type mockProvisionee struct {
	behavior int
}

func newMockProvisioner(t *testing.T) *mockProvisioner {
	return &mockProvisioner{
		uid: genUID(t),
	}
}

type nullLogOutput struct {
}

func (n *nullLogOutput) Error(s string, args ...interface{})   {}
func (n *nullLogOutput) Warning(s string, args ...interface{}) {}
func (n *nullLogOutput) Info(s string, args ...interface{})    {}
func (n *nullLogOutput) Debug(s string, args ...interface{})   {}
func (n *nullLogOutput) Profile(s string, args ...interface{}) {}

var _ rpc.LogOutput = (*nullLogOutput)(nil)

func makeLogFactory() rpc.LogFactory {
	if testing.Verbose() {
		return nil
	}
	return rpc.NewSimpleLogFactory(&nullLogOutput{}, nil)
}

func genUID(t *testing.T) keybase1.UID {
	uid := make([]byte, 8)
	if _, err := rand.Read(uid); err != nil {
		t.Fatalf("rand failed: %v\n", err)
	}
	return keybase1.UID(hex.EncodeToString(uid))
}

func genKeybase1DeviceID(t *testing.T) keybase1.DeviceID {
	did := make([]byte, 16)
	if _, err := rand.Read(did); err != nil {
		t.Fatalf("rand failed: %v\n", err)
	}
	return keybase1.DeviceID(hex.EncodeToString(did))
}

func newMockProvisionee(t *testing.T, behavior int) *mockProvisionee {
	return &mockProvisionee{behavior}
}

func (mp *mockProvisioner) GetLogFactory() rpc.LogFactory {
	return makeLogFactory()
}

func (mp *mockProvisioner) CounterSign(input keybase1.HelloRes) (output []byte, err error) {
	output = []byte(string(input))
	return
}

func (mp *mockProvisioner) GetHelloArg() (res keybase1.HelloArg, err error) {
	res.Uid = mp.uid
	return
}

func (mp *mockProvisionee) GetLogFactory() rpc.LogFactory {
	return makeLogFactory()
}

var ErrHandleHello = errors.New("handle hello failure")
var ErrHandleDidCounterSign = errors.New("handle didCounterSign failure")
var testTimeout = time.Duration(20) * time.Millisecond

func (mp *mockProvisionee) HandleHello(arg keybase1.HelloArg) (res keybase1.HelloRes, err error) {
	if (mp.behavior & BadProvisioneeSlowHello) != 0 {
		time.Sleep(testTimeout * 3)
	}
	if (mp.behavior & BadProvisioneeFailHello) != 0 {
		err = ErrHandleHello
		return
	}
	res = keybase1.HelloRes(arg.SigBody)
	return
}

func (mp *mockProvisionee) HandleDidCounterSign([]byte) error {
	if (mp.behavior & BadProvisioneeSlowDidCounterSign) != 0 {
		time.Sleep(testTimeout * 3)
	}
	if (mp.behavior & BadProvisioneeFailDidCounterSign) != 0 {
		return ErrHandleDidCounterSign
	}
	return nil
}

func testProtocolXWithBehavior(t *testing.T, provisioneeBehavior int) (results [2]error) {

	timeout := testTimeout
	router := newMockRouterWithBehaviorAndMaxPoll(GoodRouter, timeout)

	s2 := genSecret(t)

	ch := make(chan error, 3)

	secretCh := make(chan Secret)

	ctx, cancelFn := context.WithCancel(context.Background())

	// Run the provisioner
	go func() {
		err := RunProvisioner(ProvisionerArg{
			KexBaseArg: KexBaseArg{
				Ctx:           ctx,
				Mr:            router,
				Secret:        genSecret(t),
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: secretCh,
				Timeout:       timeout,
			},
			Provisioner: newMockProvisioner(t),
		})
		ch <- err
	}()

	// Run the privisionee
	go func() {
		err := RunProvisionee(ProvisioneeArg{
			KexBaseArg: KexBaseArg{
				Ctx:           context.Background(),
				Mr:            router,
				Secret:        s2,
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: make(chan Secret),
				Timeout:       timeout,
			},
			Provisionee: newMockProvisionee(t, provisioneeBehavior),
		})
		ch <- err
	}()

	if (provisioneeBehavior & BadProvisioneeCancel) != 0 {
		go func() {
			time.Sleep(testTimeout / 2)
			cancelFn()
		}()
	}

	secretCh <- s2

	for i := 0; i < 2; i++ {
		if e, eof := <-ch; !eof {
			t.Fatalf("got unexpected channel close (try %d)", i)
		} else if e != nil {
			results[i] = e
		}
	}

	return results
}

func TestFullProtocolXSuccess(t *testing.T) {
	results := testProtocolXWithBehavior(t, GoodProvisionee)
	for i, e := range results {
		if e != nil {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

// Since errors are exported as strings, then we should just test that the
// right kind of error was specified
func eeq(e1, e2 error) bool {
	return e1 != nil && e1.Error() == e2.Error()
}

func TestFullProtocolXProvisioneeFailHello(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeFailHello)
	if !eeq(results[0], ErrHandleHello) {
		t.Fatalf("Bad error 0: %v", results[0])
	}
	if !eeq(results[1], ErrHandleHello) {
		t.Fatalf("Bad error 1: %v", results[1])
	}
}

func TestFullProtocolXProvisioneeFailDidCounterSign(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeFailDidCounterSign)
	if !eeq(results[0], ErrHandleDidCounterSign) {
		t.Fatalf("Bad error 0: %v", results[0])
	}
	if !eeq(results[1], ErrHandleDidCounterSign) {
		t.Fatalf("Bad error 1: %v", results[1])
	}
}

func TestFullProtocolXProvisioneeSlowHello(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeSlowHello)
	for i, e := range results {
		if !eeq(e, ErrTimedOut) && !eeq(e, io.EOF) && !eeq(e, ErrHelloTimeout) {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

func TestFullProtocolXProvisioneeSlowHelloWithCancel(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeSlowHello|BadProvisioneeCancel)
	for i, e := range results {
		if !eeq(e, ErrCanceled) && !eeq(e, io.EOF) {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

func TestFullProtocolXProvisioneeSlowDidCounterSign(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeSlowDidCounterSign)
	for i, e := range results {
		if !eeq(e, ErrTimedOut) && !eeq(e, io.EOF) {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

func TestFullProtocolY(t *testing.T) {

	timeout := time.Duration(60) * time.Second
	router := newMockRouterWithBehaviorAndMaxPoll(GoodRouter, timeout)

	s1 := genSecret(t)

	ch := make(chan error, 3)

	secretCh := make(chan Secret)

	// Run the provisioner
	go func() {
		err := RunProvisioner(ProvisionerArg{
			KexBaseArg: KexBaseArg{
				Ctx:           context.TODO(),
				Mr:            router,
				Secret:        s1,
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: make(chan Secret),
				Timeout:       timeout,
			},
			Provisioner: newMockProvisioner(t),
		})
		ch <- err
	}()

	// Run the provisionee
	go func() {
		err := RunProvisionee(ProvisioneeArg{
			KexBaseArg: KexBaseArg{
				Ctx:           context.TODO(),
				Mr:            router,
				Secret:        genSecret(t),
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: secretCh,
				Timeout:       timeout,
			},
			Provisionee: newMockProvisionee(t, GoodProvisionee),
		})
		ch <- err
	}()

	secretCh <- s1

	for i := 0; i < 2; i++ {
		if e, eof := <-ch; !eof {
			t.Fatalf("got unexpected channel close (try %d)", i)
		} else if e != nil {
			t.Fatalf("Unexpected error (receive %d): %v", i, e)
		}
	}

}
<commit_msg>Change kex2 timeout for appveyor<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package kex2

import (
	"crypto/rand"
	"encoding/hex"
	"errors"
	"io"
	"testing"
	"time"

	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	"golang.org/x/net/context"
)

const (
	GoodProvisionee                  = 0
	BadProvisioneeFailHello          = 1 << iota
	BadProvisioneeFailDidCounterSign = 1 << iota
	BadProvisioneeSlowHello          = 1 << iota
	BadProvisioneeSlowDidCounterSign = 1 << iota
	BadProvisioneeCancel             = 1 << iota
)

type mockProvisioner struct {
	uid keybase1.UID
}

type mockProvisionee struct {
	behavior int
}

func newMockProvisioner(t *testing.T) *mockProvisioner {
	return &mockProvisioner{
		uid: genUID(t),
	}
}

type nullLogOutput struct {
}

func (n *nullLogOutput) Error(s string, args ...interface{})   {}
func (n *nullLogOutput) Warning(s string, args ...interface{}) {}
func (n *nullLogOutput) Info(s string, args ...interface{})    {}
func (n *nullLogOutput) Debug(s string, args ...interface{})   {}
func (n *nullLogOutput) Profile(s string, args ...interface{}) {}

var _ rpc.LogOutput = (*nullLogOutput)(nil)

func makeLogFactory() rpc.LogFactory {
	if testing.Verbose() {
		return nil
	}
	return rpc.NewSimpleLogFactory(&nullLogOutput{}, nil)
}

func genUID(t *testing.T) keybase1.UID {
	uid := make([]byte, 8)
	if _, err := rand.Read(uid); err != nil {
		t.Fatalf("rand failed: %v\n", err)
	}
	return keybase1.UID(hex.EncodeToString(uid))
}

func genKeybase1DeviceID(t *testing.T) keybase1.DeviceID {
	did := make([]byte, 16)
	if _, err := rand.Read(did); err != nil {
		t.Fatalf("rand failed: %v\n", err)
	}
	return keybase1.DeviceID(hex.EncodeToString(did))
}

func newMockProvisionee(t *testing.T, behavior int) *mockProvisionee {
	return &mockProvisionee{behavior}
}

func (mp *mockProvisioner) GetLogFactory() rpc.LogFactory {
	return makeLogFactory()
}

func (mp *mockProvisioner) CounterSign(input keybase1.HelloRes) (output []byte, err error) {
	output = []byte(string(input))
	return
}

func (mp *mockProvisioner) GetHelloArg() (res keybase1.HelloArg, err error) {
	res.Uid = mp.uid
	return
}

func (mp *mockProvisionee) GetLogFactory() rpc.LogFactory {
	return makeLogFactory()
}

var ErrHandleHello = errors.New("handle hello failure")
var ErrHandleDidCounterSign = errors.New("handle didCounterSign failure")
var testTimeout = time.Duration(50) * time.Millisecond

func (mp *mockProvisionee) HandleHello(arg keybase1.HelloArg) (res keybase1.HelloRes, err error) {
	if (mp.behavior & BadProvisioneeSlowHello) != 0 {
		time.Sleep(testTimeout * 3)
	}
	if (mp.behavior & BadProvisioneeFailHello) != 0 {
		err = ErrHandleHello
		return
	}
	res = keybase1.HelloRes(arg.SigBody)
	return
}

func (mp *mockProvisionee) HandleDidCounterSign([]byte) error {
	if (mp.behavior & BadProvisioneeSlowDidCounterSign) != 0 {
		time.Sleep(testTimeout * 3)
	}
	if (mp.behavior & BadProvisioneeFailDidCounterSign) != 0 {
		return ErrHandleDidCounterSign
	}
	return nil
}

func testProtocolXWithBehavior(t *testing.T, provisioneeBehavior int) (results [2]error) {

	timeout := testTimeout
	router := newMockRouterWithBehaviorAndMaxPoll(GoodRouter, timeout)

	s2 := genSecret(t)

	ch := make(chan error, 3)

	secretCh := make(chan Secret)

	ctx, cancelFn := context.WithCancel(context.Background())

	// Run the provisioner
	go func() {
		err := RunProvisioner(ProvisionerArg{
			KexBaseArg: KexBaseArg{
				Ctx:           ctx,
				Mr:            router,
				Secret:        genSecret(t),
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: secretCh,
				Timeout:       timeout,
			},
			Provisioner: newMockProvisioner(t),
		})
		ch <- err
	}()

	// Run the privisionee
	go func() {
		err := RunProvisionee(ProvisioneeArg{
			KexBaseArg: KexBaseArg{
				Ctx:           context.Background(),
				Mr:            router,
				Secret:        s2,
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: make(chan Secret),
				Timeout:       timeout,
			},
			Provisionee: newMockProvisionee(t, provisioneeBehavior),
		})
		ch <- err
	}()

	if (provisioneeBehavior & BadProvisioneeCancel) != 0 {
		go func() {
			time.Sleep(testTimeout / 2)
			cancelFn()
		}()
	}

	secretCh <- s2

	for i := 0; i < 2; i++ {
		if e, eof := <-ch; !eof {
			t.Fatalf("got unexpected channel close (try %d)", i)
		} else if e != nil {
			results[i] = e
		}
	}

	return results
}

func TestFullProtocolXSuccess(t *testing.T) {
	results := testProtocolXWithBehavior(t, GoodProvisionee)
	for i, e := range results {
		if e != nil {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

// Since errors are exported as strings, then we should just test that the
// right kind of error was specified
func eeq(e1, e2 error) bool {
	return e1 != nil && e1.Error() == e2.Error()
}

func TestFullProtocolXProvisioneeFailHello(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeFailHello)
	if !eeq(results[0], ErrHandleHello) {
		t.Fatalf("Bad error 0: %v", results[0])
	}
	if !eeq(results[1], ErrHandleHello) {
		t.Fatalf("Bad error 1: %v", results[1])
	}
}

func TestFullProtocolXProvisioneeFailDidCounterSign(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeFailDidCounterSign)
	if !eeq(results[0], ErrHandleDidCounterSign) {
		t.Fatalf("Bad error 0: %v", results[0])
	}
	if !eeq(results[1], ErrHandleDidCounterSign) {
		t.Fatalf("Bad error 1: %v", results[1])
	}
}

func TestFullProtocolXProvisioneeSlowHello(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeSlowHello)
	for i, e := range results {
		if !eeq(e, ErrTimedOut) && !eeq(e, io.EOF) && !eeq(e, ErrHelloTimeout) {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

func TestFullProtocolXProvisioneeSlowHelloWithCancel(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeSlowHello|BadProvisioneeCancel)
	for i, e := range results {
		if !eeq(e, ErrCanceled) && !eeq(e, io.EOF) {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

func TestFullProtocolXProvisioneeSlowDidCounterSign(t *testing.T) {
	results := testProtocolXWithBehavior(t, BadProvisioneeSlowDidCounterSign)
	for i, e := range results {
		if !eeq(e, ErrTimedOut) && !eeq(e, io.EOF) {
			t.Fatalf("Bad error %d: %v", i, e)
		}
	}
}

func TestFullProtocolY(t *testing.T) {

	timeout := time.Duration(60) * time.Second
	router := newMockRouterWithBehaviorAndMaxPoll(GoodRouter, timeout)

	s1 := genSecret(t)

	ch := make(chan error, 3)

	secretCh := make(chan Secret)

	// Run the provisioner
	go func() {
		err := RunProvisioner(ProvisionerArg{
			KexBaseArg: KexBaseArg{
				Ctx:           context.TODO(),
				Mr:            router,
				Secret:        s1,
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: make(chan Secret),
				Timeout:       timeout,
			},
			Provisioner: newMockProvisioner(t),
		})
		ch <- err
	}()

	// Run the provisionee
	go func() {
		err := RunProvisionee(ProvisioneeArg{
			KexBaseArg: KexBaseArg{
				Ctx:           context.TODO(),
				Mr:            router,
				Secret:        genSecret(t),
				DeviceID:      genKeybase1DeviceID(t),
				SecretChannel: secretCh,
				Timeout:       timeout,
			},
			Provisionee: newMockProvisionee(t, GoodProvisionee),
		})
		ch <- err
	}()

	secretCh <- s1

	for i := 0; i < 2; i++ {
		if e, eof := <-ch; !eof {
			t.Fatalf("got unexpected channel close (try %d)", i)
		} else if e != nil {
			t.Fatalf("Unexpected error (receive %d): %v", i, e)
		}
	}

}
<|endoftext|>