<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package ssh

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"strings"

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

var KeyBits = 2048

func GenerateKey(comment string) (private, public string, err error) {
	key, err := rsa.GenerateKey(rand.Reader, KeyBits)
	if err != nil {
		return "", "", err
	}

	identity := pem.EncodeToMemory(
		&pem.Block{
			Type:  "RSA PRIVATE KEY",
			Bytes: x509.MarshalPKCS1PrivateKey(key),
		})

	signer, err := ssh.ParsePrivateKey(identity)
	if err != nil {
		return "", "", fmt.Errorf("failed to load key: %v", err)
	}

	auth_key := string(ssh.MarshalAuthorizedKey(signer.PublicKey()))
	// Strip off the trailing new line so we can add a comment.
	auth_key = strings.TrimSpace(auth_key)
	public = fmt.Sprintf("%s %s\n", auth_key, comment)

	return string(identity), public, nil
}
<commit_msg>Add comments to generate.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package ssh

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"strings"

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

// KeyBits is used to determine the number of bits to use for the RSA keys
// created using the GenerateKey function.
var KeyBits = 2048

// GenerateKey makes a 2048 bit RSA no-passphrase SSH capable key.  The bit
// size is actually controlled by the KeyBits var. The private key returned is
// encoded to ASCII using the PKCS1 encoding.  The public key is suitable to
// be added into an authorized_keys file, and has the comment passed in as the
// comment part of the key.
func GenerateKey(comment string) (private, public string, err error) {
	key, err := rsa.GenerateKey(rand.Reader, KeyBits)
	if err != nil {
		return "", "", err
	}

	identity := pem.EncodeToMemory(
		&pem.Block{
			Type:  "RSA PRIVATE KEY",
			Bytes: x509.MarshalPKCS1PrivateKey(key),
		})

	signer, err := ssh.ParsePrivateKey(identity)
	if err != nil {
		return "", "", fmt.Errorf("failed to load key: %v", err)
	}

	auth_key := string(ssh.MarshalAuthorizedKey(signer.PublicKey()))
	// Strip off the trailing new line so we can add a comment.
	auth_key = strings.TrimSpace(auth_key)
	public = fmt.Sprintf("%s %s\n", auth_key, comment)

	return string(identity), public, nil
}
<|endoftext|>


<commit_before>// Tideland Go Application Support - Identifier - UUID
//
// Copyright (C) 2009-2015 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package identifier

//--------------------
// IMPORTS
//--------------------

import (
	"crypto/md5"
	"crypto/rand"
	"fmt"

	"github.com/tideland/goas/v3/errors"
)

//--------------------
// UUID
//--------------------

// UUIDVersion represents the version of a UUID.
type UUIDVersion byte

const (
	UUIDv3 UUIDVersion = 3
	UUIDv4 UUIDVersion = 4
)

// UUID represents a universal identifier with 16 bytes.
// See http://en.wikipedia.org/wiki/Universally_unique_identifier.
type UUID [16]byte

// NewUUID returns a new UUID with based on the default version 4.
func NewUUID() UUID {
	uuid, err := NewUUIDv4()
	if err != nil {
		// Panic due to compatibility reasons.
		panic(err)
	}
	return uuid
}

// NewUUIDv3 generates a new UUID based on version 3 (MD5 hash of a namespace
// and a name).
func NewUUIDv3(ns, name []byte) (UUID, error) {
	uuid := UUID{}
	if ns == nil {
		return uuid, errors.New(ErrInvalidNamespace, errorMessages)
	}
	hash := md5.New()
	hash.Write([]byte(uuid[:]))
	hash.Write(name)
	copy(uuid[:], hash.Sum([]byte{})[:16])

	uuid.setVersion(UUIDv3)
	uuid.setVariant()
	return uuid, nil
}

// NewUUIDv4 generates a new UUID based on version 4 (strong random number).
func NewUUIDv4() (UUID, error) {
	uuid := UUID{}
	_, err := rand.Read([]byte(uuid[:]))
	if err != nil {
		return uuid, err
	}

	uuid.setVersion(UUIDv4)
	uuid.setVariant()
	return uuid, nil
}

// Version returns the version number of the UUID algorithm.
func (uuid UUID) Version() UUIDVersion {
	return UUIDVersion(uuid[6] >> 4)
}

// Copy returns a copy of the UUID.
func (uuid UUID) Copy() UUID {
	uuidCopy := uuid
	return uuidCopy
}

// Raw returns a copy of the UUID bytes.
func (uuid UUID) Raw() [16]byte {
	return [16]byte(uuid)
}

// String returns a hexadecimal string representation with
// standardized separators.
func (uuid UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
}

// setVersion sets the version part of the UUID.
func (uuid UUID) setVersion(v UUIDVersion) {
	var version byte = byte(v) << 4
	uuid[6] = version | (uuid[6] & 15)
}

// setVariant sets the variant part of the UUID according to RfC 4122.
func (uuid UUID) setVariant() {
	var variant byte = 8 << 4
	uuid[8] = variant | (uuid[8] & 15)
}

// EOF
<commit_msg>goas/identifier: added more UUID versions and namespaces, tests yet missing<commit_after>// Tideland Go Application Support - Identifier - UUID
//
// Copyright (C) 2009-2015 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package identifier

//--------------------
// IMPORTS
//--------------------

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/sha1"
	"encoding/hex"
	"fmt"
)

//--------------------
// UUID
//--------------------

// UUIDVersion represents the version of a UUID.
type UUIDVersion byte

const (
	UUIDv3 UUIDVersion = 3
	UUIDv4 UUIDVersion = 4
	UUIDv5 UUIDVersion = 5

	UUIDNamespaceDNS = iota
	UUIDNamespaceURL
	UUIDNamespaceOID
	UUIDNamespaceX500
)

// UUID represents a universal identifier with 16 bytes.
// See http://en.wikipedia.org/wiki/Universally_unique_identifier.
type UUID [16]byte

// NewUUID returns a new UUID with based on the default version 4.
func NewUUID() UUID {
	uuid, err := NewUUIDv4()
	if err != nil {
		// Panic due to compatibility reasons.
		panic(err)
	}
	return uuid
}

// NewUUIDv3 generates a new UUID based on version 3 (MD5 hash of a namespace
// and a name).
func NewUUIDv3(ns UUID, name []byte) (UUID, error) {
	uuid := UUID{}
	hash := md5.New()
	hash.Write(ns.dump())
	hash.Write(name)
	copy(uuid[:], hash.Sum([]byte{})[:16])

	uuid.setVersion(UUIDv3)
	uuid.setVariant()
	return uuid, nil
}

// NewUUIDv4 generates a new UUID based on version 4 (strong random number).
func NewUUIDv4() (UUID, error) {
	uuid := UUID{}
	_, err := rand.Read([]byte(uuid[:]))
	if err != nil {
		return uuid, err
	}

	uuid.setVersion(UUIDv4)
	uuid.setVariant()
	return uuid, nil
}

// NewUUIDv5 generates a new UUID based on version 5 (SHA1 hash of a namespace
// and a name).
func NewUUIDv5(ns UUID, name []byte) (UUID, error) {
	uuid := UUID{}
	hash := sha1.New()
	hash.Write(ns.dump())
	hash.Write(name)
	copy(uuid[:], hash.Sum([]byte{})[:16])

	uuid.setVersion(UUIDv5)
	uuid.setVariant()
	return uuid, nil
}

// Version returns the version number of the UUID algorithm.
func (uuid UUID) Version() UUIDVersion {
	return UUIDVersion(uuid[6] >> 4)
}

// Copy returns a copy of the UUID.
func (uuid UUID) Copy() UUID {
	uuidCopy := uuid
	return uuidCopy
}

// Raw returns a copy of the UUID bytes.
func (uuid UUID) Raw() [16]byte {
	return [16]byte(uuid)
}

// dump creates a copy a byte slice.
func (uuid UUID) dump() []byte {
	dump := make([]byte, len(uuid))

	copy(dump, uuid[:])

	return dump
}

// String returns a hexadecimal string representation with
// standardized separators.
func (uuid UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
}

// setVersion sets the version part of the UUID.
func (uuid UUID) setVersion(v UUIDVersion) {
	var version byte = byte(v) << 4
	uuid[6] = version | (uuid[6] & 15)
}

// setVariant sets the variant part of the UUID according to RfC 4122.
func (uuid UUID) setVariant() {
	var variant byte = 8 << 4
	uuid[8] = variant | (uuid[8] & 15)
}

// UUIDNamespace returns a namespace as UUID.
func UUIDNamespace(nsId int) UUID {
	var uuid UUID
	var ns []byte
	switch nsId {
	case UUIDNamespaceDNS:
		ns, _ = hex.DecodeString("6ba7b8109dad11d180b400c04fd430c8")
	case UUIDNamespaceURL:
		ns, _ = hex.DecodeString("6ba7b8119dad11d180b400c04fd430c8")
	case UUIDNamespaceOID:
		ns, _ = hex.DecodeString("6ba7b8129dad11d180b400c04fd430c8")
	case UUIDNamespaceX500:
		ns, _ = hex.DecodeString("6ba7b8149dad11d180b400c04fd430c8")
	default:
		panic("invalid UUID namespace identifier")
	}
	copy(uuid[:], ns)
	return uuid
}

// EOF
<|endoftext|>


<commit_before>package appjson

func TriggerPostDeploy(appName string, imageTag string) error {
	if err := executeScript(appName, imageTag, "postdeploy"); err != nil {
		return err
	}

	if err := executeScript(appName, imageTag, "release"); err != nil {
		return err
	}
	return nil
}

func TriggerPreDeploy(appName string, imageTag string) error {
	if err := executeScript(appName, imageTag, "predeploy"); err != nil {
		return err
	}
	return nil
}
<commit_msg>fix: run release during predeploy<commit_after>package appjson

func TriggerPostDeploy(appName string, imageTag string) error {
	if err := executeScript(appName, imageTag, "postdeploy"); err != nil {
		return err
	}
	return nil
}

func TriggerPreDeploy(appName string, imageTag string) error {
	if err := executeScript(appName, imageTag, "predeploy"); err != nil {
		return err
	}

	if err := executeScript(appName, imageTag, "release"); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "fmt"
    "strings"
)

func nextToken(s *string) string {
    if s == nil {
        return ""
    }

    i := strings.Index(*s, " ")

    if i == -1 {
        tmp := *s
        *s = ""
        return tmp
    }

    token := (*s)[:i]
    rest := (*s)[i + 1:]
    *s = rest

    return token
}

func ParseMessage(line string) *RawMessage {
    var prefix string
    var arguments []string

    if strings.HasPrefix(line, ":") {
        line = line[1:]
        prefix = nextToken(&line)
    }

    command := nextToken(&line)

    for len(line) != 0 {
        if strings.HasPrefix(line, ":") {
            arguments = append(arguments, line[1:])
            break
        }

        token := nextToken(&line)
        arguments = append(arguments, token)
    }

    return &RawMessage{prefix, command, arguments}
}

type RawMessage struct {
    prefix string
    command string
    arguments []string
}

func (r *RawMessage) String() string {
    a := "["
    final := len(r.arguments) - 1

    for i := range r.arguments {
        if i == final {
            a = a + SingleQuote(r.arguments[i])
        } else {
            a = a + SingleQuote(r.arguments[i]) + ", "
        }
    }

    a = a + "]"

    return fmt.Sprintf("Prefix: '%s', Command: '%s', Parameters: %s, Count: %d", r.prefix, r.command, a, len(r.arguments))
}

