<commit_before>package integration

import (
	"bytes"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/docker/libcontainer"
	"github.com/docker/libcontainer/configs"
)

func TestExecPS(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)
	buffers, exitCode, err := runContainer(config, "", "ps")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	lines := strings.Split(buffers.Stdout.String(), "\n")
	if len(lines) < 2 {
		t.Fatalf("more than one process running for output %q", buffers.Stdout.String())
	}
	expected := `1 root     ps`
	actual := strings.Trim(lines[1], "\n ")
	if actual != expected {
		t.Fatalf("expected output %q but received %q", expected, actual)
	}
}

func TestIPCPrivate(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	l, err := os.Readlink("/proc/1/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	config := newTemplateConfig(rootfs)
	buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l {
		t.Fatalf("ipc link should be private to the conatiner but equals host %q %q", actual, l)
	}
}

func TestIPCHost(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	l, err := os.Readlink("/proc/1/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	config := newTemplateConfig(rootfs)
	i := getNamespaceIndex(config, "NEWIPC")
	config.Namespaces = append(config.Namespaces[:i], config.Namespaces[i+1:]...)
	buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l {
		t.Fatalf("ipc link not equal to host link %q %q", actual, l)
	}
}

func TestIPCJoinPath(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	l, err := os.Readlink("/proc/1/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	config := newTemplateConfig(rootfs)
	i := getNamespaceIndex(config, "NEWIPC")
	config.Namespaces[i].Path = "/proc/1/ns/ipc"

	buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l {
		t.Fatalf("ipc link not equal to host link %q %q", actual, l)
	}
}

func TestIPCBadPath(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)
	i := getNamespaceIndex(config, "NEWIPC")
	config.Namespaces[i].Path = "/proc/1/ns/ipcc"

	_, _, err = runContainer(config, "", "true")
	if err == nil {
		t.Fatal("container succeded with bad ipc path")
	}
}

func TestRlimit(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)
	out, _, err := runContainer(config, "", "/bin/sh", "-c", "ulimit -n")
	if err != nil {
		t.Fatal(err)
	}
	if limit := strings.TrimSpace(out.Stdout.String()); limit != "1024" {
		t.Fatalf("expected rlimit to be 1024, got %s", limit)
	}
}

func getNamespaceIndex(config *configs.Config, name string) int {
	for i, v := range config.Namespaces {
		if v.Name == name {
			return i
		}
	}
	return -1
}

func newTestRoot() (string, error) {
	dir, err := ioutil.TempDir("", "libcontainer")
	if err != nil {
		return "", err
	}
	if err := os.MkdirAll(dir, 0700); err != nil {
		return "", err
	}
	return dir, nil
}

func TestEnter(t *testing.T) {
	root, err := newTestRoot()
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)

	factory, err := libcontainer.New(root, []string{os.Args[0], "init", "--"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := factory.Create("test", config)
	if err != nil {
		t.Fatal(err)
	}
	defer container.Destroy()

	// Execute a first process in the container
	stdinR, stdinW, err := os.Pipe()
	if err != nil {
		t.Fatal(err)
	}

	var stdout, stdout2 bytes.Buffer

	pconfig := libcontainer.ProcessConfig{
		Args:   []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"},
		Stdin:  stdinR,
		Stdout: &stdout,
	}
	pid, err := container.StartProcess(&pconfig)
	stdinR.Close()
	defer stdinW.Close()
	if err != nil {
		t.Fatal(err)
	}

	process, err := os.FindProcess(pid)
	if err != nil {
		t.Fatal(err)
	}

	pconfig.Args = []string{"readlink", "/proc/self/ns/pid"}
	pconfig.Stdin = nil
	pconfig.Stdout = &stdout2

	pid2, err := container.StartProcess(&pconfig)
	if err != nil {
		t.Fatal(err)
	}

	process2, err := os.FindProcess(pid2)
	if err != nil {
		t.Fatal(err)
	}

	s, err := process2.Wait()
	if err != nil {
		t.Fatal(err)
	}
	if !s.Success() {
		t.Fatal(s.String())
	}

	stdinW.Close()
	s, err = process.Wait()
	if err != nil {
		t.Fatal(err)
	}
	if !s.Success() {
		t.Fatal(s.String())
	}

	// Check that both processes live in the same pidns
	pidns := string(stdout.Bytes())
	if err != nil {
		t.Fatal(err)
	}

	pidns2 := string(stdout2.Bytes())
	if err != nil {
		t.Fatal(err)
	}

	if pidns != pidns2 {
		t.Fatal("The second process isn't in the required pid namespace", pidns, pidns2)
	}
}
<commit_msg>integration: add test to check Pause and Resume operations<commit_after>package integration

import (
	"bytes"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/docker/libcontainer"
	"github.com/docker/libcontainer/configs"
)

func TestExecPS(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)
	buffers, exitCode, err := runContainer(config, "", "ps")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	lines := strings.Split(buffers.Stdout.String(), "\n")
	if len(lines) < 2 {
		t.Fatalf("more than one process running for output %q", buffers.Stdout.String())
	}
	expected := `1 root     ps`
	actual := strings.Trim(lines[1], "\n ")
	if actual != expected {
		t.Fatalf("expected output %q but received %q", expected, actual)
	}
}

func TestIPCPrivate(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	l, err := os.Readlink("/proc/1/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	config := newTemplateConfig(rootfs)
	buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l {
		t.Fatalf("ipc link should be private to the conatiner but equals host %q %q", actual, l)
	}
}

func TestIPCHost(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	l, err := os.Readlink("/proc/1/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	config := newTemplateConfig(rootfs)
	i := getNamespaceIndex(config, "NEWIPC")
	config.Namespaces = append(config.Namespaces[:i], config.Namespaces[i+1:]...)
	buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l {
		t.Fatalf("ipc link not equal to host link %q %q", actual, l)
	}
}

func TestIPCJoinPath(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	l, err := os.Readlink("/proc/1/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	config := newTemplateConfig(rootfs)
	i := getNamespaceIndex(config, "NEWIPC")
	config.Namespaces[i].Path = "/proc/1/ns/ipc"

	buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
	if err != nil {
		t.Fatal(err)
	}

	if exitCode != 0 {
		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
	}

	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l {
		t.Fatalf("ipc link not equal to host link %q %q", actual, l)
	}
}

func TestIPCBadPath(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)
	i := getNamespaceIndex(config, "NEWIPC")
	config.Namespaces[i].Path = "/proc/1/ns/ipcc"

	_, _, err = runContainer(config, "", "true")
	if err == nil {
		t.Fatal("container succeded with bad ipc path")
	}
}

func TestRlimit(t *testing.T) {
	if testing.Short() {
		return
	}

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)
	out, _, err := runContainer(config, "", "/bin/sh", "-c", "ulimit -n")
	if err != nil {
		t.Fatal(err)
	}
	if limit := strings.TrimSpace(out.Stdout.String()); limit != "1024" {
		t.Fatalf("expected rlimit to be 1024, got %s", limit)
	}
}

func getNamespaceIndex(config *configs.Config, name string) int {
	for i, v := range config.Namespaces {
		if v.Name == name {
			return i
		}
	}
	return -1
}

func newTestRoot() (string, error) {
	dir, err := ioutil.TempDir("", "libcontainer")
	if err != nil {
		return "", err
	}
	if err := os.MkdirAll(dir, 0700); err != nil {
		return "", err
	}
	return dir, nil
}

func TestEnter(t *testing.T) {
	if testing.Short() {
		return
	}
	root, err := newTestRoot()
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)

	factory, err := libcontainer.New(root, []string{os.Args[0], "init", "--"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := factory.Create("test", config)
	if err != nil {
		t.Fatal(err)
	}
	defer container.Destroy()

	// Execute a first process in the container
	stdinR, stdinW, err := os.Pipe()
	if err != nil {
		t.Fatal(err)
	}

	var stdout, stdout2 bytes.Buffer

	pconfig := libcontainer.ProcessConfig{
		Args:   []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"},
		Stdin:  stdinR,
		Stdout: &stdout,
	}
	pid, err := container.StartProcess(&pconfig)
	stdinR.Close()
	defer stdinW.Close()
	if err != nil {
		t.Fatal(err)
	}

	process, err := os.FindProcess(pid)
	if err != nil {
		t.Fatal(err)
	}

	pconfig.Args = []string{"readlink", "/proc/self/ns/pid"}
	pconfig.Stdin = nil
	pconfig.Stdout = &stdout2

	pid2, err := container.StartProcess(&pconfig)
	if err != nil {
		t.Fatal(err)
	}

	process2, err := os.FindProcess(pid2)
	if err != nil {
		t.Fatal(err)
	}

	s, err := process2.Wait()
	if err != nil {
		t.Fatal(err)
	}
	if !s.Success() {
		t.Fatal(s.String())
	}

	stdinW.Close()
	s, err = process.Wait()
	if err != nil {
		t.Fatal(err)
	}
	if !s.Success() {
		t.Fatal(s.String())
	}

	// Check that both processes live in the same pidns
	pidns := string(stdout.Bytes())
	if err != nil {
		t.Fatal(err)
	}

	pidns2 := string(stdout2.Bytes())
	if err != nil {
		t.Fatal(err)
	}

	if pidns != pidns2 {
		t.Fatal("The second process isn't in the required pid namespace", pidns, pidns2)
	}
}

func TestFreeze(t *testing.T) {
	if testing.Short() {
		return
	}
	root, err := newTestRoot()
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)

	rootfs, err := newRootFs()
	if err != nil {
		t.Fatal(err)
	}
	defer remove(rootfs)

	config := newTemplateConfig(rootfs)

	factory, err := libcontainer.New(root, []string{os.Args[0], "init", "--"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := factory.Create("test", config)
	if err != nil {
		t.Fatal(err)
	}
	defer container.Destroy()

	stdinR, stdinW, err := os.Pipe()
	if err != nil {
		t.Fatal(err)
	}

	pconfig := libcontainer.ProcessConfig{
		Args:  []string{"cat"},
		Stdin: stdinR,
	}
	pid, err := container.StartProcess(&pconfig)
	stdinR.Close()
	defer stdinW.Close()
	if err != nil {
		t.Fatal(err)
	}

	process, err := os.FindProcess(pid)
	if err != nil {
		t.Fatal(err)
	}

	if err := container.Pause(); err != nil {
		t.Fatal(err)
	}
	state, err := container.RunState()
	if err != nil {
		t.Fatal(err)
	}
	if state != configs.Paused {
		t.Fatal("Unexpected state: ", state)
	}
	if err := container.Resume(); err != nil {
		t.Fatal(err)
	}

	stdinW.Close()
	s, err := process.Wait()
	if err != nil {
		t.Fatal(err)
	}
	if !s.Success() {
		t.Fatal(s.String())
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"encoding/json"

	"github.com/lfq7413/tomato/rest"
	"github.com/lfq7413/tomato/types"
)

// FunctionsController ...
type FunctionsController struct {
	ObjectsController
}

// HandleCloudFunction ...
// @router /:functionName [post]
func (f *FunctionsController) HandleCloudFunction() {
	functionName := f.Ctx.Input.Param(":functionName")
	theFunction := rest.GetFunction(functionName)
	if theFunction == nil {
		// TODO 无效函数
		return
	}

	params := types.M{}
	if f.Ctx.Input.RequestBody != nil {
		err := json.Unmarshal(f.Ctx.Input.RequestBody, &params)
		if err != nil {
			// TODO 参数错误
			return
		}
	}

	f.Auth.IsMaster = true
	request := rest.RequestInfo{
		Auth:      f.Auth,
		NewObject: params,
	}
	resp := theFunction(request)

	f.Data["json"] = resp
	f.ServeJSON()

}

// Get ...
// @router / [get]
func (f *FunctionsController) Get() {
	f.ObjectsController.Get()
}

// Post ...
// @router / [post]
func (f *FunctionsController) Post() {
	f.ObjectsController.Post()
}

// Delete ...
// @router / [delete]
func (f *FunctionsController) Delete() {
	f.ObjectsController.Delete()
}

// Put ...
// @router / [put]
func (f *FunctionsController) Put() {
	f.ObjectsController.Put()
}
<commit_msg>重构 functions.go<commit_after>package controllers

import (
	"github.com/lfq7413/tomato/errs"
	"github.com/lfq7413/tomato/rest"
	"github.com/lfq7413/tomato/types"
)

// FunctionsController 处理 /functions 接口的请求
type FunctionsController struct {
	ObjectsController
}

// HandleCloudFunction 执行指定的云函数
// 返回数据格式如下：
// {
// 	"result":"func res"
// }
// @router /:functionName [post]
func (f *FunctionsController) HandleCloudFunction() {
	functionName := f.Ctx.Input.Param(":functionName")
	theFunction := rest.GetFunction(functionName)
	if theFunction == nil {
		f.Data["json"] = errs.ErrorMessageToMap(errs.ScriptFailed, "Invalid function.")
		f.ServeJSON()
		return
	}

	if f.JSONBody == nil {
		f.JSONBody = types.M{}
	}

	f.Auth.IsMaster = true
	request := rest.RequestInfo{
		Auth:      f.Auth,
		NewObject: f.JSONBody,
	}
	resp := theFunction(request)
	if resp == nil {
		f.Data["json"] = errs.ErrorMessageToMap(errs.ScriptFailed, "Call function fail.")
		f.ServeJSON()
		return
	}

	f.Data["json"] = resp
	f.ServeJSON()

}

// Get ...
// @router / [get]
func (f *FunctionsController) Get() {
	f.ObjectsController.Get()
}

// Post ...
// @router / [post]
func (f *FunctionsController) Post() {
	f.ObjectsController.Post()
}

// Delete ...
// @router / [delete]
func (f *FunctionsController) Delete() {
	f.ObjectsController.Delete()
}

// Put ...
// @router / [put]
func (f *FunctionsController) Put() {
	f.ObjectsController.Put()
}
<|endoftext|>


<commit_before>// This program creates an SDL window and renderer and takes in events using sdl.PeepEvents
package main

import (
	"fmt"
	"github.com/jackyb/go-sdl2/sdl"
	"os"
)

var winTitle string = "Go-SDL2 TestWaitEvent"
var winWidth, winHeight int = 800, 600
const pushTime uint32 = 1000 // number of milliseconds between event pushes

func main() {
	var window *sdl.Window
	var renderer *sdl.Renderer
	var event sdl.Event
	var running bool

	window = sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		winWidth, winHeight, sdl.WINDOW_SHOWN)
	if window == nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %s\n", sdl.GetError())
		os.Exit(1)
	}

	renderer = sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
	if renderer == nil {
		fmt.Fprintf(os.Stderr, "Failed to create renderer: %s\n", sdl.GetError())
		os.Exit(2)
	}

	var peepArray []sdl.Event = make([]sdl.Event, 2)
	peepArray[0] = &sdl.UserEvent{sdl.USEREVENT, sdl.GetTicks(), window.GetID(), 1331, nil, nil}
	peepArray[1] = &sdl.UserEvent{sdl.USEREVENT, sdl.GetTicks(), window.GetID(), 10101, nil, nil}

	running = true
	lastPushTime := sdl.GetTicks()
	for running {
		if lastPushTime + pushTime < sdl.GetTicks() {
			lastPushTime = sdl.GetTicks()
			sdl.PumpEvents()
			numEventsHandled := sdl.PeepEvents(peepArray, len(peepArray), sdl.ADDEVENT, sdl.FIRSTEVENT, sdl.LASTEVENT)
			if numEventsHandled < 0 {
				fmt.Printf("PeepEvents error: %s\n", sdl.GetError())
			} else {
				fmt.Printf("Successful push of %d events\n", numEventsHandled)
			}
		}

		for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				running = false
			case *sdl.MouseMotionEvent:
				fmt.Printf("[%d ms] MouseMotion\ttype:%d\tid:%d\tx:%d\ty:%d\txrel:%d\tyrel:%d\n",
					t.Timestamp, t.Type, t.Which, t.X, t.Y, t.XRel, t.YRel)
			case *sdl.MouseButtonEvent:
				fmt.Printf("[%d ms] MouseButton\ttype:%d\tid:%d\tx:%d\ty:%d\tbutton:%d\tstate:%d\n",
					t.Timestamp, t.Type, t.Which, t.X, t.Y, t.Button, t.State)
			case *sdl.MouseWheelEvent:
				fmt.Printf("[%d ms] MouseWheel\ttype:%d\tid:%d\tx:%d\ty:%d\n",
					t.Timestamp, t.Type, t.Which, t.X, t.Y)
			case *sdl.KeyUpEvent:
				fmt.Printf("[%d ms] Keyboard\ttype:%d\tsym:%c\tmodifiers:%d\tstate:%d\trepeat:%d\n",
					t.Timestamp, t.Type, t.Keysym.Sym, t.Keysym.Mod, t.State, t.Repeat)
			case *sdl.UserEvent:
				fmt.Printf("[%d ms] UserEvent\tcode:%d\n", t.Timestamp, t.Code)
			}
		}
		sdl.Delay(1000/30)
	}

	renderer.Destroy()
	window.Destroy()
}
<commit_msg>Fix comment in PeepEvents_add.go<commit_after>// This program creates an SDL window and renderer and pushes UserEvents using PeepEvents
package main

import (
	"fmt"
	"github.com/jackyb/go-sdl2/sdl"
	"os"
)

var winTitle string = "Go-SDL2 TestWaitEvent"
var winWidth, winHeight int = 800, 600
const pushTime uint32 = 1000 // number of milliseconds between event pushes

func main() {
	var window *sdl.Window
	var renderer *sdl.Renderer
	var event sdl.Event
	var running bool

	window = sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		winWidth, winHeight, sdl.WINDOW_SHOWN)
	if window == nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %s\n", sdl.GetError())
		os.Exit(1)
	}

	renderer = sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
	if renderer == nil {
		fmt.Fprintf(os.Stderr, "Failed to create renderer: %s\n", sdl.GetError())
		os.Exit(2)
	}

	var peepArray []sdl.Event = make([]sdl.Event, 2)
	peepArray[0] = &sdl.UserEvent{sdl.USEREVENT, sdl.GetTicks(), window.GetID(), 1331, nil, nil}
	peepArray[1] = &sdl.UserEvent{sdl.USEREVENT, sdl.GetTicks(), window.GetID(), 10101, nil, nil}

	running = true
	lastPushTime := sdl.GetTicks()
	for running {
		if lastPushTime + pushTime < sdl.GetTicks() {
			lastPushTime = sdl.GetTicks()
			sdl.PumpEvents()
			numEventsHandled := sdl.PeepEvents(peepArray, len(peepArray), sdl.ADDEVENT, sdl.FIRSTEVENT, sdl.LASTEVENT)
			if numEventsHandled < 0 {
				fmt.Printf("PeepEvents error: %s\n", sdl.GetError())
			} else {
				fmt.Printf("Successful push of %d events\n", numEventsHandled)
			}
		}

		for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				running = false
			case *sdl.MouseMotionEvent:
				fmt.Printf("[%d ms] MouseMotion\ttype:%d\tid:%d\tx:%d\ty:%d\txrel:%d\tyrel:%d\n",
					t.Timestamp, t.Type, t.Which, t.X, t.Y, t.XRel, t.YRel)
			case *sdl.MouseButtonEvent:
				fmt.Printf("[%d ms] MouseButton\ttype:%d\tid:%d\tx:%d\ty:%d\tbutton:%d\tstate:%d\n",
					t.Timestamp, t.Type, t.Which, t.X, t.Y, t.Button, t.State)
			case *sdl.MouseWheelEvent:
				fmt.Printf("[%d ms] MouseWheel\ttype:%d\tid:%d\tx:%d\ty:%d\n",
					t.Timestamp, t.Type, t.Which, t.X, t.Y)
			case *sdl.KeyUpEvent:
				fmt.Printf("[%d ms] Keyboard\ttype:%d\tsym:%c\tmodifiers:%d\tstate:%d\trepeat:%d\n",
					t.Timestamp, t.Type, t.Keysym.Sym, t.Keysym.Mod, t.State, t.Repeat)
			case *sdl.UserEvent:
				fmt.Printf("[%d ms] UserEvent\tcode:%d\n", t.Timestamp, t.Code)
			}
		}
		sdl.Delay(1000/30)
	}

	renderer.Destroy()
	window.Destroy()
}
<|endoftext|>


