<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	_ "net/http/pprof"
	"os"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/net/trace"

	"github.com/bmatsuo/lmdb-go/lmdb"
	"github.com/dgraph-io/badger"
	"github.com/dgraph-io/badger-bench/store"
	"github.com/dgraph-io/badger/y"
	"github.com/paulbellamy/ratecounter"
	"github.com/pkg/profile"
)

const mil float64 = 1000000

var (
	which     = flag.String("kv", "badger", "Which KV store to use. Options: badger, rocksdb, lmdb")
	numKeys   = flag.Float64("keys_mil", 10.0, "How many million keys to write.")
	valueSize = flag.Int("valsz", 128, "Value size in bytes.")
	dir       = flag.String("dir", "", "Base dir for writes.")
	mode      = flag.String("profile.mode", "", "enable profiling mode, one of [cpu, mem, mutex, block]")
)

func fillEntry(e *badger.Entry) {
	k := rand.Int() % int(*numKeys*mil)
	key := fmt.Sprintf("vsz=%05d-k=%010d", *valueSize, k) // 22 bytes.
	if cap(e.Key) < len(key) {
		e.Key = make([]byte, 2*len(key))
	}
	e.Key = e.Key[:len(key)]
	copy(e.Key, key)

	rand.Read(e.Value)
	e.Meta = 0
}

var bdb *badger.KV
var rdb *store.Store
var lmdbEnv *lmdb.Env
var lmdbDBI lmdb.DBI

func writeBatch(entries []*badger.Entry) int {
	for _, e := range entries {
		fillEntry(e)
	}

	if bdb != nil {
		bdb.BatchSet(entries)
		for _, e := range entries {
			y.Check(e.Error)
		}
	}

	if rdb != nil {
		rb := rdb.NewWriteBatch()
		defer rb.Destroy()

		for _, e := range entries {
			rb.Put(e.Key, e.Value)
		}
		y.Check(rdb.WriteBatch(rb))
	}

	if lmdbEnv != nil {
		err := lmdbEnv.Update(func(txn *lmdb.Txn) error {
			for _, e := range entries {
				err := txn.Put(lmdbDBI, e.Key, e.Value, 0)
				if err != nil {
					return err
				}
			}
			return nil
		})
		y.Check(err)

	}

	return len(entries)
}

func humanize(n int64) string {
	if n >= 1000000 {
		return fmt.Sprintf("%6.2fM", float64(n)/1000000.0)
	}
	if n >= 1000 {
		return fmt.Sprintf("%6.2fK", float64(n)/1000.0)
	}
	return fmt.Sprintf("%5.2f", float64(n))
}

func main() {
	flag.Parse()
	switch *mode {
	case "cpu":
		defer profile.Start(profile.CPUProfile).Stop()
	case "mem":
		defer profile.Start(profile.MemProfile).Stop()
	case "mutex":
		defer profile.Start(profile.MutexProfile).Stop()
	case "block":
		defer profile.Start(profile.BlockProfile).Stop()
	default:
		// do nothing
	}

	trace.AuthRequest = func(req *http.Request) (any, sensitive bool) {
		return true, true
	}

	nw := *numKeys * mil
	fmt.Printf("TOTAL KEYS TO WRITE: %s\n", humanize(int64(nw)))
	opt := badger.DefaultOptions
	// opt.MapTablesTo = table.Nothing
	opt.ValueGCRunInterval = 10 * time.Hour
	opt.Dir = *dir + "/badger"
	opt.ValueDir = opt.Dir
	opt.SyncWrites = false

	var err error

	var init bool

	if *which == "badger" {
		init = true
		fmt.Println("Init Badger")
		y.Check(os.RemoveAll(*dir + "/badger"))
		os.MkdirAll(*dir+"/badger", 0777)
		bdb, err = badger.NewKV(&opt)
		if err != nil {
			log.Fatalf("while opening badger: %v", err)
		}
	} else if *which == "rocksdb" {
		init = true
		fmt.Println("Init Rocks")
		os.RemoveAll(*dir + "/rocks")
		os.MkdirAll(*dir+"/rocks", 0777)
		rdb, err = store.NewStore(*dir + "/rocks")
		y.Check(err)
	} else if *which == "lmdb" {
		init = true
		fmt.Println("Init lmdb")
		os.RemoveAll(*dir + "/lmdb")
		os.MkdirAll(*dir+"/lmdb", 0777)

		lmdbEnv, err = lmdb.NewEnv()
		y.Check(err)
		err = lmdbEnv.SetMaxDBs(1)
		y.Check(err)
		err = lmdbEnv.SetMapSize(1 << 38) // ~273Gb
		y.Check(err)

		err = lmdbEnv.Open(*dir+"/lmdb", 0, 0777)
		y.Check(err)

		// Acquire handle
		err := lmdbEnv.Update(func(txn *lmdb.Txn) error {
			var err error
			lmdbDBI, err = txn.CreateDBI("bench")
			return err
		})
		y.Check(err)
	} else {
		log.Fatalf("Invalid value for option kv: '%s'", *which)
	}

	if !init {
		log.Fatalf("Invalid arguments. Unable to init any store.")
	}

	rc := ratecounter.NewRateCounter(time.Minute)
	var counter int64
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		var count int64
		t := time.NewTicker(time.Second)
		for {
			select {
			case <-t.C:
				fmt.Printf("[%04d] Write key rate per minute: %s. Total: %s\n",
					count,
					humanize(rc.Rate()),
					humanize(atomic.LoadInt64(&counter)))
				count++
			case <-ctx.Done():
				return
			}
		}
	}()
	go func() {
		if err := http.ListenAndServe("0.0.0.0:8081", nil); err != nil {
			log.Fatalf("While opening http. Error: %v", err)
		}
	}()

	N := 12
	var wg sync.WaitGroup
	for i := 0; i < N; i++ {
		wg.Add(1)
		go func(proc int) {
			entries := make([]*badger.Entry, 1000)
			for i := 0; i < len(entries); i++ {
				e := new(badger.Entry)
				e.Key = make([]byte, 22)
				e.Value = make([]byte, *valueSize)
				entries[i] = e
			}

			var written float64
			for written < nw/float64(N) {
				wrote := float64(writeBatch(entries))

				wi := int64(wrote)
				atomic.AddInt64(&counter, wi)
				rc.Incr(wi)

				written += wrote
			}
			wg.Done()
		}(i)
	}
	// 	wg.Add(1) // Block
	wg.Wait()
	cancel()

	if bdb != nil {
		fmt.Println("closing badger")
		bdb.Close()
	}

	if rdb != nil {
		fmt.Println("closing rocks")
		rdb.Close()
	}

	if lmdbEnv != nil {

		fmt.Println("closing lmdb")
		lmdbEnv.CloseDBI(lmdbDBI)
		lmdbEnv.Close()
	}

	fmt.Printf("\nWROTE %d KEYS\n", atomic.LoadInt64(&counter))
}
<commit_msg>set opt.MapTablesTo to table.MemoryMap<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	_ "net/http/pprof"
	"os"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/net/trace"

	"github.com/bmatsuo/lmdb-go/lmdb"
	"github.com/dgraph-io/badger"
	"github.com/dgraph-io/badger-bench/store"
	"github.com/dgraph-io/badger/table"
	"github.com/dgraph-io/badger/y"
	"github.com/paulbellamy/ratecounter"
	"github.com/pkg/profile"
)

const mil float64 = 1000000

var (
	which     = flag.String("kv", "badger", "Which KV store to use. Options: badger, rocksdb, lmdb")
	numKeys   = flag.Float64("keys_mil", 10.0, "How many million keys to write.")
	valueSize = flag.Int("valsz", 128, "Value size in bytes.")
	dir       = flag.String("dir", "", "Base dir for writes.")
	mode      = flag.String("profile.mode", "", "enable profiling mode, one of [cpu, mem, mutex, block]")
)

func fillEntry(e *badger.Entry) {
	k := rand.Int() % int(*numKeys*mil)
	key := fmt.Sprintf("vsz=%05d-k=%010d", *valueSize, k) // 22 bytes.
	if cap(e.Key) < len(key) {
		e.Key = make([]byte, 2*len(key))
	}
	e.Key = e.Key[:len(key)]
	copy(e.Key, key)

	rand.Read(e.Value)
	e.Meta = 0
}

var bdb *badger.KV
var rdb *store.Store
var lmdbEnv *lmdb.Env
var lmdbDBI lmdb.DBI

func writeBatch(entries []*badger.Entry) int {
	for _, e := range entries {
		fillEntry(e)
	}

	if bdb != nil {
		bdb.BatchSet(entries)
		for _, e := range entries {
			y.Check(e.Error)
		}
	}

	if rdb != nil {
		rb := rdb.NewWriteBatch()
		defer rb.Destroy()

		for _, e := range entries {
			rb.Put(e.Key, e.Value)
		}
		y.Check(rdb.WriteBatch(rb))
	}

	if lmdbEnv != nil {
		err := lmdbEnv.Update(func(txn *lmdb.Txn) error {
			for _, e := range entries {
				err := txn.Put(lmdbDBI, e.Key, e.Value, 0)
				if err != nil {
					return err
				}
			}
			return nil
		})
		y.Check(err)

	}

	return len(entries)
}

func humanize(n int64) string {
	if n >= 1000000 {
		return fmt.Sprintf("%6.2fM", float64(n)/1000000.0)
	}
	if n >= 1000 {
		return fmt.Sprintf("%6.2fK", float64(n)/1000.0)
	}
	return fmt.Sprintf("%5.2f", float64(n))
}

func main() {
	flag.Parse()
	switch *mode {
	case "cpu":
		defer profile.Start(profile.CPUProfile).Stop()
	case "mem":
		defer profile.Start(profile.MemProfile).Stop()
	case "mutex":
		defer profile.Start(profile.MutexProfile).Stop()
	case "block":
		defer profile.Start(profile.BlockProfile).Stop()
	default:
		// do nothing
	}

	trace.AuthRequest = func(req *http.Request) (any, sensitive bool) {
		return true, true
	}

	nw := *numKeys * mil
	fmt.Printf("TOTAL KEYS TO WRITE: %s\n", humanize(int64(nw)))
	opt := badger.DefaultOptions
	opt.MapTablesTo = table.MemoryMap
	opt.ValueGCRunInterval = 10 * time.Hour
	opt.Dir = *dir + "/badger"
	opt.ValueDir = opt.Dir
	opt.SyncWrites = false

	var err error

	var init bool

	if *which == "badger" {
		init = true
		fmt.Println("Init Badger")
		y.Check(os.RemoveAll(*dir + "/badger"))
		os.MkdirAll(*dir+"/badger", 0777)
		bdb, err = badger.NewKV(&opt)
		if err != nil {
			log.Fatalf("while opening badger: %v", err)
		}
	} else if *which == "rocksdb" {
		init = true
		fmt.Println("Init Rocks")
		os.RemoveAll(*dir + "/rocks")
		os.MkdirAll(*dir+"/rocks", 0777)
		rdb, err = store.NewStore(*dir + "/rocks")
		y.Check(err)
	} else if *which == "lmdb" {
		init = true
		fmt.Println("Init lmdb")
		os.RemoveAll(*dir + "/lmdb")
		os.MkdirAll(*dir+"/lmdb", 0777)

		lmdbEnv, err = lmdb.NewEnv()
		y.Check(err)
		err = lmdbEnv.SetMaxDBs(1)
		y.Check(err)
		err = lmdbEnv.SetMapSize(1 << 38) // ~273Gb
		y.Check(err)

		err = lmdbEnv.Open(*dir+"/lmdb", 0, 0777)
		y.Check(err)

		// Acquire handle
		err := lmdbEnv.Update(func(txn *lmdb.Txn) error {
			var err error
			lmdbDBI, err = txn.CreateDBI("bench")
			return err
		})
		y.Check(err)
	} else {
		log.Fatalf("Invalid value for option kv: '%s'", *which)
	}

	if !init {
		log.Fatalf("Invalid arguments. Unable to init any store.")
	}

	rc := ratecounter.NewRateCounter(time.Minute)
	var counter int64
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		var count int64
		t := time.NewTicker(time.Second)
		for {
			select {
			case <-t.C:
				fmt.Printf("[%04d] Write key rate per minute: %s. Total: %s\n",
					count,
					humanize(rc.Rate()),
					humanize(atomic.LoadInt64(&counter)))
				count++
			case <-ctx.Done():
				return
			}
		}
	}()
	go func() {
		if err := http.ListenAndServe("0.0.0.0:8081", nil); err != nil {
			log.Fatalf("While opening http. Error: %v", err)
		}
	}()

	N := 12
	var wg sync.WaitGroup
	for i := 0; i < N; i++ {
		wg.Add(1)
		go func(proc int) {
			entries := make([]*badger.Entry, 1000)
			for i := 0; i < len(entries); i++ {
				e := new(badger.Entry)
				e.Key = make([]byte, 22)
				e.Value = make([]byte, *valueSize)
				entries[i] = e
			}

			var written float64
			for written < nw/float64(N) {
				wrote := float64(writeBatch(entries))

				wi := int64(wrote)
				atomic.AddInt64(&counter, wi)
				rc.Incr(wi)

				written += wrote
			}
			wg.Done()
		}(i)
	}
	// 	wg.Add(1) // Block
	wg.Wait()
	cancel()

	if bdb != nil {
		fmt.Println("closing badger")
		bdb.Close()
	}

	if rdb != nil {
		fmt.Println("closing rocks")
		rdb.Close()
	}

	if lmdbEnv != nil {

		fmt.Println("closing lmdb")
		lmdbEnv.CloseDBI(lmdbDBI)
		lmdbEnv.Close()
	}

	fmt.Printf("\nWROTE %d KEYS\n", atomic.LoadInt64(&counter))
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	cmds "github.com/ipfs/go-ipfs/commands"
	files "github.com/ipfs/go-ipfs/commands/files"
	logging "gx/ipfs/QmNQynaz7qfriSUJkiEZUrm2Wen1u3Kj9goZzWtrPyu7XR/go-log"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
)