func (r *RawMessage) Command() string {
    return r.command
}

func (r *RawMessage) Prefix() string {
    return r.prefix
}

func (r *RawMessage) Arguments() []string {
    return r.arguments
}
<commit_msg>Rename ParseMessage to ParseRawMessage.<commit_after>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "fmt"
    "strings"
)

func nextToken(s *string) string {
    if s == nil {
        return ""
    }

    i := strings.Index(*s, " ")

    if i == -1 {
        tmp := *s
        *s = ""
        return tmp
    }

    token := (*s)[:i]
    rest := (*s)[i + 1:]
    *s = rest

    return token
}

func ParseRawMessage(message string) *RawMessage {
    var prefix string
    var arguments []string

    if strings.HasPrefix(message, ":") {
        message = message[1:]
        prefix = nextToken(&message)
    }

    command := nextToken(&message)

    for len(message) != 0 {
        if strings.HasPrefix(message, ":") {
            arguments = append(arguments, message[1:])
            break
        }

        token := nextToken(&message)
        arguments = append(arguments, token)
    }

    return &RawMessage{prefix, command, arguments}
}

type RawMessage struct {
    prefix string
    command string
    arguments []string
}

func (r *RawMessage) String() string {
    a := "["
    final := len(r.arguments) - 1

    for i := range r.arguments {
        if i == final {
            a = a + SingleQuote(r.arguments[i])
        } else {
            a = a + SingleQuote(r.arguments[i]) + ", "
        }
    }

    a = a + "]"

    return fmt.Sprintf("Prefix: '%s', Command: '%s', Parameters: %s, Count: %d", r.prefix, r.command, a, len(r.arguments))
}

func (r *RawMessage) Command() string {
    return r.command
}

func (r *RawMessage) Prefix() string {
    return r.prefix
}

func (r *RawMessage) Arguments() []string {
    return r.arguments
}
<|endoftext|>


<commit_before>//  Copyright (c) 2017 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 		http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package regexp

import (
	"encoding/binary"
	"fmt"
)

// StateLimit is the maximum number of states allowed
const StateLimit = 10000

// ErrTooManyStates is returned if you attempt to build a Levenshtein
// automaton which requires too many states.
var ErrTooManyStates = fmt.Errorf("dfa contains more than %d states",
	StateLimit)

type dfaBuilder struct {
	dfa    *dfa
	cache  map[string]int
	keyBuf []byte
}

func newDfaBuilder(insts prog) *dfaBuilder {
	d := &dfaBuilder{
		dfa: &dfa{
			insts:  insts,
			states: make([]*state, 0, 16),
		},
		cache: make(map[string]int, 1024),
	}
	// add 0 state that is invalid
	d.dfa.states = append(d.dfa.states, &state{
		next:  make([]int, 256),
		match: false,
	})
	return d
}

func (d *dfaBuilder) build() (*dfa, error) {
	cur := newSparseSet(uint(len(d.dfa.insts)))
	next := newSparseSet(uint(len(d.dfa.insts)))

	d.dfa.add(cur, 0)
	states := intStack{d.cachedState(cur)}
	seen := make(map[int]struct{})
	var s int
	states, s = states.Pop()
	for s != 0 {
		for b := 0; b < 256; b++ {
			ns := d.runState(cur, next, s, byte(b))
			if ns != 0 {
				if _, ok := seen[ns]; !ok {
					seen[ns] = struct{}{}
					states = states.Push(ns)
				}
			}
			if len(d.dfa.states) > StateLimit {
				return nil, ErrTooManyStates
			}
		}
		states, s = states.Pop()
	}
	return d.dfa, nil
}

func (d *dfaBuilder) runState(cur, next *sparseSet, state int, b byte) int {
	cur.Clear()
	for _, ip := range d.dfa.states[state].insts {
		cur.Add(ip)
	}
	d.dfa.run(cur, next, b)
	nextState := d.cachedState(next)
	d.dfa.states[state].next[b] = nextState
	return nextState
}

func instsKey(insts []uint, buf []byte) []byte {
	if cap(buf) < 8*len(insts) {
		buf = make([]byte, 8*len(insts))
	} else {
		buf = buf[0 : 8*len(insts)]
	}
	for i, inst := range insts {
		binary.LittleEndian.PutUint64(buf[i*8:], uint64(inst))
	}
	return buf
}

func (d *dfaBuilder) cachedState(set *sparseSet) int {
	insts := make([]uint, 0, set.Len())
	var isMatch bool
	for i := uint(0); i < uint(set.Len()); i++ {
		ip := set.Get(i)
		switch d.dfa.insts[ip].op {
		case OpRange:
			insts = append(insts, ip)
		case OpMatch:
			isMatch = true
			insts = append(insts, ip)
		}
	}
	if len(insts) == 0 {
		return 0
	}
	d.keyBuf = instsKey(insts, d.keyBuf)
	v, ok := d.cache[string(d.keyBuf)]
	if ok {
		return v
	}
	d.dfa.states = append(d.dfa.states, &state{
		insts: insts,
		next:  make([]int, 256),
		match: isMatch,
	})
	newV := len(d.dfa.states) - 1
	d.cache[string(d.keyBuf)] = newV
	return newV
}

type dfa struct {
	insts  prog
	states []*state
}

func (d *dfa) add(set *sparseSet, ip uint) {
	if set.Contains(ip) {
		return
	}
	set.Add(ip)
	switch d.insts[ip].op {
	case OpJmp:
		d.add(set, d.insts[ip].to)
	case OpSplit:
		d.add(set, d.insts[ip].splitA)
		d.add(set, d.insts[ip].splitB)
	}
}

func (d *dfa) run(from, to *sparseSet, b byte) bool {
	to.Clear()
	var isMatch bool
	for i := uint(0); i < uint(from.Len()); i++ {
		ip := from.Get(i)
		switch d.insts[ip].op {
		case OpMatch:
			isMatch = true
		case OpRange:
			if d.insts[ip].rangeStart <= b &&
				b <= d.insts[ip].rangeEnd {
				d.add(to, ip+1)
			}
		}
	}
	return isMatch
}

type state struct {
	insts []uint
	next  []int
	match bool
}

type intStack []int

func (s intStack) Push(v int) intStack {
	return append(s, v)
}

func (s intStack) Pop() (intStack, int) {
	l := len(s)
	if l < 1 {
		return s, 0
	}
	return s[:l-1], s[l-1]
}
<commit_msg>MB-30253 - regexp.dfaBuilder reuses prealloced insts array<commit_after>//  Copyright (c) 2017 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 		http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package regexp

import (
	"encoding/binary"
	"fmt"
)

// StateLimit is the maximum number of states allowed
const StateLimit = 10000

// ErrTooManyStates is returned if you attempt to build a Levenshtein
// automaton which requires too many states.
var ErrTooManyStates = fmt.Errorf("dfa contains more than %d states",
	StateLimit)

type dfaBuilder struct {
	dfa    *dfa
	cache  map[string]int
	keyBuf []byte
}

func newDfaBuilder(insts prog) *dfaBuilder {
	d := &dfaBuilder{
		dfa: &dfa{
			insts:  insts,
			states: make([]*state, 0, 16),
		},
		cache: make(map[string]int, 1024),
	}
	// add 0 state that is invalid
	d.dfa.states = append(d.dfa.states, &state{
		next:  make([]int, 256),
		match: false,
	})
	return d
}

func (d *dfaBuilder) build() (*dfa, error) {
	cur := newSparseSet(uint(len(d.dfa.insts)))
	next := newSparseSet(uint(len(d.dfa.insts)))

	d.dfa.add(cur, 0)
	ns, instsReuse := d.cachedState(cur, nil)
	states := intStack{ns}
	seen := make(map[int]struct{})
	var s int
	states, s = states.Pop()
	for s != 0 {
		for b := 0; b < 256; b++ {
			var ns int
			ns, instsReuse = d.runState(cur, next, s, byte(b), instsReuse)
			if ns != 0 {
				if _, ok := seen[ns]; !ok {
					seen[ns] = struct{}{}
					states = states.Push(ns)
				}
			}
			if len(d.dfa.states) > StateLimit {
				return nil, ErrTooManyStates
			}
		}
		states, s = states.Pop()
	}
	return d.dfa, nil
}

func (d *dfaBuilder) runState(cur, next *sparseSet, state int, b byte, instsReuse []uint) (
	int, []uint) {
	cur.Clear()
	for _, ip := range d.dfa.states[state].insts {
		cur.Add(ip)
	}
	d.dfa.run(cur, next, b)
	var nextState int
	nextState, instsReuse = d.cachedState(next, instsReuse)
	d.dfa.states[state].next[b] = nextState
	return nextState, instsReuse
}

func instsKey(insts []uint, buf []byte) []byte {
	if cap(buf) < 8*len(insts) {
		buf = make([]byte, 8*len(insts))
	} else {
		buf = buf[0 : 8*len(insts)]
	}
	for i, inst := range insts {
		binary.LittleEndian.PutUint64(buf[i*8:], uint64(inst))
	}
	return buf
}

func (d *dfaBuilder) cachedState(set *sparseSet,
	instsReuse []uint) (int, []uint) {
	insts := instsReuse[:0]
	if cap(insts) == 0 {
		insts = make([]uint, 0, set.Len())
	}
	var isMatch bool
	for i := uint(0); i < uint(set.Len()); i++ {
		ip := set.Get(i)
		switch d.dfa.insts[ip].op {
		case OpRange:
			insts = append(insts, ip)
		case OpMatch:
			isMatch = true
			insts = append(insts, ip)
		}
	}
	if len(insts) == 0 {
		return 0, insts
	}
	d.keyBuf = instsKey(insts, d.keyBuf)
	v, ok := d.cache[string(d.keyBuf)]
	if ok {
		return v, insts
	}
	d.dfa.states = append(d.dfa.states, &state{
		insts: insts,
		next:  make([]int, 256),
		match: isMatch,
	})
	newV := len(d.dfa.states) - 1
	d.cache[string(d.keyBuf)] = newV
	return newV, nil
}

type dfa struct {
	insts  prog
	states []*state
}

func (d *dfa) add(set *sparseSet, ip uint) {
	if set.Contains(ip) {
		return
	}
	set.Add(ip)
	switch d.insts[ip].op {
	case OpJmp:
		d.add(set, d.insts[ip].to)
	case OpSplit:
		d.add(set, d.insts[ip].splitA)
		d.add(set, d.insts[ip].splitB)
	}
}

func (d *dfa) run(from, to *sparseSet, b byte) bool {
	to.Clear()
	var isMatch bool
	for i := uint(0); i < uint(from.Len()); i++ {
		ip := from.Get(i)
		switch d.insts[ip].op {
		case OpMatch:
			isMatch = true
		case OpRange:
			if d.insts[ip].rangeStart <= b &&
				b <= d.insts[ip].rangeEnd {
				d.add(to, ip+1)
			}
		}
	}
	return isMatch
}

type state struct {
	insts []uint
	next  []int
	match bool
}

type intStack []int

func (s intStack) Push(v int) intStack {
	return append(s, v)
}

func (s intStack) Pop() (intStack, int) {
	l := len(s)
	if l < 1 {
		return s, 0
	}
	return s[:l-1], s[l-1]
}
<|endoftext|>


<commit_before>package resource