<commit_before>package config

// Config package contains the public config vars required in guble

import (
	log "github.com/Sirupsen/logrus"
	"gopkg.in/alecthomas/kingpin.v2"

	"net"
	"runtime"
	"strconv"
)

const (
	defaultHttpListen     = ":8080"
	defaultHealthEndpoint = "/_health"
	defaultStoragePath    = "/var/lib/guble"
	defaultNodePort       = "10000"
	defaultKVBackend      = "file"
	defaultMSBackend      = "file"
)

var (
	HttpListen = kingpin.Flag("http", `The address to for the HTTP server to listen on (format: "[Host]:Port")`).
			Default(defaultHttpListen).Envar("GUBLE_HTTP_LISTEN").String()
	KVS = kingpin.Flag("kvs", "The storage backend for the key-value store to use : file | memory").
		Default(defaultKVBackend).HintOptions([]string{"file", "memory"}...).Envar("GUBLE_KVS").String()
	MS = kingpin.Flag("ms", "The message storage backend : file | memory").
		Default(defaultMSBackend).HintOptions([]string{"file", "memory"}...).Envar("GUBLE_MS").String()
	StoragePath = kingpin.Flag("storage-path", "The path for storing messages and key-value data if 'file' is selected").
			Default(defaultStoragePath).Envar("GUBLE_STORAGE_PATH").String()
	HealthEndpoint = kingpin.Flag("health-endpoint", `The health endpoint to be used by the HTTP server (value for disabling it: "")`).
			Default(defaultHealthEndpoint).Envar("GUBLE_HEALTH_ENDPOINT").String()

	Metrics = struct {
		Enabled  *bool
		Endpoint *string
	}{
		Enabled: kingpin.Flag("metrics", "Enable collection of metrics").
			Default("false").Envar("GUBLE_METRICS").Bool(),
		Endpoint: kingpin.Flag("metrics-endpoint", `The metrics endpoint to be used by the HTTP server (disabled by default; a possible value for enabling it: "/_metrics" )`).
			Default("").Envar("GUBLE_METRICS_ENDPOINT").String(),
	}

	// GCM settings related to activating the GCM connector module
	GCM = struct {
		Enabled *bool
		APIKey  *string
		Workers *int
	}{
		Enabled: kingpin.Flag("gcm", "Enable the Google Cloud Messaging Connector").
			Envar("GUBLE_GCM").Bool(),
		APIKey: kingpin.Flag("gcm-api-key", "The Google API Key for Google Cloud Messaging").
			Envar("GUBLE_GCM_API_KEY").String(),
		Workers: kingpin.Flag("gcm-workers", "The number of workers handling traffic with Google Cloud Messaging (default: GOMAXPROCS)").
			Default(strconv.Itoa(runtime.GOMAXPROCS(0))).Envar("GUBLE_GCM_WORKERS").Int(),
	}

	// Cluster settings related to activating the cluster module
	Cluster = struct {
		NodeID   *int
		NodePort *int
		Remotes  *[]*net.TCPAddr
	}{
		NodeID: kingpin.Flag("node-id", "This guble node's own ID (used in cluster mode): a strictly positive integer number which must be unique in cluster").
			Default("0").Envar("GUBLE_NODE_ID").Int(),
		NodePort: kingpin.Flag("node-port", "This guble node's own local port (used in cluster mode): a strictly positive integer number").
			Default(defaultNodePort).Envar("GUBLE_NODE_PORT").Int(),
		Remotes: kingpin.Arg("tcplist", `The list of TCP addresses of some other guble nodes (used in cluster mode; format: "IP:port")`).
			TCPList(),
	}

	// Log level
	Log = kingpin.Flag("log", "Log level").
		Default(log.ErrorLevel.String()).
		Envar("GUBLE_LOG").
		Enum(logLevels()...)

	parsed = false
)

