<commit_before>package term

import . "fmt"
import . "regexp"

var anonCounter <-chan int64
func init() {
    // goroutine providing a counter for anonymous variables
    c := make(chan int64)
    var i int64 = 1000
    go func() {
        for {
            c <- i
            i++
        }
    }()
    anonCounter = c
}

// A Prolog logic variable.  See ISO §6.1.2(a)
type Variable struct {
    Name    string
    id      int64       // uniquely identifiers this variable
}

// Creates a new logic variable with the given name.
func NewVar(name string) *Variable {
    // sanity check the variable name's syntax
    isCapitalized, err := MatchString(`^[A-Z_]`, name)
    maybePanic(err)
    if !isCapitalized {
        panic("Variable names must start with a capital letter or underscore")
    }

    // make sure anonymous variables are unique
    var i int64
    if name == "_" {
        i = <-anonCounter
    }
    return &Variable{
        Name:   name,
        id:     i,
    }
}

// Id returns a unique identifier for this variable
func (self *Variable) Id() int64 {
    return self.id
}

func (self *Variable) Functor() string {
    panic("Variables have no Functor()")
}

func (self *Variable) Arity() int {
    panic("Variables have no Arity()")
}

func (self *Variable) Arguments() []Term {
    panic("Variables have no Arguments()")
}

func (self *Variable) Body() Term {
    panic("Variables have no Body()")
}

func (self *Variable) Head() Term {
    panic("Variables have no Head()")
}

func (self *Variable) IsClause() bool {
    return false
}

func (self *Variable) String() string {
    return self.Name
}

func (self *Variable) Indicator() string {
    return Sprintf("_V%d", self.id)
}

func (self *Variable) Error() error {
    panic("Can't call Error() on a Variable")
}

func (a *Variable) Unify(e Bindings, b Term) (Bindings, error) {
    var aTerm, bTerm Term

    // a variable always unifies with itself
    if IsVariable(b) {
        if a.Indicator() == b.Indicator() {
            return e, nil
        }
        bTerm = e.Resolve_(b.(*Variable))
    } else {
        bTerm = b
    }

    // resolve any previous bindings
    aTerm = e.Resolve_(a)

    // bind unbound variables
    if IsVariable(aTerm) {
        return e.Bind(aTerm.(*Variable), b)
    }
    if IsVariable(bTerm) {
        return e.Bind(bTerm.(*Variable), a)
    }

    // otherwise, punt
    return aTerm.Unify(e, bTerm)
}

func (self *Variable) ReplaceVariables(env Bindings) Term {
    return env.Resolve_(self)
}

func (self *Variable) WithNewId() *Variable {
    return &Variable{
        Name:   self.Name,
        id:     <-anonCounter,
    }
}
<commit_msg>Print anonymous variables with full ID<commit_after>package term

import . "fmt"
import . "regexp"

var anonCounter <-chan int64
func init() {
    // goroutine providing a counter for anonymous variables
    c := make(chan int64)
    var i int64 = 1000
    go func() {
        for {
            c <- i
            i++
        }
    }()
    anonCounter = c
}

// A Prolog logic variable.  See ISO §6.1.2(a)
type Variable struct {
    Name    string
    id      int64       // uniquely identifiers this variable
}

// Creates a new logic variable with the given name.
func NewVar(name string) *Variable {
    // sanity check the variable name's syntax
    isCapitalized, err := MatchString(`^[A-Z_]`, name)
    maybePanic(err)
    if !isCapitalized {
        panic("Variable names must start with a capital letter or underscore")
    }

    // make sure anonymous variables are unique
    var i int64
    if name == "_" {
        i = <-anonCounter
    }
    return &Variable{
        Name:   name,
        id:     i,
    }
}

// Id returns a unique identifier for this variable
func (self *Variable) Id() int64 {
    return self.id
}

func (self *Variable) Functor() string {
    panic("Variables have no Functor()")
}

func (self *Variable) Arity() int {
    panic("Variables have no Arity()")
}

func (self *Variable) Arguments() []Term {
    panic("Variables have no Arguments()")
}

func (self *Variable) Body() Term {
    panic("Variables have no Body()")
}

func (self *Variable) Head() Term {
    panic("Variables have no Head()")
}

func (self *Variable) IsClause() bool {
    return false
}

func (self *Variable) String() string {
	if self.Name == "_" {
		return self.Indicator()
	}
    return self.Name
}

func (self *Variable) Indicator() string {
    return Sprintf("_V%d", self.id)
}

func (self *Variable) Error() error {
    panic("Can't call Error() on a Variable")
}

func (a *Variable) Unify(e Bindings, b Term) (Bindings, error) {
    var aTerm, bTerm Term

    // a variable always unifies with itself
    if IsVariable(b) {
        if a.Indicator() == b.Indicator() {
            return e, nil
        }
        bTerm = e.Resolve_(b.(*Variable))
    } else {
        bTerm = b
    }

    // resolve any previous bindings
    aTerm = e.Resolve_(a)

    // bind unbound variables
    if IsVariable(aTerm) {
        return e.Bind(aTerm.(*Variable), b)
    }
    if IsVariable(bTerm) {
        return e.Bind(bTerm.(*Variable), a)
    }

    // otherwise, punt
    return aTerm.Unify(e, bTerm)
}

func (self *Variable) ReplaceVariables(env Bindings) Term {
    return env.Resolve_(self)
}

func (self *Variable) WithNewId() *Variable {
    return &Variable{
        Name:   self.Name,
        id:     <-anonCounter,
    }
}
<|endoftext|>


<commit_before>package urlcheck

import "errors"
import "strconv"

type Tests []Test

type Scenario struct {
	Tests Tests
	Name  string
}

func (s Scenario) Test() error {
	for i, t := range s.Tests {
		err := t.Test()
		if err != nil {
			return errors.New("Step " + strconv.Itoa(i+1) + ": " + err.Error())
		}
	}
	return nil
}
<commit_msg>Scenario: use name in String() and errors<commit_after>package urlcheck

import "errors"
import "strconv"

type Tests []Test

type Scenario struct {
	Tests Tests
	Name  string
}

func (s Scenario) Test() error {
	for i, t := range s.Tests {
		err := t.Test()
		if err != nil {
			return errors.New(s.String() + " step " + strconv.Itoa(i+1) + ": " + err.Error())
		}
	}
	return nil
}

func (s Scenario) String() string {
	if s.Name == "" {
		return "Unnamed scenario"
	} else {
		return "Scenario " + s.Name
	}
}
<|endoftext|>


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

package types2

import (
	"fmt"
)

// A Package describes a Go package.
type Package struct {
	path     string
	name     string
	scope    *Scope
	imports  []*Package
	height   int
	complete bool
	fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
	cgo      bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
}

// NewPackage returns a new Package for the given package path and name.
// The package is not complete and contains no explicit imports.
func NewPackage(path, name string) *Package {
	return NewPackageHeight(path, name, 0)
}

// NewPackageHeight is like NewPackage, but allows specifying the
// package's height.
func NewPackageHeight(path, name string, height int) *Package {
	scope := NewScope(Universe, nopos, nopos, fmt.Sprintf("package %q", path))
	return &Package{path: path, name: name, scope: scope, height: height}
}

// Path returns the package path.
func (pkg *Package) Path() string { return pkg.path }

// Name returns the package name.
func (pkg *Package) Name() string { return pkg.name }

// Height returns the package height.
func (pkg *Package) Height() int { return pkg.height }

// SetName sets the package name.
func (pkg *Package) SetName(name string) { pkg.name = name }

// Scope returns the (complete or incomplete) package scope
// holding the objects declared at package level (TypeNames,
// Consts, Vars, and Funcs).
func (pkg *Package) Scope() *Scope { return pkg.scope }

// A package is complete if its scope contains (at least) all
// exported objects; otherwise it is incomplete.
func (pkg *Package) Complete() bool { return pkg.complete }

// MarkComplete marks a package as complete.
func (pkg *Package) MarkComplete() { pkg.complete = true }

// Imports returns the list of packages directly imported by
// pkg; the list is in source order.
//
// If pkg was loaded from export data, Imports includes packages that
// provide package-level objects referenced by pkg. This may be more or
// less than the set of packages directly imported by pkg's source code.
func (pkg *Package) Imports() []*Package { return pkg.imports }

// SetImports sets the list of explicitly imported packages to list.
// It is the caller's responsibility to make sure list elements are unique.
func (pkg *Package) SetImports(list []*Package) { pkg.imports = list }

func (pkg *Package) String() string {
	return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path)
}
<commit_msg>[dev.typeparams] cmd/compile/internal/types2: return Universe for ((*Package)(nil)).Scope()<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types2

import (
	"fmt"
)

// A Package describes a Go package.
type Package struct {
	path     string
	name     string
	scope    *Scope
	imports  []*Package
	height   int
	complete bool
	fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
	cgo      bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
}

// NewPackage returns a new Package for the given package path and name.
// The package is not complete and contains no explicit imports.
func NewPackage(path, name string) *Package {
	return NewPackageHeight(path, name, 0)
}

// NewPackageHeight is like NewPackage, but allows specifying the
// package's height.
func NewPackageHeight(path, name string, height int) *Package {
	scope := NewScope(Universe, nopos, nopos, fmt.Sprintf("package %q", path))
	return &Package{path: path, name: name, scope: scope, height: height}
}

// Path returns the package path.
func (pkg *Package) Path() string { return pkg.path }

// Name returns the package name.
func (pkg *Package) Name() string { return pkg.name }

// Height returns the package height.
func (pkg *Package) Height() int { return pkg.height }

// SetName sets the package name.
func (pkg *Package) SetName(name string) { pkg.name = name }

// Scope returns the (complete or incomplete) package scope
// holding the objects declared at package level (TypeNames,
// Consts, Vars, and Funcs).
// For a nil pkg receiver, Scope returns the Universe scope.
func (pkg *Package) Scope() *Scope {
	if pkg != nil {
		return pkg.scope
	}
	return Universe
}

// A package is complete if its scope contains (at least) all
// exported objects; otherwise it is incomplete.
func (pkg *Package) Complete() bool { return pkg.complete }

// MarkComplete marks a package as complete.
func (pkg *Package) MarkComplete() { pkg.complete = true }

// Imports returns the list of packages directly imported by
// pkg; the list is in source order.
//
// If pkg was loaded from export data, Imports includes packages that
// provide package-level objects referenced by pkg. This may be more or
// less than the set of packages directly imported by pkg's source code.
func (pkg *Package) Imports() []*Package { return pkg.imports }

// SetImports sets the list of explicitly imported packages to list.
// It is the caller's responsibility to make sure list elements are unique.
func (pkg *Package) SetImports(list []*Package) { pkg.imports = list }

func (pkg *Package) String() string {
	return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path)
}
<|endoftext|>


<commit_before>package input

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
)

//ServeStatD serves the statsad protocol via UDP.
func ServeStatD(port string, metricsIn chan Metric) string {
	var buf [1024]byte
	addr, err := net.ResolveUDPAddr("udp", ":"+port)

	if err != nil {
		panic(err)
	}

	sock, err := net.ListenUDP("udp", addr)

	if err != nil {
		panic(err)
	}

	for {
		rlen, _, _ := sock.ReadFromUDP(buf[:])
		message := string(buf[:rlen])
		//a single statsD message can contain multiple metrics
		//split and then interate through each to parse and submit
		//for aggregategation
		metrics := splitStatsDMessages(message)

		for _, metric := range metrics {
			parsedMetric, err := parseStatDMetric(metric)

			if err != nil {
				//add tag to metric denoting its point of origin
				metricsIn <- parsedMetric
			}
		}

	}
}

//split statsd messages that contain multiple metrics into its respective parts
func splitStatsDMessages(messages string) []string {
	var splitMessages []string
	newline := strings.Index(messages, "\n")

	for newline != -1 {
		message := messages[0 : newline-1]
		splitMessages = append(splitMessages, message)
		messages = messages[newline+1 : len(messages)]
		newline = strings.Index(messages, "\n")
	}

	if len(messages) > 0 {
		splitMessages = append(splitMessages, messages)
	}

	return splitMessages
}