import (
	"sync"
	"time"
)

// Retry is a basic wrapper around StateChangeConf that will just retry
// a function until it no longer returns an error.
func Retry(timeout time.Duration, f RetryFunc) error {
	// These are used to pull the error out of the function; need a mutex to
	// avoid a data race.
	var resultErr error
	var resultErrMu sync.Mutex

	c := &StateChangeConf{
		Pending:    []string{"retryableerror"},
		Target:     []string{"success"},
		Timeout:    timeout,
		MinTimeout: 500 * time.Millisecond,
		Refresh: func() (interface{}, string, error) {
			rerr := f()
			if rerr == nil {
				resultErr = nil
				return 42, "success", nil
			}

			resultErrMu.Lock()
			defer resultErrMu.Unlock()
			resultErr = rerr.Err

			if rerr.Retryable {
				return 42, "retryableerror", nil
			}
			return nil, "quit", rerr.Err
		},
	}

	_, waitErr := c.WaitForState()

	// Need to acquire the lock here to be able to avoid race using resultErr as
	// the return value
	resultErrMu.Lock()
	defer resultErrMu.Unlock()

	// resultErr may be nil because the wait timed out and resultErr was never
	// set; this is still an error
	if resultErr == nil {
		return waitErr
	}
	// resultErr takes precedence over waitErr if both are set because it is
	// more likely to be useful
	return resultErr
}

// RetryFunc is the function retried until it succeeds.
type RetryFunc func() *RetryError

// RetryError is the required return type of RetryFunc. It forces client code
// to choose whether or not a given error is retryable.
type RetryError struct {
	Err       error
	Retryable bool
}

// RetryableError is a helper to create a RetryError that's retryable from a
// given error.
func RetryableError(err error) *RetryError {
	if err == nil {
		return nil
	}
	return &RetryError{Err: err, Retryable: true}
}

// NonRetryableError is a helper to create a RetryError that's _not)_ retryable
// from a given error.
func NonRetryableError(err error) *RetryError {
	if err == nil {
		return nil
	}
	return &RetryError{Err: err, Retryable: false}
}
<commit_msg>Another race in resource.Retry<commit_after>package resource

import (
	"sync"
	"time"
)

// Retry is a basic wrapper around StateChangeConf that will just retry
// a function until it no longer returns an error.
func Retry(timeout time.Duration, f RetryFunc) error {
	// These are used to pull the error out of the function; need a mutex to
	// avoid a data race.
	var resultErr error
	var resultErrMu sync.Mutex

	c := &StateChangeConf{
		Pending:    []string{"retryableerror"},
		Target:     []string{"success"},
		Timeout:    timeout,
		MinTimeout: 500 * time.Millisecond,
		Refresh: func() (interface{}, string, error) {
			rerr := f()

			resultErrMu.Lock()
			defer resultErrMu.Unlock()

			if rerr == nil {
				resultErr = nil
				return 42, "success", nil
			}

			resultErr = rerr.Err

			if rerr.Retryable {
				return 42, "retryableerror", nil
			}
			return nil, "quit", rerr.Err
		},
	}

	_, waitErr := c.WaitForState()

	// Need to acquire the lock here to be able to avoid race using resultErr as
	// the return value
	resultErrMu.Lock()
	defer resultErrMu.Unlock()

	// resultErr may be nil because the wait timed out and resultErr was never
	// set; this is still an error
	if resultErr == nil {
		return waitErr
	}
	// resultErr takes precedence over waitErr if both are set because it is
	// more likely to be useful
	return resultErr
}

// RetryFunc is the function retried until it succeeds.
type RetryFunc func() *RetryError

// RetryError is the required return type of RetryFunc. It forces client code
// to choose whether or not a given error is retryable.
type RetryError struct {
	Err       error
	Retryable bool
}

// RetryableError is a helper to create a RetryError that's retryable from a
// given error.
func RetryableError(err error) *RetryError {
	if err == nil {
		return nil
	}
	return &RetryError{Err: err, Retryable: true}
}

// NonRetryableError is a helper to create a RetryError that's _not)_ retryable
// from a given error.
func NonRetryableError(err error) *RetryError {
	if err == nil {
		return nil
	}
	return &RetryError{Err: err, Retryable: false}
}
<|endoftext|>


<commit_before>package sdl

/*
#include <SDL2/SDL.h>
#include "events.h"
*/
import "C"
import "unsafe"
import "reflect"
import "fmt"

var filterCallback EventFilter
var filterData interface{}

const (
	FIRSTEVENT              = C.SDL_FIRSTEVENT
	QUIT                    = C.SDL_QUIT
	APP_TERMINATING         = C.SDL_APP_TERMINATING
	APP_LOWMEMORY           = C.SDL_APP_LOWMEMORY
	APP_WILLENTERBACKGROUND = C.SDL_APP_WILLENTERBACKGROUND
	APP_DIDENTERBACKGROUND  = C.SDL_APP_DIDENTERBACKGROUND
	APP_WILLENTERFOREGROUND = C.SDL_APP_WILLENTERFOREGROUND
	APP_DIDENTERFOREGROUND  = C.SDL_APP_DIDENTERFOREGROUND

	/* Window events */
	WINDOWEVENT = C.SDL_WINDOWEVENT
	SYSWMEVENT  = C.SDL_SYSWMEVENT

	/* Keyboard events */
	KEYDOWN     = C.SDL_KEYDOWN
	KEYUP       = C.SDL_KEYUP
	TEXTEDITING = C.SDL_TEXTEDITING
	TEXTINPUT   = C.SDL_TEXTINPUT

	/* Mouse events */
	MOUSEMOTION     = C.SDL_MOUSEMOTION
	MOUSEBUTTONDOWN = C.SDL_MOUSEBUTTONDOWN
	MOUSEBUTTONUP   = C.SDL_MOUSEBUTTONUP
	MOUSEWHEEL      = C.SDL_MOUSEWHEEL

	/* Joystick events */
	JOYAXISMOTION    = C.SDL_JOYAXISMOTION
	JOYBALLMOTION    = C.SDL_JOYBALLMOTION
	JOYHATMOTION     = C.SDL_JOYHATMOTION
	JOYBUTTONDOWN    = C.SDL_JOYBUTTONDOWN
	JOYBUTTONUP      = C.SDL_JOYBUTTONUP
	JOYDEVICEADDED   = C.SDL_JOYDEVICEADDED
	JOYDEVICEREMOVED = C.SDL_JOYDEVICEREMOVED

	/* Game controller events */
	CONTROLLERAXISMOTION     = C.SDL_CONTROLLERAXISMOTION
	CONTROLLERBUTTONDOWN     = C.SDL_CONTROLLERBUTTONDOWN
	CONTROLLERBUTTONUP       = C.SDL_CONTROLLERBUTTONUP
	CONTROLLERDEVICEADDED    = C.SDL_CONTROLLERDEVICEADDED
	CONTROLLERDEVICEREMOVED  = C.SDL_CONTROLLERDEVICEREMOVED
	CONTROLLERDEVICEREMAPPED = C.SDL_CONTROLLERDEVICEREMAPPED

	/* Touch events */
	FINGERDOWN   = C.SDL_FINGERDOWN
	FINGERUP     = C.SDL_FINGERUP
	FINGERMOTION = C.SDL_FINGERMOTION

	/* Gesture events */
	DOLLARGESTURE = C.SDL_DOLLARGESTURE
	DOLLARRECORD  = C.SDL_DOLLARRECORD
	MULTIGESTURE  = C.SDL_MULTIGESTURE

	/* Clipboard events */
	CLIPBOARDUPDATE = C.SDL_CLIPBOARDUPDATE

	/* Drag and drop events */
	DROPFILE = C.SDL_DROPFILE

	USEREVENT = C.SDL_USEREVENT
	LASTEVENT = C.SDL_LASTEVENT
)

const (
	ADDEVENT = C.SDL_ADDEVENT
	PEEKEVENT = C.SDL_PEEKEVENT
	GETEVENT = C.SDL_PEEKEVENT
)

const (
	QUERY   = C.SDL_QUERY
	IGNORE  = C.SDL_IGNORE
	DISABLE = C.SDL_DISABLE
	ENABLE  = C.SDL_ENABLE
)

type Event interface{}

type CEvent struct {
	Type     uint32
	padding1 [52]byte
}

type CommonEvent struct {
	Type      uint32
	Timestamp uint32
}

type WindowEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Event     uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	Data1     int32
	Data2     int32
}

type KeyDownEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	State     uint8
	Repeat    uint8
	padding1  uint8
	padding2  uint8
	Keysym    Keysym
}

type KeyUpEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	State     uint8
	Repeat    uint8
	padding1  uint8
	padding2  uint8
	Keysym    Keysym
}

type TextEditingEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Text      [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte
	Start     int32
	Length    int32
}

type TextInputEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Text      [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte
}

type MouseMotionEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Which     uint32
	State     uint32
	X         int32
	Y         int32
	XRel      int32
	YRel      int32
}

type MouseButtonEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Which     uint32
	Button    uint8
	State     uint8
	padding1  uint8
	padding2  uint8
	X         int32
	Y         int32
}

type MouseWheelEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Which     uint32
	X         int32
	Y         int32
}

type JoyAxisEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Axis      uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	Value     int16
	padding4  uint16
}

type JoyBallEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Ball      uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	XRel      int16
	YRel      int16
}

type JoyHatEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Hat       uint8
	Value     uint8
	padding1  uint8
	padding2  uint8
}

type JoyButtonEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Button    uint8
	State     uint8
	padding1  uint8
	padding2  uint8
}

type JoyDeviceEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
}

type ControllerAxisEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Axis      uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	Value     int16
	padding4  uint16
}

type ControllerButtonEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Button    uint8
	State     uint8
	padding1  uint8
	padding2  uint8
}

type ControllerDeviceEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
}

type TouchFingerEvent struct {
	Type      uint32
	Timestamp uint32
	TouchID   TouchID
	FingerID  FingerID
	X         float32
	Y         float32
	DX        float32
	DY        float32
	Pressure  float32
}

type MultiGestureEvent struct {
	Type       uint32
	Timestamp  uint32
	TouchId    TouchID
	DTheta     float32
	DDist      float32
	X          float32
	Y          float32
	NumFingers uint16
	padding    uint16
}

type DollarGestureEvent struct {
	Type       uint32
	Timestamp  uint32
	TouchID    TouchID
	GestureID  GestureID
	NumFingers uint32
	Error      float32
	X          float32
	Y          float32
}

type DropEvent struct {
	Type      uint32
	Timestamp uint32
	file      unsafe.Pointer
}

type QuitEvent struct {
	Type      uint32
	Timestamp uint32
}

type OSEvent struct {
	Type      uint32
	Timestamp uint32
}

type ClipboardEvent struct {
	Type      uint32
	Timestamp uint32
}

type UserEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Code      int32
	Data1     unsafe.Pointer
	Data2     unsafe.Pointer
}

type SysWMEvent struct {
	Type      uint32
	Timestamp uint32
	msg       unsafe.Pointer
}

type EventFilter func(userdata interface{}, event Event) int
type EventAction C.SDL_eventaction

func (action EventAction) c() C.SDL_eventaction {
    return C.SDL_eventaction(action)
}

func PumpEvents() {
	C.SDL_PumpEvents()
}