var log = logging.Logger("commands/cli")

// stdinSpecialName is a name applied to the 'stdin' file so we can differentiate
// it from potential 'real' files being passed in. The '*' character is invalid in
// path names and won't appear otherwise.
const stdinSpecialName = "*stdin*"

// Parse parses the input commandline string (cmd, flags, and args).
// returns the corresponding command Request object.
func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *cmds.Command, []string, error) {
	path, opts, stringVals, cmd, err := parseOpts(input, root)
	if err != nil {
		return nil, nil, path, err
	}

	optDefs, err := root.GetOptions(path)
	if err != nil {
		return nil, cmd, path, err
	}

	req, err := cmds.NewRequest(path, opts, nil, nil, cmd, optDefs)
	if err != nil {
		return nil, cmd, path, err
	}

	// if -r is provided, and it is associated with the package builtin
	// recursive path option, allow recursive file paths
	recursiveOpt := req.Option(cmds.RecShort)
	recursive := false
	if recursiveOpt != nil && recursiveOpt.Definition() == cmds.OptionRecursivePath {
		recursive, _, err = recursiveOpt.Bool()
		if err != nil {
			return req, nil, nil, u.ErrCast()
		}
	}

	// if '--hidden' is provided, enumerate hidden paths
	hiddenOpt := req.Option("hidden")
	hidden := false
	if hiddenOpt != nil {
		hidden, _, err = hiddenOpt.Bool()
		if err != nil {
			return req, nil, nil, u.ErrCast()
		}
	}

	// This is an ugly hack to maintain our current CLI interface while fixing
	// other stdin usage bugs. Let this serve as a warning, be careful about the
	// choices you make, they will haunt you forever.
	if len(path) == 2 && path[0] == "bootstrap" {
		if (path[1] == "add" && opts["default"] == true) ||
			(path[1] == "rm" && opts["all"] == true) {
			stdin = nil
		}
	}

	stringArgs, fileArgs, err := parseArgs(stringVals, stdin, cmd.Arguments, recursive, hidden, root)
	if err != nil {
		return req, cmd, path, err
	}
	req.SetArguments(stringArgs)

	if len(fileArgs) > 0 {
		file := files.NewSliceFile("", "", fileArgs)
		req.SetFiles(file)
	}

	err = cmd.CheckArguments(req)
	if err != nil {
		return req, cmd, path, err
	}

	return req, cmd, path, nil
}

// Parse a command line made up of sub-commands, short arguments, long arguments and positional arguments
func parseOpts(args []string, root *cmds.Command) (
	path []string,
	opts map[string]interface{},
	stringVals []string,
	cmd *cmds.Command,
	err error,
) {
	path = make([]string, 0, len(args))
	stringVals = make([]string, 0, len(args))
	optDefs := map[string]cmds.Option{}
	opts = map[string]interface{}{}
	cmd = root

	// parseFlag checks that a flag is valid and saves it into opts
	// Returns true if the optional second argument is used
	parseFlag := func(name string, arg *string, mustUse bool) (bool, error) {
		if _, ok := opts[name]; ok {
			return false, fmt.Errorf("Duplicate values for option '%s'", name)
		}

		optDef, found := optDefs[name]
		if !found {
			err = fmt.Errorf("Unrecognized option '%s'", name)
			return false, err
		}
		// mustUse implies that you must use the argument given after the '='
		// eg. -r=true means you must take true into consideration
		//		mustUse == true in the above case
		// eg. ipfs -r <file> means disregard <file> since there is no '='
		//		mustUse == false in the above situation
		//arg == nil implies the flag was specified without an argument
		if optDef.Type() == cmds.Bool {
			if arg == nil || !mustUse {
				opts[name] = true
				return false, nil
			}
			argVal := strings.ToLower(*arg)
			switch argVal {
			case "true":
				opts[name] = true
				return true, nil
			case "false":
				opts[name] = false
				return true, nil
			default:
				return true, fmt.Errorf("Option '%s' takes true/false arguments, but was passed '%s'", name, argVal)
			}
		} else {
			if arg == nil {
				return true, fmt.Errorf("Missing argument for option '%s'", name)
			}
			opts[name] = *arg
			return true, nil
		}
	}

	optDefs, err = root.GetOptions(path)
	if err != nil {
		return
	}

	consumed := false
	for i, arg := range args {
		switch {
		case consumed:
			// arg was already consumed by the preceding flag
			consumed = false
			continue

		case arg == "--":
			// treat all remaining arguments as positional arguments
			stringVals = append(stringVals, args[i+1:]...)
			return

		case strings.HasPrefix(arg, "--"):
			// arg is a long flag, with an optional argument specified
			// using `=' or in args[i+1]
			var slurped bool
			var next *string
			split := strings.SplitN(arg, "=", 2)
			if len(split) == 2 {
				slurped = false
				arg = split[0]
				next = &split[1]
			} else {
				slurped = true
				if i+1 < len(args) {
					next = &args[i+1]
				} else {
					next = nil
				}
			}
			consumed, err = parseFlag(arg[2:], next, len(split) == 2)
			if err != nil {
				return
			}
			if !slurped {
				consumed = false
			}

		case strings.HasPrefix(arg, "-") && arg != "-":
			// args is one or more flags in short form, followed by an optional argument
			// all flags except the last one have type bool
			for arg = arg[1:]; len(arg) != 0; arg = arg[1:] {
				var rest *string
				var slurped bool
				mustUse := false
				if len(arg) > 1 {
					slurped = false
					str := arg[1:]
					if len(str) > 0 && str[0] == '=' {
						str = str[1:]
						mustUse = true
					}
					rest = &str
				} else {
					slurped = true
					if i+1 < len(args) {
						rest = &args[i+1]
					} else {
						rest = nil
					}
				}
				var end bool
				end, err = parseFlag(arg[:1], rest, mustUse)
				if err != nil {
					return
				}
				if end {
					consumed = slurped
					break
				}
			}

		default:
			// arg is a sub-command or a positional argument
			sub := cmd.Subcommand(arg)
			if sub != nil {
				cmd = sub
				path = append(path, arg)
				optDefs, err = root.GetOptions(path)
				if err != nil {
					return
				}

				// If we've come across an external binary call, pass all the remaining
				// arguments on to it
				if cmd.External {
					stringVals = append(stringVals, args[i+1:]...)
					return
				}
			} else {
				stringVals = append(stringVals, arg)
				if len(path) == 0 {
					// found a typo or early argument
					err = printSuggestions(stringVals, root)
					return
				}
			}
		}
	}
	return
}

const msgStdinInfo = "ipfs: Reading from %s; send Ctrl-d to stop.\n"

func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursive, hidden bool, root *cmds.Command) ([]string, []files.File, error) {
	// ignore stdin on Windows
	if runtime.GOOS == "windows" {
		stdin = nil
	}

	// count required argument definitions
	numRequired := 0
	for _, argDef := range argDefs {
		if argDef.Required {
			numRequired++
		}
	}

	// count number of values provided by user.
	// if there is at least one ArgDef, we can safely trigger the inputs loop
	// below to parse stdin.
	numInputs := len(inputs)
	if len(argDefs) > 0 && argDefs[len(argDefs)-1].SupportsStdin && stdin != nil {
		numInputs += 1
	}

	// if we have more arg values provided than argument definitions,
	// and the last arg definition is not variadic (or there are no definitions), return an error
	notVariadic := len(argDefs) == 0 || !argDefs[len(argDefs)-1].Variadic
	if notVariadic && len(inputs) > len(argDefs) {
		err := printSuggestions(inputs, root)
		return nil, nil, err
	}

	stringArgs := make([]string, 0, numInputs)

	fileArgs := make(map[string]files.File)
	argDefIndex := 0 // the index of the current argument definition

	for i := 0; i < numInputs; i++ {
		argDef := getArgDef(argDefIndex, argDefs)

		// skip optional argument definitions if there aren't sufficient remaining inputs
		for numInputs-i <= numRequired && !argDef.Required {
			argDefIndex++
			argDef = getArgDef(argDefIndex, argDefs)
		}
		if argDef.Required {
			numRequired--
		}

		fillingVariadic := argDefIndex+1 > len(argDefs)
		switch argDef.Type {
		case cmds.ArgString:
			if len(inputs) > 0 {
				stringArgs, inputs = append(stringArgs, inputs[0]), inputs[1:]
			} else {
				if stdin != nil && argDef.SupportsStdin && !fillingVariadic {
					if err := printReadInfo(stdin, msgStdinInfo); err == nil {
						fileArgs[stdin.Name()] = files.NewReaderFile(stdinSpecialName, "", stdin, nil)
						stdin = nil
					}
				}
			}
		case cmds.ArgFile:
			if len(inputs) > 0 {
				// treat stringArg values as file paths
				fpath := inputs[0]
				inputs = inputs[1:]
				var file files.File
				var err error
				if fpath == "-" {
					if err = printReadInfo(stdin, msgStdinInfo); err == nil {
						fpath = stdin.Name()
						file = files.NewReaderFile("", fpath, stdin, nil)
					}
				} else {
					file, err = appendFile(fpath, argDef, recursive, hidden)
				}
				if err != nil {
					return nil, nil, err
				}

				fileArgs[fpath] = file
			} else {
				if stdin != nil && argDef.SupportsStdin &&
					argDef.Required && !fillingVariadic {
					if err := printReadInfo(stdin, msgStdinInfo); err != nil {
						return nil, nil, err
					}
					fpath := stdin.Name()
					fileArgs[fpath] = files.NewReaderFile("", fpath, stdin, nil)
				} else {
					break
				}
			}
		}

		argDefIndex++
	}

	// check to make sure we didn't miss any required arguments
	if len(argDefs) > argDefIndex {
		for _, argDef := range argDefs[argDefIndex:] {
			if argDef.Required {
				return nil, nil, fmt.Errorf("Argument '%s' is required", argDef.Name)
			}
		}
	}

	return stringArgs, filesMapToSortedArr(fileArgs), nil
}

func filesMapToSortedArr(fs map[string]files.File) []files.File {
	var names []string
	for name, _ := range fs {
		names = append(names, name)
	}

	sort.Strings(names)

	var out []files.File
	for _, f := range names {
		out = append(out, fs[f])
	}

	return out
}

func getArgDef(i int, argDefs []cmds.Argument) *cmds.Argument {
	if i < len(argDefs) {
		// get the argument definition (usually just argDefs[i])
		return &argDefs[i]

	} else if len(argDefs) > 0 {
		// but if i > len(argDefs) we use the last argument definition)
		return &argDefs[len(argDefs)-1]
	}

	// only happens if there aren't any definitions
	return nil
}