func parseStatDMetric(message string) (Metric, error) {
	var metric Metric

	colonIndex := strings.Index(message, ":")
	ibarIndex := strings.Index(message, "|")
	atIndex := strings.Index(message, "@")

	if colonIndex == -1 || ibarIndex == -1 {
		return Metric{}, errors.New("unable to parse name from statsD message")
	}

	metric.Name = string(message[colonIndex-1])
	stringValue := message[colonIndex+1 : ibarIndex]
	floatValue, err := strconv.ParseFloat(stringValue, 64)
	metric.Value = floatValue

	if err != nil {
		return Metric{}, errors.New("unable to parse value from statsD message")
	}

	metricType := ""

	if atIndex == -1 {
		metricType = message[ibarIndex+1 : len(message)]
		metric.Sampling = 1
	} else {
		metricType = message[ibarIndex+1 : atIndex-1]
		sampleRate := message[atIndex+1 : len(message)]
		floatSampleRate, err := strconv.ParseFloat(sampleRate, 64)

		if err != nil {
			return Metric{}, errors.New("unable to parse StatsD value")
		}

		metric.Sampling = floatSampleRate
	}

	switch string(metricType[:len(metricType)]) {
	case "ms":
		metric.Type = "timer"
	case "g":
		metric.Type = "gauge"
	case "c":
		metric.Type = "counter"
	default:
		fmt.Println(metricType)
		err = fmt.Errorf("invalid metric type: %q", metricType)
		return metric, err
	}

	return metric, nil
}
<commit_msg>Added timestamp to statsD. As statsD clients don’t provide a timestamp.<commit_after>package input

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)

//ServeStatD serves the statsad protocol via UDP.
func ServeStatD(port string, metricsIn chan Metric) string {
	var buf [1024]byte
	addr, err := net.ResolveUDPAddr("udp", ":"+port)

	if err != nil {
		panic(err)
	}

	sock, err := net.ListenUDP("udp", addr)

	if err != nil {
		panic(err)
	}

	for {
		rlen, _, _ := sock.ReadFromUDP(buf[:])
		message := string(buf[:rlen])
		//a single statsD message can contain multiple metrics
		//split and then interate through each to parse and submit
		//for aggregategation
		metrics := splitStatsDMessages(message)

		for _, metric := range metrics {
			parsedMetric, err := parseStatDMetric(metric)

			if err != nil {
				//add tag to metric denoting its point of origin
				parsedMetric.Timestamp = time.Now().Format("2006-01-02 15:04:05 -0700")
				metricsIn <- parsedMetric
			}
		}

	}
}

//split statsd messages that contain multiple metrics into its respective parts
func splitStatsDMessages(messages string) []string {
	var splitMessages []string
	newline := strings.Index(messages, "\n")

	for newline != -1 {
		message := messages[0 : newline-1]
		splitMessages = append(splitMessages, message)
		messages = messages[newline+1 : len(messages)]
		newline = strings.Index(messages, "\n")
	}

	if len(messages) > 0 {
		splitMessages = append(splitMessages, messages)
	}

	return splitMessages
}

func parseStatDMetric(message string) (Metric, error) {
	var metric Metric

	colonIndex := strings.Index(message, ":")
	ibarIndex := strings.Index(message, "|")
	atIndex := strings.Index(message, "@")

	if colonIndex == -1 || ibarIndex == -1 {
		return Metric{}, errors.New("unable to parse name from statsD message")
	}

	metric.Name = string(message[colonIndex-1])
	stringValue := message[colonIndex+1 : ibarIndex]
	floatValue, err := strconv.ParseFloat(stringValue, 64)
	metric.Value = floatValue

	if err != nil {
		return Metric{}, errors.New("unable to parse value from statsD message")
	}

	metricType := ""

	if atIndex == -1 {
		metricType = message[ibarIndex+1 : len(message)]
		metric.Sampling = 1
	} else {
		metricType = message[ibarIndex+1 : atIndex-1]
		sampleRate := message[atIndex+1 : len(message)]
		floatSampleRate, err := strconv.ParseFloat(sampleRate, 64)

		if err != nil {
			return Metric{}, errors.New("unable to parse StatsD value")
		}

		metric.Sampling = floatSampleRate
	}

	switch string(metricType[:len(metricType)]) {
	case "ms":
		metric.Type = "timer"
	case "g":
		metric.Type = "gauge"
	case "c":
		metric.Type = "counter"
	default:
		fmt.Println(metricType)
		err = fmt.Errorf("invalid metric type: %q", metricType)
		return metric, err
	}

	return metric, nil
}
<|endoftext|>


<commit_before>package oak

import (
	"testing"
	"time"

	"github.com/oakmound/oak/v3/event"
	"github.com/oakmound/oak/v3/joystick"
	"github.com/oakmound/oak/v3/key"
	"github.com/oakmound/oak/v3/mouse"
	"github.com/oakmound/oak/v3/scene"
)

func TestTrackInputChanges(t *testing.T) {
	c1 := NewController()
	c1.SetLogicHandler(event.NewBus())
	c1.AddScene("1", scene.Scene{})
	go c1.Init("1", func(c Config) (Config, error) {
		c.TrackInputChanges = true
		return c, nil
	})
	time.Sleep(2 * time.Second)
	expectedType := new(InputType)
	*expectedType = KeyboardMouse
	failed := false
	c1.logicHandler.GlobalBind(event.InputChange, func(_ event.CID, payload interface{}) int {
		mode := payload.(InputType)
		if mode != *expectedType {
			failed = true
		}
		return 0
	})
	c1.TriggerKeyDown(key.Event{})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("keyboard change failed")
	}
	*expectedType = Joystick
	c1.logicHandler.Trigger("Tracking"+joystick.Change, &joystick.State{})
	c1.TriggerMouseEvent(mouse.Event{Event: mouse.Press})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("joystick change failed")
	}
	*expectedType = KeyboardMouse
	c1.TriggerMouseEvent(mouse.Event{Event: mouse.Press})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("mouse change failed")
	}
	c1.mostRecentInput = Joystick
	c1.TriggerKeyDown(key.Event{})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("keyboard change failed")
	}
}
<commit_msg>oak: fix joystick input tracker test<commit_after>package oak

import (
	"testing"
	"time"

	"github.com/oakmound/oak/v3/event"
	"github.com/oakmound/oak/v3/joystick"
	"github.com/oakmound/oak/v3/key"
	"github.com/oakmound/oak/v3/mouse"
	"github.com/oakmound/oak/v3/scene"
)

func TestTrackInputChanges(t *testing.T) {
	c1 := NewController()
	c1.SetLogicHandler(event.NewBus())
	c1.AddScene("1", scene.Scene{})
	go c1.Init("1", func(c Config) (Config, error) {
		c.TrackInputChanges = true
		return c, nil
	})
	time.Sleep(2 * time.Second)
	expectedType := new(InputType)
	*expectedType = KeyboardMouse
	failed := false
	c1.logicHandler.GlobalBind(event.InputChange, func(_ event.CID, payload interface{}) int {
		mode := payload.(InputType)
		if mode != *expectedType {
			failed = true
		}
		return 0
	})
	c1.TriggerKeyDown(key.Event{})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("keyboard change failed")
	}
	*expectedType = Joystick
	c1.logicHandler.Trigger("Tracking"+joystick.Change, &joystick.State{})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("joystick change failed")
	}
	*expectedType = KeyboardMouse
	c1.TriggerMouseEvent(mouse.Event{Event: mouse.Press})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("mouse change failed")
	}
	c1.mostRecentInput = Joystick
	c1.TriggerKeyDown(key.Event{})
	time.Sleep(2 * time.Second)
	if failed {
		t.Fatalf("keyboard change failed")
	}
}
<|endoftext|>


<commit_before>package bimg

import (
	"github.com/dustin/go-humanize"
	. "github.com/tj/go-debug"
	"runtime"
	"strconv"
	"time"
)

var debug = Debug("bimg")

// Print Go memory and garbage collector stats. Useful for debugging
func PrintMemoryStats() {
	log := Debug("memory")
	mem := memoryStats()

	log("\u001b[33m---- Memory Dump Stats ----\u001b[39m")
	log("Allocated: %s", humanize.Bytes(mem.Alloc))
	log("Total Allocated: %s", humanize.Bytes(mem.TotalAlloc))
	log("Memory Allocations: %d", mem.Mallocs)
	log("Memory Frees: %d", mem.Frees)
	log("Heap Allocated: %s", humanize.Bytes(mem.HeapAlloc))
	log("Heap System: %s", humanize.Bytes(mem.HeapSys))
	log("Heap In Use: %s", humanize.Bytes(mem.HeapInuse))
	log("Heap Idle: %s", humanize.Bytes(mem.HeapIdle))
	log("Heap OS Related: %s", humanize.Bytes(mem.HeapReleased))
	log("Heap Objects: %s", humanize.Bytes(mem.HeapObjects))
	log("Stack In Use: %s", humanize.Bytes(mem.StackInuse))
	log("Stack System: %s", humanize.Bytes(mem.StackSys))
	log("Stack Span In Use: %s", humanize.Bytes(mem.MSpanInuse))
	log("Stack Cache In Use: %s", humanize.Bytes(mem.MCacheInuse))
	log("Next GC cycle: %s", humanizeNano(mem.NextGC))
	log("Last GC cycle: %s", humanize.Time(time.Unix(0, int64(mem.LastGC))))
	log("\u001b[33m---- End Memory Dump ----\u001b[39m")
}

func memoryStats() runtime.MemStats {
	var mem runtime.MemStats
	runtime.ReadMemStats(&mem)
	return mem
}

func humanizeNano(n uint64) string {
	var suffix string

	switch {
	case n > 1e9:
		n /= 1e9
		suffix = "s"
	case n > 1e6:
		n /= 1e6
		suffix = "ms"
	case n > 1e3:
		n /= 1e3
		suffix = "us"
	default:
		suffix = "ns"
	}

	return strconv.Itoa(int(n)) + suffix
}
<commit_msg>refactor(debug)<commit_after>package bimg

import (
	"github.com/dustin/go-humanize"
	. "github.com/tj/go-debug"
	"runtime"
	"strconv"
	"time"
)

var debug = Debug("bimg")

// Print Go memory and garbage collector stats. Useful for debugging
func PrintMemoryStats() {
	log := Debug("memory")
	mem := memoryStats()

	log("\u001b[33m---- Memory Stats ----\u001b[39m")
	log("Allocated: %s", humanize.Bytes(mem.Alloc))
	log("Total Allocated: %s", humanize.Bytes(mem.TotalAlloc))
	log("Memory Allocations: %d", mem.Mallocs)
	log("Memory Frees: %d", mem.Frees)
	log("Heap Allocated: %s", humanize.Bytes(mem.HeapAlloc))
	log("Heap System: %s", humanize.Bytes(mem.HeapSys))
	log("Heap In Use: %s", humanize.Bytes(mem.HeapInuse))
	log("Heap Idle: %s", humanize.Bytes(mem.HeapIdle))
	log("Heap OS Related: %s", humanize.Bytes(mem.HeapReleased))
	log("Heap Objects: %s", humanize.Bytes(mem.HeapObjects))
	log("Stack In Use: %s", humanize.Bytes(mem.StackInuse))
	log("Stack System: %s", humanize.Bytes(mem.StackSys))
	log("Stack Span In Use: %s", humanize.Bytes(mem.MSpanInuse))
	log("Stack Cache In Use: %s", humanize.Bytes(mem.MCacheInuse))
	log("Next GC cycle: %s", humanizeNano(mem.NextGC))
	log("Last GC cycle: %s", humanize.Time(time.Unix(0, int64(mem.LastGC))))
	log("\u001b[33m---- Memory Stats ----\u001b[39m")
}

func memoryStats() runtime.MemStats {
	var mem runtime.MemStats
	runtime.ReadMemStats(&mem)
	return mem
}

func humanizeNano(n uint64) string {
	var suffix string

	switch {
	case n > 1e9:
		n /= 1e9
		suffix = "s"
	case n > 1e6:
		n /= 1e6
		suffix = "ms"
	case n > 1e3:
		n /= 1e3
		suffix = "us"
	default:
		suffix = "ns"
	}

	return strconv.Itoa(int(n)) + suffix
}
<|endoftext|>


<commit_before>package parsex

import (
	"fmt"
	"testing"
	"time"
)

var fromParser = Bind_(String("from"), TimeVar)

func TestFrom(t *testing.T) {
	theTime := time.Now()
	var fromData0 = []interface{}{"from", theTime}
	state := &StateInMemory{fromData0, 0}
	val, err := fromParser(state)
	if err == nil {
		fmt.Sprintf("success:%v\n", val)
	} else {
		t.Fatalf("except extract the time value %v", theTime)
	}
}
<commit_msg>add a test/sample for parsex<commit_after>package parsex

import (
	"testing"
	"time"
)

// 该测试用例模拟一个词法分析后的 token 流，定义一个时间区间规则，生成结果是一个匹配函数。
// 定义规则为 [from xxx] [to xxx] 。
// 匹配函数检查输入的时间是否在匹配区间内，并给出左边界到输入时间的间隔值。对于 to Time 校验，
// 因为没有左边界，返回是否在区间的校验结果，和 nil 。
//
// 这个验证证明 parsex 可以接在词法分析后面作为语法分析器使用，或者直接构造一个一般性的规则系统。

var (
	now       = time.Now()
	dur, _    = time.ParseDuration("-24h")
	yesterday = now.Add(dur)
)

var fromParser = Bind_(String("from"), TimeVar)