func PeepEvents(events []Event, action EventAction, minType, maxType uint32) int {
	var _events []CEvent = make([]CEvent, len(events))

	if action == ADDEVENT { // the contents of _events matter if they are to be added
		for i := 0; i < len(events); i++ {
			_events[i] = *cEvent(events[i])
		}
	}

	_pevents := (*C.SDL_Event)(unsafe.Pointer(&_events[0]))
	retVal := int(C.SDL_PeepEvents(_pevents, C.int(len(events)), action.c(), C.Uint32(minType), C.Uint32(maxType)))

	if action != ADDEVENT { // put events into slice, events unchanged if action = ADDEVENT
		for i := 0; i < retVal; i++ {
			events[i] = goEvent(&_events[i])
		}
	}
	return retVal
}

func HasEvent(type_ uint32) bool {
	return C.SDL_HasEvent(C.Uint32(type_)) != 0
}

func HasEvents(minType, maxType uint32) bool {
	return C.SDL_HasEvents(C.Uint32(minType), C.Uint32(maxType)) != 0
}

func FlushEvent(type_ uint32) {
	C.SDL_FlushEvent(C.Uint32(type_))
}

func FlushEvents(minType, maxType uint32) {
	C.SDL_FlushEvents(C.Uint32(minType), C.Uint32(maxType))
}

func PollEvent() Event {
	var cevent C.SDL_Event
	ret := C.SDL_PollEvent(&cevent)
	if ret == 0 {
		return nil
	}
	return goEvent((*CEvent)(unsafe.Pointer(&cevent)))
}

func goEvent(cevent *CEvent) Event {
	switch cevent.Type {
	case WINDOWEVENT:
		return (*WindowEvent)(unsafe.Pointer(cevent))
	case SYSWMEVENT:
		return (*SysWMEvent)(unsafe.Pointer(cevent))
	case KEYDOWN:
		return (*KeyDownEvent)(unsafe.Pointer(cevent))
	case KEYUP:
		return (*KeyUpEvent)(unsafe.Pointer(cevent))
	case TEXTEDITING:
		return (*TextEditingEvent)(unsafe.Pointer(cevent))
	case TEXTINPUT:
		return (*TextInputEvent)(unsafe.Pointer(cevent))
	case MOUSEMOTION:
		return (*MouseMotionEvent)(unsafe.Pointer(cevent))
	case MOUSEBUTTONDOWN, MOUSEBUTTONUP:
		return (*MouseButtonEvent)(unsafe.Pointer(cevent))
	case MOUSEWHEEL:
		return (*MouseWheelEvent)(unsafe.Pointer(cevent))
	case JOYAXISMOTION:
		return (*JoyAxisEvent)(unsafe.Pointer(cevent))
	case JOYBALLMOTION:
		return (*JoyBallEvent)(unsafe.Pointer(cevent))
	case JOYHATMOTION:
		return (*JoyHatEvent)(unsafe.Pointer(cevent))
	case JOYBUTTONDOWN, JOYBUTTONUP:
		return (*JoyButtonEvent)(unsafe.Pointer(cevent))
	case JOYDEVICEADDED, JOYDEVICEREMOVED:
		return (*JoyDeviceEvent)(unsafe.Pointer(cevent))
	case CONTROLLERAXISMOTION:
		return (*ControllerAxisEvent)(unsafe.Pointer(cevent))
	case CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP:
		return (*ControllerButtonEvent)(unsafe.Pointer(cevent))
	case CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED, CONTROLLERDEVICEREMAPPED:
		return (*ControllerDeviceEvent)(unsafe.Pointer(cevent))
	case FINGERDOWN, FINGERUP, FINGERMOTION:
		return (*TouchFingerEvent)(unsafe.Pointer(cevent))
	case DOLLARGESTURE, DOLLARRECORD:
		return (*DollarGestureEvent)(unsafe.Pointer(cevent))
	case MULTIGESTURE:
		return (*MultiGestureEvent)(unsafe.Pointer(cevent))
	case DROPFILE:
		return (*DropEvent)(unsafe.Pointer(cevent))
	case QUIT:
		return (*QuitEvent)(unsafe.Pointer(cevent))
	case USEREVENT:
		return (*UserEvent)(unsafe.Pointer(cevent))
	case CLIPBOARDUPDATE:
		return (*ClipboardEvent)(unsafe.Pointer(cevent))
	}

	panic(fmt.Errorf("Unknown event type: %v", cevent.Type))
}

func cEvent(event Event) *CEvent {
	evv := reflect.ValueOf(event)
	p := evv.Elem()
	return (*CEvent)(unsafe.Pointer(p.UnsafeAddr()))
}

func WaitEventTimeout(timeout int) Event {
	var cevent CEvent
	_event := (*C.SDL_Event)(unsafe.Pointer(&cevent))
	ok := int(C.SDL_WaitEventTimeout(_event, C.int(timeout)))
	if ok == 0 {
		return nil
	}
	return goEvent(&cevent)
}

func WaitEvent() Event {
	var cevent CEvent
	_event := (*C.SDL_Event)(unsafe.Pointer(&cevent))
	ok := int(C.SDL_WaitEvent(_event))
	if ok == 0 {
		return nil
	}
	return goEvent(&cevent)
}

func PushEvent(event Event) int {
	_event := (*C.SDL_Event)(unsafe.Pointer(cEvent(event)))
	return int(C.SDL_PushEvent(_event))
}

//export goFilter
func goFilter(userdata interface{}, e Event) int {
	a := reflect.ValueOf(&userdata).Elem()
	b := a.InterfaceData()[1]
	c := (*CEvent) (unsafe.Pointer(b))
	return filterCallback(filterData, goEvent(c))
}

func SetEventFilter(filter EventFilter, userdata interface{}) {
	filterCallback = filter
	filterData = userdata

	C._SDL_SetEventFilter(nil)
}

func GetEventFilter() (EventFilter, interface{}) {
	return filterCallback, filterData
}

func AddEventWatch(filter EventFilter, userdata interface{}) {
}

func DelEventWatch(filter EventFilter, userdata interface{}) {
}

func FilterEvents(filter EventFilter, userdata interface{}) {
}

func EventState(type_ uint32, state int) uint8 {
	return uint8(C.SDL_EventState(C.Uint32(type_), C.int(state)))
}

func GetEventState(type_ uint32) uint8 {
	return uint8(C.SDL_EventState(C.Uint32(type_), QUERY))
}

func RegisterEvents(numEvents int) uint32 {
	return uint32(C.SDL_RegisterEvents(C.int(numEvents)))
}
<commit_msg>Removed WIP code that prevented build<commit_after>package sdl

/*
#include <SDL2/SDL.h>
*/
import "C"
import "unsafe"
import "reflect"
import "fmt"

var filterCallback EventFilter
var filterData interface{}

const (
	FIRSTEVENT              = C.SDL_FIRSTEVENT
	QUIT                    = C.SDL_QUIT
	APP_TERMINATING         = C.SDL_APP_TERMINATING
	APP_LOWMEMORY           = C.SDL_APP_LOWMEMORY
	APP_WILLENTERBACKGROUND = C.SDL_APP_WILLENTERBACKGROUND
	APP_DIDENTERBACKGROUND  = C.SDL_APP_DIDENTERBACKGROUND
	APP_WILLENTERFOREGROUND = C.SDL_APP_WILLENTERFOREGROUND
	APP_DIDENTERFOREGROUND  = C.SDL_APP_DIDENTERFOREGROUND

	/* Window events */
	WINDOWEVENT = C.SDL_WINDOWEVENT
	SYSWMEVENT  = C.SDL_SYSWMEVENT

	/* Keyboard events */
	KEYDOWN     = C.SDL_KEYDOWN
	KEYUP       = C.SDL_KEYUP
	TEXTEDITING = C.SDL_TEXTEDITING
	TEXTINPUT   = C.SDL_TEXTINPUT

	/* Mouse events */
	MOUSEMOTION     = C.SDL_MOUSEMOTION
	MOUSEBUTTONDOWN = C.SDL_MOUSEBUTTONDOWN
	MOUSEBUTTONUP   = C.SDL_MOUSEBUTTONUP
	MOUSEWHEEL      = C.SDL_MOUSEWHEEL

	/* Joystick events */
	JOYAXISMOTION    = C.SDL_JOYAXISMOTION
	JOYBALLMOTION    = C.SDL_JOYBALLMOTION
	JOYHATMOTION     = C.SDL_JOYHATMOTION
	JOYBUTTONDOWN    = C.SDL_JOYBUTTONDOWN
	JOYBUTTONUP      = C.SDL_JOYBUTTONUP
	JOYDEVICEADDED   = C.SDL_JOYDEVICEADDED
	JOYDEVICEREMOVED = C.SDL_JOYDEVICEREMOVED

	/* Game controller events */
	CONTROLLERAXISMOTION     = C.SDL_CONTROLLERAXISMOTION
	CONTROLLERBUTTONDOWN     = C.SDL_CONTROLLERBUTTONDOWN
	CONTROLLERBUTTONUP       = C.SDL_CONTROLLERBUTTONUP
	CONTROLLERDEVICEADDED    = C.SDL_CONTROLLERDEVICEADDED
	CONTROLLERDEVICEREMOVED  = C.SDL_CONTROLLERDEVICEREMOVED
	CONTROLLERDEVICEREMAPPED = C.SDL_CONTROLLERDEVICEREMAPPED

	/* Touch events */
	FINGERDOWN   = C.SDL_FINGERDOWN
	FINGERUP     = C.SDL_FINGERUP
	FINGERMOTION = C.SDL_FINGERMOTION

	/* Gesture events */
	DOLLARGESTURE = C.SDL_DOLLARGESTURE
	DOLLARRECORD  = C.SDL_DOLLARRECORD
	MULTIGESTURE  = C.SDL_MULTIGESTURE

	/* Clipboard events */
	CLIPBOARDUPDATE = C.SDL_CLIPBOARDUPDATE

	/* Drag and drop events */
	DROPFILE = C.SDL_DROPFILE

	USEREVENT = C.SDL_USEREVENT
	LASTEVENT = C.SDL_LASTEVENT
)

const (
	ADDEVENT = C.SDL_ADDEVENT
	PEEKEVENT = C.SDL_PEEKEVENT
	GETEVENT = C.SDL_PEEKEVENT
)

const (
	QUERY   = C.SDL_QUERY
	IGNORE  = C.SDL_IGNORE
	DISABLE = C.SDL_DISABLE
	ENABLE  = C.SDL_ENABLE
)

type Event interface{}

type CEvent struct {
	Type     uint32
	padding1 [52]byte
}

type CommonEvent struct {
	Type      uint32
	Timestamp uint32
}

type WindowEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Event     uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	Data1     int32
	Data2     int32
}

type KeyDownEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	State     uint8
	Repeat    uint8
	padding1  uint8
	padding2  uint8
	Keysym    Keysym
}

type KeyUpEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	State     uint8
	Repeat    uint8
	padding1  uint8
	padding2  uint8
	Keysym    Keysym
}

type TextEditingEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Text      [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte
	Start     int32
	Length    int32
}

type TextInputEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Text      [C.SDL_TEXTINPUTEVENT_TEXT_SIZE]byte
}

type MouseMotionEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Which     uint32
	State     uint32
	X         int32
	Y         int32
	XRel      int32
	YRel      int32
}

type MouseButtonEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Which     uint32
	Button    uint8
	State     uint8
	padding1  uint8
	padding2  uint8
	X         int32
	Y         int32
}

type MouseWheelEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Which     uint32
	X         int32
	Y         int32
}

type JoyAxisEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Axis      uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	Value     int16
	padding4  uint16
}

type JoyBallEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Ball      uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	XRel      int16
	YRel      int16
}

type JoyHatEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Hat       uint8
	Value     uint8
	padding1  uint8
	padding2  uint8
}

type JoyButtonEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Button    uint8
	State     uint8
	padding1  uint8
	padding2  uint8
}

type JoyDeviceEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
}

type ControllerAxisEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Axis      uint8
	padding1  uint8
	padding2  uint8
	padding3  uint8
	Value     int16
	padding4  uint16
}

type ControllerButtonEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
	Button    uint8
	State     uint8
	padding1  uint8
	padding2  uint8
}

type ControllerDeviceEvent struct {
	Type      uint32
	Timestamp uint32
	Which     JoystickID
}

type TouchFingerEvent struct {
	Type      uint32
	Timestamp uint32
	TouchID   TouchID
	FingerID  FingerID
	X         float32
	Y         float32
	DX        float32
	DY        float32
	Pressure  float32
}

type MultiGestureEvent struct {
	Type       uint32
	Timestamp  uint32
	TouchId    TouchID
	DTheta     float32
	DDist      float32
	X          float32
	Y          float32
	NumFingers uint16
	padding    uint16
}

type DollarGestureEvent struct {
	Type       uint32
	Timestamp  uint32
	TouchID    TouchID
	GestureID  GestureID
	NumFingers uint32
	Error      float32
	X          float32
	Y          float32
}

type DropEvent struct {
	Type      uint32
	Timestamp uint32
	file      unsafe.Pointer
}

type QuitEvent struct {
	Type      uint32
	Timestamp uint32
}

type OSEvent struct {
	Type      uint32
	Timestamp uint32
}

type ClipboardEvent struct {
	Type      uint32
	Timestamp uint32
}

type UserEvent struct {
	Type      uint32
	Timestamp uint32
	WindowID  uint32
	Code      int32
	Data1     unsafe.Pointer
	Data2     unsafe.Pointer
}

type SysWMEvent struct {
	Type      uint32
	Timestamp uint32
	msg       unsafe.Pointer
}

type EventFilter func(userdata interface{}, event Event) int
type EventAction C.SDL_eventaction

func (action EventAction) c() C.SDL_eventaction {
    return C.SDL_eventaction(action)
}

func PumpEvents() {
	C.SDL_PumpEvents()
}

func PeepEvents(events []Event, action EventAction, minType, maxType uint32) int {
	var _events []CEvent = make([]CEvent, len(events))

	if action == ADDEVENT { // the contents of _events matter if they are to be added
		for i := 0; i < len(events); i++ {
			_events[i] = *cEvent(events[i])
		}
	}

	_pevents := (*C.SDL_Event)(unsafe.Pointer(&_events[0]))
	retVal := int(C.SDL_PeepEvents(_pevents, C.int(len(events)), action.c(), C.Uint32(minType), C.Uint32(maxType)))

	if action != ADDEVENT { // put events into slice, events unchanged if action = ADDEVENT
		for i := 0; i < retVal; i++ {
			events[i] = goEvent(&_events[i])
		}
	}
	return retVal
}

func HasEvent(type_ uint32) bool {
	return C.SDL_HasEvent(C.Uint32(type_)) != 0
}

func HasEvents(minType, maxType uint32) bool {
	return C.SDL_HasEvents(C.Uint32(minType), C.Uint32(maxType)) != 0
}

func FlushEvent(type_ uint32) {
	C.SDL_FlushEvent(C.Uint32(type_))
}

func FlushEvents(minType, maxType uint32) {
	C.SDL_FlushEvents(C.Uint32(minType), C.Uint32(maxType))
}

func PollEvent() Event {
	var cevent C.SDL_Event
	ret := C.SDL_PollEvent(&cevent)
	if ret == 0 {
		return nil
	}
	return goEvent((*CEvent)(unsafe.Pointer(&cevent)))
}

func goEvent(cevent *CEvent) Event {
	switch cevent.Type {
	case WINDOWEVENT:
		return (*WindowEvent)(unsafe.Pointer(cevent))
	case SYSWMEVENT:
		return (*SysWMEvent)(unsafe.Pointer(cevent))
	case KEYDOWN:
		return (*KeyDownEvent)(unsafe.Pointer(cevent))
	case KEYUP:
		return (*KeyUpEvent)(unsafe.Pointer(cevent))
	case TEXTEDITING:
		return (*TextEditingEvent)(unsafe.Pointer(cevent))
	case TEXTINPUT:
		return (*TextInputEvent)(unsafe.Pointer(cevent))
	case MOUSEMOTION:
		return (*MouseMotionEvent)(unsafe.Pointer(cevent))
	case MOUSEBUTTONDOWN, MOUSEBUTTONUP:
		return (*MouseButtonEvent)(unsafe.Pointer(cevent))
	case MOUSEWHEEL:
		return (*MouseWheelEvent)(unsafe.Pointer(cevent))
	case JOYAXISMOTION:
		return (*JoyAxisEvent)(unsafe.Pointer(cevent))
	case JOYBALLMOTION:
		return (*JoyBallEvent)(unsafe.Pointer(cevent))
	case JOYHATMOTION:
		return (*JoyHatEvent)(unsafe.Pointer(cevent))
	case JOYBUTTONDOWN, JOYBUTTONUP:
		return (*JoyButtonEvent)(unsafe.Pointer(cevent))
	case JOYDEVICEADDED, JOYDEVICEREMOVED:
		return (*JoyDeviceEvent)(unsafe.Pointer(cevent))
	case CONTROLLERAXISMOTION:
		return (*ControllerAxisEvent)(unsafe.Pointer(cevent))
	case CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP:
		return (*ControllerButtonEvent)(unsafe.Pointer(cevent))
	case CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED, CONTROLLERDEVICEREMAPPED:
		return (*ControllerDeviceEvent)(unsafe.Pointer(cevent))
	case FINGERDOWN, FINGERUP, FINGERMOTION:
		return (*TouchFingerEvent)(unsafe.Pointer(cevent))
	case DOLLARGESTURE, DOLLARRECORD:
		return (*DollarGestureEvent)(unsafe.Pointer(cevent))
	case MULTIGESTURE:
		return (*MultiGestureEvent)(unsafe.Pointer(cevent))
	case DROPFILE:
		return (*DropEvent)(unsafe.Pointer(cevent))
	case QUIT:
		return (*QuitEvent)(unsafe.Pointer(cevent))
	case USEREVENT:
		return (*UserEvent)(unsafe.Pointer(cevent))
	case CLIPBOARDUPDATE:
		return (*ClipboardEvent)(unsafe.Pointer(cevent))
	}

	panic(fmt.Errorf("Unknown event type: %v", cevent.Type))
}

func cEvent(event Event) *CEvent {
	evv := reflect.ValueOf(event)
	p := evv.Elem()
	return (*CEvent)(unsafe.Pointer(p.UnsafeAddr()))
}

func WaitEventTimeout(timeout int) Event {
	var cevent CEvent
	_event := (*C.SDL_Event)(unsafe.Pointer(&cevent))
	ok := int(C.SDL_WaitEventTimeout(_event, C.int(timeout)))
	if ok == 0 {
		return nil
	}
	return goEvent(&cevent)
}

func WaitEvent() Event {
	var cevent CEvent
	_event := (*C.SDL_Event)(unsafe.Pointer(&cevent))
	ok := int(C.SDL_WaitEvent(_event))
	if ok == 0 {
		return nil
	}
	return goEvent(&cevent)
}

func PushEvent(event Event) int {
	_event := (*C.SDL_Event)(unsafe.Pointer(cEvent(event)))
	return int(C.SDL_PushEvent(_event))
}

/*
//export goFilter
func goFilter(userdata interface{}, e Event) int {
	a := reflect.ValueOf(&userdata).Elem()
	b := a.InterfaceData()[1]
	c := (*CEvent) (unsafe.Pointer(b))
	return filterCallback(filterData, goEvent(c))
}

func SetEventFilter(filter EventFilter, userdata interface{}) {
	filterCallback = filter
	filterData = userdata

	C._SDL_SetEventFilter(nil)
}

func GetEventFilter() (EventFilter, interface{}) {
	return filterCallback, filterData
}

func AddEventWatch(filter EventFilter, userdata interface{}) {
}

func DelEventWatch(filter EventFilter, userdata interface{}) {
}

func FilterEvents(filter EventFilter, userdata interface{}) {
}
*/

func EventState(type_ uint32, state int) uint8 {
	return uint8(C.SDL_EventState(C.Uint32(type_), C.int(state)))
}

func GetEventState(type_ uint32) uint8 {
	return uint8(C.SDL_EventState(C.Uint32(type_), QUERY))
}

func RegisterEvents(numEvents int) uint32 {
	return uint32(C.SDL_RegisterEvents(C.int(numEvents)))
}
<|endoftext|>


<commit_before>/*
 * jQuery File Upload Plugin GAE Go Example 2.1.2
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2011, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */

package app

import (
	"appengine"
	"appengine/blobstore"
	"appengine/image"
	"appengine/taskqueue"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"
)

const (
	WEBSITE           = "http://blueimp.github.com/jQuery-File-Upload/"
	MIN_FILE_SIZE     = 1       // bytes
	MAX_FILE_SIZE     = 5000000 // bytes
	IMAGE_TYPES       = "image/(gif|p?jpeg|(x-)?png)"
	ACCEPT_FILE_TYPES = IMAGE_TYPES
	EXPIRATION_TIME   = 300 // seconds
	THUMBNAIL_PARAM   = "=s80"
)

var (
	imageTypes      = regexp.MustCompile(IMAGE_TYPES)
	acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES)
)

type FileInfo struct {
	Key          appengine.BlobKey `json:"-"`
	Url          string            `json:"url,omitempty"`
	ThumbnailUrl string            `json:"thumbnail_url,omitempty"`
	Name         string            `json:"name"`
	Type         string            `json:"type"`
	Size         int64             `json:"size"`
	Error        string            `json:"error,omitempty"`
	DeleteUrl    string            `json:"delete_url,omitempty"`
	DeleteType   string            `json:"delete_type,omitempty"`
}

func (fi *FileInfo) ValidateType() (valid bool) {
	if acceptFileTypes.MatchString(fi.Type) {
		return true
	}
	fi.Error = "Filetype not allowed"
	return false
}

func (fi *FileInfo) ValidateSize() (valid bool) {
	if fi.Size < MIN_FILE_SIZE {
		fi.Error = "File is too small"
	} else if fi.Size > MAX_FILE_SIZE {
		fi.Error = "File is too big"
	} else {
		return true
	}
	return false
}