const notRecursiveFmtStr = "'%s' is a directory, use the '-%s' flag to specify directories"
const dirNotSupportedFmtStr = "Invalid path '%s', argument '%s' does not support directories"

func appendFile(fpath string, argDef *cmds.Argument, recursive, hidden bool) (files.File, error) {
	if fpath == "." {
		cwd, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		fpath = cwd
	}

	fpath = filepath.ToSlash(filepath.Clean(fpath))
	fpath, err := filepath.EvalSymlinks(fpath)
	if err != nil {
		return nil, err
	}
	stat, err := os.Lstat(fpath)
	if err != nil {
		return nil, err
	}

	if stat.IsDir() {
		if !argDef.Recursive {
			return nil, fmt.Errorf(dirNotSupportedFmtStr, fpath, argDef.Name)
		}
		if !recursive {
			return nil, fmt.Errorf(notRecursiveFmtStr, fpath, cmds.RecShort)
		}
	}

	return files.NewSerialFile(path.Base(fpath), fpath, hidden, stat)
}

// Inform the user if a file is waiting on input
func printReadInfo(f *os.File, msg string) error {
	isTty, err := isTty(f)
	if err != nil {
		return err
	}

	if isTty {
		fmt.Fprintf(os.Stderr, msg, f.Name())
	}

	return nil
}

func isTty(f *os.File) (bool, error) {
	fInfo, err := f.Stat()
	if err != nil {
		log.Error(err)
		return false, err
	}

	return (fInfo.Mode() & os.ModeCharDevice) != 0, nil
}
<commit_msg>remove badcode<commit_after>package cli

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	cmds "github.com/ipfs/go-ipfs/commands"
	files "github.com/ipfs/go-ipfs/commands/files"
	logging "gx/ipfs/QmNQynaz7qfriSUJkiEZUrm2Wen1u3Kj9goZzWtrPyu7XR/go-log"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
)

var log = logging.Logger("commands/cli")

// Parse parses the input commandline string (cmd, flags, and args).
// returns the corresponding command Request object.
func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *cmds.Command, []string, error) {
	path, opts, stringVals, cmd, err := parseOpts(input, root)
	if err != nil {
		return nil, nil, path, err
	}

	optDefs, err := root.GetOptions(path)
	if err != nil {
		return nil, cmd, path, err
	}

	req, err := cmds.NewRequest(path, opts, nil, nil, cmd, optDefs)
	if err != nil {
		return nil, cmd, path, err
	}

	// if -r is provided, and it is associated with the package builtin
	// recursive path option, allow recursive file paths
	recursiveOpt := req.Option(cmds.RecShort)
	recursive := false
	if recursiveOpt != nil && recursiveOpt.Definition() == cmds.OptionRecursivePath {
		recursive, _, err = recursiveOpt.Bool()
		if err != nil {
			return req, nil, nil, u.ErrCast()
		}
	}

	// if '--hidden' is provided, enumerate hidden paths
	hiddenOpt := req.Option("hidden")
	hidden := false
	if hiddenOpt != nil {
		hidden, _, err = hiddenOpt.Bool()
		if err != nil {
			return req, nil, nil, u.ErrCast()
		}
	}

	// This is an ugly hack to maintain our current CLI interface while fixing
	// other stdin usage bugs. Let this serve as a warning, be careful about the
	// choices you make, they will haunt you forever.
	if len(path) == 2 && path[0] == "bootstrap" {
		if (path[1] == "add" && opts["default"] == true) ||
			(path[1] == "rm" && opts["all"] == true) {
			stdin = nil
		}
	}

	stringArgs, fileArgs, err := parseArgs(stringVals, stdin, cmd.Arguments, recursive, hidden, root)
	if err != nil {
		return req, cmd, path, err
	}
	req.SetArguments(stringArgs)

	if len(fileArgs) > 0 {
		file := files.NewSliceFile("", "", fileArgs)
		req.SetFiles(file)
	}

	err = cmd.CheckArguments(req)
	if err != nil {
		return req, cmd, path, err
	}

	return req, cmd, path, nil
}

// Parse a command line made up of sub-commands, short arguments, long arguments and positional arguments
func parseOpts(args []string, root *cmds.Command) (
	path []string,
	opts map[string]interface{},
	stringVals []string,
	cmd *cmds.Command,
	err error,
) {
	path = make([]string, 0, len(args))
	stringVals = make([]string, 0, len(args))
	optDefs := map[string]cmds.Option{}
	opts = map[string]interface{}{}
	cmd = root

	// parseFlag checks that a flag is valid and saves it into opts
	// Returns true if the optional second argument is used
	parseFlag := func(name string, arg *string, mustUse bool) (bool, error) {
		if _, ok := opts[name]; ok {
			return false, fmt.Errorf("Duplicate values for option '%s'", name)
		}

		optDef, found := optDefs[name]
		if !found {
			err = fmt.Errorf("Unrecognized option '%s'", name)
			return false, err
		}
		// mustUse implies that you must use the argument given after the '='
		// eg. -r=true means you must take true into consideration
		//		mustUse == true in the above case
		// eg. ipfs -r <file> means disregard <file> since there is no '='
		//		mustUse == false in the above situation
		//arg == nil implies the flag was specified without an argument
		if optDef.Type() == cmds.Bool {
			if arg == nil || !mustUse {
				opts[name] = true
				return false, nil
			}
			argVal := strings.ToLower(*arg)
			switch argVal {
			case "true":
				opts[name] = true
				return true, nil
			case "false":
				opts[name] = false
				return true, nil
			default:
				return true, fmt.Errorf("Option '%s' takes true/false arguments, but was passed '%s'", name, argVal)
			}
		} else {
			if arg == nil {
				return true, fmt.Errorf("Missing argument for option '%s'", name)
			}
			opts[name] = *arg
			return true, nil
		}
	}

	optDefs, err = root.GetOptions(path)
	if err != nil {
		return
	}

	consumed := false
	for i, arg := range args {
		switch {
		case consumed:
			// arg was already consumed by the preceding flag
			consumed = false
			continue

		case arg == "--":
			// treat all remaining arguments as positional arguments
			stringVals = append(stringVals, args[i+1:]...)
			return

		case strings.HasPrefix(arg, "--"):
			// arg is a long flag, with an optional argument specified
			// using `=' or in args[i+1]
			var slurped bool
			var next *string
			split := strings.SplitN(arg, "=", 2)
			if len(split) == 2 {
				slurped = false
				arg = split[0]
				next = &split[1]
			} else {
				slurped = true
				if i+1 < len(args) {
					next = &args[i+1]
				} else {
					next = nil
				}
			}
			consumed, err = parseFlag(arg[2:], next, len(split) == 2)
			if err != nil {
				return
			}
			if !slurped {
				consumed = false
			}

		case strings.HasPrefix(arg, "-") && arg != "-":
			// args is one or more flags in short form, followed by an optional argument
			// all flags except the last one have type bool
			for arg = arg[1:]; len(arg) != 0; arg = arg[1:] {
				var rest *string
				var slurped bool
				mustUse := false
				if len(arg) > 1 {
					slurped = false
					str := arg[1:]
					if len(str) > 0 && str[0] == '=' {
						str = str[1:]
						mustUse = true
					}
					rest = &str
				} else {
					slurped = true
					if i+1 < len(args) {
						rest = &args[i+1]
					} else {
						rest = nil
					}
				}
				var end bool
				end, err = parseFlag(arg[:1], rest, mustUse)
				if err != nil {
					return
				}
				if end {
					consumed = slurped
					break
				}
			}

		default:
			// arg is a sub-command or a positional argument
			sub := cmd.Subcommand(arg)
			if sub != nil {
				cmd = sub
				path = append(path, arg)
				optDefs, err = root.GetOptions(path)
				if err != nil {
					return
				}

				// If we've come across an external binary call, pass all the remaining
				// arguments on to it
				if cmd.External {
					stringVals = append(stringVals, args[i+1:]...)
					return
				}
			} else {
				stringVals = append(stringVals, arg)
				if len(path) == 0 {
					// found a typo or early argument
					err = printSuggestions(stringVals, root)
					return
				}
			}
		}
	}
	return
}

const msgStdinInfo = "ipfs: Reading from %s; send Ctrl-d to stop.\n"

func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursive, hidden bool, root *cmds.Command) ([]string, []files.File, error) {
	// ignore stdin on Windows
	if runtime.GOOS == "windows" {
		stdin = nil
	}

	// count required argument definitions
	numRequired := 0
	for _, argDef := range argDefs {
		if argDef.Required {
			numRequired++
		}
	}

	// count number of values provided by user.
	// if there is at least one ArgDef, we can safely trigger the inputs loop
	// below to parse stdin.
	numInputs := len(inputs)
	if len(argDefs) > 0 && argDefs[len(argDefs)-1].SupportsStdin && stdin != nil {
		numInputs += 1
	}

	// if we have more arg values provided than argument definitions,
	// and the last arg definition is not variadic (or there are no definitions), return an error
	notVariadic := len(argDefs) == 0 || !argDefs[len(argDefs)-1].Variadic
	if notVariadic && len(inputs) > len(argDefs) {
		err := printSuggestions(inputs, root)
		return nil, nil, err
	}

	stringArgs := make([]string, 0, numInputs)

	fileArgs := make(map[string]files.File)
	argDefIndex := 0 // the index of the current argument definition

	for i := 0; i < numInputs; i++ {
		argDef := getArgDef(argDefIndex, argDefs)

		// skip optional argument definitions if there aren't sufficient remaining inputs
		for numInputs-i <= numRequired && !argDef.Required {
			argDefIndex++
			argDef = getArgDef(argDefIndex, argDefs)
		}
		if argDef.Required {
			numRequired--
		}

		fillingVariadic := argDefIndex+1 > len(argDefs)
		switch argDef.Type {
		case cmds.ArgString:
			if len(inputs) > 0 {
				stringArgs, inputs = append(stringArgs, inputs[0]), inputs[1:]
			} else {
				if stdin != nil && argDef.SupportsStdin && !fillingVariadic {
					if err := printReadInfo(stdin, msgStdinInfo); err == nil {
						fileArgs[stdin.Name()] = files.NewReaderFile("stdin", "", stdin, nil)
						stdin = nil
					}
				}
			}
		case cmds.ArgFile:
			if len(inputs) > 0 {
				// treat stringArg values as file paths
				fpath := inputs[0]
				inputs = inputs[1:]
				var file files.File
				var err error
				if fpath == "-" {
					if err = printReadInfo(stdin, msgStdinInfo); err == nil {
						fpath = stdin.Name()
						file = files.NewReaderFile("", fpath, stdin, nil)
					}
				} else {
					file, err = appendFile(fpath, argDef, recursive, hidden)
				}
				if err != nil {
					return nil, nil, err
				}

				fileArgs[fpath] = file
			} else {
				if stdin != nil && argDef.SupportsStdin &&
					argDef.Required && !fillingVariadic {
					if err := printReadInfo(stdin, msgStdinInfo); err != nil {
						return nil, nil, err
					}
					fpath := stdin.Name()
					fileArgs[fpath] = files.NewReaderFile("", fpath, stdin, nil)
				} else {
					break
				}
			}
		}

		argDefIndex++
	}

	// check to make sure we didn't miss any required arguments
	if len(argDefs) > argDefIndex {
		for _, argDef := range argDefs[argDefIndex:] {
			if argDef.Required {
				return nil, nil, fmt.Errorf("Argument '%s' is required", argDef.Name)
			}
		}
	}

	return stringArgs, filesMapToSortedArr(fileArgs), nil
}

func filesMapToSortedArr(fs map[string]files.File) []files.File {
	var names []string
	for name, _ := range fs {
		names = append(names, name)
	}

	sort.Strings(names)

	var out []files.File
	for _, f := range names {
		out = append(out, fs[f])
	}

	return out
}

func getArgDef(i int, argDefs []cmds.Argument) *cmds.Argument {
	if i < len(argDefs) {
		// get the argument definition (usually just argDefs[i])
		return &argDefs[i]

	} else if len(argDefs) > 0 {
		// but if i > len(argDefs) we use the last argument definition)
		return &argDefs[len(argDefs)-1]
	}

	// only happens if there aren't any definitions
	return nil
}