func from(st ParsexState) (interface{}, error) {
	if ts, err := fromParser(st); err == nil {
		return func(t time.Time) (bool, interface{}) {
			return !t.Before(ts.(time.Time)), t.Sub(ts.(time.Time))
		}, nil
	} else {
		return nil, err
	}
}

var toParser = Bind_(String("to"), TimeVar)

func to(st ParsexState) (interface{}, error) {
	if ts, err := toParser(st); err == nil {
		return func(t time.Time) (bool, interface{}) {
			return !t.After(ts.(time.Time)), nil
		}, nil
	} else {
		return nil, err
	}
}

var fromToParser = Union(fromParser, toParser)

func fromto(st ParsexState) (interface{}, error) {
	if ts, err := fromToParser(st); err == nil {
		return func(ti time.Time) (bool, interface{}) {
			ft := ts.([]interface{})
			f := ft[0].(time.Time)
			t := ft[1].(time.Time)
			return !ti.Before(f) && !ti.After(t), f.Sub(ti)
		}, nil
	} else {
		return nil, err
	}
}

func TestFromP0(t *testing.T) {
	var fromData0 = []interface{}{"from", now}
	state := &StateInMemory{fromData0, 0}
	val, err := fromParser(state)
	if err == nil {
		t.Logf("success:%v\n", val)
	} else {
		t.Fatalf("except extract the time value %v but %v", now, err)
	}
}

func TestFrom0(t *testing.T) {
	fromData0 := []interface{}{"from", yesterday}
	state := &StateInMemory{fromData0, 0}
	chk, err := from(state)
	checker := chk.(func(time.Time) (bool, interface{}))
	if err == nil {
		if ok, dur := checker(now); ok {
			t.Logf("now after yesterday %v", dur)
		} else {
			t.Logf("except now after yesterday 24hours but %v", dur)
		}
	} else {
		t.Fatalf("except extract the time checker from %v but %v", now, err)
	}
}

func TestFrom1(t *testing.T) {
	fromData0 := []interface{}{"from", now}
	state := &StateInMemory{fromData0, 0}
	chk, err := from(state)
	checker := chk.(func(time.Time) (bool, interface{}))
	if err == nil {
		if ok, dur := checker(now); ok {
			t.Logf("now after yesterday %v", dur)
		} else {
			t.Logf("except now after yesterday 0hours but %v", dur)
		}
	} else {
		t.Fatalf("except extract the time checker from %v but %v", now, err)
	}
}

func TestFrom2(t *testing.T) {
	fromData0 := []interface{}{"from", now}
	state := &StateInMemory{fromData0, 0}
	chk, err := from(state)
	checker := chk.(func(time.Time) (bool, interface{}))
	if err == nil {
		if ok, dur := checker(yesterday); !ok {
			t.Logf("now after yesterday %v", dur)
		} else {
			t.Logf("except now after yesterday 0hours but %v", dur)
		}
	} else {
		t.Fatalf("except extract the time checker from %v but %v", now, err)
	}
}

func TestToP0(t *testing.T) {
	var toData0 = []interface{}{"to", now}
	state := &StateInMemory{toData0, 0}
	val, err := toParser(state)
	if err == nil {
		t.Logf("success:%v\n", val)
	} else {
		t.Fatalf("except extract the time value %v but %v", now, err)
	}
}

func TestTo0(t *testing.T) {
	toData0 := []interface{}{"to", now}
	state := &StateInMemory{toData0, 0}
	chk, err := to(state)
	if err == nil {
		checker := chk.(func(time.Time) (bool, interface{}))
		if ok, dur := checker(yesterday); !ok {
			t.Fatalf("except now after yesterday 24hours but %v", dur)
		}
	} else {
		t.Fatalf("except extract the time checker from %v but %v", now, err)
	}
}

func TestTo1(t *testing.T) {
	toData0 := []interface{}{"to", now}
	state := &StateInMemory{toData0, 0}
	chk, err := to(state)
	if err == nil {
		checker := chk.(func(time.Time) (bool, interface{}))
		if ok, dur := checker(now); !ok {
			t.Fatalf("except now after yesterday 0hours but %v", dur)
		}
	} else {
		t.Fatalf("except extract the time checker from %v but %v", now, err)
	}
}

func TestTo2(t *testing.T) {
	toData0 := []interface{}{"to", yesterday}
	state := &StateInMemory{toData0, 0}
	chk, err := to(state)
	if err == nil {
		checker := chk.(func(time.Time) (bool, interface{}))
		if ok, dur := checker(now); ok {
			t.Fatalf("except now after yesterday 0hours but %v", dur)
		}
	} else {
		t.Fatalf("except extract the time checker from %v but %v", now, err)
	}
}

func TestFromToP0(t *testing.T) {
	var toData0 = []interface{}{"from", yesterday, "to", now}
	state := &StateInMemory{toData0, 0}
	val, err := fromToParser(state)
	if err == nil {
		t.Logf("success:%v\n", val)
	} else {
		t.Fatalf("except extract the time values %v but %v", []interface{}{yesterday, now}, err)
	}
}

func TestFromTo0(t *testing.T) {
	data := []interface{}{"from", yesterday, "to", now}
	state := &StateInMemory{data, 0}
	checker, err := fromto(state)
	if err == nil {
		d, _ := time.ParseDuration("12h")
		date := yesterday.Add(d)
		if ok, dur := checker.(func(time.Time) (bool, interface{}))(date); ok {
			t.Logf("success:%v\n", dur)
		} else {
			t.Fatalf("except find %v in duration from %v to %v but failed", date, yesterday, now)
		}
	} else {
		t.Fatalf("except create a duration checker from %v to %v but failed: %v", yesterday, now, err)
	}
}
<|endoftext|>


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

package goplay

import (
	"appengine"
	"appengine/datastore"
	"bytes"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
)

const salt = "[replace this with something unique]"

type Snippet struct {
	Body []byte
}

func (s *Snippet) Id() string {
	h := sha1.New()
	io.WriteString(h, salt)
	h.Write(s.Body)
	sum := h.Sum(nil)
	b := make([]byte, base64.URLEncoding.EncodedLen(len(sum)))
	base64.URLEncoding.Encode(b, sum)
	return string(b)[:10]
}

func init() {
	http.HandleFunc("/share", share)
}