func logLevels() (levels []string) {
	for _, level := range log.AllLevels {
		levels = append(levels, level.String())
	}
	return
}

// Parse parses the flags from command line. Must be used before accessing the config.
// If there are missing or invalid arguments it will exit the application and display a
// corresponding message
func Parse() {
	if parsed {
		return
	}
	kingpin.Parse()
	parsed = true
}
<commit_msg>gubled: refactoring in config; consts; messages<commit_after>package config

// Config package contains the public config vars required in guble

import (
	log "github.com/Sirupsen/logrus"
	"gopkg.in/alecthomas/kingpin.v2"

	"net"
	"runtime"
	"strconv"
)

const (
	defaultHttpListen     = ":8080"
	defaultHealthEndpoint = "/_health"
	defaultKVSBackend     = "file"
	defaultMSBackend      = "file"
	defaultStoragePath    = "/var/lib/guble"
	defaultNodeID         = "0"
	defaultNodePort       = "10000"
)

var (
	HttpListen = kingpin.Flag("http", `The address to for the HTTP server to listen on (format: "[Host]:Port")`).
			Default(defaultHttpListen).Envar("GUBLE_HTTP_LISTEN").String()
	KVS = kingpin.Flag("kvs", "The storage backend for the key-value store to use : file | memory").
		Default(defaultKVSBackend).HintOptions([]string{"file", "memory"}...).Envar("GUBLE_KVS").String()
	MS = kingpin.Flag("ms", "The message storage backend : file | memory").
		Default(defaultMSBackend).HintOptions([]string{"file", "memory"}...).Envar("GUBLE_MS").String()
	StoragePath = kingpin.Flag("storage-path", "The path for storing messages and key-value data if 'file' is selected").
			Default(defaultStoragePath).Envar("GUBLE_STORAGE_PATH").String()
	HealthEndpoint = kingpin.Flag("health-endpoint", `The health endpoint to be used by the HTTP server (value for disabling it: "")`).
			Default(defaultHealthEndpoint).Envar("GUBLE_HEALTH_ENDPOINT").String()

	Metrics = struct {
		Enabled  *bool
		Endpoint *string
	}{
		Enabled: kingpin.Flag("metrics", "Enable collection of metrics").Envar("GUBLE_METRICS").Bool(),
		Endpoint: kingpin.Flag("metrics-endpoint", `The metrics endpoint to be used by the HTTP server (disabled by default; a possible value for enabling it: "/_metrics" )`).
			Default("").Envar("GUBLE_METRICS_ENDPOINT").String(),
	}

	// GCM settings related to activating the GCM connector module
	GCM = struct {
		Enabled *bool
		APIKey  *string
		Workers *int
	}{
		Enabled: kingpin.Flag("gcm", "Enable the Google Cloud Messaging Connector").
			Envar("GUBLE_GCM").Bool(),
		APIKey: kingpin.Flag("gcm-api-key", "The Google API Key for Google Cloud Messaging").
			Envar("GUBLE_GCM_API_KEY").String(),
		Workers: kingpin.Flag("gcm-workers", "The number of workers handling traffic with Google Cloud Messaging (default: GOMAXPROCS)").
			Default(strconv.Itoa(runtime.GOMAXPROCS(0))).Envar("GUBLE_GCM_WORKERS").Int(),
	}

	// Cluster settings related to activating the cluster module
	Cluster = struct {
		NodeID   *int
		NodePort *int
		Remotes  *[]*net.TCPAddr
	}{
		NodeID: kingpin.Flag("node-id", "(cluster mode) This guble node's own ID: a strictly positive integer number which must be unique in cluster").
			Default(defaultNodeID).Envar("GUBLE_NODE_ID").Int(),
		NodePort: kingpin.Flag("node-port", "(cluster mode) This guble node's own local port: a strictly positive integer number").
			Default(defaultNodePort).Envar("GUBLE_NODE_PORT").Int(),
		Remotes: kingpin.Arg("tcplist", `(cluster mode) The list of TCP addresses of some other guble nodes (format: "IP:port")`).
			TCPList(),
	}

	// Log level
	Log = kingpin.Flag("log", "Log level").
		Default(log.ErrorLevel.String()).
		Envar("GUBLE_LOG").
		Enum(logLevels()...)

	parsed = false
)

func logLevels() (levels []string) {
	for _, level := range log.AllLevels {
		levels = append(levels, level.String())
	}
	return
}

// Parse parses the flags from command line. Must be used before accessing the config.
// If there are missing or invalid arguments it will exit the application and display a
// corresponding message
func Parse() {
	if parsed {
		return
	}
	kingpin.Parse()
	parsed = true
}
<|endoftext|>


<commit_before>// Copyright 2019 The SQLFlow Authors. 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 sql

import (
	"text/template"
)

const analyzeTemplateText = `
import xgboost
import shap
import matplotlib.pyplot as plt
import pandas as pd

from sqlflow_submitter.db import connect, db_generator

shap.initjs()

# 1. read data
driver = "{{.Driver}}"
feature_names = [{{ range $value := .X }} "{{$value.FeatureName}}", {{end}}]
feature_metas = {}
{{ range $value := .X }}
feature_metas["{{$value.FeatureName}}"] = {
    "feature_name": "{{$value.FeatureName}}",
    "dtype": "{{$value.Dtype}}",
    "delimiter": "{{$value.Delimiter}}",
    "shape": {{$value.InputShape}},
    "is_sparse": "{{$value.IsSparse}}" == "true"
}
{{end}}

label_name = "{{.Label}}"
database = ""
{{if ne .Database ""}}
database = "{{.Database}}"
{{end}}
session_cfg = {}
{{ range $k, $v := .Session }}
session_cfg["{{$k}}"] = "{{$v}}"
{{end}}

conn = connect(driver, database, user="{{.User}}", password="{{.Password}}", host="{{.Host}}", port={{.Port}}, auth="{{.Auth}}")

def analyzer_dataset():
    stream = db_generator(driver, conn, session_cfg, """{{.AnalyzeDatasetSQL}}""", feature_names, label_name, feature_metas)
    xs = pd.DataFrame(columns=feature_names)
    ys = pd.DataFrame(columns=[label_name])
    i = 0
    for row in stream():
        xs.loc[i] = row[0]
        ys.loc[i] = row[1]
        i += 1
    return xs, ys

# 2. load the model
model_path = "{{.ModelFile}}"

summaryAttrs = {}
{{ range $k, $v := .ShapSummaryParames }}
summaryAttrs["{{$k}}"] = {{$v}}
{{end}}

X,y = analyzer_dataset()

bst = xgboost.Booster()
bst.load_model(fname=model_path)
explainer = shap.TreeExplainer(bst)
shap_values = explainer.shap_values(X)

shap.summary_plot(shap_values, X, **summaryAttrs)
plt.savefig('summary')
`