const notRecursiveFmtStr = "'%s' is a directory, use the '-%s' flag to specify directories"
const dirNotSupportedFmtStr = "Invalid path '%s', argument '%s' does not support directories"

func appendFile(fpath string, argDef *cmds.Argument, recursive, hidden bool) (files.File, error) {
	if fpath == "." {
		cwd, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		fpath = cwd
	}

	fpath = filepath.ToSlash(filepath.Clean(fpath))
	fpath, err := filepath.EvalSymlinks(fpath)
	if err != nil {
		return nil, err
	}
	stat, err := os.Lstat(fpath)
	if err != nil {
		return nil, err
	}

	if stat.IsDir() {
		if !argDef.Recursive {
			return nil, fmt.Errorf(dirNotSupportedFmtStr, fpath, argDef.Name)
		}
		if !recursive {
			return nil, fmt.Errorf(notRecursiveFmtStr, fpath, cmds.RecShort)
		}
	}

	return files.NewSerialFile(path.Base(fpath), fpath, hidden, stat)
}

// Inform the user if a file is waiting on input
func printReadInfo(f *os.File, msg string) error {
	isTty, err := isTty(f)
	if err != nil {
		return err
	}

	if isTty {
		fmt.Fprintf(os.Stderr, msg, f.Name())
	}

	return nil
}

func isTty(f *os.File) (bool, error) {
	fInfo, err := f.Stat()
	if err != nil {
		log.Error(err)
		return false, err
	}

	return (fInfo.Mode() & os.ModeCharDevice) != 0, nil
}
<|endoftext|>


<commit_before>package spectrum

import (
	"testing"
	"sdl"
	"io/ioutil"
	"image"
	"image/png"
	"os"
	"strings"
	"unsafe"
)

func (s *SDLSurface) At(x, y int) image.Color {
	var bpp = int(s.Surface.Format.BytesPerPixel)

	var pixel = uintptr(unsafe.Pointer(s.Surface.Pixels))

	pixel += uintptr(y*int(s.Surface.Pitch) + x*bpp)

	var color = *((*uint32)(unsafe.Pointer(pixel)))

	var r uint8
	var g uint8
	var b uint8
	var a uint8

	sdl.GetRGBA(color, s.Surface.Format, &r, &g, &b, &a)

	return image.RGBAColor{uint8(r), uint8(g), uint8(b), uint8(a)}
}

func initSDL() {
	if sdl.Init(sdl.INIT_VIDEO) != 0 {
		panic(sdl.GetError())
	}
}

func newSurface() *sdl.Surface {
	return sdl.SetVideoMode(TotalScreenWidth, TotalScreenHeight, 32, 0)
}

func readOutputImage(filename string) image.Image {
	var file *os.File
	var err os.Error
	var image image.Image

	if file, err = os.Open(filename, os.O_RDONLY, 0); err != nil {
		panic(err)
	}

	if image, err = png.Decode(file); err != nil {
		panic(err)
	}
	return image
}

func readInputImage(filename string) *Display {
	display := &Display{}
	display.memory, _ = ioutil.ReadFile(filename)
	return display
}

func colorsAreNotEqual(got, expected image.Color) bool {
	got_r, got_g, got_b, got_a := got.RGBA()
	expected_r, expected_g, expected_b, expected_a := expected.RGBA()
	if (got_r != expected_r) || (got_g != expected_g) || (got_b != expected_b) || (got_a != expected_a) {
		return true
	}
	return false
}

func imagesAreNotEqual(got *SDLScreen, expected image.Image) image.Image {
	diff := false
	diffImage := image.NewRGBA(TotalScreenWidth, TotalScreenHeight)

	for y := 0; y < TotalScreenHeight; y++ {
		for x := 0; x < TotalScreenWidth; x++ {
			if colorsAreNotEqual(got.ScreenSurface.At(x, y), expected.At(x, y)) {
				diff = true
				diffImage.Set(x, y, image.Red)
			}
		}
	}

	if diff {
		return diffImage
	}

	return nil

}

type RenderTest struct {
	in, out     string
	borderColor RGBA
	flash       bool
	diffImage   image.Image
}

func (r *RenderTest) renderInputImage() bool {
	renderedScreen := &SDLScreen{nil, SDLSurface{newSurface()}}

	expectedImage := readOutputImage(r.out)
	inputImage := readInputImage(r.in)

	inputImage.borderColor = r.borderColor

	if r.flash {
		inputImage.flashFrame = 0x10
		inputImage.prepare()
	}

	displayData := inputImage.prepare()

	renderedScreen.render(displayData, nil)

	if diffImage := imagesAreNotEqual(renderedScreen, expectedImage); diffImage != nil {
		r.diffImage = diffImage
		return true
	}

	return false
}

func (r *RenderTest) getDiffFn() string {
	return strings.TrimRight(r.out, ".png") + "_diff.png"
}

func (r *RenderTest) reportError(t *testing.T) {
	t.Errorf("Expected image %s is not equal to the rendered one! Check %s\n", r.out, r.getDiffFn())

	if file, err := os.Open(r.getDiffFn(), os.O_CREATE|os.O_WRONLY, 0666); err != nil {
		panic(err)
	} else {
		if err := png.Encode(file, r.diffImage); err != nil {
			panic(err)
		}
	}
}

var RenderTests = []RenderTest{
	RenderTest{in: "testdata/initial.scr", out: "testdata/initial.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_0.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_1.png", borderColor: RGBA{192, 192, 192, 255}, flash: true},
}

func TestSDLRenderer(t *testing.T) {

	initSDL()

	for _, r := range RenderTests {
		if notEqual := r.renderInputImage(); notEqual {
			r.reportError(t)
		}
	}

	sdl.Quit()

}

func BenchmarkRender(b *testing.B) {

	b.StopTimer()

	const numFrames = 100

	var (
		frames    [numFrames]DisplayData
		prevFrame *DisplayData = nil
	)

	sdlScreen := &SDLScreen{make(chan *DisplayData), SDLSurface{newSurface()}}

	if speccy, err := NewSpectrum48k(); err != nil {
		panic(err)
	} else {
		speccy.SetDisplayReceiver(sdlScreen)
		speccy.LoadSna("testdata/fire.sna")

		go func() {
			for i := 0; i < numFrames; i++ {
				speccy.RenderFrame()
			}
		}()

		go func() {
			for i := 0; i < numFrames; i++ {
				frames[i] = *<-sdlScreen.getDisplayDataCh()
			}
		}()

		var j byte

		b.StartTimer()
		for i := 0; i < b.N; i++ {
			j %= numFrames / 2
			sdlScreen.render(&frames[j], prevFrame)
			prevFrame = &frames[j]
			j++
		}

	}

}
<commit_msg>Increase numFrames in BenchmarkRender<commit_after>package spectrum

import (
	"testing"
	"sdl"
	"io/ioutil"
	"image"
	"image/png"
	"os"
	"strings"
	"unsafe"
)

func (s *SDLSurface) At(x, y int) image.Color {
	var bpp = int(s.Surface.Format.BytesPerPixel)

	var pixel = uintptr(unsafe.Pointer(s.Surface.Pixels))

	pixel += uintptr(y*int(s.Surface.Pitch) + x*bpp)

	var color = *((*uint32)(unsafe.Pointer(pixel)))

	var r uint8
	var g uint8
	var b uint8
	var a uint8

	sdl.GetRGBA(color, s.Surface.Format, &r, &g, &b, &a)

	return image.RGBAColor{uint8(r), uint8(g), uint8(b), uint8(a)}
}

func initSDL() {
	if sdl.Init(sdl.INIT_VIDEO) != 0 {
		panic(sdl.GetError())
	}
}

func newSurface() *sdl.Surface {
	return sdl.SetVideoMode(TotalScreenWidth, TotalScreenHeight, 32, 0)
}

func readOutputImage(filename string) image.Image {
	var file *os.File
	var err os.Error
	var image image.Image

	if file, err = os.Open(filename, os.O_RDONLY, 0); err != nil {
		panic(err)
	}

	if image, err = png.Decode(file); err != nil {
		panic(err)
	}
	return image
}

func readInputImage(filename string) *Display {
	display := &Display{}
	display.memory, _ = ioutil.ReadFile(filename)
	return display
}

func colorsAreNotEqual(got, expected image.Color) bool {
	got_r, got_g, got_b, got_a := got.RGBA()
	expected_r, expected_g, expected_b, expected_a := expected.RGBA()
	if (got_r != expected_r) || (got_g != expected_g) || (got_b != expected_b) || (got_a != expected_a) {
		return true
	}
	return false
}

func imagesAreNotEqual(got *SDLScreen, expected image.Image) image.Image {
	diff := false
	diffImage := image.NewRGBA(TotalScreenWidth, TotalScreenHeight)

	for y := 0; y < TotalScreenHeight; y++ {
		for x := 0; x < TotalScreenWidth; x++ {
			if colorsAreNotEqual(got.ScreenSurface.At(x, y), expected.At(x, y)) {
				diff = true
				diffImage.Set(x, y, image.Red)
			}
		}
	}

	if diff {
		return diffImage
	}

	return nil

}

type RenderTest struct {
	in, out     string
	borderColor RGBA
	flash       bool
	diffImage   image.Image
}

func (r *RenderTest) renderInputImage() bool {
	renderedScreen := &SDLScreen{nil, SDLSurface{newSurface()}}

	expectedImage := readOutputImage(r.out)
	inputImage := readInputImage(r.in)

	inputImage.borderColor = r.borderColor

	if r.flash {
		inputImage.flashFrame = 0x10
		inputImage.prepare()
	}

	displayData := inputImage.prepare()

	renderedScreen.render(displayData, nil)

	if diffImage := imagesAreNotEqual(renderedScreen, expectedImage); diffImage != nil {
		r.diffImage = diffImage
		return true
	}

	return false
}

func (r *RenderTest) getDiffFn() string {
	return strings.TrimRight(r.out, ".png") + "_diff.png"
}

func (r *RenderTest) reportError(t *testing.T) {
	t.Errorf("Expected image %s is not equal to the rendered one! Check %s\n", r.out, r.getDiffFn())

	if file, err := os.Open(r.getDiffFn(), os.O_CREATE|os.O_WRONLY, 0666); err != nil {
		panic(err)
	} else {
		if err := png.Encode(file, r.diffImage); err != nil {
			panic(err)
		}
	}
}

var RenderTests = []RenderTest{
	RenderTest{in: "testdata/initial.scr", out: "testdata/initial.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_0.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_1.png", borderColor: RGBA{192, 192, 192, 255}, flash: true},
}

func TestSDLRenderer(t *testing.T) {

	initSDL()

	for _, r := range RenderTests {
		if notEqual := r.renderInputImage(); notEqual {
			r.reportError(t)
		}
	}

	sdl.Quit()

}

func BenchmarkRender(b *testing.B) {

	b.StopTimer()

	const numFrames = 1000

	var (
		frames    [numFrames]DisplayData
		prevFrame *DisplayData = nil
	)

	sdlScreen := &SDLScreen{make(chan *DisplayData), SDLSurface{newSurface()}}

	if speccy, err := NewSpectrum48k(); err != nil {
		panic(err)
	} else {
		speccy.SetDisplayReceiver(sdlScreen)
		speccy.LoadSna("testdata/fire.sna")

		go func() {
			for i := 0; i < numFrames; i++ {
				speccy.RenderFrame()
			}
		}()

		go func() {
			for i := 0; i < numFrames; i++ {
				frames[i] = *<-sdlScreen.getDisplayDataCh()
			}
		}()

		var j int

		b.StartTimer()
		for i := 0; i < b.N; i++ {
			j %= numFrames / 2
			sdlScreen.render(&frames[j], prevFrame)
			prevFrame = &frames[j]
			j++
		}

	}

}
<|endoftext|>


<commit_before>package finalize