func share(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}
	c := appengine.NewContext(r)

	var body bytes.Buffer
	_, err := body.ReadFrom(r.Body)
	if err != nil {
		c.Errorf("reading Body: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}
	r.Body.Close()

	snip := &Snippet{Body: body.Bytes()}
	id := snip.Id()
	key := datastore.NewKey(c, "Snippet", id, 0, nil)
	_, err = datastore.Put(c, key, snip)
	if err != nil {
		c.Errorf("putting Snippet: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, id)
}
<commit_msg>playground: limit snippet size<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package goplay

import (
	"bytes"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"

	"appengine"
	"appengine/datastore"
)

const salt = "[replace this with something unique]"

const maxSnippetSize = 1 << 16 // 64KB

type Snippet struct {
	Body []byte
}

func (s *Snippet) Id() string {
	h := sha1.New()
	io.WriteString(h, salt)
	h.Write(s.Body)
	sum := h.Sum(nil)
	b := make([]byte, base64.URLEncoding.EncodedLen(len(sum)))
	base64.URLEncoding.Encode(b, sum)
	return string(b)[:10]
}

func init() {
	http.HandleFunc("/share", share)
}

func share(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}
	c := appengine.NewContext(r)

	var body bytes.Buffer
	_, err := io.Copy(&body, io.LimitReader(r.Body, maxSnippetSize+1))
	r.Body.Close()
	if err != nil {
		c.Errorf("reading Body: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}
	if body.Len() > maxSnippetSize {
		http.Error(w, "Snippet is too large", http.StatusRequestEntityTooLarge)
		return
	}

	snip := &Snippet{Body: body.Bytes()}
	id := snip.Id()
	key := datastore.NewKey(c, "Snippet", id, 0, nil)
	_, err = datastore.Put(c, key, snip)
	if err != nil {
		c.Errorf("putting Snippet: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, id)
}
<|endoftext|>


<commit_before>package audio

import (
	"time"
)

type realtimeStream struct {
	stream       Stream
	lastError    error
	buffer       []int32
	readPosition int
}

// NewRealtimeStream converts a stream into a buffered stream for use in
// realtime applications, such as audio over a network.
func NewRealtimeStream(stream Stream) Stream {
	newStream := &realtimeStream{
		stream:       stream,
		lastError:    nil,
		buffer:       make([]int32, 4096),
		readPosition: 4096,
	}

	go newStream.run()
	return newStream
}

func (r *realtimeStream) run() {
	buffer := make([]int32, 1024)
	for {
		n, err := r.stream.Read(buffer)
		r.buffer = append(r.buffer[:len(r.buffer)-n], buffer[:n]...)

		r.readPosition -= n
		if r.readPosition < 0 {
			r.readPosition = len(r.buffer) / 2
		}

		if err != nil {
			r.lastError = err
			return
		}
	}
}

func (r *realtimeStream) Read(dst interface{}) (int, error) {
	dstLen := SliceLength(dst)
	if dstLen > 2048 {
		return 0, ErrBufferTooLarge
	}

	for {
		available := (4096 - r.readPosition)
		if available >= dstLen || r.lastError != nil {
			if dstLen > available {
				err := ReadFromInt32(dst, r.buffer[r.readPosition:], available)
				r.readPosition += available
				if r.lastError != nil {
					return available, r.lastError
				}

				return available, err
			}

			err := ReadFromInt32(dst, r.buffer[r.readPosition:], dstLen)
			r.readPosition += dstLen
			if r.lastError != nil {
				return available, r.lastError
			}

			return available, err
		} else {
			time.Sleep(time.Millisecond * 10)
		}
	}
}

func (r *realtimeStream) SampleRate() int {
	return r.stream.SampleRate()
}
<commit_msg>Will the linting ever end?<commit_after>package audio

import (
	"time"
)

type realtimeStream struct {
	stream       Stream
	lastError    error
	buffer       []int32
	readPosition int
}

// NewRealtimeStream converts a stream into a buffered stream for use in
// realtime applications, such as audio over a network.
func NewRealtimeStream(stream Stream) Stream {
	newStream := &realtimeStream{
		stream:       stream,
		lastError:    nil,
		buffer:       make([]int32, 4096),
		readPosition: 4096,
	}

	go newStream.run()
	return newStream
}

func (r *realtimeStream) run() {
	buffer := make([]int32, 1024)
	for {
		n, err := r.stream.Read(buffer)
		r.buffer = append(r.buffer[:len(r.buffer)-n], buffer[:n]...)

		r.readPosition -= n
		if r.readPosition < 0 {
			r.readPosition = len(r.buffer) / 2
		}

		if err != nil {
			r.lastError = err
			return
		}
	}
}

func (r *realtimeStream) Read(dst interface{}) (int, error) {
	dstLen := SliceLength(dst)
	if dstLen > 2048 {
		return 0, ErrBufferTooLarge
	}

	for {
		available := (4096 - r.readPosition)
		if available >= dstLen || r.lastError != nil {
			if dstLen > available {
				err := ReadFromInt32(dst, r.buffer[r.readPosition:], available)
				r.readPosition += available
				if r.lastError != nil {
					return available, r.lastError
				}

				return available, err
			}

			err := ReadFromInt32(dst, r.buffer[r.readPosition:], dstLen)
			r.readPosition += dstLen
			if r.lastError != nil {
				return available, r.lastError
			}

			return available, err
		}

		time.Sleep(time.Millisecond * 10)
	}
}

func (r *realtimeStream) SampleRate() int {
	return r.stream.SampleRate()
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package ui

import (
	"strconv"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

var canvas *js.Object

type userInterface struct {
	scale       float64
	deviceScale float64
	sizeChanged bool
	windowFocus bool
}

var currentUI = &userInterface{
	sizeChanged: true,
	windowFocus: true,
}

// NOTE: This returns true even when the browser is not active.
func shown() bool {
	return !js.Global.Get("document").Get("hidden").Bool()
}

func SetScreenSize(width, height int) bool {
	return currentUI.setScreenSize(width, height, currentUI.scale)
}

func SetScreenScale(scale float64) bool {
	width, height := currentUI.size()
	return currentUI.setScreenSize(width, height, scale)
}

func ScreenScale() float64 {
	return currentUI.scale
}

func SetFullscreen(fullscreen bool) bool {
	// TODO: Implement
	return false
}

func IsFullscreen() bool {
	// TODO: Implement
	return false
}

func ScreenOffset() (float64, float64) {
	return 0, 0
}

func adjustCursorPosition(x, y int) (int, int) {
	return x, y
}

func SetCursorVisibility(visibility bool) {
	if visibility {
		canvas.Get("style").Set("cursor", "auto")
	} else {
		canvas.Get("style").Set("cursor", "none")
	}
}

func (u *userInterface) actualScreenScale() float64 {
	return u.scale * u.deviceScale
}

func (u *userInterface) update(g GraphicsContext) error {
	if !u.windowFocus {
		return nil
	}
	if opengl.GetContext().IsContextLost() {
		opengl.GetContext().RestoreContext()
		g.Invalidate()
	}
	currentInput.updateGamepads()
	if u.sizeChanged {
		u.sizeChanged = false
		w, h := u.size()
		g.SetSize(w, h, u.actualScreenScale())
		return nil
	}
	if err := g.Update(); err != nil {
		return err
	}
	return nil
}

func (u *userInterface) loop(g GraphicsContext) error {
	ch := make(chan error)
	var f func()
	f = func() {
		go func() {
			if err := u.update(g); err != nil {
				ch <- err
				close(ch)
				return
			}
			js.Global.Get("window").Call("requestAnimationFrame", f)
		}()
	}
	f()
	return <-ch
}

func touchEventToTouches(e *js.Object) []touch {
	scale := currentUI.scale
	j := e.Get("targetTouches")
	rect := canvas.Call("getBoundingClientRect")
	left, top := rect.Get("left").Int(), rect.Get("top").Int()
	t := make([]touch, j.Get("length").Int())
	for i := 0; i < len(t); i++ {
		jj := j.Call("item", i)
		t[i].id = jj.Get("identifier").Int()
		t[i].x = int(float64(jj.Get("clientX").Int()-left) / scale)
		t[i].y = int(float64(jj.Get("clientY").Int()-top) / scale)
	}
	return t
}

func init() {
	if err := initialize(); err != nil {
		panic(err)
	}
}

func initialize() error {
	// Do nothing in node.js.
	if js.Global.Get("require") != js.Undefined {
		return nil
	}

	doc := js.Global.Get("document")
	window := js.Global.Get("window")
	if doc.Get("body") == nil {
		ch := make(chan struct{})
		window.Call("addEventListener", "load", func() {
			close(ch)
		})
		<-ch
	}
	window.Call("addEventListener", "focus", func() {
		currentUI.windowFocus = true
	})
	window.Call("addEventListener", "blur", func() {
		currentUI.windowFocus = false
	})

	// Adjust the initial scale to 1.
	// https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
	meta := doc.Call("createElement", "meta")
	meta.Set("name", "viewport")
	meta.Set("content", "width=device-width, initial-scale=1")
	doc.Get("head").Call("appendChild", meta)

	canvas = doc.Call("createElement", "canvas")
	canvas.Set("width", 16)
	canvas.Set("height", 16)
	doc.Get("body").Call("appendChild", canvas)

	htmlStyle := doc.Get("documentElement").Get("style")
	htmlStyle.Set("height", "100%")
	htmlStyle.Set("margin", "0")
	htmlStyle.Set("padding", "0")

	bodyStyle := doc.Get("body").Get("style")
	bodyStyle.Set("backgroundColor", "#000")
	bodyStyle.Set("position", "relative")
	bodyStyle.Set("height", "100%")
	bodyStyle.Set("margin", "0")
	bodyStyle.Set("padding", "0")
	// TODO: This is OK as long as the game is in an independent iframe.
	// What if the canvas is embedded in a HTML directly?
	doc.Get("body").Call("addEventListener", "click", func() {
		canvas.Call("focus")
	})

	canvasStyle := canvas.Get("style")
	canvasStyle.Set("position", "absolute")

	// Make the canvas focusable.
	canvas.Call("setAttribute", "tabindex", 1)
	canvas.Get("style").Set("outline", "none")

	// Keyboard
	canvas.Call("addEventListener", "keydown", func(e *js.Object) {
		e.Call("preventDefault")
		if e.Get("code") == js.Undefined {
			// Assume that UA is Safari.
			code := e.Get("keyCode").Int()
			currentInput.keyDownSafari(code)
			return
		}
		code := e.Get("code").String()
		currentInput.keyDown(code)
	})
	canvas.Call("addEventListener", "keyup", func(e *js.Object) {
		e.Call("preventDefault")
		if e.Get("code") == js.Undefined {
			// Assume that UA is Safari.
			code := e.Get("keyCode").Int()
			currentInput.keyUpSafari(code)
		}
		code := e.Get("code").String()
		currentInput.keyUp(code)
	})

	// Mouse
	canvas.Call("addEventListener", "mousedown", func(e *js.Object) {
		e.Call("preventDefault")
		button := e.Get("button").Int()
		currentInput.mouseDown(button)
		setMouseCursorFromEvent(e)
	})
	canvas.Call("addEventListener", "mouseup", func(e *js.Object) {
		e.Call("preventDefault")
		button := e.Get("button").Int()
		currentInput.mouseUp(button)
		setMouseCursorFromEvent(e)
	})
	canvas.Call("addEventListener", "mousemove", func(e *js.Object) {
		e.Call("preventDefault")
		setMouseCursorFromEvent(e)
	})
	canvas.Call("addEventListener", "contextmenu", func(e *js.Object) {
		e.Call("preventDefault")
	})

	// Touch
	canvas.Call("addEventListener", "touchstart", func(e *js.Object) {
		e.Call("preventDefault")
		currentInput.updateTouches(touchEventToTouches(e))
	})
	canvas.Call("addEventListener", "touchend", func(e *js.Object) {
		e.Call("preventDefault")
		currentInput.updateTouches(touchEventToTouches(e))
	})
	canvas.Call("addEventListener", "touchmove", func(e *js.Object) {
		e.Call("preventDefault")
		currentInput.updateTouches(touchEventToTouches(e))
	})

	// Gamepad
	window.Call("addEventListener", "gamepadconnected", func(e *js.Object) {
		// Do nothing.
	})

	canvas.Call("addEventListener", "webglcontextlost", func(e *js.Object) {
		e.Call("preventDefault")
	})
	canvas.Call("addEventListener", "webglcontextrestored", func(e *js.Object) {
		// Do nothing.
	})

	return nil
}

func setMouseCursorFromEvent(e *js.Object) {
	scale := currentUI.scale
	rect := canvas.Call("getBoundingClientRect")
	x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
	x -= rect.Get("left").Int()
	y -= rect.Get("top").Int()
	currentInput.setMouseCursor(int(float64(x)/scale), int(float64(y)/scale))
}

func devicePixelRatio() float64 {
	ratio := js.Global.Get("window").Get("devicePixelRatio").Float()
	if ratio == 0 {
		ratio = 1
	}
	return ratio
}

func RunMainThreadLoop(ch <-chan error) error {
	return <-ch
}

func Run(width, height int, scale float64, title string, g GraphicsContext) error {
	u := currentUI
	doc := js.Global.Get("document")
	doc.Set("title", title)
	u.setScreenSize(width, height, scale)
	canvas.Call("focus")
	if err := opengl.Init(); err != nil {
		return err
	}
	return u.loop(g)
}

func (u *userInterface) size() (width, height int) {
	a := u.actualScreenScale()
	if a == 0 {
		// a == 0 only on the initial state.
		return
	}
	width = int(canvas.Get("width").Float() / a)
	height = int(canvas.Get("height").Float() / a)
	return
}

func isSafari() bool {
	ua := js.Global.Get("navigator").Get("userAgent").String()
	if !strings.Contains(ua, "Safari") {
		return false
	}
	if strings.Contains(ua, "Chrome") {
		return false
	}
	return true
}

func (u *userInterface) setScreenSize(width, height int, scale float64) bool {
	w, h := u.size()
	s := u.scale
	if w == width && h == height && s == scale {
		return false
	}
	u.scale = scale
	// CSS imageRendering seems useful to enlarge the screen,
	// but doesn't work in some cases (#306):
	// * Chrome just after restoring the lost context
	// * Safari
	// Let's use the pixel ratio as it is here.
	u.deviceScale = devicePixelRatio()
	canvas.Set("width", int(float64(width)*u.actualScreenScale()))
	canvas.Set("height", int(float64(height)*u.actualScreenScale()))
	canvasStyle := canvas.Get("style")

	cssWidth := int(float64(width) * scale)
	cssHeight := int(float64(height) * scale)
	canvasStyle.Set("width", strconv.Itoa(cssWidth)+"px")
	canvasStyle.Set("height", strconv.Itoa(cssHeight)+"px")
	// CSS calc requires space chars.
	canvasStyle.Set("left", "calc((100% - "+strconv.Itoa(cssWidth)+"px) / 2)")
	canvasStyle.Set("top", "calc((100% - "+strconv.Itoa(cssHeight)+"px) / 2)")
	u.sizeChanged = true
	return true
}
<commit_msg>ui: Implement fullscreen for browsers (#387)<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package ui

import (
	"strconv"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

var canvas *js.Object

type userInterface struct {
	width      int
	height     int
	scale      float64
	fullscreen bool

	deviceScale float64
	sizeChanged bool
	windowFocus bool
}

var currentUI = &userInterface{
	sizeChanged: true,
	windowFocus: true,
}

// NOTE: This returns true even when the browser is not active.
func shown() bool {
	return !js.Global.Get("document").Get("hidden").Bool()
}

func SetScreenSize(width, height int) bool {
	return currentUI.setScreenSize(currentUI.width, currentUI.height, currentUI.scale, currentUI.fullscreen)
}

func SetScreenScale(scale float64) bool {
	return currentUI.setScreenSize(currentUI.width, currentUI.height, scale, currentUI.fullscreen)
}

func ScreenScale() float64 {
	return currentUI.scale
}

func SetFullscreen(fullscreen bool) {
	currentUI.setScreenSize(currentUI.width, currentUI.height, currentUI.scale, fullscreen)
}

func IsFullscreen() bool {
	return currentUI.fullscreen
}

func ScreenOffset() (float64, float64) {
	return 0, 0
}

func adjustCursorPosition(x, y int) (int, int) {
	return x, y
}

func SetCursorVisibility(visibility bool) {
	if visibility {
		canvas.Get("style").Set("cursor", "auto")
	} else {
		canvas.Get("style").Set("cursor", "none")
	}
}

func (u *userInterface) getScale() float64 {
	if !u.fullscreen {
		return u.scale
	}
	doc := js.Global.Get("document")
	body := doc.Get("body")
	bw := body.Get("clientWidth").Float()
	bh := body.Get("clientHeight").Float()
	sw := bw / float64(u.width)
	sh := bh / float64(u.height)
	if sw > sh {
		return sh
	}
	return sw
}

func (u *userInterface) actualScreenScale() float64 {
	return u.getScale() * u.deviceScale
}

func (u *userInterface) update(g GraphicsContext) error {
	if !u.windowFocus {
		return nil
	}
	if opengl.GetContext().IsContextLost() {
		opengl.GetContext().RestoreContext()
		g.Invalidate()
	}
	currentInput.updateGamepads()
	if u.sizeChanged {
		u.sizeChanged = false
		g.SetSize(u.width, u.height, u.actualScreenScale())
		return nil
	}
	if err := g.Update(); err != nil {
		return err
	}
	return nil
}

func (u *userInterface) loop(g GraphicsContext) error {
	ch := make(chan error)
	var f func()
	f = func() {
		go func() {
			if err := u.update(g); err != nil {
				ch <- err
				close(ch)
				return
			}
			js.Global.Get("window").Call("requestAnimationFrame", f)
		}()
	}
	f()
	return <-ch
}

func touchEventToTouches(e *js.Object) []touch {
	scale := currentUI.getScale()
	j := e.Get("targetTouches")
	rect := canvas.Call("getBoundingClientRect")
	left, top := rect.Get("left").Int(), rect.Get("top").Int()
	t := make([]touch, j.Get("length").Int())
	for i := 0; i < len(t); i++ {
		jj := j.Call("item", i)
		t[i].id = jj.Get("identifier").Int()
		t[i].x = int(float64(jj.Get("clientX").Int()-left) / scale)
		t[i].y = int(float64(jj.Get("clientY").Int()-top) / scale)
	}
	return t
}

func init() {
	if err := initialize(); err != nil {
		panic(err)
	}
}

func initialize() error {
	// Do nothing in node.js.
	if js.Global.Get("require") != js.Undefined {
		return nil
	}

	doc := js.Global.Get("document")
	window := js.Global.Get("window")
	if doc.Get("body") == nil {
		ch := make(chan struct{})
		window.Call("addEventListener", "load", func() {
			close(ch)
		})
		<-ch
	}
	window.Call("addEventListener", "focus", func() {
		currentUI.windowFocus = true
	})
	window.Call("addEventListener", "blur", func() {
		currentUI.windowFocus = false
	})

	// Adjust the initial scale to 1.
	// https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
	meta := doc.Call("createElement", "meta")
	meta.Set("name", "viewport")
	meta.Set("content", "width=device-width, initial-scale=1")
	doc.Get("head").Call("appendChild", meta)

	canvas = doc.Call("createElement", "canvas")
	canvas.Set("width", 16)
	canvas.Set("height", 16)
	doc.Get("body").Call("appendChild", canvas)

	htmlStyle := doc.Get("documentElement").Get("style")
	htmlStyle.Set("height", "100%")
	htmlStyle.Set("margin", "0")
	htmlStyle.Set("padding", "0")

	bodyStyle := doc.Get("body").Get("style")
	bodyStyle.Set("backgroundColor", "#000")
	bodyStyle.Set("position", "relative")
	bodyStyle.Set("height", "100%")
	bodyStyle.Set("margin", "0")
	bodyStyle.Set("padding", "0")
	// TODO: This is OK as long as the game is in an independent iframe.
	// What if the canvas is embedded in a HTML directly?
	doc.Get("body").Call("addEventListener", "click", func() {
		canvas.Call("focus")
	})

	canvasStyle := canvas.Get("style")
	canvasStyle.Set("position", "absolute")

	// Make the canvas focusable.
	canvas.Call("setAttribute", "tabindex", 1)
	canvas.Get("style").Set("outline", "none")

	// Keyboard
	canvas.Call("addEventListener", "keydown", func(e *js.Object) {
		e.Call("preventDefault")
		if e.Get("code") == js.Undefined {
			// Assume that UA is Safari.
			code := e.Get("keyCode").Int()
			currentInput.keyDownSafari(code)
			return
		}
		code := e.Get("code").String()
		currentInput.keyDown(code)
	})
	canvas.Call("addEventListener", "keyup", func(e *js.Object) {
		e.Call("preventDefault")
		if e.Get("code") == js.Undefined {
			// Assume that UA is Safari.
			code := e.Get("keyCode").Int()
			currentInput.keyUpSafari(code)
		}
		code := e.Get("code").String()
		currentInput.keyUp(code)
	})

	// Mouse
	canvas.Call("addEventListener", "mousedown", func(e *js.Object) {
		e.Call("preventDefault")
		button := e.Get("button").Int()
		currentInput.mouseDown(button)
		setMouseCursorFromEvent(e)
	})
	canvas.Call("addEventListener", "mouseup", func(e *js.Object) {
		e.Call("preventDefault")
		button := e.Get("button").Int()
		currentInput.mouseUp(button)
		setMouseCursorFromEvent(e)
	})
	canvas.Call("addEventListener", "mousemove", func(e *js.Object) {
		e.Call("preventDefault")
		setMouseCursorFromEvent(e)
	})
	canvas.Call("addEventListener", "contextmenu", func(e *js.Object) {
		e.Call("preventDefault")
	})

	// Touch
	canvas.Call("addEventListener", "touchstart", func(e *js.Object) {
		e.Call("preventDefault")
		currentInput.updateTouches(touchEventToTouches(e))
	})
	canvas.Call("addEventListener", "touchend", func(e *js.Object) {
		e.Call("preventDefault")
		currentInput.updateTouches(touchEventToTouches(e))
	})
	canvas.Call("addEventListener", "touchmove", func(e *js.Object) {
		e.Call("preventDefault")
		currentInput.updateTouches(touchEventToTouches(e))
	})

	// Gamepad
	window.Call("addEventListener", "gamepadconnected", func(e *js.Object) {
		// Do nothing.
	})

	canvas.Call("addEventListener", "webglcontextlost", func(e *js.Object) {
		e.Call("preventDefault")
	})
	canvas.Call("addEventListener", "webglcontextrestored", func(e *js.Object) {
		// Do nothing.
	})

	return nil
}

func setMouseCursorFromEvent(e *js.Object) {
	scale := currentUI.getScale()
	rect := canvas.Call("getBoundingClientRect")
	x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
	x -= rect.Get("left").Int()
	y -= rect.Get("top").Int()
	currentInput.setMouseCursor(int(float64(x)/scale), int(float64(y)/scale))
}

func devicePixelRatio() float64 {
	ratio := js.Global.Get("window").Get("devicePixelRatio").Float()
	if ratio == 0 {
		ratio = 1
	}
	return ratio
}

func RunMainThreadLoop(ch <-chan error) error {
	return <-ch
}

func Run(width, height int, scale float64, title string, g GraphicsContext) error {
	u := currentUI
	doc := js.Global.Get("document")
	doc.Set("title", title)
	u.setScreenSize(width, height, scale, u.fullscreen)
	canvas.Call("focus")
	if err := opengl.Init(); err != nil {
		return err
	}
	return u.loop(g)
}

func isSafari() bool {
	ua := js.Global.Get("navigator").Get("userAgent").String()
	if !strings.Contains(ua, "Safari") {
		return false
	}
	if strings.Contains(ua, "Chrome") {
		return false
	}
	return true
}

func (u *userInterface) setScreenSize(width, height int, scale float64, fullscreen bool) bool {
	if u.width == width && u.height == height &&
		u.scale == scale && fullscreen == u.fullscreen {
		return false
	}
	u.width = width
	u.height = height
	u.scale = scale
	u.fullscreen = fullscreen

	// CSS imageRendering seems useful to enlarge the screen,
	// but doesn't work in some cases (#306):
	// * Chrome just after restoring the lost context
	// * Safari
	// Let's use the pixel ratio as it is here.
	u.deviceScale = devicePixelRatio()

	canvas.Set("width", int(float64(width)*u.actualScreenScale()))
	canvas.Set("height", int(float64(height)*u.actualScreenScale()))
	canvasStyle := canvas.Get("style")

	scale = u.getScale()
	cssWidth := int(float64(width) * scale)
	cssHeight := int(float64(height) * scale)
	canvasStyle.Set("width", strconv.Itoa(cssWidth)+"px")
	canvasStyle.Set("height", strconv.Itoa(cssHeight)+"px")
	// CSS calc requires space chars.
	canvasStyle.Set("left", "calc((100% - "+strconv.Itoa(cssWidth)+"px) / 2)")
	canvasStyle.Set("top", "calc((100% - "+strconv.Itoa(cssHeight)+"px) / 2)")

	u.sizeChanged = true
	return true
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package ui

import (
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/webgl"
	"github.com/hajimehoshi/ebiten/internal/opengl"
	"strconv"
)

var canvas js.Object
var context *opengl.Context

func shown() bool {
	return !js.Global.Get("document").Get("hidden").Bool()
}

func Use(f func(*opengl.Context)) {
	f(context)
}

func vsync() {
	ch := make(chan struct{})
	js.Global.Get("window").Call("requestAnimationFrame", func() {
		close(ch)
	})
	<-ch
}

func DoEvents() error {
	vsync()
	for !shown() {
		vsync()
	}
	currentInput.updateGamepads()
	return nil
}

func Terminate() {
	// Do nothing.
}

func IsClosed() bool {
	return false
}

func SwapBuffers() {
	// Do nothing.
}

func init() {
	if js.Global.Get("require") != js.Undefined {
		// Use headless-gl for testing.
		nodeGl := js.Global.Call("require", "gl")
		webglContext := nodeGl.Call("createContext", 16, 16)
		context = opengl.NewContext(&webgl.Context{Object: webglContext})
		return
	}

	doc := js.Global.Get("document")
	window := js.Global.Get("window")
	if doc.Get("body") == nil {
		ch := make(chan struct{})
		window.Call("addEventListener", "load", func() {
			close(ch)
		})
		<-ch
	}
	doc.Call("addEventListener", "keydown", func(e js.Object) bool {
		code := e.Get("keyCode").Int()
		// Backspace
		if code == 8 {
			return false
		}
		// Functions
		if 112 <= code && code <= 123 {
			return false
		}
		// Alt and arrows
		if code == 37 && code == 39 {
			// Don't need to check Alt.
			return false
		}
		return true
	})

	canvas = doc.Call("createElement", "canvas")
	canvas.Set("width", 16)
	canvas.Set("height", 16)
	doc.Get("body").Call("appendChild", canvas)

	htmlStyle := doc.Get("documentElement").Get("style")
	htmlStyle.Set("height", "100%")
	htmlStyle.Set("margin", "0")
	htmlStyle.Set("padding", "0")

	bodyStyle := doc.Get("body").Get("style")
	bodyStyle.Set("backgroundColor", "#000")
	bodyStyle.Set("position", "relative")
	bodyStyle.Set("height", "100%")
	bodyStyle.Set("margin", "0")
	bodyStyle.Set("padding", "0")
	doc.Get("body").Call("addEventListener", "click", func() {
		canvas.Call("focus")
	})

	canvasStyle := canvas.Get("style")
	canvasStyle.Set("position", "absolute")

	webglContext, err := webgl.NewContext(canvas, &webgl.ContextAttributes{
		Alpha:              true,
		PremultipliedAlpha: true,
	})
	if err != nil {
		panic(err)
	}
	context = opengl.NewContext(webglContext)

	// Make the canvas focusable.
	canvas.Call("setAttribute", "tabindex", 1)
	canvas.Get("style").Set("outline", "none")

	// Keyboard
	canvas.Call("addEventListener", "keydown", func(e js.Object) bool {
		code := e.Get("keyCode").Int()
		currentInput.keyDown(code)
		return false
	})
	canvas.Call("addEventListener", "keyup", func(e js.Object) bool {
		code := e.Get("keyCode").Int()
		currentInput.keyUp(code)
		return false
	})

	// Mouse
	canvas.Call("addEventListener", "mousedown", func(e js.Object) bool {
		button := e.Get("button").Int()
		currentInput.mouseDown(button)
		return false
	})
	canvas.Call("addEventListener", "mouseup", func(e js.Object) bool {
		button := e.Get("button").Int()
		currentInput.mouseUp(button)
		return false
	})
	canvas.Call("addEventListener", "contextmenu", func(e js.Object) bool {
		return false
	})

	// Gamepad
	window.Call("addEventListener", "gamepadconnected", func(e js.Object) {
	})
}

func devicePixelRatio() int {
	// TODO: What if ratio is not an integer but a float?
	ratio := js.Global.Get("window").Get("devicePixelRatio").Int()
	if ratio == 0 {
		ratio = 1
	}
	return ratio
}

func Start(width, height, scale int, title string) (actualScale int, err error) {
	doc := js.Global.Get("document")
	doc.Set("title", title)
	actualScale = scale * devicePixelRatio()
	canvas.Set("width", width*actualScale)
	canvas.Set("height", height*actualScale)
	canvasStyle := canvas.Get("style")

	cssWidth := width * scale
	cssHeight := height * scale
	canvasStyle.Set("width", strconv.Itoa(cssWidth)+"px")
	canvasStyle.Set("height", strconv.Itoa(cssHeight)+"px")
	// CSS calc requires space chars.
	canvasStyle.Set("left", "calc(50% - "+strconv.Itoa(cssWidth/2)+"px)")
	canvasStyle.Set("top", "calc(50% - "+strconv.Itoa(cssHeight/2)+"px)")

	canvas.Call("addEventListener", "mousemove", func(e js.Object) {
		rect := canvas.Call("getBoundingClientRect")
		x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
		x -= rect.Get("left").Int()
		y -= rect.Get("top").Int()
		currentInput.mouseMove(x/scale, y/scale)
	})
	canvas.Call("focus")

	return actualScale, nil
}
<commit_msg>Bug fix: Use prevent default properly<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package ui

import (
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/webgl"
	"github.com/hajimehoshi/ebiten/internal/opengl"
	"strconv"
)

var canvas js.Object
var context *opengl.Context

func shown() bool {
	return !js.Global.Get("document").Get("hidden").Bool()
}

func Use(f func(*opengl.Context)) {
	f(context)
}

func vsync() {
	ch := make(chan struct{})
	js.Global.Get("window").Call("requestAnimationFrame", func() {
		close(ch)
	})
	<-ch
}

func DoEvents() error {
	vsync()
	for !shown() {
		vsync()
	}
	currentInput.updateGamepads()
	return nil
}

func Terminate() {
	// Do nothing.
}

func IsClosed() bool {
	return false
}

func SwapBuffers() {
	// Do nothing.
}

func init() {
	if js.Global.Get("require") != js.Undefined {
		// Use headless-gl for testing.
		nodeGl := js.Global.Call("require", "gl")
		webglContext := nodeGl.Call("createContext", 16, 16)
		context = opengl.NewContext(&webgl.Context{Object: webglContext})
		return
	}

	doc := js.Global.Get("document")
	window := js.Global.Get("window")
	if doc.Get("body") == nil {
		ch := make(chan struct{})
		window.Call("addEventListener", "load", func() {
			close(ch)
		})
		<-ch
	}

	canvas = doc.Call("createElement", "canvas")
	canvas.Set("width", 16)
	canvas.Set("height", 16)
	doc.Get("body").Call("appendChild", canvas)

	htmlStyle := doc.Get("documentElement").Get("style")
	htmlStyle.Set("height", "100%")
	htmlStyle.Set("margin", "0")
	htmlStyle.Set("padding", "0")

	bodyStyle := doc.Get("body").Get("style")
	bodyStyle.Set("backgroundColor", "#000")
	bodyStyle.Set("position", "relative")
	bodyStyle.Set("height", "100%")
	bodyStyle.Set("margin", "0")
	bodyStyle.Set("padding", "0")
	doc.Get("body").Call("addEventListener", "click", func() {
		canvas.Call("focus")
	})

	canvasStyle := canvas.Get("style")
	canvasStyle.Set("position", "absolute")

	webglContext, err := webgl.NewContext(canvas, &webgl.ContextAttributes{
		Alpha:              true,
		PremultipliedAlpha: true,
	})
	if err != nil {
		panic(err)
	}
	context = opengl.NewContext(webglContext)

	// Make the canvas focusable.
	canvas.Call("setAttribute", "tabindex", 1)
	canvas.Get("style").Set("outline", "none")

	// Keyboard
	canvas.Call("addEventListener", "keydown", func(e js.Object) {
		e.Call("preventDefault")
		code := e.Get("keyCode").Int()
		currentInput.keyDown(code)
	})
	canvas.Call("addEventListener", "keyup", func(e js.Object) {
		e.Call("preventDefault")
		code := e.Get("keyCode").Int()
		currentInput.keyUp(code)
	})

	// Mouse
	canvas.Call("addEventListener", "mousedown", func(e js.Object) {
		e.Call("preventDefault")
		button := e.Get("button").Int()
		currentInput.mouseDown(button)
	})
	canvas.Call("addEventListener", "mouseup", func(e js.Object) {
		e.Call("preventDefault")
		button := e.Get("button").Int()
		currentInput.mouseUp(button)
	})
	canvas.Call("addEventListener", "contextmenu", func(e js.Object) {
		e.Call("preventDefault")
	})

	// Gamepad
	window.Call("addEventListener", "gamepadconnected", func(e js.Object) {
	})
}

func devicePixelRatio() int {
	// TODO: What if ratio is not an integer but a float?
	ratio := js.Global.Get("window").Get("devicePixelRatio").Int()
	if ratio == 0 {
		ratio = 1
	}
	return ratio
}

func Start(width, height, scale int, title string) (actualScale int, err error) {
	doc := js.Global.Get("document")
	doc.Set("title", title)
	actualScale = scale * devicePixelRatio()
	canvas.Set("width", width*actualScale)
	canvas.Set("height", height*actualScale)
	canvasStyle := canvas.Get("style")

	cssWidth := width * scale
	cssHeight := height * scale
	canvasStyle.Set("width", strconv.Itoa(cssWidth)+"px")
	canvasStyle.Set("height", strconv.Itoa(cssHeight)+"px")
	// CSS calc requires space chars.
	canvasStyle.Set("left", "calc(50% - "+strconv.Itoa(cssWidth/2)+"px)")
	canvasStyle.Set("top", "calc(50% - "+strconv.Itoa(cssHeight/2)+"px)")

	canvas.Call("addEventListener", "mousemove", func(e js.Object) {
		rect := canvas.Call("getBoundingClientRect")
		x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
		x -= rect.Get("left").Int()
		y -= rect.Get("top").Int()
		currentInput.mouseMove(x/scale, y/scale)
	})
	canvas.Call("focus")

	return actualScale, nil
}
<|endoftext|>


<commit_before>package models

import (
	// Go Builtin Packages
	"bytes"
	"compress/zlib"
	"crypto/sha256"
	"encoding/hex"
	"log"
	"net"
	"net/http"
	"strings"
	"time"

	// Google Appengine Packages
	"appengine"
	"appengine/datastore"
	"appengine/user"
)

type Tags []string
type Paste struct {
	UserID  string    `datastore:"user_id"`
	Title   string    `datastore:"title"`
	Content []byte    `datastore:"content,noindex"`
	Tags    Tags      `datastore:"tags"`
	Format  string    `datastore:"format,noindex"`
	IPAddr  net.IP    `datastore:"ipaddr,noindex"`
	Date    time.Time `datastore:"date_published"`
}

const PasteDSKind string = "Paste"

func genpasteKey(c appengine.Context, p *Paste) (*datastore.Key, string) {
	timestamp := time.Now().Format(time.StampNano)

	hasher := sha256.New()
	hasher.Write([]byte(timestamp))
	hasher.Write(p.Content)
	digest := hex.EncodeToString(hasher.Sum(nil))

	paste_id := digest[:8] // This is probably a silly way to go about it xD
	return datastore.NewKey(c, PasteDSKind, paste_id, 0, nil), paste_id
}

func (p Paste) validate() error {
	// FIXME: Implement input validation here
	return nil
}

func (p Paste) Save(c appengine.Context) (string, error) {
	if err := p.validate(); err == nil {
		key, stringID := genpasteKey(c, &p)
		_, err := datastore.Put(c, key, &p)
		if err != nil {
			log.Panic(err)
		}
		return stringID, nil
	} else {
		return "", err
	}
}

func (p Paste) Delete(c appengine.Context, paste_id string) {
	key := datastore.NewKey(c, PasteDSKind, paste_id, 0, nil)
	if err := datastore.Delete(c, key); err != nil {
		log.Panic(err)
	}
}

func NewPaste(c appengine.Context, r *http.Request) string {
	var paste Paste

	if usr := user.Current(c); usr != nil {
		paste.UserID = usr.ID
	}

	paste.Title = r.PostForm.Get("title")

	var content bytes.Buffer
	w := zlib.NewWriter(&content)
	w.Write([]byte(r.PostForm.Get("content")))
	w.Close()
	paste.Content = content.Bytes()

	paste.Tags = strings.Split(r.PostForm.Get("tags"), " ")
	paste.Format = r.PostForm.Get("format")

	if ipaddr := net.ParseIP(r.RemoteAddr); ipaddr != nil {
		paste.IPAddr = net.IP(ipaddr)
	}

	paste.Date = time.Now()

	stringID, _ := paste.Save(c) // FIXME: do something if this returns an error
	// stringID := "meep" // DEBUG: Let's not write to the datastore at the moment :o
	return stringID
}

func GetPaste(c appengine.Context, paste_id string) (*Paste, error) {
	key := datastore.NewKey(c, PasteDSKind, paste_id, 0, nil)
	paste := new(Paste)
	if err := datastore.Get(c, key, paste); err != nil {
		return paste, err
	}
	return paste, nil
}
<commit_msg>Let's not export that one<commit_after>package models

import (
	// Go Builtin Packages
	"bytes"
	"compress/zlib"
	"crypto/sha256"
	"encoding/hex"
	"log"
	"net"
	"net/http"
	"strings"
	"time"

	// Google Appengine Packages
	"appengine"
	"appengine/datastore"
	"appengine/user"
)

type Tags []string
type Paste struct {
	UserID  string    `datastore:"user_id"`
	Title   string    `datastore:"title"`
	Content []byte    `datastore:"content,noindex"`
	Tags    Tags      `datastore:"tags"`
	Format  string    `datastore:"format,noindex"`
	IPAddr  net.IP    `datastore:"ipaddr,noindex"`
	Date    time.Time `datastore:"date_published"`
}

const PasteDSKind string = "Paste"

func genpasteKey(c appengine.Context, p *Paste) (*datastore.Key, string) {
	timestamp := time.Now().Format(time.StampNano)

	hasher := sha256.New()
	hasher.Write([]byte(timestamp))
	hasher.Write(p.Content)
	digest := hex.EncodeToString(hasher.Sum(nil))

	paste_id := digest[:8] // This is probably a silly way to go about it xD
	return datastore.NewKey(c, PasteDSKind, paste_id, 0, nil), paste_id
}

func (p Paste) validate() error {
	// FIXME: Implement input validation here
	return nil
}

func (p Paste) save(c appengine.Context) (string, error) {
	if err := p.validate(); err == nil {
		key, stringID := genpasteKey(c, &p)
		_, err := datastore.Put(c, key, &p)
		if err != nil {
			log.Panic(err)
		}
		return stringID, nil
	} else {
		return "", err
	}
}

func (p Paste) Delete(c appengine.Context, paste_id string) {
	key := datastore.NewKey(c, PasteDSKind, paste_id, 0, nil)
	if err := datastore.Delete(c, key); err != nil {
		log.Panic(err)
	}
}

func NewPaste(c appengine.Context, r *http.Request) string {
	var paste Paste

	if usr := user.Current(c); usr != nil {
		paste.UserID = usr.ID
	}

	paste.Title = r.PostForm.Get("title")

	var content bytes.Buffer
	w := zlib.NewWriter(&content)
	w.Write([]byte(r.PostForm.Get("content")))
	w.Close()
	paste.Content = content.Bytes()

	paste.Tags = strings.Split(r.PostForm.Get("tags"), " ")
	paste.Format = r.PostForm.Get("format")

	if ipaddr := net.ParseIP(r.RemoteAddr); ipaddr != nil {
		paste.IPAddr = net.IP(ipaddr)
	}

	paste.Date = time.Now()

	stringID, _ := paste.save(c) // FIXME: do something if this returns an error
	// stringID := "meep" // DEBUG: Let's not write to the datastore at the moment :o
	return stringID
}

func GetPaste(c appengine.Context, paste_id string) (*Paste, error) {
	key := datastore.NewKey(c, PasteDSKind, paste_id, 0, nil)
	paste := new(Paste)
	if err := datastore.Get(c, key, paste); err != nil {
		return paste, err
	}
	return paste, nil
}
<|endoftext|>


<commit_before>package states

import (
	"DNA/common"
	"DNA/crypto"
	"io"
	"DNA/common/serialization"
	. "DNA/errors"
	"bytes"
	"DNA/core/asset"
)

type AssetState struct {
	AssetId common.Uint256
	AssetType asset.AssetType
	Name string
	Amount common.Fixed64
	Available common.Fixed64
	Precision byte
	FeeMode byte
	Fee common.Fixed64
	FeeAddress *common.Uint160
	Owner *crypto.PubKey
	Admin common.Uint160
	Issuer common.Uint160
	Expiration uint32
	IsFrozen bool
	*StateBase
}

func(assetState *AssetState)Serialize(w io.Writer) error {
	assetState.AssetId.Serialize(w)
	serialization.WriteVarString(w, assetState.Name)
	assetState.Amount.Serialize(w)
	assetState.Available.Serialize(w)
	serialization.WriteVarBytes(w, []byte{assetState.Precision})
	serialization.WriteVarBytes(w, []byte{assetState.FeeMode})
	assetState.Fee.Serialize(w)
	assetState.FeeAddress.Serialize(w)
	assetState.Owner.Serialize(w)
	assetState.Admin.Serialize(w)
	assetState.Issuer.Serialize(w)
	serialization.WriteUint32(w, assetState.Expiration)
	serialization.WriteBool(w, assetState.IsFrozen)
	return nil
}

func(assetState *AssetState)Deserialize(r io.Reader) error {
	u256 := new(common.Uint256)
	u160 := new(common.Uint160)
	f := new(common.Fixed64)
	pubkey := &crypto.PubKey{}
	err := u256.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState AssetId Deserialize fail.")
	}
	assetState.AssetId = *u256
	name, err := serialization.ReadVarString(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Name Deserialize fail.")

	}
	assetState.Name = name
	err = f.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Amount Deserialize fail.")

	}
	assetState.Amount = *f
	err = f.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Available Deserialize fail.")
	}
	assetState.Available = *f
	precisions, err := serialization.ReadVarBytes(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Precision Deserialize fail.")
	}
	assetState.Precision = precisions[0]
	feeModes, err := serialization.ReadVarBytes(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState FeeMode Deserialize fail.")
	}
	assetState.FeeMode = feeModes[0]
	err = f.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Fee Deserialize fail.")
	}
	assetState.Fee = *f
	err = u160.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState FeeAddress Deserialize fail.")
	}
	assetState.FeeAddress = u160
	err = pubkey.DeSerialize(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Owner Deserialize fail.")
	}
	assetState.Owner = pubkey
	err = u160.Deserialize(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Admin Deserialize fail.")
	}
	assetState.Admin = *u160
	err = u160.Deserialize(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Issuer Deserialize fail.")
	}
	assetState.Issuer = *u160
	expiration, err := serialization.ReadUint32(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Expiration Deserialize fail.")
	}
	assetState.Expiration = expiration
	isFrozon, err := serialization.ReadBool(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState IsFrozon Deserialize fail.")
	}
	assetState.IsFrozen = isFrozon
	return nil
}

func(assetState *AssetState) ToArray() []byte {
	b := new(bytes.Buffer)
	assetState.Serialize(b)
	return b.Bytes()
}
<commit_msg>remove pointer, it is unnecessary.<commit_after>package states

import (
	"DNA/common"
	"DNA/crypto"
	"io"
	"DNA/common/serialization"
	. "DNA/errors"
	"bytes"
	"DNA/core/asset"
)

type AssetState struct {
	AssetId common.Uint256
	AssetType asset.AssetType
	Name string
	Amount common.Fixed64
	Available common.Fixed64
	Precision byte
	FeeMode byte
	Fee common.Fixed64
	FeeAddress *common.Uint160
	Owner *crypto.PubKey
	Admin common.Uint160
	Issuer common.Uint160
	Expiration uint32
	IsFrozen bool
	StateBase
}

func(assetState *AssetState)Serialize(w io.Writer) error {
	assetState.AssetId.Serialize(w)
	serialization.WriteVarString(w, assetState.Name)
	assetState.Amount.Serialize(w)
	assetState.Available.Serialize(w)
	serialization.WriteVarBytes(w, []byte{assetState.Precision})
	serialization.WriteVarBytes(w, []byte{assetState.FeeMode})
	assetState.Fee.Serialize(w)
	assetState.FeeAddress.Serialize(w)
	assetState.Owner.Serialize(w)
	assetState.Admin.Serialize(w)
	assetState.Issuer.Serialize(w)
	serialization.WriteUint32(w, assetState.Expiration)
	serialization.WriteBool(w, assetState.IsFrozen)
	return nil
}

func(assetState *AssetState)Deserialize(r io.Reader) error {
	u256 := new(common.Uint256)
	u160 := new(common.Uint160)
	f := new(common.Fixed64)
	pubkey := &crypto.PubKey{}
	err := u256.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState AssetId Deserialize fail.")
	}
	assetState.AssetId = *u256
	name, err := serialization.ReadVarString(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Name Deserialize fail.")

	}
	assetState.Name = name
	err = f.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Amount Deserialize fail.")

	}
	assetState.Amount = *f
	err = f.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Available Deserialize fail.")
	}
	assetState.Available = *f
	precisions, err := serialization.ReadVarBytes(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Precision Deserialize fail.")
	}
	assetState.Precision = precisions[0]
	feeModes, err := serialization.ReadVarBytes(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState FeeMode Deserialize fail.")
	}
	assetState.FeeMode = feeModes[0]
	err = f.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState Fee Deserialize fail.")
	}
	assetState.Fee = *f
	err = u160.Deserialize(r)
	if err != nil{
		return NewDetailErr(err, ErrNoCode, "AssetState FeeAddress Deserialize fail.")
	}
	assetState.FeeAddress = u160
	err = pubkey.DeSerialize(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Owner Deserialize fail.")
	}
	assetState.Owner = pubkey
	err = u160.Deserialize(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Admin Deserialize fail.")
	}
	assetState.Admin = *u160
	err = u160.Deserialize(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Issuer Deserialize fail.")
	}
	assetState.Issuer = *u160
	expiration, err := serialization.ReadUint32(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState Expiration Deserialize fail.")
	}
	assetState.Expiration = expiration
	isFrozon, err := serialization.ReadBool(r)
	if err != nil {
		return NewDetailErr(err, ErrNoCode, "AssetState IsFrozon Deserialize fail.")
	}
	assetState.IsFrozen = isFrozon
	return nil
}

func(assetState *AssetState) ToArray() []byte {
	b := new(bytes.Buffer)
	assetState.Serialize(b)
	return b.Bytes()
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes 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 e2e

import (
	"fmt"
	"strconv"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	controllerFramework "k8s.io/kubernetes/pkg/controller/framework"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/master/ports"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/util"
	"k8s.io/kubernetes/pkg/util/sets"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/watch"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

// This test primarily checks 2 things:
// 1. Daemons restart automatically within some sane time (10m).
// 2. They don't take abnormal actions when restarted in the steady state.
//	- Controller manager sholdn't overshoot replicas
//	- Kubelet shouldn't restart containers
//	- Scheduler should continue assigning hosts to new pods

const (
	restartPollInterval = 5 * time.Second
	restartTimeout      = 10 * time.Minute
	numPods             = 10
	sshPort             = 22
	ADD                 = "ADD"
	DEL                 = "DEL"
	UPDATE              = "UPDATE"
)

// nodeExec execs the given cmd on node via SSH. Note that the nodeName is an sshable name,
// eg: the name returned by getMasterHost(). This is also not guaranteed to work across
// cloud providers since it involves ssh.
func nodeExec(nodeName, cmd string) (string, string, int, error) {
	stdout, stderr, code, err := SSH(cmd, fmt.Sprintf("%v:%v", nodeName, sshPort), testContext.Provider)
	Expect(err).NotTo(HaveOccurred())
	return stdout, stderr, code, err
}

// restartDaemonConfig is a config to restart a running daemon on a node, and wait till
// it comes back up. It uses ssh to send a SIGTERM to the daemon.
type restartDaemonConfig struct {
	nodeName     string
	daemonName   string
	healthzPort  int
	pollInterval time.Duration
	pollTimeout  time.Duration
}

// NewRestartConfig creates a restartDaemonConfig for the given node and daemon.
func NewRestartConfig(nodeName, daemonName string, healthzPort int, pollInterval, pollTimeout time.Duration) *restartDaemonConfig {
	if !providerIs("gce") {
		Logf("WARNING: SSH through the restart config might not work on %s", testContext.Provider)
	}
	return &restartDaemonConfig{
		nodeName:     nodeName,
		daemonName:   daemonName,
		healthzPort:  healthzPort,
		pollInterval: pollInterval,
		pollTimeout:  pollTimeout,
	}
}

func (r *restartDaemonConfig) String() string {
	return fmt.Sprintf("Daemon %v on node %v", r.daemonName, r.nodeName)
}

// waitUp polls healthz of the daemon till it returns "ok" or the polling hits the pollTimeout
func (r *restartDaemonConfig) waitUp() {
	Logf("Checking if %v is up by polling for a 200 on its /healthz endpoint", r)
	healthzCheck := fmt.Sprintf(
		"curl -s -o /dev/null -I -w \"%%{http_code}\" http://localhost:%v/healthz", r.healthzPort)

	err := wait.Poll(r.pollInterval, r.pollTimeout, func() (bool, error) {
		stdout, stderr, code, err := nodeExec(r.nodeName, healthzCheck)
		expectNoError(err)
		if code == 0 {
			httpCode, err := strconv.Atoi(stdout)
			if err != nil {
				Logf("Unable to parse healthz http return code: %v", err)
			} else if httpCode == 200 {
				return true, nil
			}
		}
		Logf("node %v exec command, '%v' failed with exitcode %v: \n\tstdout: %v\n\tstderr: %v",
			r.nodeName, healthzCheck, code, stdout, stderr)
		return false, nil
	})
	expectNoError(err, "%v did not respond with a 200 via %v within %v", r, healthzCheck, r.pollTimeout)
}

// kill sends a SIGTERM to the daemon
func (r *restartDaemonConfig) kill() {
	Logf("Killing %v", r)
	nodeExec(r.nodeName, fmt.Sprintf("pgrep %v | xargs -I {} sudo kill {}", r.daemonName))
}

// Restart checks if the daemon is up, kills it, and waits till it comes back up
func (r *restartDaemonConfig) restart() {
	r.waitUp()
	r.kill()
	r.waitUp()
}

// podTracker records a serial history of events that might've affects pods.
type podTracker struct {
	cache.ThreadSafeStore
}

func (p *podTracker) remember(pod *api.Pod, eventType string) {
	if eventType == UPDATE && pod.Status.Phase == api.PodRunning {
		return
	}
	p.Add(fmt.Sprintf("[%v] %v: %v", time.Now(), eventType, pod.Name), pod)
}

func (p *podTracker) String() (msg string) {
	for _, k := range p.ListKeys() {
		obj, exists := p.Get(k)
		if !exists {
			continue
		}
		pod := obj.(*api.Pod)
		msg += fmt.Sprintf("%v Phase %v Host %v\n", k, pod.Status.Phase, pod.Spec.NodeName)
	}
	return
}

func newPodTracker() *podTracker {
	return &podTracker{cache.NewThreadSafeStore(
		cache.Indexers{}, cache.Indices{})}
}

// replacePods replaces content of the store with the given pods.
func replacePods(pods []*api.Pod, store cache.Store) {
	found := make([]interface{}, 0, len(pods))
	for i := range pods {
		found = append(found, pods[i])
	}
	expectNoError(store.Replace(found, "0"))
}

// getContainerRestarts returns the count of container restarts across all pods matching the given labelSelector,
// and a list of nodenames across which these containers restarted.
func getContainerRestarts(c *client.Client, ns string, labelSelector labels.Selector) (int, []string) {
	pods, err := c.Pods(ns).List(labelSelector, fields.Everything())
	expectNoError(err)
	failedContainers := 0
	containerRestartNodes := sets.NewString()
	for _, p := range pods.Items {
		for _, v := range FailedContainers(&p) {
			failedContainers = failedContainers + v.restarts
			containerRestartNodes.Insert(p.Spec.NodeName)
		}
	}
	return failedContainers, containerRestartNodes.List()
}

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

	framework := Framework{BaseName: "daemonrestart"}
	rcName := "daemonrestart" + strconv.Itoa(numPods) + "-" + string(util.NewUUID())
	labelSelector := labels.Set(map[string]string{"name": rcName}).AsSelector()
	existingPods := cache.NewStore(cache.MetaNamespaceKeyFunc)
	var ns string
	var config RCConfig
	var controller *controllerFramework.Controller
	var newPods cache.Store
	var stopCh chan struct{}
	var tracker *podTracker

	BeforeEach(func() {

		// These tests require SSH
		// TODO: Enable on gke after testing (#11834)
		if !providerIs("gce") {
			By(fmt.Sprintf("Skipping test, which is not implemented for %s", testContext.Provider))
			return
		}
		framework.beforeEach()
		ns = framework.Namespace.Name

		// All the restart tests need an rc and a watch on pods of the rc.
		// Additionally some of them might scale the rc during the test.
		config = RCConfig{
			Client:      framework.Client,
			Name:        rcName,
			Namespace:   ns,
			Image:       "kubernetes/pause",
			Replicas:    numPods,
			CreatedPods: &[]*api.Pod{},
		}
		Expect(RunRC(config)).NotTo(HaveOccurred())
		replacePods(*config.CreatedPods, existingPods)

		stopCh = make(chan struct{})
		tracker = newPodTracker()
		newPods, controller = controllerFramework.NewInformer(
			&cache.ListWatch{
				ListFunc: func() (runtime.Object, error) {
					return framework.Client.Pods(ns).List(labelSelector, fields.Everything())
				},
				WatchFunc: func(rv string) (watch.Interface, error) {
					return framework.Client.Pods(ns).Watch(labelSelector, fields.Everything(), rv)
				},
			},
			&api.Pod{},
			0,
			controllerFramework.ResourceEventHandlerFuncs{
				AddFunc: func(obj interface{}) {
					tracker.remember(obj.(*api.Pod), ADD)
				},
				UpdateFunc: func(oldObj, newObj interface{}) {
					tracker.remember(newObj.(*api.Pod), UPDATE)
				},
				DeleteFunc: func(obj interface{}) {
					tracker.remember(obj.(*api.Pod), DEL)
				},
			},
		)
		go controller.Run(stopCh)
	})

	AfterEach(func() {
		close(stopCh)
		expectNoError(DeleteRC(framework.Client, ns, rcName))
		framework.afterEach()
	})

	It("Controller Manager should not create/delete replicas across restart", func() {

		restarter := NewRestartConfig(
			getMasterHost(), "kube-controller", ports.ControllerManagerPort, restartPollInterval, restartTimeout)
		restarter.restart()

		// The intent is to ensure the replication controller manager has observed and reported status of
		// the replication controller at least once since the manager restarted, so that we can determine
		// that it had the opportunity to create/delete pods, if it were going to do so. Scaling the RC
		// to the same size achieves this, because the scale operation advances the RC's sequence number
		// and awaits it to be observed and reported back in the RC's status.
		ScaleRC(framework.Client, ns, rcName, numPods, true)

		// Only check the keys, the pods can be different if the kubelet updated it.
		// TODO: Can it really?
		existingKeys := sets.NewString()
		newKeys := sets.NewString()
		for _, k := range existingPods.ListKeys() {
			existingKeys.Insert(k)
		}
		for _, k := range newPods.ListKeys() {
			newKeys.Insert(k)
		}
		if len(newKeys.List()) != len(existingKeys.List()) ||
			!newKeys.IsSuperset(existingKeys) {
			Failf("RcManager created/deleted pods after restart \n\n %+v", tracker)
		}
	})

	It("Scheduler should continue assigning pods to nodes across restart", func() {

		// TODO: Enabale this test in GKE once experimental API there is switched on
		SkipIfProviderIs("gke")

		restarter := NewRestartConfig(
			getMasterHost(), "kube-scheduler", ports.SchedulerPort, restartPollInterval, restartTimeout)

		// Create pods while the scheduler is down and make sure the scheduler picks them up by
		// scaling the rc to the same size.
		restarter.waitUp()
		restarter.kill()
		// This is best effort to try and create pods while the scheduler is down,
		// since we don't know exactly when it is restarted after the kill signal.
		expectNoError(ScaleRC(framework.Client, ns, rcName, numPods+5, false))
		restarter.waitUp()
		expectNoError(ScaleRC(framework.Client, ns, rcName, numPods+5, true))
	})

	It("Kubelet should not restart containers across restart", func() {

		// TODO: Enabale this test in GKE once experimental API there is switched on
		SkipIfProviderIs("gke")

		nodeIPs, err := getNodePublicIps(framework.Client)
		expectNoError(err)
		preRestarts, badNodes := getContainerRestarts(framework.Client, ns, labelSelector)
		if preRestarts != 0 {
			Logf("WARNING: Non-zero container restart count: %d across nodes %v", preRestarts, badNodes)
		}
		for _, ip := range nodeIPs {
			restarter := NewRestartConfig(
				ip, "kubelet", ports.KubeletReadOnlyPort, restartPollInterval, restartTimeout)
			restarter.restart()
		}
		postRestarts, badNodes := getContainerRestarts(framework.Client, ns, labelSelector)
		if postRestarts != preRestarts {
			dumpNodeDebugInfo(framework.Client, badNodes)
			Failf("Net container restart count went from %v -> %v after kubelet restart on nodes %v \n\n %+v", preRestarts, postRestarts, badNodes, tracker)
		}
	})
})
<commit_msg>Fix daemon_restart with right pause image<commit_after>/*
Copyright 2015 The Kubernetes 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 e2e

import (
	"fmt"
	"strconv"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	controllerFramework "k8s.io/kubernetes/pkg/controller/framework"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/master/ports"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/util"
	"k8s.io/kubernetes/pkg/util/sets"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/watch"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

// This test primarily checks 2 things:
// 1. Daemons restart automatically within some sane time (10m).
// 2. They don't take abnormal actions when restarted in the steady state.
//	- Controller manager sholdn't overshoot replicas
//	- Kubelet shouldn't restart containers
//	- Scheduler should continue assigning hosts to new pods

const (
	restartPollInterval = 5 * time.Second
	restartTimeout      = 10 * time.Minute
	numPods             = 10
	sshPort             = 22
	ADD                 = "ADD"
	DEL                 = "DEL"
	UPDATE              = "UPDATE"
)

// nodeExec execs the given cmd on node via SSH. Note that the nodeName is an sshable name,
// eg: the name returned by getMasterHost(). This is also not guaranteed to work across
// cloud providers since it involves ssh.
func nodeExec(nodeName, cmd string) (string, string, int, error) {
	stdout, stderr, code, err := SSH(cmd, fmt.Sprintf("%v:%v", nodeName, sshPort), testContext.Provider)
	Expect(err).NotTo(HaveOccurred())
	return stdout, stderr, code, err
}

// restartDaemonConfig is a config to restart a running daemon on a node, and wait till
// it comes back up. It uses ssh to send a SIGTERM to the daemon.
type restartDaemonConfig struct {
	nodeName     string
	daemonName   string
	healthzPort  int
	pollInterval time.Duration
	pollTimeout  time.Duration
}

// NewRestartConfig creates a restartDaemonConfig for the given node and daemon.
func NewRestartConfig(nodeName, daemonName string, healthzPort int, pollInterval, pollTimeout time.Duration) *restartDaemonConfig {
	if !providerIs("gce") {
		Logf("WARNING: SSH through the restart config might not work on %s", testContext.Provider)
	}
	return &restartDaemonConfig{
		nodeName:     nodeName,
		daemonName:   daemonName,
		healthzPort:  healthzPort,
		pollInterval: pollInterval,
		pollTimeout:  pollTimeout,
	}
}

func (r *restartDaemonConfig) String() string {
	return fmt.Sprintf("Daemon %v on node %v", r.daemonName, r.nodeName)
}

// waitUp polls healthz of the daemon till it returns "ok" or the polling hits the pollTimeout
func (r *restartDaemonConfig) waitUp() {
	Logf("Checking if %v is up by polling for a 200 on its /healthz endpoint", r)
	healthzCheck := fmt.Sprintf(
		"curl -s -o /dev/null -I -w \"%%{http_code}\" http://localhost:%v/healthz", r.healthzPort)

	err := wait.Poll(r.pollInterval, r.pollTimeout, func() (bool, error) {
		stdout, stderr, code, err := nodeExec(r.nodeName, healthzCheck)
		expectNoError(err)
		if code == 0 {
			httpCode, err := strconv.Atoi(stdout)
			if err != nil {
				Logf("Unable to parse healthz http return code: %v", err)
			} else if httpCode == 200 {
				return true, nil
			}
		}
		Logf("node %v exec command, '%v' failed with exitcode %v: \n\tstdout: %v\n\tstderr: %v",
			r.nodeName, healthzCheck, code, stdout, stderr)
		return false, nil
	})
	expectNoError(err, "%v did not respond with a 200 via %v within %v", r, healthzCheck, r.pollTimeout)
}

// kill sends a SIGTERM to the daemon
func (r *restartDaemonConfig) kill() {
	Logf("Killing %v", r)
	nodeExec(r.nodeName, fmt.Sprintf("pgrep %v | xargs -I {} sudo kill {}", r.daemonName))
}

// Restart checks if the daemon is up, kills it, and waits till it comes back up
func (r *restartDaemonConfig) restart() {
	r.waitUp()
	r.kill()
	r.waitUp()
}

// podTracker records a serial history of events that might've affects pods.
type podTracker struct {
	cache.ThreadSafeStore
}

func (p *podTracker) remember(pod *api.Pod, eventType string) {
	if eventType == UPDATE && pod.Status.Phase == api.PodRunning {
		return
	}
	p.Add(fmt.Sprintf("[%v] %v: %v", time.Now(), eventType, pod.Name), pod)
}

func (p *podTracker) String() (msg string) {
	for _, k := range p.ListKeys() {
		obj, exists := p.Get(k)
		if !exists {
			continue
		}
		pod := obj.(*api.Pod)
		msg += fmt.Sprintf("%v Phase %v Host %v\n", k, pod.Status.Phase, pod.Spec.NodeName)
	}
	return
}

func newPodTracker() *podTracker {
	return &podTracker{cache.NewThreadSafeStore(
		cache.Indexers{}, cache.Indices{})}
}

// replacePods replaces content of the store with the given pods.
func replacePods(pods []*api.Pod, store cache.Store) {
	found := make([]interface{}, 0, len(pods))
	for i := range pods {
		found = append(found, pods[i])
	}
	expectNoError(store.Replace(found, "0"))
}

// getContainerRestarts returns the count of container restarts across all pods matching the given labelSelector,
// and a list of nodenames across which these containers restarted.
func getContainerRestarts(c *client.Client, ns string, labelSelector labels.Selector) (int, []string) {
	pods, err := c.Pods(ns).List(labelSelector, fields.Everything())
	expectNoError(err)
	failedContainers := 0
	containerRestartNodes := sets.NewString()
	for _, p := range pods.Items {
		for _, v := range FailedContainers(&p) {
			failedContainers = failedContainers + v.restarts
			containerRestartNodes.Insert(p.Spec.NodeName)
		}
	}
	return failedContainers, containerRestartNodes.List()
}

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

	framework := Framework{BaseName: "daemonrestart"}
	rcName := "daemonrestart" + strconv.Itoa(numPods) + "-" + string(util.NewUUID())
	labelSelector := labels.Set(map[string]string{"name": rcName}).AsSelector()
	existingPods := cache.NewStore(cache.MetaNamespaceKeyFunc)
	var ns string
	var config RCConfig
	var controller *controllerFramework.Controller
	var newPods cache.Store
	var stopCh chan struct{}
	var tracker *podTracker

	BeforeEach(func() {

		// These tests require SSH
		// TODO: Enable on gke after testing (#11834)
		if !providerIs("gce") {
			By(fmt.Sprintf("Skipping test, which is not implemented for %s", testContext.Provider))
			return
		}
		framework.beforeEach()
		ns = framework.Namespace.Name

		// All the restart tests need an rc and a watch on pods of the rc.
		// Additionally some of them might scale the rc during the test.
		config = RCConfig{
			Client:      framework.Client,
			Name:        rcName,
			Namespace:   ns,
			Image:       "beta.gcr.io/google_containers/pause:2.0",
			Replicas:    numPods,
			CreatedPods: &[]*api.Pod{},
		}
		Expect(RunRC(config)).NotTo(HaveOccurred())
		replacePods(*config.CreatedPods, existingPods)

		stopCh = make(chan struct{})
		tracker = newPodTracker()
		newPods, controller = controllerFramework.NewInformer(
			&cache.ListWatch{
				ListFunc: func() (runtime.Object, error) {
					return framework.Client.Pods(ns).List(labelSelector, fields.Everything())
				},
				WatchFunc: func(rv string) (watch.Interface, error) {
					return framework.Client.Pods(ns).Watch(labelSelector, fields.Everything(), rv)
				},
			},
			&api.Pod{},
			0,
			controllerFramework.ResourceEventHandlerFuncs{
				AddFunc: func(obj interface{}) {
					tracker.remember(obj.(*api.Pod), ADD)
				},
				UpdateFunc: func(oldObj, newObj interface{}) {
					tracker.remember(newObj.(*api.Pod), UPDATE)
				},
				DeleteFunc: func(obj interface{}) {
					tracker.remember(obj.(*api.Pod), DEL)
				},
			},
		)
		go controller.Run(stopCh)
	})

	AfterEach(func() {
		close(stopCh)
		expectNoError(DeleteRC(framework.Client, ns, rcName))
		framework.afterEach()
	})

	It("Controller Manager should not create/delete replicas across restart", func() {

		restarter := NewRestartConfig(
			getMasterHost(), "kube-controller", ports.ControllerManagerPort, restartPollInterval, restartTimeout)
		restarter.restart()

		// The intent is to ensure the replication controller manager has observed and reported status of
		// the replication controller at least once since the manager restarted, so that we can determine
		// that it had the opportunity to create/delete pods, if it were going to do so. Scaling the RC
		// to the same size achieves this, because the scale operation advances the RC's sequence number
		// and awaits it to be observed and reported back in the RC's status.
		ScaleRC(framework.Client, ns, rcName, numPods, true)

		// Only check the keys, the pods can be different if the kubelet updated it.
		// TODO: Can it really?
		existingKeys := sets.NewString()
		newKeys := sets.NewString()
		for _, k := range existingPods.ListKeys() {
			existingKeys.Insert(k)
		}
		for _, k := range newPods.ListKeys() {
			newKeys.Insert(k)
		}
		if len(newKeys.List()) != len(existingKeys.List()) ||
			!newKeys.IsSuperset(existingKeys) {
			Failf("RcManager created/deleted pods after restart \n\n %+v", tracker)
		}
	})

	It("Scheduler should continue assigning pods to nodes across restart", func() {

		// TODO: Enabale this test in GKE once experimental API there is switched on
		SkipIfProviderIs("gke")

		restarter := NewRestartConfig(
			getMasterHost(), "kube-scheduler", ports.SchedulerPort, restartPollInterval, restartTimeout)

		// Create pods while the scheduler is down and make sure the scheduler picks them up by
		// scaling the rc to the same size.
		restarter.waitUp()
		restarter.kill()
		// This is best effort to try and create pods while the scheduler is down,
		// since we don't know exactly when it is restarted after the kill signal.
		expectNoError(ScaleRC(framework.Client, ns, rcName, numPods+5, false))
		restarter.waitUp()
		expectNoError(ScaleRC(framework.Client, ns, rcName, numPods+5, true))
	})

	It("Kubelet should not restart containers across restart", func() {

		// TODO: Enabale this test in GKE once experimental API there is switched on
		SkipIfProviderIs("gke")

		nodeIPs, err := getNodePublicIps(framework.Client)
		expectNoError(err)
		preRestarts, badNodes := getContainerRestarts(framework.Client, ns, labelSelector)
		if preRestarts != 0 {
			Logf("WARNING: Non-zero container restart count: %d across nodes %v", preRestarts, badNodes)
		}
		for _, ip := range nodeIPs {
			restarter := NewRestartConfig(
				ip, "kubelet", ports.KubeletReadOnlyPort, restartPollInterval, restartTimeout)
			restarter.restart()
		}
		postRestarts, badNodes := getContainerRestarts(framework.Client, ns, labelSelector)
		if postRestarts != preRestarts {
			dumpNodeDebugInfo(framework.Client, badNodes)
			Failf("Net container restart count went from %v -> %v after kubelet restart on nodes %v \n\n %+v", preRestarts, postRestarts, badNodes, tracker)
		}
	})
})
<|endoftext|>