func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) {
	u := &url.URL{
		Scheme: r.URL.Scheme,
		Host:   appengine.DefaultVersionHostname(c),
		Path:   "/",
	}
	uString := u.String()
	fi.Url = uString + escape(string(fi.Key)) + "/" +
		escape(string(fi.Name))
	fi.DeleteUrl = fi.Url + "?delete=true"
	fi.DeleteType = "DELETE"
	if imageTypes.MatchString(fi.Type) {
		servingUrl, err := image.ServingURL(
			c,
			fi.Key,
			&image.ServingURLOptions{
				Secure: strings.HasSuffix(u.Scheme, "s"),
				Size:   0,
				Crop:   false,
			},
		)
		check(err)
		fi.ThumbnailUrl = servingUrl.String() + THUMBNAIL_PARAM
	}
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func escape(s string) string {
	return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
}

func delayedDelete(c appengine.Context, fi *FileInfo) {
	if key := string(fi.Key); key != "" {
		task := &taskqueue.Task{
			Path:   "/" + escape(key) + "/-",
			Method: "DELETE",
			Delay:  time.Duration(EXPIRATION_TIME) * time.Second,
		}
		taskqueue.Add(c, task, "")
	}
}

func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
	fi = &FileInfo{
		Name: p.FileName(),
		Type: p.Header.Get("Content-Type"),
	}
	if !fi.ValidateType() {
		return
	}
	defer func() {
		if rec := recover(); rec != nil {
			log.Println(rec)
			fi.Error = rec.(error).Error()
		}
	}()
	lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1}
	context := appengine.NewContext(r)
	w, err := blobstore.Create(context, fi.Type)
	defer func() {
		w.Close()
		fi.Size = MAX_FILE_SIZE + 1 - lr.N
		fi.Key, err = w.Key()
		check(err)
		if !fi.ValidateSize() {
			err := blobstore.Delete(context, fi.Key)
			check(err)
			return
		}
		delayedDelete(context, fi)
		fi.CreateUrls(r, context)
	}()
	check(err)
	_, err = io.Copy(w, lr)
	return
}

func getFormValue(p *multipart.Part) string {
	var b bytes.Buffer
	io.CopyN(&b, p, int64(1<<20)) // Copy max: 1 MiB
	return b.String()
}

func handleUploads(r *http.Request) (fileInfos []*FileInfo) {
	fileInfos = make([]*FileInfo, 0)
	mr, err := r.MultipartReader()
	check(err)
	r.Form, err = url.ParseQuery(r.URL.RawQuery)
	check(err)
	part, err := mr.NextPart()
	for err == nil {
		if name := part.FormName(); name != "" {
			if part.FileName() != "" {
				fileInfos = append(fileInfos, handleUpload(r, part))
			} else {
				r.Form[name] = append(r.Form[name], getFormValue(part))
			}
		}
		part, err = mr.NextPart()
	}
	return
}

func get(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.Redirect(w, r, WEBSITE, http.StatusFound)
		return
	}
	parts := strings.Split(r.URL.Path, "/")
	if len(parts) == 3 {
		if key := parts[1]; key != "" {
			blobKey := appengine.BlobKey(key)
			bi, err := blobstore.Stat(appengine.NewContext(r), blobKey)
			if err == nil {
				w.Header().Add(
					"Cache-Control",
					fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME),
				)
				if imageTypes.MatchString(bi.ContentType) {
					w.Header().Add("X-Content-Type-Options", "nosniff")
				} else {
					w.Header().Add("Content-Type", "application/octet-stream")
					w.Header().Add(
						"Content-Disposition:",
						fmt.Sprintf("attachment; filename=%s;", parts[2]),
					)
				}
				blobstore.Send(w, blobKey)
				return
			}
		}
	}
	http.Error(w, "404 Not Found", http.StatusNotFound)
}

func post(w http.ResponseWriter, r *http.Request) {
	b, err := json.Marshal(handleUploads(r))
	check(err)
	if redirect := r.FormValue("redirect"); redirect != "" {
		http.Redirect(w, r, fmt.Sprintf(
			redirect,
			escape(string(b)),
		), http.StatusFound)
		return
	}
	w.Header().Set("Cache-Control", "no-cache")
	jsonType := "application/json"
	if strings.Index(r.Header.Get("Accept"), jsonType) != -1 {
		w.Header().Set("Content-Type", jsonType)
	}
	fmt.Fprintln(w, string(b))
}

func delete(w http.ResponseWriter, r *http.Request) {
	parts := strings.Split(r.URL.Path, "/")
	if len(parts) != 3 {
		return
	}
	if key := parts[1]; key != "" {
		c := appengine.NewContext(r)
		blobKey := appengine.BlobKey(key)
		err := blobstore.Delete(c, blobKey)
		check(err)
		err = image.DeleteServingURL(c, blobKey)
		check(err)
	}
}

func handle(w http.ResponseWriter, r *http.Request) {
	params, err := url.ParseQuery(r.URL.RawQuery)
	check(err)
	w.Header().Add("Access-Control-Allow-Origin", "*")
	w.Header().Add(
		"Access-Control-Allow-Methods",
		"OPTIONS, HEAD, GET, POST, PUT, DELETE",
	)
	switch r.Method {
	case "OPTIONS":
	case "HEAD":
	case "GET":
		get(w, r)
	case "POST":
		if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" {
			delete(w, r)
		} else {
			post(w, r)
		}
	case "DELETE":
		delete(w, r)
	default:
		http.Error(w, "501 Not Implemented", http.StatusNotImplemented)
	}
}

func init() {
	http.HandleFunc("/", handle)
}
<commit_msg>Only use fmt.Sprintf if redirect URL contains "%s".<commit_after>/*
 * jQuery File Upload Plugin GAE Go Example 2.1.3
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2011, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */

package app

import (
	"appengine"
	"appengine/blobstore"
	"appengine/image"
	"appengine/taskqueue"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"
)

const (
	WEBSITE           = "http://blueimp.github.com/jQuery-File-Upload/"
	MIN_FILE_SIZE     = 1       // bytes
	MAX_FILE_SIZE     = 5000000 // bytes
	IMAGE_TYPES       = "image/(gif|p?jpeg|(x-)?png)"
	ACCEPT_FILE_TYPES = IMAGE_TYPES
	EXPIRATION_TIME   = 300 // seconds
	THUMBNAIL_PARAM   = "=s80"
)

var (
	imageTypes      = regexp.MustCompile(IMAGE_TYPES)
	acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES)
)

type FileInfo struct {
	Key          appengine.BlobKey `json:"-"`
	Url          string            `json:"url,omitempty"`
	ThumbnailUrl string            `json:"thumbnail_url,omitempty"`
	Name         string            `json:"name"`
	Type         string            `json:"type"`
	Size         int64             `json:"size"`
	Error        string            `json:"error,omitempty"`
	DeleteUrl    string            `json:"delete_url,omitempty"`
	DeleteType   string            `json:"delete_type,omitempty"`
}

func (fi *FileInfo) ValidateType() (valid bool) {
	if acceptFileTypes.MatchString(fi.Type) {
		return true
	}
	fi.Error = "Filetype not allowed"
	return false
}

func (fi *FileInfo) ValidateSize() (valid bool) {
	if fi.Size < MIN_FILE_SIZE {
		fi.Error = "File is too small"
	} else if fi.Size > MAX_FILE_SIZE {
		fi.Error = "File is too big"
	} else {
		return true
	}
	return false
}

func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) {
	u := &url.URL{
		Scheme: r.URL.Scheme,
		Host:   appengine.DefaultVersionHostname(c),
		Path:   "/",
	}
	uString := u.String()
	fi.Url = uString + escape(string(fi.Key)) + "/" +
		escape(string(fi.Name))
	fi.DeleteUrl = fi.Url + "?delete=true"
	fi.DeleteType = "DELETE"
	if imageTypes.MatchString(fi.Type) {
		servingUrl, err := image.ServingURL(
			c,
			fi.Key,
			&image.ServingURLOptions{
				Secure: strings.HasSuffix(u.Scheme, "s"),
				Size:   0,
				Crop:   false,
			},
		)
		check(err)
		fi.ThumbnailUrl = servingUrl.String() + THUMBNAIL_PARAM
	}
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func escape(s string) string {
	return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
}

func delayedDelete(c appengine.Context, fi *FileInfo) {
	if key := string(fi.Key); key != "" {
		task := &taskqueue.Task{
			Path:   "/" + escape(key) + "/-",
			Method: "DELETE",
			Delay:  time.Duration(EXPIRATION_TIME) * time.Second,
		}
		taskqueue.Add(c, task, "")
	}
}

func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
	fi = &FileInfo{
		Name: p.FileName(),
		Type: p.Header.Get("Content-Type"),
	}
	if !fi.ValidateType() {
		return
	}
	defer func() {
		if rec := recover(); rec != nil {
			log.Println(rec)
			fi.Error = rec.(error).Error()
		}
	}()
	lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1}
	context := appengine.NewContext(r)
	w, err := blobstore.Create(context, fi.Type)
	defer func() {
		w.Close()
		fi.Size = MAX_FILE_SIZE + 1 - lr.N
		fi.Key, err = w.Key()
		check(err)
		if !fi.ValidateSize() {
			err := blobstore.Delete(context, fi.Key)
			check(err)
			return
		}
		delayedDelete(context, fi)
		fi.CreateUrls(r, context)
	}()
	check(err)
	_, err = io.Copy(w, lr)
	return
}

func getFormValue(p *multipart.Part) string {
	var b bytes.Buffer
	io.CopyN(&b, p, int64(1<<20)) // Copy max: 1 MiB
	return b.String()
}

func handleUploads(r *http.Request) (fileInfos []*FileInfo) {
	fileInfos = make([]*FileInfo, 0)
	mr, err := r.MultipartReader()
	check(err)
	r.Form, err = url.ParseQuery(r.URL.RawQuery)
	check(err)
	part, err := mr.NextPart()
	for err == nil {
		if name := part.FormName(); name != "" {
			if part.FileName() != "" {
				fileInfos = append(fileInfos, handleUpload(r, part))
			} else {
				r.Form[name] = append(r.Form[name], getFormValue(part))
			}
		}
		part, err = mr.NextPart()
	}
	return
}

func get(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.Redirect(w, r, WEBSITE, http.StatusFound)
		return
	}
	parts := strings.Split(r.URL.Path, "/")
	if len(parts) == 3 {
		if key := parts[1]; key != "" {
			blobKey := appengine.BlobKey(key)
			bi, err := blobstore.Stat(appengine.NewContext(r), blobKey)
			if err == nil {
				w.Header().Add(
					"Cache-Control",
					fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME),
				)
				if imageTypes.MatchString(bi.ContentType) {
					w.Header().Add("X-Content-Type-Options", "nosniff")
				} else {
					w.Header().Add("Content-Type", "application/octet-stream")
					w.Header().Add(
						"Content-Disposition:",
						fmt.Sprintf("attachment; filename=%s;", parts[2]),
					)
				}
				blobstore.Send(w, blobKey)
				return
			}
		}
	}
	http.Error(w, "404 Not Found", http.StatusNotFound)
}

func post(w http.ResponseWriter, r *http.Request) {
	b, err := json.Marshal(handleUploads(r))
	check(err)
	if redirect := r.FormValue("redirect"); redirect != "" {
	    if strings.Contains(redirect, "%s") {
	        redirect = fmt.Sprintf(
    			redirect,
    			escape(string(b)),
    		)
	    }
		http.Redirect(w, r, redirect, http.StatusFound)
		return
	}
	w.Header().Set("Cache-Control", "no-cache")
	jsonType := "application/json"
	if strings.Index(r.Header.Get("Accept"), jsonType) != -1 {
		w.Header().Set("Content-Type", jsonType)
	}
	fmt.Fprintln(w, string(b))
}

func delete(w http.ResponseWriter, r *http.Request) {
	parts := strings.Split(r.URL.Path, "/")
	if len(parts) != 3 {
		return
	}
	if key := parts[1]; key != "" {
		c := appengine.NewContext(r)
		blobKey := appengine.BlobKey(key)
		err := blobstore.Delete(c, blobKey)
		check(err)
		err = image.DeleteServingURL(c, blobKey)
		check(err)
	}
}