const (
	initScript = `
# ------------------------------------------------------------------------------------------------
# Copyright 2013 Jordon Bedwell.
# Apache License.
#
# 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.
# ------------------------------------------------------------------------------------------------

export APP_ROOT=$HOME
export LD_LIBRARY_PATH=$APP_ROOT/nginx/lib:$LD_LIBRARY_PATH

mv $APP_ROOT/nginx/conf/nginx.conf $APP_ROOT/nginx/conf/nginx.conf.erb
erb $APP_ROOT/nginx/conf/nginx.conf.erb > $APP_ROOT/nginx/conf/nginx.conf

if [[ ! -f $APP_ROOT/nginx/logs/access.log ]]; then
    mkfifo $APP_ROOT/nginx/logs/access.log
fi

if [[ ! -f $APP_ROOT/nginx/logs/error.log ]]; then
    mkfifo $APP_ROOT/nginx/logs/error.log
fi
`

	startLoggingScript = `
cat < $APP_ROOT/nginx/logs/access.log &
(>&2 cat) < $APP_ROOT/nginx/logs/error.log &
`

	startCommand = `#!/bin/sh
set -ex
$APP_ROOT/start_logging.sh
nginx -p $APP_ROOT/nginx -c $APP_ROOT/nginx/conf/nginx.conf
`

	nginxConfTemplate = `
worker_processes 1;
daemon off;

error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;
events { worker_connections 1024; }

http {
  charset utf-8;
  log_format cloudfoundry '$http_x_forwarded_for - $http_referer - [$time_local] "$request" $status $body_bytes_sent';
  access_log <%= ENV["APP_ROOT"] %>/nginx/logs/access.log cloudfoundry;
  default_type application/octet-stream;
  include mime.types;
  sendfile on;

  gzip on;
  gzip_disable "msie6";
  gzip_comp_level 6;
  gzip_min_length 1100;
  gzip_buffers 16 8k;
  gzip_proxied any;
  gunzip on;
  gzip_static always;
  gzip_types text/plain text/css text/js text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/xml+rss;
  gzip_vary on;

  tcp_nopush on;
  keepalive_timeout 30;
  port_in_redirect off; # Ensure that redirects don't include the internal container PORT - <%= ENV["PORT"] %>
  server_tokens off;

  server {
    listen <%= ENV["PORT"] %>;
    server_name localhost;

    root <%= ENV["APP_ROOT"] %>/public;

    {{if .ForceHTTPS}}
      set $updated_host $host;
      if ($http_x_forwarded_host != "") {
        set $updated_host $http_x_forwarded_host;
      }

      if ($http_x_forwarded_proto != "https") {
        return 301 https://$updated_host$request_uri;
      }
    {{else}}
      <% if ENV["FORCE_HTTPS"] %>
        set $updated_host $host;
        if ($http_x_forwarded_host != "") {
          set $updated_host $http_x_forwarded_host;
        }

        if ($http_x_forwarded_proto != "https") {
          return 301 https://$updated_host$request_uri;
        }
      <% end %>
    {{end}}

    location / {
      {{if .PushState}}
        if (!-e $request_filename) {
          rewrite ^(.*)$ / break;
        }
      {{end}}

        index index.html index.htm Default.htm;

      {{if .DirectoryIndex}}
        autoindex on;
        absolute_redirect off;
      {{end}}

      {{if .BasicAuth}}
        auth_basic "Restricted";  #For Basic Auth
        auth_basic_user_file <%= ENV["APP_ROOT"] %>/nginx/conf/.htpasswd;
      {{end}}

      {{if .SSI}}
        ssi on;
      {{end}}

      {{if .HSTS}}
        add_header Strict-Transport-Security "max-age=31536000{{if .HSTSIncludeSubDomains}}; includeSubDomains{{end}}{{if .HSTSPreload}}; preload{{end}}";
      {{end}}

      {{if ne .LocationInclude ""}}
        include {{.LocationInclude}};
      {{end}}

			{{ range $code, $value := .StatusCodes }}
			  error_page {{ $code }} {{ $value }};
		  {{ end }}
    }

    {{if not .HostDotFiles}}
      location ~ /\. {
        deny all;
        return 404;
      }
    {{end}}
  }
}
`
	MimeTypes = `
types {
  text/html html htm shtml;
  text/css css;
  text/xml xml;
  image/gif gif;
  image/jpeg jpeg jpg;
  application/javascript js;
  application/atom+xml atom;
  application/rss+xml rss;
  font/ttf ttf;
  font/woff woff;
  font/woff2 woff2;
  text/mathml mml;
  text/plain txt;
  text/vnd.sun.j2me.app-descriptor jad;
  text/vnd.wap.wml wml;
  text/x-component htc;
  text/cache-manifest manifest;
  image/png png;
  image/tiff tif tiff;
  image/vnd.wap.wbmp wbmp;
  image/x-icon ico;
  image/x-jng jng;
  image/x-ms-bmp bmp;
  image/svg+xml svg svgz;
  image/webp webp;
  application/java-archive jar war ear;
  application/mac-binhex40 hqx;
  application/msword doc;
  application/pdf pdf;
  application/postscript ps eps ai;
  application/rtf rtf;
  application/vnd.ms-excel xls;
  application/vnd.ms-powerpoint ppt;
  application/vnd.wap.wmlc wmlc;
  application/vnd.google-earth.kml+xml  kml;
  application/vnd.google-earth.kmz kmz;
  application/x-7z-compressed 7z;
  application/x-cocoa cco;
  application/x-java-archive-diff jardiff;
  application/x-java-jnlp-file jnlp;
  application/x-makeself run;
  application/x-perl pl pm;
  application/x-pilot prc pdb;
  application/x-rar-compressed rar;
  application/x-redhat-package-manager  rpm;
  application/x-sea sea;
  application/x-shockwave-flash swf;
  application/x-stuffit sit;
  application/x-tcl tcl tk;
  application/x-x509-ca-cert der pem crt;
  application/x-xpinstall xpi;
  application/xhtml+xml xhtml;
  application/zip zip;
  application/octet-stream bin exe dll;
  application/octet-stream deb;
  application/octet-stream dmg;
  application/octet-stream eot;
  application/octet-stream iso img;
  application/octet-stream msi msp msm;
  application/json json;
  audio/midi mid midi kar;
  audio/mpeg mp3;
  audio/ogg ogg;
  audio/x-m4a m4a;
  audio/x-realaudio ra;
  video/3gpp 3gpp 3gp;
  video/mp4 mp4;
  video/mpeg mpeg mpg;
  video/quicktime mov;
  video/webm webm;
  video/x-flv flv;
  video/x-m4v m4v;
  video/x-mng mng;
  video/x-ms-asf asx asf;
  video/x-ms-wmv wmv;
  video/x-msvideo avi;
}
`
)
<commit_msg>Convert tabs to spaces in template, which is space-indented<commit_after>package finalize

const (
	initScript = `
# ------------------------------------------------------------------------------------------------
# Copyright 2013 Jordon Bedwell.
# Apache License.
#
# 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.
# ------------------------------------------------------------------------------------------------

export APP_ROOT=$HOME
export LD_LIBRARY_PATH=$APP_ROOT/nginx/lib:$LD_LIBRARY_PATH

mv $APP_ROOT/nginx/conf/nginx.conf $APP_ROOT/nginx/conf/nginx.conf.erb
erb $APP_ROOT/nginx/conf/nginx.conf.erb > $APP_ROOT/nginx/conf/nginx.conf

if [[ ! -f $APP_ROOT/nginx/logs/access.log ]]; then
    mkfifo $APP_ROOT/nginx/logs/access.log
fi

if [[ ! -f $APP_ROOT/nginx/logs/error.log ]]; then
    mkfifo $APP_ROOT/nginx/logs/error.log
fi
`

	startLoggingScript = `
cat < $APP_ROOT/nginx/logs/access.log &
(>&2 cat) < $APP_ROOT/nginx/logs/error.log &
`

	startCommand = `#!/bin/sh
set -ex
$APP_ROOT/start_logging.sh
nginx -p $APP_ROOT/nginx -c $APP_ROOT/nginx/conf/nginx.conf
`

	nginxConfTemplate = `
worker_processes 1;
daemon off;

error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;
events { worker_connections 1024; }

http {
  charset utf-8;
  log_format cloudfoundry '$http_x_forwarded_for - $http_referer - [$time_local] "$request" $status $body_bytes_sent';
  access_log <%= ENV["APP_ROOT"] %>/nginx/logs/access.log cloudfoundry;
  default_type application/octet-stream;
  include mime.types;
  sendfile on;

  gzip on;
  gzip_disable "msie6";
  gzip_comp_level 6;
  gzip_min_length 1100;
  gzip_buffers 16 8k;
  gzip_proxied any;
  gunzip on;
  gzip_static always;
  gzip_types text/plain text/css text/js text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/xml+rss;
  gzip_vary on;

  tcp_nopush on;
  keepalive_timeout 30;
  port_in_redirect off; # Ensure that redirects don't include the internal container PORT - <%= ENV["PORT"] %>
  server_tokens off;

  server {
    listen <%= ENV["PORT"] %>;
    server_name localhost;

    root <%= ENV["APP_ROOT"] %>/public;

    {{if .ForceHTTPS}}
      set $updated_host $host;
      if ($http_x_forwarded_host != "") {
        set $updated_host $http_x_forwarded_host;
      }

      if ($http_x_forwarded_proto != "https") {
        return 301 https://$updated_host$request_uri;
      }
    {{else}}
      <% if ENV["FORCE_HTTPS"] %>
        set $updated_host $host;
        if ($http_x_forwarded_host != "") {
          set $updated_host $http_x_forwarded_host;
        }

        if ($http_x_forwarded_proto != "https") {
          return 301 https://$updated_host$request_uri;
        }
      <% end %>
    {{end}}

    location / {
      {{if .PushState}}
        if (!-e $request_filename) {
          rewrite ^(.*)$ / break;
        }
      {{end}}

        index index.html index.htm Default.htm;

      {{if .DirectoryIndex}}
        autoindex on;
        absolute_redirect off;
      {{end}}

      {{if .BasicAuth}}
        auth_basic "Restricted";  #For Basic Auth
        auth_basic_user_file <%= ENV["APP_ROOT"] %>/nginx/conf/.htpasswd;
      {{end}}

      {{if .SSI}}
        ssi on;
      {{end}}

      {{if .HSTS}}
        add_header Strict-Transport-Security "max-age=31536000{{if .HSTSIncludeSubDomains}}; includeSubDomains{{end}}{{if .HSTSPreload}}; preload{{end}}";
      {{end}}

      {{if ne .LocationInclude ""}}
        include {{.LocationInclude}};
      {{end}}

      {{ range $code, $value := .StatusCodes }}
        error_page {{ $code }} {{ $value }};
      {{ end }}
    }

    {{if not .HostDotFiles}}
      location ~ /\. {
        deny all;
        return 404;
      }
    {{end}}
  }
}
`
	MimeTypes = `
types {
  text/html html htm shtml;
  text/css css;
  text/xml xml;
  image/gif gif;
  image/jpeg jpeg jpg;
  application/javascript js;
  application/atom+xml atom;
  application/rss+xml rss;
  font/ttf ttf;
  font/woff woff;
  font/woff2 woff2;
  text/mathml mml;
  text/plain txt;
  text/vnd.sun.j2me.app-descriptor jad;
  text/vnd.wap.wml wml;
  text/x-component htc;
  text/cache-manifest manifest;
  image/png png;
  image/tiff tif tiff;
  image/vnd.wap.wbmp wbmp;
  image/x-icon ico;
  image/x-jng jng;
  image/x-ms-bmp bmp;
  image/svg+xml svg svgz;
  image/webp webp;
  application/java-archive jar war ear;
  application/mac-binhex40 hqx;
  application/msword doc;
  application/pdf pdf;
  application/postscript ps eps ai;
  application/rtf rtf;
  application/vnd.ms-excel xls;
  application/vnd.ms-powerpoint ppt;
  application/vnd.wap.wmlc wmlc;
  application/vnd.google-earth.kml+xml  kml;
  application/vnd.google-earth.kmz kmz;
  application/x-7z-compressed 7z;
  application/x-cocoa cco;
  application/x-java-archive-diff jardiff;
  application/x-java-jnlp-file jnlp;
  application/x-makeself run;
  application/x-perl pl pm;
  application/x-pilot prc pdb;
  application/x-rar-compressed rar;
  application/x-redhat-package-manager  rpm;
  application/x-sea sea;
  application/x-shockwave-flash swf;
  application/x-stuffit sit;
  application/x-tcl tcl tk;
  application/x-x509-ca-cert der pem crt;
  application/x-xpinstall xpi;
  application/xhtml+xml xhtml;
  application/zip zip;
  application/octet-stream bin exe dll;
  application/octet-stream deb;
  application/octet-stream dmg;
  application/octet-stream eot;
  application/octet-stream iso img;
  application/octet-stream msi msp msm;
  application/json json;
  audio/midi mid midi kar;
  audio/mpeg mp3;
  audio/ogg ogg;
  audio/x-m4a m4a;
  audio/x-realaudio ra;
  video/3gpp 3gpp 3gp;
  video/mp4 mp4;
  video/mpeg mpeg mpg;
  video/quicktime mov;
  video/webm webm;
  video/x-flv flv;
  video/x-m4v m4v;
  video/x-mng mng;
  video/x-ms-asf asx asf;
  video/x-ms-wmv wmv;
  video/x-msvideo avi;
}
`
)
<|endoftext|>