var analyzeTemplate = template.Must(template.New("analyzeTemplate").Parse(analyzeTemplateText))
<commit_msg>control image size for analyze result (#812)<commit_after>// Copyright 2019 The SQLFlow Authors. 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 sql

import (
	"text/template"
)

const analyzeTemplateText = `
import xgboost
import shap
import matplotlib.pyplot as plt
import pandas as pd

from sqlflow_submitter.db import connect, db_generator

shap.initjs()

# 1. read data
driver = "{{.Driver}}"
feature_names = [{{ range $value := .X }} "{{$value.FeatureName}}", {{end}}]
feature_metas = {}
{{ range $value := .X }}
feature_metas["{{$value.FeatureName}}"] = {
    "feature_name": "{{$value.FeatureName}}",
    "dtype": "{{$value.Dtype}}",
    "delimiter": "{{$value.Delimiter}}",
    "shape": {{$value.InputShape}},
    "is_sparse": "{{$value.IsSparse}}" == "true"
}
{{end}}

label_name = "{{.Label}}"
database = ""
{{if ne .Database ""}}
database = "{{.Database}}"
{{end}}
session_cfg = {}
{{ range $k, $v := .Session }}
session_cfg["{{$k}}"] = "{{$v}}"
{{end}}

conn = connect(driver, database, user="{{.User}}", password="{{.Password}}", host="{{.Host}}", port={{.Port}}, auth="{{.Auth}}")

def analyzer_dataset():
    stream = db_generator(driver, conn, session_cfg, """{{.AnalyzeDatasetSQL}}""", feature_names, label_name, feature_metas)
    xs = pd.DataFrame(columns=feature_names)
    ys = pd.DataFrame(columns=[label_name])
    i = 0
    for row in stream():
        xs.loc[i] = row[0]
        ys.loc[i] = row[1]
        i += 1
    return xs, ys

# 2. load the model
model_path = "{{.ModelFile}}"

summaryAttrs = {}
{{ range $k, $v := .ShapSummaryParames }}
summaryAttrs["{{$k}}"] = {{$v}}
{{end}}

X,y = analyzer_dataset()

bst = xgboost.Booster()
bst.load_model(fname=model_path)
explainer = shap.TreeExplainer(bst)
shap_values = explainer.shap_values(X)

shap.summary_plot(shap_values, X, show=False, **summaryAttrs)
plt.savefig('summary', bbox_inches='tight')
`

var analyzeTemplate = template.Must(template.New("analyzeTemplate").Parse(analyzeTemplateText))
<|endoftext|>


<commit_before>package interfaces

import "github.com/rcrowley/go-metrics"

type Statistics interface {
	GetStatistics() (metrics.Registry, error)
}
<commit_msg>gometalinter: rqlite/interfaces<commit_after>package interfaces

import "github.com/rcrowley/go-metrics"

// Statistics is an interface for metrics statistics
type Statistics interface {
	GetStatistics() (metrics.Registry, error)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strings"
	"testing"
)

func chkGood(t *testing.T, char string, tell string, good string, txt []string) {
	if len(txt) == 1 {
		if txt[0] != good {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
				char, tell, txt[0])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}
}

func Test_ReplyTo(t *testing.T) {
	f, err := os.OpenFile("logs/test.log", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0640)
	defer f.Close()
	ChkErr(err)
	log.SetOutput(f)

	char, tell := "Yog", "blah"
	txt := ReplyTo(char, tell)
	good := "Invalid syntax. For valid syntax: tell katumi ?, " +
		"tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "?"
	txt = ReplyTo(char, tell)
	good = "I am a Helper Bot (Beta). Valid commands: " +
		"?, help <cmd>, hidden?, who <char>, char <char>, clist <char>, " +
		"find <char>, class <class>, delalt <char>, addalt <char>, " +
		"lr, lr <report>, stat <item>, astat <item>, fstat <att> <comp> <val>. " +
		"For further information, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "help"
	txt = ReplyTo(char, tell)
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "hidden"
	txt = ReplyTo(char, tell)
	good = "Yog is NOT hidden!"
	chkGood(t, char, tell, good, txt)

	char, tell = "Someone", "hidden"
	txt = ReplyTo(char, tell)
	if len(txt) > 0 {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %v", char, tell, txt)
	}

	char, tell = "Yog", "who blah"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "who bonble"
	txt = ReplyTo(char, tell)
	good = "@Nyyrazzilyss: Nyyrazzilyss, Bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "char Blah"
	txt = ReplyTo(char, tell)
	good = "404 character not found: Blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "char bonble"
	txt = ReplyTo(char, tell)
	good = "[5 Bard] Bonble (Halfling) (@Nyyrazzilyss) seen 2013-04-13 10:00:24"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "clist bonble"
	txt = ReplyTo(char, tell)
	good = "[50 Psionicist] Nyyrazzilyss (Illithid) (@Nyyrazzilyss) seen 2013-04-13 09:59:24"
	if len(txt) == 2 {
		if txt[0] != good {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[0])
		}
		good = "[5 Bard] Bonble (Halfling) (@Nyyrazzilyss) seen 2013-04-13 10:00:24"
		if txt[1] != good {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[1])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}

	char, tell = "Yog", "clist blah"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr"
	txt = ReplyTo(char, tell)
	good = "1: ancient brass dragon in DT [Omgiso at 2013-04-13 04:02:33]"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr blah"
	txt = ReplyTo(char, tell)
	good = "Invalid syntax. For valid syntax: tell katumi ?, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr thing at place"
	txt = ReplyTo(char, tell)
	good = "Load reported: thing at place"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr"
	txt = ReplyTo(char, tell)
	good = "2: thing at place [Yog at 20"
	if len(txt) == 2 {
		if !strings.Contains(txt[1], good) {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[1])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}

	char, tell = "Yog", "lrdel 2"
	txt = ReplyTo(char, tell)
	good = "Load deleted: thing at place"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lrdel 3"
	txt = ReplyTo(char, tell)
	good = "Invalid load report number."
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lrdel blah"
	txt = ReplyTo(char, tell)
	good = "Invalid syntax. For valid syntax: tell katumi ?, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "find bonble"
	txt = ReplyTo(char, tell)
	good = "@Nyyrazzilyss last seen"
	if len(txt) == 1 {
		if !strings.Contains(txt[0], good) {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[0])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}

	char, tell = "Yog", "find blah"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "delalt bonble"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Bonble", "delalt bonble"
	txt = ReplyTo(char, tell)
	good = "Removed character from your alt list:: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Bonble", "who bonble"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "addalt bonble"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Bonble", "addalt bonble"
	txt = ReplyTo(char, tell)
	good = "Re-added character to your alt list:: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "help ?"
	txt = ReplyTo(char, tell)
	good = "Syntax: tell katumi ? -- Katumi provides a full listing of valid commands."
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "help blah"
	txt = ReplyTo(char, tell)
	good = "404 help file not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "stat bane stiletto"
	txt = ReplyTo(char, tell)
	good = "the infernal stiletto of bane (Wield) Dam:4 Hit:5 Haste Slow_Poi " +
		"* (Weapon) Dice:4D4 * Procs: 'Dragonblind' effect: blind, 3 charge - " +
		"'Dragonpoison' effect: poison, 1 charge - 'Dragonslow' effect: slow, 2 charge - " +
		"'Dragonstrike' effect: instant kill, 5 charge * Float Magic No_Burn No_Loc !Fighter " +
		"!Mage !Priest * Wt:5 Val:0 * Zone: Tiamat (R) * Last ID: 2006-01-16"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "stat blah"
	txt = ReplyTo(char, tell)
	good = "404 item not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "astat destruction sword"
	txt = ReplyTo(char, tell)
	good = "a black longsword of destruction (Wielded), Damroll: 8, Hitroll: 5, " +
		"Fire: 5%, Infravision (Item Type: Weapon) Damage Dice: 8D6 * " +
		"Procs: Battle Rage * Float, Magic, No Burn, No Drop, No Locate, Two Handed " +
		"NO-MAGE ANTI-PALADIN NO-CLERIC ANTI-RANGER NO-THIEF * " +
		"Keywords:(black sword destruction twilight) * Weight: 15, Value: 10,000 copper " +
		"* Zone: Jotunheim (From Invasion) * Last ID: 2008-04-05"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "astat blah"
	txt = ReplyTo(char, tell)
	good = "404 item not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "fstat resist fire, maxagi > 0, slot ear"
	txt = ReplyTo(char, tell)
	good = "a tiny mithril stud set with a ruby (Ear) Dam:3 Maxagi:3 Fire:5% " +
		"* No_Burn * Wt:0 Val:501,000 * Zone: SP (Q) * Last ID: 2011-05-12"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "fstat blah"
	txt = ReplyTo(char, tell)
	good = "Invalid syntax. For valid syntax: tell katumi ?, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "fstat resist blah"
	txt = ReplyTo(char, tell)
	good = "404 item(s) not found: resist blah"
	chkGood(t, char, tell, good, txt)
}
<commit_msg>Add date check, though tzone weirdness continues<commit_after>package main

import (
	"log"
	"os"
	"strings"
	"testing"
	"time"
)

func chkGood(t *testing.T, char string, tell string, good string, txt []string) {
	if len(txt) == 1 {
		if txt[0] != good {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
				char, tell, txt[0])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}
}

func Test_ReplyTo(t *testing.T) {
	f, err := os.OpenFile("logs/test.log", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0640)
	defer f.Close()
	ChkErr(err)
	log.SetOutput(f)

	date := time.Now().UTC().String()
	date = date[:13]

	char, tell := "Yog", "blah"
	txt := ReplyTo(char, tell)
	good := "Invalid syntax. For valid syntax: tell katumi ?, " +
		"tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "?"
	txt = ReplyTo(char, tell)
	good = "I am a Helper Bot (Beta). Valid commands: " +
		"?, help <cmd>, hidden?, who <char>, char <char>, clist <char>, " +
		"find <char>, class <class>, delalt <char>, addalt <char>, " +
		"lr, lr <report>, stat <item>, astat <item>, fstat <att> <comp> <val>. " +
		"For further information, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "help"
	txt = ReplyTo(char, tell)
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "hidden"
	txt = ReplyTo(char, tell)
	good = "Yog is NOT hidden!"
	chkGood(t, char, tell, good, txt)

	char, tell = "Someone", "hidden"
	txt = ReplyTo(char, tell)
	if len(txt) > 0 {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %v", char, tell, txt)
	}

	char, tell = "Yog", "who blah"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "who bonble"
	txt = ReplyTo(char, tell)
	good = "@Nyyrazzilyss: Nyyrazzilyss, Bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "char Blah"
	txt = ReplyTo(char, tell)
	good = "404 character not found: Blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "char bonble"
	txt = ReplyTo(char, tell)
	good = "[5 Bard] Bonble (Halfling) (@Nyyrazzilyss) seen 2013-04-13 10:00:24"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "clist bonble"
	txt = ReplyTo(char, tell)
	good = "[50 Psionicist] Nyyrazzilyss (Illithid) (@Nyyrazzilyss) seen 2013-04-13 09:59:24"
	if len(txt) == 2 {
		if txt[0] != good {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[0])
		}
		good = "[5 Bard] Bonble (Halfling) (@Nyyrazzilyss) seen 2013-04-13 10:00:24"
		if txt[1] != good {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[1])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}

	char, tell = "Yog", "clist blah"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr"
	txt = ReplyTo(char, tell)
	good = "1: ancient brass dragon in DT [Omgiso at 2013-04-13 04:02:33]"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr blah"
	txt = ReplyTo(char, tell)
	good = "Invalid syntax. For valid syntax: tell katumi ?, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr thing at place"
	txt = ReplyTo(char, tell)
	good = "Load reported: thing at place"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lr"
	txt = ReplyTo(char, tell)
	good = "2: thing at place [Yog at " + date
	if len(txt) == 2 {
		if !strings.Contains(txt[1], good) {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[1])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}

	char, tell = "Yog", "lrdel 2"
	txt = ReplyTo(char, tell)
	good = "Load deleted: thing at place"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lrdel 3"
	txt = ReplyTo(char, tell)
	good = "Invalid load report number."
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "lrdel blah"
	txt = ReplyTo(char, tell)
	good = "Invalid syntax. For valid syntax: tell katumi ?, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "find bonble"
	txt = ReplyTo(char, tell)
	good = "@Nyyrazzilyss last seen"
	if len(txt) == 1 {
		if !strings.Contains(txt[0], good) {
			t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s", char, tell, txt[0])
		}
	} else {
		t.Errorf("ReplyTo Check failed: %s tells you '%s' Actual response: %s",
			char, tell, "Incorrect number of responses!")
	}

	char, tell = "Yog", "find blah"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "delalt bonble"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Bonble", "delalt bonble"
	txt = ReplyTo(char, tell)
	good = "Removed character from your alt list:: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Bonble", "who bonble"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "addalt bonble"
	txt = ReplyTo(char, tell)
	good = "404 character or account not found: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Bonble", "addalt bonble"
	txt = ReplyTo(char, tell)
	good = "Re-added character to your alt list:: bonble"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "help ?"
	txt = ReplyTo(char, tell)
	good = "Syntax: tell katumi ? -- Katumi provides a full listing of valid commands."
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "help blah"
	txt = ReplyTo(char, tell)
	good = "404 help file not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "stat bane stiletto"
	txt = ReplyTo(char, tell)
	good = "the infernal stiletto of bane (Wield) Dam:4 Hit:5 Haste Slow_Poi " +
		"* (Weapon) Dice:4D4 * Procs: 'Dragonblind' effect: blind, 3 charge - " +
		"'Dragonpoison' effect: poison, 1 charge - 'Dragonslow' effect: slow, 2 charge - " +
		"'Dragonstrike' effect: instant kill, 5 charge * Float Magic No_Burn No_Loc !Fighter " +
		"!Mage !Priest * Wt:5 Val:0 * Zone: Tiamat (R) * Last ID: 2006-01-16"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "stat blah"
	txt = ReplyTo(char, tell)
	good = "404 item not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "astat destruction sword"
	txt = ReplyTo(char, tell)
	good = "a black longsword of destruction (Wielded), Damroll: 8, Hitroll: 5, " +
		"Fire: 5%, Infravision (Item Type: Weapon) Damage Dice: 8D6 * " +
		"Procs: Battle Rage * Float, Magic, No Burn, No Drop, No Locate, Two Handed " +
		"NO-MAGE ANTI-PALADIN NO-CLERIC ANTI-RANGER NO-THIEF * " +
		"Keywords:(black sword destruction twilight) * Weight: 15, Value: 10,000 copper " +
		"* Zone: Jotunheim (From Invasion) * Last ID: 2008-04-05"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "astat blah"
	txt = ReplyTo(char, tell)
	good = "404 item not found: blah"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "fstat resist fire, maxagi > 0, slot ear"
	txt = ReplyTo(char, tell)
	good = "a tiny mithril stud set with a ruby (Ear) Dam:3 Maxagi:3 Fire:5% " +
		"* No_Burn * Wt:0 Val:501,000 * Zone: SP (Q) * Last ID: 2011-05-12"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "fstat blah"
	txt = ReplyTo(char, tell)
	good = "Invalid syntax. For valid syntax: tell katumi ?, tell katumi help <cmd>"
	chkGood(t, char, tell, good, txt)

	char, tell = "Yog", "fstat resist blah"
	txt = ReplyTo(char, tell)
	good = "404 item(s) not found: resist blah"
	chkGood(t, char, tell, good, txt)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"time"

	"github.com/brutella/gouvr/uvr"
	"github.com/brutella/gouvr/uvr/1611"
	"github.com/brutella/hc/hap"
	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
	"github.com/brutella/hkuvr1611"
	"github.com/brutella/log"

	"github.com/brutella/hkuvr1611/gpio"
	"github.com/brutella/hkuvr1611/mock"
)