func handle(w http.ResponseWriter, r *http.Request) {
	params, err := url.ParseQuery(r.URL.RawQuery)
	check(err)
	w.Header().Add("Access-Control-Allow-Origin", "*")
	w.Header().Add(
		"Access-Control-Allow-Methods",
		"OPTIONS, HEAD, GET, POST, PUT, DELETE",
	)
	switch r.Method {
	case "OPTIONS":
	case "HEAD":
	case "GET":
		get(w, r)
	case "POST":
		if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" {
			delete(w, r)
		} else {
			post(w, r)
		}
	case "DELETE":
		delete(w, r)
	default:
		http.Error(w, "501 Not Implemented", http.StatusNotImplemented)
	}
}

func init() {
	http.HandleFunc("/", handle)
}
<|endoftext|>


<commit_before>package handler

import (
	"fmt"
	"net"
	"strings"
)

func HandleKill(conn net.Conn) {
	conn.Close()
}

func HandleHelo(message string, conn net.Conn) {
	// conn.LocalAddr() returns "10.62.0.117:8000" for example
	// serverInfo[0] = 10.62.0.117
	// serverInfo[1] = 8000
	serverInfo := strings.Split(conn.LocalAddr().String(), ":")
	conn.Write([]byte(fmt.Sprintf("%sIP:%s\nPort:%s\nStudentID:%s\n", message, serverInfo[0], serverInfo[1], "13321218")))
}

func HandleOther(conn net.Conn) {
	// stub methond
	fmt.Println(conn)
}
<commit_msg>fixed close bug<commit_after>package handler

import (
	"fmt"
	"net"
	"strings"
	"os"
)

func HandleKill(conn net.Conn) {
	conn.Close()
	os.Exit(1)
}

func HandleHelo(message string, conn net.Conn) {
	// conn.LocalAddr() returns "10.62.0.117:8000" for example
	// serverInfo[0] = 10.62.0.117
	// serverInfo[1] = 8000
	serverInfo := strings.Split(conn.LocalAddr().String(), ":")
	conn.Write([]byte(fmt.Sprintf("%sIP:%s\nPort:%s\nStudentID:%s\n", message, serverInfo[0], serverInfo[1], "13321218")))
}

func HandleOther(conn net.Conn) {
	// stub methond
	fmt.Println(conn)
}
<|endoftext|>


<commit_before>// Useful functions for building your own memcached server.
package memcached

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"io"

	"github.com/dustin/go-humanize"
	"github.com/dustin/gomemcached"
)

// The maximum reasonable body length to expect.
// Anything larger than this will result in an error.
var MaxBodyLen = uint32(1 * 1e6)

// Error returned when a packet doesn't start with proper magic.
type BadMagic struct {
	was uint8
}

func (b BadMagic) Error() string {
	return fmt.Sprintf("Bad magic:  0x%02x", b.was)
}

func HandleIO(s io.ReadWriteCloser, reqChannel chan gomemcached.MCRequest) {
	defer s.Close()
	for handleMessage(s, s, reqChannel) {
	}
}

func handleMessage(r io.Reader, w io.Writer, reqChannel chan gomemcached.MCRequest) (ret bool) {
	req, err := ReadPacket(r)
	if err != nil {
		return
	}

	req.ResponseChannel = make(chan gomemcached.MCResponse)
	reqChannel <- req
	res := <-req.ResponseChannel
	ret = !res.Fatal
	if ret {
		transmitResponse(w, req, res)
	}

	return
}

func ReadPacket(r io.Reader) (rv gomemcached.MCRequest, err error) {
	hdrBytes := make([]byte, gomemcached.HDR_LEN)
	bytesRead, err := io.ReadFull(r, hdrBytes)
	if err != nil {
		return
	}
	if bytesRead != gomemcached.HDR_LEN {
		panic("Expected to read full and didn't")
	}

	rv, err = grokHeader(hdrBytes)
	if err != nil {
		return
	}

	err = readContents(r, &rv)
	return
}

func readContents(s io.Reader, req *gomemcached.MCRequest) (err error) {
	err = readOb(s, req.Extras)
	if err != nil {
		return err
	}
	err = readOb(s, req.Key)
	if err != nil {
		return err
	}
	return readOb(s, req.Body)
}

func transmitResponse(s io.Writer, req gomemcached.MCRequest, res gomemcached.MCResponse) {
	o := bufio.NewWriter(s)
	writeByte(o, gomemcached.RES_MAGIC)
	writeByte(o, byte(req.Opcode))
	writeUint16(o, uint16(len(res.Key)))
	writeByte(o, uint8(len(res.Extras)))
	writeByte(o, 0)
	writeUint16(o, res.Status)
	writeUint32(o, uint32(len(res.Body))+
		uint32(len(res.Key))+
		uint32(len(res.Extras)))
	writeUint32(o, req.Opaque)
	writeUint64(o, res.Cas)
	writeBytes(o, res.Extras)
	writeBytes(o, res.Key)
	writeBytes(o, res.Body)
	o.Flush()
	return
}

func writeBytes(s *bufio.Writer, data []byte) error {
	if len(data) > 0 {
		written, err := s.Write(data)
		if err != nil {
			return err
		}
		if written != len(data) {
			panic("Expected a full write, but didn't get one")
		}
	}
	return nil
}

func writeByte(s *bufio.Writer, b byte) {
	data := make([]byte, 1)
	data[0] = b
	writeBytes(s, data)
}

func writeUint16(s *bufio.Writer, n uint16) {
	data := []byte{0, 0}
	binary.BigEndian.PutUint16(data, n)
	writeBytes(s, data)
}

func writeUint32(s *bufio.Writer, n uint32) {
	data := []byte{0, 0, 0, 0}
	binary.BigEndian.PutUint32(data, n)
	writeBytes(s, data)
}

func writeUint64(s *bufio.Writer, n uint64) {
	data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
	binary.BigEndian.PutUint64(data, n)
	writeBytes(s, data)
}

func readOb(s io.Reader, buf []byte) error {
	x, err := io.ReadFull(s, buf)
	if err == nil && x != len(buf) {
		panic("Read full didn't")
	}
	return err
}

func grokHeader(hdrBytes []byte) (rv gomemcached.MCRequest, err error) {
	if hdrBytes[0] != gomemcached.REQ_MAGIC {
		return rv, &BadMagic{was: hdrBytes[0]}
	}
	rv.Opcode = gomemcached.CommandCode(hdrBytes[1])
	rv.Key = make([]byte, binary.BigEndian.Uint16(hdrBytes[2:]))
	rv.Extras = make([]byte, hdrBytes[4])
	// Vbucket at 6:7
	rv.VBucket = binary.BigEndian.Uint16(hdrBytes[6:])
	bodyLen := binary.BigEndian.Uint32(hdrBytes[8:]) - uint32(len(rv.Key)) - uint32(len(rv.Extras))
	if bodyLen > MaxBodyLen {
		return rv, errors.New(fmt.Sprintf("%d is too big (max %s)",
			bodyLen, humanize.Bytes(uint64(MaxBodyLen))))
	}
	rv.Body = make([]byte, bodyLen)
	rv.Opaque = binary.BigEndian.Uint32(hdrBytes[12:])
	rv.Cas = binary.BigEndian.Uint64(hdrBytes[16:])
	return rv, nil
}
<commit_msg>Use res.Bytes() to encode the response.<commit_after>// Useful functions for building your own memcached server.
package memcached

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"

	"github.com/dustin/go-humanize"
	"github.com/dustin/gomemcached"
)

// The maximum reasonable body length to expect.
// Anything larger than this will result in an error.
var MaxBodyLen = uint32(1 * 1e6)

// Error returned when a packet doesn't start with proper magic.
type BadMagic struct {
	was uint8
}

func (b BadMagic) Error() string {
	return fmt.Sprintf("Bad magic:  0x%02x", b.was)
}

func HandleIO(s io.ReadWriteCloser, reqChannel chan gomemcached.MCRequest) {
	defer s.Close()
	for handleMessage(s, s, reqChannel) {
	}
}

func handleMessage(r io.Reader, w io.Writer, reqChannel chan gomemcached.MCRequest) (ret bool) {
	req, err := ReadPacket(r)
	if err != nil {
		return
	}

	req.ResponseChannel = make(chan gomemcached.MCResponse)
	reqChannel <- req
	res := <-req.ResponseChannel
	ret = !res.Fatal
	if ret {
		res.Opcode = req.Opcode
		res.Opaque = req.Opaque
		transmitResponse(w, res)
	}

	return
}

func ReadPacket(r io.Reader) (rv gomemcached.MCRequest, err error) {
	hdrBytes := make([]byte, gomemcached.HDR_LEN)
	bytesRead, err := io.ReadFull(r, hdrBytes)
	if err != nil {
		return
	}
	if bytesRead != gomemcached.HDR_LEN {
		panic("Expected to read full and didn't")
	}

	rv, err = grokHeader(hdrBytes)
	if err != nil {
		return
	}

	err = readContents(r, &rv)
	return
}

func readContents(s io.Reader, req *gomemcached.MCRequest) (err error) {
	err = readOb(s, req.Extras)
	if err != nil {
		return err
	}
	err = readOb(s, req.Key)
	if err != nil {
		return err
	}
	return readOb(s, req.Body)
}

func transmitResponse(s io.Writer, res gomemcached.MCResponse) error {
	_, err := s.Write(res.Bytes())
	return err
}

func readOb(s io.Reader, buf []byte) error {
	x, err := io.ReadFull(s, buf)
	if err == nil && x != len(buf) {
		panic("Read full didn't")
	}
	return err
}

func grokHeader(hdrBytes []byte) (rv gomemcached.MCRequest, err error) {
	if hdrBytes[0] != gomemcached.REQ_MAGIC {
		return rv, &BadMagic{was: hdrBytes[0]}
	}
	rv.Opcode = gomemcached.CommandCode(hdrBytes[1])
	rv.Key = make([]byte, binary.BigEndian.Uint16(hdrBytes[2:]))
	rv.Extras = make([]byte, hdrBytes[4])
	// Vbucket at 6:7
	rv.VBucket = binary.BigEndian.Uint16(hdrBytes[6:])
	bodyLen := binary.BigEndian.Uint32(hdrBytes[8:]) - uint32(len(rv.Key)) - uint32(len(rv.Extras))
	if bodyLen > MaxBodyLen {
		return rv, errors.New(fmt.Sprintf("%d is too big (max %s)",
			bodyLen, humanize.Bytes(uint64(MaxBodyLen))))
	}
	rv.Body = make([]byte, bodyLen)
	rv.Opaque = binary.BigEndian.Uint32(hdrBytes[12:])
	rv.Cas = binary.BigEndian.Uint64(hdrBytes[16:])
	return rv, nil
}
<|endoftext|>


<commit_before>package server

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

	"github.com/albertyw/reaction-pics/tumblr"
)