<commit_before>package provider

import (
	"crypto/rand"
	"errors"
	"github.com/GehirnInc/GOpenID"
	"strings"
	"time"
)

var (
	ErrAlreadySigned         = errors.New("response has been signed")
	ErrNotNeedsSigning       = errors.New("response does not need signing")
	ErrIdentityNotSet        = errors.New("identity not set")
	ErrIdentitySet           = errors.New("identity set")
	ErrIdentityNotMatched    = errors.New("identity not matched")
	ErrMessageNotSigned      = errors.New("message is not signed")
	ErrVerifyingNotSupported = errors.New("verifying not supported")
)

type Signer struct {
	store    gopenid.Store
	lifetime int64
}

func NewSigner(store gopenid.Store, lifetime int64) *Signer {
	return &Signer{
		store:    store,
		lifetime: lifetime,
	}
}

func (s *Signer) Invalidate(handle string, isStateless bool) (err error) {
	assoc, err := s.store.GetAssociation(handle, isStateless)
	if err != nil {
		return
	}

	err = s.store.DeleteAssociation(assoc)
	return
}

func (s *Signer) Verify(req Request, isStateless bool) (ok bool, err error) {
	var (
		assocHandle gopenid.MessageValue
		signed      gopenid.MessageValue
		sig         gopenid.MessageValue
	)

	switch ret := req.(type) {
	case *CheckAuthenticationRequest:
		assocHandle = ret.assocHandle
		signed = ret.signed
		sig = ret.sig
	default:
		err = ErrVerifyingNotSupported
		return
	}

	assoc, err := s.store.GetAssociation(assocHandle.String(), isStateless)
	if err != nil {
		return
	}

	// signing
	msg := req.GetMessage()
	verify := msg.Copy()
	if err = assoc.Sign(verify, strings.Split(signed.String(), ",")); err != nil {
		return
	}

	expected, _ := verify.GetArg(
		gopenid.NewMessageKey(verify.GetOpenIDNamespace(), "sig"),
	)
	ok = sig == expected

	return
}

func (s *Signer) Sign(res *Response, assocHandle string) (err error) {
	var assoc *gopenid.Association

	if assocHandle == "" {
		assoc, err = gopenid.CreateAssociation(
			rand.Reader,
			gopenid.ASSOC_HMAC_SHA256,
			s.getExpires(),
			true,
		)
	} else {
		assoc, err = s.store.GetAssociation(assocHandle, false)
		if err == nil {
			if !assoc.IsValid() {
				res.AddArg(
					gopenid.NewMessageKey(res.GetNamespace(), "invalidate_handle"),
					gopenid.MessageValue(assocHandle),
				)

				assoc, err = gopenid.CreateAssociation(
					rand.Reader,
					assoc.GetAssocType(),
					s.getExpires(),
					true,
				)
			}
		} else if err == gopenid.ErrAssociationNotFound {
			res.AddArg(
				gopenid.NewMessageKey(res.GetNamespace(), "invalidate_handle"),
				gopenid.MessageValue(assocHandle),
			)

			assoc, err = gopenid.CreateAssociation(
				rand.Reader,
				gopenid.ASSOC_HMAC_SHA256,
				s.getExpires(),
				true,
			)
		} else {
			return
		}
	}

	order := []string{
		"op_endpoint",
		"return_to",
		"response_nonce",
		"assoc_handle",
		"claimed_id",
		"identity",
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "identity")); !ok {
		order = order[:5]
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "claimed_id")); !ok {
		copy(order[4:], order[len(order)-1:])
		order = order[:len(order)-1]
	}

	return assoc.Sign(res.message, order)
}

func (s *Signer) getExpires() int64 {
	return time.Now().Unix() + s.lifetime
}
<commit_msg>use gopneid.ASSOC_DEFAULT<commit_after>package provider

import (
	"crypto/rand"
	"errors"
	"github.com/GehirnInc/GOpenID"
	"strings"
	"time"
)

var (
	ErrAlreadySigned         = errors.New("response has been signed")
	ErrNotNeedsSigning       = errors.New("response does not need signing")
	ErrIdentityNotSet        = errors.New("identity not set")
	ErrIdentitySet           = errors.New("identity set")
	ErrIdentityNotMatched    = errors.New("identity not matched")
	ErrMessageNotSigned      = errors.New("message is not signed")
	ErrVerifyingNotSupported = errors.New("verifying not supported")
)

type Signer struct {
	store    gopenid.Store
	lifetime int64
}

func NewSigner(store gopenid.Store, lifetime int64) *Signer {
	return &Signer{
		store:    store,
		lifetime: lifetime,
	}
}

func (s *Signer) Invalidate(handle string, isStateless bool) (err error) {
	assoc, err := s.store.GetAssociation(handle, isStateless)
	if err != nil {
		return
	}

	err = s.store.DeleteAssociation(assoc)
	return
}

func (s *Signer) Verify(req Request, isStateless bool) (ok bool, err error) {
	var (
		assocHandle gopenid.MessageValue
		signed      gopenid.MessageValue
		sig         gopenid.MessageValue
	)

	switch ret := req.(type) {
	case *CheckAuthenticationRequest:
		assocHandle = ret.assocHandle
		signed = ret.signed
		sig = ret.sig
	default:
		err = ErrVerifyingNotSupported
		return
	}

	assoc, err := s.store.GetAssociation(assocHandle.String(), isStateless)
	if err != nil {
		return
	}

	// signing
	msg := req.GetMessage()
	verify := msg.Copy()
	if err = assoc.Sign(verify, strings.Split(signed.String(), ",")); err != nil {
		return
	}

	expected, _ := verify.GetArg(
		gopenid.NewMessageKey(verify.GetOpenIDNamespace(), "sig"),
	)
	ok = sig == expected

	return
}

func (s *Signer) Sign(res *Response, assocHandle string) (err error) {
	var assoc *gopenid.Association

	if assocHandle == "" {
		assoc, err = gopenid.CreateAssociation(
			rand.Reader,
			gopenid.ASSOC_DEFAULT,
			s.getExpires(),
			true,
		)
	} else {
		assoc, err = s.store.GetAssociation(assocHandle, false)
		if err == nil {
			if !assoc.IsValid() {
				res.AddArg(
					gopenid.NewMessageKey(res.GetNamespace(), "invalidate_handle"),
					gopenid.MessageValue(assocHandle),
				)

				assoc, err = gopenid.CreateAssociation(
					rand.Reader,
					assoc.GetAssocType(),
					s.getExpires(),
					true,
				)
			}
		} else if err == gopenid.ErrAssociationNotFound {
			res.AddArg(
				gopenid.NewMessageKey(res.GetNamespace(), "invalidate_handle"),
				gopenid.MessageValue(assocHandle),
			)

			assoc, err = gopenid.CreateAssociation(
				rand.Reader,
				gopenid.ASSOC_DEFAULT,
				s.getExpires(),
				true,
			)
		} else {
			return
		}
	}

	order := []string{
		"op_endpoint",
		"return_to",
		"response_nonce",
		"assoc_handle",
		"claimed_id",
		"identity",
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "identity")); !ok {
		order = order[:5]
	}

	if _, ok := res.message.GetArg(gopenid.NewMessageKey(res.message.GetOpenIDNamespace(), "claimed_id")); !ok {
		copy(order[4:], order[len(order)-1:])
		order = order[:len(order)-1]
	}

	return assoc.Sign(res.message, order)
}

func (s *Signer) getExpires() int64 {
	return time.Now().Unix() + s.lifetime
}
<|endoftext|>


<commit_before>package pagination

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// AllItems is a convenience for requesting all items of a given entity
var AllItems = &Pagination{Offset: 0, Limit: -1}

// Pagination represents the necessary elements for a paginated request
type Pagination struct {
	Offset int
	Limit  int
}

// New takes an offset and limit.  It returns a newly created Pagination object
// and prevents the offset and limit from being set to illegal values.
func New(offset, limit int) *Pagination {
	p := &Pagination{
		Offset: offset,
		Limit:  limit,
	}

	if p.Offset < 0 {
		p.Offset = 0
	}

	if p.Limit < 1 {
		p.Limit = -1
	}

	return p
}

// ParseFromRequest parses pagination params from an http request and returns
// the pagination object and an error if the pagination is not found
func ParseFromRequest(req *http.Request) *Pagination {
	oStr := req.Header.Get("Offset")
	lStr := req.Header.Get("Limit")

	if oStr == "" {
		oStr = "0"
	}

	if lStr == "" {
		lStr = "10"
	}

	o, err := strconv.Atoi(oStr)
	if err != nil {
		o = 0
	}

	l, err := strconv.Atoi(lStr)
	if err != nil {
		l = 10
	}

	return &Pagination{Offset: o, Limit: l}
}

// AddParams appends the pagination params to the provided set of URL values
func (p *Pagination) AddParams(params *url.Values) {
	params.Set("offset", strconv.Itoa(p.Offset))
	params.Set("limit", strconv.Itoa(p.Limit))
}

// Down increments the offset down by the limit.  It will not increment the
// offset past 0.
func (p *Pagination) Down() {
	if p.Limit > 0 {
		p.Offset -= p.Limit
		if p.Offset < 0 {
			p.Offset = 0
		}
	}
}

// SQL returns a valid string representation of the pagination object
func (p *Pagination) SQL() string {
	strs := []string{}

	if p.Offset > 0 {
		strs = append(strs, fmt.Sprintf("OFFSET %d", p.Offset))
	}

	switch {
	case p.Limit > 0:
		strs = append(strs, fmt.Sprintf("LIMIT %d", p.Limit))
	case p.Limit <= 0:
	}

	return strings.Join(strs, " ")
}

// Up increments the offset up by the limit.
func (p *Pagination) Up() {
	if p.Limit > 0 {
		p.Offset += p.Limit
	}
}
<commit_msg>fixing language of docs<commit_after>package pagination

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// AllItems is a convenience for requesting all items of a given entity
var AllItems = &Pagination{Offset: 0, Limit: -1}

// Pagination represents the necessary elements for a paginated request
type Pagination struct {
	Offset int
	Limit  int
}

// New takes an offset and limit.  It returns a newly created Pagination object
// and prevents the offset and limit from being set to illegal values.
func New(offset, limit int) *Pagination {
	p := &Pagination{
		Offset: offset,
		Limit:  limit,
	}

	if p.Offset < 0 {
		p.Offset = 0
	}

	if p.Limit < 1 {
		p.Limit = -1
	}

	return p
}

// ParseFromRequest parses pagination params from an http request. It will defer
// to defaults if the pagination params are not found.
func ParseFromRequest(req *http.Request) *Pagination {
	oStr := req.Header.Get("Offset")
	lStr := req.Header.Get("Limit")

	if oStr == "" {
		oStr = "0"
	}

	if lStr == "" {
		lStr = "10"
	}

	o, err := strconv.Atoi(oStr)
	if err != nil {
		o = 0
	}

	l, err := strconv.Atoi(lStr)
	if err != nil {
		l = 10
	}

	return &Pagination{Offset: o, Limit: l}
}

// AddParams appends the pagination params to the provided set of URL values
func (p *Pagination) AddParams(params *url.Values) {
	params.Set("offset", strconv.Itoa(p.Offset))
	params.Set("limit", strconv.Itoa(p.Limit))
}

// Down increments the offset down by the limit.  It will not increment the
// offset past 0.
func (p *Pagination) Down() {
	if p.Limit > 0 {
		p.Offset -= p.Limit
		if p.Offset < 0 {
			p.Offset = 0
		}
	}
}