func HandlePacket(p uvr1611.Packet) []*accessory.Accessory {
	var sensors []*accessory.Accessory
	inputs := hkuvr1611.InputValuesFromPacket(p)
	for i, v := range inputs {
		s := HandleInputValueWithName(v, fmt.Sprintf("Sensor %d", i+1))
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	outlets := uvr1611.OutletsFromValue(p.Outgoing)
	for i, v := range outlets {
		s := HandleOutletWithName(v, fmt.Sprintf("Outlet %d", i+1))
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	h1, h2 := uvr1611.AreHeatMetersEnabled(p.HeatRegister)
	if h1 == true {
		s := HandleHeatMeterWithName(p.HeatMeter1, "Heat Meter 1")
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	if h2 == true {
		s := HandleHeatMeterWithName(p.HeatMeter2, "Heat Meter 2")
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	return sensors
}

func HandleInputValueWithName(v uvr.Value, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForInputValue(v, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithInputValue(s.Model, v)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}
	return s
}

func HandleOutletWithName(o uvr1611.Outlet, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForOutlet(o, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithOutlet(s.Model, o)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}

	return s
}

func HandleHeatMeterWithName(hm uvr.HeatMeterValue, name string) (s *hkuvr1611.Sensor) {
	return nil
}

func InfoForAccessoryName(name string) model.Info {
	info := model.Info{
		Name:         name,
		Manufacturer: "TA",
		Model:        "UVR1611",
	}

	return info
}

// Access to HAP app
var transport hap.Transport
var uvrAccessory *accessory.Accessory

// List of sensors
var sensors map[string]*hkuvr1611.Sensor

// Timer to remove not reachable accessories
var timer *time.Timer

type Connection interface {
	Close()
}

// This app can connect to the UVR1611 data bus and provide the sensor values to HomeKit clients
//
// Optimizations: To improve the performance on a Raspberry Pi B+, the interrupt handler of the
// gpio pin is removed every time after successfully decoding a packet. This allows other goroutines
// (e.g. HAP server) to do their job more quickly.
func main() {

	var (
		pin     = flag.String("pin", "", "Accessory pin required for pairing")
		mode    = flag.String("conn", "mock", "Connection type; mock, gpio, replay")
		file    = flag.String("file", "", "Log file from which to replay packets")
		port    = flag.String("port", "P8_07", "GPIO port; default P8_07")
		timeout = flag.Int("timeout", 120, "Timeout in seconds until accessories are not reachable")
	)

	flag.Parse()
	sensors = map[string]*hkuvr1611.Sensor{}

	info := InfoForAccessoryName("UVR1611")
	uvrAccessory = accessory.New(info)

	timer_duration := time.Duration(*timeout) * time.Second
	timer = time.AfterFunc(timer_duration, func() {
		log.Println("[INFO] Not Reachable")
		if transport != nil {
			sensors = map[string]*hkuvr1611.Sensor{}
			transport.Stop()
			transport = nil
		}
	})

	var conn Connection
	callback := func(packet uvr1611.Packet) {
		sensors := HandlePacket(packet)
		if transport == nil {
			config := hap.Config{Pin: *pin}
			if t, err := hap.NewIPTransport(config, uvrAccessory, sensors...); err != nil {
				log.Fatal(err)
			} else {
				go func() {
					t.Start()
				}()
				transport = t
			}
		}
		timer.Reset(timer_duration)
	}

	switch *mode {
	case "mock":
		conn = mock.NewConnection(callback)
	case "replay":
		conn = mock.NewReplayConnection(*file, callback)
	case "gpio":
		conn = gpio.NewConnection(*port, callback)
	default:
		log.Fatal("Incorrect -conn flag")
	}

	hap.OnTermination(func() {
		if transport != nil {
			transport.Stop()
		}
		conn.Close()
		timer.Stop()
		os.Exit(1)
	})

	select {}
}
<commit_msg>Specify accessory type<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"time"

	"github.com/brutella/gouvr/uvr"
	"github.com/brutella/gouvr/uvr/1611"
	"github.com/brutella/hc/hap"
	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
	"github.com/brutella/hkuvr1611"
	"github.com/brutella/log"

	"github.com/brutella/hkuvr1611/gpio"
	"github.com/brutella/hkuvr1611/mock"
)

func HandlePacket(p uvr1611.Packet) []*accessory.Accessory {
	var sensors []*accessory.Accessory
	inputs := hkuvr1611.InputValuesFromPacket(p)
	for i, v := range inputs {
		s := HandleInputValueWithName(v, fmt.Sprintf("Sensor %d", i+1))
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	outlets := uvr1611.OutletsFromValue(p.Outgoing)
	for i, v := range outlets {
		s := HandleOutletWithName(v, fmt.Sprintf("Outlet %d", i+1))
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	h1, h2 := uvr1611.AreHeatMetersEnabled(p.HeatRegister)
	if h1 == true {
		s := HandleHeatMeterWithName(p.HeatMeter1, "Heat Meter 1")
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	if h2 == true {
		s := HandleHeatMeterWithName(p.HeatMeter2, "Heat Meter 2")
		if s != nil {
			sensors = append(sensors, s.Accessory)
		}
	}

	return sensors
}

func HandleInputValueWithName(v uvr.Value, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForInputValue(v, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithInputValue(s.Model, v)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}
	return s
}

func HandleOutletWithName(o uvr1611.Outlet, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForOutlet(o, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithOutlet(s.Model, o)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}

	return s
}

func HandleHeatMeterWithName(hm uvr.HeatMeterValue, name string) (s *hkuvr1611.Sensor) {
	return nil
}

func InfoForAccessoryName(name string) model.Info {
	info := model.Info{
		Name:         name,
		Manufacturer: "TA",
		Model:        "UVR1611",
	}

	return info
}

// Access to HAP app
var transport hap.Transport
var uvrAccessory *accessory.Accessory

// List of sensors
var sensors map[string]*hkuvr1611.Sensor

// Timer to remove not reachable accessories
var timer *time.Timer

type Connection interface {
	Close()
}

// This app can connect to the UVR1611 data bus and provide the sensor values to HomeKit clients
//
// Optimizations: To improve the performance on a Raspberry Pi B+, the interrupt handler of the
// gpio pin is removed every time after successfully decoding a packet. This allows other goroutines
// (e.g. HAP server) to do their job more quickly.
func main() {

	var (
		pin     = flag.String("pin", "", "Accessory pin required for pairing")
		mode    = flag.String("conn", "mock", "Connection type; mock, gpio, replay")
		file    = flag.String("file", "", "Log file from which to replay packets")
		port    = flag.String("port", "P8_07", "GPIO port; default P8_07")
		timeout = flag.Int("timeout", 120, "Timeout in seconds until accessories are not reachable")
	)

	flag.Parse()
	sensors = map[string]*hkuvr1611.Sensor{}

	info := InfoForAccessoryName("UVR1611")
	uvrAccessory = accessory.New(info, accessory.TypeBridge)

	timer_duration := time.Duration(*timeout) * time.Second
	timer = time.AfterFunc(timer_duration, func() {
		log.Println("[INFO] Not Reachable")
		if transport != nil {
			sensors = map[string]*hkuvr1611.Sensor{}
			transport.Stop()
			transport = nil
		}
	})

	var conn Connection
	callback := func(packet uvr1611.Packet) {
		sensors := HandlePacket(packet)
		if transport == nil {
			config := hap.Config{Pin: *pin}
			if t, err := hap.NewIPTransport(config, uvrAccessory, sensors...); err != nil {
				log.Fatal(err)
			} else {
				go func() {
					t.Start()
				}()
				transport = t
			}
		}
		timer.Reset(timer_duration)
	}

	switch *mode {
	case "mock":
		conn = mock.NewConnection(callback)
	case "replay":
		conn = mock.NewReplayConnection(*file, callback)
	case "gpio":
		conn = gpio.NewConnection(*port, callback)
	default:
		log.Fatal("Incorrect -conn flag")
	}

	hap.OnTermination(func() {
		if transport != nil {
			transport.Stop()
		}
		conn.Close()
		timer.Stop()
		os.Exit(1)
	})

	select {}
}
<|endoftext|>


<commit_before>package function

// Updating Templates:
// See documentation in ./templates/README.md
// go get github.com/markbates/pkger
//go:generate pkger

import (
	"errors"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/go-git/go-billy/v5"
	"github.com/go-git/go-billy/v5/memfs"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/storage/memory"
	"github.com/markbates/pkger"
)

type filesystem interface {
	Stat(name string) (os.FileInfo, error)
	Open(path string) (file, error)
	ReadDir(path string) ([]os.FileInfo, error)
}

type file interface {
	io.Reader
	io.Closer
}

// Trigger encoding of ./templates as pkged.go
//
// When pkger is run, code analysis detects this pkger.Include statement,
// triggering the serialization of the templates directory and all its contents
// into pkged.go, which is then made available via a pkger filesystem.  Path is
// relative to the go module root.
func init() {
	_ = pkger.Include("/templates")
}

type templateWriter struct {
	// Extensible Template Repositories
	// templates on disk (extensible templates)
	// Stored on disk at path:
	//   [customTemplatesPath]/[repository]/[runtime]/[template]
	// For example
	//   ~/.config/func/boson/go/http"
	// Specified when writing templates as simply:
	//   Write([runtime], [repository], [path])
	// For example
	// w := templateWriter{templates:"/home/username/.config/func/templates")
	//   w.Write("go", "boson/http")
	// Ie. "Using the custom templates in the func configuration directory,
	//    write the Boson HTTP template for the Go runtime."
	repositories string

	// URL of a a specific network-available Git repository to use for
	// templates.  Takes precidence over both builtin and extensible
	// if defined.
	url string

	// enable verbose logging
	verbose bool
}

var (
	ErrRepositoryNotFound        = errors.New("repository not found")
	ErrRepositoriesNotDefined    = errors.New("custom template repositories location not specified")
	ErrRuntimeNotFound           = errors.New("runtime not found")
	ErrTemplateNotFound          = errors.New("template not found")
	ErrTemplateMissingRepository = errors.New("template name missing repository prefix")
)

func (t templateWriter) Write(runtime, template, dest string) error {
	if runtime == "" {
		runtime = DefaultRuntime
	}

	if template == "" {
		template = DefaultTemplate
	}

	// remote URLs, when provided, take precidence
	if t.url != "" {
		return writeRemote(t.url, runtime, template, dest)
	}

	// templates with repo prefix are on-disk "custom" (not embedded)
	if len(strings.Split(template, "/")) > 1 {
		return writeCustom(t.repositories, runtime, template, dest)
	}

	// default case is to write from the embedded set of core templates.
	return writeEmbedded(runtime, template, dest)
}

func writeRemote(url, runtime, template, dest string) error {
	// Clone a minimal copy of the remote repository in-memory.
	r, err := git.Clone(
		memory.NewStorage(),
		memfs.New(),
		&git.CloneOptions{
			URL:               url,
			Depth:             1,
			Tags:              git.NoTags,
			RecurseSubmodules: git.NoRecurseSubmodules,
		})
	if err != nil {
		return err
	}
	wt, err := r.Worktree()
	if err != nil {
		return err
	}
	fs := wt.Filesystem

	if _, err := fs.Stat(runtime); err != nil {
		return ErrRuntimeNotFound
	}

	templatePath := filepath.Join(runtime, template)

	if _, err := fs.Stat(templatePath); err != nil {
		return ErrTemplateNotFound
	}

	accessor := billyFilesystem{fs: fs}

	return copy(templatePath, dest, accessor)
}

// write from a custom repository.  The temlate full name is prefixed
func writeCustom(repositoriesPath, runtime, templateFullName, dest string) error {
	// assert path to template repos provided
	if repositoriesPath == "" {
		return ErrRepositoriesNotDefined
	}

	// assert template in form "repoName/templateName"
	cc := strings.Split(templateFullName, "/")
	if len(cc) != 2 {
		return ErrTemplateMissingRepository
	}

	var (
		repo         = cc[0]
		template     = cc[1]
		repoPath     = filepath.Join(repositoriesPath, repo)
		runtimePath  = filepath.Join(repositoriesPath, repo, runtime)
		templatePath = filepath.Join(repositoriesPath, repo, runtime, template)
		accessor     = osFilesystem{} // in instanced provider of Stat and Open
	)
	if _, err := accessor.Stat(repoPath); err != nil {
		return ErrRepositoryNotFound
	}
	if _, err := accessor.Stat(runtimePath); err != nil {
		return ErrRuntimeNotFound
	}
	if _, err := accessor.Stat(templatePath); err != nil {
		return ErrTemplateNotFound
	}
	return copy(templatePath, dest, accessor)
}

func writeEmbedded(runtime, template, dest string) error {
	var (
		repoPath     = "/templates"
		runtimePath  = filepath.Join(repoPath, runtime)
		templatePath = filepath.Join(repoPath, runtime, template)
		accessor     = pkgerFilesystem{} // instanced provder of Stat and Open
	)
	if _, err := accessor.Stat(runtimePath); err != nil {
		return ErrRuntimeNotFound
	}
	if _, err := accessor.Stat(templatePath); err != nil {
		return ErrTemplateNotFound
	}
	return copy(templatePath, dest, accessor)
}

func copy(src, dest string, accessor filesystem) (err error) {
	node, err := accessor.Stat(src)
	if err != nil {
		return
	}
	if node.IsDir() {
		return copyNode(src, dest, accessor)
	} else {
		return copyLeaf(src, dest, accessor)
	}
}

func copyNode(src, dest string, accessor filesystem) (err error) {
	node, err := accessor.Stat(src)
	if err != nil {
		return
	}

	err = os.MkdirAll(dest, node.Mode())
	if err != nil {
		return
	}

	children, err := readDir(src, accessor)
	if err != nil {
		return
	}
	for _, child := range children {
		if err = copy(filepath.Join(src, child.Name()), filepath.Join(dest, child.Name()), accessor); err != nil {
			return
		}
	}
	return
}

func readDir(src string, accessor filesystem) ([]os.FileInfo, error) {
	list, err := accessor.ReadDir(src)
	if err != nil {
		return nil, err
	}
	sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
	return list, nil
}

func copyLeaf(src, dest string, accessor filesystem) (err error) {
	srcFile, err := accessor.Open(src)
	if err != nil {
		return
	}
	defer srcFile.Close()

	srcFileInfo, err := accessor.Stat(src)
	if err != nil {
		return
	}

	destFile, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcFileInfo.Mode())
	if err != nil {
		return
	}
	defer destFile.Close()

	_, err = io.Copy(destFile, srcFile)
	return
}

// Filesystems
// Wrap the implementations of FS with their subtle differences into the
// common interface for accessing template files defined herein.
// os:    standard for on-disk extensible template repositories.
// pker:  embedded filesystem backed by the generated pkged.go.
// billy: go-git library's filesystem used for remote git template repos.

// osFilesystem is a template file accessor backed by an os
// filesystem.
type osFilesystem struct{}

func (a osFilesystem) Stat(path string) (os.FileInfo, error) {
	return os.Stat(path)
}

func (a osFilesystem) Open(path string) (file, error) {
	return os.Open(path)
}

func (a osFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return f.Readdir(-1)
}

// pkgerFilesystem is template file accessor backed by the pkger-provided
// embedded filesystem.
type pkgerFilesystem struct{}

func (a pkgerFilesystem) Stat(path string) (os.FileInfo, error) {
	return pkger.Stat(path)
}

func (a pkgerFilesystem) Open(path string) (file, error) {
	return pkger.Open(path)
}

func (a pkgerFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
	f, err := pkger.Open(path)
	if err != nil {
		return nil, err
	}
	return f.Readdir(-1) // Really?  Pkger's ReadDir is Readdir.
}

// billyFilesystem is a template file accessor backed by a billy FS
type billyFilesystem struct {
	fs billy.Filesystem
}

func (a billyFilesystem) Stat(path string) (os.FileInfo, error) {
	return a.fs.Stat(path)
}

func (a billyFilesystem) Open(path string) (file, error) {
	return a.fs.Open(path)
}

func (a billyFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
	return a.fs.ReadDir(path)
}
<commit_msg>fix: support nested subdirs in remote templates (#482)<commit_after>package function

// Updating Templates:
// See documentation in ./templates/README.md
// go get github.com/markbates/pkger
//go:generate pkger

import (
	"errors"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/go-git/go-billy/v5"
	"github.com/go-git/go-billy/v5/memfs"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/storage/memory"
	"github.com/markbates/pkger"
)

type filesystem interface {
	Stat(name string) (os.FileInfo, error)
	Open(path string) (file, error)
	ReadDir(path string) ([]os.FileInfo, error)
}

type file interface {
	io.Reader
	io.Closer
}

// Trigger encoding of ./templates as pkged.go
//
// When pkger is run, code analysis detects this pkger.Include statement,
// triggering the serialization of the templates directory and all its contents
// into pkged.go, which is then made available via a pkger filesystem.  Path is
// relative to the go module root.
func init() {
	_ = pkger.Include("/templates")
}

type templateWriter struct {
	// Extensible Template Repositories
	// templates on disk (extensible templates)
	// Stored on disk at path:
	//   [customTemplatesPath]/[repository]/[runtime]/[template]
	// For example
	//   ~/.config/func/boson/go/http"
	// Specified when writing templates as simply:
	//   Write([runtime], [repository], [path])
	// For example
	// w := templateWriter{templates:"/home/username/.config/func/templates")
	//   w.Write("go", "boson/http")
	// Ie. "Using the custom templates in the func configuration directory,
	//    write the Boson HTTP template for the Go runtime."
	repositories string

	// URL of a a specific network-available Git repository to use for
	// templates.  Takes precidence over both builtin and extensible
	// if defined.
	url string

	// enable verbose logging
	verbose bool
}

var (
	ErrRepositoryNotFound        = errors.New("repository not found")
	ErrRepositoriesNotDefined    = errors.New("custom template repositories location not specified")
	ErrRuntimeNotFound           = errors.New("runtime not found")
	ErrTemplateNotFound          = errors.New("template not found")
	ErrTemplateMissingRepository = errors.New("template name missing repository prefix")
)

func (t templateWriter) Write(runtime, template, dest string) error {
	if runtime == "" {
		runtime = DefaultRuntime
	}

	if template == "" {
		template = DefaultTemplate
	}

	// remote URLs, when provided, take precidence
	if t.url != "" {
		return writeRemote(t.url, runtime, template, dest)
	}

	// templates with repo prefix are on-disk "custom" (not embedded)
	if len(strings.Split(template, "/")) > 1 {
		return writeCustom(t.repositories, runtime, template, dest)
	}

	// default case is to write from the embedded set of core templates.
	return writeEmbedded(runtime, template, dest)
}

func writeRemote(url, runtime, template, dest string) error {
	// Clone a minimal copy of the remote repository in-memory.
	r, err := git.Clone(
		memory.NewStorage(),
		memfs.New(),
		&git.CloneOptions{
			URL:               url,
			Depth:             1,
			Tags:              git.NoTags,
			RecurseSubmodules: git.NoRecurseSubmodules,
		})
	if err != nil {
		return err
	}
	wt, err := r.Worktree()
	if err != nil {
		return err
	}
	fs := wt.Filesystem

	if _, err := fs.Stat(runtime); err != nil {
		return ErrRuntimeNotFound
	}

	templatePath := filepath.Join(runtime, template)

	if _, err := fs.Stat(templatePath); err != nil {
		return ErrTemplateNotFound
	}

	accessor := billyFilesystem{fs: fs}

	return copy(templatePath, dest, accessor)
}

// write from a custom repository.  The temlate full name is prefixed
func writeCustom(repositoriesPath, runtime, templateFullName, dest string) error {
	// assert path to template repos provided
	if repositoriesPath == "" {
		return ErrRepositoriesNotDefined
	}

	// assert template in form "repoName/templateName"
	cc := strings.Split(templateFullName, "/")
	if len(cc) != 2 {
		return ErrTemplateMissingRepository
	}

	var (
		repo         = cc[0]
		template     = cc[1]
		repoPath     = filepath.Join(repositoriesPath, repo)
		runtimePath  = filepath.Join(repositoriesPath, repo, runtime)
		templatePath = filepath.Join(repositoriesPath, repo, runtime, template)
		accessor     = osFilesystem{} // in instanced provider of Stat and Open
	)
	if _, err := accessor.Stat(repoPath); err != nil {
		return ErrRepositoryNotFound
	}
	if _, err := accessor.Stat(runtimePath); err != nil {
		return ErrRuntimeNotFound
	}
	if _, err := accessor.Stat(templatePath); err != nil {
		return ErrTemplateNotFound
	}
	return copy(templatePath, dest, accessor)
}

func writeEmbedded(runtime, template, dest string) error {
	var (
		repoPath     = "/templates"
		runtimePath  = filepath.Join(repoPath, runtime)
		templatePath = filepath.Join(repoPath, runtime, template)
		accessor     = pkgerFilesystem{} // instanced provder of Stat and Open
	)
	if _, err := accessor.Stat(runtimePath); err != nil {
		return ErrRuntimeNotFound
	}
	if _, err := accessor.Stat(templatePath); err != nil {
		return ErrTemplateNotFound
	}
	return copy(templatePath, dest, accessor)
}

func copy(src, dest string, accessor filesystem) (err error) {
	node, err := accessor.Stat(src)
	if err != nil {
		return
	}
	if node.IsDir() {
		return copyNode(src, dest, accessor)
	} else {
		return copyLeaf(src, dest, accessor)
	}
}

func copyNode(src, dest string, accessor filesystem) (err error) {
	// Ideally we should use the file mode of the src node
	// but it seems the git module is reporting directories
	// as 0644 instead of 0755. For now, just do it this way.
	err = os.MkdirAll(dest, 0755)
	if err != nil {
		return
	}

	children, err := readDir(src, accessor)
	if err != nil {
		return
	}
	for _, child := range children {
		if err = copy(filepath.Join(src, child.Name()), filepath.Join(dest, child.Name()), accessor); err != nil {
			return
		}
	}
	return
}

func readDir(src string, accessor filesystem) ([]os.FileInfo, error) {
	list, err := accessor.ReadDir(src)
	if err != nil {
		return nil, err
	}
	sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
	return list, nil
}

func copyLeaf(src, dest string, accessor filesystem) (err error) {
	srcFile, err := accessor.Open(src)
	if err != nil {
		return
	}
	defer srcFile.Close()

	srcFileInfo, err := accessor.Stat(src)
	if err != nil {
		return
	}

	destFile, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcFileInfo.Mode())
	if err != nil {
		return
	}
	defer destFile.Close()

	_, err = io.Copy(destFile, srcFile)
	return
}

// Filesystems
// Wrap the implementations of FS with their subtle differences into the
// common interface for accessing template files defined herein.
// os:    standard for on-disk extensible template repositories.
// pker:  embedded filesystem backed by the generated pkged.go.
// billy: go-git library's filesystem used for remote git template repos.

// osFilesystem is a template file accessor backed by an os
// filesystem.
type osFilesystem struct{}

func (a osFilesystem) Stat(path string) (os.FileInfo, error) {
	return os.Stat(path)
}

func (a osFilesystem) Open(path string) (file, error) {
	return os.Open(path)
}

func (a osFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return f.Readdir(-1)
}

// pkgerFilesystem is template file accessor backed by the pkger-provided
// embedded filesystem.
type pkgerFilesystem struct{}

func (a pkgerFilesystem) Stat(path string) (os.FileInfo, error) {
	return pkger.Stat(path)
}

func (a pkgerFilesystem) Open(path string) (file, error) {
	return pkger.Open(path)
}

func (a pkgerFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
	f, err := pkger.Open(path)
	if err != nil {
		return nil, err
	}
	return f.Readdir(-1) // Really?  Pkger's ReadDir is Readdir.
}

// billyFilesystem is a template file accessor backed by a billy FS
type billyFilesystem struct {
	fs billy.Filesystem
}

func (a billyFilesystem) Stat(path string) (os.FileInfo, error) {
	return a.fs.Stat(path)
}

func (a billyFilesystem) Open(path string) (file, error) {
	return a.fs.Open(path)
}

func (a billyFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
	return a.fs.ReadDir(path)
}
<|endoftext|>


<commit_before>package gforms

import (
	"bytes"
	"text/template"
)

const defaultTemplates = `
{{define "TextTypeField"}}<input type="text" name="{{.Field.GetName | html}}" value="{{.Value | html}}"></input>{{end}}
{{define "TextAreaField"}}<textarea  name="{{.Field.GetName | html}}" value="{{.Value | html}}"></textarea>{{end}}
{{define "BooleanTypeField"}}<input type="checkbox" name="{{.Field.GetName | html}}"{{if .Checked}} checked{{end}}>{{end}}
{{define "SimpleWidget"}}<input type="{{.Type | html}}" name="{{.Field.GetName | html}}" value="{{.Value | html}}"{{range $attr, $val := .Attrs}} {{$attr | html}}="{{$val | html}}"{{end}}></input>{{end}}
{{define "SelectWidget"}}<select {{if .Multiple }}multiple {{end}}name="{{.Field.GetName | html}}"{{range $attr, $val := .Attrs}}{{$attr | html}}="{{$val | html}}"{{end}}>
{{range $idx, $val := .Options}}<option value="{{$val.Value | html}}"{{if $val.Selected }} selected{{end}}{{if $val.Disabled}} disabled{{end}}>{{$val.Label | html}}</option>
{{end}}</select>{{end}}
{{define "RadioWidget"}}{{$name := .Field.GetName}}{{range $idx, $val := .Options}}<input type="radio" name="{{$name | html}}" value="{{$val.Value | html}}"{{if $val.Checked}} checked{{end}}{{if $val.Disabled}} disabled{{end}}>{{$val.Label | html}}
{{end}}{{end}}
{{define "CheckboxMultipleWidget"}}{{$name := .Field.GetName}}{{range $idx, $val := .Options}}<input type="checkbox" name="{{$name | html}}" value="{{$val.Value | html}}"{{if $val.Checked}} checked{{end}}{{if $val.Disabled}} disabled{{end}}>{{$val.Label | html}}
{{end}}{{end}}
`

// all templates of Field and Widget
var Template *template.Template

func init() {
	var err error
	Template, err = template.New("gforms").Parse(defaultTemplates)
	if err != nil {
		panic(err)
	}
}

type templateContext struct {
	Field FieldInterface
	Value string
}

func newTemplateContext(f FieldInterface) templateContext {
	ctx := templateContext{
		Field: f,
	}
	v := f.GetV()
	if v != nil {
		ctx.Value = v.RawStr
	}
	return ctx
}

func renderTemplate(name string, ctx interface{}) string {
	var buffer bytes.Buffer
	err := Template.ExecuteTemplate(&buffer, name, ctx)
	if err != nil {
		panic(err)
	}
	return buffer.String()
}
<commit_msg>added attrs to the TextArea template<commit_after>package gforms

import (
	"bytes"
	"text/template"
)

const defaultTemplates = `
{{define "TextTypeField"}}<input type="text" name="{{.Field.GetName | html}}" value="{{.Value | html}}"></input>{{end}}
{{define "TextAreaField"}}<textarea  name="{{.Field.GetName | html}}" value="{{.Value | html}}" {{range $attr, $val := .Attrs}} {{$attr | html}}="{{$val | html}}"{{end}}></textarea>{{end}}
{{define "BooleanTypeField"}}<input type="checkbox" name="{{.Field.GetName | html}}"{{if .Checked}} checked{{end}}>{{end}}
{{define "SimpleWidget"}}<input type="{{.Type | html}}" name="{{.Field.GetName | html}}" value="{{.Value | html}}"{{range $attr, $val := .Attrs}} {{$attr | html}}="{{$val | html}}"{{end}}></input>{{end}}
{{define "SelectWidget"}}<select {{if .Multiple }}multiple {{end}}name="{{.Field.GetName | html}}"{{range $attr, $val := .Attrs}}{{$attr | html}}="{{$val | html}}"{{end}}>
{{range $idx, $val := .Options}}<option value="{{$val.Value | html}}"{{if $val.Selected }} selected{{end}}{{if $val.Disabled}} disabled{{end}}>{{$val.Label | html}}</option>
{{end}}</select>{{end}}
{{define "RadioWidget"}}{{$name := .Field.GetName}}{{range $idx, $val := .Options}}<input type="radio" name="{{$name | html}}" value="{{$val.Value | html}}"{{if $val.Checked}} checked{{end}}{{if $val.Disabled}} disabled{{end}}>{{$val.Label | html}}
{{end}}{{end}}
{{define "CheckboxMultipleWidget"}}{{$name := .Field.GetName}}{{range $idx, $val := .Options}}<input type="checkbox" name="{{$name | html}}" value="{{$val.Value | html}}"{{if $val.Checked}} checked{{end}}{{if $val.Disabled}} disabled{{end}}>{{$val.Label | html}}
{{end}}{{end}}
`

// all templates of Field and Widget
var Template *template.Template

func init() {
	var err error
	Template, err = template.New("gforms").Parse(defaultTemplates)
	if err != nil {
		panic(err)
	}
}

type templateContext struct {
	Field FieldInterface
	Value string
}

func newTemplateContext(f FieldInterface) templateContext {
	ctx := templateContext{
		Field: f,
	}
	v := f.GetV()
	if v != nil {
		ctx.Value = v.RawStr
	}
	return ctx
}

func renderTemplate(name string, ctx interface{}) string {
	var buffer bytes.Buffer
	err := Template.ExecuteTemplate(&buffer, name, ctx)
	if err != nil {
		panic(err)
	}
	return buffer.String()
}
<|endoftext|>


<commit_before>package onthefly

import (
	"fmt"
	"log"
)

// For generating IDs
var (
	geometryCounter = 0
	materialCounter = 0
	meshCounter     = 0
)

// Unique prefixes when generating IDs
const (
	geometryPrefix = "g"
	materialPrefix = "ma"
	meshPrefix     = "m"
)

type (
	// For Three.JS elements, like a mesh or material
	Element struct {
		ID string // name of the variable
		JS string // javascript code for creating the element
	}
	// The Three.JS render function, where head and tail are standard
	RenderFunc struct {
		head, mid, tail string
	}
	// Different types of elements
	Geometry Element
	Material Element
	Mesh     Element
)

// Create a HTML5 page that links with Three.JS and sets up a scene
func NewThreeJS(titleText string) (*Page, *Tag) {
	page := NewHTML5Page(titleText)

	// Style the page for showing a fullscreen canvas
	page.FullCanvas()

	// Link to Three.JS
	page.LinkToJSInBody("http://threejs.org/build/three.min.js")

	// Add a scene
	script, _ := page.AddScriptToBody("var scene = new THREE.Scene();")

	// Return the script tag that can be used for adding additional
	// javascript/Three.JS code
	return page, script
}

// Add a camera with default settings
func (three *Tag) AddCamera() {
	// TODO create an AddCustomCamera function
	three.AddContent("var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);")
}

// Add a WebGL renderer with default settings
func (three *Tag) AddRenderer() {
	three.AddContent("var renderer = new THREE.WebGLRenderer();")
	three.AddContent("renderer.setSize(window.innerWidth, window.innerHeight);")
	three.AddContent("document.body.appendChild(renderer.domElement);")
}

// Add a mesh to the current scene
func (three *Tag) AddToScene(mesh *Mesh) {
	three.AddContent(mesh.JS)
	three.AddContent("scene.add(" + mesh.ID + ");")
}

// Create a new mesh, given geometry and material.
// The geometry and material will be instanciated together with the mesh.
func NewMesh(geometry *Geometry, material *Material) *Mesh {
	id := fmt.Sprintf("%s%d", meshPrefix, meshCounter)
	meshCounter++
	js := geometry.JS + material.JS
	js += "var " + id + " = new THREE.Mesh(" + geometry.ID + ", " + material.ID + ");"
	return &Mesh{id, js}
}

// Set the camera position. Axis must be "x", "y", or "z".
func (three *Tag) CameraPos(axis string, value int) {
	if (axis != "x") && (axis != "y") && (axis != "z") {
		log.Fatalln("camera axis must be x, y or z")
	}
	three.AddContent(fmt.Sprintf("camera.position.%s = %d;", axis, value))
}

// Very simple type of material
func NewMaterial(color string) *Material {
	id := fmt.Sprintf("%s%d", materialPrefix, materialCounter)
	materialCounter++
	js := "var " + id + " = new THREE.MeshBasicMaterial({color: " + color + "});"
	return &Material{id, js}
}

// Create a material which reflects the normals of the geometry
func NewNormalMaterial() *Material {
	id := fmt.Sprintf("%s%d", materialPrefix, materialCounter)
	materialCounter++
	js := "var " + id + " = new THREE.MeshNormalMaterial();"
	return &Material{id, js}
}

// Create geometry for a box
func NewBoxGeometry(w, h, d int) *Geometry {
	id := fmt.Sprintf("%s%d", geometryPrefix, geometryCounter)
	geometryCounter++
	js := fmt.Sprintf("var %s = new THREE.BoxGeometry(%d, %d, %d);", id, w, h, d)
	return &Geometry{id, js}
}

// Add a test cube to the scene
func (three *Tag) AddTestCube() *Mesh {
	// TODO Create functions for adding geometry, material and creating meshes
	//material := NewMaterial(color)
	material := NewNormalMaterial()
	geometry := NewBoxGeometry(1, 1, 1)
	cube := NewMesh(geometry, material)
	three.AddToScene(cube)
	return cube
}

// Create a new render function, which is called at every animation frame
func NewRenderFunction() *RenderFunc {
	head := "var render = function() { requestAnimationFrame(render);"
	tail := "renderer.render(scene, camera); };"
	return &RenderFunc{head, "", tail}
}

// Add javascript code to the body of a render function
func (r *RenderFunc) AddJS(s string) {
	r.mid += s
}

// Add a render function.
// If call is true, the render function is called at the end of the script.
func (three *Tag) AddRenderFunction(r *RenderFunc, call bool) {
	three.AddContent(r.head + r.mid + r.tail)
	if call {
		three.AddContent("render();")
	}
}
<commit_msg>Add a function for specifying the ThreeJS source code directly, for embedding the data in an executable<commit_after>package onthefly

import (
	"fmt"
	"log"
)

// For generating IDs
var (
	geometryCounter = 0
	materialCounter = 0
	meshCounter     = 0
)

// Unique prefixes when generating IDs
const (
	geometryPrefix = "g"
	materialPrefix = "ma"
	meshPrefix     = "m"
)

type (
	// For Three.JS elements, like a mesh or material
	Element struct {
		ID string // name of the variable
		JS string // javascript code for creating the element
	}
	// The Three.JS render function, where head and tail are standard
	RenderFunc struct {
		head, mid, tail string
	}
	// Different types of elements
	Geometry Element
	Material Element
	Mesh     Element
)

// Create a HTML5 page that links with Three.JS and sets up a scene
func NewThreeJS(titleText string) (*Page, *Tag) {
	page := NewHTML5Page(titleText)

	// Style the page for showing a fullscreen canvas
	page.FullCanvas()

	// Link to Three.JS
	page.LinkToJSInBody("http://threejs.org/build/three.min.js")

	// Add a scene
	script, _ := page.AddScriptToBody("var scene = new THREE.Scene();")

	// Return the script tag that can be used for adding additional
	// javascript/Three.JS code
	return page, script
}

// Create a HTML5 page that includes the given JavaScript code at the end of
// the <body> tag, before </body>. The given JS code must be the contents of
// the http://threejs.org/build/three.min.js script for this to work.
func NewThreeJSWithGiven(titleText, js string) (*Page, *Tag) {
	page := NewHTML5Page(titleText)

	// Style the page for showing a fullscreen canvas
	page.FullCanvas()

	// Add the given JavaScript to the body
	page.AddScriptToBody(js)

	// Add a scene
	script, _ := page.AddScriptToBody("var scene = new THREE.Scene();")

	// Return the script tag that can be used for adding additional
	// javascript/Three.JS code
	return page, script
}

// Add a camera with default settings
func (three *Tag) AddCamera() {
	// TODO create an AddCustomCamera function
	three.AddContent("var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);")
}

// Add a WebGL renderer with default settings
func (three *Tag) AddRenderer() {
	three.AddContent("var renderer = new THREE.WebGLRenderer();")
	three.AddContent("renderer.setSize(window.innerWidth, window.innerHeight);")
	three.AddContent("document.body.appendChild(renderer.domElement);")
}

// Add a mesh to the current scene
func (three *Tag) AddToScene(mesh *Mesh) {
	three.AddContent(mesh.JS)
	three.AddContent("scene.add(" + mesh.ID + ");")
}

// Create a new mesh, given geometry and material.
// The geometry and material will be instanciated together with the mesh.
func NewMesh(geometry *Geometry, material *Material) *Mesh {
	id := fmt.Sprintf("%s%d", meshPrefix, meshCounter)
	meshCounter++
	js := geometry.JS + material.JS
	js += "var " + id + " = new THREE.Mesh(" + geometry.ID + ", " + material.ID + ");"
	return &Mesh{id, js}
}

// Set the camera position. Axis must be "x", "y", or "z".
func (three *Tag) CameraPos(axis string, value int) {
	if (axis != "x") && (axis != "y") && (axis != "z") {
		log.Fatalln("camera axis must be x, y or z")
	}
	three.AddContent(fmt.Sprintf("camera.position.%s = %d;", axis, value))
}

// Very simple type of material
func NewMaterial(color string) *Material {
	id := fmt.Sprintf("%s%d", materialPrefix, materialCounter)
	materialCounter++
	js := "var " + id + " = new THREE.MeshBasicMaterial({color: " + color + "});"
	return &Material{id, js}
}

// Create a material which reflects the normals of the geometry
func NewNormalMaterial() *Material {
	id := fmt.Sprintf("%s%d", materialPrefix, materialCounter)
	materialCounter++
	js := "var " + id + " = new THREE.MeshNormalMaterial();"
	return &Material{id, js}
}

// Create geometry for a box
func NewBoxGeometry(w, h, d int) *Geometry {
	id := fmt.Sprintf("%s%d", geometryPrefix, geometryCounter)
	geometryCounter++
	js := fmt.Sprintf("var %s = new THREE.BoxGeometry(%d, %d, %d);", id, w, h, d)
	return &Geometry{id, js}
}

// Add a test cube to the scene
func (three *Tag) AddTestCube() *Mesh {
	// TODO Create functions for adding geometry, material and creating meshes
	//material := NewMaterial(color)
	material := NewNormalMaterial()
	geometry := NewBoxGeometry(1, 1, 1)
	cube := NewMesh(geometry, material)
	three.AddToScene(cube)
	return cube
}

// Create a new render function, which is called at every animation frame
func NewRenderFunction() *RenderFunc {
	head := "var render = function() { requestAnimationFrame(render);"
	tail := "renderer.render(scene, camera); };"
	return &RenderFunc{head, "", tail}
}

// Add javascript code to the body of a render function
func (r *RenderFunc) AddJS(s string) {
	r.mid += s
}

// Add a render function.
// If call is true, the render function is called at the end of the script.
func (three *Tag) AddRenderFunction(r *RenderFunc, call bool) {
	three.AddContent(r.head + r.mid + r.tail)
	if call {
		three.AddContent("render();")
	}
}
<|endoftext|>


<commit_before>package handler_test

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/m-lab/annotation-service/handler"
)

func TestRequest(t *testing.T) {
	tests := []struct {
		ip       string
		time     string
		res      string
		time_num int64
	}{
		{"1.4.128.0", "625600", `{"Geo":{"city": "Not A Real City", "postal_code":"10583"},"ASN":{}}`, 625600},
	}
	for _, test := range tests {
		w := httptest.NewRecorder()
		r := &http.Request{}
		r.URL, _ = url.Parse("/annotate?ip_addr=" + url.QueryEscape(test.ip) + "&since_epoch=" + url.QueryEscape(test.time))
		handler.Annotate(w, r)
		body := w.Body.String()
		if string(body) != test.res {
			t.Errorf("\nGot\n__%s__\nexpected\n__%s__\n", body, test.res)
		}
	}
}
<commit_msg>Cleaned up the tests in the handler package a little bit.<commit_after>package handler_test

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/m-lab/annotation-service/handler"
)

func TestAnnotate(t *testing.T) {
	tests := []struct {
		ip   string
		time string
		res  string
	}{
		{"1.4.128.0", "625600", `{"Geo":{"city": "Not A Real City", "postal_code":"10583"},"ASN":{}}`},
		{"This will be an error.", "1000", "Invalid request"},
	}
	for _, test := range tests {
		w := httptest.NewRecorder()
		r := &http.Request{}
		r.URL, _ = url.Parse("/annotate?ip_addr=" + url.QueryEscape(test.ip) + "&since_epoch=" + url.QueryEscape(test.time))
		handler.Annotate(w, r)
		body := w.Body.String()
		if string(body) != test.res {
			t.Errorf("\nGot\n__%s__\nexpected\n__%s__\n", body, test.res)
		}
	}
}
<|endoftext|>