func TestReadFile(t *testing.T) {
	request, err := http.NewRequest("GET", "/app.js", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	indexHandler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	cacheString := appCacheString()
	if !strings.Contains(response.Body.String(), cacheString) {
		t.Fail()
	}
}

func TestIndexFile(t *testing.T) {
	handler := rewriteFS(http.FileServer(http.Dir(staticPath)).ServeHTTP)
	request, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	handler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	if len(response.Body.String()) < 100 {
		t.Fail()
	}
}

func TestExactURL(t *testing.T) {
	handler := rewriteFS(http.FileServer(http.Dir(staticPath)).ServeHTTP)
	request, err := http.NewRequest("GET", "/asdf", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	handler(response, request)
	if response.Code != 404 {
		t.Fail()
	}
}

func TestNoExactURL(t *testing.T) {
	handler := rewriteFS(http.FileServer(http.Dir(staticPath)).ServeHTTP)
	request, err := http.NewRequest("GET", "/asdf", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	handler(response, request)
	if response.Code != 404 {
		t.Fail()
	}
}
func TestSearchHandler(t *testing.T) {
	request, err := http.NewRequest("GET", "/search", nil)
	if err != nil {
		t.Fail()
	}
	q := request.URL.Query()
	q.Add("query", "searchTerm")
	response := httptest.NewRecorder()
	searchHandler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	if response.Body.String() != "{\"data\":[],\"offset\":0,\"totalResults\":0}" {
		t.Fail()
	}
}

func TestSearchHandlerOffset(t *testing.T) {
	request, err := http.NewRequest("GET", "/search?offset=1", nil)
	if err != nil {
		t.Fail()
	}
	q := request.URL.Query()
	q.Add("query", "searchTerm")
	response := httptest.NewRecorder()
	searchHandler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	if response.Body.String() != "{\"data\":[],\"offset\":1,\"totalResults\":0}" {
		t.Fail()
	}
}

func TestSearchHandlerMalformedOffset(t *testing.T) {
	request, err := http.NewRequest("GET", "/search?offset=asdf", nil)
	if err != nil {
		t.Fail()
	}
	q := request.URL.Query()
	q.Add("query", "searchTerm")
	response := httptest.NewRecorder()
	searchHandler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	if response.Body.String() != "{\"data\":[],\"offset\":0,\"totalResults\":0}" {
		t.Fail()
	}
}

func TestPostHandlerMalformed(t *testing.T) {
	request, err := http.NewRequest("GET", "/post/asdf", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	postHandler(response, request)
	if response.Code != 404 {
		t.Fail()
	}
}

func TestPostHandlerNotFound(t *testing.T) {
	request, err := http.NewRequest("GET", "/post/1234", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	postHandler(response, request)
	if response.Code != 404 {
		t.Fail()
	}
}

func TestPostHandler(t *testing.T) {
	post := tumblr.Post{ID: 1234}
	board.AddPost(post)
	defer func() { board.Reset() }()
	request, err := http.NewRequest("GET", "/post/1234", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	postHandler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	if len(response.Body.String()) == 0 {
		t.Fail()
	}
}

func TestPostDataHandler(t *testing.T) {
	post := tumblr.Post{ID: 1234}
	board.AddPost(post)
	defer func() { board.Reset() }()
	request, err := http.NewRequest("GET", "/postdata/1234", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	postDataHandler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	if len(response.Body.String()) == 0 {
		t.Fail()
	}
}

func TestPostDataHandlerMalformed(t *testing.T) {
	request, err := http.NewRequest("GET", "/postdata/asdf", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	postDataHandler(response, request)
	if response.Code != 404 {
		t.Fail()
	}
}

func TestPostDataHandlerUnknown(t *testing.T) {
	request, err := http.NewRequest("GET", "/postdata/1234", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	postDataHandler(response, request)
	if response.Code != 404 {
		t.Fail()
	}
}

func TestStatsHandler(t *testing.T) {
	request, err := http.NewRequest("GET", "/stats.json", nil)
	if err != nil {
		t.Fail()
	}
	response := httptest.NewRecorder()
	statsHandler(response, request)
	if response.Code != 200 {
		t.Fail()
	}
	if response.Body.String() != "{\"keywords\":[],\"postCount\":\"0\"}" {
		t.Fail()
	}
}

func TestAddPost(t *testing.T) {
	oldLength := len(board.Posts)
	post1 := tumblr.Post{ID: 1, Title: "1"}
	post2 := tumblr.Post{ID: 2, Title: "2"}
	post3 := tumblr.Post{ID: 3, Title: "3"}
	postChan := make(chan tumblr.Post, 1)
	defer func() { close(postChan) }()
	go loadPosts(postChan)
	postChan <- post1
	postChan <- post2
	postChan <- post3
	if len(board.Posts) == oldLength {
		t.Fail()
	}
	if board.Posts[0].ID > board.Posts[1].ID {
		t.Fail()
	}
}

func TestCacheString(t *testing.T) {
	tempStaticPath := staticPath
	defer func() { staticPath = tempStaticPath }()
	cacheString := appCacheString()
	if cacheString == "" {
		t.Fail()
	}
	staticPath = ""
	cacheString = appCacheString()
	if cacheString != "" {
		t.Fail()
	}
}
<commit_msg>Switch server main_test go testify<commit_after>package server

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

	"github.com/stretchr/testify/assert"

	"github.com/albertyw/reaction-pics/tumblr"
)

func TestReadFile(t *testing.T) {
	request, err := http.NewRequest("GET", "/app.js", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	indexHandler(response, request)
	assert.Equal(t, response.Code, 200)

	cacheString := appCacheString()
	assert.Contains(t, response.Body.String(), cacheString)
}

func TestIndexFile(t *testing.T) {
	handler := rewriteFS(http.FileServer(http.Dir(staticPath)).ServeHTTP)
	request, err := http.NewRequest("GET", "/", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	handler(response, request)
	assert.Equal(t, response.Code, 200)
	assert.True(t, len(response.Body.String()) > 100)
}

func TestExactURL(t *testing.T) {
	handler := rewriteFS(http.FileServer(http.Dir(staticPath)).ServeHTTP)
	request, err := http.NewRequest("GET", "/asdf", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	handler(response, request)
	assert.Equal(t, response.Code, 404)
}

func TestNoExactURL(t *testing.T) {
	handler := rewriteFS(http.FileServer(http.Dir(staticPath)).ServeHTTP)
	request, err := http.NewRequest("GET", "/asdf", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	handler(response, request)
	assert.Equal(t, response.Code, 404)
}
func TestSearchHandler(t *testing.T) {
	request, err := http.NewRequest("GET", "/search", nil)
	assert.NoError(t, err)

	q := request.URL.Query()
	q.Add("query", "searchTerm")
	response := httptest.NewRecorder()
	searchHandler(response, request)
	assert.Equal(t, response.Code, 200)
	assert.Equal(t, response.Body.String(), "{\"data\":[],\"offset\":0,\"totalResults\":0}")
}

func TestSearchHandlerOffset(t *testing.T) {
	request, err := http.NewRequest("GET", "/search?offset=1", nil)
	assert.NoError(t, err)

	q := request.URL.Query()
	q.Add("query", "searchTerm")
	response := httptest.NewRecorder()
	searchHandler(response, request)
	assert.Equal(t, response.Code, 200)
	assert.Equal(t, response.Body.String(), "{\"data\":[],\"offset\":1,\"totalResults\":0}")
}

func TestSearchHandlerMalformedOffset(t *testing.T) {
	request, err := http.NewRequest("GET", "/search?offset=asdf", nil)
	assert.NoError(t, err)

	q := request.URL.Query()
	q.Add("query", "searchTerm")
	response := httptest.NewRecorder()
	searchHandler(response, request)
	assert.Equal(t, response.Code, 200)
	assert.Equal(t, response.Body.String(), "{\"data\":[],\"offset\":0,\"totalResults\":0}")
}

func TestPostHandlerMalformed(t *testing.T) {
	request, err := http.NewRequest("GET", "/post/asdf", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	postHandler(response, request)
	assert.Equal(t, response.Code, 404)
}

func TestPostHandlerNotFound(t *testing.T) {
	request, err := http.NewRequest("GET", "/post/1234", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	postHandler(response, request)
	assert.Equal(t, response.Code, 404)
}

func TestPostHandler(t *testing.T) {
	post := tumblr.Post{ID: 1234}
	board.AddPost(post)
	defer func() { board.Reset() }()
	request, err := http.NewRequest("GET", "/post/1234", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	postHandler(response, request)
	assert.Equal(t, response.Code, 200)
	assert.NotEqual(t, len(response.Body.String()), 0)
}

func TestPostDataHandler(t *testing.T) {
	post := tumblr.Post{ID: 1234}
	board.AddPost(post)
	defer func() { board.Reset() }()
	request, err := http.NewRequest("GET", "/postdata/1234", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	postDataHandler(response, request)
	assert.Equal(t, response.Code, 200)
	assert.NotEqual(t, len(response.Body.String()), 0)
}

func TestPostDataHandlerMalformed(t *testing.T) {
	request, err := http.NewRequest("GET", "/postdata/asdf", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	postDataHandler(response, request)
	assert.Equal(t, response.Code, 404)
}

func TestPostDataHandlerUnknown(t *testing.T) {
	request, err := http.NewRequest("GET", "/postdata/1234", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	postDataHandler(response, request)
	assert.Equal(t, response.Code, 404)
}

func TestStatsHandler(t *testing.T) {
	request, err := http.NewRequest("GET", "/stats.json", nil)
	assert.NoError(t, err)

	response := httptest.NewRecorder()
	statsHandler(response, request)
	assert.Equal(t, response.Code, 200)
	assert.Equal(t, response.Body.String(), "{\"keywords\":[],\"postCount\":\"0\"}")
}

func TestAddPost(t *testing.T) {
	oldLength := len(board.Posts)
	post1 := tumblr.Post{ID: 1, Title: "1"}
	post2 := tumblr.Post{ID: 2, Title: "2"}
	post3 := tumblr.Post{ID: 3, Title: "3"}
	postChan := make(chan tumblr.Post, 1)
	defer func() { close(postChan) }()
	go loadPosts(postChan)
	postChan <- post1
	postChan <- post2
	postChan <- post3
	assert.NotEqual(t, len(board.Posts), oldLength)
	assert.True(t, board.Posts[0].ID < board.Posts[1].ID)
}

func TestCacheString(t *testing.T) {
	tempStaticPath := staticPath
	defer func() { staticPath = tempStaticPath }()
	cacheString := appCacheString()
	assert.NotEqual(t, cacheString, "")

	staticPath = ""
	cacheString = appCacheString()
	assert.Equal(t, cacheString, "")
}
<|endoftext|>


<commit_before>package video

type PictureData struct {
	slices []*Slice
}

func (self *VideoSequence) picture_data() (err error) {

	pd := PictureData{}

	for {
		s, err := self.slice()
		if err != nil {
			return err
		}

		pd.slices = append(pd.slices, s)

		nextbits, err := self.Peek32(32)
		if err != nil {
			return err
		}
		if is_slice_start_code(StartCode(nextbits)) {
			break
		}
	}

	self.PictureData = &pd

	return self.next_start_code()
}
<commit_msg>break if its *not* a slice<commit_after>package video

type PictureData struct {
	slices []*Slice
}

func (self *VideoSequence) picture_data() (err error) {

	pd := PictureData{}

	for {
		s, err := self.slice()
		if err != nil {
			return err
		}

		pd.slices = append(pd.slices, s)

		nextbits, err := self.Peek32(32)
		if err != nil {
			return err
		}

		if !is_slice_start_code(StartCode(nextbits)) {
			break
		}
	}

	self.PictureData = &pd

	return self.next_start_code()
}
<|endoftext|>