// SQL returns a valid string representation of the pagination object
func (p *Pagination) SQL() string {
	strs := []string{}

	if p.Offset > 0 {
		strs = append(strs, fmt.Sprintf("OFFSET %d", p.Offset))
	}

	switch {
	case p.Limit > 0:
		strs = append(strs, fmt.Sprintf("LIMIT %d", p.Limit))
	case p.Limit <= 0:
	}

	return strings.Join(strs, " ")
}

// Up increments the offset up by the limit.
func (p *Pagination) Up() {
	if p.Limit > 0 {
		p.Offset += p.Limit
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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 sippy

import (
    "sippy/conf"
    "sippy/time"
    "sippy/types"
)

type UasStateUpdating struct {
    *uaStateGeneric
}

func NewUasStateUpdating(ua sippy_types.UA, config sippy_conf.Config) *UasStateUpdating {
    self := &UasStateUpdating{
        uaStateGeneric : newUaStateGeneric(ua, config),
    }
    self.connected = true
    return self
}

func (self *UasStateUpdating) String() string {
    return "Updating(UAS)"
}

func (self *UasStateUpdating) RecvRequest(req sippy_types.SipRequest, t sippy_types.ServerTransaction) (sippy_types.UaState, func()) {
    if req.GetMethod() == "INVITE" {
        t.SendResponseWithLossEmul(req.GenResponse(491, "Request Pending", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
        return nil, nil
    } else if req.GetMethod() == "BYE" {
        self.ua.SendUasResponse(t, 487, "Request Terminated", nil, nil, false)
        t.SendResponseWithLossEmul(req.GenResponse(200, "OK", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
        //print "BYE received in the Updating state, going to the Disconnected state"
        event := NewCCEventDisconnect(nil, req.GetRtime(), self.ua.GetOrigin())
        event.SetReason(req.GetReason())
        self.ua.Enqueue(event)
        self.ua.CancelCreditTimer()
        self.ua.SetDisconnectTs(req.GetRtime())
        return NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(req.GetRtime(), self.ua.GetOrigin(), 0, req) }
    } else if req.GetMethod() == "REFER" {
        if req.GetReferTo() == nil {
            t.SendResponseWithLossEmul(req.GenResponse(400, "Bad Request", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
            return nil, nil
        }
        self.ua.SendUasResponse(t, 487, "Request Terminated", nil, nil, false)
        t.SendResponseWithLossEmul(req.GenResponse(202, "Accepted", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
        refer_to, err := req.GetReferTo().GetBody(self.config)
        if err != nil {
            self.config.ErrorLogger().Error("UasStateUpdating::RecvRequest: #1: " + err.Error())
            return nil, nil
        }
        self.ua.Enqueue(NewCCEventDisconnect(refer_to.GetCopy(), req.GetRtime(), self.ua.GetOrigin()))
        self.ua.CancelCreditTimer()
        self.ua.SetDisconnectTs(req.GetRtime())
        return NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(req.GetRtime(), self.ua.GetOrigin(), 0, req) }
    }
    //print "wrong request %s in the state Updating" % req.getMethod()
    return nil, nil
}

func (self *UasStateUpdating) RecvEvent(_event sippy_types.CCEvent) (sippy_types.UaState, func(), error) {
    eh := _event.GetExtraHeaders()
    switch event := _event.(type) {
    case *CCEventRing:
        code, reason, body := event.scode, event.scode_reason, event.body
        if code == 0 {
            code, reason, body = 180, "Ringing", nil
        }
        if body != nil && body.NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
            self.ua.OnLocalSdpChange(body, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
            return nil, nil, nil
        }
        self.ua.SetLSDP(body)
        self.ua.SendUasResponse(nil, code, reason, body, nil, false, eh...)
        return nil, nil, nil
    case *CCEventPreConnect:
        code, reason, body := event.scode, event.scode_reason, event.body
        if body != nil && body.NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
            self.ua.OnLocalSdpChange(body, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
            return nil, nil, nil
        }
        self.ua.SetLSDP(body)
        self.ua.SendUasResponse(nil, code, reason, body, self.ua.GetLContacts(), true /*ack_wait*/, eh...)
        return NewUasStatePreConnect(self.ua, self.config, true /*confirm_connect*/), nil, nil
    case *CCEventConnect:
        code, reason, body := event.scode, event.scode_reason, event.body
        if body != nil && body.NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
            self.ua.OnLocalSdpChange(body, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
            return nil, nil, nil
        }
        self.ua.SetLSDP(body)
        self.ua.SendUasResponse(nil, code, reason, body, self.ua.GetLContacts(), true, eh...)
        return NewUasStatePreConnect(self.ua, self.config, false /*confirm_connect*/), nil, nil
    case *CCEventRedirect:
        self.ua.SendUasResponse(nil, event.scode, event.scode_reason, event.body, event.GetContacts(), false, eh...)
        return NewUaStateConnected(self.ua, self.config), nil, nil
    case *CCEventFail:
        code, reason := event.scode, event.scode_reason
        if code == 0 {
            code, reason = 500, "Failed"
        }
        if event.warning != nil {
            eh = append(eh, event.warning)
        }
        self.ua.SendUasResponse(nil, code, reason, nil, nil, false, eh...)
        return NewUaStateConnected(self.ua, self.config), nil, nil
    case *CCEventDisconnect:
        self.ua.SendUasResponse(nil, 487, "Request Terminated", nil, nil, false, eh...)
        req, err := self.ua.GenRequest("BYE", nil, nil, eh...)
        if err != nil {
            return nil, nil, err
        }
        self.ua.BeginNewClientTransaction(req, nil)
        self.ua.CancelCreditTimer()
        self.ua.SetDisconnectTs(event.GetRtime())
        return NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(event.GetRtime(), event.GetOrigin(), 0, nil) }, nil
    }
    //return nil, fmt.Errorf("wrong event %s in the Updating state", _event.String())
    return nil, nil, nil
}

func (self *UasStateUpdating) RecvCancel(rtime *sippy_time.MonoTime, inreq sippy_types.SipRequest) {
    req, err := self.ua.GenRequest("BYE", nil, nil)
    if err != nil {
        self.config.ErrorLogger().Error("UasStateUpdating::Cancel: #1: " + err.Error())
        return
    }
    self.ua.BeginNewClientTransaction(req, nil)
    self.ua.CancelCreditTimer()
    self.ua.SetDisconnectTs(rtime)
    self.ua.ChangeState(NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(rtime, self.ua.GetOrigin(), 0, inreq) })
    event := NewCCEventDisconnect(nil, rtime, self.ua.GetOrigin())
    if inreq != nil {
        event.SetReason(inreq.GetReason())
    }
    self.ua.EmitEvent(event)
}

func (self *UasStateUpdating) ID() sippy_types.UaStateID {
    return sippy_types.UAS_STATE_UPDATING
}
<commit_msg>Final responses to re-INVITE expect ACK.<commit_after>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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 sippy

import (
    "sippy/conf"
    "sippy/time"
    "sippy/types"
)

type UasStateUpdating struct {
    *uaStateGeneric
}

func NewUasStateUpdating(ua sippy_types.UA, config sippy_conf.Config) *UasStateUpdating {
    self := &UasStateUpdating{
        uaStateGeneric : newUaStateGeneric(ua, config),
    }
    self.connected = true
    return self
}

func (self *UasStateUpdating) String() string {
    return "Updating(UAS)"
}

func (self *UasStateUpdating) RecvRequest(req sippy_types.SipRequest, t sippy_types.ServerTransaction) (sippy_types.UaState, func()) {
    if req.GetMethod() == "INVITE" {
        t.SendResponseWithLossEmul(req.GenResponse(491, "Request Pending", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
        return nil, nil
    } else if req.GetMethod() == "BYE" {
        self.ua.SendUasResponse(t, 487, "Request Terminated", nil, nil, false)
        t.SendResponseWithLossEmul(req.GenResponse(200, "OK", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
        //print "BYE received in the Updating state, going to the Disconnected state"
        event := NewCCEventDisconnect(nil, req.GetRtime(), self.ua.GetOrigin())
        event.SetReason(req.GetReason())
        self.ua.Enqueue(event)
        self.ua.CancelCreditTimer()
        self.ua.SetDisconnectTs(req.GetRtime())
        return NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(req.GetRtime(), self.ua.GetOrigin(), 0, req) }
    } else if req.GetMethod() == "REFER" {
        if req.GetReferTo() == nil {
            t.SendResponseWithLossEmul(req.GenResponse(400, "Bad Request", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
            return nil, nil
        }
        self.ua.SendUasResponse(t, 487, "Request Terminated", nil, nil, false)
        t.SendResponseWithLossEmul(req.GenResponse(202, "Accepted", nil, self.ua.GetLocalUA().AsSipServer()), false, nil, self.ua.UasLossEmul())
        refer_to, err := req.GetReferTo().GetBody(self.config)
        if err != nil {
            self.config.ErrorLogger().Error("UasStateUpdating::RecvRequest: #1: " + err.Error())
            return nil, nil
        }
        self.ua.Enqueue(NewCCEventDisconnect(refer_to.GetCopy(), req.GetRtime(), self.ua.GetOrigin()))
        self.ua.CancelCreditTimer()
        self.ua.SetDisconnectTs(req.GetRtime())
        return NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(req.GetRtime(), self.ua.GetOrigin(), 0, req) }
    }
    //print "wrong request %s in the state Updating" % req.getMethod()
    return nil, nil
}

func (self *UasStateUpdating) RecvEvent(_event sippy_types.CCEvent) (sippy_types.UaState, func(), error) {
    eh := _event.GetExtraHeaders()
    switch event := _event.(type) {
    case *CCEventRing:
        code, reason, body := event.scode, event.scode_reason, event.body
        if code == 0 {
            code, reason, body = 180, "Ringing", nil
        }
        if body != nil && body.NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
            self.ua.OnLocalSdpChange(body, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
            return nil, nil, nil
        }
        self.ua.SetLSDP(body)
        self.ua.SendUasResponse(nil, code, reason, body, nil, false, eh...)
        return nil, nil, nil
    case *CCEventPreConnect:
        code, reason, body := event.scode, event.scode_reason, event.body
        if body != nil && body.NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
            self.ua.OnLocalSdpChange(body, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
            return nil, nil, nil
        }
        self.ua.SetLSDP(body)
        self.ua.SendUasResponse(nil, code, reason, body, self.ua.GetLContacts(), true /*ack_wait*/, eh...)
        return NewUasStatePreConnect(self.ua, self.config, true /*confirm_connect*/), nil, nil
    case *CCEventConnect:
        code, reason, body := event.scode, event.scode_reason, event.body
        if body != nil && body.NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
            self.ua.OnLocalSdpChange(body, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
            return nil, nil, nil
        }
        self.ua.SetLSDP(body)
        self.ua.SendUasResponse(nil, code, reason, body, self.ua.GetLContacts(), true, eh...)
        return NewUasStatePreConnect(self.ua, self.config, false /*confirm_connect*/), nil, nil
    case *CCEventRedirect:
        self.ua.SendUasResponse(nil, event.scode, event.scode_reason, event.body, event.GetContacts(), true /*ack_wait*/, eh...)
        return NewUasStatePreConnect(self.ua, self.config, false /*confirm_connect*/), nil, nil
    case *CCEventFail:
        code, reason := event.scode, event.scode_reason
        if code == 0 {
            code, reason = 500, "Failed"
        }
        if event.warning != nil {
            eh = append(eh, event.warning)
        }
        self.ua.SendUasResponse(nil, code, reason, nil, nil, true /*ack_wait*/, eh...)
        return NewUasStatePreConnect(self.ua, self.config, false /*confirm_connect*/), nil, nil
    case *CCEventDisconnect:
        self.ua.SendUasResponse(nil, 487, "Request Terminated", nil, nil, false, eh...)
        req, err := self.ua.GenRequest("BYE", nil, nil, eh...)
        if err != nil {
            return nil, nil, err
        }
        self.ua.BeginNewClientTransaction(req, nil)
        self.ua.CancelCreditTimer()
        self.ua.SetDisconnectTs(event.GetRtime())
        return NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(event.GetRtime(), event.GetOrigin(), 0, nil) }, nil
    }
    //return nil, fmt.Errorf("wrong event %s in the Updating state", _event.String())
    return nil, nil, nil
}

func (self *UasStateUpdating) RecvCancel(rtime *sippy_time.MonoTime, inreq sippy_types.SipRequest) {
    req, err := self.ua.GenRequest("BYE", nil, nil)
    if err != nil {
        self.config.ErrorLogger().Error("UasStateUpdating::Cancel: #1: " + err.Error())
        return
    }
    self.ua.BeginNewClientTransaction(req, nil)
    self.ua.CancelCreditTimer()
    self.ua.SetDisconnectTs(rtime)
    self.ua.ChangeState(NewUaStateDisconnected(self.ua, self.config), func() { self.ua.DiscCb(rtime, self.ua.GetOrigin(), 0, inreq) })
    event := NewCCEventDisconnect(nil, rtime, self.ua.GetOrigin())
    if inreq != nil {
        event.SetReason(inreq.GetReason())
    }
    self.ua.EmitEvent(event)
}

func (self *UasStateUpdating) ID() sippy_types.UaStateID {
    return sippy_types.UAS_STATE_UPDATING
}
<|endoftext|>


<commit_before>package eveConsumer

import "testing"

func TestEntities(t *testing.T) {
	r := ctx.Cache.Get()
	defer r.Close()
	err := EntityAddToQueue(1, &r)
	if err != nil {
		t.Error(err)
		return
	}
}

func TestEntitiesTrigger(t *testing.T) {
	_, err := entitiesTrigger(eC)
	if err != nil {
		t.Error(err)
		return
	}
}

func TestEntitiesConsumer(t *testing.T) {
	r := ctx.Cache.Get()
	defer r.Close()
	for {
		work, err := entitiesConsumer(eC, &r)
		if err != nil {
			t.Error(err)
			return
		}
		if work == false {
			break
		}
	}
}

func TestCharSearchConsumer(t *testing.T) {
	r := ctx.Cache.Get()
	defer r.Close()

	CharSearchAddToQueue("croakroach", &r)

	for {
		work, err := charSearchConsumer(eC, &r)
		if err != nil {
			t.Error(err)
			return
		}
		if work == false {
			break
		}
	}
}
<commit_msg>update tests<commit_after>package eveConsumer

import "testing"

func TestEntities(t *testing.T) {
	r := ctx.Cache.Get()
	defer r.Close()
	err := EntityAddToQueue(1, &r)
	if err != nil {
		t.Error(err)
		return
	}
}

func TestEntitiesTrigger(t *testing.T) {
	_, err := entitiesTrigger(eC)
	if err != nil {
		t.Error(err)
		return
	}
}

func TestEntitiesConsumer(t *testing.T) {
	r := ctx.Cache.Get()
	defer r.Close()
	for {
		work, err := entitiesConsumer(eC, &r)
		if err != nil {
			t.Error(err)
			return
		}
		if work == false {
			break
		}
	}
}

func TestCharSearchConsumer(t *testing.T) {
	r := ctx.Cache.Get()
	defer r.Close()

	CharSearchAddToQueue([]interface{}{"croakroach", "some other dude"}, &r)

	for {
		work, err := charSearchConsumer(eC, &r)
		if err != nil {
			t.Error(err)
			return
		}
		if work == false {
			break
		}
	}
}
<|endoftext|>


<commit_before>package spectrum

import (
	"testing"
	"sdl"
	"io/ioutil"
	"image"
	"image/png"
	"os"
	"strings"
	"unsafe"
)

func (s *SDLSurface) At(x, y int) image.Color {
	var bpp = int(s.Surface.Format.BytesPerPixel)

	var pixel = uintptr(unsafe.Pointer(s.Surface.Pixels))

	pixel += uintptr(y*int(s.Surface.Pitch) + x*bpp)

	var color = *((*uint32)(unsafe.Pointer(pixel)))

	var r uint8
	var g uint8
	var b uint8
	var a uint8

	sdl.GetRGBA(color, s.Surface.Format, &r, &g, &b, &a)

	return image.RGBAColor{uint8(r), uint8(g), uint8(b), uint8(a)}
}

func initSDL() {
	if sdl.Init(sdl.INIT_VIDEO) != 0 {
		panic(sdl.GetError())
	}
}

func newSurface() *sdl.Surface {
	return sdl.SetVideoMode(TotalScreenWidth, TotalScreenHeight, 32, 0)
}

func readOutputImage(filename string) image.Image {
	var file *os.File
	var err os.Error
	var image image.Image

	if file, err = os.Open(filename, os.O_RDONLY, 0); err != nil {
		panic(err)
	}

	if image, err = png.Decode(file); err != nil {
		panic(err)
	}
	return image
}

func readInputImage(filename string) *Display {
	display := &Display{}
	display.memory, _ = ioutil.ReadFile(filename)
	return display
}

func colorsAreNotEqual(got, expected image.Color) bool {
	got_r, got_g, got_b, got_a := got.RGBA()
	expected_r, expected_g, expected_b, expected_a := expected.RGBA()
	if (got_r != expected_r) || (got_g != expected_g) || (got_b != expected_b) || (got_a != expected_a) {
		return true
	}
	return false
}

func imagesAreNotEqual(got *SDLScreen, expected image.Image) image.Image {
	diff := false
	diffImage := image.NewRGBA(TotalScreenWidth, TotalScreenHeight)

	for y := 0; y < TotalScreenHeight; y++ {
		for x := 0; x < TotalScreenWidth; x++ {
			if colorsAreNotEqual(got.ScreenSurface.At(x, y), expected.At(x, y)) {
				diff = true
				diffImage.Set(x, y, image.Red)
			}
		}
	}

	if diff {
		return diffImage
	}

	return nil

}

type RenderTest struct {
	in, out     string
	borderColor RGBA
	flash       bool
	diffImage   image.Image
}

func (r *RenderTest) renderInputImage() bool {
	renderedScreen := &SDLScreen{nil, SDLSurface{newSurface()}}

	expectedImage := readOutputImage(r.out)
	inputImage := readInputImage(r.in)

	inputImage.borderColor = r.borderColor

	if r.flash {
		inputImage.flashFrame = 0x10
		inputImage.prepare()
	}

	displayData := inputImage.prepare()

	renderedScreen.render(displayData, nil)

	if diffImage := imagesAreNotEqual(renderedScreen, expectedImage); diffImage != nil {
		r.diffImage = diffImage
		return true
	}

	return false
}

func (r *RenderTest) getDiffFn() string {
	return strings.TrimRight(r.out, ".png") + "_diff.png"
}

func (r *RenderTest) reportError(t *testing.T) {
	t.Errorf("Expected image %s is not equal to the rendered one! Check %s\n", r.out, r.getDiffFn())

	if file, err := os.Open(r.getDiffFn(), os.O_CREATE|os.O_WRONLY, 0666); err != nil {
		panic(err)
	} else {
		if err := png.Encode(file, r.diffImage); err != nil {
			panic(err)
		}
	}
}

var RenderTests = []RenderTest{
	RenderTest{in: "testdata/initial.scr", out: "testdata/initial.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_0.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_1.png", borderColor: RGBA{192, 192, 192, 255}, flash: true},
}

// Test the static render capabilities. Flashing is not tested here.
func TestSDLRenderer(t *testing.T) {

	initSDL()

	for _, r := range RenderTests {
		if notEqual := r.renderInputImage(); notEqual {
			r.reportError(t)
		}
	}

	sdl.Quit()

}
<commit_msg>Add initial benchmarks for the sdl renderer<commit_after>package spectrum

import (
	"testing"
	"sdl"
	"io/ioutil"
	"image"
	"image/png"
	"os"
	"strings"
	"unsafe"
)

func (s *SDLSurface) At(x, y int) image.Color {
	var bpp = int(s.Surface.Format.BytesPerPixel)

	var pixel = uintptr(unsafe.Pointer(s.Surface.Pixels))

	pixel += uintptr(y*int(s.Surface.Pitch) + x*bpp)

	var color = *((*uint32)(unsafe.Pointer(pixel)))

	var r uint8
	var g uint8
	var b uint8
	var a uint8

	sdl.GetRGBA(color, s.Surface.Format, &r, &g, &b, &a)

	return image.RGBAColor{uint8(r), uint8(g), uint8(b), uint8(a)}
}

func initSDL() {
	if sdl.Init(sdl.INIT_VIDEO) != 0 {
		panic(sdl.GetError())
	}
}

func newSurface() *sdl.Surface {
	return sdl.SetVideoMode(TotalScreenWidth, TotalScreenHeight, 32, 0)
}

func readOutputImage(filename string) image.Image {
	var file *os.File
	var err os.Error
	var image image.Image

	if file, err = os.Open(filename, os.O_RDONLY, 0); err != nil {
		panic(err)
	}

	if image, err = png.Decode(file); err != nil {
		panic(err)
	}
	return image
}

func readInputImage(filename string) *Display {
	display := &Display{}
	display.memory, _ = ioutil.ReadFile(filename)
	return display
}

func colorsAreNotEqual(got, expected image.Color) bool {
	got_r, got_g, got_b, got_a := got.RGBA()
	expected_r, expected_g, expected_b, expected_a := expected.RGBA()
	if (got_r != expected_r) || (got_g != expected_g) || (got_b != expected_b) || (got_a != expected_a) {
		return true
	}
	return false
}

func imagesAreNotEqual(got *SDLScreen, expected image.Image) image.Image {
	diff := false
	diffImage := image.NewRGBA(TotalScreenWidth, TotalScreenHeight)

	for y := 0; y < TotalScreenHeight; y++ {
		for x := 0; x < TotalScreenWidth; x++ {
			if colorsAreNotEqual(got.ScreenSurface.At(x, y), expected.At(x, y)) {
				diff = true
				diffImage.Set(x, y, image.Red)
			}
		}
	}

	if diff {
		return diffImage
	}

	return nil

}

type RenderTest struct {
	in, out     string
	borderColor RGBA
	flash       bool
	diffImage   image.Image
}

func (r *RenderTest) renderInputImage() bool {
	renderedScreen := &SDLScreen{nil, SDLSurface{newSurface()}}

	expectedImage := readOutputImage(r.out)
	inputImage := readInputImage(r.in)

	inputImage.borderColor = r.borderColor

	if r.flash {
		inputImage.flashFrame = 0x10
		inputImage.prepare()
	}

	displayData := inputImage.prepare()

	renderedScreen.render(displayData, nil)

	if diffImage := imagesAreNotEqual(renderedScreen, expectedImage); diffImage != nil {
		r.diffImage = diffImage
		return true
	}

	return false
}

func (r *RenderTest) getDiffFn() string {
	return strings.TrimRight(r.out, ".png") + "_diff.png"
}

func (r *RenderTest) reportError(t *testing.T) {
	t.Errorf("Expected image %s is not equal to the rendered one! Check %s\n", r.out, r.getDiffFn())

	if file, err := os.Open(r.getDiffFn(), os.O_CREATE|os.O_WRONLY, 0666); err != nil {
		panic(err)
	} else {
		if err := png.Encode(file, r.diffImage); err != nil {
			panic(err)
		}
	}
}

var RenderTests = []RenderTest{
	RenderTest{in: "testdata/initial.scr", out: "testdata/initial.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_0.png", borderColor: RGBA{192, 192, 192, 255}},
	RenderTest{in: "testdata/flash.scr", out: "testdata/flash_1.png", borderColor: RGBA{192, 192, 192, 255}, flash: true},
}

func TestSDLRenderer(t *testing.T) {

	initSDL()

	for _, r := range RenderTests {
		if notEqual := r.renderInputImage(); notEqual {
			r.reportError(t)
		}
	}

	sdl.Quit()

}

func BenchmarkRender(b *testing.B) {
	renderedScreen := &SDLScreen{nil, SDLSurface{newSurface()}}

	inputImage := readInputImage("testdata/initial.scr")
	inputImage.borderColor = RGBA{192, 192, 192, 255}

	displayData := inputImage.prepare()

	for i := 0; i < b.N; i++ {
		renderedScreen.render(displayData, nil)
	}

}

func BenchmarkRenderWithoutChanges(b *testing.B) {
	var oldDisplayData *DisplayData = nil
	renderedScreen := &SDLScreen{nil, SDLSurface{newSurface()}}

	inputImage := readInputImage("testdata/initial.scr")
	inputImage.borderColor = RGBA{192, 192, 192, 255}

	displayData := inputImage.prepare()

	for i := 0; i < b.N; i++ {
		renderedScreen.render(displayData, oldDisplayData)
		oldDisplayData = displayData
	}

}
<|endoftext|>